メインコンテンツまでスキップ
バージョン: 🚧 Canary

🛣️ Chat routes

Chat routes are SDK composers, not Express middleware. The inventory and details below document the exact public HTTP and WebSocket endpoints.

Inventory

RouteMethod / protocolPathSchemaValidatorsSuccess status
createChatChannelRoutePOST / HTTP/channelscreateChatChannelSchemaisAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'ownerId']) )201
findChatChannelsRouteGET / HTTP/channelsfindChatChannelsSchemaisAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestQuery', 'ownerId']) )200
getChatChannelRouteGET / HTTP/channels/:channelIdgetChatChannelSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId']) )200
updateChatChannelRoutePATCH / HTTP/channels/:channelIdupdateChatChannelSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) )200
deleteChatChannelRouteDELETE / HTTP/channels/:channelIddeleteChatChannelSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) )204
getChannelMessagesRouteGET / HTTP/channels/:channelId/messagesgetChannelMessagesSchemaisAuthenticated(), channelExists(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId'])200
getChatChannelIconUploadUrlRouteGET / HTTP/channels/:channelId/icon-upload-urlgetSignedImageUploadUrlSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) )200
createChatMessageRoutePOST / HTTP/messagescreateChatMessageSchemaisAuthenticated(), isSelf(['params', 'requestBody', 'senderId']), hasSubscription(['params', 'requestBody', 'channelId'])201
findChatMessagesRouteGET / HTTP/messagesfindChatMessagesSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasSubscription(['params', 'requestQuery', 'channelId']), isSelf(['params', 'requestQuery', 'senderId']) )200
getChatMessageRouteGET / HTTP/messages/:messageIdgetChatMessageSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) )200
updateChatMessageRoutePATCH / HTTP/messages/:messageIdupdateChatMessageSchemaisAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId'])200
deleteChatMessageRouteDELETE / HTTP/messages/:messageIddeleteChatMessageSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) )204
getChatMessageAttachmentUploadUrlRouteGET / HTTP/messages/:messageId/attachment-upload-urlgetSignedFileUploadUrlSchemaisAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId'])200
streamChatMessagesRouteWS / WebSocket/messages/listenstreamChatMessagesSchemaNoneMessage stream
createChatMessageAttachmentRoutePOST / HTTP/messages/:messageId/attachmentscreateChatMessageAttachmentSchemaisAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId'])201
deleteChatMessageAttachmentRouteDELETE / HTTP/messages/:messageId/attachments/:attachmentIddeleteChatMessageAttachmentSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) )204
createChatMessageTemplateRoutePOST / HTTP/message-templatescreateChatMessageTemplateSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestBody', 'organizationId'] ) )201
getChatMessageTemplateRouteGET / HTTP/message-templates/:messageTemplateIdgetChatMessageTemplateSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) )200
updateChatMessageTemplateRoutePATCH / HTTP/message-templates/:messageTemplateIdupdateChatMessageTemplateSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) )200
deleteChatMessageTemplateRouteDELETE / HTTP/message-templates/:messageTemplateIddeleteChatMessageTemplateSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) )204
findChatMessageTemplatesRouteGET / HTTP/message-templatesfindChatMessageTemplatesSchemaisAuthenticated(), checkIdentityType(['admin'])200
findChatMessageTemplatesForOrganizationRouteGET / HTTP/organizations/:organizationId/message-templatesfindChatMessageTemplatesForOrganizationSchemaisAuthenticated(), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] )200
upsertChatChannelReadStateRoutePUT / HTTP/channels/:channelId/read-stateupsertChatChannelReadStateSchemaisAuthenticated(), channelExists(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId']), isSelf(['params', 'requestBody', 'identityId'])204
createChatSubscriptionRoutePOST / HTTP/subscriptionscreateChatSubscriptionSchemaisAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'subscribedId']) )201
findChatSubscriptionsRouteGET / HTTP/subscriptionsfindChatSubscriptionsSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasSubscription(['params', 'requestQuery', 'channelId']), ownsChannel(['params', 'requestQuery', 'channelId']), isSelf(['params', 'requestQuery', 'subscribedId']) )200
getChatSubscriptionRouteGET / HTTP/subscriptions/:subscriptionIdgetChatSubscriptionSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsSubscription(['params', 'requestParams', 'subscriptionId']) )200
deleteChatSubscriptionRouteDELETE / HTTP/subscriptions/:subscriptionIddeleteChatSubscriptionSchemaisAuthenticated(), some( checkIdentityType(['admin']), ownsSubscription(['params', 'requestParams', 'subscriptionId']) )204

Details

createChatChannelRoute

Implementation

Endpoint: POST /channels

Access: isAuthenticated()some(...)checkIdentityType(...)isSelf(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'ownerId']) ),.

Request: createChatChannelSchema validates the application/json body: Required name and ownerId; optional nullable icon.

Pipeline: createChatChannelgetChatChannelByIdcreateChatChannelTerminator.

Success: 201 with the normalized channel in the response descriptor’s data.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const createChatChannelRoute = withRoute({
handler: compose(
withLogging(createChatChannel),
flatMapAsync(withLogging(getChatChannelById)),
lift(withLogging(createChatChannelTerminator))
),
method: 'POST',
path: '/channels',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
isSelf(['params', 'requestBody', 'ownerId'])
),
],
});

findChatChannelsRoute

Implementation

Endpoint: GET /channels

Access: isAuthenticated()some(...)checkIdentityType(...)isSelf(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestQuery', 'ownerId']) ),.

Request: findChatChannelsSchema validates query parameters: Optional name, ownerId, and shared pagination fields.

Pipeline: findChatChannelsnormalizeChatChannelsListTerminator.

Success: 200 with normalized channels and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const findChatChannelsRoute = withRoute({
handler: compose(
withPagination(withLogging(findChatChannels)),
lift(withLogging(normalizeChatChannelsListTerminator))
),
method: 'GET',
path: '/channels',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
isSelf(['params', 'requestQuery', 'ownerId'])
),
],
});

getChatChannelRoute

Implementation

Endpoint: GET /channels/:channelId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsChannel(...)hasSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId']) ),.

Request: getChatChannelSchema validates path parameters: Required channelId.

Pipeline: getChatChannelByIdnormalizeChatChannelTerminator.

Success: 200 with the normalized channel.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const getChatChannelRoute = withRoute({
handler: compose(
withLogging(getChatChannelById),
lift(withLogging(normalizeChatChannelTerminator))
),
method: 'GET',
path: '/channels/:channelId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsChannel(['params', 'requestParams', 'channelId']),
hasSubscription(['params', 'requestParams', 'channelId'])
),
],
});

updateChatChannelRoute

Implementation

Endpoint: PATCH /channels/:channelId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsChannel(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) ),.

Request: updateChatChannelSchema validates path parameters and the application/json body: Required channelId; body permits optional name and nullable icon.

Pipeline: updateChatChannelgetChatChannelByIdnormalizeChatChannelTerminator.

Success: 200 with the updated, normalized channel.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const updateChatChannelRoute = withRoute({
handler: compose(
withLogging(updateChatChannel),
flatMapAsync(withLogging(getChatChannelById)),
lift(withLogging(normalizeChatChannelTerminator))
),
method: 'PATCH',
path: '/channels/:channelId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsChannel(['params', 'requestParams', 'channelId'])
),
],
});

deleteChatChannelRoute

Implementation

Endpoint: DELETE /channels/:channelId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsChannel(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) ),.

Request: deleteChatChannelSchema validates path parameters: Required channelId.

Pipeline: deleteChatChanneldeleteChatChannelTerminator.

Success: Empty 204 response.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const deleteChatChannelRoute = withRoute({
handler: compose(
withLogging(deleteChatChannel),
lift(withLogging(deleteChatChannelTerminator))
),
method: 'DELETE',
path: '/channels/:channelId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsChannel(['params', 'requestParams', 'channelId'])
),
],
});

getChannelMessagesRoute

Implementation

Endpoint: GET /channels/:channelId/messages

Access: isAuthenticated()hasSubscription(...)channelExists(...) execute in the source order shown here. Exact invocation: isAuthenticated(), channelExists(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId']),.

Request: getChannelMessagesSchema validates path and query parameters: Required channelId and optional shared pagination fields.

Pipeline: getChannelMessagesByChannelId → pagination → normalizeChatMessages → response projection.

Success: 200 with normalized messages and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatChannelUnknownError500 as shown in its source.

View complete source
export const getChannelMessagesRoute = withRoute({
handler: compose(
withPagination(
withLogging(
applyPayloadArgs(
getChannelMessagesByChannelId,
[
['context', 'db', 'chatMessages'],
['params', 'requestParams', 'channelId'],
],
'paginatedMessages'
)
)
),
flatMapAsync(
applyPayloadArgs(
normalizeChatMessages,
[
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedMessages', 'data'],
],
'normalizedMessages'
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedMessages'],
['context', 'data', 'paginatedMessages', 'metadata'],
],
'normalizedMessagesWithPagination'
)
),
lift(
orThrow(
[[ChatChannelUnknownError, 500]],
[['context', 'data', 'normalizedMessagesWithPagination'], 200]
)
)
),
method: 'GET',
path: '/channels/:channelId/messages',
validators: [
isAuthenticated(),
channelExists(['params', 'requestParams', 'channelId']),
hasSubscription(['params', 'requestParams', 'channelId']),
],
});

getChatChannelIconUploadUrlRoute

Implementation

Endpoint: GET /channels/:channelId/icon-upload-url

Access: isAuthenticated()some(...)checkIdentityType(...)ownsChannel(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsChannel(['params', 'requestParams', 'channelId']) ),.

Request: The shared getSignedImageUploadUrlSchema validates the path channelId and the signed-image upload request contract.

Pipeline: generateChatChannelIconUploadUrlorThrow.

Success: 200 with { objectId, url }.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps FileStorageServiceError500, ChatChannelUnknownError500 as shown in its source.

View complete source
export const getChatChannelIconUploadUrlRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
generateChatChannelIconUploadUrl,
[
['context', 'fileStorageDriver'],
['params', 'requestQuery', 'contentType'],
['params', 'requestQuery', 'contentLength'],
],
'iconUploadUrlResult'
)
),
lift(
orThrow(
[
[FileStorageServiceError, 500],
[ChatChannelUnknownError, 500],
],
[['context', 'data', 'iconUploadUrlResult'], 200]
)
)
),
method: 'GET',
path: '/channels/:channelId/icon-upload-url',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsChannel(['params', 'requestParams', 'channelId'])
),
],
});

createChatMessageRoute

Implementation

Endpoint: POST /messages

Access: isAuthenticated()isSelf(...)hasSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), isSelf(['params', 'requestBody', 'senderId']), hasSubscription(['params', 'requestBody', 'channelId']),.

Request: createChatMessageSchema validates the application/json body: Required content, senderId, and channelId; optional title.

Pipeline: createChatMessagegetChatMessageByIdnormalizeChatMessageorThrow.

Success: 201 with the normalized message and signed attachment URLs.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, FileStorageServiceError500, ChatMessageUnexpectedDBError500 as shown in its source.

View complete source
export const createChatMessageRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
createChatMessage,
[
['context', 'db', 'chatMessages'],
['params', 'requestBody'],
],
'messageId'
)
),

flatMapAsync(
applyPayloadArgs(
getChatMessageByIdBlock,
[
['context', 'db', 'chatMessages'],
['context', 'data', 'messageId'],
],
'message'
)
),

flatMapAsync(
applyPayloadArgs(
normalizeChatMessage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'message'],
],
'normalizedMessage'
)
),

lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[FileStorageServiceError, 500],
[ChatMessageUnexpectedDBError, 500],
],
[['context', 'data', 'normalizedMessage'], 201]
)
)
),
method: 'POST',
path: '/messages',
validators: [
isAuthenticated(),
isSelf(['params', 'requestBody', 'senderId']),
hasSubscription(['params', 'requestBody', 'channelId']),
],
});

findChatMessagesRoute

Implementation

Endpoint: GET /messages

Access: isAuthenticated()some(...)checkIdentityType(...)isSelf(...)hasSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasSubscription(['params', 'requestQuery', 'channelId']), isSelf(['params', 'requestQuery', 'senderId']) ),.

Request: findChatMessagesSchema validates query parameters: Required channelId; optional message filters and pagination.

Pipeline: findChatMessages.

Success: 200 with normalized messages and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, FileStorageServiceError500, ChatMessageBlockError500 as shown in its source.

View complete source
export const findChatMessagesRoute = withRoute({
handler: compose(
withPagination(
withLogging(
applyPayloadArgs(
findChatMessages,
[
['context', 'db', 'chatMessages'],
['params', 'requestQuery'],
],
'paginatedMessages'
)
)
),
flatMapAsync(
applyPayloadArgs(
normalizeChatMessages,
[
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedMessages', 'data'],
],
'normalizedMessages'
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedMessages'],
['context', 'data', 'paginatedMessages', 'metadata'],
],
'normalizedMessagesWithPagination'
)
),
lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[FileStorageServiceError, 500],
[ChatMessageBlockError, 500],
],
[['context', 'data', 'normalizedMessagesWithPagination']]
)
)
),
method: 'GET',
path: '/messages',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasSubscription(['params', 'requestQuery', 'channelId']),
isSelf(['params', 'requestQuery', 'senderId'])
),
],
});

getChatMessageRoute

Implementation

Endpoint: GET /messages/:messageId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) ),.

Request: getChatMessageSchema validates path parameters: Required messageId.

Pipeline: getChatMessageByIdnormalizeChatMessageorThrow.

Success: 200 with the normalized message.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, FileStorageServiceError500, ChatMessageBlockError500 as shown in its source.

View complete source
export const getChatMessageRoute = withRoute({
handler: compose(
applyPayloadArgs(
getChatMessageByIdBlock,
[
['context', 'db', 'chatMessages'],
['params', 'requestParams', 'messageId'],
],
'message'
),

flatMapAsync(
applyPayloadArgs(
normalizeChatMessage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'message'],
],
'normalizedMessage'
)
),

lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[FileStorageServiceError, 500],
[ChatMessageBlockError, 500],
],
[['context', 'data', 'normalizedMessage']]
)
)
),
method: 'GET',
path: '/messages/:messageId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsMessage(['params', 'requestParams', 'messageId'])
),
],
});

updateChatMessageRoute

Implementation

Endpoint: PATCH /messages/:messageId

Access: isAuthenticated()ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId']),.

Request: updateChatMessageSchema validates path parameters and the application/json body: Required messageId; optional content, senderId, and title.

Pipeline: updateChatMessagegetChatMessageById.

Success: 200 with the updated, normalized message.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, FileStorageServiceError500, ChatMessageBlockError500 as shown in its source.

View complete source
export const updateChatMessageRoute = withRoute({
handler: compose(
withLogging(updateChatMessage),
flatMapAsync(withLogging(getChatMessageById)),

flatMapAsync(
applyPayloadArgs(
normalizeChatMessage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'chatMessage'],
],
'normalizedMessage'
)
),

lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[FileStorageServiceError, 500],
[ChatMessageBlockError, 500],
],
[['context', 'data', 'normalizedMessage'], 200]
)
)
),
method: 'PATCH',
path: '/messages/:messageId',
validators: [
isAuthenticated(),
ownsMessage(['params', 'requestParams', 'messageId']),
],
});

deleteChatMessageRoute

Implementation

Endpoint: DELETE /messages/:messageId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) ),.

Request: deleteChatMessageSchema validates path parameters: Required messageId.

Pipeline: deleteChatMessagedeleteChatMessageTerminator.

Success: Empty 204 response.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const deleteChatMessageRoute = withRoute({
handler: compose(
withLogging(deleteChatMessage),
lift(withLogging(deleteChatMessageTerminator))
),
method: 'DELETE',
path: '/messages/:messageId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsMessage(['params', 'requestParams', 'messageId'])
),
],
});

getChatMessageAttachmentUploadUrlRoute

Implementation

Endpoint: GET /messages/:messageId/attachment-upload-url

Access: isAuthenticated()ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId']),.

Request: The shared getSignedFileUploadUrlSchema validates the path messageId and the signed-file upload request contract.

Pipeline: generateChatMessageAttachmentUploadUrlorThrow.

Success: 200 with { objectId, url }.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps FileStorageServiceError500, ChatMessageBlockError500 as shown in its source.

View complete source
export const getChatMessageAttachmentUploadUrlRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
generateChatMessageAttachmentUploadUrl,
[
['context', 'fileStorageDriver'],
['params', 'requestQuery', 'contentType'],
['params', 'requestQuery', 'contentLength'],
],
'attachmentUploadUrlResult'
)
),
lift(
orThrow(
[
[FileStorageServiceError, 500],
[ChatMessageBlockError, 500],
],
[['context', 'data', 'attachmentUploadUrlResult'], 200]
)
)
),
method: 'GET',
path: '/messages/:messageId/attachment-upload-url',
validators: [
isAuthenticated(),
ownsMessage(['params', 'requestParams', 'messageId']),
],
});

streamChatMessagesRoute

Implementation

Endpoint: ws /messages/listen

Access: No active validator. The source comments out isAuthenticated() and hasSubscription(...), so the current WebSocket endpoint does not enforce Bearer/cookie authentication or channel membership.

Request: streamChatMessagesSchema validates query parameters: Required channelId.

Pipeline: streamChatMessagesnormalizeChatMessageStreamorThrow, producing the WebSocket subject.

Success: A WebSocket subject that emits normalized inserted messages and serializes each value as JSON.

Failure: No access validator runs. Pipeline mappings are ChatMessageBadRequestError400, ChatMessageUnknownError500; subject/database failures can also terminate the WebSocket stream.

View complete source
export const streamChatMessagesRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
streamChatMessages,
[
['context', 'db', 'chatMessages'],
['params', 'requestQuery', 'channelId'],
],
'streamSubject'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeChatMessageStream,
[
['context', 'fileStorageDriver'],
['context', 'data', 'streamSubject'],
],
'normalizedStreamSubject'
)
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageBadRequestError, 400],
[ChatMessageUnknownError, 500],
],
[['context', 'data', 'normalizedStreamSubject']]
)
)
)
),
path: '/messages/listen',
protocol: 'ws',
validators: [
// @TODO: Websockets have different IP address format than the regular HTTP requests. So once that is fixed, we can uncomment this.
// isAuthenticated(),
// hasSubscription(['params', 'requestQuery', 'channelId']),
],
});

createChatMessageAttachmentRoute

Implementation

Endpoint: POST /messages/:messageId/attachments

Access: isAuthenticated()ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), ownsMessage(['params', 'requestParams', 'messageId']),.

Request: createChatMessageAttachmentSchema validates the application/json body: Required UUID objectId and string type.

Pipeline: createChatMessageAttachmentgetChatMessageAttachmentByIdnormalizeChatMessageAttachmentorThrow.

Success: 201 with the normalized attachment { type, url }.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, ChatMessageAttachmentNotFoundBlockError404, ChatMessageUnexpectedDBError500 as shown in its source.

View complete source
export const createChatMessageAttachmentRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
createChatMessageAttachment,
[
['context', 'db', 'chatMessages'],
['params', 'requestParams', 'messageId'],
['params', 'requestBody'],
],
'messageAttachmentId'
)
),

flatMapAsync(
withLogging(
applyPayloadArgs(
getChatMessageAttachmentById,
[
['context', 'db', 'chatMessages'],
['params', 'requestParams', 'messageId'],
['context', 'data', 'messageAttachmentId'],
],
'messageAttachment'
)
)
),

flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeChatMessageAttachment,
[
['context', 'fileStorageDriver'],
['context', 'data', 'messageAttachment'],
],
'normalizedMessageAttachment'
)
)
),

lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[ChatMessageAttachmentNotFoundBlockError, 404],
[ChatMessageUnexpectedDBError, 500],
],
[['context', 'data', 'normalizedMessageAttachment'], 201]
)
)
),
method: 'POST',
path: '/messages/:messageId/attachments',
validators: [
isAuthenticated(),
ownsMessage(['params', 'requestParams', 'messageId']),
],
});

deleteChatMessageAttachmentRoute

Implementation

Endpoint: DELETE /messages/:messageId/attachments/:attachmentId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsMessage(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsMessage(['params', 'requestParams', 'messageId']) ),.

Request: deleteChatMessageAttachmentSchema validates path parameters: Required messageId and attachmentId.

Pipeline: deleteChatMessageAttachmentorThrow.

Success: Empty 204 response after metadata and stored file deletion.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageNotFoundBlockError404, ChatMessageAttachmentNotFoundBlockError404, ChatMessageUnexpectedDBError500, ChatMessageBlockError500, FileStorageServiceError500 as shown in its source.

View complete source
export const deleteChatMessageAttachmentRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
deleteChatMessageAttachment,
[
['context', 'fileStorageDriver'],
['context', 'db', 'chatMessages'],
['params', 'requestParams', 'messageId'],
['params', 'requestParams', 'attachmentId'],
],
'messageAttachmentDeleted'
)
),

lift(
orThrow(
[
[ChatMessageNotFoundBlockError, 404],
[ChatMessageAttachmentNotFoundBlockError, 404],
[ChatMessageUnexpectedDBError, 500],
[ChatMessageBlockError, 500],
[FileStorageServiceError, 500],
],
[['context', 'data', 'messageAttachmentDeleted'], 204]
)
)
),
method: 'DELETE',
path: '/messages/:messageId/attachments/:attachmentId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsMessage(['params', 'requestParams', 'messageId'])
),
],
});

createChatMessageTemplateRoute

Implementation

Endpoint: POST /message-templates

Access: isAuthenticated()some(...)checkIdentityType(...)hasOrgRole(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestBody', 'organizationId'] ) ),.

Request: createChatMessageTemplateSchema validates the application/json body: Required content and title; optional organizationId.

Pipeline: createChatMessageTemplategetChatMessageTemplateByIdorThrow.

Success: 201 with the created template, excluding MongoDB _id.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const createChatMessageTemplateRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
createChatMessageTemplate,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestBody'],
],
'messageTemplateId'
)
),
flatMapAsync(
applyPayloadArgs(
getChatMessageTemplateById,
[
['context', 'db', 'chatMessageTemplates'],
['context', 'data', 'messageTemplateId'],
],
'messageTemplate'
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[['context', 'data', 'messageTemplate'], 201]
)
)
)
),
method: 'POST',
path: '/message-templates',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin'],
['params', 'requestBody', 'organizationId']
)
),
],
});

getChatMessageTemplateRoute

Implementation

Endpoint: GET /message-templates/:messageTemplateId

Access: isAuthenticated()some(...)checkIdentityType(...)hasOrganizationAccessToMessageTemplate(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) ),.

Request: getChatMessageTemplateSchema validates path parameters: Required messageTemplateId.

Pipeline: getChatMessageTemplateByIdorThrow.

Success: 200 with the template, excluding MongoDB _id.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateUnauthorizedError403, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const getChatMessageTemplateRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getChatMessageTemplateById,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestParams', 'messageTemplateId'],
],
'messageTemplate'
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateUnauthorizedError, 403],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[['context', 'data', 'messageTemplate']]
)
)
)
),
method: 'GET',
path: '/message-templates/:messageTemplateId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrganizationAccessToMessageTemplate(
['owner', 'admin'],
['params', 'requestParams', 'messageTemplateId']
)
),
],
});

updateChatMessageTemplateRoute

Implementation

Endpoint: PATCH /message-templates/:messageTemplateId

Access: isAuthenticated()some(...)checkIdentityType(...)hasOrganizationAccessToMessageTemplate(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) ),.

Request: updateChatMessageTemplateSchema validates path parameters and the application/json body: Required template ID; optional content and title.

Pipeline: updateChatMessageTemplategetChatMessageTemplateByIdorThrow.

Success: 200 with the updated template, excluding MongoDB _id.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateUnauthorizedError403, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const updateChatMessageTemplateRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
updateChatMessageTemplate,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestParams', 'messageTemplateId'],
['params', 'requestBody'],
],
'hasUpdatedMessageTemplate'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getChatMessageTemplateById,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestParams', 'messageTemplateId'],
],
'messageTemplate'
)
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateUnauthorizedError, 403],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[['context', 'data', 'messageTemplate'], 200]
)
)
)
),
method: 'PATCH',
path: '/message-templates/:messageTemplateId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrganizationAccessToMessageTemplate(
['owner', 'admin'],
['params', 'requestParams', 'messageTemplateId']
)
),
],
});

deleteChatMessageTemplateRoute

Implementation

Endpoint: DELETE /message-templates/:messageTemplateId

Access: isAuthenticated()some(...)checkIdentityType(...)hasOrganizationAccessToMessageTemplate(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasOrganizationAccessToMessageTemplate( ['owner', 'admin'], ['params', 'requestParams', 'messageTemplateId'] ) ),.

Request: deleteChatMessageTemplateSchema validates path parameters: Required messageTemplateId.

Pipeline: deleteChatMessageTemplateorThrow.

Success: Empty 204 response.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateUnauthorizedError403, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const deleteChatMessageTemplateRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
deleteChatMessageTemplate,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestParams', 'messageTemplateId'],
],
'hasDeletedMessageTemplate'
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateUnauthorizedError, 403],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[[''], 204]
)
)
)
),
method: 'DELETE',
path: '/message-templates/:messageTemplateId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrganizationAccessToMessageTemplate(
['owner', 'admin'],
['params', 'requestParams', 'messageTemplateId']
)
),
],
});

findChatMessageTemplatesRoute

Implementation

Endpoint: GET /message-templates

Access: isAuthenticated()checkIdentityType(...) execute in the source order shown here. Exact invocation: isAuthenticated(), checkIdentityType(['admin']).

Request: findChatMessageTemplatesSchema validates query parameters: Shared pagination fields only.

Pipeline: findChatMessageTemplates → pagination → shared normalizeDocumentsorThrow.

Success: 200 with normalized templates and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateUnauthorizedError403, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const findChatMessageTemplatesRoute = withRoute({
handler: compose(
withPagination(
withLogging(
applyPayloadArgs(
findChatMessageTemplates,
[
['context', 'db', 'chatMessageTemplates'],
['params', 'requestQuery'],
],
'messageTemplates'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeDocuments,
[['context', 'data', 'messageTemplates', 'data']],
'normalizedMessageTemplates'
)
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedMessageTemplates'],
['context', 'data', 'messageTemplates', 'metadata'],
],
'normalizedBody'
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateUnauthorizedError, 403],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[['context', 'data', 'normalizedBody']]
)
)
)
),
method: 'GET',
path: '/message-templates',
validators: [isAuthenticated(), checkIdentityType(['admin'])],
});

findChatMessageTemplatesForOrganizationRoute

Implementation

Endpoint: GET /organizations/:organizationId/message-templates

Access: isAuthenticated()hasOrgRole(...) execute in the source order shown here. Exact invocation: isAuthenticated(), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ),.

Request: findChatMessageTemplatesForOrganizationSchema validates path and query parameters: Required organizationId and shared pagination fields.

Pipeline: buildFilterToGetChatMessageTemplatesByOrganizationIdfindChatMessageTemplates → pagination → shared normalizeDocumentsorThrow.

Success: 200 with normalized templates for the path organization and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatMessageTemplateNotFoundError404, ChatMessageTemplateUnauthorizedError403, ChatMessageTemplateInternalError500, ChatMessageTemplateDbError500 as shown in its source.

View complete source
export const findChatMessageTemplatesForOrganizationRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
buildFilterToGetChatMessageTemplatesByOrganizationId,
[['params', 'requestParams', 'organizationId']],
'filter'
)
),
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(
findChatMessageTemplates,
[
['context', 'db', 'chatMessageTemplates'],
['context', 'data', 'filter'],
],
'messageTemplates'
)
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeDocuments,
[['context', 'data', 'messageTemplates', 'data']],
'normalizedMessageTemplates'
)
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedMessageTemplates'],
['context', 'data', 'messageTemplates', 'metadata'],
],
'normalizedBody'
)
),
lift(
withLogging(
orThrow(
[
[ChatMessageTemplateNotFoundError, 404],
[ChatMessageTemplateUnauthorizedError, 403],
[ChatMessageTemplateInternalError, 500],
[ChatMessageTemplateDbError, 500],
],
[['context', 'data', 'normalizedBody']]
)
)
)
),
method: 'GET',
path: '/organizations/:organizationId/message-templates',
validators: [
isAuthenticated(),
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
),
],
});

upsertChatChannelReadStateRoute

Implementation

Endpoint: PUT /channels/:channelId/read-state

Access: isAuthenticated()isSelf(...)hasSubscription(...)channelExists(...) execute in the source order shown here. Exact invocation: isAuthenticated(), channelExists(['params', 'requestParams', 'channelId']), hasSubscription(['params', 'requestParams', 'channelId']), isSelf(['params', 'requestBody', 'identityId']),.

Request: upsertChatChannelReadStateSchema validates path parameters and the application/json body: Required channelId, identityId, and lastReadMessageId.

Pipeline: findChatMessages.

Success: Empty 204 response after creating or updating the read state.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. This route maps ChatChannelReadStateNotFoundError404, ChatChannelReadStateDatabaseError500, ChatChannelReadStateUnknownError500 as shown in its source.

View complete source
export const upsertChatChannelReadStateRoute = withRoute({
handler: compose(
// Find the existing chat channel read state by channel and identity
compose(
withLogging(
applyPayloadArgs(
buildChatChannelReadStateQuery,
[
['params', 'requestParams', 'channelId'],
['params', 'requestBody', 'identityId'],
],
'chatChannelReadStateQuery'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
findChatChannelReadStates,
[
['context', 'db', 'chatChannelReadStates'],
['context', 'data', 'chatChannelReadStateQuery'],
],
'findChatChannelReadStatesResult'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
head,
[['context', 'data', 'findChatChannelReadStatesResult']],
'chatChannelReadState'
)
)
)
),
// Find the last read message by message id, channel id, and identity id
compose(
flatMapAsync(
withLogging(
applyPayloadArgs(
buildLastReadMessageQuery,
[
['params', 'requestBody', 'lastReadMessageId'],
['params', 'requestParams', 'channelId'],
['params', 'requestBody', 'identityId'],
],
'lastReadMessageQuery'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
findChatMessages,
[
['context', 'db', 'chatMessages'],
['context', 'data', 'lastReadMessageQuery'],
],
'findChatMessagesResult'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
head,
[['context', 'data', 'findChatMessagesResult']],
'lastReadMessage'
)
)
)
),
flatMapAsync(
ifElse(
match(hasValue, ['context', 'data', 'chatChannelReadState']),
// Update the existing chat channel read state
compose(
withLogging(
applyPayloadArgs(
buildUpdateChatChannelReadStatePayload,
[['context', 'data', 'lastReadMessage']],
'updateChatChannelReadStatePayload'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
updateChatChannelReadState,
[
['context', 'db', 'chatChannelReadStates'],
['context', 'data', 'chatChannelReadState', 'id'],
['context', 'data', 'updateChatChannelReadStatePayload'],
],
'upsertChatChannelReadStateResult'
)
)
)
),
// Create a new chat channel read state
compose(
withLogging(
applyPayloadArgs(
buildCreateChatChannelReadStatePayload,
[
['params', 'requestParams', 'channelId'],
['params', 'requestBody', 'identityId'],
['context', 'data', 'lastReadMessage'],
],
'createChatChannelReadStatePayload'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
createChatChannelReadState,
[
['context', 'db', 'chatChannelReadStates'],
['context', 'data', 'createChatChannelReadStatePayload'],
],
'upsertChatChannelReadStateResult'
)
)
)
)
)
),
lift(
withLogging(
orThrow(
[
[ChatChannelReadStateNotFoundError, 404],
[ChatChannelReadStateDatabaseError, 500],
[ChatChannelReadStateUnknownError, 500],
],
[['context', 'data', 'upsertChatChannelReadStateResult'], 204]
)
)
)
),
method: 'PUT',
path: '/channels/:channelId/read-state',
validators: [
isAuthenticated(),
channelExists(['params', 'requestParams', 'channelId']),
hasSubscription(['params', 'requestParams', 'channelId']),
isSelf(['params', 'requestBody', 'identityId']),
],
});

createChatSubscriptionRoute

Implementation

Endpoint: POST /subscriptions

Access: isAuthenticated()some(...)checkIdentityType(...)isSelf(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestBody', 'subscribedId']) ),.

Request: createChatSubscriptionSchema validates the application/json body: Required channelId and subscribedId; other subscription fields optional.

Pipeline: createChatSubscriptiongetChatSubscriptionByIdcreateChatSubscriptionTerminator.

Success: 201 with the created subscription in the response descriptor’s data.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const createChatSubscriptionRoute = withRoute({
handler: compose(
// TODO: need to check if the user is already subscribed to the channel
withLogging(createChatSubscription),
flatMapAsync(withLogging(getChatSubscriptionById)),
lift(withLogging(createChatSubscriptionTerminator))
),
method: 'POST',
path: '/subscriptions',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
isSelf(['params', 'requestBody', 'subscribedId'])
),
],
});

findChatSubscriptionsRoute

Implementation

Endpoint: GET /subscriptions

Access: isAuthenticated()some(...)checkIdentityType(...)isSelf(...)ownsChannel(...)hasSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), hasSubscription(['params', 'requestQuery', 'channelId']), ownsChannel(['params', 'requestQuery', 'channelId']), isSelf(['params', 'requestQuery', 'subscribedId']) ),.

Request: findChatSubscriptionsSchema validates query parameters: Optional subscription filters and shared pagination fields.

Pipeline: findChatSubscriptionsnormalizeChatSubscriptionsListTerminator.

Success: 200 with normalized subscriptions and pagination metadata.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const findChatSubscriptionsRoute = withRoute({
handler: compose(
withPagination(withLogging(findChatSubscriptions)),
lift(withLogging(normalizeChatSubscriptionsListTerminator))
),
method: 'GET',
path: '/subscriptions',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasSubscription(['params', 'requestQuery', 'channelId']),
ownsChannel(['params', 'requestQuery', 'channelId']),
isSelf(['params', 'requestQuery', 'subscribedId'])
),
],
});

getChatSubscriptionRoute

Implementation

Endpoint: GET /subscriptions/:subscriptionId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsSubscription(['params', 'requestParams', 'subscriptionId']) ),.

Request: getChatSubscriptionSchema validates path parameters: Required subscriptionId.

Pipeline: getChatSubscriptionByIdnormalizeChatSubscriptionTerminator.

Success: 200 with the subscription excluding MongoDB _id.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const getChatSubscriptionRoute = withRoute({
handler: compose(
withLogging(getChatSubscriptionById),
lift(withLogging(normalizeChatSubscriptionTerminator))
),
method: 'GET',
path: '/subscriptions/:subscriptionId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsSubscription(['params', 'requestParams', 'subscriptionId'])
),
],
});

deleteChatSubscriptionRoute

Implementation

Endpoint: DELETE /subscriptions/:subscriptionId

Access: isAuthenticated()some(...)checkIdentityType(...)ownsSubscription(...) execute in the source order shown here. Exact invocation: isAuthenticated(), some( checkIdentityType(['admin']), ownsSubscription(['params', 'requestParams', 'subscriptionId']) ),.

Request: deleteChatSubscriptionSchema validates path parameters: Required subscriptionId.

Pipeline: deleteChatSubscriptiondeleteChatSubscriptionTerminator.

Success: Empty 204 response.

Failure: Authentication and authorization failures follow the linked validators before the handler pipeline. Pipeline failures follow the linked handler/block contracts and shared error middleware; this route adds no separate inline error mapping.

View complete source
export const deleteChatSubscriptionRoute = withRoute({
handler: compose(
withLogging(deleteChatSubscription),
lift(withLogging(deleteChatSubscriptionTerminator))
),
method: 'DELETE',
path: '/subscriptions/:subscriptionId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
ownsSubscription(['params', 'requestParams', 'subscriptionId'])
),
],
});