@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.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-PRHNGA4G.mjs";
30
+ } from "./chunk-E3SU36C2.mjs";
29
31
  import {
30
32
  StarknetClient
31
- } from "./chunk-EFIURACP.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,
@@ -7061,6 +7069,15 @@ var CrossOriginAuth = class {
7061
7069
  if (options?.sessionChallenge) {
7062
7070
  authUrl.searchParams.set("challenge", options.sessionChallenge);
7063
7071
  }
7072
+ if (options?.register) {
7073
+ authUrl.searchParams.set("register", "true");
7074
+ }
7075
+ if (options?.username) {
7076
+ authUrl.searchParams.set("username", options.username);
7077
+ }
7078
+ if (options?.displayName) {
7079
+ authUrl.searchParams.set("display_name", options.displayName);
7080
+ }
7064
7081
  const popup = window.open(
7065
7082
  authUrl.toString(),
7066
7083
  "veridex-auth",
@@ -7114,6 +7131,15 @@ var CrossOriginAuth = class {
7114
7131
  if (options?.sessionChallenge) {
7115
7132
  authUrl.searchParams.set("challenge", options.sessionChallenge);
7116
7133
  }
7134
+ if (options?.register) {
7135
+ authUrl.searchParams.set("register", "true");
7136
+ }
7137
+ if (options?.username) {
7138
+ authUrl.searchParams.set("username", options.username);
7139
+ }
7140
+ if (options?.displayName) {
7141
+ authUrl.searchParams.set("display_name", options.displayName);
7142
+ }
7117
7143
  window.location.href = authUrl.toString();
7118
7144
  return new Promise(() => {
7119
7145
  });
@@ -7164,7 +7190,8 @@ var CrossOriginAuth = class {
7164
7190
  return bytes;
7165
7191
  }
7166
7192
  async requestServerSessionChallenge(options) {
7167
- const response = await fetch(`${this.config.relayerUrl}/session/challenge`, {
7193
+ const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
7194
+ const response = await fetch(challengeUrl, {
7168
7195
  method: "POST",
7169
7196
  headers: { "Content-Type": "application/json" },
7170
7197
  body: JSON.stringify({
@@ -7210,7 +7237,7 @@ var CrossOriginAuth = class {
7210
7237
  if (!session.serverChallengeId) {
7211
7238
  throw new Error("Session must include a relayer-issued serverChallengeId");
7212
7239
  }
7213
- const response = await fetch(`${this.config.relayerUrl}/session/create`, {
7240
+ const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
7214
7241
  method: "POST",
7215
7242
  headers: { "Content-Type": "application/json" },
7216
7243
  body: JSON.stringify({
@@ -7233,7 +7260,9 @@ var CrossOriginAuth = class {
7233
7260
  * Returns the session details if valid, null if expired/revoked.
7234
7261
  */
7235
7262
  async validateServerSession(sessionId) {
7236
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`);
7263
+ const response = await fetch(
7264
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
7265
+ );
7237
7266
  if (!response.ok) {
7238
7267
  return null;
7239
7268
  }
@@ -7247,9 +7276,12 @@ var CrossOriginAuth = class {
7247
7276
  * Revoke a server session token.
7248
7277
  */
7249
7278
  async revokeServerSession(sessionId) {
7250
- const response = await fetch(`${this.config.relayerUrl}/session/${encodeURIComponent(sessionId)}`, {
7251
- method: "DELETE"
7252
- });
7279
+ const response = await fetch(
7280
+ buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
7281
+ {
7282
+ method: "DELETE"
7283
+ }
7284
+ );
7253
7285
  return response.ok;
7254
7286
  }
7255
7287
  /**
@@ -7806,39 +7838,44 @@ var IndexedDBSessionStorage = class {
7806
7838
  );
7807
7839
  }
7808
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
+ }
7809
7864
  /**
7810
- * Load the active session (decrypts private key)
7865
+ * Load a session (decrypts private key)
7811
7866
  */
7812
- async load() {
7867
+ async load(keyHash) {
7813
7868
  try {
7814
7869
  await this.initialize();
7815
7870
  if (!this.db) {
7816
7871
  throw new Error("Database not initialized");
7817
7872
  }
7818
- const allSessions = await this.getAllSessions();
7819
- if (allSessions.length === 0) {
7820
- return null;
7821
- }
7822
- const now = Date.now();
7823
- 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);
7824
7875
  if (validSessions.length === 0) {
7825
- await this.clear();
7826
7876
  return null;
7827
7877
  }
7828
- const stored = validSessions[0];
7829
- const key = await this.getEncryptionKey();
7830
- const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
7831
- const privateKey = await decrypt(encryptedPrivateKey, key);
7832
- const session = {
7833
- keyHash: stored.keyHash,
7834
- publicKey: new Uint8Array(stored.publicKey),
7835
- privateKey,
7836
- expiry: stored.expiry,
7837
- maxValue: BigInt(stored.maxValue),
7838
- chainScopes: stored.chainScopes,
7839
- userKeyHash: stored.userKeyHash
7840
- };
7841
- return session;
7878
+ return this.decryptSession(validSessions[0]);
7842
7879
  } catch (error) {
7843
7880
  if (error instanceof SessionError) {
7844
7881
  throw error;
@@ -7871,6 +7908,75 @@ var IndexedDBSessionStorage = class {
7871
7908
  };
7872
7909
  });
7873
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
+ }
7874
7980
  /**
7875
7981
  * Clear all sessions
7876
7982
  */
@@ -7907,14 +8013,9 @@ var IndexedDBSessionStorage = class {
7907
8013
  /**
7908
8014
  * Check if any session exists
7909
8015
  */
7910
- async exists() {
8016
+ async exists(keyHash) {
7911
8017
  try {
7912
- await this.initialize();
7913
- if (!this.db) {
7914
- return false;
7915
- }
7916
- const sessions = await this.getAllSessions();
7917
- return sessions.length > 0;
8018
+ return await this.load(keyHash) !== null;
7918
8019
  } catch {
7919
8020
  return false;
7920
8021
  }
@@ -7933,7 +8034,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
7933
8034
  var LocalStorageSessionStorage = class {
7934
8035
  encryptionKey = null;
7935
8036
  credentialId;
7936
- storageKey;
8037
+ credentialHash;
8038
+ legacyStorageKey;
7937
8039
  /**
7938
8040
  * @param credentialId User's Passkey credential ID (for key derivation)
7939
8041
  */
@@ -7945,7 +8047,60 @@ var LocalStorageSessionStorage = class {
7945
8047
  );
7946
8048
  }
7947
8049
  this.credentialId = credentialId;
7948
- 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);
7949
8104
  }
7950
8105
  /**
7951
8106
  * Get or derive encryption key
@@ -7974,7 +8129,7 @@ var LocalStorageSessionStorage = class {
7974
8129
  userKeyHash: session.userKeyHash,
7975
8130
  savedAt: Date.now()
7976
8131
  };
7977
- localStorage.setItem(this.storageKey, JSON.stringify(storageObject));
8132
+ localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
7978
8133
  } catch (error) {
7979
8134
  if (error instanceof SessionError) {
7980
8135
  throw error;
@@ -7987,32 +8142,15 @@ var LocalStorageSessionStorage = class {
7987
8142
  }
7988
8143
  }
7989
8144
  /**
7990
- * Load the active session (decrypts private key)
8145
+ * Load a session (decrypts private key)
7991
8146
  */
7992
- async load() {
8147
+ async load(keyHash) {
7993
8148
  try {
7994
- const data = localStorage.getItem(this.storageKey);
7995
- if (!data) {
7996
- return null;
7997
- }
7998
- const stored = JSON.parse(data);
7999
- if (stored.expiry <= Date.now()) {
8000
- await this.clear();
8149
+ const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
8150
+ if (records.length === 0) {
8001
8151
  return null;
8002
8152
  }
8003
- const key = await this.getEncryptionKey();
8004
- const encryptedPrivateKey = ethers10.getBytes(stored.encryptedPrivateKey);
8005
- const privateKey = await decrypt(encryptedPrivateKey, key);
8006
- const session = {
8007
- keyHash: stored.keyHash,
8008
- publicKey: ethers10.getBytes(stored.publicKey),
8009
- privateKey,
8010
- expiry: stored.expiry,
8011
- maxValue: BigInt(stored.maxValue),
8012
- chainScopes: stored.chainScopes,
8013
- userKeyHash: stored.userKeyHash
8014
- };
8015
- return session;
8153
+ return this.deserializeSession(records[0]);
8016
8154
  } catch (error) {
8017
8155
  await this.clear();
8018
8156
  if (error instanceof SessionError) {
@@ -8025,12 +8163,55 @@ var LocalStorageSessionStorage = class {
8025
8163
  );
8026
8164
  }
8027
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
+ }
8028
8200
  /**
8029
8201
  * Clear all sessions
8030
8202
  */
8031
8203
  async clear() {
8032
8204
  try {
8033
- 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);
8034
8215
  } catch (error) {
8035
8216
  throw new SessionError(
8036
8217
  "Failed to clear sessions",
@@ -8042,9 +8223,9 @@ var LocalStorageSessionStorage = class {
8042
8223
  /**
8043
8224
  * Check if any session exists
8044
8225
  */
8045
- async exists() {
8226
+ async exists(keyHash) {
8046
8227
  try {
8047
- return localStorage.getItem(this.storageKey) !== null;
8228
+ return await this.load(keyHash) !== null;
8048
8229
  } catch {
8049
8230
  return false;
8050
8231
  }
@@ -8109,6 +8290,14 @@ var SessionManager = class {
8109
8290
  refreshTimer = null;
8110
8291
  eventCallbacks = [];
8111
8292
  debug;
8293
+ resolveConfig(configOverride) {
8294
+ const resolvedConfig = {
8295
+ ...this.config,
8296
+ ...configOverride
8297
+ };
8298
+ validateSessionConfig(resolvedConfig);
8299
+ return resolvedConfig;
8300
+ }
8112
8301
  // ========================================================================
8113
8302
  // Session Lifecycle
8114
8303
  // ========================================================================
@@ -8125,15 +8314,16 @@ var SessionManager = class {
8125
8314
  * @returns Created session key
8126
8315
  * @throws SessionError if registration fails
8127
8316
  */
8128
- async createSession() {
8317
+ async createSession(configOverride) {
8129
8318
  try {
8130
8319
  this.log("Creating new session...");
8320
+ const sessionConfig = this.resolveConfig(configOverride);
8131
8321
  const keyPair = generateSecp256k1KeyPair();
8132
8322
  const keyHash = computeSessionKeyHash(keyPair.publicKey);
8133
8323
  this.log("Generated session key:", keyHash);
8134
8324
  const challenge = ethers11.solidityPacked(
8135
8325
  ["string", "bytes32", "uint256", "uint256"],
8136
- ["registerSession", keyHash, this.config.duration, this.config.maxValue]
8326
+ ["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
8137
8327
  );
8138
8328
  this.log("Challenge prepared, requesting Passkey signature...");
8139
8329
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
@@ -8143,20 +8333,20 @@ var SessionManager = class {
8143
8333
  publicKeyX: this.credential.publicKeyX,
8144
8334
  publicKeyY: this.credential.publicKeyY,
8145
8335
  sessionKeyHash: keyHash,
8146
- duration: this.config.duration,
8147
- maxValue: this.config.maxValue,
8336
+ duration: sessionConfig.duration,
8337
+ maxValue: sessionConfig.maxValue,
8148
8338
  requireUV: true
8149
8339
  };
8150
8340
  await this.hubClient.registerSession(registerParams);
8151
8341
  this.log("Session registered on Hub");
8152
- const expiry = Date.now() + this.config.duration * 1e3;
8342
+ const expiry = Date.now() + sessionConfig.duration * 1e3;
8153
8343
  this.currentSession = {
8154
8344
  publicKey: keyPair.publicKey,
8155
8345
  privateKey: keyPair.privateKey,
8156
8346
  keyHash,
8157
8347
  expiry,
8158
- maxValue: this.config.maxValue,
8159
- chainScopes: this.config.chainScopes,
8348
+ maxValue: sessionConfig.maxValue,
8349
+ chainScopes: sessionConfig.chainScopes,
8160
8350
  userKeyHash: this.credential.keyHash
8161
8351
  };
8162
8352
  await this.storage.save(this.currentSession);
@@ -8181,12 +8371,15 @@ var SessionManager = class {
8181
8371
  *
8182
8372
  * @returns Loaded session or null if no valid session exists
8183
8373
  */
8184
- async loadSession() {
8374
+ async loadSession(keyHash) {
8185
8375
  try {
8186
- this.log("Loading session from storage...");
8187
- const session = await this.storage.load();
8376
+ this.log("Loading session from storage...", keyHash ?? "latest");
8377
+ const session = await this.storage.load(keyHash);
8188
8378
  if (!session) {
8189
8379
  this.log("No session found in storage");
8380
+ if (!keyHash) {
8381
+ this.currentSession = null;
8382
+ }
8190
8383
  return null;
8191
8384
  }
8192
8385
  if (session.expiry <= Date.now()) {
@@ -8203,27 +8396,43 @@ var SessionManager = class {
8203
8396
  return session;
8204
8397
  } catch (error) {
8205
8398
  this.log("Failed to load session:", error);
8206
- await this.storage.clear();
8399
+ if (!keyHash) {
8400
+ await this.storage.clear();
8401
+ }
8207
8402
  return null;
8208
8403
  }
8209
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
+ }
8210
8418
  /**
8211
8419
  * Revoke the current session (requires biometric authentication)
8212
8420
  *
8213
8421
  * @throws SessionError if no active session or revocation fails
8214
8422
  */
8215
- async revokeSession() {
8216
- if (!this.currentSession) {
8423
+ async revokeSession(keyHash) {
8424
+ const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8425
+ if (!targetSession) {
8217
8426
  throw new SessionError(
8218
- "No active session to revoke",
8219
- "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 */
8220
8429
  );
8221
8430
  }
8222
8431
  try {
8223
- this.log("Revoking session:", this.currentSession.keyHash);
8432
+ this.log("Revoking session:", targetSession.keyHash);
8224
8433
  const challenge = ethers11.solidityPacked(
8225
8434
  ["string", "bytes32"],
8226
- ["revokeSession", this.currentSession.keyHash]
8435
+ ["revokeSession", targetSession.keyHash]
8227
8436
  );
8228
8437
  const signature = await this.passkeySign(ethers11.getBytes(challenge));
8229
8438
  this.log("Passkey signature obtained, revoking on Hub...");
@@ -8231,18 +8440,24 @@ var SessionManager = class {
8231
8440
  signature,
8232
8441
  publicKeyX: this.credential.publicKeyX,
8233
8442
  publicKeyY: this.credential.publicKeyY,
8234
- sessionKeyHash: this.currentSession.keyHash,
8443
+ sessionKeyHash: targetSession.keyHash,
8235
8444
  requireUV: true
8236
8445
  };
8237
8446
  await this.hubClient.revokeSession(revokeParams);
8238
8447
  this.log("Session revoked on Hub");
8239
- await this.storage.clear();
8240
- if (this.refreshTimer) {
8241
- clearTimeout(this.refreshTimer);
8242
- 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
+ }
8243
8460
  }
8244
- const revokedKeyHash = this.currentSession.keyHash;
8245
- this.currentSession = null;
8246
8461
  this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
8247
8462
  this.log("Session revoked successfully");
8248
8463
  } catch (error) {
@@ -8320,45 +8535,46 @@ var SessionManager = class {
8320
8535
  * @returns Session signature
8321
8536
  * @throws SessionError if no active session, expired, or value exceeds limit
8322
8537
  */
8323
- async signWithSession(action) {
8324
- if (!this.currentSession) {
8538
+ async signWithSession(action, keyHash) {
8539
+ const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
8540
+ if (!session) {
8325
8541
  throw new SessionError(
8326
- "No active session available",
8327
- "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 */
8328
8544
  );
8329
8545
  }
8330
8546
  const now = Date.now();
8331
- if (now >= this.currentSession.expiry) {
8332
- this.emit({ type: "session-expired", keyHash: this.currentSession.keyHash });
8547
+ if (now >= session.expiry) {
8548
+ this.emit({ type: "session-expired", keyHash: session.keyHash });
8333
8549
  throw new SessionError(
8334
8550
  "Session has expired",
8335
8551
  "SESSION_EXPIRED" /* SESSION_EXPIRED */
8336
8552
  );
8337
8553
  }
8338
- if (this.currentSession.maxValue > 0n && action.value > this.currentSession.maxValue) {
8554
+ if (session.maxValue > 0n && action.value > session.maxValue) {
8339
8555
  throw new SessionError(
8340
- `Transaction value (${action.value}) exceeds session limit (${this.currentSession.maxValue})`,
8556
+ `Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
8341
8557
  "VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
8342
- { value: action.value, limit: this.currentSession.maxValue }
8558
+ { value: action.value, limit: session.maxValue }
8343
8559
  );
8344
8560
  }
8345
- if (this.currentSession.chainScopes.length > 0 && !this.currentSession.chainScopes.includes(action.targetChain)) {
8561
+ if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
8346
8562
  throw new SessionError(
8347
8563
  `Chain ${action.targetChain} not in session scope`,
8348
8564
  "CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
8349
- { chain: action.targetChain, allowedChains: this.currentSession.chainScopes }
8565
+ { chain: action.targetChain, allowedChains: session.chainScopes }
8350
8566
  );
8351
8567
  }
8352
8568
  this.log("Signing action with session key...");
8353
8569
  const messageHash = hashAction(action);
8354
8570
  const { signature } = signWithSessionKey(
8355
- this.currentSession.privateKey,
8571
+ session.privateKey,
8356
8572
  messageHash
8357
8573
  );
8358
8574
  const sessionSignature = {
8359
8575
  signature,
8360
- sessionKeyHash: this.currentSession.keyHash,
8361
- userKeyHash: this.currentSession.userKeyHash,
8576
+ sessionKeyHash: session.keyHash,
8577
+ userKeyHash: session.userKeyHash,
8362
8578
  timestamp: now,
8363
8579
  nonce: action.nonce
8364
8580
  };
@@ -8371,8 +8587,8 @@ var SessionManager = class {
8371
8587
  * @param action Action parameters
8372
8588
  * @returns Session-signed action ready for submission
8373
8589
  */
8374
- async signAction(action) {
8375
- const signature = await this.signWithSession(action);
8590
+ async signAction(action, keyHash) {
8591
+ const signature = await this.signWithSession(action, keyHash);
8376
8592
  return {
8377
8593
  action,
8378
8594
  signature,
@@ -9235,6 +9451,7 @@ export {
9235
9451
  calculatePercentage,
9236
9452
  computeKeyHash,
9237
9453
  computeSessionKeyHash,
9454
+ configureDefaultRpcUrls,
9238
9455
  createAuditEntry,
9239
9456
  createChainClient,
9240
9457
  createChainDetector,
@@ -9305,6 +9522,7 @@ export {
9305
9522
  getExplorerUrl,
9306
9523
  getFeatureFlags,
9307
9524
  getHubChains,
9525
+ getRpcUrlOverride,
9308
9526
  getSequenceFromTxReceipt,
9309
9527
  getContractPrincipal as getStacksContractPrincipal,
9310
9528
  getStacksExplorerAddressUrl,