@calimero-network/mero-js 25.0.7 → 25.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.
package/dist/index.mjs CHANGED
@@ -48,14 +48,14 @@ function extractErrorMessage(bodyText) {
48
48
  return void 0;
49
49
  }
50
50
  var HTTPError = class extends Error {
51
- constructor(status, statusText, url, headers, bodyText) {
51
+ constructor(status, statusText, url2, headers, bodyText) {
52
52
  const explanation = extractErrorMessage(bodyText) ?? (status === 0 && bodyText?.trim() ? bodyText.trim() : void 0);
53
53
  super(
54
54
  explanation ? `HTTP ${status} ${statusText}: ${explanation}` : `HTTP ${status} ${statusText}`
55
55
  );
56
56
  this.status = status;
57
57
  this.statusText = statusText;
58
- this.url = url;
58
+ this.url = url2;
59
59
  this.headers = headers;
60
60
  this.bodyText = bodyText;
61
61
  this.name = "HTTPError";
@@ -72,8 +72,8 @@ var HTTPError = class extends Error {
72
72
  }
73
73
  };
74
74
  var AuthRevokedError = class extends HTTPError {
75
- constructor(reason, status, statusText, url, headers, bodyText) {
76
- super(status, statusText, url, headers, bodyText);
75
+ constructor(reason, status, statusText, url2, headers, bodyText) {
76
+ super(status, statusText, url2, headers, bodyText);
77
77
  this.reason = reason;
78
78
  this.name = "AuthRevokedError";
79
79
  this.message = `Authentication revoked (${reason}): HTTP ${status} ${statusText}`;
@@ -86,12 +86,12 @@ function headersToRecord(headers) {
86
86
  });
87
87
  return record;
88
88
  }
89
- function pathForProof(url) {
89
+ function pathForProof(url2) {
90
90
  try {
91
- return new URL(url).pathname;
91
+ return new URL(url2).pathname;
92
92
  } catch {
93
- const query = url.indexOf("?");
94
- return query === -1 ? url : url.slice(0, query);
93
+ const query = url2.indexOf("?");
94
+ return query === -1 ? url2 : url2.slice(0, query);
95
95
  }
96
96
  }
97
97
  var WebHttpClient = class {
@@ -157,7 +157,7 @@ var WebHttpClient = class {
157
157
  }
158
158
  async makeRequest(path, init, retryCount = 0, requestStartTime) {
159
159
  const MAX_RETRY_ATTEMPTS = 1;
160
- const url = this.buildUrl(path);
160
+ const url2 = this.buildUrl(path);
161
161
  const startTime = requestStartTime ?? Date.now();
162
162
  const signal = this.createAbortSignal(init);
163
163
  const headers = await this.buildHeaders(init?.headers);
@@ -182,7 +182,7 @@ var WebHttpClient = class {
182
182
  headersObj,
183
183
  await this.transport.authorizeRequest({
184
184
  method,
185
- path: new URL(url).pathname,
185
+ path: new URL(url2).pathname,
186
186
  // Narrowed by the guard above; `BodyInit` is wider than what can be
187
187
  // signed.
188
188
  body
@@ -242,7 +242,7 @@ var WebHttpClient = class {
242
242
  if (this.transport.getProof) {
243
243
  const proof = await this.transport.getProof({
244
244
  method: requestInit.method ?? "GET",
245
- path: pathForProof(url),
245
+ path: pathForProof(url2),
246
246
  body: requestInit.body
247
247
  });
248
248
  if (proof) {
@@ -250,13 +250,13 @@ var WebHttpClient = class {
250
250
  }
251
251
  }
252
252
  try {
253
- const response = await this.transport.fetch(url, requestInit);
253
+ const response = await this.transport.fetch(url2, requestInit);
254
254
  if (!response.ok) {
255
255
  const bodyText = await this.getBodyText(response);
256
256
  const httpError = new HTTPError(
257
257
  response.status,
258
258
  response.statusText,
259
- url,
259
+ url2,
260
260
  response.headers,
261
261
  bodyText
262
262
  );
@@ -274,7 +274,7 @@ var WebHttpClient = class {
274
274
  authError,
275
275
  response.status,
276
276
  response.statusText,
277
- url,
277
+ url2,
278
278
  response.headers,
279
279
  bodyText
280
280
  );
@@ -339,7 +339,7 @@ var WebHttpClient = class {
339
339
  throw new HTTPError(
340
340
  0,
341
341
  "Network Error",
342
- url,
342
+ url2,
343
343
  new Headers(),
344
344
  error instanceof Error ? error.message : "Unknown error"
345
345
  );
@@ -442,7 +442,7 @@ function createBrowserHttpClient(options) {
442
442
  const transport2 = {
443
443
  // globalThis.fetch must be called as a method on globalThis, not through a
444
444
  // variable, or browsers throw "Illegal invocation".
445
- fetch: (url, init) => options.fetch ? options.fetch(url, init) : globalThis.fetch(url, init),
445
+ fetch: (url2, init) => options.fetch ? options.fetch(url2, init) : globalThis.fetch(url2, init),
446
446
  baseUrl: options.baseUrl,
447
447
  getAuthToken: options.getAuthToken,
448
448
  getProof: options.getProof,
@@ -469,7 +469,7 @@ function createNodeHttpClient(options) {
469
469
  // Wrap fetch in arrow function to prevent "Illegal invocation" error
470
470
  // For globalThis.fetch, call it directly to preserve 'this' context
471
471
  // For custom implementations, calling through the variable is safe
472
- fetch: isDefaultFetch ? (url, init) => globalThis.fetch(url, init) : (url, init) => fetchImpl(url, init),
472
+ fetch: isDefaultFetch ? (url2, init) => globalThis.fetch(url2, init) : (url2, init) => fetchImpl(url2, init),
473
473
  baseUrl: options.baseUrl,
474
474
  getAuthToken: options.getAuthToken,
475
475
  getProof: options.getProof,
@@ -1045,10 +1045,10 @@ function compareSemverId(a, b) {
1045
1045
  if (nb) return 1;
1046
1046
  return a < b ? -1 : a > b ? 1 : 0;
1047
1047
  }
1048
- async function fetchRegistry(url, kind, context) {
1048
+ async function fetchRegistry(url2, kind, context) {
1049
1049
  return withRetry(
1050
1050
  async () => {
1051
- const resp = await fetch(url, { signal: AbortSignal.timeout(1e4) });
1051
+ const resp = await fetch(url2, { signal: AbortSignal.timeout(1e4) });
1052
1052
  if (!resp.ok) {
1053
1053
  const err = new Error(
1054
1054
  `registry ${kind} fetch failed (${resp.status}) for ${context}`
@@ -1100,9 +1100,9 @@ var AdminApiClient = class {
1100
1100
  * the running `Context.applicationVersion` to detect "a new version exists".
1101
1101
  */
1102
1102
  async getRegistryVersions(registryUrl, packageName) {
1103
- const url = new URL("/api/v2/bundles", new URL(registryUrl).origin);
1104
- url.searchParams.set("package", packageName);
1105
- const resp = await fetchRegistry(url.toString(), "versions", packageName);
1103
+ const url2 = new URL("/api/v2/bundles", new URL(registryUrl).origin);
1104
+ url2.searchParams.set("package", packageName);
1105
+ const resp = await fetchRegistry(url2.toString(), "versions", packageName);
1106
1106
  const bundles = await resp.json();
1107
1107
  return (Array.isArray(bundles) ? bundles : []).map((b) => b.appVersion).filter((v) => typeof v === "string").sort((a, b) => compareSemver(b, a));
1108
1108
  }
@@ -2420,11 +2420,11 @@ function createAdminApiClientFromHttpClient(httpClient, _config) {
2420
2420
  }
2421
2421
 
2422
2422
  // src/auth/index.ts
2423
- function parseAuthCallback(url) {
2423
+ function parseAuthCallback(url2) {
2424
2424
  try {
2425
- const hashIndex = url.indexOf("#");
2425
+ const hashIndex = url2.indexOf("#");
2426
2426
  if (hashIndex === -1) return null;
2427
- const hash = url.substring(hashIndex + 1);
2427
+ const hash = url2.substring(hashIndex + 1);
2428
2428
  const params = new URLSearchParams(hash);
2429
2429
  const accessToken = params.get("access_token");
2430
2430
  if (!accessToken) return null;
@@ -2781,7 +2781,7 @@ var SseClient = class {
2781
2781
  throw new Error("SseClient needs either `getAuthToken` or `authorize`");
2782
2782
  }
2783
2783
  this.reconnectDelayMs = opts.reconnectDelayMs ?? 3e3;
2784
- this.fetchImpl = (url, init) => opts.fetch ? opts.fetch(url, init) : globalThis.fetch(url, init);
2784
+ this.fetchImpl = (url2, init) => opts.fetch ? opts.fetch(url2, init) : globalThis.fetch(url2, init);
2785
2785
  }
2786
2786
  on(event, handler) {
2787
2787
  const key = event;
@@ -2846,10 +2846,10 @@ var SseClient = class {
2846
2846
  this.closed = false;
2847
2847
  this.abortController = new AbortController();
2848
2848
  try {
2849
- const url = `${this.baseUrl}/sse`;
2850
- const response = await this.fetchImpl(url, {
2849
+ const url2 = `${this.baseUrl}/sse`;
2850
+ const response = await this.fetchImpl(url2, {
2851
2851
  headers: {
2852
- ...await this.authorize({ method: "GET", path: new URL(url).pathname }),
2852
+ ...await this.authorize({ method: "GET", path: new URL(url2).pathname }),
2853
2853
  "Accept": "text/event-stream"
2854
2854
  },
2855
2855
  signal: this.abortController.signal
@@ -2862,7 +2862,7 @@ var SseClient = class {
2862
2862
  terminal,
2863
2863
  response.status,
2864
2864
  response.statusText,
2865
- url,
2865
+ url2,
2866
2866
  response.headers,
2867
2867
  bodyText
2868
2868
  );
@@ -2870,7 +2870,7 @@ var SseClient = class {
2870
2870
  throw new HTTPError(
2871
2871
  response.status,
2872
2872
  response.statusText,
2873
- url,
2873
+ url2,
2874
2874
  response.headers,
2875
2875
  bodyText
2876
2876
  );
@@ -3049,12 +3049,12 @@ var SseClient = class {
3049
3049
  const params = {};
3050
3050
  if (ids.contextIds && ids.contextIds.length > 0) params.contextIds = ids.contextIds;
3051
3051
  if (ids.groupIds && ids.groupIds.length > 0) params.groupIds = ids.groupIds;
3052
- const url = `${this.baseUrl}/sse/subscription`;
3052
+ const url2 = `${this.baseUrl}/sse/subscription`;
3053
3053
  const body = JSON.stringify({ id: this.sessionId, method, params });
3054
- const response = await this.fetchImpl(url, {
3054
+ const response = await this.fetchImpl(url2, {
3055
3055
  method: "POST",
3056
3056
  headers: {
3057
- ...await this.authorize({ method: "POST", path: new URL(url).pathname, body }),
3057
+ ...await this.authorize({ method: "POST", path: new URL(url2).pathname, body }),
3058
3058
  "Content-Type": "application/json"
3059
3059
  },
3060
3060
  body,
@@ -5965,14 +5965,14 @@ function reportDataOf(quote) {
5965
5965
  }
5966
5966
  async function attestRelayNodeKey(opts) {
5967
5967
  const nonce2 = crypto.getRandomValues(new Uint8Array(32));
5968
- const url = `${opts.relayUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
5968
+ const url2 = `${opts.relayUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
5969
5969
  const body = JSON.stringify({
5970
5970
  nonce: hex(nonce2),
5971
5971
  bindNodeKey: true,
5972
5972
  ...opts.verify?.includeCollateral ? { includeCollateral: true } : {}
5973
5973
  });
5974
5974
  const init = { method: "POST", headers: { "Content-Type": "application/json" }, body };
5975
- const response = opts.fetch ? await opts.fetch(url, init) : await globalThis.fetch(url, init);
5975
+ const response = opts.fetch ? await opts.fetch(url2, init) : await globalThis.fetch(url2, init);
5976
5976
  if (!response.ok) {
5977
5977
  const text = await response.text().catch(() => "");
5978
5978
  throw new Error(`the relay would not attest (HTTP ${response.status})${text ? `: ${text}` : ""}`);
@@ -6294,13 +6294,13 @@ function createSealedFetch(options) {
6294
6294
  };
6295
6295
  return async (input, init) => {
6296
6296
  const request = new Request(input, init);
6297
- const url = new URL(request.url);
6298
- if (url.origin !== base.origin || !url.pathname.startsWith(`${basePath}/`)) {
6299
- throw new Error(`Refusing to send ${url.href} outside the sealed node at ${options.baseUrl}`);
6297
+ const url2 = new URL(request.url);
6298
+ if (url2.origin !== base.origin || !url2.pathname.startsWith(`${basePath}/`)) {
6299
+ throw new Error(`Refusing to send ${url2.href} outside the sealed node at ${options.baseUrl}`);
6300
6300
  }
6301
6301
  const headers = [];
6302
6302
  request.headers.forEach((value, name) => headers.push([name, value]));
6303
- const head = { method: request.method, path: url.pathname.slice(basePath.length) + url.search, headers };
6303
+ const head = { method: request.method, path: url2.pathname.slice(basePath.length) + url2.search, headers };
6304
6304
  const body = new Uint8Array(await request.arrayBuffer());
6305
6305
  const send = async (open2) => {
6306
6306
  const { requestId, header, envelope } = await sealRequest(open2, head, body);
@@ -6522,7 +6522,7 @@ function createQuoteVerifier(options) {
6522
6522
  const allowedMrtd = measurements(options.allowedMrtd ?? [], "allowedMrtd");
6523
6523
  const allowedImages = (options.allowedMeasurements ?? []).map((image, index) => {
6524
6524
  const label2 = `allowedMeasurements[${index}]`;
6525
- return REGISTERS.map((register) => measurements([image?.[register] ?? ""], `${label2}.${register}`)[0]).join();
6525
+ return REGISTERS.map((register2) => measurements([image?.[register2] ?? ""], `${label2}.${register2}`)[0]).join();
6526
6526
  });
6527
6527
  const allowedRtmr = [
6528
6528
  measurements(options.allowedRtmr0 ?? [], "allowedRtmr0"),
@@ -6571,7 +6571,7 @@ function createQuoteVerifier(options) {
6571
6571
  if (td.tdAttributes?.length !== 8 || (td.tdAttributes[0] & 1) !== 0) {
6572
6572
  throw new Error("The quote is from a debug TD, or its TD attributes cannot be read");
6573
6573
  }
6574
- const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register) => hex(register));
6574
+ const measured = [td.mrTd, td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3].map((register2) => hex(register2));
6575
6575
  if (allowedImages.length > 0 && !allowedImages.includes(measured.join())) {
6576
6576
  throw new Error(
6577
6577
  `The measurements (MRTD ${measured[0]}, RTMR0-3 ${measured.slice(1).join(", ")}) are not an image this verifier trusts`
@@ -6581,10 +6581,10 @@ function createQuoteVerifier(options) {
6581
6581
  throw new Error(`MRTD ${measured[0]} is not an image this verifier trusts`);
6582
6582
  }
6583
6583
  const registers = [td.rtMr0, td.rtMr1, td.rtMr2, td.rtMr3];
6584
- registers.forEach((register, index) => {
6584
+ registers.forEach((register2, index) => {
6585
6585
  const allowed = allowedRtmr[index];
6586
- if (allowed.length > 0 && !allowed.includes(hex(register))) {
6587
- throw new Error(`RTMR${index} ${hex(register)} is not one this verifier trusts`);
6586
+ if (allowed.length > 0 && !allowed.includes(hex(register2))) {
6587
+ throw new Error(`RTMR${index} ${hex(register2)} is not one this verifier trusts`);
6588
6588
  }
6589
6589
  });
6590
6590
  if (hex(td.reportData) !== `${nonce2}${reportDataSuffix}`.toLowerCase()) {
@@ -7061,7 +7061,7 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
7061
7061
  throw new Error(`The signed release is a ${JSON.stringify(release?.role)} release, not a node one`);
7062
7062
  }
7063
7063
  const profiles = Object.values(release.profiles ?? {});
7064
- const measured = (image) => MEASUREMENTS.every((register) => /^[0-9a-f]{96}$/i.test(String(image?.[register])));
7064
+ const measured = (image) => MEASUREMENTS.every((register2) => /^[0-9a-f]{96}$/i.test(String(image?.[register2])));
7065
7065
  if (typeof release.tag !== "string" || profiles.length === 0 || !profiles.every(measured)) {
7066
7066
  throw new Error("The signed file is not a release's published-mrtds.json: it lists no measured profiles");
7067
7067
  }
@@ -7070,17 +7070,17 @@ async function verifySignedNodeRelease(publishedMrtds, bundle, options = {}) {
7070
7070
  }
7071
7071
  return release;
7072
7072
  }
7073
- async function fetchNodeRelease(url, options = {}) {
7074
- const response = await (options.fetch ?? fetch)(url, { headers: { accept: "application/json" } });
7075
- if (!response.ok) throw new Error(`Fetching the node release from ${url} failed: HTTP ${response.status}`);
7073
+ async function fetchNodeRelease(url2, options = {}) {
7074
+ const response = await (options.fetch ?? fetch)(url2, { headers: { accept: "application/json" } });
7075
+ if (!response.ok) throw new Error(`Fetching the node release from ${url2} failed: HTTP ${response.status}`);
7076
7076
  let release;
7077
7077
  try {
7078
7078
  release = (await response.json())?.data;
7079
7079
  } catch {
7080
- throw new Error(`${url} did not answer with JSON`);
7080
+ throw new Error(`${url2} did not answer with JSON`);
7081
7081
  }
7082
7082
  if (typeof release?.version !== "string" || typeof release.publishedMrtds !== "string" || typeof release.bundle !== "string") {
7083
- throw new Error(`${url} did not answer with a signed node release`);
7083
+ throw new Error(`${url2} did not answer with a signed node release`);
7084
7084
  }
7085
7085
  return { version: release.version, publishedMrtds: release.publishedMrtds, bundle: release.bundle };
7086
7086
  }
@@ -7102,20 +7102,20 @@ function infoUrl(baseUrl) {
7102
7102
  return `${baseUrl.replace(/\/+$/, "")}/admin-api/tee/info`;
7103
7103
  }
7104
7104
  async function readNodeReleaseVersion(baseUrl, givenFetch) {
7105
- const url = infoUrl(baseUrl);
7106
- const response = await givenFetch(url, { headers: { accept: "application/json" } });
7105
+ const url2 = infoUrl(baseUrl);
7106
+ const response = await givenFetch(url2, { headers: { accept: "application/json" } });
7107
7107
  if (response.status === 403) {
7108
7108
  const code = await response.json().then((body) => body?.error?.code).catch(() => void 0);
7109
7109
  if (code === "sealed_required") return void 0;
7110
7110
  }
7111
- if (!response.ok) throw new Error(`Fetching ${url} failed: HTTP ${response.status}`);
7111
+ if (!response.ok) throw new Error(`Fetching ${url2} failed: HTTP ${response.status}`);
7112
7112
  let osImage;
7113
7113
  try {
7114
7114
  osImage = (await response.json())?.data?.osImage;
7115
7115
  } catch {
7116
- throw new Error(`${url} did not answer with JSON`);
7116
+ throw new Error(`${url2} did not answer with JSON`);
7117
7117
  }
7118
- if (typeof osImage !== "string") throw new Error(`${url} did not name the node's image`);
7118
+ if (typeof osImage !== "string") throw new Error(`${url2} did not name the node's image`);
7119
7119
  return nodeReleaseVersionFromImage(osImage);
7120
7120
  }
7121
7121
  function cloudNodeReleaseUrl(cloudUrl, version) {
@@ -8725,8 +8725,8 @@ function createProofAuthorizer(credential) {
8725
8725
  return { [REQUEST_PROOF_HEADER]: proof };
8726
8726
  };
8727
8727
  }
8728
- function signedPath(url) {
8729
- return new URL(url).pathname;
8728
+ function signedPath(url2) {
8729
+ return new URL(url2).pathname;
8730
8730
  }
8731
8731
 
8732
8732
  // src/presence/statement.ts
@@ -8913,7 +8913,7 @@ var MeroClient = class {
8913
8913
  const authorizeRequest = this.proofAuthorizer;
8914
8914
  this.relayAdmin = createAdminApiClientFromHttpClient(
8915
8915
  createHttpClient({
8916
- fetch: (url, init) => fetchImpl ? fetchImpl(url, init) : globalThis.fetch(url, init),
8916
+ fetch: (url2, init) => fetchImpl ? fetchImpl(url2, init) : globalThis.fetch(url2, init),
8917
8917
  baseUrl: relay.relayUrl,
8918
8918
  authorizeRequest
8919
8919
  }),
@@ -9556,9 +9556,9 @@ function writeRelayMap(account, map) {
9556
9556
  }
9557
9557
  function rememberRelay(account, relayUrl, at) {
9558
9558
  const map = readRelayMap(account);
9559
- const url = relayOrigin(relayUrl);
9560
- if (at.namespaceId) map.namespaces[at.namespaceId] = url;
9561
- if (at.contextId) map.contexts[at.contextId] = url;
9559
+ const url2 = relayOrigin(relayUrl);
9560
+ if (at.namespaceId) map.namespaces[at.namespaceId] = url2;
9561
+ if (at.contextId) map.contexts[at.contextId] = url2;
9562
9562
  writeRelayMap(account, map);
9563
9563
  }
9564
9564
  function relayForContext(account, contextId) {
@@ -9941,7 +9941,7 @@ function beginLinkState(account, returnTo) {
9941
9941
  if (!ACCOUNT_HEX.test(account)) {
9942
9942
  throw new Error("accountId must be 64 lowercase hex characters");
9943
9943
  }
9944
- const url = new URL(returnTo);
9944
+ const url2 = new URL(returnTo);
9945
9945
  const now = Date.now();
9946
9946
  const pending = readPending(now);
9947
9947
  const bytes = crypto.getRandomValues(new Uint8Array(16));
@@ -9950,8 +9950,8 @@ function beginLinkState(account, returnTo) {
9950
9950
  );
9951
9951
  pending[state] = { account, expiresAt: now + LIFETIME_MS };
9952
9952
  writePending(Object.fromEntries(Object.entries(pending).slice(-MAX_PENDING)));
9953
- url.searchParams.set(STATE_PARAM, state);
9954
- return url.toString();
9953
+ url2.searchParams.set(STATE_PARAM, state);
9954
+ return url2.toString();
9955
9955
  }
9956
9956
  function takeLinkState(search) {
9957
9957
  const state = new URLSearchParams(search).get(STATE_PARAM);
@@ -9973,10 +9973,10 @@ function withoutLinkState(search) {
9973
9973
  // src/cloud/link-redirect.ts
9974
9974
  var DEFAULT_CLOUD_WEB_URL = "https://cloud.calimero.network";
9975
9975
  function cloudLinkUrl(options) {
9976
- const url = new URL(options.cloudWebUrl ?? DEFAULT_CLOUD_WEB_URL);
9977
- url.searchParams.set("link-account", options.accountId);
9978
- url.searchParams.set("callback-url", beginLinkState(options.accountId, options.returnTo));
9979
- return url.toString();
9976
+ const url2 = new URL(options.cloudWebUrl ?? DEFAULT_CLOUD_WEB_URL);
9977
+ url2.searchParams.set("link-account", options.accountId);
9978
+ url2.searchParams.set("callback-url", beginLinkState(options.accountId, options.returnTo));
9979
+ return url2.toString();
9980
9980
  }
9981
9981
  function beginCloudLink(options) {
9982
9982
  window.location.assign(cloudLinkUrl(options));
@@ -10032,12 +10032,12 @@ function deviceEnrolmentUrl(options) {
10032
10032
  assertHex(options.kemPublicKey, "kemPublicKey");
10033
10033
  assertSafeReturnTo(options.returnTo);
10034
10034
  warnOnForeignCallback(options.returnTo);
10035
- const url = new URL(options.walletUrl);
10036
- url.searchParams.set(DEVICE_PARAM, options.devicePublicKey);
10037
- url.searchParams.set(KEM_PARAM, options.kemPublicKey);
10038
- url.searchParams.set(CALLBACK_PARAM, options.returnTo);
10039
- if (options.state) url.searchParams.set(STATE_PARAM2, options.state);
10040
- return url.toString();
10035
+ const url2 = new URL(options.walletUrl);
10036
+ url2.searchParams.set(DEVICE_PARAM, options.devicePublicKey);
10037
+ url2.searchParams.set(KEM_PARAM, options.kemPublicKey);
10038
+ url2.searchParams.set(CALLBACK_PARAM, options.returnTo);
10039
+ if (options.state) url2.searchParams.set(STATE_PARAM2, options.state);
10040
+ return url2.toString();
10041
10041
  }
10042
10042
  function beginDeviceEnrolment(options) {
10043
10043
  window.location.assign(deviceEnrolmentUrl(options));
@@ -10122,17 +10122,17 @@ function warnOnForeignCallback(returnTo) {
10122
10122
  );
10123
10123
  }
10124
10124
  function assertSafeReturnTo(returnTo) {
10125
- let url;
10125
+ let url2;
10126
10126
  try {
10127
- url = new URL(returnTo);
10127
+ url2 = new URL(returnTo);
10128
10128
  } catch {
10129
10129
  throw new Error(`returnTo must be an absolute URL, got ${returnTo}`);
10130
10130
  }
10131
- const loopback = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]" || url.hostname === "::1";
10132
- if (url.protocol === "https:") return;
10133
- if (url.protocol === "http:" && loopback) return;
10131
+ const loopback = url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]" || url2.hostname === "::1";
10132
+ if (url2.protocol === "https:") return;
10133
+ if (url2.protocol === "http:" && loopback) return;
10134
10134
  throw new Error(
10135
- `returnTo must be https:, or http: on localhost \u2014 got ${url.protocol}//${url.hostname}`
10135
+ `returnTo must be https:, or http: on localhost \u2014 got ${url2.protocol}//${url2.hostname}`
10136
10136
  );
10137
10137
  }
10138
10138
 
@@ -10419,8 +10419,8 @@ function joinNonce(account) {
10419
10419
  const source = createLocalStorageNonceSource(`calimero.delegated.joinnonce.${account}`);
10420
10420
  return () => source.next();
10421
10421
  }
10422
- function origin(url) {
10423
- return url.replace(/\/+$/, "");
10422
+ function origin(url2) {
10423
+ return url2.replace(/\/+$/, "");
10424
10424
  }
10425
10425
  async function joinWithNode(input) {
10426
10426
  const { account, credential, deviceSecret } = input.credential;
@@ -10442,11 +10442,11 @@ async function joinWithNode(input) {
10442
10442
  };
10443
10443
  }
10444
10444
  const body = { invitation: input.invitation, signedOp };
10445
- const url = input.admitUrl ?? `${origin(input.nodeUrl)}/admin-api/namespaces/${pathSegment(input.namespaceId)}/admit`;
10445
+ const url2 = input.admitUrl ?? `${origin(input.nodeUrl)}/admin-api/namespaces/${pathSegment(input.namespaceId)}/admit`;
10446
10446
  const doFetch = input.deps?.fetch ?? fetch;
10447
10447
  let response;
10448
10448
  try {
10449
- response = await doFetch(url, {
10449
+ response = await doFetch(url2, {
10450
10450
  method: "POST",
10451
10451
  // No Authorization header and no request proof, deliberately: the route is
10452
10452
  // unauthenticated because the joiner's signature is the authorization.
@@ -10569,8 +10569,8 @@ function selectLatestBundle(bundles) {
10569
10569
  );
10570
10570
  }
10571
10571
  async function fetchRegistryBundles(registryUrl, pkg, fetchFn = globalThis.fetch) {
10572
- const url = `${registryUrl.replace(/\/+$/, "")}/api/v2/bundles?package=${encodeURIComponent(pkg)}`;
10573
- const response = await fetchFn(url, { headers: { Accept: "application/json" } });
10572
+ const url2 = `${registryUrl.replace(/\/+$/, "")}/api/v2/bundles?package=${encodeURIComponent(pkg)}`;
10573
+ const response = await fetchFn(url2, { headers: { Accept: "application/json" } });
10574
10574
  if (!response.ok) throw new Error(`the registry has no ${pkg} (HTTP ${response.status})`);
10575
10575
  const body = await response.json();
10576
10576
  return Array.isArray(body) ? body : [];
@@ -10610,9 +10610,9 @@ function nextGovernanceNonce(relay, group) {
10610
10610
  return next;
10611
10611
  }
10612
10612
  function relayFor(s, namespaceId) {
10613
- const url = readRelayMap(s.account).namespaces[namespaceId] ?? s.relayUrl;
10614
- if (!url) throw new Error("no relay is known for this namespace, so there is nowhere to send this");
10615
- return url.replace(/\/+$/, "");
10613
+ const url2 = readRelayMap(s.account).namespaces[namespaceId] ?? s.relayUrl;
10614
+ if (!url2) throw new Error("no relay is known for this namespace, so there is nowhere to send this");
10615
+ return url2.replace(/\/+$/, "");
10616
10616
  }
10617
10617
  function initArgsOf(params) {
10618
10618
  if (!params || params.length === 0) return {};
@@ -10695,7 +10695,7 @@ async function foundingExecutor(s, relay, fetch2) {
10695
10695
  const named = s.executorAccount && s.relayUrl?.replace(/\/+$/, "") === relay ? s.executorAccount : null;
10696
10696
  if (named) return { executorAccount: named, executorKey: await attestedNodeKey(relay) };
10697
10697
  const known = Object.entries(readRelayMap(s.account).namespaces).find(
10698
- ([, url]) => url.replace(/\/+$/, "") === relay
10698
+ ([, url2]) => url2.replace(/\/+$/, "") === relay
10699
10699
  )?.[0];
10700
10700
  if (!known) {
10701
10701
  throw new Error(
@@ -11142,8 +11142,8 @@ function accountHexOrNull(value) {
11142
11142
  return typeof value === "string" && ACCOUNT_HEX.test(value) ? value : null;
11143
11143
  }
11144
11144
  var AccountHaRefusedError = class extends HTTPError {
11145
- constructor(code, status, statusText, url, headers, bodyText) {
11146
- super(status, statusText, url, headers, bodyText);
11145
+ constructor(code, status, statusText, url2, headers, bodyText) {
11146
+ super(status, statusText, url2, headers, bodyText);
11147
11147
  this.code = code;
11148
11148
  this.name = "AccountHaRefusedError";
11149
11149
  }
@@ -12460,8 +12460,8 @@ var MeroJs = class {
12460
12460
  /**
12461
12461
  * Parse an auth callback URL hash fragment (static utility)
12462
12462
  */
12463
- static parseAuthCallback(url) {
12464
- return parseAuthCallback(url);
12463
+ static parseAuthCallback(url2) {
12464
+ return parseAuthCallback(url2);
12465
12465
  }
12466
12466
  /**
12467
12467
  * Build an auth login URL (static utility)
@@ -12726,8 +12726,8 @@ async function probeNodeHealth(baseUrl, options = {}) {
12726
12726
  if (abortSignal) abortSignal.addEventListener("abort", onAbort, { once: true });
12727
12727
  const timer = setTimeout(() => controller.abort(), timeoutMs);
12728
12728
  try {
12729
- const url = nodeEndpoint(baseUrl, "admin-api/health");
12730
- const res = await fetch(url, {
12729
+ const url2 = nodeEndpoint(baseUrl, "admin-api/health");
12730
+ const res = await fetch(url2, {
12731
12731
  method: "GET",
12732
12732
  signal: controller.signal
12733
12733
  });
@@ -12751,20 +12751,457 @@ async function discoverLocalNodes(options = {}) {
12751
12751
  const { ports = DEFAULT_LOCAL_NODE_PORTS, timeoutMs, signal } = options;
12752
12752
  const results = await Promise.all(
12753
12753
  ports.map(async (port) => {
12754
- const url = localNodeUrl(port);
12755
- const ok = await probeNodeHealth(url, { timeoutMs, signal });
12756
- return ok ? url : null;
12754
+ const url2 = localNodeUrl(port);
12755
+ const ok = await probeNodeHealth(url2, { timeoutMs, signal });
12756
+ return ok ? url2 : null;
12757
12757
  })
12758
12758
  );
12759
- return results.filter((url) => url !== null);
12759
+ return results.filter((url2) => url2 !== null);
12760
+ }
12761
+
12762
+ // src/agent-gate/chacha20poly1305.ts
12763
+ var KEY_LEN = 32;
12764
+ var NONCE_LEN = 12;
12765
+ var TAG_LEN2 = 16;
12766
+ function rotl(value, shift) {
12767
+ return (value << shift | value >>> 32 - shift) >>> 0;
12768
+ }
12769
+ function quarterRound(s, a, b, c, d) {
12770
+ s[a] = s[a] + s[b] >>> 0;
12771
+ s[d] = rotl(s[d] ^ s[a], 16);
12772
+ s[c] = s[c] + s[d] >>> 0;
12773
+ s[b] = rotl(s[b] ^ s[c], 12);
12774
+ s[a] = s[a] + s[b] >>> 0;
12775
+ s[d] = rotl(s[d] ^ s[a], 8);
12776
+ s[c] = s[c] + s[d] >>> 0;
12777
+ s[b] = rotl(s[b] ^ s[c], 7);
12778
+ }
12779
+ function u32le2(bytes, offset) {
12780
+ return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
12781
+ }
12782
+ function chacha20Block(key, counter, nonce2) {
12783
+ const state = new Uint32Array(16);
12784
+ state[0] = 1634760805;
12785
+ state[1] = 857760878;
12786
+ state[2] = 2036477234;
12787
+ state[3] = 1797285236;
12788
+ for (let i = 0; i < 8; i += 1) state[4 + i] = u32le2(key, i * 4);
12789
+ state[12] = counter >>> 0;
12790
+ for (let i = 0; i < 3; i += 1) state[13 + i] = u32le2(nonce2, i * 4);
12791
+ const working = state.slice();
12792
+ for (let round = 0; round < 10; round += 1) {
12793
+ quarterRound(working, 0, 4, 8, 12);
12794
+ quarterRound(working, 1, 5, 9, 13);
12795
+ quarterRound(working, 2, 6, 10, 14);
12796
+ quarterRound(working, 3, 7, 11, 15);
12797
+ quarterRound(working, 0, 5, 10, 15);
12798
+ quarterRound(working, 1, 6, 11, 12);
12799
+ quarterRound(working, 2, 7, 8, 13);
12800
+ quarterRound(working, 3, 4, 9, 14);
12801
+ }
12802
+ const out = new Uint8Array(64);
12803
+ for (let i = 0; i < 16; i += 1) {
12804
+ const word = working[i] + state[i] >>> 0;
12805
+ out[i * 4] = word & 255;
12806
+ out[i * 4 + 1] = word >>> 8 & 255;
12807
+ out[i * 4 + 2] = word >>> 16 & 255;
12808
+ out[i * 4 + 3] = word >>> 24 & 255;
12809
+ }
12810
+ return out;
12811
+ }
12812
+ function chacha20(key, counter, nonce2, data) {
12813
+ const out = new Uint8Array(data.length);
12814
+ for (let offset = 0, block = counter; offset < data.length; offset += 64, block += 1) {
12815
+ const stream = chacha20Block(key, block, nonce2);
12816
+ const end = Math.min(offset + 64, data.length);
12817
+ for (let i = offset; i < end; i += 1) out[i] = data[i] ^ stream[i - offset];
12818
+ }
12819
+ return out;
12820
+ }
12821
+ function leToBigInt(bytes) {
12822
+ let value = 0n;
12823
+ for (let i = bytes.length - 1; i >= 0; i -= 1) value = value << 8n | BigInt(bytes[i]);
12824
+ return value;
12825
+ }
12826
+ var P1305 = (1n << 130n) - 5n;
12827
+ function poly1305(key, message) {
12828
+ const r = leToBigInt(key.subarray(0, 16)) & 0x0ffffffc0ffffffc0ffffffc0fffffffn;
12829
+ const s = leToBigInt(key.subarray(16, 32));
12830
+ let acc = 0n;
12831
+ for (let offset = 0; offset < message.length; offset += 16) {
12832
+ const block = message.subarray(offset, Math.min(offset + 16, message.length));
12833
+ const n = leToBigInt(block) + (1n << BigInt(8 * block.length));
12834
+ acc = (acc + n) * r % P1305;
12835
+ }
12836
+ let tag3 = acc + s & (1n << 128n) - 1n;
12837
+ const out = new Uint8Array(TAG_LEN2);
12838
+ for (let i = 0; i < TAG_LEN2; i += 1) {
12839
+ out[i] = Number(tag3 & 0xffn);
12840
+ tag3 >>= 8n;
12841
+ }
12842
+ return out;
12843
+ }
12844
+ function pad16(length) {
12845
+ return new Uint8Array((16 - length % 16) % 16);
12846
+ }
12847
+ function u64le2(value) {
12848
+ const out = new Uint8Array(8);
12849
+ new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
12850
+ return out;
12851
+ }
12852
+ function macData(aad, ciphertext) {
12853
+ const parts = [aad, pad16(aad.length), ciphertext, pad16(ciphertext.length), u64le2(aad.length), u64le2(ciphertext.length)];
12854
+ const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
12855
+ let offset = 0;
12856
+ for (const part of parts) {
12857
+ out.set(part, offset);
12858
+ offset += part.length;
12859
+ }
12860
+ return out;
12861
+ }
12862
+ function check(key, nonce2) {
12863
+ if (key.length !== KEY_LEN) throw new Error("ChaCha20-Poly1305 needs a 32-byte key");
12864
+ if (nonce2.length !== NONCE_LEN) throw new Error("ChaCha20-Poly1305 needs a 12-byte nonce");
12865
+ }
12866
+ function chacha20Poly1305Seal(key, nonce2, plaintext, aad = new Uint8Array(0)) {
12867
+ check(key, nonce2);
12868
+ const otk = chacha20Block(key, 0, nonce2).subarray(0, 32);
12869
+ const ciphertext = chacha20(key, 1, nonce2, plaintext);
12870
+ const tag3 = poly1305(otk, macData(aad, ciphertext));
12871
+ const out = new Uint8Array(ciphertext.length + TAG_LEN2);
12872
+ out.set(ciphertext);
12873
+ out.set(tag3, ciphertext.length);
12874
+ return out;
12875
+ }
12876
+
12877
+ // src/agent-gate/hpke.ts
12878
+ var KEM_ID = 32;
12879
+ var KDF_ID = 1;
12880
+ var AEAD_ID = 3;
12881
+ var MODE_AUTH = 2;
12882
+ var N_SECRET = 32;
12883
+ var N_KEY = 32;
12884
+ var N_NONCE = 12;
12885
+ var utf84 = (s) => new TextEncoder().encode(s);
12886
+ var i2osp2 = (n) => new Uint8Array([n >> 8 & 255, n & 255]);
12887
+ var KEM_SUITE = concat(utf84("KEM"), i2osp2(KEM_ID));
12888
+ var HPKE_SUITE = concat(utf84("HPKE"), i2osp2(KEM_ID), i2osp2(KDF_ID), i2osp2(AEAD_ID));
12889
+ async function hmac(key, data) {
12890
+ const raw = key.length === 0 ? new Uint8Array(32) : key;
12891
+ const k = await crypto.subtle.importKey("raw", raw, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
12892
+ return new Uint8Array(await crypto.subtle.sign("HMAC", k, data));
12893
+ }
12894
+ async function expand(prk, info, length) {
12895
+ const out = new Uint8Array(length);
12896
+ let previous = new Uint8Array(0);
12897
+ for (let i = 1, offset = 0; offset < length; i += 1) {
12898
+ previous = await hmac(prk, concat(previous, info, new Uint8Array([i])));
12899
+ out.set(previous.subarray(0, Math.min(previous.length, length - offset)), offset);
12900
+ offset += previous.length;
12901
+ }
12902
+ return out;
12903
+ }
12904
+ function labeledExtract(suite, salt, label2, ikm) {
12905
+ return hmac(salt, concat(utf84("HPKE-v1"), suite, utf84(label2), ikm));
12906
+ }
12907
+ function labeledExpand(suite, prk, label2, info, length) {
12908
+ return expand(prk, concat(i2osp2(length), utf84("HPKE-v1"), suite, utf84(label2), info), length);
12909
+ }
12910
+ async function extractAndExpand(dhValue, kemContext) {
12911
+ const prk = await labeledExtract(KEM_SUITE, new Uint8Array(0), "eae_prk", dhValue);
12912
+ return labeledExpand(KEM_SUITE, prk, "shared_secret", kemContext, N_SECRET);
12913
+ }
12914
+ async function keySchedule(sharedSecret, info) {
12915
+ const empty = new Uint8Array(0);
12916
+ const pskIdHash = await labeledExtract(HPKE_SUITE, empty, "psk_id_hash", empty);
12917
+ const infoHash = await labeledExtract(HPKE_SUITE, empty, "info_hash", info);
12918
+ const context = concat(new Uint8Array([MODE_AUTH]), pskIdHash, infoHash);
12919
+ const secret = await labeledExtract(HPKE_SUITE, sharedSecret, "secret", empty);
12920
+ return {
12921
+ key: await labeledExpand(HPKE_SUITE, secret, "key", context, N_KEY),
12922
+ nonce: await labeledExpand(HPKE_SUITE, secret, "base_nonce", context, N_NONCE)
12923
+ };
12924
+ }
12925
+ async function hpkeSealAuth(recipientPublic, senderSecret, info, plaintext, aad = new Uint8Array(0), ephemeralSecret) {
12926
+ if (recipientPublic.length !== 32) throw new Error("The recipient key is not 32 bytes of X25519");
12927
+ const ephemeral = await x25519KeyPair(ephemeralSecret);
12928
+ const sender = await x25519KeyPair(senderSecret);
12929
+ const dhValue = concat(await dh(ephemeral.privateKey, recipientPublic), await dh(sender.privateKey, recipientPublic));
12930
+ const shared = await extractAndExpand(dhValue, concat(ephemeral.publicKey, recipientPublic, sender.publicKey));
12931
+ const { key, nonce: nonce2 } = await keySchedule(shared, info);
12932
+ return { enc: ephemeral.publicKey, ciphertext: chacha20Poly1305Seal(key, nonce2, plaintext, aad) };
12933
+ }
12934
+
12935
+ // src/agent-gate/gate.ts
12936
+ var AGENT_ATTEST_DOMAIN = "mero-agent-gate/attest/v3";
12937
+ var AGENT_PROVISION_INFO_DOMAIN = "mero-agent-gate/provision/v2";
12938
+ var AGENT_ID = /^[a-z0-9][a-z0-9-]{0,62}$/;
12939
+ var SECRET_NAME = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
12940
+ var MAX_SECRETS = 64;
12941
+ var MAX_SECRET_LEN = 64 * 1024;
12942
+ var AgentGateError = class extends Error {
12943
+ constructor(message, status, code) {
12944
+ super(message);
12945
+ this.status = status;
12946
+ this.code = code;
12947
+ this.name = "AgentGateError";
12948
+ }
12949
+ };
12950
+ function validateAgentId(agentId) {
12951
+ if (!AGENT_ID.test(agentId)) {
12952
+ throw new Error(`Agent id ${JSON.stringify(agentId)} must match [a-z0-9][a-z0-9-]{0,62}`);
12953
+ }
12954
+ }
12955
+ function utf85(value) {
12956
+ return new TextEncoder().encode(value);
12957
+ }
12958
+ function lengthPrefixed(agentId) {
12959
+ const id = utf85(agentId);
12960
+ return concat(new Uint8Array([id.length]), id);
12961
+ }
12962
+ function toBase64(bytes) {
12963
+ let binary = "";
12964
+ for (const byte of bytes) binary += String.fromCharCode(byte);
12965
+ return btoa(binary);
12966
+ }
12967
+ function fromBase644(value, label2, length) {
12968
+ let bytes;
12969
+ try {
12970
+ bytes = Uint8Array.from(atob(value.trim()), (c) => c.charCodeAt(0));
12971
+ } catch {
12972
+ throw new Error(`${label2} is not base64`);
12973
+ }
12974
+ if (length !== void 0 && bytes.length !== length) throw new Error(`${label2} is not ${length} bytes`);
12975
+ return bytes;
12976
+ }
12977
+ async function agentKeyBinding(provisioningPublic, agentId, signingPublic, ownerPublic) {
12978
+ const zero = new Uint8Array(32);
12979
+ const data = concat(
12980
+ utf85(AGENT_ATTEST_DOMAIN),
12981
+ provisioningPublic,
12982
+ lengthPrefixed(agentId),
12983
+ signingPublic ?? zero,
12984
+ ownerPublic ?? zero
12985
+ );
12986
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", data));
12987
+ }
12988
+ function provisionInfo(recipientPublic, agentId) {
12989
+ return concat(utf85(AGENT_PROVISION_INFO_DOMAIN), recipientPublic, lengthPrefixed(agentId));
12990
+ }
12991
+ async function generateOwnerKey() {
12992
+ const secret = crypto.getRandomValues(new Uint8Array(32));
12993
+ return { secret, publicKey: await ownerPublicKey(secret) };
12994
+ }
12995
+ async function ownerPublicKey(secret) {
12996
+ if (secret.length !== 32) throw new Error("An owner key is 32 bytes");
12997
+ return toBase64((await x25519KeyPair(secret)).publicKey);
12998
+ }
12999
+ function url(gateUrl, path) {
13000
+ return `${gateUrl.replace(/\/+$/, "")}${path}`;
13001
+ }
13002
+ async function postJson(fetchImpl, target, body) {
13003
+ const response = await fetchImpl(target, {
13004
+ method: "POST",
13005
+ headers: { "content-type": "application/json" },
13006
+ body: JSON.stringify(body)
13007
+ });
13008
+ const text = await response.text();
13009
+ let parsed = void 0;
13010
+ try {
13011
+ parsed = text ? JSON.parse(text) : void 0;
13012
+ } catch {
13013
+ }
13014
+ if (!response.ok) {
13015
+ const error = parsed;
13016
+ throw new AgentGateError(
13017
+ `The gate answered ${response.status}${error?.error ? ` ${error.error}` : ""}: ${error?.details ?? text.slice(0, 200)}`,
13018
+ response.status,
13019
+ error?.error
13020
+ );
13021
+ }
13022
+ return parsed;
13023
+ }
13024
+ async function attestAgent(options) {
13025
+ const agentId = options.agentId ?? "";
13026
+ if (agentId) validateAgentId(agentId);
13027
+ const nonce2 = crypto.getRandomValues(new Uint8Array(32));
13028
+ const body = await postJson(options.fetch ?? fetch, url(options.gateUrl, "/attest"), {
13029
+ nonceB64: toBase64(nonce2),
13030
+ ...agentId ? { agentId } : {}
13031
+ });
13032
+ if ((body?.agentId ?? "") !== agentId) {
13033
+ throw new Error(`Asked about agent ${JSON.stringify(agentId)}, the gate answered for ${JSON.stringify(body?.agentId)}`);
13034
+ }
13035
+ const provisioning = fromBase644(body.provisioningPublicKeyB64 ?? "", "provisioningPublicKeyB64", 32);
13036
+ const signing = body.signingPublicKeyB64 ? fromBase644(body.signingPublicKeyB64, "signingPublicKeyB64", 32) : void 0;
13037
+ const owner = body.ownerPublicKeyB64 ? fromBase644(body.ownerPublicKeyB64, "ownerPublicKeyB64", 32) : void 0;
13038
+ if (!signing !== !owner) {
13039
+ throw new Error("A claimed agent has both a signing key and an owner; the gate named one");
13040
+ }
13041
+ const binding = await agentKeyBinding(provisioning, agentId, signing, owner);
13042
+ await options.verifier({ quoteB64: body.quoteB64, nonce: hex(nonce2), reportDataSuffix: hex(binding) });
13043
+ return {
13044
+ agentId,
13045
+ provisioningPublicKey: toBase64(provisioning),
13046
+ ...signing ? { signingPublicKey: toBase64(signing) } : {},
13047
+ ...owner ? { ownerPublicKey: toBase64(owner) } : {}
13048
+ };
13049
+ }
13050
+ async function checkOwner(agent, ownerSecret) {
13051
+ const mine = await ownerPublicKey(ownerSecret);
13052
+ if (agent.ownerPublicKey && agent.ownerPublicKey !== mine) {
13053
+ throw new AgentGateError(
13054
+ `This agent is claimed by another key (${agent.ownerPublicKey}); it is not yours. Send it nothing and do not authorize its signing key`,
13055
+ void 0,
13056
+ "not_yours"
13057
+ );
13058
+ }
13059
+ return mine;
13060
+ }
13061
+ function validateSecrets(secrets) {
13062
+ const names = Object.keys(secrets);
13063
+ if (names.length === 0) throw new Error("There are no secrets to provision");
13064
+ if (names.length > MAX_SECRETS) throw new Error(`At most ${MAX_SECRETS} secrets at once`);
13065
+ for (const name of names) {
13066
+ 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}`);
13067
+ if (typeof secrets[name] !== "string") throw new Error(`Secret ${name} is not a string`);
13068
+ if (utf85(secrets[name]).length > MAX_SECRET_LEN) throw new Error(`Secret ${name} is over ${MAX_SECRET_LEN} bytes`);
13069
+ }
13070
+ }
13071
+ async function sendSealed(fetchImpl, gateUrl, path, agent, ownerSecret, message) {
13072
+ if (!agent.agentId) throw new Error("This quote names no agent; attest with the agent id");
13073
+ const mine = await checkOwner(agent, ownerSecret);
13074
+ const recipient = fromBase644(agent.provisioningPublicKey, "provisioningPublicKey", 32);
13075
+ const sealed = await hpkeSealAuth(
13076
+ recipient,
13077
+ ownerSecret,
13078
+ provisionInfo(recipient, agent.agentId),
13079
+ utf85(JSON.stringify(message))
13080
+ );
13081
+ return postJson(fetchImpl, url(gateUrl, path), {
13082
+ agentId: agent.agentId,
13083
+ provisioningPublicKeyB64: agent.provisioningPublicKey,
13084
+ senderPublicKeyB64: mine,
13085
+ encappedKeyB64: toBase64(sealed.enc),
13086
+ ciphertextB64: toBase64(sealed.ciphertext)
13087
+ });
13088
+ }
13089
+ async function provisionAgent(options) {
13090
+ validateSecrets(options.secrets);
13091
+ const fetchImpl = options.fetch ?? fetch;
13092
+ const answer = await sendSealed(fetchImpl, options.gateUrl, "/provision", options.agent, options.ownerSecret, {
13093
+ secrets: options.secrets
13094
+ });
13095
+ const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
13096
+ const mine = await ownerPublicKey(options.ownerSecret);
13097
+ if (after.ownerPublicKey !== mine || !after.signingPublicKey) {
13098
+ throw new AgentGateError("The gate accepted the secrets, but its quote does not name your key as owner");
13099
+ }
13100
+ if (options.agent.signingPublicKey && options.agent.signingPublicKey !== after.signingPublicKey) {
13101
+ throw new AgentGateError("The agent's signing key changed while provisioning");
13102
+ }
13103
+ return {
13104
+ agentId: after.agentId,
13105
+ provisioningPublicKey: after.provisioningPublicKey,
13106
+ signingPublicKey: after.signingPublicKey,
13107
+ ownerPublicKey: mine,
13108
+ written: answer?.written ?? [],
13109
+ claimed: answer?.claimed === true
13110
+ };
13111
+ }
13112
+ async function releaseAgent(options) {
13113
+ if (!options.agent.ownerPublicKey) throw new Error("This agent is not claimed; there is nothing to release");
13114
+ const fetchImpl = options.fetch ?? fetch;
13115
+ await sendSealed(fetchImpl, options.gateUrl, "/release", options.agent, options.ownerSecret, { release: true });
13116
+ const after = await attestAgent({ gateUrl: options.gateUrl, agentId: options.agent.agentId, verifier: options.verifier, fetch: fetchImpl });
13117
+ if (after.ownerPublicKey) {
13118
+ throw new AgentGateError("The gate says it released the agent, but its quote still names an owner");
13119
+ }
13120
+ }
13121
+
13122
+ // src/agent-gate/policy.ts
13123
+ var KMS_RELEASE_SIGNER = Object.freeze({
13124
+ identity: "https://github.com/calimero-network/mero-tee/.github/workflows/release-kms.yaml@refs/heads/master",
13125
+ issuer: "https://token.actions.githubusercontent.com"
13126
+ });
13127
+ var LISTS = [
13128
+ "allowed_tcb_statuses",
13129
+ "allowed_mrtd",
13130
+ "allowed_rtmr0",
13131
+ "allowed_rtmr1",
13132
+ "allowed_rtmr2",
13133
+ "allowed_rtmr3"
13134
+ ];
13135
+ async function verifySignedAgentPolicy(policy, bundle, options = {}) {
13136
+ const body = typeof policy === "string" ? new TextEncoder().encode(policy) : policy;
13137
+ await verifyCosignBundle(body, bundle, {
13138
+ identity: options.identity ?? KMS_RELEASE_SIGNER.identity,
13139
+ issuer: options.issuer ?? KMS_RELEASE_SIGNER.issuer
13140
+ });
13141
+ let parsed;
13142
+ try {
13143
+ parsed = JSON.parse(new TextDecoder().decode(body));
13144
+ } catch {
13145
+ throw new Error("The signed agent policy is not JSON");
13146
+ }
13147
+ if (parsed?.role !== "agent") {
13148
+ throw new Error(`The signed file is a ${JSON.stringify(parsed?.role)} policy, not an agent one`);
13149
+ }
13150
+ const profile = options.profile ?? PRODUCTION_PROFILE;
13151
+ if (parsed.profile !== profile) {
13152
+ throw new Error(`The signed agent policy is for the ${JSON.stringify(parsed.profile)} profile, not ${profile}`);
13153
+ }
13154
+ if (options.expectedVersion !== void 0 && parsed.version !== options.expectedVersion) {
13155
+ throw new Error(`The signed agent policy is release ${JSON.stringify(parsed.version)}, not ${options.expectedVersion}`);
13156
+ }
13157
+ checkLists(parsed);
13158
+ return parsed;
13159
+ }
13160
+ function checkLists(policy) {
13161
+ for (const list of LISTS) {
13162
+ if (!Array.isArray(policy?.[list]) || policy[list].length === 0) {
13163
+ throw new Error(`The agent policy's ${list} is empty, so no agent would be accepted`);
13164
+ }
13165
+ }
13166
+ }
13167
+ var TCB_STATUSES2 = [
13168
+ "UpToDate",
13169
+ "SWHardeningNeeded",
13170
+ "ConfigurationNeeded",
13171
+ "ConfigurationAndSWHardeningNeeded",
13172
+ "OutOfDate",
13173
+ "OutOfDateConfigurationNeeded"
13174
+ ];
13175
+ function tcbStatus2(value) {
13176
+ const found = TCB_STATUSES2.find((status) => status.toLowerCase() === value.trim().toLowerCase());
13177
+ if (!found) throw new Error(`The agent policy allows an unknown TCB status ${JSON.stringify(value)}`);
13178
+ return found;
13179
+ }
13180
+ var register = (value) => value.trim().replace(/^0x/i, "");
13181
+ function agentQuoteVerifier(policy, options) {
13182
+ checkLists(policy);
13183
+ return createQuoteVerifier({
13184
+ dcapVerify: options.dcapVerify,
13185
+ fetchCollateral: options.fetchCollateral,
13186
+ now: options.now,
13187
+ allowedTcbStatuses: policy.allowed_tcb_statuses.map(tcbStatus2),
13188
+ allowedMrtd: policy.allowed_mrtd.map(register),
13189
+ allowedRtmr0: policy.allowed_rtmr0.map(register),
13190
+ allowedRtmr1: policy.allowed_rtmr1.map(register),
13191
+ allowedRtmr2: policy.allowed_rtmr2.map(register),
13192
+ allowedRtmr3: policy.allowed_rtmr3.map(register)
13193
+ });
12760
13194
  }
12761
13195
  export {
12762
13196
  ACCOUNT_HA_AUDIENCE,
12763
13197
  ACCOUNT_OWNERSHIP_AUDIENCE,
13198
+ AGENT_ATTEST_DOMAIN,
13199
+ AGENT_PROVISION_INFO_DOMAIN,
12764
13200
  AccountHaRefusedError,
12765
13201
  AccountLinkedToSeveralUsersError,
12766
13202
  AccountNotLinkedError,
12767
13203
  AdminApiClient,
13204
+ AgentGateError,
12768
13205
  AuthApiClient,
12769
13206
  AuthRevokedError,
12770
13207
  CAPABILITIES,
@@ -12781,6 +13218,7 @@ export {
12781
13218
  INVITED_ROLE,
12782
13219
  IntentRefusedError,
12783
13220
  InvitationNotClaimableError,
13221
+ KMS_RELEASE_SIGNER,
12784
13222
  LocalStorageTokenStore,
12785
13223
  MAX_INVITATION_VALIDITY_SECS,
12786
13224
  MemoryTokenStore,
@@ -12819,8 +13257,11 @@ export {
12819
13257
  accountRootSignerFromPhrase,
12820
13258
  adminChangedOp,
12821
13259
  admitterAddrsFromNetworkStatus,
13260
+ agentKeyBinding,
13261
+ agentQuoteVerifier,
12822
13262
  applicationIdForBundle,
12823
13263
  attemptRelayNodeKey,
13264
+ attestAgent,
12824
13265
  attestKeyBinding,
12825
13266
  attestRelayNodeKey,
12826
13267
  authorNonceLookup,
@@ -12834,6 +13275,7 @@ export {
12834
13275
  capMask,
12835
13276
  capNames,
12836
13277
  carryExecutorAccount,
13278
+ checkOwner,
12837
13279
  classifyError,
12838
13280
  clearDelegatedCredential,
12839
13281
  clearDelegatedSession,
@@ -12901,6 +13343,7 @@ export {
12901
13343
  foundDelegatedNamespace,
12902
13344
  foundedNamespaceId,
12903
13345
  generateAccountRoot,
13346
+ generateOwnerKey,
12904
13347
  generateSessionKey,
12905
13348
  governGroup,
12906
13349
  governRoot,
@@ -12941,6 +13384,7 @@ export {
12941
13384
  normaliseAccount,
12942
13385
  ownerOpDigest,
12943
13386
  ownerOpSigningPayload,
13387
+ ownerPublicKey,
12944
13388
  parseAuthCallback,
12945
13389
  parseCreationWarrant,
12946
13390
  parseDeviceCredential,
@@ -12950,6 +13394,8 @@ export {
12950
13394
  pinRelayNodeKey,
12951
13395
  presenceStatementBytes,
12952
13396
  probeNodeHealth,
13397
+ provisionAgent,
13398
+ provisionInfo,
12953
13399
  readCloudLinkCallback,
12954
13400
  readDelegatedCredential,
12955
13401
  readDelegatedSession,
@@ -12959,6 +13405,7 @@ export {
12959
13405
  redeemInvitation,
12960
13406
  relayForContext,
12961
13407
  relayTransportFetch,
13408
+ releaseAgent,
12962
13409
  rememberGroupNamespace,
12963
13410
  rememberRelay,
12964
13411
  reportDataOf,
@@ -13005,7 +13452,9 @@ export {
13005
13452
  transportKeyBinding,
13006
13453
  trustSignedRelease,
13007
13454
  trustedMeasurementsFromReleases,
13455
+ validateAgentId,
13008
13456
  verifyDeviceCredential,
13457
+ verifySignedAgentPolicy,
13009
13458
  verifySignedNodeRelease,
13010
13459
  withCap,
13011
13460
  withRetry,