@calimero-network/mero-js 19.16.0 → 19.17.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
@@ -1913,6 +1913,196 @@ function buildAuthLoginUrl(nodeUrl, opts) {
1913
1913
  return `${base}/auth/login?${params.toString()}`;
1914
1914
  }
1915
1915
 
1916
+ // src/crypto/internal.ts
1917
+ var PKCS8_ED25519_PREFIX = new Uint8Array([
1918
+ 48,
1919
+ 46,
1920
+ 2,
1921
+ 1,
1922
+ 0,
1923
+ 48,
1924
+ 5,
1925
+ 6,
1926
+ 3,
1927
+ 43,
1928
+ 101,
1929
+ 112,
1930
+ 4,
1931
+ 34,
1932
+ 4,
1933
+ 32
1934
+ ]);
1935
+ function u32le(value) {
1936
+ const out = new Uint8Array(4);
1937
+ new DataView(out.buffer).setUint32(0, value, true);
1938
+ return out;
1939
+ }
1940
+ function hex(bytes) {
1941
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
1942
+ }
1943
+ function fromHex(value, label, expectedBytes) {
1944
+ const clean = value.trim();
1945
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
1946
+ throw new Error(
1947
+ `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
1948
+ );
1949
+ }
1950
+ const bytes = new Uint8Array(expectedBytes);
1951
+ for (let i = 0; i < expectedBytes; i += 1) {
1952
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
1953
+ }
1954
+ return bytes;
1955
+ }
1956
+ function fromHexUnsized(value, label) {
1957
+ const clean = value.trim();
1958
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
1959
+ throw new Error(`${label} must be an even number of hex characters`);
1960
+ }
1961
+ const bytes = new Uint8Array(clean.length / 2);
1962
+ for (let i = 0; i < bytes.length; i += 1) {
1963
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
1964
+ }
1965
+ return bytes;
1966
+ }
1967
+ function u64le(value) {
1968
+ const out = new Uint8Array(8);
1969
+ new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
1970
+ return out;
1971
+ }
1972
+ function concat(...parts) {
1973
+ const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
1974
+ let offset = 0;
1975
+ for (const part of parts) {
1976
+ out.set(part, offset);
1977
+ offset += part.length;
1978
+ }
1979
+ return out;
1980
+ }
1981
+ async function domainHash(domain, parts) {
1982
+ const chunks = [u64le(domain.length), domain];
1983
+ for (const part of parts) {
1984
+ chunks.push(u64le(part.length), part);
1985
+ }
1986
+ return new Uint8Array(
1987
+ await crypto.subtle.digest("SHA-256", concat(...chunks))
1988
+ );
1989
+ }
1990
+ async function importSigningKey(secretHex) {
1991
+ const seed = fromHex(secretHex, "deviceSecret", 32);
1992
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
1993
+ try {
1994
+ return await crypto.subtle.importKey(
1995
+ "pkcs8",
1996
+ pkcs8,
1997
+ { name: "Ed25519" },
1998
+ false,
1999
+ ["sign"]
2000
+ );
2001
+ } catch (cause) {
2002
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
2003
+ throw new Error(
2004
+ "this runtime has no WebCrypto Ed25519, so a warrant cannot be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; otherwise mint the warrant with `merod account warrant`" + detail
2005
+ );
2006
+ }
2007
+ }
2008
+ async function derivePublicKey(secretHex) {
2009
+ const seed = fromHex(secretHex, "deviceSecret", 32);
2010
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2011
+ const key = await crypto.subtle.importKey(
2012
+ "pkcs8",
2013
+ pkcs8,
2014
+ { name: "Ed25519" },
2015
+ true,
2016
+ ["sign"]
2017
+ );
2018
+ const jwk = await crypto.subtle.exportKey("jwk", key);
2019
+ const raw = jwk.x;
2020
+ return Uint8Array.from(
2021
+ atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2022
+ (c) => c.charCodeAt(0)
2023
+ );
2024
+ }
2025
+
2026
+ // src/request/request-sig.ts
2027
+ var SIGN_DOMAIN = new TextEncoder().encode("calimero.auth.request.v1");
2028
+ var BODY_DOMAIN = new TextEncoder().encode("calimero.auth.request.body.v1");
2029
+ function borshString(value) {
2030
+ const bytes = new TextEncoder().encode(value);
2031
+ return concat(u32le(bytes.length), bytes);
2032
+ }
2033
+ async function requestBodyHash(body = new Uint8Array(0)) {
2034
+ const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body;
2035
+ return domainHash(BODY_DOMAIN, [bytes]);
2036
+ }
2037
+ async function signRequest(input) {
2038
+ const key = await importSigningKey(input.signerSecret);
2039
+ const bodyHash = await requestBodyHash(input.body);
2040
+ const issuedAt = u64le(input.issuedAt);
2041
+ const expiresAt = u64le(input.expiresAt);
2042
+ const encoder = new TextEncoder();
2043
+ const preimage = await domainHash(SIGN_DOMAIN, [
2044
+ encoder.encode(input.method),
2045
+ encoder.encode(input.path),
2046
+ bodyHash,
2047
+ issuedAt,
2048
+ expiresAt
2049
+ ]);
2050
+ const signature = new Uint8Array(
2051
+ await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
2052
+ );
2053
+ return hex(
2054
+ concat(
2055
+ borshString(input.method),
2056
+ borshString(input.path),
2057
+ bodyHash,
2058
+ issuedAt,
2059
+ expiresAt,
2060
+ signature
2061
+ )
2062
+ );
2063
+ }
2064
+
2065
+ // src/request/caller-proof.ts
2066
+ function callerProof(input) {
2067
+ const credential = fromHexUnsized(input.credential, "credential");
2068
+ const request = fromHexUnsized(input.request, "request signature");
2069
+ const session = input.session === void 0 ? new Uint8Array([0]) : concat(new Uint8Array([1]), fromHexUnsized(input.session, "session statement"));
2070
+ return hex(concat(credential, session, request));
2071
+ }
2072
+
2073
+ // src/request/proof-signer.ts
2074
+ function bodyBytes(body) {
2075
+ if (body === void 0 || body === null) return new Uint8Array(0);
2076
+ if (typeof body === "string") return body;
2077
+ if (body instanceof Uint8Array) return body;
2078
+ if (body instanceof ArrayBuffer) return new Uint8Array(body);
2079
+ if (ArrayBuffer.isView(body)) {
2080
+ return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
2081
+ }
2082
+ throw new Error(
2083
+ `a request-carried proof cannot commit to a ${body?.constructor?.name ?? typeof body} body: pass a string or bytes, or use a session for this call`
2084
+ );
2085
+ }
2086
+ function createProofSigner(options) {
2087
+ const ttl = options.ttlSeconds ?? 120;
2088
+ const clock = options.now ?? (() => Math.floor(Date.now() / 1e3));
2089
+ return async (request) => {
2090
+ const issuedAt = clock();
2091
+ return callerProof({
2092
+ credential: options.credential,
2093
+ session: options.session,
2094
+ request: await signRequest({
2095
+ method: request.method,
2096
+ path: request.path,
2097
+ body: bodyBytes(request.body),
2098
+ issuedAt,
2099
+ expiresAt: issuedAt + ttl,
2100
+ signerSecret: options.signerSecret
2101
+ })
2102
+ });
2103
+ };
2104
+ }
2105
+
1916
2106
  // src/rpc/index.ts
1917
2107
  var RpcError = class extends Error {
1918
2108
  constructor(code, message, data, type) {
@@ -2552,116 +2742,6 @@ var EphemeralClient = class {
2552
2742
  }
2553
2743
  };
2554
2744
 
2555
- // src/crypto/internal.ts
2556
- var PKCS8_ED25519_PREFIX = new Uint8Array([
2557
- 48,
2558
- 46,
2559
- 2,
2560
- 1,
2561
- 0,
2562
- 48,
2563
- 5,
2564
- 6,
2565
- 3,
2566
- 43,
2567
- 101,
2568
- 112,
2569
- 4,
2570
- 34,
2571
- 4,
2572
- 32
2573
- ]);
2574
- function u32le(value) {
2575
- const out = new Uint8Array(4);
2576
- new DataView(out.buffer).setUint32(0, value, true);
2577
- return out;
2578
- }
2579
- function hex(bytes) {
2580
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2581
- }
2582
- function fromHex(value, label, expectedBytes) {
2583
- const clean = value.trim();
2584
- if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
2585
- throw new Error(
2586
- `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
2587
- );
2588
- }
2589
- const bytes = new Uint8Array(expectedBytes);
2590
- for (let i = 0; i < expectedBytes; i += 1) {
2591
- bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2592
- }
2593
- return bytes;
2594
- }
2595
- function fromHexUnsized(value, label) {
2596
- const clean = value.trim();
2597
- if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
2598
- throw new Error(`${label} must be an even number of hex characters`);
2599
- }
2600
- const bytes = new Uint8Array(clean.length / 2);
2601
- for (let i = 0; i < bytes.length; i += 1) {
2602
- bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2603
- }
2604
- return bytes;
2605
- }
2606
- function u64le(value) {
2607
- const out = new Uint8Array(8);
2608
- new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
2609
- return out;
2610
- }
2611
- function concat(...parts) {
2612
- const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
2613
- let offset = 0;
2614
- for (const part of parts) {
2615
- out.set(part, offset);
2616
- offset += part.length;
2617
- }
2618
- return out;
2619
- }
2620
- async function domainHash(domain, parts) {
2621
- const chunks = [u64le(domain.length), domain];
2622
- for (const part of parts) {
2623
- chunks.push(u64le(part.length), part);
2624
- }
2625
- return new Uint8Array(
2626
- await crypto.subtle.digest("SHA-256", concat(...chunks))
2627
- );
2628
- }
2629
- async function importSigningKey(secretHex) {
2630
- const seed = fromHex(secretHex, "deviceSecret", 32);
2631
- const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2632
- try {
2633
- return await crypto.subtle.importKey(
2634
- "pkcs8",
2635
- pkcs8,
2636
- { name: "Ed25519" },
2637
- false,
2638
- ["sign"]
2639
- );
2640
- } catch (cause) {
2641
- const detail = cause instanceof Error ? `: ${cause.message}` : "";
2642
- throw new Error(
2643
- "this runtime has no WebCrypto Ed25519, so a warrant cannot be signed here. Node 18.4+, Safari 17+, Firefox 129+ and Chrome 137+ have it; otherwise mint the warrant with `merod account warrant`" + detail
2644
- );
2645
- }
2646
- }
2647
- async function derivePublicKey(secretHex) {
2648
- const seed = fromHex(secretHex, "deviceSecret", 32);
2649
- const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2650
- const key = await crypto.subtle.importKey(
2651
- "pkcs8",
2652
- pkcs8,
2653
- { name: "Ed25519" },
2654
- true,
2655
- ["sign"]
2656
- );
2657
- const jwk = await crypto.subtle.exportKey("jwk", key);
2658
- const raw = jwk.x;
2659
- return Uint8Array.from(
2660
- atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2661
- (c) => c.charCodeAt(0)
2662
- );
2663
- }
2664
-
2665
2745
  // src/device-cert/device-cert.ts
2666
2746
  var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
2667
2747
  var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
@@ -5659,6 +5739,10 @@ var CloudClient = class {
5659
5739
  };
5660
5740
 
5661
5741
  // src/mero-js.ts
5742
+ function resolveProofSigner(config) {
5743
+ if (!config) return void 0;
5744
+ return typeof config === "function" ? config : createProofSigner(config);
5745
+ }
5662
5746
  var REFRESH_LOCK_NAME = "mero-js:token-refresh";
5663
5747
  function getLockManager() {
5664
5748
  const nav = globalThis.navigator;
@@ -5697,8 +5781,10 @@ var MeroJs = class {
5697
5781
  this.tokenData = this.tokenStore.getTokens();
5698
5782
  }
5699
5783
  const isTauri = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
5784
+ const getProof = resolveProofSigner(this.config.requestProof);
5700
5785
  this.httpClient = createBrowserHttpClient({
5701
5786
  baseUrl: this.config.baseUrl,
5787
+ getProof,
5702
5788
  getAuthToken: async () => {
5703
5789
  const token = await this.getValidToken();
5704
5790
  return token?.access_token || "";
@@ -6052,7 +6138,7 @@ var LocalStorageTokenStore = class {
6052
6138
  };
6053
6139
 
6054
6140
  // src/warrant/warrant.ts
6055
- var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v2");
6141
+ var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.warrant.v2");
6056
6142
  var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
6057
6143
  var MAX_CITED_HEADS = 64;
6058
6144
  var UNPINNED_APP = "00".repeat(32);
@@ -6077,7 +6163,7 @@ async function signWarrant(input) {
6077
6163
  const commitment = await intentHash(input.method, input.argsJson);
6078
6164
  const nonce = u64le(input.nonce);
6079
6165
  const notAfter = u64le(input.notAfter);
6080
- const preimage = await domainHash(SIGN_DOMAIN, [
6166
+ const preimage = await domainHash(SIGN_DOMAIN2, [
6081
6167
  context,
6082
6168
  authorAccount,
6083
6169
  publicKey,
@@ -6396,7 +6482,7 @@ function optionalBytes32(value, label) {
6396
6482
  }
6397
6483
  return concat(new Uint8Array([1]), new Uint8Array(value));
6398
6484
  }
6399
- function borshString(value) {
6485
+ function borshString2(value) {
6400
6486
  const bytes = new TextEncoder().encode(value);
6401
6487
  return concat(u32le(bytes.length), bytes);
6402
6488
  }
@@ -6420,7 +6506,7 @@ function encodeSignedInvitation(signed) {
6420
6506
  // ...then the enclosing SignedGroupOpenInvitation, in declaration order.
6421
6507
  // `inviter_account` sits between the signature and the addresses; putting it
6422
6508
  // anywhere else still encodes 32 bytes and still verifies as nothing.
6423
- borshString(signed.inviter_signature),
6509
+ borshString2(signed.inviter_signature),
6424
6510
  signed.inviter_account ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, "inviter_account", 32)) : new Uint8Array([0]),
6425
6511
  // A `Vec<String>`, so each entry is a bare borsh string. This carried an
6426
6512
  // enum until core dropped the URL variant, and an enum writes a
@@ -6428,7 +6514,7 @@ function encodeSignedInvitation(signed) {
6428
6514
  // every following byte and fail as `invalid invitation signature`, pointing
6429
6515
  // nowhere near this line.
6430
6516
  u32le(admitterAddrs.length),
6431
- ...admitterAddrs.map(borshString),
6517
+ ...admitterAddrs.map(borshString2),
6432
6518
  optionalBytes32(signed.application_id, "application_id"),
6433
6519
  // Borsh order follows core's field order, where this is `bytecode_id`; the
6434
6520
  // JSON key is `app_key`, a rename covering both directions that core pins in
@@ -6473,86 +6559,6 @@ async function signMemberJoinOp(input) {
6473
6559
  return hex(concat(signable, signature, unendorsed));
6474
6560
  }
6475
6561
 
6476
- // src/request/request-sig.ts
6477
- var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.auth.request.v1");
6478
- var BODY_DOMAIN = new TextEncoder().encode("calimero.auth.request.body.v1");
6479
- function borshString2(value) {
6480
- const bytes = new TextEncoder().encode(value);
6481
- return concat(u32le(bytes.length), bytes);
6482
- }
6483
- async function requestBodyHash(body = new Uint8Array(0)) {
6484
- const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body;
6485
- return domainHash(BODY_DOMAIN, [bytes]);
6486
- }
6487
- async function signRequest(input) {
6488
- const key = await importSigningKey(input.signerSecret);
6489
- const bodyHash = await requestBodyHash(input.body);
6490
- const issuedAt = u64le(input.issuedAt);
6491
- const expiresAt = u64le(input.expiresAt);
6492
- const encoder = new TextEncoder();
6493
- const preimage = await domainHash(SIGN_DOMAIN2, [
6494
- encoder.encode(input.method),
6495
- encoder.encode(input.path),
6496
- bodyHash,
6497
- issuedAt,
6498
- expiresAt
6499
- ]);
6500
- const signature = new Uint8Array(
6501
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6502
- );
6503
- return hex(
6504
- concat(
6505
- borshString2(input.method),
6506
- borshString2(input.path),
6507
- bodyHash,
6508
- issuedAt,
6509
- expiresAt,
6510
- signature
6511
- )
6512
- );
6513
- }
6514
-
6515
- // src/request/caller-proof.ts
6516
- function callerProof(input) {
6517
- const credential = fromHexUnsized(input.credential, "credential");
6518
- const request = fromHexUnsized(input.request, "request signature");
6519
- const session = input.session === void 0 ? new Uint8Array([0]) : concat(new Uint8Array([1]), fromHexUnsized(input.session, "session statement"));
6520
- return hex(concat(credential, session, request));
6521
- }
6522
-
6523
- // src/request/proof-signer.ts
6524
- function bodyBytes(body) {
6525
- if (body === void 0 || body === null) return new Uint8Array(0);
6526
- if (typeof body === "string") return body;
6527
- if (body instanceof Uint8Array) return body;
6528
- if (body instanceof ArrayBuffer) return new Uint8Array(body);
6529
- if (ArrayBuffer.isView(body)) {
6530
- return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
6531
- }
6532
- throw new Error(
6533
- `a request-carried proof cannot commit to a ${body?.constructor?.name ?? typeof body} body: pass a string or bytes, or use a session for this call`
6534
- );
6535
- }
6536
- function createProofSigner(options) {
6537
- const ttl = options.ttlSeconds ?? 120;
6538
- const clock = options.now ?? (() => Math.floor(Date.now() / 1e3));
6539
- return async (request) => {
6540
- const issuedAt = clock();
6541
- return callerProof({
6542
- credential: options.credential,
6543
- session: options.session,
6544
- request: await signRequest({
6545
- method: request.method,
6546
- path: request.path,
6547
- body: bodyBytes(request.body),
6548
- issuedAt,
6549
- expiresAt: issuedAt + ttl,
6550
- signerSecret: options.signerSecret
6551
- })
6552
- });
6553
- };
6554
- }
6555
-
6556
6562
  // src/login/login.ts
6557
6563
  var SIGN_DOMAIN3 = new TextEncoder().encode("calimero.auth.login.v1");
6558
6564
  var AUDIENCE_TAG = {