@agentunion/fastaun 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.
- package/CHANGELOG.md +126 -90
- 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
- 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
- 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
- package/_packed_docs/CHANGELOG.md +126 -90
- package/_packed_docs/INDEX.md +127 -69
- package/_packed_docs/KITE_DOCS_GUIDE.md +63 -29
- 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
- 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
- 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
- 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
- package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +6 -4
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +58 -20
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +219 -247
- package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +14 -14
- package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +3 -3
- 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
- package/_packed_docs/protocol/README.md +1 -0
- package/_packed_docs/protocol/aun-docs-guide.md +7 -4
- package/_packed_docs/protocol/index.md +25 -19
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +62 -17
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +22 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -78
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +6 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +50 -14
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +18 -5
- package/_packed_docs/sdk/09-group-rpc-manual.md +312 -282
- package/_packed_docs/sdk/09-message-rpc-manual.md +142 -103
- package/_packed_docs/sdk/09-payload-reference.md +1 -1
- package/_packed_docs/sdk/09-stream-rpc-manual.md +8 -8
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +26 -17
- package/_packed_docs/sdk/INDEX.md +42 -34
- package/_packed_docs/sdk/README.md +7 -6
- 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
- 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
- package/dist/agent-md.js +8 -2
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +2 -0
- package/dist/aid-store.js +43 -7
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.js +97 -50
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +70 -7
- package/dist/client/delivery.js +1332 -236
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +25 -22
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +46 -3
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/mention-mode.d.ts +6 -0
- package/dist/client/mention-mode.js +184 -0
- package/dist/client/mention-mode.js.map +1 -0
- package/dist/client/peers.d.ts +1 -1
- package/dist/client/peers.js +26 -3
- package/dist/client/peers.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +20 -1
- package/dist/client/rpc-pipeline.js +332 -73
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +20 -1
- package/dist/client/v2-e2ee.js +625 -105
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +17 -5
- package/dist/client.js +332 -167
- package/dist/client.js.map +1 -1
- package/dist/errors.js +4 -1
- package/dist/errors.js.map +1 -1
- package/dist/facades.d.ts +3 -0
- package/dist/facades.js +109 -53
- package/dist/facades.js.map +1 -1
- package/dist/group-index.d.ts +5 -0
- package/dist/group-index.js +65 -30
- package/dist/group-index.js.map +1 -1
- package/dist/keystore/aid-db.d.ts +12 -0
- package/dist/keystore/aid-db.js +68 -4
- package/dist/keystore/aid-db.js.map +1 -1
- package/dist/keystore/index.d.ts +12 -0
- package/dist/keystore/local-identity-store.d.ts +10 -0
- package/dist/keystore/local-identity-store.js +8 -2
- package/dist/keystore/local-identity-store.js.map +1 -1
- package/dist/keystore/local-token-store.d.ts +10 -0
- package/dist/keystore/local-token-store.js +8 -2
- package/dist/keystore/local-token-store.js.map +1 -1
- package/dist/register-flow.d.ts +0 -1
- package/dist/register-flow.js +96 -38
- package/dist/register-flow.js.map +1 -1
- package/dist/secret-store/file-store.d.ts +3 -14
- package/dist/secret-store/file-store.js +7 -98
- package/dist/secret-store/file-store.js.map +1 -1
- package/dist/secret-store/index.d.ts +1 -4
- package/dist/secret-store/index.js +2 -2
- package/dist/secret-store/index.js.map +1 -1
- package/dist/seq-tracker.d.ts +29 -9
- package/dist/seq-tracker.js +233 -64
- package/dist/seq-tracker.js.map +1 -1
- package/dist/storage/vfs.d.ts +1 -0
- package/dist/storage/vfs.js +28 -4
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.js +360 -8
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +19 -0
- package/dist/transport.js +197 -14
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.js +26 -23
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/v2/session/session.js +3 -4
- package/dist/v2/session/session.js.map +1 -1
- package/dist/v2/state/commitment.js +1 -2
- package/dist/v2/state/commitment.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -4
- package/dist/e2ee-group.d.ts +0 -249
- package/dist/e2ee-group.js +0 -1567
- package/dist/e2ee-group.js.map +0 -1
- package/dist/group-resources.d.ts +0 -31
- package/dist/group-resources.js +0 -84
- package/dist/group-resources.js.map +0 -1
- package/dist/keystore/file.d.ts +0 -109
- package/dist/keystore/file.js +0 -772
- package/dist/keystore/file.js.map +0 -1
- package/dist/keystore/sqlite-backup.d.ts +0 -44
- package/dist/keystore/sqlite-backup.js +0 -382
- package/dist/keystore/sqlite-backup.js.map +0 -1
- package/dist/namespaces/auth.d.ts +0 -118
- package/dist/namespaces/auth.js +0 -968
- package/dist/namespaces/auth.js.map +0 -1
- package/dist/namespaces/custody.d.ts +0 -48
- package/dist/namespaces/custody.js +0 -313
- package/dist/namespaces/custody.js.map +0 -1
- package/dist/namespaces/meta.d.ts +0 -76
- package/dist/namespaces/meta.js +0 -490
- package/dist/namespaces/meta.js.map +0 -1
|
@@ -7,6 +7,7 @@ import { URL } from 'node:url';
|
|
|
7
7
|
import { AUNClient } from '../client.js';
|
|
8
8
|
import { AIDStore } from '../aid-store.js';
|
|
9
9
|
import { publicKeyFingerprint } from '../cert-utils.js';
|
|
10
|
+
import { VERSION } from '../version.js';
|
|
10
11
|
function envBool(name, fallback = false) {
|
|
11
12
|
const raw = process.env[name];
|
|
12
13
|
if (raw == null)
|
|
@@ -106,7 +107,7 @@ function sendJson(res, status, data) {
|
|
|
106
107
|
}
|
|
107
108
|
class CrossSdkTsAgent {
|
|
108
109
|
language = 'ts';
|
|
109
|
-
sdkVersion =
|
|
110
|
+
sdkVersion = VERSION;
|
|
110
111
|
aid = textOf(process.env.AUN_TEST_AID || 'cross-ts.agentid.pub').trim();
|
|
111
112
|
issuer = textOf(process.env.AUN_TEST_ISSUER || 'agentid.pub').trim() || 'agentid.pub';
|
|
112
113
|
gatewayAid = textOf(process.env.AUN_GATEWAY_AID || `gateway.${this.issuer}`).trim();
|
|
@@ -118,16 +119,38 @@ class CrossSdkTsAgent {
|
|
|
118
119
|
startupError = '';
|
|
119
120
|
inbox = [];
|
|
120
121
|
groupInbox = [];
|
|
122
|
+
rawPushObservations = [];
|
|
123
|
+
rawPushObservationId = '';
|
|
124
|
+
rawPushRpcMethods = [];
|
|
125
|
+
rpcObservedTransports = new WeakSet();
|
|
126
|
+
groupChangedEvents = [];
|
|
121
127
|
traces = new Map();
|
|
122
128
|
sendResults = new Map();
|
|
129
|
+
inlineRealtimePayloadV1 = true;
|
|
123
130
|
constructor() {
|
|
124
|
-
this.client =
|
|
125
|
-
|
|
131
|
+
this.client = this.newClient();
|
|
132
|
+
}
|
|
133
|
+
async start() {
|
|
134
|
+
this.bindClientEvents();
|
|
135
|
+
// Cross-SDK runner 需要先由显式 Tail 建立窗口证明;启动阶段不得遗留后台 Pull。
|
|
136
|
+
await this.ensureConnected(false);
|
|
137
|
+
this.ready = true;
|
|
138
|
+
}
|
|
139
|
+
newClient() {
|
|
140
|
+
const client = new AUNClient();
|
|
141
|
+
const internal = client;
|
|
126
142
|
if (internal._configModel)
|
|
127
143
|
internal._configModel.requireForwardSecrecy = false;
|
|
128
144
|
internal._testSlotId = this.slotId;
|
|
145
|
+
return client;
|
|
129
146
|
}
|
|
130
|
-
|
|
147
|
+
bindClientEvents() {
|
|
148
|
+
this.installTransportRpcObserver();
|
|
149
|
+
this.client.on('_raw.message.received', (data) => this.storeRawPushObservation('_raw.message.received', 'p2p', 'legacy', data));
|
|
150
|
+
this.client.on('_raw.peer.v2.message_received', (data) => this.storeRawPushObservation('_raw.peer.v2.message_received', 'p2p', 'v2', data));
|
|
151
|
+
this.client.on('_raw.group.message_created', (data) => this.storeRawPushObservation('_raw.group.message_created', 'group', 'legacy', data));
|
|
152
|
+
this.client.on('_raw.group.v2.message_created', (data) => this.storeRawPushObservation('_raw.group.v2.message_created', 'group', 'v2', data));
|
|
153
|
+
this.client.on('_raw.group.changed', (data) => this.storeRawGroupChangedObservation(data));
|
|
131
154
|
this.client.on('message.received', (msg) => {
|
|
132
155
|
void this.storeInboxItem(this.normalizeMessage(msg, true));
|
|
133
156
|
});
|
|
@@ -140,8 +163,103 @@ class CrossSdkTsAgent {
|
|
|
140
163
|
this.client.on('group.message_undecryptable', (msg) => {
|
|
141
164
|
void this.storeGroupInboxItem(this.normalizeGroupMessage(msg, false, 'undecryptable'));
|
|
142
165
|
});
|
|
143
|
-
|
|
144
|
-
|
|
166
|
+
this.client.on('group.changed', (data) => this.storeGroupChangedPublicEvent(data));
|
|
167
|
+
}
|
|
168
|
+
installTransportRpcObserver() {
|
|
169
|
+
const transport = this.client._transport;
|
|
170
|
+
transport?.setTraceMode('diag');
|
|
171
|
+
if (!transport?.call || this.rpcObservedTransports.has(transport))
|
|
172
|
+
return;
|
|
173
|
+
const originalCall = transport.call;
|
|
174
|
+
this.rpcObservedTransports.add(transport);
|
|
175
|
+
transport.call = async (method, params, timeout, trace, background) => {
|
|
176
|
+
this.storeRawPushRpcMethod({ type: 'rpc', method, request_window: this.rawPushRequestWindow(params) });
|
|
177
|
+
let requestParams = params;
|
|
178
|
+
if (method === 'auth.connect' && !this.inlineRealtimePayloadV1 && jsonObjectOf(params)) {
|
|
179
|
+
const request = { ...jsonObjectOf(params) };
|
|
180
|
+
const capabilities = jsonObjectOf(request.capabilities);
|
|
181
|
+
if (capabilities) {
|
|
182
|
+
delete capabilities.inline_realtime_payload_v1;
|
|
183
|
+
request.capabilities = capabilities;
|
|
184
|
+
}
|
|
185
|
+
requestParams = request;
|
|
186
|
+
}
|
|
187
|
+
return await originalCall.call(transport, method, requestParams, timeout, trace, background);
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
storeRawPushObservation(rawEvent, scope, defaultKind, value) {
|
|
191
|
+
const data = jsonObjectOf(value) ?? {};
|
|
192
|
+
const hasInline = Object.prototype.hasOwnProperty.call(data, 'inline_message');
|
|
193
|
+
const inlineMessage = jsonObjectOf(data.inline_message);
|
|
194
|
+
this.rawPushObservations.push({
|
|
195
|
+
observation_id: this.rawPushObservationId,
|
|
196
|
+
time: Date.now(), raw_event: rawEvent, scope, group_id: textOf(data.group_id),
|
|
197
|
+
kind: textOf(data.kind || defaultKind),
|
|
198
|
+
action: textOf(data.action),
|
|
199
|
+
event_seq: Number(data.event_seq ?? 0) || 0,
|
|
200
|
+
seq: Number(data.seq ?? data.message_seq ?? data.msg_seq ?? 0) || 0,
|
|
201
|
+
message_id: textOf(data.message_id ?? data.id ?? ''),
|
|
202
|
+
has_inline: hasInline,
|
|
203
|
+
inline_version: textOf(data.inline_version ?? inlineMessage?.version ?? ''),
|
|
204
|
+
inline_is_object: inlineMessage !== null,
|
|
205
|
+
target_device_present: Boolean(textOf(data.target_device_id)),
|
|
206
|
+
target_slot_present: Boolean(textOf(data.target_slot_id)),
|
|
207
|
+
target_device_id: textOf(data.target_device_id),
|
|
208
|
+
target_slot_id: textOf(data.target_slot_id),
|
|
209
|
+
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(),
|
|
210
|
+
top_level_sensitive_keys: Object.keys(data).filter((key) => [
|
|
211
|
+
'inline_message', 'payload', 'message', 'envelope_json', 'ciphertext',
|
|
212
|
+
'_inline_message_candidates_v1', '_group_inline_plain_source_v1', '_group_inline_v2_source_v1',
|
|
213
|
+
].includes(key)).sort(),
|
|
214
|
+
});
|
|
215
|
+
if (this.rawPushObservations.length > 1000)
|
|
216
|
+
this.rawPushObservations = this.rawPushObservations.slice(-1000);
|
|
217
|
+
}
|
|
218
|
+
storeRawGroupChangedObservation(value) {
|
|
219
|
+
this.storeRawPushObservation('_raw.group.changed', 'group', 'changed', value);
|
|
220
|
+
}
|
|
221
|
+
storeGroupChangedPublicEvent(value) {
|
|
222
|
+
const data = jsonObjectOf(value) ?? {};
|
|
223
|
+
this.groupChangedEvents.push({
|
|
224
|
+
observation_id: this.rawPushObservationId,
|
|
225
|
+
time: Date.now(),
|
|
226
|
+
group_id: textOf(data.group_id),
|
|
227
|
+
action: textOf(data.action),
|
|
228
|
+
event_seq: Number(data.event_seq ?? 0) || 0,
|
|
229
|
+
event_id: textOf(data.event_id),
|
|
230
|
+
envelope_present: jsonObjectOf(data.envelope) !== null,
|
|
231
|
+
});
|
|
232
|
+
if (this.groupChangedEvents.length > 1000)
|
|
233
|
+
this.groupChangedEvents = this.groupChangedEvents.slice(-1000);
|
|
234
|
+
}
|
|
235
|
+
storeRawPushRpcMethod(traceInfo) {
|
|
236
|
+
if (traceInfo.type !== 'rpc')
|
|
237
|
+
return;
|
|
238
|
+
if (!this.rawPushObservationId)
|
|
239
|
+
return;
|
|
240
|
+
const method = textOf(traceInfo.method).trim();
|
|
241
|
+
if (!method)
|
|
242
|
+
return;
|
|
243
|
+
const requestWindow = jsonObjectOf(traceInfo.request_window) ?? {};
|
|
244
|
+
this.rawPushRpcMethods.push({
|
|
245
|
+
observation_id: this.rawPushObservationId,
|
|
246
|
+
time: Date.now(),
|
|
247
|
+
method,
|
|
248
|
+
...this.rawPushRequestWindow(requestWindow),
|
|
249
|
+
});
|
|
250
|
+
if (this.rawPushRpcMethods.length > 1000)
|
|
251
|
+
this.rawPushRpcMethods = this.rawPushRpcMethods.slice(-1000);
|
|
252
|
+
}
|
|
253
|
+
rawPushRequestWindow(value) {
|
|
254
|
+
const params = jsonObjectOf(value) ?? {};
|
|
255
|
+
const afterSeq = params.after_seq;
|
|
256
|
+
const limit = params.limit;
|
|
257
|
+
// 仅返回恢复窗口元数据;不得将 RPC params(其中可能含正文)暴露给测试接口。
|
|
258
|
+
return {
|
|
259
|
+
window_mode: typeof params.window_mode === 'string' ? params.window_mode : '',
|
|
260
|
+
after_seq: typeof afterSeq === 'number' && Number.isInteger(afterSeq) ? afterSeq : null,
|
|
261
|
+
limit: typeof limit === 'number' && Number.isInteger(limit) ? limit : null,
|
|
262
|
+
};
|
|
145
263
|
}
|
|
146
264
|
async close() {
|
|
147
265
|
try {
|
|
@@ -151,7 +269,7 @@ class CrossSdkTsAgent {
|
|
|
151
269
|
// 退出清理失败不影响容器关闭。
|
|
152
270
|
}
|
|
153
271
|
}
|
|
154
|
-
async ensureConnected() {
|
|
272
|
+
async ensureConnected(backgroundSync = true) {
|
|
155
273
|
const internal = this.client;
|
|
156
274
|
const store = new AIDStore({
|
|
157
275
|
aunPath: this.aunPath,
|
|
@@ -179,7 +297,8 @@ class CrossSdkTsAgent {
|
|
|
179
297
|
throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
|
|
180
298
|
}
|
|
181
299
|
this.client.loadIdentity(loaded.data.aid);
|
|
182
|
-
|
|
300
|
+
this.installTransportRpcObserver();
|
|
301
|
+
await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
|
|
183
302
|
}
|
|
184
303
|
identity() {
|
|
185
304
|
const internal = this.client;
|
|
@@ -292,6 +411,46 @@ class CrossSdkTsAgent {
|
|
|
292
411
|
sendJson(res, 200, { ok: true });
|
|
293
412
|
return;
|
|
294
413
|
}
|
|
414
|
+
if (req.method === 'POST' && url.pathname === '/test/raw-push/reset') {
|
|
415
|
+
const body = await readJson(req);
|
|
416
|
+
this.rawPushObservations = [];
|
|
417
|
+
this.rawPushRpcMethods = [];
|
|
418
|
+
this.groupChangedEvents = [];
|
|
419
|
+
this.rawPushObservationId = textOf(body.observation_id ?? '');
|
|
420
|
+
sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (req.method === 'GET' && url.pathname === '/test/raw-push') {
|
|
424
|
+
const filters = {};
|
|
425
|
+
for (const key of ['observation_id', 'scope', 'group_id', 'kind', 'raw_event'])
|
|
426
|
+
filters[key] = textOf(url.searchParams.get(key) ?? '');
|
|
427
|
+
const limit = Math.max(1, Math.min(Number(url.searchParams.get('limit') ?? 1000) || 1000, 1000));
|
|
428
|
+
let items = [...this.rawPushObservations];
|
|
429
|
+
for (const [key, value] of Object.entries(filters))
|
|
430
|
+
if (value)
|
|
431
|
+
items = items.filter((item) => textOf(item[key]) === value);
|
|
432
|
+
items = items.slice(-limit);
|
|
433
|
+
const observationId = filters.observation_id;
|
|
434
|
+
let rpcEntries = [...this.rawPushRpcMethods];
|
|
435
|
+
let groupChangedEvents = [...this.groupChangedEvents];
|
|
436
|
+
if (observationId)
|
|
437
|
+
rpcEntries = rpcEntries.filter((item) => textOf(item.observation_id) === observationId);
|
|
438
|
+
if (observationId)
|
|
439
|
+
groupChangedEvents = groupChangedEvents.filter((item) => textOf(item.observation_id) === observationId);
|
|
440
|
+
if (filters.group_id)
|
|
441
|
+
groupChangedEvents = groupChangedEvents.filter((item) => textOf(item.group_id) === filters.group_id);
|
|
442
|
+
rpcEntries = rpcEntries.slice(-limit);
|
|
443
|
+
const rpcMethods = rpcEntries.map((item) => textOf(item.method));
|
|
444
|
+
const rpcMethodCounts = {};
|
|
445
|
+
for (const method of rpcMethods)
|
|
446
|
+
rpcMethodCounts[method] = Number(rpcMethodCounts[method] ?? 0) + 1;
|
|
447
|
+
sendJson(res, 200, {
|
|
448
|
+
ok: true, items, count: items.length, rpc_methods: rpcMethods, rpc_method_counts: rpcMethodCounts,
|
|
449
|
+
rpc_calls: rpcEntries,
|
|
450
|
+
group_changed_events: groupChangedEvents.slice(-limit),
|
|
451
|
+
});
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
295
454
|
if (req.method === 'GET' && url.pathname === '/identity') {
|
|
296
455
|
sendJson(res, 200, this.identity());
|
|
297
456
|
return;
|
|
@@ -308,6 +467,34 @@ class CrossSdkTsAgent {
|
|
|
308
467
|
await this.pull(req, res);
|
|
309
468
|
return;
|
|
310
469
|
}
|
|
470
|
+
if (req.method === 'GET' && url.pathname === '/sync/state') {
|
|
471
|
+
this.syncState(url, res);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (req.method === 'POST' && url.pathname === '/sync/tail') {
|
|
475
|
+
await this.syncTail(req, res);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (req.method === 'POST' && url.pathname === '/sync/forward') {
|
|
479
|
+
await this.syncForward(req, res);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
if (req.method === 'POST' && url.pathname === '/sync/history') {
|
|
483
|
+
await this.syncHistory(req, res);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (req.method === 'POST' && url.pathname === '/session/disconnect') {
|
|
487
|
+
await this.sessionDisconnect(res);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (req.method === 'POST' && url.pathname === '/session/connect') {
|
|
491
|
+
await this.sessionConnect(req, res);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (req.method === 'POST' && url.pathname === '/session/restart') {
|
|
495
|
+
await this.sessionRestart(req, res);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
311
498
|
if (req.method === 'POST' && url.pathname === '/group/create') {
|
|
312
499
|
await this.groupCreate(req, res);
|
|
313
500
|
return;
|
|
@@ -494,6 +681,171 @@ class CrossSdkTsAgent {
|
|
|
494
681
|
});
|
|
495
682
|
}
|
|
496
683
|
}
|
|
684
|
+
syncNamespace(scope, groupId = '') {
|
|
685
|
+
if (scope === 'p2p')
|
|
686
|
+
return `p2p:${this.aid}`;
|
|
687
|
+
if (scope === 'group' && groupId)
|
|
688
|
+
return `group:${groupId}`;
|
|
689
|
+
throw new Error('scope must be p2p, or group with group_id');
|
|
690
|
+
}
|
|
691
|
+
syncStateValue(scope, groupId = '') {
|
|
692
|
+
const namespace = this.syncNamespace(scope, groupId);
|
|
693
|
+
const tracker = this.client._seqTracker;
|
|
694
|
+
if (!tracker)
|
|
695
|
+
throw new Error('SeqTracker is unavailable');
|
|
696
|
+
return { namespace, state: tracker.getSyncState(namespace) };
|
|
697
|
+
}
|
|
698
|
+
syncState(url, res) {
|
|
699
|
+
const scope = textOf(url.searchParams.get('scope') || 'p2p').trim().toLowerCase();
|
|
700
|
+
const groupId = textOf(url.searchParams.get('group_id') || '').trim();
|
|
701
|
+
try {
|
|
702
|
+
const snapshot = this.syncStateValue(scope, groupId);
|
|
703
|
+
sendJson(res, 200, { ok: true, scope, ...snapshot });
|
|
704
|
+
}
|
|
705
|
+
catch (err) {
|
|
706
|
+
sendJson(res, 400, {
|
|
707
|
+
ok: false,
|
|
708
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
709
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
async syncTail(req, res) {
|
|
714
|
+
await this.syncPull(req, res, true);
|
|
715
|
+
}
|
|
716
|
+
async syncForward(req, res) {
|
|
717
|
+
await this.syncPull(req, res, false);
|
|
718
|
+
}
|
|
719
|
+
async syncPull(req, res, tail) {
|
|
720
|
+
const body = await readJson(req);
|
|
721
|
+
const scope = textOf(body.scope || 'p2p').trim().toLowerCase();
|
|
722
|
+
const groupId = textOf(body.group_id || '').trim();
|
|
723
|
+
const afterSeq = Number(body.after_seq ?? 0) || 0;
|
|
724
|
+
const limit = Number(body.limit ?? 50) || 50;
|
|
725
|
+
try {
|
|
726
|
+
const params = { after_seq: afterSeq, limit };
|
|
727
|
+
if (tail)
|
|
728
|
+
params.window_mode = 'tail';
|
|
729
|
+
const method = scope === 'group' ? 'group.pull' : 'message.pull';
|
|
730
|
+
if (scope === 'group')
|
|
731
|
+
params.group_id = groupId;
|
|
732
|
+
this.syncNamespace(scope, groupId);
|
|
733
|
+
let result;
|
|
734
|
+
if (tail) {
|
|
735
|
+
result = await this.client.call(method, params);
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
const transport = this.client._transport;
|
|
739
|
+
if (!transport?.call)
|
|
740
|
+
throw new Error('raw transport is unavailable');
|
|
741
|
+
const wireMethod = scope === 'group' ? 'group.v2.pull' : 'message.v2.pull';
|
|
742
|
+
result = await transport.call(wireMethod, params);
|
|
743
|
+
}
|
|
744
|
+
const resultObj = jsonObjectOf(result) ?? {};
|
|
745
|
+
const messages = Array.isArray(resultObj.messages) ? resultObj.messages : [];
|
|
746
|
+
if (tail) {
|
|
747
|
+
for (const msg of messages) {
|
|
748
|
+
if (scope === 'group')
|
|
749
|
+
await this.storeGroupInboxItem(this.normalizeGroupMessage(msg, true));
|
|
750
|
+
else
|
|
751
|
+
await this.storeInboxItem(this.normalizeMessage(msg, true));
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
const snapshot = this.syncStateValue(scope, groupId);
|
|
755
|
+
sendJson(res, 200, { ok: true, scope, ...snapshot, result: jsonSafe(result) });
|
|
756
|
+
}
|
|
757
|
+
catch (err) {
|
|
758
|
+
sendJson(res, 500, {
|
|
759
|
+
ok: false,
|
|
760
|
+
scope,
|
|
761
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
762
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
async syncHistory(req, res) {
|
|
767
|
+
const body = await readJson(req);
|
|
768
|
+
const scope = textOf(body.scope || 'p2p').trim().toLowerCase();
|
|
769
|
+
const groupId = textOf(body.group_id || '').trim();
|
|
770
|
+
const beforeSeq = Number(body.before_seq ?? 0) || 0;
|
|
771
|
+
const limit = Number(body.limit ?? 50) || 50;
|
|
772
|
+
try {
|
|
773
|
+
const params = { before_seq: beforeSeq, limit };
|
|
774
|
+
const method = scope === 'group' ? 'group.history' : 'message.history';
|
|
775
|
+
if (scope === 'group')
|
|
776
|
+
params.group_id = groupId;
|
|
777
|
+
this.syncNamespace(scope, groupId);
|
|
778
|
+
const result = await this.client.call(method, params);
|
|
779
|
+
const snapshot = this.syncStateValue(scope, groupId);
|
|
780
|
+
sendJson(res, 200, { ok: true, scope, ...snapshot, result: jsonSafe(result) });
|
|
781
|
+
}
|
|
782
|
+
catch (err) {
|
|
783
|
+
sendJson(res, 500, {
|
|
784
|
+
ok: false,
|
|
785
|
+
scope,
|
|
786
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
787
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
async sessionDisconnect(res) {
|
|
792
|
+
try {
|
|
793
|
+
this.ready = false;
|
|
794
|
+
await this.client.disconnect();
|
|
795
|
+
sendJson(res, 200, { ok: true, state: textOf(this.client.state) });
|
|
796
|
+
}
|
|
797
|
+
catch (err) {
|
|
798
|
+
sendJson(res, 500, {
|
|
799
|
+
ok: false,
|
|
800
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
801
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
async sessionConnect(req, res) {
|
|
806
|
+
const body = await readJson(req);
|
|
807
|
+
const backgroundSync = body.background_sync === true;
|
|
808
|
+
if (Object.prototype.hasOwnProperty.call(body, 'inline_realtime_payload_v1')) {
|
|
809
|
+
this.inlineRealtimePayloadV1 = body.inline_realtime_payload_v1 !== false;
|
|
810
|
+
}
|
|
811
|
+
try {
|
|
812
|
+
await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
|
|
813
|
+
this.ready = true;
|
|
814
|
+
sendJson(res, 200, { ok: true, background_sync: backgroundSync, inline_realtime_payload_v1: this.inlineRealtimePayloadV1 });
|
|
815
|
+
}
|
|
816
|
+
catch (err) {
|
|
817
|
+
sendJson(res, 500, {
|
|
818
|
+
ok: false,
|
|
819
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
820
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async sessionRestart(req, res) {
|
|
825
|
+
const body = await readJson(req);
|
|
826
|
+
const backgroundSync = body.background_sync === true;
|
|
827
|
+
if (Object.prototype.hasOwnProperty.call(body, 'inline_realtime_payload_v1')) {
|
|
828
|
+
this.inlineRealtimePayloadV1 = body.inline_realtime_payload_v1 !== false;
|
|
829
|
+
}
|
|
830
|
+
this.ready = false;
|
|
831
|
+
try {
|
|
832
|
+
await this.client.close();
|
|
833
|
+
this.client = this.newClient();
|
|
834
|
+
this.bindClientEvents();
|
|
835
|
+
await this.ensureConnected(backgroundSync);
|
|
836
|
+
this.startupError = '';
|
|
837
|
+
this.ready = true;
|
|
838
|
+
sendJson(res, 200, { ok: true, background_sync: backgroundSync, inline_realtime_payload_v1: this.inlineRealtimePayloadV1 });
|
|
839
|
+
}
|
|
840
|
+
catch (err) {
|
|
841
|
+
this.startupError = `${err instanceof Error ? err.name : 'Error'}: ${err instanceof Error ? err.message : String(err)}`;
|
|
842
|
+
sendJson(res, 500, {
|
|
843
|
+
ok: false,
|
|
844
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
845
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
}
|
|
497
849
|
async groupCreate(req, res) {
|
|
498
850
|
const body = await readJson(req);
|
|
499
851
|
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|