Skip to main content
Version: 🚧 Canary

🚀 Chat Features

Chat features provide complete, pre-composed functionality for chat management operations in Nodeblocks applications. These features combine schemas, routes, and handlers to create ready-to-use API endpoints with proper validation, authentication, and error handling.


🎯 Overview

Chat features are designed to:

  • Provide complete API endpoints for chat management operations
  • Combine schemas with routes for validated operations
  • Include authentication and authorization checks automatically
  • Support functional composition patterns
  • Handle logging and error management seamlessly

This documentation is organized into three main subsections:

  • 📺 Channel Features: Manage chat channels (create, read, update, delete, search)
  • 💬 Message Features: Handle chat messages (create, read, update, delete, search)
  • 🔔 Subscription Features: Manage user subscriptions to channels (create, read, delete, search)

📋 Feature Structure

Each chat feature follows a consistent composition pattern:

  • Schema: Validates input data and parameters
  • Route: Provides HTTP endpoint with handlers
  • Composition: Combines schema and route using compose function

🔧 Available Chat Features

📺 Channel Features

createChannelFeature

Creates a new chat channel with validation and routing.

Purpose: Handles channel creation with complete validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.createChannelFeature, [{ dataStores: db }])));

API Endpoint: POST /api/channels


getChannelFeature

Retrieves individual channel data with access control.

Purpose: Fetches channel details with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.getChannelFeature, [{ dataStores: db }])));

API Endpoint: GET /api/channels/:channelId


findChannelsFeature

Searches and lists channels with filtering and pagination.

Purpose: Provides channel listing with search capabilities

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.findChannelsFeature, [{ dataStores: db }])));

API Endpoint: GET /api/channels


updateChannelFeature

Updates channel information with validation and access control.

Purpose: Modifies channel data with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.updateChannelFeature, [{ dataStores: db }])));

API Endpoint: PATCH /api/channels/:channelId


deleteChannelFeature

Deletes channels with proper authorization.

Purpose: Removes channels with access control

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.deleteChannelFeature, [{ dataStores: db }])));

API Endpoint: DELETE /api/channels/:channelId


getChannelMessagesFeature

Channel messages retrieval feature with schema validation and routing.

Purpose: Handles fetching all messages for a specific channel with complete validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage:
app.use('/api', defService(getChannelMessagesFeature));

// With database (handlers need dataStores):
app.use('/api', defService(partial(getChannelMessagesFeature, [{ dataStores: db }])));

API Endpoint: GET /api/channels/:channelId/messages

Response (200 OK): Array of message objects

Features:

  • Validates user authentication and channel subscription
  • Retrieves all messages for the specified channel
  • Supports pagination via query parameters
  • Proper error handling for missing channels or unauthorized access

Error Responses:

  • 401: User is not authenticated
  • 403: User is not subscribed to the channel
  • 404: Channel does not exist
  • 500: Database operation failed

getChannelIconUploadUrlFeature

Chat channel icon upload URL feature with schema validation and routing.

Purpose: Generates signed upload URLs for chat channel icon images with proper authentication and authorization.

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage:
app.use('/api', defService(features.getChannelIconUploadUrlFeature));

// With database configuration:
app.use('/api', defService(
partial(features.getChannelIconUploadUrlFeature, [
{ dataStores: db, fileStorageDriver: storageDriver }
])
));

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

Response (200 OK):

{
"objectId": "string",
"url": "string"
}

Key Features:

  • Secure Upload URLs: Generates pre-signed URLs for direct file uploads to cloud storage
  • File Type Validation: Validates content type and file size constraints
  • Unique Object IDs: Generates UUID-based object identifiers for uploaded files
  • Authorization Control: Restricts access to channel owners and admins
  • Error Handling: Comprehensive error handling for storage and validation failures

Authorization:

  • Requires authentication
  • Accessible by channel owners or administrators
  • Uses some validator for flexible permission checking

Validation Rules:

  • Path parameter channelId is required
  • Query parameters contentType and contentLength are validated
  • File size limited to 10MB maximum
  • Content type must be valid image MIME type

Error Responses:

  • 400 Bad Request: Invalid query parameters or file constraints
  • 401 Unauthorized: Authentication required
  • 403 Forbidden: Insufficient permissions (not channel owner or admin)
  • 500 Internal Server Error: File storage service failure

Handler Process:

  1. Validates user authentication and channel ownership permissions
  2. Validates file upload parameters (content type, size)
  3. Generates unique object ID with file extension
  4. Creates signed upload URL using file storage driver
  5. Returns object ID and signed URL for client upload

Use Cases:

  • Uploading channel profile images
  • Updating channel avatars
  • Managing channel branding assets
  • Providing secure file upload capabilities

Data Flow:

  • Input: Channel ID, content type, content length
  • Validation: Authentication, authorization, file constraints
  • Processing: UUID generation, file extension extraction, URL signing
  • Output: Object ID and signed upload URL

Performance Notes:

  • URL generation is lightweight and doesn't involve file operations
  • No database writes during URL generation
  • Suitable for high-frequency requests
  • File storage driver handles the actual upload process

💬 Message Features

createChatMessageFeature

Creates a new chat message with validation and routing.

Purpose: Handles message creation with complete validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.createChatMessageFeature, [{ dataStores: db }])));

API Endpoint: POST /api/messages


getChatMessageFeature

Retrieves individual message data with access control.

Purpose: Fetches message details with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.getChatMessageFeature, [{ dataStores: db }])));

API Endpoint: GET /api/messages/:messageId


findChatMessagesFeature

Searches and lists messages with filtering and pagination.

Purpose: Provides message listing with search capabilities

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.findChatMessagesFeature, [{ dataStores: db }])));

API Endpoint: GET /api/messages


updateChatMessageFeature

Updates message content with validation and access control.

Purpose: Modifies message data with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.updateChatMessageFeature, [{ dataStores: db }])));

API Endpoint: PATCH /api/messages/:messageId


deleteChatMessageFeature

Deletes messages with proper authorization.

Purpose: Removes messages with access control

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.deleteChatMessageFeature, [{ dataStores: db }])));

API Endpoint: DELETE /api/messages/:messageId


getChatMessageAttachmentUrlFeature

Chat message attachment upload URL generation feature with schema validation and routing.

Purpose: Provides secure file upload URLs for chat message attachments with malicious file type filtering

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage with file storage driver:
app.use('/api', defService(partial(features.getChatMessageAttachmentUrlFeature, [{ fileStorageDriver }])));

// With database and file storage:
app.use('/api', defService(partial(features.getChatMessageAttachmentUrlFeature, [{
dataStores: db,
fileStorageDriver
}])));

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

Query Parameters:

  • contentType: string (required) - MIME type of file (validated against safe types)
  • contentLength: integer (required) - File size in bytes (max 10MB)

Response Body:

{
"objectId": "unique-file-id.png",
"url": "https://storage.googleapis.com/bucket/unique-file-id.png?signature=..."
}

Key Features:

  • Security-first approach with dangerous MIME type filtering
  • File size validation (10MB maximum)
  • Message ownership verification
  • Time-limited signed URLs
  • Proper file extension handling based on MIME type

Error Responses:

  • 400 - Invalid content type or file size exceeds limit
  • 401 - Not authenticated
  • 403 - Not authorized to access this message
  • 500 - File storage or server error

Notes:

  • Excludes dangerous file types (executables, scripts, archives)
  • Uses mime-types library for content type validation
  • Requires fileStorageDriver in service configuration
  • Returns signed URL that clients use for direct upload to storage

createChatMessageAttachmentFeature

Chat message attachment creation feature with schema validation and routing.

Purpose: Enables adding file attachments to existing messages with automatic base entity generation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage with database:
app.use('/api', defService(partial(features.createChatMessageAttachmentFeature, [{ dataStores: db }])));

// Full configuration:
app.use('/api', defService(partial(features.createChatMessageAttachmentFeature, [{
dataStores: db,
configuration
}])));

API Endpoint: POST /api/messages/:messageId/attachments

Request Body:

{
"objectId": "550e8400-e29b-41d4-a716-446655440000",
"type": "image/png"
}

Response Body (status 201):

{
"objectId": "550e8400-e29b-41d4-a716-446655440000",
"type": "image/png",
"id": "generated-uuid",
"createdAt": "2023-10-15T10:30:00.000Z",
"updatedAt": "2023-10-15T10:30:00.000Z"
}

Key Features:

  • Automatic base entity field generation (id, createdAt, updatedAt)
  • Message ownership validation (sender-only access)
  • UUID validation for objectId
  • Atomic MongoDB $push operation
  • Returns complete attachment with generated fields
  • Full error handling

Error Responses:

  • 400 - Invalid request body (missing objectId or type, invalid UUID)
  • 401 - Not authenticated
  • 403 - Not authorized (not message owner)
  • 404 - Message not found
  • 500 - Database error

Workflow:

  1. Get upload URL via getChatMessageAttachmentUrlFeature
  2. Upload file to signed URL
  3. Create attachment via createChatMessageAttachmentFeature with returned objectId
  4. Attachment is added to message's attachments array with auto-generated fields

Notes:

  • Requires message to exist before adding attachments
  • Each attachment gets unique ID and timestamps
  • Works in conjunction with getChatMessageAttachmentUrlFeature for complete file upload workflow
  • Message owner can add multiple attachments to same message

deleteChatMessageAttachmentFeature

Chat message attachment deletion feature with schema validation and routing.

Purpose: Enables removing file attachments from messages and deleting them from storage

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage with database and file storage:
app.use('/api', defService(partial(features.deleteChatMessageAttachmentFeature, [{
dataStores: db,
fileStorageDriver
}])));

// Full configuration:
app.use('/api', defService(partial(features.deleteChatMessageAttachmentFeature, [{
dataStores: db,
fileStorageDriver,
configuration
}])));

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

Response: No content (status 204) on success

Key Features:

  • Removes attachment from message's attachments array
  • Deletes physical file from storage
  • Automatic message updatedAt timestamp update
  • Admin or owner authorization (admin can delete any, owner can delete own)
  • Atomic MongoDB $pull operation
  • Full error handling

Error Responses:

  • 401 - Not authenticated
  • 403 - Not authorized (not admin or message owner)
  • 404 - Message not found or attachment not found
  • 500 - Database error or file storage error

Usage Example:

// Client-side deletion:
const response = await fetch(`/api/messages/${messageId}/attachments/${attachmentId}`, {
method: 'DELETE',
headers: {
'Authorization': 'Bearer <token>'
}
});

if (response.status === 204) {
// Attachment deleted successfully
}

Notes:

  • Requires message to exist with matching attachment
  • Deletes both database reference and physical file
  • Admin users can delete any attachment; regular users can only delete attachments from their own messages
  • Works in conjunction with createChatMessageAttachmentFeature for complete attachment lifecycle

streamChatMessagesFeature

Streams chat messages in real-time via WebSocket with schema validation.

Purpose: Enables real-time message streaming to clients with proper validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// With database and WebSocket server configuration
app.use('/api', defService(
partial(features.streamChatMessagesFeature, [{ dataStores: db }]),
webSocketServer
));

WebSocket Endpoint: ws://localhost:3000/api/messages/listen?channelId={channelId}

Client Example:

// Establish WebSocket connection
const ws = new WebSocket(
'ws://localhost:3000/api/messages/listen?channelId=channel123'
);

// Handle incoming messages
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('New message received:', message);
// message contains: id, channelId, senderId, content, createdAt, updatedAt
};

// Handle connection open
ws.onopen = () => {
console.log('Connected to chat stream');
};

// Handle errors
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};

// Handle connection close
ws.onclose = (event) => {
console.log('Disconnected from chat stream');
};

Server Setup:

import { WebSocketServer } from 'ws';
import { chatService } from '@nodeblocks/backend-sdk';

// Create WebSocket server
const wss = new WebSocketServer({ noServer: true });

// Register chat service with WebSocket support
app.use('/api/chat', chatService(
database,
config,
{ webSocketServer: wss }
));

// Upgrade HTTP server for WebSocket
server.on('upgrade', (request, socket, head) => {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request);
});
});

Features:

  • Real-time message streaming using MongoDB change streams
  • Automatic message normalization (removes internal fields)
  • Channel-specific filtering (only messages for specified channel)
  • Schema validation for channelId parameter
  • WebSocket protocol support

Error Responses:

  • 400: Missing or invalid channelId parameter
  • 500: Failed to create change stream or unknown error

Notes:

  • Only new messages (insert operations) are streamed
  • Messages are automatically normalized before transmission
  • Connection stays open until client disconnects
  • Authentication validators pending WebSocket IP format fix

🧩 Message Template Features

createChatMessageTemplateFeature

Creates a new chat message template with validation and routing.

Purpose: Handles creation of reusable message templates

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

app.use('/api', defService(partial(features.createChatMessageTemplateFeature, [{ dataStores: db }])));

API Endpoint: POST /api/message-templates


getChatMessageTemplateFeature

Retrieves a chat message template by ID with access control.

Purpose: Fetches template data securely

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

app.use('/api', defService(partial(features.getChatMessageTemplateFeature, [{ dataStores: db }])));

API Endpoint: GET /api/message-templates/:messageTemplateId


updateChatMessageTemplateFeature

Updates an existing chat message template with partial data support.

Purpose: Modifies existing message templates for content updates with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

app.use('/api', defService(partial(features.updateChatMessageTemplateFeature, [{ dataStores: db }])));

API Endpoint: PATCH /api/message-templates/:messageTemplateId


deleteChatMessageTemplateFeature

Deletes a chat message template with proper authorization.

Purpose: Removes existing message templates from the database with access control and validation.

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

app.use('/api', defService(partial(features.deleteChatMessageTemplateFeature, [{ dataStores: db }])));

API Endpoint: DELETE /api/message-templates/:messageTemplateId

Response (204 No Content):

{}

Key Features:

  • Authorization Control: Restricts access to template owners, organization admins, or system admins
  • Safe Deletion: Validates template existence before deletion
  • Atomic Operations: Uses MongoDB atomic delete operations
  • Error Handling: Comprehensive error handling for validation and database failures

Authorization:

  • Requires authentication
  • Accessible by template owners, organization administrators, or system administrators

Error Responses:

  • 401: Unauthorized - Invalid or missing authentication
  • 403: Forbidden - User lacks permission to delete this template
  • 404: Not Found - Template does not exist
  • 500: Internal Server Error - Database or system error

findChatMessageTemplatesFeature

Chat message templates listing feature with schema validation and routing.

Purpose: Lists chat message templates with filtering, pagination, and data normalization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage:
app.use('/api', defService(findChatMessageTemplatesFeature));

// With database configuration:
app.use('/api', defService(partial(findChatMessageTemplatesFeature, [{ dataStores: db }])));

API Endpoint: GET /api/message-templates

Request Parameters:

  • Query Parameters:
    • page (optional): Page number for pagination (default: 1)
    • limit (optional): Number of templates per page (default: 10)

Response (200 - Success):

{
"data": [
{
"id": "template-123",
"title": "Welcome Message",
"content": "Hello, welcome to our chat!",
"organizationId": "org-456",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"metadata": {
"pagination": {
"hasNext": false,
"hasPrev": false,
"limit": 10,
"page": 1,
"total": 1,
"totalPages": 1
}
}
}

Authorization:

  • Requires authentication
  • Restricted to admin users only (checkIdentityType(['admin']))

Error Responses:

  • 401: Unauthorized - Invalid or missing authentication
  • 403: Forbidden - User is not an admin
  • 404: Not Found - No templates found (returns empty array, not error)
  • 500: Internal Server Error - Database or system error

findChatMessageTemplatesForOrganizationFeature

Chat message templates listing for organization feature with schema validation and routing.

Purpose: Lists chat message templates scoped to a specific organization with filtering, pagination, and data normalization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage:
app.use('/api', defService(findChatMessageTemplatesForOrganizationFeature));

// With database configuration:
app.use('/api', defService(partial(findChatMessageTemplatesForOrganizationFeature, [{ dataStores: db }])));

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

Request Parameters:

  • Path Parameters:
    • organizationId (required): Target organization ID to retrieve templates for
  • Query Parameters:
    • page (optional): Page number for pagination (default: 1)
    • limit (optional): Number of templates per page (default: 10)

Response (200 - Success):

{
"data": [
{
"id": "template-123",
"title": "Welcome Message",
"content": "Hello, welcome to our organization!",
"organizationId": "org-456",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
],
"metadata": {
"pagination": {
"hasNext": false,
"hasPrev": false,
"limit": 10,
"page": 1,
"total": 1,
"totalPages": 1
}
}
}

Authorization:

  • Requires authentication
  • Restricted to organization members with 'owner' or 'admin' roles via hasOrgRole(['owner', 'admin'])

Error Responses:

  • 401: Unauthorized - Invalid or missing authentication token
  • 403: Forbidden - User lacks organization access or insufficient role permissions
  • 404: Not Found - Organization not found or no templates available
  • 500: Internal Server Error - Database or normalization error

Key Features:

  • Organization Scoping: Templates are filtered by organization membership
  • Role-Based Access: Only organization owners and admins can access
  • Pagination Support: Full pagination with metadata for large template sets
  • Data Normalization: Automatic document normalization for API responses

🔔 Subscription Features

createChatSubscriptionFeature

Creates a new chat subscription with validation and routing.

Purpose: Handles subscription creation with complete validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.createChatSubscriptionFeature, [{ dataStores: db }])));

API Endpoint: POST /api/subscriptions


getChatSubscriptionFeature

Retrieves individual subscription data with access control.

Purpose: Fetches subscription details with proper authorization

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.getChatSubscriptionFeature, [{ dataStores: db }])));

API Endpoint: GET /api/subscriptions/:subscriptionId


findChatSubscriptionsFeature

Searches and lists subscriptions with filtering and pagination.

Purpose: Provides subscription listing with search capabilities

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.findChatSubscriptionsFeature, [{ dataStores: db }])));

API Endpoint: GET /api/subscriptions


deleteChatSubscriptionFeature

Deletes subscriptions with proper authorization.

Purpose: Removes subscriptions with access control

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';


// With database configuration
app.use('/api', defService(partial(features.deleteChatSubscriptionFeature, [{ dataStores: db }])));

API Endpoint: DELETE /api/subscriptions/:subscriptionId


upsertChatChannelReadStateFeature

Chat channel read state upsert feature with schema validation and routing.

Purpose: Handles upserting channel read states with complete validation

Composition:

Usage:

import { features } from '@nodeblocks/backend-sdk';

// Direct usage:
app.use('/api', defService(upsertChatChannelReadStateFeature));

// With database (handlers need dataStores):
app.use('/api', defService(partial(upsertChatChannelReadStateFeature, [{ dataStores: db }])));

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

Request Body:

{
identityId: string; // required - user identity ID
lastReadMessageId: string; // required - last read message ID
}

Response (204 No Content): Empty response body on successful upsert

Features:

  • Automatic upsert logic (create or update based on existence)
  • Validates channel existence and user subscription
  • Validates last read message existence
  • Ensures user can only update their own read state
  • Automatic timestamp management
  • Proper error handling for missing resources

Error Responses:

  • 401: User is not authenticated
  • 403: User is not subscribed to channel or trying to update another user's read state
  • 404: Channel or last read message not found
  • 500: Database operation failed