@cg-devcenter/rtc-fpnn-webjs-sdk 1.0.0-cg.2 → 1.0.0-cg.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,61 +1,102 @@
1
1
  # @cg-devcenter/rtc-fpnn-webjs-sdk
2
2
 
3
- RTC WebSocket Client SDK。新接入使用 `tlv-v1`;`fpnn` 仅保留浏览器兼容能力。
3
+ RTC WebSocket Client SDK。新接入建议使用 `protocol: 'tlv-v1'`;`fpnn` 用于兼容已有浏览器接入。完整接入说明和 API 参数见 [USAGE.md](docs/USAGE.md)。
4
4
 
5
- ## 模块导出
5
+ ## 安装
6
6
 
7
- - `RTMClient`
8
- - `RTMConfig`
9
- - `RTMProcessor`
10
- - `TLVCodec`
11
- - `TLVWebSocketClient`
7
+ ```bash
8
+ npm install @cg-devcenter/rtc-fpnn-webjs-sdk@1.0.0-cg.3
9
+ ```
12
10
 
13
- ## 客户端构造
11
+ 本文档中的 Promise API、`RTMSharedWorkerClient` 和 Vite 入口从 `1.0.0-cg.3` 起提供;此前发布的 `1.0.0-cg.2` 不包含这些能力。若 `.3` 尚未发布到 npm,可让测试项目安装本地 tarball:`npm install ./cg-devcenter-rtc-fpnn-webjs-sdk-1.0.0-cg.3.tgz`。
14
12
 
15
- `new rtm.RTMClient(options)`
13
+ 浏览器可加载 `dist/rtm.min.js` 并从 `window.rtm` 使用;CommonJS:
16
14
 
17
- | 参数 | 类型 | TLV v1 规则 |
18
- | --- | --- | --- |
19
- | `pid` | `number` | 必填。 |
20
- | `protocol` | `'tlv-v1' \| 'fpnn'` | 新接入为 `'tlv-v1'`。 |
21
- | `tlvEndpoint` | `string` | 必填完整 WebSocket URL。 |
22
- | `autoReconnect` | `boolean` | 缺省为 `true`。 |
23
- | `connectionTimeout` | `number` | 毫秒。 |
24
- | `requestMetadata` | `() => Record<string, unknown>` | 可返回 `trace`、`sent_ms`。 |
25
- | `webSocketFactory` | `(url) => RTMWebSocket` | 无全局 `WebSocket` 时必填。 |
26
- | `locale` | `string` | 映射为 `auth.login.locale`。 |
27
- | `clientVersion` | `string` | 映射为 `auth.login.client_ver`。 |
15
+ ```js
16
+ const rtm = require('@cg-devcenter/rtc-fpnn-webjs-sdk');
17
+ ```
28
18
 
29
- `fpnn` 仅支持浏览器。TLV credential 由业务服务端签发,项目密钥不属于客户端参数。
19
+ Node.js 使用 TLV v1 时,需自行提供 `webSocketFactory(url)`。SDK 不携带 Node WebSocket 实现。`fpnn` 和 `RTMSharedWorkerClient` 仅适用于浏览器。
30
20
 
31
- ## 生命周期 API
21
+ ## Quick Start
32
22
 
33
- | API | 回调/结果 |
34
- | --- | --- |
35
- | `login(uid, credential, callback, timeout)` | `callback(accepted, errorCode)` |
36
- | `bye()` | 发送 `connection.close`。 |
37
- | `close()` | 主动关闭。 |
38
- | `startAutoReconnect()` | 关闭当前连接后重新登录。 |
39
- | `destroy()` | 释放客户端资源。 |
40
- | `getServerTime(timeout, callback)` | `callback(err, data)` |
23
+ ### 默认共享入口(当前源码)
41
24
 
42
- `uid`、消息 ID、群 ID、房间 ID 和时间游标超出安全整数范围时使用 `RTMConfig.Int64`。
25
+ `createClient()` 默认共享连接,默认协议为 TLV。Worker 名称由 SDK 按 **PID + 协议 + UID** 自动生成,UID 可直接从 `login()` 获取,业务无需维护 `workerName`。已发布 `.3` 不包含这个入口;请先使用本地构建或后续版本。
43
26
 
44
- ## Push API
27
+ ```js
28
+ const client = rtm.createClient({ pid, tlvEndpoint: endpoint });
29
+ client.processor.on(rtm.RTMConfig.TLV_SERVER_PUSH.recvMessage, renderMessage);
30
+ await client.promises.login(uid, credential); // 同 UID 已登录时 credential 可省略
31
+ await client.promises.sendChat(peerUid, 'hello', '{}');
32
+ // 离开页面只释放本页,其他页面继续收发。
33
+ client.destroy();
34
+ ```
45
35
 
46
- 通过 `client.processor.on(name, callback)` 注册:
36
+ 片段中的 `rtm`、项目参数、credential 和 `renderMessage` 由应用提供;完整流程和能力边界见 [默认共享接入](docs/USAGE.md#默认共享接入当前源码)。设置 `sharing: false` 创建独立连接;旧 `new RTMClient()` 的默认行为保持不变。Vite 项目从包的 `/vite` 入口导入,SDK 自动打包 Worker。
47
37
 
48
- - `RTMConfig.TLV_SERVER_PUSH.recvMessage`:`event.direct`
49
- - `RTMConfig.TLV_SERVER_PUSH.recvGroupMessage`:`event.group`
50
- - `RTMConfig.TLV_SERVER_PUSH.recvRoomMessage`:`event.room`
51
- - `RTMConfig.TLV_SERVER_PUSH.recvBroadcastMessage`:`event.broadcast`
52
- - `RTMConfig.TLV_SERVER_PUSH.kickOut`:`event.kicked`
53
- - `RTMConfig.TLV_SERVER_PUSH.kickOutRoom`:`event.room_removed`
38
+ ### 原有单连接入口
54
39
 
55
- 可靠消息 Push 由 SDK 自动 ACK 并按 `message_ref` 去重。
40
+ 从业务服务端取得当前 UID 的 credential,然后连接 Gate。credential 必须由服务端签发;项目 SecretKey 不要放进浏览器。
56
41
 
57
- ## API 文档
42
+ ```js
43
+ async function startChat(rtm, { pid, endpoint, uid, peerUid, credential }) {
44
+ const client = new rtm.RTMClient({
45
+ protocol: 'tlv-v1',
46
+ pid,
47
+ tlvEndpoint: endpoint,
48
+ });
49
+ let loggedIn = false;
58
50
 
59
- - [公开方法与参数](docs/USAGE.md)
60
- - [TLV v1 wire 契约](docs/TLV_CONTRACT.md)
51
+ client.processor.on(rtm.RTMConfig.TLV_SERVER_PUSH.recvMessage, (event) => {
52
+ console.log('Direct message', event);
53
+ });
54
+
55
+ try {
56
+ await client.promises.login(uid, credential);
57
+ loggedIn = true;
58
+ return await client.promises.sendChat(peerUid, 'hello', '{}');
59
+ } finally {
60
+ try {
61
+ if (loggedIn) await client.promises.bye(5000);
62
+ } finally {
63
+ client.destroy();
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ 此片段假定调用方已加载 SDK,并取得 `pid`、完整 WebSocket endpoint、`uid`、`peerUid` 和服务端签发的 `credential`。带 credential 获取方式、错误处理、关闭流程、参数和返回值的完整示例见 [SDK 接入指南](docs/USAGE.md#2-快速开始登录收-push发消息关闭)。
70
+
71
+ ## 同 UID 多窗口
72
+
73
+ 需要同一浏览器内多个同源页面共用一个 UID 的 RTC 登录和 WebSocket 时,新接入推荐使用 SDK 的 `createClient()` 默认共享入口。SDK 按 PID、协议和 UID 确定共享会话,业务代码无需维护 `workerName`;普通浏览器部署时将 `rtm.min.js` 和 `rtm.shared-worker.js` 放在同一同源目录即可。首次登录需要 credential;同 UID 后续页面复用共享会话。完整说明见 [默认共享接入](docs/USAGE.md#默认共享接入当前源码)。
74
+
75
+ Vite 项目从 `@cg-devcenter/rtc-fpnn-webjs-sdk/vite` 导入 ESM 入口,SDK 会自动打包和配置 Worker 文件。若使用底层 `RTMSharedWorkerClient` 构造器,可通过 `uid` 自动生成 Worker 名称,或显式传入 `workerName`;`createClient()` 会按登录 UID 自动绑定,不要求手动设置名称。最后一个页面 detach 后默认 5 秒关闭共享连接。需要固定在已发布 `.3` 上时仍可直接使用 `RTMSharedWorkerClient`;当前源码新增的 `createClient()` 尚未包含在 `.3` 中。
76
+
77
+ 当前源码的 SharedWorker 也支持显式选择 `clientOptions.protocol: 'fpnn'`,登录共享和会话路由沿用同一套 API。已发布的 `1.0.0-cg.3` 尚不含 FPNN 共享扩展;本地构建或后续版本的用法与限制见 [FPNN 多窗口接入](docs/USAGE.md#fpnn-多窗口接入)。
78
+
79
+ 仓库的演示页面可用以下命令启动:
80
+
81
+ ```bash
82
+ npm run build
83
+ npm run demo:shared-worker
84
+ ```
85
+
86
+ 发送台和收件箱 demo 地址、真实 Gate 配置方式见 [Demo 使用说明](examples/shared-worker-demo/README.md)。
87
+
88
+ 另有使用 Vue 3、Vite 和 npm 包导入方式的同功能示例;本次新入口需先通过 yalc 链接本地构建:[Vue 3 SharedWorker Demo](examples/vue3-shared-worker-demo/README.md)。
89
+
90
+ ## TLV v1 最小接入 Demo
91
+
92
+ 需要在浏览器里手动验证普通 `RTMClient` 接入时,在仓库根目录运行 `npm run build` 后执行 `npm run demo:tlv-basic`,再打开 `http://127.0.0.1:4174`。Demo 使用本机静态服务器;PID、WebSocket endpoint、UID 和服务端签发的 credential 由接入者填写,不会保存到浏览器存储。详见 [Demo 使用说明](examples/tlv-basic-demo/README.md)。
93
+
94
+ ## 文档
95
+
96
+ - [接入指南与 API 参数](docs/USAGE.md)
97
+ - [FPNN 与 TLV v1 迁移对照](docs/PROTOCOL_MIGRATION.md)
98
+ - [能力总览与典型业务流程](docs/CAPABILITIES.md)
99
+ - [TLV v1 URI、请求字段与返回值](docs/TLV_CONTRACT.md)
61
100
  - [TLV v1 传输规则](docs/TLV.md)
101
+ - [在线 Gate 验证](docs/TLV_LIVE_E2E_TEST.md)
102
+ - [TypeScript 声明](dist/rtm.d.ts)
package/dist/rtm.d.ts CHANGED
@@ -2,6 +2,39 @@ export as namespace rtm;
2
2
 
3
3
  declare namespace rtm {
4
4
  type RTMProtocol = 'fpnn' | 'tlv-v1';
5
+ export type RTMId = string | number | { toString(): string };
6
+
7
+ export interface RTMLoginPromiseResult {
8
+ accepted: true;
9
+ errorCode: number;
10
+ }
11
+
12
+ type RTMPromiseExcludedMethod = 'close' | 'destroy' | 'emit' | 'off' | 'on'
13
+ | 'removeEvent' | 'startAutoReconnect' | 'promises' | 'processor';
14
+
15
+ /** Promise versions of callback-based RTM requests. Parameters keep the original order, without callback. */
16
+ export type RTMPromiseApi = {
17
+ [Method in Exclude<keyof RTMClient, RTMPromiseExcludedMethod>]:
18
+ RTMClient[Method] extends (...args: any[]) => any ? (...args: any[]) => Promise<any> : never;
19
+ } & {
20
+ login(uid: RTMId, credential: string, timeout?: number): Promise<RTMLoginPromiseResult>;
21
+ bye(timeout?: number): Promise<any>;
22
+ sendChat(to: RTMId, msg: string | ArrayBuffer | Uint8Array, attrs?: string, mid?: RTMId, timeout?: number): Promise<any>;
23
+ sendGroupChat(gid: RTMId, msg: string | ArrayBuffer | Uint8Array, attrs?: string, mid?: RTMId, timeout?: number): Promise<any>;
24
+ sendRoomChat(rid: RTMId, msg: string | ArrayBuffer | Uint8Array, attrs?: string, mid?: RTMId, timeout?: number): Promise<any>;
25
+ getP2PMessage(ouid: RTMId, desc?: boolean, num?: number, begin?: RTMId, end?: RTMId, lastid?: RTMId, mtypes?: number[], timeout?: number): Promise<any>;
26
+ getGroupMessage(gid: RTMId, desc?: boolean, num?: number, begin?: RTMId, end?: RTMId, lastid?: RTMId, mtypes?: number[], timeout?: number): Promise<any>;
27
+ getRoomMessage(rid: RTMId, desc?: boolean, num?: number, begin?: RTMId, end?: RTMId, lastid?: RTMId, mtypes?: number[], timeout?: number): Promise<any>;
28
+ getSession(timeout?: number): Promise<any>;
29
+ getUnreadMessage(clear?: boolean, withLogout?: boolean, timeout?: number): Promise<any>;
30
+ };
31
+
32
+ export type RTMSharedWorkerPromiseApi = RTMPromiseApi;
33
+
34
+ export type RTMDefaultPromiseApi = Omit<RTMPromiseApi, 'login'> & {
35
+ /** Only the first same-UID page requires a credential. */
36
+ login(uid: RTMId, credential?: string, timeout?: number): Promise<RTMLoginPromiseResult>;
37
+ };
5
38
 
6
39
  interface RTMRegressiveStrategy {
7
40
  startConnectFailedCount: number;
@@ -33,7 +66,7 @@ declare namespace rtm {
33
66
  clientVersion?: string;
34
67
  authSec?: number;
35
68
  authVer?: 2;
36
- requestMetadata?: () => Record<string, unknown>;
69
+ requestMetadata?: Record<string, unknown> | (() => Record<string, unknown>);
37
70
  requestMetadataProvider?: () => Record<string, unknown>;
38
71
  webSocketFactory?: (url: string) => RTMWebSocket;
39
72
  attrs?: Record<string, string>;
@@ -46,6 +79,8 @@ declare namespace rtm {
46
79
 
47
80
  export class RTMClient {
48
81
  constructor(options: RTMClientOptions);
82
+ /** Promise facade for callback-based business request methods. */
83
+ readonly promises: RTMPromiseApi;
49
84
  processor;
50
85
  login(uid, token, callback, timeout);
51
86
  destroy();
@@ -75,7 +110,8 @@ declare namespace rtm {
75
110
  fileToken(cmd, tos, to, rid, gid, timeout, callback);
76
111
  close();
77
112
  startAutoReconnect();
78
- bye();
113
+ bye(callback?: (err?: Error | null, data?: any) => void): void;
114
+ bye(timeout?: number, callback?: (err?: Error | null, data?: any) => void): void;
79
115
  addAttrs(attrs, timeout, callback);
80
116
  getAttrs(timeout, callback);
81
117
  addDebugLog(msg, attrs, timeout, callback);
@@ -157,6 +193,143 @@ declare namespace rtm {
157
193
  removeEvent();
158
194
  }
159
195
 
196
+ export interface RTMSharedWorkerBaseClientOptions {
197
+ pid: number;
198
+ maxPingIntervalSeconds?: number;
199
+ autoReconnect?: boolean;
200
+ connectionTimeout?: number;
201
+ requestTimeout?: number;
202
+ /** Static TLV metadata; only trace and sent_ms are sent on the wire. */
203
+ requestMetadata?: Record<string, unknown>;
204
+ locale?: string;
205
+ clientVersion?: string;
206
+ authSec?: number;
207
+ authVer?: 2;
208
+ attrs?: Record<string, string>;
209
+ tlvHeartbeatIdleMs?: number;
210
+ tlvHeartbeatTimeoutMs?: number;
211
+ pushDedupTtlMs?: number;
212
+ regressiveStrategy?: RTMRegressiveStrategy;
213
+ }
214
+
215
+ /** Defaults to TLV; FPNN must be explicitly selected. Functions cannot cross the Worker boundary. */
216
+ export type RTMSharedWorkerClientOptions = RTMSharedWorkerBaseClientOptions & (
217
+ { protocol?: 'tlv-v1'; tlvEndpoint: string }
218
+ | ({ protocol: 'fpnn' } & (
219
+ { endpoint: string; ssl_endpoint?: string } | { ssl_endpoint: string; endpoint?: string }
220
+ ))
221
+ );
222
+
223
+ export type RTMConversationType = 'direct' | 'group' | 'room';
224
+
225
+ export interface RTMConversation {
226
+ type: RTMConversationType;
227
+ /** Use a decimal string for IDs larger than Number.MAX_SAFE_INTEGER. */
228
+ id: string | number | { toString(): string };
229
+ }
230
+
231
+ export interface RTMSharedWorkerOptions {
232
+ /** Optional same-origin Worker URL. The classic entry defaults beside its script; the Vite entry bundles this resource automatically. */
233
+ workerUrl?: string;
234
+ /** Explicit stable name. When omitted and uid is provided, the SDK derives one from protocol, pid, uid, endpoint, and workerNamespace. */
235
+ workerName?: string;
236
+ /** UID used only to derive workerName when workerName is omitted; it does not log in automatically. */
237
+ uid?: RTMId;
238
+ /** Optional application/environment scope included in the derived workerName. */
239
+ workerNamespace?: string;
240
+ /** Maximum time to wait for the SharedWorker init response; defaults to 10000 ms. */
241
+ readyTimeout?: number;
242
+ /** Close and release the RTC session after the last page detaches; defaults to 5000 ms. Use 0 to close immediately. All tabs sharing a Worker must use the same value. */
243
+ idleShutdownTimeout?: number;
244
+ /** Structured-cloneable RTM options. Supports TLV and FPNN; file uploads remain unsupported. */
245
+ clientOptions: RTMSharedWorkerClientOptions;
246
+ /** Optional route for this page. When omitted, this page receives all conversation Push events. */
247
+ conversation?: RTMConversation | null;
248
+ }
249
+
250
+ /** Flat client options. Browser sharing defaults to true; protocol defaults to TLV in both modes. */
251
+ export type RTMCreateClientOptions = RTMSharedWorkerClientOptions &
252
+ Omit<RTMSharedWorkerOptions, 'clientOptions'> & { sharing?: true };
253
+
254
+ /** Default shared facade. Worker is attached on login, or immediately when options.uid is set. */
255
+ export interface RTMDefaultClient extends Omit<RTMSharedWorkerClient, 'promises' | 'login' | 'whenReady'> {
256
+ readonly promises: RTMDefaultPromiseApi;
257
+ on(type: 'SharedWorkerReady' | 'SharedSessionState', callback: (session: RTMSharedSessionSnapshot) => void): this;
258
+ on(type: string, callback: (...args: any[]) => void): this;
259
+ off(type: string, callback?: (...args: any[]) => void): this;
260
+ removeEvent(type?: string, callback?: (...args: any[]) => void): this;
261
+ setConversation(conversation: RTMConversation | null, callback?: (error?: Error | null) => void): this;
262
+ /** All callback failures use (false, numericCode); local/Worker details are emitted as SharedWorkerError. */
263
+ login(uid: RTMId, credential?: string, callback?: (accepted: boolean, errorCode?: number) => void, timeout?: number): void;
264
+ /** Requires a UID from options.uid, login(), or this argument. Never waits for an unspecified UID. */
265
+ whenReady(uid?: RTMId): Promise<RTMSharedSessionSnapshot>;
266
+ emit(type: string, ...args: any[]): void;
267
+ }
268
+
269
+ export function createClient(options: RTMClientOptions & { sharing: false }): RTMClient;
270
+ export function createClient(options: RTMCreateClientOptions): RTMDefaultClient;
271
+
272
+ export interface RTMSharedSessionSnapshot {
273
+ status: 'idle' | 'connecting' | 'authenticated';
274
+ /** Decimal UID string for the shared session; null while idle. */
275
+ uid: string | null;
276
+ }
277
+
278
+ export interface RTMSharedLoginResult {
279
+ accepted: boolean;
280
+ errorCode: number;
281
+ /** True when this call reused an authenticated session or joined its login attempt. */
282
+ reused: boolean;
283
+ /** Decimal UID of the resulting or conflicting shared session. */
284
+ uid: string | null;
285
+ }
286
+
287
+ interface RTMSharedProcessor {
288
+ on(type: string, callback: (...args: any[]) => void): this;
289
+ off(type: string, callback?: (...args: any[]) => void): this;
290
+ removeEvent(type?: string, callback?: (...args: any[]) => void): this;
291
+ }
292
+
293
+ export class RTMSharedWorkerClient {
294
+ constructor(options: RTMSharedWorkerOptions);
295
+ /** Creates a stable name for the same protocol, project, UID, endpoint, and optional application/environment namespace. */
296
+ static createWorkerName(identity: RTMSharedWorkerIdentity): string;
297
+ /** Promise facade for callback-based business request methods. */
298
+ readonly promises: RTMSharedWorkerPromiseApi;
299
+ processor: RTMSharedProcessor;
300
+ /** Resolves with the session snapshot after this page attaches to the Worker. */
301
+ whenReady(): Promise<RTMSharedSessionSnapshot>;
302
+ /** Returns the latest session snapshot observed by this page. */
303
+ getSharedSession(): RTMSharedSessionSnapshot;
304
+ /** Reuses/joins a same-UID login; credential is required only when the shared session is idle. */
305
+ loginIfNeeded(uid: string | number | { toString(): string }, credential?: string, timeout?: number): Promise<RTMSharedLoginResult>;
306
+ /** Receives the current snapshot on ready and whenever a shared tab's login state changes. */
307
+ on(type: 'SharedWorkerReady' | 'SharedSessionState', callback: (session: RTMSharedSessionSnapshot) => void): this;
308
+ on(type: string, callback: (...args: any[]) => void): this;
309
+ off(type: string, callback?: (...args: any[]) => void): this;
310
+ removeEvent(type?: string, callback?: (...args: any[]) => void): this;
311
+ /** Route matching conversation Push events to this page; pass null to receive all conversations. */
312
+ setConversation(conversation: RTMConversation | null, callback?: (error?: Error | null) => void): this;
313
+ /** Detaches this page; also called automatically on pagehide (except BFCache). It does not close the shared connection. */
314
+ destroy(): void;
315
+ }
316
+
317
+ export interface RTMSharedWorkerIdentity {
318
+ /** Defaults to tlv-v1. FPNN names are isolated from TLV names. */
319
+ protocol?: RTMProtocol;
320
+ pid: string | number;
321
+ uid: RTMId;
322
+ endpoint?: string;
323
+ namespace?: string;
324
+ }
325
+
326
+ export function createSharedWorkerName(identity: RTMSharedWorkerIdentity): string;
327
+
328
+ type RTMSharedWorkerClientMethods = Pick<RTMClient, Exclude<keyof RTMClient,
329
+ 'emit' | 'promises'>>;
330
+
331
+ export interface RTMSharedWorkerClient extends RTMSharedWorkerClientMethods {}
332
+
160
333
  export class RTMConfig {
161
334
  static ERROR_CODE;
162
335
  static Int64;