@agentunion/fastaun 0.5.21 → 0.5.22
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 +58 -1
- package/_packed_docs/CHANGELOG.md +58 -1
- package/_packed_docs/INDEX.md +465 -453
- package/_packed_docs/KITE_DOCS_GUIDE.md +168 -164
- 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 +307 -67
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +5 -5
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +669 -666
- package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
- package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +16 -0
- package/_packed_docs/sdk/09-group-rpc-manual.md +10 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +3 -1
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +2 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +138 -134
- package/_packed_docs/sdk/INDEX.md +255 -239
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +939 -930
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +312 -363
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +322 -553
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +4 -4
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +484 -480
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +190 -97
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +158 -127
- package/dist/agent-md.d.ts +1 -1
- package/dist/agent-md.js +11 -4
- package/dist/agent-md.js.map +1 -1
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +18 -2
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +28 -0
- package/dist/client/delivery.js +399 -44
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +3 -0
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/rpc-pipeline.js +28 -2
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +109 -39
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.js +38 -10
- package/dist/client.js.map +1 -1
- package/dist/group-fs.d.ts +1 -0
- package/dist/group-fs.js +37 -19
- package/dist/group-fs.js.map +1 -1
- package/dist/org-protocol.d.ts +1 -0
- package/dist/org-protocol.js +54 -7
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +21 -3
- package/dist/ownership-v21.js +135 -37
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +7 -2
- package/dist/ownership-workflow.js +173 -17
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/storage/lowlevel.d.ts +6 -0
- package/dist/storage/lowlevel.js +24 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +70 -0
- package/dist/storage/read-cache.js +625 -0
- package/dist/storage/read-cache.js.map +1 -0
- package/dist/storage/vfs.d.ts +2 -0
- package/dist/storage/vfs.js +50 -15
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +21 -1
- package/dist/tools/cross-sdk-agent.js +301 -19
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.js +6 -2
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ import * as crypto from 'node:crypto';
|
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
6
|
import * as path from 'node:path';
|
|
7
7
|
import { tmpdir } from 'node:os';
|
|
8
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
8
9
|
import { URL } from 'node:url';
|
|
9
10
|
import { fileURLToPath } from 'node:url';
|
|
10
11
|
import { AUNClient } from '../client.js';
|
|
@@ -15,6 +16,32 @@ import { VERSION } from '../version.js';
|
|
|
15
16
|
import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
|
|
16
17
|
import { ownershipTaskResult } from '../ownership-workflow.js';
|
|
17
18
|
import { TimeoutError } from '../errors.js';
|
|
19
|
+
const credentialProcessStartupId = crypto.randomUUID();
|
|
20
|
+
const cacheReadContext = new AsyncLocalStorage();
|
|
21
|
+
const cacheReadObservers = new WeakMap();
|
|
22
|
+
function acquireCacheReadObserver(target, key, wrap) {
|
|
23
|
+
let observers = cacheReadObservers.get(target);
|
|
24
|
+
if (!observers) {
|
|
25
|
+
observers = new Map();
|
|
26
|
+
cacheReadObservers.set(target, observers);
|
|
27
|
+
}
|
|
28
|
+
let observer = observers.get(key);
|
|
29
|
+
if (!observer) {
|
|
30
|
+
const original = target[key];
|
|
31
|
+
target[key] = wrap(original);
|
|
32
|
+
observer = { users: 0, restore: () => { target[key] = original; } };
|
|
33
|
+
observers.set(key, observer);
|
|
34
|
+
}
|
|
35
|
+
observer.users += 1;
|
|
36
|
+
return () => {
|
|
37
|
+
if (--observer.users === 0) {
|
|
38
|
+
observer.restore();
|
|
39
|
+
observers.delete(key);
|
|
40
|
+
if (!observers.size)
|
|
41
|
+
cacheReadObservers.delete(target);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
18
45
|
function envBool(name, fallback = false) {
|
|
19
46
|
const raw = process.env[name];
|
|
20
47
|
if (raw == null)
|
|
@@ -136,6 +163,13 @@ export class CrossSdkTsAgent {
|
|
|
136
163
|
eventBoundClients = new WeakSet();
|
|
137
164
|
batchEventClient;
|
|
138
165
|
batchEventHandlers = [];
|
|
166
|
+
p2pSubscription = true;
|
|
167
|
+
p2pEventClient;
|
|
168
|
+
p2pEventHandler;
|
|
169
|
+
p2pDeliveryPaused = false;
|
|
170
|
+
p2pDeliveryBlocked = 0;
|
|
171
|
+
p2pDeliveryGate = null;
|
|
172
|
+
p2pDeliveryRetiredClients = new WeakSet();
|
|
139
173
|
rpcSpans = [];
|
|
140
174
|
observationGeneration = 0;
|
|
141
175
|
pullBarrier = null;
|
|
@@ -155,6 +189,18 @@ export class CrossSdkTsAgent {
|
|
|
155
189
|
constructor() {
|
|
156
190
|
this.client = this.newClient();
|
|
157
191
|
}
|
|
192
|
+
credentialStartup;
|
|
193
|
+
credentialProcessId = credentialProcessStartupId;
|
|
194
|
+
credentialProcessCheckpoint() {
|
|
195
|
+
const internal = this.client;
|
|
196
|
+
const metadata = internal._tokenStore._loadMetadataStrict(this.aid) ?? {};
|
|
197
|
+
return structuredClone({ pid: process.pid, startup_uuid: this.credentialProcessId, aid: this.aid,
|
|
198
|
+
cert_fingerprint: this.client.currentAid?.certFingerprint, store: this.aunPath,
|
|
199
|
+
records: metadata.credential_renewals_v1 ?? {}, revocations: metadata.credential_revocations_v1 ?? { version: 1, authorities: {} } });
|
|
200
|
+
}
|
|
201
|
+
captureCredentialStartup() {
|
|
202
|
+
this.credentialStartup ??= { ...this.credentialProcessCheckpoint(), phase: 'before_connect' };
|
|
203
|
+
}
|
|
158
204
|
async start() {
|
|
159
205
|
this.bindClientEvents();
|
|
160
206
|
// Cross-SDK runner 需要先由显式 Tail 建立窗口证明;启动阶段不得遗留后台 Pull。
|
|
@@ -172,7 +218,7 @@ export class CrossSdkTsAgent {
|
|
|
172
218
|
bindClientEvents() {
|
|
173
219
|
this.eventBoundClients ??= new WeakSet();
|
|
174
220
|
if (this.eventBoundClients.has(this.client)) {
|
|
175
|
-
this.
|
|
221
|
+
this.setP2pSubscription(this.p2pSubscription ?? true);
|
|
176
222
|
return;
|
|
177
223
|
}
|
|
178
224
|
this.eventBoundClients.add(this.client);
|
|
@@ -182,10 +228,6 @@ export class CrossSdkTsAgent {
|
|
|
182
228
|
this.client.on('_raw.group.message_created', (data) => this.storeRawPushObservation('_raw.group.message_created', 'group', 'legacy', data));
|
|
183
229
|
this.client.on('_raw.group.v2.message_created', (data) => this.storeRawPushObservation('_raw.group.v2.message_created', 'group', 'v2', data));
|
|
184
230
|
this.client.on('_raw.group.changed', (data) => this.storeRawGroupChangedObservation(data));
|
|
185
|
-
this.client.on('message.received', (msg) => {
|
|
186
|
-
this.countSingleEvent('message.received');
|
|
187
|
-
void this.storeApplicationEvent('message.received', msg);
|
|
188
|
-
});
|
|
189
231
|
this.client.on('message.undecryptable', (msg) => {
|
|
190
232
|
void this.storeInboxItem(this.normalizeMessage(msg, false, 'undecryptable'));
|
|
191
233
|
});
|
|
@@ -219,7 +261,7 @@ export class CrossSdkTsAgent {
|
|
|
219
261
|
this.recordTrace(textOf(payload.org_id), { stage: event, payload });
|
|
220
262
|
});
|
|
221
263
|
}
|
|
222
|
-
this.
|
|
264
|
+
this.setP2pSubscription(this.p2pSubscription ?? true);
|
|
223
265
|
}
|
|
224
266
|
countSingleEvent(event) {
|
|
225
267
|
this.singleEventCounts ??= { 'message.received': 0, 'group.message_created': 0, 'group.changed': 0 };
|
|
@@ -237,18 +279,78 @@ export class CrossSdkTsAgent {
|
|
|
237
279
|
else if (event === 'group.changed')
|
|
238
280
|
this.storeGroupChangedPublicEvent(value);
|
|
239
281
|
}
|
|
282
|
+
setP2pSubscription(enabled) {
|
|
283
|
+
this.p2pSubscription = enabled;
|
|
284
|
+
if (this.p2pEventHandler && (this.p2pEventClient !== this.client || !enabled)) {
|
|
285
|
+
this.p2pEventClient?.off('message.received', this.p2pEventHandler);
|
|
286
|
+
this.p2pEventHandler = undefined;
|
|
287
|
+
}
|
|
288
|
+
this.p2pEventClient = this.client;
|
|
289
|
+
if (enabled && !this.p2pEventHandler) {
|
|
290
|
+
const client = this.client;
|
|
291
|
+
this.p2pEventHandler = async (msg) => {
|
|
292
|
+
if ((this.p2pDeliveryPaused || this.p2pDeliveryRetiredClients?.has(client)) && !await this.waitForP2pDelivery(client))
|
|
293
|
+
return;
|
|
294
|
+
this.countSingleEvent('message.received');
|
|
295
|
+
await this.storeApplicationEvent('message.received', msg);
|
|
296
|
+
};
|
|
297
|
+
this.client.on('message.received', this.p2pEventHandler);
|
|
298
|
+
}
|
|
299
|
+
this.setBatchEventMode(this.batchEventMode ?? false);
|
|
300
|
+
}
|
|
301
|
+
setP2pDeliveryPaused(paused) {
|
|
302
|
+
this.p2pDeliveryPaused = paused;
|
|
303
|
+
if (!paused) {
|
|
304
|
+
const gate = this.p2pDeliveryGate;
|
|
305
|
+
this.p2pDeliveryGate = null;
|
|
306
|
+
gate?.release();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
async waitForP2pDelivery(client) {
|
|
310
|
+
if (this.p2pDeliveryRetiredClients?.has(client))
|
|
311
|
+
return false;
|
|
312
|
+
this.p2pDeliveryBlocked = (this.p2pDeliveryBlocked ?? 0) + 1;
|
|
313
|
+
try {
|
|
314
|
+
while (this.p2pDeliveryPaused && !this.p2pDeliveryRetiredClients?.has(client)) {
|
|
315
|
+
if (!this.p2pDeliveryGate) {
|
|
316
|
+
let release;
|
|
317
|
+
const promise = new Promise((resolve) => { release = resolve; });
|
|
318
|
+
this.p2pDeliveryGate = { promise, release };
|
|
319
|
+
}
|
|
320
|
+
await this.p2pDeliveryGate.promise;
|
|
321
|
+
}
|
|
322
|
+
return !this.p2pDeliveryRetiredClients?.has(client);
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
this.p2pDeliveryBlocked -= 1;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
retireP2pDelivery(client) {
|
|
329
|
+
this.p2pDeliveryRetiredClients ??= new WeakSet();
|
|
330
|
+
this.p2pDeliveryRetiredClients.add(client);
|
|
331
|
+
const gate = this.p2pDeliveryGate;
|
|
332
|
+
this.p2pDeliveryGate = null;
|
|
333
|
+
gate?.release();
|
|
334
|
+
}
|
|
335
|
+
applicationDeliveryState() {
|
|
336
|
+
const dispatcher = this.client._dispatcher;
|
|
337
|
+
return { subscribed: this.p2pSubscription ?? true, paused: this.p2pDeliveryPaused ?? false, blocked: this.p2pDeliveryBlocked ?? 0,
|
|
338
|
+
capacity: dispatcher?._messageQueueCapacity?.() ?? 0, used: dispatcher?._queuedMessageCount ?? 0, waiting: dispatcher?._messageAdmissionWaiters ?? 0 };
|
|
339
|
+
}
|
|
240
340
|
setBatchEventMode(enabled) {
|
|
241
341
|
this.batchEventMode = enabled;
|
|
242
|
-
|
|
342
|
+
const events = enabled ? ['message.batch', 'group.message_batch', 'group.event_batch'].filter((event) => event !== 'message.batch' || this.p2pSubscription !== false) : [];
|
|
343
|
+
if (this.batchEventClient === this.client && this.batchEventHandlers?.length === events.length && this.batchEventHandlers.every((item, index) => item.event === events[index]))
|
|
243
344
|
return;
|
|
244
345
|
for (const { event, handler } of this.batchEventHandlers ?? [])
|
|
245
346
|
this.batchEventClient?.off(event, handler);
|
|
246
347
|
this.batchEventClient = this.client;
|
|
247
348
|
this.batchEventHandlers = [];
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
for (const event of ['message.batch', 'group.message_batch', 'group.event_batch']) {
|
|
349
|
+
const client = this.client;
|
|
350
|
+
for (const event of events) {
|
|
251
351
|
const handler = async (value) => {
|
|
352
|
+
if (event === 'message.batch' && (this.p2pDeliveryPaused || this.p2pDeliveryRetiredClients?.has(client)) && !await this.waitForP2pDelivery(client))
|
|
353
|
+
return;
|
|
252
354
|
const data = jsonObjectOf(value) ?? {};
|
|
253
355
|
const items = JSON.parse(JSON.stringify(jsonSafe(Array.isArray(data.items) ? data.items : [])));
|
|
254
356
|
this.batchEvents ??= [];
|
|
@@ -617,6 +719,7 @@ export class CrossSdkTsAgent {
|
|
|
617
719
|
}
|
|
618
720
|
async close() {
|
|
619
721
|
this.resetObservationLedgers();
|
|
722
|
+
this.retireP2pDelivery(this.client);
|
|
620
723
|
try {
|
|
621
724
|
await this.client.close();
|
|
622
725
|
}
|
|
@@ -628,7 +731,7 @@ export class CrossSdkTsAgent {
|
|
|
628
731
|
const internal = this.client;
|
|
629
732
|
const store = new AIDStore({
|
|
630
733
|
aunPath: this.aunPath,
|
|
631
|
-
encryptionSeed: '',
|
|
734
|
+
encryptionSeed: process.env.AUN_TEST_ENCRYPTION_SEED || process.env.AUN_ENCRYPTION_SEED || '',
|
|
632
735
|
slotId: this.slotId,
|
|
633
736
|
debug: this.debug,
|
|
634
737
|
});
|
|
@@ -661,6 +764,7 @@ export class CrossSdkTsAgent {
|
|
|
661
764
|
throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
|
|
662
765
|
}
|
|
663
766
|
this.client.loadIdentity(loaded.data.aid);
|
|
767
|
+
this.captureCredentialStartup();
|
|
664
768
|
const checked = await store.checkAgentMd(this.aid);
|
|
665
769
|
const localEtag = checked.ok ? String(checked.data.local_etag ?? '').trim() : '';
|
|
666
770
|
const remoteEtag = checked.ok ? String(checked.data.remote_etag ?? '').trim() : '';
|
|
@@ -886,10 +990,23 @@ export class CrossSdkTsAgent {
|
|
|
886
990
|
if ((body.pull_barrier_count !== undefined && (typeof body.pull_barrier_count !== 'number' || !Number.isSafeInteger(body.pull_barrier_count) || body.pull_barrier_count < 0)) ||
|
|
887
991
|
(body.pull_barrier_scope !== undefined && !['all', 'p2p'].includes(body.pull_barrier_scope)) ||
|
|
888
992
|
(body.observation_id !== undefined && typeof body.observation_id !== 'string') ||
|
|
889
|
-
(body.release_pull_barrier !== undefined && typeof body.release_pull_barrier !== 'boolean')
|
|
993
|
+
(body.release_pull_barrier !== undefined && typeof body.release_pull_barrier !== 'boolean') ||
|
|
994
|
+
['p2p_subscription', 'p2p_delivery_paused', 'preserve_observations'].some((key) => body[key] !== undefined && typeof body[key] !== 'boolean')) {
|
|
890
995
|
sendJson(res, 400, { ok: false, error_code: 'bad_request', error_message: 'invalid observation parameters' });
|
|
891
996
|
return;
|
|
892
997
|
}
|
|
998
|
+
if (typeof body.p2p_subscription === 'boolean')
|
|
999
|
+
this.setP2pSubscription(body.p2p_subscription);
|
|
1000
|
+
const p2pPullSpanIds = body.preserve_observations === true && body.p2p_subscription === false
|
|
1001
|
+
? this.rpcSpans.filter((span) => span.method === 'message.pull' || span.method === 'message.v2.pull').map((span) => textOf(span.span_id)) : undefined;
|
|
1002
|
+
if (typeof body.p2p_delivery_paused === 'boolean')
|
|
1003
|
+
this.setP2pDeliveryPaused(body.p2p_delivery_paused);
|
|
1004
|
+
if (body.preserve_observations === true) {
|
|
1005
|
+
if (body.release_pull_barrier === true)
|
|
1006
|
+
this.releasePullBarrier();
|
|
1007
|
+
sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId, ...(p2pPullSpanIds !== undefined ? { p2p_pull_span_ids: p2pPullSpanIds } : {}) });
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
893
1010
|
if (body.release_pull_barrier === true) {
|
|
894
1011
|
this.releasePullBarrier();
|
|
895
1012
|
sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
|
|
@@ -954,6 +1071,7 @@ export class CrossSdkTsAgent {
|
|
|
954
1071
|
rpcMethodCounts[method] = Number(rpcMethodCounts[method] ?? 0) + 1;
|
|
955
1072
|
sendJson(res, 200, {
|
|
956
1073
|
ok: true, time_ms: Date.now(), items, count: items.length, rpc_methods: rpcMethods, rpc_method_counts: rpcMethodCounts,
|
|
1074
|
+
observation_id: this.rawPushObservationId,
|
|
957
1075
|
rpc_calls: rpcEntries,
|
|
958
1076
|
group_changed_events: groupChangedEvents.slice(-limit),
|
|
959
1077
|
group_invite_events: groupInviteEvents.slice(-limit),
|
|
@@ -964,6 +1082,7 @@ export class CrossSdkTsAgent {
|
|
|
964
1082
|
batch_event_mode: this.batchEventMode ?? false,
|
|
965
1083
|
batch_events: batchEvents,
|
|
966
1084
|
single_event_counts: this.singleEventCounts ?? { 'message.received': 0, 'group.message_created': 0, 'group.changed': 0 },
|
|
1085
|
+
application_delivery: this.applicationDeliveryState(),
|
|
967
1086
|
pull_barrier: { target: this.pullBarrier?.target ?? 0, waiting: this.pullBarrier?.waiting ?? 0, released: this.pullBarrier?.released ?? true, scope: this.pullBarrier?.scope ?? 'all' },
|
|
968
1087
|
});
|
|
969
1088
|
return;
|
|
@@ -1584,6 +1703,7 @@ export class CrossSdkTsAgent {
|
|
|
1584
1703
|
try {
|
|
1585
1704
|
if (typeof body.batch_events === 'boolean')
|
|
1586
1705
|
this.batchEventMode = body.batch_events;
|
|
1706
|
+
this.retireP2pDelivery(this.client);
|
|
1587
1707
|
await this.client.close();
|
|
1588
1708
|
this.client = this.newClient();
|
|
1589
1709
|
this.bindClientEvents();
|
|
@@ -1660,15 +1780,36 @@ export class CrossSdkTsAgent {
|
|
|
1660
1780
|
const now = Math.floor(Date.now() / 1000);
|
|
1661
1781
|
if (op === 'request')
|
|
1662
1782
|
return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
|
|
1663
|
-
if (
|
|
1783
|
+
if (op === 'revocation_checkpoint') {
|
|
1784
|
+
const internal = this.client;
|
|
1785
|
+
if (params.sync === true)
|
|
1786
|
+
await internal._getCredentialRenewal()._syncRevocations();
|
|
1787
|
+
return internal._tokenStore._loadMetadataStrict(this.aid)?.credential_revocations_v1 ?? { version: 1, authorities: {} };
|
|
1788
|
+
}
|
|
1789
|
+
if (op === 'credential_process')
|
|
1790
|
+
return params.startup === true ? this.credentialStartup : this.credentialProcessCheckpoint();
|
|
1791
|
+
if (op === 'manage_credential') {
|
|
1792
|
+
const manager = this.client._getCredentialRenewal();
|
|
1793
|
+
await manager.serial(() => manager.rememberNow(params.credential, {}, this.aid, undefined, true));
|
|
1794
|
+
return await this.client.credential.current(textOf(params.credential.cid));
|
|
1795
|
+
}
|
|
1796
|
+
if (op === 'current_credential')
|
|
1797
|
+
return await this.client.credential.current(textOf(params.credential_cid));
|
|
1798
|
+
if (['register', 'sign', 'certificate', 'local_certificate', 'create', 'prepare', 'transfer_accept', 'renew'].includes(op)) {
|
|
1664
1799
|
const store = this.aidStore();
|
|
1665
1800
|
try {
|
|
1666
|
-
if (op === '
|
|
1801
|
+
if (op === 'transfer_accept')
|
|
1802
|
+
return await this.client.org.lifecycle.transferAccept({ ...jsonObjectOf(params.params), aidStore: store });
|
|
1803
|
+
if (op === 'prepare' || op === 'renew') {
|
|
1667
1804
|
const request = jsonObjectOf(params.params) ?? {};
|
|
1668
1805
|
const orgId = textOf(params.org_id ?? request.org_id);
|
|
1669
1806
|
const loaded = orgId ? store.load(orgId) : null;
|
|
1670
1807
|
const orgSigner = loaded?.ok && loaded.data.aid.isPrivateKeyValid() ? loaded.data.aid : undefined;
|
|
1671
|
-
|
|
1808
|
+
const credentialOptions = jsonObjectOf(params.credential_options);
|
|
1809
|
+
if (op === 'prepare')
|
|
1810
|
+
return this.client.org.prepareRequest(textOf(params.method), request, textOf(params.target), this.client.currentAid, { ...jsonObjectOf(params.options), orgSigner, ...(credentialOptions ? { credentialOptions } : {}) });
|
|
1811
|
+
const prepared = this.client.org.prepareRequest('org.member.renewCredential', request, textOf(params.target) || `org.${orgId.slice(orgId.indexOf('.') + 1)}`, this.client.currentAid, { orgSigner, credentialOptions: jsonObjectOf(params.credential_options) ?? undefined });
|
|
1812
|
+
return { result: await this.client.org.member.renewCredential(prepared), params: prepared };
|
|
1672
1813
|
}
|
|
1673
1814
|
if (op === 'register') {
|
|
1674
1815
|
const registered = await store.register(textOf(params.org_id), { type: 'org', owner: this.aid, exttype: 'company' });
|
|
@@ -1677,12 +1818,14 @@ export class CrossSdkTsAgent {
|
|
|
1677
1818
|
}
|
|
1678
1819
|
const loaded = op === 'certificate'
|
|
1679
1820
|
? await store.resolve(textOf(params.as_aid), { skipAgentMd: true })
|
|
1680
|
-
: (params.as_aid || params.org_id) ? store.load(textOf(params.as_aid ?? params.org_id)) : null;
|
|
1821
|
+
: (params.as_aid || op === 'local_certificate' || params.org_id) ? store.load(textOf(params.as_aid ?? params.org_id)) : null;
|
|
1681
1822
|
if (loaded && !loaded.ok)
|
|
1682
1823
|
throw new Error(String(loaded.error));
|
|
1683
1824
|
const identity = loaded?.data?.aid ?? this.client.currentAid;
|
|
1684
1825
|
const result = { cert_fingerprint: identity.certFingerprint, certificate: identity.certPem };
|
|
1685
|
-
if (op === '
|
|
1826
|
+
if (op === 'local_certificate')
|
|
1827
|
+
result.has_private_key = identity.isPrivateKeyValid();
|
|
1828
|
+
else if (op === 'sign') {
|
|
1686
1829
|
const signed = await identity.sign(Buffer.from(canonicalJson(params.payload)));
|
|
1687
1830
|
if (!signed.ok)
|
|
1688
1831
|
throw new Error(String(signed.error));
|
|
@@ -1710,6 +1853,7 @@ export class CrossSdkTsAgent {
|
|
|
1710
1853
|
const actual = jsonObjectOf(params.context) ?? params;
|
|
1711
1854
|
const memberships = jsonObjectOf(params.memberships) ?? {};
|
|
1712
1855
|
result.verification = { ...this.client.credential.verify(value, { resolveCertificate: resolver, resolveActorCertificate: resolver,
|
|
1856
|
+
resolveStatusProof: (cid) => params.status_proofs?.[cid],
|
|
1713
1857
|
resolveStatus: (cid) => params.statuses?.[cid], now: verificationNow, audience: textOf(actual.audience), subject: textOf(actual.subject) || undefined,
|
|
1714
1858
|
ns: textOf(actual.ns), action: textOf(actual.action), resource: textOf(actual.resource), rootIssuer: textOf(actual.root_issuer) || undefined,
|
|
1715
1859
|
params: jsonObjectOf(actual.params) ?? {}, units: jsonObjectOf(actual.units) ?? {}, clientIp: textOf(actual.client_ip), method: textOf(actual.method), target: textOf(actual.target),
|
|
@@ -1751,6 +1895,18 @@ export class CrossSdkTsAgent {
|
|
|
1751
1895
|
case 'sdk.org.protocol':
|
|
1752
1896
|
result = await this.orgProtocol(params);
|
|
1753
1897
|
break;
|
|
1898
|
+
case 'credential.register':
|
|
1899
|
+
result = await this.client.credential.register(params);
|
|
1900
|
+
break;
|
|
1901
|
+
case 'credential.status':
|
|
1902
|
+
result = await this.client.credential.status(params);
|
|
1903
|
+
break;
|
|
1904
|
+
case 'credential.revoke':
|
|
1905
|
+
result = await this.client.credential.revoke(params);
|
|
1906
|
+
break;
|
|
1907
|
+
case 'credential.revocationList':
|
|
1908
|
+
result = await this.client.credential.revocationList(params);
|
|
1909
|
+
break;
|
|
1754
1910
|
case 'org.lifecycle.create':
|
|
1755
1911
|
result = await this.client.org.lifecycle.create(params);
|
|
1756
1912
|
break;
|
|
@@ -1843,6 +1999,10 @@ export class CrossSdkTsAgent {
|
|
|
1843
1999
|
error_code: err instanceof Error ? err.name : 'Error',
|
|
1844
2000
|
error_message: err instanceof Error ? err.message : String(err),
|
|
1845
2001
|
};
|
|
2002
|
+
if (method.startsWith('org.') || method === 'sdk.org.protocol') {
|
|
2003
|
+
const remote = err;
|
|
2004
|
+
error.rpc_error_code = remote?.stringCode || remote?.data?.error_code || remote?.data?.code || (typeof remote?.code === 'string' ? remote.code : '');
|
|
2005
|
+
}
|
|
1846
2006
|
this.recordTrace(traceId, { stage: 'group_call_error', method, error });
|
|
1847
2007
|
sendJson(res, 500, error);
|
|
1848
2008
|
}
|
|
@@ -2007,6 +2167,8 @@ export class CrossSdkTsAgent {
|
|
|
2007
2167
|
}
|
|
2008
2168
|
}
|
|
2009
2169
|
async callGroupFsAction(action, params, asGroupAid = '') {
|
|
2170
|
+
if (action === 'cache_read')
|
|
2171
|
+
return await this.cacheRead(params, true, asGroupAid);
|
|
2010
2172
|
const groupFs = this.client.group.fs;
|
|
2011
2173
|
let signingStore = null;
|
|
2012
2174
|
const withSigning = (source) => {
|
|
@@ -2146,7 +2308,124 @@ export class CrossSdkTsAgent {
|
|
|
2146
2308
|
}
|
|
2147
2309
|
return response;
|
|
2148
2310
|
}
|
|
2311
|
+
async cacheRead(params, group = false, asGroupAid = '') {
|
|
2312
|
+
const operation = textOf(params.operation || 'read_bytes');
|
|
2313
|
+
if (!['read_bytes', 'stat', 'lstat', 'list', 'ls', 'find', 'du', 'df'].includes(operation)) {
|
|
2314
|
+
throw new Error(`unsupported cache read operation: ${operation}`);
|
|
2315
|
+
}
|
|
2316
|
+
const transport = this.client._transport;
|
|
2317
|
+
const lowlevel = group ? this.client.group.fs.lowlevel : this.client.storage.lowlevel;
|
|
2318
|
+
const counters = { rpc_count: 0, http_count: 0, body_transfers: 0, body_bytes: 0, methods: {}, wire_params: [] };
|
|
2319
|
+
const releaseCall = acquireCacheReadObserver(transport, 'call', (originalCall) => (method, request, ...tail) => {
|
|
2320
|
+
const context = cacheReadContext.getStore();
|
|
2321
|
+
const counted = context && (method.startsWith('storage.') || method.startsWith('group.fs.'));
|
|
2322
|
+
if (counted) {
|
|
2323
|
+
context.rpc_count += 1;
|
|
2324
|
+
context.methods[method] = (context.methods[method] || 0) + 1;
|
|
2325
|
+
context.wire_params.push({ method, params: JSON.parse(JSON.stringify(request ?? {})) });
|
|
2326
|
+
}
|
|
2327
|
+
const pending = originalCall.call(transport, method, request, ...tail);
|
|
2328
|
+
const observed = pending.then((result) => {
|
|
2329
|
+
const payload = jsonObjectOf(result);
|
|
2330
|
+
const content = payload?.content_base64 ?? payload?.content;
|
|
2331
|
+
if (counted && !payload?.not_modified && typeof content === 'string') {
|
|
2332
|
+
context.body_transfers += 1;
|
|
2333
|
+
context.body_bytes += Buffer.from(content, 'base64').byteLength;
|
|
2334
|
+
}
|
|
2335
|
+
return result;
|
|
2336
|
+
});
|
|
2337
|
+
if (pending.cancel)
|
|
2338
|
+
observed.cancel = () => pending.cancel();
|
|
2339
|
+
return observed;
|
|
2340
|
+
});
|
|
2341
|
+
const releaseHttp = acquireCacheReadObserver(lowlevel, 'httpGet', (originalHttp) => async (...args) => {
|
|
2342
|
+
const context = cacheReadContext.getStore();
|
|
2343
|
+
if (context)
|
|
2344
|
+
context.http_count += 1;
|
|
2345
|
+
const data = await originalHttp.call(lowlevel, ...args);
|
|
2346
|
+
if (context) {
|
|
2347
|
+
context.body_transfers += 1;
|
|
2348
|
+
context.body_bytes += data.byteLength;
|
|
2349
|
+
}
|
|
2350
|
+
return data;
|
|
2351
|
+
});
|
|
2352
|
+
const readOnce = async () => {
|
|
2353
|
+
const remotePath = textOf(params.path);
|
|
2354
|
+
const noCache = Boolean(params.no_cache ?? params.noCache);
|
|
2355
|
+
if (group) {
|
|
2356
|
+
const options = withoutKeys(params, ['operation', 'count', 'concurrent', 'no_cache']);
|
|
2357
|
+
options.noCache = noCache;
|
|
2358
|
+
if (operation !== 'read_bytes')
|
|
2359
|
+
return await this.callGroupFsAction(operation === 'list' ? 'ls' : operation, options, asGroupAid);
|
|
2360
|
+
delete options.path;
|
|
2361
|
+
const dst = this.writeTempText('', '.bin');
|
|
2362
|
+
try {
|
|
2363
|
+
const result = await this.callGroupFsAction('cp', { ...options, src: remotePath, dst, force: true }, asGroupAid);
|
|
2364
|
+
const response = jsonObjectOf(result);
|
|
2365
|
+
return { content_base64: response.content_base64, size_bytes: response.size_bytes };
|
|
2366
|
+
}
|
|
2367
|
+
finally {
|
|
2368
|
+
fs.rmSync(dst, { force: true });
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
const storage = this.client.storage;
|
|
2372
|
+
const options = {
|
|
2373
|
+
owner: textOf(params.owner_aid ?? params.ownerAID).trim() || undefined,
|
|
2374
|
+
bucket: textOf(params.bucket).trim() || 'default', noCache,
|
|
2375
|
+
};
|
|
2376
|
+
if (operation !== 'df')
|
|
2377
|
+
options.token = textOf(params.token).trim() || undefined;
|
|
2378
|
+
if (operation === 'read_bytes') {
|
|
2379
|
+
const shareId = textOf(params.share_id ?? params.shareId).trim();
|
|
2380
|
+
if (shareId) {
|
|
2381
|
+
const result = await storage.lowlevel.getByShare({ shareId, noCache });
|
|
2382
|
+
const data = result.download_url ? await storage.lowlevel.httpGet(textOf(result.download_url)) : Buffer.from(textOf(result.content_base64 ?? result.content), 'base64');
|
|
2383
|
+
return { content_base64: Buffer.from(data).toString('base64'), size_bytes: data.byteLength };
|
|
2384
|
+
}
|
|
2385
|
+
for (const key of ['offset', 'limit'])
|
|
2386
|
+
if (params[key] != null)
|
|
2387
|
+
options[key] = Number(params[key]);
|
|
2388
|
+
const data = await storage.readBytes(remotePath, options);
|
|
2389
|
+
return { content_base64: Buffer.from(data).toString('base64'), size_bytes: data.byteLength };
|
|
2390
|
+
}
|
|
2391
|
+
const fields = { list: ['page', 'size', 'marker', 'long', 'recursive'], find: ['name', 'mtime', 'page'], du: [] };
|
|
2392
|
+
for (const key of fields[operation] ?? [])
|
|
2393
|
+
if (params[key] != null)
|
|
2394
|
+
options[key] = params[key];
|
|
2395
|
+
if (params.page_size != null || params.pageSize != null)
|
|
2396
|
+
options.pageSize = Number(params.page_size ?? params.pageSize);
|
|
2397
|
+
if (params.max_depth != null || params.maxDepth != null)
|
|
2398
|
+
options.maxDepth = Number(params.max_depth ?? params.maxDepth);
|
|
2399
|
+
if (params.node_type != null || params.nodeType != null)
|
|
2400
|
+
options.nodeType = params.node_type ?? params.nodeType;
|
|
2401
|
+
if (operation === 'find' && (params.size_expr != null || params.sizeExpr != null))
|
|
2402
|
+
options.size = params.size_expr ?? params.sizeExpr;
|
|
2403
|
+
const method = storage[operation === 'ls' ? 'list' : operation];
|
|
2404
|
+
return await method.call(storage, ...(operation === 'df' ? [options] : [remotePath, options]));
|
|
2405
|
+
};
|
|
2406
|
+
try {
|
|
2407
|
+
const count = Math.max(1, Number(params.count || 1));
|
|
2408
|
+
const values = await cacheReadContext.run(counters, async () => {
|
|
2409
|
+
if (params.concurrent)
|
|
2410
|
+
return await Promise.all(Array.from({ length: count }, () => readOnce()));
|
|
2411
|
+
const items = [];
|
|
2412
|
+
for (let index = 0; index < count; index += 1)
|
|
2413
|
+
items.push(await readOnce());
|
|
2414
|
+
return items;
|
|
2415
|
+
});
|
|
2416
|
+
if (values.some((value) => stableStringify(value) !== stableStringify(values[0])))
|
|
2417
|
+
throw new Error('cache_read returned inconsistent values');
|
|
2418
|
+
const result = operation === 'read_bytes' ? jsonObjectOf(values[0]) : { value: values[0] };
|
|
2419
|
+
return { ...result, ...counters };
|
|
2420
|
+
}
|
|
2421
|
+
finally {
|
|
2422
|
+
releaseCall();
|
|
2423
|
+
releaseHttp();
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2149
2426
|
async callStorageAction(action, params) {
|
|
2427
|
+
if (action === 'cache_read')
|
|
2428
|
+
return await this.cacheRead(params);
|
|
2150
2429
|
const storage = this.client.storage;
|
|
2151
2430
|
const path = textOf(params.path).trim();
|
|
2152
2431
|
const owner = textOf(params.owner_aid ?? params.ownerAID).trim() || undefined;
|
|
@@ -2325,7 +2604,10 @@ export class CrossSdkTsAgent {
|
|
|
2325
2604
|
case 'revoke_share_link':
|
|
2326
2605
|
return await storage.lowlevel.revokeShareLink({ shareId: textOf(params.share_id ?? params.shareId).trim() });
|
|
2327
2606
|
case 'get_by_share': {
|
|
2328
|
-
const result = await storage.lowlevel.getByShare({
|
|
2607
|
+
const result = await storage.lowlevel.getByShare({
|
|
2608
|
+
shareId: textOf(params.share_id ?? params.shareId).trim(),
|
|
2609
|
+
noCache: Boolean(params.no_cache ?? params.noCache),
|
|
2610
|
+
});
|
|
2329
2611
|
const resultObj = jsonObjectOf(result);
|
|
2330
2612
|
const content = textOf(resultObj?.content);
|
|
2331
2613
|
if (content) {
|
|
@@ -2616,7 +2898,7 @@ export class CrossSdkTsAgent {
|
|
|
2616
2898
|
aidStore() {
|
|
2617
2899
|
return new AIDStore({
|
|
2618
2900
|
aunPath: this.aunPath,
|
|
2619
|
-
encryptionSeed: '',
|
|
2901
|
+
encryptionSeed: process.env.AUN_TEST_ENCRYPTION_SEED || process.env.AUN_ENCRYPTION_SEED || '',
|
|
2620
2902
|
slotId: this.slotId,
|
|
2621
2903
|
debug: this.debug,
|
|
2622
2904
|
});
|