@agentunion/fastaun 0.5.26 → 0.5.27
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 +41 -0
- package/_packed_docs/CHANGELOG.md +41 -0
- package/_packed_docs/INDEX.md +22 -14
- package/_packed_docs/KITE_DOCS_GUIDE.md +11 -6
- 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 +16 -1
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +37 -9
- package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +20 -9
- package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +57 -12
- package/_packed_docs/cli//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241CLI/345/274/200/345/217/221/344/270/216/344/275/277/347/224/250/346/214/207/345/215/227.md +869 -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 +2 -2
- package/_packed_docs/sdk/0.5.27-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +408 -0
- package/_packed_docs/sdk/0.5.27-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +410 -0
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +2 -2
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +187 -73
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +1 -1
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -9
- package/_packed_docs/sdk/INDEX.md +21 -13
- 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 +973 -266
- 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 +950 -242
- package/dist/agent-md-schema.js +1 -1
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.js +5 -0
- package/dist/agent-md.js.map +1 -1
- package/dist/aid.js +3 -3
- package/dist/aid.js.map +1 -1
- package/dist/auth.js +21 -19
- package/dist/auth.js.map +1 -1
- package/dist/cert-utils.d.ts +1 -1
- package/dist/cert-utils.js +4 -4
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/lifecycle.d.ts +1 -1
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.js +8 -1
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.js +7 -0
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +12 -0
- package/dist/client.js +305 -29
- package/dist/client.js.map +1 -1
- package/dist/facades.d.ts +38 -0
- package/dist/facades.js +49 -5
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/org-protocol.d.ts +1 -0
- package/dist/org-protocol.js +39 -36
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.js +7 -7
- package/dist/ownership-v21.js.map +1 -1
- package/dist/register-flow.js +2 -2
- package/dist/register-flow.js.map +1 -1
- package/dist/semantic-facade.d.ts +176 -0
- package/dist/semantic-facade.js +611 -0
- package/dist/semantic-facade.js.map +1 -0
- package/dist/semantic-protocol.d.ts +810 -0
- package/dist/semantic-protocol.js +894 -0
- package/dist/semantic-protocol.js.map +1 -0
- package/dist/tools/cross-sdk-agent.d.ts +11 -1
- package/dist/tools/cross-sdk-agent.js +388 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.js +28 -2
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +5 -0
- package/dist/v2/e2ee/decrypt.js +22 -2
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ import * as https from 'node:https';
|
|
|
4
4
|
import * as crypto from 'node:crypto';
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
6
|
import * as path from 'node:path';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
7
8
|
import { tmpdir } from 'node:os';
|
|
8
9
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
9
10
|
import { URL } from 'node:url';
|
|
@@ -11,13 +12,38 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
12
|
import { AUNClient } from '../client.js';
|
|
12
13
|
import { AID } from '../aid.js';
|
|
13
14
|
import { AIDStore } from '../aid-store.js';
|
|
14
|
-
import { publicKeyFingerprint } from '../cert-utils.js';
|
|
15
|
+
import { certCommonName, certFingerprint, isStrictBase64, publicKeyFingerprint, verifySignatureWithCert } from '../cert-utils.js';
|
|
16
|
+
import { validateAgentMdCertificate } from '../agent-md-schema.js';
|
|
17
|
+
import { createDefaultSecretStore } from '../secret-store/index.js';
|
|
18
|
+
import { normalizeGroupId } from '../group-id.js';
|
|
19
|
+
import { validateAIDFormat } from '../validators.js';
|
|
15
20
|
import { VERSION } from '../version.js';
|
|
16
21
|
import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
|
|
22
|
+
import { decodeBase64 as semanticBase64, decodeSignedJson, digest as semanticDigest, validateStatusProof, SemanticProtocolError } from '../semantic-protocol.js';
|
|
17
23
|
import { TimeoutError } from '../errors.js';
|
|
18
24
|
const credentialProcessStartupId = crypto.randomUUID();
|
|
25
|
+
const { DatabaseSync } = createRequire(import.meta.url)('node:sqlite');
|
|
19
26
|
const cacheReadContext = new AsyncLocalStorage();
|
|
20
27
|
const cacheReadObservers = new WeakMap();
|
|
28
|
+
function loadTrustedArchive(configPath, issuer) {
|
|
29
|
+
if (!configPath)
|
|
30
|
+
return undefined;
|
|
31
|
+
const value = jsonObjectOf(JSON.parse(fs.readFileSync(configPath, 'utf8')));
|
|
32
|
+
const owner = value?.owner_aid, routed = typeof owner === 'string' && owner.indexOf('.') > 0 && owner.indexOf('.') < owner.length - 1;
|
|
33
|
+
if (!value || Object.keys(value).some(key => !['service_aid', 'objects', 'owner_aid'].includes(key)) || Object.keys(value).length !== (routed ? 3 : 2) || ('owner_aid' in value && !routed) || value.service_aid !== `storage.${routed ? owner.slice(owner.indexOf('.') + 1) : issuer}` || !Array.isArray(value.objects))
|
|
34
|
+
throw new Error('ARCHIVE_SERVICE_UNTRUSTED');
|
|
35
|
+
const objects = new Map();
|
|
36
|
+
for (const row of value.objects) {
|
|
37
|
+
const item = jsonObjectOf(row);
|
|
38
|
+
if (!item || Object.keys(item).length !== 3 || !['object_id', 'object_version', 'share_id'].every(key => typeof item[key] === 'string' && item[key]))
|
|
39
|
+
throw new Error('ARCHIVE_OBJECT_UNTRUSTED');
|
|
40
|
+
const key = JSON.stringify([item.object_id, item.object_version]);
|
|
41
|
+
if (objects.has(key))
|
|
42
|
+
throw new Error('ARCHIVE_OBJECT_DUPLICATE');
|
|
43
|
+
objects.set(key, item.share_id);
|
|
44
|
+
}
|
|
45
|
+
return { serviceAid: value.service_aid, ...(routed ? { ownerAid: owner } : {}), objects };
|
|
46
|
+
}
|
|
21
47
|
function acquireCacheReadObserver(target, key, wrap) {
|
|
22
48
|
let observers = cacheReadObservers.get(target);
|
|
23
49
|
if (!observers) {
|
|
@@ -147,6 +173,10 @@ export class CrossSdkTsAgent {
|
|
|
147
173
|
slotId = textOf(process.env.AUN_TEST_SLOT_ID || `cross-sdk-ts-${crypto.randomUUID().slice(0, 8)}`).trim();
|
|
148
174
|
aunPath = textOf(process.env.AUN_TEST_AUN_PATH || process.env.AUN_DATA_ROOT || '/data/aun').trim();
|
|
149
175
|
debug = envBool('AUN_TEST_DEBUG', false);
|
|
176
|
+
semanticReaderIdentityDir = textOf(process.env.AUN_SEMANTIC_READER_IDENTITY_DIR).trim();
|
|
177
|
+
semanticReaderAid = textOf(process.env.AUN_SEMANTIC_READER_AID).trim();
|
|
178
|
+
semanticReaderSeed = process.env.AUN_TEST_ENCRYPTION_SEED || process.env.AUN_ENCRYPTION_SEED || '';
|
|
179
|
+
semanticArchive = loadTrustedArchive(textOf(process.env.AUN_TEST_SEMANTIC_ARCHIVE_CONFIG), this.issuer);
|
|
150
180
|
client;
|
|
151
181
|
ready = false;
|
|
152
182
|
startupError = '';
|
|
@@ -740,7 +770,10 @@ export class CrossSdkTsAgent {
|
|
|
740
770
|
const identity = JSON.parse(fs.readFileSync(fixedIdentityFile, 'utf-8'));
|
|
741
771
|
if (identity.aid !== this.aid)
|
|
742
772
|
throw new Error('固定测试身份与配置 AID 不一致');
|
|
743
|
-
store.
|
|
773
|
+
const local = store.load(this.aid);
|
|
774
|
+
if (!local.ok || !local.data.aid.isPrivateKeyValid()) {
|
|
775
|
+
store._keystore.saveIdentity(this.aid, identity);
|
|
776
|
+
}
|
|
744
777
|
}
|
|
745
778
|
const registered = fixedIdentityFile ? store.load(this.aid) : await store.register(this.aid, { type: 'service' });
|
|
746
779
|
if (!registered.ok) {
|
|
@@ -913,6 +946,7 @@ export class CrossSdkTsAgent {
|
|
|
913
946
|
error_code: errorCode,
|
|
914
947
|
raw_sha256: sha256Json(data),
|
|
915
948
|
...metadata,
|
|
949
|
+
...(decrypted && jsonObjectOf(data._semantic_evidence) ? { _semantic_evidence: structuredClone(data._semantic_evidence) } : {}),
|
|
916
950
|
};
|
|
917
951
|
}
|
|
918
952
|
normalizeGroupMessage(msg, decrypted, errorCode = '') {
|
|
@@ -934,6 +968,7 @@ export class CrossSdkTsAgent {
|
|
|
934
968
|
error_code: errorCode,
|
|
935
969
|
raw_sha256: sha256Json(data),
|
|
936
970
|
...metadata,
|
|
971
|
+
...(decrypted && jsonObjectOf(data._semantic_evidence) ? { _semantic_evidence: structuredClone(data._semantic_evidence) } : {}),
|
|
937
972
|
};
|
|
938
973
|
}
|
|
939
974
|
async storeGroupInboxItem(item) {
|
|
@@ -954,6 +989,7 @@ export class CrossSdkTsAgent {
|
|
|
954
989
|
aid: this.aid,
|
|
955
990
|
language: this.language,
|
|
956
991
|
sdk_version: this.sdkVersion,
|
|
992
|
+
gateway_url: textOf(this.client._gatewayUrl),
|
|
957
993
|
startup_error: this.startupError,
|
|
958
994
|
});
|
|
959
995
|
return;
|
|
@@ -1775,8 +1811,11 @@ export class CrossSdkTsAgent {
|
|
|
1775
1811
|
return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
|
|
1776
1812
|
if (op === 'revocation_checkpoint') {
|
|
1777
1813
|
const internal = this.client;
|
|
1778
|
-
if (params.sync === true)
|
|
1779
|
-
|
|
1814
|
+
if (params.sync === true) {
|
|
1815
|
+
const manager = internal._getCredentialRenewal();
|
|
1816
|
+
manager.invalidateQueries();
|
|
1817
|
+
await manager._syncRevocations();
|
|
1818
|
+
}
|
|
1780
1819
|
return internal._tokenStore._loadMetadataStrict(this.aid)?.credential_revocations_v1 ?? { version: 1, authorities: {} };
|
|
1781
1820
|
}
|
|
1782
1821
|
if (op === 'credential_process')
|
|
@@ -1870,6 +1909,333 @@ export class CrossSdkTsAgent {
|
|
|
1870
1909
|
}
|
|
1871
1910
|
return result;
|
|
1872
1911
|
}
|
|
1912
|
+
semanticReaderMessageContext() {
|
|
1913
|
+
const root = this.semanticReaderIdentityDir, aid = this.semanticReaderAid;
|
|
1914
|
+
if (!root && !aid)
|
|
1915
|
+
return {};
|
|
1916
|
+
if (!root || !aid || validateAIDFormat(aid) !== aid || !fs.statSync(root).isDirectory())
|
|
1917
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'fixed semantic reader identity is unavailable');
|
|
1918
|
+
const device = fs.readFileSync(path.join(root, '.device_id'), 'utf8').trim(), directory = path.join(root, 'AIDs', aid);
|
|
1919
|
+
if (!device)
|
|
1920
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver device is unavailable');
|
|
1921
|
+
const stored = JSON.parse(fs.readFileSync(path.join(directory, 'private', 'key.json'), 'utf8'));
|
|
1922
|
+
const pem = stored.private_key_pem || (stored.private_key_protection && createDefaultSecretStore(root, this.semanticReaderSeed).reveal(aid, 'identity/private_key', stored.private_key_protection)?.toString('utf8'));
|
|
1923
|
+
if (!pem)
|
|
1924
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver identity key is unavailable');
|
|
1925
|
+
const privateKey = crypto.createPrivateKey(pem), publicKey = crypto.createPublicKey(privateKey).export({ format: 'der', type: 'spki' });
|
|
1926
|
+
const certPem = fs.readFileSync(path.join(directory, 'public', 'cert.pem'), 'utf8'), certificate = new crypto.X509Certificate(certPem);
|
|
1927
|
+
const jwk = privateKey.export({ format: 'jwk' });
|
|
1928
|
+
if (certCommonName(certPem) !== aid || jwk.kty !== 'EC' || jwk.crv !== 'P-256' || !jwk.d
|
|
1929
|
+
|| !publicKey.equals(certificate.publicKey.export({ format: 'der', type: 'spki' })))
|
|
1930
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver certificate or key differs');
|
|
1931
|
+
const ikPriv = new Uint8Array(Buffer.from(jwk.d, 'base64url'));
|
|
1932
|
+
return { selfAid: aid, selfDeviceId: device, resolveDecryptionKeys: (envelope) => {
|
|
1933
|
+
const row = Array.isArray(envelope.recipients) ? envelope.recipients.find((item) => Array.isArray(item) && item.length === 8 && item[0] === aid && (item[1] === device || item[1] === '')) : undefined;
|
|
1934
|
+
const recipient = jsonObjectOf(envelope.recipient);
|
|
1935
|
+
if (!row && (!recipient || recipient.aid !== aid || recipient.device_id !== device && recipient.device_id !== ''))
|
|
1936
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original receiver row is unavailable');
|
|
1937
|
+
let spkId = textOf(row ? row[5] : recipient.spk_id), groupId = envelope.type === 'e2ee.group_encrypted' ? textOf(envelope.aad?.group_id) : '';
|
|
1938
|
+
if (!spkId)
|
|
1939
|
+
return { ikPriv };
|
|
1940
|
+
const separator = spkId.indexOf('\0');
|
|
1941
|
+
if (separator >= 0) {
|
|
1942
|
+
if (!groupId || normalizeGroupId(spkId.slice(0, separator)) !== normalizeGroupId(groupId))
|
|
1943
|
+
throw new SemanticProtocolError('SEMANTIC_BINDING_INVALID', 'original group SPK scope differs');
|
|
1944
|
+
spkId = spkId.slice(separator + 1);
|
|
1945
|
+
}
|
|
1946
|
+
const db = new DatabaseSync(path.join(directory, 'aun.db'), { readOnly: true });
|
|
1947
|
+
try {
|
|
1948
|
+
const find = (type, group) => db.prepare('SELECT private_key FROM v2_device_keys WHERE device_id=? AND key_type=? AND group_id=? AND key_id=?').get(device, type, group, spkId);
|
|
1949
|
+
let key;
|
|
1950
|
+
if (groupId)
|
|
1951
|
+
for (const candidate of new Set([groupId, normalizeGroupId(groupId)])) {
|
|
1952
|
+
key = find('group_spk', candidate);
|
|
1953
|
+
if (key)
|
|
1954
|
+
break;
|
|
1955
|
+
}
|
|
1956
|
+
key ??= find('spk', '');
|
|
1957
|
+
if (key)
|
|
1958
|
+
return { ikPriv, spkPriv: new Uint8Array(key.private_key) };
|
|
1959
|
+
const alias = find('ik', '');
|
|
1960
|
+
if (alias)
|
|
1961
|
+
return { ikPriv: new Uint8Array(alias.private_key), spkPriv: new Uint8Array(alias.private_key) };
|
|
1962
|
+
if (spkId === 'sha256:' + crypto.createHash('sha256').update(publicKey).digest('hex').slice(0, 16))
|
|
1963
|
+
return { ikPriv, spkPriv: ikPriv };
|
|
1964
|
+
throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'original receiver SPK is unavailable');
|
|
1965
|
+
}
|
|
1966
|
+
finally {
|
|
1967
|
+
db.close();
|
|
1968
|
+
}
|
|
1969
|
+
} };
|
|
1970
|
+
}
|
|
1971
|
+
semanticHistoricalSenderContext(context) {
|
|
1972
|
+
const certificates = jsonObjectOf(context.certificates);
|
|
1973
|
+
if (!certificates || Object.keys(certificates).length === 0)
|
|
1974
|
+
return {};
|
|
1975
|
+
const key = (fingerprint) => new crypto.X509Certificate(textOf(certificates[fingerprint])).publicKey.export({ type: 'spki', format: 'der' });
|
|
1976
|
+
return {
|
|
1977
|
+
resolveSenderKey: async (_sender, _device, fingerprint) => new Uint8Array(key(fingerprint)),
|
|
1978
|
+
verifySenderIdentity: async (sender, _device, fingerprint, signedAt, publicKey) => {
|
|
1979
|
+
if (!key(fingerprint).equals(Buffer.from(publicKey)))
|
|
1980
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'historical sender identity differs from message key');
|
|
1981
|
+
await this.client._semanticVerificationContext().verifyCertificateTrust(textOf(certificates[fingerprint]), { expectedAID: sender, signedAt, now: Math.floor(Date.now() / 1000) });
|
|
1982
|
+
},
|
|
1983
|
+
};
|
|
1984
|
+
}
|
|
1985
|
+
semanticContext(context, nativeOnline = false, original) {
|
|
1986
|
+
if (!nativeOnline && (['query', 'queries', 'query_started_monotonic', 'elapsed_seconds', 'elapsedSeconds', 'monotonicNow'].some(key => Object.hasOwn(context, key))
|
|
1987
|
+
|| context.policy !== undefined && jsonObjectOf(context.policy)?.mode !== 'bounded') || context.require_current_validity === false || context.legacy_context !== undefined) {
|
|
1988
|
+
throw new SemanticProtocolError('SEMANTIC_FORMAT_INVALID', 'unsupported cross-process semantic verification context override');
|
|
1989
|
+
}
|
|
1990
|
+
const native = this.client._semanticVerificationContext();
|
|
1991
|
+
const certificates = jsonObjectOf(context.certificates) ?? {};
|
|
1992
|
+
const signers = jsonObjectOf(context.credential_signers);
|
|
1993
|
+
const services = jsonObjectOf(context.credential_services);
|
|
1994
|
+
const supplied = jsonObjectOf(original), credential = supplied && Object.hasOwn(supplied, 'bytes_base64') ? jsonObjectOf(decodeSignedJson(supplied)) : supplied;
|
|
1995
|
+
const signer = credential && signers ? textOf(signers[semanticDigest(credential)]) : '';
|
|
1996
|
+
const expectedAid = textOf(context.expected_aid);
|
|
1997
|
+
if (signer && expectedAid && signer !== expectedAid)
|
|
1998
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'explicit signer differs from trusted original signer');
|
|
1999
|
+
return { ...native, now: typeof context.now === 'number' ? context.now : Math.floor(Date.now() / 1000),
|
|
2000
|
+
expectedAid: expectedAid || signer || textOf(credential?.iss) || undefined, expectedServiceAid: textOf(context.service_aid) || undefined,
|
|
2001
|
+
audience: textOf(context.audience), statePolicy: context.policy,
|
|
2002
|
+
resolveCertificate: async (fingerprint, aid, signedAt) => Object.hasOwn(certificates, fingerprint)
|
|
2003
|
+
? certificates[fingerprint] : native.resolveCertificate(fingerprint, aid, signedAt),
|
|
2004
|
+
...(signers ? { originalSigner: (entry) => {
|
|
2005
|
+
const signer = textOf(signers[semanticDigest(entry.credential)]) || entry.credential.iss;
|
|
2006
|
+
if (!signer)
|
|
2007
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted original signer is required');
|
|
2008
|
+
return signer;
|
|
2009
|
+
} } : {}),
|
|
2010
|
+
...(services ? { serviceFor: (cid) => {
|
|
2011
|
+
const service = Object.hasOwn(services, cid) ? textOf(services[cid]) : '';
|
|
2012
|
+
if (!service)
|
|
2013
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted credential service is required');
|
|
2014
|
+
return service;
|
|
2015
|
+
} } : {}),
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
trustedArchiveResolvers() {
|
|
2019
|
+
const config = this.semanticArchive;
|
|
2020
|
+
if (!config)
|
|
2021
|
+
return {};
|
|
2022
|
+
return { [config.serviceAid]: async (locator) => {
|
|
2023
|
+
if (Object.keys(locator).length !== 4 || locator.resolver !== 'aun-evidence-archive/1' || locator.service_aid !== config.serviceAid)
|
|
2024
|
+
throw new Error('ARCHIVE_LOCATOR_UNTRUSTED');
|
|
2025
|
+
const share = config.objects.get(JSON.stringify([locator.object_id, locator.object_version]));
|
|
2026
|
+
if (!share)
|
|
2027
|
+
throw new Error('ARCHIVE_OBJECT_UNTRUSTED');
|
|
2028
|
+
const result = jsonObjectOf(await this.client.call('storage.get_by_share', { share_id: share, ...(config.ownerAid ? { owner_aid: config.ownerAid } : {}) }));
|
|
2029
|
+
if (!result || result.object_id !== locator.object_id || String(result.version) !== locator.object_version)
|
|
2030
|
+
throw new Error('ARCHIVE_OBJECT_VERSION_MISMATCH');
|
|
2031
|
+
const content = result.content;
|
|
2032
|
+
if (typeof content !== 'string' || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(content)
|
|
2033
|
+
|| Buffer.from(content, 'base64').toString('base64') !== content)
|
|
2034
|
+
throw new Error('ARCHIVE_CONTENT_INVALID');
|
|
2035
|
+
return new Uint8Array(Buffer.from(content, 'base64'));
|
|
2036
|
+
} };
|
|
2037
|
+
}
|
|
2038
|
+
async verifySemanticRepresentative(request, context) {
|
|
2039
|
+
for (const grant of context.representation_grants ?? []) {
|
|
2040
|
+
const root = grant.lineage[0], leaf = grant.lineage.at(-1);
|
|
2041
|
+
if (root.credential.iss !== request.sub || root.metadata.iss !== request.sub || leaf.metadata.sub !== request.actor || !root.credential.cap.some((cap) => cap.ns === request.ns && [request.action, '*'].includes(cap.action) && [request.resource, '*'].includes(cap.resource) && cap.constraints.length === 0)
|
|
2042
|
+
|| root.credential.authorization.kind !== 'text' || root.credential.authorization.text !== '签发者明确授权已确认持有人代表签发者执行所列能力,仅限本次隔离报告测试。')
|
|
2043
|
+
continue;
|
|
2044
|
+
const { params_hash: _paramsHash, request_binding: _binding, ...fixed } = request;
|
|
2045
|
+
const represented = await this.client.credential.buildRequest({ ...fixed, sub: request.actor, grant,
|
|
2046
|
+
request_id: request.request_id + '-representation', nonce: Buffer.from(semanticDigest([request.request_binding.request_hash, 'representation']).slice(7), 'hex').toString('base64url') });
|
|
2047
|
+
const nested = { ...context, representation_grants: undefined, grantors: [request.sub],
|
|
2048
|
+
credential_services: Object.fromEntries(grant.lineage.map((item) => [item.credential.cid, context.representation_service])),
|
|
2049
|
+
credential_signers: Object.fromEntries(grant.lineage.map((item) => [semanticDigest(item.credential), item.metadata.iss])) };
|
|
2050
|
+
const result = await this.semanticProtocol({ op: 'refresh_and_verify_request', params: represented, context: nested });
|
|
2051
|
+
return result.report.request_bound === true;
|
|
2052
|
+
}
|
|
2053
|
+
return false;
|
|
2054
|
+
}
|
|
2055
|
+
async semanticProtocol(params) {
|
|
2056
|
+
if (params.op === 'state_checkpoint')
|
|
2057
|
+
return { startup_id: credentialProcessStartupId, aid: this.aid, scope_identity: this.client._semanticContextKey(), state: this.client._loadSemanticState() };
|
|
2058
|
+
const facade = this.client.credential, op = textOf(params.op);
|
|
2059
|
+
if (op === 'probe_online_status') {
|
|
2060
|
+
const began = performance.now() / 1000, input = jsonObjectOf(params.params) ?? {}, target = textOf(params.target);
|
|
2061
|
+
const query = { request_hash: textOf(params.request_hash), nonce: crypto.randomBytes(24).toString('base64url') };
|
|
2062
|
+
const proof = await facade.status({ ...input, request_id: crypto.randomUUID(), nonce: query.nonce, query }, { serviceAid: target });
|
|
2063
|
+
const expectedQuery = { ...query };
|
|
2064
|
+
if (params.probe === 'nonce')
|
|
2065
|
+
expectedQuery.nonce = 'AAAAAAAAAAAAAAAAAAAAAA';
|
|
2066
|
+
if (params.probe === 'request_hash')
|
|
2067
|
+
expectedQuery.request_hash = `sha256:${'0'.repeat(64)}`;
|
|
2068
|
+
if (params.probe === 'timeout')
|
|
2069
|
+
await new Promise(resolve => setTimeout(resolve, Math.max(0, 30100 - (performance.now() / 1000 - began) * 1000)));
|
|
2070
|
+
const context = this.semanticContext({ service_aid: target, audience: input.audience }, true);
|
|
2071
|
+
const report = await facade.verifyStatus(proof, { ...context, policy: { mode: 'online' },
|
|
2072
|
+
query: params.probe === 'missing_query' ? undefined : expectedQuery, elapsedSeconds: performance.now() / 1000 - began });
|
|
2073
|
+
return { proof, query, report, elapsed_seconds: performance.now() / 1000 - began };
|
|
2074
|
+
}
|
|
2075
|
+
if (op === 'refresh_and_verify_request') {
|
|
2076
|
+
const began = performance.now() / 1000, request = structuredClone(params.params);
|
|
2077
|
+
const input = jsonObjectOf(params.context) ?? {}, context = this.semanticContext({ ...input, now: Math.floor(Date.now() / 1000) }, true);
|
|
2078
|
+
const query = { request_hash: request.request_binding.request_hash, nonce: crypto.randomBytes(24).toString('base64url') };
|
|
2079
|
+
const queries = {};
|
|
2080
|
+
const legacyProofs = new Map(), legacyChecks = [], reader = this.client.aid;
|
|
2081
|
+
const legacyCertificate = async (aid, signature, verifiedAt = Math.floor(Date.now() / 1000)) => {
|
|
2082
|
+
if (!signature || !Number.isSafeInteger(signature.timestamp) || signature.timestamp < 0 || signature.timestamp > Math.floor(Date.now() / 1000) + 300
|
|
2083
|
+
|| typeof signature.cert_fingerprint !== 'string' || !/^sha256:[0-9a-f]{64}$/i.test(signature.cert_fingerprint)
|
|
2084
|
+
|| typeof signature.signature !== 'string' || !isStrictBase64(signature.signature)
|
|
2085
|
+
|| Object.keys(signature).some(key => !['cert_fingerprint', 'public_key_fingerprint', 'timestamp', 'signature'].includes(key)))
|
|
2086
|
+
throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy signature is invalid');
|
|
2087
|
+
const resolved = await context.resolveCertificate(signature.cert_fingerprint, aid, signature.timestamp);
|
|
2088
|
+
const material = resolved && typeof resolved === 'object' && !(resolved instanceof Uint8Array) ? resolved.certificatePem : resolved;
|
|
2089
|
+
if (!material)
|
|
2090
|
+
throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy certificate is unavailable');
|
|
2091
|
+
const certificate = new crypto.X509Certificate(typeof material === 'string' && !material.startsWith('-----BEGIN') ? Buffer.from(material, 'base64') : material).toString();
|
|
2092
|
+
if (certFingerprint(certificate).toLowerCase() !== signature.cert_fingerprint.toLowerCase()
|
|
2093
|
+
|| signature.public_key_fingerprint !== undefined && (typeof signature.public_key_fingerprint !== 'string' || publicKeyFingerprint(certificate).toLowerCase() !== signature.public_key_fingerprint.toLowerCase()))
|
|
2094
|
+
throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'legacy certificate fingerprint differs');
|
|
2095
|
+
validateAgentMdCertificate(certificate, aid, signature.timestamp, { now: verifiedAt, requireCurrentValidity: true });
|
|
2096
|
+
await context.verifyCertificateTrust(certificate, { expectedAID: aid, signedAt: signature.timestamp, now: Math.floor(Date.now() / 1000) });
|
|
2097
|
+
return certificate;
|
|
2098
|
+
};
|
|
2099
|
+
for (const entry of request.grant.lineage) {
|
|
2100
|
+
const cid = entry.credential.cid;
|
|
2101
|
+
if (!context.serviceFor)
|
|
2102
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'trusted credential service is required');
|
|
2103
|
+
const service = context.serviceFor(cid);
|
|
2104
|
+
if (entry.credential.ver === 'aun-cap/1' && 'legacy' in entry) {
|
|
2105
|
+
const original = entry.credential, requestedAt = Math.floor(Date.now() / 1000);
|
|
2106
|
+
const statusQuery = { credential_cid: cid, include_chain: true, request_id: crypto.randomUUID(), nonce: crypto.randomBytes(24).toString('base64url') };
|
|
2107
|
+
statusQuery.request_binding = buildRequestBinding('credential.status', service, statusQuery, cid, String(statusQuery.nonce), String(statusQuery.request_id), requestedAt, requestedAt + 300);
|
|
2108
|
+
const proof = await facade.status(statusQuery), now = Math.floor(Date.now() / 1000);
|
|
2109
|
+
if (!reader || reader !== this.client.aid || !proof || proof.ver !== 'aun-credential-status/1' || proof.credentialCid !== cid || proof.credential_hash !== digest(original)
|
|
2110
|
+
|| proof.issuerAid !== original.iss || proof.subjectAid !== original.sub || proof.expiresAt !== original.exp || proof.responder !== service
|
|
2111
|
+
|| proof.target !== reader || proof.request_id !== statusQuery.request_id || proof.nonce !== statusQuery.nonce || proof.status !== 'active'
|
|
2112
|
+
|| !Number.isSafeInteger(proof.asOf) || proof.asOf < 0 || !Number.isSafeInteger(proof.proofExpiresAt) || proof.proofExpiresAt <= proof.asOf
|
|
2113
|
+
|| proof.proofExpiresAt > proof.asOf + 300 || proof.asOf > now + 300 || now > proof.proofExpiresAt + 300
|
|
2114
|
+
|| proof.signature?.timestamp !== proof.asOf)
|
|
2115
|
+
throw new ProtocolError('CREDENTIAL_STATUS_UNKNOWN', 'fresh legacy status differs from credential or query');
|
|
2116
|
+
const certificate = await legacyCertificate(service, proof.signature), unsigned = { ...proof };
|
|
2117
|
+
delete unsigned.signature;
|
|
2118
|
+
if (!verifySignatureWithCert(certificate, Buffer.from(proof.signature.signature, 'base64'), Buffer.from(canonicalJson(unsigned))))
|
|
2119
|
+
throw new ProtocolError('CREDENTIAL_SIGNATURE_INVALID', 'fresh legacy status signature is invalid');
|
|
2120
|
+
entry.legacy.status_proof = proof;
|
|
2121
|
+
legacyProofs.set(cid, proof);
|
|
2122
|
+
continue;
|
|
2123
|
+
}
|
|
2124
|
+
if (entry.credential.ver !== 'aun-cap/semantic-1' || !('metadata' in entry))
|
|
2125
|
+
continue;
|
|
2126
|
+
const semantic = entry;
|
|
2127
|
+
queries[cid] = query;
|
|
2128
|
+
semantic.status = await facade.status({ request_id: crypto.randomUUID(), nonce: crypto.randomBytes(24).toString('base64url'),
|
|
2129
|
+
credential_cid: cid, authority: input.authority, audience: context.audience,
|
|
2130
|
+
expected_revision: { cid, original_hash: semantic.metadata.original_hash, metadata_hash: semanticDigest(semantic.metadata), metadata_version: semantic.metadata.version },
|
|
2131
|
+
policy: { mode: 'online' }, query }, { serviceAid: service, verificationContext: context });
|
|
2132
|
+
}
|
|
2133
|
+
if (legacyProofs.size)
|
|
2134
|
+
context.legacyVerifier = async (entry, audience) => {
|
|
2135
|
+
const original = entry.credential, index = request.grant.lineage.findIndex(item => item.credential.cid === original.cid && digest(item.credential) === digest(original));
|
|
2136
|
+
if (index < 0)
|
|
2137
|
+
throw new ProtocolError('CREDENTIAL_CHAIN_INVALID', 'legacy original differs from fixed request lineage');
|
|
2138
|
+
const ancestors = request.grant.lineage.slice(0, index).reverse().map(item => item.credential), root = ancestors.at(-1) ?? original;
|
|
2139
|
+
if (!Array.isArray(input.grantors) || !input.grantors.includes(root.iss))
|
|
2140
|
+
throw new ProtocolError('CREDENTIAL_CHAIN_INVALID', 'legacy root issuer is not trusted for this resource');
|
|
2141
|
+
const certificates = new Map();
|
|
2142
|
+
for (const document of [original, ...ancestors])
|
|
2143
|
+
certificates.set(document.signature.cert_fingerprint, await legacyCertificate(document.iss, document.signature));
|
|
2144
|
+
const receipt = 'legacy' in entry ? entry.legacy.registration_receipt : undefined;
|
|
2145
|
+
if (receipt) {
|
|
2146
|
+
const service = context.serviceFor(original.cid), certificate = await legacyCertificate(service, receipt.signature, receipt.registered_at);
|
|
2147
|
+
facade.verifyRegistrationReceipt(receipt, original, { request_id: receipt.request_id, nonce: receipt.nonce, registrar_aid: original.iss, proof_chain: ancestors }, () => certificate, service, receipt.registered_at);
|
|
2148
|
+
}
|
|
2149
|
+
const now = Math.floor(Date.now() / 1000), method = request.ns + '.' + request.action;
|
|
2150
|
+
const requestBinding = buildRequestBinding(method, request.target, request.params, original.cid, request.nonce, request.request_id, now, now + 300);
|
|
2151
|
+
const verifyLegacy = () => {
|
|
2152
|
+
facade.verify(original, { audience, subject: original.sub, actor: original.sub, rootIssuer: root.iss, ns: request.ns, action: request.action, resource: request.resource,
|
|
2153
|
+
params: request.params, method, target: request.target, requestId: request.request_id, nonce: request.nonce,
|
|
2154
|
+
requestBinding, proofChain: ancestors, resolveCertificate: fingerprint => certificates.get(fingerprint), resolveStatusProof: cid => legacyProofs.get(cid), now: Math.floor(Date.now() / 1000) });
|
|
2155
|
+
};
|
|
2156
|
+
verifyLegacy();
|
|
2157
|
+
legacyChecks.push(verifyLegacy);
|
|
2158
|
+
};
|
|
2159
|
+
const packageReport = await facade.verifyPackage(request.grant, { ...context, audience: context.audience, now: Math.floor(Date.now() / 1000),
|
|
2160
|
+
statePolicy: { mode: 'online' }, queries, elapsedSeconds: performance.now() / 1000 - began });
|
|
2161
|
+
const requestReport = await facade.verifyRequest(request, input.authenticated, { now: Math.floor(Date.now() / 1000), representedActor: () => this.verifySemanticRepresentative(request, input) });
|
|
2162
|
+
const elapsedSeconds = performance.now() / 1000 - began;
|
|
2163
|
+
if (!Number.isFinite(elapsedSeconds) || elapsedSeconds < 0 || elapsedSeconds >= 30)
|
|
2164
|
+
throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'online status monotonic lifetime exceeded');
|
|
2165
|
+
for (const entry of request.grant.lineage)
|
|
2166
|
+
if (entry.credential.ver === 'aun-cap/semantic-1' && 'status' in entry) {
|
|
2167
|
+
validateStatusProof(entry.status, { mode: 'online' }, { now: Math.floor(Date.now() / 1000), elapsedSeconds, query });
|
|
2168
|
+
}
|
|
2169
|
+
for (const proof of legacyProofs.values())
|
|
2170
|
+
if (reader !== this.client.aid || Math.floor(Date.now() / 1000) < Number(proof.asOf) - 300 || Math.floor(Date.now() / 1000) > Number(proof.proofExpiresAt) + 300)
|
|
2171
|
+
throw new ProtocolError('CREDENTIAL_STATUS_UNKNOWN', 'fresh legacy status expired before verification completed');
|
|
2172
|
+
for (const verifyLegacy of legacyChecks)
|
|
2173
|
+
verifyLegacy();
|
|
2174
|
+
if (legacyChecks.length && performance.now() / 1000 - began >= 30)
|
|
2175
|
+
throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'online status monotonic lifetime exceeded');
|
|
2176
|
+
if (requestReport.request_hash !== query.request_hash)
|
|
2177
|
+
throw new SemanticProtocolError('SEMANTIC_BINDING_INVALID', 'refreshed request hash differs');
|
|
2178
|
+
return { request, language: 'typescript', report: { ...packageReport, request_bound: true, request_hash: requestReport.request_hash,
|
|
2179
|
+
checked: [...new Set([...packageReport.checked, ...requestReport.checked, 'lineage_structure', 'signatures', 'identities', 'revisions', 'state', 'usage_refs', 'authenticated_request'])],
|
|
2180
|
+
required: [...new Set([...packageReport.required, ...requestReport.required.filter(item => item !== 'package_verification')])] } };
|
|
2181
|
+
}
|
|
2182
|
+
const management = { register: 'register', revise: 'revise', get: 'get', status: 'status', revoke: 'revoke', revocations: 'revocations', prepare_usage: 'prepareUsage', commit_usage: 'commitUsage', abort_usage: 'abortUsage' };
|
|
2183
|
+
if (Object.hasOwn(management, op)) {
|
|
2184
|
+
const method = management[op];
|
|
2185
|
+
return facade[method].call(facade, params.params, params.target ? { serviceAid: textOf(params.target) } : {});
|
|
2186
|
+
}
|
|
2187
|
+
const signatures = { sign_credential: 'signCredential', sign_metadata: 'signMetadata', sign_allocation: 'signAllocation' };
|
|
2188
|
+
if (Object.hasOwn(signatures, op))
|
|
2189
|
+
return facade[signatures[op]](params.value, undefined, typeof params.now === 'number' ? { timestamp: params.now } : {});
|
|
2190
|
+
if (op === 'sign_usage_record')
|
|
2191
|
+
return facade.signUsageRecord(params.domain, params.value, undefined, typeof params.now === 'number' ? { timestamp: params.now } : {});
|
|
2192
|
+
if (op === 'build_package')
|
|
2193
|
+
return facade.buildPackage(params.params.lineage);
|
|
2194
|
+
if (op === 'build_request')
|
|
2195
|
+
return facade.buildRequest(params.params, typeof params.now === 'number' ? { now: params.now } : {});
|
|
2196
|
+
const verification = { verify_original: 'verifyOriginal', verify_metadata: 'verifyMetadata', verify_receipt: 'verifyReceipt', verify_package: 'verifyPackage' };
|
|
2197
|
+
if (Object.hasOwn(verification, op))
|
|
2198
|
+
return facade[verification[op]].call(facade, params.value, this.semanticContext(jsonObjectOf(params.context) ?? {}, false, op === 'verify_original' ? params.value : undefined));
|
|
2199
|
+
if (op === 'verify_status') {
|
|
2200
|
+
const context = this.semanticContext(jsonObjectOf(params.context) ?? {});
|
|
2201
|
+
return facade.verifyStatus(params.value, { ...context, policy: context.statePolicy });
|
|
2202
|
+
}
|
|
2203
|
+
if (op === 'verify_usage_record')
|
|
2204
|
+
return facade.verifyUsageRecord(params.domain, params.value, this.semanticContext(jsonObjectOf(params.context) ?? {}));
|
|
2205
|
+
const input = (jsonObjectOf(params.params) ?? {});
|
|
2206
|
+
if (op === 'archive_received_message') {
|
|
2207
|
+
const item = [...this.inbox, ...this.groupInbox].find(value => value.message_id === input.message_id && value.decrypted === true && jsonObjectOf(value._semantic_evidence));
|
|
2208
|
+
const evidence = jsonObjectOf(item?._semantic_evidence);
|
|
2209
|
+
if (!evidence)
|
|
2210
|
+
throw new SemanticProtocolError('SEMANTIC_STATE_UNAVAILABLE', 'original decrypted message evidence is unavailable');
|
|
2211
|
+
const receiver = this.client.aid;
|
|
2212
|
+
if (!receiver || evidence.received_by !== receiver || receiver !== this.aid)
|
|
2213
|
+
throw new SemanticProtocolError('SEMANTIC_IDENTITY_INVALID', 'original message receiver differs from current identity');
|
|
2214
|
+
const envelope = new Uint8Array(semanticBase64(evidence.envelope_bytes_base64));
|
|
2215
|
+
semanticBase64(evidence.payload_bytes_base64);
|
|
2216
|
+
return { archive: await facade.archiveMessage(envelope, { received_by: receiver, received_at: evidence.received_at, source: textOf(evidence.source) }),
|
|
2217
|
+
envelope_bytes_base64: evidence.envelope_bytes_base64, payload_bytes_base64: evidence.payload_bytes_base64 };
|
|
2218
|
+
}
|
|
2219
|
+
if (op === 'verify_request') {
|
|
2220
|
+
const request = input.request ?? input, actual = jsonObjectOf(input.context) ?? jsonObjectOf(params.context) ?? {}, context = this.semanticContext(actual);
|
|
2221
|
+
const packageReport = await facade.verifyPackage(request.grant, context);
|
|
2222
|
+
const requestReport = await facade.verifyRequest(request, actual.authenticated, { now: context.now });
|
|
2223
|
+
return { ...packageReport, ...requestReport, request_bound: true, checked: [...new Set([...packageReport.checked, ...requestReport.checked])] };
|
|
2224
|
+
}
|
|
2225
|
+
if (op === 'build_decision_input')
|
|
2226
|
+
return facade.buildDecisionInput(input.request, input.bodies, input.facts, input.policy);
|
|
2227
|
+
if (op === 'create_evidence_ref')
|
|
2228
|
+
return facade.createEvidenceRef(new Uint8Array(Buffer.from(textOf(input.bytes_base64), 'base64')), textOf(input.profile), input.locator);
|
|
2229
|
+
if (op === 'resolve_evidence')
|
|
2230
|
+
return { bytes_base64: Buffer.from(await facade.resolveEvidence(input.evidence ?? input, this.trustedArchiveResolvers())).toString('base64') };
|
|
2231
|
+
if (op === 'archive_message')
|
|
2232
|
+
return facade.archiveMessage(new Uint8Array(Buffer.from(textOf(input.bytes_base64), 'base64')), { received_by: this.aid, received_at: input.received_at, source: input.source });
|
|
2233
|
+
if (op === 'verify_message_body') {
|
|
2234
|
+
const context = jsonObjectOf(input.context) ?? jsonObjectOf(params.context) ?? {};
|
|
2235
|
+
return facade.verifyMessageBody(input.credential ?? input, { ...this.semanticContext(context, false, input.credential ?? input), ...this.semanticReaderMessageContext(), ...this.semanticHistoricalSenderContext(context), resolvers: this.trustedArchiveResolvers() });
|
|
2236
|
+
}
|
|
2237
|
+
throw new SemanticProtocolError('SEMANTIC_FORMAT_INVALID', `unsupported semantic protocol operation: ${op}`);
|
|
2238
|
+
}
|
|
1873
2239
|
async groupCall(req, res) {
|
|
1874
2240
|
const body = await readJson(req);
|
|
1875
2241
|
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
@@ -1888,6 +2254,9 @@ export class CrossSdkTsAgent {
|
|
|
1888
2254
|
case 'sdk.org.protocol':
|
|
1889
2255
|
result = await this.orgProtocol(params);
|
|
1890
2256
|
break;
|
|
2257
|
+
case 'sdk.semantic.protocol':
|
|
2258
|
+
result = await this.semanticProtocol(params);
|
|
2259
|
+
break;
|
|
1891
2260
|
case 'credential.register':
|
|
1892
2261
|
result = await this.client.credential.register(params);
|
|
1893
2262
|
break;
|
|
@@ -1900,9 +2269,16 @@ export class CrossSdkTsAgent {
|
|
|
1900
2269
|
case 'credential.revocationList':
|
|
1901
2270
|
result = await this.client.credential.revocationList(params);
|
|
1902
2271
|
break;
|
|
1903
|
-
case 'org.lifecycle.create':
|
|
1904
|
-
|
|
2272
|
+
case 'org.lifecycle.create': {
|
|
2273
|
+
const store = this.aidStore();
|
|
2274
|
+
try {
|
|
2275
|
+
result = await this.client.org.lifecycle.create({ ...params, aidStore: store });
|
|
2276
|
+
}
|
|
2277
|
+
finally {
|
|
2278
|
+
store.close();
|
|
2279
|
+
}
|
|
1905
2280
|
break;
|
|
2281
|
+
}
|
|
1906
2282
|
case 'org.lifecycle.dissolve':
|
|
1907
2283
|
result = await this.client.org.lifecycle.dissolve(params);
|
|
1908
2284
|
break;
|
|
@@ -1992,9 +2368,14 @@ export class CrossSdkTsAgent {
|
|
|
1992
2368
|
error_code: err instanceof Error ? err.name : 'Error',
|
|
1993
2369
|
error_message: err instanceof Error ? err.message : String(err),
|
|
1994
2370
|
};
|
|
1995
|
-
if (method.startsWith('org.') || method === 'sdk.org.protocol') {
|
|
2371
|
+
if (method.startsWith('org.') || method.startsWith('credential.semantic.') || method === 'sdk.org.protocol' || method === 'sdk.semantic.protocol') {
|
|
1996
2372
|
const remote = err;
|
|
1997
2373
|
error.rpc_error_code = remote?.stringCode || remote?.data?.error_code || remote?.data?.code || (typeof remote?.code === 'string' ? remote.code : '');
|
|
2374
|
+
if (method.startsWith('credential.semantic.') || method === 'sdk.semantic.protocol') {
|
|
2375
|
+
error.rpc_numeric_code = typeof remote?.code === 'number' ? remote.code : null;
|
|
2376
|
+
error.error_data = jsonSafe(remote?.data);
|
|
2377
|
+
error.retryable = remote?.retryable === true || remote?.data?.retryable === true;
|
|
2378
|
+
}
|
|
1998
2379
|
}
|
|
1999
2380
|
this.recordTrace(traceId, { stage: 'group_call_error', method, error });
|
|
2000
2381
|
sendJson(res, 500, error);
|