@agentunion/fastaun-browser 0.5.4 → 0.5.6

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.
Files changed (151) hide show
  1. package/CHANGELOG.md +130 -94
  2. package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/216/245/345/205/245/344/270/216/346/274/224/347/244/272/346/214/207/345/215/227.md +290 -0
  3. package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/234/215/345/212/241/346/236/266/346/236/204/344/270/216/350/257/246/347/273/206/345/256/236/347/216/260/350/256/241/345/210/222-codex.md +994 -0
  4. package/_packed_docs/AUN/347/246/273/347/272/277/346/216/250/351/200/201/346/234/215/345/212/241/350/277/220/347/273/264/344/270/216/345/217/221/345/270/203/346/214/207/345/215/227.md +144 -0
  5. package/_packed_docs/CHANGELOG.md +130 -94
  6. package/_packed_docs/INDEX.md +127 -69
  7. package/_packed_docs/KITE_DOCS_GUIDE.md +63 -29
  8. package/_packed_docs/audit/AUN/346/234/215/345/212/241Go/345/214/226/351/207/215/346/236/204/347/262/276/347/273/206/345/214/226/346/272/220/347/240/201/345/256/241/346/237/245-20260718.md +366 -0
  9. package/_packed_docs/aun/345/205/254/347/275/221/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +227 -0
  10. package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +1004 -0
  11. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +999 -0
  12. package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +6 -4
  13. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +58 -20
  14. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +219 -247
  15. package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +14 -14
  16. package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +3 -3
  17. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +165 -421
  18. package/_packed_docs/protocol/README.md +1 -0
  19. package/_packed_docs/protocol/aun-docs-guide.md +7 -4
  20. package/_packed_docs/protocol/index.md +25 -19
  21. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +62 -17
  22. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +22 -0
  23. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -78
  24. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +6 -2
  25. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +50 -14
  26. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +18 -5
  27. package/_packed_docs/sdk/09-group-rpc-manual.md +312 -282
  28. package/_packed_docs/sdk/09-message-rpc-manual.md +142 -103
  29. package/_packed_docs/sdk/09-payload-reference.md +1 -1
  30. package/_packed_docs/sdk/09-stream-rpc-manual.md +8 -8
  31. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +26 -17
  32. package/_packed_docs/sdk/INDEX.md +42 -34
  33. package/_packed_docs/sdk/README.md +7 -6
  34. package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +229 -0
  35. package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/346/224/271/351/200/240/346/226/271/346/241/210.md +750 -0
  36. package/dist/agent-md.d.ts +4 -5
  37. package/dist/agent-md.d.ts.map +1 -1
  38. package/dist/agent-md.js +66 -43
  39. package/dist/agent-md.js.map +1 -1
  40. package/dist/aid-store.d.ts +2 -6
  41. package/dist/aid-store.d.ts.map +1 -1
  42. package/dist/aid-store.js +20 -14
  43. package/dist/aid-store.js.map +1 -1
  44. package/dist/auth.d.ts.map +1 -1
  45. package/dist/auth.js +30 -11
  46. package/dist/auth.js.map +1 -1
  47. package/dist/bundle.js +3297 -1023
  48. package/dist/client/delivery.d.ts +75 -8
  49. package/dist/client/delivery.d.ts.map +1 -1
  50. package/dist/client/delivery.js +1419 -245
  51. package/dist/client/delivery.js.map +1 -1
  52. package/dist/client/group-state.d.ts.map +1 -1
  53. package/dist/client/group-state.js +27 -24
  54. package/dist/client/group-state.js.map +1 -1
  55. package/dist/client/lifecycle.d.ts.map +1 -1
  56. package/dist/client/lifecycle.js +48 -4
  57. package/dist/client/lifecycle.js.map +1 -1
  58. package/dist/client/mention-mode.d.ts +7 -0
  59. package/dist/client/mention-mode.d.ts.map +1 -0
  60. package/dist/client/mention-mode.js +184 -0
  61. package/dist/client/mention-mode.js.map +1 -0
  62. package/dist/client/peers.d.ts +1 -1
  63. package/dist/client/peers.d.ts.map +1 -1
  64. package/dist/client/peers.js +26 -3
  65. package/dist/client/peers.js.map +1 -1
  66. package/dist/client/rpc-pipeline.d.ts +22 -1
  67. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  68. package/dist/client/rpc-pipeline.js +309 -74
  69. package/dist/client/rpc-pipeline.js.map +1 -1
  70. package/dist/client/v2-e2ee.d.ts +25 -2
  71. package/dist/client/v2-e2ee.d.ts.map +1 -1
  72. package/dist/client/v2-e2ee.js +606 -97
  73. package/dist/client/v2-e2ee.js.map +1 -1
  74. package/dist/client.d.ts +24 -5
  75. package/dist/client.d.ts.map +1 -1
  76. package/dist/client.js +404 -215
  77. package/dist/client.js.map +1 -1
  78. package/dist/errors.d.ts.map +1 -1
  79. package/dist/errors.js +4 -1
  80. package/dist/errors.js.map +1 -1
  81. package/dist/facades.d.ts +3 -0
  82. package/dist/facades.d.ts.map +1 -1
  83. package/dist/facades.js +91 -53
  84. package/dist/facades.js.map +1 -1
  85. package/dist/group-index.d.ts +6 -1
  86. package/dist/group-index.d.ts.map +1 -1
  87. package/dist/group-index.js +44 -25
  88. package/dist/group-index.js.map +1 -1
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +1 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/keystore/index.d.ts +10 -5
  94. package/dist/keystore/index.d.ts.map +1 -1
  95. package/dist/keystore/indexeddb-identity-store.d.ts +0 -12
  96. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  97. package/dist/keystore/indexeddb-identity-store.js +0 -60
  98. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  99. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  100. package/dist/keystore/indexeddb-shared.js +9 -5
  101. package/dist/keystore/indexeddb-shared.js.map +1 -1
  102. package/dist/keystore/indexeddb-token-store.d.ts +3 -1
  103. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  104. package/dist/keystore/indexeddb-token-store.js +47 -2
  105. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  106. package/dist/register-flow.d.ts.map +1 -1
  107. package/dist/register-flow.js +28 -3
  108. package/dist/register-flow.js.map +1 -1
  109. package/dist/seq-tracker.d.ts +28 -8
  110. package/dist/seq-tracker.d.ts.map +1 -1
  111. package/dist/seq-tracker.js +218 -61
  112. package/dist/seq-tracker.js.map +1 -1
  113. package/dist/storage/vfs.d.ts +1 -0
  114. package/dist/storage/vfs.d.ts.map +1 -1
  115. package/dist/storage/vfs.js +26 -2
  116. package/dist/storage/vfs.js.map +1 -1
  117. package/dist/tools/cross-sdk-agent.js +376 -10
  118. package/dist/tools/cross-sdk-agent.js.map +1 -1
  119. package/dist/transport.d.ts +12 -0
  120. package/dist/transport.d.ts.map +1 -1
  121. package/dist/transport.js +218 -101
  122. package/dist/transport.js.map +1 -1
  123. package/dist/v2/session/session.d.ts.map +1 -1
  124. package/dist/v2/session/session.js +3 -4
  125. package/dist/v2/session/session.js.map +1 -1
  126. package/dist/v2/state/commitment.d.ts.map +1 -1
  127. package/dist/v2/state/commitment.js +1 -2
  128. package/dist/v2/state/commitment.js.map +1 -1
  129. package/dist/version.d.ts +1 -1
  130. package/dist/version.js +1 -1
  131. package/package.json +6 -5
  132. package/dist/group-resources.d.ts +0 -98
  133. package/dist/group-resources.d.ts.map +0 -1
  134. package/dist/group-resources.js +0 -635
  135. package/dist/group-resources.js.map +0 -1
  136. package/dist/keystore/indexeddb.d.ts +0 -179
  137. package/dist/keystore/indexeddb.d.ts.map +0 -1
  138. package/dist/keystore/indexeddb.js +0 -2031
  139. package/dist/keystore/indexeddb.js.map +0 -1
  140. package/dist/namespaces/auth.d.ts +0 -98
  141. package/dist/namespaces/auth.d.ts.map +0 -1
  142. package/dist/namespaces/auth.js +0 -992
  143. package/dist/namespaces/auth.js.map +0 -1
  144. package/dist/namespaces/custody.d.ts +0 -51
  145. package/dist/namespaces/custody.d.ts.map +0 -1
  146. package/dist/namespaces/custody.js +0 -302
  147. package/dist/namespaces/custody.js.map +0 -1
  148. package/dist/namespaces/meta.d.ts +0 -109
  149. package/dist/namespaces/meta.d.ts.map +0 -1
  150. package/dist/namespaces/meta.js +0 -549
  151. package/dist/namespaces/meta.js.map +0 -1
@@ -5,7 +5,7 @@ import * as https from 'node:https';
5
5
  import * as crypto from 'node:crypto';
6
6
  import * as fs from 'node:fs';
7
7
  import { URL } from 'node:url';
8
- import { AIDStore, AUNClient } from '../index.js';
8
+ import { AID, AIDStore, AUNClient, __version__ } from '../index.js';
9
9
  import { publicKeyFingerprint } from '../cert-utils.js';
10
10
  function installNodeBrowserShims() {
11
11
  const root = globalThis;
@@ -122,7 +122,7 @@ function envelopeMetadata(data) {
122
122
  }
123
123
  class CrossSdkJsAgent {
124
124
  language = 'js';
125
- sdkVersion = 'unknown';
125
+ sdkVersion = __version__;
126
126
  aid = textOf(process.env.AUN_TEST_AID || `cross-js-${crypto.randomUUID().slice(0, 8)}.agentid.pub`).trim();
127
127
  issuer = textOf(process.env.AUN_TEST_ISSUER || 'agentid.pub').trim() || 'agentid.pub';
128
128
  slotId = textOf(process.env.AUN_TEST_SLOT_ID || `cross-sdk-js-${crypto.randomUUID().slice(0, 8)}`).trim();
@@ -133,15 +133,36 @@ class CrossSdkJsAgent {
133
133
  startupError = '';
134
134
  inbox = [];
135
135
  groupInbox = [];
136
+ rawPushObservations = [];
137
+ rawPushObservationId = '';
138
+ rawPushRpcMethods = [];
139
+ rpcObservedTransports = new WeakSet();
140
+ groupChangedEvents = [];
136
141
  traces = new Map();
137
142
  sendResults = new Map();
143
+ inlineRealtimePayloadV1 = true;
138
144
  constructor() {
139
- this.client = new AUNClient();
140
- const internal = this.client;
145
+ this.client = this.newClient();
146
+ }
147
+ async start() {
148
+ this.bindClientEvents();
149
+ await this.ensureConnected(false);
150
+ this.ready = true;
151
+ }
152
+ newClient() {
153
+ const client = new AUNClient();
154
+ const internal = client;
141
155
  if (internal._configModel)
142
156
  internal._configModel.requireForwardSecrecy = false;
157
+ return client;
143
158
  }
144
- async start() {
159
+ bindClientEvents() {
160
+ this.installTransportRpcObserver();
161
+ this.client.on('_raw.message.received', (data) => this.storeRawPushObservation('_raw.message.received', 'p2p', 'legacy', data));
162
+ this.client.on('_raw.peer.v2.message_received', (data) => this.storeRawPushObservation('_raw.peer.v2.message_received', 'p2p', 'v2', data));
163
+ this.client.on('_raw.group.message_created', (data) => this.storeRawPushObservation('_raw.group.message_created', 'group', 'legacy', data));
164
+ this.client.on('_raw.group.v2.message_created', (data) => this.storeRawPushObservation('_raw.group.v2.message_created', 'group', 'v2', data));
165
+ this.client.on('_raw.group.changed', (data) => this.storeRawGroupChangedObservation(data));
145
166
  this.client.on('message.received', (msg) => {
146
167
  void this.storeInboxItem(this.normalizeMessage(msg, true));
147
168
  });
@@ -154,8 +175,103 @@ class CrossSdkJsAgent {
154
175
  this.client.on('group.message_undecryptable', (msg) => {
155
176
  void this.storeGroupInboxItem(this.normalizeGroupMessage(msg, false, 'undecryptable'));
156
177
  });
157
- await this.ensureConnected();
158
- this.ready = true;
178
+ this.client.on('group.changed', (data) => this.storeGroupChangedPublicEvent(data));
179
+ }
180
+ installTransportRpcObserver() {
181
+ const transport = this.client._transport;
182
+ transport?.setTraceMode('diag');
183
+ if (!transport?.call || this.rpcObservedTransports.has(transport))
184
+ return;
185
+ const originalCall = transport.call;
186
+ this.rpcObservedTransports.add(transport);
187
+ transport.call = async (method, params, timeout, trace, background) => {
188
+ this.storeRawPushRpcMethod({ type: 'rpc', method, request_window: this.rawPushRequestWindow(params) });
189
+ let requestParams = params;
190
+ if (method === 'auth.connect' && !this.inlineRealtimePayloadV1 && jsonObjectOf(params)) {
191
+ const request = { ...jsonObjectOf(params) };
192
+ const capabilities = jsonObjectOf(request.capabilities);
193
+ if (capabilities) {
194
+ delete capabilities.inline_realtime_payload_v1;
195
+ request.capabilities = capabilities;
196
+ }
197
+ requestParams = request;
198
+ }
199
+ return await originalCall.call(transport, method, requestParams, timeout, trace, background);
200
+ };
201
+ }
202
+ storeRawPushObservation(rawEvent, scope, defaultKind, value) {
203
+ const data = jsonObjectOf(value) ?? {};
204
+ const hasInline = Object.prototype.hasOwnProperty.call(data, 'inline_message');
205
+ const inlineMessage = jsonObjectOf(data.inline_message);
206
+ this.rawPushObservations.push({
207
+ observation_id: this.rawPushObservationId,
208
+ time: Date.now(), raw_event: rawEvent, scope, group_id: textOf(data.group_id),
209
+ kind: textOf(data.kind || defaultKind),
210
+ action: textOf(data.action),
211
+ event_seq: Number(data.event_seq ?? 0) || 0,
212
+ seq: Number(data.seq ?? data.message_seq ?? data.msg_seq ?? 0) || 0,
213
+ message_id: textOf(data.message_id ?? data.id ?? ''),
214
+ has_inline: hasInline,
215
+ inline_version: textOf(data.inline_version ?? inlineMessage?.version ?? ''),
216
+ inline_is_object: inlineMessage !== null,
217
+ target_device_present: Boolean(textOf(data.target_device_id)),
218
+ target_slot_present: Boolean(textOf(data.target_slot_id)),
219
+ target_device_id: textOf(data.target_device_id),
220
+ target_slot_id: textOf(data.target_slot_id),
221
+ inline_candidate_keys: Object.keys(data).filter((key) => key.startsWith('inline_') || key.startsWith('_inline_message_candidates_') || key === '_group_inline_plain_source_v1' || key === '_group_inline_v2_source_v1').sort(),
222
+ top_level_sensitive_keys: Object.keys(data).filter((key) => [
223
+ 'inline_message', 'payload', 'message', 'envelope_json', 'ciphertext',
224
+ '_inline_message_candidates_v1', '_group_inline_plain_source_v1', '_group_inline_v2_source_v1',
225
+ ].includes(key)).sort(),
226
+ });
227
+ if (this.rawPushObservations.length > 1000)
228
+ this.rawPushObservations = this.rawPushObservations.slice(-1000);
229
+ }
230
+ storeRawGroupChangedObservation(value) {
231
+ this.storeRawPushObservation('_raw.group.changed', 'group', 'changed', value);
232
+ }
233
+ storeGroupChangedPublicEvent(value) {
234
+ const data = jsonObjectOf(value) ?? {};
235
+ this.groupChangedEvents.push({
236
+ observation_id: this.rawPushObservationId,
237
+ time: Date.now(),
238
+ group_id: textOf(data.group_id),
239
+ action: textOf(data.action),
240
+ event_seq: Number(data.event_seq ?? 0) || 0,
241
+ event_id: textOf(data.event_id),
242
+ envelope_present: jsonObjectOf(data.envelope) !== null,
243
+ });
244
+ if (this.groupChangedEvents.length > 1000)
245
+ this.groupChangedEvents = this.groupChangedEvents.slice(-1000);
246
+ }
247
+ storeRawPushRpcMethod(traceInfo) {
248
+ if (traceInfo.type !== 'rpc')
249
+ return;
250
+ if (!this.rawPushObservationId)
251
+ return;
252
+ const method = textOf(traceInfo.method).trim();
253
+ if (!method)
254
+ return;
255
+ const requestWindow = jsonObjectOf(traceInfo.request_window) ?? {};
256
+ this.rawPushRpcMethods.push({
257
+ observation_id: this.rawPushObservationId,
258
+ time: Date.now(),
259
+ method,
260
+ ...this.rawPushRequestWindow(requestWindow),
261
+ });
262
+ if (this.rawPushRpcMethods.length > 1000)
263
+ this.rawPushRpcMethods = this.rawPushRpcMethods.slice(-1000);
264
+ }
265
+ rawPushRequestWindow(value) {
266
+ const params = jsonObjectOf(value) ?? {};
267
+ const afterSeq = params.after_seq;
268
+ const limit = params.limit;
269
+ // 仅返回恢复窗口元数据;不得将 RPC params(其中可能含正文)暴露给测试接口。
270
+ return {
271
+ window_mode: typeof params.window_mode === 'string' ? params.window_mode : '',
272
+ after_seq: typeof afterSeq === 'number' && Number.isInteger(afterSeq) ? afterSeq : null,
273
+ limit: typeof limit === 'number' && Number.isInteger(limit) ? limit : null,
274
+ };
159
275
  }
160
276
  async close() {
161
277
  try {
@@ -173,7 +289,7 @@ class CrossSdkJsAgent {
173
289
  verifySsl: false,
174
290
  });
175
291
  }
176
- async ensureConnected() {
292
+ async ensureConnected(backgroundSync = true) {
177
293
  const store = this.aidStore();
178
294
  try {
179
295
  const registered = await store.register(this.aid);
@@ -187,12 +303,29 @@ class CrossSdkJsAgent {
187
303
  if (!loaded.ok) {
188
304
  throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
189
305
  }
190
- this.client.loadIdentity(loaded.data.aid);
306
+ let identity = loaded.data.aid;
307
+ if (this.debug && !identity.debug) {
308
+ identity = await AID.create({
309
+ aid: identity.aid,
310
+ aunPath: identity.aunPath,
311
+ certPem: identity.certPem,
312
+ privateKeyPem: identity.privateKeyPem,
313
+ certValid: identity.isCertValid(),
314
+ privateKeyValid: identity.isPrivateKeyValid(),
315
+ deviceId: identity.deviceId,
316
+ slotId: identity.slotId,
317
+ verifySsl: identity.verifySsl,
318
+ rootCaPath: identity.rootCaPath,
319
+ debug: true,
320
+ });
321
+ }
322
+ this.client.loadIdentity(identity);
323
+ this.installTransportRpcObserver();
191
324
  }
192
325
  finally {
193
326
  store.close();
194
327
  }
195
- await this.client.connect({ auto_reconnect: false, background_sync: true });
328
+ await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
196
329
  }
197
330
  async identity() {
198
331
  const internal = this.client;
@@ -303,6 +436,46 @@ class CrossSdkJsAgent {
303
436
  sendJson(res, 200, { ok: true });
304
437
  return;
305
438
  }
439
+ if (req.method === 'POST' && url.pathname === '/test/raw-push/reset') {
440
+ const body = await readJson(req);
441
+ this.rawPushObservations = [];
442
+ this.rawPushRpcMethods = [];
443
+ this.groupChangedEvents = [];
444
+ this.rawPushObservationId = textOf(body.observation_id ?? '');
445
+ sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
446
+ return;
447
+ }
448
+ if (req.method === 'GET' && url.pathname === '/test/raw-push') {
449
+ const filters = {};
450
+ for (const key of ['observation_id', 'scope', 'group_id', 'kind', 'raw_event'])
451
+ filters[key] = textOf(url.searchParams.get(key) ?? '');
452
+ const limit = Math.max(1, Math.min(Number(url.searchParams.get('limit') ?? 1000) || 1000, 1000));
453
+ let items = [...this.rawPushObservations];
454
+ for (const [key, value] of Object.entries(filters))
455
+ if (value)
456
+ items = items.filter((item) => textOf(item[key]) === value);
457
+ items = items.slice(-limit);
458
+ const observationId = filters.observation_id;
459
+ let rpcEntries = [...this.rawPushRpcMethods];
460
+ let groupChangedEvents = [...this.groupChangedEvents];
461
+ if (observationId)
462
+ rpcEntries = rpcEntries.filter((item) => textOf(item.observation_id) === observationId);
463
+ if (observationId)
464
+ groupChangedEvents = groupChangedEvents.filter((item) => textOf(item.observation_id) === observationId);
465
+ if (filters.group_id)
466
+ groupChangedEvents = groupChangedEvents.filter((item) => textOf(item.group_id) === filters.group_id);
467
+ rpcEntries = rpcEntries.slice(-limit);
468
+ const rpcMethods = rpcEntries.map((item) => textOf(item.method));
469
+ const rpcMethodCounts = {};
470
+ for (const method of rpcMethods)
471
+ rpcMethodCounts[method] = Number(rpcMethodCounts[method] ?? 0) + 1;
472
+ sendJson(res, 200, {
473
+ ok: true, items, count: items.length, rpc_methods: rpcMethods, rpc_method_counts: rpcMethodCounts,
474
+ rpc_calls: rpcEntries,
475
+ group_changed_events: groupChangedEvents.slice(-limit),
476
+ });
477
+ return;
478
+ }
306
479
  if (req.method === 'GET' && url.pathname === '/identity') {
307
480
  sendJson(res, 200, await this.identity());
308
481
  return;
@@ -319,6 +492,34 @@ class CrossSdkJsAgent {
319
492
  await this.pull(req, res);
320
493
  return;
321
494
  }
495
+ if (req.method === 'GET' && url.pathname === '/sync/state') {
496
+ this.syncState(url, res);
497
+ return;
498
+ }
499
+ if (req.method === 'POST' && url.pathname === '/sync/tail') {
500
+ await this.syncTail(req, res);
501
+ return;
502
+ }
503
+ if (req.method === 'POST' && url.pathname === '/sync/forward') {
504
+ await this.syncForward(req, res);
505
+ return;
506
+ }
507
+ if (req.method === 'POST' && url.pathname === '/sync/history') {
508
+ await this.syncHistory(req, res);
509
+ return;
510
+ }
511
+ if (req.method === 'POST' && url.pathname === '/session/disconnect') {
512
+ await this.sessionDisconnect(res);
513
+ return;
514
+ }
515
+ if (req.method === 'POST' && url.pathname === '/session/connect') {
516
+ await this.sessionConnect(req, res);
517
+ return;
518
+ }
519
+ if (req.method === 'POST' && url.pathname === '/session/restart') {
520
+ await this.sessionRestart(req, res);
521
+ return;
522
+ }
322
523
  if (req.method === 'POST' && url.pathname === '/group/create') {
323
524
  await this.groupCreate(req, res);
324
525
  return;
@@ -1105,6 +1306,171 @@ class CrossSdkJsAgent {
1105
1306
  });
1106
1307
  }
1107
1308
  }
1309
+ syncNamespace(scope, groupId = '') {
1310
+ if (scope === 'p2p')
1311
+ return `p2p:${this.aid}`;
1312
+ if (scope === 'group' && groupId)
1313
+ return `group:${groupId}`;
1314
+ throw new Error('scope must be p2p, or group with group_id');
1315
+ }
1316
+ syncStateValue(scope, groupId = '') {
1317
+ const namespace = this.syncNamespace(scope, groupId);
1318
+ const tracker = this.client._seqTracker;
1319
+ if (!tracker)
1320
+ throw new Error('SeqTracker is unavailable');
1321
+ return { namespace, state: tracker.getSyncState(namespace) };
1322
+ }
1323
+ syncState(url, res) {
1324
+ const scope = textOf(url.searchParams.get('scope') || 'p2p').trim().toLowerCase();
1325
+ const groupId = textOf(url.searchParams.get('group_id') || '').trim();
1326
+ try {
1327
+ const snapshot = this.syncStateValue(scope, groupId);
1328
+ sendJson(res, 200, { ok: true, scope, ...snapshot });
1329
+ }
1330
+ catch (err) {
1331
+ sendJson(res, 400, {
1332
+ ok: false,
1333
+ error_code: err instanceof Error ? err.name : 'Error',
1334
+ error_message: err instanceof Error ? err.message : String(err),
1335
+ });
1336
+ }
1337
+ }
1338
+ async syncTail(req, res) {
1339
+ await this.syncPull(req, res, true);
1340
+ }
1341
+ async syncForward(req, res) {
1342
+ await this.syncPull(req, res, false);
1343
+ }
1344
+ async syncPull(req, res, tail) {
1345
+ const body = await readJson(req);
1346
+ const scope = textOf(body.scope || 'p2p').trim().toLowerCase();
1347
+ const groupId = textOf(body.group_id || '').trim();
1348
+ const afterSeq = Number(body.after_seq ?? 0) || 0;
1349
+ const limit = Number(body.limit ?? 50) || 50;
1350
+ try {
1351
+ const params = { after_seq: afterSeq, limit };
1352
+ if (tail)
1353
+ params.window_mode = 'tail';
1354
+ const method = scope === 'group' ? 'group.pull' : 'message.pull';
1355
+ if (scope === 'group')
1356
+ params.group_id = groupId;
1357
+ this.syncNamespace(scope, groupId);
1358
+ let result;
1359
+ if (tail) {
1360
+ result = await this.client.call(method, params);
1361
+ }
1362
+ else {
1363
+ const transport = this.client._transport;
1364
+ if (!transport?.call)
1365
+ throw new Error('raw transport is unavailable');
1366
+ const wireMethod = scope === 'group' ? 'group.v2.pull' : 'message.v2.pull';
1367
+ result = await transport.call(wireMethod, params);
1368
+ }
1369
+ const resultObj = jsonObjectOf(result) ?? {};
1370
+ const messages = Array.isArray(resultObj.messages) ? resultObj.messages : [];
1371
+ if (tail) {
1372
+ for (const msg of messages) {
1373
+ if (scope === 'group')
1374
+ await this.storeGroupInboxItem(this.normalizeGroupMessage(msg, true));
1375
+ else
1376
+ await this.storeInboxItem(this.normalizeMessage(msg, true));
1377
+ }
1378
+ }
1379
+ const snapshot = this.syncStateValue(scope, groupId);
1380
+ sendJson(res, 200, { ok: true, scope, ...snapshot, result: jsonSafe(result) });
1381
+ }
1382
+ catch (err) {
1383
+ sendJson(res, 500, {
1384
+ ok: false,
1385
+ scope,
1386
+ error_code: err instanceof Error ? err.name : 'Error',
1387
+ error_message: err instanceof Error ? err.message : String(err),
1388
+ });
1389
+ }
1390
+ }
1391
+ async syncHistory(req, res) {
1392
+ const body = await readJson(req);
1393
+ const scope = textOf(body.scope || 'p2p').trim().toLowerCase();
1394
+ const groupId = textOf(body.group_id || '').trim();
1395
+ const beforeSeq = Number(body.before_seq ?? 0) || 0;
1396
+ const limit = Number(body.limit ?? 50) || 50;
1397
+ try {
1398
+ const params = { before_seq: beforeSeq, limit };
1399
+ const method = scope === 'group' ? 'group.history' : 'message.history';
1400
+ if (scope === 'group')
1401
+ params.group_id = groupId;
1402
+ this.syncNamespace(scope, groupId);
1403
+ const result = await this.client.call(method, params);
1404
+ const snapshot = this.syncStateValue(scope, groupId);
1405
+ sendJson(res, 200, { ok: true, scope, ...snapshot, result: jsonSafe(result) });
1406
+ }
1407
+ catch (err) {
1408
+ sendJson(res, 500, {
1409
+ ok: false,
1410
+ scope,
1411
+ error_code: err instanceof Error ? err.name : 'Error',
1412
+ error_message: err instanceof Error ? err.message : String(err),
1413
+ });
1414
+ }
1415
+ }
1416
+ async sessionDisconnect(res) {
1417
+ try {
1418
+ this.ready = false;
1419
+ await this.client.disconnect();
1420
+ sendJson(res, 200, { ok: true, state: textOf(this.client.state) });
1421
+ }
1422
+ catch (err) {
1423
+ sendJson(res, 500, {
1424
+ ok: false,
1425
+ error_code: err instanceof Error ? err.name : 'Error',
1426
+ error_message: err instanceof Error ? err.message : String(err),
1427
+ });
1428
+ }
1429
+ }
1430
+ async sessionConnect(req, res) {
1431
+ const body = await readJson(req);
1432
+ const backgroundSync = body.background_sync === true;
1433
+ if (Object.prototype.hasOwnProperty.call(body, 'inline_realtime_payload_v1')) {
1434
+ this.inlineRealtimePayloadV1 = body.inline_realtime_payload_v1 !== false;
1435
+ }
1436
+ try {
1437
+ await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
1438
+ this.ready = true;
1439
+ sendJson(res, 200, { ok: true, background_sync: backgroundSync, inline_realtime_payload_v1: this.inlineRealtimePayloadV1 });
1440
+ }
1441
+ catch (err) {
1442
+ sendJson(res, 500, {
1443
+ ok: false,
1444
+ error_code: err instanceof Error ? err.name : 'Error',
1445
+ error_message: err instanceof Error ? err.message : String(err),
1446
+ });
1447
+ }
1448
+ }
1449
+ async sessionRestart(req, res) {
1450
+ const body = await readJson(req);
1451
+ const backgroundSync = body.background_sync === true;
1452
+ if (Object.prototype.hasOwnProperty.call(body, 'inline_realtime_payload_v1')) {
1453
+ this.inlineRealtimePayloadV1 = body.inline_realtime_payload_v1 !== false;
1454
+ }
1455
+ this.ready = false;
1456
+ try {
1457
+ await this.client.close();
1458
+ this.client = this.newClient();
1459
+ this.bindClientEvents();
1460
+ await this.ensureConnected(backgroundSync);
1461
+ this.startupError = '';
1462
+ this.ready = true;
1463
+ sendJson(res, 200, { ok: true, background_sync: backgroundSync, inline_realtime_payload_v1: this.inlineRealtimePayloadV1 });
1464
+ }
1465
+ catch (err) {
1466
+ this.startupError = `${err instanceof Error ? err.name : 'Error'}: ${err instanceof Error ? err.message : String(err)}`;
1467
+ sendJson(res, 500, {
1468
+ ok: false,
1469
+ error_code: err instanceof Error ? err.name : 'Error',
1470
+ error_message: err instanceof Error ? err.message : String(err),
1471
+ });
1472
+ }
1473
+ }
1108
1474
  async groupCreate(req, res) {
1109
1475
  const body = await readJson(req);
1110
1476
  const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));