@calimero-network/mero-js 19.26.0 → 19.27.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
@@ -6467,92 +6467,6 @@ function createLocalStorageNonceSource(key, storage) {
6467
6467
  };
6468
6468
  }
6469
6469
 
6470
- // src/cloud/connect.ts
6471
- async function connectCloud(options) {
6472
- if (!options.sessionToken && !options.googleIdToken) {
6473
- throw new Error("connectCloud needs either a sessionToken or a googleIdToken");
6474
- }
6475
- const cloud = new CloudClient({
6476
- cloudBaseUrl: options.cloudBaseUrl,
6477
- sessionToken: options.sessionToken,
6478
- onSession: options.onSession,
6479
- fetch: options.fetch,
6480
- timeoutMs: options.timeoutMs
6481
- });
6482
- if (!options.sessionToken && options.googleIdToken) {
6483
- await cloud.signInWithGoogle(options.googleIdToken);
6484
- }
6485
- const namespaces = await cloud.getMyNamespaces();
6486
- const namespace = pickNamespace(namespaces, options.namespaceId);
6487
- const relays = await cloud.getNamespaceRelays(namespace.namespaceId);
6488
- const relayInfo = relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ?? null;
6489
- if (!relayInfo) {
6490
- throw new Error(explainNoRelay(namespace, relays));
6491
- }
6492
- const relay = new RelayClient({
6493
- // Checked by `findExecutingRelay`, which is the only thing that returns a
6494
- // relay — narrowed here rather than re-validated, so the invariant lives in
6495
- // one place.
6496
- relayUrl: relayInfo.relayUrl,
6497
- executorAccount: relayInfo.executorAccount,
6498
- authorAccount: options.authorAccount,
6499
- authorProof: options.authorProof,
6500
- deviceSecret: options.deviceSecret,
6501
- nonces: options.nonces ?? await defaultNonceSource(options.deviceSecret),
6502
- ttlSeconds: options.ttlSeconds,
6503
- fetch: options.fetch,
6504
- timeoutMs: options.timeoutMs
6505
- });
6506
- return {
6507
- cloud,
6508
- relay,
6509
- namespaceId: namespace.namespaceId,
6510
- namespace,
6511
- relayInfo,
6512
- execute: (contextId, method, argsJson) => relay.execute(contextId, method, argsJson)
6513
- };
6514
- }
6515
- function pickNamespace(namespaces, requested) {
6516
- if (requested) {
6517
- const found = namespaces.find((n) => n.namespaceId === requested);
6518
- if (!found) {
6519
- throw new Error(
6520
- `this account owns no namespace ${requested}; it owns: ${namespaces.map((n) => n.namespaceId).join(", ") || "(none)"}`
6521
- );
6522
- }
6523
- return found;
6524
- }
6525
- if (namespaces.length === 0) {
6526
- throw new Error(
6527
- "this account owns no namespaces in the cloud: claim one first, then enable HA on it so a relay is assigned"
6528
- );
6529
- }
6530
- if (namespaces.length > 1) {
6531
- throw new Error(
6532
- `this account owns ${namespaces.length} namespaces \u2014 pass namespaceId to say which: ${namespaces.map((n) => n.namespaceId).join(", ")}`
6533
- );
6534
- }
6535
- return namespaces[0];
6536
- }
6537
- function explainNoRelay(namespace, relays) {
6538
- if (relays.length === 0) {
6539
- return namespace.haStatus === "enabled" ? `namespace ${namespace.namespaceId} has HA enabled but no relay has been assigned to it yet \u2014 retry shortly` : `namespace ${namespace.namespaceId} has no relays: enable HA on it in the cloud to have an attested node assigned`;
6540
- }
6541
- const waitingOnGrant = relays.filter((r) => !r.authorshipReady);
6542
- if (waitingOnGrant.length === relays.length) {
6543
- return `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(", ") || "the relay account"} \u2014 with AdminClient.grantAuthorship(namespaceId, account) for these relays, and AdminClient.openToDelegatedExecution(namespaceId) so relays assigned later need no further op`;
6544
- }
6545
- return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none reported both a URL and an executor account yet \u2014 retry shortly`;
6546
- }
6547
- async function defaultNonceSource(deviceSecret) {
6548
- const key = `mero-js:warrant-nonce:${hex(await derivePublicKey(deviceSecret))}`;
6549
- try {
6550
- return createLocalStorageNonceSource(key);
6551
- } catch {
6552
- return createMemoryNonceSource(1);
6553
- }
6554
- }
6555
-
6556
6470
  // src/sealed/noise.ts
6557
6471
  var PROTOCOL_NAME = "Noise_NK_25519_AESGCM_SHA256";
6558
6472
  var DH_LEN = 32;
@@ -6772,6 +6686,33 @@ async function fetchAttestedTransportKey(admin, verify, options = {}) {
6772
6686
  }
6773
6687
  return transportKey;
6774
6688
  }
6689
+ function createAttestedSealedFetch(options) {
6690
+ const baseFetch = options.fetch ?? ((input, init) => fetch(input, init));
6691
+ const attestUrl = `${options.baseUrl.replace(/\/+$/, "")}/admin-api/tee/attest`;
6692
+ const admin = {
6693
+ async teeAttest(request) {
6694
+ const response = await baseFetch(attestUrl, {
6695
+ method: "POST",
6696
+ headers: { "content-type": "application/json" },
6697
+ body: JSON.stringify(request)
6698
+ });
6699
+ if (!response.ok) {
6700
+ throw new Error(`The node refused to attest: HTTP ${response.status}`);
6701
+ }
6702
+ const body = await response.json();
6703
+ if (!body.data) throw new Error("The attestation response is malformed");
6704
+ return body.data;
6705
+ }
6706
+ };
6707
+ return createSealedFetch({
6708
+ baseUrl: options.baseUrl,
6709
+ transportPublicKey: () => fetchAttestedTransportKey(admin, options.verify, {
6710
+ applicationId: options.applicationId,
6711
+ applicationHash: options.applicationHash
6712
+ }),
6713
+ fetch: baseFetch
6714
+ });
6715
+ }
6775
6716
  function createSealedFetch(options) {
6776
6717
  const base = new URL(options.baseUrl);
6777
6718
  const basePath = base.pathname.replace(/\/+$/, "");
@@ -6779,6 +6720,7 @@ function createSealedFetch(options) {
6779
6720
  const baseFetch = options.fetch ?? ((input, init) => fetch(input, init));
6780
6721
  const attest = typeof options.transportPublicKey === "function" ? options.transportPublicKey : void 0;
6781
6722
  let transportKey = attest ? Promise.resolve().then(attest) : Promise.resolve(options.transportPublicKey);
6723
+ transportKey.catch(() => void 0);
6782
6724
  let session;
6783
6725
  const openSession = async () => {
6784
6726
  try {
@@ -7029,6 +6971,98 @@ async function envelopeRefusal(response) {
7029
6971
  return new SealedTransportError(response.status, code, message, retryAfterMs);
7030
6972
  }
7031
6973
 
6974
+ // src/cloud/connect.ts
6975
+ async function connectCloud(options) {
6976
+ if (!options.sessionToken && !options.googleIdToken) {
6977
+ throw new Error("connectCloud needs either a sessionToken or a googleIdToken");
6978
+ }
6979
+ const cloud = new CloudClient({
6980
+ cloudBaseUrl: options.cloudBaseUrl,
6981
+ sessionToken: options.sessionToken,
6982
+ onSession: options.onSession,
6983
+ fetch: options.fetch,
6984
+ timeoutMs: options.timeoutMs
6985
+ });
6986
+ if (!options.sessionToken && options.googleIdToken) {
6987
+ await cloud.signInWithGoogle(options.googleIdToken);
6988
+ }
6989
+ const namespaces = await cloud.getMyNamespaces();
6990
+ const namespace = pickNamespace(namespaces, options.namespaceId);
6991
+ const relays = await cloud.getNamespaceRelays(namespace.namespaceId);
6992
+ const relayInfo = relays.find((r) => r.authorshipReady && r.relayUrl !== null && r.executorAccount !== null) ?? null;
6993
+ if (!relayInfo) {
6994
+ throw new Error(explainNoRelay(namespace, relays));
6995
+ }
6996
+ const relay = new RelayClient({
6997
+ // Checked by `findExecutingRelay`, which is the only thing that returns a
6998
+ // relay — narrowed here rather than re-validated, so the invariant lives in
6999
+ // one place.
7000
+ relayUrl: relayInfo.relayUrl,
7001
+ executorAccount: relayInfo.executorAccount,
7002
+ authorAccount: options.authorAccount,
7003
+ authorProof: options.authorProof,
7004
+ deviceSecret: options.deviceSecret,
7005
+ nonces: options.nonces ?? await defaultNonceSource(options.deviceSecret),
7006
+ ttlSeconds: options.ttlSeconds,
7007
+ // Only the relay is sealed: a sealed fetch is bound to one node and refuses
7008
+ // any other URL, and the cloud calls above carry no intent.
7009
+ fetch: options.seal ? createAttestedSealedFetch({
7010
+ baseUrl: relayInfo.relayUrl,
7011
+ verify: options.seal,
7012
+ fetch: options.fetch
7013
+ }) : options.fetch,
7014
+ timeoutMs: options.timeoutMs
7015
+ });
7016
+ return {
7017
+ cloud,
7018
+ relay,
7019
+ namespaceId: namespace.namespaceId,
7020
+ namespace,
7021
+ relayInfo,
7022
+ execute: (contextId, method, argsJson) => relay.execute(contextId, method, argsJson)
7023
+ };
7024
+ }
7025
+ function pickNamespace(namespaces, requested) {
7026
+ if (requested) {
7027
+ const found = namespaces.find((n) => n.namespaceId === requested);
7028
+ if (!found) {
7029
+ throw new Error(
7030
+ `this account owns no namespace ${requested}; it owns: ${namespaces.map((n) => n.namespaceId).join(", ") || "(none)"}`
7031
+ );
7032
+ }
7033
+ return found;
7034
+ }
7035
+ if (namespaces.length === 0) {
7036
+ throw new Error(
7037
+ "this account owns no namespaces in the cloud: claim one first, then enable HA on it so a relay is assigned"
7038
+ );
7039
+ }
7040
+ if (namespaces.length > 1) {
7041
+ throw new Error(
7042
+ `this account owns ${namespaces.length} namespaces \u2014 pass namespaceId to say which: ${namespaces.map((n) => n.namespaceId).join(", ")}`
7043
+ );
7044
+ }
7045
+ return namespaces[0];
7046
+ }
7047
+ function explainNoRelay(namespace, relays) {
7048
+ if (relays.length === 0) {
7049
+ return namespace.haStatus === "enabled" ? `namespace ${namespace.namespaceId} has HA enabled but no relay has been assigned to it yet \u2014 retry shortly` : `namespace ${namespace.namespaceId} has no relays: enable HA on it in the cloud to have an attested node assigned`;
7050
+ }
7051
+ const waitingOnGrant = relays.filter((r) => !r.authorshipReady);
7052
+ if (waitingOnGrant.length === relays.length) {
7053
+ return `every relay on namespace ${namespace.namespaceId} is waiting for the authorship grant: an admin of the namespace must grant CAN_AUTHOR_ON_BEHALF to ${waitingOnGrant.map((r) => r.executorAccount ?? r.peerId).join(", ") || "the relay account"} \u2014 with AdminClient.grantAuthorship(namespaceId, account) for these relays, and AdminClient.openToDelegatedExecution(namespaceId) so relays assigned later need no further op`;
7054
+ }
7055
+ return `namespace ${namespace.namespaceId} has ${relays.length} relay(s), but none reported both a URL and an executor account yet \u2014 retry shortly`;
7056
+ }
7057
+ async function defaultNonceSource(deviceSecret) {
7058
+ const key = `mero-js:warrant-nonce:${hex(await derivePublicKey(deviceSecret))}`;
7059
+ try {
7060
+ return createLocalStorageNonceSource(key);
7061
+ } catch {
7062
+ return createMemoryNonceSource(1);
7063
+ }
7064
+ }
7065
+
7032
7066
  // src/sealed/verify.ts
7033
7067
  var MEASUREMENT_HEX = /^[0-9a-f]{96}$/;
7034
7068
  function createQuoteVerifier(options) {
@@ -7468,6 +7502,7 @@ export {
7468
7502
  connectCloud,
7469
7503
  createAdminApiClient,
7470
7504
  createAdminApiClientFromHttpClient,
7505
+ createAttestedSealedFetch,
7471
7506
  createAuthApiClient,
7472
7507
  createAuthApiClientFromHttpClient,
7473
7508
  createBrowserAdminApiClient,