@anywalletkit/extension-kit 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -110,6 +110,8 @@ interface VaultEnvelopeV2 {
110
110
  createdAt: number;
111
111
  /** When a v1 envelope was re-sealed as v2. */
112
112
  upgradedAt?: number;
113
+ /** When {@link Vault.rotateVaultKey} last replaced the DEK. */
114
+ rotatedAt?: number;
113
115
  }
114
116
  type VaultEnvelope = VaultEnvelopeV1 | VaultEnvelopeV2;
115
117
  /** Where the envelope lives. `chromeLocalVaultStorage()` for the extension, `memoryVaultStorage()` for tests. */
@@ -170,8 +172,24 @@ declare class Vault {
170
172
  */
171
173
  unlock(password: string): Promise<Uint8Array>;
172
174
  private _unlock;
173
- /** Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched. */
175
+ /**
176
+ * Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched —
177
+ * and so is the DEK: after a suspected compromise (a copied profile, a leaked session, a lost passkey)
178
+ * this is not enough, because whoever holds the DEK still opens every secret, old and new. Use
179
+ * {@link Vault.rotateVaultKey} then.
180
+ */
174
181
  changePassword(oldPassword: string, newPassword: string): Promise<void>;
182
+ /**
183
+ * Replace the DEK (scan 2026-10-27 modules, F30): a fresh random DEK, every secret re-sealed under it,
184
+ * the DEK wrapped under `password` with a fresh salt — written as one envelope, so a failure leaves the
185
+ * old vault as it was. Returns the new DEK: hand it to `session.unlock(dek)`, which overwrites the old
186
+ * one in `chrome.storage.session`. A DEK copied before the rotation opens nothing in the new envelope,
187
+ * and {@link Vault.setSecret} refuses it, so a stale session cannot seal new secrets under it.
188
+ *
189
+ * Passkeys are dropped — their boxes hold the old DEK and cannot be re-wrapped without their PRF
190
+ * output — and must be registered again ({@link Vault.addPasskey} with the new DEK).
191
+ */
192
+ rotateVaultKey(password: string): Promise<Uint8Array>;
175
193
  /** Public view of the registered passkeys (ids, labels; whether each can verify assertions). */
176
194
  listPasskeys(): Promise<Array<{
177
195
  id: string;
@@ -200,9 +218,13 @@ declare class Vault {
200
218
  private _addPasskey;
201
219
  /** Unseal the DEK with a passkey's PRF output. `wrong-password` when the box does not open, `missing` when the id is unknown. */
202
220
  unlockWithPasskey(id: string, prf: Uint8Array): Promise<Uint8Array>;
221
+ /** Forget one passkey's box. A DEK that passkey already unwrapped stays valid: after a lost or compromised passkey, {@link Vault.rotateVaultKey}. */
203
222
  removePasskey(id: string): Promise<void>;
204
223
  listSecretIds(): Promise<string[]>;
205
- /** Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). */
224
+ /**
225
+ * Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). The DEK must open the
226
+ * vault's secrets (`locked` otherwise): a key retired by {@link Vault.rotateVaultKey} never seals a new one.
227
+ */
206
228
  setSecret(dek: Uint8Array, sourceId: string, secret: Uint8Array): Promise<void>;
207
229
  /** Unseal one secret. `null` when the id is unknown; the caller zeroizes the result after use. */
208
230
  getSecret(dek: Uint8Array, sourceId: string): Promise<Uint8Array | null>;
@@ -405,6 +427,15 @@ interface RelayEvent {
405
427
  }
406
428
  type RelayToWorker = RelayRequest;
407
429
  type RelayToContent = RelayResponse | RelayEvent;
430
+ /** Longest method name a request may carry. */
431
+ declare const RELAY_METHOD_MAX = 128;
432
+ /**
433
+ * A method name as the providers spell them (`eth_sendTransaction`, `signAndSendTransaction`,
434
+ * `tron_requestAccounts`): letters, digits and `_`, at most {@link RELAY_METHOD_MAX}. Anything else
435
+ * is dropped at the relay, so a megabyte "method" never reaches a regex, a log or an error message
436
+ * (scan 2026-10-27 modules, F5).
437
+ */
438
+ declare const isRelayMethod: (x: unknown) => x is string;
408
439
  declare function isPageRequest(x: unknown): x is PageRequest;
409
440
  declare function isPageResponse(x: unknown): x is PageResponse;
410
441
  declare function isPageEvent(x: unknown): x is PageEvent;
@@ -1605,4 +1636,4 @@ declare class RecipientBook {
1605
1636
  }>;
1606
1637
  }
1607
1638
 
1608
- export { ACTIVE_STATUSES, APPROVALS_MAX_PENDING_PER_ORIGIN, type AddChainApproval, type AlarmsLike, type ApprovalKind, ApprovalQueue, type ApprovalQueueOptions, type ApprovalRequest, type ApprovalWindow, type AssertionExpectations, type AssertionInput, type AssertionVerdict, BTC_CHAIN, BTC_ESPLORA, CHAIN_ACCOUNT_KEYS, type ChainAccountsKey, type ChainDescriptor, type ConnectApproval, DEFAULT_CHAIN, DEFAULT_NETWORKS, type EarnApproval, type EarnPlan, type EarnReviewMeta, type EarnTx, type EvmNetwork, type EvmSigner, FLOOR_TOLERANCE_BPS, type GateMatcher, type GatedOp, type HostCheck, type JsonStorage, KEYRING_STORAGE_KEY, LOOKALIKE_PREFIX, LOOKALIKE_SUFFIX, NEAR_CHAIN, NEAR_PROVIDERS, NON_EVM_CHAINS, NetworksTable, type OriginPermission, OriginRefused, type OriginVia, PAGE_TARGET, PORT_NAME, type PageEvent, type PageMessageEvent, type PageRequest, type PageResponse, type PageWindow, PermissionStore, type PermissionsState, PhishingDetector, type PhishingList, type PortSender, type PreparedTx, QueueLimitError, type QuoteRoutesOptions, READ_METHODS, RELAY_ERRORS, RecipientBook, type RecipientsState, type RelayChain, type RelayError, type RelayErrorOptions, type RelayEvent, type RelayRequest, type RelayResponse, type RelayToContent, type RelayToWorker, RequestRouter, ReviewDeclined, ReviewGate, type RouteListView, type RouteView, type RouterDeps, RouterError, SESSION_DEFAULT_AUTOLOCK_MS, SIGNING_METHODS, SOLANA_CHAIN, SOLANA_RPCS, type SealedBox, Session, type SessionAlarms, type SessionOptions, type SessionStorage, type SignApproval, type SignDeps, type SignRequestInfo, type SiweContext, type SiweInfo, type SiweMessage, type StorageAreaLike, type SwapApproval, type SwapRecord, type SwapRecordStatus, type SwapReviewMeta, SwapTracker, type SwapTrackerDeps, SwapsStore, type SwitchChainApproval, TONCONNECT_ERRORS, TONCONNECT_MAX_MESSAGES, TON_CHAIN, TON_ENDPOINTS, TRON_CHAIN, TRON_PROVIDERS, type TonAddressParts, TonConnectError, type TonConnectMessage, type TonConnectRequest, type TonConnectSendTransaction, type TonSignDataPayload, type TypedData, VAULT_DEFAULT_ITERATIONS, VAULT_LIMITS, VAULT_MIN_ITERATIONS, VAULT_MIN_PASSWORD_LENGTH, VAULT_MIN_SCRYPT, VAULT_SCRYPT, VAULT_STORAGE_KEY, Vault, type VaultEnvelope, type VaultEnvelopeV1, type VaultEnvelopeV2, VaultError, type VaultErrorCode, type VaultKdfInfo, type VaultOptions, type VaultPasskey, type VaultStorage, ZCASH_BLOCKCHAIR, ZCASH_CHAIN, approvalChallenge, caip2FromChainId, chainHex, chainTxMatcher, checkSenderOrigin, chromeAlarms, chromeJsonStorage, chromeKeyringStorage, chromeLocalVaultStorage, chromeSessionStorage, classifySignRequest, createSignHandler, decodedMessage, derToRaw, describeSiwe, earnApprovalPayload, earnPlanMatchers, encodeApproveCalldata, evmCallMatcher, executionFloor, fromBase64Url, hostOf, isCatalogChain, isEnvelopeV1, isEnvelopeV2, isLocalHost, isPageEvent, isPageRequest, isPageResponse, isRelayRequest, isRelayToContent, levenshtein, lookalikeOf, memoryAlarms, memoryApprovalWindow, memoryJsonStorage, memorySessionStorage, memoryVaultStorage, messageText, newRequestId, nonEvmChain, normalizeHost, pageRequestFrom, parseAddChainParams, parseConnectRequest, parseRawAddress, parseSendTransaction, parseSignData, parseSiwe, parseSwapId, planMatchers, prepareTransaction, proofDomain, quoteRoutes, rank, rawToDer, relayError, reviewEarnPlan, reviewSwapPlan, siweProblems, stampOrigin, swapApprovalPayload, toBase64Url, toRelayError, tonConnectErrorCode, tonProofMessage, tonSignDataMessage, typedDataMatcher, vaultSecretStorage, verifyAssertion };
1639
+ export { ACTIVE_STATUSES, APPROVALS_MAX_PENDING_PER_ORIGIN, type AddChainApproval, type AlarmsLike, type ApprovalKind, ApprovalQueue, type ApprovalQueueOptions, type ApprovalRequest, type ApprovalWindow, type AssertionExpectations, type AssertionInput, type AssertionVerdict, BTC_CHAIN, BTC_ESPLORA, CHAIN_ACCOUNT_KEYS, type ChainAccountsKey, type ChainDescriptor, type ConnectApproval, DEFAULT_CHAIN, DEFAULT_NETWORKS, type EarnApproval, type EarnPlan, type EarnReviewMeta, type EarnTx, type EvmNetwork, type EvmSigner, FLOOR_TOLERANCE_BPS, type GateMatcher, type GatedOp, type HostCheck, type JsonStorage, KEYRING_STORAGE_KEY, LOOKALIKE_PREFIX, LOOKALIKE_SUFFIX, NEAR_CHAIN, NEAR_PROVIDERS, NON_EVM_CHAINS, NetworksTable, type OriginPermission, OriginRefused, type OriginVia, PAGE_TARGET, PORT_NAME, type PageEvent, type PageMessageEvent, type PageRequest, type PageResponse, type PageWindow, PermissionStore, type PermissionsState, PhishingDetector, type PhishingList, type PortSender, type PreparedTx, QueueLimitError, type QuoteRoutesOptions, READ_METHODS, RELAY_ERRORS, RELAY_METHOD_MAX, RecipientBook, type RecipientsState, type RelayChain, type RelayError, type RelayErrorOptions, type RelayEvent, type RelayRequest, type RelayResponse, type RelayToContent, type RelayToWorker, RequestRouter, ReviewDeclined, ReviewGate, type RouteListView, type RouteView, type RouterDeps, RouterError, SESSION_DEFAULT_AUTOLOCK_MS, SIGNING_METHODS, SOLANA_CHAIN, SOLANA_RPCS, type SealedBox, Session, type SessionAlarms, type SessionOptions, type SessionStorage, type SignApproval, type SignDeps, type SignRequestInfo, type SiweContext, type SiweInfo, type SiweMessage, type StorageAreaLike, type SwapApproval, type SwapRecord, type SwapRecordStatus, type SwapReviewMeta, SwapTracker, type SwapTrackerDeps, SwapsStore, type SwitchChainApproval, TONCONNECT_ERRORS, TONCONNECT_MAX_MESSAGES, TON_CHAIN, TON_ENDPOINTS, TRON_CHAIN, TRON_PROVIDERS, type TonAddressParts, TonConnectError, type TonConnectMessage, type TonConnectRequest, type TonConnectSendTransaction, type TonSignDataPayload, type TypedData, VAULT_DEFAULT_ITERATIONS, VAULT_LIMITS, VAULT_MIN_ITERATIONS, VAULT_MIN_PASSWORD_LENGTH, VAULT_MIN_SCRYPT, VAULT_SCRYPT, VAULT_STORAGE_KEY, Vault, type VaultEnvelope, type VaultEnvelopeV1, type VaultEnvelopeV2, VaultError, type VaultErrorCode, type VaultKdfInfo, type VaultOptions, type VaultPasskey, type VaultStorage, ZCASH_BLOCKCHAIR, ZCASH_CHAIN, approvalChallenge, caip2FromChainId, chainHex, chainTxMatcher, checkSenderOrigin, chromeAlarms, chromeJsonStorage, chromeKeyringStorage, chromeLocalVaultStorage, chromeSessionStorage, classifySignRequest, createSignHandler, decodedMessage, derToRaw, describeSiwe, earnApprovalPayload, earnPlanMatchers, encodeApproveCalldata, evmCallMatcher, executionFloor, fromBase64Url, hostOf, isCatalogChain, isEnvelopeV1, isEnvelopeV2, isLocalHost, isPageEvent, isPageRequest, isPageResponse, isRelayMethod, isRelayRequest, isRelayToContent, levenshtein, lookalikeOf, memoryAlarms, memoryApprovalWindow, memoryJsonStorage, memorySessionStorage, memoryVaultStorage, messageText, newRequestId, nonEvmChain, normalizeHost, pageRequestFrom, parseAddChainParams, parseConnectRequest, parseRawAddress, parseSendTransaction, parseSignData, parseSiwe, parseSwapId, planMatchers, prepareTransaction, proofDomain, quoteRoutes, rank, rawToDer, relayError, reviewEarnPlan, reviewSwapPlan, siweProblems, stampOrigin, swapApprovalPayload, toBase64Url, toRelayError, tonConnectErrorCode, tonProofMessage, tonSignDataMessage, typedDataMatcher, vaultSecretStorage, verifyAssertion };
package/dist/index.d.ts CHANGED
@@ -110,6 +110,8 @@ interface VaultEnvelopeV2 {
110
110
  createdAt: number;
111
111
  /** When a v1 envelope was re-sealed as v2. */
112
112
  upgradedAt?: number;
113
+ /** When {@link Vault.rotateVaultKey} last replaced the DEK. */
114
+ rotatedAt?: number;
113
115
  }
114
116
  type VaultEnvelope = VaultEnvelopeV1 | VaultEnvelopeV2;
115
117
  /** Where the envelope lives. `chromeLocalVaultStorage()` for the extension, `memoryVaultStorage()` for tests. */
@@ -170,8 +172,24 @@ declare class Vault {
170
172
  */
171
173
  unlock(password: string): Promise<Uint8Array>;
172
174
  private _unlock;
173
- /** Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched. */
175
+ /**
176
+ * Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched —
177
+ * and so is the DEK: after a suspected compromise (a copied profile, a leaked session, a lost passkey)
178
+ * this is not enough, because whoever holds the DEK still opens every secret, old and new. Use
179
+ * {@link Vault.rotateVaultKey} then.
180
+ */
174
181
  changePassword(oldPassword: string, newPassword: string): Promise<void>;
182
+ /**
183
+ * Replace the DEK (scan 2026-10-27 modules, F30): a fresh random DEK, every secret re-sealed under it,
184
+ * the DEK wrapped under `password` with a fresh salt — written as one envelope, so a failure leaves the
185
+ * old vault as it was. Returns the new DEK: hand it to `session.unlock(dek)`, which overwrites the old
186
+ * one in `chrome.storage.session`. A DEK copied before the rotation opens nothing in the new envelope,
187
+ * and {@link Vault.setSecret} refuses it, so a stale session cannot seal new secrets under it.
188
+ *
189
+ * Passkeys are dropped — their boxes hold the old DEK and cannot be re-wrapped without their PRF
190
+ * output — and must be registered again ({@link Vault.addPasskey} with the new DEK).
191
+ */
192
+ rotateVaultKey(password: string): Promise<Uint8Array>;
175
193
  /** Public view of the registered passkeys (ids, labels; whether each can verify assertions). */
176
194
  listPasskeys(): Promise<Array<{
177
195
  id: string;
@@ -200,9 +218,13 @@ declare class Vault {
200
218
  private _addPasskey;
201
219
  /** Unseal the DEK with a passkey's PRF output. `wrong-password` when the box does not open, `missing` when the id is unknown. */
202
220
  unlockWithPasskey(id: string, prf: Uint8Array): Promise<Uint8Array>;
221
+ /** Forget one passkey's box. A DEK that passkey already unwrapped stays valid: after a lost or compromised passkey, {@link Vault.rotateVaultKey}. */
203
222
  removePasskey(id: string): Promise<void>;
204
223
  listSecretIds(): Promise<string[]>;
205
- /** Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). */
224
+ /**
225
+ * Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). The DEK must open the
226
+ * vault's secrets (`locked` otherwise): a key retired by {@link Vault.rotateVaultKey} never seals a new one.
227
+ */
206
228
  setSecret(dek: Uint8Array, sourceId: string, secret: Uint8Array): Promise<void>;
207
229
  /** Unseal one secret. `null` when the id is unknown; the caller zeroizes the result after use. */
208
230
  getSecret(dek: Uint8Array, sourceId: string): Promise<Uint8Array | null>;
@@ -405,6 +427,15 @@ interface RelayEvent {
405
427
  }
406
428
  type RelayToWorker = RelayRequest;
407
429
  type RelayToContent = RelayResponse | RelayEvent;
430
+ /** Longest method name a request may carry. */
431
+ declare const RELAY_METHOD_MAX = 128;
432
+ /**
433
+ * A method name as the providers spell them (`eth_sendTransaction`, `signAndSendTransaction`,
434
+ * `tron_requestAccounts`): letters, digits and `_`, at most {@link RELAY_METHOD_MAX}. Anything else
435
+ * is dropped at the relay, so a megabyte "method" never reaches a regex, a log or an error message
436
+ * (scan 2026-10-27 modules, F5).
437
+ */
438
+ declare const isRelayMethod: (x: unknown) => x is string;
408
439
  declare function isPageRequest(x: unknown): x is PageRequest;
409
440
  declare function isPageResponse(x: unknown): x is PageResponse;
410
441
  declare function isPageEvent(x: unknown): x is PageEvent;
@@ -1605,4 +1636,4 @@ declare class RecipientBook {
1605
1636
  }>;
1606
1637
  }
1607
1638
 
1608
- export { ACTIVE_STATUSES, APPROVALS_MAX_PENDING_PER_ORIGIN, type AddChainApproval, type AlarmsLike, type ApprovalKind, ApprovalQueue, type ApprovalQueueOptions, type ApprovalRequest, type ApprovalWindow, type AssertionExpectations, type AssertionInput, type AssertionVerdict, BTC_CHAIN, BTC_ESPLORA, CHAIN_ACCOUNT_KEYS, type ChainAccountsKey, type ChainDescriptor, type ConnectApproval, DEFAULT_CHAIN, DEFAULT_NETWORKS, type EarnApproval, type EarnPlan, type EarnReviewMeta, type EarnTx, type EvmNetwork, type EvmSigner, FLOOR_TOLERANCE_BPS, type GateMatcher, type GatedOp, type HostCheck, type JsonStorage, KEYRING_STORAGE_KEY, LOOKALIKE_PREFIX, LOOKALIKE_SUFFIX, NEAR_CHAIN, NEAR_PROVIDERS, NON_EVM_CHAINS, NetworksTable, type OriginPermission, OriginRefused, type OriginVia, PAGE_TARGET, PORT_NAME, type PageEvent, type PageMessageEvent, type PageRequest, type PageResponse, type PageWindow, PermissionStore, type PermissionsState, PhishingDetector, type PhishingList, type PortSender, type PreparedTx, QueueLimitError, type QuoteRoutesOptions, READ_METHODS, RELAY_ERRORS, RecipientBook, type RecipientsState, type RelayChain, type RelayError, type RelayErrorOptions, type RelayEvent, type RelayRequest, type RelayResponse, type RelayToContent, type RelayToWorker, RequestRouter, ReviewDeclined, ReviewGate, type RouteListView, type RouteView, type RouterDeps, RouterError, SESSION_DEFAULT_AUTOLOCK_MS, SIGNING_METHODS, SOLANA_CHAIN, SOLANA_RPCS, type SealedBox, Session, type SessionAlarms, type SessionOptions, type SessionStorage, type SignApproval, type SignDeps, type SignRequestInfo, type SiweContext, type SiweInfo, type SiweMessage, type StorageAreaLike, type SwapApproval, type SwapRecord, type SwapRecordStatus, type SwapReviewMeta, SwapTracker, type SwapTrackerDeps, SwapsStore, type SwitchChainApproval, TONCONNECT_ERRORS, TONCONNECT_MAX_MESSAGES, TON_CHAIN, TON_ENDPOINTS, TRON_CHAIN, TRON_PROVIDERS, type TonAddressParts, TonConnectError, type TonConnectMessage, type TonConnectRequest, type TonConnectSendTransaction, type TonSignDataPayload, type TypedData, VAULT_DEFAULT_ITERATIONS, VAULT_LIMITS, VAULT_MIN_ITERATIONS, VAULT_MIN_PASSWORD_LENGTH, VAULT_MIN_SCRYPT, VAULT_SCRYPT, VAULT_STORAGE_KEY, Vault, type VaultEnvelope, type VaultEnvelopeV1, type VaultEnvelopeV2, VaultError, type VaultErrorCode, type VaultKdfInfo, type VaultOptions, type VaultPasskey, type VaultStorage, ZCASH_BLOCKCHAIR, ZCASH_CHAIN, approvalChallenge, caip2FromChainId, chainHex, chainTxMatcher, checkSenderOrigin, chromeAlarms, chromeJsonStorage, chromeKeyringStorage, chromeLocalVaultStorage, chromeSessionStorage, classifySignRequest, createSignHandler, decodedMessage, derToRaw, describeSiwe, earnApprovalPayload, earnPlanMatchers, encodeApproveCalldata, evmCallMatcher, executionFloor, fromBase64Url, hostOf, isCatalogChain, isEnvelopeV1, isEnvelopeV2, isLocalHost, isPageEvent, isPageRequest, isPageResponse, isRelayRequest, isRelayToContent, levenshtein, lookalikeOf, memoryAlarms, memoryApprovalWindow, memoryJsonStorage, memorySessionStorage, memoryVaultStorage, messageText, newRequestId, nonEvmChain, normalizeHost, pageRequestFrom, parseAddChainParams, parseConnectRequest, parseRawAddress, parseSendTransaction, parseSignData, parseSiwe, parseSwapId, planMatchers, prepareTransaction, proofDomain, quoteRoutes, rank, rawToDer, relayError, reviewEarnPlan, reviewSwapPlan, siweProblems, stampOrigin, swapApprovalPayload, toBase64Url, toRelayError, tonConnectErrorCode, tonProofMessage, tonSignDataMessage, typedDataMatcher, vaultSecretStorage, verifyAssertion };
1639
+ export { ACTIVE_STATUSES, APPROVALS_MAX_PENDING_PER_ORIGIN, type AddChainApproval, type AlarmsLike, type ApprovalKind, ApprovalQueue, type ApprovalQueueOptions, type ApprovalRequest, type ApprovalWindow, type AssertionExpectations, type AssertionInput, type AssertionVerdict, BTC_CHAIN, BTC_ESPLORA, CHAIN_ACCOUNT_KEYS, type ChainAccountsKey, type ChainDescriptor, type ConnectApproval, DEFAULT_CHAIN, DEFAULT_NETWORKS, type EarnApproval, type EarnPlan, type EarnReviewMeta, type EarnTx, type EvmNetwork, type EvmSigner, FLOOR_TOLERANCE_BPS, type GateMatcher, type GatedOp, type HostCheck, type JsonStorage, KEYRING_STORAGE_KEY, LOOKALIKE_PREFIX, LOOKALIKE_SUFFIX, NEAR_CHAIN, NEAR_PROVIDERS, NON_EVM_CHAINS, NetworksTable, type OriginPermission, OriginRefused, type OriginVia, PAGE_TARGET, PORT_NAME, type PageEvent, type PageMessageEvent, type PageRequest, type PageResponse, type PageWindow, PermissionStore, type PermissionsState, PhishingDetector, type PhishingList, type PortSender, type PreparedTx, QueueLimitError, type QuoteRoutesOptions, READ_METHODS, RELAY_ERRORS, RELAY_METHOD_MAX, RecipientBook, type RecipientsState, type RelayChain, type RelayError, type RelayErrorOptions, type RelayEvent, type RelayRequest, type RelayResponse, type RelayToContent, type RelayToWorker, RequestRouter, ReviewDeclined, ReviewGate, type RouteListView, type RouteView, type RouterDeps, RouterError, SESSION_DEFAULT_AUTOLOCK_MS, SIGNING_METHODS, SOLANA_CHAIN, SOLANA_RPCS, type SealedBox, Session, type SessionAlarms, type SessionOptions, type SessionStorage, type SignApproval, type SignDeps, type SignRequestInfo, type SiweContext, type SiweInfo, type SiweMessage, type StorageAreaLike, type SwapApproval, type SwapRecord, type SwapRecordStatus, type SwapReviewMeta, SwapTracker, type SwapTrackerDeps, SwapsStore, type SwitchChainApproval, TONCONNECT_ERRORS, TONCONNECT_MAX_MESSAGES, TON_CHAIN, TON_ENDPOINTS, TRON_CHAIN, TRON_PROVIDERS, type TonAddressParts, TonConnectError, type TonConnectMessage, type TonConnectRequest, type TonConnectSendTransaction, type TonSignDataPayload, type TypedData, VAULT_DEFAULT_ITERATIONS, VAULT_LIMITS, VAULT_MIN_ITERATIONS, VAULT_MIN_PASSWORD_LENGTH, VAULT_MIN_SCRYPT, VAULT_SCRYPT, VAULT_STORAGE_KEY, Vault, type VaultEnvelope, type VaultEnvelopeV1, type VaultEnvelopeV2, VaultError, type VaultErrorCode, type VaultKdfInfo, type VaultOptions, type VaultPasskey, type VaultStorage, ZCASH_BLOCKCHAIR, ZCASH_CHAIN, approvalChallenge, caip2FromChainId, chainHex, chainTxMatcher, checkSenderOrigin, chromeAlarms, chromeJsonStorage, chromeKeyringStorage, chromeLocalVaultStorage, chromeSessionStorage, classifySignRequest, createSignHandler, decodedMessage, derToRaw, describeSiwe, earnApprovalPayload, earnPlanMatchers, encodeApproveCalldata, evmCallMatcher, executionFloor, fromBase64Url, hostOf, isCatalogChain, isEnvelopeV1, isEnvelopeV2, isLocalHost, isPageEvent, isPageRequest, isPageResponse, isRelayMethod, isRelayRequest, isRelayToContent, levenshtein, lookalikeOf, memoryAlarms, memoryApprovalWindow, memoryJsonStorage, memorySessionStorage, memoryVaultStorage, messageText, newRequestId, nonEvmChain, normalizeHost, pageRequestFrom, parseAddChainParams, parseConnectRequest, parseRawAddress, parseSendTransaction, parseSignData, parseSiwe, parseSwapId, planMatchers, prepareTransaction, proofDomain, quoteRoutes, rank, rawToDer, relayError, reviewEarnPlan, reviewSwapPlan, siweProblems, stampOrigin, swapApprovalPayload, toBase64Url, toRelayError, tonConnectErrorCode, tonProofMessage, tonSignDataMessage, typedDataMatcher, vaultSecretStorage, verifyAssertion };
package/dist/index.js CHANGED
@@ -144,7 +144,12 @@ var Vault = class {
144
144
  const kek = await this._deriveScrypt(password, fromBase64(envelope.kdf.salt), envelope.kdf);
145
145
  return this._open(kek, envelope.dek, aadDekV2(envelope.kdf), "wrong-password");
146
146
  }
147
- /** Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched. */
147
+ /**
148
+ * Re-wrap the DEK under a new password (fresh salt, current KDF). Secrets and passkeys are untouched —
149
+ * and so is the DEK: after a suspected compromise (a copied profile, a leaked session, a lost passkey)
150
+ * this is not enough, because whoever holds the DEK still opens every secret, old and new. Use
151
+ * {@link Vault.rotateVaultKey} then.
152
+ */
148
153
  async changePassword(oldPassword, newPassword) {
149
154
  requirePassword(newPassword, VAULT_MIN_PASSWORD_LENGTH);
150
155
  requirePassword(oldPassword);
@@ -160,6 +165,45 @@ var Vault = class {
160
165
  }
161
166
  });
162
167
  }
168
+ /**
169
+ * Replace the DEK (scan 2026-10-27 modules, F30): a fresh random DEK, every secret re-sealed under it,
170
+ * the DEK wrapped under `password` with a fresh salt — written as one envelope, so a failure leaves the
171
+ * old vault as it was. Returns the new DEK: hand it to `session.unlock(dek)`, which overwrites the old
172
+ * one in `chrome.storage.session`. A DEK copied before the rotation opens nothing in the new envelope,
173
+ * and {@link Vault.setSecret} refuses it, so a stale session cannot seal new secrets under it.
174
+ *
175
+ * Passkeys are dropped — their boxes hold the old DEK and cannot be re-wrapped without their PRF
176
+ * output — and must be registered again ({@link Vault.addPasskey} with the new DEK).
177
+ */
178
+ async rotateVaultKey(password) {
179
+ requirePassword(password);
180
+ return this._exclusive(async () => {
181
+ const oldDek = await this._unlock(password);
182
+ const dek = this._random(DEK_BYTES);
183
+ try {
184
+ const envelope = await this._load();
185
+ const [oldKey, newKey] = await Promise.all([this._importDek(oldDek), this._importDek(dek)]);
186
+ const secrets = {};
187
+ for (const [id, box] of Object.entries(envelope.secrets)) {
188
+ const plaintext = await this._open(oldKey, box, aadSecret(id), "locked");
189
+ try {
190
+ secrets[id] = await this._seal(newKey, plaintext, aadSecret(id));
191
+ } finally {
192
+ zeroize(plaintext);
193
+ }
194
+ }
195
+ const next = await this._sealEnvelope(password, dek, secrets, [], envelope.createdAt);
196
+ const upgradedAt = isEnvelopeV2(envelope) ? envelope.upgradedAt : void 0;
197
+ await this._write(isEnvelopeV2(next) ? { ...next, ...upgradedAt !== void 0 ? { upgradedAt } : {}, rotatedAt: Date.now() } : next);
198
+ return dek;
199
+ } catch (e) {
200
+ zeroize(dek);
201
+ throw e;
202
+ } finally {
203
+ zeroize(oldDek);
204
+ }
205
+ });
206
+ }
163
207
  // ---- passkeys (v2) ----
164
208
  /** Public view of the registered passkeys (ids, labels; whether each can verify assertions). */
165
209
  async listPasskeys() {
@@ -217,6 +261,7 @@ var Vault = class {
217
261
  zeroize(prf);
218
262
  }
219
263
  }
264
+ /** Forget one passkey's box. A DEK that passkey already unwrapped stays valid: after a lost or compromised passkey, {@link Vault.rotateVaultKey}. */
220
265
  async removePasskey(id) {
221
266
  requireId(id);
222
267
  return this._exclusive(async () => {
@@ -230,13 +275,17 @@ var Vault = class {
230
275
  const envelope = await this._storage.get();
231
276
  return envelope ? Object.keys(envelope.secrets) : [];
232
277
  }
233
- /** Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). */
278
+ /**
279
+ * Seal `secret` under the DEK as `sourceId` (overwrites an entry with the same id). The DEK must open the
280
+ * vault's secrets (`locked` otherwise): a key retired by {@link Vault.rotateVaultKey} never seals a new one.
281
+ */
234
282
  async setSecret(dek, sourceId, secret) {
235
283
  requireId(sourceId);
236
284
  if (secret.length > VAULT_LIMITS.secretBytes) throw new VaultError(`A secret is at most ${VAULT_LIMITS.secretBytes} bytes.`, "invalid-input");
237
285
  const key = await this._importDek(dek);
238
286
  return this._exclusive(async () => {
239
287
  const envelope = await this._load();
288
+ if (Object.keys(envelope.secrets).length > 0) await this._requireDek(dek, envelope);
240
289
  if (!(sourceId in envelope.secrets) && Object.keys(envelope.secrets).length >= VAULT_LIMITS.secrets) {
241
290
  throw new VaultError(`A vault holds at most ${VAULT_LIMITS.secrets} secrets.`, "invalid-input");
242
291
  }
@@ -620,8 +669,10 @@ var RELAY_ERRORS = {
620
669
  var CHAINS = /* @__PURE__ */ new Set(["eip155", "solana", "ton", "tron", "bip122", "near"]);
621
670
  var isRecord = (x) => typeof x === "object" && x !== null;
622
671
  var isId = (x) => typeof x === "string" && x.length > 0 && x.length <= 64;
672
+ var RELAY_METHOD_MAX = 128;
673
+ var isRelayMethod = (x) => typeof x === "string" && x.length > 0 && x.length <= RELAY_METHOD_MAX && /^[A-Za-z0-9_]+$/.test(x);
623
674
  function isPageRequest(x) {
624
- return isRecord(x) && x.target === PAGE_TARGET.toContent && isId(x.id) && CHAINS.has(x.chain) && typeof x.method === "string";
675
+ return isRecord(x) && x.target === PAGE_TARGET.toContent && isId(x.id) && CHAINS.has(x.chain) && isRelayMethod(x.method);
625
676
  }
626
677
  function isPageResponse(x) {
627
678
  return isRecord(x) && x.target === PAGE_TARGET.toPage && isId(x.id);
@@ -630,7 +681,7 @@ function isPageEvent(x) {
630
681
  return isRecord(x) && x.target === PAGE_TARGET.toPage && !("id" in x) && CHAINS.has(x.chain) && typeof x.event === "string";
631
682
  }
632
683
  function isRelayRequest(x) {
633
- return isRecord(x) && x.kind === "request" && isId(x.id) && typeof x.origin === "string" && CHAINS.has(x.chain) && typeof x.method === "string";
684
+ return isRecord(x) && x.kind === "request" && isId(x.id) && typeof x.origin === "string" && CHAINS.has(x.chain) && isRelayMethod(x.method);
634
685
  }
635
686
  function isRelayToContent(x) {
636
687
  return isRecord(x) && (x.kind === "response" && isId(x.id) || x.kind === "event" && typeof x.event === "string");
@@ -757,6 +808,7 @@ function vaultSecretStorage(vault, session) {
757
808
  }
758
809
 
759
810
  // src/networks.ts
811
+ import { isPublicHttpsUrl } from "@anywalletkit/networks/url";
760
812
  import { ccChain } from "@anywalletkit/swap2-assets";
761
813
  var DEFAULT_CHAIN = "eip155:1";
762
814
  var net = (chainId, name, symbol, rpcs, explorer) => explorer === void 0 ? { caip2: `eip155:${chainId}`, chainId, name, symbol, rpcs } : { caip2: `eip155:${chainId}`, chainId, name, symbol, rpcs, explorer };
@@ -870,26 +922,14 @@ var NetworksTable = class {
870
922
  return this._loading;
871
923
  }
872
924
  };
873
- function isPrivateRpcHost(url) {
874
- const m = /^https:\/\/(?:[^@/?#]*@)?(\[[^\]]+\]|[^:/?#]+)/i.exec(url);
875
- if (!m) return true;
876
- const h = m[1].toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
877
- if (h === "localhost" || h.endsWith(".localhost") || h.endsWith(".local") || h === "0.0.0.0") return true;
878
- const v4 = /^(\d{1,3})\.(\d{1,3})\.\d{1,3}\.\d{1,3}$/.exec(h);
879
- if (v4) {
880
- const a = Number(v4[1]), b = Number(v4[2]);
881
- return a === 127 || a === 10 || a === 0 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 169 && b === 254;
882
- }
883
- if (h.includes(":")) return h === "::1" || h === "::" || /^f[cd]/.test(h) || /^fe[89ab]/.test(h);
884
- return false;
885
- }
925
+ var isSiteRpcUrl = (u) => typeof u === "string" && u.length <= 2048 && isPublicHttpsUrl(u);
886
926
  function parseAddChainParams(params, known = isCatalogChain) {
887
927
  const p = Array.isArray(params) ? params[0] : params;
888
928
  if (!p || typeof p !== "object") return relayError(RELAY_ERRORS.invalidParams, "wallet_addEthereumChain expects one object parameter.");
889
929
  const caip2 = caip2FromChainId(p.chainId);
890
930
  if (!caip2) return relayError(RELAY_ERRORS.invalidParams, "chainId must be a 0x-prefixed hex string.");
891
931
  if (!known(caip2)) return relayError(RELAY_ERRORS.chainNotAdded, `Chain ${String(p.chainId)} is not in this wallet's catalog.`);
892
- const rpcs = Array.isArray(p.rpcUrls) ? p.rpcUrls.filter((u) => typeof u === "string" && /^https:\/\/[^\s/?#]+/i.test(u) && !isPrivateRpcHost(u)) : [];
932
+ const rpcs = Array.isArray(p.rpcUrls) ? p.rpcUrls.filter(isSiteRpcUrl) : [];
893
933
  if (rpcs.length === 0) return relayError(RELAY_ERRORS.invalidParams, "rpcUrls must contain at least one public https URL (a site cannot add a private / local endpoint).");
894
934
  const name = typeof p.chainName === "string" && p.chainName.trim() ? p.chainName.trim().slice(0, 64) : caip2;
895
935
  const currency = p.nativeCurrency;
@@ -1250,8 +1290,9 @@ var RouterError = class _RouterError extends Error {
1250
1290
  };
1251
1291
  var PROVIDER_CODES = /* @__PURE__ */ new Set([4001, 4100, 4200, 4900, 4901, 4902]);
1252
1292
  var isNodeCode = (code) => typeof code === "number" && Number.isInteger(code) && (code === 3 || code >= -32768 && code <= -32e3);
1253
- var URL_RE = /\b[a-z][a-z0-9+.-]*:\/\/[^\s"'<>()]+/gi;
1254
- var pageText = (text) => text.replace(URL_RE, "[url]").split("\n")[0].slice(0, 300);
1293
+ var URL_RE = /[a-z][a-z0-9+.-]{0,31}:\/\/[^\s"'<>()]+/gi;
1294
+ var PAGE_TEXT_WINDOW = 1024;
1295
+ var pageText = (text) => text.slice(0, PAGE_TEXT_WINDOW).split("\n", 1)[0].replace(URL_RE, "[url]").slice(0, 300);
1255
1296
  var isHexData = (v) => typeof v === "string" && /^0x[0-9a-fA-F]*$/.test(v) && v.length <= 2 + 2 * 8192;
1256
1297
  function nodeError(e) {
1257
1298
  for (let cur = e, depth = 0; cur && typeof cur === "object" && depth < 8; cur = cur.cause, depth++) {
@@ -1310,6 +1351,7 @@ var RequestRouter = class {
1310
1351
  async handle(origin, chain, method, rawParams) {
1311
1352
  const refused = this.deps.refuse?.(origin);
1312
1353
  if (refused) throw new RouterError(RELAY_ERRORS.unauthorized, refused);
1354
+ if (!isRelayMethod(method)) throw new RouterError(RELAY_ERRORS.invalidRequest, "The request has no valid method name.");
1313
1355
  if (chain !== "eip155") throw new RouterError(RELAY_ERRORS.unsupportedMethod, `${chain} providers are not available yet.`);
1314
1356
  const params = Array.isArray(rawParams) ? rawParams : rawParams === void 0 ? [] : [rawParams];
1315
1357
  const network = await this.chainFor(origin);
@@ -2464,6 +2506,7 @@ export {
2464
2506
  QueueLimitError,
2465
2507
  READ_METHODS,
2466
2508
  RELAY_ERRORS,
2509
+ RELAY_METHOD_MAX,
2467
2510
  RecipientBook,
2468
2511
  RequestRouter,
2469
2512
  ReviewDeclined,
@@ -2523,6 +2566,7 @@ export {
2523
2566
  isPageEvent,
2524
2567
  isPageRequest,
2525
2568
  isPageResponse,
2569
+ isRelayMethod,
2526
2570
  isRelayRequest,
2527
2571
  isRelayToContent,
2528
2572
  levenshtein,