@provablehq/sdk 0.10.6-rc.1 → 0.11.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.
Files changed (47) hide show
  1. package/dist/mainnet/browser.cjs +105 -66
  2. package/dist/mainnet/browser.cjs.map +1 -1
  3. package/dist/mainnet/browser.d.cts +1 -1
  4. package/dist/mainnet/browser.d.ts +1 -1
  5. package/dist/mainnet/browser.js +102 -67
  6. package/dist/mainnet/browser.js.map +1 -1
  7. package/dist/mainnet/keys/keystore/indexeddb.d.cts +11 -0
  8. package/dist/mainnet/keys/keystore/indexeddb.d.ts +11 -0
  9. package/dist/mainnet/network-client.d.cts +5 -1
  10. package/dist/mainnet/network-client.d.ts +5 -1
  11. package/dist/mainnet/node.cjs +4 -0
  12. package/dist/mainnet/node.cjs.map +1 -1
  13. package/dist/mainnet/node.js +1 -1
  14. package/dist/mainnet/record-scanner.d.cts +11 -0
  15. package/dist/mainnet/record-scanner.d.ts +11 -0
  16. package/dist/mainnet/utils/logger.d.cts +4 -0
  17. package/dist/mainnet/utils/logger.d.ts +4 -0
  18. package/dist/mainnet/wasm-Bnb_v1_O.js +3 -0
  19. package/dist/mainnet/wasm-Bnb_v1_O.js.map +1 -0
  20. package/dist/mainnet/wasm.cjs +251 -0
  21. package/dist/mainnet/wasm.cjs.map +1 -0
  22. package/dist/mainnet/wasm.d.cts +1 -1
  23. package/dist/mainnet/wasm.d.ts +1 -1
  24. package/dist/testnet/browser.cjs +105 -66
  25. package/dist/testnet/browser.cjs.map +1 -1
  26. package/dist/testnet/browser.d.cts +1 -1
  27. package/dist/testnet/browser.d.ts +1 -1
  28. package/dist/testnet/browser.js +102 -67
  29. package/dist/testnet/browser.js.map +1 -1
  30. package/dist/testnet/keys/keystore/indexeddb.d.cts +11 -0
  31. package/dist/testnet/keys/keystore/indexeddb.d.ts +11 -0
  32. package/dist/testnet/network-client.d.cts +5 -1
  33. package/dist/testnet/network-client.d.ts +5 -1
  34. package/dist/testnet/node.cjs +4 -0
  35. package/dist/testnet/node.cjs.map +1 -1
  36. package/dist/testnet/node.js +1 -1
  37. package/dist/testnet/record-scanner.d.cts +11 -0
  38. package/dist/testnet/record-scanner.d.ts +11 -0
  39. package/dist/testnet/utils/logger.d.cts +4 -0
  40. package/dist/testnet/utils/logger.d.ts +4 -0
  41. package/dist/testnet/wasm-BCrMb35a.js +3 -0
  42. package/dist/testnet/wasm-BCrMb35a.js.map +1 -0
  43. package/dist/testnet/wasm.cjs +251 -0
  44. package/dist/testnet/wasm.cjs.map +1 -0
  45. package/dist/testnet/wasm.d.cts +1 -1
  46. package/dist/testnet/wasm.d.ts +1 -1
  47. package/package.json +2 -2
@@ -20,9 +20,16 @@ let currentLevel = "info";
20
20
  * - "warn" — errors + warnings
21
21
  * - "info" — errors + warnings + info (default)
22
22
  * - "debug" — everything including debug traces
23
+ *
24
+ * This controls both TS-side and WASM-side logging. WASM log calls
25
+ * (e.g., "Loading program", "Executing program") are silenced when
26
+ * the level is below "info".
23
27
  */
24
28
  function setLogLevel(level) {
25
29
  currentLevel = level;
30
+ Promise.resolve().then(function () { return require('./wasm.cjs'); })
31
+ .then(({ setWasmLogLevel }) => setWasmLogLevel(LEVEL_PRIORITY[level]))
32
+ .catch(() => { }); // WASM not loaded yet — will use default level (info)
26
33
  }
27
34
  /** Returns the current SDK log level. */
28
35
  function getLogLevel() {
@@ -211,6 +218,17 @@ class MemKeyVerifier {
211
218
  * It persists proving and verifying keys across page reloads and browser sessions using the
212
219
  * IndexedDB API available in all modern browsers and Web Workers.
213
220
  *
221
+ * **Environment**: Browser / Web Worker only. Instantiating this class is safe in any
222
+ * environment, but the first IndexedDB operation will reject with a clear error when
223
+ * `globalThis.indexedDB` is not available (e.g., Node.js, SSR contexts). Guard your
224
+ * imports accordingly if you bundle for server-side rendering.
225
+ *
226
+ * **Security**: Keys are stored as plaintext `Uint8Array` in IndexedDB. Any script
227
+ * running on the same origin — including scripts injected via XSS — can read the stored
228
+ * proving and verifying keys. Do **not** use this keystore for data that must remain
229
+ * confidential under an XSS-capable adversary; encrypt sensitive material at the
230
+ * application layer before persisting, or use an in-memory store.
231
+ *
214
232
  * @example
215
233
  * ```ts
216
234
  * import { IndexedDBKeyStore, ProgramManager } from "@provablehq/sdk";
@@ -240,6 +258,13 @@ class IndexedDBKeyStore {
240
258
  openDB() {
241
259
  if (this.dbPromise)
242
260
  return this.dbPromise;
261
+ // Env check sits outside the Promise constructor so a failure doesn't
262
+ // poison the cache; a later call (e.g. after a polyfill loads) can retry.
263
+ if (typeof indexedDB === "undefined") {
264
+ return Promise.reject(new Error("IndexedDBKeyStore requires a browser or Web Worker environment: " +
265
+ "`indexedDB` is not defined. If you are in Node.js or an SSR " +
266
+ "context, use LocalFileKeyStore or an in-memory key provider instead."));
267
+ }
243
268
  this.dbPromise = new Promise((resolve, reject) => {
244
269
  const request = indexedDB.open(this.dbName, 1);
245
270
  request.onupgradeneeded = () => {
@@ -1265,7 +1290,7 @@ class AleoNetworkClient {
1265
1290
  else {
1266
1291
  this.headers = {
1267
1292
  // This is replaced by the actual version by a Rollup plugin
1268
- "X-Aleo-SDK-Version": "0.10.6-rc.1",
1293
+ "X-Aleo-SDK-Version": "0.11.0",
1269
1294
  "X-Aleo-environment": environment(),
1270
1295
  };
1271
1296
  }
@@ -1281,7 +1306,7 @@ class AleoNetworkClient {
1281
1306
  else {
1282
1307
  this.headers = {
1283
1308
  // This is replaced by the actual version by a Rollup plugin
1284
- "X-Aleo-SDK-Version": "0.10.6-rc.1",
1309
+ "X-Aleo-SDK-Version": "0.11.0",
1285
1310
  "X-Aleo-environment": environment(),
1286
1311
  };
1287
1312
  }
@@ -2728,7 +2753,7 @@ class AleoNetworkClient {
2728
2753
  };
2729
2754
  }
2730
2755
  /**
2731
- * Parses a /prove or /prove/encrypted response. Returns a result object (never throws for 200/400/500/503).
2756
+ * Parses a /prove/authorization or /prove/request response. Returns a result object (never throws for 200/400/500/503).
2732
2757
  */
2733
2758
  async handleProvingResponse(response) {
2734
2759
  // Get the proving response text.
@@ -2789,14 +2814,12 @@ class AleoNetworkClient {
2789
2814
  async submitProvingRequestSafe(options) {
2790
2815
  // Attempt to get the Prover URI first from the options, then from any configured globally, or third try the main configured host.
2791
2816
  const proverUri = (options.url ?? this.proverUri) ?? this.host;
2792
- const provingRequestString = options.provingRequest instanceof testnet_js.ProvingRequest
2793
- ? options.provingRequest.toString()
2794
- : options.provingRequest;
2795
2817
  // Try to get JWT data to access the Provable API.
2796
2818
  const apiKey = options.apiKey ?? this.apiKey;
2797
2819
  const consumerId = options.consumerId ?? this.consumerId;
2798
2820
  let jwtData = options.jwtData ?? this.jwtData;
2799
- // Check to see if the JWT needs refreshing.
2821
+ // Check to see if the JWT needs refreshing. Runs before parsing the
2822
+ // proving request so JWT refresh errors propagate as they always have.
2800
2823
  const isExpired = jwtData && Date.now() >= jwtData.expiration - FIVE_MINUTES;
2801
2824
  if (!jwtData || isExpired) {
2802
2825
  if (apiKey && consumerId) {
@@ -2817,59 +2840,58 @@ class AleoNetworkClient {
2817
2840
  if (jwtData?.jwt) {
2818
2841
  headers["Authorization"] = jwtData.jwt;
2819
2842
  }
2820
- // Encapsulate the requests in a locally scoped function that can be run with a retry closure.
2821
- const runRequest = async () => {
2822
- // If DPS privacy is set, call invoke the encrypted flow.
2823
- if (options.dpsPrivacy) {
2824
- // Get an ephemeral public key from a DPS service.
2825
- const pubKeyResponse = await get(proverUri + "/pubkey", {
2826
- headers,
2827
- credentials: "include",
2828
- }, this.transport);
2829
- // Encrypt the provingRequest.
2830
- const pubkey = parseJSON(await pubKeyResponse.text());
2831
- const ciphertext = encryptProvingRequest(pubkey.public_key, testnet_js.ProvingRequest.fromString(provingRequestString));
2832
- // Form the expected query a DPS service expects (including the key_id).
2833
- const payload = {
2834
- key_id: pubkey.key_id,
2835
- ciphertext: ciphertext,
2836
- };
2837
- // We're in node, attempt to set the cookie manually.
2838
- const cookie = isNode() ? pubKeyResponse.headers.get("set-cookie") : undefined;
2839
- // Send the encrypted proving request to the DPS service.
2840
- const res = await this.transport(`${proverUri}/prove/encrypted`, {
2841
- method: "POST",
2842
- body: JSON.stringify(payload),
2843
- headers: {
2844
- ...headers,
2845
- ...(cookie ? { Cookie: cookie } : {})
2846
- },
2847
- credentials: "include",
2848
- });
2849
- // Properly handle the proving response.
2850
- return this.handleProvingResponse(res);
2851
- }
2852
- // If encrypted usage is not specified use the unencrypted endpoint.
2853
- const proveEndpoint = proverUri.endsWith("/prove")
2854
- ? proverUri
2855
- : proverUri + "/prove";
2856
- const res = await this.transport(proveEndpoint, {
2857
- method: "POST",
2858
- body: provingRequestString,
2843
+ // Send the proving request encrypted (libsodium-compatible sealed box).
2844
+ // Used by both `/prove/authorization` (Authorization variant) and
2845
+ // `/prove/request` (Request variant). The legacy plaintext `/prove`
2846
+ // route is no longer used.
2847
+ const sendEncrypted = async (endpoint, provingRequestObj) => {
2848
+ // Get an ephemeral public key from the DPS.
2849
+ const pubKeyResponse = await get(proverUri + "/pubkey", {
2859
2850
  headers,
2851
+ credentials: "include",
2852
+ }, this.transport);
2853
+ // Encrypt the provingRequest using the ephemeral pubkey.
2854
+ const pubkey = parseJSON(await pubKeyResponse.text());
2855
+ const ciphertext = encryptProvingRequest(pubkey.public_key, provingRequestObj);
2856
+ const payload = {
2857
+ key_id: pubkey.key_id,
2858
+ ciphertext: ciphertext,
2859
+ };
2860
+ // We're in node, attempt to set the cookie manually.
2861
+ const cookie = isNode() ? pubKeyResponse.headers.get("set-cookie") : undefined;
2862
+ const res = await this.transport(`${proverUri}${endpoint}`, {
2863
+ method: "POST",
2864
+ body: JSON.stringify(payload),
2865
+ headers: {
2866
+ ...headers,
2867
+ ...(cookie ? { Cookie: cookie } : {})
2868
+ },
2869
+ credentials: "include",
2860
2870
  });
2861
- // Properly handle the proving response.
2862
2871
  return this.handleProvingResponse(res);
2863
2872
  };
2873
+ // Parse the proving request once, up front, so the variant the SDK
2874
+ // routes on matches the bytes it will eventually send (a Request-
2875
+ // variant string must hit /prove/request, not /prove/authorization).
2876
+ // A malformed input string throws synchronously — the safe-API
2877
+ // contract only promises to return `{ ok: false, ... }` for HTTP
2878
+ // failures (400/500/503); a parse error is a caller-side bug and
2879
+ // surfacing it as a fake 500 would mislead callers debugging it.
2880
+ // `options.dpsPrivacy` is ignored; the legacy plaintext `/prove`
2881
+ // route is deprecated.
2882
+ const provingRequestObj = options.provingRequest instanceof testnet_js.ProvingRequest
2883
+ ? options.provingRequest
2884
+ : testnet_js.ProvingRequest.fromString(options.provingRequest);
2885
+ const endpoint = provingRequestObj.kind() === "request"
2886
+ ? "/prove/request"
2887
+ : "/prove/authorization";
2864
2888
  try {
2865
- // Run the request with retries.
2866
2889
  return await retryWithBackoff(async () => {
2867
- // Run the encrypted or non-encrypted flow as specified by the flags.
2868
- const result = await runRequest();
2890
+ const result = await sendEncrypted(endpoint, provingRequestObj);
2869
2891
  if (result.ok) {
2870
2892
  return result;
2871
2893
  }
2872
- // If 500s are hit responses are returned, attempt retries.
2894
+ // Retry on 500/503; surface 400 verbatim.
2873
2895
  if (result.status === 500 || result.status === 503) {
2874
2896
  const err = new Error(result.error.message);
2875
2897
  err.status = result.status;
@@ -2879,7 +2901,7 @@ class AleoNetworkClient {
2879
2901
  });
2880
2902
  }
2881
2903
  catch (err) {
2882
- // If an error is returned, provide usable information to the caller.
2904
+ // HTTP failure inside the retry loop convert to a result object.
2883
2905
  const e = err;
2884
2906
  return {
2885
2907
  ok: false,
@@ -4601,6 +4623,19 @@ class RecordScanner {
4601
4623
  const response = await this.request(new Request(`${this.url}/pubkey`, { method: "GET" }));
4602
4624
  return parseJSON(await response.text());
4603
4625
  }
4626
+ /**
4627
+ * Registers the account with the record scanning service using the encrypted flow.
4628
+ * Alias of {@link registerEncrypted} — preserved so existing callers using the
4629
+ * previous unencrypted `register(viewKey, startBlock)` API continue to work
4630
+ * unchanged while transparently using the encrypted endpoint.
4631
+ *
4632
+ * @param {ViewKey} viewKey The view key to register.
4633
+ * @param {number} startBlock The block height to start scanning from.
4634
+ * @returns {Promise<RegisterResult>} `{ ok: true, data }` on success, or `{ ok: false, status, error }` on failure.
4635
+ */
4636
+ async register(viewKey, startBlock) {
4637
+ return this.registerEncrypted(viewKey, startBlock);
4638
+ }
4604
4639
  /**
4605
4640
  * Registers the account with the record scanning service using the encrypted flow: 1. fetches an ephemeral public key from /pubkey - 2. encrypts the registration request (view key + start block) - 3. POSTs to /register/encrypted. Does not HTTP error on a proper error response from the record scanner; returns a result object instead.
4606
4641
  *
@@ -5561,7 +5596,7 @@ class ProgramManager {
5561
5596
  resolvedImports = await this.networkClient.getProgramImports(programSource);
5562
5597
  }
5563
5598
  catch (e) {
5564
- console.warn(`Failed to resolve program imports from network: ${e}.`);
5599
+ logger.warn(`Failed to resolve program imports from network: ${e}.`);
5565
5600
  }
5566
5601
  }
5567
5602
  // Build a map of which functions each import actually calls,
@@ -5609,7 +5644,7 @@ class ProgramManager {
5609
5644
  }
5610
5645
  }
5611
5646
  catch (e) {
5612
- console.warn(`Failed to resolve transitive imports for ${name}: ${e}`);
5647
+ logger.warn(`Failed to resolve transitive imports for ${name}: ${e}`);
5613
5648
  }
5614
5649
  }
5615
5650
  // Phase 2: Add programs in topological order (leaves first).
@@ -5657,7 +5692,7 @@ class ProgramManager {
5657
5692
  }
5658
5693
  }
5659
5694
  catch (e) {
5660
- console.warn(`Failed to trace call graph for ${name}: ${e}`);
5695
+ logger.warn(`Failed to trace call graph for ${name}: ${e}`);
5661
5696
  }
5662
5697
  }
5663
5698
  }
@@ -5675,7 +5710,7 @@ class ProgramManager {
5675
5710
  builder.addProgram(name, source, importEdition);
5676
5711
  }
5677
5712
  catch (e) {
5678
- console.warn(`Failed to add import ${name} to builder: ${e}`);
5713
+ logger.warn(`Failed to add import ${name} to builder: ${e}`);
5679
5714
  continue;
5680
5715
  }
5681
5716
  if (loadKeys) {
@@ -5733,7 +5768,7 @@ class ProgramManager {
5733
5768
  return { edition: info.edition, amendment: info.amendment_count };
5734
5769
  }
5735
5770
  catch (e) {
5736
- console.warn(`Error finding edition/amendment for ${programName}. Network response: '${e.message}'. Defaulting to edition ${fallbackEdition ?? 1}, amendment 0.`);
5771
+ logger.warn(`Error finding edition/amendment for ${programName}. Network response: '${e.message}'. Defaulting to edition ${fallbackEdition ?? 1}, amendment 0.`);
5737
5772
  return { edition: fallbackEdition ?? 1, amendment: 0 };
5738
5773
  }
5739
5774
  }
@@ -5768,7 +5803,7 @@ class ProgramManager {
5768
5803
  builder.addVerifyingKey(programName, fnName, vk);
5769
5804
  }
5770
5805
  catch (e) {
5771
- console.debug(`Failed to load keys for ${programName}/${fnName}: ${e}`);
5806
+ logger.debug(`Failed to load keys for ${programName}/${fnName}: ${e}`);
5772
5807
  }
5773
5808
  }
5774
5809
  }
@@ -5800,7 +5835,7 @@ class ProgramManager {
5800
5835
  fns = Array.from(builder.functionKeysAvailable(programName));
5801
5836
  }
5802
5837
  catch (e) {
5803
- console.debug(`Failed to query keys for ${programName}: ${e}`);
5838
+ logger.debug(`Failed to query keys for ${programName}: ${e}`);
5804
5839
  continue;
5805
5840
  }
5806
5841
  for (const fnName of fns) {
@@ -5818,7 +5853,7 @@ class ProgramManager {
5818
5853
  }
5819
5854
  }
5820
5855
  catch (e) {
5821
- console.debug(`Failed to persist key for ${programName}/${fnName}: ${e}`);
5856
+ logger.debug(`Failed to persist key for ${programName}/${fnName}: ${e}`);
5822
5857
  }
5823
5858
  }
5824
5859
  }
@@ -6320,7 +6355,7 @@ class ProgramManager {
6320
6355
  [provingKey, verifyingKey] = keys;
6321
6356
  }
6322
6357
  else {
6323
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6358
+ logger.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6324
6359
  }
6325
6360
  }
6326
6361
  // Get the fee record from the account if it is not provided in the parameters
@@ -6359,7 +6394,7 @@ class ProgramManager {
6359
6394
  await this.persistExtractedKeys(programImportsBuilder, importEditions);
6360
6395
  }
6361
6396
  catch (e) {
6362
- console.debug(`Failed to persist extracted keys: ${e}`);
6397
+ logger.debug(`Failed to persist extracted keys: ${e}`);
6363
6398
  }
6364
6399
  return result;
6365
6400
  }
@@ -6481,7 +6516,7 @@ class ProgramManager {
6481
6516
  [provingKey, verifyingKey] = keys;
6482
6517
  }
6483
6518
  else {
6484
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6519
+ logger.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6485
6520
  }
6486
6521
  }
6487
6522
  const query = offlineQuery
@@ -6499,7 +6534,7 @@ class ProgramManager {
6499
6534
  await this.persistExtractedKeys(programImportsBuilder, importEditions);
6500
6535
  }
6501
6536
  catch (e) {
6502
- console.debug(`Failed to persist extracted keys: ${e}`);
6537
+ logger.debug(`Failed to persist extracted keys: ${e}`);
6503
6538
  }
6504
6539
  return result;
6505
6540
  }
@@ -6982,7 +7017,7 @@ class ProgramManager {
6982
7017
  [provingKey, verifyingKey] = keys;
6983
7018
  }
6984
7019
  else {
6985
- console.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
7020
+ logger.log("Function keys not found in KeyStore or KeyProvider. The function keys will be synthesized");
6986
7021
  }
6987
7022
  }
6988
7023
  // Auto-convert bare string inputs to field elements where the function expects field type.
@@ -7001,7 +7036,7 @@ class ProgramManager {
7001
7036
  await this.persistExtractedKeys(builder, importEditions);
7002
7037
  }
7003
7038
  catch (e) {
7004
- console.debug(`Failed to persist extracted keys: ${e}`);
7039
+ logger.debug(`Failed to persist extracted keys: ${e}`);
7005
7040
  }
7006
7041
  return result;
7007
7042
  }
@@ -9053,6 +9088,10 @@ Object.defineProperty(exports, "initThreadPool", {
9053
9088
  enumerable: true,
9054
9089
  get: function () { return testnet_js.initThreadPool; }
9055
9090
  });
9091
+ Object.defineProperty(exports, "setWasmLogLevel", {
9092
+ enumerable: true,
9093
+ get: function () { return testnet_js.setWasmLogLevel; }
9094
+ });
9056
9095
  Object.defineProperty(exports, "snarkVerify", {
9057
9096
  enumerable: true,
9058
9097
  get: function () { return testnet_js.snarkVerify; }