@veridex/sdk 1.0.1 → 1.1.1

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 (87) hide show
  1. package/dist/auth/prepareAuth.js +107 -32
  2. package/dist/auth/prepareAuth.js.map +1 -1
  3. package/dist/auth/prepareAuth.mjs +6 -6
  4. package/dist/auth/prepareAuth.mjs.map +1 -1
  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.js.map +1 -1
  8. package/dist/chains/avalanche/index.mjs +4 -4
  9. package/dist/chains/evm/index.d.mts +2 -2
  10. package/dist/chains/evm/index.js.map +1 -1
  11. package/dist/chains/evm/index.mjs +3 -3
  12. package/dist/chains/solana/index.js.map +1 -1
  13. package/dist/chains/solana/index.mjs +3 -3
  14. package/dist/chains/stacks/index.d.mts +1 -1
  15. package/dist/chains/stacks/index.js.map +1 -1
  16. package/dist/chains/stacks/index.mjs +3 -3
  17. package/dist/chains/starknet/index.d.mts +2 -3
  18. package/dist/chains/starknet/index.js +1 -13
  19. package/dist/chains/starknet/index.js.map +1 -1
  20. package/dist/chains/starknet/index.mjs +3 -3
  21. package/dist/chains/sui/index.d.mts +3 -3
  22. package/dist/chains/sui/index.js +2 -2
  23. package/dist/chains/sui/index.js.map +1 -1
  24. package/dist/chains/sui/index.mjs +3 -3
  25. package/dist/{chunk-Q5O3M5LP.mjs → chunk-2TS375ET.mjs} +2 -2
  26. package/dist/{chunk-QT4ZZ4GM.mjs → chunk-5FDOTI5G.mjs} +2 -2
  27. package/dist/{chunk-5T6KPH7A.mjs → chunk-CSU4IV2F.mjs} +2 -2
  28. package/dist/{chunk-YCUJZ6Z7.mjs → chunk-CTYDGO6E.mjs} +63 -6
  29. package/dist/chunk-CTYDGO6E.mjs.map +1 -0
  30. package/dist/{chunk-PRHNGA4G.mjs → chunk-E3SU36C2.mjs} +4 -4
  31. package/dist/{chunk-PRHNGA4G.mjs.map → chunk-E3SU36C2.mjs.map} +1 -1
  32. package/dist/{chunk-NUWSMJFJ.mjs → chunk-EFIXFA6V.mjs} +2 -2
  33. package/dist/{chunk-EFIURACP.mjs → chunk-GM5DKEHD.mjs} +3 -15
  34. package/dist/chunk-GM5DKEHD.mjs.map +1 -0
  35. package/dist/{chunk-GWJRKDSA.mjs → chunk-GOWXQPTW.mjs} +3 -3
  36. package/dist/{chunk-OVMMTL6H.mjs → chunk-ICGB3AHI.mjs} +2 -2
  37. package/dist/{chunk-QDO6NQ7P.mjs → chunk-M3GUNREX.mjs} +20 -3
  38. package/dist/{chunk-QDO6NQ7P.mjs.map → chunk-M3GUNREX.mjs.map} +1 -1
  39. package/dist/{chunk-N4A2RMUN.mjs → chunk-PEGOXMBU.mjs} +2 -2
  40. package/dist/{chunk-X7BZMSPQ.mjs → chunk-RD6ZYUVG.mjs} +52 -30
  41. package/dist/chunk-RD6ZYUVG.mjs.map +1 -0
  42. package/dist/{chunk-F3YAGZSW.mjs → chunk-TPEP6XUA.mjs} +2 -2
  43. package/dist/{chunk-M3MM4YMF.mjs → chunk-UPO55SBK.mjs} +2 -2
  44. package/dist/{chunk-USDA5JTN.mjs → chunk-YBN2VC6E.mjs} +2 -2
  45. package/dist/{chunk-PDHZ5X5O.mjs → chunk-YYT3V7CI.mjs} +2 -2
  46. package/dist/constants.d.mts +2 -2
  47. package/dist/constants.js +51 -29
  48. package/dist/constants.js.map +1 -1
  49. package/dist/constants.mjs +1 -1
  50. package/dist/{index-DDalBhAm.d.mts → index-CySMITQ9.d.mts} +9 -6
  51. package/dist/index.d.mts +44 -13
  52. package/dist/index.js +466 -162
  53. package/dist/index.js.map +1 -1
  54. package/dist/index.mjs +345 -127
  55. package/dist/index.mjs.map +1 -1
  56. package/dist/passkey.js +57 -4
  57. package/dist/passkey.js.map +1 -1
  58. package/dist/passkey.mjs +3 -3
  59. package/dist/payload.js.map +1 -1
  60. package/dist/payload.mjs +2 -2
  61. package/dist/portfolio-JA4OTF7Y.mjs +13 -0
  62. package/dist/queries/index.js +49 -27
  63. package/dist/queries/index.js.map +1 -1
  64. package/dist/queries/index.mjs +5 -5
  65. package/dist/{types-B7V5VNbO.d.mts → types-DWx-5jmz.d.mts} +12 -3
  66. package/dist/utils.js +49 -27
  67. package/dist/utils.js.map +1 -1
  68. package/dist/utils.mjs +2 -2
  69. package/dist/wormhole.js.map +1 -1
  70. package/dist/wormhole.mjs +2 -2
  71. package/package.json +1 -1
  72. package/dist/chunk-EFIURACP.mjs.map +0 -1
  73. package/dist/chunk-X7BZMSPQ.mjs.map +0 -1
  74. package/dist/chunk-YCUJZ6Z7.mjs.map +0 -1
  75. package/dist/portfolio-V347KZOL.mjs +0 -13
  76. /package/dist/{chunk-Q5O3M5LP.mjs.map → chunk-2TS375ET.mjs.map} +0 -0
  77. /package/dist/{chunk-QT4ZZ4GM.mjs.map → chunk-5FDOTI5G.mjs.map} +0 -0
  78. /package/dist/{chunk-5T6KPH7A.mjs.map → chunk-CSU4IV2F.mjs.map} +0 -0
  79. /package/dist/{chunk-NUWSMJFJ.mjs.map → chunk-EFIXFA6V.mjs.map} +0 -0
  80. /package/dist/{chunk-GWJRKDSA.mjs.map → chunk-GOWXQPTW.mjs.map} +0 -0
  81. /package/dist/{chunk-OVMMTL6H.mjs.map → chunk-ICGB3AHI.mjs.map} +0 -0
  82. /package/dist/{chunk-N4A2RMUN.mjs.map → chunk-PEGOXMBU.mjs.map} +0 -0
  83. /package/dist/{chunk-F3YAGZSW.mjs.map → chunk-TPEP6XUA.mjs.map} +0 -0
  84. /package/dist/{chunk-M3MM4YMF.mjs.map → chunk-UPO55SBK.mjs.map} +0 -0
  85. /package/dist/{chunk-USDA5JTN.mjs.map → chunk-YBN2VC6E.mjs.map} +0 -0
  86. /package/dist/{chunk-PDHZ5X5O.mjs.map → chunk-YYT3V7CI.mjs.map} +0 -0
  87. /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
@@ -7090,7 +7191,7 @@ var SuiClient = class {
7090
7191
  * @param registryObjectId - Shared VaultRegistry object ID
7091
7192
  * @returns Vault object ID or null if not found
7092
7193
  */
7093
- async getVaultId(ownerKeyHash, registryObjectId) {
7194
+ async getVaultId(_ownerKeyHash, registryObjectId) {
7094
7195
  try {
7095
7196
  const registryObject = await this.client.getObject({
7096
7197
  id: registryObjectId,
@@ -7167,7 +7268,7 @@ var SuiClient = class {
7167
7268
  * @param processedVaasObjectId - ProcessedVAAs shared object ID
7168
7269
  * @returns Whether the VAA has been processed
7169
7270
  */
7170
- async isVaaProcessed(vaaHash, processedVaasObjectId) {
7271
+ async isVaaProcessed(_vaaHash, processedVaasObjectId) {
7171
7272
  try {
7172
7273
  const processedObject = await this.client.getObject({
7173
7274
  id: processedVaasObjectId,
@@ -7211,7 +7312,6 @@ var SuiClient = class {
7211
7312
  var import_crypto3 = require("crypto");
7212
7313
  var import_starknet = require("starknet");
7213
7314
  init_payload();
7214
- var FELT252_MAX = BigInt("0x0800000000000000000000000000000000000000000000000000000000000000") - 1n;
7215
7315
  var U128_MAX = BigInt("0x100000000000000000000000000000000");
7216
7316
  function toStarknetU256(keyHash) {
7217
7317
  const cleanHash = keyHash.replace("0x", "").padStart(64, "0");
@@ -7454,7 +7554,7 @@ var StarknetClient = class {
7454
7554
  * @param sessionKeyHash - Hash of session key to validate
7455
7555
  * @returns Session validation result with expiry and limits
7456
7556
  */
7457
- async isSessionActive(userKeyHash, sessionKeyHash) {
7557
+ async isSessionActive(_userKeyHash, _sessionKeyHash) {
7458
7558
  if (!this.hubRpcUrl || !this.hubContractAddress) {
7459
7559
  throw new Error(
7460
7560
  "Hub configuration required for session validation. Provide hubRpcUrl and hubContractAddress in StarknetClientConfig."
@@ -7546,17 +7646,6 @@ var StarknetClient = class {
7546
7646
  const hash = (0, import_crypto3.createHash)("sha256").update(combined).digest("hex");
7547
7647
  return "0x" + hash;
7548
7648
  }
7549
- buildMessageHash(keyHash, targetChain, actionPayload, nonce) {
7550
- const keyHashBuffer = Buffer.from(keyHash.replace(/^0x/, ""), "hex");
7551
- const targetChainBuffer = Buffer.alloc(2);
7552
- targetChainBuffer.writeUInt16BE(targetChain);
7553
- const payloadBuffer = Buffer.from(actionPayload.replace(/^0x/, ""), "hex");
7554
- const nonceHex = nonce.toString(16).padStart(64, "0");
7555
- const nonceBuffer = Buffer.from(nonceHex, "hex");
7556
- const combined = Buffer.concat([keyHashBuffer, targetChainBuffer, payloadBuffer, nonceBuffer]);
7557
- const hash = (0, import_crypto3.createHash)("sha256").update(combined).digest("hex");
7558
- return "0x" + hash;
7559
- }
7560
7649
  // ============================================================================
7561
7650
  // Social Recovery Methods (Issue #23)
7562
7651
  // ============================================================================
@@ -15381,13 +15470,14 @@ function inferBackupEligibility(platform) {
15381
15470
  }
15382
15471
 
15383
15472
  // src/core/CredentialManager.ts
15473
+ init_relayerUrl();
15384
15474
  var DEFAULT_STORAGE_KEY = "veridex_credential_metadata";
15385
15475
  var CredentialManager = class {
15386
15476
  config;
15387
15477
  constructor(config = {}) {
15388
15478
  this.config = {
15389
15479
  storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
15390
- relayerUrl: config.relayerUrl ?? ""
15480
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
15391
15481
  };
15392
15482
  }
15393
15483
  // ========================================================================
@@ -15535,7 +15625,7 @@ var CredentialManager = class {
15535
15625
  const managed = this.getCredential(credentialId);
15536
15626
  if (!managed) return false;
15537
15627
  try {
15538
- const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {
15628
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential/metadata"), {
15539
15629
  method: "PUT",
15540
15630
  headers: { "Content-Type": "application/json" },
15541
15631
  body: JSON.stringify({
@@ -15561,7 +15651,10 @@ var CredentialManager = class {
15561
15651
  if (!this.config.relayerUrl) return null;
15562
15652
  try {
15563
15653
  const response = await fetch(
15564
- `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
15654
+ buildRelayerApiUrl(
15655
+ this.config.relayerUrl,
15656
+ `/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
15657
+ )
15565
15658
  );
15566
15659
  if (!response.ok) return null;
15567
15660
  const data = await response.json();
@@ -15683,9 +15776,10 @@ var CredentialManager = class {
15683
15776
 
15684
15777
  // src/core/CrossOriginAuth.ts
15685
15778
  init_PasskeyManager();
15779
+ init_relayerUrl();
15686
15780
  init_PasskeyManager();
15687
15781
  var DEFAULT_AUTH_PORTAL_URL = "https://auth.veridex.network";
15688
- var DEFAULT_RELAYER_URL = "https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1";
15782
+ var DEFAULT_RELAYER_URL = "https://relayer.veridex.network";
15689
15783
  var AUTH_MESSAGE_TYPES = {
15690
15784
  AUTH_REQUEST: "VERIDEX_AUTH_REQUEST",
15691
15785
  AUTH_RESPONSE: "VERIDEX_AUTH_RESPONSE",
@@ -15697,7 +15791,7 @@ var CrossOriginAuth = class {
15697
15791
  this.config = {
15698
15792
  rpId: config.rpId ?? VERIDEX_RP_ID,
15699
15793
  authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,
15700
- relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,
15794
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? DEFAULT_RELAYER_URL),
15701
15795
  mode: config.mode ?? "popup",
15702
15796
  popupFeatures: config.popupFeatures ?? "width=500,height=600,left=100,top=100",
15703
15797
  timeout: config.timeout ?? 12e4,
@@ -15793,6 +15887,15 @@ var CrossOriginAuth = class {
15793
15887
  if (options?.sessionChallenge) {
15794
15888
  authUrl.searchParams.set("challenge", options.sessionChallenge);
15795
15889
  }
15890
+ if (options?.register) {
15891
+ authUrl.searchParams.set("register", "true");
15892
+ }
15893
+ if (options?.username) {
15894
+ authUrl.searchParams.set("username", options.username);
15895
+ }
15896
+ if (options?.displayName) {
15897
+ authUrl.searchParams.set("display_name", options.displayName);
15898
+ }
15796
15899
  const popup = window.open(
15797
15900
  authUrl.toString(),
15798
15901
  "veridex-auth",
@@ -15846,6 +15949,15 @@ var CrossOriginAuth = class {
15846
15949
  if (options?.sessionChallenge) {
15847
15950
  authUrl.searchParams.set("challenge", options.sessionChallenge);
15848
15951
  }
15952
+ if (options?.register) {
15953
+ authUrl.searchParams.set("register", "true");
15954
+ }
15955
+ if (options?.username) {
15956
+ authUrl.searchParams.set("username", options.username);
15957
+ }
15958
+ if (options?.displayName) {
15959
+ authUrl.searchParams.set("display_name", options.displayName);
15960
+ }
15849
15961
  window.location.href = authUrl.toString();
15850
15962
  return new Promise(() => {
15851
15963
  });
@@ -15896,7 +16008,8 @@ var CrossOriginAuth = class {
15896
16008
  return bytes;
15897
16009
  }
15898
16010
  async requestServerSessionChallenge(options) {
15899
- const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {
16011
+ const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
16012
+ const response = await fetch(challengeUrl, {
15900
16013
  method: "POST",
15901
16014
  headers: { "Content-Type": "application/json" },
15902
16015
  body: JSON.stringify({
@@ -15942,7 +16055,7 @@ var CrossOriginAuth = class {
15942
16055
  if (!session.serverChallengeId) {
15943
16056
  throw new Error("Session must include a relayer-issued serverChallengeId");
15944
16057
  }
15945
- const response = await fetch(`${this.config.relayerUrl}/session/create`, {
16058
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
15946
16059
  method: "POST",
15947
16060
  headers: { "Content-Type": "application/json" },
15948
16061
  body: JSON.stringify({
@@ -15965,7 +16078,9 @@ var CrossOriginAuth = class {
15965
16078
  * Returns the session details if valid, null if expired/revoked.
15966
16079
  */
15967
16080
  async validateServerSession(sessionId) {
15968
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);
16081
+ const response = await fetch(
16082
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
16083
+ );
15969
16084
  if (!response.ok) {
15970
16085
  return null;
15971
16086
  }
@@ -15979,9 +16094,12 @@ var CrossOriginAuth = class {
15979
16094
  * Revoke a server session token.
15980
16095
  */
15981
16096
  async revokeServerSession(sessionId) {
15982
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {
15983
- method: "DELETE"
15984
- });
16097
+ const response = await fetch(
16098
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
16099
+ {
16100
+ method: "DELETE"
16101
+ }
16102
+ );
15985
16103
  return response.ok;
15986
16104
  }
15987
16105
  /**
@@ -16541,39 +16659,44 @@ var IndexedDBSessionStorage = class {
16541
16659
  );
16542
16660
  }
16543
16661
  }
16662
+ async decryptSession(stored) {
16663
+ const key = await this.getEncryptionKey();
16664
+ const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
16665
+ const privateKey = await decrypt(encryptedPrivateKey, key);
16666
+ return {
16667
+ keyHash: stored.keyHash,
16668
+ publicKey: new Uint8Array(stored.publicKey),
16669
+ privateKey,
16670
+ expiry: stored.expiry,
16671
+ maxValue: BigInt(stored.maxValue),
16672
+ chainScopes: stored.chainScopes ?? [],
16673
+ userKeyHash: stored.userKeyHash
16674
+ };
16675
+ }
16676
+ async pruneExpiredSessions(records) {
16677
+ const now = Date.now();
16678
+ const validRecords = records.filter((record) => record.expiry > now);
16679
+ const expiredRecords = records.filter((record) => record.expiry <= now);
16680
+ if (expiredRecords.length > 0) {
16681
+ await Promise.all(expiredRecords.map((record) => this.remove(record.keyHash)));
16682
+ }
16683
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
16684
+ }
16544
16685
  /**
16545
- * Load the active session (decrypts private key)
16686
+ * Load a session (decrypts private key)
16546
16687
  */
16547
- async load() {
16688
+ async load(keyHash) {
16548
16689
  try {
16549
16690
  await this.initialize();
16550
16691
  if (!this.db) {
16551
16692
  throw new Error("Database not initialized");
16552
16693
  }
16553
- const allSessions = await this.getAllSessions();
16554
- if (allSessions.length === 0) {
16555
- return null;
16556
- }
16557
- const now = Date.now();
16558
- const validSessions = allSessions.filter((s) => s.expiry > now).sort((a, b) => b.savedAt - a.savedAt);
16694
+ const sessions = keyHash ? await this.getSessionByKeyHash(keyHash) : await this.getAllSessions();
16695
+ const validSessions = await this.pruneExpiredSessions(sessions);
16559
16696
  if (validSessions.length === 0) {
16560
- await this.clear();
16561
16697
  return null;
16562
16698
  }
16563
- const stored = validSessions[0];
16564
- const key = await this.getEncryptionKey();
16565
- const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
16566
- const privateKey = await decrypt(encryptedPrivateKey, key);
16567
- const session = {
16568
- keyHash: stored.keyHash,
16569
- publicKey: new Uint8Array(stored.publicKey),
16570
- privateKey,
16571
- expiry: stored.expiry,
16572
- maxValue: BigInt(stored.maxValue),
16573
- chainScopes: stored.chainScopes,
16574
- userKeyHash: stored.userKeyHash
16575
- };
16576
- return session;
16699
+ return this.decryptSession(validSessions[0]);
16577
16700
  } catch (error) {
16578
16701
  if (error instanceof SessionError) {
16579
16702
  throw error;
@@ -16606,6 +16729,75 @@ var IndexedDBSessionStorage = class {
16606
16729
  };
16607
16730
  });
16608
16731
  }
16732
+ async getSessionByKeyHash(keyHash) {
16733
+ if (!this.db) {
16734
+ return [];
16735
+ }
16736
+ return new Promise((resolve, reject) => {
16737
+ const transaction = this.db.transaction([STORE_NAME], "readonly");
16738
+ const store = transaction.objectStore(STORE_NAME);
16739
+ const request = store.get(keyHash);
16740
+ request.onsuccess = () => {
16741
+ resolve(request.result ? [request.result] : []);
16742
+ };
16743
+ request.onerror = () => {
16744
+ reject(new SessionError(
16745
+ "Failed to get session",
16746
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16747
+ request.error
16748
+ ));
16749
+ };
16750
+ });
16751
+ }
16752
+ async loadAll() {
16753
+ try {
16754
+ await this.initialize();
16755
+ if (!this.db) {
16756
+ return [];
16757
+ }
16758
+ const records = await this.pruneExpiredSessions(await this.getAllSessions());
16759
+ return Promise.all(records.map((record) => this.decryptSession(record)));
16760
+ } catch (error) {
16761
+ if (error instanceof SessionError) {
16762
+ throw error;
16763
+ }
16764
+ throw new SessionError(
16765
+ "Failed to load sessions",
16766
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16767
+ error
16768
+ );
16769
+ }
16770
+ }
16771
+ async remove(keyHash) {
16772
+ try {
16773
+ await this.initialize();
16774
+ if (!this.db) {
16775
+ return;
16776
+ }
16777
+ return new Promise((resolve, reject) => {
16778
+ const transaction = this.db.transaction([STORE_NAME], "readwrite");
16779
+ const store = transaction.objectStore(STORE_NAME);
16780
+ const request = store.delete(keyHash);
16781
+ request.onsuccess = () => resolve();
16782
+ request.onerror = () => {
16783
+ reject(new SessionError(
16784
+ "Failed to remove session",
16785
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16786
+ request.error
16787
+ ));
16788
+ };
16789
+ });
16790
+ } catch (error) {
16791
+ if (error instanceof SessionError) {
16792
+ throw error;
16793
+ }
16794
+ throw new SessionError(
16795
+ "Failed to remove session",
16796
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16797
+ error
16798
+ );
16799
+ }
16800
+ }
16609
16801
  /**
16610
16802
  * Clear all sessions
16611
16803
  */
@@ -16642,14 +16834,9 @@ var IndexedDBSessionStorage = class {
16642
16834
  /**
16643
16835
  * Check if any session exists
16644
16836
  */
16645
- async exists() {
16837
+ async exists(keyHash) {
16646
16838
  try {
16647
- await this.initialize();
16648
- if (!this.db) {
16649
- return false;
16650
- }
16651
- const sessions = await this.getAllSessions();
16652
- return sessions.length > 0;
16839
+ return await this.load(keyHash) !== null;
16653
16840
  } catch {
16654
16841
  return false;
16655
16842
  }
@@ -16668,7 +16855,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
16668
16855
  var LocalStorageSessionStorage = class {
16669
16856
  encryptionKey = null;
16670
16857
  credentialId;
16671
- storageKey;
16858
+ credentialHash;
16859
+ legacyStorageKey;
16672
16860
  /**
16673
16861
  * @param credentialId User's Passkey credential ID (for key derivation)
16674
16862
  */
@@ -16680,7 +16868,60 @@ var LocalStorageSessionStorage = class {
16680
16868
  );
16681
16869
  }
16682
16870
  this.credentialId = credentialId;
16683
- this.storageKey = STORAGE_KEY_PREFIX + import_ethers20.ethers.keccak256(import_ethers20.ethers.toUtf8Bytes(credentialId));
16871
+ this.credentialHash = import_ethers20.ethers.keccak256(import_ethers20.ethers.toUtf8Bytes(credentialId));
16872
+ this.legacyStorageKey = STORAGE_KEY_PREFIX + this.credentialHash;
16873
+ }
16874
+ getSessionStorageKey(keyHash) {
16875
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:${keyHash}`;
16876
+ }
16877
+ getSessionStoragePrefix() {
16878
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:`;
16879
+ }
16880
+ async deserializeSession(stored) {
16881
+ const key = await this.getEncryptionKey();
16882
+ const encryptedPrivateKey = typeof stored.encryptedPrivateKey === "string" ? import_ethers20.ethers.getBytes(stored.encryptedPrivateKey) : new Uint8Array(stored.encryptedPrivateKey);
16883
+ const privateKey = await decrypt(encryptedPrivateKey, key);
16884
+ return {
16885
+ keyHash: stored.keyHash,
16886
+ publicKey: typeof stored.publicKey === "string" ? import_ethers20.ethers.getBytes(stored.publicKey) : new Uint8Array(stored.publicKey),
16887
+ privateKey,
16888
+ expiry: stored.expiry,
16889
+ maxValue: BigInt(stored.maxValue),
16890
+ chainScopes: stored.chainScopes ?? [],
16891
+ userKeyHash: stored.userKeyHash
16892
+ };
16893
+ }
16894
+ getRawRecords() {
16895
+ const records = [];
16896
+ const prefix = this.getSessionStoragePrefix();
16897
+ for (let index = 0; index < localStorage.length; index++) {
16898
+ const key = localStorage.key(index);
16899
+ if (!key || !key.startsWith(prefix)) {
16900
+ continue;
16901
+ }
16902
+ const value = localStorage.getItem(key);
16903
+ if (!value) {
16904
+ continue;
16905
+ }
16906
+ records.push(JSON.parse(value));
16907
+ }
16908
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
16909
+ if (legacyValue) {
16910
+ records.push(JSON.parse(legacyValue));
16911
+ }
16912
+ return records;
16913
+ }
16914
+ async getValidRecords() {
16915
+ const now = Date.now();
16916
+ const validRecords = [];
16917
+ for (const record of this.getRawRecords()) {
16918
+ if (record.expiry <= now) {
16919
+ await this.remove(record.keyHash);
16920
+ continue;
16921
+ }
16922
+ validRecords.push(record);
16923
+ }
16924
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
16684
16925
  }
16685
16926
  /**
16686
16927
  * Get or derive encryption key
@@ -16709,7 +16950,7 @@ var LocalStorageSessionStorage = class {
16709
16950
  userKeyHash: session.userKeyHash,
16710
16951
  savedAt: Date.now()
16711
16952
  };
16712
- localStorage.setItem(this.storageKey, JSON.stringify(storageObject));
16953
+ localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
16713
16954
  } catch (error) {
16714
16955
  if (error instanceof SessionError) {
16715
16956
  throw error;
@@ -16722,32 +16963,15 @@ var LocalStorageSessionStorage = class {
16722
16963
  }
16723
16964
  }
16724
16965
  /**
16725
- * Load the active session (decrypts private key)
16966
+ * Load a session (decrypts private key)
16726
16967
  */
16727
- async load() {
16968
+ async load(keyHash) {
16728
16969
  try {
16729
- const data = localStorage.getItem(this.storageKey);
16730
- if (!data) {
16970
+ const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
16971
+ if (records.length === 0) {
16731
16972
  return null;
16732
16973
  }
16733
- const stored = JSON.parse(data);
16734
- if (stored.expiry <= Date.now()) {
16735
- await this.clear();
16736
- return null;
16737
- }
16738
- const key = await this.getEncryptionKey();
16739
- const encryptedPrivateKey = import_ethers20.ethers.getBytes(stored.encryptedPrivateKey);
16740
- const privateKey = await decrypt(encryptedPrivateKey, key);
16741
- const session = {
16742
- keyHash: stored.keyHash,
16743
- publicKey: import_ethers20.ethers.getBytes(stored.publicKey),
16744
- privateKey,
16745
- expiry: stored.expiry,
16746
- maxValue: BigInt(stored.maxValue),
16747
- chainScopes: stored.chainScopes,
16748
- userKeyHash: stored.userKeyHash
16749
- };
16750
- return session;
16974
+ return this.deserializeSession(records[0]);
16751
16975
  } catch (error) {
16752
16976
  await this.clear();
16753
16977
  if (error instanceof SessionError) {
@@ -16760,12 +16984,55 @@ var LocalStorageSessionStorage = class {
16760
16984
  );
16761
16985
  }
16762
16986
  }
16987
+ async loadAll() {
16988
+ try {
16989
+ const records = await this.getValidRecords();
16990
+ return Promise.all(records.map((record) => this.deserializeSession(record)));
16991
+ } catch (error) {
16992
+ await this.clear();
16993
+ if (error instanceof SessionError) {
16994
+ throw error;
16995
+ }
16996
+ throw new SessionError(
16997
+ "Failed to load sessions",
16998
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
16999
+ error
17000
+ );
17001
+ }
17002
+ }
17003
+ async remove(keyHash) {
17004
+ try {
17005
+ localStorage.removeItem(this.getSessionStorageKey(keyHash));
17006
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
17007
+ if (legacyValue) {
17008
+ const legacyRecord = JSON.parse(legacyValue);
17009
+ if (legacyRecord.keyHash === keyHash) {
17010
+ localStorage.removeItem(this.legacyStorageKey);
17011
+ }
17012
+ }
17013
+ } catch (error) {
17014
+ throw new SessionError(
17015
+ "Failed to remove session",
17016
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
17017
+ error
17018
+ );
17019
+ }
17020
+ }
16763
17021
  /**
16764
17022
  * Clear all sessions
16765
17023
  */
16766
17024
  async clear() {
16767
17025
  try {
16768
- localStorage.removeItem(this.storageKey);
17026
+ const keysToRemove = [];
17027
+ const prefix = this.getSessionStoragePrefix();
17028
+ for (let index = 0; index < localStorage.length; index++) {
17029
+ const key = localStorage.key(index);
17030
+ if (key && key.startsWith(prefix)) {
17031
+ keysToRemove.push(key);
17032
+ }
17033
+ }
17034
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
17035
+ localStorage.removeItem(this.legacyStorageKey);
16769
17036
  } catch (error) {
16770
17037
  throw new SessionError(
16771
17038
  "Failed to clear sessions",
@@ -16777,9 +17044,9 @@ var LocalStorageSessionStorage = class {
16777
17044
  /**
16778
17045
  * Check if any session exists
16779
17046
  */
16780
- async exists() {
17047
+ async exists(keyHash) {
16781
17048
  try {
16782
- return localStorage.getItem(this.storageKey) !== null;
17049
+ return await this.load(keyHash) !== null;
16783
17050
  } catch {
16784
17051
  return false;
16785
17052
  }
@@ -16844,6 +17111,14 @@ var SessionManager = class {
16844
17111
  refreshTimer = null;
16845
17112
  eventCallbacks = [];
16846
17113
  debug;
17114
+ resolveConfig(configOverride) {
17115
+ const resolvedConfig = {
17116
+ ...this.config,
17117
+ ...configOverride
17118
+ };
17119
+ validateSessionConfig(resolvedConfig);
17120
+ return resolvedConfig;
17121
+ }
16847
17122
  // ========================================================================
16848
17123
  // Session Lifecycle
16849
17124
  // ========================================================================
@@ -16860,15 +17135,16 @@ var SessionManager = class {
16860
17135
  * @returns Created session key
16861
17136
  * @throws SessionError if registration fails
16862
17137
  */
16863
- async createSession() {
17138
+ async createSession(configOverride) {
16864
17139
  try {
16865
17140
  this.log("Creating new session...");
17141
+ const sessionConfig = this.resolveConfig(configOverride);
16866
17142
  const keyPair = generateSecp256k1KeyPair();
16867
17143
  const keyHash = computeSessionKeyHash(keyPair.publicKey);
16868
17144
  this.log("Generated session key:", keyHash);
16869
17145
  const challenge = import_ethers21.ethers.solidityPacked(
16870
17146
  ["string", "bytes32", "uint256", "uint256"],
16871
- ["registerSession", keyHash, this.config.duration, this.config.maxValue]
17147
+ ["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
16872
17148
  );
16873
17149
  this.log("Challenge prepared, requesting Passkey signature...");
16874
17150
  const signature = await this.passkeySign(import_ethers21.ethers.getBytes(challenge));
@@ -16878,20 +17154,20 @@ var SessionManager = class {
16878
17154
  publicKeyX: this.credential.publicKeyX,
16879
17155
  publicKeyY: this.credential.publicKeyY,
16880
17156
  sessionKeyHash: keyHash,
16881
- duration: this.config.duration,
16882
- maxValue: this.config.maxValue,
17157
+ duration: sessionConfig.duration,
17158
+ maxValue: sessionConfig.maxValue,
16883
17159
  requireUV: true
16884
17160
  };
16885
17161
  await this.hubClient.registerSession(registerParams);
16886
17162
  this.log("Session registered on Hub");
16887
- const expiry = Date.now() + this.config.duration * 1e3;
17163
+ const expiry = Date.now() + sessionConfig.duration * 1e3;
16888
17164
  this.currentSession = {
16889
17165
  publicKey: keyPair.publicKey,
16890
17166
  privateKey: keyPair.privateKey,
16891
17167
  keyHash,
16892
17168
  expiry,
16893
- maxValue: this.config.maxValue,
16894
- chainScopes: this.config.chainScopes,
17169
+ maxValue: sessionConfig.maxValue,
17170
+ chainScopes: sessionConfig.chainScopes,
16895
17171
  userKeyHash: this.credential.keyHash
16896
17172
  };
16897
17173
  await this.storage.save(this.currentSession);
@@ -16916,12 +17192,15 @@ var SessionManager = class {
16916
17192
  *
16917
17193
  * @returns Loaded session or null if no valid session exists
16918
17194
  */
16919
- async loadSession() {
17195
+ async loadSession(keyHash) {
16920
17196
  try {
16921
- this.log("Loading session from storage...");
16922
- const session = await this.storage.load();
17197
+ this.log("Loading session from storage...", keyHash ?? "latest");
17198
+ const session = await this.storage.load(keyHash);
16923
17199
  if (!session) {
16924
17200
  this.log("No session found in storage");
17201
+ if (!keyHash) {
17202
+ this.currentSession = null;
17203
+ }
16925
17204
  return null;
16926
17205
  }
16927
17206
  if (session.expiry <= Date.now()) {
@@ -16938,27 +17217,43 @@ var SessionManager = class {
16938
17217
  return session;
16939
17218
  } catch (error) {
16940
17219
  this.log("Failed to load session:", error);
16941
- await this.storage.clear();
17220
+ if (!keyHash) {
17221
+ await this.storage.clear();
17222
+ }
16942
17223
  return null;
16943
17224
  }
16944
17225
  }
17226
+ async listSessions() {
17227
+ return this.storage.loadAll();
17228
+ }
17229
+ async selectSession(keyHash) {
17230
+ const session = await this.loadSession(keyHash);
17231
+ if (!session) {
17232
+ throw new SessionError(
17233
+ `Session ${keyHash} not found`,
17234
+ "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */
17235
+ );
17236
+ }
17237
+ return session;
17238
+ }
16945
17239
  /**
16946
17240
  * Revoke the current session (requires biometric authentication)
16947
17241
  *
16948
17242
  * @throws SessionError if no active session or revocation fails
16949
17243
  */
16950
- async revokeSession() {
16951
- if (!this.currentSession) {
17244
+ async revokeSession(keyHash) {
17245
+ const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
17246
+ if (!targetSession) {
16952
17247
  throw new SessionError(
16953
- "No active session to revoke",
16954
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17248
+ keyHash ? `Session ${keyHash} not found` : "No active session to revoke",
17249
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
16955
17250
  );
16956
17251
  }
16957
17252
  try {
16958
- this.log("Revoking session:", this.currentSession.keyHash);
17253
+ this.log("Revoking session:", targetSession.keyHash);
16959
17254
  const challenge = import_ethers21.ethers.solidityPacked(
16960
17255
  ["string", "bytes32"],
16961
- ["revokeSession", this.currentSession.keyHash]
17256
+ ["revokeSession", targetSession.keyHash]
16962
17257
  );
16963
17258
  const signature = await this.passkeySign(import_ethers21.ethers.getBytes(challenge));
16964
17259
  this.log("Passkey signature obtained, revoking on Hub...");
@@ -16966,18 +17261,24 @@ var SessionManager = class {
16966
17261
  signature,
16967
17262
  publicKeyX: this.credential.publicKeyX,
16968
17263
  publicKeyY: this.credential.publicKeyY,
16969
- sessionKeyHash: this.currentSession.keyHash,
17264
+ sessionKeyHash: targetSession.keyHash,
16970
17265
  requireUV: true
16971
17266
  };
16972
17267
  await this.hubClient.revokeSession(revokeParams);
16973
17268
  this.log("Session revoked on Hub");
16974
- await this.storage.clear();
16975
- if (this.refreshTimer) {
16976
- clearTimeout(this.refreshTimer);
16977
- this.refreshTimer = null;
17269
+ await this.storage.remove(targetSession.keyHash);
17270
+ const revokedKeyHash = targetSession.keyHash;
17271
+ const revokedCurrentSession = this.currentSession?.keyHash === revokedKeyHash;
17272
+ if (revokedCurrentSession) {
17273
+ if (this.refreshTimer) {
17274
+ clearTimeout(this.refreshTimer);
17275
+ this.refreshTimer = null;
17276
+ }
17277
+ this.currentSession = await this.storage.load();
17278
+ if (this.currentSession && this.config.autoRefresh) {
17279
+ this.scheduleRefresh();
17280
+ }
16978
17281
  }
16979
- const revokedKeyHash = this.currentSession.keyHash;
16980
- this.currentSession = null;
16981
17282
  this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
16982
17283
  this.log("Session revoked successfully");
16983
17284
  } catch (error) {
@@ -17055,45 +17356,46 @@ var SessionManager = class {
17055
17356
  * @returns Session signature
17056
17357
  * @throws SessionError if no active session, expired, or value exceeds limit
17057
17358
  */
17058
- async signWithSession(action) {
17059
- if (!this.currentSession) {
17359
+ async signWithSession(action, keyHash) {
17360
+ const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
17361
+ if (!session) {
17060
17362
  throw new SessionError(
17061
- "No active session available",
17062
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17363
+ keyHash ? `Session ${keyHash} not found` : "No active session available",
17364
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
17063
17365
  );
17064
17366
  }
17065
17367
  const now = Date.now();
17066
- if (now >= this.currentSession.expiry) {
17067
- this.emit({ type: "session-expired", keyHash: this.currentSession.keyHash });
17368
+ if (now >= session.expiry) {
17369
+ this.emit({ type: "session-expired", keyHash: session.keyHash });
17068
17370
  throw new SessionError(
17069
17371
  "Session has expired",
17070
17372
  "SESSION_EXPIRED" /* SESSION_EXPIRED */
17071
17373
  );
17072
17374
  }
17073
- if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {
17375
+ if (session.maxValue > 0n && action.value > session.maxValue) {
17074
17376
  throw new SessionError(
17075
- `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,
17377
+ `Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
17076
17378
  "VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
17077
- { value: action.value, limit: this.currentSession.maxValue }
17379
+ { value: action.value, limit: session.maxValue }
17078
17380
  );
17079
17381
  }
17080
- if (this.currentSession.chainScopes.length > 0 && !this.currentSession.chainScopes.includes(action.targetChain)) {
17382
+ if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
17081
17383
  throw new SessionError(
17082
17384
  `Chain ${action.targetChain} not in session scope`,
17083
17385
  "CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
17084
- { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }
17386
+ { chain: action.targetChain, allowedChains: session.chainScopes }
17085
17387
  );
17086
17388
  }
17087
17389
  this.log("Signing action with session key...");
17088
17390
  const messageHash = hashAction(action);
17089
17391
  const { signature } = signWithSessionKey(
17090
- this.currentSession.privateKey,
17392
+ session.privateKey,
17091
17393
  messageHash
17092
17394
  );
17093
17395
  const sessionSignature = {
17094
17396
  signature,
17095
- sessionKeyHash: this.currentSession.keyHash,
17096
- userKeyHash: this.currentSession.userKeyHash,
17397
+ sessionKeyHash: session.keyHash,
17398
+ userKeyHash: session.userKeyHash,
17097
17399
  timestamp: now,
17098
17400
  nonce: action.nonce
17099
17401
  };
@@ -17106,8 +17408,8 @@ var SessionManager = class {
17106
17408
  * @param action Action parameters
17107
17409
  * @returns Session-signed action ready for submission
17108
17410
  */
17109
- async signAction(action) {
17110
- const signature = await this.signWithSession(action);
17411
+ async signAction(action, keyHash) {
17412
+ const signature = await this.signWithSession(action, keyHash);
17111
17413
  return {
17112
17414
  action,
17113
17415
  signature,
@@ -18091,6 +18393,7 @@ var VALIDATION_REGISTRY_ABI = [
18091
18393
  calculatePercentage,
18092
18394
  computeKeyHash,
18093
18395
  computeSessionKeyHash,
18396
+ configureDefaultRpcUrls,
18094
18397
  createAuditEntry,
18095
18398
  createChainClient,
18096
18399
  createChainDetector,
@@ -18160,6 +18463,7 @@ var VALIDATION_REGISTRY_ABI = [
18160
18463
  getExplorerUrl,
18161
18464
  getFeatureFlags,
18162
18465
  getHubChains,
18466
+ getRpcUrlOverride,
18163
18467
  getSequenceFromTxReceipt,
18164
18468
  getStacksContractPrincipal,
18165
18469
  getStacksExplorerAddressUrl,