@agentunion/fastaun-browser 0.5.20 → 0.5.21
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 +47 -0
- package/_packed_docs/CHANGELOG.md +47 -0
- package/_packed_docs/INDEX.md +453 -440
- package/_packed_docs/KITE_DOCS_GUIDE.md +164 -161
- package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/344/270/216/346/215/242owner/347/274/226/346/216/222/346/226/271/346/241/210.md +530 -0
- package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/345/256/214/346/225/264/350/256/276/350/256/241/344/270/216/345/256/236/346/226/275/350/256/241/345/210/222.md +685 -0
- package/_packed_docs/agent.md/working/agent.md-schema/344/270/216/347/255/276/345/217/221/351/252/214/347/255/276/346/265/201/347/250/213/346/276/204/346/270/205.md +349 -0
- package/_packed_docs/agent.md/working//346/234/254/345/234/260Docker/346/265/213/350/257/225Bug/346/270/205/345/215/225.md +40 -0
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1433 -1392
- package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +2 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -658
- package/_packed_docs/sdk/0.5.21-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +368 -0
- package/_packed_docs/sdk/0.5.21-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +350 -0
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +4 -1
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +42 -39
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +147 -14
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +48 -47
- package/_packed_docs/sdk/09-group-rpc-manual.md +5 -2
- package/_packed_docs/sdk/09-message-rpc-manual.md +250 -160
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +71 -0
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +88 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +134 -130
- package/_packed_docs/sdk/INDEX.md +239 -221
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -922
- 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 +106 -43
- 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 +180 -9
- 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 +708 -708
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -476
- 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 +1 -1
- 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 +2 -2
- package/dist/agent-md-schema.d.ts +1 -0
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +5 -4
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +25 -1
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +148 -71
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +13 -0
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +55 -8
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +2 -1
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +4 -0
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +4981 -1219
- package/dist/cert-utils.d.ts +1 -0
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +21 -0
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +101 -16
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +1172 -160
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +122 -48
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +22 -3
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +1258 -649
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +23 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +391 -87
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/events.d.ts +19 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +146 -23
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +42 -1
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +363 -7
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +14 -1
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.d.ts +4 -0
- package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.js +30 -13
- package/dist/keystore/indexeddb-identity-store.js.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +19 -2
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +193 -6
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +15 -2
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +308 -27
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +45 -0
- package/dist/org-protocol.d.ts.map +1 -1
- package/dist/org-protocol.js +757 -11
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +21 -4
- package/dist/ownership-v21.d.ts.map +1 -1
- package/dist/ownership-v21.js +49 -16
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +30 -0
- package/dist/ownership-workflow.d.ts.map +1 -1
- package/dist/ownership-workflow.js +412 -54
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/seq-tracker.d.ts +2 -0
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +3 -2
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +60 -3
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +433 -37
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +3 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +62 -30
- 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
package/dist/agent-md.js
CHANGED
|
@@ -18,7 +18,7 @@ export function buildOwnershipAgentMdV21(content, statement) {
|
|
|
18
18
|
}
|
|
19
19
|
function updateOwnershipAgentMd(content, fields) {
|
|
20
20
|
const payload = parseAgentMdTailSignature(String(content ?? '')).payload;
|
|
21
|
-
const match =
|
|
21
|
+
const match = /^\ufeff?---(?:\r\n|\n|\r)([\s\S]*?)(?:\r\n|\n|\r)---([\s\S]*)$/.exec(payload);
|
|
22
22
|
if (!match)
|
|
23
23
|
throw new ValidationError('agent.md must start with YAML frontmatter');
|
|
24
24
|
const document = parseDocument(match[1], { uniqueKeys: true });
|
|
@@ -34,7 +34,7 @@ function updateOwnershipAgentMd(content, fields) {
|
|
|
34
34
|
for (const [name, value] of Object.entries(fields))
|
|
35
35
|
document.set(name, value);
|
|
36
36
|
const yamlText = document.toString().replace(/\r\n/g, '\n');
|
|
37
|
-
const updated =
|
|
37
|
+
const updated = `${payload.startsWith('\ufeff') ? '\ufeff' : ''}---\n${yamlText.endsWith('\n') ? yamlText : `${yamlText}\n`}---${match[2]}`;
|
|
38
38
|
validateAgentMdDocument(updated, { expectedAid: String(frontmatter.aid ?? '') });
|
|
39
39
|
return updated;
|
|
40
40
|
}
|
|
@@ -206,6 +206,10 @@ function requestWithNodeHost(input, init, timeoutMs) {
|
|
|
206
206
|
}
|
|
207
207
|
});
|
|
208
208
|
}
|
|
209
|
+
export function readAgentMdFrontmatter(content) {
|
|
210
|
+
const payload = parseAgentMdTailSignatureForRead(content).payload;
|
|
211
|
+
return payload.replace(/^\ufeff/, '').split(/\r\n|\n|\r/, 1)[0]?.trim() === '---' ? parseFileFrontmatter(payload, true, false) : {};
|
|
212
|
+
}
|
|
209
213
|
async function fetchWithTimeout(input, init, timeoutMs = DEFAULT_HTTP_TIMEOUT_MS) {
|
|
210
214
|
if (new Headers(init.headers).has('host')) {
|
|
211
215
|
return await requestWithNodeHost(input, init, timeoutMs);
|
|
@@ -344,10 +348,19 @@ export class AgentMdManager {
|
|
|
344
348
|
if (fallback && fallback !== url)
|
|
345
349
|
response = await read(fallback);
|
|
346
350
|
}
|
|
347
|
-
if (!response.ok && response.status !== 404)
|
|
348
|
-
throw new StateError(`NS ownership check unavailable: HTTP ${response.status}`, { stringCode: 'unavailable', retryable: true });
|
|
349
351
|
if (headerValue(response.headers, 'X-AUN-Ownership-Status') === 'not_applicable')
|
|
350
352
|
throw new StateError('group/org uses its lifecycle owner relationship', { stringCode: 'not_applicable' });
|
|
353
|
+
if (response.status === 400) {
|
|
354
|
+
let failure;
|
|
355
|
+
try {
|
|
356
|
+
failure = await response.json();
|
|
357
|
+
}
|
|
358
|
+
catch { }
|
|
359
|
+
if (isJsonObject(failure) && failure.error === 'invalid')
|
|
360
|
+
throw new ValidationError('NS ownership material is invalid', { stringCode: 'invalid' });
|
|
361
|
+
}
|
|
362
|
+
if (!response.ok && response.status !== 404)
|
|
363
|
+
throw new StateError(`NS ownership check unavailable: HTTP ${response.status}`, { stringCode: 'unavailable', retryable: true });
|
|
351
364
|
const protocol = headerValue(response.headers, 'X-AUN-Ownership-Protocol');
|
|
352
365
|
const version = headerValue(response.headers, 'X-AUN-Ownership-Version');
|
|
353
366
|
const lock = headerValue(response.headers, 'X-AUN-Ownership-Lock');
|
|
@@ -369,7 +382,7 @@ export class AgentMdManager {
|
|
|
369
382
|
}
|
|
370
383
|
return { sub_aid: target, exists: response.ok, content, etag, protocol, relation_version: Number(version), lock: lock, observed_at: Math.trunc(Date.now() / 1000) };
|
|
371
384
|
}
|
|
372
|
-
async submitOwnershipRaw(aid, content, condition) {
|
|
385
|
+
async submitOwnershipRaw(aid, content, condition, guard) {
|
|
373
386
|
const target = this._safeAid(aid);
|
|
374
387
|
if (this._currentAid()?.aid !== target)
|
|
375
388
|
throw new ValidationError('ownership upload requires its own identity', { stringCode: 'forbidden' });
|
|
@@ -378,15 +391,44 @@ export class AgentMdManager {
|
|
|
378
391
|
throw new ValidationError('ownership upload requires its original document condition');
|
|
379
392
|
const gatewayUrl = await this._resolveGateway(target);
|
|
380
393
|
const token = await this._uploadAccessToken(target, gatewayUrl);
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
394
|
+
const viaGatewayHost = this._uploadViaGatewayHost && nodeBuiltin('node:http') !== null;
|
|
395
|
+
let url = this._url(target, gatewayUrl);
|
|
396
|
+
if (viaGatewayHost) {
|
|
397
|
+
const parsed = new URL(gatewayUrl);
|
|
398
|
+
const port = parsed.port && parsed.port !== '443' && parsed.port !== '20001' ? `:${parsed.port}` : '';
|
|
399
|
+
url = `${agentMdHttpScheme(gatewayUrl)}://${parsed.hostname}${port}/agent.md`;
|
|
400
|
+
}
|
|
401
|
+
const submit = async (targetUrl) => {
|
|
402
|
+
await guard?.();
|
|
403
|
+
return fetchWithTimeout(targetUrl, {
|
|
404
|
+
method: 'PUT', cache: 'no-store', redirect: 'error', body: content,
|
|
405
|
+
headers: { 'X-AUN-Signature-Format': 'multi-v1', 'Content-Type': 'text/markdown; charset=utf-8', Authorization: `Bearer ${token}`,
|
|
406
|
+
...(viaGatewayHost ? { Host: target } : {}),
|
|
407
|
+
...(condition.if_match ? { 'If-Match': condition.if_match } : { 'If-None-Match': '*' }) },
|
|
408
|
+
});
|
|
409
|
+
};
|
|
410
|
+
let response;
|
|
411
|
+
try {
|
|
412
|
+
response = await submit(url);
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
if (!viaGatewayHost)
|
|
416
|
+
throw error;
|
|
417
|
+
const fallback = nameServiceAgentMdUrl(target, gatewayUrl);
|
|
418
|
+
if (!fallback || fallback === url)
|
|
419
|
+
throw error;
|
|
420
|
+
url = fallback;
|
|
421
|
+
response = await submit(url);
|
|
422
|
+
}
|
|
423
|
+
if (response.status === 404 && !headerValue(response.headers, 'X-AUN-Ownership-Protocol') && headerValue(response.headers, 'X-AUN-Ownership-Status') !== 'not_applicable' && viaGatewayHost) {
|
|
424
|
+
const fallback = nameServiceAgentMdUrl(target, gatewayUrl);
|
|
425
|
+
if (fallback && fallback !== url)
|
|
426
|
+
response = await submit(fallback);
|
|
427
|
+
}
|
|
386
428
|
if (!response.ok) {
|
|
387
429
|
const reason = (await response.text()).trim();
|
|
388
430
|
const code = response.status === 409 || response.status === 412 ? 'conflict' : response.status === 401 || response.status === 403 ? 'forbidden' : response.status === 428 ? 'unsupported_protocol' : response.status >= 500 ? 'unavailable' : 'invalid';
|
|
389
|
-
throw new StateError(`
|
|
431
|
+
throw new StateError(`agent.md upload failed: HTTP ${response.status}${reason ? ` ${reason}` : ''}`, { stringCode: /owner_locked/.test(reason) ? 'owner_locked' : code, retryable: code === 'unavailable' });
|
|
390
432
|
}
|
|
391
433
|
return await this.readOwnershipFresh(target);
|
|
392
434
|
}
|
|
@@ -476,9 +518,30 @@ export class AgentMdManager {
|
|
|
476
518
|
throw new StateError('pending agent.md requires its original document condition', { stringCode: 'persistence_unavailable' });
|
|
477
519
|
const pendingDocument = validateAgentMdDocument(pending.content, { expectedAid: aid, validateOwnership: false });
|
|
478
520
|
const meta = pendingDocument.frontmatter;
|
|
479
|
-
|
|
521
|
+
const priorRelation = this._isLegacyBodyRelation(meta) && pending.relation && Object.keys(pending.relation).length === 4 && ['relation_version', 'lock', 'owner_aid', 'statement'].every((field) => Object.hasOwn(pending.relation, field));
|
|
522
|
+
if (this._isLegacyBodyRelation(meta) && pending.relation?.protocol !== 'legacy' && !priorRelation)
|
|
480
523
|
throw new StateError('legacy ownership pending agent.md requires its original relationship snapshot', { stringCode: 'unsupported_protocol' });
|
|
481
524
|
try {
|
|
525
|
+
if (priorRelation) {
|
|
526
|
+
const relation = pending.relation, statement = parseOwnershipFile(pending.content, 'agent', { expectedSubAid: aid }).statement;
|
|
527
|
+
if (!statement || !this._sameBodyRelation(statement, relation.statement) || statement.relation_version !== relation.relation_version || statement.owner_aid !== relation.owner_aid || !['locked', 'unlocked'].includes(String(relation.lock)) || pending.content_etag !== await AgentMdManager.contentEtag(pending.content))
|
|
528
|
+
throw new StateError('pending original relationship context is corrupt', { stringCode: 'persistence_unavailable' });
|
|
529
|
+
const identity = signer ?? this._currentAid();
|
|
530
|
+
if (!identity || identity.aid !== aid || this._currentAid()?.aid !== aid || this._ownerAid() !== aid)
|
|
531
|
+
throw new StateError('body recovery requires its current subject identity', { stringCode: 'forbidden' });
|
|
532
|
+
await this._verifyBodyUpload(aid, pending.content, identity);
|
|
533
|
+
const remote = await this.readAgentMdFresh(aid);
|
|
534
|
+
if (!remote.exists || !this._sameBodyRelation(this._bodyRelationFields(meta), this._bodyRelationFields(validateAgentMdDocumentForRead(remote.content, { expectedAid: aid, validateOwnership: false }).frontmatter)))
|
|
535
|
+
throw new StateError('pending agent.md relationship material changed', { stringCode: 'conflict' });
|
|
536
|
+
if (remote.etag === pending.content_etag && remote.content === pending.content) {
|
|
537
|
+
await this.saveRecord(aid, { content: pending.content, remote_etag: remote.etag, local_draft_content: '', pending_operation: '', pending_content: '', pending_content_etag: '', pending_error: '', pending_condition: {}, pending_relation: {}, pending_authorization: '' });
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
if (!condition.if_match || remote.etag !== condition.if_match)
|
|
541
|
+
throw new StateError('pending agent.md original document condition changed', { stringCode: 'conflict' });
|
|
542
|
+
await this._uploadPrepared(aid, pending.content, identity, condition);
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
482
545
|
if (pending.relation?.protocol === 'legacy') {
|
|
483
546
|
const relation = pending.relation;
|
|
484
547
|
if (!condition.if_match || condition.if_match !== relation.original_etag || typeof relation.original_content !== 'string' || relation.original_content_etag !== await AgentMdManager.contentEtag(relation.original_content) || pending.content_etag !== await AgentMdManager.contentEtag(pending.content))
|
|
@@ -487,7 +550,7 @@ export class AgentMdManager {
|
|
|
487
550
|
if (!this._isLegacyBodyRelation(original) || !this._sameBodyRelation(this._bodyRelationFields(original), relation.fields))
|
|
488
551
|
throw new StateError('pending legacy original relationship snapshot is corrupt', { stringCode: 'persistence_unavailable' });
|
|
489
552
|
if (!this._sameBodyRelation(this._bodyRelationFields(meta), relation.fields))
|
|
490
|
-
throw new StateError('legacy relationship
|
|
553
|
+
throw new StateError('legacy relationship material changed', { stringCode: 'conflict' });
|
|
491
554
|
const identity = signer ?? this._currentAid();
|
|
492
555
|
if (!identity || identity.aid.toLowerCase() !== aid.toLowerCase() || this._currentAid()?.aid.toLowerCase() !== aid.toLowerCase())
|
|
493
556
|
throw new StateError('legacy body recovery requires its current subject identity', { stringCode: 'forbidden' });
|
|
@@ -533,26 +596,11 @@ export class AgentMdManager {
|
|
|
533
596
|
throw new StateError('pending agent.md requires a signer identity');
|
|
534
597
|
await this._verifyBodyUpload(aid, pending.content, identity);
|
|
535
598
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
if (candidate.statement && !relation)
|
|
542
|
-
throw fail('persistence_unavailable', 'pending ownership body update requires its original relationship context');
|
|
543
|
-
if (relation) {
|
|
544
|
-
if (remote.relation_version !== relation.relation_version || remote.lock !== relation.lock)
|
|
545
|
-
throw fail('conflict', 'pending agent.md original relationship changed');
|
|
546
|
-
if (!sameStatement(candidate.statement, relation.statement))
|
|
547
|
-
throw fail('unsupported_protocol', 'ownership changes require their persisted 2.1 task');
|
|
548
|
-
if (remote.exists && (remote.relation_version > 0 || candidate.statement)) {
|
|
549
|
-
const current = parseOwnershipFile(remote.content, 'agent', { expectedSubAid: aid });
|
|
550
|
-
if (!sameStatement(current.statement, relation.statement) || (remote.owner_aid ?? current.statement?.owner_aid ?? null) !== relation.owner_aid)
|
|
551
|
-
throw fail('conflict', 'pending agent.md relationship statement changed');
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
if (!relation && (remote.relation_version !== 0 || remote.lock !== 'unlocked'))
|
|
555
|
-
throw fail('unavailable', 'pending agent.md cannot overwrite relationship history', true);
|
|
599
|
+
if (pending.content_etag !== await AgentMdManager.contentEtag(pending.content))
|
|
600
|
+
throw new StateError('pending agent.md original bytes are corrupt', { stringCode: 'persistence_unavailable' });
|
|
601
|
+
const remote = await this.readAgentMdFresh(aid);
|
|
602
|
+
if (remote.exists && this._isLegacyBodyRelation(validateAgentMdDocumentForRead(remote.content, { expectedAid: aid, validateOwnership: false }).frontmatter))
|
|
603
|
+
throw new StateError('legacy relationship material cannot be removed or replaced', { stringCode: 'conflict' });
|
|
556
604
|
if (remote.exists && remote.etag === pending.content_etag && remote.content === pending.content) {
|
|
557
605
|
const saved = await this.saveRecord(aid, { content: pending.content, remote_etag: remote.etag, local_draft_content: '', pending_operation: '', pending_content: '', pending_content_etag: '', pending_error: '', pending_condition: {}, pending_relation: {}, pending_authorization: '' });
|
|
558
606
|
if (!saved.aid)
|
|
@@ -580,12 +628,7 @@ export class AgentMdManager {
|
|
|
580
628
|
_isLegacyBodyRelation(meta) {
|
|
581
629
|
if (['group', 'org'].includes(String(meta.type)))
|
|
582
630
|
return false;
|
|
583
|
-
|
|
584
|
-
const ownership = meta.ownership;
|
|
585
|
-
const statement = isJsonObject(ownership) ? ownership.statement : undefined;
|
|
586
|
-
return isJsonObject(statement) && statement.version === 2 && !Object.hasOwn(statement, 'relation_version');
|
|
587
|
-
}
|
|
588
|
-
return ['owner', 'ownership_proof', 'ownership_release'].some((field) => Object.hasOwn(meta, field));
|
|
631
|
+
return ['owner', 'ownership', 'ownership_proof', 'ownership_release'].some((field) => Object.hasOwn(meta, field));
|
|
589
632
|
}
|
|
590
633
|
_bodyRelationFields(meta) {
|
|
591
634
|
return Object.fromEntries(['owner', 'ownership', 'ownership_proof', 'ownership_release'].filter((field) => Object.hasOwn(meta, field)).map((field) => [field, meta[field]]));
|
|
@@ -594,14 +637,32 @@ export class AgentMdManager {
|
|
|
594
637
|
const stable = (value) => Array.isArray(value) ? value.map(stable) : isJsonObject(value) ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])])) : value;
|
|
595
638
|
return JSON.stringify(stable(first)) === JSON.stringify(stable(second));
|
|
596
639
|
}
|
|
597
|
-
async
|
|
640
|
+
async readAgentMdFresh(aid) {
|
|
641
|
+
const target = this._safeAid(aid);
|
|
598
642
|
const gateway = await this._resolveGateway(target);
|
|
599
|
-
const
|
|
643
|
+
const viaGatewayHost = this._uploadViaGatewayHost && nodeBuiltin('node:http') !== null;
|
|
644
|
+
const headers = { 'X-AUN-Signature-Format': 'multi-v1', Accept: 'text/markdown', 'Cache-Control': 'no-cache', ...(viaGatewayHost ? { Host: target } : {}) };
|
|
645
|
+
let url = this._url(target, gateway);
|
|
646
|
+
if (viaGatewayHost) {
|
|
647
|
+
const parsed = new URL(gateway);
|
|
648
|
+
const port = parsed.port && parsed.port !== '443' && parsed.port !== '20001' ? `:${parsed.port}` : '';
|
|
649
|
+
url = `${agentMdHttpScheme(gateway)}://${parsed.hostname}${port}/agent.md`;
|
|
650
|
+
}
|
|
651
|
+
let response;
|
|
652
|
+
try {
|
|
653
|
+
response = await fetchWithTimeout(url, { method: 'GET', headers, cache: 'no-store', redirect: 'error' });
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
const fallback = viaGatewayHost ? nameServiceAgentMdUrl(target, gateway) : '';
|
|
657
|
+
if (!fallback || fallback === url)
|
|
658
|
+
throw error;
|
|
659
|
+
response = await fetchWithTimeout(fallback, { method: 'GET', headers, cache: 'no-store', redirect: 'error' });
|
|
660
|
+
}
|
|
600
661
|
if (response.status === 404)
|
|
601
|
-
|
|
662
|
+
return { exists: false, content: '', etag: '', last_modified: '', status: 404 };
|
|
602
663
|
const etag = headerValue(response.headers, 'ETag');
|
|
603
664
|
if (response.status !== 200 || !etag)
|
|
604
|
-
throw new StateError('
|
|
665
|
+
throw new StateError('agent.md original document or ETag is unavailable', { stringCode: 'unavailable', retryable: true });
|
|
605
666
|
let content;
|
|
606
667
|
try {
|
|
607
668
|
content = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(await response.arrayBuffer());
|
|
@@ -609,7 +670,13 @@ export class AgentMdManager {
|
|
|
609
670
|
catch {
|
|
610
671
|
throw new ValidationError('agent.md must be valid UTF-8', { stringCode: 'invalid' });
|
|
611
672
|
}
|
|
612
|
-
return { content, etag, last_modified: headerValue(response.headers, 'Last-Modified'), status:
|
|
673
|
+
return { exists: true, content, etag, last_modified: headerValue(response.headers, 'Last-Modified'), status: 200 };
|
|
674
|
+
}
|
|
675
|
+
async _readLegacyBodyFresh(target) {
|
|
676
|
+
const fresh = await this.readAgentMdFresh(target);
|
|
677
|
+
if (!fresh.exists)
|
|
678
|
+
throw new StateError('legacy relationship cannot be created by an ordinary body update', { stringCode: 'unsupported_protocol' });
|
|
679
|
+
return fresh;
|
|
613
680
|
}
|
|
614
681
|
async _verifyLegacyBodyOriginal(target, content) {
|
|
615
682
|
const parsed = validateAgentMdDocumentForRead(content, { expectedAid: target, validateOwnership: false, requireSignature: true });
|
|
@@ -658,30 +725,21 @@ export class AgentMdManager {
|
|
|
658
725
|
if (entity)
|
|
659
726
|
await this._verifyEntityDocument(target, signed);
|
|
660
727
|
let condition = originalCondition;
|
|
661
|
-
|
|
728
|
+
const pendingRelation = originalCondition ? (await this.pendingUpload(target))?.relation : undefined;
|
|
729
|
+
let relation = entityContext ?? (pendingRelation?.protocol === 'legacy' ? pendingRelation : {});
|
|
662
730
|
if (!condition) {
|
|
663
731
|
let fresh;
|
|
664
732
|
if (!entity && this._isLegacyBodyRelation(meta))
|
|
665
733
|
fresh = await this._readLegacyBodyFresh(target);
|
|
666
|
-
else
|
|
667
|
-
|
|
668
|
-
fresh = entity ? await this._readEntityFresh(target) : await this.readOwnershipFresh(target);
|
|
669
|
-
}
|
|
670
|
-
catch (error) {
|
|
671
|
-
if (entity || !['unavailable', 'unsupported_protocol'].includes(String(error?.stringCode)))
|
|
672
|
-
throw error;
|
|
673
|
-
const legacy = await this._readLegacyBodyFresh(target);
|
|
674
|
-
const legacyMeta = validateAgentMdDocumentForRead(legacy.content, { expectedAid: target, validateOwnership: false }).frontmatter;
|
|
675
|
-
if (!this._isLegacyBodyRelation(legacyMeta))
|
|
676
|
-
throw error;
|
|
677
|
-
fresh = legacy;
|
|
678
|
-
}
|
|
679
|
-
}
|
|
734
|
+
else
|
|
735
|
+
fresh = entity ? await this._readEntityFresh(target) : await this.readAgentMdFresh(target);
|
|
680
736
|
const freshMeta = !entity && (!('exists' in fresh) || fresh.exists) && fresh.content ? validateAgentMdDocumentForRead(fresh.content, { expectedAid: target, validateOwnership: false }).frontmatter : undefined;
|
|
681
737
|
const legacy = !entity && (this._isLegacyBodyRelation(meta) || freshMeta && this._isLegacyBodyRelation(freshMeta));
|
|
682
738
|
if (legacy) {
|
|
683
|
-
if (!freshMeta || !this._isLegacyBodyRelation(freshMeta)
|
|
739
|
+
if (!freshMeta || !this._isLegacyBodyRelation(freshMeta))
|
|
684
740
|
throw new StateError('legacy relationship changes require their original protocol', { stringCode: 'unsupported_protocol' });
|
|
741
|
+
if (!this._sameBodyRelation(this._bodyRelationFields(meta), this._bodyRelationFields(freshMeta)))
|
|
742
|
+
throw new StateError('legacy relationship material changed', { stringCode: 'conflict' });
|
|
685
743
|
if (!fresh.etag)
|
|
686
744
|
throw new StateError('legacy original document ETag is unavailable', { stringCode: 'unavailable', retryable: true });
|
|
687
745
|
await this._verifyLegacyBodyOriginal(target, fresh.content);
|
|
@@ -689,20 +747,14 @@ export class AgentMdManager {
|
|
|
689
747
|
relation = { protocol: 'legacy', original_content: fresh.content, original_content_etag: await AgentMdManager.contentEtag(fresh.content), original_etag: fresh.etag, fields: this._bodyRelationFields(freshMeta) };
|
|
690
748
|
}
|
|
691
749
|
else {
|
|
692
|
-
|
|
693
|
-
condition = authority.exists ? { if_match: fresh.etag } : { if_none_match: '*' };
|
|
694
|
-
if (!entity) {
|
|
695
|
-
const candidate = parseOwnershipFile(signed, 'agent', { expectedSubAid: target });
|
|
696
|
-
const statement = authority.exists && (authority.relation_version > 0 || candidate.statement) ? parseOwnershipFile(fresh.content, 'agent', { expectedSubAid: target }).statement : undefined;
|
|
697
|
-
relation = { relation_version: authority.relation_version, lock: authority.lock, owner_aid: authority.owner_aid ?? statement?.owner_aid ?? null, statement: statement ?? null };
|
|
698
|
-
}
|
|
750
|
+
condition = 'exists' in fresh && fresh.exists ? { if_match: fresh.etag } : { if_none_match: '*' };
|
|
699
751
|
}
|
|
700
752
|
}
|
|
701
753
|
if (relation?.protocol === 'legacy') {
|
|
702
754
|
if (signer.aid.toLowerCase() !== target.toLowerCase() || this._currentAid()?.aid.toLowerCase() !== target.toLowerCase() || this._currentAid()?.certFingerprint !== signer.certFingerprint)
|
|
703
755
|
throw new StateError('legacy body update requires its current subject identity', { stringCode: 'forbidden' });
|
|
704
756
|
if (!this._isLegacyBodyRelation(meta) || !this._sameBodyRelation(this._bodyRelationFields(meta), relation.fields))
|
|
705
|
-
throw new StateError('legacy relationship
|
|
757
|
+
throw new StateError('legacy relationship material changed', { stringCode: 'conflict' });
|
|
706
758
|
await this._verifyBodyUpload(target, signed, signer);
|
|
707
759
|
}
|
|
708
760
|
const entityAuthorization = '';
|
|
@@ -718,7 +770,7 @@ export class AgentMdManager {
|
|
|
718
770
|
if (delegated && !owner?.isPrivateKeyValid())
|
|
719
771
|
throw new StateError('owner agent.md upload requires a loaded owner identity');
|
|
720
772
|
const authorization = entity ? '' : delegated ? await this._ownerUploadAuthorization(target, signed, owner) : '';
|
|
721
|
-
const result = await this._uploadHttp(target, signed, authorization, condition
|
|
773
|
+
const result = await this._uploadHttp(target, signed, authorization, condition);
|
|
722
774
|
const remoteEtag = String(result.etag ?? '').trim();
|
|
723
775
|
const contentEtag = await AgentMdManager.contentEtag(signed);
|
|
724
776
|
const saved = await this.saveRecord(target, {
|
|
@@ -927,6 +979,7 @@ export class AgentMdManager {
|
|
|
927
979
|
return {
|
|
928
980
|
aid: target,
|
|
929
981
|
content: contentResult.content,
|
|
982
|
+
frontmatter: readAgentMdFrontmatter(contentResult.content),
|
|
930
983
|
verification,
|
|
931
984
|
signature,
|
|
932
985
|
cert_pem: peer.certPem,
|
|
@@ -1127,6 +1180,31 @@ export class AgentMdManager {
|
|
|
1127
1180
|
const root = this.root;
|
|
1128
1181
|
return await this._readStorage(this._contentKey(aid), root);
|
|
1129
1182
|
}
|
|
1183
|
+
async ownType() {
|
|
1184
|
+
try {
|
|
1185
|
+
const target = this._ownerAid();
|
|
1186
|
+
const current = this._currentAid();
|
|
1187
|
+
if (!target || !current?.isCertValid() || current.aid.toLowerCase() !== target.toLowerCase())
|
|
1188
|
+
return '';
|
|
1189
|
+
const record = await this.loadRecord(target);
|
|
1190
|
+
const content = String(record?.local_draft_content ?? '') || String(record?.content ?? '') || await this.readContent(target) || '';
|
|
1191
|
+
if (!content)
|
|
1192
|
+
return '';
|
|
1193
|
+
const parsed = validateAgentMdDocumentForRead(content, { expectedAid: target, validateOwnership: false, requireSignature: true });
|
|
1194
|
+
const type = parseFileFrontmatter(parsed.payload, false, false).type;
|
|
1195
|
+
if (typeof type !== 'string' || !type.trim())
|
|
1196
|
+
return '';
|
|
1197
|
+
const verified = await current.verifyAgentMd(content, async (signer, fingerprint) => {
|
|
1198
|
+
if (signer.toLowerCase() === current.aid.toLowerCase() && await certMatchesFingerprint(current.certPem, fingerprint))
|
|
1199
|
+
return current;
|
|
1200
|
+
throw new StateError('自身 agent.md 签名证书不在本地可信身份中');
|
|
1201
|
+
});
|
|
1202
|
+
return verified.ok && verified.data.status === 'verified' ? type.trim() : '';
|
|
1203
|
+
}
|
|
1204
|
+
catch {
|
|
1205
|
+
return '';
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1130
1208
|
async writeContent(aid, content) {
|
|
1131
1209
|
const root = this.root;
|
|
1132
1210
|
await this._writeStorage(this._contentKey(aid), String(content ?? ''), root);
|
|
@@ -1333,7 +1411,7 @@ export class AgentMdManager {
|
|
|
1333
1411
|
_url(aid, gatewayUrl) {
|
|
1334
1412
|
return `${agentMdHttpScheme(gatewayUrl)}://${this._safeAid(aid)}/agent.md`;
|
|
1335
1413
|
}
|
|
1336
|
-
async _uploadHttp(aid, content, ownerAuthorization = '', condition
|
|
1414
|
+
async _uploadHttp(aid, content, ownerAuthorization = '', condition) {
|
|
1337
1415
|
if (!condition || Object.keys(condition).length !== 1 || !(typeof condition.if_match === 'string' && condition.if_match || condition.if_none_match === '*'))
|
|
1338
1416
|
throw new StateError('agent.md upload requires its original document condition', { stringCode: 'persistence_unavailable' });
|
|
1339
1417
|
const gatewayUrl = await this._resolveGateway(aid);
|
|
@@ -1344,7 +1422,6 @@ export class AgentMdManager {
|
|
|
1344
1422
|
const viaGatewayHost = this._uploadViaGatewayHost && nodeBuiltin('node:http') !== null;
|
|
1345
1423
|
const headers = { 'X-AUN-Signature-Format': 'multi-v1',
|
|
1346
1424
|
'Content-Type': 'text/markdown; charset=utf-8',
|
|
1347
|
-
...(!entity && !(legacyBodyUpdate && this._isLegacyBodyRelation(meta)) ? { 'X-AUN-Ownership-Check': '1' } : {}),
|
|
1348
1425
|
...(condition.if_match ? { 'If-Match': condition.if_match } : { 'If-None-Match': '*' }),
|
|
1349
1426
|
...(viaGatewayHost ? { Host: this._safeAid(aid) } : {}),
|
|
1350
1427
|
...(!entity && authorization ? { 'X-AUN-AgentMD-Owner-Authorization': authorization } : {}),
|