๐ฌ Chat
Chat provides HTTP and WebSocket composition for channels, messages, attachments, templates, subscriptions, and per-channel read states through chatService.
Start hereโ
Mount the service below /api. defService installs JSON parsing on the returned router. Cookie transport additionally needs cookie-parser before the mount, signed attachment and channel-icon operations need a fileStorageDriver, and the current service must receive a webSocketServer because it always composes the WebSocket route.
chatService selects getBearerTokenInfo unless authMode === 'cookie', when it selects getCookieTokenInfo. The typed store requires identities, chatChannels, subscriptions, chatMessages, and chatChannelReadStates; organizations and chatMessageTemplates are optional in the type but required at runtime by routes that query them.
import express from 'express';
import cookieParser from 'cookie-parser';
import { services } from '@nodeblocks/backend-sdk';
const app = express();
app.use(cookieParser()); // Only required for authMode: 'cookie'.
app.use('/api', services.chatService(
{ identities, chatChannels, organizations, subscriptions, chatMessages, chatMessageTemplates, chatChannelReadStates },
{
authSecrets: { authEncSecret: process.env.AUTH_ENC_SECRET!, authSignSecret: process.env.AUTH_SIGN_SECRET! },
authMode: 'bearer',
identity: { typeIds: { admin: 'admin-type-id', guest: 'guest-type-id', regular: 'regular-type-id' } },
organization: { roles: { admin: 'organization-admin-role-id', member: 'organization-member-role-id', owner: 'organization-owner-role-id' } },
},
{ fileStorageDriver, webSocketServer },
));
| Configuration | Default / source behavior | Effect |
|---|---|---|
authSecrets.authEncSecret | Required; passed to every composed feature through configuration | Required authentication secret material. |
authSecrets.authSignSecret | Required; passed to every composed feature through configuration | Required authentication secret material. |
authMode | Omitted and 'bearer' select getBearerTokenInfo; 'cookie' selects getCookieTokenInfo | Selects the protected-route access-token transport. |
identity.typeIds.admin | Read by administrator checks when supplied | Enables the admin branch of channel, subscription, and template access rules. |
organization.roles.owner / admin | Read by template routes when supplied | Enables organization-template authorization. |
fileStorageDriver | Required for attachment upload/download URLs and channel icon upload URLs | Supplies signed-file operations. |
webSocketServer | Required when constructing the current full chatService | Registers streamChatMessagesRoute. |
Common tasksโ
| Task | Start with | Contract |
|---|---|---|
| Manage channels | Channel features | Features, routes |
| Send, list, edit, or stream messages | Message features | Routes, schemas |
| Attach files or obtain upload URLs | File-storage-backed routes | Blocks, routes |
| Manage templates, subscriptions, and read states | Template feature groups | Features |
Chat exposes no public HTTP endpoint: every HTTP route begins with isAuthenticated(). The WebSocket stream is currently unguarded because its intended authentication and subscription validators are commented out; this is a source limitation, not a public-HTTP authentication workflow.
Bearer HTTP workflowโ
export ACCESS_TOKEN='replace-with-an-access-token'
export CHANNEL_ID='replace-with-a-channel-id'
curl -X POST 'http://localhost:8080/api/channels' \
-H "authorization: Bearer $ACCESS_TOKEN" \
-H 'content-type: application/json' \
-d '{"name":"Support","description":"Customer support"}'
curl "http://localhost:8080/api/channels/$CHANNEL_ID/messages" \
-H "authorization: Bearer $ACCESS_TOKEN"
This is a host-application fragment: the token must identify an existing identity, and the second request needs an existing channel subscription. Channel creation returns 201 with the normalized channel in data; channel-message lookup returns 200 with normalized messages and pagination metadata. A missing/invalid token fails authentication, while a missing subscription fails authorization. Consult createChatChannelRoute, createChatChannelSchema, getChannelMessagesRoute, and getChannelMessagesSchema.
Cookie HTTP workflowโ
With authMode: 'cookie', register cookie-parser before Chat, obtain an access cookie through Authentication, and include that cookie in the request. The example returns 200 with normalized channels and pagination metadata when the token identity matches the requested scope; a missing/invalid cookie fails authentication. The same protected route rules applyโonly token extraction changes. See findChatChannelsRoute and findChatChannelsSchema.
export ACCESS_COOKIE='accessToken=replace-with-an-access-token'
curl 'http://localhost:8080/api/channels' \
-H "cookie: $ACCESS_COOKIE"
WebSocket workflowโ
Pass webSocketServer to chatService before construction, then connect to streamChatMessagesRoute with the required channelId query value defined by streamChatMessagesSchema. The route uses protocol ws at /messages/listen and emits normalized inserted messages as JSON. A missing channel ID maps to 400, and stream construction failure maps to 500. Its intended isAuthenticated() and hasSubscription(...) validators are currently commented out in source, so configured Bearer/cookie extraction is not enforced for this endpoint.
Custom feature compositionโ
Compose only the public feature exports needed by your host, then call defService with the same data-store/configuration context passed by chatService. Add fileStorageDriver and webSocketServer only when the selected features require them.
import { partial } from 'ramda';
import { features, primitives, utils } from '@nodeblocks/backend-sdk';
const channelFeature = primitives.compose(
features.createChannelFeature,
features.getChannelFeature,
);
const router = primitives.defService(partial(channelFeature, [{
authenticate: utils.getBearerTokenInfo,
configuration,
dataStores: { identities, chatChannels, subscriptions },
fileStorageDriver,
}]));
app.use('/api', router);
This HTTP-only custom composition does not include streamChatMessagesFeature, so it does not need a WebSocket server. Supply every collection and driver read by the selected features.
Reference mapโ
| Page | Purpose |
|---|---|
| Blocks | Reusable persistence, normalization, signed-file, and stream operations. |
| Features | Schema-to-route composition. |
| Handlers | HTTP pipeline operations and terminators. |
| Routes | Exact HTTP and WebSocket endpoint contracts. |
| Schemas | Field-level request contracts. |
| Validators | Shared access and existence guards. |
Related modulesโ
See Authentication for token transport, file-storage for signed-file drivers, Organization for role configuration, and error handling for shared failures.