acp-runtime 0.1.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.
@@ -0,0 +1,17 @@
1
+ import { JsonMap } from "./jsonSupport.js";
2
+ export declare const DEFAULT_AMQP_EXCHANGE = "acp.exchange";
3
+ export declare const DEFAULT_AMQP_EXCHANGE_TYPE = "direct";
4
+ export type AmqpMessageHandler = (message: JsonMap) => boolean | Promise<boolean>;
5
+ export declare class AmqpTransportClient {
6
+ readonly broker_url: string;
7
+ readonly exchange: string;
8
+ readonly exchange_type: string;
9
+ readonly timeout_seconds: number;
10
+ constructor(brokerUrl: string, exchange?: string, exchangeType?: string, timeoutSeconds?: number);
11
+ static agentIdentifierToken(agentId: string): string;
12
+ static queueNameForAgent(agentId: string): string;
13
+ static routingKeyForAgent(agentId: string): string;
14
+ static buildServiceHint(agentId: string, brokerUrl: string, exchange?: string): JsonMap;
15
+ publish(message: JsonMap, recipientAgentId: string, service?: JsonMap): Promise<void>;
16
+ consume(agentId: string, handler: AmqpMessageHandler, service?: JsonMap, maxMessages?: number): Promise<number>;
17
+ }
@@ -0,0 +1,164 @@
1
+ /*
2
+ * Copyright 2026 ACP Project
3
+ * Licensed under the Apache License, Version 2.0
4
+ * See LICENSE file for details.
5
+ */
6
+ import { connect } from "amqplib";
7
+ import { invalidArgument, transportError, validationError } from "./errors.js";
8
+ export const DEFAULT_AMQP_EXCHANGE = "acp.exchange";
9
+ export const DEFAULT_AMQP_EXCHANGE_TYPE = "direct";
10
+ function pickString(service, key, fallback) {
11
+ const value = service?.[key];
12
+ if (typeof value === "string" && value.trim()) {
13
+ return value.trim();
14
+ }
15
+ return fallback;
16
+ }
17
+ function metadataHeaders(message) {
18
+ const envelope = message.envelope && typeof message.envelope === "object" && !Array.isArray(message.envelope)
19
+ ? message.envelope
20
+ : {};
21
+ const headers = {};
22
+ for (const [source, destination] of [
23
+ ["acp_version", "acp_version"],
24
+ ["message_class", "acp_message_class"],
25
+ ["message_id", "acp_message_id"],
26
+ ["operation_id", "acp_operation_id"],
27
+ ["sender", "acp_sender"]
28
+ ]) {
29
+ const value = envelope[source];
30
+ if (typeof value === "string" && value.trim()) {
31
+ headers[destination] = value.trim();
32
+ }
33
+ }
34
+ return headers;
35
+ }
36
+ export class AmqpTransportClient {
37
+ broker_url;
38
+ exchange;
39
+ exchange_type;
40
+ timeout_seconds;
41
+ constructor(brokerUrl, exchange, exchangeType, timeoutSeconds = 10) {
42
+ if (!brokerUrl.trim()) {
43
+ throw invalidArgument("broker_url must be provided");
44
+ }
45
+ this.broker_url = brokerUrl;
46
+ this.exchange = exchange?.trim() || DEFAULT_AMQP_EXCHANGE;
47
+ this.exchange_type = exchangeType?.trim() || DEFAULT_AMQP_EXCHANGE_TYPE;
48
+ this.timeout_seconds = Math.max(1, timeoutSeconds);
49
+ }
50
+ static agentIdentifierToken(agentId) {
51
+ const match = /^agent:(?<name>[^@]+)(?:@(?<domain>.+))?$/.exec(agentId);
52
+ if (!match?.groups?.name) {
53
+ throw validationError(`Invalid agent identifier: ${agentId}`);
54
+ }
55
+ const base = match.groups.domain ? `${match.groups.name}.${match.groups.domain}` : match.groups.name;
56
+ const normalized = base
57
+ .split("")
58
+ .map((char) => (/^[A-Za-z0-9._-]$/.test(char) ? char : "."))
59
+ .join("")
60
+ .split(".")
61
+ .filter((segment) => segment.length > 0)
62
+ .join(".");
63
+ return normalized || "unknown";
64
+ }
65
+ static queueNameForAgent(agentId) {
66
+ return `acp.agent.${AmqpTransportClient.agentIdentifierToken(agentId)}`;
67
+ }
68
+ static routingKeyForAgent(agentId) {
69
+ return `agent.${AmqpTransportClient.agentIdentifierToken(agentId)}`;
70
+ }
71
+ static buildServiceHint(agentId, brokerUrl, exchange) {
72
+ return {
73
+ broker_url: brokerUrl,
74
+ exchange: exchange?.trim() || DEFAULT_AMQP_EXCHANGE,
75
+ queue: AmqpTransportClient.queueNameForAgent(agentId),
76
+ routing_key: AmqpTransportClient.routingKeyForAgent(agentId)
77
+ };
78
+ }
79
+ async publish(message, recipientAgentId, service) {
80
+ const brokerUrl = pickString(service, "broker_url", this.broker_url);
81
+ const exchange = pickString(service, "exchange", this.exchange);
82
+ const queue = pickString(service, "queue", AmqpTransportClient.queueNameForAgent(recipientAgentId));
83
+ const routingKey = pickString(service, "routing_key", AmqpTransportClient.routingKeyForAgent(recipientAgentId));
84
+ const body = JSON.stringify(message);
85
+ const headers = metadataHeaders(message);
86
+ let connection;
87
+ let channel;
88
+ try {
89
+ connection = await connect(brokerUrl);
90
+ channel = await connection.createChannel();
91
+ await channel.assertExchange(exchange, this.exchange_type, { durable: true });
92
+ await channel.assertQueue(queue, { durable: true });
93
+ await channel.bindQueue(queue, exchange, routingKey);
94
+ channel.publish(exchange, routingKey, Buffer.from(body, "utf-8"), {
95
+ contentType: "application/json",
96
+ deliveryMode: 2,
97
+ headers
98
+ });
99
+ await channel.close();
100
+ await connection.close();
101
+ }
102
+ catch (error) {
103
+ if (channel) {
104
+ await channel.close().catch(() => undefined);
105
+ }
106
+ if (connection) {
107
+ await connection.close().catch(() => undefined);
108
+ }
109
+ throw transportError(`amqp publish failed: ${String(error)}`);
110
+ }
111
+ }
112
+ async consume(agentId, handler, service, maxMessages = 0) {
113
+ const brokerUrl = pickString(service, "broker_url", this.broker_url);
114
+ const exchange = pickString(service, "exchange", this.exchange);
115
+ const queue = pickString(service, "queue", AmqpTransportClient.queueNameForAgent(agentId));
116
+ const routingKey = pickString(service, "routing_key", AmqpTransportClient.routingKeyForAgent(agentId));
117
+ const limit = maxMessages === 0 ? Number.MAX_SAFE_INTEGER : maxMessages;
118
+ let processed = 0;
119
+ let connection;
120
+ let channel;
121
+ try {
122
+ connection = await connect(brokerUrl);
123
+ channel = await connection.createChannel();
124
+ await channel.assertExchange(exchange, this.exchange_type, { durable: true });
125
+ await channel.assertQueue(queue, { durable: true });
126
+ await channel.bindQueue(queue, exchange, routingKey);
127
+ while (processed < limit) {
128
+ const result = await channel.get(queue, { noAck: false });
129
+ if (!result) {
130
+ break;
131
+ }
132
+ let shouldAck = false;
133
+ try {
134
+ const parsed = JSON.parse(result.content.toString("utf-8"));
135
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
136
+ shouldAck = await handler(parsed);
137
+ }
138
+ }
139
+ catch {
140
+ shouldAck = false;
141
+ }
142
+ if (shouldAck) {
143
+ channel.ack(result);
144
+ }
145
+ else {
146
+ channel.nack(result, false, true);
147
+ }
148
+ processed += 1;
149
+ }
150
+ await channel.close();
151
+ await connection.close();
152
+ return processed;
153
+ }
154
+ catch (error) {
155
+ if (channel) {
156
+ await channel.close().catch(() => undefined);
157
+ }
158
+ if (connection) {
159
+ await connection.close().catch(() => undefined);
160
+ }
161
+ throw transportError(`amqp consume failed: ${String(error)}`);
162
+ }
163
+ }
164
+ }
@@ -0,0 +1,16 @@
1
+ import { JsonMap } from "./jsonSupport.js";
2
+ export interface CapabilityMatch {
3
+ compatible: boolean;
4
+ reason?: string;
5
+ }
6
+ export declare class AgentCapabilities {
7
+ agent_id: string;
8
+ protocol_versions: string[];
9
+ crypto_suites: string[];
10
+ transports: string[];
11
+ supports: Record<string, boolean>;
12
+ constructor(agentId: string);
13
+ toMap(): JsonMap;
14
+ static fromMap(map: JsonMap | undefined, fallbackAgentId: string): AgentCapabilities;
15
+ chooseCompatible(remote: AgentCapabilities): CapabilityMatch;
16
+ }
@@ -0,0 +1,81 @@
1
+ /*
2
+ * Copyright 2026 ACP Project
3
+ * Licensed under the Apache License, Version 2.0
4
+ * See LICENSE file for details.
5
+ */
6
+ import { ACP_VERSION, DEFAULT_CRYPTO_SUITE } from "./constants.js";
7
+ export class AgentCapabilities {
8
+ agent_id;
9
+ protocol_versions;
10
+ crypto_suites;
11
+ transports;
12
+ supports;
13
+ constructor(agentId) {
14
+ this.agent_id = agentId;
15
+ this.protocol_versions = [ACP_VERSION];
16
+ this.crypto_suites = [DEFAULT_CRYPTO_SUITE];
17
+ this.transports = ["https", "http", "relay", "amqp", "mqtt"];
18
+ this.supports = {
19
+ capabilities: true,
20
+ compensate: true,
21
+ amqp: true,
22
+ mqtt: true,
23
+ overlay: true
24
+ };
25
+ }
26
+ toMap() {
27
+ return {
28
+ agent_id: this.agent_id,
29
+ protocol_versions: [...this.protocol_versions],
30
+ crypto_suites: [...this.crypto_suites],
31
+ transports: [...this.transports],
32
+ supports: { ...this.supports }
33
+ };
34
+ }
35
+ static fromMap(map, fallbackAgentId) {
36
+ const capabilities = new AgentCapabilities(fallbackAgentId);
37
+ if (!map) {
38
+ return capabilities;
39
+ }
40
+ const agentId = typeof map.agent_id === "string" ? map.agent_id : fallbackAgentId;
41
+ capabilities.agent_id = agentId;
42
+ if (Array.isArray(map.protocol_versions)) {
43
+ capabilities.protocol_versions = map.protocol_versions
44
+ .filter((item) => typeof item === "string")
45
+ .map((item) => item.trim())
46
+ .filter((item) => item.length > 0);
47
+ }
48
+ if (Array.isArray(map.crypto_suites)) {
49
+ capabilities.crypto_suites = map.crypto_suites
50
+ .filter((item) => typeof item === "string")
51
+ .map((item) => item.trim())
52
+ .filter((item) => item.length > 0);
53
+ }
54
+ if (Array.isArray(map.transports)) {
55
+ capabilities.transports = map.transports
56
+ .filter((item) => typeof item === "string")
57
+ .map((item) => item.trim().toLowerCase())
58
+ .filter((item) => item.length > 0);
59
+ }
60
+ if (map.supports && typeof map.supports === "object" && !Array.isArray(map.supports)) {
61
+ const supports = {};
62
+ for (const [key, value] of Object.entries(map.supports)) {
63
+ supports[key] = Boolean(value);
64
+ }
65
+ capabilities.supports = supports;
66
+ }
67
+ return capabilities;
68
+ }
69
+ chooseCompatible(remote) {
70
+ if (!this.protocol_versions.some((version) => remote.protocol_versions.includes(version))) {
71
+ return { compatible: false, reason: "No compatible protocol version" };
72
+ }
73
+ if (!this.crypto_suites.some((suite) => remote.crypto_suites.includes(suite))) {
74
+ return { compatible: false, reason: "No compatible crypto suite" };
75
+ }
76
+ if (!this.transports.some((transport) => remote.transports.includes(transport))) {
77
+ return { compatible: false, reason: "No compatible transport" };
78
+ }
79
+ return { compatible: true };
80
+ }
81
+ }
@@ -0,0 +1,7 @@
1
+ export declare const ACP_VERSION = "1.0";
2
+ export declare const ACP_IDENTITY_VERSION = "1.0";
3
+ export declare const DEFAULT_CRYPTO_SUITE = "ACP-AES256-GCM+X25519+ED25519";
4
+ export declare const DEFAULT_IDENTITY_DOCUMENT_PATH = "/api/v1/acp/identity";
5
+ export declare const TRUST_PROFILES: readonly ["self_asserted", "domain_verified"];
6
+ export type TrustProfile = (typeof TRUST_PROFILES)[number];
7
+ export declare function isSupportedTrustProfile(value: string): value is TrustProfile;
@@ -0,0 +1,13 @@
1
+ /*
2
+ * Copyright 2026 ACP Project
3
+ * Licensed under the Apache License, Version 2.0
4
+ * See LICENSE file for details.
5
+ */
6
+ export const ACP_VERSION = "1.0";
7
+ export const ACP_IDENTITY_VERSION = "1.0";
8
+ export const DEFAULT_CRYPTO_SUITE = "ACP-AES256-GCM+X25519+ED25519";
9
+ export const DEFAULT_IDENTITY_DOCUMENT_PATH = "/api/v1/acp/identity";
10
+ export const TRUST_PROFILES = ["self_asserted", "domain_verified"];
11
+ export function isSupportedTrustProfile(value) {
12
+ return TRUST_PROFILES.includes(value);
13
+ }
@@ -0,0 +1,20 @@
1
+ import { JsonMap } from "./jsonSupport.js";
2
+ import { Envelope, ProtectedPayload } from "./messages.js";
3
+ export declare function sha256Hex(input: Uint8Array): string;
4
+ export declare function generateEd25519Keypair(): {
5
+ private_key: string;
6
+ public_key: string;
7
+ };
8
+ export declare function ed25519PublicFromPrivate(signingPrivateKeyB64: string): string;
9
+ export declare function generateX25519Keypair(): {
10
+ private_key: string;
11
+ public_key: string;
12
+ };
13
+ export declare function x25519PublicFromPrivate(encryptionPrivateKeyB64: string): string;
14
+ export declare function signBytes(data: Uint8Array, signingPrivateKeyB64: string): string;
15
+ export declare function verifySignature(data: Uint8Array, signatureB64: string, signingPublicKeyB64: string): boolean;
16
+ export declare function envelopeAad(envelope: Envelope): Uint8Array;
17
+ export declare function encryptForRecipients(payload: JsonMap, envelope: Envelope, recipientEncryptionPublicKeys: Record<string, string>): ProtectedPayload;
18
+ export declare function signProtectedPayload(envelope: Envelope, protectedPayload: ProtectedPayload, signingPrivateKeyB64: string, signatureKid: string): ProtectedPayload;
19
+ export declare function verifyProtectedPayloadSignature(envelope: Envelope, protectedPayload: ProtectedPayload, senderSigningPublicKeyB64: string): boolean;
20
+ export declare function decryptForRecipient(envelope: Envelope, protectedPayload: ProtectedPayload, recipientId: string, recipientEncryptionPrivateKeyB64: string): JsonMap;
package/dist/crypto.js ADDED
@@ -0,0 +1,173 @@
1
+ /*
2
+ * Copyright 2026 ACP Project
3
+ * Licensed under the Apache License, Version 2.0
4
+ * See LICENSE file for details.
5
+ */
6
+ import { createCipheriv, createDecipheriv, createHash, hkdfSync, randomBytes } from "node:crypto";
7
+ import nacl from "tweetnacl";
8
+ import { cryptoError } from "./errors.js";
9
+ import { canonicalJsonBytes, parseJsonMap } from "./jsonSupport.js";
10
+ function toBase64Url(bytes) {
11
+ return Buffer.from(bytes).toString("base64url");
12
+ }
13
+ function fromBase64Url(value) {
14
+ try {
15
+ return Buffer.from(value, "base64url");
16
+ }
17
+ catch (error) {
18
+ throw cryptoError(`invalid base64 value: ${String(error)}`);
19
+ }
20
+ }
21
+ function asFixedBytes(value, length, label) {
22
+ if (value.length !== length) {
23
+ throw cryptoError(`invalid ${label} length`);
24
+ }
25
+ return value;
26
+ }
27
+ export function sha256Hex(input) {
28
+ return createHash("sha256").update(input).digest("hex");
29
+ }
30
+ export function generateEd25519Keypair() {
31
+ const seed = randomBytes(32);
32
+ const keypair = nacl.sign.keyPair.fromSeed(seed);
33
+ return {
34
+ private_key: toBase64Url(seed),
35
+ public_key: toBase64Url(keypair.publicKey)
36
+ };
37
+ }
38
+ export function ed25519PublicFromPrivate(signingPrivateKeyB64) {
39
+ const seed = asFixedBytes(fromBase64Url(signingPrivateKeyB64), 32, "Ed25519 private key");
40
+ return toBase64Url(nacl.sign.keyPair.fromSeed(seed).publicKey);
41
+ }
42
+ export function generateX25519Keypair() {
43
+ const keypair = nacl.box.keyPair();
44
+ return {
45
+ private_key: toBase64Url(keypair.secretKey),
46
+ public_key: toBase64Url(keypair.publicKey)
47
+ };
48
+ }
49
+ export function x25519PublicFromPrivate(encryptionPrivateKeyB64) {
50
+ const privateKey = asFixedBytes(fromBase64Url(encryptionPrivateKeyB64), 32, "X25519 private key");
51
+ const keypair = nacl.box.keyPair.fromSecretKey(privateKey);
52
+ return toBase64Url(keypair.publicKey);
53
+ }
54
+ export function signBytes(data, signingPrivateKeyB64) {
55
+ const seed = asFixedBytes(fromBase64Url(signingPrivateKeyB64), 32, "Ed25519 private key");
56
+ const signingKeypair = nacl.sign.keyPair.fromSeed(seed);
57
+ const signature = nacl.sign.detached(data, signingKeypair.secretKey);
58
+ return toBase64Url(signature);
59
+ }
60
+ export function verifySignature(data, signatureB64, signingPublicKeyB64) {
61
+ const signature = fromBase64Url(signatureB64);
62
+ const publicKey = fromBase64Url(signingPublicKeyB64);
63
+ if (signature.length !== nacl.sign.signatureLength || publicKey.length !== nacl.sign.publicKeyLength) {
64
+ return false;
65
+ }
66
+ return nacl.sign.detached.verify(data, signature, publicKey);
67
+ }
68
+ export function envelopeAad(envelope) {
69
+ return canonicalJsonBytes({
70
+ acp_version: envelope.acp_version,
71
+ message_id: envelope.message_id,
72
+ operation_id: envelope.operation_id,
73
+ sender: envelope.sender,
74
+ recipients: envelope.recipients
75
+ });
76
+ }
77
+ function deriveWrapKey(sharedSecret, recipient) {
78
+ const derived = hkdfSync("sha256", sharedSecret, Buffer.alloc(0), `acp-v1-wrap:${recipient}`, 32);
79
+ return new Uint8Array(derived);
80
+ }
81
+ function encryptAesGcm(key, nonce, plaintext, aad) {
82
+ const cipher = createCipheriv("aes-256-gcm", key, nonce);
83
+ cipher.setAAD(aad);
84
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
85
+ const authTag = cipher.getAuthTag();
86
+ return Buffer.concat([ciphertext, authTag]);
87
+ }
88
+ function decryptAesGcm(key, nonce, ciphertextWithTag, aad) {
89
+ if (ciphertextWithTag.length < 16) {
90
+ throw cryptoError("ciphertext is too short");
91
+ }
92
+ const ciphertext = ciphertextWithTag.subarray(0, ciphertextWithTag.length - 16);
93
+ const tag = ciphertextWithTag.subarray(ciphertextWithTag.length - 16);
94
+ const decipher = createDecipheriv("aes-256-gcm", key, nonce);
95
+ decipher.setAAD(aad);
96
+ decipher.setAuthTag(tag);
97
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
98
+ }
99
+ export function encryptForRecipients(payload, envelope, recipientEncryptionPublicKeys) {
100
+ const plaintext = canonicalJsonBytes(payload);
101
+ const contentKey = randomBytes(32);
102
+ const payloadNonce = randomBytes(12);
103
+ const payloadCiphertext = encryptAesGcm(contentKey, payloadNonce, plaintext, envelopeAad(envelope));
104
+ const ephemeral = nacl.box.keyPair();
105
+ const wrappedContentKeys = [];
106
+ for (const [recipient, recipientPublicKeyB64] of Object.entries(recipientEncryptionPublicKeys)) {
107
+ const recipientPublicKey = asFixedBytes(fromBase64Url(recipientPublicKeyB64), 32, "X25519 public key");
108
+ const sharedSecret = nacl.scalarMult(ephemeral.secretKey, recipientPublicKey);
109
+ const wrapKey = deriveWrapKey(sharedSecret, recipient);
110
+ const wrapNonce = randomBytes(12);
111
+ const wrappedContentKey = encryptAesGcm(wrapKey, wrapNonce, contentKey, new TextEncoder().encode(envelope.message_id));
112
+ wrappedContentKeys.push({
113
+ recipient,
114
+ ephemeral_public_key: toBase64Url(ephemeral.publicKey),
115
+ nonce: toBase64Url(wrapNonce),
116
+ ciphertext: toBase64Url(wrappedContentKey)
117
+ });
118
+ }
119
+ return {
120
+ nonce: toBase64Url(payloadNonce),
121
+ ciphertext: toBase64Url(payloadCiphertext),
122
+ wrapped_content_keys: wrappedContentKeys,
123
+ payload_hash: sha256Hex(payloadCiphertext),
124
+ signature_kid: "",
125
+ signature: ""
126
+ };
127
+ }
128
+ function messageSignatureInput(envelope, protectedPayload) {
129
+ const signableProtected = {
130
+ nonce: protectedPayload.nonce,
131
+ ciphertext: protectedPayload.ciphertext,
132
+ wrapped_content_keys: [...protectedPayload.wrapped_content_keys].sort((a, b) => a.recipient.localeCompare(b.recipient)),
133
+ payload_hash: protectedPayload.payload_hash,
134
+ signature_kid: protectedPayload.signature_kid
135
+ };
136
+ return canonicalJsonBytes({
137
+ envelope,
138
+ protected: signableProtected
139
+ });
140
+ }
141
+ export function signProtectedPayload(envelope, protectedPayload, signingPrivateKeyB64, signatureKid) {
142
+ const signedPayload = {
143
+ ...protectedPayload,
144
+ signature_kid: signatureKid
145
+ };
146
+ const signatureInput = messageSignatureInput(envelope, signedPayload);
147
+ signedPayload.signature = signBytes(signatureInput, signingPrivateKeyB64);
148
+ return signedPayload;
149
+ }
150
+ export function verifyProtectedPayloadSignature(envelope, protectedPayload, senderSigningPublicKeyB64) {
151
+ if (!protectedPayload.signature.trim()) {
152
+ return false;
153
+ }
154
+ const signatureInput = messageSignatureInput(envelope, protectedPayload);
155
+ return verifySignature(signatureInput, protectedPayload.signature, senderSigningPublicKeyB64);
156
+ }
157
+ export function decryptForRecipient(envelope, protectedPayload, recipientId, recipientEncryptionPrivateKeyB64) {
158
+ const wrapped = protectedPayload.wrapped_content_keys.find((item) => item.recipient === recipientId);
159
+ if (!wrapped) {
160
+ throw cryptoError(`No wrapped content key available for recipient ${recipientId}`);
161
+ }
162
+ const recipientPrivateKey = asFixedBytes(fromBase64Url(recipientEncryptionPrivateKeyB64), 32, "X25519 private key");
163
+ const ephemeralPublicKey = asFixedBytes(fromBase64Url(wrapped.ephemeral_public_key), 32, "X25519 public key");
164
+ const sharedSecret = nacl.scalarMult(recipientPrivateKey, ephemeralPublicKey);
165
+ const wrapKey = deriveWrapKey(sharedSecret, recipientId);
166
+ const wrappedNonce = asFixedBytes(fromBase64Url(wrapped.nonce), 12, "wrapped nonce");
167
+ const wrappedCiphertext = fromBase64Url(wrapped.ciphertext);
168
+ const contentKey = decryptAesGcm(wrapKey, wrappedNonce, wrappedCiphertext, new TextEncoder().encode(envelope.message_id));
169
+ const payloadNonce = asFixedBytes(fromBase64Url(protectedPayload.nonce), 12, "payload nonce");
170
+ const payloadCiphertext = fromBase64Url(protectedPayload.ciphertext);
171
+ const plaintext = decryptAesGcm(contentKey, payloadNonce, payloadCiphertext, envelopeAad(envelope));
172
+ return parseJsonMap(new TextDecoder().decode(plaintext));
173
+ }
@@ -0,0 +1,26 @@
1
+ import { HttpSecurityPolicy } from "./httpSecurity.js";
2
+ import { JsonMap } from "./jsonSupport.js";
3
+ export declare class DiscoveryClient {
4
+ private readonly cache_path;
5
+ private readonly default_scheme;
6
+ private readonly relay_hints;
7
+ private readonly enterprise_directory_hints;
8
+ private readonly timeout_seconds;
9
+ private readonly policy;
10
+ private readonly cache;
11
+ private readonly registry;
12
+ private readonly fetchOptions;
13
+ constructor(cache_path: string | undefined, default_scheme?: string, relay_hints?: string[], enterprise_directory_hints?: string[], timeout_seconds?: number, policy?: HttpSecurityPolicy);
14
+ seed(identityDocument: JsonMap): void;
15
+ registerIdentityDocument(identityDocument: JsonMap): void;
16
+ resolve(agentId: string): Promise<JsonMap>;
17
+ resolveWellKnown(baseUrl: string, expectedAgentId?: string): Promise<JsonMap>;
18
+ private tryCache;
19
+ private tryWellKnown;
20
+ private tryHintLookups;
21
+ private resolveWellKnownUrl;
22
+ private fetchJson;
23
+ private cacheIdentity;
24
+ private loadCache;
25
+ private persistCache;
26
+ }