@provablehq/veil-aleo-sdk 0.9.0 → 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.
package/dist/index.js CHANGED
@@ -194,7 +194,6 @@ function mnemonicToHDKey(mnemonic, options = {}) {
194
194
  }
195
195
 
196
196
  // src/provableApi.ts
197
- var DEFAULT_PROVABLE_API_URL = "https://api.provable.com";
198
197
  var EXPIRY_SKEW_MS = 5 * 60 * 1e3;
199
198
  function memoryCredentialStore(initial) {
200
199
  let held = initial;
@@ -206,35 +205,15 @@ function memoryCredentialStore(initial) {
206
205
  };
207
206
  }
208
207
  async function registerProvableApi(params) {
209
- const baseUrl = params.baseUrl ?? DEFAULT_PROVABLE_API_URL;
210
- const transport = params.transport ?? fetch;
211
- const response = await transport(`${baseUrl}/consumers`, {
212
- method: "POST",
213
- headers: { "content-type": "application/json" },
214
- body: JSON.stringify({ username: params.username })
215
- });
216
- if (!response.ok) {
217
- const body2 = await response.text();
218
- if (response.status === 409) {
219
- throw new Error(
220
- `Provable API username '${params.username}' is already registered. Credentials cannot be recovered from a username: supply the existing consumerId and apiKey, or register under a different name. (HTTP 409: ${body2})`
221
- );
222
- }
223
- throw new Error(
224
- `Provable API consumer registration failed (HTTP ${response.status}): ${body2}`
225
- );
226
- }
227
- const body = await response.json();
228
- if (!body.consumer?.id || !body.key) {
229
- throw new Error("Provable API consumer registration response carried no consumer id and key.");
230
- }
231
- return { consumerId: body.consumer.id, apiKey: body.key };
208
+ void params;
209
+ return void 0;
232
210
  }
233
211
  async function mintJwt(credentials, baseUrl, transport) {
234
212
  const response = await transport(`${baseUrl}/jwts/${encodeURIComponent(credentials.consumerId)}`, {
235
213
  method: "POST",
236
214
  headers: { "X-Provable-API-Key": credentials.apiKey }
237
215
  });
216
+ if (response.status === 404) return void 0;
238
217
  if (!response.ok) {
239
218
  throw new Error(
240
219
  `Provable API JWT mint failed (HTTP ${response.status}): ${await response.text()}`
@@ -251,42 +230,20 @@ async function mintJwt(credentials, baseUrl, transport) {
251
230
  return { jwt: header, expiration: body.exp * 1e3 };
252
231
  }
253
232
  function createProvableSession(options = {}) {
254
- const baseUrl = options.baseUrl ?? DEFAULT_PROVABLE_API_URL;
233
+ const baseUrl = options.baseUrl;
255
234
  const transport = options.transport ?? fetch;
256
235
  const consumers = { proving: false, recordScanning: false };
257
236
  let credentials = options.credentials;
258
- let registered = false;
259
237
  let credentialsInFlight;
260
238
  let jwt;
261
239
  let jwtInFlight;
262
- async function resolveCredentials(usernameOverride) {
263
- if (credentials) return credentials;
264
- const stored = await options.store?.load();
265
- if (stored) {
240
+ let noJwtRoute = false;
241
+ function getCredentials() {
242
+ if (credentials) return Promise.resolve(credentials);
243
+ credentialsInFlight ??= Promise.resolve(options.store?.load()).then((stored) => {
266
244
  credentials = stored;
267
- return credentials;
268
- }
269
- const username = usernameOverride ?? (typeof options.username === "function" ? options.username() : options.username);
270
- if (!username) {
271
- throw new Error(
272
- "No Provable API credentials available \u2014 pass credentials, a store holding them, or a username to register with."
273
- );
274
- }
275
- const issued = await registerProvableApi({ username, baseUrl, transport });
276
- credentials = issued;
277
- registered = true;
278
- try {
279
- await options.store?.save(issued);
280
- } catch (cause) {
281
- throw new Error(
282
- `Registered Provable API consumer ${issued.consumerId}, but persisting its credentials failed. They are live for this process \u2014 read them from getCredentials() and store them yourself \u2014 but the API key cannot be reissued, so a restart loses it.`,
283
- { cause }
284
- );
285
- }
286
- return credentials;
287
- }
288
- function getCredentials({ username } = {}) {
289
- credentialsInFlight ??= resolveCredentials(username).finally(() => {
245
+ return stored;
246
+ }).finally(() => {
290
247
  credentialsInFlight = void 0;
291
248
  });
292
249
  return credentialsInFlight;
@@ -295,8 +252,11 @@ function createProvableSession(options = {}) {
295
252
  const stale = !jwt || Date.now() >= jwt.expiration - EXPIRY_SKEW_MS;
296
253
  if (!forceRefresh && !stale) return Promise.resolve(jwt);
297
254
  jwtInFlight ??= (async () => {
255
+ if (!baseUrl || noJwtRoute) return void 0;
298
256
  const resolved = await getCredentials();
257
+ if (!resolved) return void 0;
299
258
  jwt = await mintJwt(resolved, baseUrl, transport);
259
+ if (!jwt) noJwtRoute = true;
300
260
  return jwt;
301
261
  })().finally(() => {
302
262
  jwtInFlight = void 0;
@@ -304,7 +264,7 @@ function createProvableSession(options = {}) {
304
264
  return jwtInFlight;
305
265
  }
306
266
  return {
307
- registeredConsumer: () => registered,
267
+ registeredConsumer: () => false,
308
268
  getCredentials,
309
269
  getJwt,
310
270
  consumers,
@@ -317,23 +277,21 @@ function getProvableSession(client) {
317
277
  return client.proving?.session;
318
278
  }
319
279
  async function authenticateProvableApi(client, params = {}) {
320
- if (client.proving?.keyedAuth) {
321
- throw new Error(
322
- "This client authenticates with a provisioned API key \u2014 every request already carries it, and there is no consumer or JWT to resolve. Remove the authenticateProvableApi call."
323
- );
324
- }
325
280
  const session = getProvableSession(client);
326
281
  if (!session) {
327
- throw new Error(
328
- "No Provable API session on this client \u2014 pass consumerId and apiKey, or a credentialStore, when creating it."
329
- );
282
+ return {
283
+ credentials: void 0,
284
+ expiration: void 0,
285
+ registered: false,
286
+ applied: { proving: false, recordScanning: false }
287
+ };
330
288
  }
331
- const credentials = await session.getCredentials({ username: params.username });
332
- const { expiration } = await session.getJwt({ forceRefresh: params.forceRefresh });
289
+ const credentials = await session.getCredentials();
290
+ const minted = credentials ? await session.getJwt({ forceRefresh: params.forceRefresh }) : void 0;
333
291
  return {
334
292
  credentials,
335
- expiration,
336
- registered: session.registeredConsumer(),
293
+ expiration: minted?.expiration,
294
+ registered: false,
337
295
  applied: { ...session.consumers }
338
296
  };
339
297
  }
@@ -344,8 +302,32 @@ function provableApiActions() {
344
302
  }
345
303
 
346
304
  // src/index.ts
347
- var DEFAULT_PROVER_URL = "https://api.provable.com/prove";
348
- var DEFAULT_SCANNER_URL = "https://api.provable.com/scanner";
305
+ var DEFAULT_PROVER_URL = "https://edge.provable.com/api/prove";
306
+ var DEFAULT_SCANNER_URL = "https://edge.provable.com/api/scanner";
307
+ var DEFAULT_NETWORK_URL = "https://edge.provable.com/api/v2";
308
+ var EDGE_GATEWAY = "https://edge.provable.com/api";
309
+ function legacyMintRoot(...targets) {
310
+ for (const target of targets) {
311
+ if (!target || target.startsWith(EDGE_GATEWAY)) continue;
312
+ try {
313
+ return new URL(target).origin;
314
+ } catch {
315
+ continue;
316
+ }
317
+ }
318
+ return void 0;
319
+ }
320
+ function sessionForCredentials(options, ...targets) {
321
+ if (options.auth) return void 0;
322
+ if (options.session) return options.session;
323
+ if (options.apiKey && options.consumerId) {
324
+ return createProvableSession({
325
+ credentials: { consumerId: options.consumerId, apiKey: options.apiKey },
326
+ baseUrl: legacyMintRoot(...targets)
327
+ });
328
+ }
329
+ return void 0;
330
+ }
349
331
  async function loadNetwork(name) {
350
332
  const sdk = await loadSdk(name);
351
333
  silenceSdkLogs(sdk);
@@ -402,7 +384,8 @@ function buildSdk(initialNetwork, initialSdk) {
402
384
  let networkUrl = options.networkUrl;
403
385
  let keyProvider = new currentSdk.AleoKeyProvider();
404
386
  keyProvider.useCache(true);
405
- options.session?.attach("proving");
387
+ const session = sessionForCredentials(options, options.proverUrl);
388
+ session?.attach("proving");
406
389
  let configNetwork = network;
407
390
  const resolveProverUrl = () => {
408
391
  const configured = options.proverUrl ?? (options.mode === "delegated" ? DEFAULT_PROVER_URL : void 0);
@@ -421,7 +404,7 @@ function buildSdk(initialNetwork, initialSdk) {
421
404
  // Carried for `authenticateProvableApi` to find on a client. Core never
422
405
  // reads binding-specific fields on a proving config — `url` and `apiKey`
423
406
  // already travel the same way.
424
- session: options.session,
407
+ session,
425
408
  keyedAuth: options.auth,
426
409
  buildTransaction: async (txOptions) => {
427
410
  const programManager = new currentSdk.ProgramManager(
@@ -443,6 +426,68 @@ function buildSdk(initialNetwork, initialSdk) {
443
426
  }
444
427
  resolvedImports = merged;
445
428
  }
429
+ if (options.mode === "delegated") {
430
+ const proverUrl = resolveProverUrl();
431
+ if (!proverUrl) {
432
+ throw new ConfigurationError(
433
+ "Delegated execution requires proverUrl. Pass proverUrl to createProvingConfig or createAleoClient."
434
+ );
435
+ }
436
+ try {
437
+ const provingRequest = await programManager.provingRequest({
438
+ programName: txOptions.programName,
439
+ functionName: txOptions.functionName,
440
+ priorityFee: 0,
441
+ privateFee: txOptions.privateFee ?? false,
442
+ inputs: txOptions.inputs,
443
+ ...resolvedImports ? { programImports: resolvedImports } : {},
444
+ broadcast: false,
445
+ useFeeMaster: options.useFeeMaster ?? false
446
+ });
447
+ await txOptions.onProgress?.({ type: "request-built" });
448
+ const dpsClient = new AleoNetworkClient(proverUrl);
449
+ const auth = async (forceRefresh) => {
450
+ if (options.auth) return { auth: options.auth };
451
+ if (session) return { jwtData: await session.getJwt({ forceRefresh }) };
452
+ return { apiKey: options.apiKey, consumerId: options.consumerId };
453
+ };
454
+ await txOptions.onProgress?.({ type: "prover-submitted" });
455
+ let credentials = await auth(false);
456
+ let result = await dpsClient.submitProvingRequestSafe({
457
+ provingRequest,
458
+ url: proverUrl,
459
+ ...credentials
460
+ });
461
+ if (!result.ok && (result.status === 401 || result.status === 403) && session) {
462
+ credentials = await auth(true);
463
+ result = await dpsClient.submitProvingRequestSafe({
464
+ provingRequest,
465
+ url: proverUrl,
466
+ ...credentials
467
+ });
468
+ }
469
+ if (!result.ok) {
470
+ throw new ProvingError({
471
+ message: `Delegated proving failed (HTTP ${result.status}): ${result.error?.message ?? "unknown error"}`,
472
+ statusCode: result.status
473
+ });
474
+ }
475
+ const transaction = result.data.transaction;
476
+ if (!transaction?.id) {
477
+ throw new ConfigurationError(
478
+ "DPS response did not contain a transaction ID \u2014 check prover service configuration."
479
+ );
480
+ }
481
+ await txOptions.onProgress?.({
482
+ type: "prover-returned",
483
+ transactionId: transaction.id
484
+ });
485
+ return transaction;
486
+ } catch (error) {
487
+ if (error instanceof BaseError) throw error;
488
+ throw classifyProvingError(error);
489
+ }
490
+ }
446
491
  const tx = await programManager.buildExecutionTransaction({
447
492
  programName: txOptions.programName,
448
493
  functionName: txOptions.functionName,
@@ -530,12 +575,12 @@ function buildSdk(initialNetwork, initialSdk) {
530
575
  priorityFee,
531
576
  privateFee: execOptions.privateFee ?? false,
532
577
  broadcast: true,
533
- useFeeMaster: options.useFeeMaster ?? true
578
+ useFeeMaster: options.useFeeMaster ?? false
534
579
  });
535
580
  const dpsClient = new AleoNetworkClient(proverUrl);
536
581
  const auth = async (forceRefresh) => {
537
582
  if (options.auth) return { auth: options.auth };
538
- if (options.session) return { jwtData: await options.session.getJwt({ forceRefresh }) };
583
+ if (session) return { jwtData: await session.getJwt({ forceRefresh }) };
539
584
  return { apiKey: options.apiKey, consumerId: options.consumerId };
540
585
  };
541
586
  let credentials = await auth(false);
@@ -544,7 +589,7 @@ function buildSdk(initialNetwork, initialSdk) {
544
589
  url: proverUrl,
545
590
  ...credentials
546
591
  });
547
- if (!result.ok && (result.status === 401 || result.status === 403) && options.session) {
592
+ if (!result.ok && (result.status === 401 || result.status === 403) && session) {
548
593
  credentials = await auth(true);
549
594
  result = await dpsClient.submitProvingRequestSafe({
550
595
  provingRequest,
@@ -565,6 +610,15 @@ function buildSdk(initialNetwork, initialSdk) {
565
610
  }
566
611
  const txId = response.transaction?.id;
567
612
  if (!txId) throw new ConfigurationError("DPS response did not contain a transaction ID \u2014 check prover service configuration.");
613
+ const broadcastResult = response.broadcast_result;
614
+ if (!broadcastResult || broadcastResult.status !== "Accepted") {
615
+ const message = broadcastResult?.status === "Skipped" ? "Delegated prover skipped transaction broadcast" : broadcastResult?.message ?? "Delegated prover did not report an accepted transaction broadcast";
616
+ const error = new Error(message);
617
+ if (broadcastResult && "status_code" in broadcastResult) {
618
+ error.status = Number(broadcastResult.status_code);
619
+ }
620
+ throw classifyBroadcastError(error, txId);
621
+ }
568
622
  const confirmedTx = await waitForConfirmation(buildPollingClient(), txId, options.confirmationTimeout);
569
623
  const { transitions, outputs } = extractTransitions(confirmedTx, decryptor);
570
624
  return { transactionId: txId, transitions, outputs };
@@ -670,11 +724,11 @@ function buildSdk(initialNetwork, initialSdk) {
670
724
  );
671
725
  }
672
726
  }
673
- async function scanOwned(scanner, params, hasCredentials, session) {
727
+ async function scanOwned(scanner, params, session) {
674
728
  const ownedFilter = buildOwnedFilter(params);
675
729
  const ALWAYS_RETRY = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
676
730
  const AUTH_RETRY = /* @__PURE__ */ new Set([401, 403]);
677
- const canReMint = hasCredentials || !!session;
731
+ const canReMint = !!session && !!await session.getJwt();
678
732
  const retryable = (status) => ALWAYS_RETRY.has(status) || canReMint && AUTH_RETRY.has(status);
679
733
  const MAX_ATTEMPTS = 4;
680
734
  let last = "";
@@ -691,9 +745,8 @@ function buildSdk(initialNetwork, initialSdk) {
691
745
  lastStatus = void 0;
692
746
  }
693
747
  if (attempt === MAX_ATTEMPTS - 1) break;
694
- if (lastStatus !== void 0 && AUTH_RETRY.has(lastStatus)) {
695
- if (session) scanner.setJwtData(await session.getJwt({ forceRefresh: true }));
696
- else scanner.setJwtData(void 0);
748
+ if (canReMint && lastStatus !== void 0 && AUTH_RETRY.has(lastStatus)) {
749
+ scanner.setJwtData(await session.getJwt({ forceRefresh: true }));
697
750
  }
698
751
  await new Promise((resolve) => setTimeout(resolve, 500 * 2 ** attempt));
699
752
  }
@@ -707,7 +760,7 @@ function buildSdk(initialNetwork, initialSdk) {
707
760
  });
708
761
  if (!options.session && options.apiKey && !options.consumerId) {
709
762
  throw new ConfigurationError(
710
- "Record scanning with an apiKey also needs consumerId \u2014 a JWT is minted from the pair. Pass both, pass a session, or omit both for an unauthenticated service."
763
+ "Record scanning with an apiKey also needs consumerId. Pass both, use auth: { mode: 'api-key' } for a provisioned key, or omit both for the open gateway."
711
764
  );
712
765
  }
713
766
  let scannerSdk = { RecordScanner, ViewKey };
@@ -715,7 +768,7 @@ function buildSdk(initialNetwork, initialSdk) {
715
768
  let viewKey;
716
769
  let viewKeyString;
717
770
  let registration = makeRegisterOnce(options.startBlock ?? 0);
718
- let credential = options.auth ?? options.session;
771
+ let credential = options.auth ?? sessionForCredentials(options, options.url);
719
772
  const sessionOf = (source) => source && !("mode" in source) ? source : void 0;
720
773
  sessionOf(credential)?.attach("recordScanning");
721
774
  const url = options.url ?? DEFAULT_SCANNER_URL;
@@ -736,6 +789,7 @@ function buildSdk(initialNetwork, initialSdk) {
736
789
  registration = makeRegisterOnce(options.startBlock ?? 0);
737
790
  }
738
791
  return {
792
+ url,
739
793
  setAccount: (account) => {
740
794
  viewKeyString = account.viewKey;
741
795
  buildScanner();
@@ -774,8 +828,7 @@ function buildSdk(initialNetwork, initialSdk) {
774
828
  const activeSession = sessionOf(credential);
775
829
  if (activeSession) activeScanner.setJwtData(await activeSession.getJwt());
776
830
  await activeRegistration.ensure(activeScanner, activeViewKey);
777
- const canReMint = !credential && !!(options.apiKey && options.consumerId);
778
- return scanOwned(activeScanner, params, canReMint, activeSession);
831
+ return scanOwned(activeScanner, params, activeSession);
779
832
  },
780
833
  switchNetwork: async (newNetwork) => {
781
834
  if (newNetwork !== "mainnet" && newNetwork !== "testnet") {
@@ -796,11 +849,11 @@ function buildSdk(initialNetwork, initialSdk) {
796
849
  });
797
850
  if (!options.session && options.apiKey && !options.consumerId) {
798
851
  throw new ConfigurationError(
799
- "Record scanning with an apiKey also needs consumerId \u2014 a JWT is minted from the pair. Pass both, pass a session, or omit both for an unauthenticated service."
852
+ "Record scanning with an apiKey also needs consumerId. Pass both, use auth: { mode: 'api-key' } for a provisioned key, or omit both for the open gateway."
800
853
  );
801
854
  }
802
855
  const viewKey = ViewKey.from_string(options.viewKey);
803
- const session = options.session;
856
+ const session = sessionForCredentials(options, options.url);
804
857
  const credentialProps = options.auth ? { auth: options.auth } : session ? {} : {
805
858
  ...options.consumerId ? { consumerId: options.consumerId } : {},
806
859
  ...options.apiKey ? { apiKey: options.apiKey } : {}
@@ -817,7 +870,7 @@ function buildSdk(initialNetwork, initialSdk) {
817
870
  requestRecords: async (params) => {
818
871
  if (session) scanner.setJwtData(await session.getJwt());
819
872
  await registration.ensure(scanner, viewKey);
820
- return scanOwned(scanner, params, !!(options.apiKey && options.consumerId), session);
873
+ return scanOwned(scanner, params, session);
821
874
  }
822
875
  };
823
876
  }
@@ -829,28 +882,28 @@ function buildSdk(initialNetwork, initialSdk) {
829
882
  credentialStore: options.credentialStore,
830
883
  session: options.session
831
884
  });
832
- if (options.auth && options.records && !options.records.setAuth) {
885
+ const networkUrl = options.networkUrl ?? DEFAULT_NETWORK_URL;
886
+ const records = options.records ?? createRemoteScanner();
887
+ if (options.auth && !records.setAuth) {
833
888
  throw new ConfigurationError(
834
889
  "Provisioned-key auth needs a record provider with setAuth \u2014 pass a scanner from createRemoteScanner, or construct the provider with the key."
835
890
  );
836
891
  }
837
892
  const account = privateKeyToAccount(options.privateKey);
838
- const transport = http(options.networkUrl, { network });
893
+ const transport = http(networkUrl, { network });
839
894
  const credentials = options.consumerId && options.apiKey ? { consumerId: options.consumerId, apiKey: options.apiKey } : void 0;
840
895
  const configured = !!(credentials || options.credentialStore || options.session);
841
896
  const session = options.auth ? void 0 : options.session ?? createProvableSession({
842
897
  credentials,
843
898
  store: options.credentialStore ?? memoryCredentialStore(),
844
- // Resolved lazily: only a registration needs it. The derived default
845
- // carries a random suffix because a username is spent once — an account
846
- // that lost its stored key must still be able to register, and the old
847
- // key is unrecoverable. A caller-supplied name is used verbatim, so a
848
- // collision fails rather than quietly registering something else.
849
- username: options.username ?? (() => `veil-${account.address.slice(5, 13)}-${Math.random().toString(36).slice(2, 8)}`)
899
+ // The prover names the legacy gateway first; a legacy scanner url
900
+ // counts too, so a client on the default prover that scans the
901
+ // legacy service still mints for it.
902
+ baseUrl: legacyMintRoot(options.proverUrl, records.url)
850
903
  });
851
904
  const proving = createProvingConfig({
852
905
  mode: options.provingMode ?? "delegated",
853
- networkUrl: options.networkUrl,
906
+ networkUrl,
854
907
  proverUrl: options.proverUrl,
855
908
  session,
856
909
  auth: options.auth,
@@ -859,20 +912,20 @@ function buildSdk(initialNetwork, initialSdk) {
859
912
  apiKey: options.apiKey,
860
913
  consumerId: options.consumerId,
861
914
  account,
862
- ...options.useFeeMaster !== void 0 ? { useFeeMaster: options.useFeeMaster } : {},
915
+ // The hosted prover pays fees by default, so an account holding no public
916
+ // credits can write; a caller funding its own fees opts out.
917
+ useFeeMaster: options.useFeeMaster ?? true,
863
918
  ...options.confirmationTimeout !== void 0 ? { confirmationTimeout: options.confirmationTimeout } : {}
864
919
  });
865
920
  const publicClient = createPublicClient({ transport });
866
- if (options.records) {
867
- if (options.auth) options.records.setAuth?.(options.auth);
868
- else if (configured && session) options.records.setSession?.(session);
869
- options.records.setAccount({ viewKey: account.viewKey });
870
- }
921
+ if (options.auth) records.setAuth?.(options.auth);
922
+ else if (configured && session) records.setSession?.(session);
923
+ records.setAccount({ viewKey: account.viewKey });
871
924
  const walletClient = createWalletClient({
872
925
  account,
873
926
  transport,
874
927
  proving,
875
- ...options.records ? { recordProvider: options.records } : {}
928
+ recordProvider: records
876
929
  }).extend(provableApiActions());
877
930
  return { publicClient, walletClient, account };
878
931
  }
@@ -1002,6 +1055,7 @@ function createDevnodeClient(options) {
1002
1055
  }
1003
1056
  export {
1004
1057
  BLS12377HDKey,
1058
+ DEFAULT_NETWORK_URL,
1005
1059
  DEFAULT_PROVER_URL,
1006
1060
  DEFAULT_SCANNER_URL,
1007
1061
  DEVNODE_ADDR,