@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.cjs CHANGED
@@ -2010,6 +2010,196 @@ function buildAuthLoginUrl(nodeUrl, opts) {
2010
2010
  return `${base}/auth/login?${params.toString()}`;
2011
2011
  }
2012
2012
 
2013
+ // src/crypto/internal.ts
2014
+ var PKCS8_ED25519_PREFIX = new Uint8Array([
2015
+ 48,
2016
+ 46,
2017
+ 2,
2018
+ 1,
2019
+ 0,
2020
+ 48,
2021
+ 5,
2022
+ 6,
2023
+ 3,
2024
+ 43,
2025
+ 101,
2026
+ 112,
2027
+ 4,
2028
+ 34,
2029
+ 4,
2030
+ 32
2031
+ ]);
2032
+ function u32le(value) {
2033
+ const out = new Uint8Array(4);
2034
+ new DataView(out.buffer).setUint32(0, value, true);
2035
+ return out;
2036
+ }
2037
+ function hex(bytes) {
2038
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2039
+ }
2040
+ function fromHex(value, label, expectedBytes) {
2041
+ const clean = value.trim();
2042
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
2043
+ throw new Error(
2044
+ `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
2045
+ );
2046
+ }
2047
+ const bytes = new Uint8Array(expectedBytes);
2048
+ for (let i = 0; i < expectedBytes; i += 1) {
2049
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2050
+ }
2051
+ return bytes;
2052
+ }
2053
+ function fromHexUnsized(value, label) {
2054
+ const clean = value.trim();
2055
+ if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
2056
+ throw new Error(`${label} must be an even number of hex characters`);
2057
+ }
2058
+ const bytes = new Uint8Array(clean.length / 2);
2059
+ for (let i = 0; i < bytes.length; i += 1) {
2060
+ bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2061
+ }
2062
+ return bytes;
2063
+ }
2064
+ function u64le(value) {
2065
+ const out = new Uint8Array(8);
2066
+ new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
2067
+ return out;
2068
+ }
2069
+ function concat(...parts) {
2070
+ const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
2071
+ let offset = 0;
2072
+ for (const part of parts) {
2073
+ out.set(part, offset);
2074
+ offset += part.length;
2075
+ }
2076
+ return out;
2077
+ }
2078
+ async function domainHash(domain, parts) {
2079
+ const chunks = [u64le(domain.length), domain];
2080
+ for (const part of parts) {
2081
+ chunks.push(u64le(part.length), part);
2082
+ }
2083
+ return new Uint8Array(
2084
+ await crypto.subtle.digest("SHA-256", concat(...chunks))
2085
+ );
2086
+ }
2087
+ async function importSigningKey(secretHex) {
2088
+ const seed = fromHex(secretHex, "deviceSecret", 32);
2089
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2090
+ try {
2091
+ return await crypto.subtle.importKey(
2092
+ "pkcs8",
2093
+ pkcs8,
2094
+ { name: "Ed25519" },
2095
+ false,
2096
+ ["sign"]
2097
+ );
2098
+ } catch (cause) {
2099
+ const detail = cause instanceof Error ? `: ${cause.message}` : "";
2100
+ throw new Error(
2101
+ "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
2102
+ );
2103
+ }
2104
+ }
2105
+ async function derivePublicKey(secretHex) {
2106
+ const seed = fromHex(secretHex, "deviceSecret", 32);
2107
+ const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2108
+ const key = await crypto.subtle.importKey(
2109
+ "pkcs8",
2110
+ pkcs8,
2111
+ { name: "Ed25519" },
2112
+ true,
2113
+ ["sign"]
2114
+ );
2115
+ const jwk = await crypto.subtle.exportKey("jwk", key);
2116
+ const raw = jwk.x;
2117
+ return Uint8Array.from(
2118
+ atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2119
+ (c) => c.charCodeAt(0)
2120
+ );
2121
+ }
2122
+
2123
+ // src/request/request-sig.ts
2124
+ var SIGN_DOMAIN = new TextEncoder().encode("calimero.auth.request.v1");
2125
+ var BODY_DOMAIN = new TextEncoder().encode("calimero.auth.request.body.v1");
2126
+ function borshString(value) {
2127
+ const bytes = new TextEncoder().encode(value);
2128
+ return concat(u32le(bytes.length), bytes);
2129
+ }
2130
+ async function requestBodyHash(body = new Uint8Array(0)) {
2131
+ const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body;
2132
+ return domainHash(BODY_DOMAIN, [bytes]);
2133
+ }
2134
+ async function signRequest(input) {
2135
+ const key = await importSigningKey(input.signerSecret);
2136
+ const bodyHash = await requestBodyHash(input.body);
2137
+ const issuedAt = u64le(input.issuedAt);
2138
+ const expiresAt = u64le(input.expiresAt);
2139
+ const encoder = new TextEncoder();
2140
+ const preimage = await domainHash(SIGN_DOMAIN, [
2141
+ encoder.encode(input.method),
2142
+ encoder.encode(input.path),
2143
+ bodyHash,
2144
+ issuedAt,
2145
+ expiresAt
2146
+ ]);
2147
+ const signature = new Uint8Array(
2148
+ await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
2149
+ );
2150
+ return hex(
2151
+ concat(
2152
+ borshString(input.method),
2153
+ borshString(input.path),
2154
+ bodyHash,
2155
+ issuedAt,
2156
+ expiresAt,
2157
+ signature
2158
+ )
2159
+ );
2160
+ }
2161
+
2162
+ // src/request/caller-proof.ts
2163
+ function callerProof(input) {
2164
+ const credential = fromHexUnsized(input.credential, "credential");
2165
+ const request = fromHexUnsized(input.request, "request signature");
2166
+ const session = input.session === void 0 ? new Uint8Array([0]) : concat(new Uint8Array([1]), fromHexUnsized(input.session, "session statement"));
2167
+ return hex(concat(credential, session, request));
2168
+ }
2169
+
2170
+ // src/request/proof-signer.ts
2171
+ function bodyBytes(body) {
2172
+ if (body === void 0 || body === null) return new Uint8Array(0);
2173
+ if (typeof body === "string") return body;
2174
+ if (body instanceof Uint8Array) return body;
2175
+ if (body instanceof ArrayBuffer) return new Uint8Array(body);
2176
+ if (ArrayBuffer.isView(body)) {
2177
+ return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
2178
+ }
2179
+ throw new Error(
2180
+ `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`
2181
+ );
2182
+ }
2183
+ function createProofSigner(options) {
2184
+ const ttl = options.ttlSeconds ?? 120;
2185
+ const clock = options.now ?? (() => Math.floor(Date.now() / 1e3));
2186
+ return async (request) => {
2187
+ const issuedAt = clock();
2188
+ return callerProof({
2189
+ credential: options.credential,
2190
+ session: options.session,
2191
+ request: await signRequest({
2192
+ method: request.method,
2193
+ path: request.path,
2194
+ body: bodyBytes(request.body),
2195
+ issuedAt,
2196
+ expiresAt: issuedAt + ttl,
2197
+ signerSecret: options.signerSecret
2198
+ })
2199
+ });
2200
+ };
2201
+ }
2202
+
2013
2203
  // src/rpc/index.ts
2014
2204
  var RpcError = class extends Error {
2015
2205
  constructor(code, message, data, type) {
@@ -2649,116 +2839,6 @@ var EphemeralClient = class {
2649
2839
  }
2650
2840
  };
2651
2841
 
2652
- // src/crypto/internal.ts
2653
- var PKCS8_ED25519_PREFIX = new Uint8Array([
2654
- 48,
2655
- 46,
2656
- 2,
2657
- 1,
2658
- 0,
2659
- 48,
2660
- 5,
2661
- 6,
2662
- 3,
2663
- 43,
2664
- 101,
2665
- 112,
2666
- 4,
2667
- 34,
2668
- 4,
2669
- 32
2670
- ]);
2671
- function u32le(value) {
2672
- const out = new Uint8Array(4);
2673
- new DataView(out.buffer).setUint32(0, value, true);
2674
- return out;
2675
- }
2676
- function hex(bytes) {
2677
- return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2678
- }
2679
- function fromHex(value, label, expectedBytes) {
2680
- const clean = value.trim();
2681
- if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length !== expectedBytes * 2) {
2682
- throw new Error(
2683
- `${label} must be ${expectedBytes * 2} hex characters, got ${clean.length}`
2684
- );
2685
- }
2686
- const bytes = new Uint8Array(expectedBytes);
2687
- for (let i = 0; i < expectedBytes; i += 1) {
2688
- bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2689
- }
2690
- return bytes;
2691
- }
2692
- function fromHexUnsized(value, label) {
2693
- const clean = value.trim();
2694
- if (!/^[0-9a-fA-F]*$/.test(clean) || clean.length % 2 !== 0) {
2695
- throw new Error(`${label} must be an even number of hex characters`);
2696
- }
2697
- const bytes = new Uint8Array(clean.length / 2);
2698
- for (let i = 0; i < bytes.length; i += 1) {
2699
- bytes[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
2700
- }
2701
- return bytes;
2702
- }
2703
- function u64le(value) {
2704
- const out = new Uint8Array(8);
2705
- new DataView(out.buffer).setBigUint64(0, BigInt(value), true);
2706
- return out;
2707
- }
2708
- function concat(...parts) {
2709
- const out = new Uint8Array(parts.reduce((total, p) => total + p.length, 0));
2710
- let offset = 0;
2711
- for (const part of parts) {
2712
- out.set(part, offset);
2713
- offset += part.length;
2714
- }
2715
- return out;
2716
- }
2717
- async function domainHash(domain, parts) {
2718
- const chunks = [u64le(domain.length), domain];
2719
- for (const part of parts) {
2720
- chunks.push(u64le(part.length), part);
2721
- }
2722
- return new Uint8Array(
2723
- await crypto.subtle.digest("SHA-256", concat(...chunks))
2724
- );
2725
- }
2726
- async function importSigningKey(secretHex) {
2727
- const seed = fromHex(secretHex, "deviceSecret", 32);
2728
- const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2729
- try {
2730
- return await crypto.subtle.importKey(
2731
- "pkcs8",
2732
- pkcs8,
2733
- { name: "Ed25519" },
2734
- false,
2735
- ["sign"]
2736
- );
2737
- } catch (cause) {
2738
- const detail = cause instanceof Error ? `: ${cause.message}` : "";
2739
- throw new Error(
2740
- "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
2741
- );
2742
- }
2743
- }
2744
- async function derivePublicKey(secretHex) {
2745
- const seed = fromHex(secretHex, "deviceSecret", 32);
2746
- const pkcs8 = concat(PKCS8_ED25519_PREFIX, seed);
2747
- const key = await crypto.subtle.importKey(
2748
- "pkcs8",
2749
- pkcs8,
2750
- { name: "Ed25519" },
2751
- true,
2752
- ["sign"]
2753
- );
2754
- const jwk = await crypto.subtle.exportKey("jwk", key);
2755
- const raw = jwk.x;
2756
- return Uint8Array.from(
2757
- atob(raw.replace(/-/g, "+").replace(/_/g, "/")),
2758
- (c) => c.charCodeAt(0)
2759
- );
2760
- }
2761
-
2762
2842
  // src/device-cert/device-cert.ts
2763
2843
  var CERT_DOMAIN = new TextEncoder().encode("calimero.device.cert.v1");
2764
2844
  var ACCOUNT_ID_DOMAIN = new TextEncoder().encode("calimero.account.genesis.v1");
@@ -5756,6 +5836,10 @@ var CloudClient = class {
5756
5836
  };
5757
5837
 
5758
5838
  // src/mero-js.ts
5839
+ function resolveProofSigner(config) {
5840
+ if (!config) return void 0;
5841
+ return typeof config === "function" ? config : createProofSigner(config);
5842
+ }
5759
5843
  var REFRESH_LOCK_NAME = "mero-js:token-refresh";
5760
5844
  function getLockManager() {
5761
5845
  const nav = globalThis.navigator;
@@ -5794,8 +5878,10 @@ var MeroJs = class {
5794
5878
  this.tokenData = this.tokenStore.getTokens();
5795
5879
  }
5796
5880
  const isTauri = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
5881
+ const getProof = resolveProofSigner(this.config.requestProof);
5797
5882
  this.httpClient = createBrowserHttpClient({
5798
5883
  baseUrl: this.config.baseUrl,
5884
+ getProof,
5799
5885
  getAuthToken: async () => {
5800
5886
  const token = await this.getValidToken();
5801
5887
  return token?.access_token || "";
@@ -6149,7 +6235,7 @@ var LocalStorageTokenStore = class {
6149
6235
  };
6150
6236
 
6151
6237
  // src/warrant/warrant.ts
6152
- var SIGN_DOMAIN = new TextEncoder().encode("calimero.warrant.v2");
6238
+ var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.warrant.v2");
6153
6239
  var INTENT_DOMAIN = new TextEncoder().encode("calimero.warrant.intent.v1");
6154
6240
  var MAX_CITED_HEADS = 64;
6155
6241
  var UNPINNED_APP = "00".repeat(32);
@@ -6174,7 +6260,7 @@ async function signWarrant(input) {
6174
6260
  const commitment = await intentHash(input.method, input.argsJson);
6175
6261
  const nonce = u64le(input.nonce);
6176
6262
  const notAfter = u64le(input.notAfter);
6177
- const preimage = await domainHash(SIGN_DOMAIN, [
6263
+ const preimage = await domainHash(SIGN_DOMAIN2, [
6178
6264
  context,
6179
6265
  authorAccount,
6180
6266
  publicKey,
@@ -6493,7 +6579,7 @@ function optionalBytes32(value, label) {
6493
6579
  }
6494
6580
  return concat(new Uint8Array([1]), new Uint8Array(value));
6495
6581
  }
6496
- function borshString(value) {
6582
+ function borshString2(value) {
6497
6583
  const bytes = new TextEncoder().encode(value);
6498
6584
  return concat(u32le(bytes.length), bytes);
6499
6585
  }
@@ -6517,7 +6603,7 @@ function encodeSignedInvitation(signed) {
6517
6603
  // ...then the enclosing SignedGroupOpenInvitation, in declaration order.
6518
6604
  // `inviter_account` sits between the signature and the addresses; putting it
6519
6605
  // anywhere else still encodes 32 bytes and still verifies as nothing.
6520
- borshString(signed.inviter_signature),
6606
+ borshString2(signed.inviter_signature),
6521
6607
  signed.inviter_account ? concat(new Uint8Array([1]), fromHex(signed.inviter_account, "inviter_account", 32)) : new Uint8Array([0]),
6522
6608
  // A `Vec<String>`, so each entry is a bare borsh string. This carried an
6523
6609
  // enum until core dropped the URL variant, and an enum writes a
@@ -6525,7 +6611,7 @@ function encodeSignedInvitation(signed) {
6525
6611
  // every following byte and fail as `invalid invitation signature`, pointing
6526
6612
  // nowhere near this line.
6527
6613
  u32le(admitterAddrs.length),
6528
- ...admitterAddrs.map(borshString),
6614
+ ...admitterAddrs.map(borshString2),
6529
6615
  optionalBytes32(signed.application_id, "application_id"),
6530
6616
  // Borsh order follows core's field order, where this is `bytecode_id`; the
6531
6617
  // JSON key is `app_key`, a rename covering both directions that core pins in
@@ -6570,86 +6656,6 @@ async function signMemberJoinOp(input) {
6570
6656
  return hex(concat(signable, signature, unendorsed));
6571
6657
  }
6572
6658
 
6573
- // src/request/request-sig.ts
6574
- var SIGN_DOMAIN2 = new TextEncoder().encode("calimero.auth.request.v1");
6575
- var BODY_DOMAIN = new TextEncoder().encode("calimero.auth.request.body.v1");
6576
- function borshString2(value) {
6577
- const bytes = new TextEncoder().encode(value);
6578
- return concat(u32le(bytes.length), bytes);
6579
- }
6580
- async function requestBodyHash(body = new Uint8Array(0)) {
6581
- const bytes = typeof body === "string" ? new TextEncoder().encode(body) : body;
6582
- return domainHash(BODY_DOMAIN, [bytes]);
6583
- }
6584
- async function signRequest(input) {
6585
- const key = await importSigningKey(input.signerSecret);
6586
- const bodyHash = await requestBodyHash(input.body);
6587
- const issuedAt = u64le(input.issuedAt);
6588
- const expiresAt = u64le(input.expiresAt);
6589
- const encoder = new TextEncoder();
6590
- const preimage = await domainHash(SIGN_DOMAIN2, [
6591
- encoder.encode(input.method),
6592
- encoder.encode(input.path),
6593
- bodyHash,
6594
- issuedAt,
6595
- expiresAt
6596
- ]);
6597
- const signature = new Uint8Array(
6598
- await crypto.subtle.sign({ name: "Ed25519" }, key, preimage)
6599
- );
6600
- return hex(
6601
- concat(
6602
- borshString2(input.method),
6603
- borshString2(input.path),
6604
- bodyHash,
6605
- issuedAt,
6606
- expiresAt,
6607
- signature
6608
- )
6609
- );
6610
- }
6611
-
6612
- // src/request/caller-proof.ts
6613
- function callerProof(input) {
6614
- const credential = fromHexUnsized(input.credential, "credential");
6615
- const request = fromHexUnsized(input.request, "request signature");
6616
- const session = input.session === void 0 ? new Uint8Array([0]) : concat(new Uint8Array([1]), fromHexUnsized(input.session, "session statement"));
6617
- return hex(concat(credential, session, request));
6618
- }
6619
-
6620
- // src/request/proof-signer.ts
6621
- function bodyBytes(body) {
6622
- if (body === void 0 || body === null) return new Uint8Array(0);
6623
- if (typeof body === "string") return body;
6624
- if (body instanceof Uint8Array) return body;
6625
- if (body instanceof ArrayBuffer) return new Uint8Array(body);
6626
- if (ArrayBuffer.isView(body)) {
6627
- return new Uint8Array(body.buffer, body.byteOffset, body.byteLength);
6628
- }
6629
- throw new Error(
6630
- `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`
6631
- );
6632
- }
6633
- function createProofSigner(options) {
6634
- const ttl = options.ttlSeconds ?? 120;
6635
- const clock = options.now ?? (() => Math.floor(Date.now() / 1e3));
6636
- return async (request) => {
6637
- const issuedAt = clock();
6638
- return callerProof({
6639
- credential: options.credential,
6640
- session: options.session,
6641
- request: await signRequest({
6642
- method: request.method,
6643
- path: request.path,
6644
- body: bodyBytes(request.body),
6645
- issuedAt,
6646
- expiresAt: issuedAt + ttl,
6647
- signerSecret: options.signerSecret
6648
- })
6649
- });
6650
- };
6651
- }
6652
-
6653
6659
  // src/login/login.ts
6654
6660
  var SIGN_DOMAIN3 = new TextEncoder().encode("calimero.auth.login.v1");
6655
6661
  var AUDIENCE_TAG = {