Skip to content

Migrate ccs-chat-client 2.x to 3.0.0

Upgrade your backend from ccs-chat-client 2.x to 3.0.0. Version 3.0.0 follows the conventions of the Identity Server client: request and response objects use the Chat API’s own snake_case field names, and the granular scopes are the ones the Identity Server defines on the Chat API.

  • A backend on ccs-chat-client 2.x. See the changelog for the release.
  • Access to your backend client in the Identity Server admin UI, to grant the new scope names.

Constructor options are unchanged and stay camelCase (issuerUrl, clientId, chatApiUrl, tenantId, applicationId).

2.x 3.0.0
conversations.create({ type, memberUserIds, actorUserId }) conversations.create({ type, member_user_ids, actor_user_id })
conversations.addMember(id, { userId, displayName, email }) conversations.addMember(id, { user_id, display_name, email })
messages.send(id, { body, actorUserId, messageType, replyToMessageId, mentionedUserIds, attachments: [{ fileId, mimeType, … }] }) messages.send(id, { body, actor_user_id, message_type, reply_to_message_id, mentioned_user_ids, attachments: [{ file_id, mime_type, … }] })
Conversation (id, memberCount, …) ChatConversation (conversation_id, member_count, …), the API response unchanged
ChatMessage (id, senderUserId, …) ChatMessage (message_id, sender_user_id, …)
Member, UserRef ChatMember, ChatUserRef. users.lookup returns ChatUserProfile[].
Page { items, nextCursor } Page { items, next_cursor }
Scopes chat:conversation:create, chat:conversation:read chat:conversations.manage, chat:conversations.read, plus chat:groups.manage, chat:channels.manage, chat:messages.send, chat:users.lookup
scope?: string scope?: ChatMachineScope | ChatMachineScope[] | string
Not available conversations.archive(id) and conversations.reactivate(id). A backend client may change the status of a DIRECT conversation.
Not available ChatRateLimitedError (429) with retryAfterSeconds
  1. Upgrade the package. Install @central-code-station/ccs-chat-client 3.0.0 or later.

  2. Grant the new scope names. In the Identity Server admin UI, open your backend client’s Resource Permissions for the Chat API and grant chat:sync, or the granular scopes you need. See Grant Chat scopes. If you set scope in the constructor, change it to the new names.

  3. Rename request fields. The compiler lists every place. For example:

    // 2.x
    await chat.conversations.create({ type: 'DIRECT', memberUserIds: [a, b], actorUserId: a });
    // 3.0.0
    await chat.conversations.create({ type: 'DIRECT', member_user_ids: [a, b], actor_user_id: a });
  4. Rename the fields you read. conversation.id becomes conversation.conversation_id, message.id becomes message.message_id, page.nextCursor becomes page.next_cursor, and so on. Rename any of your own types that import Conversation, Member or UserRef.

  5. Use the new methods. Replace a hand-written update(id, { status: 'ARCHIVED' }) with archive(id), and handle ChatRateLimitedError for 429.

To find leftovers, search your code for the 2.x names: memberUserIds, actorUserId, userId, displayName, messageType, replyToMessageId, mentionedUserIds, fileId, mimeType and nextCursor.

The same calls on 3.0.0:

after-migration.ts
import { chat } from './guide-chat-client';
export async function afterMigration(): Promise<void> {
const conversation = await chat.conversations.create({
type: 'GROUP',
name: 'Morning squad',
member_user_ids: ['coach-ana', 'client-john'],
actor_user_id: 'coach-ana',
});
await chat.conversations.addMember(conversation.conversation_id, { user_id: 'client-sarah', display_name: 'Sarah Client' });
const message = await chat.messages.send(conversation.conversation_id, {
body: 'Welcome!',
actor_user_id: 'coach-ana',
message_type: 'TEXT',
mentioned_user_ids: ['client-john'],
});
console.log(message.message_id, message.sender_user_id);
const page = await chat.messages.list(conversation.conversation_id, { limit: 50 });
console.log(page.items.length, page.next_cursor); // was nextCursor
}

The project compiles with no errors. Then create a conversation and send a message in a test tenant. Both calls succeed, and conversation_id and message_id are present on the results. A token request with the new scope names returns a token whose scope lists them.

Symptom Cause and fix
TypeScript: “Object literal may only specify known properties” A camelCase field is left. Rename it.
400 invalid_request Your code sent a camelCase field the API does not accept. Check the request body.
undefined where you read .id or .nextCursor The response fields are snake_case now.
Token request fails with invalid_scope The client is not granted the new scope names. Grant them, or reduce scope.
403 insufficient_scope The scopes in your token do not carry the permission the call needs.