@veridex/sdk 1.1.0 → 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 (83) 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/chains/aptos/index.js.map +1 -1
  5. package/dist/chains/aptos/index.mjs +3 -3
  6. package/dist/chains/avalanche/index.js.map +1 -1
  7. package/dist/chains/avalanche/index.mjs +4 -4
  8. package/dist/chains/evm/index.d.mts +2 -2
  9. package/dist/chains/evm/index.js.map +1 -1
  10. package/dist/chains/evm/index.mjs +3 -3
  11. package/dist/chains/solana/index.js.map +1 -1
  12. package/dist/chains/solana/index.mjs +3 -3
  13. package/dist/chains/stacks/index.d.mts +1 -1
  14. package/dist/chains/stacks/index.js.map +1 -1
  15. package/dist/chains/stacks/index.mjs +3 -3
  16. package/dist/chains/starknet/index.d.mts +1 -1
  17. package/dist/chains/starknet/index.js.map +1 -1
  18. package/dist/chains/starknet/index.mjs +3 -3
  19. package/dist/chains/sui/index.d.mts +1 -1
  20. package/dist/chains/sui/index.js.map +1 -1
  21. package/dist/chains/sui/index.mjs +3 -3
  22. package/dist/{chunk-Q5O3M5LP.mjs → chunk-2TS375ET.mjs} +2 -2
  23. package/dist/{chunk-QT4ZZ4GM.mjs → chunk-5FDOTI5G.mjs} +2 -2
  24. package/dist/{chunk-5T6KPH7A.mjs → chunk-CSU4IV2F.mjs} +2 -2
  25. package/dist/{chunk-YCUJZ6Z7.mjs → chunk-CTYDGO6E.mjs} +63 -6
  26. package/dist/chunk-CTYDGO6E.mjs.map +1 -0
  27. package/dist/{chunk-SXXGTQIR.mjs → chunk-E3SU36C2.mjs} +2 -2
  28. package/dist/{chunk-NUWSMJFJ.mjs → chunk-EFIXFA6V.mjs} +2 -2
  29. package/dist/{chunk-MLXQHIH2.mjs → chunk-GM5DKEHD.mjs} +2 -2
  30. package/dist/{chunk-GWJRKDSA.mjs → chunk-GOWXQPTW.mjs} +3 -3
  31. package/dist/{chunk-OVMMTL6H.mjs → chunk-ICGB3AHI.mjs} +2 -2
  32. package/dist/{chunk-QDO6NQ7P.mjs → chunk-M3GUNREX.mjs} +20 -3
  33. package/dist/{chunk-QDO6NQ7P.mjs.map → chunk-M3GUNREX.mjs.map} +1 -1
  34. package/dist/{chunk-N4A2RMUN.mjs → chunk-PEGOXMBU.mjs} +2 -2
  35. package/dist/{chunk-X7BZMSPQ.mjs → chunk-RD6ZYUVG.mjs} +52 -30
  36. package/dist/chunk-RD6ZYUVG.mjs.map +1 -0
  37. package/dist/{chunk-F3YAGZSW.mjs → chunk-TPEP6XUA.mjs} +2 -2
  38. package/dist/{chunk-M3MM4YMF.mjs → chunk-UPO55SBK.mjs} +2 -2
  39. package/dist/{chunk-USDA5JTN.mjs → chunk-YBN2VC6E.mjs} +2 -2
  40. package/dist/{chunk-PDHZ5X5O.mjs → chunk-YYT3V7CI.mjs} +2 -2
  41. package/dist/constants.d.mts +2 -2
  42. package/dist/constants.js +51 -29
  43. package/dist/constants.js.map +1 -1
  44. package/dist/constants.mjs +1 -1
  45. package/dist/{index-DDalBhAm.d.mts → index-CySMITQ9.d.mts} +9 -6
  46. package/dist/index.d.mts +41 -13
  47. package/dist/index.js +445 -147
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +327 -127
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/passkey.js +57 -4
  52. package/dist/passkey.js.map +1 -1
  53. package/dist/passkey.mjs +3 -3
  54. package/dist/payload.js.map +1 -1
  55. package/dist/payload.mjs +2 -2
  56. package/dist/portfolio-JA4OTF7Y.mjs +13 -0
  57. package/dist/queries/index.js +49 -27
  58. package/dist/queries/index.js.map +1 -1
  59. package/dist/queries/index.mjs +5 -5
  60. package/dist/{types-B7V5VNbO.d.mts → types-DWx-5jmz.d.mts} +12 -3
  61. package/dist/utils.js +49 -27
  62. package/dist/utils.js.map +1 -1
  63. package/dist/utils.mjs +2 -2
  64. package/dist/wormhole.js.map +1 -1
  65. package/dist/wormhole.mjs +2 -2
  66. package/package.json +1 -1
  67. package/dist/chunk-X7BZMSPQ.mjs.map +0 -1
  68. package/dist/chunk-YCUJZ6Z7.mjs.map +0 -1
  69. package/dist/portfolio-V347KZOL.mjs +0 -13
  70. /package/dist/{chunk-Q5O3M5LP.mjs.map → chunk-2TS375ET.mjs.map} +0 -0
  71. /package/dist/{chunk-QT4ZZ4GM.mjs.map → chunk-5FDOTI5G.mjs.map} +0 -0
  72. /package/dist/{chunk-5T6KPH7A.mjs.map → chunk-CSU4IV2F.mjs.map} +0 -0
  73. /package/dist/{chunk-SXXGTQIR.mjs.map → chunk-E3SU36C2.mjs.map} +0 -0
  74. /package/dist/{chunk-NUWSMJFJ.mjs.map → chunk-EFIXFA6V.mjs.map} +0 -0
  75. /package/dist/{chunk-MLXQHIH2.mjs.map → chunk-GM5DKEHD.mjs.map} +0 -0
  76. /package/dist/{chunk-GWJRKDSA.mjs.map → chunk-GOWXQPTW.mjs.map} +0 -0
  77. /package/dist/{chunk-OVMMTL6H.mjs.map → chunk-ICGB3AHI.mjs.map} +0 -0
  78. /package/dist/{chunk-N4A2RMUN.mjs.map → chunk-PEGOXMBU.mjs.map} +0 -0
  79. /package/dist/{chunk-F3YAGZSW.mjs.map → chunk-TPEP6XUA.mjs.map} +0 -0
  80. /package/dist/{chunk-M3MM4YMF.mjs.map → chunk-UPO55SBK.mjs.map} +0 -0
  81. /package/dist/{chunk-USDA5JTN.mjs.map → chunk-YBN2VC6E.mjs.map} +0 -0
  82. /package/dist/{chunk-PDHZ5X5O.mjs.map → chunk-YYT3V7CI.mjs.map} +0 -0
  83. /package/dist/{portfolio-V347KZOL.mjs.map → portfolio-JA4OTF7Y.mjs.map} +0 -0
package/dist/index.mjs CHANGED
@@ -1,34 +1,36 @@
1
1
  import {
2
2
  CHAIN_NAMES,
3
3
  CHAIN_PRESETS,
4
+ configureDefaultRpcUrls,
4
5
  getChainConfig,
5
6
  getChainPreset,
6
7
  getDefaultHub,
7
8
  getEffectivePrimaryHub,
8
9
  getFeatureFlags,
9
10
  getHubChains,
11
+ getRpcUrlOverride,
10
12
  getSupportedChains,
11
13
  isChainSupported,
12
14
  isHubChain,
13
15
  isMultiHubEnabled,
14
16
  resetFeatureFlags,
15
17
  setFeatureFlags
16
- } from "./chunk-QDO6NQ7P.mjs";
18
+ } from "./chunk-M3GUNREX.mjs";
17
19
  import {
18
20
  EVMHubClientAdapter
19
21
  } from "./chunk-V636MIV3.mjs";
20
22
  import {
21
23
  SolanaClient
22
- } from "./chunk-Q5O3M5LP.mjs";
24
+ } from "./chunk-2TS375ET.mjs";
23
25
  import {
24
26
  AptosClient
25
- } from "./chunk-QT4ZZ4GM.mjs";
27
+ } from "./chunk-5FDOTI5G.mjs";
26
28
  import {
27
29
  SuiClient
28
- } from "./chunk-SXXGTQIR.mjs";
30
+ } from "./chunk-E3SU36C2.mjs";
29
31
  import {
30
32
  StarknetClient
31
- } from "./chunk-MLXQHIH2.mjs";
33
+ } from "./chunk-GM5DKEHD.mjs";
32
34
  import {
33
35
  STACKS_ACTION_TYPES,
34
36
  StacksClient,
@@ -56,13 +58,13 @@ import {
56
58
  parseContractPrincipal,
57
59
  rsToCompactSignature,
58
60
  validatePostConditions
59
- } from "./chunk-5T6KPH7A.mjs";
61
+ } from "./chunk-CSU4IV2F.mjs";
60
62
  import {
61
63
  AvalancheClient
62
- } from "./chunk-N4A2RMUN.mjs";
64
+ } from "./chunk-PEGOXMBU.mjs";
63
65
  import {
64
66
  EVMClient
65
- } from "./chunk-USDA5JTN.mjs";
67
+ } from "./chunk-YBN2VC6E.mjs";
66
68
  import {
67
69
  CONSISTENCY_LEVELS,
68
70
  GUARDIAN_CONFIG,
@@ -85,7 +87,7 @@ import {
85
87
  supportsRelayer,
86
88
  validateEmitter,
87
89
  waitForGuardianSignatures
88
- } from "./chunk-M3MM4YMF.mjs";
90
+ } from "./chunk-UPO55SBK.mjs";
89
91
  import {
90
92
  buildChallenge,
91
93
  buildGaslessChallenge,
@@ -109,7 +111,7 @@ import {
109
111
  parseAmount,
110
112
  solanaAddressToBytes32,
111
113
  trimTo20Bytes
112
- } from "./chunk-F3YAGZSW.mjs";
114
+ } from "./chunk-TPEP6XUA.mjs";
113
115
  import {
114
116
  ARBITRUM_SEPOLIA_TOKENS,
115
117
  BASE_SEPOLIA_TOKENS,
@@ -127,13 +129,15 @@ import {
127
129
  getTokenBySymbol,
128
130
  getTokenList,
129
131
  isNativeToken
130
- } from "./chunk-PDHZ5X5O.mjs";
132
+ } from "./chunk-YYT3V7CI.mjs";
131
133
  import {
132
134
  PasskeyManager,
133
135
  VERIDEX_RP_ID,
136
+ buildRelayerApiUrl,
134
137
  detectRpId,
138
+ normalizeRelayerOrigin,
135
139
  supportsRelatedOrigins
136
- } from "./chunk-YCUJZ6Z7.mjs";
140
+ } from "./chunk-CTYDGO6E.mjs";
137
141
  import {
138
142
  base64URLDecode,
139
143
  base64URLEncode,
@@ -149,7 +153,7 @@ import {
149
153
  isValidWormholeChainId,
150
154
  parseDERSignature,
151
155
  retryWithBackoff
152
- } from "./chunk-NUWSMJFJ.mjs";
156
+ } from "./chunk-EFIXFA6V.mjs";
153
157
  import {
154
158
  ACTION_BRIDGE,
155
159
  ACTION_CONFIG,
@@ -165,7 +169,7 @@ import {
165
169
  WORMHOLE_API,
166
170
  WORMHOLE_CHAIN_IDS,
167
171
  WORMHOLE_CHAIN_IDS_FLAT
168
- } from "./chunk-X7BZMSPQ.mjs";
172
+ } from "./chunk-RD6ZYUVG.mjs";
169
173
 
170
174
  // src/core/BalanceManager.ts
171
175
  import { ethers } from "ethers";
@@ -1014,7 +1018,7 @@ var RelayerClient = class _RelayerClient {
1014
1018
  baseUrl;
1015
1019
  config;
1016
1020
  constructor(config) {
1017
- this.baseUrl = config.baseUrl.replace(/\/+$/, "");
1021
+ this.baseUrl = normalizeRelayerOrigin(config.baseUrl);
1018
1022
  this.config = { ...DEFAULT_CONFIG2, ...config };
1019
1023
  }
1020
1024
  // ========================================================================
@@ -1281,6 +1285,7 @@ var RelayerClient = class _RelayerClient {
1281
1285
  * Make an HTTP request to the relayer
1282
1286
  */
1283
1287
  async fetch(path, options = {}) {
1288
+ const resolvedUrl = path.startsWith("/api/v1/") ? buildRelayerApiUrl(this.baseUrl, path.replace(/^\/api\/v1/, "")) : `${this.baseUrl}${path}`;
1284
1289
  const headers = {
1285
1290
  "Content-Type": "application/json",
1286
1291
  "User-Agent": `@veridex/sdk/${_RelayerClient.SDK_VERSION}`,
@@ -1294,7 +1299,7 @@ var RelayerClient = class _RelayerClient {
1294
1299
  let lastError = null;
1295
1300
  for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
1296
1301
  try {
1297
- const response = await fetch(`${this.baseUrl}${path}`, {
1302
+ const response = await fetch(resolvedUrl, {
1298
1303
  ...options,
1299
1304
  headers,
1300
1305
  signal: controller.signal
@@ -5300,7 +5305,7 @@ var VeridexSDK = class {
5300
5305
  const wormholeChainId = chainConfig.wormholeChainId;
5301
5306
  const tokenList = getAllTokens(wormholeChainId);
5302
5307
  const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
5303
- const { queryPortfolio } = await import("./portfolio-V347KZOL.mjs");
5308
+ const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
5304
5309
  const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
5305
5310
  network: this.testnet ? "testnet" : "mainnet",
5306
5311
  vaultAddresses: { [wormholeChainId]: vaultAddress },
@@ -5663,7 +5668,7 @@ var VeridexSDK = class {
5663
5668
  const tokenList = getAllTokens(wormholeChainId);
5664
5669
  const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
5665
5670
  const rpcUrl = this.chainRpcUrls?.[wormholeChainId] ?? chainConfig.rpcUrl;
5666
- const { queryPortfolio } = await import("./portfolio-V347KZOL.mjs");
5671
+ const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
5667
5672
  const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
5668
5673
  network: this.testnet ? "testnet" : "mainnet",
5669
5674
  vaultAddresses: { [wormholeChainId]: vaultAddress },
@@ -6657,7 +6662,7 @@ var CredentialManager = class {
6657
6662
  constructor(config = {}) {
6658
6663
  this.config = {
6659
6664
  storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
6660
- relayerUrl: config.relayerUrl ?? ""
6665
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
6661
6666
  };
6662
6667
  }
6663
6668
  // ========================================================================
@@ -6805,7 +6810,7 @@ var CredentialManager = class {
6805
6810
  const managed = this.getCredential(credentialId);
6806
6811
  if (!managed) return false;
6807
6812
  try {
6808
- const response = await fetch(`${this.config.relayerUrl}/api/v1/credential/metadata`, {
6813
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential/metadata"), {
6809
6814
  method: "PUT",
6810
6815
  headers: { "Content-Type": "application/json" },
6811
6816
  body: JSON.stringify({
@@ -6831,7 +6836,10 @@ var CredentialManager = class {
6831
6836
  if (!this.config.relayerUrl) return null;
6832
6837
  try {
6833
6838
  const response = await fetch(
6834
- `${this.config.relayerUrl}/api/v1/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
6839
+ buildRelayerApiUrl(
6840
+ this.config.relayerUrl,
6841
+ `/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
6842
+ )
6835
6843
  );
6836
6844
  if (!response.ok) return null;
6837
6845
  const data = await response.json();
@@ -6953,7 +6961,7 @@ var CredentialManager = class {
6953
6961
 
6954
6962
  // src/core/CrossOriginAuth.ts
6955
6963
  var DEFAULT_AUTH_PORTAL_URL = "https://auth.veridex.network";
6956
- var DEFAULT_RELAYER_URL = "https://amused-kameko-veridex-demo-37453117.koyeb.app/api/v1";
6964
+ var DEFAULT_RELAYER_URL = "https://relayer.veridex.network";
6957
6965
  var AUTH_MESSAGE_TYPES = {
6958
6966
  AUTH_REQUEST: "VERIDEX_AUTH_REQUEST",
6959
6967
  AUTH_RESPONSE: "VERIDEX_AUTH_RESPONSE",
@@ -6965,7 +6973,7 @@ var CrossOriginAuth = class {
6965
6973
  this.config = {
6966
6974
  rpId: config.rpId ?? VERIDEX_RP_ID,
6967
6975
  authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,
6968
- relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,
6976
+ relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? DEFAULT_RELAYER_URL),
6969
6977
  mode: config.mode ?? "popup",
6970
6978
  popupFeatures: config.popupFeatures ?? "width=500,height=600,left=100,top=100",
6971
6979
  timeout: config.timeout ?? 12e4,
@@ -7182,7 +7190,8 @@ var CrossOriginAuth = class {
7182
7190
  return bytes;
7183
7191
  }
7184
7192
  async requestServerSessionChallenge(options) {
7185
- const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {
7193
+ const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
7194
+ const response = await fetch(challengeUrl, {
7186
7195
  method: "POST",
7187
7196
  headers: { "Content-Type": "application/json" },
7188
7197
  body: JSON.stringify({
@@ -7228,7 +7237,7 @@ var CrossOriginAuth = class {
7228
7237
  if (!session.serverChallengeId) {
7229
7238
  throw new Error("Session must include a relayer-issued serverChallengeId");
7230
7239
  }
7231
- const response = await fetch(`${this.config.relayerUrl}/session/create`, {
7240
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
7232
7241
  method: "POST",
7233
7242
  headers: { "Content-Type": "application/json" },
7234
7243
  body: JSON.stringify({
@@ -7251,7 +7260,9 @@ var CrossOriginAuth = class {
7251
7260
  * Returns the session details if valid, null if expired/revoked.
7252
7261
  */
7253
7262
  async validateServerSession(sessionId) {
7254
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);
7263
+ const response = await fetch(
7264
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
7265
+ );
7255
7266
  if (!response.ok) {
7256
7267
  return null;
7257
7268
  }
@@ -7265,9 +7276,12 @@ var CrossOriginAuth = class {
7265
7276
  * Revoke a server session token.
7266
7277
  */
7267
7278
  async revokeServerSession(sessionId) {
7268
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {
7269
- method: "DELETE"
7270
- });
7279
+ const response = await fetch(
7280
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
7281
+ {
7282
+ method: "DELETE"
7283
+ }
7284
+ );
7271
7285
  return response.ok;
7272
7286
  }
7273
7287
  /**
@@ -7824,39 +7838,44 @@ var IndexedDBSessionStorage = class {
7824
7838
  );
7825
7839
  }
7826
7840
  }
7841
+ async decryptSession(stored) {
7842
+ const key = await this.getEncryptionKey();
7843
+ const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
7844
+ const privateKey = await decrypt(encryptedPrivateKey, key);
7845
+ return {
7846
+ keyHash: stored.keyHash,
7847
+ publicKey: new Uint8Array(stored.publicKey),
7848
+ privateKey,
7849
+ expiry: stored.expiry,
7850
+ maxValue: BigInt(stored.maxValue),
7851
+ chainScopes: stored.chainScopes ?? [],
7852
+ userKeyHash: stored.userKeyHash
7853
+ };
7854
+ }
7855
+ async pruneExpiredSessions(records) {
7856
+ const now = Date.now();
7857
+ const validRecords = records.filter((record) => record.expiry > now);
7858
+ const expiredRecords = records.filter((record) => record.expiry <= now);
7859
+ if (expiredRecords.length > 0) {
7860
+ await Promise.all(expiredRecords.map((record) => this.remove(record.keyHash)));
7861
+ }
7862
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
7863
+ }
7827
7864
  /**
7828
- * Load the active session (decrypts private key)
7865
+ * Load a session (decrypts private key)
7829
7866
  */
7830
- async load() {
7867
+ async load(keyHash) {
7831
7868
  try {
7832
7869
  await this.initialize();
7833
7870
  if (!this.db) {
7834
7871
  throw new Error("Database not initialized");
7835
7872
  }
7836
- const allSessions = await this.getAllSessions();
7837
- if (allSessions.length === 0) {
7838
- return null;
7839
- }
7840
- const now = Date.now();
7841
- const validSessions = allSessions.filter((s) => s.expiry > now).sort((a, b) => b.savedAt - a.savedAt);
7873
+ const sessions = keyHash ? await this.getSessionByKeyHash(keyHash) : await this.getAllSessions();
7874
+ const validSessions = await this.pruneExpiredSessions(sessions);
7842
7875
  if (validSessions.length === 0) {
7843
- await this.clear();
7844
7876
  return null;
7845
7877
  }
7846
- const stored = validSessions[0];
7847
- const key = await this.getEncryptionKey();
7848
- const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
7849
- const privateKey = await decrypt(encryptedPrivateKey, key);
7850
- const session = {
7851
- keyHash: stored.keyHash,
7852
- publicKey: new Uint8Array(stored.publicKey),
7853
- privateKey,
7854
- expiry: stored.expiry,
7855
- maxValue: BigInt(stored.maxValue),
7856
- chainScopes: stored.chainScopes,
7857
- userKeyHash: stored.userKeyHash
7858
- };
7859
- return session;
7878
+ return this.decryptSession(validSessions[0]);
7860
7879
  } catch (error) {
7861
7880
  if (error instanceof SessionError) {
7862
7881
  throw error;
@@ -7889,6 +7908,75 @@ var IndexedDBSessionStorage = class {
7889
7908
  };
7890
7909
  });
7891
7910
  }
7911
+ async getSessionByKeyHash(keyHash) {
7912
+ if (!this.db) {
7913
+ return [];
7914
+ }
7915
+ return new Promise((resolve, reject) => {
7916
+ const transaction = this.db.transaction([STORE_NAME], "readonly");
7917
+ const store = transaction.objectStore(STORE_NAME);
7918
+ const request = store.get(keyHash);
7919
+ request.onsuccess = () => {
7920
+ resolve(request.result ? [request.result] : []);
7921
+ };
7922
+ request.onerror = () => {
7923
+ reject(new SessionError(
7924
+ "Failed to get session",
7925
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7926
+ request.error
7927
+ ));
7928
+ };
7929
+ });
7930
+ }
7931
+ async loadAll() {
7932
+ try {
7933
+ await this.initialize();
7934
+ if (!this.db) {
7935
+ return [];
7936
+ }
7937
+ const records = await this.pruneExpiredSessions(await this.getAllSessions());
7938
+ return Promise.all(records.map((record) => this.decryptSession(record)));
7939
+ } catch (error) {
7940
+ if (error instanceof SessionError) {
7941
+ throw error;
7942
+ }
7943
+ throw new SessionError(
7944
+ "Failed to load sessions",
7945
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7946
+ error
7947
+ );
7948
+ }
7949
+ }
7950
+ async remove(keyHash) {
7951
+ try {
7952
+ await this.initialize();
7953
+ if (!this.db) {
7954
+ return;
7955
+ }
7956
+ return new Promise((resolve, reject) => {
7957
+ const transaction = this.db.transaction([STORE_NAME], "readwrite");
7958
+ const store = transaction.objectStore(STORE_NAME);
7959
+ const request = store.delete(keyHash);
7960
+ request.onsuccess = () => resolve();
7961
+ request.onerror = () => {
7962
+ reject(new SessionError(
7963
+ "Failed to remove session",
7964
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7965
+ request.error
7966
+ ));
7967
+ };
7968
+ });
7969
+ } catch (error) {
7970
+ if (error instanceof SessionError) {
7971
+ throw error;
7972
+ }
7973
+ throw new SessionError(
7974
+ "Failed to remove session",
7975
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
7976
+ error
7977
+ );
7978
+ }
7979
+ }
7892
7980
  /**
7893
7981
  * Clear all sessions
7894
7982
  */
@@ -7925,14 +8013,9 @@ var IndexedDBSessionStorage = class {
7925
8013
  /**
7926
8014
  * Check if any session exists
7927
8015
  */
7928
- async exists() {
8016
+ async exists(keyHash) {
7929
8017
  try {
7930
- await this.initialize();
7931
- if (!this.db) {
7932
- return false;
7933
- }
7934
- const sessions = await this.getAllSessions();
7935
- return sessions.length > 0;
8018
+ return await this.load(keyHash) !== null;
7936
8019
  } catch {
7937
8020
  return false;
7938
8021
  }
@@ -7951,7 +8034,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
7951
8034
  var LocalStorageSessionStorage = class {
7952
8035
  encryptionKey = null;
7953
8036
  credentialId;
7954
- storageKey;
8037
+ credentialHash;
8038
+ legacyStorageKey;
7955
8039
  /**
7956
8040
  * @param credentialId User's Passkey credential ID (for key derivation)
7957
8041
  */
@@ -7963,7 +8047,60 @@ var LocalStorageSessionStorage = class {
7963
8047
  );
7964
8048
  }
7965
8049
  this.credentialId = credentialId;
7966
- this.storageKey = STORAGE_KEY_PREFIX + ethers10.keccak256(ethers10.toUtf8Bytes(credentialId));
8050
+ this.credentialHash = ethers10.keccak256(ethers10.toUtf8Bytes(credentialId));
8051
+ this.legacyStorageKey = STORAGE_KEY_PREFIX + this.credentialHash;
8052
+ }
8053
+ getSessionStorageKey(keyHash) {
8054
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:${keyHash}`;
8055
+ }
8056
+ getSessionStoragePrefix() {
8057
+ return `${STORAGE_KEY_PREFIX}${this.credentialHash}:`;
8058
+ }
8059
+ async deserializeSession(stored) {
8060
+ const key = await this.getEncryptionKey();
8061
+ const encryptedPrivateKey = typeof stored.encryptedPrivateKey === "string" ? ethers10.getBytes(stored.encryptedPrivateKey) : new Uint8Array(stored.encryptedPrivateKey);
8062
+ const privateKey = await decrypt(encryptedPrivateKey, key);
8063
+ return {
8064
+ keyHash: stored.keyHash,
8065
+ publicKey: typeof stored.publicKey === "string" ? ethers10.getBytes(stored.publicKey) : new Uint8Array(stored.publicKey),
8066
+ privateKey,
8067
+ expiry: stored.expiry,
8068
+ maxValue: BigInt(stored.maxValue),
8069
+ chainScopes: stored.chainScopes ?? [],
8070
+ userKeyHash: stored.userKeyHash
8071
+ };
8072
+ }
8073
+ getRawRecords() {
8074
+ const records = [];
8075
+ const prefix = this.getSessionStoragePrefix();
8076
+ for (let index = 0; index < localStorage.length; index++) {
8077
+ const key = localStorage.key(index);
8078
+ if (!key || !key.startsWith(prefix)) {
8079
+ continue;
8080
+ }
8081
+ const value = localStorage.getItem(key);
8082
+ if (!value) {
8083
+ continue;
8084
+ }
8085
+ records.push(JSON.parse(value));
8086
+ }
8087
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
8088
+ if (legacyValue) {
8089
+ records.push(JSON.parse(legacyValue));
8090
+ }
8091
+ return records;
8092
+ }
8093
+ async getValidRecords() {
8094
+ const now = Date.now();
8095
+ const validRecords = [];
8096
+ for (const record of this.getRawRecords()) {
8097
+ if (record.expiry <= now) {
8098
+ await this.remove(record.keyHash);
8099
+ continue;
8100
+ }
8101
+ validRecords.push(record);
8102
+ }
8103
+ return validRecords.sort((left, right) => right.savedAt - left.savedAt);
7967
8104
  }
7968
8105
  /**
7969
8106
  * Get or derive encryption key
@@ -7992,7 +8129,7 @@ var LocalStorageSessionStorage = class {
7992
8129
  userKeyHash: session.userKeyHash,
7993
8130
  savedAt: Date.now()
7994
8131
  };
7995
- localStorage.setItem(this.storageKey, JSON.stringify(storageObject));
8132
+ localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
7996
8133
  } catch (error) {
7997
8134
  if (error instanceof SessionError) {
7998
8135
  throw error;
@@ -8005,32 +8142,15 @@ var LocalStorageSessionStorage = class {
8005
8142
  }
8006
8143
  }
8007
8144
  /**
8008
- * Load the active session (decrypts private key)
8145
+ * Load a session (decrypts private key)
8009
8146
  */
8010
- async load() {
8147
+ async load(keyHash) {
8011
8148
  try {
8012
- const data = localStorage.getItem(this.storageKey);
8013
- if (!data) {
8149
+ const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
8150
+ if (records.length === 0) {
8014
8151
  return null;
8015
8152
  }
8016
- const stored = JSON.parse(data);
8017
- if (stored.expiry <= Date.now()) {
8018
- await this.clear();
8019
- return null;
8020
- }
8021
- const key = await this.getEncryptionKey();
8022
- const encryptedPrivateKey = ethers10.getBytes(stored.encryptedPrivateKey);
8023
- const privateKey = await decrypt(encryptedPrivateKey, key);
8024
- const session = {
8025
- keyHash: stored.keyHash,
8026
- publicKey: ethers10.getBytes(stored.publicKey),
8027
- privateKey,
8028
- expiry: stored.expiry,
8029
- maxValue: BigInt(stored.maxValue),
8030
- chainScopes: stored.chainScopes,
8031
- userKeyHash: stored.userKeyHash
8032
- };
8033
- return session;
8153
+ return this.deserializeSession(records[0]);
8034
8154
  } catch (error) {
8035
8155
  await this.clear();
8036
8156
  if (error instanceof SessionError) {
@@ -8043,12 +8163,55 @@ var LocalStorageSessionStorage = class {
8043
8163
  );
8044
8164
  }
8045
8165
  }
8166
+ async loadAll() {
8167
+ try {
8168
+ const records = await this.getValidRecords();
8169
+ return Promise.all(records.map((record) => this.deserializeSession(record)));
8170
+ } catch (error) {
8171
+ await this.clear();
8172
+ if (error instanceof SessionError) {
8173
+ throw error;
8174
+ }
8175
+ throw new SessionError(
8176
+ "Failed to load sessions",
8177
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
8178
+ error
8179
+ );
8180
+ }
8181
+ }
8182
+ async remove(keyHash) {
8183
+ try {
8184
+ localStorage.removeItem(this.getSessionStorageKey(keyHash));
8185
+ const legacyValue = localStorage.getItem(this.legacyStorageKey);
8186
+ if (legacyValue) {
8187
+ const legacyRecord = JSON.parse(legacyValue);
8188
+ if (legacyRecord.keyHash === keyHash) {
8189
+ localStorage.removeItem(this.legacyStorageKey);
8190
+ }
8191
+ }
8192
+ } catch (error) {
8193
+ throw new SessionError(
8194
+ "Failed to remove session",
8195
+ "STORAGE_ERROR" /* STORAGE_ERROR */,
8196
+ error
8197
+ );
8198
+ }
8199
+ }
8046
8200
  /**
8047
8201
  * Clear all sessions
8048
8202
  */
8049
8203
  async clear() {
8050
8204
  try {
8051
- localStorage.removeItem(this.storageKey);
8205
+ const keysToRemove = [];
8206
+ const prefix = this.getSessionStoragePrefix();
8207
+ for (let index = 0; index < localStorage.length; index++) {
8208
+ const key = localStorage.key(index);
8209
+ if (key && key.startsWith(prefix)) {
8210
+ keysToRemove.push(key);
8211
+ }
8212
+ }
8213
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
8214
+ localStorage.removeItem(this.legacyStorageKey);
8052
8215
  } catch (error) {
8053
8216
  throw new SessionError(
8054
8217
  "Failed to clear sessions",
@@ -8060,9 +8223,9 @@ var LocalStorageSessionStorage = class {
8060
8223
  /**
8061
8224
  * Check if any session exists
8062
8225
  */
8063
- async exists() {
8226
+ async exists(keyHash) {
8064
8227
  try {
8065
- return localStorage.getItem(this.storageKey) !== null;
8228
+ return await this.load(keyHash) !== null;
8066
8229
  } catch {
8067
8230
  return false;
8068
8231
  }
@@ -8127,6 +8290,14 @@ var SessionManager = class {
8127
8290
  refreshTimer = null;
8128
8291
  eventCallbacks = [];
8129
8292
  debug;
8293
+ resolveConfig(configOverride) {
8294
+ const resolvedConfig = {
8295
+ ...this.config,
8296
+ ...configOverride
8297
+ };
8298
+ validateSessionConfig(resolvedConfig);
8299
+ return resolvedConfig;
8300
+ }
8130
8301
  // ========================================================================
8131
8302
  // Session Lifecycle
8132
8303
  // ========================================================================
@@ -8143,15 +8314,16 @@ var SessionManager = class {
8143
8314
  * @returns Created session key
8144
8315
  * @throws SessionError if registration fails
8145
8316
  */
8146
- async createSession() {
8317
+ async createSession(configOverride) {
8147
8318
  try {
8148
8319
  this.log("Creating new session...");
8320
+ const sessionConfig = this.resolveConfig(configOverride);
8149
8321
  const keyPair = generateSecp256k1KeyPair();
8150
8322
  const keyHash = computeSessionKeyHash(keyPair.publicKey);
8151
8323
  this.log("Generated session key:", keyHash);
8152
8324
  const challenge = ethers11.solidityPacked(
8153
8325
  ["string", "bytes32", "uint256", "uint256"],
8154
- ["registerSession", keyHash, this.config.duration, this.config.maxValue]
8326
+ ["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
8155
8327
  );
8156
8328
  this.log("Challenge prepared, requesting Passkey signature...");
8157
8329
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
@@ -8161,20 +8333,20 @@ var SessionManager = class {
8161
8333
  publicKeyX: this.credential.publicKeyX,
8162
8334
  publicKeyY: this.credential.publicKeyY,
8163
8335
  sessionKeyHash: keyHash,
8164
- duration: this.config.duration,
8165
- maxValue: this.config.maxValue,
8336
+ duration: sessionConfig.duration,
8337
+ maxValue: sessionConfig.maxValue,
8166
8338
  requireUV: true
8167
8339
  };
8168
8340
  await this.hubClient.registerSession(registerParams);
8169
8341
  this.log("Session registered on Hub");
8170
- const expiry = Date.now() + this.config.duration * 1e3;
8342
+ const expiry = Date.now() + sessionConfig.duration * 1e3;
8171
8343
  this.currentSession = {
8172
8344
  publicKey: keyPair.publicKey,
8173
8345
  privateKey: keyPair.privateKey,
8174
8346
  keyHash,
8175
8347
  expiry,
8176
- maxValue: this.config.maxValue,
8177
- chainScopes: this.config.chainScopes,
8348
+ maxValue: sessionConfig.maxValue,
8349
+ chainScopes: sessionConfig.chainScopes,
8178
8350
  userKeyHash: this.credential.keyHash
8179
8351
  };
8180
8352
  await this.storage.save(this.currentSession);
@@ -8199,12 +8371,15 @@ var SessionManager = class {
8199
8371
  *
8200
8372
  * @returns Loaded session or null if no valid session exists
8201
8373
  */
8202
- async loadSession() {
8374
+ async loadSession(keyHash) {
8203
8375
  try {
8204
- this.log("Loading session from storage...");
8205
- const session = await this.storage.load();
8376
+ this.log("Loading session from storage...", keyHash ?? "latest");
8377
+ const session = await this.storage.load(keyHash);
8206
8378
  if (!session) {
8207
8379
  this.log("No session found in storage");
8380
+ if (!keyHash) {
8381
+ this.currentSession = null;
8382
+ }
8208
8383
  return null;
8209
8384
  }
8210
8385
  if (session.expiry <= Date.now()) {
@@ -8221,27 +8396,43 @@ var SessionManager = class {
8221
8396
  return session;
8222
8397
  } catch (error) {
8223
8398
  this.log("Failed to load session:", error);
8224
- await this.storage.clear();
8399
+ if (!keyHash) {
8400
+ await this.storage.clear();
8401
+ }
8225
8402
  return null;
8226
8403
  }
8227
8404
  }
8405
+ async listSessions() {
8406
+ return this.storage.loadAll();
8407
+ }
8408
+ async selectSession(keyHash) {
8409
+ const session = await this.loadSession(keyHash);
8410
+ if (!session) {
8411
+ throw new SessionError(
8412
+ `Session ${keyHash} not found`,
8413
+ "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */
8414
+ );
8415
+ }
8416
+ return session;
8417
+ }
8228
8418
  /**
8229
8419
  * Revoke the current session (requires biometric authentication)
8230
8420
  *
8231
8421
  * @throws SessionError if no active session or revocation fails
8232
8422
  */
8233
- async revokeSession() {
8234
- if (!this.currentSession) {
8423
+ async revokeSession(keyHash) {
8424
+ const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8425
+ if (!targetSession) {
8235
8426
  throw new SessionError(
8236
- "No active session to revoke",
8237
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8427
+ keyHash ? `Session ${keyHash} not found` : "No active session to revoke",
8428
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8238
8429
  );
8239
8430
  }
8240
8431
  try {
8241
- this.log("Revoking session:", this.currentSession.keyHash);
8432
+ this.log("Revoking session:", targetSession.keyHash);
8242
8433
  const challenge = ethers11.solidityPacked(
8243
8434
  ["string", "bytes32"],
8244
- ["revokeSession", this.currentSession.keyHash]
8435
+ ["revokeSession", targetSession.keyHash]
8245
8436
  );
8246
8437
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
8247
8438
  this.log("Passkey signature obtained, revoking on Hub...");
@@ -8249,18 +8440,24 @@ var SessionManager = class {
8249
8440
  signature,
8250
8441
  publicKeyX: this.credential.publicKeyX,
8251
8442
  publicKeyY: this.credential.publicKeyY,
8252
- sessionKeyHash: this.currentSession.keyHash,
8443
+ sessionKeyHash: targetSession.keyHash,
8253
8444
  requireUV: true
8254
8445
  };
8255
8446
  await this.hubClient.revokeSession(revokeParams);
8256
8447
  this.log("Session revoked on Hub");
8257
- await this.storage.clear();
8258
- if (this.refreshTimer) {
8259
- clearTimeout(this.refreshTimer);
8260
- this.refreshTimer = null;
8448
+ await this.storage.remove(targetSession.keyHash);
8449
+ const revokedKeyHash = targetSession.keyHash;
8450
+ const revokedCurrentSession = this.currentSession?.keyHash === revokedKeyHash;
8451
+ if (revokedCurrentSession) {
8452
+ if (this.refreshTimer) {
8453
+ clearTimeout(this.refreshTimer);
8454
+ this.refreshTimer = null;
8455
+ }
8456
+ this.currentSession = await this.storage.load();
8457
+ if (this.currentSession && this.config.autoRefresh) {
8458
+ this.scheduleRefresh();
8459
+ }
8261
8460
  }
8262
- const revokedKeyHash = this.currentSession.keyHash;
8263
- this.currentSession = null;
8264
8461
  this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
8265
8462
  this.log("Session revoked successfully");
8266
8463
  } catch (error) {
@@ -8338,45 +8535,46 @@ var SessionManager = class {
8338
8535
  * @returns Session signature
8339
8536
  * @throws SessionError if no active session, expired, or value exceeds limit
8340
8537
  */
8341
- async signWithSession(action) {
8342
- if (!this.currentSession) {
8538
+ async signWithSession(action, keyHash) {
8539
+ const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8540
+ if (!session) {
8343
8541
  throw new SessionError(
8344
- "No active session available",
8345
- "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8542
+ keyHash ? `Session ${keyHash} not found` : "No active session available",
8543
+ keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
8346
8544
  );
8347
8545
  }
8348
8546
  const now = Date.now();
8349
- if (now >= this.currentSession.expiry) {
8350
- this.emit({ type: "session-expired", keyHash: this.currentSession.keyHash });
8547
+ if (now >= session.expiry) {
8548
+ this.emit({ type: "session-expired", keyHash: session.keyHash });
8351
8549
  throw new SessionError(
8352
8550
  "Session has expired",
8353
8551
  "SESSION_EXPIRED" /* SESSION_EXPIRED */
8354
8552
  );
8355
8553
  }
8356
- if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {
8554
+ if (session.maxValue > 0n && action.value > session.maxValue) {
8357
8555
  throw new SessionError(
8358
- `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,
8556
+ `Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
8359
8557
  "VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
8360
- { value: action.value, limit: this.currentSession.maxValue }
8558
+ { value: action.value, limit: session.maxValue }
8361
8559
  );
8362
8560
  }
8363
- if (this.currentSession.chainScopes.length > 0 && !this.currentSession.chainScopes.includes(action.targetChain)) {
8561
+ if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
8364
8562
  throw new SessionError(
8365
8563
  `Chain ${action.targetChain} not in session scope`,
8366
8564
  "CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
8367
- { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }
8565
+ { chain: action.targetChain, allowedChains: session.chainScopes }
8368
8566
  );
8369
8567
  }
8370
8568
  this.log("Signing action with session key...");
8371
8569
  const messageHash = hashAction(action);
8372
8570
  const { signature } = signWithSessionKey(
8373
- this.currentSession.privateKey,
8571
+ session.privateKey,
8374
8572
  messageHash
8375
8573
  );
8376
8574
  const sessionSignature = {
8377
8575
  signature,
8378
- sessionKeyHash: this.currentSession.keyHash,
8379
- userKeyHash: this.currentSession.userKeyHash,
8576
+ sessionKeyHash: session.keyHash,
8577
+ userKeyHash: session.userKeyHash,
8380
8578
  timestamp: now,
8381
8579
  nonce: action.nonce
8382
8580
  };
@@ -8389,8 +8587,8 @@ var SessionManager = class {
8389
8587
  * @param action Action parameters
8390
8588
  * @returns Session-signed action ready for submission
8391
8589
  */
8392
- async signAction(action) {
8393
- const signature = await this.signWithSession(action);
8590
+ async signAction(action, keyHash) {
8591
+ const signature = await this.signWithSession(action, keyHash);
8394
8592
  return {
8395
8593
  action,
8396
8594
  signature,
@@ -9253,6 +9451,7 @@ export {
9253
9451
  calculatePercentage,
9254
9452
  computeKeyHash,
9255
9453
  computeSessionKeyHash,
9454
+ configureDefaultRpcUrls,
9256
9455
  createAuditEntry,
9257
9456
  createChainClient,
9258
9457
  createChainDetector,
@@ -9323,6 +9522,7 @@ export {
9323
9522
  getExplorerUrl,
9324
9523
  getFeatureFlags,
9325
9524
  getHubChains,
9525
+ getRpcUrlOverride,
9326
9526
  getSequenceFromTxReceipt,
9327
9527
  getContractPrincipal as getStacksContractPrincipal,
9328
9528
  getStacksExplorerAddressUrl,