diff --git a/README.md b/README.md index d1deebb..c4d44d5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,33 @@ The wallet uses **Native Messaging** for secure communication between the browse - **Native Host**: A small binary (`native-host`) that bridges extension ↔ Electron via stdio/socket - **Electron App**: Runs the wallet-worker process that handles account management and signing +## Wallet flavors + +This repo contains five wallet flavors that share a common core in `shared/`: + +| Flavor | Where wallet logic runs | Directory | +| ---------------------------- | -------------------------------------------------------- | ------------------- | +| Native (Electron) | Worker thread inside an Electron app | `app/` | +| Web standalone | Browser page at the wallet's own origin | `web/` | +| Web iframe | Browser page embedded by dApps via postMessage | `web/` (same build) | +| Extension (relay) | Forwards to the Electron app via Native Messaging | `extension/` | +| Extension (self-contained) | Inside the extension itself (offscreen document) | `extension-wallet/` | + +The relay extension and self-contained extension can be installed side-by-side; they appear as two separate wallet options in dApp wallet pickers (different `WALLET_ID`s). + +### Self-contained extension wallet + +The `extension-wallet/` directory contains a MetaMask-shaped extension where the wallet logic runs inside the extension. No Electron app required. + +```bash +cd extension-wallet +yarn install +yarn dev # Chrome +yarn dev:firefox # Firefox +``` + +See `extension-wallet/README.md` for the architecture and `docs/superpowers/specs/2026-04-28-browser-extension-wallet-design.md` for the full design. + ## Updating to Latest Nightly ```bash diff --git a/extension-wallet/.gitignore b/extension-wallet/.gitignore new file mode 100644 index 0000000..7cf936d --- /dev/null +++ b/extension-wallet/.gitignore @@ -0,0 +1,13 @@ +# WXT generated artifacts +.wxt +.output + +# Build stats +stats.html +stats-*.json + +# Logs +*.log + +# Firefox-specific dev config that WXT may generate locally +web-ext.config.ts diff --git a/extension-wallet/README.md b/extension-wallet/README.md new file mode 100644 index 0000000..674bdcf --- /dev/null +++ b/extension-wallet/README.md @@ -0,0 +1,116 @@ +# extension-wallet + +Self-contained Aztec wallet browser extension. Wallet logic runs inside the extension itself (no Electron dependency), modeled on MetaMask. + +This is distinct from `extension/` at the repo root, which is a transport-only relay between dApps and the Electron app at `app/`. + +## Development + +```bash +yarn install # also runs `wxt prepare` to generate .wxt/ +yarn dev # Chrome +yarn dev:firefox # Firefox +yarn test # vitest unit tests +yarn compile # tsc --noEmit +``` + +`yarn dev` opens a Chrome instance with the extension loaded and an isolated profile. The first run pops an onboarding tab automatically. + +## Architecture + +``` + ┌───────────────────────────────┐ + │ dApp page (any origin) │ + └────┬──────────────────────────┘ + content script (entrypoints/content.ts) + │ + ▼ + ┌───────────────────────────────┐ + │ Background service worker │ + │ (entrypoints/background.ts) │ + │ - BackgroundConnectionHandler│ + │ - Approval window queue │ + │ - Auto-lock alarm │ + │ - Remembered apps │ + └────┬──────────────────────────┘ + chrome.runtime.Port (PortClient ↔ PortServer) + │ + ▼ + ┌───────────────────────────────┐ + │ Offscreen document │ + │ (entrypoints/offscreen/) │ + │ - VaultState (lock/unlock) │ + │ - WalletHost (RPC dispatch) │ + │ - PXE / WalletDB / shared │ + │ session (lifted from web/) │ + └───────────────────────────────┘ + ▲ ▲ + │ │ + ┌─────────────┘ └────────────────┐ + │ │ +┌──────────────────┐ ┌─────────────────────┐ +│ Popup │ │ Approval window │ +│ (lock screen + │ │ (per-request) │ +│ status) │ └─────────────────────┘ +└──────────────────┘ + ┌─────────────────────┐ + │ Expanded view │ + │ (StandaloneShell │ + │ from shared/) │ + └─────────────────────┘ +``` + +### Files + +- `entrypoints/background.ts` — Service worker (router only) +- `entrypoints/offscreen/` — Wallet host bootstrap +- `entrypoints/content.ts` — dApp ↔ extension relay +- `entrypoints/popup/` — Status + lock screen +- `entrypoints/approval/` — Per-request approval window +- `entrypoints/expanded/` — Full wallet UI (reuses `StandaloneShell` from `@demo-wallet/shared/ui`) +- `entrypoints/onboarding/` — First-install setup wizard +- `src/vault/` — Argon2id KDF, vault metadata store, lock state machine +- `src/ipc/` — Port message envelope (Zod), `PortServer` (offscreen-side), `PortClient` (UI/SW-side) +- `src/offscreen/wallet-host.ts` — Wires `VaultState`, the lifted session manager, and `PortServer` +- `src/background/` — SW helpers: offscreen lifecycle, approval queue, auto-lock alarm, remembered apps +- `src/ui/port-wallet-api.ts` — Builds an `InternalWalletInterface` Proxy that forwards over `PortClient` + +### RPC namespaces + +The port server multiplexes four namespaces: + +| Prefix | Caller | Target | Examples | +|--------------|-----------------|------------------|---------------------------------------------| +| `vault.*` | UI surfaces | `VaultState` | `vault.unlock`, `vault.isUnlocked` | +| `network.*` | UI surfaces | host config | `network.set`, `network.get` | +| `wallet.*` | UI surfaces | `InternalWallet` | `wallet.getAccounts`, `wallet.createAccount`| +| `dapp.*` | dApp (via SW) | `ExternalWallet` | `dapp.simulateTx`, `dapp.sendTx` | + +`wallet.*` and `dapp.*` are populated dynamically by enumerating `InternalWalletInterfaceSchema` and `WalletSchema`. + +## Extension ID + +The Chromium extension ID is derived from the `key` field in `wxt.config.ts`. Run `yarn dev` once and look at the `chrome://extensions` page — the ID will appear under the loaded extension. Copy it back into this README if you want it handy. + +## Browser support + +- **Chrome / Brave / Edge**: full support via `chrome.offscreen`. +- **Firefox**: no `chrome.offscreen` API; falls back to a hidden minimized window hosting `offscreen.html` (see `src/background/offscreen-lifecycle.ts`). + +## Coexistence with `extension/` + +Both extensions can be installed side-by-side. They use different `WALLET_ID`s (`aztec-extension-wallet` vs `aztec-keychain`), so the wallet-sdk discovery flow lists both as options in dApp wallet pickers. + +## Known deviations from the design plan + +- **`dapp.*` and `wallet.*` dispatch use explicit schema-key enumeration** (not a JS `Proxy`). Rationale: spreading a Proxy into a plain object loses the `get` trap, defeating the dispatcher. +- **Approval window uses `authorization.getPending`** (one-shot read at mount) instead of a broadcast-replay mechanism. Avoids spamming every open UI surface with re-broadcasts of every pending auth. +- **`tsconfig.json` overrides `strict: false`** to match `web/`/`shared/` workspace conventions. WXT's auto-generated config is `strict: true`, but `shared/`'s source isn't strict-clean, so following imports under strict tsc would fail in unrelated files. Re-enabling strict mode is gated on making `shared/` strict-clean first. + +## Caveats (v1) + +- **At-rest encryption is deferred.** The vault uses Argon2id + a probe-based password check, but account secrets are stored in plaintext in IndexedDB. This is intentional pending the in-progress IndexedDB replacement; the lock UX is preserved so the surface area doesn't change when encryption is added later. + +## Design + +See `docs/superpowers/specs/2026-04-28-browser-extension-wallet-design.md` for the full design. diff --git a/extension-wallet/entrypoints/approval/index.html b/extension-wallet/entrypoints/approval/index.html new file mode 100644 index 0000000..dd32d2b --- /dev/null +++ b/extension-wallet/entrypoints/approval/index.html @@ -0,0 +1,11 @@ + + + + + Approve Request + + +
+ + + diff --git a/extension-wallet/entrypoints/approval/main.tsx b/extension-wallet/entrypoints/approval/main.tsx new file mode 100644 index 0000000..5508575 --- /dev/null +++ b/extension-wallet/entrypoints/approval/main.tsx @@ -0,0 +1,121 @@ +import { useEffect, useRef, useState } from "react"; +import { createRoot } from "react-dom/client"; +import { ThemeProvider, createTheme, CssBaseline } from "@mui/material"; +import { Fr } from "@aztec/aztec.js/fields"; +import { AuthorizationDialog, WalletContext } from "@demo-wallet/shared/ui"; +import type { + AuthorizationRequest, + AuthorizationItemResponse, +} from "@demo-wallet/shared/core"; +import { PortClient } from "../../src/ipc/port-client"; +import { makePortWalletApi } from "../../src/ui/port-wallet-api"; + +function Approval() { + const [client] = useState(() => { + const c = new PortClient(); + c.connect(); + return c; + }); + const [request, setRequest] = useState(null); + const [walletAPI, setWalletAPI] = useState | null>( + null, + ); + const resolved = useRef(false); + const requestId = new URLSearchParams(window.location.search).get("requestId"); + + // Resolve current chain → build a port-backed wallet API for the dialog. + useEffect(() => { + void (async () => { + const net = await client.call<{ chainId: string; version: string }>( + "network.get", + [], + ); + setWalletAPI( + makePortWalletApi(client, Fr.fromString(net.chainId), Fr.fromString(net.version)), + ); + })(); + }, [client]); + + // Fetch pending requests, find the one matching our requestId. + useEffect(() => { + if (!requestId) return; + void (async () => { + const pending = await client.call( + "authorization.getPending", + [], + ); + const found = pending.find((r) => r.id === requestId); + if (found) setRequest(found); + })(); + }, [client, requestId]); + + // Window-close = denial (only if the user hasn't already resolved). + useEffect(() => { + function onUnload() { + if (resolved.current || !request) return; + const itemResponses: Record = {}; + for (const item of request.items) { + itemResponses[item.id] = { + id: item.id, + approved: false, + appId: item.appId, + }; + } + // Best-effort: postMessage on a port runs synchronously; the offscreen + // may or may not see it before the SW unloads us. + void client.call("authorization.resolve", [ + { id: request.id, approved: false, appId: request.appId, itemResponses }, + ]); + } + window.addEventListener("beforeunload", onUnload); + return () => window.removeEventListener("beforeunload", onUnload); + }, [client, request]); + + if (!request || !walletAPI) return null; + + const handleApprove = async ( + itemResponses: Record, + ) => { + resolved.current = true; + await client.call("authorization.resolve", [ + { id: request.id, approved: true, appId: request.appId, itemResponses }, + ]); + window.close(); + }; + + const handleDeny = async () => { + resolved.current = true; + const itemResponses: Record = {}; + for (const item of request.items) { + itemResponses[item.id] = { + id: item.id, + approved: false, + appId: item.appId, + }; + } + await client.call("authorization.resolve", [ + { id: request.id, approved: false, appId: request.appId, itemResponses }, + ]); + window.close(); + }; + + return ( + + + + ); +} + +const theme = createTheme({ palette: { mode: "dark" } }); + +createRoot(document.getElementById("root")!).render( + + + + , +); diff --git a/extension-wallet/entrypoints/background.ts b/extension-wallet/entrypoints/background.ts new file mode 100644 index 0000000..b41776b --- /dev/null +++ b/extension-wallet/entrypoints/background.ts @@ -0,0 +1,244 @@ +import "../src/shared/polyfills"; +import { BackgroundConnectionHandler } from "@aztec/wallet-sdk/extension/handlers"; +import type { WalletResponse } from "@aztec/wallet-sdk/types"; +import { WALLET_ID, WALLET_NAME, WALLET_VERSION } from "../src/shared/constants"; +import { isAppRemembered, rememberApp } from "../src/background/remembered-apps"; +import { + ensureOffscreen, + acquireKeepAlive, + releaseKeepAlive, + markOffscreenReady, +} from "../src/background/offscreen-lifecycle"; +import { enqueueApproval, isApprovalWindowOpen } from "../src/background/approval-window"; +import { bumpActivity, onAutoLockFired } from "../src/background/auto-lock"; +import { PortClient } from "../src/ipc/port-client"; +import { parseEventDetail } from "../src/ipc/parse-event-detail"; +import { hasVaultMeta } from "../src/vault/vault-meta"; + +export default defineBackground(() => { + let portClient: PortClient | null = null; + let pendingDappCount = 0; + + async function getPortClient(): Promise { + await ensureOffscreen(); + if (!portClient) { + // SW already ensured the offscreen above; skip the round-trip ping. + portClient = new PortClient({ skipEnsureOffscreen: true }); + portClient.connect(); + portClient.onBroadcast("authorization-request", (payload) => { + // Wallet-emitted events arrive as `jsonStringify(content)` strings — + // parse before reading fields. Without this, `req.id` is undefined + // and the approval window opens with `?requestId=undefined`. + const req = parseEventDetail(payload) as { id: string; type?: string }; + enqueueApproval({ id: req.id, type: req.type ?? "unknown" }); + }); + } + return portClient; + } + + // Open onboarding tab on first install (no vault meta yet). + chrome.runtime.onInstalled.addListener(async (details) => { + if (details.reason !== "install") return; + const initialized = await hasVaultMeta(); + if (!initialized) { + await chrome.tabs.create({ + url: chrome.runtime.getURL("onboarding.html"), + }); + } + }); + + const sessionHandler = new BackgroundConnectionHandler( + { walletId: WALLET_ID, walletName: WALLET_NAME, walletVersion: WALLET_VERSION }, + { + sendToTab: (tabId, message) => browser.tabs.sendMessage(tabId, message), + addContentListener: (handler) => browser.runtime.onMessage.addListener(handler), + }, + { + onPendingDiscovery: async (discovery) => { + const chainId = discovery.chainInfo.chainId.toString(); + const version = discovery.chainInfo.version.toString(); + if ( + await isAppRemembered(discovery.appId, discovery.origin, chainId, version) + ) { + sessionHandler.approveDiscovery(discovery.requestId); + } else { + chrome.action.openPopup().catch(() => {}); + } + }, + onSessionEstablished: () => { + chrome.action.openPopup().catch(() => {}); + }, + onWalletMessage: async (session, message) => { + // TEMP DEBUG: log every dApp message and what we send back so we can + // see whether responses leave the SW. Revert once the bug is found. + console.log("[SW] onWalletMessage", { + messageId: message.messageId, + type: message.type, + sessionId: session.sessionId, + }); + if (!(await hasVaultMeta())) { + await sessionHandler.sendResponse(session.sessionId, { + messageId: message.messageId, + walletId: WALLET_ID, + error: { + message: "Wallet not yet initialized — complete onboarding first", + }, + }); + return; + } + + const client = await getPortClient(); + pendingDappCount++; + acquireKeepAlive(); + await bumpActivity(); + + try { + // If locked, open the popup as an unlock prompt. The dApp call below + // will reject with "Vault is locked" until the user unlocks. + const isUnlocked = await client.call("vault.isUnlocked", []); + if (!isUnlocked) { + chrome.action.openPopup().catch(() => { + chrome.windows.create({ + url: chrome.runtime.getURL( + "popup.html?reason=unlock-for-request", + ), + type: "popup", + width: 380, + height: 560, + focused: true, + }); + }); + } + + const result = await client.call(`dapp.${message.type}`, [ + session, + message, + ]); + console.log("[SW] dapp call returned", { + messageId: message.messageId, + type: message.type, + resultPreview: typeof result === "object" ? Object.keys(result ?? {}) : typeof result, + }); + const response: WalletResponse = { + messageId: message.messageId, + walletId: WALLET_ID, + result, + }; + await sessionHandler.sendResponse(session.sessionId, response); + console.log("[SW] sendResponse OK", { messageId: message.messageId }); + } catch (err) { + const e = err as Error; + console.error("[SW] dapp call failed", { + messageId: message.messageId, + type: message.type, + error: e.message, + }); + const response: WalletResponse = { + messageId: message.messageId, + walletId: WALLET_ID, + error: { message: e.message ?? String(err) }, + }; + await sessionHandler.sendResponse(session.sessionId, response); + console.log("[SW] sendResponse(error) OK", { messageId: message.messageId }); + } finally { + pendingDappCount--; + releaseKeepAlive(); + } + }, + }, + ); + sessionHandler.initialize(); + + onAutoLockFired(async () => { + // Don't lock while a user is mid-approval or while a dApp request is in flight. + if (isApprovalWindowOpen() || pendingDappCount > 0) { + await bumpActivity(); + return; + } + const client = await getPortClient(); + await client.call("vault.lock", []); + }); + + // Bump activity whenever a UI surface connects (popup/expanded/approval open). + chrome.runtime.onConnect.addListener((port) => { + if (port.name === "ui-activity") void bumpActivity(); + }); + + // Multiplexed onMessage handler. Each `type` is a distinct UI ↔ SW request. + chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => { + const type = (msg as { type?: string })?.type; + if (type === "ensure-offscreen") { + ensureOffscreen().then( + () => sendResponse({ ok: true }), + (err: Error) => sendResponse({ ok: false, error: err.message }), + ); + return true; + } + if (type === "offscreen-ready") { + markOffscreenReady(); + sendResponse({ ok: true }); + return false; + } + if (type === "get-pending-discoveries") { + // Surface the SDK-managed pending list to the popup so it can render + // approve/reject UI. We expose only the fields the popup needs. + const discoveries = sessionHandler.getPendingDiscoveries().map((d) => ({ + requestId: d.requestId, + origin: d.origin, + appId: d.appId, + chainId: d.chainInfo.chainId.toString(), + version: d.chainInfo.version.toString(), + })); + sendResponse({ ok: true, discoveries }); + return false; + } + if (type === "approve-discovery") { + const { requestId, remember } = msg as { + requestId: string; + remember?: boolean; + }; + const discovery = sessionHandler + .getPendingDiscoveries() + .find((d) => d.requestId === requestId); + const ok = sessionHandler.approveDiscovery(requestId); + if (ok && remember && discovery) { + void rememberApp( + discovery.appId, + discovery.origin, + discovery.chainInfo.chainId.toString(), + discovery.chainInfo.version.toString(), + ); + } + sendResponse({ ok }); + return false; + } + if (type === "reject-discovery") { + const { requestId } = msg as { requestId: string }; + const ok = sessionHandler.rejectDiscovery(requestId); + sendResponse({ ok }); + return false; + } + if (type === "get-active-sessions") { + // Active (post-key-exchange) dApp sessions. Each carries a + // `verificationHash` the popup can render as emojis for the user to + // compare with what the dApp displays — that's the security check that + // the ECDH handshake produced the same shared secret on both sides. + const sessions = sessionHandler.getActiveSessions().map((s) => ({ + sessionId: s.sessionId, + origin: s.origin, + appId: s.appId, + verificationHash: s.verificationHash, + chainId: s.chainInfo.chainId.toString(), + version: s.chainInfo.version.toString(), + })); + sendResponse({ ok: true, sessions }); + return false; + } + return false; + }); + + browser.tabs.onRemoved.addListener((tabId) => sessionHandler.terminateForTab(tabId)); + browser.webNavigation.onBeforeNavigate.addListener((details) => { + if (details.frameId === 0) sessionHandler.terminateForTab(details.tabId); + }); +}); diff --git a/extension-wallet/entrypoints/content.ts b/extension-wallet/entrypoints/content.ts new file mode 100644 index 0000000..e13d629 --- /dev/null +++ b/extension-wallet/entrypoints/content.ts @@ -0,0 +1,24 @@ +import { ContentScriptConnectionHandler } from "@aztec/wallet-sdk/extension/handlers"; + +/** + * Content script that acts as a pure message relay between the web page and the background script. + * + * Uses ContentScriptConnectionHandler from wallet-sdk for the connection logic. + * + * Security model: + * - Content script NEVER has access to private keys or shared secrets + * - All decisions and crypto happen in the offscreen document (via the background router) + * - Content script only forwards opaque payloads + * - This minimizes the attack surface since content scripts run in the page context + */ +export default defineContentScript({ + matches: ["*://*/*"], + main() { + const handler = new ContentScriptConnectionHandler({ + sendToBackground: (message) => browser.runtime.sendMessage(message), + addBackgroundListener: (listener) => browser.runtime.onMessage.addListener(listener), + }); + + handler.start(); + }, +}); diff --git a/extension-wallet/entrypoints/expanded/index.html b/extension-wallet/entrypoints/expanded/index.html new file mode 100644 index 0000000..2d22088 --- /dev/null +++ b/extension-wallet/entrypoints/expanded/index.html @@ -0,0 +1,11 @@ + + + + + Aztec Wallet + + +
+ + + diff --git a/extension-wallet/entrypoints/expanded/main.tsx b/extension-wallet/entrypoints/expanded/main.tsx new file mode 100644 index 0000000..295c915 --- /dev/null +++ b/extension-wallet/entrypoints/expanded/main.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState } from "react"; +import { createRoot } from "react-dom/client"; +import { ThemeProvider, createTheme, CssBaseline } from "@mui/material"; +import { StandaloneShell } from "@demo-wallet/shared/ui"; +import { PortClient } from "../../src/ipc/port-client"; +import { hasVaultMeta } from "../../src/vault/vault-meta"; +import { makePortWalletApi } from "../../src/ui/port-wallet-api"; + +const client = new PortClient(); +client.connect(); + +// Dev-only helper for testing reactive vault state across surfaces. Run e.g. +// `extensionWallet.lock()` in the expanded view's console with the popup +// detached (right-click popup → Inspect) and watch the popup snap to lock. +(globalThis as { extensionWallet?: unknown }).extensionWallet = { + lock: () => client.call("vault.lock", []), + unlock: (password: string) => client.call("vault.unlock", [password]), + isUnlocked: () => client.call("vault.isUnlocked", []), + client, +}; + +const theme = createTheme({ palette: { mode: "dark" } }); + +/** + * Wraps StandaloneShell so it remounts on every vault-locked broadcast. The + * shell's `isAlreadyUnlocked` check only runs at mount; without remounting, + * locking the vault from another surface (popup, devtools) leaves the expanded + * view stuck on the unlocked Root view. Bumping a `key` is the cheapest way to + * force remount without touching the shared shell. + */ +function ExpandedApp() { + const [epoch, setEpoch] = useState(0); + useEffect(() => client.onBroadcast("vault-locked", () => setEpoch((e) => e + 1)), []); + + return ( + client.call("vault.isUnlocked", [])} + verifyPin={async (pin) => { + const ok = await client.call("vault.unlock", [pin]); + if (!ok) throw new Error("wrong password"); + }} + setPin={async (pin) => { + // First-install path: if no vault yet, treat the entered PIN as the + // initial password. Otherwise verifyPin (above) has already unlocked + // the vault on the offscreen side, so this is a no-op. + const initialized = await client.call("vault.isInitialized", []); + if (!initialized) { + await client.call("vault.initialize", [pin]); + } + }} + walletApiFactory={(chainId, version) => makePortWalletApi(client, chainId, version)} + /> + ); +} + +createRoot(document.getElementById("root")!).render( + + + + , +); diff --git a/extension-wallet/entrypoints/offscreen/index.html b/extension-wallet/entrypoints/offscreen/index.html new file mode 100644 index 0000000..688e2b6 --- /dev/null +++ b/extension-wallet/entrypoints/offscreen/index.html @@ -0,0 +1,10 @@ + + + + + Aztec Wallet — Offscreen + + + + + diff --git a/extension-wallet/entrypoints/offscreen/main.ts b/extension-wallet/entrypoints/offscreen/main.ts new file mode 100644 index 0000000..35496e1 --- /dev/null +++ b/extension-wallet/entrypoints/offscreen/main.ts @@ -0,0 +1,14 @@ +import "../../src/shared/polyfills"; +import { WalletHost } from "../../src/offscreen/wallet-host"; + +const host = new WalletHost(); +host.start(); +console.log("[offscreen] Wallet host started"); + +// Tell the SW our PortServer is registered and ready to receive UI connections. +// The SW gates `ensureOffscreen()` on this signal — without it, the UI's +// runtime.connect arrives before our onConnect listener is wired up. +chrome.runtime.sendMessage({ type: "offscreen-ready" }).catch(() => { + // SW may have suspended in the brief window between our boot and this call; + // it'll re-spawn us next time and the new instance's signal will be heard. +}); diff --git a/extension-wallet/entrypoints/onboarding/Onboarding.tsx b/extension-wallet/entrypoints/onboarding/Onboarding.tsx new file mode 100644 index 0000000..e1425cd --- /dev/null +++ b/extension-wallet/entrypoints/onboarding/Onboarding.tsx @@ -0,0 +1,125 @@ +import { useState } from "react"; +import { + Box, + Button, + TextField, + Typography, + Stepper, + Step, + StepLabel, +} from "@mui/material"; +import { PortClient } from "../../src/ipc/port-client"; + +const steps = ["Welcome", "Set Password", "Done"]; + +export function Onboarding() { + const [active, setActive] = useState(0); + const [pw, setPw] = useState(""); + const [confirm, setConfirm] = useState(""); + const [error, setError] = useState(null); + const [submitting, setSubmitting] = useState(false); + const [client] = useState(() => { + const c = new PortClient(); + c.connect(); + return c; + }); + + async function handleCreate() { + setError(null); + if (pw.length < 8) { + setError("Password must be at least 8 characters"); + return; + } + if (pw !== confirm) { + setError("Passwords don't match"); + return; + } + setSubmitting(true); + try { + await client.call("vault.initialize", [pw]); + setActive(2); + } catch (e) { + setError((e as Error).message); + } finally { + setSubmitting(false); + } + } + + return ( + + + {steps.map((s) => ( + + {s} + + ))} + + + {active === 0 && ( + + + Welcome to Aztec Wallet + + + This extension stores Aztec accounts and signs transactions for dApps. + You'll set a password next — it locks the wallet UI on idle. + + + + )} + + {active === 1 && ( + + + Set a password + + setPw(e.target.value)} + /> + setConfirm(e.target.value)} + /> + {error && ( + + {error} + + )} + + + )} + + {active === 2 && ( + + + You're all set + + + Click the toolbar icon to open the wallet, or visit a dApp to begin. + + + + )} + + ); +} diff --git a/extension-wallet/entrypoints/onboarding/index.html b/extension-wallet/entrypoints/onboarding/index.html new file mode 100644 index 0000000..e19a462 --- /dev/null +++ b/extension-wallet/entrypoints/onboarding/index.html @@ -0,0 +1,11 @@ + + + + + Aztec Wallet — Setup + + +
+ + + diff --git a/extension-wallet/entrypoints/onboarding/main.tsx b/extension-wallet/entrypoints/onboarding/main.tsx new file mode 100644 index 0000000..e053f57 --- /dev/null +++ b/extension-wallet/entrypoints/onboarding/main.tsx @@ -0,0 +1,12 @@ +import { createRoot } from "react-dom/client"; +import { ThemeProvider, createTheme, CssBaseline } from "@mui/material"; +import { Onboarding } from "./Onboarding"; + +const theme = createTheme({ palette: { mode: "dark" } }); + +createRoot(document.getElementById("root")!).render( + + + + , +); diff --git a/extension-wallet/entrypoints/popup/Popup.tsx b/extension-wallet/entrypoints/popup/Popup.tsx new file mode 100644 index 0000000..c25d297 --- /dev/null +++ b/extension-wallet/entrypoints/popup/Popup.tsx @@ -0,0 +1,330 @@ +import { useEffect, useState } from "react"; +import { Box, Button, TextField, Typography, Stack } from "@mui/material"; +import { hashToEmoji } from "@aztec/wallet-sdk/crypto"; +import { PortClient } from "../../src/ipc/port-client"; + +export function Popup() { + const [client] = useState(() => { + const c = new PortClient(); + c.connect(); + // Dev helper: expose so we can test broadcast wiring from the popup's + // own console (right-click popup → Inspect, then run popupClient.call(...)). + (globalThis as { popupClient?: unknown }).popupClient = c; + return c; + }); + // Three states: uninitialized (no vault yet), locked (have vault, need pw), + // unlocked. `null` while we're still asking the offscreen which we're in. + const [vaultState, setVaultState] = useState< + "uninitialized" | "locked" | "unlocked" | null + >(null); + const [pw, setPw] = useState(""); + const [error, setError] = useState(null); + + // Pending discovery requests the dApp sent. The SW opens the popup when one + // arrives; the popup queries the list and renders approve/reject UI. + type Pending = { + requestId: string; + origin: string; + appId: string; + chainId: string; + version: string; + }; + const [pendingDiscoveries, setPendingDiscoveries] = useState([]); + + // Active (key-exchange-completed) sessions. Each has a `verificationHash` + // the user compares with the dApp's emoji display — security check that + // both sides ended up with the same shared secret. + type ActiveSession = { + sessionId: string; + origin: string; + appId: string; + verificationHash: string; + chainId: string; + version: string; + }; + const [activeSessions, setActiveSessions] = useState([]); + + // Sessions the user has already eyeballed against the dApp's emojis. Stored + // in chrome.storage.session so it survives popup-close/reopen but resets on + // browser restart (security default: re-verify after restart). + const [verifiedSessionIds, setVerifiedSessionIds] = useState>(new Set()); + + const VERIFIED_KEY = "verifiedSessionIds"; + + const loadVerified = async () => { + const result = await chrome.storage.session.get(VERIFIED_KEY); + setVerifiedSessionIds(new Set((result[VERIFIED_KEY] as string[] | undefined) ?? [])); + }; + + const markAllVerified = async () => { + const ids = activeSessions.map((s) => s.sessionId); + const merged = new Set([...Array.from(verifiedSessionIds), ...ids]); + await chrome.storage.session.set({ [VERIFIED_KEY]: Array.from(merged) }); + setVerifiedSessionIds(merged); + }; + + const refreshPending = async () => { + const reply = (await chrome.runtime.sendMessage({ + type: "get-pending-discoveries", + })) as { ok: boolean; discoveries: Pending[] } | undefined; + if (reply?.ok) setPendingDiscoveries(reply.discoveries); + }; + + const refreshSessions = async () => { + const reply = (await chrome.runtime.sendMessage({ + type: "get-active-sessions", + })) as { ok: boolean; sessions: ActiveSession[] } | undefined; + if (reply?.ok) setActiveSessions(reply.sessions); + }; + + const approveDiscovery = async (requestId: string, remember: boolean) => { + await chrome.runtime.sendMessage({ type: "approve-discovery", requestId, remember }); + void refreshPending(); + }; + + const rejectDiscovery = async (requestId: string) => { + await chrome.runtime.sendMessage({ type: "reject-discovery", requestId }); + void refreshPending(); + }; + + useEffect(() => { + void (async () => { + const initialized = await client.call("vault.isInitialized", []); + if (!initialized) { + setVaultState("uninitialized"); + } else { + const unlocked = await client.call("vault.isUnlocked", []); + setVaultState(unlocked ? "unlocked" : "locked"); + } + void refreshPending(); + void refreshSessions(); + void loadVerified(); + })(); + const off1 = client.onBroadcast("vault-locked", () => setVaultState("locked")); + const off2 = client.onBroadcast("vault-unlocked", () => setVaultState("unlocked")); + return () => { + off1(); + off2(); + }; + }, [client]); + + async function handleUnlock() { + setError(null); + const ok = await client.call("vault.unlock", [pw]); + if (!ok) setError("Incorrect password"); + setPw(""); + } + + if (vaultState === null) return null; + + // Filter out sessions the user has already verified — they've seen the + // emojis and confirmed they matched. Remaining sessions are the new ones + // (since browser start) that still need verification. + const unverifiedSessions = activeSessions.filter( + (s) => !verifiedSessionIds.has(s.sessionId), + ); + + // Active session verification takes precedence over the normal vault UI: + // when the SW opened us because a session was just established + // (`onSessionEstablished` → `chrome.action.openPopup()`), the user is here + // to compare emojis with the dApp's display. That's a security-critical + // moment, so it should be the first thing they see. + if (unverifiedSessions.length > 0 && pendingDiscoveries.length === 0) { + // TODO: design the active-session verification UI here. + // + // For each session, you have: + // - origin (the dApp's URL — anchor of trust) + // - appId (dApp's self-declared name) + // - verificationHash (string; pass to hashToEmoji to get an emoji string) + // - chainId / version + // + // The user's job: check that the emoji string we render here MATCHES the + // emoji string the dApp shows on their end. Identical = handshake produced + // matching shared secrets on both sides = no MITM. Different = something + // is very wrong; the user should not trust this connection. + // + // Design considerations: + // - Make emojis BIG and easy to read at a glance + // - Show origin clearly (phishing protection) + // - Maybe label the emojis "Verify this matches the dApp" + // - Optional: add a "Disconnect" button per session for quick revoke + // - Optional: add a "Got it" / "Dismiss" to hide and return to vault UI + // + // The emojis come from: hashToEmoji(session.verificationHash) + // (already imported at the top of this file). + // + // 15–25 lines of JSX is plenty for a v1. + return ( + + + Verify connection + + + Compare these emojis with what the dApp displays. + + + {unverifiedSessions.map((s) => ( + + + {s.origin} + + + {hashToEmoji(s.verificationHash)} + + + ))} + + + + ); + } + + // Pending discovery takes priority over the regular vault UI. If the SW + // opened us because a dApp asked, that's what the user wants to see first. + // Approval doesn't expose any wallet data, so showing it even when locked + // is fine (user still has to unlock to actually transact later). + if (pendingDiscoveries.length > 0) { + // TODO: design the discovery approval UI here. + // + // For each `pendingDiscoveries` entry you'll want to show: + // - origin (dApp's URL — most important security signal for the user) + // - appId (dApp's self-declared identifier) + // - chainId / version (which network the dApp expects) + // - Approve and Reject buttons + // - (optional) "Remember this dApp" checkbox; pass to approveDiscovery + // + // Action handlers are already defined above: + // approveDiscovery(requestId, remember) -> sends approval, refreshes list + // rejectDiscovery(requestId) -> rejects, refreshes list + // + // Trade-offs to think about: + // - One discovery at a time vs. queue all visible (rare but possible) + // - How prominent to make the origin text — phishing protection + // - Whether "remember" should be on by default (more friction-free) + // or off by default (more secure) + // + // 10–20 lines of JSX is plenty for a v1. + return ( + + + Pending dApp connection + + + Replace this with your design. {pendingDiscoveries.length} pending. + + + {pendingDiscoveries.map((d) => ( + + {d.origin} + + appId={d.appId} + + + + + + + ))} + + + ); + } + + if (vaultState === "uninitialized") { + // TODO: implement the "no wallet yet" UI here. + // + // Constraints: + // - Popup is small (~380px wide). One headline + one button is plenty. + // - The button should open the onboarding tab: + // chrome.tabs.create({ url: chrome.runtime.getURL("onboarding.html") }) + // - On first-install Chrome already auto-opens onboarding, so this state + // is most likely reached when storage was wiped manually (test path) + // or onboarding was closed without finishing. + // + // Trade-offs to think about: + // - Hard nudge ("you must onboard first") vs. soft nudge ("set up here") + // - Whether to dismiss the popup on click (better flow, fewer surfaces) + // or keep it open (lets user see status as onboarding completes) + // + // 5–10 lines of JSX is plenty. + return ( + + + Wallet not set up + + + Replace this with your design. + + + ); + } + + if (vaultState === "locked") { + return ( + + + Wallet locked + + setPw(e.target.value)} + onKeyDown={(e) => { + if (e.key === "Enter") handleUnlock(); + }} + /> + {error && ( + + {error} + + )} + + + ); + } + + return ( + + + Aztec Wallet + + Wallet unlocked. Use the expanded view for full features. + + + + + + ); +} diff --git a/extension-wallet/entrypoints/popup/index.html b/extension-wallet/entrypoints/popup/index.html new file mode 100644 index 0000000..dabdac5 --- /dev/null +++ b/extension-wallet/entrypoints/popup/index.html @@ -0,0 +1,19 @@ + + + + + Aztec Wallet + + + +
+ + + diff --git a/extension-wallet/entrypoints/popup/main.tsx b/extension-wallet/entrypoints/popup/main.tsx new file mode 100644 index 0000000..b6c294a --- /dev/null +++ b/extension-wallet/entrypoints/popup/main.tsx @@ -0,0 +1,12 @@ +import { createRoot } from "react-dom/client"; +import { ThemeProvider, createTheme, CssBaseline } from "@mui/material"; +import { Popup } from "./Popup"; + +const theme = createTheme({ palette: { mode: "dark" } }); + +createRoot(document.getElementById("root")!).render( + + + + , +); diff --git a/extension-wallet/package.json b/extension-wallet/package.json new file mode 100644 index 0000000..d4c5c68 --- /dev/null +++ b/extension-wallet/package.json @@ -0,0 +1,48 @@ +{ + "name": "demo-aztec-extension-wallet", + "description": "Self-contained Aztec wallet browser extension", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "wxt", + "dev:firefox": "wxt -b firefox", + "build": "wxt build", + "build:firefox": "wxt build -b firefox", + "zip": "wxt zip", + "zip:firefox": "wxt zip -b firefox", + "compile": "tsc --noEmit", + "typecheck": "yarn exec tsc --noEmit", + "test": "vitest run", + "postinstall": "wxt prepare" + }, + "dependencies": { + "@aztec/accounts": "v4.3.0-nightly.20260423", + "@aztec/aztec.js": "v4.3.0-nightly.20260423", + "@aztec/foundation": "v4.3.0-nightly.20260423", + "@aztec/kv-store": "v4.3.0-nightly.20260423", + "@aztec/pxe": "v4.3.0-nightly.20260423", + "@aztec/stdlib": "v4.3.0-nightly.20260423", + "@aztec/wallet-sdk": "v4.3.0-nightly.20260423", + "@demo-wallet/shared": "workspace:*", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", + "@mui/icons-material": "^6.4.4", + "@mui/material": "^6.4.4", + "@noble/hashes": "^1.5.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "zod": "^3.23.8" + }, + "devDependencies": { + "@types/chrome": "^0.0.270", + "@types/react": "^18.3.1", + "@types/react-dom": "^18.3.1", + "@wxt-dev/module-react": "1.1.3", + "typescript": "~5.6.2", + "vite-plugin-node-polyfills": "^0.26.0", + "vitest": "^3.0.0", + "wxt": "^0.20.6" + }, + "packageManager": "yarn@4.5.2" +} diff --git a/extension-wallet/public/icon/128.png b/extension-wallet/public/icon/128.png new file mode 100644 index 0000000..9e35d13 Binary files /dev/null and b/extension-wallet/public/icon/128.png differ diff --git a/extension-wallet/public/icon/16.png b/extension-wallet/public/icon/16.png new file mode 100644 index 0000000..cd09f8c Binary files /dev/null and b/extension-wallet/public/icon/16.png differ diff --git a/extension-wallet/public/icon/32.png b/extension-wallet/public/icon/32.png new file mode 100644 index 0000000..f51ce1b Binary files /dev/null and b/extension-wallet/public/icon/32.png differ diff --git a/extension-wallet/public/icon/48.png b/extension-wallet/public/icon/48.png new file mode 100644 index 0000000..cb7a449 Binary files /dev/null and b/extension-wallet/public/icon/48.png differ diff --git a/extension-wallet/public/icon/96.png b/extension-wallet/public/icon/96.png new file mode 100644 index 0000000..c28ad52 Binary files /dev/null and b/extension-wallet/public/icon/96.png differ diff --git a/extension-wallet/src/background/approval-window.ts b/extension-wallet/src/background/approval-window.ts new file mode 100644 index 0000000..63c5818 --- /dev/null +++ b/extension-wallet/src/background/approval-window.ts @@ -0,0 +1,39 @@ +type ApprovalRequest = { id: string; type: string }; + +const queue: ApprovalRequest[] = []; +let openWindowId: number | null = null; + +chrome.windows.onRemoved.addListener((windowId) => { + if (windowId === openWindowId) { + openWindowId = null; + // Bump activity on close so auto-lock doesn't fire while we open the next. + void import("./auto-lock").then(({ bumpActivity }) => bumpActivity()); + void openNext(); + } +}); + +export function isApprovalWindowOpen(): boolean { + return openWindowId !== null; +} + +export async function enqueueApproval(req: ApprovalRequest): Promise { + if (queue.find((r) => r.id === req.id)) return; + queue.push(req); + if (openWindowId === null) await openNext(); +} + +async function openNext(): Promise { + const next = queue.shift(); + if (!next) return; + const url = chrome.runtime.getURL( + `approval.html?requestId=${encodeURIComponent(next.id)}`, + ); + const win = await chrome.windows.create({ + url, + type: "popup", + width: 400, + height: 600, + focused: true, + }); + openWindowId = win.id ?? null; +} diff --git a/extension-wallet/src/background/auto-lock.ts b/extension-wallet/src/background/auto-lock.ts new file mode 100644 index 0000000..734eca9 --- /dev/null +++ b/extension-wallet/src/background/auto-lock.ts @@ -0,0 +1,31 @@ +import { + AUTO_LOCK_ALARM, + DEFAULT_AUTO_LOCK_MINUTES, + SETTINGS_KEY, +} from "../shared/constants"; + +interface Settings { + autoLockMinutes?: number; +} + +async function getMinutes(): Promise { + const result = await chrome.storage.local.get(SETTINGS_KEY); + const settings = (result[SETTINGS_KEY] as Settings | undefined) ?? {}; + return settings.autoLockMinutes ?? DEFAULT_AUTO_LOCK_MINUTES; +} + +export async function bumpActivity(): Promise { + const minutes = await getMinutes(); + await chrome.alarms.clear(AUTO_LOCK_ALARM); + await chrome.alarms.create(AUTO_LOCK_ALARM, { delayInMinutes: minutes }); +} + +export async function cancelAutoLock(): Promise { + await chrome.alarms.clear(AUTO_LOCK_ALARM); +} + +export function onAutoLockFired(handler: () => void): void { + chrome.alarms.onAlarm.addListener((alarm) => { + if (alarm.name === AUTO_LOCK_ALARM) handler(); + }); +} diff --git a/extension-wallet/src/background/offscreen-lifecycle.ts b/extension-wallet/src/background/offscreen-lifecycle.ts new file mode 100644 index 0000000..f41ad74 --- /dev/null +++ b/extension-wallet/src/background/offscreen-lifecycle.ts @@ -0,0 +1,102 @@ +import { KEEP_ALIVE_PORT_NAME } from "../ipc/port-envelope"; + +const OFFSCREEN_URL = "offscreen.html"; + +/** True if running on Chromium-based browsers that support `chrome.offscreen`. */ +function hasOffscreenApi(): boolean { + return typeof chrome !== "undefined" && typeof chrome.offscreen !== "undefined"; +} + +let creating: Promise | null = null; +let firefoxOffscreenWindowId: number | null = null; + +// `chrome.offscreen.createDocument` resolves when the document is created, +// not after its scripts have run. Without this gate, the SW can return from +// `ensureOffscreen()` before `WalletHost.start()` has registered its +// `onConnect` listener — the next UI port-open finds no listener and hangs. +// The offscreen's `WalletHost.start()` calls `notifyOffscreenReady()` (via +// `chrome.runtime.sendMessage({ type: "offscreen-ready" })`) once it's set +// up; we resolve `readyResolver` then. Each spawn cycle gets a fresh promise. +let readyPromise: Promise | null = null; +let readyResolver: (() => void) | null = null; + +function resetReadyGate() { + readyPromise = new Promise((resolve) => { + readyResolver = resolve; + }); +} + +/** Called by the SW's onMessage handler when the offscreen reports ready. */ +export function markOffscreenReady() { + readyResolver?.(); + readyResolver = null; +} + +export async function ensureOffscreen(): Promise { + if (creating) { + await creating; + if (readyPromise) await readyPromise; + return; + } + + if (hasOffscreenApi()) { + const existing = await chrome.offscreen.hasDocument?.(); + if (existing) { + // Document is already up; either it signaled ready earlier (and our + // gate is a no-op), or it's mid-init and we're about to await the + // signal. Either way, awaiting an already-resolved promise is cheap. + if (readyPromise) await readyPromise; + return; + } + + resetReadyGate(); + creating = chrome.offscreen + .createDocument({ + url: OFFSCREEN_URL, + reasons: ["DOM_PARSER" as chrome.offscreen.Reason], + justification: "Host wallet runtime (PXE, WalletDB, vault)", + }) + .finally(() => { + creating = null; + }); + await creating; + await readyPromise; + return; + } + + // Firefox fallback: open a hidden minimized window. Re-use across calls. + if (firefoxOffscreenWindowId !== null) { + if (readyPromise) await readyPromise; + return; + } + resetReadyGate(); + creating = (async () => { + const win = await chrome.windows.create({ + url: chrome.runtime.getURL(OFFSCREEN_URL), + state: "minimized", + focused: false, + }); + firefoxOffscreenWindowId = win.id ?? null; + })().finally(() => { + creating = null; + }); + await creating; + await readyPromise; +} + +const keepAliveCount = { n: 0, port: null as chrome.runtime.Port | null }; + +export function acquireKeepAlive(): void { + if (keepAliveCount.n === 0) { + keepAliveCount.port = chrome.runtime.connect({ name: KEEP_ALIVE_PORT_NAME }); + } + keepAliveCount.n++; +} + +export function releaseKeepAlive(): void { + keepAliveCount.n = Math.max(0, keepAliveCount.n - 1); + if (keepAliveCount.n === 0) { + keepAliveCount.port?.disconnect(); + keepAliveCount.port = null; + } +} diff --git a/extension-wallet/src/background/remembered-apps.ts b/extension-wallet/src/background/remembered-apps.ts new file mode 100644 index 0000000..c320edf --- /dev/null +++ b/extension-wallet/src/background/remembered-apps.ts @@ -0,0 +1,66 @@ +import { REMEMBERED_APPS_KEY } from "../shared/constants"; + +export interface RememberedApp { + appId: string; + origin: string; + rememberedAt: number; + /** Chain ID as hex string */ + chainId: string; + /** Network version as hex string */ + version: string; +} + +export async function getRememberedApps(): Promise { + if (!chrome?.storage?.local) return []; + const result = await chrome.storage.local.get(REMEMBERED_APPS_KEY); + const apps = (result[REMEMBERED_APPS_KEY] as RememberedApp[] | undefined) ?? []; + // Filter out old format entries that don't have chainId/version + return apps.filter((app) => app.chainId && app.version); +} + +export async function isAppRemembered( + appId: string, + origin: string, + chainId: string, + version: string, +): Promise { + const apps = await getRememberedApps(); + return apps.some( + (a) => + a.appId === appId && a.origin === origin && a.chainId === chainId && a.version === version, + ); +} + +export async function rememberApp( + appId: string, + origin: string, + chainId: string, + version: string, +): Promise { + if (!chrome?.storage?.local) return; + const apps = await getRememberedApps(); + if ( + !apps.some( + (a) => + a.appId === appId && a.origin === origin && a.chainId === chainId && a.version === version, + ) + ) { + apps.push({ appId, origin, rememberedAt: Date.now(), chainId, version }); + await chrome.storage.local.set({ [REMEMBERED_APPS_KEY]: apps }); + } +} + +export async function forgetApp( + appId: string, + origin: string, + chainId: string, + version: string, +): Promise { + if (!chrome?.storage?.local) return; + const apps = await getRememberedApps(); + const filtered = apps.filter( + (a) => + !(a.appId === appId && a.origin === origin && a.chainId === chainId && a.version === version), + ); + await chrome.storage.local.set({ [REMEMBERED_APPS_KEY]: filtered }); +} diff --git a/extension-wallet/src/ipc/parse-event-detail.ts b/extension-wallet/src/ipc/parse-event-detail.ts new file mode 100644 index 0000000..81634fe --- /dev/null +++ b/extension-wallet/src/ipc/parse-event-detail.ts @@ -0,0 +1,14 @@ +/** + * Wallet `wallet-update`, `authorization-request`, and + * `proof-debug-export-request` events are emitted with `detail: jsonStringify(content)`. + * Both UI surfaces and the SW's broadcast subscribers need to parse on receive. + * Unrecognized non-JSON strings (or already-object payloads) pass through unchanged. + */ +export function parseEventDetail(raw: unknown): unknown { + if (typeof raw !== "string") return raw; + try { + return JSON.parse(raw); + } catch { + return raw; + } +} diff --git a/extension-wallet/src/ipc/port-client.ts b/extension-wallet/src/ipc/port-client.ts new file mode 100644 index 0000000..cb68bf2 --- /dev/null +++ b/extension-wallet/src/ipc/port-client.ts @@ -0,0 +1,123 @@ +import { + OFFSCREEN_PORT_NAME, + PortMessageSchema, + type PortBroadcast, + type PortRequest, + type PortResponse, +} from "./port-envelope"; + +type BroadcastHandler = (payload: unknown) => void; + +export interface PortClientOptions { + /** If true, skip the ensure-offscreen ping (caller guarantees offscreen is alive). */ + skipEnsureOffscreen?: boolean; +} + +export class PortClient { + private port: chrome.runtime.Port | null = null; + private connecting: Promise | null = null; + private pending = new Map< + string, + { resolve: (v: unknown) => void; reject: (e: Error) => void } + >(); + private subscriptions = new Map>(); + + constructor(private options: PortClientOptions = {}) {} + + /** + * Kicks off connection. Safe to fire-and-forget; `call()` awaits internally + * if the port isn't ready yet. + */ + connect(): Promise { + if (this.port) return Promise.resolve(); + if (this.connecting) return this.connecting; + this.connecting = this.doConnect().finally(() => { + this.connecting = null; + }); + return this.connecting; + } + + private async doConnect(): Promise { + if (!this.options.skipEnsureOffscreen) { + // Ask the SW to spawn the offscreen doc first; without this the port + // opens before any listener exists and immediately disconnects. + const reply = (await chrome.runtime.sendMessage({ + type: "ensure-offscreen", + })) as { ok: boolean; error?: string } | undefined; + if (!reply?.ok) { + throw new Error(reply?.error ?? "Failed to ensure offscreen document"); + } + } + this.port = chrome.runtime.connect({ name: OFFSCREEN_PORT_NAME }); + this.port.onMessage.addListener((raw) => this.onMessage(raw)); + this.port.onDisconnect.addListener(() => this.onDisconnect()); + } + + disconnect() { + this.port?.disconnect(); + this.port = null; + } + + async call(method: string, args: unknown[]): Promise { + if (!this.port) await this.connect(); + if (!this.port) throw new Error("Port not connected"); + const id = crypto.randomUUID(); + const req: PortRequest = { kind: "request", id, method, args }; + return new Promise((resolve, reject) => { + this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject }); + this.port!.postMessage(req); + }); + } + + onBroadcast(event: PortBroadcast["event"], handler: BroadcastHandler): () => void { + let set = this.subscriptions.get(event); + if (!set) { + set = new Set(); + this.subscriptions.set(event, set); + } + set.add(handler); + return () => set!.delete(handler); + } + + private onMessage(raw: unknown) { + const parsed = PortMessageSchema.safeParse(raw); + if (!parsed.success) return; + const msg = parsed.data; + if (msg.kind === "response") { + this.onResponse(msg); + } else if (msg.kind === "broadcast") { + this.onBroadcastReceived(msg); + } + } + + private onResponse(msg: PortResponse) { + const pending = this.pending.get(msg.id); + if (!pending) return; + this.pending.delete(msg.id); + if (msg.ok) { + // Fallback path on the server side stringified the result (when + // structured clone couldn't handle it). Parse it back here so the + // caller still gets a normal value. + const result = + msg.resultIsJson && typeof msg.result === "string" + ? JSON.parse(msg.result) + : msg.result; + pending.resolve(result); + } else { + pending.reject(new Error(msg.error?.message ?? "Unknown error")); + } + } + + private onBroadcastReceived(msg: PortBroadcast) { + const set = this.subscriptions.get(msg.event); + if (!set) return; + for (const handler of set) handler(msg.payload); + } + + private onDisconnect() { + const err = new Error("Port disconnected"); + for (const { reject } of this.pending.values()) reject(err); + this.pending.clear(); + this.port = null; + } +} diff --git a/extension-wallet/src/ipc/port-envelope.ts b/extension-wallet/src/ipc/port-envelope.ts new file mode 100644 index 0000000..e24d790 --- /dev/null +++ b/extension-wallet/src/ipc/port-envelope.ts @@ -0,0 +1,53 @@ +import { z } from "zod"; + +export const PortRequestSchema = z.object({ + kind: z.literal("request"), + id: z.string(), + method: z.string(), + args: z.array(z.unknown()), +}); +export type PortRequest = z.infer; + +export const PortResponseSchema = z.object({ + kind: z.literal("response"), + id: z.string(), + ok: z.boolean(), + result: z.unknown().optional(), + /** + * Set when `result` is a JSON-serialized string of the actual result. Used + * as a fallback when structured clone can't handle the result (e.g. class + * instances with non-cloneable internal slots). Receivers that see this + * flag must `JSON.parse(result)` to recover the value. + */ + resultIsJson: z.boolean().optional(), + error: z + .object({ + message: z.string(), + stack: z.string().optional(), + }) + .optional(), +}); +export type PortResponse = z.infer; + +export const PortBroadcastSchema = z.object({ + kind: z.literal("broadcast"), + event: z.enum([ + "wallet-update", + "authorization-request", + "proof-debug-export-request", + "vault-locked", + "vault-unlocked", + ]), + payload: z.unknown(), +}); +export type PortBroadcast = z.infer; + +export const PortMessageSchema = z.discriminatedUnion("kind", [ + PortRequestSchema, + PortResponseSchema, + PortBroadcastSchema, +]); +export type PortMessage = z.infer; + +export const OFFSCREEN_PORT_NAME = "offscreen-wallet"; +export const KEEP_ALIVE_PORT_NAME = "keep-alive"; diff --git a/extension-wallet/src/ipc/port-server.ts b/extension-wallet/src/ipc/port-server.ts new file mode 100644 index 0000000..9385df8 --- /dev/null +++ b/extension-wallet/src/ipc/port-server.ts @@ -0,0 +1,114 @@ +import { jsonStringify } from "@aztec/foundation/json-rpc"; +import { + OFFSCREEN_PORT_NAME, + PortMessageSchema, + type PortBroadcast, + type PortRequest, + type PortResponse, +} from "./port-envelope"; + +export interface MethodHandlerMap { + [methodName: string]: (...args: unknown[]) => Promise; +} + +export class PortServer { + private ports = new Set(); + + constructor(private handlers: MethodHandlerMap) {} + + start() { + chrome.runtime.onConnect.addListener((port) => { + if (port.name !== OFFSCREEN_PORT_NAME) return; + this.ports.add(port); + port.onMessage.addListener((raw) => this.onMessage(port, raw)); + port.onDisconnect.addListener(() => this.ports.delete(port)); + }); + } + + broadcast(event: PortBroadcast["event"], payload: unknown) { + const msg: PortBroadcast = { kind: "broadcast", event, payload }; + for (const port of this.ports) { + try { + port.postMessage(msg); + } catch { + // port disconnected; will be cleaned up by onDisconnect + } + } + } + + private async onMessage(port: chrome.runtime.Port, raw: unknown) { + const parsed = PortMessageSchema.safeParse(raw); + if (!parsed.success || parsed.data.kind !== "request") return; + const req = parsed.data as PortRequest; + + const response: PortResponse = await this.dispatch(req); + try { + port.postMessage(response); + } catch (err) { + // postMessage failed with DataCloneError or similar. Wallet results + // often contain class instances with `toJSON()` (Fr, AztecAddress, + // TxSimulationResult) — JSON.stringify is more permissive than + // structured clone for these. Fall back to a stringified result. + console.warn("[PortServer] postMessage failed; retrying as JSON", { + method: req.method, + id: req.id, + error: (err as Error).message, + }); + try { + // Use the foundation's `jsonStringify` instead of plain + // `JSON.stringify`: it handles BigInt (→ decimal string), Buffer + // (→ base64), Map / Set, plus respects `toJSON()`. This matches the + // wire format the wallet-sdk uses internally. + port.postMessage({ + ...response, + result: response.ok ? jsonStringify(response.result) : undefined, + resultIsJson: response.ok, + } satisfies PortResponse); + } catch (fallbackErr) { + // JSON.stringify failure (rare — typically circular refs only). + // Send an error response so the caller doesn't hang. + console.error("[PortServer] JSON fallback also failed", { + method: req.method, + id: req.id, + error: (fallbackErr as Error).message, + }); + try { + port.postMessage({ + kind: "response", + id: req.id, + ok: false, + error: { + message: `Response not serializable: ${(fallbackErr as Error).message}`, + }, + } satisfies PortResponse); + } catch { + // Truly disconnected; nothing more to do. + } + } + } + } + + private async dispatch(req: PortRequest): Promise { + const handler = this.handlers[req.method]; + if (!handler) { + return { + kind: "response", + id: req.id, + ok: false, + error: { message: `Unknown method: ${req.method}` }, + }; + } + try { + const result = await handler(...req.args); + return { kind: "response", id: req.id, ok: true, result }; + } catch (err: unknown) { + const e = err as Error; + return { + kind: "response", + id: req.id, + ok: false, + error: { message: e.message ?? String(err), stack: e.stack }, + }; + } + } +} diff --git a/extension-wallet/src/ipc/port.test.ts b/extension-wallet/src/ipc/port.test.ts new file mode 100644 index 0000000..c030ecf --- /dev/null +++ b/extension-wallet/src/ipc/port.test.ts @@ -0,0 +1,67 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { PortServer } from "./port-server"; +import { PortClient } from "./port-client"; + +class MockPort { + listeners: ((m: any) => void)[] = []; + disconnectListeners: (() => void)[] = []; + peer!: MockPort; + name: string; + constructor(name: string) { + this.name = name; + } + postMessage(m: any) { + queueMicrotask(() => this.peer.listeners.forEach((l) => l(m))); + } + onMessage = { addListener: (l: (m: any) => void) => this.listeners.push(l) }; + onDisconnect = { addListener: (l: () => void) => this.disconnectListeners.push(l) }; +} + +function installChromeMock() { + const onConnectListeners: ((p: MockPort) => void)[] = []; + (globalThis as any).chrome = { + runtime: { + onConnect: { addListener: (l: any) => onConnectListeners.push(l) }, + // PortClient pings the SW first; in tests we just say "ok" — the + // server-side onConnect listener is already registered by the test setup. + sendMessage: async (_msg: unknown) => ({ ok: true }), + connect: (opts: { name: string }) => { + const a = new MockPort(opts.name); + const b = new MockPort(opts.name); + a.peer = b; + b.peer = a; + queueMicrotask(() => onConnectListeners.forEach((l) => l(b))); + return a; + }, + }, + }; +} + +describe("Port transport", () => { + beforeEach(() => installChromeMock()); + + it("round-trips a request through server and client", async () => { + const server = new PortServer({ + echo: async (s: unknown) => `echo:${s as string}`, + }); + server.start(); + const client = new PortClient(); + client.connect(); + const result = await client.call("echo", ["hello"]); + expect(result).toBe("echo:hello"); + }); + + it("delivers broadcasts to subscribed clients", async () => { + const server = new PortServer({}); + server.start(); + const client = new PortClient(); + await client.connect(); + const seen: any[] = []; + client.onBroadcast("wallet-update", (p) => seen.push(p)); + // Wait a microtask for the connect to register on the server side. + await new Promise((r) => queueMicrotask(() => r(null))); + server.broadcast("wallet-update", { foo: 1 }); + await new Promise((r) => setTimeout(r, 0)); + expect(seen).toEqual([{ foo: 1 }]); + }); +}); diff --git a/extension-wallet/src/offscreen/wallet-host.ts b/extension-wallet/src/offscreen/wallet-host.ts new file mode 100644 index 0000000..50100e6 --- /dev/null +++ b/extension-wallet/src/offscreen/wallet-host.ts @@ -0,0 +1,238 @@ +import type { ChainInfo } from "@aztec/aztec.js/account"; +import { Fr } from "@aztec/aztec.js/fields"; +import { WalletSchema } from "@aztec/aztec.js/wallet"; + +/** + * Build an args parser from a Zod-function schema. Returns a function that + * pads the incoming args with `undefined` up to the schema's tuple length + * before parsing — needed because `z.function().args(a, b, c.optional())` + * compiles to a tuple of fixed length 3 even though the third slot is + * optional. Without padding, callers passing 2 args trip a "min 3" error. + */ +function makeArgsParser( + methodSchema: unknown, +): ((args: unknown[]) => unknown[]) | undefined { + if (!methodSchema || typeof methodSchema !== "object" || !("_def" in methodSchema)) { + return undefined; + } + const def = (methodSchema as { _def: { args?: unknown } })._def; + const argsSchema = def.args as + | { parse: (a: unknown[]) => unknown[]; _def?: { items?: unknown[] } } + | undefined; + if (!argsSchema || typeof argsSchema.parse !== "function") return undefined; + const expectedLen = argsSchema._def?.items?.length ?? 0; + return (args: unknown[]) => { + const padded = args.length < expectedLen + ? [...args, ...Array(expectedLen - args.length).fill(undefined)] + : args; + return argsSchema.parse(padded); + }; +} + +/** + * Coerce a `chainInfo`-shaped value back into one with `Fr` instances after + * it's crossed a JSON-serializing port boundary (where Fr → hex string). Same + * tolerant narrowing as the rollup-version case in shared session.ts. + */ +function reviveChainInfo(raw: unknown): ChainInfo { + const r = raw as { chainId: unknown; version: unknown }; + const toFr = (v: unknown): Fr => + v instanceof Fr + ? v + : typeof v === "string" + ? Fr.fromString(v) + : new Fr(v as bigint | number | boolean); + return { chainId: toFr(r.chainId), version: toFr(r.version) }; +} +import { + getOrCreateSession, + getRunningSessionIds, + getSharedResources, + InternalWalletInterfaceSchema, +} from "@demo-wallet/shared/core"; +import { VaultState } from "../vault/vault-state"; +import { PortServer, type MethodHandlerMap } from "../ipc/port-server"; + +export class WalletHost { + private vault = new VaultState(); + private server: PortServer; + /** Currently selected network (set by UI; defaults to localhost). */ + private currentChainInfo: ChainInfo = { chainId: new Fr(31337), version: new Fr(0) }; + + constructor() { + this.server = new PortServer(this.buildHandlers()); + } + + start() { + this.server.start(); + this.vault.onChange((state) => { + if (state === "locked") { + this.server.broadcast("vault-locked", null); + } else { + this.server.broadcast("vault-unlocked", null); + } + }); + } + + private buildHandlers(): MethodHandlerMap { + return { + "vault.isInitialized": async () => await this.vault.isInitialized(), + "vault.isUnlocked": async () => this.vault.isUnlocked(), + "vault.initialize": async (password) => + await this.vault.initialize(password as string), + "vault.unlock": async (password) => await this.vault.unlock(password as string), + "vault.lock": async () => this.vault.lock(), + + "network.set": async (chainId, version) => { + this.currentChainInfo = { + chainId: Fr.fromString(chainId as string), + version: Fr.fromString(version as string), + }; + }, + "network.get": async () => ({ + chainId: this.currentChainInfo.chainId.toString(), + version: this.currentChainInfo.version.toString(), + }), + + // Returns ALL pending authorization requests across every running + // session. Pending authorizations live on per-session shared resources, + // and the dApp call's session (e.g. testnet) may differ from the UI's + // currentChainInfo (e.g. localhost) — so a single-session lookup misses + // requests entirely. The approval window only knows the requestId; we + // give it everything and let it filter. + "authorization.getPending": async () => { + const sessionIds = getRunningSessionIds(); + const all = []; + for (const sessionId of sessionIds) { + const shared = await getSharedResources(sessionId); + for (const entry of shared.pendingAuthorizations.values()) { + all.push(entry.request); + } + } + return all; + }, + + // Resolve an authorization across any session: find the session whose + // pendingAuthorizations contains the requestId, resolve there. + // Mirrors AuthorizationManager.resolveAuthorization but operates + // directly on the shared map so we don't need access to the manager. + "authorization.resolve": async (responseRaw) => { + const response = responseRaw as { + id: string; + approved: boolean; + appId: string; + itemResponses: Record; + }; + const sessionIds = getRunningSessionIds(); + for (const sessionId of sessionIds) { + const shared = await getSharedResources(sessionId); + const pending = shared.pendingAuthorizations.get(response.id); + if (pending) { + pending.promise.resolve(response as never); + shared.pendingAuthorizations.delete(response.id); + return true; + } + } + return false; + }, + + ...this.buildWalletMethodHandlers(), + ...this.buildDappMethodHandlers(), + }; + } + + private forwardWalletEvent = (eventType: string, detail: unknown) => { + if (eventType === "wallet-update") { + this.server.broadcast("wallet-update", detail); + } else if (eventType === "authorization-request") { + this.server.broadcast("authorization-request", detail); + } else if (eventType === "proof-debug-export-request") { + this.server.broadcast("proof-debug-export-request", detail); + } + }; + + private buildWalletMethodHandlers(): MethodHandlerMap { + const guard = async () => { + if (!this.vault.isUnlocked()) { + throw new Error("Vault is locked"); + } + const { internal } = await getOrCreateSession( + this.currentChainInfo, + "ui", + this.forwardWalletEvent, + ); + return internal; + }; + + const handlers: MethodHandlerMap = {}; + for (const methodName of Object.keys(InternalWalletInterfaceSchema)) { + // chrome.runtime.Port serializes via JSON across contexts, so Aztec + // primitives the UI passes (Fr, AztecAddress, Buffer, …) arrive as their + // toJSON forms (hex strings, plain objects). The Zod schema for each + // method already knows how to parse those back into class instances — + // pull the args parser once per method. + const methodSchema = ( + InternalWalletInterfaceSchema as Record + )[methodName]; + const argsParser = makeArgsParser(methodSchema); + + handlers[`wallet.${methodName}`] = async (...args: unknown[]) => { + const wallet = await guard(); + const fn = (wallet as unknown as Record unknown>)[ + methodName + ]; + if (typeof fn !== "function") { + throw new Error(`Method ${methodName} not found on InternalWallet`); + } + const parsedArgs = argsParser ? argsParser(args) : args; + return await fn.apply(wallet, parsedArgs); + }; + } + return handlers; + } + + /** + * Build handlers for `dapp.*` methods. Each forwards to the per-session + * ExternalWallet identified by `session.appId` + `session.chainInfo`. + * Called shape: handler(session, message), where message.args is the call payload. + */ + private buildDappMethodHandlers(): MethodHandlerMap { + const handlers: MethodHandlerMap = {}; + for (const methodName of Object.keys(WalletSchema)) { + // Same JSON-round-trip-revival pattern as wallet.* methods: pull a Zod + // args parser once per method so primitives (Fr, AztecAddress, ...) get + // reconstructed from their hex-string forms after the SW→offscreen hop. + const methodSchema = (WalletSchema as Record)[methodName]; + const argsParser = makeArgsParser(methodSchema); + + handlers[`dapp.${methodName}`] = async (...callArgs: unknown[]) => { + if (!this.vault.isUnlocked()) { + throw new Error("Vault is locked"); + } + const [session, message] = callArgs; + const sess = session as { appId: string; chainInfo: unknown }; + const msg = message as { args?: unknown[] }; + + // Session crossed the port as JSON; chainInfo's Fr instances are now + // hex strings. Revive them so getOrCreateSession's .toNumber() works. + const chainInfo = reviveChainInfo(sess.chainInfo); + + const { external } = await getOrCreateSession( + chainInfo, + sess.appId, + this.forwardWalletEvent, + ); + const rawArgs = msg.args ?? []; + const args = argsParser ? argsParser(rawArgs) : rawArgs; + const fn = (external as unknown as Record unknown>)[ + methodName + ]; + if (typeof fn !== "function") { + throw new Error(`Method ${methodName} not found on ExternalWallet`); + } + return await fn.apply(external, args); + }; + } + return handlers; + } +} diff --git a/extension-wallet/src/shared/constants.ts b/extension-wallet/src/shared/constants.ts new file mode 100644 index 0000000..301ebc1 --- /dev/null +++ b/extension-wallet/src/shared/constants.ts @@ -0,0 +1,13 @@ +export const WALLET_ID = "aztec-extension-wallet"; +export const WALLET_NAME = "Aztec Extension Wallet"; +export const WALLET_VERSION = "0.1.0"; + +export const REMEMBERED_APPS_KEY = "rememberedApps"; +export const SETTINGS_KEY = "settings"; + +export const AUTO_LOCK_ALARM = "auto-lock"; +export const DEFAULT_AUTO_LOCK_MINUTES = 15; +export const MIN_AUTO_LOCK_MINUTES = 1; +export const MAX_AUTO_LOCK_MINUTES = 60 * 24; + +export const UNLOCK_TIMEOUT_MS = 60_000; diff --git a/extension-wallet/src/shared/function-bind-stub.cjs b/extension-wallet/src/shared/function-bind-stub.cjs new file mode 100644 index 0000000..6b51c04 --- /dev/null +++ b/extension-wallet/src/shared/function-bind-stub.cjs @@ -0,0 +1,22 @@ +// CSP-safe replacement for the `function-bind` npm package and its +// `/implementation` entry point. The original constructs a bound function from +// a dynamic string to preserve `f.length`, which Manifest V3's CSP rejects. +// Native `Function.prototype.bind` does the same thing in modern engines +// without dynamic code construction. +// +// This file is intentionally CommonJS (.cjs) because consumers of +// `function-bind` rely on `module.exports = fn` — i.e. the module *itself* is +// the bind function. ESM `export default` would resolve to `{ default: fn }` +// under CJS interop and crash callers that do `bind.apply(...)`. +// +// Wired in via `resolve.alias` in `wxt.config.ts`. + +"use strict"; + +var nativeBind = Function.prototype.bind; + +function bind(that) { + return nativeBind.apply(this, arguments); +} + +module.exports = bind; diff --git a/extension-wallet/src/shared/polyfills.ts b/extension-wallet/src/shared/polyfills.ts new file mode 100644 index 0000000..264f7ba --- /dev/null +++ b/extension-wallet/src/shared/polyfills.ts @@ -0,0 +1,5 @@ +import { Buffer } from "buffer"; + +if (typeof (globalThis as { Buffer?: unknown }).Buffer === "undefined") { + (globalThis as { Buffer?: unknown }).Buffer = Buffer; +} diff --git a/extension-wallet/src/ui/port-wallet-api.ts b/extension-wallet/src/ui/port-wallet-api.ts new file mode 100644 index 0000000..8aa74df --- /dev/null +++ b/extension-wallet/src/ui/port-wallet-api.ts @@ -0,0 +1,46 @@ +import type { Fr } from "@aztec/aztec.js/fields"; +import type { InternalWalletInterface } from "@demo-wallet/shared/core"; +import type { PortClient } from "../ipc/port-client"; +import { parseEventDetail } from "../ipc/parse-event-detail"; + +const EVENT_BY_METHOD: Record< + string, + "wallet-update" | "authorization-request" | "proof-debug-export-request" +> = { + onWalletUpdate: "wallet-update", + onAuthorizationRequest: "authorization-request", + onProofDebugExportRequest: "proof-debug-export-request", +}; + +/** + * Port-backed implementation of InternalWalletInterface. + * + * Method calls become `wallet.` requests over the port; event-listener + * registrations (`onWalletUpdate`, etc.) become broadcast subscriptions. + * + * Tells the offscreen which network this UI is bound to via `network.set`. + */ +export function makePortWalletApi( + client: PortClient, + chainId: Fr, + version: Fr, +): InternalWalletInterface { + void client.call("network.set", [chainId.toString(), version.toString()]); + + return new Proxy({} as InternalWalletInterface, { + get(_t, prop) { + if (typeof prop !== "string" || prop === "then") return undefined; + const event = EVENT_BY_METHOD[prop]; + if (event) { + // Wallet event payloads (wallet-update / authorization-request / + // proof-debug-export-request) are JSON-stringified at the source — + // see `WalletUpdateEvent` in shared/wallet/types/wallet-interaction.ts. + // The web flavor's `wallet-api.ts` parses them on receive; our port + // proxy needs to do the same so consumers get an object, not a string. + return (cb: (p: unknown) => void) => + client.onBroadcast(event, (raw) => cb(parseEventDetail(raw))); + } + return (...args: unknown[]) => client.call(`wallet.${prop}`, args); + }, + }) as InternalWalletInterface; +} diff --git a/extension-wallet/src/vault/kdf.test.ts b/extension-wallet/src/vault/kdf.test.ts new file mode 100644 index 0000000..40ccbe4 --- /dev/null +++ b/extension-wallet/src/vault/kdf.test.ts @@ -0,0 +1,64 @@ +import { describe, it, expect } from "vitest"; +import { deriveKey, makeProbe, verifyProbe, generateSalt, DEFAULT_KDF_PARAMS } from "./kdf"; + +// Production-grade Argon2id at DEFAULT_KDF_PARAMS runs ~2-5s per derivation under CI/sandbox load. +const KDF_TEST_TIMEOUT = 30_000; + +describe("deriveKey (Argon2id)", () => { + it( + "is deterministic given the same salt and password", + async () => { + const salt = new Uint8Array(16).fill(7); + const k1 = await deriveKey("hunter2", salt, DEFAULT_KDF_PARAMS); + const k2 = await deriveKey("hunter2", salt, DEFAULT_KDF_PARAMS); + expect(Array.from(k1)).toEqual(Array.from(k2)); + }, + KDF_TEST_TIMEOUT, + ); + + it( + "produces different keys for different passwords", + async () => { + const salt = new Uint8Array(16).fill(7); + const k1 = await deriveKey("hunter2", salt, DEFAULT_KDF_PARAMS); + const k2 = await deriveKey("hunter3", salt, DEFAULT_KDF_PARAMS); + expect(Array.from(k1)).not.toEqual(Array.from(k2)); + }, + KDF_TEST_TIMEOUT, + ); + + it( + "produces different keys for different salts", + async () => { + const a = await deriveKey("hunter2", new Uint8Array(16).fill(1), DEFAULT_KDF_PARAMS); + const b = await deriveKey("hunter2", new Uint8Array(16).fill(2), DEFAULT_KDF_PARAMS); + expect(Array.from(a)).not.toEqual(Array.from(b)); + }, + KDF_TEST_TIMEOUT, + ); +}); + +describe("vault probe", () => { + it( + "verifies with the same key it was made with", + async () => { + const salt = generateSalt(); + const key = await deriveKey("hunter2", salt, DEFAULT_KDF_PARAMS); + const probe = await makeProbe(key); + expect(await verifyProbe(probe, key)).toBe(true); + }, + KDF_TEST_TIMEOUT, + ); + + it( + "rejects a different key", + async () => { + const salt = generateSalt(); + const right = await deriveKey("hunter2", salt, DEFAULT_KDF_PARAMS); + const wrong = await deriveKey("hunter3", salt, DEFAULT_KDF_PARAMS); + const probe = await makeProbe(right); + expect(await verifyProbe(probe, wrong)).toBe(false); + }, + KDF_TEST_TIMEOUT, + ); +}); diff --git a/extension-wallet/src/vault/kdf.ts b/extension-wallet/src/vault/kdf.ts new file mode 100644 index 0000000..1a5155b --- /dev/null +++ b/extension-wallet/src/vault/kdf.ts @@ -0,0 +1,71 @@ +import { argon2id } from "@noble/hashes/argon2"; + +export interface KdfParams { + /** Memory cost in KiB. */ + m: number; + /** Iterations. */ + t: number; + /** Parallelism. */ + p: number; +} + +/** Conservative defaults sized to <500ms on a 2024-era laptop. */ +export const DEFAULT_KDF_PARAMS: KdfParams = { m: 64 * 1024, t: 3, p: 1 }; + +const KEY_LEN = 32; +const SALT_LEN = 16; +const PROBE_PLAINTEXT = new TextEncoder().encode("aztec-extension-wallet/probe/v1"); + +export function generateSalt(): Uint8Array { + return crypto.getRandomValues(new Uint8Array(SALT_LEN)); +} + +export async function deriveKey( + password: string, + salt: Uint8Array, + params: KdfParams, +): Promise { + return argon2id(new TextEncoder().encode(password), salt, { + m: params.m, + t: params.t, + p: params.p, + dkLen: KEY_LEN, + }); +} + +export interface VaultProbe { + iv: Uint8Array; + ciphertext: Uint8Array; +} + +async function importAesKey(rawKey: Uint8Array): Promise { + return crypto.subtle.importKey("raw", rawKey, { name: "AES-GCM" }, false, [ + "encrypt", + "decrypt", + ]); +} + +export async function makeProbe(rawKey: Uint8Array): Promise { + const key = await importAesKey(rawKey); + const iv = crypto.getRandomValues(new Uint8Array(12)); + const ciphertext = new Uint8Array( + await crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, PROBE_PLAINTEXT), + ); + return { iv, ciphertext }; +} + +export async function verifyProbe(probe: VaultProbe, rawKey: Uint8Array): Promise { + const key = await importAesKey(rawKey); + try { + const plain = new Uint8Array( + await crypto.subtle.decrypt({ name: "AES-GCM", iv: probe.iv }, key, probe.ciphertext), + ); + if (plain.length !== PROBE_PLAINTEXT.length) return false; + for (let i = 0; i < plain.length; i++) { + if (plain[i] !== PROBE_PLAINTEXT[i]) return false; + } + return true; + } catch { + return false; + } +} diff --git a/extension-wallet/src/vault/vault-meta.ts b/extension-wallet/src/vault/vault-meta.ts new file mode 100644 index 0000000..bfb4096 --- /dev/null +++ b/extension-wallet/src/vault/vault-meta.ts @@ -0,0 +1,64 @@ +import { createStore } from "@aztec/kv-store/indexeddb"; +import { createLogger } from "@aztec/aztec.js/log"; +import type { KdfParams, VaultProbe } from "./kdf"; + +const STORE_NAME = "vault-meta"; +const META_KEY = "v1"; + +export interface VaultMeta { + kdfSalt: Uint8Array; + kdfParams: KdfParams; + vaultProbe: VaultProbe; +} + +interface SerializedMeta { + kdfSalt: number[]; + kdfParams: KdfParams; + vaultProbe: { iv: number[]; ciphertext: number[] }; +} + +let cachedStore: Awaited> | null = null; + +async function getMetaMap() { + if (!cachedStore) { + cachedStore = await createStore( + STORE_NAME, + { dataDirectory: STORE_NAME, dataStoreMapSizeKb: 1024 }, + 1, + createLogger("vault-meta"), + ); + } + return cachedStore.openMap("meta"); +} + +export async function readVaultMeta(): Promise { + const map = await getMetaMap(); + const raw = await map.getAsync(META_KEY); + if (!raw) return null; + const parsed = JSON.parse(raw) as SerializedMeta; + return { + kdfSalt: Uint8Array.from(parsed.kdfSalt), + kdfParams: parsed.kdfParams, + vaultProbe: { + iv: Uint8Array.from(parsed.vaultProbe.iv), + ciphertext: Uint8Array.from(parsed.vaultProbe.ciphertext), + }, + }; +} + +export async function writeVaultMeta(meta: VaultMeta): Promise { + const map = await getMetaMap(); + const serialized: SerializedMeta = { + kdfSalt: Array.from(meta.kdfSalt), + kdfParams: meta.kdfParams, + vaultProbe: { + iv: Array.from(meta.vaultProbe.iv), + ciphertext: Array.from(meta.vaultProbe.ciphertext), + }, + }; + await map.set(META_KEY, JSON.stringify(serialized)); +} + +export async function hasVaultMeta(): Promise { + return (await readVaultMeta()) !== null; +} diff --git a/extension-wallet/src/vault/vault-state.test.ts b/extension-wallet/src/vault/vault-state.test.ts new file mode 100644 index 0000000..10dd69b --- /dev/null +++ b/extension-wallet/src/vault/vault-state.test.ts @@ -0,0 +1,79 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { VaultState } from "./vault-state"; + +// Mock the meta store so tests don't hit IndexedDB. +vi.mock("./vault-meta", () => { + let stored: any = null; + return { + readVaultMeta: vi.fn(async () => stored), + writeVaultMeta: vi.fn(async (m: any) => { + stored = m; + }), + hasVaultMeta: vi.fn(async () => stored !== null), + __reset: () => { + stored = null; + }, + }; +}); + +// Each test triggers ~1-2 Argon2id derivations under production params (~2-5s each in CI). +const VAULT_TEST_TIMEOUT = 30_000; + +describe("VaultState", () => { + beforeEach(async () => { + const meta = await import("./vault-meta"); + (meta as any).__reset(); + }); + + it("starts locked when no meta exists", async () => { + const v = new VaultState(); + expect(v.isUnlocked()).toBe(false); + expect(await v.isInitialized()).toBe(false); + }); + + it( + "initialize sets meta and unlocks", + async () => { + const v = new VaultState(); + await v.initialize("hunter2"); + expect(v.isUnlocked()).toBe(true); + expect(await v.isInitialized()).toBe(true); + }, + VAULT_TEST_TIMEOUT, + ); + + it( + "lock clears the in-memory key", + async () => { + const v = new VaultState(); + await v.initialize("hunter2"); + v.lock(); + expect(v.isUnlocked()).toBe(false); + }, + VAULT_TEST_TIMEOUT, + ); + + it( + "unlock with correct password succeeds", + async () => { + const v = new VaultState(); + await v.initialize("hunter2"); + v.lock(); + expect(await v.unlock("hunter2")).toBe(true); + expect(v.isUnlocked()).toBe(true); + }, + VAULT_TEST_TIMEOUT, + ); + + it( + "unlock with wrong password fails and stays locked", + async () => { + const v = new VaultState(); + await v.initialize("hunter2"); + v.lock(); + expect(await v.unlock("hunter3")).toBe(false); + expect(v.isUnlocked()).toBe(false); + }, + VAULT_TEST_TIMEOUT, + ); +}); diff --git a/extension-wallet/src/vault/vault-state.ts b/extension-wallet/src/vault/vault-state.ts new file mode 100644 index 0000000..5bec9ba --- /dev/null +++ b/extension-wallet/src/vault/vault-state.ts @@ -0,0 +1,64 @@ +import { + deriveKey, + generateSalt, + makeProbe, + verifyProbe, + DEFAULT_KDF_PARAMS, +} from "./kdf"; +import { hasVaultMeta, readVaultMeta, writeVaultMeta } from "./vault-meta"; + +type Listener = (state: "locked" | "unlocked") => void; + +export class VaultState { + private unlockedKey: Uint8Array | null = null; + private listeners = new Set(); + + isUnlocked(): boolean { + return this.unlockedKey !== null; + } + + isInitialized(): Promise { + return hasVaultMeta(); + } + + /** First-install: pick a password, write meta, leave unlocked. */ + async initialize(password: string): Promise { + if (await hasVaultMeta()) { + throw new Error("Vault already initialized"); + } + const kdfSalt = generateSalt(); + const kdfParams = DEFAULT_KDF_PARAMS; + const key = await deriveKey(password, kdfSalt, kdfParams); + const vaultProbe = await makeProbe(key); + await writeVaultMeta({ kdfSalt, kdfParams, vaultProbe }); + this.unlockedKey = key; + this.notify("unlocked"); + } + + /** Try to unlock with a password. Returns true on success. */ + async unlock(password: string): Promise { + const meta = await readVaultMeta(); + if (!meta) return false; + const key = await deriveKey(password, meta.kdfSalt, meta.kdfParams); + if (!(await verifyProbe(meta.vaultProbe, key))) return false; + this.unlockedKey = key; + this.notify("unlocked"); + return true; + } + + lock(): void { + if (!this.unlockedKey) return; + this.unlockedKey.fill(0); + this.unlockedKey = null; + this.notify("locked"); + } + + onChange(listener: Listener): () => void { + this.listeners.add(listener); + return () => this.listeners.delete(listener); + } + + private notify(state: "locked" | "unlocked") { + for (const l of this.listeners) l(state); + } +} diff --git a/extension-wallet/tsconfig.json b/extension-wallet/tsconfig.json new file mode 100644 index 0000000..705380c --- /dev/null +++ b/extension-wallet/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./.wxt/tsconfig.json", + "compilerOptions": { + "allowImportingTsExtensions": true, + "jsx": "react-jsx", + "types": ["chrome", "vitest/globals"], + "strict": false + }, + "include": ["entrypoints/**/*", "src/**/*", "tests/**/*", ".wxt/**/*"] +} diff --git a/extension-wallet/wxt.config.ts b/extension-wallet/wxt.config.ts new file mode 100644 index 0000000..c65fa5a --- /dev/null +++ b/extension-wallet/wxt.config.ts @@ -0,0 +1,76 @@ +import { defineConfig } from "wxt"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +const here = dirname(fileURLToPath(import.meta.url)); +const fnBindStub = resolve(here, "src/shared/function-bind-stub.cjs"); + +// See https://wxt.dev/api/config.html +export default defineConfig({ + modules: ["@wxt-dev/module-react"], + vite: () => ({ + // Aztec deps (`@aztec/foundation`, `@aztec/bb.js`, etc.) reach for Node + // globals — `Buffer`, `process.env.*`, sometimes `global` — at module-init + // time. The SW and offscreen contexts have none of these. `nodePolyfills` + // injects globalThis bindings into every chunk via @rollup/plugin-inject, + // which survives code-splitting (a runtime shim in a single entry does not). + plugins: [ + nodePolyfills({ + include: ["buffer", "process"], + globals: { Buffer: true, process: true, global: false }, + protocolImports: false, + }), + ], + resolve: { + // MV3 forbids `'unsafe-eval'` in CSP. The `function-bind` package (a + // transitive dep of `get-intrinsic` / `call-bind` and many others) + // dynamically constructs a bound function from a string to preserve + // `f.length` — that triggers CSP and breaks RPC response handling. + // Native `Function.prototype.bind` does the same thing without eval, so + // we alias both `function-bind` and its `/implementation` entry point + // (some deps import the latter directly) to a thin stub. + alias: [ + { find: /^function-bind$/, replacement: fnBindStub }, + { find: /^function-bind\/implementation$/, replacement: fnBindStub }, + ], + }, + define: { + // Belt and braces: `process.env.X` references are still substituted at + // build time so dead-code elimination can strip dev branches even though + // the polyfill provides a `process` object at runtime. + "process.env.NODE_ENV": JSON.stringify("production"), + }, + }), + manifest: { + name: "Aztec Wallet (Extension)", + description: "Self-contained Aztec wallet — runs the wallet inside the extension", + permissions: ["storage", "alarms", "offscreen", "webNavigation"], + host_permissions: ["*://*/*"], + // MV3 only permits `'wasm-unsafe-eval'` here — `'unsafe-eval'` is + // rejected outright. We rely on the Vite alias above to neutralise the + // one transitive dep (`function-bind`) that needed it. + content_security_policy: { + extension_pages: "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';", + }, + action: { + default_popup: "popup.html", + default_title: "Aztec Wallet", + }, + web_accessible_resources: [ + { + resources: ["approval.html", "expanded.html", "onboarding.html"], + matches: [""], + }, + ], + // Chrome extension key for stable extension ID. + // Generated with: openssl genrsa 2048 | openssl rsa -pubout -outform DER | base64 | tr -d '\n' + key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi37s/BnZg6PsFPMfUrSFYqGDmkWogQP1koulIpesrpYyaoOUv8s9dJFAK6HyRT+2HrbAGcZxuxqHpvURd0jf1ETr50tRGUtz65+SEom9QFXQJ1iJflyOwlcuYCmEzN7HNHX2egKgE+33dHZ0mXql8XiaA3b+hugRjn9w+cJXoDuhdtMTChncq8O5AqspSNxSPQIeveB8cOsaAFZJZRmB8jD8EV9x88TjQY9+X1o8/yLSN7NoTWGVTdm3MHXWDdZu6ffUkZtOLHmT++L655VnkG48PqSnvv0DLKK3koOBaKIjfFPrXrhZyUuFBcpOi8jsDfEB9jWZV/Zvant4l0P75QIDAQAB", + // Firefox requires explicit extension ID. + browser_specific_settings: { + gecko: { + id: "aztec-extension-wallet@aztec.network", + }, + }, + }, +}); diff --git a/package.json b/package.json index e240798..9e08b9a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "workspaces": [ "app", "web", - "shared" + "shared", + "extension-wallet" ], "scripts": { "build": "turbo run build", diff --git a/shared/src/ui.ts b/shared/src/ui.ts index 1ee417b..b11443c 100644 --- a/shared/src/ui.ts +++ b/shared/src/ui.ts @@ -2,10 +2,12 @@ // Import @demo-wallet/shared/core for wallet logic, config, and IPC types export * from "./ui/App.tsx"; export * from "./ui/renderer.tsx"; +export * from "./ui/StandaloneShell.tsx"; export * from "./ui/styles.ts"; export * from "./ui/contexts/NetworkContext.tsx"; export * from "./ui/utils/format.ts"; // UI components +export * from "./ui/components/PinDialog.tsx"; export * from "./ui/components/dialogs/AuthorizationDialog.tsx"; export * from "./ui/components/dialogs/EditAccountAuthorizationDialog.tsx"; export * from "./ui/components/dialogs/EditAddressBookAuthorizationDialog.tsx"; diff --git a/shared/src/ui/StandaloneShell.tsx b/shared/src/ui/StandaloneShell.tsx new file mode 100644 index 0000000..a4aef4f --- /dev/null +++ b/shared/src/ui/StandaloneShell.tsx @@ -0,0 +1,85 @@ +/** + * StandaloneShell — full wallet UI shell used when the wallet is rendered + * directly (not embedded as an iframe). + * + * Gating flow: + * 1. PIN check — first load: set a new PIN; subsequent loads: enter existing PIN + * 2. Once PIN is verified → mount Root (PXE + wallet UI) + * + * Host-specific bits (vault existence check, PIN verification, PIN persistence, + * wallet API factory) are injected via props so that web, extension, and other + * flavors can share the same shell. + */ + +import { useState, useCallback, useEffect } from "react"; +import { Root, type RootProps } from "./renderer.tsx"; +import { PinDialog } from "./components/PinDialog.tsx"; + +export interface StandaloneShellProps { + /** Whether persisted vault/cookie data exists. Used to choose set-PIN vs enter-PIN. */ + hasExistingVault: () => boolean | Promise; + /** + * Whether the vault is already unlocked from another surface (extension flavor). + * If provided and resolves true, the PIN gate is skipped entirely. Web flavor + * has no such concept — leave undefined. + */ + isAlreadyUnlocked?: () => boolean | Promise; + /** Verify the entered PIN/password. Throws on wrong password. */ + verifyPin: (pin: string) => Promise; + /** + * Persist the PIN/password for this session. May be sync (web cookie) or + * async (extension storage); the shell awaits it before mounting Root, so + * downstream code can rely on persistence completing first. + */ + setPin: (pin: string) => void | Promise; + /** Wallet API factory passed to . */ + walletApiFactory: RootProps["walletApiFactory"]; +} + +export function StandaloneShell({ + hasExistingVault, + isAlreadyUnlocked, + verifyPin, + setPin, + walletApiFactory, +}: StandaloneShellProps) { + const [pinReady, setPinReady] = useState(false); + const [pinMode, setPinMode] = useState<"set" | "enter">("set"); + const [pinError, setPinError] = useState(null); + + useEffect(() => { + (async () => { + if (isAlreadyUnlocked && (await isAlreadyUnlocked())) { + setPinReady(true); + return; + } + const existing = await hasExistingVault(); + setPinMode(existing ? "enter" : "set"); + })(); + }, [hasExistingVault, isAlreadyUnlocked]); + + const handlePinSubmit = useCallback( + async (pin: string) => { + setPinError(null); + + if (pinMode === "enter") { + try { + await verifyPin(pin); + } catch { + setPinError("Wrong PIN. Please try again."); + return; + } + } + + await setPin(pin); + setPinReady(true); + }, + [pinMode, verifyPin, setPin], + ); + + if (!pinReady) { + return ; + } + + return ; +} diff --git a/web/src/ui/components/PinDialog.tsx b/shared/src/ui/components/PinDialog.tsx similarity index 92% rename from web/src/ui/components/PinDialog.tsx rename to shared/src/ui/components/PinDialog.tsx index 2b383bd..1a6bce4 100644 --- a/web/src/ui/components/PinDialog.tsx +++ b/shared/src/ui/components/PinDialog.tsx @@ -1,14 +1,14 @@ /** * PIN dialog — prompts the user for a short passphrase (PIN) used to - * encrypt/decrypt account secrets stored in the cross-origin cookie. + * encrypt/decrypt account secrets. * * Two modes: - * - "set": User sets a new PIN (standalone wallet, first time) - * - "enter": User enters existing PIN (iframe, or standalone after reload) + * - "set": User sets a new PIN (first time) + * - "enter": User enters existing PIN (after reload, or in iframe context) * * Renders as a full-viewport centered card. Dark styling is applied inline - * so it looks correct even without a ThemeProvider ancestor (standalone shell - * renders this before the Root/ThemeProvider mounts). + * so it looks correct even without a ThemeProvider ancestor (host shells + * may render this before the Root/ThemeProvider mounts). */ import { useState, useCallback } from "react"; diff --git a/shared/src/wallet/index.ts b/shared/src/wallet/index.ts index 6205e5e..8650f54 100644 --- a/shared/src/wallet/index.ts +++ b/shared/src/wallet/index.ts @@ -4,3 +4,4 @@ export * from "./database"; export * from "./types"; export * from "./decoding"; export * from "./utils"; +export * from "./session"; diff --git a/shared/src/wallet/session/barrel-leak.test.ts b/shared/src/wallet/session/barrel-leak.test.ts new file mode 100644 index 0000000..933acbc --- /dev/null +++ b/shared/src/wallet/session/barrel-leak.test.ts @@ -0,0 +1,18 @@ +import { describe, it, expect } from "vitest"; + +// Pulls in the barrel only, the same way `@demo-wallet/shared/core` re-exports it. +import * as barrel from "./index"; + +describe("session barrel", () => { + it("does not leak test seams", () => { + expect("__resetSessionsForTests" in barrel).toBe(false); + expect("__setSharedResourcesFactoryForTests" in barrel).toBe(false); + expect("__setNodeClientFactoryForTests" in barrel).toBe(false); + }); + + it("re-exports the public surface", () => { + expect("getOrCreateSession" in barrel).toBe(true); + expect("getRunningSessionIds" in barrel).toBe(true); + expect("getSharedResources" in barrel).toBe(true); + }); +}); diff --git a/shared/src/wallet/session/index.ts b/shared/src/wallet/session/index.ts new file mode 100644 index 0000000..e3e031f --- /dev/null +++ b/shared/src/wallet/session/index.ts @@ -0,0 +1,8 @@ +// Public API only — test seams (`__*ForTests`) and factory-type aliases stay +// internal. Tests import them directly from "./session" via a relative path. +export { + getOrCreateSession, + getRunningSessionIds, + getSharedResources, +} from "./session"; +export type { SessionData, SharedResources } from "./session"; diff --git a/shared/src/wallet/session/session.test.ts b/shared/src/wallet/session/session.test.ts new file mode 100644 index 0000000..bef1229 --- /dev/null +++ b/shared/src/wallet/session/session.test.ts @@ -0,0 +1,76 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { Fr } from "@aztec/aztec.js/fields"; +import type { ChainInfo } from "@aztec/aztec.js/account"; +import type { AztecNode } from "@aztec/aztec.js/node"; +import { + getOrCreateSession, + getRunningSessionIds, + __resetSessionsForTests, + __setSharedResourcesFactoryForTests, + __setNodeClientFactoryForTests, + type SharedResources, +} from "./session"; + +const CHAIN_A: ChainInfo = { chainId: new Fr(31337), version: new Fr(1) }; +const CHAIN_B: ChainInfo = { chainId: new Fr(31337), version: new Fr(2) }; + +/** + * The session manager's `getOrCreateSession` does real PXE init: it spins up + * an Aztec node client and calls `node.getL1ContractAddresses()`, which + * requires a running Aztec node and a browser-like environment with + * IndexedDB. These tests cover only the routing/keying logic, so we stub + * out both the node-client factory and the shared-resources factory. + * + * The `ExternalWallet` / `InternalWallet` constructors are still real (they + * are the things we want to verify get instantiated correctly per appId), + * but they only need a `pxe`, `node`, and `db` reference; they do not call + * methods on those during construction. + */ +function fakeNodeClient(): AztecNode { + return {} as AztecNode; +} + +function fakeSharedResources(): SharedResources { + return { + // The wallet constructors store these references; they are not invoked + // during construction or wireEvents, so empty objects suffice. + pxe: {} as SharedResources["pxe"], + node: fakeNodeClient(), + db: {} as SharedResources["db"], + pendingAuthorizations: new Map(), + }; +} + +describe("session manager", () => { + beforeEach(() => { + __resetSessionsForTests(); + __setNodeClientFactoryForTests(() => fakeNodeClient()); + __setSharedResourcesFactoryForTests(async () => fakeSharedResources()); + }); + + it("creates a session keyed by chainId-version and reuses it", async () => { + const a1 = await getOrCreateSession(CHAIN_A, "app-1", () => {}); + const a2 = await getOrCreateSession(CHAIN_A, "app-2", () => {}); + expect(getRunningSessionIds()).toEqual(["31337-1"]); + expect(a1.external).not.toBe(a2.external); // separate appIds → separate wallets + }); + + it("creates separate sessions for different chainId-version", async () => { + await getOrCreateSession(CHAIN_A, "app-1", () => {}); + await getOrCreateSession(CHAIN_B, "app-1", () => {}); + expect(getRunningSessionIds().sort()).toEqual(["31337-1", "31337-2"]); + }); + + it("returns the same wallet pair for the same (session, appId)", async () => { + const w1 = await getOrCreateSession(CHAIN_A, "app-1", () => {}); + const w2 = await getOrCreateSession(CHAIN_A, "app-1", () => {}); + expect(w1.external).toBe(w2.external); + expect(w1.internal).toBe(w2.internal); + }); + + it("returns the resolved sessionId on the wallet pair", async () => { + const result = await getOrCreateSession(CHAIN_A, "app-1", () => {}); + expect(result.sessionId).toBe("31337-1"); + expect(getRunningSessionIds()).toContain(result.sessionId); + }); +}); diff --git a/shared/src/wallet/session/session.ts b/shared/src/wallet/session/session.ts new file mode 100644 index 0000000..bd3103c --- /dev/null +++ b/shared/src/wallet/session/session.ts @@ -0,0 +1,284 @@ +/** + * Host-agnostic browser-wallet session manager. + * + * Manages PXE sessions indexed by `chainId-version`. Each session has one + * shared PXE instance (critical: multiple PXE instances sharing the same + * IndexedDB store cause Map/storage desync) plus per-appId wallet pairs. + * + * This module is the host-agnostic core that the web wallet and the + * browser-extension wallet both build on. It does not know about cookies, + * iframes, or any host-specific persistence; callers wire those concerns + * via the `onWalletEvent` callback. + * + * Key differences from Electron wallet-worker.ts: + * - Uses @aztec/pxe/client/lazy (WASM prover, lazy artifact loading) + * - Uses @aztec/kv-store IndexedDB backend instead of LMDB + * - Runs in the main browser thread (no worker thread / MessagePortMain) + * - Logger uses createLogger directly (no proxy logger needed) + */ + +import { createAztecNodeClient, type AztecNode } from "@aztec/aztec.js/node"; +import { type ChainInfo } from "@aztec/aztec.js/account"; +import { Fr } from "@aztec/aztec.js/fields"; +import { createLogger } from "@aztec/aztec.js/log"; +import { type PromiseWithResolvers } from "@aztec/foundation/promise"; +import { + ExternalWallet, + InternalWallet, + WalletDB, + type AuthorizationRequest, + type AuthorizationResponse, +} from "../index.ts"; +import { getNetworkByChainId } from "../../config/networks.ts"; +import { + createPXE, + getPXEConfig, + type PXE, + type PXEConfig, + type PXECreationOptions, +} from "@aztec/pxe/client/lazy"; +import { createStore } from "@aztec/kv-store/indexeddb"; + +export type SharedResources = { + pxe: PXE; + node: AztecNode; + db: WalletDB; + pendingAuthorizations: Map< + string, + { + promise: PromiseWithResolvers; + request: AuthorizationRequest; + } + >; +}; + +export type SessionData = { + sharedResources: Promise; + wallets: Map>; +}; + +/** + * Test seam: factory that produces the shared resources for a session. + * + * Production code uses `defaultSharedResourcesFactory`, which spins up a real + * PXE / IndexedDB store / WalletDB. Tests can override this via + * `__setSharedResourcesFactoryForTests` to exercise the session-keying logic + * without requiring a live Aztec node. + */ +export type SharedResourcesFactory = (node: AztecNode) => Promise; + +const sessionLog = createLogger("wallet:session"); + +const defaultSharedResourcesFactory: SharedResourcesFactory = async (node) => { + const l1Contracts = await node.getL1ContractAddresses(); + const rollupAddress = l1Contracts.rollupAddress; + + const configOverrides: Partial = { + dataDirectory: `./pxe-${rollupAddress}`, + proverEnabled: true, + }; + + const options: PXECreationOptions = { + loggers: { + store: createLogger("pxe:data:lmdb"), + pxe: createLogger("pxe:service"), + prover: createLogger("bb:native"), + }, + store: await createStore( + `pxe-${rollupAddress}`, + { + dataDirectory: configOverrides.dataDirectory, + dataStoreMapSizeKb: 2e10, + }, + 2, + createLogger("pxe:data:lmdb"), + ), + }; + + const walletDBLogger = createLogger("wallet:data:lmdb"); + const walletDBStore = await createStore( + `wallet-${rollupAddress}`, + { + dataDirectory: `wallet-${rollupAddress}`, + dataStoreMapSizeKb: 2e10, + }, + 2, + walletDBLogger, + ); + const db = WalletDB.init(walletDBStore, walletDBLogger); + + const pxe = await createPXE(node, { ...getPXEConfig(), ...configOverrides }, options); + + const pendingAuthorizations = new Map< + string, + { + promise: PromiseWithResolvers; + request: AuthorizationRequest; + } + >(); + + return { pxe, node, db, pendingAuthorizations }; +}; + +let sharedResourcesFactory: SharedResourcesFactory = defaultSharedResourcesFactory; + +/** + * Test seam for the node-client builder. Production code uses + * `createAztecNodeClient` from @aztec/aztec.js/node, but tests can swap in + * a fake node via `__setNodeClientFactoryForTests` to skip auto-version + * detection (which performs a real network call). + */ +export type NodeClientFactory = (nodeUrl: string) => AztecNode; +let nodeClientFactory: NodeClientFactory = createAztecNodeClient; + +const RUNNING_SESSIONS = new Map(); + +/** + * Get-or-create the session for `chainInfo` and the wallet pair for `appId`. + * + * Returns the resolved canonical `sessionId` (`${chainId}-${version}`) + * alongside the wallet pair. Callers should prefer this `sessionId` over + * recomputing one from the input `chainInfo` because version auto-detection + * (when `chainInfo.version === 0`) happens inside this function — the + * input `chainInfo`'s version may differ from the resolved one. + */ +export async function getOrCreateSession( + chainInfo: ChainInfo, + appId: string, + onWalletEvent: (eventType: string, detail: unknown) => void, +): Promise<{ external: ExternalWallet; internal: InternalWallet; sessionId: string }> { + const network = getNetworkByChainId(chainInfo.chainId.toNumber(), chainInfo.version.toNumber()); + if (!network) { + throw new Error( + `Unknown network: chainId=${chainInfo.chainId.toNumber()}, version=${chainInfo.version.toNumber()}`, + ); + } + + const node = nodeClientFactory(network.nodeUrl!); + + // Auto-detect version if 0. `rollupVersion` shape has shifted across Aztec + // SDK versions — sometimes Fr, sometimes bigint/number, sometimes a hex + // string. Narrow defensively at runtime so we accept any of those, since + // the SDK's compile-time type doesn't always match the runtime value. + if (chainInfo.version.equals(new Fr(0))) { + const { rollupVersion } = await node.getNodeInfo(); + const raw: unknown = rollupVersion; + const versionFr = + raw instanceof Fr + ? raw + : typeof raw === "string" + ? Fr.fromString(raw) + : new Fr(raw as bigint | number | boolean); + chainInfo = { ...chainInfo, version: versionFr }; + } + + const sessionId = `${chainInfo.chainId.toNumber()}-${chainInfo.version.toNumber()}`; + let session = RUNNING_SESSIONS.get(sessionId); + + if (!session) { + sessionLog.info( + `[PXE-INIT] Creating NEW session with shared PXE instance for sessionId=${sessionId}`, + ); + + const sharedResources = sharedResourcesFactory(node); + session = { sharedResources, wallets: new Map() }; + RUNNING_SESSIONS.set(sessionId, session); + } else { + sessionLog.info( + `[PXE-INIT] Reusing existing shared PXE instance for sessionId=${sessionId}`, + ); + } + + const sharedResources = await session.sharedResources; + + if (!session.wallets.has(appId)) { + const walletInit = async () => { + const externalLog = createLogger(`wallet:external:${appId}`); + const internalLog = createLogger(`wallet:internal:${appId}`); + + const externalWallet = new ExternalWallet( + sharedResources.pxe, + sharedResources.node, + sharedResources.db, + sharedResources.pendingAuthorizations, + appId, + chainInfo, + externalLog, + ); + + const internalWallet = new InternalWallet( + sharedResources.pxe, + sharedResources.node, + sharedResources.db, + sharedResources.pendingAuthorizations, + appId, + chainInfo, + internalLog, + ); + + const wireEvents = (wallet: ExternalWallet | InternalWallet) => { + wallet.addEventListener("wallet-update", (event: Event) => { + const detail = (event as CustomEvent).detail; + onWalletEvent("wallet-update", detail); + }); + wallet.addEventListener("authorization-request", (event: Event) => { + onWalletEvent("authorization-request", (event as CustomEvent).detail); + }); + wallet.addEventListener("proof-debug-export-request", (event: Event) => { + onWalletEvent("proof-debug-export-request", (event as CustomEvent).detail); + }); + }; + + wireEvents(externalWallet); + wireEvents(internalWallet); + + return { external: externalWallet, internal: internalWallet }; + }; + + session.wallets.set(appId, walletInit()); + } + + const wallet = await session.wallets.get(appId)!; + return { ...wallet, sessionId }; +} + +/** Returns the current sessions map (for debugging / UI inspection) */ +export function getRunningSessionIds(): string[] { + return Array.from(RUNNING_SESSIONS.keys()); +} + +/** + * Returns the shared resources for a session (pxe, node, db, pendingAuthorizations). + * Used by the UI wallet-api to resolve authorization requests directly. + * + * Pass the canonical `sessionId` returned from `getOrCreateSession`. Computing + * a sessionId from a `chainInfo` whose `version` is still `0` will not find + * the session — that's by design; callers must flow the resolved sessionId. + */ +export async function getSharedResources(sessionId: string): Promise { + const session = RUNNING_SESSIONS.get(sessionId); + if (!session) { + throw new Error(`No session found for sessionId=${sessionId}`); + } + return session.sharedResources; +} + +/** + * Test-only helper. Not exported from the package barrel; import directly + * from `./session` in tests. + */ +export function __resetSessionsForTests() { + RUNNING_SESSIONS.clear(); + sharedResourcesFactory = defaultSharedResourcesFactory; + nodeClientFactory = createAztecNodeClient; +} + +/** Test-only: override the shared-resources factory (e.g. to bypass real PXE init). */ +export function __setSharedResourcesFactoryForTests(factory: SharedResourcesFactory) { + sharedResourcesFactory = factory; +} + +/** Test-only: override the node-client factory (e.g. to bypass real network calls). */ +export function __setNodeClientFactoryForTests(factory: NodeClientFactory) { + nodeClientFactory = factory; +} diff --git a/web/src/ui/IframeShell.tsx b/web/src/ui/IframeShell.tsx index 226c9df..04a6b5a 100644 --- a/web/src/ui/IframeShell.tsx +++ b/web/src/ui/IframeShell.tsx @@ -46,13 +46,13 @@ import { type IframeConnectionConfig, } from "@aztec/wallet-sdk/iframe/handlers"; import { - getOrCreateSession, + getOrCreateSessionWithCookieSync, setCookiePassphrase, hasCookiePassphrase, } from "../wallet/wallet-service.ts"; import { hasAccountsCookie, readAccountsCookie } from "../wallet/sync-cookies.ts"; import { EmojiVerification } from "./components/EmojiVerification.tsx"; -import { PinDialog } from "./components/PinDialog.tsx"; +import { PinDialog } from "@demo-wallet/shared/ui"; import { Fr } from "@aztec/aztec.js/fields"; const themeOptions: ThemeOptions = { @@ -107,7 +107,7 @@ function WalletUI({ chainId: chainInfo.chainId, version: chainInfo.version, }; - await getOrCreateSession(normalizedChainInfo, "refresh", () => {}); + await getOrCreateSessionWithCookieSync(normalizedChainInfo, "refresh", () => {}); }, [chainInfo.chainId, chainInfo.version]); const walletContext = useMemo( @@ -426,7 +426,7 @@ function IframeContent() { await pinGateRef.current.promise; const normalizedChainInfo = { chainId, version }; - const { external } = await getOrCreateSession( + const { external } = await getOrCreateSessionWithCookieSync( normalizedChainInfo, appId, (eventType, detail) => { diff --git a/web/src/ui/StandaloneShell.tsx b/web/src/ui/StandaloneShell.tsx index d6c62ec..de4aa87 100644 --- a/web/src/ui/StandaloneShell.tsx +++ b/web/src/ui/StandaloneShell.tsx @@ -1,50 +1,20 @@ /** - * StandaloneShell — full wallet UI when the web wallet is accessed directly - * (not embedded as an iframe). Identical in look/feel to the Electron app. - * - * Gating flow: - * 1. PIN check — first load: set a new PIN; subsequent loads: enter existing PIN - * 2. Once PIN is verified → mount Root (PXE + wallet UI) + * Web flavor's StandaloneShell — thin wrapper that wires the shared + * StandaloneShell to the web's cookie-passphrase auth and WalletApi transport. */ -import { useState, useCallback, useEffect } from "react"; -import { Root } from "@demo-wallet/shared/ui"; +import { StandaloneShell as Shell } from "@demo-wallet/shared/ui"; import { WalletApi } from "./utils/wallet-api.ts"; -import { PinDialog } from "./components/PinDialog.tsx"; import { hasAccountsCookie, readAccountsCookie } from "../wallet/sync-cookies.ts"; import { setCookiePassphrase } from "../wallet/wallet-service.ts"; export function StandaloneShell() { - const [pinReady, setPinReady] = useState(false); - const [pinMode, setPinMode] = useState<"set" | "enter">("set"); - const [pinError, setPinError] = useState(null); - - useEffect(() => { - setPinMode(hasAccountsCookie() ? "enter" : "set"); - }, []); - - const handlePinSubmit = useCallback( - async (pin: string) => { - setPinError(null); - - if (pinMode === "enter") { - try { - await readAccountsCookie(pin); - } catch { - setPinError("Wrong PIN. Please try again."); - return; - } - } - - setCookiePassphrase(pin); - setPinReady(true); - }, - [pinMode], + return ( + readAccountsCookie(pin).then(() => undefined)} + setPin={setCookiePassphrase} + walletApiFactory={WalletApi.create} + /> ); - - if (!pinReady) { - return ; - } - - return ; } diff --git a/web/src/ui/utils/wallet-api.ts b/web/src/ui/utils/wallet-api.ts index cc268c7..9f92715 100644 --- a/web/src/ui/utils/wallet-api.ts +++ b/web/src/ui/utils/wallet-api.ts @@ -8,7 +8,7 @@ import { type Fr } from "@aztec/foundation/schemas"; import type { InternalWalletInterface, AuthorizationResponse } from "@demo-wallet/shared/core"; -import { getOrCreateSession } from "../../wallet/wallet-service.ts"; +import { getOrCreateSessionWithCookieSync } from "../../wallet/wallet-service.ts"; // Event emitter for wallet update and authorization request events. // These are global because they are session-level (not per-API instance). @@ -36,30 +36,36 @@ function emitProofDebugExportRequest(detail: unknown) { proofDebugExportListeners.forEach((cb) => cb(parsed)); } -// Cache: chainId-version → InternalWallet -const walletCache = new Map< - string, - Promise>["internal"]> ->(); +// Cache: input-key (chainId-version, may use unresolved version=0) → session pair. +// We cache the whole pair (not just the wallet) so callers can reach the +// resolved `sessionId` for downstream calls like `getSharedResources`. +type CachedSession = Awaited>; +const walletCache = new Map>(); function getCacheKey(chainId: Fr, version: Fr): string { return `${chainId.toString()}-${version.toString()}`; } -async function getInternalWallet( - chainId: Fr, - version: Fr, -): Promise>["internal"]> { +function getOrCreateSessionEntry(chainId: Fr, version: Fr): Promise { const key = getCacheKey(chainId, version); - if (!walletCache.has(key)) { - const p = getOrCreateSession({ chainId, version }, "internal-ui", (eventType, detail) => { + let entry = walletCache.get(key); + if (!entry) { + entry = getOrCreateSessionWithCookieSync({ chainId, version }, "internal-ui", (eventType, detail) => { if (eventType === "wallet-update") emitWalletUpdate(detail); else if (eventType === "authorization-request") emitAuthorizationRequest(detail); else if (eventType === "proof-debug-export-request") emitProofDebugExportRequest(detail); - }).then(({ internal }) => internal); - walletCache.set(key, p); + }); + walletCache.set(key, entry); } - return walletCache.get(key)!; + return entry; +} + +async function getInternalWallet( + chainId: Fr, + version: Fr, +): Promise { + const { internal } = await getOrCreateSessionEntry(chainId, version); + return internal; } export class WalletApi { @@ -133,7 +139,8 @@ export class WalletApi { } // resolveAuthorization needs to reach the shared pendingAuthorizations map. -// We access it by going through wallet-service's session. +// We access it by going through wallet-service's session, using the resolved +// sessionId captured when the session was first created. import { getSharedResources } from "../../wallet/wallet-service.ts"; async function resolveAuthorizationViaSession( @@ -141,7 +148,10 @@ async function resolveAuthorizationViaSession( version: Fr, response: AuthorizationResponse, ): Promise { - const resources = await getSharedResources({ chainId, version }); + // Reuses the cached session (resolves version=0 if needed) rather than + // recomputing a sessionId from the un-resolved (chainId, version). + const { sessionId } = await getOrCreateSessionEntry(chainId, version); + const resources = await getSharedResources(sessionId); const pending = resources.pendingAuthorizations.get(response.id); if (pending) { pending.promise.resolve(response); diff --git a/web/src/wallet/wallet-service.ts b/web/src/wallet/wallet-service.ts index 599ff75..f3a113d 100644 --- a/web/src/wallet/wallet-service.ts +++ b/web/src/wallet/wallet-service.ts @@ -1,39 +1,33 @@ /** - * Browser wallet service — the browser equivalent of wallet-worker.ts. + * Browser wallet service — web-flavor wrapper around the host-agnostic + * session manager in `@demo-wallet/shared/core`. * - * Manages PXE sessions indexed by `chainId-version`. Each session has one - * shared PXE instance (critical: multiple PXE instances sharing the same - * IndexedDB store cause Map/storage desync) plus per-appId wallet pairs. + * The host-agnostic core (PXE per chainId-version, wallet pair per appId, + * RUNNING_SESSIONS map) lives in `shared/wallet/session/`. This file layers + * the web-only cookie-sync glue on top: + * - cookie-passphrase state and accessors + * - bootstrapping accounts/contacts/capabilities from encrypted cookies + * - syncing wallet state back to cookies on `wallet-update` events + * - iframe-vs-standalone behavior gates via the `IS_IFRAME` flag * - * Key differences from Electron wallet-worker.ts: - * - Uses @aztec/pxe/client/lazy (WASM prover, lazy artifact loading) - * - Uses @aztec/kv-store IndexedDB backend instead of LMDB - * - Runs in the main browser thread (no worker thread / MessagePortMain) - * - Logger uses createLogger directly (no proxy logger needed) + * Call sites that previously imported `getOrCreateSession` directly should + * use `getOrCreateSessionWithCookieSync` instead — same signature plus the + * cookie-sync side effects wired in. */ -import { createAztecNodeClient, type AztecNode } from "@aztec/aztec.js/node"; import { type ChainInfo } from "@aztec/aztec.js/account"; import { Fr } from "@aztec/aztec.js/fields"; import { AztecAddress } from "@aztec/aztec.js/addresses"; import { createLogger } from "@aztec/aztec.js/log"; -import { type PromiseWithResolvers } from "@aztec/foundation/promise"; import { ExternalWallet, InternalWallet, WalletDB, - type AuthorizationRequest, - type AuthorizationResponse, - getNetworkByChainId, + getOrCreateSession, + getRunningSessionIds, + getSharedResources, } from "@demo-wallet/shared/core"; -import { - createPXE, - getPXEConfig, - type PXE, - type PXEConfig, - type PXECreationOptions, -} from "@aztec/pxe/client/lazy"; -import { createStore } from "@aztec/kv-store/indexeddb"; +import { type PXE } from "@aztec/pxe/client/lazy"; import { writeAccountsCookie, readAccountsCookie, @@ -45,27 +39,11 @@ import { type PortableContact, } from "./sync-cookies.ts"; -const IS_IFRAME = typeof window !== "undefined" && window.self !== window.top; - -type SessionData = { - sharedResources: Promise<{ - pxe: PXE; - node: AztecNode; - db: WalletDB; - pendingAuthorizations: Map< - string, - { - promise: PromiseWithResolvers; - request: AuthorizationRequest; - } - >; - }>; - /** One-time account/contact bootstrap from cookies. Runs once per session. */ - bootstrapDone: Promise | null; - wallets: Map>; -}; +// Re-export the lifted host-agnostic API so existing callers can keep +// importing from this module. +export { getOrCreateSession, getRunningSessionIds, getSharedResources }; -const RUNNING_SESSIONS = new Map(); +const IS_IFRAME = typeof window !== "undefined" && window.self !== window.top; // ─── Targeted cookie sync ─── // Each cookie is synced only when the relevant data changes, not on every @@ -102,189 +80,102 @@ export function hasCookiePassphrase(): boolean { return _cookiePassphrase !== null; } -export async function getOrCreateSession( +// Tracks one-time cookie bootstrap per session id so that the first call to +// `getOrCreateSessionWithCookieSync` for a given `chainId-version` runs the +// bootstrap exactly once. Subsequent calls await the same promise. +const cookieBootstrapBySession = new Map>(); + +/** + * Web-flavor wrapper around `getOrCreateSession`. Same signature, plus: + * - schedules the appropriate cookie sync when `wallet-update` fires + * - filters out internal `capabilityChange` events from the UI callback + * - in iframe mode, bootstraps accounts/contacts/capabilities from cookies + * once per session before the first wallet pair is returned + * - in standalone mode, runs the initial capability bootstrap-and-resync + * once per session before the first wallet pair is returned + */ +export async function getOrCreateSessionWithCookieSync( chainInfo: ChainInfo, appId: string, onWalletEvent: (eventType: string, detail: unknown) => void, -): Promise<{ external: ExternalWallet; internal: InternalWallet }> { - const network = getNetworkByChainId(chainInfo.chainId.toNumber(), chainInfo.version.toNumber()); - if (!network) { - throw new Error( - `Unknown network: chainId=${chainInfo.chainId.toNumber()}, version=${chainInfo.version.toNumber()}`, - ); - } +): Promise<{ external: ExternalWallet; internal: InternalWallet; sessionId: string }> { + // Captured after the lifted getOrCreateSession resolves. Events can only + // fire after wallet construction, which can only happen after the session's + // shared resources resolve, so by the time `wrappedOnWalletEvent` is invoked + // this reference is guaranteed to be set. + let sessionDb: WalletDB | null = null; + + const wrappedOnWalletEvent = (eventType: string, detail: unknown) => { + if (eventType === "wallet-update") { + // Sync only the relevant cookie based on the interaction type. + let type: string | undefined; + try { + type = JSON.parse(detail as string)?.type; + } catch { + /* ignore parse errors */ + } - const node = createAztecNodeClient(network.nodeUrl!); + if (sessionDb) { + if (!IS_IFRAME && (type === "createAccount" || type === "deployAccount")) { + scheduleAccountSync(sessionDb); + } else if (!IS_IFRAME && type === "registerSender") { + scheduleContactSync(sessionDb); + } else if (type === "requestCapabilities" || type === "capabilityChange") { + scheduleCapabilitySync(sessionDb); + } + } - // Auto-detect version if 0 - if (chainInfo.version.equals(new Fr(0))) { - const { rollupVersion } = await node.getNodeInfo(); - chainInfo = { ...chainInfo, version: new Fr(rollupVersion) }; - } + // Don't forward internal-only events to the UI. + if (type === "capabilityChange") return; + } + onWalletEvent(eventType, detail); + }; - const sessionId = `${chainInfo.chainId.toNumber()}-${chainInfo.version.toNumber()}`; - let session = RUNNING_SESSIONS.get(sessionId); - - if (!session) { - const log = createLogger("wallet:session"); - log.info(`[PXE-INIT] Creating NEW session with shared PXE instance for sessionId=${sessionId}`); - - const pxeInit = (async () => { - const l1Contracts = await node.getL1ContractAddresses(); - const rollupAddress = l1Contracts.rollupAddress; - - const configOverrides: Partial = { - dataDirectory: `./pxe-${rollupAddress}`, - proverEnabled: true, - }; - - const options: PXECreationOptions = { - loggers: { - store: createLogger("pxe:data:lmdb"), - pxe: createLogger("pxe:service"), - prover: createLogger("bb:native"), - }, - store: await createStore( - `pxe-${rollupAddress}`, - { - dataDirectory: configOverrides.dataDirectory, - dataStoreMapSizeKb: 2e10, - }, - 2, - createLogger("pxe:data:lmdb"), - ), - }; - - const walletDBLogger = createLogger("wallet:data:lmdb"); - const walletDBStore = await createStore( - `wallet-${rollupAddress}`, - { - dataDirectory: `wallet-${rollupAddress}`, - dataStoreMapSizeKb: 2e10, - }, - 2, - walletDBLogger, - ); - const db = WalletDB.init(walletDBStore, walletDBLogger); - - const pxe = await createPXE(node, { ...getPXEConfig(), ...configOverrides }, options); - - const pendingAuthorizations = new Map< - string, - { - promise: PromiseWithResolvers; - request: AuthorizationRequest; - } - >(); + // `getOrCreateSession` resolves `version=0` internally, so its returned + // `sessionId` is the canonical key. We use that for both `getSharedResources` + // and the `cookieBootstrapBySession` keying — recomputing one from the + // (possibly version-0) input `chainInfo` would diverge. + const pair = await getOrCreateSession(chainInfo, appId, wrappedOnWalletEvent); + const { sessionId } = pair; + const resources = await getSharedResources(sessionId); + sessionDb = resources.db; + + // ─── One-shot per-session cookie bootstrap ─── + // The original `wallet-service.ts` ran this inline inside the lifted `pxeInit` + // block, but the lifted module no longer knows about cookies. Run it here on + // the first call per session id, gated on the passphrase being set. + if (_cookiePassphrase) { + let bootstrap = cookieBootstrapBySession.get(sessionId); + if (!bootstrap) { + bootstrap = (async () => { + const { db, pxe } = resources; - if (_cookiePassphrase) { // Import capabilities from cookie (full overwrite: cookie is authoritative). await bootstrapCapabilitiesFromCookie(db); - if (!IS_IFRAME) { - // Accounts and contacts are standalone-only (source of truth). + if (IS_IFRAME) { + // Iframe: import accounts and contacts from cookies into PXE. + // Must be serialized to avoid concurrent PXE operations on the same + // IndexedDB (IDB transactions auto-close on browser, causing + // "object not usable" errors). + await bootstrapAccountsFromCookie(sessionId, pair.internal); + await bootstrapContactsFromCookie(db, pxe); + } else { + // Standalone: accounts and contacts are the source of truth — push + // the current state to the cookie so the iframe can pick it up. await syncAccountsToCookie(db); await syncContactsToCookie(db); } + // Export capabilities to cookie (includes both local + newly imported). await syncCapabilitiesToCookie(db); - } - - return { pxe, node, db, pendingAuthorizations }; - })(); - - session = { sharedResources: pxeInit, bootstrapDone: null, wallets: new Map() }; - RUNNING_SESSIONS.set(sessionId, session); - } else { - createLogger("wallet:session").info( - `[PXE-INIT] Reusing existing shared PXE instance for sessionId=${sessionId}`, - ); - } - - const sharedResources = await session.sharedResources; - - if (!session.wallets.has(appId)) { - const walletInit = async () => { - const externalLog = createLogger(`wallet:external:${appId}`); - const internalLog = createLogger(`wallet:internal:${appId}`); - - const externalWallet = new ExternalWallet( - sharedResources.pxe, - sharedResources.node, - sharedResources.db, - sharedResources.pendingAuthorizations, - appId, - chainInfo, - externalLog, - ); - - const internalWallet = new InternalWallet( - sharedResources.pxe, - sharedResources.node, - sharedResources.db, - sharedResources.pendingAuthorizations, - appId, - chainInfo, - internalLog, - ); - - const wireEvents = (wallet: ExternalWallet | InternalWallet) => { - wallet.addEventListener("wallet-update", (event: Event) => { - const detail = (event as CustomEvent).detail; - - // Sync only the relevant cookie based on the interaction type. - let type: string | undefined; - try { - type = JSON.parse(detail)?.type; - } catch { - /* ignore parse errors */ - } - - if (!IS_IFRAME && (type === "createAccount" || type === "deployAccount")) { - scheduleAccountSync(sharedResources.db); - } else if (!IS_IFRAME && type === "registerSender") { - scheduleContactSync(sharedResources.db); - } else if (type === "requestCapabilities" || type === "capabilityChange") { - scheduleCapabilitySync(sharedResources.db); - } - - // Don't forward internal-only events to the UI. - if (type === "capabilityChange") return; - - onWalletEvent("wallet-update", detail); - }); - wallet.addEventListener("authorization-request", (event: Event) => { - onWalletEvent("authorization-request", (event as CustomEvent).detail); - }); - wallet.addEventListener("proof-debug-export-request", (event: Event) => { - onWalletEvent("proof-debug-export-request", (event as CustomEvent).detail); - }); - }; - - wireEvents(externalWallet); - wireEvents(internalWallet); - - // In iframe mode, bootstrap accounts and contacts from cookies into PXE. - // Runs once per session — first appId triggers it, others await the same promise. - // Must be serialized to avoid concurrent PXE operations on the same IndexedDB - // (IDB transactions auto-close on browser, causing "object not usable" errors). - if (IS_IFRAME && _cookiePassphrase && !session.bootstrapDone) { - session.bootstrapDone = (async () => { - await bootstrapAccountsFromCookie(chainInfo, internalWallet); - await bootstrapContactsFromCookie(sharedResources.db, sharedResources.pxe); - })(); - } - if (session.bootstrapDone) { - await session.bootstrapDone; - } - - return { external: externalWallet, internal: internalWallet }; - }; - - session.wallets.set(appId, walletInit()); + })(); + cookieBootstrapBySession.set(sessionId, bootstrap); + } + await bootstrap; } - return session.wallets.get(appId)!; + return pair; } /** @@ -294,10 +185,13 @@ export async function getOrCreateSession( * Requires passphrase to have been set via setCookiePassphrase(). * Skips accounts that already exist in the DB. * + * @param sessionId - The canonical sessionId returned from + * `getOrCreateSession`. Pass the resolved sessionId, not one recomputed + * from a (possibly version=0) chainInfo. * @param wallet - An InternalWallet instance used to register accounts with PXE. */ export async function bootstrapAccountsFromCookie( - chainInfo: ChainInfo, + sessionId: string, wallet: InternalWallet, ): Promise { const log = createLogger("wallet:cookie"); @@ -314,7 +208,7 @@ export async function bootstrapAccountsFromCookie( return 0; } - const { db } = await getSharedResources(chainInfo); + const { db } = await getSharedResources(sessionId); const existingAccounts = await db.listAccounts(); const existingAddresses = new Set(existingAccounts.map((a) => a.item.toString())); @@ -485,44 +379,3 @@ async function bootstrapCapabilitiesFromCookie(db: WalletDB): Promise { ); return imported; } - -/** Returns the current sessions map (for debugging / UI inspection) */ -export function getRunningSessionIds(): string[] { - return Array.from(RUNNING_SESSIONS.keys()); -} - -/** - * Returns the shared resources for a session (pxe, node, db, pendingAuthorizations). - * Used by the UI wallet-api to resolve authorization requests directly. - */ -export async function getSharedResources(chainInfo: ChainInfo): Promise<{ - pxe: PXE; - node: AztecNode; - db: WalletDB; - pendingAuthorizations: Map< - string, - { - promise: PromiseWithResolvers; - request: AuthorizationRequest; - } - >; -}> { - const sessionId = `${chainInfo.chainId.toNumber()}-${chainInfo.version.toNumber()}`; - let session = RUNNING_SESSIONS.get(sessionId); - - // If version is 0 (unresolved), find the session by chainId prefix - if (!session && chainInfo.version.toNumber() === 0) { - const prefix = `${chainInfo.chainId.toNumber()}-`; - for (const [key, value] of RUNNING_SESSIONS) { - if (key.startsWith(prefix) && key !== sessionId) { - session = value; - break; - } - } - } - - if (!session) { - throw new Error(`No session found for sessionId=${sessionId}`); - } - return session.sharedResources; -} diff --git a/yarn.lock b/yarn.lock index 7c15417..2c872bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,6 +5,16 @@ __metadata: version: 8 cacheKey: 10c0 +"@1natsu/wait-element@npm:^4.1.2": + version: 4.2.0 + resolution: "@1natsu/wait-element@npm:4.2.0" + dependencies: + defu: "npm:^6.1.4" + many-keys-map: "npm:^3.0.0" + checksum: 10c0/56eed29b426bc7329baca44d346407c16862c7ef5960d4506729563cf33e7cf28630d321fd1fdb330743f6702cbfe942596c56a160728cf1121ec5fe19144dcc + languageName: node + linkType: hard + "@adraffy/ens-normalize@npm:^1.11.0": version: 1.11.1 resolution: "@adraffy/ens-normalize@npm:1.11.1" @@ -12,6 +22,25 @@ __metadata: languageName: node linkType: hard +"@aklinker1/rollup-plugin-visualizer@npm:5.12.0": + version: 5.12.0 + resolution: "@aklinker1/rollup-plugin-visualizer@npm:5.12.0" + dependencies: + open: "npm:^8.4.0" + picomatch: "npm:^2.3.1" + source-map: "npm:^0.7.4" + yargs: "npm:^17.5.1" + peerDependencies: + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rollup: + optional: true + bin: + rollup-plugin-visualizer: dist/bin/cli.js + checksum: 10c0/9081f9cb6d6b2efb94ed5dfc888bcaafc3582e05c6e7263f99870163ad73e3ac0b937ff8e95224301a740364d5aef6021d9da3710851bad39ab587c7108a65c3 + languageName: node + linkType: hard + "@aws-crypto/crc32@npm:5.2.0": version: 5.2.0 resolution: "@aws-crypto/crc32@npm:5.2.0" @@ -1109,7 +1138,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": version: 7.29.0 resolution: "@babel/code-frame@npm:7.29.0" dependencies: @@ -1120,6 +1149,36 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.28.6": + version: 7.29.0 + resolution: "@babel/compat-data@npm:7.29.0" + checksum: 10c0/08f348554989d23aa801bf1405aa34b15e841c0d52d79da7e524285c77a5f9d298e70e11d91cc578d8e2c9542efc586d50c5f5cf8e1915b254a9dcf786913a94 + languageName: node + linkType: hard + +"@babel/core@npm:^7.28.0": + version: 7.29.0 + resolution: "@babel/core@npm:7.29.0" + dependencies: + "@babel/code-frame": "npm:^7.29.0" + "@babel/generator": "npm:^7.29.0" + "@babel/helper-compilation-targets": "npm:^7.28.6" + "@babel/helper-module-transforms": "npm:^7.28.6" + "@babel/helpers": "npm:^7.28.6" + "@babel/parser": "npm:^7.29.0" + "@babel/template": "npm:^7.28.6" + "@babel/traverse": "npm:^7.29.0" + "@babel/types": "npm:^7.29.0" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/5127d2e8e842ae409e11bcbb5c2dff9874abf5415e8026925af7308e903f4f43397341467a130490d1a39884f461bc2b67f3063bce0be44340db89687fd852aa + languageName: node + linkType: hard + "@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.29.0": version: 7.29.1 resolution: "@babel/generator@npm:7.29.1" @@ -1133,6 +1192,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-compilation-targets@npm:7.28.6" + dependencies: + "@babel/compat-data": "npm:^7.28.6" + "@babel/helper-validator-option": "npm:^7.27.1" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/3fcdf3b1b857a1578e99d20508859dbd3f22f3c87b8a0f3dc540627b4be539bae7f6e61e49d931542fe5b557545347272bbdacd7f58a5c77025a18b745593a50 + languageName: node + linkType: hard + "@babel/helper-globals@npm:^7.28.0": version: 7.28.0 resolution: "@babel/helper-globals@npm:7.28.0" @@ -1140,7 +1212,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.16.7": +"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.28.6": version: 7.28.6 resolution: "@babel/helper-module-imports@npm:7.28.6" dependencies: @@ -1150,6 +1222,26 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.28.6": + version: 7.28.6 + resolution: "@babel/helper-module-transforms@npm:7.28.6" + dependencies: + "@babel/helper-module-imports": "npm:^7.28.6" + "@babel/helper-validator-identifier": "npm:^7.28.5" + "@babel/traverse": "npm:^7.28.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/6f03e14fc30b287ce0b839474b5f271e72837d0cafe6b172d759184d998fbee3903a035e81e07c2c596449e504f453463d58baa65b6f40a37ded5bec74620b2b + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.27.1": + version: 7.28.6 + resolution: "@babel/helper-plugin-utils@npm:7.28.6" + checksum: 10c0/3f5f8acc152fdbb69a84b8624145ff4f9b9f6e776cb989f9f968f8606eb7185c5c3cfcf3ba08534e37e1e0e1c118ac67080610333f56baa4f7376c99b5f1143d + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-string-parser@npm:7.27.1" @@ -1164,6 +1256,34 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-validator-option@npm:7.27.1" + checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.28.6": + version: 7.29.2 + resolution: "@babel/helpers@npm:7.29.2" + dependencies: + "@babel/template": "npm:^7.28.6" + "@babel/types": "npm:^7.29.0" + checksum: 10c0/dab0e65b9318b2502a62c58bc0913572318595eec0482c31f0ad416b72636e6698a1d7c57cd2791d4528eb8c548bca88d338dc4d2a55a108dc1f6702f9bc5512 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7": + version: 7.29.2 + resolution: "@babel/parser@npm:7.29.2" + dependencies: + "@babel/types": "npm:^7.29.0" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/e5a4e69e3ac7acdde995f37cf299a68458cfe7009dff66bd0962fd04920bef287201169006af365af479c08ff216bfefbb595e331f87f6ae7283858aebbc3317 + languageName: node + linkType: hard + "@babel/parser@npm:^7.23.0, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": version: 7.29.0 resolution: "@babel/parser@npm:7.29.0" @@ -1175,6 +1295,35 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-react-jsx-self@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/00a4f917b70a608f9aca2fb39aabe04a60aa33165a7e0105fd44b3a8531630eb85bf5572e9f242f51e6ad2fa38c2e7e780902176c863556c58b5ba6f6e164031 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-source@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.27.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.27.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/5e67b56c39c4d03e59e03ba80692b24c5a921472079b63af711b1d250fc37c1733a17069b63537f750f3e937ec44a42b1ee6a46cd23b1a0df5163b17f741f7f2 + languageName: node + linkType: hard + +"@babel/runtime@npm:7.28.2": + version: 7.28.2 + resolution: "@babel/runtime@npm:7.28.2" + checksum: 10c0/c20afe253629d53a405a610b12a62ac74d341a2c1e0fb202bbef0c118f6b5c84f94bf16039f58fd0483dd256901259930a43976845bdeb180cab1f882c21b6e0 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.24.4, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.28.6, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7": version: 7.28.6 resolution: "@babel/runtime@npm:7.28.6" @@ -1193,7 +1342,7 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.28.6": +"@babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0": version: 7.29.0 resolution: "@babel/traverse@npm:7.29.0" dependencies: @@ -1208,7 +1357,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.23.0, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.23.0, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0": version: 7.29.0 resolution: "@babel/types@npm:7.29.0" dependencies: @@ -1319,6 +1468,37 @@ __metadata: languageName: unknown linkType: soft +"@devicefarmer/adbkit-logcat@npm:^2.1.2": + version: 2.1.3 + resolution: "@devicefarmer/adbkit-logcat@npm:2.1.3" + checksum: 10c0/d8d6108a0c47f994fd3073f19c8de9e38c6c70b420c55be3fc1a924b873f35cb24120f11e0173ab94c2f14e190f575ff62dc7de801b3272d56f6e46c4be8cde1 + languageName: node + linkType: hard + +"@devicefarmer/adbkit-monkey@npm:~1.2.1": + version: 1.2.1 + resolution: "@devicefarmer/adbkit-monkey@npm:1.2.1" + checksum: 10c0/3c397e7b5242034e29455b94792b6b3ce7d0adbd3e9da59b85c24aa6a5e99ae45f36078f56a8dc5b8df2e1c8f57726f88e5017081c6a4301e1945cf88d8864a2 + languageName: node + linkType: hard + +"@devicefarmer/adbkit@npm:3.3.8": + version: 3.3.8 + resolution: "@devicefarmer/adbkit@npm:3.3.8" + dependencies: + "@devicefarmer/adbkit-logcat": "npm:^2.1.2" + "@devicefarmer/adbkit-monkey": "npm:~1.2.1" + bluebird: "npm:~3.7" + commander: "npm:^9.1.0" + debug: "npm:~4.3.1" + node-forge: "npm:^1.3.1" + split: "npm:~1.0.1" + bin: + adbkit: bin/adbkit + checksum: 10c0/1d15f598ef7e2eae76580d463b61005a966faa5a5bf14e555657166ca638c381d88e5ead074ad8bbb3dc71c0f4ddd85d88cf13f6a1d014b66330292626ad7066 + languageName: node + linkType: hard + "@electron-forge/cli@npm:^7.9.0": version: 7.11.1 resolution: "@electron-forge/cli@npm:7.11.1" @@ -1805,6 +1985,34 @@ __metadata: languageName: node linkType: hard +"@emnapi/core@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/core@npm:1.10.0" + dependencies: + "@emnapi/wasi-threads": "npm:1.2.1" + tslib: "npm:^2.4.0" + checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb + languageName: node + linkType: hard + +"@emnapi/runtime@npm:1.10.0": + version: 1.10.0 + resolution: "@emnapi/runtime@npm:1.10.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093 + languageName: node + linkType: hard + +"@emnapi/wasi-threads@npm:1.2.1": + version: 1.2.1 + resolution: "@emnapi/wasi-threads@npm:1.2.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 + languageName: node + linkType: hard + "@emotion/babel-plugin@npm:^11.13.5": version: 11.13.5 resolution: "@emotion/babel-plugin@npm:11.13.5" @@ -1965,6 +2173,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/aix-ppc64@npm:0.27.7" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/android-arm64@npm:0.21.5" @@ -1979,6 +2194,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm64@npm:0.27.7" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/android-arm@npm:0.21.5" @@ -1993,6 +2215,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-arm@npm:0.27.7" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/android-x64@npm:0.21.5" @@ -2007,6 +2236,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/android-x64@npm:0.27.7" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/darwin-arm64@npm:0.21.5" @@ -2021,6 +2257,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-arm64@npm:0.27.7" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/darwin-x64@npm:0.21.5" @@ -2035,6 +2278,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/darwin-x64@npm:0.27.7" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/freebsd-arm64@npm:0.21.5" @@ -2049,6 +2299,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-arm64@npm:0.27.7" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/freebsd-x64@npm:0.21.5" @@ -2063,6 +2320,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/freebsd-x64@npm:0.27.7" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-arm64@npm:0.21.5" @@ -2077,6 +2341,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm64@npm:0.27.7" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-arm@npm:0.21.5" @@ -2091,6 +2362,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-arm@npm:0.27.7" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-ia32@npm:0.21.5" @@ -2105,6 +2383,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ia32@npm:0.27.7" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-loong64@npm:0.21.5" @@ -2119,6 +2404,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-loong64@npm:0.27.7" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-mips64el@npm:0.21.5" @@ -2133,6 +2425,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-mips64el@npm:0.27.7" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-ppc64@npm:0.21.5" @@ -2147,6 +2446,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-ppc64@npm:0.27.7" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-riscv64@npm:0.21.5" @@ -2161,6 +2467,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-riscv64@npm:0.27.7" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-s390x@npm:0.21.5" @@ -2175,6 +2488,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-s390x@npm:0.27.7" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/linux-x64@npm:0.21.5" @@ -2189,6 +2509,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/linux-x64@npm:0.27.7" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-arm64@npm:0.27.3": version: 0.27.3 resolution: "@esbuild/netbsd-arm64@npm:0.27.3" @@ -2196,6 +2523,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-arm64@npm:0.27.7" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/netbsd-x64@npm:0.21.5" @@ -2210,6 +2544,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/netbsd-x64@npm:0.27.7" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.27.3": version: 0.27.3 resolution: "@esbuild/openbsd-arm64@npm:0.27.3" @@ -2217,6 +2558,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-arm64@npm:0.27.7" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/openbsd-x64@npm:0.21.5" @@ -2231,6 +2579,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openbsd-x64@npm:0.27.7" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openharmony-arm64@npm:0.27.3": version: 0.27.3 resolution: "@esbuild/openharmony-arm64@npm:0.27.3" @@ -2238,6 +2593,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openharmony-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/openharmony-arm64@npm:0.27.7" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/sunos-x64@npm:0.21.5" @@ -2252,6 +2614,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/sunos-x64@npm:0.27.7" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/win32-arm64@npm:0.21.5" @@ -2266,6 +2635,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-arm64@npm:0.27.7" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/win32-ia32@npm:0.21.5" @@ -2280,6 +2656,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-ia32@npm:0.27.7" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.21.5": version: 0.21.5 resolution: "@esbuild/win32-x64@npm:0.21.5" @@ -2294,6 +2677,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.27.7": + version: 0.27.7 + resolution: "@esbuild/win32-x64@npm:0.27.7" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1": version: 4.9.1 resolution: "@eslint-community/eslint-utils@npm:4.9.1" @@ -2750,6 +3140,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/remapping@npm:^2.3.5": + version: 2.3.5 + resolution: "@jridgewell/remapping@npm:2.3.5" + dependencies: + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.2 resolution: "@jridgewell/resolve-uri@npm:3.1.2" @@ -3137,6 +3537,18 @@ __metadata: languageName: node linkType: hard +"@napi-rs/wasm-runtime@npm:^1.1.4": + version: 1.1.4 + resolution: "@napi-rs/wasm-runtime@npm:1.1.4" + dependencies: + "@tybys/wasm-util": "npm:^0.10.1" + peerDependencies: + "@emnapi/core": ^1.7.1 + "@emnapi/runtime": ^1.7.1 + checksum: 10c0/2e88e1955258949ccf2d18c79975821ad38071b465ef126a5e14110977b97868867b016c1ad046e963cccc42c0bd9db6c8ff5fd1ebb61b87bb3487f339041658 + languageName: node + linkType: hard + "@noble/ciphers@npm:^1.3.0": version: 1.3.0 resolution: "@noble/ciphers@npm:1.3.0" @@ -3178,7 +3590,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.6.1, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": +"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.6.1, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0": version: 1.8.0 resolution: "@noble/hashes@npm:1.8.0" checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77 @@ -3553,6 +3965,13 @@ __metadata: languageName: node linkType: hard +"@oxc-project/types@npm:=0.127.0": + version: 0.127.0 + resolution: "@oxc-project/types@npm:0.127.0" + checksum: 10c0/52c0947ac64a9ca119fe971f947e784a35ecd14a072fa3f542a58a5f6c42010b53f2bf92731e39b9899b83c990a9517bbd29d1e5a5b7b489e52616685c6a9278 + languageName: node + linkType: hard + "@pinojs/redact@npm:^0.4.0": version: 0.4.0 resolution: "@pinojs/redact@npm:0.4.0" @@ -3560,6 +3979,33 @@ __metadata: languageName: node linkType: hard +"@pnpm/config.env-replace@npm:^1.1.0": + version: 1.1.0 + resolution: "@pnpm/config.env-replace@npm:1.1.0" + checksum: 10c0/4cfc4a5c49ab3d0c6a1f196cfd4146374768b0243d441c7de8fa7bd28eaab6290f514b98490472cc65dbd080d34369447b3e9302585e1d5c099befd7c8b5e55f + languageName: node + linkType: hard + +"@pnpm/network.ca-file@npm:^1.0.1": + version: 1.0.2 + resolution: "@pnpm/network.ca-file@npm:1.0.2" + dependencies: + graceful-fs: "npm:4.2.10" + checksum: 10c0/95f6e0e38d047aca3283550719155ce7304ac00d98911e4ab026daedaf640a63bd83e3d13e17c623fa41ac72f3801382ba21260bcce431c14fbbc06430ecb776 + languageName: node + linkType: hard + +"@pnpm/npm-conf@npm:^3.0.2": + version: 3.0.2 + resolution: "@pnpm/npm-conf@npm:3.0.2" + dependencies: + "@pnpm/config.env-replace": "npm:^1.1.0" + "@pnpm/network.ca-file": "npm:^1.0.1" + config-chain: "npm:^1.1.11" + checksum: 10c0/50026ae4cac7d5d055d4dd4b2886fbc41964db6179406cf2decf625e7a280fbfffd47380df584c085464deba060101169caca5f79e6a062b6c25b527bf60cb67 + languageName: node + linkType: hard + "@popperjs/core@npm:^2.11.8": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" @@ -3640,21 +4086,137 @@ __metadata: languageName: node linkType: hard -"@rolldown/pluginutils@npm:1.0.0-beta.27": - version: 1.0.0-beta.27 - resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27" - checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c +"@rolldown/binding-android-arm64@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-android-arm64@npm:1.0.0-rc.17" + conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/plugin-inject@npm:^5.0.5": - version: 5.0.5 - resolution: "@rollup/plugin-inject@npm:5.0.5" - dependencies: - "@rollup/pluginutils": "npm:^5.0.1" - estree-walker: "npm:^2.0.2" - magic-string: "npm:^0.30.3" - peerDependencies: +"@rolldown/binding-darwin-arm64@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.0-rc.17" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-darwin-x64@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.0-rc.17" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/binding-freebsd-x64@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.0-rc.17" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.0-rc.17" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.0-rc.17" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.0-rc.17" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.0-rc.17" + conditions: os=linux & cpu=ppc64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.0-rc.17" + conditions: os=linux & cpu=s390x & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.0-rc.17" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.0-rc.17" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.0-rc.17" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.0-rc.17" + dependencies: + "@emnapi/core": "npm:1.10.0" + "@emnapi/runtime": "npm:1.10.0" + "@napi-rs/wasm-runtime": "npm:^1.1.4" + conditions: cpu=wasm32 + languageName: node + linkType: hard + +"@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.0-rc.17" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.0-rc.17" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:1.0.0-beta.27": + version: 1.0.0-beta.27 + resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27" + checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c + languageName: node + linkType: hard + +"@rolldown/pluginutils@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "@rolldown/pluginutils@npm:1.0.0-rc.17" + checksum: 10c0/5e840b20cc531910c093c1ca36e550952cf4936465a50d89f0a98fc9d0dfd7d319d06a10a5f4376209d89e9bf4d60af6cc8363ebf0dcc5e60842f7fef438b2f0 + languageName: node + linkType: hard + +"@rollup/plugin-inject@npm:^5.0.5": + version: 5.0.5 + resolution: "@rollup/plugin-inject@npm:5.0.5" + dependencies: + "@rollup/pluginutils": "npm:^5.0.1" + estree-walker: "npm:^2.0.2" + magic-string: "npm:^0.30.3" + peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: @@ -4721,6 +5283,56 @@ __metadata: languageName: node linkType: hard +"@tybys/wasm-util@npm:^0.10.1": + version: 0.10.1 + resolution: "@tybys/wasm-util@npm:0.10.1" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/b255094f293794c6d2289300c5fbcafbb5532a3aed3a5ffd2f8dc1828e639b88d75f6a376dd8f94347a44813fd7a7149d8463477a9a49525c8b2dcaa38c2d1e8 + languageName: node + linkType: hard + +"@types/babel__core@npm:^7.20.5": + version: 7.20.5 + resolution: "@types/babel__core@npm:7.20.5" + dependencies: + "@babel/parser": "npm:^7.20.7" + "@babel/types": "npm:^7.20.7" + "@types/babel__generator": "npm:*" + "@types/babel__template": "npm:*" + "@types/babel__traverse": "npm:*" + checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff + languageName: node + linkType: hard + +"@types/babel__generator@npm:*": + version: 7.27.0 + resolution: "@types/babel__generator@npm:7.27.0" + dependencies: + "@babel/types": "npm:^7.0.0" + checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd + languageName: node + linkType: hard + +"@types/babel__template@npm:*": + version: 7.4.4 + resolution: "@types/babel__template@npm:7.4.4" + dependencies: + "@babel/parser": "npm:^7.1.0" + "@babel/types": "npm:^7.0.0" + checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b + languageName: node + linkType: hard + +"@types/babel__traverse@npm:*": + version: 7.28.0 + resolution: "@types/babel__traverse@npm:7.28.0" + dependencies: + "@babel/types": "npm:^7.28.2" + checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994 + languageName: node + linkType: hard + "@types/cacheable-request@npm:^6.0.1": version: 6.0.3 resolution: "@types/cacheable-request@npm:6.0.3" @@ -4750,6 +5362,16 @@ __metadata: languageName: node linkType: hard +"@types/chrome@npm:^0.0.270": + version: 0.0.270 + resolution: "@types/chrome@npm:0.0.270" + dependencies: + "@types/filesystem": "npm:*" + "@types/har-format": "npm:*" + checksum: 10c0/7922dd4d69c4766be93fe58d7aaf381192f7a5d90887a065dad63e4130ff5214917405c66fee78c93a8422d08deeff63606e7625a1939073cc9aeadb9179d80e + languageName: node + linkType: hard + "@types/deep-eql@npm:*": version: 4.0.2 resolution: "@types/deep-eql@npm:4.0.2" @@ -4791,6 +5413,22 @@ __metadata: languageName: node linkType: hard +"@types/filesystem@npm:*": + version: 0.0.36 + resolution: "@types/filesystem@npm:0.0.36" + dependencies: + "@types/filewriter": "npm:*" + checksum: 10c0/3ebec32f0494b0a2612187d148e9f253ff55672c53f566d9a1e6d891eb6e2372df93c252b594b2775bc53e6660c4c37fdb05dc1b26e72b60a31010da8e1f7317 + languageName: node + linkType: hard + +"@types/filewriter@npm:*": + version: 0.0.33 + resolution: "@types/filewriter@npm:0.0.33" + checksum: 10c0/363ef9a658a961ceae04f52934562e4ebdcdc3a2564dd8544f593d77113c16574938b6ba4fea0bee418c37bda0668c1e03dfedb6adf00d55853f51fb3a59247b + languageName: node + linkType: hard + "@types/fs-extra@npm:^9.0.1": version: 9.0.13 resolution: "@types/fs-extra@npm:9.0.13" @@ -4800,6 +5438,13 @@ __metadata: languageName: node linkType: hard +"@types/har-format@npm:*": + version: 1.2.16 + resolution: "@types/har-format@npm:1.2.16" + checksum: 10c0/77e952bc219db0c1f0588cab3b95865bc343b922e8423a76fbbd6a757c40709a256933fa415eb8fefda6ea5897c8e3dd3191bb8a82b37c13d9232467d31ae485 + languageName: node + linkType: hard + "@types/http-cache-semantics@npm:*": version: 4.2.0 resolution: "@types/http-cache-semantics@npm:4.2.0" @@ -4830,6 +5475,13 @@ __metadata: languageName: node linkType: hard +"@types/minimatch@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/minimatch@npm:3.0.5" + checksum: 10c0/a1a19ba342d6f39b569510f621ae4bbe972dc9378d15e9a5e47904c440ee60744f5b09225bc73be1c6490e3a9c938eee69eb53debf55ce1f15761201aa965f97 + languageName: node + linkType: hard + "@types/mute-stream@npm:^0.0.4": version: 0.0.4 resolution: "@types/mute-stream@npm:0.0.4" @@ -5111,6 +5763,22 @@ __metadata: languageName: node linkType: hard +"@vitejs/plugin-react@npm:^4.3.4": + version: 4.7.0 + resolution: "@vitejs/plugin-react@npm:4.7.0" + dependencies: + "@babel/core": "npm:^7.28.0" + "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" + "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" + "@rolldown/pluginutils": "npm:1.0.0-beta.27" + "@types/babel__core": "npm:^7.20.5" + react-refresh: "npm:^0.17.0" + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253 + languageName: node + linkType: hard + "@vitest/expect@npm:3.2.4": version: 3.2.4 resolution: "@vitest/expect@npm:3.2.4" @@ -5352,6 +6020,63 @@ __metadata: languageName: node linkType: hard +"@webext-core/fake-browser@npm:^1.3.4": + version: 1.3.4 + resolution: "@webext-core/fake-browser@npm:1.3.4" + dependencies: + lodash.merge: "npm:^4.6.2" + checksum: 10c0/2f92aad623d9d1eb1c18b77b972a3bd4e5d13e1bd063dd6e1ffe5d41785cd270d5337ef95329cdb82df07b62e74f43fd1ccab79a88870c062fdfb61f8215ab6b + languageName: node + linkType: hard + +"@webext-core/isolated-element@npm:^1.1.3": + version: 1.1.5 + resolution: "@webext-core/isolated-element@npm:1.1.5" + dependencies: + is-potential-custom-element-name: "npm:^1.0.1" + checksum: 10c0/348a32904f6a640cdb02b0d0d5f1569cc8afd7c943e75bb4bfedbbf7695ff42b3177eb2a3da5efd636072887b5dcd9969cf0bedb42bdc386763bf198996207d7 + languageName: node + linkType: hard + +"@webext-core/match-patterns@npm:^1.0.3": + version: 1.0.3 + resolution: "@webext-core/match-patterns@npm:1.0.3" + checksum: 10c0/eb219006f03420ef2221d17b07b28923078ca817cf2f4f5cf031856137c102b0c0f75ce1c18627514e767fcc672cf6a673c2bbb3a0a20c322ff3c1d6b6bb9920 + languageName: node + linkType: hard + +"@wxt-dev/browser@npm:^0.1.37, @wxt-dev/browser@npm:^0.1.40": + version: 0.1.40 + resolution: "@wxt-dev/browser@npm:0.1.40" + dependencies: + "@types/filesystem": "npm:*" + "@types/har-format": "npm:*" + checksum: 10c0/d873d906bff23ba84ac3db57fcb6cf9f704652a5152deab15aab03ea73125c75bf3b489930b9facce0debf85ca37ccadf9f12978335abfbeaedafe0ebeebe9b1 + languageName: node + linkType: hard + +"@wxt-dev/module-react@npm:1.1.3": + version: 1.1.3 + resolution: "@wxt-dev/module-react@npm:1.1.3" + dependencies: + "@vitejs/plugin-react": "npm:^4.3.4" + peerDependencies: + wxt: ">=0.19.16" + checksum: 10c0/77067147c54ece1d237a1128763a380a11a946066c53dd6db50e26389513b268e1f50599dc11d077935e329e0dc541bd40c4e34eb234e8589e09fb6f5ea01c6a + languageName: node + linkType: hard + +"@wxt-dev/storage@npm:^1.0.0": + version: 1.2.8 + resolution: "@wxt-dev/storage@npm:1.2.8" + dependencies: + "@wxt-dev/browser": "npm:^0.1.37" + async-mutex: "npm:^0.5.0" + dequal: "npm:^2.0.3" + checksum: 10c0/40531c3a4f0069cb4c68b2a92ca65a9ffa249d0ade197c6fb0f3e7d0099224d6e66e2c556eedc4da0d9b169e11bfd93947f476e204474c03ec07bd49d076b597 + languageName: node + linkType: hard + "@xmldom/xmldom@npm:^0.8.8": version: 0.8.11 resolution: "@xmldom/xmldom@npm:0.8.11" @@ -5517,6 +6242,13 @@ __metadata: languageName: node linkType: hard +"adm-zip@npm:~0.5.x": + version: 0.5.17 + resolution: "adm-zip@npm:0.5.17" + checksum: 10c0/29b8f2a1070fc540ad9a45b13d0ceffd141d78e5a4501f102e978f0256f8290326009ccd3411213e90f3a810c830b39453548638879b3295ddc3814c20a8307b + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -5601,6 +6333,15 @@ __metadata: languageName: node linkType: hard +"ansi-align@npm:^3.0.1": + version: 3.0.1 + resolution: "ansi-align@npm:3.0.1" + dependencies: + string-width: "npm:^4.1.0" + checksum: 10c0/ad8b755a253a1bc8234eb341e0cec68a857ab18bf97ba2bda529e86f6e30460416523e0ec58c32e5c21f0ca470d779503244892873a5895dbd0c39c788e82467 + languageName: node + linkType: hard + "ansi-escapes@npm:^4.3.2": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -5619,6 +6360,15 @@ __metadata: languageName: node linkType: hard +"ansi-escapes@npm:^7.0.0": + version: 7.3.0 + resolution: "ansi-escapes@npm:7.3.0" + dependencies: + environment: "npm:^1.0.0" + checksum: 10c0/068961d99f0ef28b661a4a9f84a5d645df93ccf3b9b93816cc7d46bbe1913321d4cdf156bb842a4e1e4583b7375c631fa963efb43001c4eb7ff9ab8f78fc0679 + languageName: node + linkType: hard + "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -5651,7 +6401,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0": +"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1, ansi-styles@npm:^6.2.3": version: 6.2.3 resolution: "ansi-styles@npm:6.2.3" checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868 @@ -5760,6 +6510,13 @@ __metadata: languageName: node linkType: hard +"array-differ@npm:^4.0.0": + version: 4.0.0 + resolution: "array-differ@npm:4.0.0" + checksum: 10c0/72c035c505a7629d2983827a16654d73db6a9a2d6340ba9d0803aed516f46a202f3b7042c5a4a57534952f7477ca5394f3b65ecb9be5192e5d269f445f066d75 + languageName: node + linkType: hard + "array-includes@npm:^3.1.9": version: 3.1.9 resolution: "array-includes@npm:3.1.9" @@ -5776,6 +6533,13 @@ __metadata: languageName: node linkType: hard +"array-union@npm:^3.0.1": + version: 3.0.1 + resolution: "array-union@npm:3.0.1" + checksum: 10c0/b5271d7e5688d2d1932928b271796dbbddc422448557ab05ef6f34a9f84fb645eb855384feec6234bf59c226053a0e21b8a00b0e6cd588874b90a5c13dbeb64e + languageName: node + linkType: hard + "array.prototype.findlastindex@npm:^1.2.6": version: 1.2.6 resolution: "array.prototype.findlastindex@npm:1.2.6" @@ -5875,6 +6639,15 @@ __metadata: languageName: node linkType: hard +"async-mutex@npm:^0.5.0": + version: 0.5.0 + resolution: "async-mutex@npm:0.5.0" + dependencies: + tslib: "npm:^2.4.0" + checksum: 10c0/9096e6ad6b674c894d8ddd5aa4c512b09bb05931b8746ebd634952b05685608b2b0820ed5c406e6569919ff5fe237ab3c491e6f2887d6da6b6ba906db3ee9c32 + languageName: node + linkType: hard + "async-retry@npm:^1.3.3": version: 1.3.3 resolution: "async-retry@npm:1.3.3" @@ -5884,6 +6657,13 @@ __metadata: languageName: node linkType: hard +"async@npm:^3.2.0": + version: 3.2.6 + resolution: "async@npm:3.2.6" + checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -5905,6 +6685,16 @@ __metadata: languageName: node linkType: hard +"atomically@npm:^2.0.3": + version: 2.1.1 + resolution: "atomically@npm:2.1.1" + dependencies: + stubborn-fs: "npm:^2.0.0" + when-exit: "npm:^2.1.4" + checksum: 10c0/8813decdea834eab9b95c63ae3762355e9182e718b49be50153539bb52f727851f5096ef180f84901572dac31c51cb113a3bf3dda12fa633a16bc58f49ba003d + languageName: node + linkType: hard + "author-regex@npm:^1.0.0": version: 1.0.0 resolution: "author-regex@npm:1.0.0" @@ -5964,6 +6754,15 @@ __metadata: languageName: node linkType: hard +"baseline-browser-mapping@npm:^2.10.12": + version: 2.10.24 + resolution: "baseline-browser-mapping@npm:2.10.24" + bin: + baseline-browser-mapping: dist/cli.cjs + checksum: 10c0/ae41f20b7d594909eac68e54b876127a456c99e85f49ba928a79c97ea288007617ad6638ddd1e36db45bbacef7b95b0f436d347602b2e1be2047099fcbbd5f37 + languageName: node + linkType: hard + "baseline-browser-mapping@npm:^2.9.0": version: 2.10.0 resolution: "baseline-browser-mapping@npm:2.10.0" @@ -6005,7 +6804,7 @@ __metadata: languageName: node linkType: hard -"bluebird@npm:^3.1.1": +"bluebird@npm:^3.1.1, bluebird@npm:~3.7": version: 3.7.2 resolution: "bluebird@npm:3.7.2" checksum: 10c0/680de03adc54ff925eaa6c7bb9a47a0690e8b5de60f4792604aae8ed618c65e6b63a7893b57ca924beaf53eee69c5af4f8314148c08124c550fe1df1add897d2 @@ -6026,6 +6825,13 @@ __metadata: languageName: node linkType: hard +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf + languageName: node + linkType: hard + "boolean@npm:^3.0.1": version: 3.2.0 resolution: "boolean@npm:3.2.0" @@ -6040,6 +6846,22 @@ __metadata: languageName: node linkType: hard +"boxen@npm:^8.0.1": + version: 8.0.1 + resolution: "boxen@npm:8.0.1" + dependencies: + ansi-align: "npm:^3.0.1" + camelcase: "npm:^8.0.0" + chalk: "npm:^5.3.0" + cli-boxes: "npm:^3.0.0" + string-width: "npm:^7.2.0" + type-fest: "npm:^4.21.0" + widest-line: "npm:^5.0.0" + wrap-ansi: "npm:^9.0.0" + checksum: 10c0/8c54f9797bf59eec0b44c9043d9cb5d5b2783dc673e4650235e43a5155c43334e78ec189fd410cf92056c1054aee3758279809deed115b49e68f1a1c6b3faa32 + languageName: node + linkType: hard + "brace-expansion@npm:^1.1.7": version: 1.1.12 resolution: "brace-expansion@npm:1.1.12" @@ -6167,6 +6989,21 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0": + version: 4.28.2 + resolution: "browserslist@npm:4.28.2" + dependencies: + baseline-browser-mapping: "npm:^2.10.12" + caniuse-lite: "npm:^1.0.30001782" + electron-to-chromium: "npm:^1.5.328" + node-releases: "npm:^2.0.36" + update-browserslist-db: "npm:^1.2.3" + bin: + browserslist: cli.js + checksum: 10c0/c0228b6330f785b7fa59d2d360124ec6d9322f96ed9f3ee1f873e33ecc9503a6f0ffc3b71191a28c4ff6e930b753b30043da1c33844a9548f3018d491f09ce60 + languageName: node + linkType: hard + "browserslist@npm:^4.28.1": version: 4.28.1 resolution: "browserslist@npm:4.28.1" @@ -6237,6 +7074,15 @@ __metadata: languageName: node linkType: hard +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: "npm:^7.0.0" + checksum: 10c0/8e575981e79c2bcf14d8b1c027a3775c095d362d1382312f444a7c861b0e21513c0bd8db5bd2b16e50ba0709fa622d4eab6b53192d222120305e68359daece29 + languageName: node + linkType: hard + "bytes@npm:^3.1.2, bytes@npm:~3.1.2": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -6244,6 +7090,31 @@ __metadata: languageName: node linkType: hard +"c12@npm:^3.3.3": + version: 3.3.4 + resolution: "c12@npm:3.3.4" + dependencies: + chokidar: "npm:^5.0.0" + confbox: "npm:^0.2.4" + defu: "npm:^6.1.6" + dotenv: "npm:^17.3.1" + exsolve: "npm:^1.0.8" + giget: "npm:^3.2.0" + jiti: "npm:^2.6.1" + ohash: "npm:^2.0.11" + pathe: "npm:^2.0.3" + perfect-debounce: "npm:^2.1.0" + pkg-types: "npm:^2.3.0" + rc9: "npm:^3.0.1" + peerDependencies: + magicast: "*" + peerDependenciesMeta: + magicast: + optional: true + checksum: 10c0/d305df0c6e219464b3460fdd3443e62590e7d0d2f331e450a44f29e31e7120a0c7a6a76b6212bc0cf9f41058e3545c4fd04b0f1c6ea8d549678ea6479d94d8ad + languageName: node + linkType: hard + "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -6251,6 +7122,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14 || ^7.0.0, cac@npm:^7.0.0": + version: 7.0.0 + resolution: "cac@npm:7.0.0" + checksum: 10c0/e9da33cb9f0425546ae92a450d479276f9969a050fe64f5d6fedf058bdd87f22a370797fe1c158e07655fa9fc183749df7cb2037431e3772faa7bee9919fb763 + languageName: node + linkType: hard + "cacache@npm:^16.1.0": version: 16.1.3 resolution: "cacache@npm:16.1.3" @@ -6367,6 +7245,13 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:^8.0.0": + version: 8.0.0 + resolution: "camelcase@npm:8.0.0" + checksum: 10c0/56c5fe072f0523c9908cdaac21d4a3b3fb0f608fb2e9ba90a60e792b95dd3bb3d1f3523873ab17d86d146e94171305f73ef619e2f538bd759675bc4a14b4bff3 + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001759": version: 1.0.30001775 resolution: "caniuse-lite@npm:1.0.30001775" @@ -6374,6 +7259,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001782": + version: 1.0.30001791 + resolution: "caniuse-lite@npm:1.0.30001791" + checksum: 10c0/53c8b5dad1c196a5e495405a7d2dc1db58aed9be02f60cf2a2e29d2c8d8cbb6c39beabf958d6aa191ab967ddcf49f22319452256b980bad1e271615acfe58940 + languageName: node + linkType: hard + "catering@npm:^2.0.0, catering@npm:^2.1.0": version: 2.1.1 resolution: "catering@npm:2.1.1" @@ -6415,6 +7307,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.3.0": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976 + languageName: node + linkType: hard + "change-case@npm:^5.4.4": version: 5.4.4 resolution: "change-case@npm:5.4.4" @@ -6455,6 +7354,15 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:^5.0.0": + version: 5.0.0 + resolution: "chokidar@npm:5.0.0" + dependencies: + readdirp: "npm:^5.0.0" + checksum: 10c0/42fc907cb2a7ff5c9e220f84dae75380a77997f851c2a5e7865a2cf9ae45dd407a23557208cdcdbf3ac8c93341135a1748e4c48c31855f3bfa095e5159b6bdec + languageName: node + linkType: hard + "chownr@npm:^1.1.1": version: 1.1.4 resolution: "chownr@npm:1.1.4" @@ -6476,6 +7384,20 @@ __metadata: languageName: node linkType: hard +"chrome-launcher@npm:1.2.0": + version: 1.2.0 + resolution: "chrome-launcher@npm:1.2.0" + dependencies: + "@types/node": "npm:*" + escape-string-regexp: "npm:^4.0.0" + is-wsl: "npm:^2.2.0" + lighthouse-logger: "npm:^2.0.1" + bin: + print-chrome-path: bin/print-chrome-path.cjs + checksum: 10c0/3598bedecf70e42babada1df4f1bfa37071906973044737ff91d0e9ab53c4fac8cabd7489edb8bd4fcd83a70ae50c671265453d62f612419b745bfab63875817 + languageName: node + linkType: hard + "chrome-trace-event@npm:^1.0.2, chrome-trace-event@npm:^1.0.3": version: 1.0.4 resolution: "chrome-trace-event@npm:1.0.4" @@ -6483,6 +7405,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^4.4.0": + version: 4.4.0 + resolution: "ci-info@npm:4.4.0" + checksum: 10c0/44156201545b8dde01aa8a09ee2fe9fc7a73b1bef9adbd4606c9f61c8caeeb73fb7a575c88b0443f7b4edb5ee45debaa59ed54ba5f99698339393ca01349eb3a + languageName: node + linkType: hard + "cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3": version: 1.0.7 resolution: "cipher-base@npm:1.0.7" @@ -6494,6 +7423,13 @@ __metadata: languageName: node linkType: hard +"citty@npm:^0.2.2": + version: 0.2.2 + resolution: "citty@npm:0.2.2" + checksum: 10c0/c896c9dcd187d2a16685706d11428dcdec9eb59aa13fe50aff7b12e1d3521f1bf434d6a5316fe75a341f8ba5ce1d2beceb84f7f261d018985a73d3f6f2a793e3 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -6501,6 +7437,13 @@ __metadata: languageName: node linkType: hard +"cli-boxes@npm:^3.0.0": + version: 3.0.0 + resolution: "cli-boxes@npm:3.0.0" + checksum: 10c0/4db3e8fbfaf1aac4fb3a6cbe5a2d3fa048bee741a45371b906439b9ffc821c6e626b0f108bdcd3ddf126a4a319409aedcf39a0730573ff050fdd7b6731e99fb9 + languageName: node + linkType: hard + "cli-cursor@npm:^3.1.0": version: 3.1.0 resolution: "cli-cursor@npm:3.1.0" @@ -6519,7 +7462,16 @@ __metadata: languageName: node linkType: hard -"cli-spinners@npm:^2.5.0": +"cli-cursor@npm:^5.0.0": + version: 5.0.0 + resolution: "cli-cursor@npm:5.0.0" + dependencies: + restore-cursor: "npm:^5.0.0" + checksum: 10c0/7ec62f69b79f6734ab209a3e4dbdc8af7422d44d360a7cb1efa8a0887bbe466a6e625650c466fe4359aee44dbe2dc0b6994b583d40a05d0808a5cb193641d220 + languageName: node + linkType: hard + +"cli-spinners@npm:^2.5.0": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" checksum: 10c0/907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3 @@ -6536,6 +7488,16 @@ __metadata: languageName: node linkType: hard +"cli-truncate@npm:^5.2.0": + version: 5.2.0 + resolution: "cli-truncate@npm:5.2.0" + dependencies: + slice-ansi: "npm:^8.0.0" + string-width: "npm:^8.2.0" + checksum: 10c0/0d4ec94702ca85b64522ac93633837fb5ea7db17b79b1322a60f6045e6ae2b8cd7bd4c1d19ac7d1f9e10e3bbda1112e172e439b68c02b785ee00da8d6a5c5471 + languageName: node + linkType: hard + "cli-width@npm:^4.1.0": version: 4.1.0 resolution: "cli-width@npm:4.1.0" @@ -6687,6 +7649,15 @@ __metadata: languageName: node linkType: hard +"commander@npm:2.9.0": + version: 2.9.0 + resolution: "commander@npm:2.9.0" + dependencies: + graceful-readlink: "npm:>= 1.0.0" + checksum: 10c0/56bcda1e47f453016ed25d9f300bed9e622842a5515802658adb62792fa2ff9af6ee3f9ff16e058d7b20aacc78fb3baa3e02f982414bae1fb5f198c7cb41d5ad + languageName: node + linkType: hard + "commander@npm:^11.1.0": version: 11.1.0 resolution: "commander@npm:11.1.0" @@ -6715,7 +7686,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^9.4.0": +"commander@npm:^9.1.0, commander@npm:^9.4.0": version: 9.5.0 resolution: "commander@npm:9.5.0" checksum: 10c0/5f7784fbda2aaec39e89eb46f06a999e00224b3763dc65976e05929ec486e174fe9aac2655f03ba6a5e83875bd173be5283dc19309b7c65954701c02025b3c1d @@ -6745,6 +7716,61 @@ __metadata: languageName: node linkType: hard +"concat-stream@npm:^1.4.7": + version: 1.6.2 + resolution: "concat-stream@npm:1.6.2" + dependencies: + buffer-from: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^2.2.2" + typedarray: "npm:^0.0.6" + checksum: 10c0/2e9864e18282946dabbccb212c5c7cec0702745e3671679eb8291812ca7fd12023f7d8cb36493942a62f770ac96a7f90009dc5c82ad69893438371720fa92617 + languageName: node + linkType: hard + +"confbox@npm:^0.1.8": + version: 0.1.8 + resolution: "confbox@npm:0.1.8" + checksum: 10c0/fc2c68d97cb54d885b10b63e45bd8da83a8a71459d3ecf1825143dd4c7f9f1b696b3283e07d9d12a144c1301c2ebc7842380bdf0014e55acc4ae1c9550102418 + languageName: node + linkType: hard + +"confbox@npm:^0.2.4": + version: 0.2.4 + resolution: "confbox@npm:0.2.4" + checksum: 10c0/4c36af33d9df7034300c452f7b289179264493bd0671fa81b995a0d70dc897b1d37f1af10d3ffb187f178d17ba1ed2ba167ed0f599ba3a139c271205dd553f73 + languageName: node + linkType: hard + +"config-chain@npm:^1.1.11": + version: 1.1.13 + resolution: "config-chain@npm:1.1.13" + dependencies: + ini: "npm:^1.3.4" + proto-list: "npm:~1.2.1" + checksum: 10c0/39d1df18739d7088736cc75695e98d7087aea43646351b028dfabd5508d79cf6ef4c5bcd90471f52cd87ae470d1c5490c0a8c1a292fbe6ee9ff688061ea0963e + languageName: node + linkType: hard + +"configstore@npm:^7.0.0": + version: 7.1.0 + resolution: "configstore@npm:7.1.0" + dependencies: + atomically: "npm:^2.0.3" + dot-prop: "npm:^9.0.0" + graceful-fs: "npm:^4.2.11" + xdg-basedir: "npm:^5.1.0" + checksum: 10c0/98f74ee84eb7fea8361f588d2f0f8fbec2dd680a628bb1e50668cfd3001ea2584565d31de1d57f18ab498d339778701f9bc1e77a997107e8ff10abd8afb267a6 + languageName: node + linkType: hard + +"consola@npm:^3.4.2": + version: 3.4.2 + resolution: "consola@npm:3.4.2" + checksum: 10c0/7cebe57ecf646ba74b300bcce23bff43034ed6fbec9f7e39c27cee1dc00df8a21cd336b466ad32e304ea70fba04ec9e890c200270de9a526ce021ba8a7e4c11a + languageName: node + linkType: hard + "console-browserify@npm:^1.1.0": version: 1.2.0 resolution: "console-browserify@npm:1.2.0" @@ -6789,6 +7815,13 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b + languageName: node + linkType: hard + "convert-string@npm:~0.1.0": version: 0.1.0 resolution: "convert-string@npm:0.1.0" @@ -6935,6 +7968,33 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: 10c0/d79fffa97106007f2802589f3ed17b8c903f1c961c0fc28aa8a051eee0cbad394d8446223862efd4c1b40445a6034f626bb639cf2035b0bfc468544177593c99 + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": + version: 6.2.2 + resolution: "css-what@npm:6.2.2" + checksum: 10c0/91e24c26fb977b4ccef30d7007d2668c1c10ac0154cc3f42f7304410e9594fb772aea4f30c832d2993b132ca8d99338050866476210316345ec2e7d47b248a56 + languageName: node + linkType: hard + +"cssom@npm:^0.5.0": + version: 0.5.0 + resolution: "cssom@npm:0.5.0" + checksum: 10c0/8c4121c243baf0678c65dcac29b201ff0067dfecf978de9d5c83b2ff127a8fdefd2bfd54577f5ad8c80ed7d2c8b489ae01c82023545d010c4ecb87683fb403dd + languageName: node + linkType: hard + "csstype@npm:^3.0.2, csstype@npm:^3.1.3, csstype@npm:^3.2.2": version: 3.2.3 resolution: "csstype@npm:3.2.3" @@ -6982,6 +8042,13 @@ __metadata: languageName: node linkType: hard +"debounce@npm:1.2.1": + version: 1.2.1 + resolution: "debounce@npm:1.2.1" + checksum: 10c0/6c9320aa0973fc42050814621a7a8a78146c1975799b5b3cc1becf1f77ba9a5aa583987884230da0842a03f385def452fad5d60db97c3d1c8b824e38a8edf500 + languageName: node + linkType: hard + "debug@npm:4, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.4.1, debug@npm:^4.4.3": version: 4.4.3 resolution: "debug@npm:4.4.3" @@ -7012,6 +8079,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:~4.3.1": + version: 4.3.7 + resolution: "debug@npm:4.3.7" + dependencies: + ms: "npm:^2.1.3" + peerDependenciesMeta: + supports-color: + optional: true + checksum: 10c0/1471db19c3b06d485a622d62f65947a19a23fbd0dd73f7fd3eafb697eec5360cde447fb075919987899b1a2096e85d35d4eb5a4de09a57600ac9cf7e6c8e768b + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -7049,6 +8128,23 @@ __metadata: languageName: node linkType: hard +"default-browser-id@npm:^5.0.0": + version: 5.0.1 + resolution: "default-browser-id@npm:5.0.1" + checksum: 10c0/5288b3094c740ef3a86df9b999b04ff5ba4dee6b64e7b355c0fff5217752c8c86908d67f32f6cba9bb4f9b7b61a1b640c0a4f9e34c57e0ff3493559a625245ee + languageName: node + linkType: hard + +"default-browser@npm:^5.4.0": + version: 5.5.0 + resolution: "default-browser@npm:5.5.0" + dependencies: + bundle-name: "npm:^4.1.0" + default-browser-id: "npm:^5.0.0" + checksum: 10c0/576593b617b17a7223014b4571bfe1c06a2581a4eb8b130985d90d253afa3f40999caec70eb0e5776e80d4af6a41cce91018cd3f86e57ad578bf59e46fb19abe + languageName: node + linkType: hard + "defaults@npm:^1.0.3": version: 1.0.4 resolution: "defaults@npm:1.0.4" @@ -7076,6 +8172,20 @@ __metadata: languageName: node linkType: hard +"define-lazy-prop@npm:^2.0.0": + version: 2.0.0 + resolution: "define-lazy-prop@npm:2.0.0" + checksum: 10c0/db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 + languageName: node + linkType: hard + +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 10c0/5ab0b2bf3fa58b3a443140bbd4cd3db1f91b985cc8a246d330b9ac3fc0b6a325a6d82bddc0b055123d745b3f9931afeea74a5ec545439a1630b9c8512b0eeb49 + languageName: node + linkType: hard + "define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" @@ -7087,6 +8197,13 @@ __metadata: languageName: node linkType: hard +"defu@npm:^6.1.4, defu@npm:^6.1.6": + version: 6.1.7 + resolution: "defu@npm:6.1.7" + checksum: 10c0/e6635388103c8be3c574ac31302f6930e5e6eeedba32cb1b30cf993c7d9fb571aec2485446dfa23bfa63e55e66156fe109027a9695db82a50f931e91e8d4bedb + languageName: node + linkType: hard + "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -7101,6 +8218,37 @@ __metadata: languageName: node linkType: hard +"demo-aztec-extension-wallet@workspace:extension-wallet": + version: 0.0.0-use.local + resolution: "demo-aztec-extension-wallet@workspace:extension-wallet" + dependencies: + "@aztec/accounts": "npm:v4.3.0-nightly.20260423" + "@aztec/aztec.js": "npm:v4.3.0-nightly.20260423" + "@aztec/foundation": "npm:v4.3.0-nightly.20260423" + "@aztec/kv-store": "npm:v4.3.0-nightly.20260423" + "@aztec/pxe": "npm:v4.3.0-nightly.20260423" + "@aztec/stdlib": "npm:v4.3.0-nightly.20260423" + "@aztec/wallet-sdk": "npm:v4.3.0-nightly.20260423" + "@demo-wallet/shared": "workspace:*" + "@emotion/react": "npm:^11.14.0" + "@emotion/styled": "npm:^11.14.0" + "@mui/icons-material": "npm:^6.4.4" + "@mui/material": "npm:^6.4.4" + "@noble/hashes": "npm:^1.5.0" + "@types/chrome": "npm:^0.0.270" + "@types/react": "npm:^18.3.1" + "@types/react-dom": "npm:^18.3.1" + "@wxt-dev/module-react": "npm:1.1.3" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + typescript: "npm:~5.6.2" + vite-plugin-node-polyfills: "npm:^0.26.0" + vitest: "npm:^3.0.0" + wxt: "npm:^0.20.6" + zod: "npm:^3.23.8" + languageName: unknown + linkType: soft + "demo-wallet@workspace:.": version: 0.0.0-use.local resolution: "demo-wallet@workspace:." @@ -7133,6 +8281,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 10c0/f98860cdf58b64991ae10205137c0e97d384c3a4edc7f807603887b7c4b850af1224a33d88012009f150861cbee4fa2d322c4cc04b9313bee312e47f6ecaa888 + languageName: node + linkType: hard + "des.js@npm:^1.0.0": version: 1.1.0 resolution: "des.js@npm:1.1.0" @@ -7143,6 +8298,13 @@ __metadata: languageName: node linkType: hard +"destr@npm:^2.0.5": + version: 2.0.5 + resolution: "destr@npm:2.0.5" + checksum: 10c0/efabffe7312a45ad90d79975376be958c50069f1156b94c181199763a7f971e113bd92227c26b94a169c71ca7dbc13583b7e96e5164743969fc79e1ff153e646 + languageName: node + linkType: hard + "destroy@npm:^1.0.4": version: 1.2.0 resolution: "destroy@npm:1.2.0" @@ -7150,7 +8312,7 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1": +"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1, detect-libc@npm:^2.0.3": version: 2.1.2 resolution: "detect-libc@npm:2.1.2" checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 @@ -7204,6 +8366,17 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + languageName: node + linkType: hard + "domain-browser@npm:4.22.0": version: 4.22.0 resolution: "domain-browser@npm:4.22.0" @@ -7211,13 +8384,65 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^16.0.3": +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + languageName: node + linkType: hard + +"domutils@npm:^3.0.1, domutils@npm:^3.2.2": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10c0/47938f473b987ea71cd59e59626eb8666d3aa8feba5266e45527f3b636c7883cca7e582d901531961f742c519d7514636b7973353b648762b2e3bedbf235fada + languageName: node + linkType: hard + +"dot-prop@npm:^9.0.0": + version: 9.0.0 + resolution: "dot-prop@npm:9.0.0" + dependencies: + type-fest: "npm:^4.18.2" + checksum: 10c0/4bac49a2f559156811862ac92813906f70529c50da918eaab81b38dd869743c667d578e183607f5ae11e8ae2a02e43e98e32c8a37bc4cae76b04d5b576e3112f + languageName: node + linkType: hard + +"dotenv-expand@npm:^12.0.3": + version: 12.0.3 + resolution: "dotenv-expand@npm:12.0.3" + dependencies: + dotenv: "npm:^16.4.5" + checksum: 10c0/0824bdc74fc816a28b0744b7853a23e046602e9616c82121dfdae21ebc13c6e89afeb773e794e97c35d48be2be0a990fbca721ee3869a49c04210a58a3cf296f + languageName: node + linkType: hard + +"dotenv@npm:^16.0.3, dotenv@npm:^16.4.5": version: 16.6.1 resolution: "dotenv@npm:16.6.1" checksum: 10c0/15ce56608326ea0d1d9414a5c8ee6dcf0fffc79d2c16422b4ac2268e7e2d76ff5a572d37ffe747c377de12005f14b3cc22361e79fc7f1061cce81f77d2c973dc languageName: node linkType: hard +"dotenv@npm:^17.2.4, dotenv@npm:^17.3.1": + version: 17.4.2 + resolution: "dotenv@npm:17.4.2" + checksum: 10c0/164f8e77a646c8446867d5b588d26ea6005c8ea7c5eb41cf926f6113d23f2191355f6e0cfd95ea9bab98394a5b0a3f1e51a8399711b666fe55cc7b0bd745f942 + languageName: node + linkType: hard + "dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": version: 1.0.1 resolution: "dunder-proto@npm:1.0.1" @@ -7336,6 +8561,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.328": + version: 1.5.344 + resolution: "electron-to-chromium@npm:1.5.344" + checksum: 10c0/36624a59b2da4cb2bdee3085f5fc814bc0ba5830162a26f45c4b189177455869fd9d9c2e05fa28e69a45fb95c04d3e995962ff0e1658f552dcbe147a731c4f1d + languageName: node + linkType: hard + "electron-winstaller@npm:^5.3.0": version: 5.4.0 resolution: "electron-winstaller@npm:5.4.0" @@ -7381,6 +8613,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.6.0 + resolution: "emoji-regex@npm:10.6.0" + checksum: 10c0/1e4aa097bb007301c3b4b1913879ae27327fdc48e93eeefefe3b87e495eb33c5af155300be951b4349ff6ac084f4403dc9eff970acba7c1c572d89396a9a32d7 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -7430,6 +8669,20 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.2.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 + languageName: node + linkType: hard + +"entities@npm:^7.0.1": + version: 7.0.1 + resolution: "entities@npm:7.0.1" + checksum: 10c0/b4fb9937bb47ecb00aaaceb9db9cdd1cc0b0fb649c0e843d05cf5dbbd2e9d2df8f98721d8b1b286445689c72af7b54a7242fc2d63ef7c9739037a8c73363e7ca + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -7437,6 +8690,13 @@ __metadata: languageName: node linkType: hard +"environment@npm:^1.0.0": + version: 1.1.0 + resolution: "environment@npm:1.1.0" + checksum: 10c0/fb26434b0b581ab397039e51ff3c92b34924a98b2039dcb47e41b7bca577b9dbf134a8eadb364415c74464b682e2d3afe1a4c0eb9873dc44ea814c5d3103331d + languageName: node + linkType: hard + "err-code@npm:^2.0.2": version: 2.0.3 resolution: "err-code@npm:2.0.3" @@ -7444,7 +8704,7 @@ __metadata: languageName: node linkType: hard -"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1": +"error-ex@npm:^1.2.0, error-ex@npm:^1.3.1, error-ex@npm:^1.3.2": version: 1.3.4 resolution: "error-ex@npm:1.3.4" dependencies: @@ -7584,7 +8844,7 @@ __metadata: languageName: node linkType: hard -"es6-error@npm:^4.1.1": +"es6-error@npm:4.1.1, es6-error@npm:^4.1.1": version: 4.1.1 resolution: "es6-error@npm:4.1.1" checksum: 10c0/357663fb1e845c047d548c3d30f86e005db71e122678f4184ced0693f634688c3f3ef2d7de7d4af732f734de01f528b05954e270f06aa7d133679fb9fe6600ef @@ -7760,6 +9020,95 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.27.1": + version: 0.27.7 + resolution: "esbuild@npm:0.27.7" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.7" + "@esbuild/android-arm": "npm:0.27.7" + "@esbuild/android-arm64": "npm:0.27.7" + "@esbuild/android-x64": "npm:0.27.7" + "@esbuild/darwin-arm64": "npm:0.27.7" + "@esbuild/darwin-x64": "npm:0.27.7" + "@esbuild/freebsd-arm64": "npm:0.27.7" + "@esbuild/freebsd-x64": "npm:0.27.7" + "@esbuild/linux-arm": "npm:0.27.7" + "@esbuild/linux-arm64": "npm:0.27.7" + "@esbuild/linux-ia32": "npm:0.27.7" + "@esbuild/linux-loong64": "npm:0.27.7" + "@esbuild/linux-mips64el": "npm:0.27.7" + "@esbuild/linux-ppc64": "npm:0.27.7" + "@esbuild/linux-riscv64": "npm:0.27.7" + "@esbuild/linux-s390x": "npm:0.27.7" + "@esbuild/linux-x64": "npm:0.27.7" + "@esbuild/netbsd-arm64": "npm:0.27.7" + "@esbuild/netbsd-x64": "npm:0.27.7" + "@esbuild/openbsd-arm64": "npm:0.27.7" + "@esbuild/openbsd-x64": "npm:0.27.7" + "@esbuild/openharmony-arm64": "npm:0.27.7" + "@esbuild/sunos-x64": "npm:0.27.7" + "@esbuild/win32-arm64": "npm:0.27.7" + "@esbuild/win32-ia32": "npm:0.27.7" + "@esbuild/win32-x64": "npm:0.27.7" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/ccd51f0555708bc9ff4ec9dc3ac92d3daacd45ecaac949ca8645984c5c323bf8cefe98c2df307418685e0b4ce37f9a3bdbfe8e3651fe632a0059a436195a17d4 + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -7767,6 +9116,13 @@ __metadata: languageName: node linkType: hard +"escape-goat@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-goat@npm:4.0.0" + checksum: 10c0/9d2a8314e2370f2dd9436d177f6b3b1773525df8f895c8f3e1acb716f5fd6b10b336cb1cd9862d4709b36eb207dbe33664838deca9c6d55b8371be4eebb972f6 + languageName: node + linkType: hard + "escape-html@npm:^1.0.3": version: 1.0.3 resolution: "escape-html@npm:1.0.3" @@ -7788,6 +9144,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 10c0/6366f474c6f37a802800a435232395e04e9885919873e382b157ab7e8f0feb8fed71497f84a6f6a81a49aab41815522f5839112bd38026d203aea0c91622df95 + languageName: node + linkType: hard + "eslint-config-prettier@npm:^10.1.3": version: 10.1.8 resolution: "eslint-config-prettier@npm:10.1.8" @@ -8046,7 +9409,7 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^5.0.1": +"eventemitter3@npm:^5.0.1, eventemitter3@npm:^5.0.4": version: 5.0.4 resolution: "eventemitter3@npm:5.0.4" checksum: 10c0/575b8cac8d709e1473da46f8f15ef311b57ff7609445a7c71af5cd42598583eee6f098fa7a593e30f27e94b8865642baa0689e8fa97c016f742abdb3b1bf6d9a @@ -8124,6 +9487,13 @@ __metadata: languageName: node linkType: hard +"exsolve@npm:^1.0.8": + version: 1.0.8 + resolution: "exsolve@npm:1.0.8" + checksum: 10c0/65e44ae05bd4a4a5d87cfdbbd6b8f24389282cf9f85fa5feb17ca87ad3f354877e6af4cd99e02fc29044174891f82d1d68c77f69234410eb8f163530e6278c67 + languageName: node + linkType: hard + "extend@npm:^3.0.2": version: 3.0.2 resolution: "extend@npm:3.0.2" @@ -8313,6 +9683,13 @@ __metadata: languageName: node linkType: hard +"filesize@npm:^11.0.15": + version: 11.0.17 + resolution: "filesize@npm:11.0.17" + checksum: 10c0/c7d633559731c70e6400fd0f59d4bfef8e9ca44ee932276ee972bfa03eeab925dc7b8af5747b61a36ac2f04c03a3472c106d7e62797cd2c445ccdd8ed665d44a + languageName: node + linkType: hard + "fill-range@npm:^7.1.1": version: 7.1.1 resolution: "fill-range@npm:7.1.1" @@ -8357,6 +9734,21 @@ __metadata: languageName: node linkType: hard +"firefox-profile@npm:4.7.0": + version: 4.7.0 + resolution: "firefox-profile@npm:4.7.0" + dependencies: + adm-zip: "npm:~0.5.x" + fs-extra: "npm:^11.2.0" + ini: "npm:^4.1.3" + minimist: "npm:^1.2.8" + xml2js: "npm:^0.6.2" + bin: + firefox-profile: lib/cli.js + checksum: 10c0/032949c923336f843015757f1aba90d19b9f0d7277ba91705958a5579d55c98a424700388ac263a1dc67d6a942403e25090443703ff0f38347a20e9dbc40e1a3 + languageName: node + linkType: hard + "flat-cache@npm:^4.0.0": version: 4.0.1 resolution: "flat-cache@npm:4.0.1" @@ -8413,6 +9805,13 @@ __metadata: languageName: node linkType: hard +"form-data-encoder@npm:^4.1.0": + version: 4.1.0 + resolution: "form-data-encoder@npm:4.1.0" + checksum: 10c0/cbd655aa8ffff6f7c2733b1d8e95fa9a2fe8a88a90bde29fb54b8e02c9406e51f32a014bfe8297d67fbac9f77614d14a8b4bbc4fd0352838e67e97a881d06332 + languageName: node + linkType: hard + "form-data@npm:^2.5.5": version: 2.5.5 resolution: "form-data@npm:2.5.5" @@ -8440,9 +9839,16 @@ __metadata: languageName: node linkType: hard -"fresh@npm:~0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" +"formdata-node@npm:^6.0.3": + version: 6.0.3 + resolution: "formdata-node@npm:6.0.3" + checksum: 10c0/9b8ada280c7b0c7314bed57fd50b3562f8825bd3ede6f6231b1bc7683b649e7f3ffb7b0f13d8e9e6cae8042ea21eaf497a7c676d2fe6dc63daefefaea4838240 + languageName: node + linkType: hard + +"fresh@npm:~0.5.2": + version: 0.5.2 + resolution: "fresh@npm:0.5.2" checksum: 10c0/c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a languageName: node linkType: hard @@ -8486,6 +9892,17 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.3.4 + resolution: "fs-extra@npm:11.3.4" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/e08276f767a62496ae97d711aaa692c6a478177f24a85979b6a2881c9db9c68b8c2ad5da0bcf92c0b2a474cea6e935ec245656441527958fd8372cb647087df0 + languageName: node + linkType: hard + "fs-extra@npm:^7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" @@ -8592,6 +10009,22 @@ __metadata: languageName: node linkType: hard +"fx-runner@npm:1.4.0": + version: 1.4.0 + resolution: "fx-runner@npm:1.4.0" + dependencies: + commander: "npm:2.9.0" + shell-quote: "npm:1.7.3" + spawn-sync: "npm:1.0.15" + when: "npm:3.7.7" + which: "npm:1.2.4" + winreg: "npm:0.0.12" + bin: + fx-runner: bin/fx-runner + checksum: 10c0/32ab32c5b9f92deced7103ed03de0dee1dca2c51f2e1d545ad34bafe600fb7f634f717b4a2c2fdab20058341846682f4d867a7081f6a75e66d658425a551d37c + languageName: node + linkType: hard + "galactus@npm:^1.0.0": version: 1.0.0 resolution: "galactus@npm:1.0.0" @@ -8641,6 +10074,13 @@ __metadata: languageName: node linkType: hard +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -8648,6 +10088,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0, get-east-asian-width@npm:^1.3.1, get-east-asian-width@npm:^1.5.0": + version: 1.5.0 + resolution: "get-east-asian-width@npm:1.5.0" + checksum: 10c0/bff8bbc8d81790b9477f7aa55b1806b9f082a8dc1359fff7bd8b96939622c86b729685afc2bfeb22def1fc6ef1e5228e4d87dd4e6da60bc43a5edfb03c4ee167 + languageName: node + linkType: hard + "get-folder-size@npm:^2.0.1": version: 2.0.1 resolution: "get-folder-size@npm:2.0.1" @@ -8690,6 +10137,13 @@ __metadata: languageName: node linkType: hard +"get-port-please@npm:^3.2.0": + version: 3.2.0 + resolution: "get-port-please@npm:3.2.0" + checksum: 10c0/7e48443110b463e76ef47efc381c9f16d78798f9ea9f6d928dad2b5cee53a199cf64e6e2f22603e5f8a1f742e3d4a144cd367f6ef82ac48759bfd2beb48ee9e5 + languageName: node + linkType: hard + "get-port@npm:^6.1.2": version: 6.1.2 resolution: "get-port@npm:6.1.2" @@ -8743,6 +10197,15 @@ __metadata: languageName: node linkType: hard +"giget@npm:^1.2.3 || ^2.0.0 || ^3.0.0, giget@npm:^3.2.0": + version: 3.2.0 + resolution: "giget@npm:3.2.0" + bin: + giget: dist/cli.mjs + checksum: 10c0/c3d670435e9247e658ab34201f7a944281bdf001d1e10fbb16016926735e8c57f38273a6ef0703feb63551a9628baa8ffa76edbc216118f33abdd42174b0e714 + languageName: node + linkType: hard + "github-from-package@npm:0.0.0": version: 0.0.0 resolution: "github-from-package@npm:0.0.0" @@ -8843,6 +10306,15 @@ __metadata: languageName: node linkType: hard +"global-directory@npm:^4.0.1": + version: 4.0.1 + resolution: "global-directory@npm:4.0.1" + dependencies: + ini: "npm:4.1.1" + checksum: 10c0/f9cbeef41db4876f94dd0bac1c1b4282a7de9c16350ecaaf83e7b2dd777b32704cc25beeb1170b5a63c42a2c9abfade74d46357fe0133e933218bc89e613d4b2 + languageName: node + linkType: hard + "global-dirs@npm:^3.0.0": version: 3.0.1 resolution: "global-dirs@npm:3.0.1" @@ -8923,6 +10395,13 @@ __metadata: languageName: node linkType: hard +"graceful-fs@npm:4.2.10": + version: 4.2.10 + resolution: "graceful-fs@npm:4.2.10" + checksum: 10c0/4223a833e38e1d0d2aea630c2433cfb94ddc07dfc11d511dbd6be1d16688c5be848acc31f9a5d0d0ddbfb56d2ee5a6ae0278aceeb0ca6a13f27e06b9956fb952 + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -8930,6 +10409,20 @@ __metadata: languageName: node linkType: hard +"graceful-readlink@npm:>= 1.0.0": + version: 1.0.1 + resolution: "graceful-readlink@npm:1.0.1" + checksum: 10c0/c53e703257e77f8a4495ff0d476c09aa413251acd26684f4544771b15e0ad361d1075b8f6d27b52af6942ea58155a9bbdb8125d717c70df27117460fee295a54 + languageName: node + linkType: hard + +"growly@npm:^1.3.0": + version: 1.3.0 + resolution: "growly@npm:1.3.0" + checksum: 10c0/3043bd5c064e87f89e8c9b66894ed09fd882c7fa645621a543b45b72f040c7241e25061207a858ab191be2fbdac34795ff57c2a40962b154a6b2908a5e509252 + languageName: node + linkType: hard + "gtoken@npm:^7.0.0": version: 7.1.0 resolution: "gtoken@npm:7.1.0" @@ -9063,6 +10556,13 @@ __metadata: languageName: node linkType: hard +"hookable@npm:^6.1.0": + version: 6.1.1 + resolution: "hookable@npm:6.1.1" + checksum: 10c0/bb46cd9ffc0a997af21febd97835da4e59a6989adec73dc3c215fcc44c7ac01de4781f251c3d420bf45862d2592a695f5f0de095b6f5df52db8afb5166938212 + languageName: node + linkType: hard + "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -9077,6 +10577,25 @@ __metadata: languageName: node linkType: hard +"html-escaper@npm:^3.0.3": + version: 3.0.3 + resolution: "html-escaper@npm:3.0.3" + checksum: 10c0/a042fa4139127ff7546513e90ea39cc9161a1938ce90122dbc4260d4b7252c9aa8452f4509c0c2889901b8ae9a8699179150f1f99d3f80bcf7317573c5f08f4e + languageName: node + linkType: hard + +"htmlparser2@npm:^10.0.0": + version: 10.1.0 + resolution: "htmlparser2@npm:10.1.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.2.2" + entities: "npm:^7.0.1" + checksum: 10c0/36394e29b80cfcc5e78e0fa4d3aa21fdaac3e6778d23e5c933e625c290987cd9a724a2eb0753ab60ed0c69dfaba0ab115f0ee50fb112fd8f0c4d522e7e0089a2 + languageName: node + linkType: hard + "http-assert@npm:^1.3.0": version: 1.5.0 resolution: "http-assert@npm:1.5.0" @@ -9267,6 +10786,13 @@ __metadata: languageName: node linkType: hard +"immediate@npm:~3.0.5": + version: 3.0.6 + resolution: "immediate@npm:3.0.6" + checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1": version: 3.3.1 resolution: "import-fresh@npm:3.3.1" @@ -9277,6 +10803,13 @@ __metadata: languageName: node linkType: hard +"import-meta-resolve@npm:^4.2.0": + version: 4.2.0 + resolution: "import-meta-resolve@npm:4.2.0" + checksum: 10c0/3ee8aeecb61d19b49d2703987f977e9d1c7d4ba47db615a570eaa02fe414f40dfa63f7b953e842cbe8470d26df6371332bfcf21b2fd92b0112f9fea80dde2c4c + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -9329,13 +10862,27 @@ __metadata: languageName: node linkType: hard -"ini@npm:~1.3.0": +"ini@npm:4.1.1": + version: 4.1.1 + resolution: "ini@npm:4.1.1" + checksum: 10c0/7fddc8dfd3e63567d4fdd5d999d1bf8a8487f1479d0b34a1d01f28d391a9228d261e19abc38e1a6a1ceb3400c727204fce05725d5eb598dfcf2077a1e3afe211 + languageName: node + linkType: hard + +"ini@npm:^1.3.4, ini@npm:~1.3.0": version: 1.3.8 resolution: "ini@npm:1.3.8" checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a languageName: node linkType: hard +"ini@npm:^4.1.3": + version: 4.1.3 + resolution: "ini@npm:4.1.3" + checksum: 10c0/0d27eff094d5f3899dd7c00d0c04ea733ca03a8eb6f9406ce15daac1a81de022cb417d6eaff7e4342451ffa663389c565ffc68d6825eaf686bf003280b945764 + languageName: node + linkType: hard + "internal-slot@npm:^1.1.0": version: 1.1.0 resolution: "internal-slot@npm:1.1.0" @@ -9371,6 +10918,15 @@ __metadata: languageName: node linkType: hard +"is-absolute@npm:^0.1.7": + version: 0.1.7 + resolution: "is-absolute@npm:0.1.7" + dependencies: + is-relative: "npm:^0.1.0" + checksum: 10c0/ffa42b79866c16e54c00a98a94f1eaf4b5bf1debae5e321b80b24d529d9a1e8f47ec1bcdc2dd0773ea814c8facbe76680582d099a57c3d5775720adcc4071850 + languageName: node + linkType: hard + "is-arguments@npm:^1.0.4": version: 1.2.0 resolution: "is-arguments@npm:1.2.0" @@ -9484,6 +11040,24 @@ __metadata: languageName: node linkType: hard +"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": + version: 2.2.1 + resolution: "is-docker@npm:2.2.1" + bin: + is-docker: cli.js + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc + languageName: node + linkType: hard + +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: 10c0/d2c4f8e6d3e34df75a5defd44991b6068afad4835bb783b902fa12d13ebdb8f41b2a199dcb0b5ed2cb78bfee9e4c0bbdb69c2d9646f4106464674d3e697a5856 + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -9514,6 +11088,15 @@ __metadata: languageName: node linkType: hard +"is-fullwidth-code-point@npm:^5.0.0, is-fullwidth-code-point@npm:^5.1.0": + version: 5.1.0 + resolution: "is-fullwidth-code-point@npm:5.1.0" + dependencies: + get-east-asian-width: "npm:^1.3.1" + checksum: 10c0/c1172c2e417fb73470c56c431851681591f6a17233603a9e6f94b7ba870b2e8a5266506490573b607fb1081318589372034aa436aec07b465c2029c0bc7f07a4 + languageName: node + linkType: hard + "is-generator-function@npm:^1.0.10, is-generator-function@npm:^1.0.7": version: 1.1.2 resolution: "is-generator-function@npm:1.1.2" @@ -9536,6 +11119,43 @@ __metadata: languageName: node linkType: hard +"is-in-ci@npm:^1.0.0": + version: 1.0.0 + resolution: "is-in-ci@npm:1.0.0" + bin: + is-in-ci: cli.js + checksum: 10c0/98f9cec4c35aece4cf731abf35ebf28359a9b0324fac810da05b842515d9ccb33b8999c1d9a679f0362e1a4df3292065c38d7f86327b1387fa667bc0150f4898 + languageName: node + linkType: hard + +"is-in-ssh@npm:^1.0.0": + version: 1.0.0 + resolution: "is-in-ssh@npm:1.0.0" + checksum: 10c0/fbb4c25d85c543df09997fbe7aeca410ae0c839c5825bba2d4c672df765e9ce0e7558e781b371c0a21d6ef9bbac39b31875617a68eaaea5504438d07db9a2ffa + languageName: node + linkType: hard + +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: "npm:^3.0.0" + bin: + is-inside-container: cli.js + checksum: 10c0/a8efb0e84f6197e6ff5c64c52890fa9acb49b7b74fed4da7c95383965da6f0fa592b4dbd5e38a79f87fc108196937acdbcd758fcefc9b140e479b39ce1fcd1cd + languageName: node + linkType: hard + +"is-installed-globally@npm:^1.0.0": + version: 1.0.0 + resolution: "is-installed-globally@npm:1.0.0" + dependencies: + global-directory: "npm:^4.0.1" + is-path-inside: "npm:^4.0.0" + checksum: 10c0/5f57745b6e75b2e9e707a26470d0cb74291d9be33c0fe0dc06c6955fe086bc2ca0a8960631b1ecb9677100eac90af33e911aec7a2c0b88097d702bfa3b76486d + languageName: node + linkType: hard + "is-interactive@npm:^1.0.0": version: 1.0.0 resolution: "is-interactive@npm:1.0.0" @@ -9574,6 +11194,13 @@ __metadata: languageName: node linkType: hard +"is-npm@npm:^6.0.0": + version: 6.1.0 + resolution: "is-npm@npm:6.1.0" + checksum: 10c0/2319580963e7b77f51b07d242064926894472e0b8aab7d4f67aa58a2032715a18c77844a2d963718b8ee1eac112ce4dbcd55a9d994f589d5994d46b57b5cdfda + languageName: node + linkType: hard + "is-number-object@npm:^1.1.1": version: 1.1.1 resolution: "is-number-object@npm:1.1.1" @@ -9591,6 +11218,36 @@ __metadata: languageName: node linkType: hard +"is-path-inside@npm:^4.0.0": + version: 4.0.0 + resolution: "is-path-inside@npm:4.0.0" + checksum: 10c0/51188d7e2b1d907a9a5f7c18d99a90b60870b951ed87cf97595d9aaa429d4c010652c3350bcbf31182e7f4b0eab9a1860b43e16729b13cb1a44baaa6cdb64c46 + languageName: node + linkType: hard + +"is-plain-object@npm:^2.0.4": + version: 2.0.4 + resolution: "is-plain-object@npm:2.0.4" + dependencies: + isobject: "npm:^3.0.1" + checksum: 10c0/f050fdd5203d9c81e8c4df1b3ff461c4bc64e8b5ca383bcdde46131361d0a678e80bcf00b5257646f6c636197629644d53bd8e2375aea633de09a82d57e942f4 + languageName: node + linkType: hard + +"is-potential-custom-element-name@npm:^1.0.1": + version: 1.0.1 + resolution: "is-potential-custom-element-name@npm:1.0.1" + checksum: 10c0/b73e2f22bc863b0939941d369486d308b43d7aef1f9439705e3582bfccaa4516406865e32c968a35f97a99396dac84e2624e67b0a16b0a15086a785e16ce7db9 + languageName: node + linkType: hard + +"is-primitive@npm:^3.0.1": + version: 3.0.1 + resolution: "is-primitive@npm:3.0.1" + checksum: 10c0/2e3b6f029fabbdda467ea51ea4fdd00e6552434108b863a08f296638072c506a7c195089e3e31f83e7fc14bebbd1c5c9f872fe127c9284a7665c8227b47ffdd6 + languageName: node + linkType: hard + "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -9603,6 +11260,13 @@ __metadata: languageName: node linkType: hard +"is-relative@npm:^0.1.0": + version: 0.1.3 + resolution: "is-relative@npm:0.1.3" + checksum: 10c0/91a4fe81b3b93ee220562e56e817b16c243a265d6c2daf9872ee583718db506b3b54036e852aedbb14ed693d7fc439e8836d0a5e44c56f450f730d074600c3ab + languageName: node + linkType: hard + "is-set@npm:^2.0.3": version: 2.0.3 resolution: "is-set@npm:2.0.3" @@ -9703,6 +11367,24 @@ __metadata: languageName: node linkType: hard +"is-wsl@npm:^2.2.0": + version: 2.2.0 + resolution: "is-wsl@npm:2.2.0" + dependencies: + is-docker: "npm:^2.0.0" + checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e + languageName: node + linkType: hard + +"is-wsl@npm:^3.1.0, is-wsl@npm:^3.1.1": + version: 3.1.1 + resolution: "is-wsl@npm:3.1.1" + dependencies: + is-inside-container: "npm:^1.0.0" + checksum: 10c0/7e5023522bfb8f27de4de960b0d82c4a8146c0bddb186529a3616d78b5bbbfc19ef0c5fc60d0b3a3cc0bf95a415fbdedc18454310ea3049587c879b07ace5107 + languageName: node + linkType: hard + "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" @@ -9724,6 +11406,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^1.1.1": + version: 1.1.2 + resolution: "isexe@npm:1.1.2" + checksum: 10c0/a61c79949c6198046d147df44693dc645f3605f8d3078e3720cf048daa7d966c8b4890a39924cec8e948395a9b6b33051af9fd7264d8ad96a4a3f562a592e33f + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -9738,6 +11427,13 @@ __metadata: languageName: node linkType: hard +"isobject@npm:^3.0.1": + version: 3.0.1 + resolution: "isobject@npm:3.0.1" + checksum: 10c0/03344f5064a82f099a0cd1a8a407f4c0d20b7b8485e8e816c39f249e9416b06c322e8dec5b842b6bb8a06de0af9cb48e7bc1b5352f0fadc2f0abac033db3d4db + languageName: node + linkType: hard + "isomorphic-timers-promises@npm:^1.0.1": version: 1.0.1 resolution: "isomorphic-timers-promises@npm:1.0.1" @@ -9774,7 +11470,7 @@ __metadata: languageName: node linkType: hard -"jiti@npm:^2.4.2": +"jiti@npm:^2.4.2, jiti@npm:^2.6.1": version: 2.6.1 resolution: "jiti@npm:2.6.1" bin: @@ -9847,6 +11543,13 @@ __metadata: languageName: node linkType: hard +"json-parse-even-better-errors@npm:^3.0.0": + version: 3.0.2 + resolution: "json-parse-even-better-errors@npm:3.0.2" + checksum: 10c0/147f12b005768abe9fab78d2521ce2b7e1381a118413d634a40e6d907d7d10f5e9a05e47141e96d6853af7cc36d2c834d0a014251be48791e037ff2f13d2b94b + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -9893,6 +11596,15 @@ __metadata: languageName: node linkType: hard +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c + languageName: node + linkType: hard + "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -9918,6 +11630,36 @@ __metadata: languageName: node linkType: hard +"jsonwebtoken@npm:^9.0.3": + version: 9.0.3 + resolution: "jsonwebtoken@npm:9.0.3" + dependencies: + jws: "npm:^4.0.1" + lodash.includes: "npm:^4.3.0" + lodash.isboolean: "npm:^3.0.3" + lodash.isinteger: "npm:^4.0.4" + lodash.isnumber: "npm:^3.0.3" + lodash.isplainobject: "npm:^4.0.6" + lodash.isstring: "npm:^4.0.1" + lodash.once: "npm:^4.0.0" + ms: "npm:^2.1.1" + semver: "npm:^7.5.4" + checksum: 10c0/6ca7f1e54886ea3bde7146a5a22b53847c46e25453c7f7307a69818b9a6ad48c390b2e59d5690fcfd03c529b01960060cc4bb0c686991d6edae2285dfd30f4ba + languageName: node + linkType: hard + +"jszip@npm:^3.10.1, jszip@npm:^3.2.2": + version: 3.10.1 + resolution: "jszip@npm:3.10.1" + dependencies: + lie: "npm:~3.3.0" + pako: "npm:~1.0.2" + readable-stream: "npm:~2.3.6" + setimmediate: "npm:^1.0.5" + checksum: 10c0/58e01ec9c4960383fb8b38dd5f67b83ccc1ec215bf74c8a5b32f42b6e5fb79fada5176842a11409c4051b5b94275044851814a31076bf49e1be218d3ef57c863 + languageName: node + linkType: hard + "junk@npm:^3.1.0": version: 3.1.0 resolution: "junk@npm:3.1.0" @@ -9936,7 +11678,7 @@ __metadata: languageName: node linkType: hard -"jws@npm:^4.0.0": +"jws@npm:^4.0.0, jws@npm:^4.0.1": version: 4.0.1 resolution: "jws@npm:4.0.1" dependencies: @@ -9964,6 +11706,13 @@ __metadata: languageName: node linkType: hard +"kleur@npm:^3.0.3": + version: 3.0.3 + resolution: "kleur@npm:3.0.3" + checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b + languageName: node + linkType: hard + "koa-bodyparser@npm:^4.4.0": version: 4.4.1 resolution: "koa-bodyparser@npm:4.4.1" @@ -10055,6 +11804,22 @@ __metadata: languageName: node linkType: hard +"ky@npm:^1.2.0": + version: 1.14.3 + resolution: "ky@npm:1.14.3" + checksum: 10c0/8e91c9512c8f1501201108ad58ed437eaf3f5b0a0da842bd846d785932426e84a31cf51d0fffce1921d4e70e26465a9b2b89ed2477822975568258a1fa68a740 + languageName: node + linkType: hard + +"latest-version@npm:^9.0.0": + version: 9.0.0 + resolution: "latest-version@npm:9.0.0" + dependencies: + package-json: "npm:^10.0.0" + checksum: 10c0/643cfda3a58dfb3af221a2950e433393d28a5adbe225d1cbbb358dbcbb04e9f8dce15b892f8ae3e3156f50693428dbd7ca13a69edfbdfcd94e62519480d7041e + languageName: node + linkType: hard + "level-concat-iterator@npm:^3.0.0": version: 3.1.0 resolution: "level-concat-iterator@npm:3.1.0" @@ -10093,6 +11858,145 @@ __metadata: languageName: node linkType: hard +"lie@npm:~3.3.0": + version: 3.3.0 + resolution: "lie@npm:3.3.0" + dependencies: + immediate: "npm:~3.0.5" + checksum: 10c0/56dd113091978f82f9dc5081769c6f3b947852ecf9feccaf83e14a123bc630c2301439ce6182521e5fbafbde88e88ac38314327a4e0493a1bea7e0699a7af808 + languageName: node + linkType: hard + +"lighthouse-logger@npm:^2.0.1": + version: 2.0.2 + resolution: "lighthouse-logger@npm:2.0.2" + dependencies: + debug: "npm:^4.4.1" + marky: "npm:^1.2.2" + checksum: 10c0/bbce3939a0359d5f1f84b7cc623f1ee3daf5a28e55b7b9bf7d461d906121e64fa6de290c53bd6bdd6068a67442fa39a7deb6f61da2e0e1721c39ec4cc80876b8 + languageName: node + linkType: hard + +"lightningcss-android-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-android-arm64@npm:1.32.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-arm64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-arm64@npm:1.32.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-darwin-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-darwin-x64@npm:1.32.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-freebsd-x64@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-freebsd-x64@npm:1.32.0" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lightningcss-linux-arm-gnueabihf@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm-gnueabihf@npm:1.32.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"lightningcss-linux-arm64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-gnu@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-arm64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-arm64-musl@npm:1.32.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-linux-x64-gnu@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-gnu@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"lightningcss-linux-x64-musl@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-linux-x64-musl@npm:1.32.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"lightningcss-win32-arm64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-arm64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lightningcss-win32-x64-msvc@npm:1.32.0": + version: 1.32.0 + resolution: "lightningcss-win32-x64-msvc@npm:1.32.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"lightningcss@npm:^1.32.0": + version: 1.32.0 + resolution: "lightningcss@npm:1.32.0" + dependencies: + detect-libc: "npm:^2.0.3" + lightningcss-android-arm64: "npm:1.32.0" + lightningcss-darwin-arm64: "npm:1.32.0" + lightningcss-darwin-x64: "npm:1.32.0" + lightningcss-freebsd-x64: "npm:1.32.0" + lightningcss-linux-arm-gnueabihf: "npm:1.32.0" + lightningcss-linux-arm64-gnu: "npm:1.32.0" + lightningcss-linux-arm64-musl: "npm:1.32.0" + lightningcss-linux-x64-gnu: "npm:1.32.0" + lightningcss-linux-x64-musl: "npm:1.32.0" + lightningcss-win32-arm64-msvc: "npm:1.32.0" + lightningcss-win32-x64-msvc: "npm:1.32.0" + dependenciesMeta: + lightningcss-android-arm64: + optional: true + lightningcss-darwin-arm64: + optional: true + lightningcss-darwin-x64: + optional: true + lightningcss-freebsd-x64: + optional: true + lightningcss-linux-arm-gnueabihf: + optional: true + lightningcss-linux-arm64-gnu: + optional: true + lightningcss-linux-arm64-musl: + optional: true + lightningcss-linux-x64-gnu: + optional: true + lightningcss-linux-x64-musl: + optional: true + lightningcss-win32-arm64-msvc: + optional: true + lightningcss-win32-x64-msvc: + optional: true + checksum: 10c0/70945bd55097af46fc9fab7f5ed09cd5869d85940a2acab7ee06d0117004a1d68155708a2d462531cea2fc3c67aefc9333a7068c80b0b78dd404c16838809e03 + languageName: node + linkType: hard + "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" @@ -10100,6 +12004,44 @@ __metadata: languageName: node linkType: hard +"lines-and-columns@npm:^2.0.3": + version: 2.0.4 + resolution: "lines-and-columns@npm:2.0.4" + checksum: 10c0/4db28bf065cd7ad897c0700f22d3d0d7c5ed6777e138861c601c496d545340df3fc19e18bd04ff8d95a246a245eb55685b82ca2f8c2ca53a008e9c5316250379 + languageName: node + linkType: hard + +"linkedom@npm:^0.18.12": + version: 0.18.12 + resolution: "linkedom@npm:0.18.12" + dependencies: + css-select: "npm:^5.1.0" + cssom: "npm:^0.5.0" + html-escaper: "npm:^3.0.3" + htmlparser2: "npm:^10.0.0" + uhyphen: "npm:^0.2.0" + peerDependencies: + canvas: ">= 2" + peerDependenciesMeta: + canvas: + optional: true + checksum: 10c0/d7e4f9f40e02da81effa4d462a1ea9e23c0ed2d478aa2f0a96279cf2b51b77e3e637d074c9d5d92877816ab9f4c098bcf5151c8ceb82855b60e9dbba2f91b143 + languageName: node + linkType: hard + +"listr2@npm:^10.1.0": + version: 10.2.1 + resolution: "listr2@npm:10.2.1" + dependencies: + cli-truncate: "npm:^5.2.0" + eventemitter3: "npm:^5.0.4" + log-update: "npm:^6.1.0" + rfdc: "npm:^1.4.1" + wrap-ansi: "npm:^10.0.0" + checksum: 10c0/a381a7aaef2e8625e6e882835ef446d14306c8fa371b56c4499cf23ece86f84922008af11962bfba5411b51589e02d280bea2b820451a2efad89ebf78bbe68a4 + languageName: node + linkType: hard + "listr2@npm:^7.0.2": version: 7.0.2 resolution: "listr2@npm:7.0.2" @@ -10172,6 +12114,17 @@ __metadata: languageName: node linkType: hard +"local-pkg@npm:^1.1.2": + version: 1.1.2 + resolution: "local-pkg@npm:1.1.2" + dependencies: + mlly: "npm:^1.7.4" + pkg-types: "npm:^2.3.0" + quansync: "npm:^0.2.11" + checksum: 10c0/1bcfcc5528dea95cba3caa478126a348d3985aad9f69ecf7802c13efef90897e1c5ff7851974332c5e6d4a4698efe610fef758a068c8bc3feb5322aeb35d5993 + languageName: node + linkType: hard + "locate-path@npm:^2.0.0": version: 2.0.0 resolution: "locate-path@npm:2.0.0" @@ -10226,6 +12179,20 @@ __metadata: languageName: node linkType: hard +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b + languageName: node + linkType: hard + +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 + languageName: node + linkType: hard + "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -10233,6 +12200,34 @@ __metadata: languageName: node linkType: hard +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d + languageName: node + linkType: hard + +"lodash.isplainobject@npm:^4.0.6": + version: 4.0.6 + resolution: "lodash.isplainobject@npm:4.0.6" + checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb + languageName: node + linkType: hard + +"lodash.isstring@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.isstring@npm:4.0.1" + checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 + languageName: node + linkType: hard + "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -10247,6 +12242,13 @@ __metadata: languageName: node linkType: hard +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 + languageName: node + linkType: hard + "lodash.pickby@npm:^4.5.0": version: 4.6.0 resolution: "lodash.pickby@npm:4.6.0" @@ -10291,6 +12293,19 @@ __metadata: languageName: node linkType: hard +"log-update@npm:^6.1.0": + version: 6.1.0 + resolution: "log-update@npm:6.1.0" + dependencies: + ansi-escapes: "npm:^7.0.0" + cli-cursor: "npm:^5.0.0" + slice-ansi: "npm:^7.1.0" + strip-ansi: "npm:^7.1.0" + wrap-ansi: "npm:^9.0.0" + checksum: 10c0/4b350c0a83d7753fea34dcac6cd797d1dc9603291565de009baa4aa91c0447eab0d3815a05c8ec9ac04fdfffb43c82adcdb03ec1fceafd8518e1a8c1cff4ff89 + languageName: node + linkType: hard + "long@npm:^5.0.0": version: 5.3.2 resolution: "long@npm:5.3.2" @@ -10330,6 +12345,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 + languageName: node + linkType: hard + "lru-cache@npm:^7.7.1": version: 7.18.3 resolution: "lru-cache@npm:7.18.3" @@ -10337,12 +12361,30 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.17, magic-string@npm:^0.30.3": - version: 0.30.21 - resolution: "magic-string@npm:0.30.21" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.5.5" - checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a +"magic-string@npm:^0.30.17, magic-string@npm:^0.30.21, magic-string@npm:^0.30.3": + version: 0.30.21 + resolution: "magic-string@npm:0.30.21" + dependencies: + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a + languageName: node + linkType: hard + +"magicast@npm:^0.5.2": + version: 0.5.2 + resolution: "magicast@npm:0.5.2" + dependencies: + "@babel/parser": "npm:^7.29.0" + "@babel/types": "npm:^7.29.0" + source-map-js: "npm:^1.2.1" + checksum: 10c0/924af677643c5a0a7d6cdb3247c0eb96fa7611b2ba6a5e720d35d81c503d3d9f5948eb5227f80f90f82ea3e7d38cffd10bb988f3fc09020db428e14f26e960d7 + languageName: node + linkType: hard + +"make-error@npm:^1.3.2": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: 10c0/171e458d86854c6b3fc46610cfacf0b45149ba043782558c6875d9f42f222124384ad0b468c92e996d815a8a2003817a710c0a160e49c1c394626f76fa45396f languageName: node linkType: hard @@ -10389,6 +12431,13 @@ __metadata: languageName: node linkType: hard +"many-keys-map@npm:^3.0.0": + version: 3.0.3 + resolution: "many-keys-map@npm:3.0.3" + checksum: 10c0/1804ef07e45ef3f5ea58a7c6346bcb85e6563bd6d3116d7e60451cf009ce6c045a79511aed46c5d9afa3b6e4bccd897f2d37503a424162f0d7c065cb4069a793 + languageName: node + linkType: hard + "map-age-cleaner@npm:^0.1.1": version: 0.1.3 resolution: "map-age-cleaner@npm:0.1.3" @@ -10398,6 +12447,13 @@ __metadata: languageName: node linkType: hard +"marky@npm:^1.2.2": + version: 1.3.0 + resolution: "marky@npm:1.3.0" + checksum: 10c0/6619cdb132fdc4f7cd3e2bed6eebf81a38e50ff4b426bbfb354db68731e4adfebf35ebfd7c8e5a6e846cbf9b872588c4f76db25782caee8c1529ec9d483bf98b + languageName: node + linkType: hard + "matcher@npm:^3.0.0": version: 3.0.0 resolution: "matcher@npm:3.0.0" @@ -10525,6 +12581,13 @@ __metadata: languageName: node linkType: hard +"mimic-function@npm:^5.0.0": + version: 5.0.1 + resolution: "mimic-function@npm:5.0.1" + checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d + languageName: node + linkType: hard + "mimic-response@npm:^1.0.0": version: 1.0.1 resolution: "mimic-response@npm:1.0.1" @@ -10749,6 +12812,18 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^1.7.4, mlly@npm:^1.8.2": + version: 1.8.2 + resolution: "mlly@npm:1.8.2" + dependencies: + acorn: "npm:^8.16.0" + pathe: "npm:^2.0.3" + pkg-types: "npm:^1.3.1" + ufo: "npm:^1.6.3" + checksum: 10c0/aa826683a6daddf2aef65f9c8142e362731cf8e415a5591faf92fd51040a76697e45ab6dbb7a3b38be74e0f8c464825a7eabe827750455c7472421953f5da733 + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -10818,6 +12893,18 @@ __metadata: languageName: node linkType: hard +"multimatch@npm:6.0.0": + version: 6.0.0 + resolution: "multimatch@npm:6.0.0" + dependencies: + "@types/minimatch": "npm:^3.0.5" + array-differ: "npm:^4.0.0" + array-union: "npm:^3.0.1" + minimatch: "npm:^3.0.4" + checksum: 10c0/e303c3d83a66bdffbe6bb50b7be000dd299f1928a602323adc92daef3c1028ef1ee4cabf7d2ac458e32096c5dac2a263209835464348faf8a8332d076b58c35a + languageName: node + linkType: hard + "multistream@npm:^4.1.0": version: 4.1.0 resolution: "multistream@npm:4.1.0" @@ -10835,6 +12922,13 @@ __metadata: languageName: node linkType: hard +"nano-spawn@npm:^2.0.0": + version: 2.1.0 + resolution: "nano-spawn@npm:2.1.0" + checksum: 10c0/3becc67ed9ab630b6572feab69a4ef468891ad1f89d5c8643f14a2044cf32ba64533033506208039b1e3d9ddcb2f5f4f87ec360f13b3c4f0774304aedf0f0290 + languageName: node + linkType: hard + "nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" @@ -10844,6 +12938,15 @@ __metadata: languageName: node linkType: hard +"nanospinner@npm:^1.2.2": + version: 1.2.2 + resolution: "nanospinner@npm:1.2.2" + dependencies: + picocolors: "npm:^1.1.1" + checksum: 10c0/07264f63816a8ec24d84ffe216a605cf11dffd8b098d4c5e6790437304b47e10ce4fc341de8dbcfc1b59aa42107f9949c89bcc201239eb61a80e14b6b1a20c90 + languageName: node + linkType: hard + "napi-build-utils@npm:^2.0.0": version: 2.0.0 resolution: "napi-build-utils@npm:2.0.0" @@ -10927,6 +13030,13 @@ __metadata: languageName: node linkType: hard +"node-fetch-native@npm:^1.6.7": + version: 1.6.7 + resolution: "node-fetch-native@npm:1.6.7" + checksum: 10c0/8b748300fb053d21ca4d3db9c3ff52593d5e8f8a2d9fe90cbfad159676e324b954fdaefab46aeca007b5b9edab3d150021c4846444e4e8ab1f4e44cd3807be87 + languageName: node + linkType: hard + "node-fetch@npm:^2.6.6, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.9": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" @@ -10941,6 +13051,13 @@ __metadata: languageName: node linkType: hard +"node-forge@npm:^1.3.1": + version: 1.4.0 + resolution: "node-forge@npm:1.4.0" + checksum: 10c0/67330a5f1f95257a4c8a93b7d555abe87b5f15e350123aa396c97a21a8ca94f9c6549008eb2c73668a91e0d7e3a905785acbd8f8bd0751c29401292011f8f8e1 + languageName: node + linkType: hard + "node-gyp-build-optional-packages@npm:5.2.2": version: 5.2.2 resolution: "node-gyp-build-optional-packages@npm:5.2.2" @@ -10985,6 +13102,20 @@ __metadata: languageName: node linkType: hard +"node-notifier@npm:10.0.1": + version: 10.0.1 + resolution: "node-notifier@npm:10.0.1" + dependencies: + growly: "npm:^1.3.0" + is-wsl: "npm:^2.2.0" + semver: "npm:^7.3.5" + shellwords: "npm:^0.1.1" + uuid: "npm:^8.3.2" + which: "npm:^2.0.2" + checksum: 10c0/8888f6c4c277c588e6be991019e32ebbf4abdd598151683de59b9f70c31e6bbbddf0e443ea373da44338ab82a958695dcf73035c96e336a398940228d59399eb + languageName: node + linkType: hard + "node-pg-migrate@npm:^8.0.4": version: 8.0.4 resolution: "node-pg-migrate@npm:8.0.4" @@ -11010,7 +13141,14 @@ __metadata: languageName: node linkType: hard -"node-stdlib-browser@npm:^1.2.0": +"node-releases@npm:^2.0.36": + version: 2.0.38 + resolution: "node-releases@npm:2.0.38" + checksum: 10c0/db9909234ed750c5b9d0075f83214cd16b76370b54eab50e3554f3ba939ba7ac39f3aca2ddf93471ae8553dbde2ea9354b0ae380c9cff1f8e53b55e414903413 + languageName: node + linkType: hard + +"node-stdlib-browser@npm:^1.2.0, node-stdlib-browser@npm:^1.3.1": version: 1.3.1 resolution: "node-stdlib-browser@npm:1.3.1" dependencies: @@ -11111,6 +13249,28 @@ __metadata: languageName: node linkType: hard +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: "npm:^1.0.0" + checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 + languageName: node + linkType: hard + +"nypm@npm:^0.6.5": + version: 0.6.6 + resolution: "nypm@npm:0.6.6" + dependencies: + citty: "npm:^0.2.2" + pathe: "npm:^2.0.3" + tinyexec: "npm:^1.1.1" + bin: + nypm: dist/cli.mjs + checksum: 10c0/74918579bef694a9ae1cadbace9e316e323e4ec753c8ef03f47600ad08247a8744472c8ed86e4f5667cb5a1e4e5f871f225f27a5d2ceee619ef50c4deab818d7 + languageName: node + linkType: hard + "object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -11191,6 +13351,24 @@ __metadata: languageName: node linkType: hard +"obug@npm:^2.1.1": + version: 2.1.1 + resolution: "obug@npm:2.1.1" + checksum: 10c0/59dccd7de72a047e08f8649e94c1015ec72f94eefb6ddb57fb4812c4b425a813bc7e7cd30c9aca20db3c59abc3c85cc7a62bb656a968741d770f4e8e02bc2e78 + languageName: node + linkType: hard + +"ofetch@npm:^1.5.1": + version: 1.5.1 + resolution: "ofetch@npm:1.5.1" + dependencies: + destr: "npm:^2.0.5" + node-fetch-native: "npm:^1.6.7" + ufo: "npm:^1.6.1" + checksum: 10c0/97ebc600512ea0ab401e97c73313218cc53c9b530b32ec8c995c347b0c68887129993168d1753f527761a64c6f93a5d823ce1378ccec95fc65a606f323a79a6c + languageName: node + linkType: hard + "ohash@npm:^2.0.11": version: 2.0.11 resolution: "ohash@npm:2.0.11" @@ -11241,6 +13419,15 @@ __metadata: languageName: node linkType: hard +"onetime@npm:^7.0.0": + version: 7.0.0 + resolution: "onetime@npm:7.0.0" + dependencies: + mimic-function: "npm:^5.0.0" + checksum: 10c0/5cb9179d74b63f52a196a2e7037ba2b9a893245a5532d3f44360012005c9cadb60851d56716ebff18a6f47129dab7168022445df47c2aff3b276d92585ed1221 + languageName: node + linkType: hard + "only@npm:~0.0.2": version: 0.0.2 resolution: "only@npm:0.0.2" @@ -11248,6 +13435,31 @@ __metadata: languageName: node linkType: hard +"open@npm:^11.0.0": + version: 11.0.0 + resolution: "open@npm:11.0.0" + dependencies: + default-browser: "npm:^5.4.0" + define-lazy-prop: "npm:^3.0.0" + is-in-ssh: "npm:^1.0.0" + is-inside-container: "npm:^1.0.0" + powershell-utils: "npm:^0.1.0" + wsl-utils: "npm:^0.3.0" + checksum: 10c0/7aeeda4131268ed90f90e7728dda5c46bb0c6205b27a4be3e86ea33593e30dd393423e20e31c00802a8e635ef59becaee33ef9749a8ceb027567cd253e9e7b1e + languageName: node + linkType: hard + +"open@npm:^8.4.0": + version: 8.4.2 + resolution: "open@npm:8.4.2" + dependencies: + define-lazy-prop: "npm:^2.0.0" + is-docker: "npm:^2.1.1" + is-wsl: "npm:^2.2.0" + checksum: 10c0/bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 + languageName: node + linkType: hard + "optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" @@ -11293,6 +13505,13 @@ __metadata: languageName: node linkType: hard +"os-shim@npm:^0.1.2": + version: 0.1.3 + resolution: "os-shim@npm:0.1.3" + checksum: 10c0/eaa09098c0f6a3115b2d0c027927cba9c2706e362b7767021b7ac83d159f18806ac1e95786b496d1912ce1aea8a6866e526d3f18f075c7c719eb08a0ffb9177f + languageName: node + linkType: hard + "os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" @@ -11433,6 +13652,18 @@ __metadata: languageName: node linkType: hard +"package-json@npm:^10.0.0": + version: 10.0.1 + resolution: "package-json@npm:10.0.1" + dependencies: + ky: "npm:^1.2.0" + registry-auth-token: "npm:^5.0.2" + registry-url: "npm:^6.0.1" + semver: "npm:^7.6.0" + checksum: 10c0/4a55648d820496326730a7b149fd3fd8382e96f3d6def5ec687f46b75063894acf06b21f79832b40bb094c821d97f532cb0f009f85c4102d0084b488d4f492d3 + languageName: node + linkType: hard + "pako@npm:^2.1.0": version: 2.1.0 resolution: "pako@npm:2.1.0" @@ -11440,7 +13671,7 @@ __metadata: languageName: node linkType: hard -"pako@npm:~1.0.5": +"pako@npm:~1.0.2, pako@npm:~1.0.5": version: 1.0.11 resolution: "pako@npm:1.0.11" checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe @@ -11478,6 +13709,19 @@ __metadata: languageName: node linkType: hard +"parse-json@npm:7.1.1": + version: 7.1.1 + resolution: "parse-json@npm:7.1.1" + dependencies: + "@babel/code-frame": "npm:^7.21.4" + error-ex: "npm:^1.3.2" + json-parse-even-better-errors: "npm:^3.0.0" + lines-and-columns: "npm:^2.0.3" + type-fest: "npm:^3.8.0" + checksum: 10c0/a85ebc7430af7763fa52eb456d7efd35c35be5b06f04d8d80c37d0d33312ac6cdff12647acb9c95448dcc8b907dfafa81fb126e094aa132b0abc2a71b9df51d5 + languageName: node + linkType: hard + "parse-json@npm:^2.2.0": version: 2.2.0 resolution: "parse-json@npm:2.2.0" @@ -11602,7 +13846,7 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^2.0.3": +"pathe@npm:^2.0.1, pathe@npm:^2.0.3": version: 2.0.3 resolution: "pathe@npm:2.0.3" checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1 @@ -11644,6 +13888,13 @@ __metadata: languageName: node linkType: hard +"perfect-debounce@npm:^2.1.0": + version: 2.1.0 + resolution: "perfect-debounce@npm:2.1.0" + checksum: 10c0/c4f833816f249129cea996d60b1351b640cf06954ab4eecaca440234ef70f4aefe6483637049750f5b00e15a5036307ea77f831c9779d6ad878457680af49b6d + languageName: node + linkType: hard + "pg-cloudflare@npm:^1.3.0": version: 1.3.0 resolution: "pg-cloudflare@npm:1.3.0" @@ -11746,6 +13997,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.4": + version: 4.0.4 + resolution: "picomatch@npm:4.0.4" + checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 + languageName: node + linkType: hard + "pify@npm:^2.0.0": version: 2.3.0 resolution: "pify@npm:2.3.0" @@ -11822,6 +14080,27 @@ __metadata: languageName: node linkType: hard +"pino@npm:9.7.0": + version: 9.7.0 + resolution: "pino@npm:9.7.0" + dependencies: + atomic-sleep: "npm:^1.0.0" + fast-redact: "npm:^3.1.1" + on-exit-leak-free: "npm:^2.1.0" + pino-abstract-transport: "npm:^2.0.0" + pino-std-serializers: "npm:^7.0.0" + process-warning: "npm:^5.0.0" + quick-format-unescaped: "npm:^4.0.3" + real-require: "npm:^0.2.0" + safe-stable-stringify: "npm:^2.3.1" + sonic-boom: "npm:^4.0.1" + thread-stream: "npm:^3.0.0" + bin: + pino: bin.js + checksum: 10c0/c7f8a83a9a9d728b4eff6d0f4b9367f031c91bcaa5806fbf0eedcc8e77faba593d59baf11a8fba0dd1c778bb17ca7ed01418ac1df4ec129faeedd4f3ecaff66f + languageName: node + linkType: hard + "pino@npm:^9.5.0": version: 9.14.0 resolution: "pino@npm:9.14.0" @@ -11852,6 +14131,28 @@ __metadata: languageName: node linkType: hard +"pkg-types@npm:^1.3.1": + version: 1.3.1 + resolution: "pkg-types@npm:1.3.1" + dependencies: + confbox: "npm:^0.1.8" + mlly: "npm:^1.7.4" + pathe: "npm:^2.0.1" + checksum: 10c0/19e6cb8b66dcc66c89f2344aecfa47f2431c988cfa3366bdfdcfb1dd6695f87dcce37fbd90fe9d1605e2f4440b77f391e83c23255347c35cf84e7fd774d7fcea + languageName: node + linkType: hard + +"pkg-types@npm:^2.3.0, pkg-types@npm:^2.3.1": + version: 2.3.1 + resolution: "pkg-types@npm:2.3.1" + dependencies: + confbox: "npm:^0.2.4" + exsolve: "npm:^1.0.8" + pathe: "npm:^2.0.3" + checksum: 10c0/dd9b20682426abaddcac9dc786aa22542e12df15a03dea2afa7bf54da0933358c6c7f545c0c3c1c7b24a2904ab4a451bf4e34a50c6837e458359eea30c257ed4 + languageName: node + linkType: hard + "plist@npm:^3.0.0, plist@npm:^3.0.5, plist@npm:^3.1.0": version: 3.1.0 resolution: "plist@npm:3.1.0" @@ -11881,6 +14182,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:^8.5.10": + version: 8.5.12 + resolution: "postcss@npm:8.5.12" + dependencies: + nanoid: "npm:^3.3.11" + picocolors: "npm:^1.1.1" + source-map-js: "npm:^1.2.1" + checksum: 10c0/5baebaf574c567bc1b3d61197f38af4ce5920b8f611c887fb6bc3dcc14af00253c169dbf19897bc889cce0b0d9818ab5eb4ea0caedf02b0bab10da8a43ce8c12 + languageName: node + linkType: hard + "postgres-array@npm:~2.0.0": version: 2.0.0 resolution: "postgres-array@npm:2.0.0" @@ -11922,6 +14234,13 @@ __metadata: languageName: node linkType: hard +"powershell-utils@npm:^0.1.0": + version: 0.1.0 + resolution: "powershell-utils@npm:0.1.0" + checksum: 10c0/a64713cf3583259c9ed6be211c06b4b19e8608bcb0f7f6287ffac0a95b8c7582b6b662eea0e201fd659492c8e9f9c5fd0bfc4579645c5add9c1a600075621c95 + languageName: node + linkType: hard + "prebuild-install@npm:^7.1.1": version: 7.1.3 resolution: "prebuild-install@npm:7.1.3" @@ -12036,6 +14355,25 @@ __metadata: languageName: node linkType: hard +"promise-toolbox@npm:0.21.0": + version: 0.21.0 + resolution: "promise-toolbox@npm:0.21.0" + dependencies: + make-error: "npm:^1.3.2" + checksum: 10c0/f1de739b200113f17b49017d8de43c4f2d579a60fbf696201e9ae68a3b78d4d4d9f7777ebbc3745f0c427bd6f065aec6a40b98d1a4351807d165d15281b8a3a9 + languageName: node + linkType: hard + +"prompts@npm:^2.4.2": + version: 2.4.2 + resolution: "prompts@npm:2.4.2" + dependencies: + kleur: "npm:^3.0.3" + sisteransi: "npm:^1.0.5" + checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 + languageName: node + linkType: hard + "prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" @@ -12047,6 +14385,13 @@ __metadata: languageName: node linkType: hard +"proto-list@npm:~1.2.1": + version: 1.2.4 + resolution: "proto-list@npm:1.2.4" + checksum: 10c0/b9179f99394ec8a68b8afc817690185f3b03933f7b46ce2e22c1930dc84b60d09f5ad222beab4e59e58c6c039c7f7fcf620397235ef441a356f31f9744010e12 + languageName: node + linkType: hard + "protobufjs@npm:^7.3.0": version: 7.5.4 resolution: "protobufjs@npm:7.5.4" @@ -12088,6 +14433,25 @@ __metadata: languageName: node linkType: hard +"publish-browser-extension@npm:^2.3.0 || ^3.0.2 || ^4.0.4": + version: 4.0.5 + resolution: "publish-browser-extension@npm:4.0.5" + dependencies: + cac: "npm:^6.7.14" + consola: "npm:^3.4.2" + dotenv: "npm:^17.2.4" + form-data-encoder: "npm:^4.1.0" + formdata-node: "npm:^6.0.3" + jsonwebtoken: "npm:^9.0.3" + listr2: "npm:^10.1.0" + ofetch: "npm:^1.5.1" + zod: "npm:3.25.76 || ^4.3.6" + bin: + publish-extension: bin/publish-extension.mjs + checksum: 10c0/290195f5b04beecf54d840d36d1cf77da47f88f15e575ced759b8f49c70168b6d8d807a958a7012cbd70f15e31dd4dca82e6cfc9eebeaa97311a77996e77ef43 + languageName: node + linkType: hard + "pump@npm:^3.0.0": version: 3.0.4 resolution: "pump@npm:3.0.4" @@ -12112,6 +14476,15 @@ __metadata: languageName: node linkType: hard +"pupa@npm:^3.1.0": + version: 3.3.0 + resolution: "pupa@npm:3.3.0" + dependencies: + escape-goat: "npm:^4.0.0" + checksum: 10c0/9707e0a7f00e5922d47527d1c8d88d4224b1e86502da2fca27943eb0e9bb218121c91fa0af6c30531a2ee5ade0c326b5d33c40fdf61bc593c4224027412fd9b7 + languageName: node + linkType: hard + "qr.js@npm:0.0.0": version: 0.0.0 resolution: "qr.js@npm:0.0.0" @@ -12128,6 +14501,13 @@ __metadata: languageName: node linkType: hard +"quansync@npm:^0.2.11": + version: 0.2.11 + resolution: "quansync@npm:0.2.11" + checksum: 10c0/cb9a1f8ebce074069f2f6a78578873ffedd9de9f6aa212039b44c0870955c04a71c3b1311b5d97f8ac2f2ec476de202d0a5c01160cb12bc0a11b7ef36d22ef56 + languageName: node + linkType: hard + "querystring-es3@npm:^0.2.1": version: 0.2.1 resolution: "querystring-es3@npm:0.2.1" @@ -12187,7 +14567,17 @@ __metadata: languageName: node linkType: hard -"rc@npm:^1.2.7": +"rc9@npm:^3.0.1": + version: 3.0.1 + resolution: "rc9@npm:3.0.1" + dependencies: + defu: "npm:^6.1.6" + destr: "npm:^2.0.5" + checksum: 10c0/f952f80a6008b1be8b89f06cfec83ecc948aceb4ec4fabc25144bc0fa88aa601beb838d86720ae2c623971c4643cfea272535d6df15e40055082a4b6e4a24277 + languageName: node + linkType: hard + +"rc@npm:1.2.8, rc@npm:^1.2.7": version: 1.2.8 resolution: "rc@npm:1.2.8" dependencies: @@ -12239,6 +14629,13 @@ __metadata: languageName: node linkType: hard +"react-refresh@npm:^0.17.0": + version: 0.17.0 + resolution: "react-refresh@npm:0.17.0" + checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c + languageName: node + linkType: hard + "react-transition-group@npm:^4.4.5": version: 4.4.5 resolution: "react-transition-group@npm:4.4.5" @@ -12295,7 +14692,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.0, readable-stream@npm:^2.1.4, readable-stream@npm:^2.3.8": +"readable-stream@npm:^2.0.0, readable-stream@npm:^2.1.4, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -12321,6 +14718,13 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:^5.0.0": + version: 5.0.0 + resolution: "readdirp@npm:5.0.0" + checksum: 10c0/faf1ec57cff2020f473128da3f8d2a57813cc3a08a36c38cae1c9af32c1579906cc50ba75578043b35bade77e945c098233665797cf9730ba3613a62d6e79219 + languageName: node + linkType: hard + "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -12383,6 +14787,24 @@ __metadata: languageName: node linkType: hard +"registry-auth-token@npm:^5.0.2": + version: 5.1.1 + resolution: "registry-auth-token@npm:5.1.1" + dependencies: + "@pnpm/npm-conf": "npm:^3.0.2" + checksum: 10c0/86b0f7fd87d327cb4177fee69bcf96563147ea72e206bc9c7a6a50a51c785a31b83a6c45956a489ed292d23b908b2755a075d0b2f7fec1ba91b1fb800b24cee3 + languageName: node + linkType: hard + +"registry-url@npm:^6.0.1": + version: 6.0.1 + resolution: "registry-url@npm:6.0.1" + dependencies: + rc: "npm:1.2.8" + checksum: 10c0/66e2221c8113fc35ee9d23fe58cb516fc8d556a189fb8d6f1011a02efccc846c4c9b5075b4027b99a5d5c9ad1345ac37f297bea3c0ca30d607ec8084bf561b90 + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -12482,6 +14904,16 @@ __metadata: languageName: node linkType: hard +"restore-cursor@npm:^5.0.0": + version: 5.1.0 + resolution: "restore-cursor@npm:5.1.0" + dependencies: + onetime: "npm:^7.0.0" + signal-exit: "npm:^4.1.0" + checksum: 10c0/c2ba89131eea791d1b25205bdfdc86699767e2b88dee2a590b1a6caa51737deac8bad0260a5ded2f7c074b7db2f3a626bcf1fcf3cdf35974cbeea5e2e6764f60 + languageName: node + linkType: hard + "retry-request@npm:^7.0.0": version: 7.0.2 resolution: "retry-request@npm:7.0.2" @@ -12514,7 +14946,7 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.3.0": +"rfdc@npm:^1.3.0, rfdc@npm:^1.4.1": version: 1.4.1 resolution: "rfdc@npm:1.4.1" checksum: 10c0/4614e4292356cafade0b6031527eea9bc90f2372a22c012313be1dcc69a3b90c7338158b414539be863fa95bfcb2ddcd0587be696841af4e6679d85e62c060c7 @@ -12567,6 +14999,64 @@ __metadata: languageName: node linkType: hard +"rolldown@npm:1.0.0-rc.17": + version: 1.0.0-rc.17 + resolution: "rolldown@npm:1.0.0-rc.17" + dependencies: + "@oxc-project/types": "npm:=0.127.0" + "@rolldown/binding-android-arm64": "npm:1.0.0-rc.17" + "@rolldown/binding-darwin-arm64": "npm:1.0.0-rc.17" + "@rolldown/binding-darwin-x64": "npm:1.0.0-rc.17" + "@rolldown/binding-freebsd-x64": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.0-rc.17" + "@rolldown/binding-linux-x64-musl": "npm:1.0.0-rc.17" + "@rolldown/binding-openharmony-arm64": "npm:1.0.0-rc.17" + "@rolldown/binding-wasm32-wasi": "npm:1.0.0-rc.17" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.0-rc.17" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.0-rc.17" + "@rolldown/pluginutils": "npm:1.0.0-rc.17" + dependenciesMeta: + "@rolldown/binding-android-arm64": + optional: true + "@rolldown/binding-darwin-arm64": + optional: true + "@rolldown/binding-darwin-x64": + optional: true + "@rolldown/binding-freebsd-x64": + optional: true + "@rolldown/binding-linux-arm-gnueabihf": + optional: true + "@rolldown/binding-linux-arm64-gnu": + optional: true + "@rolldown/binding-linux-arm64-musl": + optional: true + "@rolldown/binding-linux-ppc64-gnu": + optional: true + "@rolldown/binding-linux-s390x-gnu": + optional: true + "@rolldown/binding-linux-x64-gnu": + optional: true + "@rolldown/binding-linux-x64-musl": + optional: true + "@rolldown/binding-openharmony-arm64": + optional: true + "@rolldown/binding-wasm32-wasi": + optional: true + "@rolldown/binding-win32-arm64-msvc": + optional: true + "@rolldown/binding-win32-x64-msvc": + optional: true + bin: + rolldown: bin/cli.mjs + checksum: 10c0/bb99abc62ece4e34edd06d2b8eb9ffb7194dc2f0465a4329bb106cbde3006a10f1575e3580b198b793341109a2109581aed623c537c12b0c3a4ba0d72169b2fb + languageName: node + linkType: hard + "rollup@npm:^4.20.0, rollup@npm:^4.43.0": version: 4.59.0 resolution: "rollup@npm:4.59.0" @@ -12657,6 +15147,13 @@ __metadata: languageName: node linkType: hard +"run-applescript@npm:^7.0.0": + version: 7.1.0 + resolution: "run-applescript@npm:7.1.0" + checksum: 10c0/ab826c57c20f244b2ee807704b1ef4ba7f566aa766481ae5922aac785e2570809e297c69afcccc3593095b538a8a77d26f2b2e9a1d9dffee24e0e039502d1a03 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -12728,6 +15225,13 @@ __metadata: languageName: node linkType: hard +"sax@npm:>=0.6.0": + version: 1.6.0 + resolution: "sax@npm:1.6.0" + checksum: 10c0/e5593f4a91eb25761a688c4d96902e4e95a0dd6017bc65146b6f21236e3d715cf893333b76bc758923c9574c2fb5a7a76c3a81e96ea15432f2624f906c027c1e + languageName: node + linkType: hard + "scheduler@npm:^0.23.2": version: 0.23.2 resolution: "scheduler@npm:0.23.2" @@ -12749,6 +15253,13 @@ __metadata: languageName: node linkType: hard +"scule@npm:^1.3.0": + version: 1.3.0 + resolution: "scule@npm:1.3.0" + checksum: 10c0/5d1736daa10622c420f2aa74e60d3c722e756bfb139fa784ae5c66669fdfe92932d30ed5072e4ce3107f9c3053e35ad73b2461cb18de45b867e1d4dea63f8823 + languageName: node + linkType: hard + "secure-json-parse@npm:^4.0.0": version: 4.1.0 resolution: "secure-json-parse@npm:4.1.0" @@ -12781,7 +15292,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.1, semver@npm:^7.1.3, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.7.3": +"semver@npm:^7.1.1, semver@npm:^7.1.3, semver@npm:^7.2.1, semver@npm:^7.3.2, semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3, semver@npm:^7.7.3": version: 7.7.4 resolution: "semver@npm:7.7.4" bin: @@ -12845,7 +15356,17 @@ __metadata: languageName: node linkType: hard -"setimmediate@npm:^1.0.4": +"set-value@npm:4.1.0": + version: 4.1.0 + resolution: "set-value@npm:4.1.0" + dependencies: + is-plain-object: "npm:^2.0.4" + is-primitive: "npm:^3.0.1" + checksum: 10c0/dc186676b6cc0cfcf1656b8acdfe7a68591f0645dd2872250100817fb53e5e9298dc1727a95605ac03f82110e9b3820c90a0a02d84e0fb89f210922b08b37e02 + languageName: node + linkType: hard + +"setimmediate@npm:^1.0.4, setimmediate@npm:^1.0.5": version: 1.0.5 resolution: "setimmediate@npm:1.0.5" checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49 @@ -12923,6 +15444,20 @@ __metadata: languageName: node linkType: hard +"shell-quote@npm:1.7.3": + version: 1.7.3 + resolution: "shell-quote@npm:1.7.3" + checksum: 10c0/cf997c325f49c4393a859074f1ee9ca3da7d9e1940225bab24a86f0266504c7d7e356b83f13c74932cb243d53125b5c8c57b714017c53490bf1fe10540422014 + languageName: node + linkType: hard + +"shellwords@npm:^0.1.1": + version: 0.1.1 + resolution: "shellwords@npm:0.1.1" + checksum: 10c0/7d66b28927e0b524b71b2e185651fcd88a70473a077dd230fbf86188380e948ffb36cea00832d78fc13c93cd15f6f52286fb05f2746b7580623ca1ec619eb004 + languageName: node + linkType: hard + "side-channel-list@npm:^1.0.0": version: 1.0.0 resolution: "side-channel-list@npm:1.0.0" @@ -13010,6 +15545,13 @@ __metadata: languageName: node linkType: hard +"sisteransi@npm:^1.0.5": + version: 1.0.5 + resolution: "sisteransi@npm:1.0.5" + checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 + languageName: node + linkType: hard + "slice-ansi@npm:^5.0.0": version: 5.0.0 resolution: "slice-ansi@npm:5.0.0" @@ -13020,6 +15562,26 @@ __metadata: languageName: node linkType: hard +"slice-ansi@npm:^7.1.0": + version: 7.1.2 + resolution: "slice-ansi@npm:7.1.2" + dependencies: + ansi-styles: "npm:^6.2.1" + is-fullwidth-code-point: "npm:^5.0.0" + checksum: 10c0/36742f2eb0c03e2e81a38ed14d13a64f7b732fe38c3faf96cce0599788a345011e840db35f1430ca606ea3f8db2abeb92a8d25c2753a819e3babaa10c2e289a2 + languageName: node + linkType: hard + +"slice-ansi@npm:^8.0.0": + version: 8.0.0 + resolution: "slice-ansi@npm:8.0.0" + dependencies: + ansi-styles: "npm:^6.2.3" + is-fullwidth-code-point: "npm:^5.1.0" + checksum: 10c0/0ce4aa91febb7cea4a00c2c27bb820fa53b6d2862ce0f80f7120134719f7914fc416b0ed966cf35250a3169e152916392f35917a2d7cad0fcc5d8b841010fa9a + languageName: node + linkType: hard + "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -13075,7 +15637,7 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.13, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.20": +"source-map-support@npm:0.5.21, source-map-support@npm:^0.5.13, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: @@ -13099,6 +15661,23 @@ __metadata: languageName: node linkType: hard +"source-map@npm:^0.7.4": + version: 0.7.6 + resolution: "source-map@npm:0.7.6" + checksum: 10c0/59f6f05538539b274ba771d2e9e32f6c65451982510564438e048bc1352f019c6efcdc6dd07909b1968144941c14015c2c7d4369fb7c4d7d53ae769716dcc16c + languageName: node + linkType: hard + +"spawn-sync@npm:1.0.15": + version: 1.0.15 + resolution: "spawn-sync@npm:1.0.15" + dependencies: + concat-stream: "npm:^1.4.7" + os-shim: "npm:^0.1.2" + checksum: 10c0/7c4b626a075940c7ffccbcf612a0ff88316fdb2266be40a824e90e60092278025f055e6f9895eae45ff828bae0add181cc88c70e6c32ca3ee38823110055f6eb + languageName: node + linkType: hard + "spdx-correct@npm:^3.0.0": version: 3.2.0 resolution: "spdx-correct@npm:3.2.0" @@ -13140,6 +15719,15 @@ __metadata: languageName: node linkType: hard +"split@npm:~1.0.1": + version: 1.0.1 + resolution: "split@npm:1.0.1" + dependencies: + through: "npm:2" + checksum: 10c0/7f489e7ed5ff8a2e43295f30a5197ffcb2d6202c9cf99357f9690d645b19c812bccf0be3ff336fea5054cda17ac96b91d67147d95dbfc31fbb5804c61962af85 + languageName: node + linkType: hard + "sprintf-js@npm:^1.1.2": version: 1.1.3 resolution: "sprintf-js@npm:1.1.3" @@ -13279,6 +15867,27 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.0.0, string-width@npm:^7.2.0": + version: 7.2.0 + resolution: "string-width@npm:7.2.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9 + languageName: node + linkType: hard + +"string-width@npm:^8.2.0": + version: 8.2.1 + resolution: "string-width@npm:8.2.1" + dependencies: + get-east-asian-width: "npm:^1.5.0" + strip-ansi: "npm:^7.1.2" + checksum: 10c0/d467b4eaf4c40a01bb438a2620e77badd2456ffd5131c9973abe4f3acf7c802d5b21f3b6a00a5e33a7fc28ca8f9c103226e01bac61e9f259659c6f46d78e353a + languageName: node + linkType: hard + "string.prototype.trim@npm:^1.2.10": version: 1.2.10 resolution: "string.prototype.trim@npm:1.2.10" @@ -13344,7 +15953,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0, strip-ansi@npm:^7.1.2": version: 7.2.0 resolution: "strip-ansi@npm:7.2.0" dependencies: @@ -13353,6 +15962,13 @@ __metadata: languageName: node linkType: hard +"strip-bom@npm:5.0.0": + version: 5.0.0 + resolution: "strip-bom@npm:5.0.0" + checksum: 10c0/f87e212f8a41e08e77d3994b3d9c4112258bd3a13688f9c7c85a6705a87a8e526422bce0762326cc2d9655c32a8c0ff1a2b14936795384c353828e4637823bc6 + languageName: node + linkType: hard + "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -13374,6 +15990,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:5.0.2": + version: 5.0.2 + resolution: "strip-json-comments@npm:5.0.2" + checksum: 10c0/e9841b8face78a01b0eb66f81e0a3419186a96f1d26817a5e1f5260b0631c10e0a7f711dddc5988edf599e5c079e4dd6e91defd21523e556636ba5679786f5ac + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -13395,7 +16018,7 @@ __metadata: languageName: node linkType: hard -"strip-literal@npm:^3.0.0": +"strip-literal@npm:^3.0.0, strip-literal@npm:^3.1.0": version: 3.1.0 resolution: "strip-literal@npm:3.1.0" dependencies: @@ -13420,6 +16043,22 @@ __metadata: languageName: node linkType: hard +"stubborn-fs@npm:^2.0.0": + version: 2.0.0 + resolution: "stubborn-fs@npm:2.0.0" + dependencies: + stubborn-utils: "npm:^1.0.1" + checksum: 10c0/31a60c9b2a61ce380b688f2649acaeff63cb0f2503bb6820c3ccd4f3af584c6310a48efa41b40c16b1717f1728572ed887c2c88650955c776a088228797e8d0e + languageName: node + linkType: hard + +"stubborn-utils@npm:^1.0.1": + version: 1.0.2 + resolution: "stubborn-utils@npm:1.0.2" + checksum: 10c0/e65c5820d02c993df55c88e938796c2fb2f3a6d3dc247c961d1e4be4d6d88c355283f4b74157e89d1a1a761d66b5ae79560a416384241a7d3b4e8ba8f1ff5a78 + languageName: node + linkType: hard + "stubs@npm:^3.0.0": version: 3.0.0 resolution: "stubs@npm:3.0.0" @@ -13635,6 +16274,13 @@ __metadata: languageName: node linkType: hard +"through@npm:2": + version: 2.3.8 + resolution: "through@npm:2.3.8" + checksum: 10c0/4b09f3774099de0d4df26d95c5821a62faee32c7e96fb1f4ebd54a2d7c11c57fe88b0a0d49cf375de5fee5ae6bf4eb56dbbf29d07366864e2ee805349970d3cc + languageName: node + linkType: hard + "timers-browserify@npm:^2.0.4": version: 2.0.12 resolution: "timers-browserify@npm:2.0.12" @@ -13665,6 +16311,13 @@ __metadata: languageName: node linkType: hard +"tinyexec@npm:^1.1.1": + version: 1.1.1 + resolution: "tinyexec@npm:1.1.1" + checksum: 10c0/48433cb32573a767e2b63bb92343cbbae4240d05a19a63f7869f9447491305e7bd82d11daccb79b2628b596ad703a25798226c50bfd1d8e63477fb42af6a5b35 + languageName: node + linkType: hard + "tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.14, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.9": version: 0.2.15 resolution: "tinyglobby@npm:0.2.15" @@ -13675,6 +16328,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.16": + version: 0.2.16 + resolution: "tinyglobby@npm:0.2.16" + dependencies: + fdir: "npm:^6.5.0" + picomatch: "npm:^4.0.4" + checksum: 10c0/f2e09fd93dd95c41e522113b686ff6f7c13020962f8698a864a257f3d7737599afc47722b7ab726e12f8a813f779906187911ff8ee6701ede65072671a7e934b + languageName: node + linkType: hard + "tinypool@npm:^1.1.1": version: 1.1.1 resolution: "tinypool@npm:1.1.1" @@ -13705,6 +16368,13 @@ __metadata: languageName: node linkType: hard +"tmp@npm:0.2.5, tmp@npm:^0.2.0": + version: 0.2.5 + resolution: "tmp@npm:0.2.5" + checksum: 10c0/cee5bb7d674bb4ba3ab3f3841c2ca7e46daeb2109eec395c1ec7329a91d52fcb21032b79ac25161a37b2565c4858fefab927af9735926a113ef7bac9091a6e0e + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -13714,13 +16384,6 @@ __metadata: languageName: node linkType: hard -"tmp@npm:^0.2.0": - version: 0.2.5 - resolution: "tmp@npm:0.2.5" - checksum: 10c0/cee5bb7d674bb4ba3ab3f3841c2ca7e46daeb2109eec395c1ec7329a91d52fcb21032b79ac25161a37b2565c4858fefab927af9735926a113ef7bac9091a6e0e - languageName: node - linkType: hard - "to-buffer@npm:^1.2.0, to-buffer@npm:^1.2.1, to-buffer@npm:^1.2.2": version: 1.2.2 resolution: "to-buffer@npm:1.2.2" @@ -13888,6 +16551,20 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^3.8.0": + version: 3.13.1 + resolution: "type-fest@npm:3.13.1" + checksum: 10c0/547d22186f73a8c04590b70dcf63baff390078c75ea8acd366bbd510fd0646e348bd1970e47ecf795b7cff0b41d26e9c475c1fedd6ef5c45c82075fbf916b629 + languageName: node + linkType: hard + +"type-fest@npm:^4.18.2, type-fest@npm:^4.21.0": + version: 4.41.0 + resolution: "type-fest@npm:4.41.0" + checksum: 10c0/f5ca697797ed5e88d33ac8f1fec21921839871f808dc59345c9cf67345bfb958ce41bd821165dbf3ae591cedec2bf6fe8882098dfdd8dc54320b859711a2c1e4 + languageName: node + linkType: hard + "type-is@npm:^1.6.16, type-is@npm:^1.6.18": version: 1.6.18 resolution: "type-is@npm:1.6.18" @@ -13951,6 +16628,13 @@ __metadata: languageName: node linkType: hard +"typedarray@npm:^0.0.6": + version: 0.0.6 + resolution: "typedarray@npm:0.0.6" + checksum: 10c0/6005cb31df50eef8b1f3c780eb71a17925f3038a100d82f9406ac2ad1de5eb59f8e6decbdc145b3a1f8e5836e17b0c0002fb698b9fe2516b8f9f9ff602d36412 + languageName: node + linkType: hard + "typescript-eslint@npm:^8.32.0": version: 8.56.1 resolution: "typescript-eslint@npm:8.56.1" @@ -14020,6 +16704,20 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.6.1, ufo@npm:^1.6.3": + version: 1.6.3 + resolution: "ufo@npm:1.6.3" + checksum: 10c0/bf0e4ebff99e54da1b9c7182ac2f40475988b41faa881d579bc97bc2a0509672107b0a0e94c4b8d31a0ab8c4bf07f4aa0b469ac6da8536d56bda5b085ea2e953 + languageName: node + linkType: hard + +"uhyphen@npm:^0.2.0": + version: 0.2.0 + resolution: "uhyphen@npm:0.2.0" + checksum: 10c0/1e7129fe7a5c86445d1adf04d5c58913b5992e4899ea5553d9ddf6e7ef88af0f807a47f1bf9673b92f705276e5cf1b2c1d3852f1ab5d08ecac3382bcc3a642f9 + languageName: node + linkType: hard + "unbox-primitive@npm:^1.1.0": version: 1.1.0 resolution: "unbox-primitive@npm:1.1.0" @@ -14055,6 +16753,33 @@ __metadata: languageName: node linkType: hard +"unimport@npm:^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0": + version: 6.2.0 + resolution: "unimport@npm:6.2.0" + dependencies: + acorn: "npm:^8.16.0" + escape-string-regexp: "npm:^5.0.0" + estree-walker: "npm:^3.0.3" + local-pkg: "npm:^1.1.2" + magic-string: "npm:^0.30.21" + mlly: "npm:^1.8.2" + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.4" + pkg-types: "npm:^2.3.1" + scule: "npm:^1.3.0" + strip-literal: "npm:^3.1.0" + tinyglobby: "npm:^0.2.16" + unplugin: "npm:^3.0.0" + unplugin-utils: "npm:^0.3.1" + peerDependencies: + oxc-parser: "*" + peerDependenciesMeta: + oxc-parser: + optional: true + checksum: 10c0/ea529143eaab4742eb3d211fcccb54f90b3d2a3f2e2400579192bf71b8ff3a5b4b9c9f1cae48a325bc90591ef600341bccef780ecd4e173981856044865c5770 + languageName: node + linkType: hard + "unique-filename@npm:^2.0.0": version: 2.0.1 resolution: "unique-filename@npm:2.0.1" @@ -14112,7 +16837,28 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.2.0": +"unplugin-utils@npm:^0.3.1": + version: 0.3.1 + resolution: "unplugin-utils@npm:0.3.1" + dependencies: + pathe: "npm:^2.0.3" + picomatch: "npm:^4.0.3" + checksum: 10c0/e563b15f2ae604d4f84ac664a7b1738585d2e82a068e59612589e61e555b3d93aa7379a4b6938df3788fe5658cae53d752dd72f6072bd4a642b6e0385c0e4eab + languageName: node + linkType: hard + +"unplugin@npm:^3.0.0": + version: 3.0.0 + resolution: "unplugin@npm:3.0.0" + dependencies: + "@jridgewell/remapping": "npm:^2.3.5" + picomatch: "npm:^4.0.3" + webpack-virtual-modules: "npm:^0.6.2" + checksum: 10c0/9b3a9eb7c1cfaab677160b9659b008b4562e08360b6c715f31bdd7692738a75de91f217931032ec247979f71e83d4c9b908245cf47d984b26fb318b60b1d2d36 + languageName: node + linkType: hard + +"update-browserslist-db@npm:^1.2.0, update-browserslist-db@npm:^1.2.3": version: 1.2.3 resolution: "update-browserslist-db@npm:1.2.3" dependencies: @@ -14126,6 +16872,24 @@ __metadata: languageName: node linkType: hard +"update-notifier@npm:7.3.1": + version: 7.3.1 + resolution: "update-notifier@npm:7.3.1" + dependencies: + boxen: "npm:^8.0.1" + chalk: "npm:^5.3.0" + configstore: "npm:^7.0.0" + is-in-ci: "npm:^1.0.0" + is-installed-globally: "npm:^1.0.0" + is-npm: "npm:^6.0.0" + latest-version: "npm:^9.0.0" + pupa: "npm:^3.1.0" + semver: "npm:^7.6.3" + xdg-basedir: "npm:^5.1.0" + checksum: 10c0/678839453840f46bb75e8cfebc0ff522262d2d3ece343fca722dd506039832e2a952d14ae39153f05f684467c8293ebc4c6479c9652c1bf97908fcaf300c2b31 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -14175,7 +16939,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^8.0.0": +"uuid@npm:^8.0.0, uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" bin: @@ -14246,6 +17010,21 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:^3.2.4 || ^5.0.0 || ^6.0.0": + version: 6.0.0 + resolution: "vite-node@npm:6.0.0" + dependencies: + cac: "npm:^7.0.0" + es-module-lexer: "npm:^2.0.0" + obug: "npm:^2.1.1" + pathe: "npm:^2.0.3" + vite: "npm:^8.0.0" + bin: + vite-node: dist/cli.mjs + checksum: 10c0/e586b17dcd6326dc746ba3f0655e6abaaece3b08c9570407cc24d3c238123679b43b05d37b57959afb05376e5b9cf152a0c62b0de8351c738c38cd042f4d7b14 + languageName: node + linkType: hard + "vite-plugin-node-polyfills@npm:^0.24.0": version: 0.24.0 resolution: "vite-plugin-node-polyfills@npm:0.24.0" @@ -14258,6 +17037,18 @@ __metadata: languageName: node linkType: hard +"vite-plugin-node-polyfills@npm:^0.26.0": + version: 0.26.0 + resolution: "vite-plugin-node-polyfills@npm:0.26.0" + dependencies: + "@rollup/plugin-inject": "npm:^5.0.5" + node-stdlib-browser: "npm:^1.3.1" + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: 10c0/31ce1a878519460c318ef58d6556878ce6a8692fbd125738390be9e15825bbf41792f2f89282f9bc21b2226ddcbe2e86383ec42391091bb4bb58a07e7d92b4c9 + languageName: node + linkType: hard + "vite-plugin-static-copy@npm:^3.1.2": version: 3.2.0 resolution: "vite-plugin-static-copy@npm:3.2.0" @@ -14327,6 +17118,63 @@ __metadata: languageName: node linkType: hard +"vite@npm:^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0, vite@npm:^8.0.0": + version: 8.0.10 + resolution: "vite@npm:8.0.10" + dependencies: + fsevents: "npm:~2.3.3" + lightningcss: "npm:^1.32.0" + picomatch: "npm:^4.0.4" + postcss: "npm:^8.5.10" + rolldown: "npm:1.0.0-rc.17" + tinyglobby: "npm:^0.2.16" + peerDependencies: + "@types/node": ^20.19.0 || >=22.12.0 + "@vitejs/devtools": ^0.1.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: ">=1.21.0" + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: ">=0.54.8" + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + "@vitejs/devtools": + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + bin: + vite: bin/vite.js + checksum: 10c0/92188b82654f856dbe562a1b679de695bb6ca18c0f43c4c276f84a869fb78e22dedb7c2df83b5617d6afdca979c059d654b5f61a0936a45f49917f352b9325ca + languageName: node + linkType: hard + "vite@npm:^5.4.20": version: 5.4.21 resolution: "vite@npm:5.4.21" @@ -14433,6 +17281,16 @@ __metadata: languageName: node linkType: hard +"watchpack@npm:2.4.4": + version: 2.4.4 + resolution: "watchpack@npm:2.4.4" + dependencies: + glob-to-regexp: "npm:^0.4.1" + graceful-fs: "npm:^4.1.2" + checksum: 10c0/6c0901f75ce245d33991225af915eea1c5ae4ba087f3aee2b70dd377d4cacb34bef02a48daf109da9d59b2d31ec6463d924a0d72f8618ae1643dd07b95de5275 + languageName: node + linkType: hard + "watchpack@npm:^2.5.1": version: 2.5.1 resolution: "watchpack@npm:2.5.1" @@ -14459,6 +17317,34 @@ __metadata: languageName: node linkType: hard +"web-ext-run@npm:^0.2.4": + version: 0.2.4 + resolution: "web-ext-run@npm:0.2.4" + dependencies: + "@babel/runtime": "npm:7.28.2" + "@devicefarmer/adbkit": "npm:3.3.8" + chrome-launcher: "npm:1.2.0" + debounce: "npm:1.2.1" + es6-error: "npm:4.1.1" + firefox-profile: "npm:4.7.0" + fx-runner: "npm:1.4.0" + multimatch: "npm:6.0.0" + node-notifier: "npm:10.0.1" + parse-json: "npm:7.1.1" + pino: "npm:9.7.0" + promise-toolbox: "npm:0.21.0" + set-value: "npm:4.1.0" + source-map-support: "npm:0.5.21" + strip-bom: "npm:5.0.0" + strip-json-comments: "npm:5.0.2" + tmp: "npm:0.2.5" + update-notifier: "npm:7.3.1" + watchpack: "npm:2.4.4" + zip-dir: "npm:2.0.0" + checksum: 10c0/ac902a8b8aff07dc44c56a779161579aadfe0e8eecd79d6034f7c46e00fa13c0b58d5e69fbce84afb091a531efdba660b4fbf248cfbcc0ad91c8fe424dc04227 + languageName: node + linkType: hard + "web-wallet@workspace:web": version: 0.0.0-use.local resolution: "web-wallet@workspace:web" @@ -14509,6 +17395,13 @@ __metadata: languageName: node linkType: hard +"webpack-virtual-modules@npm:^0.6.2": + version: 0.6.2 + resolution: "webpack-virtual-modules@npm:0.6.2" + checksum: 10c0/5ffbddf0e84bf1562ff86cf6fcf039c74edf09d78358a6904a09bbd4484e8bb6812dc385fe14330b715031892dcd8423f7a88278b57c9f5002c84c2860179add + languageName: node + linkType: hard + "webpack@npm:^5.69.1": version: 5.105.3 resolution: "webpack@npm:5.105.3" @@ -14557,6 +17450,20 @@ __metadata: languageName: node linkType: hard +"when-exit@npm:^2.1.4": + version: 2.1.5 + resolution: "when-exit@npm:2.1.5" + checksum: 10c0/7db41b28c98456b784c25780ca327653f233c6eb7b25d4ce251d04519828cbd609fb6d10548caf9031d4d6fab2999d6f6911c32e1731efab24c93a522573470d + languageName: node + linkType: hard + +"when@npm:3.7.7": + version: 3.7.7 + resolution: "when@npm:3.7.7" + checksum: 10c0/2385c08ea86e74060248acf607526e75addf64ad7c5bae5563a42b7afa2dbf181d7fd8a247f27fdb7ccac9768e765805489f47242f99082ece765805f5cb3e3d + languageName: node + linkType: hard + "which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": version: 1.1.1 resolution: "which-boxed-primitive@npm:1.1.1" @@ -14618,6 +17525,18 @@ __metadata: languageName: node linkType: hard +"which@npm:1.2.4": + version: 1.2.4 + resolution: "which@npm:1.2.4" + dependencies: + is-absolute: "npm:^0.1.7" + isexe: "npm:^1.1.1" + bin: + which: ./bin/which + checksum: 10c0/618944508e04fefa02fa811b1a68d8a27b4f712f2f8332c27ed8bf8d1dc7e469bb9bbe20b4e197311ce798c16bb96b5c5e32ceaf275a3b5388bd8144536f5247 + languageName: node + linkType: hard + "which@npm:^1.2.9": version: 1.3.1 resolution: "which@npm:1.3.1" @@ -14663,6 +17582,22 @@ __metadata: languageName: node linkType: hard +"widest-line@npm:^5.0.0": + version: 5.0.0 + resolution: "widest-line@npm:5.0.0" + dependencies: + string-width: "npm:^7.0.0" + checksum: 10c0/6bd6cca8cda502ef50e05353fd25de0df8c704ffc43ada7e0a9cf9a5d4f4e12520485d80e0b77cec8a21f6c3909042fcf732aa9281e5dbb98cc9384a138b2578 + languageName: node + linkType: hard + +"winreg@npm:0.0.12": + version: 0.0.12 + resolution: "winreg@npm:0.0.12" + checksum: 10c0/148b6aca1c3e88badd0d2b77ee0a71f1033e22e1cfcb41b71a5bba9e97cb3e7b6a2ec6b00cf0397959a13d65577d9173932588b3cd57b3f2e774b77ad14394ba + languageName: node + linkType: hard + "word-wrap@npm:^1.2.3, word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -14680,6 +17615,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^10.0.0": + version: 10.0.0 + resolution: "wrap-ansi@npm:10.0.0" + dependencies: + ansi-styles: "npm:^6.2.3" + string-width: "npm:^8.2.0" + strip-ansi: "npm:^7.1.2" + checksum: 10c0/6b163457630fe6d1c72aeed283a7410b2cc7487312df8b0ce96df3fbd64a2a7c948856ea97c25148c848627587c5c7945be474d8e723ab6011bb0756a53a9e89 + languageName: node + linkType: hard + "wrap-ansi@npm:^6.2.0": version: 6.2.0 resolution: "wrap-ansi@npm:6.2.0" @@ -14713,6 +17659,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^9.0.0": + version: 9.0.2 + resolution: "wrap-ansi@npm:9.0.2" + dependencies: + ansi-styles: "npm:^6.2.1" + string-width: "npm:^7.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/3305839b9a0d6fb930cb63a52f34d3936013d8b0682ff3ec133c9826512620f213800ffa19ea22904876d5b7e9a3c1f40682f03597d986a4ca881fa7b033688c + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -14750,6 +17707,91 @@ __metadata: languageName: node linkType: hard +"wsl-utils@npm:^0.3.0": + version: 0.3.1 + resolution: "wsl-utils@npm:0.3.1" + dependencies: + is-wsl: "npm:^3.1.0" + powershell-utils: "npm:^0.1.0" + checksum: 10c0/b3ba99cc6b71f66457eef598d529beeb8cb57a72646877fe25993894b808c60b82f6d47df5463f0b6e54632272f62f5eaea105c12784fd09b06f500f3f53aa2e + languageName: node + linkType: hard + +"wxt@npm:^0.20.6": + version: 0.20.25 + resolution: "wxt@npm:0.20.25" + dependencies: + "@1natsu/wait-element": "npm:^4.1.2" + "@aklinker1/rollup-plugin-visualizer": "npm:5.12.0" + "@webext-core/fake-browser": "npm:^1.3.4" + "@webext-core/isolated-element": "npm:^1.1.3" + "@webext-core/match-patterns": "npm:^1.0.3" + "@wxt-dev/browser": "npm:^0.1.40" + "@wxt-dev/storage": "npm:^1.0.0" + async-mutex: "npm:^0.5.0" + c12: "npm:^3.3.3" + cac: "npm:^6.7.14 || ^7.0.0" + chokidar: "npm:^5.0.0" + ci-info: "npm:^4.4.0" + consola: "npm:^3.4.2" + defu: "npm:^6.1.4" + dotenv-expand: "npm:^12.0.3" + esbuild: "npm:^0.27.1" + filesize: "npm:^11.0.15" + get-port-please: "npm:^3.2.0" + giget: "npm:^1.2.3 || ^2.0.0 || ^3.0.0" + hookable: "npm:^6.1.0" + import-meta-resolve: "npm:^4.2.0" + is-wsl: "npm:^3.1.1" + json5: "npm:^2.2.3" + jszip: "npm:^3.10.1" + linkedom: "npm:^0.18.12" + magicast: "npm:^0.5.2" + nano-spawn: "npm:^2.0.0" + nanospinner: "npm:^1.2.2" + normalize-path: "npm:^3.0.0" + nypm: "npm:^0.6.5" + ohash: "npm:^2.0.11" + open: "npm:^11.0.0" + perfect-debounce: "npm:^2.1.0" + picomatch: "npm:^4.0.3" + prompts: "npm:^2.4.2" + publish-browser-extension: "npm:^2.3.0 || ^3.0.2 || ^4.0.4" + scule: "npm:^1.3.0" + tinyglobby: "npm:^0.2.15" + unimport: "npm:^3.13.1 || ^4.0.0 || ^5.0.0 || ^6.0.0" + vite: "npm:^5.4.19 || ^6.3.4 || ^7.0.0 || ^8.0.0-0" + vite-node: "npm:^3.2.4 || ^5.0.0 || ^6.0.0" + web-ext-run: "npm:^0.2.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + bin: + wxt: bin/wxt.mjs + wxt-publish-extension: bin/wxt-publish-extension.mjs + checksum: 10c0/f40971f968b2a99456716972aad2243f81a28ef1e9f208ce89ddefa0d046e89bea3321bf91c29e94ae6f9f7e2d420213b0ef5a9ca5d365eda36e599fb386b75c + languageName: node + linkType: hard + +"xdg-basedir@npm:^5.1.0": + version: 5.1.0 + resolution: "xdg-basedir@npm:5.1.0" + checksum: 10c0/c88efabc71ffd996ba9ad8923a8cc1c7c020a03e2c59f0ffa72e06be9e724ad2a0fccef488757bc6ed3d8849d753dd25082d1035d95cb179e79eae4d034d0b80 + languageName: node + linkType: hard + +"xml2js@npm:^0.6.2": + version: 0.6.2 + resolution: "xml2js@npm:0.6.2" + dependencies: + sax: "npm:>=0.6.0" + xmlbuilder: "npm:~11.0.0" + checksum: 10c0/e98a84e9c172c556ee2c5afa0fc7161b46919e8b53ab20de140eedea19903ed82f7cd5b1576fb345c84f0a18da1982ddf65908129b58fc3d7cbc658ae232108f + languageName: node + linkType: hard + "xmlbuilder@npm:^15.1.1": version: 15.1.1 resolution: "xmlbuilder@npm:15.1.1" @@ -14757,6 +17799,13 @@ __metadata: languageName: node linkType: hard +"xmlbuilder@npm:~11.0.0": + version: 11.0.1 + resolution: "xmlbuilder@npm:11.0.1" + checksum: 10c0/74b979f89a0a129926bc786b913459bdbcefa809afaa551c5ab83f89b1915bdaea14c11c759284bb9b931e3b53004dbc2181e21d3ca9553eeb0b2a7b4e40c35b + languageName: node + linkType: hard + "xtend@npm:^4.0.0, xtend@npm:^4.0.2": version: 4.0.2 resolution: "xtend@npm:4.0.2" @@ -14771,6 +17820,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -14821,7 +17877,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^17.0.1, yargs@npm:~17.7.0": +"yargs@npm:^17.0.1, yargs@npm:^17.5.1, yargs@npm:~17.7.0": version: 17.7.2 resolution: "yargs@npm:17.7.2" dependencies: @@ -14867,6 +17923,23 @@ __metadata: languageName: node linkType: hard +"zip-dir@npm:2.0.0": + version: 2.0.0 + resolution: "zip-dir@npm:2.0.0" + dependencies: + async: "npm:^3.2.0" + jszip: "npm:^3.2.2" + checksum: 10c0/3bc6f84caeaaa19e7a65be01b5f042332eb09ec4a609d4ebebd93f854dfd2deb635f4b4486de224c6bdcb7e4e88b5e98792ffd14f1c58ce9b196061a83560be6 + languageName: node + linkType: hard + +"zod@npm:3.25.76 || ^4.3.6": + version: 4.3.6 + resolution: "zod@npm:4.3.6" + checksum: 10c0/860d25a81ab41d33aa25f8d0d07b091a04acb426e605f396227a796e9e800c44723ed96d0f53a512b57be3d1520f45bf69c0cb3b378a232a00787a2609625307 + languageName: node + linkType: hard + "zod@npm:^3.23.8": version: 3.25.76 resolution: "zod@npm:3.25.76"