@calimero-network/mero-js 25.0.7 → 25.1.1

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/dist/index.cjs CHANGED
@@ -31,10 +31,13 @@ var index_exports = {};
31
31
  __export(index_exports, {
32
32
  ACCOUNT_HA_AUDIENCE: () => ACCOUNT_HA_AUDIENCE,
33
33
  ACCOUNT_OWNERSHIP_AUDIENCE: () => ACCOUNT_OWNERSHIP_AUDIENCE,
34
+ AGENT_ATTEST_DOMAIN: () => AGENT_ATTEST_DOMAIN,
35
+ AGENT_PROVISION_INFO_DOMAIN: () => AGENT_PROVISION_INFO_DOMAIN,
34
36
  AccountHaRefusedError: () => AccountHaRefusedError,
35
37
  AccountLinkedToSeveralUsersError: () => AccountLinkedToSeveralUsersError,
36
38
  AccountNotLinkedError: () => AccountNotLinkedError,
37
39
  AdminApiClient: () => AdminApiClient,
40
+ AgentGateError: () => AgentGateError,
38
41
  AuthApiClient: () => AuthApiClient,
39
42
  AuthRevokedError: () => AuthRevokedError,
40
43
  CAPABILITIES: () => CAPABILITIES,
@@ -51,6 +54,7 @@ __export(index_exports, {
51
54
  INVITED_ROLE: () => INVITED_ROLE,
52
55
  IntentRefusedError: () => IntentRefusedError,
53
56
  InvitationNotClaimableError: () => InvitationNotClaimableError,
57
+ KMS_RELEASE_SIGNER: () => KMS_RELEASE_SIGNER,
54
58
  LocalStorageTokenStore: () => LocalStorageTokenStore,
55
59
  MAX_INVITATION_VALIDITY_SECS: () => MAX_INVITATION_VALIDITY_SECS,
56
60
  MemoryTokenStore: () => MemoryTokenStore,
@@ -89,8 +93,11 @@ __export(index_exports, {
89
93
  accountRootSignerFromPhrase: () => accountRootSignerFromPhrase,
90
94
  adminChangedOp: () => adminChangedOp,
91
95
  admitterAddrsFromNetworkStatus: () => admitterAddrsFromNetworkStatus,
96
+ agentKeyBinding: () => agentKeyBinding,
97
+ agentQuoteVerifier: () => agentQuoteVerifier,
92
98
  applicationIdForBundle: () => applicationIdForBundle,
93
99
  attemptRelayNodeKey: () => attemptRelayNodeKey,
100
+ attestAgent: () => attestAgent,
94
101
  attestKeyBinding: () => attestKeyBinding,
95
102
  attestRelayNodeKey: () => attestRelayNodeKey,
96
103
  authorNonceLookup: () => authorNonceLookup,
@@ -104,6 +111,7 @@ __export(index_exports, {
104
111
  capMask: () => capMask,
105
112
  capNames: () => capNames,
106
113
  carryExecutorAccount: () => carryExecutorAccount,
114
+ checkOwner: () => checkOwner,
107
115
  classifyError: () => classifyError,
108
116
  clearDelegatedCredential: () => clearDelegatedCredential,
109
117
  clearDelegatedSession: () => clearDelegatedSession,
@@ -171,6 +179,7 @@ __export(index_exports, {
171
179
  foundDelegatedNamespace: () => foundDelegatedNamespace,
172
180
  foundedNamespaceId: () => foundedNamespaceId,
173
181
  generateAccountRoot: () => generateAccountRoot,
182
+ generateOwnerKey: () => generateOwnerKey,
174
183
  generateSessionKey: () => generateSessionKey,
175
184
  governGroup: () => governGroup,
176
185
  governRoot: () => governRoot,
@@ -211,6 +220,7 @@ __export(index_exports, {
211
220
  normaliseAccount: () => normaliseAccount,
212
221
  ownerOpDigest: () => ownerOpDigest,
213
222
  ownerOpSigningPayload: () => ownerOpSigningPayload,
223
+ ownerPublicKey: () => ownerPublicKey,
214
224
  parseAuthCallback: () => parseAuthCallback,
215
225
  parseCreationWarrant: () => parseCreationWarrant,
216
226
  parseDeviceCredential: () => parseDeviceCredential,
@@ -220,6 +230,8 @@ __export(index_exports, {
220
230
  pinRelayNodeKey: () => pinRelayNodeKey,
221
231
  presenceStatementBytes: () => presenceStatementBytes,
222
232
  probeNodeHealth: () => probeNodeHealth,
233
+ provisionAgent: () => provisionAgent,
234
+ provisionInfo: () => provisionInfo,
223
235
  readCloudLinkCallback: () => readCloudLinkCallback,
224
236
  readDelegatedCredential: () => readDelegatedCredential,
225
237
  readDelegatedSession: () => readDelegatedSession,
@@ -229,6 +241,7 @@ __export(index_exports, {
229
241
  redeemInvitation: () => redeemInvitation,
230
242
  relayForContext: () => relayForContext,
231
243
  relayTransportFetch: () => relayTransportFetch,
244
+ releaseAgent: () => releaseAgent,
232
245
  rememberGroupNamespace: () => rememberGroupNamespace,
233
246
  rememberRelay: () => rememberRelay,
234
247
  reportDataOf: () => reportDataOf,
@@ -275,7 +288,9 @@ __export(index_exports, {
275
288
  transportKeyBinding: () => transportKeyBinding,
276
289
  trustSignedRelease: () => trustSignedRelease,
277
290
  trustedMeasurementsFromReleases: () => trustedMeasurementsFromReleases,
291
+ validateAgentId: () => validateAgentId,
278
292
  verifyDeviceCredential: () => verifyDeviceCredential,
293
+ verifySignedAgentPolicy: () => verifySignedAgentPolicy,
279
294
  verifySignedNodeRelease: () => verifySignedNodeRelease,
280
295
  withCap: () => withCap,
281
296
  withRetry: () => withRetry,
@@ -333,14 +348,14 @@ function extractErrorMessage(bodyText) {
333
348
  return void 0;
334
349
  }
335
350
  var HTTPError = class extends Error {
336
- constructor(status, statusText, url, headers, bodyText) {
351
+ constructor(status, statusText, url2, headers, bodyText) {
337
352
  const explanation = extractErrorMessage(bodyText) ?? (status === 0 && bodyText?.trim() ? bodyText.trim() : void 0);
338
353
  super(
339
354
  explanation ? `HTTP ${status} ${statusText}: ${explanation}` : `HTTP ${status} ${statusText}`
340
355
  );
341
356
  this.status = status;
342
357
  this.statusText = statusText;
343
- this.url = url;
358
+ this.url = url2;
344
359
  this.headers = headers;
345
360
  this.bodyText = bodyText;
346
361
  this.name = "HTTPError";
@@ -357,8 +372,8 @@ var HTTPError = class extends Error {
357
372
  }
358
373
  };
359
374
  var AuthRevokedError = class extends HTTPError {
360
- constructor(reason, status, statusText, url, headers, bodyText) {
361
- super(status, statusText, url, headers, bodyText);
375
+ constructor(reason, status, statusText, url2, headers, bodyText) {
376
+ super(status, statusText, url2, headers, bodyText);
362
377
  this.reason = reason;
363
378
  this.name = "AuthRevokedError";
364
379
  this.message = `Authentication revoked (${reason}): HTTP ${status} ${statusText}`;
@@ -371,12 +386,12 @@ function headersToRecord(headers) {
371
386
  });
372
387
  return record;
373
388
  }
374
- function pathForProof(url) {
389
+ function pathForProof(url2) {
375
390
  try {
376
- return new URL(url).pathname;
391
+ return new URL(url2).pathname;
377
392
  } catch {
378
- const query = url.indexOf("?");
379
- return query === -1 ? url : url.slice(0, query);
393
+ const query = url2.indexOf("?");
394
+ return query === -1 ? url2 : url2.slice(0, query);
380
395
  }
381
396
  }
382
397
  var WebHttpClient = class {
@@ -442,7 +457,7 @@ var WebHttpClient = class {
442
457
  }
443
458
  async makeRequest(path, init, retryCount = 0, requestStartTime) {
444
459
  const MAX_RETRY_ATTEMPTS = 1;
445
- const url = this.buildUrl(path);
460
+ const url2 = this.buildUrl(path);
446
461
  const startTime = requestStartTime ?? Date.now();
447
462
  const signal = this.createAbortSignal(init);
448
463
  const headers = await this.buildHeaders(init?.headers);
@@ -467,7 +482,7 @@ var WebHttpClient = class {
467
482
  headersObj,
468
483
  await this.transport.authorizeRequest({
469
484
  method,
470
- path: new URL(url).pathname,
485
+ path: new URL(url2).pathname,
471
486
  // Narrowed by the guard above; `BodyInit` is wider than what can be
472
487
  // signed.
473
488
  body
@@ -527,7 +542,7 @@ var WebHttpClient = class {
527
542
  if (this.transport.getProof) {
528
543
  const proof = await this.transport.getProof({
529
544
  method: requestInit.method ?? "GET",
530
- path: pathForProof(url),
545
+ path: pathForProof(url2),
531
546
  body: requestInit.body
532
547
  });
533
548
  if (proof) {
@@ -535,13 +550,13 @@ var WebHttpClient = class {
535
550
  }
536
551
  }
537
552
  try {
538
- const response = await this.transport.fetch(url, requestInit);
553
+ const response = await this.transport.fetch(url2, requestInit);
539
554
  if (!response.ok) {
540
555
  const bodyText = await this.getBodyText(response);
541
556
  const httpError = new HTTPError(
542
557
  response.status,
543
558
  response.statusText,
544
- url,
559
+ url2,
545
560
  response.headers,
546
561
  bodyText
547
562
  );
@@ -559,7 +574,7 @@ var WebHttpClient = class {
559
574
  authError,
560
575
  response.status,
561
576
  response.statusText,
562
- url,
577
+ url2,
563
578
  response.headers,
564
579
  bodyText
565
580
  );
@@ -624,7 +639,7 @@ var WebHttpClient = class {
624
639
  throw new HTTPError(
625
640
  0,
626
641
  "Network Error",
627
- url,
642
+ url2,
628
643
  new Headers(),
629
644
  error instanceof Error ? error.message : "Unknown error"
630
645
  );
@@ -727,7 +742,7 @@ function createBrowserHttpClient(options) {
727
742
  const transport2 = {
728
743
  // globalThis.fetch must be called as a method on globalThis, not through a
729
744
  // variable, or browsers throw "Illegal invocation".
730
- fetch: (url, init) => options.fetch ? options.fetch(url, init) : globalThis.fetch(url, init),
745
+ fetch: (url2, init) => options.fetch ? options.fetch(url2, init) : globalThis.fetch(url2, init),
731
746
  baseUrl: options.baseUrl,
732
747
  getAuthToken: options.getAuthToken,
733
748
  getProof: options.getProof,
@@ -754,7 +769,7 @@ function createNodeHttpClient(options) {
754
769
  // Wrap fetch in arrow function to prevent "Illegal invocation" error
755
770
  // For globalThis.fetch, call it directly to preserve 'this' context
756
771
  // For custom implementations, calling through the variable is safe
757
- fetch: isDefaultFetch ? (url, init) => globalThis.fetch(url, init) : (url, init) => fetchImpl(url, init),
772
+ fetch: isDefaultFetch ? (url2, init) => globalThis.fetch(url2, init) : (url2, init) => fetchImpl(url2, init),
758
773
  baseUrl: options.baseUrl,
759
774
  getAuthToken: options.getAuthToken,
760
775
  getProof: options.getProof,
@@ -1330,10 +1345,10 @@ function compareSemverId(a, b) {
1330
1345
  if (nb) return 1;
1331
1346
  return a < b ? -1 : a > b ? 1 : 0;
1332
1347
  }
1333
- async function fetchRegistry(url, kind, context) {
1348
+ async function fetchRegistry(url2, kind, context) {
1334
1349
  return withRetry(
1335
1350
  async () => {
1336
- const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
1351
+ const resp = await fetch(url2, { signal: AbortSignal.timeout(1e4) });
1337
1352
  if (!resp.ok) {
1338
1353
  const err = new Error(
1339
1354
  `registry ${kind} fetch failed (${resp.status}) for ${context}`
@@ -1385,9 +1400,9 @@ var AdminApiClient = class {
1385
1400
  * the running `Context.applicationVersion` to detect "a new version exists".
1386
1401
  */
1387
1402
  async getRegistryVersions(registryUrl, packageName) {
1388
- const url = new URL("/api/v2/bundles", new URL(registryUrl).origin);
1389
- url.searchParams.set("package", packageName);
1390
- const resp = await fetchRegistry(url.toString(), "versions", packageName);
1403
+ const url2 = new URL("/api/v2/bundles", new URL(registryUrl).origin);
1404
+ url2.searchParams.set("package", packageName);
1405
+ const resp = await fetchRegistry(url2.toString(), "versions", packageName);
1391
1406
  const bundles = await resp.json();
1392
1407
  return (Array.isArray(bundles) ? bundles : []).map((b) => b.appVersion).filter((v) => typeof v === "string").sort((a, b) => compareSemver(b, a));
1393
1408
  }
@@ -2705,11 +2720,11 @@ function createAdminApiClientFromHttpClient(httpClient, _config) {
2705
2720
  }
2706
2721
 
2707
2722
  // src/auth/index.ts
2708
- function parseAuthCallback(url) {
2723
+ function parseAuthCallback(url2) {
2709
2724
  try {
2710
- const hashIndex = url.indexOf("#");
2725
+ const hashIndex = url2.indexOf("#");
2711
2726
  if (hashIndex === -1) return null;
2712
- const hash = url.substring(hashIndex + 1);
2727
+ const hash = url2.substring(hashIndex + 1);
2713
2728
  const params = new URLSearchParams(hash);
2714
2729
  const accessToken = params.get("access_token");
2715
2730
  if (!accessToken) return null;
@@ -3066,7 +3081,7 @@ var SseClient = class {
3066
3081
  throw new Error("SseClient needs either `getAuthToken` or `authorize`");
3067
3082
  }
3068
3083
  this.reconnectDelayMs = opts.reconnectDelayMs ?? 3e3;
3069
- this.fetchImpl = (url, init) => opts.fetch ? opts.fetch(url, init) : globalThis.fetch(url, init);
3084
+ this.fetchImpl = (url2, init) => opts.fetch ? opts.fetch(url2, init) : globalThis.fetch(url2, init);
3070
3085
  }
3071
3086
  on(event, handler) {
3072
3087
  const key = event;
@@ -3131,10 +3146,10 @@ var SseClient = class {
3131
3146
  this.closed = false;
3132
3147
  this.abortController = new AbortController();
3133
3148
  try {
3134
- const url = `${this.baseUrl}/sse`;
3135
- const response = await this.fetchImpl(url, {
3149
+ const url2 = `${this.baseUrl}/sse`;
3150
+ const response = await this.fetchImpl(url2, {
3136
3151
  headers: {
3137
- ...await this.authorize({ method: "GET", path: new URL(url).pathname }),
3152
+ ...await this.authorize({ method: "GET", path: new URL(url2).pathname }),
3138
3153
  "Accept": "text/event-stream"
3139
3154
  },
3140
3155
  signal: this.abortController.signal
@@ -3147,7 +3162,7 @@ var SseClient = class {
3147
3162
  terminal,
3148
3163
  response.status,
3149
3164
  response.statusText,
3150
- url,
3165
+ url2,
3151
3166
  response.headers,
3152
3167
  bodyText
3153
3168
  );
@@ -3155,7 +3170,7 @@ var SseClient = class {
3155
3170
  throw new HTTPError(
3156
3171
  response.status,
3157
3172
  response.statusText,
3158
- url,
3173
+ url2,
3159
3174
  response.headers,
3160
3175
  bodyText
3161
3176
  );
@@ -3334,12 +3349,12 @@ var SseClient = class {
3334
3349
  const params = {};
3335
3350
  if (ids.contextIds && ids.contextIds.length > 0) params.contextIds = ids.contextIds;
3336
3351
  if (ids.groupIds && ids.groupIds.length > 0) params.groupIds = ids.groupIds;
3337
- const url = `${this.baseUrl}/sse/subscription`;
3352
+ const url2 = `${this.baseUrl}/sse/subscription`;
3338
3353
  const body = JSON.stringify({ id: this.sessionId, method, params });
3339
- const response = await this.fetchImpl(url, {
3354
+ const response = await this.fetchImpl(url2, {
3340
3355
  method: "POST",
3341
3356
  headers: {
3342
- ...await this.authorize({ method: "POST", path: new URL(url).pathname, body }),
3357
+ ...await this.authorize({ method: "POST", path: new URL(url2).pathname, body }),
3343
3358
  "Content-Type": "application/json"
3344
3359
  },
3345
3360
  body,
@@ -6250,14 +6265,14 @@ function reportDataOf(quote) {
6250
6265
  }
6251
6266
  async function attestRelayNodeKey(opts) {
6252
6267
  const nonce2 = crypto.getRandomValues(new Uint8Array(32));
6253
- const url = `${opts.relayUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
6268
+ const url2 = `${opts.relayUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
6254
6269
  const body = JSON.stringify({
6255
6270
  nonce: hex(nonce2),
6256
6271
  bindNodeKey: true,
6257
6272
  ...opts.verify?.includeCollateral ? { includeCollateral: true } : {}
6258
6273
  });
6259
6274
  const init = { method: "POST", headers: { "Content-Type": "application/json" }, body };
6260
- const response = opts.fetch ? await opts.fetch(url, init) : await globalThis.fetch(url, init);
6275
+ const response = opts.fetch ? await opts.fetch(url2, init) : await globalThis.fetch(url2, init);
6261
6276
  if (!response.ok) {
6262
6277
  const text = await response.text().catch(() => "");
6263
6278
  throw new Error(`the relay would not attest (HTTP ${response.status})${text ? `: ${text}` : ""}`);
@@ -6579,13 +6594,13 @@ function createSealedFetch(options) {
6579
6594
  };
6580
6595
  return async (input, init) => {
6581
6596
  const request = new Request(input, init);
6582
- const url = new URL(request.url);
6583
- if (url.origin !== base.origin || !url.pathname.startsWith(`${basePath}/`)) {
6584
- throw new Error(`Refusing to send ${url.href} outside the sealed node at ${options.baseUrl}`);
6597
+ const url2 = new URL(request.url);
6598
+ if (url2.origin !== base.origin || !url2.pathname.startsWith(`${basePath}/`)) {
6599
+ throw new Error(`Refusing to send ${url2.href} outside the sealed node at ${options.baseUrl}`);
6585
6600
  }
6586
6601
  const headers = [];
6587
6602
  request.headers.forEach((value, name) => headers.push([name, value]));
6588
- const head = { method: request.method, path: url.pathname.slice(basePath.length) + url.search, headers };
6603
+ const head = { method: request.method, path: url2.pathname.slice(basePath.length) + url2.search, headers };
6589
6604
  const body = new Uint8Array(await request.arrayBuffer());
6590
6605
  const send = async (open2) => {
6591
6606
  const { requestId, header, envelope } = await sealRequest(open2, head, body);
@@ -6807,7 +6822,7 @@ function createQuoteVerifier(options) {
6807
6822
  const allowedMrtd = measurements(options.allowedMrtd ?? [], "allowedMrtd");
6808
6823
  const allowedImages = (options.allowedMeasurements ?? []).map((image, index) => {
6809
6824
  const label2 = `allowedMeasurements[${index}]`;
6810
- return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${label2}.${register}`)[0]).join();
6825
+ return REGISTERS.map((register2) => measurements([image?.[register2] ?? ""], `${label2}.${register2}`)[0]).join();
6811
6826
  });
6812
6827
  const allowedRtmr = [
6813
6828
  measurements(options.allowedRtmr0 ?? [], "allowedRtmr0"),
@@ -6856,7 +6871,7 @@ function createQuoteVerifier(options) {
6856
6871
  if (td.tdAttributes?.length !== 8 || (td.tdAttributes[0] & 1) !== 0) {
6857
6872
  throw new Error("The quote is from a debug TD, or its TD attributes cannot be read");
6858
6873
  }
6859
- const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register) => hex(register));
6874
+ const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register2) => hex(register2));
6860
6875
  if (allowedImages.length > 0 && !allowedImages.includes(measured.join())) {
6861
6876
  throw new Error(
6862
6877
  `The measurements (MRTD ${measured[0]}, RTMR0-3 ${measured.slice(1).join(", ")}) are not an image this verifier trusts`
@@ -6866,10 +6881,10 @@ function createQuoteVerifier(options) {
6866
6881
  throw new Error(`MRTD ${measured[0]} is not an image this verifier trusts`);
6867
6882
  }
6868
6883
  const registers = [td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3];
6869
- registers.forEach((register, index) => {
6884
+ registers.forEach((register2, index) => {
6870
6885
  const allowed = allowedRtmr[index];
6871
- if (allowed.length > 0 && !allowed.includes(hex(register))) {
6872
- throw new Error(`RTMR${index} ${hex(register)} is not one this verifier trusts`);
6886
+ if (allowed.length > 0 && !allowed.includes(hex(register2))) {
6887
+ throw new Error(`RTMR${index} ${hex(register2)} is not one this verifier trusts`);
6873
6888
  }
6874
6889
  });
6875
6890
  if (hex(td.reportData) !== `${nonce2}${reportDataSuffix}`.toLowerCase()) {
@@ -7346,7 +7361,7 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
7346
7361
  throw new Error(`The signed release is a ${JSON.stringify(release?.role)} release, not a node one`);
7347
7362
  }
7348
7363
  const profiles = Object.values(release.profiles ?? {});
7349
- const measured = (image) => MEASUREMENTS.every((register) => /^[0-9a-f]{96}$/i.test(String(image?.[register])));
7364
+ const measured = (image) => MEASUREMENTS.every((register2) => /^[0-9a-f]{96}$/i.test(String(image?.[register2])));
7350
7365
  if (typeof release.tag !== "string" || profiles.length === 0 || !profiles.every(measured)) {
7351
7366
  throw new Error("The signed file is not a release's published-mrtds.json: it lists no measured profiles");
7352
7367
  }
@@ -7355,17 +7370,17 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
7355
7370
  }
7356
7371
  return release;
7357
7372
  }
7358
- async function fetchNodeRelease(url, options = {}) {
7359
- const response = await (options.fetch ?? fetch)(url, { headers: { accept: "application/json" } });
7360
- if (!response.ok) throw new Error(`Fetching the node release from ${url} failed: HTTP ${response.status}`);
7373
+ async function fetchNodeRelease(url2, options = {}) {
7374
+ const response = await (options.fetch ?? fetch)(url2, { headers: { accept: "application/json" } });
7375
+ if (!response.ok) throw new Error(`Fetching the node release from ${url2} failed: HTTP ${response.status}`);
7361
7376
  let release;
7362
7377
  try {
7363
7378
  release = (await response.json())?.data;
7364
7379
  } catch {
7365
- throw new Error(`${url} did not answer with JSON`);
7380
+ throw new Error(`${url2} did not answer with JSON`);
7366
7381
  }
7367
7382
  if (typeof release?.version !== "string" || typeof release.publishedMrtds !== "string" || typeof release.bundle !== "string") {
7368
- throw new Error(`${url} did not answer with a signed node release`);
7383
+ throw new Error(`${url2} did not answer with a signed node release`);
7369
7384
  }
7370
7385
  return { version: release.version, publishedMrtds: release.publishedMrtds, bundle: release.bundle };
7371
7386
  }
@@ -7387,20 +7402,20 @@ function infoUrl(baseUrl) {
7387
7402
  return `${baseUrl.replace(/\/+$/, "")}/admin-api/tee/info`;
7388
7403
  }
7389
7404
  async function readNodeReleaseVersion(baseUrl, givenFetch) {
7390
- const url = infoUrl(baseUrl);
7391
- const response = await givenFetch(url, { headers: { accept: "application/json" } });
7405
+ const url2 = infoUrl(baseUrl);
7406
+ const response = await givenFetch(url2, { headers: { accept: "application/json" } });
7392
7407
  if (response.status === 403) {
7393
7408
  const code = await response.json().then((body) => body?.error?.code).catch(() => void 0);
7394
7409
  if (code === "sealed_required") return void 0;
7395
7410
  }
7396
- if (!response.ok) throw new Error(`Fetching ${url} failed: HTTP ${response.status}`);
7411
+ if (!response.ok) throw new Error(`Fetching ${url2} failed: HTTP ${response.status}`);
7397
7412
  let osImage;
7398
7413
  try {
7399
7414
  osImage = (await response.json())?.data?.osImage;
7400
7415
  } catch {
7401
- throw new Error(`${url} did not answer with JSON`);
7416
+ throw new Error(`${url2} did not answer with JSON`);
7402
7417
  }
7403
- if (typeof osImage !== "string") throw new Error(`${url} did not name the node's image`);
7418
+ if (typeof osImage !== "string") throw new Error(`${url2} did not name the node's image`);
7404
7419
  return nodeReleaseVersionFromImage(osImage);
7405
7420
  }
7406
7421
  function cloudNodeReleaseUrl(cloudUrl, version) {
@@ -9010,8 +9025,8 @@ function createProofAuthorizer(credential) {
9010
9025
  return { [REQUEST_PROOF_HEADER]: proof };
9011
9026
  };
9012
9027
  }
9013
- function signedPath(url) {
9014
- return new URL(url).pathname;
9028
+ function signedPath(url2) {
9029
+ return new URL(url2).pathname;
9015
9030
  }
9016
9031
 
9017
9032
  // src/presence/statement.ts
@@ -9198,7 +9213,7 @@ var MeroClient = class {
9198
9213
  const authorizeRequest = this.proofAuthorizer;
9199
9214
  this.relayAdmin = createAdminApiClientFromHttpClient(
9200
9215
  createHttpClient({
9201
- fetch: (url, init) => fetchImpl ? fetchImpl(url, init) : globalThis.fetch(url, init),
9216
+ fetch: (url2, init) => fetchImpl ? fetchImpl(url2, init) : globalThis.fetch(url2, init),
9202
9217
  baseUrl: relay.relayUrl,
9203
9218
  authorizeRequest
9204
9219
  }),
@@ -9841,9 +9856,9 @@ function writeRelayMap(account, map) {
9841
9856
  }
9842
9857
  function rememberRelay(account, relayUrl, at) {
9843
9858
  const map = readRelayMap(account);
9844
- const url = relayOrigin(relayUrl);
9845
- if (at.namespaceId) map.namespaces[at.namespaceId] = url;
9846
- if (at.contextId) map.contexts[at.contextId] = url;
9859
+ const url2 = relayOrigin(relayUrl);
9860
+ if (at.namespaceId) map.namespaces[at.namespaceId] = url2;
9861
+ if (at.contextId) map.contexts[at.contextId] = url2;
9847
9862
  writeRelayMap(account, map);
9848
9863
  }
9849
9864
  function relayForContext(account, contextId) {
@@ -10226,7 +10241,7 @@ function beginLinkState(account, returnTo) {
10226
10241
  if (!ACCOUNT_HEX.test(account)) {
10227
10242
  throw new Error("accountId must be 64 lowercase hex characters");
10228
10243
  }
10229
- const url = new URL(returnTo);
10244
+ const url2 = new URL(returnTo);
10230
10245
  const now = Date.now();
10231
10246
  const pending = readPending(now);
10232
10247
  const bytes = crypto.getRandomValues(new Uint8Array(16));
@@ -10235,8 +10250,8 @@ function beginLinkState(account, returnTo) {
10235
10250
  );
10236
10251
  pending[state] = { account, expiresAt: now + LIFETIME_MS };
10237
10252
  writePending(Object.fromEntries(Object.entries(pending).slice(-MAX_PENDING)));
10238
- url.searchParams.set(STATE_PARAM, state);
10239
- return url.toString();
10253
+ url2.searchParams.set(STATE_PARAM, state);
10254
+ return url2.toString();
10240
10255
  }
10241
10256
  function takeLinkState(search) {
10242
10257
  const state = new URLSearchParams(search).get(STATE_PARAM);
@@ -10258,10 +10273,10 @@ function withoutLinkState(search) {
10258
10273
  // src/cloud/link-redirect.ts
10259
10274
  var DEFAULT_CLOUD_WEB_URL = "https://cloud.calimero.network";
10260
10275
  function cloudLinkUrl(options) {
10261
- const url = new URL(options.cloudWebUrl ?? DEFAULT_CLOUD_WEB_URL);
10262
- url.searchParams.set("link-account", options.accountId);
10263
- url.searchParams.set("callback-url", beginLinkState(options.accountId, options.returnTo));
10264
- return url.toString();
10276
+ const url2 = new URL(options.cloudWebUrl ?? DEFAULT_CLOUD_WEB_URL);
10277
+ url2.searchParams.set("link-account", options.accountId);
10278
+ url2.searchParams.set("callback-url", beginLinkState(options.accountId, options.returnTo));
10279
+ return url2.toString();
10265
10280
  }
10266
10281
  function beginCloudLink(options) {
10267
10282
  window.location.assign(cloudLinkUrl(options));
@@ -10317,12 +10332,12 @@ function deviceEnrolmentUrl(options) {
10317
10332
  assertHex(options.kemPublicKey, "kemPublicKey");
10318
10333
  assertSafeReturnTo(options.returnTo);
10319
10334
  warnOnForeignCallback(options.returnTo);
10320
- const url = new URL(options.walletUrl);
10321
- url.searchParams.set(DEVICE_PARAM, options.devicePublicKey);
10322
- url.searchParams.set(KEM_PARAM, options.kemPublicKey);
10323
- url.searchParams.set(CALLBACK_PARAM, options.returnTo);
10324
- if (options.state) url.searchParams.set(STATE_PARAM2, options.state);
10325
- return url.toString();
10335
+ const url2 = new URL(options.walletUrl);
10336
+ url2.searchParams.set(DEVICE_PARAM, options.devicePublicKey);
10337
+ url2.searchParams.set(KEM_PARAM, options.kemPublicKey);
10338
+ url2.searchParams.set(CALLBACK_PARAM, options.returnTo);
10339
+ if (options.state) url2.searchParams.set(STATE_PARAM2, options.state);
10340
+ return url2.toString();
10326
10341
  }
10327
10342
  function beginDeviceEnrolment(options) {
10328
10343
  window.location.assign(deviceEnrolmentUrl(options));
@@ -10407,17 +10422,17 @@ function warnOnForeignCallback(returnTo) {
10407
10422
  );
10408
10423
  }
10409
10424
  function assertSafeReturnTo(returnTo) {
10410
- let url;
10425
+ let url2;
10411
10426
  try {
10412
- url = new URL(returnTo);
10427
+ url2 = new URL(returnTo);
10413
10428
  } catch {
10414
10429
  throw new Error(`returnTo must be an absolute URL, got ${returnTo}`);
10415
10430
  }
10416
- const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]" || url.hostname === "::1";
10417
- if (url.protocol === "https:") return;
10418
- if (url.protocol === "http:" && loopback) return;
10431
+ const loopback = url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]" || url2.hostname === "::1";
10432
+ if (url2.protocol === "https:") return;
10433
+ if (url2.protocol === "http:" && loopback) return;
10419
10434
  throw new Error(
10420
- `returnTo must be https:, or http: on localhost \u2014 got ${url.protocol}//${url.hostname}`
10435
+ `returnTo must be https:, or http: on localhost \u2014 got ${url2.protocol}//${url2.hostname}`
10421
10436
  );
10422
10437
  }
10423
10438
 
@@ -10596,7 +10611,7 @@ function bytes32(value, label2) {
10596
10611
  }
10597
10612
 
10598
10613
  // src/namespace-op/namespace-op.ts
10599
- var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 24;
10614
+ var SIGNED_NAMESPACE_OP_SCHEMA_VERSION = 25;
10600
10615
  var NAMESPACE_SIGN_DOMAIN = new TextEncoder().encode("calimero.namespace.v1");
10601
10616
  var NAMESPACE_OP_ROOT = 0;
10602
10617
  var ROOT_OP2 = {
@@ -10704,8 +10719,8 @@ function joinNonce(account) {
10704
10719
  const source = createLocalStorageNonceSource(`calimero.delegated.joinnonce.${account}`);
10705
10720
  return () => source.next();
10706
10721
  }
10707
- function origin(url) {
10708
- return url.replace(/\/+$/, "");
10722
+ function origin(url2) {
10723
+ return url2.replace(/\/+$/, "");
10709
10724
  }
10710
10725
  async function joinWithNode(input) {
10711
10726
  const { account, credential, deviceSecret } = input.credential;
@@ -10727,11 +10742,11 @@ async function joinWithNode(input) {
10727
10742
  };
10728
10743
  }
10729
10744
  const body = { invitation: input.invitation, signedOp };
10730
- const url = input.admitUrl ?? `${origin(input.nodeUrl)}/admin-api/namespaces/${pathSegment(input.namespaceId)}/admit`;
10745
+ const url2 = input.admitUrl ?? `${origin(input.nodeUrl)}/admin-api/namespaces/${pathSegment(input.namespaceId)}/admit`;
10731
10746
  const doFetch = input.deps?.fetch ?? fetch;
10732
10747
  let response;
10733
10748
  try {
10734
- response = await doFetch(url, {
10749
+ response = await doFetch(url2, {
10735
10750
  method: "POST",
10736
10751
  // No Authorization header and no request proof, deliberately: the route is
10737
10752
  // unauthenticated because the joiner's signature is the authorization.
@@ -10854,8 +10869,8 @@ function selectLatestBundle(bundles) {
10854
10869
  );
10855
10870
  }
10856
10871
  async function fetchRegistryBundles(registryUrl, pkg, fetchFn = globalThis.fetch) {
10857
- const url = `${registryUrl.replace(/\/+$/, "")}/api/v2/bundles?package=${encodeURIComponent(pkg)}`;
10858
- const response = await fetchFn(url, { headers: { Accept: "application/json" } });
10872
+ const url2 = `${registryUrl.replace(/\/+$/, "")}/api/v2/bundles?package=${encodeURIComponent(pkg)}`;
10873
+ const response = await fetchFn(url2, { headers: { Accept: "application/json" } });
10859
10874
  if (!response.ok) throw new Error(`the registry has no ${pkg} (HTTP ${response.status})`);
10860
10875
  const body = await response.json();
10861
10876
  return Array.isArray(body) ? body : [];
@@ -10895,9 +10910,9 @@ function nextGovernanceNonce(relay, group) {
10895
10910
  return next;
10896
10911
  }
10897
10912
  function relayFor(s, namespaceId) {
10898
- const url = readRelayMap(s.account).namespaces[namespaceId] ?? s.relayUrl;
10899
- if (!url) throw new Error("no relay is known for this namespace, so there is nowhere to send this");
10900
- return url.replace(/\/+$/, "");
10913
+ const url2 = readRelayMap(s.account).namespaces[namespaceId] ?? s.relayUrl;
10914
+ if (!url2) throw new Error("no relay is known for this namespace, so there is nowhere to send this");
10915
+ return url2.replace(/\/+$/, "");
10901
10916
  }
10902
10917
  function initArgsOf(params) {
10903
10918
  if (!params || params.length === 0) return {};
@@ -10980,7 +10995,7 @@ async function foundingExecutor(s, relay, fetch2) {
10980
10995
  const named = s.executorAccount && s.relayUrl?.replace(/\/+$/, "") === relay ? s.executorAccount : null;
10981
10996
  if (named) return { executorAccount: named, executorKey: await attestedNodeKey(relay) };
10982
10997
  const known = Object.entries(readRelayMap(s.account).namespaces).find(
10983
- ([, url]) => url.replace(/\/+$/, "") === relay
10998
+ ([, url2]) => url2.replace(/\/+$/, "") === relay
10984
10999
  )?.[0];
10985
11000
  if (!known) {
10986
11001
  throw new Error(
@@ -11427,8 +11442,8 @@ function accountHexOrNull(value) {
11427
11442
  return typeof value === "string" && ACCOUNT_HEX.test(value) ? value : null;
11428
11443
  }
11429
11444
  var AccountHaRefusedError = class extends HTTPError {
11430
- constructor(code, status, statusText, url, headers, bodyText) {
11431
- super(status, statusText, url, headers, bodyText);
11445
+ constructor(code, status, statusText, url2, headers, bodyText) {
11446
+ super(status, statusText, url2, headers, bodyText);
11432
11447
  this.code = code;
11433
11448
  this.name = "AccountHaRefusedError";
11434
11449
  }
@@ -12745,8 +12760,8 @@ var MeroJs = class {
12745
12760
  /**
12746
12761
  * Parse an auth callback URL hash fragment (static utility)
12747
12762
  */
12748
- static parseAuthCallback(url) {
12749
- return parseAuthCallback(url);
12763
+ static parseAuthCallback(url2) {
12764
+ return parseAuthCallback(url2);
12750
12765
  }
12751
12766
  /**
12752
12767
  * Build an auth login URL (static utility)
@@ -13011,8 +13026,8 @@ async function probeNodeHealth(baseUrl, options = {}) {
13011
13026
  if (abortSignal) abortSignal.addEventListener("abort", onAbort, { once: true });
13012
13027
  const timer = setTimeout(() => controller.abort(), timeoutMs);
13013
13028
  try {
13014
- const url = nodeEndpoint(baseUrl, "admin-api/health");
13015
- const res = await fetch(url, {
13029
+ const url2 = nodeEndpoint(baseUrl, "admin-api/health");
13030
+ const res = await fetch(url2, {
13016
13031
  method: "GET",
13017
13032
  signal: controller.signal
13018
13033
  });
@@ -13036,11 +13051,445 @@ async function discoverLocalNodes(options = {}) {
13036
13051
  const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
13037
13052
  const results = await Promise.all(
13038
13053
  ports.map(async (port) => {
13039
- const url = localNodeUrl(port);
13040
- const ok = await probeNodeHealth(url, { timeoutMs, signal });
13041
- return ok ? url : null;
13054
+ const url2 = localNodeUrl(port);
13055
+ const ok = await probeNodeHealth(url2, { timeoutMs, signal });
13056
+ return ok ? url2 : null;
13042
13057
  })
13043
13058
  );
13044
- return results.filter((url) => url !== null);
13059
+ return results.filter((url2) => url2 !== null);
13060
+ }
13061
+
13062
+ // src/agent-gate/chacha20poly1305.ts
13063
+ var KEY_LEN = 32;
13064
+ var NONCE_LEN = 12;
13065
+ var TAG_LEN2 = 16;
13066
+ function rotl(value, shift) {
13067
+ return (value << shift | value >>> 32 - shift) >>> 0;
13068
+ }
13069
+ function quarterRound(s, a, b, c, d) {
13070
+ s[a] = s[a] + s[b] >>> 0;
13071
+ s[d] = rotl(s[d] ^ s[a], 16);
13072
+ s[c] = s[c] + s[d] >>> 0;
13073
+ s[b] = rotl(s[b] ^ s[c], 12);
13074
+ s[a] = s[a] + s[b] >>> 0;
13075
+ s[d] = rotl(s[d] ^ s[a], 8);
13076
+ s[c] = s[c] + s[d] >>> 0;
13077
+ s[b] = rotl(s[b] ^ s[c], 7);
13078
+ }
13079
+ function u32le2(bytes, offset) {
13080
+ return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
13081
+ }
13082
+ function chacha20Block(key, counter, nonce2) {
13083
+ const state = new Uint32Array(16);
13084
+ state[0] = 1634760805;
13085
+ state[1] = 857760878;
13086
+ state[2] = 2036477234;
13087
+ state[3] = 1797285236;
13088
+ for (let i = 0; i < 8; i += 1) state[4 + i] = u32le2(key, i * 4);
13089
+ state[12] = counter >>> 0;
13090
+ for (let i = 0; i < 3; i += 1) state[13 + i] = u32le2(nonce2, i * 4);
13091
+ const working = state.slice();
13092
+ for (let round = 0; round < 10; round += 1) {
13093
+ quarterRound(working, 0, 4, 8, 12);
13094
+ quarterRound(working, 1, 5, 9, 13);
13095
+ quarterRound(working, 2, 6, 10, 14);
13096
+ quarterRound(working, 3, 7, 11, 15);
13097
+ quarterRound(working, 0, 5, 10, 15);
13098
+ quarterRound(working, 1, 6, 11, 12);
13099
+ quarterRound(working, 2, 7, 8, 13);
13100
+ quarterRound(working, 3, 4, 9, 14);
13101
+ }
13102
+ const out = new Uint8Array(64);
13103
+ for (let i = 0; i < 16; i += 1) {
13104
+ const word = working[i] + state[i] >>> 0;
13105
+ out[i * 4] = word & 255;
13106
+ out[i * 4 + 1] = word >>> 8 & 255;
13107
+ out[i * 4 + 2] = word >>> 16 & 255;
13108
+ out[i * 4 + 3] = word >>> 24 & 255;
13109
+ }
13110
+ return out;
13111
+ }
13112
+ function chacha20(key, counter, nonce2, data) {
13113
+ const out = new Uint8Array(data.length);
13114
+ for (let offset = 0, block = counter; offset < data.length; offset += 64, block += 1) {
13115
+ const stream = chacha20Block(key, block, nonce2);
13116
+ const end = Math.min(offset + 64, data.length);
13117
+ for (let i = offset; i < end; i += 1) out[i] = data[i] ^ stream[i - offset];
13118
+ }
13119
+ return out;
13120
+ }
13121
+ function leToBigInt(bytes) {
13122
+ let value = 0n;
13123
+ for (let i = bytes.length - 1; i >= 0; i -= 1) value = value << 8n | BigInt(bytes[i]);
13124
+ return value;
13125
+ }
13126
+ var P1305 = (1n << 130n) - 5n;
13127
+ function poly1305(key, message) {
13128
+ const r = leToBigInt(key.subarray(0, 16)) & 0x0ffffffc0ffffffc0ffffffc0fffffffn;
13129
+ const s = leToBigInt(key.subarray(16, 32));
13130
+ let acc = 0n;
13131
+ for (let offset = 0; offset < message.length; offset += 16) {
13132
+ const block = message.subarray(offset, Math.min(offset + 16, message.length));
13133
+ const n = leToBigInt(block) + (1n << BigInt(8 * block.length));
13134
+ acc = (acc + n) * r % P1305;
13135
+ }
13136
+ let tag3 = acc + s & (1n << 128n) - 1n;
13137
+ const out = new Uint8Array(TAG_LEN2);
13138
+ for (let i = 0; i < TAG_LEN2; i += 1) {
13139
+ out[i] = Number(tag3 & 0xffn);
13140
+ tag3 >>= 8n;
13141
+ }
13142
+ return out;
13143
+ }
13144
+ function pad16(length) {
13145
+ return new Uint8Array((16 - length % 16) % 16);
13146
+ }
13147
+ function u64le2(value) {
13148
+ const out = new Uint8Array(8);
13149
+ new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
13150
+ return out;
13151
+ }
13152
+ function macData(aad, ciphertext) {
13153
+ const parts = [aad, pad16(aad.length), ciphertext, pad16(ciphertext.length), u64le2(aad.length), u64le2(ciphertext.length)];
13154
+ const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
13155
+ let offset = 0;
13156
+ for (const part of parts) {
13157
+ out.set(part, offset);
13158
+ offset += part.length;
13159
+ }
13160
+ return out;
13161
+ }
13162
+ function check(key, nonce2) {
13163
+ if (key.length !== KEY_LEN) throw new Error("ChaCha20-Poly1305 needs a 32-byte key");
13164
+ if (nonce2.length !== NONCE_LEN) throw new Error("ChaCha20-Poly1305 needs a 12-byte nonce");
13165
+ }
13166
+ function chacha20Poly1305Seal(key, nonce2, plaintext, aad = new Uint8Array(0)) {
13167
+ check(key, nonce2);
13168
+ const otk = chacha20Block(key, 0, nonce2).subarray(0, 32);
13169
+ const ciphertext = chacha20(key, 1, nonce2, plaintext);
13170
+ const tag3 = poly1305(otk, macData(aad, ciphertext));
13171
+ const out = new Uint8Array(ciphertext.length + TAG_LEN2);
13172
+ out.set(ciphertext);
13173
+ out.set(tag3, ciphertext.length);
13174
+ return out;
13175
+ }
13176
+
13177
+ // src/agent-gate/hpke.ts
13178
+ var KEM_ID = 32;
13179
+ var KDF_ID = 1;
13180
+ var AEAD_ID = 3;
13181
+ var MODE_AUTH = 2;
13182
+ var N_SECRET = 32;
13183
+ var N_KEY = 32;
13184
+ var N_NONCE = 12;
13185
+ var utf84 = (s) => new TextEncoder().encode(s);
13186
+ var i2osp2 = (n) => new Uint8Array([n >> 8 & 255, n & 255]);
13187
+ var KEM_SUITE = concat(utf84("KEM"), i2osp2(KEM_ID));
13188
+ var HPKE_SUITE = concat(utf84("HPKE"), i2osp2(KEM_ID), i2osp2(KDF_ID), i2osp2(AEAD_ID));
13189
+ async function hmac(key, data) {
13190
+ const raw = key.length === 0 ? new Uint8Array(32) : key;
13191
+ const k = await crypto.subtle.importKey("raw", raw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
13192
+ return new Uint8Array(await crypto.subtle.sign("HMAC", k, data));
13193
+ }
13194
+ async function expand(prk, info, length) {
13195
+ const out = new Uint8Array(length);
13196
+ let previous = new Uint8Array(0);
13197
+ for (let i = 1, offset = 0; offset < length; i += 1) {
13198
+ previous = await hmac(prk, concat(previous, info, new Uint8Array([i])));
13199
+ out.set(previous.subarray(0, Math.min(previous.length, length - offset)), offset);
13200
+ offset += previous.length;
13201
+ }
13202
+ return out;
13203
+ }
13204
+ function labeledExtract(suite, salt, label2, ikm) {
13205
+ return hmac(salt, concat(utf84("HPKE-v1"), suite, utf84(label2), ikm));
13206
+ }
13207
+ function labeledExpand(suite, prk, label2, info, length) {
13208
+ return expand(prk, concat(i2osp2(length), utf84("HPKE-v1"), suite, utf84(label2), info), length);
13209
+ }
13210
+ async function extractAndExpand(dhValue, kemContext) {
13211
+ const prk = await labeledExtract(KEM_SUITE, new Uint8Array(0), "eae_prk", dhValue);
13212
+ return labeledExpand(KEM_SUITE, prk, "shared_secret", kemContext, N_SECRET);
13213
+ }
13214
+ async function keySchedule(sharedSecret, info) {
13215
+ const empty = new Uint8Array(0);
13216
+ const pskIdHash = await labeledExtract(HPKE_SUITE, empty, "psk_id_hash", empty);
13217
+ const infoHash = await labeledExtract(HPKE_SUITE, empty, "info_hash", info);
13218
+ const context = concat(new Uint8Array([MODE_AUTH]), pskIdHash, infoHash);
13219
+ const secret = await labeledExtract(HPKE_SUITE, sharedSecret, "secret", empty);
13220
+ return {
13221
+ key: await labeledExpand(HPKE_SUITE, secret, "key", context, N_KEY),
13222
+ nonce: await labeledExpand(HPKE_SUITE, secret, "base_nonce", context, N_NONCE)
13223
+ };
13224
+ }
13225
+ async function hpkeSealAuth(recipientPublic, senderSecret, info, plaintext, aad = new Uint8Array(0), ephemeralSecret) {
13226
+ if (recipientPublic.length !== 32) throw new Error("The recipient key is not 32 bytes of X25519");
13227
+ const ephemeral = await x25519KeyPair(ephemeralSecret);
13228
+ const sender = await x25519KeyPair(senderSecret);
13229
+ const dhValue = concat(await dh(ephemeral.privateKey, recipientPublic), await dh(sender.privateKey, recipientPublic));
13230
+ const shared = await extractAndExpand(dhValue, concat(ephemeral.publicKey, recipientPublic, sender.publicKey));
13231
+ const { key, nonce: nonce2 } = await keySchedule(shared, info);
13232
+ return { enc: ephemeral.publicKey, ciphertext: chacha20Poly1305Seal(key, nonce2, plaintext, aad) };
13233
+ }
13234
+
13235
+ // src/agent-gate/gate.ts
13236
+ var AGENT_ATTEST_DOMAIN = "mero-agent-gate/attest/v3";
13237
+ var AGENT_PROVISION_INFO_DOMAIN = "mero-agent-gate/provision/v2";
13238
+ var AGENT_ID = /^[a-z0-9][a-z0-9-]{0,62}$/;
13239
+ var SECRET_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
13240
+ var MAX_SECRETS = 64;
13241
+ var MAX_SECRET_LEN = 64 * 1024;
13242
+ var AgentGateError = class extends Error {
13243
+ constructor(message, status, code) {
13244
+ super(message);
13245
+ this.status = status;
13246
+ this.code = code;
13247
+ this.name = "AgentGateError";
13248
+ }
13249
+ };
13250
+ function validateAgentId(agentId) {
13251
+ if (!AGENT_ID.test(agentId)) {
13252
+ throw new Error(`Agent id ${JSON.stringify(agentId)} must match [a-z0-9][a-z0-9-]{0,62}`);
13253
+ }
13254
+ }
13255
+ function utf85(value) {
13256
+ return new TextEncoder().encode(value);
13257
+ }
13258
+ function lengthPrefixed(agentId) {
13259
+ const id = utf85(agentId);
13260
+ return concat(new Uint8Array([id.length]), id);
13261
+ }
13262
+ function toBase64(bytes) {
13263
+ let binary = "";
13264
+ for (const byte of bytes) binary += String.fromCharCode(byte);
13265
+ return btoa(binary);
13266
+ }
13267
+ function fromBase644(value, label2, length) {
13268
+ let bytes;
13269
+ try {
13270
+ bytes = Uint8Array.from(atob(value.trim()), (c) => c.charCodeAt(0));
13271
+ } catch {
13272
+ throw new Error(`${label2} is not base64`);
13273
+ }
13274
+ if (length !== void 0 && bytes.length !== length) throw new Error(`${label2} is not ${length} bytes`);
13275
+ return bytes;
13276
+ }
13277
+ async function agentKeyBinding(provisioningPublic, agentId, signingPublic, ownerPublic) {
13278
+ const zero = new Uint8Array(32);
13279
+ const data = concat(
13280
+ utf85(AGENT_ATTEST_DOMAIN),
13281
+ provisioningPublic,
13282
+ lengthPrefixed(agentId),
13283
+ signingPublic ?? zero,
13284
+ ownerPublic ?? zero
13285
+ );
13286
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", data));
13287
+ }
13288
+ function provisionInfo(recipientPublic, agentId) {
13289
+ return concat(utf85(AGENT_PROVISION_INFO_DOMAIN), recipientPublic, lengthPrefixed(agentId));
13290
+ }
13291
+ async function generateOwnerKey() {
13292
+ const secret = crypto.getRandomValues(new Uint8Array(32));
13293
+ return { secret, publicKey: await ownerPublicKey(secret) };
13294
+ }
13295
+ async function ownerPublicKey(secret) {
13296
+ if (secret.length !== 32) throw new Error("An owner key is 32 bytes");
13297
+ return toBase64((await x25519KeyPair(secret)).publicKey);
13298
+ }
13299
+ function url(gateUrl, path) {
13300
+ return `${gateUrl.replace(/\/+$/, "")}${path}`;
13301
+ }
13302
+ async function postJson(fetchImpl, target, body) {
13303
+ const response = await fetchImpl(target, {
13304
+ method: "POST",
13305
+ headers: { "content-type": "application/json" },
13306
+ body: JSON.stringify(body)
13307
+ });
13308
+ const text = await response.text();
13309
+ let parsed = void 0;
13310
+ try {
13311
+ parsed = text ? JSON.parse(text) : void 0;
13312
+ } catch {
13313
+ }
13314
+ if (!response.ok) {
13315
+ const error = parsed;
13316
+ throw new AgentGateError(
13317
+ `The gate answered ${response.status}${error?.error ? ` ${error.error}` : ""}: ${error?.details ?? text.slice(0, 200)}`,
13318
+ response.status,
13319
+ error?.error
13320
+ );
13321
+ }
13322
+ return parsed;
13323
+ }
13324
+ async function attestAgent(options) {
13325
+ const agentId = options.agentId ?? "";
13326
+ if (agentId) validateAgentId(agentId);
13327
+ const nonce2 = crypto.getRandomValues(new Uint8Array(32));
13328
+ const body = await postJson(options.fetch ?? fetch, url(options.gateUrl, "/attest"), {
13329
+ nonceB64: toBase64(nonce2),
13330
+ ...agentId ? { agentId } : {}
13331
+ });
13332
+ if ((body?.agentId ?? "") !== agentId) {
13333
+ throw new Error(`Asked about agent ${JSON.stringify(agentId)}, the gate answered for ${JSON.stringify(body?.agentId)}`);
13334
+ }
13335
+ const provisioning = fromBase644(body.provisioningPublicKeyB64 ?? "", "provisioningPublicKeyB64", 32);
13336
+ const signing = body.signingPublicKeyB64 ? fromBase644(body.signingPublicKeyB64, "signingPublicKeyB64", 32) : void 0;
13337
+ const owner = body.ownerPublicKeyB64 ? fromBase644(body.ownerPublicKeyB64, "ownerPublicKeyB64", 32) : void 0;
13338
+ if (!signing !== !owner) {
13339
+ throw new Error("A claimed agent has both a signing key and an owner; the gate named one");
13340
+ }
13341
+ const binding = await agentKeyBinding(provisioning, agentId, signing, owner);
13342
+ await options.verifier({ quoteB64: body.quoteB64, nonce: hex(nonce2), reportDataSuffix: hex(binding) });
13343
+ return {
13344
+ agentId,
13345
+ provisioningPublicKey: toBase64(provisioning),
13346
+ ...signing ? { signingPublicKey: toBase64(signing) } : {},
13347
+ ...owner ? { ownerPublicKey: toBase64(owner) } : {}
13348
+ };
13349
+ }
13350
+ async function checkOwner(agent, ownerSecret) {
13351
+ const mine = await ownerPublicKey(ownerSecret);
13352
+ if (agent.ownerPublicKey && agent.ownerPublicKey !== mine) {
13353
+ throw new AgentGateError(
13354
+ `This agent is claimed by another key (${agent.ownerPublicKey}); it is not yours. Send it nothing and do not authorize its signing key`,
13355
+ void 0,
13356
+ "not_yours"
13357
+ );
13358
+ }
13359
+ return mine;
13360
+ }
13361
+ function validateSecrets(secrets) {
13362
+ const names = Object.keys(secrets);
13363
+ if (names.length === 0) throw new Error("There are no secrets to provision");
13364
+ if (names.length > MAX_SECRETS) throw new Error(`At most ${MAX_SECRETS} secrets at once`);
13365
+ for (const name of names) {
13366
+ if (!SECRET_NAME.test(name)) throw new Error(`Secret name ${JSON.stringify(name)} must match [A-Za-z0-9][A-Za-z0-9_.-]{0,63}`);
13367
+ if (typeof secrets[name] !== "string") throw new Error(`Secret ${name} is not a string`);
13368
+ if (utf85(secrets[name]).length > MAX_SECRET_LEN) throw new Error(`Secret ${name} is over ${MAX_SECRET_LEN} bytes`);
13369
+ }
13370
+ }
13371
+ async function sendSealed(fetchImpl, gateUrl, path, agent, ownerSecret, message) {
13372
+ if (!agent.agentId) throw new Error("This quote names no agent; attest with the agent id");
13373
+ const mine = await checkOwner(agent, ownerSecret);
13374
+ const recipient = fromBase644(agent.provisioningPublicKey, "provisioningPublicKey", 32);
13375
+ const sealed = await hpkeSealAuth(
13376
+ recipient,
13377
+ ownerSecret,
13378
+ provisionInfo(recipient, agent.agentId),
13379
+ utf85(JSON.stringify(message))
13380
+ );
13381
+ return postJson(fetchImpl, url(gateUrl, path), {
13382
+ agentId: agent.agentId,
13383
+ provisioningPublicKeyB64: agent.provisioningPublicKey,
13384
+ senderPublicKeyB64: mine,
13385
+ encappedKeyB64: toBase64(sealed.enc),
13386
+ ciphertextB64: toBase64(sealed.ciphertext)
13387
+ });
13388
+ }
13389
+ async function provisionAgent(options) {
13390
+ validateSecrets(options.secrets);
13391
+ const fetchImpl = options.fetch ?? fetch;
13392
+ const answer = await sendSealed(fetchImpl, options.gateUrl, "/provision", options.agent, options.ownerSecret, {
13393
+ secrets: options.secrets
13394
+ });
13395
+ const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
13396
+ const mine = await ownerPublicKey(options.ownerSecret);
13397
+ if (after.ownerPublicKey !== mine || !after.signingPublicKey) {
13398
+ throw new AgentGateError("The gate accepted the secrets, but its quote does not name your key as owner");
13399
+ }
13400
+ if (options.agent.signingPublicKey && options.agent.signingPublicKey !== after.signingPublicKey) {
13401
+ throw new AgentGateError("The agent's signing key changed while provisioning");
13402
+ }
13403
+ return {
13404
+ agentId: after.agentId,
13405
+ provisioningPublicKey: after.provisioningPublicKey,
13406
+ signingPublicKey: after.signingPublicKey,
13407
+ ownerPublicKey: mine,
13408
+ written: answer?.written ?? [],
13409
+ claimed: answer?.claimed === true
13410
+ };
13411
+ }
13412
+ async function releaseAgent(options) {
13413
+ if (!options.agent.ownerPublicKey) throw new Error("This agent is not claimed; there is nothing to release");
13414
+ const fetchImpl = options.fetch ?? fetch;
13415
+ await sendSealed(fetchImpl, options.gateUrl, "/release", options.agent, options.ownerSecret, { release: true });
13416
+ const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
13417
+ if (after.ownerPublicKey) {
13418
+ throw new AgentGateError("The gate says it released the agent, but its quote still names an owner");
13419
+ }
13420
+ }
13421
+
13422
+ // src/agent-gate/policy.ts
13423
+ var KMS_RELEASE_SIGNER = Object.freeze({
13424
+ identity: "https://github.com/calimero-network/mero-tee/.github/workflows/release-kms.yaml@refs/heads/master",
13425
+ issuer: "https://token.actions.githubusercontent.com"
13426
+ });
13427
+ var LISTS = [
13428
+ "allowed_tcb_statuses",
13429
+ "allowed_mrtd",
13430
+ "allowed_rtmr0",
13431
+ "allowed_rtmr1",
13432
+ "allowed_rtmr2",
13433
+ "allowed_rtmr3"
13434
+ ];
13435
+ async function verifySignedAgentPolicy(policy, bundle, options = {}) {
13436
+ const body = typeof policy === "string" ? new TextEncoder().encode(policy) : policy;
13437
+ await verifyCosignBundle(body, bundle, {
13438
+ identity: options.identity ?? KMS_RELEASE_SIGNER.identity,
13439
+ issuer: options.issuer ?? KMS_RELEASE_SIGNER.issuer
13440
+ });
13441
+ let parsed;
13442
+ try {
13443
+ parsed = JSON.parse(new TextDecoder().decode(body));
13444
+ } catch {
13445
+ throw new Error("The signed agent policy is not JSON");
13446
+ }
13447
+ if (parsed?.role !== "agent") {
13448
+ throw new Error(`The signed file is a ${JSON.stringify(parsed?.role)} policy, not an agent one`);
13449
+ }
13450
+ const profile = options.profile ?? PRODUCTION_PROFILE;
13451
+ if (parsed.profile !== profile) {
13452
+ throw new Error(`The signed agent policy is for the ${JSON.stringify(parsed.profile)} profile, not ${profile}`);
13453
+ }
13454
+ if (options.expectedVersion !== void 0 && parsed.version !== options.expectedVersion) {
13455
+ throw new Error(`The signed agent policy is release ${JSON.stringify(parsed.version)}, not ${options.expectedVersion}`);
13456
+ }
13457
+ checkLists(parsed);
13458
+ return parsed;
13459
+ }
13460
+ function checkLists(policy) {
13461
+ for (const list of LISTS) {
13462
+ if (!Array.isArray(policy?.[list]) || policy[list].length === 0) {
13463
+ throw new Error(`The agent policy's ${list} is empty, so no agent would be accepted`);
13464
+ }
13465
+ }
13466
+ }
13467
+ var TCB_STATUSES2 = [
13468
+ "UpToDate",
13469
+ "SWHardeningNeeded",
13470
+ "ConfigurationNeeded",
13471
+ "ConfigurationAndSWHardeningNeeded",
13472
+ "OutOfDate",
13473
+ "OutOfDateConfigurationNeeded"
13474
+ ];
13475
+ function tcbStatus2(value) {
13476
+ const found = TCB_STATUSES2.find((status) => status.toLowerCase() === value.trim().toLowerCase());
13477
+ if (!found) throw new Error(`The agent policy allows an unknown TCB status ${JSON.stringify(value)}`);
13478
+ return found;
13479
+ }
13480
+ var register = (value) => value.trim().replace(/^0x/i, "");
13481
+ function agentQuoteVerifier(policy, options) {
13482
+ checkLists(policy);
13483
+ return createQuoteVerifier({
13484
+ dcapVerify: options.dcapVerify,
13485
+ fetchCollateral: options.fetchCollateral,
13486
+ now: options.now,
13487
+ allowedTcbStatuses: policy.allowed_tcb_statuses.map(tcbStatus2),
13488
+ allowedMrtd: policy.allowed_mrtd.map(register),
13489
+ allowedRtmr0: policy.allowed_rtmr0.map(register),
13490
+ allowedRtmr1: policy.allowed_rtmr1.map(register),
13491
+ allowedRtmr2: policy.allowed_rtmr2.map(register),
13492
+ allowedRtmr3: policy.allowed_rtmr3.map(register)
13493
+ });
13045
13494
  }
13046
13495
  //# sourceMappingURL=index.cjs.map