@private.me/xbind 1.2.0
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/AGENTS.md +778 -0
- package/LICENSE.md +27 -0
- package/README.md +400 -0
- package/dist-standalone/_deps/crypto/base64.d.ts +29 -0
- package/dist-standalone/_deps/crypto/base64.js +97 -0
- package/dist-standalone/_deps/crypto/cjs/base64.js +103 -0
- package/dist-standalone/_deps/crypto/cjs/errors.js +119 -0
- package/dist-standalone/_deps/crypto/cjs/hmac.js +71 -0
- package/dist-standalone/_deps/crypto/cjs/index.js +86 -0
- package/dist-standalone/_deps/crypto/cjs/padding.js +57 -0
- package/dist-standalone/_deps/crypto/cjs/share-header.js +68 -0
- package/dist-standalone/_deps/crypto/cjs/shares.js +152 -0
- package/dist-standalone/_deps/crypto/cjs/tlv.js +199 -0
- package/dist-standalone/_deps/crypto/cjs/uuid.js +61 -0
- package/dist-standalone/_deps/crypto/cjs/verify.js +24 -0
- package/dist-standalone/_deps/crypto/cjs/xorida.js +221 -0
- package/dist-standalone/_deps/crypto/errors.d.ts +51 -0
- package/dist-standalone/_deps/crypto/errors.js +109 -0
- package/dist-standalone/_deps/crypto/hmac.d.ts +39 -0
- package/dist-standalone/_deps/crypto/hmac.js +66 -0
- package/dist-standalone/_deps/crypto/index.d.ts +20 -0
- package/dist-standalone/_deps/crypto/index.js +45 -0
- package/dist-standalone/_deps/crypto/padding.d.ts +19 -0
- package/dist-standalone/_deps/crypto/padding.js +53 -0
- package/dist-standalone/_deps/crypto/share-header.d.ts +44 -0
- package/dist-standalone/_deps/crypto/share-header.js +63 -0
- package/dist-standalone/_deps/crypto/shares.d.ts +27 -0
- package/dist-standalone/_deps/crypto/shares.js +148 -0
- package/dist-standalone/_deps/crypto/tlv.d.ts +26 -0
- package/dist-standalone/_deps/crypto/tlv.js +195 -0
- package/dist-standalone/_deps/crypto/uuid.d.ts +22 -0
- package/dist-standalone/_deps/crypto/uuid.js +56 -0
- package/dist-standalone/_deps/crypto/verify.d.ts +15 -0
- package/dist-standalone/_deps/crypto/verify.js +15 -0
- package/dist-standalone/_deps/crypto/xorida.d.ts +44 -0
- package/dist-standalone/_deps/crypto/xorida.js +215 -0
- package/dist-standalone/_deps/mldsa-wasm/LICENSE +24 -0
- package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1920 -0
- package/dist-standalone/_deps/mldsa-wasm/package.json +46 -0
- package/dist-standalone/_deps/mldsa-wasm/types/mldsa.d.ts +30 -0
- package/dist-standalone/_deps/shared/cjs/errors.js +582 -0
- package/dist-standalone/_deps/shared/cjs/index.js +492 -0
- package/dist-standalone/_deps/shared/cjs/package.json +1 -0
- package/dist-standalone/_deps/shared/cjs/types.js +403 -0
- package/dist-standalone/_deps/shared/errors.d.ts +48 -0
- package/dist-standalone/_deps/shared/errors.d.ts.map +1 -0
- package/dist-standalone/_deps/shared/errors.js +192 -0
- package/dist-standalone/_deps/shared/errors.js.map +1 -0
- package/dist-standalone/_deps/shared/index.d.ts +4 -0
- package/dist-standalone/_deps/shared/index.d.ts.map +1 -0
- package/dist-standalone/_deps/shared/index.js +78 -0
- package/dist-standalone/_deps/shared/index.js.map +1 -0
- package/dist-standalone/_deps/shared/types.d.ts +1097 -0
- package/dist-standalone/_deps/shared/types.d.ts.map +1 -0
- package/dist-standalone/_deps/shared/types.js +89 -0
- package/dist-standalone/_deps/shared/types.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/errors.d.ts +115 -0
- package/dist-standalone/_deps/ux-helpers/cjs/errors.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/errors.js +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/errors.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/index.d.ts +13 -0
- package/dist-standalone/_deps/ux-helpers/cjs/index.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/index.js +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/index.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/package.json +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.d.ts +39 -0
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.js +83 -0
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/progress.d.ts +99 -0
- package/dist-standalone/_deps/ux-helpers/cjs/progress.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/progress.js +143 -0
- package/dist-standalone/_deps/ux-helpers/cjs/progress.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/search.d.ts +32 -0
- package/dist-standalone/_deps/ux-helpers/cjs/search.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/search.js +119 -0
- package/dist-standalone/_deps/ux-helpers/cjs/search.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/types.d.ts +109 -0
- package/dist-standalone/_deps/ux-helpers/cjs/types.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/cjs/types.js +8 -0
- package/dist-standalone/_deps/ux-helpers/cjs/types.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/errors.d.ts +115 -0
- package/dist-standalone/_deps/ux-helpers/errors.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/errors.js +253 -0
- package/dist-standalone/_deps/ux-helpers/errors.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/index.d.ts +13 -0
- package/dist-standalone/_deps/ux-helpers/index.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/index.js +16 -0
- package/dist-standalone/_deps/ux-helpers/index.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/pagination.d.ts +39 -0
- package/dist-standalone/_deps/ux-helpers/pagination.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/pagination.js +79 -0
- package/dist-standalone/_deps/ux-helpers/pagination.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/progress.d.ts +99 -0
- package/dist-standalone/_deps/ux-helpers/progress.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/progress.js +138 -0
- package/dist-standalone/_deps/ux-helpers/progress.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/search.d.ts +32 -0
- package/dist-standalone/_deps/ux-helpers/search.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/search.js +116 -0
- package/dist-standalone/_deps/ux-helpers/search.js.map +1 -0
- package/dist-standalone/_deps/ux-helpers/types.d.ts +109 -0
- package/dist-standalone/_deps/ux-helpers/types.d.ts.map +1 -0
- package/dist-standalone/_deps/ux-helpers/types.js +7 -0
- package/dist-standalone/_deps/ux-helpers/types.js.map +1 -0
- package/dist-standalone/_deps/xchange/auto-accept.d.ts +127 -0
- package/dist-standalone/_deps/xchange/auto-accept.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/auto-accept.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/errors.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/index.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/invite-client.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/lazy-init.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/package.json +1 -0
- package/dist-standalone/_deps/xchange/cjs/trust-integration.js +1 -0
- package/dist-standalone/_deps/xchange/cjs/xchange.js +1 -0
- package/dist-standalone/_deps/xchange/errors.d.ts +69 -0
- package/dist-standalone/_deps/xchange/errors.js +1 -0
- package/dist-standalone/_deps/xchange/index.d.ts +15 -0
- package/dist-standalone/_deps/xchange/index.js +1 -0
- package/dist-standalone/_deps/xchange/invite-client.d.ts +178 -0
- package/dist-standalone/_deps/xchange/invite-client.js +1 -0
- package/dist-standalone/_deps/xchange/lazy-init.d.ts +176 -0
- package/dist-standalone/_deps/xchange/lazy-init.js +1 -0
- package/dist-standalone/_deps/xchange/trust-integration.d.ts +102 -0
- package/dist-standalone/_deps/xchange/trust-integration.js +1 -0
- package/dist-standalone/_deps/xchange/xchange.d.ts +60 -0
- package/dist-standalone/_deps/xchange/xchange.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/discovery.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/errors.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/index.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/package.json +1 -0
- package/dist-standalone/_deps/xregistry/cjs/registry.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/schema.js +1 -0
- package/dist-standalone/_deps/xregistry/cjs/types.js +1 -0
- package/dist-standalone/_deps/xregistry/discovery.d.ts +126 -0
- package/dist-standalone/_deps/xregistry/discovery.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/discovery.js +1 -0
- package/dist-standalone/_deps/xregistry/discovery.js.map +1 -0
- package/dist-standalone/_deps/xregistry/errors.d.ts +41 -0
- package/dist-standalone/_deps/xregistry/errors.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/errors.js +1 -0
- package/dist-standalone/_deps/xregistry/errors.js.map +1 -0
- package/dist-standalone/_deps/xregistry/index.d.ts +8 -0
- package/dist-standalone/_deps/xregistry/index.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/index.js +1 -0
- package/dist-standalone/_deps/xregistry/index.js.map +1 -0
- package/dist-standalone/_deps/xregistry/registry.d.ts +85 -0
- package/dist-standalone/_deps/xregistry/registry.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/registry.js +1 -0
- package/dist-standalone/_deps/xregistry/registry.js.map +1 -0
- package/dist-standalone/_deps/xregistry/schema.d.ts +81 -0
- package/dist-standalone/_deps/xregistry/schema.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/schema.js +1 -0
- package/dist-standalone/_deps/xregistry/schema.js.map +1 -0
- package/dist-standalone/_deps/xregistry/types.d.ts +95 -0
- package/dist-standalone/_deps/xregistry/types.d.ts.map +1 -0
- package/dist-standalone/_deps/xregistry/types.js +1 -0
- package/dist-standalone/_deps/xregistry/types.js.map +1 -0
- package/dist-standalone/agent-call.d.ts +286 -0
- package/dist-standalone/agent-call.js +642 -0
- package/dist-standalone/agent-sdk.d.ts +207 -0
- package/dist-standalone/agent-sdk.js +328 -0
- package/dist-standalone/agent.d.ts +670 -0
- package/dist-standalone/agent.js +1529 -0
- package/dist-standalone/approval.d.ts +145 -0
- package/dist-standalone/approval.js +193 -0
- package/dist-standalone/auth.d.ts +75 -0
- package/dist-standalone/auth.js +219 -0
- package/dist-standalone/auto-accept.d.ts +102 -0
- package/dist-standalone/auto-accept.js +229 -0
- package/dist-standalone/backup-config.d.ts +150 -0
- package/dist-standalone/backup-config.js +201 -0
- package/dist-standalone/checkpoint.d.ts +125 -0
- package/dist-standalone/checkpoint.js +186 -0
- package/dist-standalone/cjs/agent-call.js +651 -0
- package/dist-standalone/cjs/agent-sdk.js +332 -0
- package/dist-standalone/cjs/agent.js +1566 -0
- package/dist-standalone/cjs/approval.js +199 -0
- package/dist-standalone/cjs/auth.js +225 -0
- package/dist-standalone/cjs/auto-accept.js +233 -0
- package/dist-standalone/cjs/backup-config.js +207 -0
- package/dist-standalone/cjs/checkpoint.js +193 -0
- package/dist-standalone/cjs/cli/init.js +487 -0
- package/dist-standalone/cjs/connect.js +312 -0
- package/dist-standalone/cjs/did-document.js +101 -0
- package/dist-standalone/cjs/did-privateme.js +130 -0
- package/dist-standalone/cjs/did-web.js +201 -0
- package/dist-standalone/cjs/discovery.js +462 -0
- package/dist-standalone/cjs/dual-mode.js +251 -0
- package/dist-standalone/cjs/email-templates.js +313 -0
- package/dist-standalone/cjs/email-transport.js +239 -0
- package/dist-standalone/cjs/envelope.js +510 -0
- package/dist-standalone/cjs/errors.js +562 -0
- package/dist-standalone/cjs/gateway-state.js +55 -0
- package/dist-standalone/cjs/gateway-transport.js +120 -0
- package/dist-standalone/cjs/guardrails.js +223 -0
- package/dist-standalone/cjs/http-compat.js +272 -0
- package/dist-standalone/cjs/identity.js +541 -0
- package/dist-standalone/cjs/index.js +224 -0
- package/dist-standalone/cjs/invitation.js +421 -0
- package/dist-standalone/cjs/invite.js +328 -0
- package/dist-standalone/cjs/key-agreement.js +246 -0
- package/dist-standalone/cjs/lazy-init.js +300 -0
- package/dist-standalone/cjs/mdns-discovery.js +202 -0
- package/dist-standalone/cjs/nonce-store.js +66 -0
- package/dist-standalone/cjs/package.json +3 -0
- package/dist-standalone/cjs/pairing-manager.js +223 -0
- package/dist-standalone/cjs/policy.js +320 -0
- package/dist-standalone/cjs/redis-nonce-store.js +76 -0
- package/dist-standalone/cjs/registry-middleware.js +50 -0
- package/dist-standalone/cjs/retry-transport.js +102 -0
- package/dist-standalone/cjs/security-policy.js +204 -0
- package/dist-standalone/cjs/split-channel.js +177 -0
- package/dist-standalone/cjs/subscription-proof.js +230 -0
- package/dist-standalone/cjs/succession.js +148 -0
- package/dist-standalone/cjs/transport.js +63 -0
- package/dist-standalone/cjs/trust-registry.js +742 -0
- package/dist-standalone/cjs/verify.js +25 -0
- package/dist-standalone/cjs/xfetch.js +252 -0
- package/dist-standalone/cli/init.d.ts +63 -0
- package/dist-standalone/cli/init.js +450 -0
- package/dist-standalone/connect.d.ts +143 -0
- package/dist-standalone/connect.js +274 -0
- package/dist-standalone/did-document.d.ts +65 -0
- package/dist-standalone/did-document.js +96 -0
- package/dist-standalone/did-privateme.d.ts +70 -0
- package/dist-standalone/did-privateme.js +121 -0
- package/dist-standalone/did-web.d.ts +73 -0
- package/dist-standalone/did-web.js +196 -0
- package/dist-standalone/discovery.d.ts +176 -0
- package/dist-standalone/discovery.js +458 -0
- package/dist-standalone/dual-mode.d.ts +145 -0
- package/dist-standalone/dual-mode.js +247 -0
- package/dist-standalone/email-templates.d.ts +41 -0
- package/dist-standalone/email-templates.js +309 -0
- package/dist-standalone/email-transport.d.ts +139 -0
- package/dist-standalone/email-transport.js +232 -0
- package/dist-standalone/envelope.d.ts +288 -0
- package/dist-standalone/envelope.js +497 -0
- package/dist-standalone/errors.d.ts +74 -0
- package/dist-standalone/errors.js +548 -0
- package/dist-standalone/gateway-state.d.ts +32 -0
- package/dist-standalone/gateway-state.js +51 -0
- package/dist-standalone/gateway-transport.d.ts +59 -0
- package/dist-standalone/gateway-transport.js +116 -0
- package/dist-standalone/guardrails.d.ts +136 -0
- package/dist-standalone/guardrails.js +216 -0
- package/dist-standalone/http-compat.d.ts +150 -0
- package/dist-standalone/http-compat.js +267 -0
- package/dist-standalone/identity.d.ts +176 -0
- package/dist-standalone/identity.js +516 -0
- package/dist-standalone/index.d.ts +83 -0
- package/dist-standalone/index.js +51 -0
- package/dist-standalone/invitation.d.ts +211 -0
- package/dist-standalone/invitation.js +415 -0
- package/dist-standalone/invite.d.ts +192 -0
- package/dist-standalone/invite.js +324 -0
- package/dist-standalone/key-agreement.d.ts +122 -0
- package/dist-standalone/key-agreement.js +236 -0
- package/dist-standalone/lazy-init.d.ts +167 -0
- package/dist-standalone/lazy-init.js +295 -0
- package/dist-standalone/mdns-discovery.d.ts +117 -0
- package/dist-standalone/mdns-discovery.js +195 -0
- package/dist-standalone/nonce-store.d.ts +39 -0
- package/dist-standalone/nonce-store.js +62 -0
- package/dist-standalone/package.json +11 -0
- package/dist-standalone/pairing-manager.d.ts +147 -0
- package/dist-standalone/pairing-manager.js +219 -0
- package/dist-standalone/policy.d.ts +150 -0
- package/dist-standalone/policy.js +315 -0
- package/dist-standalone/redis-nonce-store.d.ts +93 -0
- package/dist-standalone/redis-nonce-store.js +72 -0
- package/dist-standalone/registry-middleware.d.ts +38 -0
- package/dist-standalone/registry-middleware.js +47 -0
- package/dist-standalone/retry-transport.d.ts +76 -0
- package/dist-standalone/retry-transport.js +98 -0
- package/dist-standalone/security-policy.d.ts +146 -0
- package/dist-standalone/security-policy.js +198 -0
- package/dist-standalone/split-channel.d.ts +69 -0
- package/dist-standalone/split-channel.js +171 -0
- package/dist-standalone/subscription-proof.d.ts +103 -0
- package/dist-standalone/subscription-proof.js +224 -0
- package/dist-standalone/succession.d.ts +57 -0
- package/dist-standalone/succession.js +142 -0
- package/dist-standalone/transport.d.ts +50 -0
- package/dist-standalone/transport.js +59 -0
- package/dist-standalone/trust-registry.d.ts +286 -0
- package/dist-standalone/trust-registry.js +702 -0
- package/dist-standalone/verify.d.ts +16 -0
- package/dist-standalone/verify.js +16 -0
- package/dist-standalone/xfetch.d.ts +129 -0
- package/dist-standalone/xfetch.js +247 -0
- package/llms.txt +800 -0
- package/package.json +79 -0
- package/share1.dat +0 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { ok, err } from"./_deps/shared/index.js";
|
|
2
|
+
import { MlKem768 } from 'mlkem';
|
|
3
|
+
/* -- Constants -- */
|
|
4
|
+
const X25519_RAW_KEY_BYTES = 32;
|
|
5
|
+
const AES_KEY_BITS = 256;
|
|
6
|
+
/* -- Helpers -- */
|
|
7
|
+
/** Copy Uint8Array to fresh ArrayBuffer. */
|
|
8
|
+
function toArrayBuffer(data) {
|
|
9
|
+
const buf = new ArrayBuffer(data.byteLength);
|
|
10
|
+
new Uint8Array(buf).set(data);
|
|
11
|
+
return buf;
|
|
12
|
+
}
|
|
13
|
+
/* -- Key Generation -- */
|
|
14
|
+
/**
|
|
15
|
+
* Generate an ephemeral X25519 key pair for ECDH key agreement.
|
|
16
|
+
*
|
|
17
|
+
* Uses Web Crypto API to generate a fresh X25519 key pair.
|
|
18
|
+
* The key pair is ephemeral -- it should be used for a single
|
|
19
|
+
* key agreement and then discarded.
|
|
20
|
+
*
|
|
21
|
+
* @returns Result containing the ephemeral key pair or error.
|
|
22
|
+
*/
|
|
23
|
+
export async function generateEphemeralKeyPair() {
|
|
24
|
+
try {
|
|
25
|
+
// SAFETY: X25519 generateKey always returns CryptoKeyPair
|
|
26
|
+
const keyPair = await crypto.subtle.generateKey({ name: 'X25519' }, true, ['deriveBits']);
|
|
27
|
+
const rawPub = new Uint8Array(await crypto.subtle.exportKey('raw', keyPair.publicKey));
|
|
28
|
+
return ok({
|
|
29
|
+
privateKey: keyPair.privateKey,
|
|
30
|
+
publicKey: keyPair.publicKey,
|
|
31
|
+
rawPublicKey: rawPub,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return err('KEYGEN_FAILED');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/* -- Key Import -- */
|
|
39
|
+
/**
|
|
40
|
+
* Import a raw 32-byte X25519 public key into a CryptoKey.
|
|
41
|
+
*
|
|
42
|
+
* Used by the receiver to import the sender's ephemeral public
|
|
43
|
+
* key from the envelope for ECDH derivation.
|
|
44
|
+
*
|
|
45
|
+
* @param rawPublicKey - Raw 32-byte X25519 public key.
|
|
46
|
+
* @returns Result containing the imported CryptoKey or error.
|
|
47
|
+
*/
|
|
48
|
+
export async function importX25519PublicKey(rawPublicKey) {
|
|
49
|
+
if (rawPublicKey.length !== X25519_RAW_KEY_BYTES) {
|
|
50
|
+
return err('INVALID_KEY_LENGTH:EXPECTED_32');
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const key = await crypto.subtle.importKey('raw', toArrayBuffer(rawPublicKey), { name: 'X25519' }, true, []);
|
|
54
|
+
return ok(key);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return err('IMPORT_FAILED');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/* -- ECDH Key Derivation -- */
|
|
61
|
+
/**
|
|
62
|
+
* Derive a shared AES-256-GCM key via X25519 ECDH.
|
|
63
|
+
*
|
|
64
|
+
* Performs ECDH key agreement between a local private key and a
|
|
65
|
+
* remote public key, producing 256 bits of shared secret that
|
|
66
|
+
* are imported as an AES-256-GCM key.
|
|
67
|
+
*
|
|
68
|
+
* @param localPrivateKey - Local X25519 private key.
|
|
69
|
+
* @param remotePublicKey - Remote X25519 public key (CryptoKey).
|
|
70
|
+
* @returns Result containing the derived AES-256-GCM key or error.
|
|
71
|
+
*/
|
|
72
|
+
export async function deriveSharedKeyECDH(localPrivateKey, remotePublicKey) {
|
|
73
|
+
try {
|
|
74
|
+
const sharedBits = await crypto.subtle.deriveBits({ name: 'X25519', public: remotePublicKey }, localPrivateKey, AES_KEY_BITS);
|
|
75
|
+
const aesKey = await crypto.subtle.importKey('raw', sharedBits, { name: 'AES-GCM', length: AES_KEY_BITS }, false, ['encrypt', 'decrypt']);
|
|
76
|
+
return ok(aesKey);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return err('DERIVE_FAILED');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/* -- High-Level API -- */
|
|
83
|
+
/**
|
|
84
|
+
* Perform sender-side ECDH key agreement.
|
|
85
|
+
*
|
|
86
|
+
* Generates an ephemeral X25519 key pair, derives a shared key
|
|
87
|
+
* with the recipient's static X25519 public key, and returns
|
|
88
|
+
* both the shared key and the ephemeral public key to include
|
|
89
|
+
* in the envelope.
|
|
90
|
+
*
|
|
91
|
+
* @param recipientX25519PubKey - Recipient's static X25519 public key.
|
|
92
|
+
* @returns Result containing the key agreement result or error.
|
|
93
|
+
*/
|
|
94
|
+
export async function senderKeyAgreement(recipientX25519PubKey) {
|
|
95
|
+
const ephemeral = await generateEphemeralKeyPair();
|
|
96
|
+
if (!ephemeral.ok)
|
|
97
|
+
return ephemeral;
|
|
98
|
+
const shared = await deriveSharedKeyECDH(ephemeral.value.privateKey, recipientX25519PubKey);
|
|
99
|
+
if (!shared.ok)
|
|
100
|
+
return shared;
|
|
101
|
+
return ok({
|
|
102
|
+
sharedKey: shared.value,
|
|
103
|
+
ephemeralPublicKey: ephemeral.value.rawPublicKey,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Perform receiver-side ECDH key agreement.
|
|
108
|
+
*
|
|
109
|
+
* Imports the sender's ephemeral public key from the envelope
|
|
110
|
+
* and derives the shared key using the receiver's static X25519
|
|
111
|
+
* private key.
|
|
112
|
+
*
|
|
113
|
+
* @param receiverPrivateKey - Receiver's static X25519 private key.
|
|
114
|
+
* @param senderEphemeralPubRaw - Sender's ephemeral public key (raw bytes).
|
|
115
|
+
* @returns Result containing the derived AES-256-GCM key or error.
|
|
116
|
+
*/
|
|
117
|
+
export async function receiverKeyAgreement(receiverPrivateKey, senderEphemeralPubRaw) {
|
|
118
|
+
const imported = await importX25519PublicKey(senderEphemeralPubRaw);
|
|
119
|
+
if (!imported.ok)
|
|
120
|
+
return imported;
|
|
121
|
+
return deriveSharedKeyECDH(receiverPrivateKey, imported.value);
|
|
122
|
+
}
|
|
123
|
+
/* -- Hybrid Key Agreement (X25519 + ML-KEM-768) -- */
|
|
124
|
+
const HYBRID_HKDF_INFO = 'xail-hybrid-kem-v2';
|
|
125
|
+
/**
|
|
126
|
+
* Combine X25519 and ML-KEM shared secrets via HKDF-SHA256.
|
|
127
|
+
*
|
|
128
|
+
* Concatenates 32B X25519 + 32B ML-KEM shared secrets, runs HKDF
|
|
129
|
+
* with zero salt and 'xail-hybrid-kem-v2' info, outputs 256-bit AES key.
|
|
130
|
+
* Secure as long as either X25519 OR ML-KEM remains unbroken.
|
|
131
|
+
*
|
|
132
|
+
* @param x25519Shared - 32-byte raw X25519 ECDH shared bits.
|
|
133
|
+
* @param mlKemShared - 32-byte ML-KEM-768 shared secret.
|
|
134
|
+
* @returns AES-256-GCM CryptoKey derived from both secrets.
|
|
135
|
+
*/
|
|
136
|
+
export async function combineSharedSecrets(x25519Shared, mlKemShared) {
|
|
137
|
+
try {
|
|
138
|
+
const combined = new Uint8Array(x25519Shared.length + mlKemShared.length);
|
|
139
|
+
combined.set(x25519Shared);
|
|
140
|
+
combined.set(mlKemShared, x25519Shared.length);
|
|
141
|
+
const baseKey = await crypto.subtle.importKey('raw', toArrayBuffer(combined), 'HKDF', false, ['deriveBits']);
|
|
142
|
+
const derived = await crypto.subtle.deriveBits({
|
|
143
|
+
name: 'HKDF',
|
|
144
|
+
hash: 'SHA-256',
|
|
145
|
+
salt: new Uint8Array(32),
|
|
146
|
+
info: new TextEncoder().encode(HYBRID_HKDF_INFO),
|
|
147
|
+
}, baseKey, AES_KEY_BITS);
|
|
148
|
+
const aesKey = await crypto.subtle.importKey('raw', derived, { name: 'AES-GCM', length: AES_KEY_BITS }, false, ['encrypt', 'decrypt']);
|
|
149
|
+
return ok(aesKey);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return err('HKDF_FAILED');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Perform sender-side hybrid key agreement (X25519 + ML-KEM-768).
|
|
157
|
+
*
|
|
158
|
+
* 1. Generate ephemeral X25519, ECDH → x25519SharedBits
|
|
159
|
+
* 2. ML-KEM-768 encapsulate → kemCiphertext + mlKemShared
|
|
160
|
+
* 3. HKDF(x25519Shared || mlKemShared) → AES-256-GCM key
|
|
161
|
+
*
|
|
162
|
+
* @param recipientX25519Pub - Recipient's static X25519 public key.
|
|
163
|
+
* @param recipientMlKemPub - Recipient's ML-KEM-768 public key (1184B).
|
|
164
|
+
* @returns Hybrid key agreement result with shared key, ephemeral pub, and KEM ciphertext.
|
|
165
|
+
*/
|
|
166
|
+
export async function senderHybridKeyAgreement(recipientX25519Pub, recipientMlKemPub) {
|
|
167
|
+
// Step 1: Ephemeral X25519 ECDH
|
|
168
|
+
const ephemeral = await generateEphemeralKeyPair();
|
|
169
|
+
if (!ephemeral.ok)
|
|
170
|
+
return ephemeral;
|
|
171
|
+
let x25519Shared;
|
|
172
|
+
try {
|
|
173
|
+
x25519Shared = new Uint8Array(await crypto.subtle.deriveBits({ name: 'X25519', public: recipientX25519Pub }, ephemeral.value.privateKey, AES_KEY_BITS));
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return err('DERIVE_FAILED');
|
|
177
|
+
}
|
|
178
|
+
// Step 2: ML-KEM-768 encapsulate
|
|
179
|
+
let kemCipherText;
|
|
180
|
+
let kemSharedSecret;
|
|
181
|
+
try {
|
|
182
|
+
const mlkem = new MlKem768();
|
|
183
|
+
const [cipherText, sharedSecret] = await mlkem.encap(recipientMlKemPub);
|
|
184
|
+
kemCipherText = cipherText;
|
|
185
|
+
kemSharedSecret = sharedSecret;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return err('KEM_ENCAPSULATE_FAILED');
|
|
189
|
+
}
|
|
190
|
+
// Step 3: Combine via HKDF
|
|
191
|
+
const combined = await combineSharedSecrets(x25519Shared, kemSharedSecret);
|
|
192
|
+
if (!combined.ok)
|
|
193
|
+
return combined;
|
|
194
|
+
return ok({
|
|
195
|
+
sharedKey: combined.value,
|
|
196
|
+
ephemeralPublicKey: ephemeral.value.rawPublicKey,
|
|
197
|
+
kemCiphertext: kemCipherText,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Perform receiver-side hybrid key agreement (X25519 + ML-KEM-768).
|
|
202
|
+
*
|
|
203
|
+
* 1. Import ephemeral X25519, ECDH → x25519SharedBits
|
|
204
|
+
* 2. ML-KEM-768 decapsulate → mlKemShared
|
|
205
|
+
* 3. HKDF(x25519Shared || mlKemShared) → same AES-256-GCM key
|
|
206
|
+
*
|
|
207
|
+
* @param x25519PrivateKey - Receiver's static X25519 private key.
|
|
208
|
+
* @param ephPubRaw - Sender's ephemeral X25519 public key (32B).
|
|
209
|
+
* @param kemCiphertext - ML-KEM-768 ciphertext from sender (1088B).
|
|
210
|
+
* @param mlKemSecretKey - Receiver's ML-KEM-768 secret key (2400B).
|
|
211
|
+
* @returns AES-256-GCM shared key or error.
|
|
212
|
+
*/
|
|
213
|
+
export async function receiverHybridKeyAgreement(x25519PrivateKey, ephPubRaw, kemCiphertext, mlKemSecretKey) {
|
|
214
|
+
// Step 1: X25519 ECDH
|
|
215
|
+
const imported = await importX25519PublicKey(ephPubRaw);
|
|
216
|
+
if (!imported.ok)
|
|
217
|
+
return imported;
|
|
218
|
+
let x25519Shared;
|
|
219
|
+
try {
|
|
220
|
+
x25519Shared = new Uint8Array(await crypto.subtle.deriveBits({ name: 'X25519', public: imported.value }, x25519PrivateKey, AES_KEY_BITS));
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
return err('DERIVE_FAILED');
|
|
224
|
+
}
|
|
225
|
+
// Step 2: ML-KEM-768 decapsulate
|
|
226
|
+
let mlKemShared;
|
|
227
|
+
try {
|
|
228
|
+
const mlkem = new MlKem768();
|
|
229
|
+
mlKemShared = await mlkem.decap(kemCiphertext, mlKemSecretKey);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return err('KEM_DECAPSULATE_FAILED');
|
|
233
|
+
}
|
|
234
|
+
// Step 3: Combine via HKDF
|
|
235
|
+
return combineSharedSecrets(x25519Shared, mlKemShared);
|
|
236
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module lazy-init
|
|
3
|
+
* Lazy agent initialization for zero-click onboarding.
|
|
4
|
+
*
|
|
5
|
+
* Defers invite acceptance and identity generation until first
|
|
6
|
+
* send/receive call. Enables: `Agent.lazy({ name: 'my-service' })`
|
|
7
|
+
* with no async/await at construction time.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Environment: XBIND_INVITE_CODE=XBD-abc123
|
|
12
|
+
*
|
|
13
|
+
* // Old way (explicit):
|
|
14
|
+
* const agent = await Agent.create({ name: 'my-service', registry, transport });
|
|
15
|
+
*
|
|
16
|
+
* // New way (lazy):
|
|
17
|
+
* const agent = Agent.lazy({ name: 'my-service' });
|
|
18
|
+
* // No await, no async — agent is constructed synchronously.
|
|
19
|
+
* // Invite auto-accepts on first send/receive:
|
|
20
|
+
* await agent.send({ to: partnerDid, payload: data, scope: 'test' });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { Result } from '@private.me/shared';
|
|
24
|
+
import { Agent } from './agent.js';
|
|
25
|
+
import type { AgentError, AgentSendOptions, AgentMessage, AgentReceiveOptions } from './agent.js';
|
|
26
|
+
import type { AnyTransportEnvelope } from './envelope.js';
|
|
27
|
+
import type { AutoAcceptConfig } from './auto-accept.js';
|
|
28
|
+
import type { TrustRegistry } from './trust-registry.js';
|
|
29
|
+
import type { XailTransportAdapter } from './transport.js';
|
|
30
|
+
/**
|
|
31
|
+
* Lazy agent configuration options.
|
|
32
|
+
*/
|
|
33
|
+
export interface LazyAgentConfig {
|
|
34
|
+
/** Service name (required). */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Invite code or URL. If omitted, reads from XBIND_INVITE_CODE. */
|
|
37
|
+
inviteCode?: string;
|
|
38
|
+
/** Auto-accept config (optional). */
|
|
39
|
+
autoAccept?: AutoAcceptConfig;
|
|
40
|
+
/** Custom trust registry (optional, auto-configured from invite if omitted). */
|
|
41
|
+
registry?: TrustRegistry;
|
|
42
|
+
/** Custom transport adapter (optional, auto-configured from invite if omitted). */
|
|
43
|
+
transport?: XailTransportAdapter | XailTransportAdapter[];
|
|
44
|
+
/** Enable post-quantum signatures (default: false). */
|
|
45
|
+
postQuantumSig?: boolean;
|
|
46
|
+
/** Enable Xchange mode support (default: false). */
|
|
47
|
+
xchange?: boolean;
|
|
48
|
+
/** Service endpoint URL (required for invite acceptance). */
|
|
49
|
+
endpoint?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Lazy agent error codes.
|
|
53
|
+
*/
|
|
54
|
+
export declare enum LazyAgentErrorCode {
|
|
55
|
+
INIT_FAILED = "LAZY_AGENT_INIT_FAILED",
|
|
56
|
+
AUTO_ACCEPT_FAILED = "LAZY_AGENT_AUTO_ACCEPT_FAILED",
|
|
57
|
+
AGENT_CREATION_FAILED = "LAZY_AGENT_AGENT_CREATION_FAILED"
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Lazy agent error.
|
|
61
|
+
*/
|
|
62
|
+
export interface LazyAgentError {
|
|
63
|
+
code: LazyAgentErrorCode;
|
|
64
|
+
message: string;
|
|
65
|
+
hint?: string;
|
|
66
|
+
cause?: unknown;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Lazy agent wrapper.
|
|
70
|
+
*
|
|
71
|
+
* Proxies all Agent methods and initializes on first call.
|
|
72
|
+
* Caches the initialized agent for subsequent calls.
|
|
73
|
+
*/
|
|
74
|
+
export declare class LazyAgent {
|
|
75
|
+
private config;
|
|
76
|
+
private agent;
|
|
77
|
+
private initPromise;
|
|
78
|
+
private lastError;
|
|
79
|
+
constructor(config: LazyAgentConfig);
|
|
80
|
+
/**
|
|
81
|
+
* Get the agent's DID.
|
|
82
|
+
*
|
|
83
|
+
* Triggers initialization if not already initialized.
|
|
84
|
+
* Throws if initialization fails.
|
|
85
|
+
*/
|
|
86
|
+
get did(): string;
|
|
87
|
+
/**
|
|
88
|
+
* Check if agent is ready (initialized).
|
|
89
|
+
*/
|
|
90
|
+
isReady(): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Get last initialization error (if any).
|
|
93
|
+
*/
|
|
94
|
+
getLastError(): LazyAgentError | null;
|
|
95
|
+
/**
|
|
96
|
+
* Ensure agent is initialized.
|
|
97
|
+
*
|
|
98
|
+
* Can be called explicitly to trigger init before first send/receive.
|
|
99
|
+
* Safe to call multiple times — subsequent calls return cached agent.
|
|
100
|
+
*
|
|
101
|
+
* @returns Agent instance or error
|
|
102
|
+
*/
|
|
103
|
+
ensureInitialized(): Promise<Result<Agent, AgentError>>;
|
|
104
|
+
/**
|
|
105
|
+
* Internal initialization logic.
|
|
106
|
+
*
|
|
107
|
+
* 1. Auto-accept invite (if XBIND_INVITE_CODE set)
|
|
108
|
+
* 2. Create agent identity
|
|
109
|
+
* 3. Configure registry and transport
|
|
110
|
+
* 4. Return initialized agent
|
|
111
|
+
*/
|
|
112
|
+
private initialize;
|
|
113
|
+
/**
|
|
114
|
+
* Send a message (proxied to underlying agent).
|
|
115
|
+
*
|
|
116
|
+
* Automatically initializes agent on first call.
|
|
117
|
+
*/
|
|
118
|
+
send(opts: AgentSendOptions): Promise<Result<void, AgentError>>;
|
|
119
|
+
/**
|
|
120
|
+
* Receive a message (proxied to underlying agent).
|
|
121
|
+
*
|
|
122
|
+
* Automatically initializes agent on first call.
|
|
123
|
+
*/
|
|
124
|
+
receive(envelope: AnyTransportEnvelope, opts?: AgentReceiveOptions): Promise<Result<AgentMessage, AgentError>>;
|
|
125
|
+
/**
|
|
126
|
+
* Receive a split-channel share (proxied to underlying agent).
|
|
127
|
+
*
|
|
128
|
+
* Automatically initializes agent on first call.
|
|
129
|
+
*/
|
|
130
|
+
receiveSplitShare(envelope: AnyTransportEnvelope): Promise<Result<AgentMessage | null, AgentError>>;
|
|
131
|
+
/**
|
|
132
|
+
* Get environment variable value.
|
|
133
|
+
*
|
|
134
|
+
* @param key - Environment variable name
|
|
135
|
+
* @returns Environment variable value or empty string
|
|
136
|
+
*/
|
|
137
|
+
private getEnv;
|
|
138
|
+
/**
|
|
139
|
+
* Export the underlying agent (for advanced use cases).
|
|
140
|
+
*
|
|
141
|
+
* Throws if agent is not initialized.
|
|
142
|
+
*/
|
|
143
|
+
getAgent(): Agent;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create a lazy agent that initializes on first use.
|
|
147
|
+
*
|
|
148
|
+
* Extension method for Agent class. Adds `Agent.lazy()` factory.
|
|
149
|
+
*
|
|
150
|
+
* @param config - Lazy agent configuration
|
|
151
|
+
* @returns Lazy agent wrapper
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* // Environment: XBIND_INVITE_CODE=XBD-abc123
|
|
156
|
+
*
|
|
157
|
+
* const agent = createLazyAgent({ name: 'my-service' });
|
|
158
|
+
*
|
|
159
|
+
* // No initialization yet — happens on first send:
|
|
160
|
+
* await agent.send({
|
|
161
|
+
* to: 'did:key:z6Mk...',
|
|
162
|
+
* payload: { action: 'test' },
|
|
163
|
+
* scope: 'test',
|
|
164
|
+
* });
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function createLazyAgent(config: LazyAgentConfig): LazyAgent;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module lazy-init
|
|
3
|
+
* Lazy agent initialization for zero-click onboarding.
|
|
4
|
+
*
|
|
5
|
+
* Defers invite acceptance and identity generation until first
|
|
6
|
+
* send/receive call. Enables: `Agent.lazy({ name: 'my-service' })`
|
|
7
|
+
* with no async/await at construction time.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Environment: XBIND_INVITE_CODE=XBD-abc123
|
|
12
|
+
*
|
|
13
|
+
* // Old way (explicit):
|
|
14
|
+
* const agent = await Agent.create({ name: 'my-service', registry, transport });
|
|
15
|
+
*
|
|
16
|
+
* // New way (lazy):
|
|
17
|
+
* const agent = Agent.lazy({ name: 'my-service' });
|
|
18
|
+
* // No await, no async — agent is constructed synchronously.
|
|
19
|
+
* // Invite auto-accepts on first send/receive:
|
|
20
|
+
* await agent.send({ to: partnerDid, payload: data, scope: 'test' });
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import { ok, err } from"./_deps/shared/index.js";
|
|
24
|
+
import { Agent } from './agent.js';
|
|
25
|
+
import { autoAcceptInvite } from './auto-accept.js';
|
|
26
|
+
import { MemoryTrustRegistry } from './trust-registry.js';
|
|
27
|
+
import { HttpsTransportAdapter } from './transport.js';
|
|
28
|
+
import { toBase64 } from"./_deps/crypto/index.js";
|
|
29
|
+
/**
|
|
30
|
+
* Lazy agent error codes.
|
|
31
|
+
*/
|
|
32
|
+
export var LazyAgentErrorCode;
|
|
33
|
+
(function (LazyAgentErrorCode) {
|
|
34
|
+
LazyAgentErrorCode["INIT_FAILED"] = "LAZY_AGENT_INIT_FAILED";
|
|
35
|
+
LazyAgentErrorCode["AUTO_ACCEPT_FAILED"] = "LAZY_AGENT_AUTO_ACCEPT_FAILED";
|
|
36
|
+
LazyAgentErrorCode["AGENT_CREATION_FAILED"] = "LAZY_AGENT_AGENT_CREATION_FAILED";
|
|
37
|
+
})(LazyAgentErrorCode || (LazyAgentErrorCode = {}));
|
|
38
|
+
/**
|
|
39
|
+
* Lazy agent wrapper.
|
|
40
|
+
*
|
|
41
|
+
* Proxies all Agent methods and initializes on first call.
|
|
42
|
+
* Caches the initialized agent for subsequent calls.
|
|
43
|
+
*/
|
|
44
|
+
export class LazyAgent {
|
|
45
|
+
config;
|
|
46
|
+
agent = null;
|
|
47
|
+
initPromise = null;
|
|
48
|
+
lastError = null;
|
|
49
|
+
constructor(config) {
|
|
50
|
+
this.config = config;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the agent's DID.
|
|
54
|
+
*
|
|
55
|
+
* Triggers initialization if not already initialized.
|
|
56
|
+
* Throws if initialization fails.
|
|
57
|
+
*/
|
|
58
|
+
get did() {
|
|
59
|
+
if (!this.agent) {
|
|
60
|
+
throw new Error('Agent not initialized. Call send/receive first or await ensureInitialized().');
|
|
61
|
+
}
|
|
62
|
+
return this.agent.did;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check if agent is ready (initialized).
|
|
66
|
+
*/
|
|
67
|
+
isReady() {
|
|
68
|
+
return this.agent !== null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get last initialization error (if any).
|
|
72
|
+
*/
|
|
73
|
+
getLastError() {
|
|
74
|
+
return this.lastError;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Ensure agent is initialized.
|
|
78
|
+
*
|
|
79
|
+
* Can be called explicitly to trigger init before first send/receive.
|
|
80
|
+
* Safe to call multiple times — subsequent calls return cached agent.
|
|
81
|
+
*
|
|
82
|
+
* @returns Agent instance or error
|
|
83
|
+
*/
|
|
84
|
+
async ensureInitialized() {
|
|
85
|
+
// If already initialized, return cached agent
|
|
86
|
+
if (this.agent) {
|
|
87
|
+
return ok(this.agent);
|
|
88
|
+
}
|
|
89
|
+
// If initialization is in progress, wait for it
|
|
90
|
+
if (this.initPromise) {
|
|
91
|
+
return this.initPromise;
|
|
92
|
+
}
|
|
93
|
+
// Start initialization
|
|
94
|
+
this.initPromise = this.initialize();
|
|
95
|
+
const result = await this.initPromise;
|
|
96
|
+
// Clear promise after completion (success or failure)
|
|
97
|
+
this.initPromise = null;
|
|
98
|
+
if (result.ok) {
|
|
99
|
+
this.agent = result.value;
|
|
100
|
+
this.lastError = null;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.lastError = {
|
|
104
|
+
code: LazyAgentErrorCode.INIT_FAILED,
|
|
105
|
+
message: `Agent initialization failed: ${result.error}`,
|
|
106
|
+
cause: result.error,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Internal initialization logic.
|
|
113
|
+
*
|
|
114
|
+
* 1. Auto-accept invite (if XBIND_INVITE_CODE set)
|
|
115
|
+
* 2. Create agent identity
|
|
116
|
+
* 3. Configure registry and transport
|
|
117
|
+
* 4. Return initialized agent
|
|
118
|
+
*/
|
|
119
|
+
async initialize() {
|
|
120
|
+
// Step 1: Attempt auto-accept if invite code is available
|
|
121
|
+
const inviteCode = this.config.inviteCode ?? this.getEnv('XBIND_INVITE_CODE');
|
|
122
|
+
let registry = this.config.registry;
|
|
123
|
+
let transport = this.config.transport;
|
|
124
|
+
const endpoint = this.config.endpoint ?? this.getEnv('XBIND_ENDPOINT') ?? '';
|
|
125
|
+
if (inviteCode) {
|
|
126
|
+
// Create temporary agent to get DID and public key for invite acceptance
|
|
127
|
+
const tempAgentResult = await Agent.create({
|
|
128
|
+
name: this.config.name,
|
|
129
|
+
registry: new MemoryTrustRegistry(),
|
|
130
|
+
transport: new HttpsTransportAdapter({ baseUrl: 'http://localhost' }), // Placeholder
|
|
131
|
+
postQuantumSig: this.config.postQuantumSig,
|
|
132
|
+
xchange: this.config.xchange,
|
|
133
|
+
});
|
|
134
|
+
if (!tempAgentResult.ok) {
|
|
135
|
+
return err(tempAgentResult.error);
|
|
136
|
+
}
|
|
137
|
+
const tempAgent = tempAgentResult.value;
|
|
138
|
+
// Export public key for invite acceptance
|
|
139
|
+
const seedsResult = await tempAgent.exportSeeds();
|
|
140
|
+
if (!seedsResult.ok) {
|
|
141
|
+
return err('IDENTITY_FAILED');
|
|
142
|
+
}
|
|
143
|
+
const publicKey = toBase64(tempAgent.identity.rawPublicKey);
|
|
144
|
+
const x25519PublicKey = tempAgent.identity.rawX25519PublicKey
|
|
145
|
+
? toBase64(tempAgent.identity.rawX25519PublicKey)
|
|
146
|
+
: undefined;
|
|
147
|
+
// Auto-accept invite
|
|
148
|
+
const acceptResult = await autoAcceptInvite({
|
|
149
|
+
inviteCode,
|
|
150
|
+
enabled: true,
|
|
151
|
+
registry: this.config.autoAccept?.registry,
|
|
152
|
+
inviteApiUrl: this.config.autoAccept?.inviteApiUrl,
|
|
153
|
+
}, {
|
|
154
|
+
name: this.config.name,
|
|
155
|
+
did: tempAgent.did,
|
|
156
|
+
endpoint,
|
|
157
|
+
publicKey,
|
|
158
|
+
x25519PublicKey,
|
|
159
|
+
});
|
|
160
|
+
if (!acceptResult.ok) {
|
|
161
|
+
this.lastError = {
|
|
162
|
+
code: LazyAgentErrorCode.AUTO_ACCEPT_FAILED,
|
|
163
|
+
message: acceptResult.error.message,
|
|
164
|
+
hint: acceptResult.error.hint,
|
|
165
|
+
cause: acceptResult.error,
|
|
166
|
+
};
|
|
167
|
+
// Non-fatal: continue with temp agent even if auto-accept fails
|
|
168
|
+
// (registry may already be configured)
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// Use auto-configured registry if not provided
|
|
172
|
+
if (!registry && acceptResult.value.registryAutoconfigured) {
|
|
173
|
+
// Registry was already configured by autoAcceptInvite
|
|
174
|
+
registry = this.config.autoAccept?.registry ?? new MemoryTrustRegistry();
|
|
175
|
+
}
|
|
176
|
+
// Use inviter's endpoint as default transport if not provided
|
|
177
|
+
if (!transport) {
|
|
178
|
+
transport = new HttpsTransportAdapter({
|
|
179
|
+
baseUrl: acceptResult.value.from.endpoint,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Return temp agent as initialized agent
|
|
184
|
+
this.agent = tempAgent;
|
|
185
|
+
return ok(tempAgent);
|
|
186
|
+
}
|
|
187
|
+
// Step 2: No invite code — create agent normally
|
|
188
|
+
const defaultRegistry = registry ?? new MemoryTrustRegistry();
|
|
189
|
+
const defaultTransport = transport ?? new HttpsTransportAdapter({
|
|
190
|
+
baseUrl: endpoint || 'http://localhost',
|
|
191
|
+
});
|
|
192
|
+
const agentResult = await Agent.create({
|
|
193
|
+
name: this.config.name,
|
|
194
|
+
registry: defaultRegistry,
|
|
195
|
+
transport: defaultTransport,
|
|
196
|
+
postQuantumSig: this.config.postQuantumSig,
|
|
197
|
+
xchange: this.config.xchange,
|
|
198
|
+
});
|
|
199
|
+
if (!agentResult.ok) {
|
|
200
|
+
this.lastError = {
|
|
201
|
+
code: LazyAgentErrorCode.AGENT_CREATION_FAILED,
|
|
202
|
+
message: `Agent creation failed: ${agentResult.error}`,
|
|
203
|
+
cause: agentResult.error,
|
|
204
|
+
};
|
|
205
|
+
return agentResult;
|
|
206
|
+
}
|
|
207
|
+
this.agent = agentResult.value;
|
|
208
|
+
return ok(this.agent);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Send a message (proxied to underlying agent).
|
|
212
|
+
*
|
|
213
|
+
* Automatically initializes agent on first call.
|
|
214
|
+
*/
|
|
215
|
+
async send(opts) {
|
|
216
|
+
const agentResult = await this.ensureInitialized();
|
|
217
|
+
if (!agentResult.ok) {
|
|
218
|
+
return agentResult;
|
|
219
|
+
}
|
|
220
|
+
return agentResult.value.send(opts);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Receive a message (proxied to underlying agent).
|
|
224
|
+
*
|
|
225
|
+
* Automatically initializes agent on first call.
|
|
226
|
+
*/
|
|
227
|
+
async receive(envelope, opts) {
|
|
228
|
+
const agentResult = await this.ensureInitialized();
|
|
229
|
+
if (!agentResult.ok) {
|
|
230
|
+
return err(agentResult.error);
|
|
231
|
+
}
|
|
232
|
+
return agentResult.value.receive(envelope, opts);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Receive a split-channel share (proxied to underlying agent).
|
|
236
|
+
*
|
|
237
|
+
* Automatically initializes agent on first call.
|
|
238
|
+
*/
|
|
239
|
+
async receiveSplitShare(envelope) {
|
|
240
|
+
const agentResult = await this.ensureInitialized();
|
|
241
|
+
if (!agentResult.ok) {
|
|
242
|
+
return err(agentResult.error);
|
|
243
|
+
}
|
|
244
|
+
return agentResult.value.receiveSplitShare(envelope);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get environment variable value.
|
|
248
|
+
*
|
|
249
|
+
* @param key - Environment variable name
|
|
250
|
+
* @returns Environment variable value or empty string
|
|
251
|
+
*/
|
|
252
|
+
getEnv(key) {
|
|
253
|
+
// SAFETY: Check for Node.js environment before accessing process
|
|
254
|
+
if (typeof process !== 'undefined' && typeof process.env !== 'undefined') {
|
|
255
|
+
return process.env[key] ?? '';
|
|
256
|
+
}
|
|
257
|
+
return '';
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Export the underlying agent (for advanced use cases).
|
|
261
|
+
*
|
|
262
|
+
* Throws if agent is not initialized.
|
|
263
|
+
*/
|
|
264
|
+
getAgent() {
|
|
265
|
+
if (!this.agent) {
|
|
266
|
+
throw new Error('Agent not initialized. Call send/receive first or await ensureInitialized().');
|
|
267
|
+
}
|
|
268
|
+
return this.agent;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Create a lazy agent that initializes on first use.
|
|
273
|
+
*
|
|
274
|
+
* Extension method for Agent class. Adds `Agent.lazy()` factory.
|
|
275
|
+
*
|
|
276
|
+
* @param config - Lazy agent configuration
|
|
277
|
+
* @returns Lazy agent wrapper
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* // Environment: XBIND_INVITE_CODE=XBD-abc123
|
|
282
|
+
*
|
|
283
|
+
* const agent = createLazyAgent({ name: 'my-service' });
|
|
284
|
+
*
|
|
285
|
+
* // No initialization yet — happens on first send:
|
|
286
|
+
* await agent.send({
|
|
287
|
+
* to: 'did:key:z6Mk...',
|
|
288
|
+
* payload: { action: 'test' },
|
|
289
|
+
* scope: 'test',
|
|
290
|
+
* });
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
export function createLazyAgent(config) {
|
|
294
|
+
return new LazyAgent(config);
|
|
295
|
+
}
|