JS SDK — Node (@loopchat/node)
The server-side SDK for customer backends. It authenticates with the app's api_secret, which must never ship in client apps.
- Repo:
js-sdk/packages/node. Node ≥ 22.12 (usesnode:crypto). - Dependencies:
@loopchat/core(workspace) — for the error class and protocol types only. - Build: tsup → ESM + CJS +
.d.ts.
import { LoopChatServerClient } from '@loopchat/node';
const server = new LoopChatServerClient(apiKey, apiSecret, { baseUrl: 'https://chat.example.com' });
const token = server.createToken('user-42'); // HS256 user JWT for connectUser
await server.upsertUser({ id: 'user-42', name: 'Ada' });
await server.addMembers('messaging', 'pool-abc', ['user-42'], {
create_if_missing: { created_by_id: 'user-42' }, // ensureMembership in one call
});
LoopChatServerClient
new LoopChatServerClient(apiKey: string, apiSecret: string, opts?: LoopChatServerClientOptions)
LoopChatServerClientOptions: baseUrl? (default http://localhost:8080), fetchImpl? (injectable for tests).
All requests are server-authenticated with the x-api-key + x-api-secret headers (see API Reference). Non-2xx responses throw LoopChatNetworkError (re-exported from core).
Tokens
| Method | Description |
|---|---|
createToken(userId, { expiresInSec? }) |
Mints the HS256 user JWT ({ user_id, iat[, exp] }) signed with the app's api_secret — what clients pass to client.connectUser. Omit expiresInSec for a non-expiring token. Local operation, no network call. |
Users
| Method | Endpoint | Description |
|---|---|---|
upsertUser(user): Promise<UserObject> |
POST /users |
Create or update a chat user ({ id, name?, image?, role?, custom? }). |
deleteUser(id): Promise<void> |
DELETE /users/:id |
Hard-delete a user (also removes memberships, read state, devices server-side). |
Channels
| Method | Endpoint | Description |
|---|---|---|
createChannel(type, input) |
POST /channels/:type |
Idempotent create ({ id, name?, members?, created_by_id, custom? }); returns { channel, members }. The creator is always added as a member with role owner. |
deleteChannel(type, id, { hard? }) |
DELETE /channels/:type/:id[?hard=true] |
Soft delete freezes the channel; hard: true removes it and its data. |
addMembers(type, id, members, { create_if_missing? }) |
POST /channels/:type/:id/members |
Idempotent — existing members are silently kept. With create_if_missing: { created_by_id, name?, custom? } the channel is created when absent, collapsing the ensureMembership self-heal pattern into one call. |
removeMembers(type, id, userIds) |
DELETE /channels/:type/:id/members/:userId (per user) |
Removes each user from the channel. |