@veridex/sdk 1.1.0 → 1.1.2

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 (93) hide show
  1. package/dist/{EVMClient-DtqvdfUP.d.mts → EVMClient-Bmy9czkE.d.mts} +2 -0
  2. package/dist/auth/prepareAuth.js +107 -32
  3. package/dist/auth/prepareAuth.js.map +1 -1
  4. package/dist/auth/prepareAuth.mjs +6 -6
  5. package/dist/chains/aptos/index.js.map +1 -1
  6. package/dist/chains/aptos/index.mjs +3 -3
  7. package/dist/chains/avalanche/index.d.mts +1 -1
  8. package/dist/chains/avalanche/index.js +59 -11
  9. package/dist/chains/avalanche/index.js.map +1 -1
  10. package/dist/chains/avalanche/index.mjs +4 -4
  11. package/dist/chains/evm/index.d.mts +3 -3
  12. package/dist/chains/evm/index.js +59 -11
  13. package/dist/chains/evm/index.js.map +1 -1
  14. package/dist/chains/evm/index.mjs +3 -3
  15. package/dist/chains/solana/index.js.map +1 -1
  16. package/dist/chains/solana/index.mjs +3 -3
  17. package/dist/chains/stacks/index.d.mts +1 -1
  18. package/dist/chains/stacks/index.js.map +1 -1
  19. package/dist/chains/stacks/index.mjs +3 -3
  20. package/dist/chains/starknet/index.d.mts +1 -1
  21. package/dist/chains/starknet/index.js.map +1 -1
  22. package/dist/chains/starknet/index.mjs +3 -3
  23. package/dist/chains/stellar/index.d.mts +312 -0
  24. package/dist/chains/stellar/index.js +300 -0
  25. package/dist/chains/stellar/index.js.map +1 -0
  26. package/dist/chains/stellar/index.mjs +260 -0
  27. package/dist/chains/stellar/index.mjs.map +1 -0
  28. package/dist/chains/sui/index.d.mts +1 -1
  29. package/dist/chains/sui/index.js.map +1 -1
  30. package/dist/chains/sui/index.mjs +3 -3
  31. package/dist/{chunk-Q5O3M5LP.mjs → chunk-2TS375ET.mjs} +2 -2
  32. package/dist/{chunk-QT4ZZ4GM.mjs → chunk-5FDOTI5G.mjs} +2 -2
  33. package/dist/{chunk-N4A2RMUN.mjs → chunk-AFHWA4CZ.mjs} +2 -2
  34. package/dist/{chunk-5T6KPH7A.mjs → chunk-CSU4IV2F.mjs} +2 -2
  35. package/dist/{chunk-YCUJZ6Z7.mjs → chunk-CTYDGO6E.mjs} +63 -6
  36. package/dist/chunk-CTYDGO6E.mjs.map +1 -0
  37. package/dist/{chunk-USDA5JTN.mjs → chunk-DZUNCSI5.mjs} +61 -13
  38. package/dist/chunk-DZUNCSI5.mjs.map +1 -0
  39. package/dist/{chunk-SXXGTQIR.mjs → chunk-E3SU36C2.mjs} +2 -2
  40. package/dist/{chunk-NUWSMJFJ.mjs → chunk-EFIXFA6V.mjs} +2 -2
  41. package/dist/{chunk-MLXQHIH2.mjs → chunk-GM5DKEHD.mjs} +2 -2
  42. package/dist/{chunk-GWJRKDSA.mjs → chunk-GOWXQPTW.mjs} +3 -3
  43. package/dist/{chunk-OVMMTL6H.mjs → chunk-ICGB3AHI.mjs} +2 -2
  44. package/dist/{chunk-QDO6NQ7P.mjs → chunk-M3GUNREX.mjs} +20 -3
  45. package/dist/{chunk-QDO6NQ7P.mjs.map → chunk-M3GUNREX.mjs.map} +1 -1
  46. package/dist/{chunk-X7BZMSPQ.mjs → chunk-RD6ZYUVG.mjs} +52 -30
  47. package/dist/chunk-RD6ZYUVG.mjs.map +1 -0
  48. package/dist/{chunk-F3YAGZSW.mjs → chunk-TPEP6XUA.mjs} +2 -2
  49. package/dist/{chunk-M3MM4YMF.mjs → chunk-UPO55SBK.mjs} +2 -2
  50. package/dist/{chunk-PDHZ5X5O.mjs → chunk-YYT3V7CI.mjs} +2 -2
  51. package/dist/constants.d.mts +2 -2
  52. package/dist/constants.js +51 -29
  53. package/dist/constants.js.map +1 -1
  54. package/dist/constants.mjs +1 -1
  55. package/dist/{index-DDalBhAm.d.mts → index-CKKUV4J7.d.mts} +10 -7
  56. package/dist/index.d.mts +43 -14
  57. package/dist/index.js +512 -159
  58. package/dist/index.js.map +1 -1
  59. package/dist/index.mjs +335 -128
  60. package/dist/index.mjs.map +1 -1
  61. package/dist/passkey.js +57 -4
  62. package/dist/passkey.js.map +1 -1
  63. package/dist/passkey.mjs +3 -3
  64. package/dist/payload.js.map +1 -1
  65. package/dist/payload.mjs +2 -2
  66. package/dist/portfolio-JA4OTF7Y.mjs +13 -0
  67. package/dist/queries/index.js +49 -27
  68. package/dist/queries/index.js.map +1 -1
  69. package/dist/queries/index.mjs +5 -5
  70. package/dist/{types-B7V5VNbO.d.mts → types-C564CfsE.d.mts} +33 -4
  71. package/dist/utils.js +49 -27
  72. package/dist/utils.js.map +1 -1
  73. package/dist/utils.mjs +2 -2
  74. package/dist/wormhole.js.map +1 -1
  75. package/dist/wormhole.mjs +2 -2
  76. package/package.json +8 -1
  77. package/dist/chunk-USDA5JTN.mjs.map +0 -1
  78. package/dist/chunk-X7BZMSPQ.mjs.map +0 -1
  79. package/dist/chunk-YCUJZ6Z7.mjs.map +0 -1
  80. package/dist/portfolio-V347KZOL.mjs +0 -13
  81. /package/dist/{chunk-Q5O3M5LP.mjs.map → chunk-2TS375ET.mjs.map} +0 -0
  82. /package/dist/{chunk-QT4ZZ4GM.mjs.map → chunk-5FDOTI5G.mjs.map} +0 -0
  83. /package/dist/{chunk-N4A2RMUN.mjs.map → chunk-AFHWA4CZ.mjs.map} +0 -0
  84. /package/dist/{chunk-5T6KPH7A.mjs.map → chunk-CSU4IV2F.mjs.map} +0 -0
  85. /package/dist/{chunk-SXXGTQIR.mjs.map → chunk-E3SU36C2.mjs.map} +0 -0
  86. /package/dist/{chunk-NUWSMJFJ.mjs.map → chunk-EFIXFA6V.mjs.map} +0 -0
  87. /package/dist/{chunk-MLXQHIH2.mjs.map → chunk-GM5DKEHD.mjs.map} +0 -0
  88. /package/dist/{chunk-GWJRKDSA.mjs.map → chunk-GOWXQPTW.mjs.map} +0 -0
  89. /package/dist/{chunk-OVMMTL6H.mjs.map → chunk-ICGB3AHI.mjs.map} +0 -0
  90. /package/dist/{chunk-F3YAGZSW.mjs.map → chunk-TPEP6XUA.mjs.map} +0 -0
  91. /package/dist/{chunk-M3MM4YMF.mjs.map → chunk-UPO55SBK.mjs.map} +0 -0
  92. /package/dist/{chunk-PDHZ5X5O.mjs.map → chunk-YYT3V7CI.mjs.map} +0 -0
  93. /package/dist/{portfolio-V347KZOL.mjs.map → portfolio-JA4OTF7Y.mjs.map} +0 -0
package/dist/index.js CHANGED
@@ -90,7 +90,7 @@ var init_constants = __esm({
90
90
  SOLANA_DEVNET: 1,
91
91
  GOERLI: 2,
92
92
  BSC_TESTNET: 4,
93
- POLYGON_MUMBAI: 5,
93
+ POLYGON_AMOY: 10007,
94
94
  AVALANCHE_FUJI: 6,
95
95
  FANTOM_TESTNET: 10,
96
96
  CELO_ALFAJORES: 14,
@@ -152,7 +152,7 @@ var init_constants = __esm({
152
152
  SOLANA_DEVNET: 1,
153
153
  GOERLI: 2,
154
154
  BSC_TESTNET: 4,
155
- POLYGON_MUMBAI: 5,
155
+ POLYGON_AMOY: 10007,
156
156
  AVALANCHE_FUJI: 6,
157
157
  FANTOM_TESTNET: 10,
158
158
  CELO_ALFAJORES: 14,
@@ -173,13 +173,12 @@ var init_constants = __esm({
173
173
  chainId: 84532,
174
174
  wormholeChainId: 10004,
175
175
  rpcUrl: "https://sepolia.base.org",
176
- // Public CORS-friendly RPC
177
176
  explorerUrl: "https://sepolia.basescan.org",
178
177
  isEvm: true,
179
178
  contracts: {
180
- hub: "0x23a39c294891703146c3607e1FEEB5Fe78F7F28d",
181
- vaultFactory: "0x31e8dc9428575334739754Ab2bdB0E8b9Dc707FD",
182
- vaultImplementation: "0xD65E996CD6d5B01689dc54ad30B51f1D88a100f5",
179
+ hub: "0xD5D29b6EaeE6FF4b765e704298a7e48D22607059",
180
+ vaultFactory: "0xb25b73D5FeD5693dcd1Bb78f8e33387B59A022EC",
181
+ vaultImplementation: "0x2CB8397df988c1880d9e5cFfF65bfC22D7D90EE6",
183
182
  wormholeCoreBridge: "0x79A1027a6A159502049F10906D333EC57E95F083",
184
183
  tokenBridge: "0x86F55A04690fd7815A3D802bD587e83eA888B239"
185
184
  }
@@ -192,8 +191,8 @@ var init_constants = __esm({
192
191
  explorerUrl: "https://sepolia.etherscan.io",
193
192
  isEvm: true,
194
193
  contracts: {
195
- vaultFactory: "0x52a6dc19C11b3B53B434Fc7f6D31F8b62ed18F0a",
196
- vaultImplementation: "0xfab72dd1fd3AD79f738B49506f32251B60c95f01",
194
+ vaultFactory: "0x265c10763B4d16AD970bC3d7670c645e37f63AF4",
195
+ vaultImplementation: "0x942426C94652ebC48f4f404928016B95ADb1DA25",
197
196
  wormholeCoreBridge: "0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78",
198
197
  tokenBridge: "0xDB5492265f6038831E89f495670FF909aDe94bd9"
199
198
  }
@@ -206,8 +205,8 @@ var init_constants = __esm({
206
205
  explorerUrl: "https://sepolia-optimism.etherscan.io",
207
206
  isEvm: true,
208
207
  contracts: {
209
- vaultFactory: "0x347feeaBB5655a7a80b56D8D554DA30BE6c28225",
210
- vaultImplementation: "0x26C4FD8fC66150ef5964562F7A69271fB0cd02A4",
208
+ vaultFactory: "0x3c5e4aCdC8Cd53ae5ae603B4c511885191fBb868",
209
+ vaultImplementation: "0xA45dBF322c5A3028687fEEB161603d3BCe02e119",
211
210
  wormholeCoreBridge: "0x31377888146f3253211EFEf5c676D41ECe7D58Fe",
212
211
  tokenBridge: "0x99737Ec4B815d816c49A385943baf0380e75c0Ac"
213
212
  }
@@ -220,24 +219,52 @@ var init_constants = __esm({
220
219
  explorerUrl: "https://sepolia.arbiscan.io",
221
220
  isEvm: true,
222
221
  contracts: {
223
- vaultFactory: "0x708eEE22621A64CDF51d98d3e8D97902D7dF52dD",
224
- vaultImplementation: "0x9f74Dc14A98E59df7AEC5571a2B9E329153dF5Cd",
222
+ vaultFactory: "0xB9C3e6bad3c6f26956be4a4bb5a366376Fd3045D",
223
+ vaultImplementation: "0x8601881b94B68B09b485f407317686103d3CB681",
225
224
  wormholeCoreBridge: "0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35",
226
225
  tokenBridge: "0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e"
227
226
  }
228
227
  },
229
- seiTestnet: {
230
- name: "Sei Atlantic-2",
231
- chainId: 1328,
232
- wormholeChainId: 40,
233
- rpcUrl: "https://evm-rpc-testnet.sei-apis.com",
234
- explorerUrl: "https://seitrace.com/?chain=atlantic-2",
228
+ monadTestnet: {
229
+ name: "Monad Testnet",
230
+ chainId: 10143,
231
+ wormholeChainId: 10048,
232
+ rpcUrl: "https://testnet-rpc.monad.xyz",
233
+ explorerUrl: "https://testnet.monadexplorer.com",
234
+ isEvm: true,
235
+ contracts: {
236
+ vaultFactory: "0xbE9B9c39956448DA75Ac97E5e3dE17e34171660A",
237
+ vaultImplementation: "0x500853DCc54Fd1A707ec9d443032Bb7748f426d3",
238
+ wormholeCoreBridge: "0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd",
239
+ tokenBridge: "0x0000000000000000000000000000000000000000"
240
+ }
241
+ },
242
+ avalancheFuji: {
243
+ name: "Avalanche Fuji",
244
+ chainId: 43113,
245
+ wormholeChainId: 6,
246
+ rpcUrl: "https://api.avax-test.network/ext/bc/C/rpc",
247
+ explorerUrl: "https://testnet.snowtrace.io",
248
+ isEvm: true,
249
+ contracts: {
250
+ vaultFactory: "0x50F2c37584823A6cc293bd0d7647D558d05CA4C1",
251
+ vaultImplementation: "0x53d4D3943d0E524836f0B1955AbB216449F538fF",
252
+ wormholeCoreBridge: "0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C",
253
+ tokenBridge: "0x61E44E506Ca5659E6c0bba9b678586fA2d729756"
254
+ }
255
+ },
256
+ polygonAmoy: {
257
+ name: "Polygon Amoy",
258
+ chainId: 80002,
259
+ wormholeChainId: 10007,
260
+ rpcUrl: "https://rpc-amoy.polygon.technology",
261
+ explorerUrl: "https://amoy.polygonscan.com",
235
262
  isEvm: true,
236
263
  contracts: {
237
264
  vaultFactory: "0x07F608AFf6d63b68029488b726d895c4Bb593038",
238
265
  vaultImplementation: "0xD66153fccFB6731fB6c4944FbD607ba86A76a1f6",
239
- wormholeCoreBridge: "0x0000000000000000000000000000000000000000"
240
- // Mock - not yet deployed
266
+ wormholeCoreBridge: "0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35",
267
+ tokenBridge: "0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e"
241
268
  }
242
269
  },
243
270
  solanaDevnet: {
@@ -274,26 +301,21 @@ var init_constants = __esm({
274
301
  explorerUrl: "https://suiscan.xyz/testnet",
275
302
  isEvm: false,
276
303
  contracts: {
277
- hub: "0x7f6b9a3f9dba7ac6b20d180a9274f525c23a2a9f7e5445218c595c3696c55667",
304
+ hub: "0x1f8f9b79561525275c2de4579a1e5243cfe789656ec666485b7737f4784c1bfc",
278
305
  wormholeCoreBridge: "0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790"
279
306
  }
280
307
  },
281
308
  starknetSepolia: {
282
309
  name: "Starknet Sepolia",
283
310
  chainId: 0,
284
- // Native Starknet chain ID (SN_SEPOLIA = 0x534e5f5345504f4c4941)
285
311
  wormholeChainId: 50001,
286
- // Custom chain ID (50000+ reserved for non-Wormhole chains)
287
- rpcUrl: "https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/tsOnfTBZDKMXcUA26OED-",
312
+ rpcUrl: "https://starknet-sepolia-rpc.publicnode.com",
288
313
  explorerUrl: "https://sepolia.starkscan.co",
289
314
  isEvm: false,
290
315
  contracts: {
291
- // Starknet spoke contract
292
- hub: "0x46139177b8a1d7187cf35fbcddca637882a1d6f50d91f048c59d1322eee9ede",
293
- // Custom bridge contract (NOT Wormhole)
294
- wormholeCoreBridge: "0x700488242f8f03248b2311edddc394f0408a18c36181446eabd265067809c83"
316
+ hub: "0x1c87ca930ad46a5fef167f2d03d6df5b1dd6cdb841955c059edabb0566ff2d6",
317
+ wormholeCoreBridge: "0x30280c19d413eef7515c479186f206498c7f5077e30cb7277ce753d35adab00"
295
318
  },
296
- // Hub chain ID that Starknet bridge validates (Base Sepolia = 10004)
297
319
  hubChainId: 10004
298
320
  }
299
321
  };
@@ -580,6 +602,65 @@ var init_utils = __esm({
580
602
  }
581
603
  });
582
604
 
605
+ // src/core/relayerUrl.ts
606
+ function trimTrailingSlashes(value) {
607
+ return value.trim().replace(/\/+$/, "");
608
+ }
609
+ function normalizeRelayerOrigin(value) {
610
+ const trimmed = trimTrailingSlashes(value);
611
+ if (!trimmed) {
612
+ return "";
613
+ }
614
+ if (trimmed.startsWith("/")) {
615
+ return trimmed.replace(/\/api\/v1$/i, "");
616
+ }
617
+ try {
618
+ const url = new URL(trimmed);
619
+ url.pathname = url.pathname.replace(/\/api\/v1$/i, "").replace(/\/+$/, "");
620
+ return url.toString().replace(/\/+$/, "");
621
+ } catch {
622
+ return trimmed.replace(/\/api\/v1$/i, "");
623
+ }
624
+ }
625
+ function buildRelayerApiUrl(baseUrl, path) {
626
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
627
+ const trimmed = trimTrailingSlashes(baseUrl);
628
+ if (!trimmed) {
629
+ return `${API_ROOT}${normalizedPath}`;
630
+ }
631
+ if (trimmed.startsWith("/")) {
632
+ if (/\/api\/v1$/i.test(trimmed) || /\/api\/auth\/relay$/i.test(trimmed)) {
633
+ return `${trimmed}${normalizedPath}`;
634
+ }
635
+ return `${trimmed}${normalizedPath}`;
636
+ }
637
+ try {
638
+ const url = new URL(trimmed);
639
+ if (/\/api\/v1$/i.test(url.pathname) || /\/api\/auth\/relay$/i.test(url.pathname)) {
640
+ url.pathname = `${url.pathname.replace(/\/+$/, "")}${normalizedPath}`;
641
+ return url.toString();
642
+ }
643
+ if (!url.pathname || url.pathname === "/") {
644
+ url.pathname = `${API_ROOT}${normalizedPath}`;
645
+ return url.toString();
646
+ }
647
+ url.pathname = `${url.pathname.replace(/\/+$/, "")}${normalizedPath}`;
648
+ return url.toString();
649
+ } catch {
650
+ if (/\/api\/v1$/i.test(trimmed) || /\/api\/auth\/relay$/i.test(trimmed)) {
651
+ return `${trimmed}${normalizedPath}`;
652
+ }
653
+ return `${trimmed}${API_ROOT}${normalizedPath}`;
654
+ }
655
+ }
656
+ var API_ROOT;
657
+ var init_relayerUrl = __esm({
658
+ "src/core/relayerUrl.ts"() {
659
+ "use strict";
660
+ API_ROOT = "/api/v1";
661
+ }
662
+ });
663
+
583
664
  // src/core/PasskeyManager.ts
584
665
  function detectRpId(forceLocal) {
585
666
  if (typeof window === "undefined") return "localhost";
@@ -618,6 +699,7 @@ var init_PasskeyManager = __esm({
618
699
  import_browser = require("@simplewebauthn/browser");
619
700
  import_ethers2 = require("ethers");
620
701
  init_utils();
702
+ init_relayerUrl();
621
703
  VERIDEX_RP_ID = "veridex.network";
622
704
  PasskeyManager = class _PasskeyManager {
623
705
  config;
@@ -629,7 +711,7 @@ var init_PasskeyManager = __esm({
629
711
  timeout: config.timeout ?? 6e4,
630
712
  userVerification: config.userVerification ?? "required",
631
713
  authenticatorAttachment: config.authenticatorAttachment ?? "platform",
632
- relayerUrl: config.relayerUrl ?? ""
714
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
633
715
  };
634
716
  }
635
717
  static isSupported() {
@@ -900,7 +982,7 @@ var init_PasskeyManager = __esm({
900
982
  return false;
901
983
  }
902
984
  try {
903
- const response = await fetch(`${this.config.relayerUrl}/api/v1/credential`, {
985
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential"), {
904
986
  method: "POST",
905
987
  headers: { "Content-Type": "application/json" },
906
988
  body: JSON.stringify({
@@ -932,7 +1014,7 @@ var init_PasskeyManager = __esm({
932
1014
  }
933
1015
  try {
934
1016
  const response = await fetch(
935
- `${this.config.relayerUrl}/api/v1/credential/by-id/${encodeURIComponent(credentialId)}`
1017
+ buildRelayerApiUrl(this.config.relayerUrl, `/credential/by-id/${encodeURIComponent(credentialId)}`)
936
1018
  );
937
1019
  if (!response.ok) {
938
1020
  return null;
@@ -971,7 +1053,7 @@ var init_PasskeyManager = __esm({
971
1053
  }
972
1054
  try {
973
1055
  const response = await fetch(
974
- `${this.config.relayerUrl}/api/v1/credential/${encodeURIComponent(keyHash)}`
1056
+ buildRelayerApiUrl(this.config.relayerUrl, `/credential/${encodeURIComponent(keyHash)}`)
975
1057
  );
976
1058
  if (!response.ok) {
977
1059
  return null;
@@ -2228,6 +2310,15 @@ var init_featureFlags = __esm({
2228
2310
  });
2229
2311
 
2230
2312
  // src/presets.ts
2313
+ function configureDefaultRpcUrls(overrides) {
2314
+ for (const key of Object.keys(_rpcOverrides)) {
2315
+ delete _rpcOverrides[key];
2316
+ }
2317
+ Object.assign(_rpcOverrides, overrides);
2318
+ }
2319
+ function getRpcUrlOverride(chain, network) {
2320
+ return _rpcOverrides[chain]?.[network];
2321
+ }
2231
2322
  function getChainConfig(chain, network = "testnet") {
2232
2323
  const preset = CHAIN_PRESETS[chain];
2233
2324
  if (!preset) {
@@ -2235,7 +2326,12 @@ function getChainConfig(chain, network = "testnet") {
2235
2326
  `Unknown chain: "${chain}". Supported chains: ${Object.keys(CHAIN_PRESETS).join(", ")}`
2236
2327
  );
2237
2328
  }
2238
- return preset[network];
2329
+ const config = preset[network];
2330
+ const rpcOverride = getRpcUrlOverride(chain, network);
2331
+ if (rpcOverride) {
2332
+ return { ...config, rpcUrl: rpcOverride };
2333
+ }
2334
+ return config;
2239
2335
  }
2240
2336
  function getChainPreset(chain) {
2241
2337
  const preset = CHAIN_PRESETS[chain];
@@ -2270,7 +2366,7 @@ function getDefaultHub(network = "testnet") {
2270
2366
  const primary = getEffectivePrimaryHub();
2271
2367
  return CHAIN_PRESETS[primary][network];
2272
2368
  }
2273
- var CHAIN_NAMES, CHAIN_PRESETS;
2369
+ var CHAIN_NAMES, CHAIN_PRESETS, _rpcOverrides;
2274
2370
  var init_presets = __esm({
2275
2371
  "src/presets.ts"() {
2276
2372
  "use strict";
@@ -2930,7 +3026,7 @@ var init_presets = __esm({
2930
3026
  chainId: 0,
2931
3027
  wormholeChainId: 50001,
2932
3028
  // Custom bridge (non-Wormhole)
2933
- rpcUrl: "https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/tsOnfTBZDKMXcUA26OED-",
3029
+ rpcUrl: "https://starknet-sepolia-rpc.publicnode.com",
2934
3030
  explorerUrl: "https://sepolia.starkscan.co",
2935
3031
  isEvm: false,
2936
3032
  contracts: {
@@ -3029,6 +3125,7 @@ var init_presets = __esm({
3029
3125
  }
3030
3126
  }
3031
3127
  };
3128
+ _rpcOverrides = {};
3032
3129
  }
3033
3130
  });
3034
3131
 
@@ -4143,6 +4240,7 @@ __export(src_exports, {
4143
4240
  calculatePercentage: () => calculatePercentage,
4144
4241
  computeKeyHash: () => computeKeyHash,
4145
4242
  computeSessionKeyHash: () => computeSessionKeyHash,
4243
+ configureDefaultRpcUrls: () => configureDefaultRpcUrls,
4146
4244
  createAuditEntry: () => createAuditEntry,
4147
4245
  createChainClient: () => createChainClient,
4148
4246
  createChainDetector: () => createChainDetector,
@@ -4213,6 +4311,7 @@ __export(src_exports, {
4213
4311
  getExplorerUrl: () => getExplorerUrl,
4214
4312
  getFeatureFlags: () => getFeatureFlags,
4215
4313
  getHubChains: () => getHubChains,
4314
+ getRpcUrlOverride: () => getRpcUrlOverride,
4216
4315
  getSequenceFromTxReceipt: () => getSequenceFromTxReceipt,
4217
4316
  getStacksContractPrincipal: () => getContractPrincipal,
4218
4317
  getStacksExplorerAddressUrl: () => getStacksExplorerAddressUrl,
@@ -5507,6 +5606,7 @@ var CrossChainManager = class {
5507
5606
  var crossChainManager = new CrossChainManager();
5508
5607
 
5509
5608
  // src/core/RelayerClient.ts
5609
+ init_relayerUrl();
5510
5610
  var DEFAULT_CONFIG2 = {
5511
5611
  apiKey: "",
5512
5612
  timeoutMs: 3e4,
@@ -5516,7 +5616,7 @@ var RelayerClient = class _RelayerClient {
5516
5616
  baseUrl;
5517
5617
  config;
5518
5618
  constructor(config) {
5519
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
5619
+ this.baseUrl = normalizeRelayerOrigin(config.baseUrl);
5520
5620
  this.config = { ...DEFAULT_CONFIG2, ...config };
5521
5621
  }
5522
5622
  // ========================================================================
@@ -5783,6 +5883,7 @@ var RelayerClient = class _RelayerClient {
5783
5883
  * Make an HTTP request to the relayer
5784
5884
  */
5785
5885
  async fetch(path, options = {}) {
5886
+ const resolvedUrl = path.startsWith("/api/v1/") ? buildRelayerApiUrl(this.baseUrl, path.replace(/^\/api\/v1/, "")) : `${this.baseUrl}${path}`;
5786
5887
  const headers = {
5787
5888
  "Content-Type": "application/json",
5788
5889
  "User-Agent": `@veridex/sdk/${_RelayerClient.SDK_VERSION}`,
@@ -5796,7 +5897,7 @@ var RelayerClient = class _RelayerClient {
5796
5897
  let lastError = null;
5797
5898
  for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
5798
5899
  try {
5799
- const response = await fetch(`${this.baseUrl}${path}`, {
5900
+ const response = await fetch(resolvedUrl, {
5800
5901
  ...options,
5801
5902
  headers,
5802
5903
  signal: controller.signal
@@ -12654,7 +12755,9 @@ var ERC20_ABI2 = [
12654
12755
  var HUB_ABI2 = [
12655
12756
  "function dispatch(tuple(bytes authenticatorData, string clientDataJSON, uint256 challengeIndex, uint256 typeIndex, uint256 r, uint256 s) signature, uint256 publicKeyX, uint256 publicKeyY, uint16 targetChain, bytes actionPayload, uint256 nonce) payable returns (uint64 sequence)",
12656
12757
  "function userNonces(bytes32 userKeyHash) view returns (uint256)",
12657
- "function getMessageFee() view returns (uint256)",
12758
+ // Hub exposes the Wormhole core bridge address; message fee is read from the
12759
+ // bridge directly (getMessageFee() was removed from the Hub).
12760
+ "function wormhole() view returns (address)",
12658
12761
  "function getVaultAddress(bytes32 userKeyHash) view returns (address)",
12659
12762
  "function vaultExists(bytes32 userKeyHash) view returns (bool)",
12660
12763
  "function createVault(bytes32 userKeyHash) returns (address)",
@@ -12711,6 +12814,8 @@ var EVMClient = class {
12711
12814
  hubContract;
12712
12815
  factoryContract = null;
12713
12816
  cachedImplementation = null;
12817
+ cachedWormholeAddress = null;
12818
+ cachedMessageFee = null;
12714
12819
  constructor(config) {
12715
12820
  this.config = {
12716
12821
  name: config.name ?? `EVM Chain ${config.chainId}`,
@@ -12883,8 +12988,24 @@ var EVMClient = class {
12883
12988
  return Number(count);
12884
12989
  }
12885
12990
  async getMessageFee() {
12886
- const fee = await this.hubContract.getMessageFee();
12887
- return BigInt(fee.toString());
12991
+ const now = Date.now();
12992
+ if (this.cachedMessageFee && this.cachedMessageFee.expiresAt > now) {
12993
+ return this.cachedMessageFee.value;
12994
+ }
12995
+ let wormholeAddress = this.config.contracts.wormholeCoreBridge ?? this.cachedWormholeAddress;
12996
+ if (!wormholeAddress) {
12997
+ wormholeAddress = await this.hubContract.wormhole();
12998
+ this.cachedWormholeAddress = wormholeAddress;
12999
+ }
13000
+ const wormhole = new import_ethers16.ethers.Contract(
13001
+ wormholeAddress,
13002
+ ["function messageFee() view returns (uint256)"],
13003
+ this.provider
13004
+ );
13005
+ const fee = await wormhole.messageFee();
13006
+ const value = BigInt(fee.toString());
13007
+ this.cachedMessageFee = { value, expiresAt: now + 3e4 };
13008
+ return value;
12888
13009
  }
12889
13010
  async buildTransferPayload(params) {
12890
13011
  return encodeTransferAction(
@@ -12983,13 +13104,41 @@ var EVMClient = class {
12983
13104
  actionPayload,
12984
13105
  nonce: Number(nonce)
12985
13106
  };
12986
- const response = await fetch(`${relayerUrl}/api/v1/submit`, {
12987
- method: "POST",
12988
- headers: {
12989
- "Content-Type": "application/json"
12990
- },
12991
- body: JSON.stringify(request)
12992
- });
13107
+ const MAX_ATTEMPTS = 3;
13108
+ const baseDelayMs = 1e3;
13109
+ const sleep5 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
13110
+ let response;
13111
+ let lastError;
13112
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
13113
+ try {
13114
+ response = await fetch(`${relayerUrl}/api/v1/submit`, {
13115
+ method: "POST",
13116
+ headers: {
13117
+ "Content-Type": "application/json"
13118
+ },
13119
+ body: JSON.stringify(request)
13120
+ });
13121
+ const retryable = response.status >= 500 || response.status === 408 || response.status === 429;
13122
+ if (!retryable) {
13123
+ break;
13124
+ }
13125
+ if (attempt === MAX_ATTEMPTS) break;
13126
+ const retryAfter = response.headers.get("retry-after");
13127
+ const explicitDelay = retryAfter ? parseInt(retryAfter, 10) * 1e3 : 0;
13128
+ const backoff = explicitDelay > 0 ? explicitDelay : baseDelayMs * 2 ** (attempt - 1) + Math.floor(Math.random() * 200);
13129
+ await sleep5(backoff);
13130
+ } catch (err) {
13131
+ lastError = err;
13132
+ if (attempt === MAX_ATTEMPTS) break;
13133
+ const backoff = baseDelayMs * 2 ** (attempt - 1) + Math.floor(Math.random() * 200);
13134
+ await sleep5(backoff);
13135
+ }
13136
+ }
13137
+ if (!response) {
13138
+ throw new Error(
13139
+ `Relayer submission failed after ${MAX_ATTEMPTS} attempts: ${lastError instanceof Error ? lastError.message : String(lastError)}`
13140
+ );
13141
+ }
12993
13142
  if (!response.ok) {
12994
13143
  const error = await response.json().catch(() => ({ error: response.statusText }));
12995
13144
  throw new Error(`Relayer submission failed: ${error.error || response.statusText}`);
@@ -13820,7 +13969,7 @@ var EVMClient = class {
13820
13969
  async executeTransactionProposal(proposalId, signer) {
13821
13970
  const s = signer;
13822
13971
  const hub = this.hubContract.connect(s);
13823
- const fee = await this.hubContract.getMessageFee();
13972
+ const fee = await this.getMessageFee();
13824
13973
  const tx = await hub.executeTransactionProposal(proposalId, { value: fee });
13825
13974
  const receipt = await tx.wait();
13826
13975
  const sequence = this._extractSequenceFromReceipt(receipt);
@@ -15369,13 +15518,14 @@ function inferBackupEligibility(platform) {
15369
15518
  }
15370
15519
 
15371
15520
  // src/core/CredentialManager.ts
15521
+ init_relayerUrl();
15372
15522
  var DEFAULT_STORAGE_KEY = "veridex_credential_metadata";
15373
15523
  var CredentialManager = class {
15374
15524
  config;
15375
15525
  constructor(config = {}) {
15376
15526
  this.config = {
15377
15527
  storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
15378
- relayerUrl: config.relayerUrl ?? ""
15528
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
15379
15529
  };
15380
15530
  }
15381
15531
  // ========================================================================
@@ -15523,7 +15673,7 @@ var CredentialManager = class {
15523
15673
  const managed = this.getCredential(credentialId);
15524
15674
  if (!managed) return false;
15525
15675
  try {
15526
- const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {
15676
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential/metadata"), {
15527
15677
  method: "PUT",
15528
15678
  headers: { "Content-Type": "application/json" },
15529
15679
  body: JSON.stringify({
@@ -15549,7 +15699,10 @@ var CredentialManager = class {
15549
15699
  if (!this.config.relayerUrl) return null;
15550
15700
  try {
15551
15701
  const response = await fetch(
15552
- `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
15702
+ buildRelayerApiUrl(
15703
+ this.config.relayerUrl,
15704
+ `/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
15705
+ )
15553
15706
  );
15554
15707
  if (!response.ok) return null;
15555
15708
  const data = await response.json();
@@ -15671,9 +15824,10 @@ var CredentialManager = class {
15671
15824
 
15672
15825
  // src/core/CrossOriginAuth.ts
15673
15826
  init_PasskeyManager();
15827
+ init_relayerUrl();
15674
15828
  init_PasskeyManager();
15675
15829
  var DEFAULT_AUTH_PORTAL_URL = "https://auth.veridex.network";
15676
- var DEFAULT_RELAYER_URL = "https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1";
15830
+ var DEFAULT_RELAYER_URL = "https://relayer.veridex.network";
15677
15831
  var AUTH_MESSAGE_TYPES = {
15678
15832
  AUTH_REQUEST: "VERIDEX_AUTH_REQUEST",
15679
15833
  AUTH_RESPONSE: "VERIDEX_AUTH_RESPONSE",
@@ -15685,7 +15839,7 @@ var CrossOriginAuth = class {
15685
15839
  this.config = {
15686
15840
  rpId: config.rpId ?? VERIDEX_RP_ID,
15687
15841
  authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,
15688
- relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,
15842
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? DEFAULT_RELAYER_URL),
15689
15843
  mode: config.mode ?? "popup",
15690
15844
  popupFeatures: config.popupFeatures ?? "width=500,height=600,left=100,top=100",
15691
15845
  timeout: config.timeout ?? 12e4,
@@ -15902,7 +16056,8 @@ var CrossOriginAuth = class {
15902
16056
  return bytes;
15903
16057
  }
15904
16058
  async requestServerSessionChallenge(options) {
15905
- const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {
16059
+ const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
16060
+ const response = await fetch(challengeUrl, {
15906
16061
  method: "POST",
15907
16062
  headers: { "Content-Type": "application/json" },
15908
16063
  body: JSON.stringify({
@@ -15948,7 +16103,7 @@ var CrossOriginAuth = class {
15948
16103
  if (!session.serverChallengeId) {
15949
16104
  throw new Error("Session must include a relayer-issued serverChallengeId");
15950
16105
  }
15951
- const response = await fetch(`${this.config.relayerUrl}/session/create`, {
16106
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
15952
16107
  method: "POST",
15953
16108
  headers: { "Content-Type": "application/json" },
15954
16109
  body: JSON.stringify({
@@ -15971,7 +16126,9 @@ var CrossOriginAuth = class {
15971
16126
  * Returns the session details if valid, null if expired/revoked.
15972
16127
  */
15973
16128
  async validateServerSession(sessionId) {
15974
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);
16129
+ const response = await fetch(
16130
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
16131
+ );
15975
16132
  if (!response.ok) {
15976
16133
  return null;
15977
16134
  }
@@ -15985,9 +16142,12 @@ var CrossOriginAuth = class {
15985
16142
  * Revoke a server session token.
15986
16143
  */
15987
16144
  async revokeServerSession(sessionId) {
15988
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {
15989
- method: "DELETE"
15990
- });
16145
+ const response = await fetch(
16146
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
16147
+ {
16148
+ method: "DELETE"
16149
+ }
16150
+ );
15991
16151
  return response.ok;
15992
16152
  }
15993
16153
  /**
@@ -16439,6 +16599,12 @@ function validateSessionConfig(config) {
16439
16599
  "INVALID_CONFIG" /* INVALID_CONFIG */
16440
16600
  );
16441
16601
  }
16602
+ if (config.maxValue === 0n && config.allowUnboundedMaxValue !== true) {
16603
+ throw new SessionError(
16604
+ 'Session maxValue=0 means "no per-tx limit" \u2014 the vault daily cap is then the only bound. This is a foot-gun: a compromised session key can drain the vault up to that cap. Pass a non-zero maxValue, or set allowUnboundedMaxValue:true if you have verified the vault daily cap and accept the residual risk.',
16605
+ "INVALID_CONFIG" /* INVALID_CONFIG */
16606
+ );
16607
+ }
16442
16608
  }
16443
16609
 
16444
16610
  // src/sessions/storage.ts
@@ -16547,39 +16713,44 @@ var IndexedDBSessionStorage = class {
16547
16713
  );
16548
16714
  }
16549
16715
  }
16716
+ async decryptSession(stored) {
16717
+ const key = await this.getEncryptionKey();
16718
+ const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
16719
+ const privateKey = await decrypt(encryptedPrivateKey, key);
16720
+ return {
16721
+ keyHash: stored.keyHash,
16722
+ publicKey: new Uint8Array(stored.publicKey),
16723
+ privateKey,
16724
+ expiry: stored.expiry,
16725
+ maxValue: BigInt(stored.maxValue),
16726
+ chainScopes: stored.chainScopes ?? [],
16727
+ userKeyHash: stored.userKeyHash
16728
+ };
16729
+ }
16730
+ async pruneExpiredSessions(records) {
16731
+ const now = Date.now();
16732
+ const validRecords = records.filter((record) => record.expiry > now);
16733
+ const expiredRecords = records.filter((record) => record.expiry <= now);
16734
+ if (expiredRecords.length > 0) {
16735
+ await Promise.all(expiredRecords.map((record) => this.remove(record.keyHash)));
16736
+ }
16737
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
16738
+ }
16550
16739
  /**
16551
- * Load the active session (decrypts private key)
16740
+ * Load a session (decrypts private key)
16552
16741
  */
16553
- async load() {
16742
+ async load(keyHash) {
16554
16743
  try {
16555
16744
  await this.initialize();
16556
16745
  if (!this.db) {
16557
16746
  throw new Error("Database not initialized");
16558
16747
  }
16559
- const allSessions = await this.getAllSessions();
16560
- if (allSessions.length === 0) {
16561
- return null;
16562
- }
16563
- const now = Date.now();
16564
- const validSessions = allSessions.filter((s) => s.expiry > now).sort((a, b) => b.savedAt - a.savedAt);
16748
+ const sessions = keyHash ? await this.getSessionByKeyHash(keyHash) : await this.getAllSessions();
16749
+ const validSessions = await this.pruneExpiredSessions(sessions);
16565
16750
  if (validSessions.length === 0) {
16566
- await this.clear();
16567
16751
  return null;
16568
16752
  }
16569
- const stored = validSessions[0];
16570
- const key = await this.getEncryptionKey();
16571
- const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
16572
- const privateKey = await decrypt(encryptedPrivateKey, key);
16573
- const session = {
16574
- keyHash: stored.keyHash,
16575
- publicKey: new Uint8Array(stored.publicKey),
16576
- privateKey,
16577
- expiry: stored.expiry,
16578
- maxValue: BigInt(stored.maxValue),
16579
- chainScopes: stored.chainScopes,
16580
- userKeyHash: stored.userKeyHash
16581
- };
16582
- return session;
16753
+ return this.decryptSession(validSessions[0]);
16583
16754
  } catch (error) {
16584
16755
  if (error instanceof SessionError) {
16585
16756
  throw error;
@@ -16612,6 +16783,75 @@ var IndexedDBSessionStorage = class {
16612
16783
  };
16613
16784
  });
16614
16785
  }
16786
+ async getSessionByKeyHash(keyHash) {
16787
+ if (!this.db) {
16788
+ return [];
16789
+ }
16790
+ return new Promise((resolve, reject) => {
16791
+ const transaction = this.db.transaction([STORE_NAME], "readonly");
16792
+ const store = transaction.objectStore(STORE_NAME);
16793
+ const request = store.get(keyHash);
16794
+ request.onsuccess = () => {
16795
+ resolve(request.result ? [request.result] : []);
16796
+ };
16797
+ request.onerror = () => {
16798
+ reject(new SessionError(
16799
+ "Failed to get session",
16800
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16801
+ request.error
16802
+ ));
16803
+ };
16804
+ });
16805
+ }
16806
+ async loadAll() {
16807
+ try {
16808
+ await this.initialize();
16809
+ if (!this.db) {
16810
+ return [];
16811
+ }
16812
+ const records = await this.pruneExpiredSessions(await this.getAllSessions());
16813
+ return Promise.all(records.map((record) => this.decryptSession(record)));
16814
+ } catch (error) {
16815
+ if (error instanceof SessionError) {
16816
+ throw error;
16817
+ }
16818
+ throw new SessionError(
16819
+ "Failed to load sessions",
16820
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16821
+ error
16822
+ );
16823
+ }
16824
+ }
16825
+ async remove(keyHash) {
16826
+ try {
16827
+ await this.initialize();
16828
+ if (!this.db) {
16829
+ return;
16830
+ }
16831
+ return new Promise((resolve, reject) => {
16832
+ const transaction = this.db.transaction([STORE_NAME], "readwrite");
16833
+ const store = transaction.objectStore(STORE_NAME);
16834
+ const request = store.delete(keyHash);
16835
+ request.onsuccess = () => resolve();
16836
+ request.onerror = () => {
16837
+ reject(new SessionError(
16838
+ "Failed to remove session",
16839
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16840
+ request.error
16841
+ ));
16842
+ };
16843
+ });
16844
+ } catch (error) {
16845
+ if (error instanceof SessionError) {
16846
+ throw error;
16847
+ }
16848
+ throw new SessionError(
16849
+ "Failed to remove session",
16850
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16851
+ error
16852
+ );
16853
+ }
16854
+ }
16615
16855
  /**
16616
16856
  * Clear all sessions
16617
16857
  */
@@ -16648,14 +16888,9 @@ var IndexedDBSessionStorage = class {
16648
16888
  /**
16649
16889
  * Check if any session exists
16650
16890
  */
16651
- async exists() {
16891
+ async exists(keyHash) {
16652
16892
  try {
16653
- await this.initialize();
16654
- if (!this.db) {
16655
- return false;
16656
- }
16657
- const sessions = await this.getAllSessions();
16658
- return sessions.length > 0;
16893
+ return await this.load(keyHash) !== null;
16659
16894
  } catch {
16660
16895
  return false;
16661
16896
  }
@@ -16674,7 +16909,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
16674
16909
  var LocalStorageSessionStorage = class {
16675
16910
  encryptionKey = null;
16676
16911
  credentialId;
16677
- storageKey;
16912
+ credentialHash;
16913
+ legacyStorageKey;
16678
16914
  /**
16679
16915
  * @param credentialId User's Passkey credential ID (for key derivation)
16680
16916
  */
@@ -16686,7 +16922,60 @@ var LocalStorageSessionStorage = class {
16686
16922
  );
16687
16923
  }
16688
16924
  this.credentialId = credentialId;
16689
- this.storageKey = STORAGE_KEY_PREFIX + import_ethers20.ethers.keccak256(import_ethers20.ethers.toUtf8Bytes(credentialId));
16925
+ this.credentialHash = import_ethers20.ethers.keccak256(import_ethers20.ethers.toUtf8Bytes(credentialId));
16926
+ this.legacyStorageKey = STORAGE_KEY_PREFIX + this.credentialHash;
16927
+ }
16928
+ getSessionStorageKey(keyHash) {
16929
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:${keyHash}`;
16930
+ }
16931
+ getSessionStoragePrefix() {
16932
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:`;
16933
+ }
16934
+ async deserializeSession(stored) {
16935
+ const key = await this.getEncryptionKey();
16936
+ const encryptedPrivateKey = typeof stored.encryptedPrivateKey === "string" ? import_ethers20.ethers.getBytes(stored.encryptedPrivateKey) : new Uint8Array(stored.encryptedPrivateKey);
16937
+ const privateKey = await decrypt(encryptedPrivateKey, key);
16938
+ return {
16939
+ keyHash: stored.keyHash,
16940
+ publicKey: typeof stored.publicKey === "string" ? import_ethers20.ethers.getBytes(stored.publicKey) : new Uint8Array(stored.publicKey),
16941
+ privateKey,
16942
+ expiry: stored.expiry,
16943
+ maxValue: BigInt(stored.maxValue),
16944
+ chainScopes: stored.chainScopes ?? [],
16945
+ userKeyHash: stored.userKeyHash
16946
+ };
16947
+ }
16948
+ getRawRecords() {
16949
+ const records = [];
16950
+ const prefix = this.getSessionStoragePrefix();
16951
+ for (let index = 0; index < localStorage.length; index++) {
16952
+ const key = localStorage.key(index);
16953
+ if (!key || !key.startsWith(prefix)) {
16954
+ continue;
16955
+ }
16956
+ const value = localStorage.getItem(key);
16957
+ if (!value) {
16958
+ continue;
16959
+ }
16960
+ records.push(JSON.parse(value));
16961
+ }
16962
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
16963
+ if (legacyValue) {
16964
+ records.push(JSON.parse(legacyValue));
16965
+ }
16966
+ return records;
16967
+ }
16968
+ async getValidRecords() {
16969
+ const now = Date.now();
16970
+ const validRecords = [];
16971
+ for (const record of this.getRawRecords()) {
16972
+ if (record.expiry <= now) {
16973
+ await this.remove(record.keyHash);
16974
+ continue;
16975
+ }
16976
+ validRecords.push(record);
16977
+ }
16978
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
16690
16979
  }
16691
16980
  /**
16692
16981
  * Get or derive encryption key
@@ -16715,7 +17004,7 @@ var LocalStorageSessionStorage = class {
16715
17004
  userKeyHash: session.userKeyHash,
16716
17005
  savedAt: Date.now()
16717
17006
  };
16718
- localStorage.setItem(this.storageKey, JSON.stringify(storageObject));
17007
+ localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
16719
17008
  } catch (error) {
16720
17009
  if (error instanceof SessionError) {
16721
17010
  throw error;
@@ -16728,32 +17017,15 @@ var LocalStorageSessionStorage = class {
16728
17017
  }
16729
17018
  }
16730
17019
  /**
16731
- * Load the active session (decrypts private key)
17020
+ * Load a session (decrypts private key)
16732
17021
  */
16733
- async load() {
17022
+ async load(keyHash) {
16734
17023
  try {
16735
- const data = localStorage.getItem(this.storageKey);
16736
- if (!data) {
16737
- return null;
16738
- }
16739
- const stored = JSON.parse(data);
16740
- if (stored.expiry <= Date.now()) {
16741
- await this.clear();
17024
+ const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
17025
+ if (records.length === 0) {
16742
17026
  return null;
16743
17027
  }
16744
- const key = await this.getEncryptionKey();
16745
- const encryptedPrivateKey = import_ethers20.ethers.getBytes(stored.encryptedPrivateKey);
16746
- const privateKey = await decrypt(encryptedPrivateKey, key);
16747
- const session = {
16748
- keyHash: stored.keyHash,
16749
- publicKey: import_ethers20.ethers.getBytes(stored.publicKey),
16750
- privateKey,
16751
- expiry: stored.expiry,
16752
- maxValue: BigInt(stored.maxValue),
16753
- chainScopes: stored.chainScopes,
16754
- userKeyHash: stored.userKeyHash
16755
- };
16756
- return session;
17028
+ return this.deserializeSession(records[0]);
16757
17029
  } catch (error) {
16758
17030
  await this.clear();
16759
17031
  if (error instanceof SessionError) {
@@ -16766,12 +17038,55 @@ var LocalStorageSessionStorage = class {
16766
17038
  );
16767
17039
  }
16768
17040
  }
17041
+ async loadAll() {
17042
+ try {
17043
+ const records = await this.getValidRecords();
17044
+ return Promise.all(records.map((record) => this.deserializeSession(record)));
17045
+ } catch (error) {
17046
+ await this.clear();
17047
+ if (error instanceof SessionError) {
17048
+ throw error;
17049
+ }
17050
+ throw new SessionError(
17051
+ "Failed to load sessions",
17052
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
17053
+ error
17054
+ );
17055
+ }
17056
+ }
17057
+ async remove(keyHash) {
17058
+ try {
17059
+ localStorage.removeItem(this.getSessionStorageKey(keyHash));
17060
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
17061
+ if (legacyValue) {
17062
+ const legacyRecord = JSON.parse(legacyValue);
17063
+ if (legacyRecord.keyHash === keyHash) {
17064
+ localStorage.removeItem(this.legacyStorageKey);
17065
+ }
17066
+ }
17067
+ } catch (error) {
17068
+ throw new SessionError(
17069
+ "Failed to remove session",
17070
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
17071
+ error
17072
+ );
17073
+ }
17074
+ }
16769
17075
  /**
16770
17076
  * Clear all sessions
16771
17077
  */
16772
17078
  async clear() {
16773
17079
  try {
16774
- localStorage.removeItem(this.storageKey);
17080
+ const keysToRemove = [];
17081
+ const prefix = this.getSessionStoragePrefix();
17082
+ for (let index = 0; index < localStorage.length; index++) {
17083
+ const key = localStorage.key(index);
17084
+ if (key && key.startsWith(prefix)) {
17085
+ keysToRemove.push(key);
17086
+ }
17087
+ }
17088
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
17089
+ localStorage.removeItem(this.legacyStorageKey);
16775
17090
  } catch (error) {
16776
17091
  throw new SessionError(
16777
17092
  "Failed to clear sessions",
@@ -16783,9 +17098,9 @@ var LocalStorageSessionStorage = class {
16783
17098
  /**
16784
17099
  * Check if any session exists
16785
17100
  */
16786
- async exists() {
17101
+ async exists(keyHash) {
16787
17102
  try {
16788
- return localStorage.getItem(this.storageKey) !== null;
17103
+ return await this.load(keyHash) !== null;
16789
17104
  } catch {
16790
17105
  return false;
16791
17106
  }
@@ -16835,7 +17150,8 @@ var SessionManager = class {
16835
17150
  maxValue: config.maxValue ?? 0n,
16836
17151
  autoRefresh: config.autoRefresh ?? true,
16837
17152
  refreshBuffer: config.refreshBuffer ?? DEFAULT_REFRESH_BUFFER,
16838
- chainScopes: config.chainScopes ?? []
17153
+ chainScopes: config.chainScopes ?? [],
17154
+ allowUnboundedMaxValue: config.allowUnboundedMaxValue ?? false
16839
17155
  };
16840
17156
  validateSessionConfig(this.config);
16841
17157
  this.debug = managerConfig?.debug ?? false;
@@ -16850,6 +17166,14 @@ var SessionManager = class {
16850
17166
  refreshTimer = null;
16851
17167
  eventCallbacks = [];
16852
17168
  debug;
17169
+ resolveConfig(configOverride) {
17170
+ const resolvedConfig = {
17171
+ ...this.config,
17172
+ ...configOverride
17173
+ };
17174
+ validateSessionConfig(resolvedConfig);
17175
+ return resolvedConfig;
17176
+ }
16853
17177
  // ========================================================================
16854
17178
  // Session Lifecycle
16855
17179
  // ========================================================================
@@ -16866,15 +17190,16 @@ var SessionManager = class {
16866
17190
  * @returns Created session key
16867
17191
  * @throws SessionError if registration fails
16868
17192
  */
16869
- async createSession() {
17193
+ async createSession(configOverride) {
16870
17194
  try {
16871
17195
  this.log("Creating new session...");
17196
+ const sessionConfig = this.resolveConfig(configOverride);
16872
17197
  const keyPair = generateSecp256k1KeyPair();
16873
17198
  const keyHash = computeSessionKeyHash(keyPair.publicKey);
16874
17199
  this.log("Generated session key:", keyHash);
16875
17200
  const challenge = import_ethers21.ethers.solidityPacked(
16876
17201
  ["string", "bytes32", "uint256", "uint256"],
16877
- ["registerSession", keyHash, this.config.duration, this.config.maxValue]
17202
+ ["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
16878
17203
  );
16879
17204
  this.log("Challenge prepared, requesting Passkey signature...");
16880
17205
  const signature = await this.passkeySign(import_ethers21.ethers.getBytes(challenge));
@@ -16884,20 +17209,20 @@ var SessionManager = class {
16884
17209
  publicKeyX: this.credential.publicKeyX,
16885
17210
  publicKeyY: this.credential.publicKeyY,
16886
17211
  sessionKeyHash: keyHash,
16887
- duration: this.config.duration,
16888
- maxValue: this.config.maxValue,
17212
+ duration: sessionConfig.duration,
17213
+ maxValue: sessionConfig.maxValue,
16889
17214
  requireUV: true
16890
17215
  };
16891
17216
  await this.hubClient.registerSession(registerParams);
16892
17217
  this.log("Session registered on Hub");
16893
- const expiry = Date.now() + this.config.duration * 1e3;
17218
+ const expiry = Date.now() + sessionConfig.duration * 1e3;
16894
17219
  this.currentSession = {
16895
17220
  publicKey: keyPair.publicKey,
16896
17221
  privateKey: keyPair.privateKey,
16897
17222
  keyHash,
16898
17223
  expiry,
16899
- maxValue: this.config.maxValue,
16900
- chainScopes: this.config.chainScopes,
17224
+ maxValue: sessionConfig.maxValue,
17225
+ chainScopes: sessionConfig.chainScopes,
16901
17226
  userKeyHash: this.credential.keyHash
16902
17227
  };
16903
17228
  await this.storage.save(this.currentSession);
@@ -16922,12 +17247,15 @@ var SessionManager = class {
16922
17247
  *
16923
17248
  * @returns Loaded session or null if no valid session exists
16924
17249
  */
16925
- async loadSession() {
17250
+ async loadSession(keyHash) {
16926
17251
  try {
16927
- this.log("Loading session from storage...");
16928
- const session = await this.storage.load();
17252
+ this.log("Loading session from storage...", keyHash ?? "latest");
17253
+ const session = await this.storage.load(keyHash);
16929
17254
  if (!session) {
16930
17255
  this.log("No session found in storage");
17256
+ if (!keyHash) {
17257
+ this.currentSession = null;
17258
+ }
16931
17259
  return null;
16932
17260
  }
16933
17261
  if (session.expiry <= Date.now()) {
@@ -16944,27 +17272,43 @@ var SessionManager = class {
16944
17272
  return session;
16945
17273
  } catch (error) {
16946
17274
  this.log("Failed to load session:", error);
16947
- await this.storage.clear();
17275
+ if (!keyHash) {
17276
+ await this.storage.clear();
17277
+ }
16948
17278
  return null;
16949
17279
  }
16950
17280
  }
17281
+ async listSessions() {
17282
+ return this.storage.loadAll();
17283
+ }
17284
+ async selectSession(keyHash) {
17285
+ const session = await this.loadSession(keyHash);
17286
+ if (!session) {
17287
+ throw new SessionError(
17288
+ `Session ${keyHash} not found`,
17289
+ "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */
17290
+ );
17291
+ }
17292
+ return session;
17293
+ }
16951
17294
  /**
16952
17295
  * Revoke the current session (requires biometric authentication)
16953
17296
  *
16954
17297
  * @throws SessionError if no active session or revocation fails
16955
17298
  */
16956
- async revokeSession() {
16957
- if (!this.currentSession) {
17299
+ async revokeSession(keyHash) {
17300
+ const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
17301
+ if (!targetSession) {
16958
17302
  throw new SessionError(
16959
- "No active session to revoke",
16960
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17303
+ keyHash ? `Session ${keyHash} not found` : "No active session to revoke",
17304
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
16961
17305
  );
16962
17306
  }
16963
17307
  try {
16964
- this.log("Revoking session:", this.currentSession.keyHash);
17308
+ this.log("Revoking session:", targetSession.keyHash);
16965
17309
  const challenge = import_ethers21.ethers.solidityPacked(
16966
17310
  ["string", "bytes32"],
16967
- ["revokeSession", this.currentSession.keyHash]
17311
+ ["revokeSession", targetSession.keyHash]
16968
17312
  );
16969
17313
  const signature = await this.passkeySign(import_ethers21.ethers.getBytes(challenge));
16970
17314
  this.log("Passkey signature obtained, revoking on Hub...");
@@ -16972,18 +17316,24 @@ var SessionManager = class {
16972
17316
  signature,
16973
17317
  publicKeyX: this.credential.publicKeyX,
16974
17318
  publicKeyY: this.credential.publicKeyY,
16975
- sessionKeyHash: this.currentSession.keyHash,
17319
+ sessionKeyHash: targetSession.keyHash,
16976
17320
  requireUV: true
16977
17321
  };
16978
17322
  await this.hubClient.revokeSession(revokeParams);
16979
17323
  this.log("Session revoked on Hub");
16980
- await this.storage.clear();
16981
- if (this.refreshTimer) {
16982
- clearTimeout(this.refreshTimer);
16983
- this.refreshTimer = null;
17324
+ await this.storage.remove(targetSession.keyHash);
17325
+ const revokedKeyHash = targetSession.keyHash;
17326
+ const revokedCurrentSession = this.currentSession?.keyHash === revokedKeyHash;
17327
+ if (revokedCurrentSession) {
17328
+ if (this.refreshTimer) {
17329
+ clearTimeout(this.refreshTimer);
17330
+ this.refreshTimer = null;
17331
+ }
17332
+ this.currentSession = await this.storage.load();
17333
+ if (this.currentSession && this.config.autoRefresh) {
17334
+ this.scheduleRefresh();
17335
+ }
16984
17336
  }
16985
- const revokedKeyHash = this.currentSession.keyHash;
16986
- this.currentSession = null;
16987
17337
  this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
16988
17338
  this.log("Session revoked successfully");
16989
17339
  } catch (error) {
@@ -17061,45 +17411,46 @@ var SessionManager = class {
17061
17411
  * @returns Session signature
17062
17412
  * @throws SessionError if no active session, expired, or value exceeds limit
17063
17413
  */
17064
- async signWithSession(action) {
17065
- if (!this.currentSession) {
17414
+ async signWithSession(action, keyHash) {
17415
+ const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
17416
+ if (!session) {
17066
17417
  throw new SessionError(
17067
- "No active session available",
17068
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17418
+ keyHash ? `Session ${keyHash} not found` : "No active session available",
17419
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17069
17420
  );
17070
17421
  }
17071
17422
  const now = Date.now();
17072
- if (now >= this.currentSession.expiry) {
17073
- this.emit({ type: "session-expired", keyHash: this.currentSession.keyHash });
17423
+ if (now >= session.expiry) {
17424
+ this.emit({ type: "session-expired", keyHash: session.keyHash });
17074
17425
  throw new SessionError(
17075
17426
  "Session has expired",
17076
17427
  "SESSION_EXPIRED" /* SESSION_EXPIRED */
17077
17428
  );
17078
17429
  }
17079
- if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {
17430
+ if (session.maxValue > 0n && action.value > session.maxValue) {
17080
17431
  throw new SessionError(
17081
- `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,
17432
+ `Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
17082
17433
  "VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
17083
- { value: action.value, limit: this.currentSession.maxValue }
17434
+ { value: action.value, limit: session.maxValue }
17084
17435
  );
17085
17436
  }
17086
- if (this.currentSession.chainScopes.length > 0 && !this.currentSession.chainScopes.includes(action.targetChain)) {
17437
+ if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
17087
17438
  throw new SessionError(
17088
17439
  `Chain ${action.targetChain} not in session scope`,
17089
17440
  "CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
17090
- { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }
17441
+ { chain: action.targetChain, allowedChains: session.chainScopes }
17091
17442
  );
17092
17443
  }
17093
17444
  this.log("Signing action with session key...");
17094
17445
  const messageHash = hashAction(action);
17095
17446
  const { signature } = signWithSessionKey(
17096
- this.currentSession.privateKey,
17447
+ session.privateKey,
17097
17448
  messageHash
17098
17449
  );
17099
17450
  const sessionSignature = {
17100
17451
  signature,
17101
- sessionKeyHash: this.currentSession.keyHash,
17102
- userKeyHash: this.currentSession.userKeyHash,
17452
+ sessionKeyHash: session.keyHash,
17453
+ userKeyHash: session.userKeyHash,
17103
17454
  timestamp: now,
17104
17455
  nonce: action.nonce
17105
17456
  };
@@ -17112,8 +17463,8 @@ var SessionManager = class {
17112
17463
  * @param action Action parameters
17113
17464
  * @returns Session-signed action ready for submission
17114
17465
  */
17115
- async signAction(action) {
17116
- const signature = await this.signWithSession(action);
17466
+ async signAction(action, keyHash) {
17467
+ const signature = await this.signWithSession(action, keyHash);
17117
17468
  return {
17118
17469
  action,
17119
17470
  signature,
@@ -18097,6 +18448,7 @@ var VALIDATION_REGISTRY_ABI = [
18097
18448
  calculatePercentage,
18098
18449
  computeKeyHash,
18099
18450
  computeSessionKeyHash,
18451
+ configureDefaultRpcUrls,
18100
18452
  createAuditEntry,
18101
18453
  createChainClient,
18102
18454
  createChainDetector,
@@ -18166,6 +18518,7 @@ var VALIDATION_REGISTRY_ABI = [
18166
18518
  getExplorerUrl,
18167
18519
  getFeatureFlags,
18168
18520
  getHubChains,
18521
+ getRpcUrlOverride,
18169
18522
  getSequenceFromTxReceipt,
18170
18523
  getStacksContractPrincipal,
18171
18524
  getStacksExplorerAddressUrl,