From 8b6106b2c00dbc1ed3ffa4a223723eea6ce5dcb4 Mon Sep 17 00:00:00 2001 From: Alejandro Dopico Date: Wed, 28 Oct 2026 13:30:18 -0500 Subject: [PATCH 1/3] Add Crossmint Agent Checkouts with approved payments Two tools let Bell buy through Crossmint Agent Checkouts: crossmint_checkout starts a run from a product URL, a plain-language task and a spending cap, answers form questions and declines or cancels; crossmint_pay settles the payment request with the operator's order intent. Payment goes through Eve's tool approval rather than a confirmation in chat. crossmint_pay is declared with approval: always(), the prompt shows the amount, currency and merchant the model put in the call, and after approval the server compares those with the live Crossmint request and with the cap the run was created under before paying. Payments need an authenticated sender, and only the requesting principal can approve. Operator policy is checked before a run is created, so a refused request is never billed: an optional per-checkout ceiling (CROSSMINT_MAX_COST) and an optional merchant allowlist (CROSSMINT_ALLOWED_MERCHANTS). A saved buyer profile (CROSSMINT_BUYER_PROFILE_ID) lets checkouts skip shipping and contact questions. The API key, buyer id, buyer profile and order intent id stay on the server. Each snapshot is projected to a metadata allowlist before Eve can persist it, and a conversation can only act on runs it started in this process. Link, the browser runtime and the hooks are unchanged; with the Crossmint variables unset both tools return not_configured. --- .env.example | 11 + README.md | 1 + agent/instructions.md | 10 + agent/tools/crossmint_checkout.ts | 181 +++++++++ agent/tools/crossmint_pay.ts | 123 ++++++ docs/crossmint.md | 133 +++++++ docs/repository.md | 1 + server/crossmint/client.ts | 622 ++++++++++++++++++++++++++++++ server/crossmint/payment.ts | 91 +++++ server/crossmint/runs.ts | 41 ++ tests/crossmint.test.ts | 367 ++++++++++++++++++ 11 files changed, 1581 insertions(+) create mode 100644 agent/tools/crossmint_checkout.ts create mode 100644 agent/tools/crossmint_pay.ts create mode 100644 docs/crossmint.md create mode 100644 server/crossmint/client.ts create mode 100644 server/crossmint/payment.ts create mode 100644 server/crossmint/runs.ts create mode 100644 tests/crossmint.test.ts diff --git a/.env.example b/.env.example index dcd6a48..fcdc4a0 100644 --- a/.env.example +++ b/.env.example @@ -66,3 +66,14 @@ LINK_TOKEN_ENCRYPTION_KEY= # Exact trusted checkout/frame origins per approved merchant (JSON object). LINK_CHECKOUT_ORIGINS={} + +# Optional Crossmint Agent Checkouts. Production server key (sk_) with agent-checkouts.* scopes. +# See docs/crossmint.md. Leave unset to keep the tools disabled. +CROSSMINT_SERVER_API_KEY= +CROSSMINT_USER_ID= +# The operator's approved order intent id. Required only to pay; never shown to the model. +CROSSMINT_ORDER_INTENT_ID= +# Optional saved buyer profile, per-checkout ceiling ("50.00 EUR"), and exact merchant origins. +CROSSMINT_BUYER_PROFILE_ID= +CROSSMINT_MAX_COST= +CROSSMINT_ALLOWED_MERCHANTS= diff --git a/README.md b/README.md index f7457b7..ab9c12b 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ pnpm dev | Link by Stripe | Wallet authorization, spend approval, and checkout through Linq | [Sandbox and wallet setup](docs/link.md) | | 1Password | Operator credentials and OTP; personal Agentic Autofill is disabled by default | [Operator access](docs/browser-runtime.md#credentials-and-otp) ยท [Personal access status](docs/onepassword.md) | | Baselayer | Verified access to approved merchants using short-lived credentials | [Merchant access](docs/baselayer.md) | +| Crossmint | Checkout at any merchant under a spending cap, paid after the person approves the exact total | [Agent checkouts](docs/crossmint.md) | See the [repository layout and implementation map](docs/repository.md) to extend Bell. diff --git a/agent/instructions.md b/agent/instructions.md index 56ea2dc..b27068f 100644 --- a/agent/instructions.md +++ b/agent/instructions.md @@ -38,3 +38,13 @@ navigation needs a fresh proof. After access, call snapshot and screenshot to ve Do not claim a successful mint or merchant access unless the tool result confirms it. For private Linq senders, use `onepassword_connect`, `onepassword_status`, `onepassword_login`, and `onepassword_disconnect` for personal 1Password access. If status is disabled, explain that personal 1Password login is not available yet; do not offer a consent link or fall back to the operator vault. Never use the operator vault tools for a messaging sender. Connecting is separate from approving a website login. Use the exact login URL and a distinct expected success path on the same origin. A verified destination is not proof of account identity. The first version supports single-step sign-in only. Approval links are sent through Eve authorization; do not ask for tokens, integration keys, passwords, or OTPs in chat. If a private fill fails, start a new conversation rather than inspecting the blocked browser. Personal browser mode does not support reusable Contexts. + +Use crossmint_checkout when Crossmint Agent Checkouts is configured and the user wants a purchase +completed by Crossmint rather than in this conversation's browser. Start with the product URL, the +request, and the user's spending cap. Answer form questions from what the user said; never fill +protected fields. At a payment request, call crossmint_pay with the amount, currency, and merchant +copied from the request; Eve asks the person to approve, and the server verifies those values +against Crossmint before paying. Call crossmint_checkout decline if the person says no. Only a +succeeded result with purchase.kind receipt_captured is a placed order; report any other outcome as +what it is. Never start a second checkout for the same request while one is unresolved, and never +ask for or print API keys or order intent ids. diff --git a/agent/tools/crossmint_checkout.ts b/agent/tools/crossmint_checkout.ts new file mode 100644 index 0000000..fd94ca5 --- /dev/null +++ b/agent/tools/crossmint_checkout.ts @@ -0,0 +1,181 @@ +import { defineTool, toolOutput } from "eve/tools"; +import { z } from "zod"; + +import { + answerForm, + cancelCheckout, + createCheckout, + CrossmintPolicyError, + CrossmintRequestError, + CrossmintSetupError, + declineRequest, + getCheckout, + isCrossmintConfigured, + waitForCheckout, + type CheckoutSnapshot, +} from "../../server/crossmint/client"; +import { assertSessionCheckout, rememberCheckout } from "../../server/crossmint/runs"; + +const maxCost = z.object({ + amount: z + .string() + .regex(/^\d+(\.\d{1,2})?$/, "Decimal string such as 20.00") + .describe("Spending cap including shipping and tax, as a decimal string."), + currency: z.string().length(3).toUpperCase().describe("ISO 4217 code, such as USD or EUR."), +}); + +const runId = z.string().min(1).max(200); +const requestId = z.string().min(1).max(200); + +const inputSchema = z.discriminatedUnion("action", [ + z.object({ + action: z.literal("start"), + startUrl: z.string().url().max(2048).describe("Product or store page to start from."), + task: z + .string() + .min(1) + .max(20_000) + .describe("What to buy, in plain language: item, options, quantity, delivery."), + maxCost, + merchantGuidance: z + .string() + .max(20_000) + .optional() + .describe("Optional notes about this merchant's checkout."), + countryCode: z + .string() + .length(2) + .toUpperCase() + .optional() + .describe("Optional browser location for the checkout, such as ES or US."), + }), + z.object({ action: z.literal("status"), runId }), + z.object({ + action: z.literal("answer"), + runId, + requestId, + answers: z + .record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.array(z.string())])) + .describe("One value per form field key. Protected fields cannot be answered here."), + }), + z.object({ action: z.literal("decline"), runId, requestId }), + z.object({ action: z.literal("cancel"), runId }), +]); + +export type CheckoutToolOutput = + | { status: "not_configured"; hint: string } + | { status: "error"; reason: string; message: string } + | CheckoutSnapshot; + +export function errorOutput(error: unknown): CheckoutToolOutput { + if ( + error instanceof CrossmintSetupError || + error instanceof CrossmintRequestError || + error instanceof CrossmintPolicyError + ) { + return { status: "error", reason: error.reason, message: error.message }; + } + throw error; +} + +export const WAIT_MS = 90_000; + +export default defineTool({ + description: + "Buy from a merchant through Crossmint Agent Checkouts with a hard spending cap. Crossmint runs the checkout in its own service, not in this conversation's browser. Actions: start (product URL, plain-language task, maxCost), then follow requiredAction. For a form, call answer with one value per field key. For a payment request, call crossmint_pay; the person approves the exact amount there. decline refuses a request; cancel stops the run. Returns status snapshots only. A succeeded result whose purchase.kind is receipt_captured is the only proof of a placed order. Never start a second checkout for the same request while one is unresolved.", + inputSchema, + label: { + start: (input) => + input.action === "start" + ? `Starting a Crossmint checkout at ${new URL(input.startUrl).hostname}` + : `Crossmint checkout: ${input.action}`, + }, + async execute(input, ctx): Promise { + ctx.abortSignal.throwIfAborted(); + if (!isCrossmintConfigured()) { + return { + status: "not_configured", + hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md.", + }; + } + const sessionId = ctx.session.id; + const signal = ctx.abortSignal; + try { + switch (input.action) { + case "start": { + const { runId } = await createCheckout( + { + startUrl: input.startUrl, + task: input.task, + maxCost: input.maxCost, + ...(input.merchantGuidance ? { merchantGuidance: input.merchantGuidance } : {}), + ...(input.countryCode ? { countryCode: input.countryCode } : {}), + }, + { signal }, + ); + rememberCheckout(sessionId, { + runId, + maxCost: input.maxCost, + principalId: ctx.session.auth.current?.principalId ?? null, + }); + return await waitForCheckout(runId, { signal, timeoutMs: WAIT_MS }); + } + case "status": { + assertSessionCheckout(sessionId, input.runId); + return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS }); + } + case "answer": { + assertSessionCheckout(sessionId, input.runId); + const current = await getCheckout(input.runId, { signal }); + const action = current.requiredAction; + if (!action || action.requestId !== input.requestId) return current; + if (action.interaction.kind !== "form") { + return { + status: "error", + reason: "wrong_interaction", + message: "This request is not a form. Payment requests go through crossmint_pay.", + }; + } + const protectedKeys = new Set( + action.interaction.fields + .filter((field) => field.handling === "protected") + .map((field) => field.key), + ); + if (Object.keys(input.answers).some((key) => protectedKeys.has(key))) { + return { + status: "error", + reason: "protected_field", + message: + "Protected fields (codes, passwords, card data) cannot be answered through the model. Decline the request or ask the person to finish in Crossmint's hosted flow.", + }; + } + await answerForm(input.runId, input.requestId, input.answers, { signal }); + return await waitForCheckout(input.runId, { + signal, + timeoutMs: WAIT_MS, + skipRequestId: input.requestId, + }); + } + case "decline": { + assertSessionCheckout(sessionId, input.runId); + await declineRequest(input.runId, input.requestId, { signal }); + return await waitForCheckout(input.runId, { + signal, + timeoutMs: 30_000, + skipRequestId: input.requestId, + }); + } + case "cancel": { + assertSessionCheckout(sessionId, input.runId); + await cancelCheckout(input.runId, { signal }); + return await waitForCheckout(input.runId, { signal, timeoutMs: 30_000 }); + } + } + } catch (error) { + return errorOutput(error); + } + }, + toModelOutput(output) { + return toolOutput.json(output); + }, +}); diff --git a/agent/tools/crossmint_pay.ts b/agent/tools/crossmint_pay.ts new file mode 100644 index 0000000..8b28a0f --- /dev/null +++ b/agent/tools/crossmint_pay.ts @@ -0,0 +1,123 @@ +import { defineTool, toolOutput } from "eve/tools"; +import { always } from "eve/tools/approval"; +import { z } from "zod"; + +import { + CrossmintSetupError, + getCheckout, + isCrossmintConfigured, + payWithOrderIntent, + waitForCheckout, +} from "../../server/crossmint/client"; +import { assertPaymentMatches, PaymentMismatchError } from "../../server/crossmint/payment"; +import { assertSessionCheckout } from "../../server/crossmint/runs"; +import { errorOutput, WAIT_MS, type CheckoutToolOutput } from "./crossmint_checkout"; + +const inputSchema = z.object({ + runId: z.string().min(1).max(200), + requestId: z.string().min(1).max(200).describe("The open payment request's id."), + amount: z + .string() + .regex(/^\d+(\.\d{1,2})?$/) + .describe("The exact total Crossmint is asking for, copied from the payment request."), + currency: z.string().length(3).toUpperCase(), + merchant: z + .string() + .min(1) + .max(255) + .describe("The merchant URL or host from the payment request."), +}); + +type Input = z.infer; + +type PayOutput = + | CheckoutToolOutput + | { status: "payment_not_configured"; runId: string; requestId: string; hint: string }; + +export default defineTool({ + description: + "Pay an open Crossmint checkout payment request with the operator's order intent. Copy amount, currency, and merchant exactly from the payment request. Eve stops and asks the person to approve this call; the server then checks those three values against the live request and the checkout's cap before paying, and refuses on any difference. Requires an authenticated sender. Call once per payment request. Use crossmint_checkout decline if the person says no.", + inputSchema, + label: { + start: (input: Readonly) => + `Paying ${input.amount} ${input.currency} at ${input.merchant} through Crossmint`, + }, + approval: { + request: always(), + prompt: ({ input }) => + `Pay ${input.amount} ${input.currency} to ${input.merchant} with your Crossmint order intent?`, + response: ({ request, response }) => { + const requester = request.principal; + if (!requester) { + return { status: "rejected", reason: "Payments need an authenticated sender." }; + } + const same = + response.principal.principalId === requester.principalId && + response.principal.authenticator === requester.authenticator; + return same + ? { status: "allowed" } + : { status: "rejected", reason: "Only the person who requested this payment can approve it." }; + }, + }, + async execute(input, ctx): Promise { + ctx.abortSignal.throwIfAborted(); + if (!isCrossmintConfigured()) { + return { + status: "not_configured", + hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md.", + }; + } + const sessionId = ctx.session.id; + const signal = ctx.abortSignal; + const auth = ctx.session.auth.current; + if (!auth) { + return { + status: "error", + reason: "authentication_required", + message: "Payments are available to authenticated senders only. The anonymous web demo cannot pay.", + }; + } + try { + const record = assertSessionCheckout(sessionId, input.runId); + if (record.principalId !== null && record.principalId !== auth.principalId) { + return { + status: "error", + reason: "principal_mismatch", + message: "A different sender started this checkout.", + }; + } + const live = await getCheckout(input.runId, { signal }); + try { + assertPaymentMatches(input, live, record); + } catch (error) { + if (error instanceof PaymentMismatchError) { + return { status: "error", reason: error.reason, message: error.message }; + } + throw error; + } + try { + await payWithOrderIntent(input.runId, input.requestId, { signal }); + } catch (error) { + if (error instanceof CrossmintSetupError && error.setting === "CROSSMINT_ORDER_INTENT_ID") { + return { + status: "payment_not_configured", + runId: input.runId, + requestId: input.requestId, + hint: "No order intent is configured on the server, so Bell cannot pay. Decline the request and tell the person. See docs/crossmint.md.", + }; + } + throw error; + } + return await waitForCheckout(input.runId, { + signal, + timeoutMs: WAIT_MS, + skipRequestId: input.requestId, + }); + } catch (error) { + return errorOutput(error); + } + }, + toModelOutput(output) { + return toolOutput.json(output); + }, +}); diff --git a/docs/crossmint.md b/docs/crossmint.md new file mode 100644 index 0000000..98b4722 --- /dev/null +++ b/docs/crossmint.md @@ -0,0 +1,133 @@ +# Crossmint Agent Checkouts + +Bell's `crossmint_checkout` and `crossmint_pay` tools buy from a merchant through +[Crossmint Agent Checkouts](https://docs.crossmint.com/agents/checkouts/overview). One request +carries a product URL, a plain-language task, and a spending cap. Crossmint runs the checkout in +its own service and exposes it as a run with status snapshots. Payment comes from an order intent +the operator approved in Crossmint beforehand, funded by a Crossmint agent card, a card on file, or +an agent card from another provider such as Link. + +```text +Bell -> create run (URL, task, cap) -> Crossmint works through the merchant checkout + -> awaiting_input (form) -> Bell answers from the conversation + -> awaiting_input (payment) -> Eve asks the person to approve the exact total + -> server checks total, currency, merchant, cap -> pays + -> succeeded (receipt) -> Bell reports the order +``` + +The checkout does not use this conversation's Browserbase browser. Link, the browser runtime, and +the hooks are unchanged. With the Crossmint variables unset, both tools return `not_configured`. + +## Configure + +Server-only values in Bell's ignored `.env.local`: + +```dotenv +CROSSMINT_SERVER_API_KEY= +CROSSMINT_USER_ID= +# Optional until the first payment: the operator's approved order intent id. +CROSSMINT_ORDER_INTENT_ID= +# Optional. Saved buyer profile (name, email, shipping) so checkouts ask fewer questions. +CROSSMINT_BUYER_PROFILE_ID= +# Optional. Ceiling for any single checkout's cap, "amount currency". +CROSSMINT_MAX_COST=50.00 EUR +# Optional. Exact HTTPS origins a checkout may start from. Empty allows any merchant. +CROSSMINT_ALLOWED_MERCHANTS=https://shop.example +``` + +Create the key in the [Crossmint console](https://www.crossmint.com/console) with the +`agent-checkouts.create`, `.read`, `.update`, and `.cancel` scopes. Agent Checkouts run in +production only; a staging key returns `unauthorized`. Client keys (`ck_`) are rejected at startup. + +`CROSSMINT_USER_ID` identifies the buyer to Crossmint. Bell serves one trusted operator, so a fixed +value is enough; every run, order intent, and receipt is scoped to it. + +`CROSSMINT_ORDER_INTENT_ID` is the budget the operator approved in Crossmint: a saved card plus an +amount, merchant scope, and expiry. The [cards quickstart](https://docs.crossmint.com/agents/cards-quickstart) +walks through saving a card and approving an order intent. Only the `pay` path on the server reads +this id. Without it, checkouts run up to the payment step and `crossmint_pay` returns +`payment_not_configured`. + +`CROSSMINT_MAX_COST` and `CROSSMINT_ALLOWED_MERCHANTS` are checked before a run is created, so a +refused request is never billed. They bound what a prompt can ask for; the order intent still bounds +what can be paid. + +Restart Bell after changing these values. No database, migration, or browser setting is involved. + +## Use + +With `pnpm dev` running, in a web conversation or a Linq chat: + +1. "Buy one sticker pack from https://shop.example/products/sticker-pack, standard delivery, max + 20 USD." Bell starts the run and waits up to 90 seconds for the next step. +2. When Crossmint asks a form question (size, email, delivery option), Bell asks you and answers + with the `answer` action. Fields marked `protected` (one-time codes, passwords, card data) cannot + be answered through the model; Bell declines or asks you to finish in Crossmint's hosted flow. +3. At the payment step Bell calls `crossmint_pay` with the amount, currency, and merchant from the + request. Eve pauses and shows you an approval: "Pay 12.49 USD to shop.example with your + Crossmint order intent?" Approving runs the tool; cancelling does not. Only the authenticated + sender who asked for the purchase can approve. +4. `succeeded` with `purchase.kind: receipt_captured` carries `receipt.total` and + `receipt.merchantOrderId`. That is the only result Bell reports as a placed order. + `confirmed_without_receipt` and `nothing_placed` are reported as what they are. + +`blocked` returns a code such as `merchant.payment_declined`, `policy.max_cost_exceeded`, or +`product.item_unavailable`; `failed` returns a reason such as `cost_limit` or `input_expired`. Bell +reports these and does not retry on its own. `cancel` stops a run that is still in progress. + +Crossmint bills each run that starts, including runs that end `blocked`. Keep the cap tight and do +not start a second run for the same request while one is unresolved. + +## How payment is guarded + +Approval in chat is not the control. Eve's tool approval is: `crossmint_pay` is declared with +`approval: always()`, so the runtime stops before executing it and shows the person the amount, +currency, and merchant the model put in the call. After approval the server fetches the live +payment request from Crossmint and compares it with those three values and with the cap the run was +started under. Any difference, an expired or replaced request, a `maximum` instead of an `exact` +amount, or a run this conversation did not start refuses the payment and returns the reason. The +approval dialog shows the model's numbers; the cross-check makes sure they are Crossmint's numbers. + +Payments need an authenticated sender: a verified Linq number, the HTTP Basic operator, or local +development auth. The anonymous web demo can start and inspect runs but cannot pay, and the +approval response policy rejects anyone other than the principal who requested the call. + +## Transcript boundary + +Only a projection of each snapshot reaches the model: run id, status, revision, the open question +with its form fields or payment amount and merchant, and the result summary with receipt metadata. +Browser embed URLs, the echoed input, provider error bodies, and any unexpected field are dropped +before Eve can persist them. The API key, buyer id, buyer profile, and order intent id are read from +the server environment inside the tools and never appear in tool arguments or output. + +Runs are registered per conversation in process memory, like the Link sandbox request set. After a +restart or worker change an unfinished run cannot be resumed from chat; reconcile it in the +Crossmint console before starting another. + +Crossmint's and the merchant's own records are outside Bell's control. Transcripts still contain +the merchant, items, totals, and form answers, so apply your host's retention policy. + +## When to use this instead of Bell's browser + +For merchants that support an agentic commerce protocol, Agent Checkouts is a pure API call with no +browser session anywhere. For other merchants Crossmint runs its own browser and per-merchant +behavior in its service, so fixes land without a change in Bell. Bell's own browser tools and +`link__checkout` remain the path when the purchase has to happen inside this conversation's +Browserbase session, for example after Baselayer-verified access or in a saved Context. + +## Verify + +`pnpm check` runs mock provider tests: request shapes and headers against the documented API, +sanitized errors, the merchant allowlist and spending ceiling, snapshot projection including +protected fields and payment interactions, the payment cross-check with one case per refusal +reason, polling with an answered request skipped, the timeout and cancellation paths, and +per-conversation run isolation. No test calls Crossmint. + +For a live smoke test, set the key and buyer id, pick a merchant test checkout or an item under a +few dollars, and run the four steps above. Watch the run in the Crossmint console and compare the +receipt with the merchant's confirmation before trusting the flow for anything larger. + +References: [Agent Checkouts overview](https://docs.crossmint.com/agents/checkouts/overview), +[quickstart](https://docs.crossmint.com/agents/agent-checkouts-quickstart), +[pay for a checkout](https://docs.crossmint.com/agents/checkouts/payments), +[API reference](https://docs.crossmint.com/api-reference/agent-checkouts/create-agent-checkout). diff --git a/docs/repository.md b/docs/repository.md index f77d120..f75be39 100644 --- a/docs/repository.md +++ b/docs/repository.md @@ -33,6 +33,7 @@ lifecycle; channel callbacks also handle terminal-session cleanup. Restart Bell | Link by Stripe | [Eve extension and tools](../agent/extensions/link/), [authorization](../agent/lib/link-auth.ts), [server implementation](../server/link/) | [Sandbox and wallet setup](link.md) | | 1Password | [Operator SDK/CLI access](../server/browser/vault/onepassword.ts), [personal authorization](../agent/lib/onepassword-auth.ts), [personal server implementation](../server/onepassword/) | [Operator credentials](browser-runtime.md#credentials-and-otp), [personal access status](onepassword.md) | | Baselayer | [Agent tool](../agent/tools/merchant_access.ts), [credential minting](../server/baselayer.ts), [merchant verification](../server/verified-merchant.ts) | [Merchant access](baselayer.md) | +| Crossmint | [Checkout tool](../agent/tools/crossmint_checkout.ts), [approved payment tool](../agent/tools/crossmint_pay.ts), [server client](../server/crossmint/client.ts), [payment cross-check](../server/crossmint/payment.ts) | [Agent checkouts](crossmint.md) | Personal 1Password Agentic Autofill is implemented but disabled by default pending hosted extension support and live verification. Keep `ONEPASSWORD_ENABLED=false` and the extension ID unset as diff --git a/server/crossmint/client.ts b/server/crossmint/client.ts new file mode 100644 index 0000000..e2881a7 --- /dev/null +++ b/server/crossmint/client.ts @@ -0,0 +1,622 @@ +import { randomUUID } from "node:crypto"; + +/** + * Crossmint Agent Checkouts, server side. + * + * Crossmint runs the merchant checkout in its own service and exposes it as a run with status + * snapshots. Bell holds the API key, the buyer id, the optional buyer profile, and the order + * intent on the server. The model sees a projection of each snapshot and nothing else. + * API reference: https://docs.crossmint.com/api-reference/agent-checkouts + */ + +export class CrossmintSetupError extends Error { + constructor( + readonly reason: "missing_configuration" | "invalid_configuration", + readonly setting: string, + ) { + super(`Check ${setting} in the server configuration.`); + this.name = "CrossmintSetupError"; + } +} + +export type CrossmintRequestReason = + | "unauthorized" + | "not_found" + | "rate_limited" + | "transport" + | "invalid_response" + | "http_error"; + +export class CrossmintRequestError extends Error { + constructor( + readonly reason: CrossmintRequestReason, + readonly status?: number, + ) { + super( + reason === "unauthorized" + ? "Crossmint rejected the API key or its scopes." + : reason === "not_found" + ? "Crossmint has no checkout with that id for this buyer." + : reason === "rate_limited" + ? "Crossmint rate limited the request. Retry shortly." + : reason === "transport" + ? "Crossmint request failed. Check connectivity and retry." + : reason === "invalid_response" + ? "Crossmint returned an unexpected response." + : `Crossmint returned HTTP ${status}.`, + ); + this.name = "CrossmintRequestError"; + } +} + +/** A request the operator's policy refuses before it reaches Crossmint. */ +export class CrossmintPolicyError extends Error { + constructor( + readonly reason: "merchant_not_allowed" | "cap_exceeded" | "currency_mismatch", + message: string, + ) { + super(message); + this.name = "CrossmintPolicyError"; + } +} + +export interface MaxCost { + amount: string; + currency: string; +} + +export interface CrossmintConfig { + apiKey: string; + userId: string; + baseUrl: string; + /** Optional saved buyer profile (name, email, shipping) so checkouts ask fewer questions. */ + buyerProfileId?: string; + /** Optional ceiling on any single checkout's maxCost, enforced before the request is created. */ + maxCost?: MaxCost; + /** Optional exact HTTPS origins a checkout may start from. Empty allows any merchant. */ + allowedMerchants: string[]; + /** The operator's approved order intent, used to pay. Never exposed to the model. */ + orderIntentId?: string; +} + +export const DEFAULT_BASE_URL = "https://www.crossmint.com/api/unstable"; + +const DECIMAL = /^\d+(\.\d{1,2})?$/; +const CURRENCY = /^[A-Z]{3}$/; + +export function isCrossmintConfigured( + env: Record = process.env, +): boolean { + return Boolean(env.CROSSMINT_SERVER_API_KEY?.trim() && env.CROSSMINT_USER_ID?.trim()); +} + +export function crossmintConfig( + env: Record = process.env, +): CrossmintConfig { + const required = (name: string) => { + const value = env[name]?.trim(); + if (!value) throw new CrossmintSetupError("missing_configuration", name); + return value; + }; + const invalid = (name: string) => new CrossmintSetupError("invalid_configuration", name); + + const apiKey = required("CROSSMINT_SERVER_API_KEY"); + if (!apiKey.startsWith("sk_")) throw invalid("CROSSMINT_SERVER_API_KEY"); + const userId = required("CROSSMINT_USER_ID"); + + const baseUrl = env.CROSSMINT_API_BASE_URL?.trim() || DEFAULT_BASE_URL; + let base: URL; + try { + base = new URL(baseUrl); + } catch { + throw invalid("CROSSMINT_API_BASE_URL"); + } + if (base.protocol !== "https:" || base.username || base.password || base.search || base.hash) { + throw invalid("CROSSMINT_API_BASE_URL"); + } + + let maxCost: MaxCost | undefined; + const cap = env.CROSSMINT_MAX_COST?.trim(); + if (cap) { + const [amount, currency] = cap.split(/\s+/); + if (!amount || !currency || !DECIMAL.test(amount) || !CURRENCY.test(currency)) { + throw invalid("CROSSMINT_MAX_COST"); + } + maxCost = { amount, currency }; + } + + const allowedMerchants = + env.CROSSMINT_ALLOWED_MERCHANTS?.split(",") + .map((value) => value.trim()) + .filter(Boolean) ?? []; + for (const origin of allowedMerchants) { + let url: URL; + try { + url = new URL(origin); + } catch { + throw invalid("CROSSMINT_ALLOWED_MERCHANTS"); + } + if (url.protocol !== "https:" || url.origin !== origin || url.username || url.password) { + throw invalid("CROSSMINT_ALLOWED_MERCHANTS"); + } + } + + return { + apiKey, + userId, + baseUrl: base.href.replace(/\/$/, ""), + buyerProfileId: env.CROSSMINT_BUYER_PROFILE_ID?.trim() || undefined, + maxCost, + allowedMerchants, + orderIntentId: env.CROSSMINT_ORDER_INTENT_ID?.trim() || undefined, + }; +} + +/** Compare two decimal strings without floating point. Returns -1, 0, or 1. */ +export function compareAmounts(a: string, b: string): number { + const scale = (value: string) => { + const [whole, fraction = ""] = value.split("."); + return BigInt(whole + fraction.padEnd(2, "0").slice(0, 2)); + }; + const left = scale(a); + const right = scale(b); + return left < right ? -1 : left > right ? 1 : 0; +} + +/** Enforce the operator's merchant allowlist and spending ceiling before anything is created. */ +export function assertCheckoutPolicy( + startUrl: string, + maxCost: MaxCost, + config: CrossmintConfig, +): void { + if (config.allowedMerchants.length) { + let url: URL; + try { + url = new URL(startUrl); + } catch { + throw new CrossmintPolicyError("merchant_not_allowed", "The start URL is not a valid HTTPS URL."); + } + if ( + url.protocol !== "https:" || + url.username || + url.password || + !config.allowedMerchants.includes(url.origin) + ) { + throw new CrossmintPolicyError( + "merchant_not_allowed", + "This merchant is not in CROSSMINT_ALLOWED_MERCHANTS.", + ); + } + } + if (config.maxCost) { + if (maxCost.currency !== config.maxCost.currency) { + throw new CrossmintPolicyError( + "currency_mismatch", + `Checkouts are limited to ${config.maxCost.currency} by CROSSMINT_MAX_COST.`, + ); + } + if (compareAmounts(maxCost.amount, config.maxCost.amount) > 0) { + throw new CrossmintPolicyError( + "cap_exceeded", + `The spending cap exceeds the operator ceiling of ${config.maxCost.amount} ${config.maxCost.currency}.`, + ); + } + } +} + +export interface CreateCheckoutInput { + startUrl: string; + task: string; + maxCost: MaxCost; + merchantGuidance?: string; + countryCode?: string; +} + +export type CheckoutStatus = + | "queued" + | "running" + | "awaiting_input" + | "succeeded" + | "failed" + | "cancelled" + | "blocked"; + +export const TERMINAL_STATUSES: ReadonlySet = new Set([ + "succeeded", + "failed", + "cancelled", + "blocked", +]); + +/** Model-safe view of a form field. `protected` fields cannot be answered through the model. */ +export interface CheckoutFormField { + key: string; + label: string; + required: boolean; + handling: "standard" | "protected"; + type: string; + choices?: string[]; +} + +export interface CheckoutAmount { + kind: "exact" | "maximum"; + value: string; + currency: string; +} + +export interface CheckoutMerchant { + name?: string; + url?: string; + countryCode?: string; +} + +export type CheckoutInteraction = + | { kind: "form"; fields: CheckoutFormField[] } + | { kind: "payment"; method: string; amount: CheckoutAmount; merchant: CheckoutMerchant } + | { kind: "unsupported" }; + +export interface CheckoutRequiredAction { + requestId: string; + question: string; + expiresAt?: string; + interaction: CheckoutInteraction; +} + +/** The projection returned to the model. Browser URLs, the echoed input, and unknown fields are dropped. */ +export interface CheckoutSnapshot { + runId: string; + status: CheckoutStatus; + revision: number; + requiredAction: CheckoutRequiredAction | null; + result: { + outcome?: string; + summary?: string; + code?: string; + purchase?: { + kind: string; + receipt?: { total?: MaxCost; merchantOrderId?: string }; + }; + } | null; + failureReason: string | null; +} + +export interface CrossmintClientOptions { + config?: CrossmintConfig; + fetch?: typeof fetch; + signal?: AbortSignal; +} + +const REQUEST_TIMEOUT_MS = 20_000; + +async function request( + path: string, + init: { method: "GET" | "POST"; body?: unknown }, + options: CrossmintClientOptions, +): Promise { + const config = options.config ?? crossmintConfig(); + const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS); + const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout; + signal.throwIfAborted(); + let response: Response; + try { + response = await (options.fetch ?? fetch)(`${config.baseUrl}${path}`, { + method: init.method, + headers: { + "X-API-KEY": config.apiKey, + "x-crossmint-user-id": config.userId, + ...(init.body !== undefined ? { "Content-Type": "application/json" } : {}), + }, + body: init.body !== undefined ? JSON.stringify(init.body) : undefined, + redirect: "error", + signal, + }); + } catch { + signal.throwIfAborted(); + throw new CrossmintRequestError("transport"); + } + if (!response.ok) { + // Provider bodies can echo the request, the key prefix, or merchant data. Drop them. + if (response.status === 401 || response.status === 403) { + throw new CrossmintRequestError("unauthorized", response.status); + } + if (response.status === 404) throw new CrossmintRequestError("not_found", 404); + if (response.status === 429) throw new CrossmintRequestError("rate_limited", 429); + throw new CrossmintRequestError("http_error", response.status); + } + const text = await response.text().catch(() => ""); + if (!text.trim()) return null; + try { + return JSON.parse(text) as unknown; + } catch { + throw new CrossmintRequestError("invalid_response", response.status); + } +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function asString(value: unknown): string | undefined { + return typeof value === "string" ? value : undefined; +} + +function projectAmount(value: unknown): MaxCost | undefined { + if (!isRecord(value)) return undefined; + const amount = asString(value.amount); + const currency = asString(value.currency); + return amount && currency ? { amount, currency } : undefined; +} + +function projectInteraction(value: unknown): CheckoutInteraction { + if (!isRecord(value)) return { kind: "unsupported" }; + if (value.kind === "form" && Array.isArray(value.fields)) { + const fields: CheckoutFormField[] = []; + for (const field of value.fields) { + if (!isRecord(field)) continue; + const key = asString(field.key); + if (!key) continue; + const input = isRecord(field.input) ? field.input : {}; + const choices = Array.isArray(input.choices) + ? input.choices + .map((choice) => { + if (typeof choice === "string") return choice; + if (isRecord(choice)) return asString(choice.value) ?? asString(choice.label); + return undefined; + }) + .filter((choice): choice is string => Boolean(choice)) + : undefined; + fields.push({ + key, + label: asString(field.label) ?? key, + required: field.required === true, + handling: field.handling === "protected" ? "protected" : "standard", + type: asString(input.type) ?? "text", + ...(choices?.length ? { choices } : {}), + }); + } + return { kind: "form", fields }; + } + if (value.kind === "payment") { + const amount = isRecord(value.amount) ? value.amount : {}; + const merchant = isRecord(value.merchant) ? value.merchant : {}; + return { + kind: "payment", + method: asString(value.method) ?? "unknown", + amount: { + kind: amount.kind === "maximum" ? "maximum" : "exact", + value: asString(amount.value) ?? "", + currency: asString(amount.currency) ?? "", + }, + merchant: { + ...(asString(merchant.name) ? { name: asString(merchant.name) } : {}), + ...(asString(merchant.url) ? { url: asString(merchant.url) } : {}), + ...(asString(merchant.countryCode) ? { countryCode: asString(merchant.countryCode) } : {}), + }, + }; + } + return { kind: "unsupported" }; +} + +const STATUSES: ReadonlySet = new Set([ + "queued", + "running", + "awaiting_input", + "succeeded", + "failed", + "cancelled", + "blocked", +]); + +/** Project a raw snapshot to the fields the model may see. Anything unlisted is discarded. */ +export function projectCheckout(raw: unknown): CheckoutSnapshot { + if (!isRecord(raw)) throw new CrossmintRequestError("invalid_response"); + const runId = asString(raw.runId); + const status = asString(raw.status); + if (!runId || !status || !STATUSES.has(status)) { + throw new CrossmintRequestError("invalid_response"); + } + const revision = typeof raw.revision === "number" ? raw.revision : 0; + let requiredAction: CheckoutRequiredAction | null = null; + if (status === "awaiting_input" && isRecord(raw.requiredAction)) { + const action = raw.requiredAction; + const requestId = asString(action.requestId); + const req = isRecord(action.request) ? action.request : {}; + if (requestId) { + requiredAction = { + requestId, + question: asString(req.question) ?? "", + ...(asString(req.expiresAt) ? { expiresAt: asString(req.expiresAt) } : {}), + interaction: projectInteraction(req.interaction), + }; + } + } + let result: CheckoutSnapshot["result"] = null; + if (isRecord(raw.result)) { + const purchase = isRecord(raw.result.purchase) ? raw.result.purchase : undefined; + const receipt = purchase && isRecord(purchase.receipt) ? purchase.receipt : undefined; + const kind = purchase ? asString(purchase.kind) : undefined; + result = { + ...(asString(raw.result.outcome) ? { outcome: asString(raw.result.outcome) } : {}), + ...(asString(raw.result.summary) ? { summary: asString(raw.result.summary) } : {}), + ...(asString(raw.result.code) ? { code: asString(raw.result.code) } : {}), + ...(kind + ? { + purchase: { + kind, + ...(receipt + ? { + receipt: { + ...(projectAmount(receipt.total) ? { total: projectAmount(receipt.total) } : {}), + ...(asString(receipt.merchantOrderId) + ? { merchantOrderId: asString(receipt.merchantOrderId) } + : {}), + }, + } + : {}), + }, + } + : {}), + }; + } + return { + runId, + status: status as CheckoutStatus, + revision, + requiredAction, + result, + failureReason: status === "failed" ? (asString(raw.reason) ?? "unknown") : null, + }; +} + +export async function createCheckout( + input: CreateCheckoutInput, + options: CrossmintClientOptions = {}, +): Promise<{ runId: string }> { + const config = options.config ?? crossmintConfig(); + assertCheckoutPolicy(input.startUrl, input.maxCost, config); + const body = { + request: { startUrl: input.startUrl, task: input.task }, + constraints: { maxCost: input.maxCost }, + ...(config.buyerProfileId ? { buyerProfileId: config.buyerProfileId } : {}), + ...(input.merchantGuidance ? { merchantGuidance: input.merchantGuidance } : {}), + ...(input.countryCode + ? { browser: { location: { type: "country", countryCode: input.countryCode } } } + : {}), + }; + const raw = await request("/agent-checkouts", { method: "POST", body }, { ...options, config }); + const runId = isRecord(raw) ? asString(raw.runId) : undefined; + if (!runId) throw new CrossmintRequestError("invalid_response"); + return { runId }; +} + +export async function getCheckout( + runId: string, + options: CrossmintClientOptions = {}, +): Promise { + const raw = await request( + `/agent-checkouts/${encodeURIComponent(runId)}`, + { method: "GET" }, + options, + ); + return projectCheckout(raw); +} + +export type FormAnswer = string | number | boolean | string[]; + +function message(parts: unknown[]) { + return { id: `bell_${randomUUID()}`, parts }; +} + +export async function answerForm( + runId: string, + requestId: string, + answers: Record, + options: CrossmintClientOptions = {}, +): Promise { + await request( + `/agent-checkouts/${encodeURIComponent(runId)}/messages`, + { + method: "POST", + body: message([ + { + type: "input_response", + requestId, + action: "submit", + response: { kind: "form", answers }, + }, + ]), + }, + options, + ); +} + +/** Pay with the operator's order intent. The id is read from configuration and never returned. */ +export async function payWithOrderIntent( + runId: string, + requestId: string, + options: CrossmintClientOptions = {}, +): Promise { + const config = options.config ?? crossmintConfig(); + if (!config.orderIntentId) { + throw new CrossmintSetupError("missing_configuration", "CROSSMINT_ORDER_INTENT_ID"); + } + await request( + `/agent-checkouts/${encodeURIComponent(runId)}/messages`, + { + method: "POST", + body: message([ + { + type: "input_response", + requestId, + action: "submit", + response: { kind: "payment", orderIntentId: config.orderIntentId }, + }, + ]), + }, + { ...options, config }, + ); +} + +export async function declineRequest( + runId: string, + requestId: string, + options: CrossmintClientOptions = {}, +): Promise { + await request( + `/agent-checkouts/${encodeURIComponent(runId)}/messages`, + { method: "POST", body: message([{ type: "input_response", requestId, action: "decline" }]) }, + options, + ); +} + +export async function cancelCheckout( + runId: string, + options: CrossmintClientOptions = {}, +): Promise { + await request(`/agent-checkouts/${encodeURIComponent(runId)}/cancel`, { method: "POST" }, options); +} + +export interface WaitOptions extends CrossmintClientOptions { + /** Stop waiting after this many milliseconds and return the latest snapshot. */ + timeoutMs?: number; + intervalMs?: number; + /** A request id already answered. Crossmint can keep showing it briefly. */ + skipRequestId?: string; +} + +function sleep(ms: number, signal?: AbortSignal): Promise { + return new Promise((resolve, reject) => { + const onAbort = () => { + clearTimeout(timer); + reject(signal?.reason); + }; + const timer = setTimeout(() => { + signal?.removeEventListener("abort", onAbort); + resolve(); + }, ms); + signal?.addEventListener("abort", onAbort, { once: true }); + }); +} + +/** Poll until the checkout needs input or ends, or until the timeout. Always returns a snapshot. */ +export async function waitForCheckout( + runId: string, + options: WaitOptions = {}, +): Promise { + const timeoutMs = options.timeoutMs ?? 90_000; + const intervalMs = options.intervalMs ?? 2_000; + const deadline = Date.now() + timeoutMs; + let snapshot = await getCheckout(runId, options); + for (;;) { + const settled = + TERMINAL_STATUSES.has(snapshot.status) || + (snapshot.status === "awaiting_input" && + snapshot.requiredAction !== null && + snapshot.requiredAction.requestId !== options.skipRequestId); + if (settled || Date.now() >= deadline) return snapshot; + options.signal?.throwIfAborted(); + await sleep(Math.min(intervalMs, Math.max(0, deadline - Date.now())), options.signal); + const next = await getCheckout(runId, options); + if (next.revision >= snapshot.revision) snapshot = next; + } +} diff --git a/server/crossmint/payment.ts b/server/crossmint/payment.ts new file mode 100644 index 0000000..f8b3c2b --- /dev/null +++ b/server/crossmint/payment.ts @@ -0,0 +1,91 @@ +import { compareAmounts, type CheckoutSnapshot, type MaxCost } from "./client"; +import type { CheckoutRecord } from "./runs"; + +/** The payment the person approved, as the model stated it in the tool call. */ +export interface ApprovedPayment { + requestId: string; + amount: string; + currency: string; + merchant: string; +} + +export class PaymentMismatchError extends Error { + constructor( + readonly reason: + | "no_payment_request" + | "request_changed" + | "amount_mismatch" + | "currency_mismatch" + | "merchant_mismatch" + | "cap_exceeded" + | "unsupported_amount", + message: string, + ) { + super(message); + this.name = "PaymentMismatchError"; + } +} + +function hostOf(value: string): string | undefined { + try { + return new URL(value.includes("://") ? value : `https://${value}`).hostname.toLowerCase(); + } catch { + return undefined; + } +} + +/** + * Compare the approved payment with the request Crossmint is showing right now and with the cap + * the run was created under. Anything that differs refuses the payment. The approval dialog shows + * the person the model's numbers; this check makes sure those are also Crossmint's numbers. + */ +export function assertPaymentMatches( + approved: ApprovedPayment, + live: CheckoutSnapshot, + record: CheckoutRecord, +): { amount: MaxCost; merchant: string } { + const action = live.requiredAction; + if (live.status !== "awaiting_input" || !action || action.interaction.kind !== "payment") { + throw new PaymentMismatchError( + "no_payment_request", + "Crossmint is not waiting for a payment on this checkout.", + ); + } + if (action.requestId !== approved.requestId) { + throw new PaymentMismatchError( + "request_changed", + "The payment request changed since approval. Show the person the new request.", + ); + } + const { amount, merchant } = action.interaction; + if (amount.kind !== "exact") { + throw new PaymentMismatchError( + "unsupported_amount", + "Crossmint sent a maximum rather than an exact total. Decline and ask the person how to proceed.", + ); + } + if (amount.currency !== approved.currency) { + throw new PaymentMismatchError("currency_mismatch", "The approved currency differs from Crossmint's."); + } + if (compareAmounts(amount.value, approved.amount) !== 0) { + throw new PaymentMismatchError( + "amount_mismatch", + `Crossmint is asking for ${amount.value} ${amount.currency}, not the approved amount.`, + ); + } + const liveHost = merchant.url ? hostOf(merchant.url) : undefined; + const approvedHost = hostOf(approved.merchant); + if (!liveHost || !approvedHost || liveHost !== approvedHost) { + throw new PaymentMismatchError( + "merchant_mismatch", + "The approved merchant differs from the one Crossmint is checking out at.", + ); + } + if (record.maxCost.currency !== amount.currency || compareAmounts(amount.value, record.maxCost.amount) > 0) { + throw new PaymentMismatchError( + "cap_exceeded", + `The total exceeds the ${record.maxCost.amount} ${record.maxCost.currency} cap this checkout was started with.`, + ); + } + return { amount: { amount: amount.value, currency: amount.currency }, merchant: liveHost }; +} diff --git a/server/crossmint/runs.ts b/server/crossmint/runs.ts new file mode 100644 index 0000000..485e824 --- /dev/null +++ b/server/crossmint/runs.ts @@ -0,0 +1,41 @@ +import type { MaxCost } from "./client"; + +/** + * Checkouts started in this process, keyed by Eve session. A conversation can only read, answer, + * pay for, or cancel a checkout it started, so a model-supplied id cannot reach another buyer's + * run. The cap each run was created with is kept here and checked again at payment time. + * + * The registry lives in process memory, like the Link sandbox request set. After a restart or a + * worker change an unfinished checkout is reconciled in the Crossmint console, not retried here. + */ +export interface CheckoutRecord { + runId: string; + maxCost: MaxCost; + /** Authenticated principal that started the run, when the channel provided one. */ + principalId: string | null; +} + +const runs = new Map>(); + +export function rememberCheckout(sessionId: string, record: CheckoutRecord): void { + let session = runs.get(sessionId); + if (!session) { + session = new Map(); + runs.set(sessionId, session); + } + session.set(record.runId, record); +} + +export function sessionCheckout(sessionId: string, runId: string): CheckoutRecord | undefined { + return runs.get(sessionId)?.get(runId); +} + +export function assertSessionCheckout(sessionId: string, runId: string): CheckoutRecord { + const record = sessionCheckout(sessionId, runId); + if (!record) { + throw new Error( + "This conversation did not start that checkout in this process. Start a new checkout, or reconcile the existing one in the Crossmint console.", + ); + } + return record; +} diff --git a/tests/crossmint.test.ts b/tests/crossmint.test.ts new file mode 100644 index 0000000..8944b21 --- /dev/null +++ b/tests/crossmint.test.ts @@ -0,0 +1,367 @@ +import { describe, expect, it, vi } from "vitest"; +import { + answerForm, + assertCheckoutPolicy, + cancelCheckout, + compareAmounts, + createCheckout, + crossmintConfig, + CrossmintPolicyError, + CrossmintRequestError, + CrossmintSetupError, + declineRequest, + getCheckout, + isCrossmintConfigured, + payWithOrderIntent, + projectCheckout, + waitForCheckout, + type CheckoutSnapshot, +} from "../server/crossmint/client.js"; +import { assertPaymentMatches, PaymentMismatchError } from "../server/crossmint/payment.js"; +import { assertSessionCheckout, rememberCheckout, sessionCheckout } from "../server/crossmint/runs.js"; + +const config = { + apiKey: "sk_unit_test_only", + userId: "operator-1", + baseUrl: "https://www.crossmint.com/api/unstable", + allowedMerchants: [] as string[], + orderIntentId: "oi_test_secret", +}; + +const snapshot = (overrides: Record) => ({ + runId: "run_1", + status: "running", + revision: 1, + createdAt: "2026-10-28T12:00:00.000Z", + browser: { embedUrl: "https://browser.example/secret", permissions: ["read"] }, + input: { request: { startUrl: "https://shop.example/p/1" }, constraints: { maxCost: { amount: "20.00", currency: "USD" } } }, + requiredAction: null, + ...overrides, +}); + +const paymentRequest = (amount = "12.49", currency = "USD", url = "https://shop.example") => + snapshot({ + status: "awaiting_input", + requiredAction: { + requestId: "req_pay", + request: { + question: `Authorize a card payment of ${amount} ${currency}.`, + interaction: { + kind: "payment", + method: "card", + purpose: "checkout_payment", + amount: { kind: "exact", value: amount, currency }, + merchant: { name: "Example Shop", url, countryCode: "US" }, + }, + }, + }, + }); + +describe("Crossmint configuration", () => { + it("is optional until used", () => { + expect(isCrossmintConfigured({})).toBe(false); + expect(isCrossmintConfigured({ CROSSMINT_SERVER_API_KEY: "sk_x", CROSSMINT_USER_ID: "u" })).toBe(true); + }); + + it("names the missing or invalid setting without logging values", () => { + const base = { CROSSMINT_SERVER_API_KEY: "sk_x", CROSSMINT_USER_ID: "u" }; + expect(() => crossmintConfig({})).toThrow(CrossmintSetupError); + expect(() => crossmintConfig({})).toThrow("CROSSMINT_SERVER_API_KEY"); + expect(() => crossmintConfig({ ...base, CROSSMINT_SERVER_API_KEY: "ck_client_key" })).toThrow("CROSSMINT_SERVER_API_KEY"); + expect(() => crossmintConfig({ ...base, CROSSMINT_API_BASE_URL: "http://insecure.example" })).toThrow("CROSSMINT_API_BASE_URL"); + expect(() => crossmintConfig({ ...base, CROSSMINT_MAX_COST: "50 dollars" })).toThrow("CROSSMINT_MAX_COST"); + expect(() => crossmintConfig({ ...base, CROSSMINT_ALLOWED_MERCHANTS: "https://shop.example/path" })).toThrow("CROSSMINT_ALLOWED_MERCHANTS"); + expect(() => crossmintConfig({ ...base, CROSSMINT_ALLOWED_MERCHANTS: "http://shop.example" })).toThrow("CROSSMINT_ALLOWED_MERCHANTS"); + + const parsed = crossmintConfig({ + ...base, + CROSSMINT_MAX_COST: "50.00 EUR", + CROSSMINT_ALLOWED_MERCHANTS: "https://shop.example, https://other.example", + CROSSMINT_BUYER_PROFILE_ID: "bp_1", + }); + expect(parsed).toMatchObject({ + baseUrl: "https://www.crossmint.com/api/unstable", + maxCost: { amount: "50.00", currency: "EUR" }, + allowedMerchants: ["https://shop.example", "https://other.example"], + buyerProfileId: "bp_1", + }); + expect(parsed.orderIntentId).toBeUndefined(); + }); +}); + +describe("Crossmint checkout policy", () => { + it("compares decimal amounts without floating point", () => { + expect(compareAmounts("20", "20.00")).toBe(0); + expect(compareAmounts("19.99", "20.00")).toBe(-1); + expect(compareAmounts("20.01", "20.00")).toBe(1); + expect(compareAmounts("0.1", "0.10")).toBe(0); + }); + + it("allows any merchant and any cap when no policy is set", () => { + expect(() => assertCheckoutPolicy("https://anything.example/p", { amount: "9999.00", currency: "USD" }, config)).not.toThrow(); + }); + + it("refuses merchants outside the allowlist before any request is made", () => { + const policy = { ...config, allowedMerchants: ["https://shop.example"] }; + expect(() => assertCheckoutPolicy("https://shop.example/p/1", { amount: "1.00", currency: "USD" }, policy)).not.toThrow(); + for (const url of ["https://evil.example/p", "http://shop.example/p", "https://shop.example.evil.example/p", "https://user:pw@shop.example/p"]) { + expect(() => assertCheckoutPolicy(url, { amount: "1.00", currency: "USD" }, policy)).toThrow(CrossmintPolicyError); + } + }); + + it("refuses caps above the operator ceiling or in another currency", () => { + const policy = { ...config, maxCost: { amount: "50.00", currency: "EUR" } }; + expect(() => assertCheckoutPolicy("https://shop.example", { amount: "50.00", currency: "EUR" }, policy)).not.toThrow(); + expect(() => assertCheckoutPolicy("https://shop.example", { amount: "50.01", currency: "EUR" }, policy)).toThrow("operator ceiling"); + expect(() => assertCheckoutPolicy("https://shop.example", { amount: "1.00", currency: "USD" }, policy)).toThrow("limited to EUR"); + }); + + it("stops createCheckout at the policy, so a refused run is never billed", async () => { + const fetcher = vi.fn(); + await expect( + createCheckout( + { startUrl: "https://evil.example/p", task: "x", maxCost: { amount: "1.00", currency: "USD" } }, + { config: { ...config, allowedMerchants: ["https://shop.example"] }, fetch: fetcher }, + ), + ).rejects.toThrow(CrossmintPolicyError); + expect(fetcher).not.toHaveBeenCalled(); + }); +}); + +describe("Crossmint client", () => { + it("creates a checkout with the documented body and headers", async () => { + const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + expect(String(url)).toBe("https://www.crossmint.com/api/unstable/agent-checkouts"); + expect(init?.method).toBe("POST"); + expect(init?.redirect).toBe("error"); + expect(init?.headers).toMatchObject({ + "X-API-KEY": config.apiKey, + "x-crossmint-user-id": config.userId, + "Content-Type": "application/json", + }); + expect(JSON.parse(init!.body as string)).toEqual({ + request: { startUrl: "https://shop.example/p/1", task: "One sticker pack" }, + constraints: { maxCost: { amount: "20.00", currency: "USD" } }, + buyerProfileId: "bp_1", + browser: { location: { type: "country", countryCode: "ES" } }, + }); + return Response.json({ runId: "run_1" }); + }); + await expect( + createCheckout( + { startUrl: "https://shop.example/p/1", task: "One sticker pack", maxCost: { amount: "20.00", currency: "USD" }, countryCode: "ES" }, + { config: { ...config, buyerProfileId: "bp_1" }, fetch: fetcher }, + ), + ).resolves.toEqual({ runId: "run_1" }); + }); + + it("answers a form with a fresh message id and the submit shape", async () => { + const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + expect(String(url)).toBe("https://www.crossmint.com/api/unstable/agent-checkouts/run_1/messages"); + const body = JSON.parse(init!.body as string); + expect(body.id).toMatch(/^bell_/); + expect(body.parts).toEqual([ + { type: "input_response", requestId: "req_1", action: "submit", response: { kind: "form", answers: { email: "ada@example.com", size: "M" } } }, + ]); + return Response.json({ messageId: "msg_1", status: "accepted" }, { status: 202 }); + }); + await answerForm("run_1", "req_1", { email: "ada@example.com", size: "M" }, { config, fetch: fetcher }); + expect(fetcher).toHaveBeenCalledOnce(); + }); + + it("pays with the server-side order intent only", async () => { + const fetcher = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => { + const body = JSON.parse(init!.body as string); + expect(body.parts[0].response).toEqual({ kind: "payment", orderIntentId: "oi_test_secret" }); + return Response.json({ messageId: "msg_2", status: "accepted" }, { status: 202 }); + }); + await payWithOrderIntent("run_1", "req_pay", { config, fetch: fetcher }); + await expect( + payWithOrderIntent("run_1", "req_pay", { config: { ...config, orderIntentId: undefined }, fetch: fetcher }), + ).rejects.toThrow("CROSSMINT_ORDER_INTENT_ID"); + expect(fetcher).toHaveBeenCalledOnce(); + }); + + it("declines and cancels through the documented endpoints and accepts empty 202 bodies", async () => { + const calls: string[] = []; + const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + calls.push(`${init?.method} ${String(url).replace(config.baseUrl, "")}`); + if (init?.body) expect(JSON.parse(init.body as string).parts[0]).toMatchObject({ action: "decline", requestId: "req_1" }); + return new Response(null, { status: 202 }); + }); + await declineRequest("run_1", "req_1", { config, fetch: fetcher }); + await cancelCheckout("run_1", { config, fetch: fetcher }); + expect(calls).toEqual(["POST /agent-checkouts/run_1/messages", "POST /agent-checkouts/run_1/cancel"]); + }); + + it("does not expose provider error bodies", async () => { + const run = (status: number) => getCheckout("run_1", { config, fetch: async () => new Response("private merchant data", { status }) }); + await expect(run(401)).rejects.toThrow(/^Crossmint rejected the API key or its scopes\.$/); + await expect(run(404)).rejects.toThrow(/^Crossmint has no checkout with that id for this buyer\.$/); + await expect(run(429)).rejects.toThrow(/rate limited/); + await expect(run(500)).rejects.toThrow(/^Crossmint returned HTTP 500\.$/); + await expect( + getCheckout("run_1", { config, fetch: async () => { throw new Error("private request details"); } }), + ).rejects.toThrow(/^Crossmint request failed\. Check connectivity and retry\.$/); + }); + + it("does not call the API after cancellation", async () => { + const fetcher = vi.fn(); + await expect(getCheckout("run_1", { config, fetch: fetcher, signal: AbortSignal.abort() })).rejects.toThrow(); + expect(fetcher).not.toHaveBeenCalled(); + }); +}); + +describe("Crossmint snapshot projection", () => { + it("drops browser URLs, the echoed input, and unknown fields", () => { + const projected = projectCheckout(snapshot({ secret: "x" })); + expect(projected).toEqual({ runId: "run_1", status: "running", revision: 1, requiredAction: null, result: null, failureReason: null }); + expect(JSON.stringify(projected)).not.toContain("browser.example"); + }); + + it("projects a form request and keeps protected handling", () => { + const projected = projectCheckout( + snapshot({ + status: "awaiting_input", + requiredAction: { + messageId: "m", + requestId: "req_1", + type: "input_response", + request: { + question: "Which size?", + expiresAt: "2026-10-28T12:10:00.000Z", + interaction: { + kind: "form", + fields: [ + { key: "size", label: "Size", required: true, handling: "standard", input: { type: "choice", choices: [{ value: "M", label: "Medium" }, "L"] } }, + { key: "otp", label: "Code", required: true, handling: "protected", input: { type: "text" } }, + ], + }, + }, + }, + }), + ); + expect(projected.requiredAction).toEqual({ + requestId: "req_1", + question: "Which size?", + expiresAt: "2026-10-28T12:10:00.000Z", + interaction: { + kind: "form", + fields: [ + { key: "size", label: "Size", required: true, handling: "standard", type: "choice", choices: ["M", "L"] }, + { key: "otp", label: "Code", required: true, handling: "protected", type: "text" }, + ], + }, + }); + }); + + it("projects a payment request to amount and merchant only", () => { + const raw = paymentRequest(); + (raw.requiredAction as unknown as { request: { interaction: Record } }).request.interaction.card = { number: "4242" }; + const projected = projectCheckout(raw); + expect(projected.requiredAction?.interaction).toEqual({ + kind: "payment", + method: "card", + amount: { kind: "exact", value: "12.49", currency: "USD" }, + merchant: { name: "Example Shop", url: "https://shop.example", countryCode: "US" }, + }); + expect(JSON.stringify(projected)).not.toContain("4242"); + }); + + it("keeps receipt metadata on success and codes on blocked or failed runs", () => { + expect( + projectCheckout( + snapshot({ + status: "succeeded", + result: { outcome: "succeeded", summary: "Ordered one sticker pack.", purchase: { kind: "receipt_captured", receipt: { total: { amount: "12.49", currency: "USD" }, merchantOrderId: "A-100" } } }, + }), + ).result, + ).toEqual({ outcome: "succeeded", summary: "Ordered one sticker pack.", purchase: { kind: "receipt_captured", receipt: { total: { amount: "12.49", currency: "USD" }, merchantOrderId: "A-100" } } }); + expect(projectCheckout(snapshot({ status: "blocked", result: { outcome: "blocked", code: "merchant.payment_declined", summary: "Declined." } })).result) + .toEqual({ outcome: "blocked", code: "merchant.payment_declined", summary: "Declined." }); + expect(projectCheckout(snapshot({ status: "failed", reason: "cost_limit" })).failureReason).toBe("cost_limit"); + }); + + it("rejects malformed snapshots", () => { + expect(() => projectCheckout({ status: "running" })).toThrow(CrossmintRequestError); + expect(() => projectCheckout(snapshot({ status: "exploded" }))).toThrow(CrossmintRequestError); + }); +}); + +describe("Crossmint payment cross-check", () => { + const record = { runId: "run_1", maxCost: { amount: "20.00", currency: "USD" }, principalId: "linq:1" }; + const approved = { requestId: "req_pay", amount: "12.49", currency: "USD", merchant: "shop.example" }; + const live = (raw: Record): CheckoutSnapshot => projectCheckout(raw); + + it("accepts a payment whose amount, currency, merchant, and cap all agree", () => { + expect(assertPaymentMatches(approved, live(paymentRequest()), record)).toEqual({ amount: { amount: "12.49", currency: "USD" }, merchant: "shop.example" }); + expect(assertPaymentMatches({ ...approved, merchant: "https://shop.example/checkout" }, live(paymentRequest()), record).merchant).toBe("shop.example"); + }); + + it.each([ + ["no_payment_request", approved, snapshot({ status: "running" })], + ["request_changed", { ...approved, requestId: "req_old" }, paymentRequest()], + ["amount_mismatch", { ...approved, amount: "12.48" }, paymentRequest()], + ["currency_mismatch", { ...approved, currency: "EUR" }, paymentRequest()], + ["merchant_mismatch", { ...approved, merchant: "evil.example" }, paymentRequest()], + ["cap_exceeded", { ...approved, amount: "20.01" }, paymentRequest("20.01")], + ] as const)("refuses on %s", (reason, input, raw) => { + let caught: unknown; + try { + assertPaymentMatches(input, live(raw), record); + } catch (error) { + caught = error; + } + expect(caught).toBeInstanceOf(PaymentMismatchError); + expect((caught as PaymentMismatchError).reason).toBe(reason); + }); + + it("refuses a maximum amount, which cannot be shown to the person as an exact total", () => { + const raw = paymentRequest(); + (raw.requiredAction as unknown as { request: { interaction: { amount: { kind: string } } } }).request.interaction.amount.kind = "maximum"; + expect(() => assertPaymentMatches(approved, live(raw), record)).toThrow(/maximum rather than an exact total/); + }); +}); + +describe("Crossmint polling", () => { + it("waits through running states, skips an answered request, and stops on new input or a terminal state", async () => { + const sequence = [ + snapshot({ status: "running", revision: 1 }), + snapshot({ status: "awaiting_input", revision: 2, requiredAction: { requestId: "answered", request: { question: "old", interaction: { kind: "form", fields: [] } } } }), + snapshot({ status: "awaiting_input", revision: 3, requiredAction: { requestId: "req_new", request: { question: "new", interaction: { kind: "form", fields: [] } } } }), + ]; + const fetcher = vi.fn(async () => Response.json(sequence.shift() ?? sequence.at(-1))); + const result = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, skipRequestId: "answered" }); + expect(result.status).toBe("awaiting_input"); + expect(result.requiredAction?.requestId).toBe("req_new"); + expect(fetcher).toHaveBeenCalledTimes(3); + }); + + it("returns the latest snapshot at the timeout instead of hanging", async () => { + const fetcher = vi.fn(async () => Response.json(snapshot({ status: "running" }))); + const result = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 10 }); + expect(result.status).toBe("running"); + expect(fetcher.mock.calls.length).toBeGreaterThan(1); + }); + + it("stops polling when the turn is cancelled", async () => { + const controller = new AbortController(); + const fetcher = vi.fn(async () => { + controller.abort(); + return Response.json(snapshot({ status: "running" })); + }); + await expect(waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 50, signal: controller.signal })).rejects.toThrow(); + expect(fetcher).toHaveBeenCalledOnce(); + }); +}); + +describe("Crossmint run registry", () => { + it("scopes checkouts to the conversation that started them and keeps the cap", () => { + const record = { runId: "run_a", maxCost: { amount: "20.00", currency: "USD" }, principalId: "linq:1" }; + rememberCheckout("session-a", record); + expect(sessionCheckout("session-a", "run_a")).toEqual(record); + expect(sessionCheckout("session-b", "run_a")).toBeUndefined(); + expect(assertSessionCheckout("session-a", "run_a")).toEqual(record); + expect(() => assertSessionCheckout("session-b", "run_a")).toThrow("did not start that checkout"); + }); +}); From 6a21f8309b6db0cd4e528d65d610478d839eaf4e Mon Sep 17 00:00:00 2001 From: Alejandro Dopico Date: Wed, 28 Oct 2026 16:22:31 -0500 Subject: [PATCH 2/3] Add Crossmint Agent Checkouts as an optional way to buy One tool starts a checkout at any store with a product URL, a sentence and a spending cap, then answers the forms. A second tool pays after the person approves the exact total in Eve, and the server checks that total, the currency, the merchant and the cap against Crossmint's live request before paying. The card number never reaches Bell or the model. Nothing changes unless the Crossmint variables are set. --- .env.example | 4 +- README.md | 2 +- agent/instructions.md | 17 +- agent/lib/crossmint.ts | 35 +++ agent/tools/crossmint_checkout.ts | 135 ++------- agent/tools/crossmint_pay.ts | 94 ++---- docs/crossmint.md | 183 +++++++----- docs/repository.md | 2 +- scripts/demo-crossmint.mjs | 75 +++++ server/crossmint/client.ts | 481 ++++++++++-------------------- server/crossmint/payment.ts | 60 ++-- server/crossmint/runs.ts | 4 +- tests/crossmint.test.ts | 145 +++++++-- 13 files changed, 571 insertions(+), 666 deletions(-) create mode 100644 agent/lib/crossmint.ts create mode 100644 scripts/demo-crossmint.mjs diff --git a/.env.example b/.env.example index fcdc4a0..3c884db 100644 --- a/.env.example +++ b/.env.example @@ -67,8 +67,8 @@ LINK_TOKEN_ENCRYPTION_KEY= # Exact trusted checkout/frame origins per approved merchant (JSON object). LINK_CHECKOUT_ORIGINS={} -# Optional Crossmint Agent Checkouts. Production server key (sk_) with agent-checkouts.* scopes. -# See docs/crossmint.md. Leave unset to keep the tools disabled. +# Optional Crossmint Agent Checkouts. Buy at any store with the person's own card. +# Production server key (sk_) with agent-checkouts.* scopes. See docs/crossmint.md. Leave unset to keep the tools disabled. CROSSMINT_SERVER_API_KEY= CROSSMINT_USER_ID= # The operator's approved order intent id. Required only to pay; never shown to the model. diff --git a/README.md b/README.md index ab9c12b..3d03caf 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ pnpm dev | Link by Stripe | Wallet authorization, spend approval, and checkout through Linq | [Sandbox and wallet setup](docs/link.md) | | 1Password | Operator credentials and OTP; personal Agentic Autofill is disabled by default | [Operator access](docs/browser-runtime.md#credentials-and-otp) ยท [Personal access status](docs/onepassword.md) | | Baselayer | Verified access to approved merchants using short-lived credentials | [Merchant access](docs/baselayer.md) | -| Crossmint | Checkout at any merchant under a spending cap, paid after the person approves the exact total | [Agent checkouts](docs/crossmint.md) | +| Crossmint | Buy at any store with the person's own card, worldwide, under a spending cap the person approves | [Agent checkouts](docs/crossmint.md) | See the [repository layout and implementation map](docs/repository.md) to extend Bell. diff --git a/agent/instructions.md b/agent/instructions.md index b27068f..dd99a2e 100644 --- a/agent/instructions.md +++ b/agent/instructions.md @@ -40,11 +40,12 @@ Do not claim a successful mint or merchant access unless the tool result confirm For private Linq senders, use `onepassword_connect`, `onepassword_status`, `onepassword_login`, and `onepassword_disconnect` for personal 1Password access. If status is disabled, explain that personal 1Password login is not available yet; do not offer a consent link or fall back to the operator vault. Never use the operator vault tools for a messaging sender. Connecting is separate from approving a website login. Use the exact login URL and a distinct expected success path on the same origin. A verified destination is not proof of account identity. The first version supports single-step sign-in only. Approval links are sent through Eve authorization; do not ask for tokens, integration keys, passwords, or OTPs in chat. If a private fill fails, start a new conversation rather than inspecting the blocked browser. Personal browser mode does not support reusable Contexts. Use crossmint_checkout when Crossmint Agent Checkouts is configured and the user wants a purchase -completed by Crossmint rather than in this conversation's browser. Start with the product URL, the -request, and the user's spending cap. Answer form questions from what the user said; never fill -protected fields. At a payment request, call crossmint_pay with the amount, currency, and merchant -copied from the request; Eve asks the person to approve, and the server verifies those values -against Crossmint before paying. Call crossmint_checkout decline if the person says no. Only a -succeeded result with purchase.kind receipt_captured is a placed order; report any other outcome as -what it is. Never start a second checkout for the same request while one is unresolved, and never -ask for or print API keys or order intent ids. +completed by Crossmint rather than in this conversation's browser. It works at any store, pays with +the user's own card, and the card number never reaches you. Start with the product URL, the request, +and the user's spending cap. Answer form questions from what the user said, using option values for +choice fields, and never fill protected fields. At a payment request, call crossmint_pay with the +amount, currency, and merchant copied from the request. Eve asks the person to approve, and the +server verifies those values against Crossmint before paying. Call crossmint_checkout decline if the +person says no. Only a succeeded result with purchase.kind receipt_captured is a placed order. Report +any other outcome as what it is. Never start a second checkout for the same request while one is +unresolved, and never ask for or print API keys or order intent ids. diff --git a/agent/lib/crossmint.ts b/agent/lib/crossmint.ts new file mode 100644 index 0000000..87cb67d --- /dev/null +++ b/agent/lib/crossmint.ts @@ -0,0 +1,35 @@ +import { z } from "zod"; +import { + AMOUNT, + CrossmintPolicyError, + CrossmintRequestError, + CrossmintSetupError, + isCrossmintConfigured, + type CheckoutSnapshot, +} from "../../server/crossmint/client"; + +/** How long one tool call waits for Crossmint before returning the latest snapshot. */ +export const WAIT_MS = 90_000; + +export const amount = z.string().regex(AMOUNT, "Decimal string such as 20.00"); +export const currency = z.string().length(3).toUpperCase().describe("ISO 4217 code, such as USD or EUR."); +export const runId = z.string().min(1).max(200); +export const requestId = z.string().min(1).max(200); + +export type CheckoutToolOutput = + | { status: "not_configured"; hint: string } + | { status: "error"; reason: string; message: string } + | CheckoutSnapshot; + +export function notConfigured(): CheckoutToolOutput | undefined { + if (isCrossmintConfigured()) return undefined; + return { status: "not_configured", hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md." }; +} + +/** Crossmint errors carry fixed, sanitized messages the model may see. Anything else is rethrown. */ +export function errorOutput(error: unknown): CheckoutToolOutput { + if (error instanceof CrossmintSetupError || error instanceof CrossmintRequestError || error instanceof CrossmintPolicyError) { + return { status: "error", reason: error.reason, message: error.message }; + } + throw error; +} diff --git a/agent/tools/crossmint_checkout.ts b/agent/tools/crossmint_checkout.ts index fd94ca5..a024df4 100644 --- a/agent/tools/crossmint_checkout.ts +++ b/agent/tools/crossmint_checkout.ts @@ -1,53 +1,17 @@ import { defineTool, toolOutput } from "eve/tools"; import { z } from "zod"; - -import { - answerForm, - cancelCheckout, - createCheckout, - CrossmintPolicyError, - CrossmintRequestError, - CrossmintSetupError, - declineRequest, - getCheckout, - isCrossmintConfigured, - waitForCheckout, - type CheckoutSnapshot, -} from "../../server/crossmint/client"; +import { amount, currency, errorOutput, notConfigured, requestId, runId, WAIT_MS, type CheckoutToolOutput } from "../lib/crossmint"; +import { answerForm, cancelCheckout, createCheckout, declineRequest, getCheckout, waitForCheckout } from "../../server/crossmint/client"; import { assertSessionCheckout, rememberCheckout } from "../../server/crossmint/runs"; -const maxCost = z.object({ - amount: z - .string() - .regex(/^\d+(\.\d{1,2})?$/, "Decimal string such as 20.00") - .describe("Spending cap including shipping and tax, as a decimal string."), - currency: z.string().length(3).toUpperCase().describe("ISO 4217 code, such as USD or EUR."), -}); - -const runId = z.string().min(1).max(200); -const requestId = z.string().min(1).max(200); - const inputSchema = z.discriminatedUnion("action", [ z.object({ action: z.literal("start"), startUrl: z.string().url().max(2048).describe("Product or store page to start from."), - task: z - .string() - .min(1) - .max(20_000) - .describe("What to buy, in plain language: item, options, quantity, delivery."), - maxCost, - merchantGuidance: z - .string() - .max(20_000) - .optional() - .describe("Optional notes about this merchant's checkout."), - countryCode: z - .string() - .length(2) - .toUpperCase() - .optional() - .describe("Optional browser location for the checkout, such as ES or US."), + task: z.string().min(1).max(20_000).describe("What to buy, in plain language. Item, options, quantity, delivery."), + maxCost: z.object({ amount: amount.describe("Spending cap including shipping and tax."), currency }), + merchantGuidance: z.string().min(1).max(20_000).optional().describe("Optional notes about this merchant's checkout."), + countryCode: z.string().length(2).toUpperCase().optional().describe("Optional browser location for the checkout, such as ES or US."), }), z.object({ action: z.literal("status"), runId }), z.object({ @@ -56,120 +20,63 @@ const inputSchema = z.discriminatedUnion("action", [ requestId, answers: z .record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.array(z.string())])) - .describe("One value per form field key. Protected fields cannot be answered here."), + .describe("One value per form field key. For a choice field, an option value. Protected fields cannot be answered here."), }), z.object({ action: z.literal("decline"), runId, requestId }), z.object({ action: z.literal("cancel"), runId }), ]); -export type CheckoutToolOutput = - | { status: "not_configured"; hint: string } - | { status: "error"; reason: string; message: string } - | CheckoutSnapshot; - -export function errorOutput(error: unknown): CheckoutToolOutput { - if ( - error instanceof CrossmintSetupError || - error instanceof CrossmintRequestError || - error instanceof CrossmintPolicyError - ) { - return { status: "error", reason: error.reason, message: error.message }; - } - throw error; -} - -export const WAIT_MS = 90_000; - export default defineTool({ description: - "Buy from a merchant through Crossmint Agent Checkouts with a hard spending cap. Crossmint runs the checkout in its own service, not in this conversation's browser. Actions: start (product URL, plain-language task, maxCost), then follow requiredAction. For a form, call answer with one value per field key. For a payment request, call crossmint_pay; the person approves the exact amount there. decline refuses a request; cancel stops the run. Returns status snapshots only. A succeeded result whose purchase.kind is receipt_captured is the only proof of a placed order. Never start a second checkout for the same request while one is unresolved.", + "Buy at any store through Crossmint Agent Checkouts under a hard spending cap. Crossmint picks the fastest path for the store, the merchant API, an agent protocol, or its own checkout browser, so nothing runs in this conversation's browser. The person pays with their own card, worldwide, and the card number never reaches this assistant. Call start with the product URL, a plain-language task, and maxCost, then follow requiredAction. For a form, call answer with one value per field key. For a payment, call crossmint_pay. decline refuses a request and cancel stops the run. Each call returns a status snapshot and waits up to ninety seconds for the next step. A succeeded result with purchase.kind receipt_captured is the only proof of a placed order. Never start a second checkout for the same request while one is unresolved.", inputSchema, label: { start: (input) => - input.action === "start" - ? `Starting a Crossmint checkout at ${new URL(input.startUrl).hostname}` - : `Crossmint checkout: ${input.action}`, + input.action === "start" ? `Starting a Crossmint checkout at ${new URL(input.startUrl).hostname}` : `Crossmint checkout: ${input.action}`, }, async execute(input, ctx): Promise { ctx.abortSignal.throwIfAborted(); - if (!isCrossmintConfigured()) { - return { - status: "not_configured", - hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md.", - }; - } + const unavailable = notConfigured(); + if (unavailable) return unavailable; const sessionId = ctx.session.id; const signal = ctx.abortSignal; try { switch (input.action) { case "start": { - const { runId } = await createCheckout( - { - startUrl: input.startUrl, - task: input.task, - maxCost: input.maxCost, - ...(input.merchantGuidance ? { merchantGuidance: input.merchantGuidance } : {}), - ...(input.countryCode ? { countryCode: input.countryCode } : {}), - }, - { signal }, - ); - rememberCheckout(sessionId, { - runId, - maxCost: input.maxCost, - principalId: ctx.session.auth.current?.principalId ?? null, - }); + const { runId } = await createCheckout(input, { signal }); + rememberCheckout(sessionId, { runId, maxCost: input.maxCost, principalId: ctx.session.auth.current?.principalId ?? null }); return await waitForCheckout(runId, { signal, timeoutMs: WAIT_MS }); } - case "status": { + case "status": assertSessionCheckout(sessionId, input.runId); return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS }); - } case "answer": { assertSessionCheckout(sessionId, input.runId); const current = await getCheckout(input.runId, { signal }); const action = current.requiredAction; if (!action || action.requestId !== input.requestId) return current; if (action.interaction.kind !== "form") { - return { - status: "error", - reason: "wrong_interaction", - message: "This request is not a form. Payment requests go through crossmint_pay.", - }; + return { status: "error", reason: "wrong_interaction", message: "This request is not a form. Payment requests go through crossmint_pay." }; } - const protectedKeys = new Set( - action.interaction.fields - .filter((field) => field.handling === "protected") - .map((field) => field.key), - ); + const protectedKeys = new Set(action.interaction.fields.filter((field) => field.handling === "protected").map((field) => field.key)); if (Object.keys(input.answers).some((key) => protectedKeys.has(key))) { return { status: "error", reason: "protected_field", - message: - "Protected fields (codes, passwords, card data) cannot be answered through the model. Decline the request or ask the person to finish in Crossmint's hosted flow.", + message: "Protected fields (codes, passwords, card data) cannot be answered through the model. Decline the request or ask the person to finish in Crossmint's hosted flow.", }; } await answerForm(input.runId, input.requestId, input.answers, { signal }); - return await waitForCheckout(input.runId, { - signal, - timeoutMs: WAIT_MS, - skipRequestId: input.requestId, - }); + return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS, skipRequestId: input.requestId }); } - case "decline": { + case "decline": assertSessionCheckout(sessionId, input.runId); await declineRequest(input.runId, input.requestId, { signal }); - return await waitForCheckout(input.runId, { - signal, - timeoutMs: 30_000, - skipRequestId: input.requestId, - }); - } - case "cancel": { + return await waitForCheckout(input.runId, { signal, timeoutMs: 30_000, skipRequestId: input.requestId }); + case "cancel": assertSessionCheckout(sessionId, input.runId); await cancelCheckout(input.runId, { signal }); return await waitForCheckout(input.runId, { signal, timeoutMs: 30_000 }); - } } } catch (error) { return errorOutput(error); diff --git a/agent/tools/crossmint_pay.ts b/agent/tools/crossmint_pay.ts index 8b28a0f..6c2c2c1 100644 --- a/agent/tools/crossmint_pay.ts +++ b/agent/tools/crossmint_pay.ts @@ -1,103 +1,59 @@ import { defineTool, toolOutput } from "eve/tools"; import { always } from "eve/tools/approval"; import { z } from "zod"; - -import { - CrossmintSetupError, - getCheckout, - isCrossmintConfigured, - payWithOrderIntent, - waitForCheckout, -} from "../../server/crossmint/client"; +import { amount, currency, errorOutput, notConfigured, requestId, runId, WAIT_MS, type CheckoutToolOutput } from "../lib/crossmint"; +import { CrossmintSetupError, getCheckout, payWithOrderIntent, waitForCheckout } from "../../server/crossmint/client"; import { assertPaymentMatches, PaymentMismatchError } from "../../server/crossmint/payment"; import { assertSessionCheckout } from "../../server/crossmint/runs"; -import { errorOutput, WAIT_MS, type CheckoutToolOutput } from "./crossmint_checkout"; const inputSchema = z.object({ - runId: z.string().min(1).max(200), - requestId: z.string().min(1).max(200).describe("The open payment request's id."), - amount: z - .string() - .regex(/^\d+(\.\d{1,2})?$/) - .describe("The exact total Crossmint is asking for, copied from the payment request."), - currency: z.string().length(3).toUpperCase(), - merchant: z - .string() - .min(1) - .max(255) - .describe("The merchant URL or host from the payment request."), + runId, + requestId: requestId.describe("The open payment request's id."), + amount: amount.describe("The exact total Crossmint is asking for, copied from the payment request."), + currency, + merchant: z.string().min(1).max(255).describe("The merchant URL or host from the payment request."), }); type Input = z.infer; -type PayOutput = - | CheckoutToolOutput - | { status: "payment_not_configured"; runId: string; requestId: string; hint: string }; +type PayOutput = CheckoutToolOutput | { status: "payment_not_configured"; runId: string; requestId: string; hint: string }; export default defineTool({ description: - "Pay an open Crossmint checkout payment request with the operator's order intent. Copy amount, currency, and merchant exactly from the payment request. Eve stops and asks the person to approve this call; the server then checks those three values against the live request and the checkout's cap before paying, and refuses on any difference. Requires an authenticated sender. Call once per payment request. Use crossmint_checkout decline if the person says no.", + "Pay the open payment request of a Crossmint checkout with the person's own card, through the order intent held on the server. Copy amount, currency, and merchant exactly from the payment request. Eve stops and asks the person to approve this call. The server then compares those three values with the live request and with the cap the run started with, and refuses on any difference. The card number never reaches this assistant. Needs an authenticated sender. Call once per payment request. Use crossmint_checkout decline if the person says no.", inputSchema, label: { - start: (input: Readonly) => - `Paying ${input.amount} ${input.currency} at ${input.merchant} through Crossmint`, + start: (input: Readonly) => `Paying ${input.amount} ${input.currency} at ${input.merchant} through Crossmint`, }, approval: { request: always(), - prompt: ({ input }) => - `Pay ${input.amount} ${input.currency} to ${input.merchant} with your Crossmint order intent?`, + prompt: ({ input }) => `Pay ${input.amount} ${input.currency} to ${input.merchant} with your Crossmint order intent?`, response: ({ request, response }) => { const requester = request.principal; - if (!requester) { - return { status: "rejected", reason: "Payments need an authenticated sender." }; - } - const same = - response.principal.principalId === requester.principalId && - response.principal.authenticator === requester.authenticator; - return same - ? { status: "allowed" } - : { status: "rejected", reason: "Only the person who requested this payment can approve it." }; + if (!requester) return { status: "rejected", reason: "Payments need an authenticated sender." }; + const same = response.principal.principalId === requester.principalId && response.principal.authenticator === requester.authenticator; + return same ? { status: "allowed" } : { status: "rejected", reason: "Only the person who requested this payment can approve it." }; }, }, async execute(input, ctx): Promise { ctx.abortSignal.throwIfAborted(); - if (!isCrossmintConfigured()) { - return { - status: "not_configured", - hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md.", - }; - } - const sessionId = ctx.session.id; - const signal = ctx.abortSignal; + const unavailable = notConfigured(); + if (unavailable) return unavailable; const auth = ctx.session.auth.current; if (!auth) { - return { - status: "error", - reason: "authentication_required", - message: "Payments are available to authenticated senders only. The anonymous web demo cannot pay.", - }; + return { status: "error", reason: "authentication_required", message: "Payments are available to authenticated senders only. The anonymous web demo cannot pay." }; } + const signal = ctx.abortSignal; try { - const record = assertSessionCheckout(sessionId, input.runId); + const record = assertSessionCheckout(ctx.session.id, input.runId); if (record.principalId !== null && record.principalId !== auth.principalId) { - return { - status: "error", - reason: "principal_mismatch", - message: "A different sender started this checkout.", - }; - } - const live = await getCheckout(input.runId, { signal }); - try { - assertPaymentMatches(input, live, record); - } catch (error) { - if (error instanceof PaymentMismatchError) { - return { status: "error", reason: error.reason, message: error.message }; - } - throw error; + return { status: "error", reason: "principal_mismatch", message: "A different sender started this checkout." }; } try { + assertPaymentMatches(input, await getCheckout(input.runId, { signal }), record); await payWithOrderIntent(input.runId, input.requestId, { signal }); } catch (error) { + if (error instanceof PaymentMismatchError) return { status: "error", reason: error.reason, message: error.message }; if (error instanceof CrossmintSetupError && error.setting === "CROSSMINT_ORDER_INTENT_ID") { return { status: "payment_not_configured", @@ -108,11 +64,7 @@ export default defineTool({ } throw error; } - return await waitForCheckout(input.runId, { - signal, - timeoutMs: WAIT_MS, - skipRequestId: input.requestId, - }); + return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS, skipRequestId: input.requestId }); } catch (error) { return errorOutput(error); } diff --git a/docs/crossmint.md b/docs/crossmint.md index 98b4722..d3ef6f5 100644 --- a/docs/crossmint.md +++ b/docs/crossmint.md @@ -1,133 +1,164 @@ # Crossmint Agent Checkouts -Bell's `crossmint_checkout` and `crossmint_pay` tools buy from a merchant through -[Crossmint Agent Checkouts](https://docs.crossmint.com/agents/checkouts/overview). One request -carries a product URL, a plain-language task, and a spending cap. Crossmint runs the checkout in -its own service and exposes it as a run with status snapshots. Payment comes from an order intent -the operator approved in Crossmint beforehand, funded by a Crossmint agent card, a card on file, or -an agent card from another provider such as Link. +Bell's `crossmint_checkout` and `crossmint_pay` tools buy through +[Crossmint Agent Checkouts](https://docs.crossmint.com/agents/checkouts/overview), part of the +Agent Commerce Toolkit. It works at any store. One call carries a product URL, a sentence, and a +spending cap. Crossmint picks the fastest path for that store, the merchant API, an agent protocol, +or its own checkout browser, and returns a run with status snapshots. The person pays with their own +card, at stores worldwide. The card number never reaches Bell or the model. ```text -Bell -> create run (URL, task, cap) -> Crossmint works through the merchant checkout +Bell -> create run (URL, task, cap) -> Crossmint works through the store's checkout -> awaiting_input (form) -> Bell answers from the conversation -> awaiting_input (payment) -> Eve asks the person to approve the exact total -> server checks total, currency, merchant, cap -> pays -> succeeded (receipt) -> Bell reports the order ``` -The checkout does not use this conversation's Browserbase browser. Link, the browser runtime, and -the hooks are unchanged. With the Crossmint variables unset, both tools return `not_configured`. +The checkout runs in Crossmint's service, not in this conversation's browser. Nothing in the Link +integration, the browser runtime, or the hooks changes. With the Crossmint variables unset, both +tools answer `not_configured`. ## Configure -Server-only values in Bell's ignored `.env.local`: +Set these server-only values in Bell's ignored `.env.local`: ```dotenv CROSSMINT_SERVER_API_KEY= CROSSMINT_USER_ID= -# Optional until the first payment: the operator's approved order intent id. +# Needed only to pay. The operator's approved order intent id. CROSSMINT_ORDER_INTENT_ID= # Optional. Saved buyer profile (name, email, shipping) so checkouts ask fewer questions. CROSSMINT_BUYER_PROFILE_ID= # Optional. Ceiling for any single checkout's cap, "amount currency". CROSSMINT_MAX_COST=50.00 EUR -# Optional. Exact HTTPS origins a checkout may start from. Empty allows any merchant. +# Optional. Exact HTTPS origins a checkout may start from. Empty allows any store. CROSSMINT_ALLOWED_MERCHANTS=https://shop.example ``` Create the key in the [Crossmint console](https://www.crossmint.com/console) with the -`agent-checkouts.create`, `.read`, `.update`, and `.cancel` scopes. Agent Checkouts run in -production only; a staging key returns `unauthorized`. Client keys (`ck_`) are rejected at startup. +`agent-checkouts.create`, `agent-checkouts.read`, `agent-checkouts.update`, and +`agent-checkouts.cancel` scopes. Agent Checkouts runs in production only, so a staging key answers +`unauthorized`. A client key (`ck_`) is rejected at startup. `CROSSMINT_USER_ID` identifies the buyer to Crossmint. Bell serves one trusted operator, so a fixed -value is enough; every run, order intent, and receipt is scoped to it. +value is enough. Every run, order intent, and receipt is scoped to it. -`CROSSMINT_ORDER_INTENT_ID` is the budget the operator approved in Crossmint: a saved card plus an -amount, merchant scope, and expiry. The [cards quickstart](https://docs.crossmint.com/agents/cards-quickstart) -walks through saving a card and approving an order intent. Only the `pay` path on the server reads -this id. Without it, checkouts run up to the payment step and `crossmint_pay` returns -`payment_not_configured`. +`CROSSMINT_ORDER_INTENT_ID` is the budget the person approved in Crossmint beforehand. It names a +saved card, an amount, a merchant scope, and an expiry. The card can be a Crossmint agent card, a card +on file, or an agent card from another provider. The +[cards quickstart](https://docs.crossmint.com/agents/cards-quickstart) walks through saving a card +and approving an order intent. Only the pay path on the server reads this id. Without it, checkouts +run up to the payment step and `crossmint_pay` answers `payment_not_configured`. -`CROSSMINT_MAX_COST` and `CROSSMINT_ALLOWED_MERCHANTS` are checked before a run is created, so a -refused request is never billed. They bound what a prompt can ask for; the order intent still bounds -what can be paid. +`CROSSMINT_MAX_COST` and `CROSSMINT_ALLOWED_MERCHANTS` are checked before a run exists, so a refused +request is never billed. They bound what a prompt can ask for. The order intent bounds what can be +paid. Restart Bell after changing these values. No database, migration, or browser setting is involved. +## Try it in five minutes + +This run needs only `CROSSMINT_SERVER_API_KEY` and `CROSSMINT_USER_ID`. It reaches the payment step +and stops there, so nothing is bought. Pick a product under a few dollars at a store that ships to +you. + +1. Start Bell with `pnpm dev` and open `http://127.0.0.1:4320`. Local development auth signs the web + conversation in, which the payment step requires. +2. Send "Buy one of https://shop.example/products/sticker-pack with standard delivery, max 20 USD". + Bell starts the run and waits up to ninety seconds for the next step. +3. Answer the questions Bell relays, such as a size or an email. With a buyer profile configured + most of them do not come up. +4. At the payment step Bell calls `crossmint_pay`. Eve pauses and shows "Pay 12.49 USD to + shop.example with your Crossmint order intent?". Approve it. The server fetches the live request, + checks it, finds no order intent, and answers `payment_not_configured`. +5. Say "Cancel it". Bell cancels the run and the status becomes `cancelled`. + +Crossmint bills each run that starts, including runs that end `blocked`. The first thousand runs a +month are free. The run appears in the Crossmint console under Agent Checkouts with the same id Bell +reports. To buy for real, set `CROSSMINT_ORDER_INTENT_ID` and repeat the steps. The approval is the +same. The server then pays, and `succeeded` with `purchase.kind` `receipt_captured` carries +`receipt.total` and `receipt.merchantOrderId`. + ## Use -With `pnpm dev` running, in a web conversation or a Linq chat: +With `pnpm dev` running, in a web conversation or a Linq chat, give Bell the product URL, what to +buy, and the cap. Bell starts the run with `crossmint_checkout` and follows `requiredAction`. -1. "Buy one sticker pack from https://shop.example/products/sticker-pack, standard delivery, max - 20 USD." Bell starts the run and waits up to 90 seconds for the next step. -2. When Crossmint asks a form question (size, email, delivery option), Bell asks you and answers - with the `answer` action. Fields marked `protected` (one-time codes, passwords, card data) cannot - be answered through the model; Bell declines or asks you to finish in Crossmint's hosted flow. -3. At the payment step Bell calls `crossmint_pay` with the amount, currency, and merchant from the - request. Eve pauses and shows you an approval: "Pay 12.49 USD to shop.example with your - Crossmint order intent?" Approving runs the tool; cancelling does not. Only the authenticated - sender who asked for the purchase can approve. -4. `succeeded` with `purchase.kind: receipt_captured` carries `receipt.total` and - `receipt.merchantOrderId`. That is the only result Bell reports as a placed order. - `confirmed_without_receipt` and `nothing_placed` are reported as what they are. +When Crossmint asks a form question, Bell answers from what you said or asks you, then calls +`answer` with one value per field key. A choice field lists its option values. Fields marked +`protected`, such as one-time codes, passwords, and card data, cannot be answered through the model. +Bell declines or asks you to finish in Crossmint's hosted flow. -`blocked` returns a code such as `merchant.payment_declined`, `policy.max_cost_exceeded`, or -`product.item_unavailable`; `failed` returns a reason such as `cost_limit` or `input_expired`. Bell -reports these and does not retry on its own. `cancel` stops a run that is still in progress. +At the payment step Bell calls `crossmint_pay` with the amount, currency, and merchant copied from +the request. Eve pauses and asks you to approve. Approving runs the tool and cancelling does not. +Only the authenticated sender who asked for the purchase can approve. A payment request for a method +other than a card, such as Klarna, is refused, because an order intent cannot pay it. -Crossmint bills each run that starts, including runs that end `blocked`. Keep the cap tight and do -not start a second run for the same request while one is unresolved. +`succeeded` with `purchase.kind` `receipt_captured` is the only result Bell reports as a placed order. +`confirmed_without_receipt` and `nothing_placed` are reported as what they are. `blocked` carries a +code such as `merchant.payment_declined`, `policy.max_cost_exceeded`, or `product.item_unavailable`. +`failed` carries a reason such as `cost_limit` or `input_expired`. Bell reports these and does not +retry on its own. `cancel` stops a run that is still in progress. Keep the cap tight and do not start +a second run for the same request while one is unresolved. ## How payment is guarded -Approval in chat is not the control. Eve's tool approval is: `crossmint_pay` is declared with +Approval in chat is not the control. Eve's tool approval is. `crossmint_pay` is declared with `approval: always()`, so the runtime stops before executing it and shows the person the amount, -currency, and merchant the model put in the call. After approval the server fetches the live -payment request from Crossmint and compares it with those three values and with the cap the run was -started under. Any difference, an expired or replaced request, a `maximum` instead of an `exact` -amount, or a run this conversation did not start refuses the payment and returns the reason. The -approval dialog shows the model's numbers; the cross-check makes sure they are Crossmint's numbers. - -Payments need an authenticated sender: a verified Linq number, the HTTP Basic operator, or local -development auth. The anonymous web demo can start and inspect runs but cannot pay, and the +currency, and merchant the model put in the call. After approval the server fetches the live payment +request from Crossmint and compares it with those three values and with the cap the run started +with. Any difference, an expired or replaced request, a method other than a card, a `maximum` instead +of an `exact` amount, or a run this conversation did not start refuses the payment and answers the +reason. The approval dialog shows the model's numbers. The cross-check makes sure they are +Crossmint's numbers. + +Payments need an authenticated sender, which is a verified Linq number, the HTTP Basic operator, or +local development auth. The anonymous web demo can start and inspect runs but cannot pay, and the approval response policy rejects anyone other than the principal who requested the call. ## Transcript boundary -Only a projection of each snapshot reaches the model: run id, status, revision, the open question -with its form fields or payment amount and merchant, and the result summary with receipt metadata. -Browser embed URLs, the echoed input, provider error bodies, and any unexpected field are dropped -before Eve can persist them. The API key, buyer id, buyer profile, and order intent id are read from -the server environment inside the tools and never appear in tool arguments or output. +Only a projection of each snapshot reaches the model. That is the run id, status, revision, the open +question with its form fields or payment amount and merchant, and the result summary with receipt +metadata. Browser embed URLs, payment authorization links, the echoed input, provider error bodies, +and any unexpected field are dropped before Eve can persist them. The API key, buyer id, buyer +profile, and order intent id are read from the server environment inside the tools and never appear +in tool arguments or output. -Runs are registered per conversation in process memory, like the Link sandbox request set. After a -restart or worker change an unfinished run cannot be resumed from chat; reconcile it in the -Crossmint console before starting another. +Runs are registered per conversation in process memory. After a restart or worker change an +unfinished run cannot be resumed from chat. Reconcile it in the Crossmint console before starting +another. -Crossmint's and the merchant's own records are outside Bell's control. Transcripts still contain -the merchant, items, totals, and form answers, so apply your host's retention policy. +Crossmint's and the store's own records are outside Bell's control. Transcripts still contain the +store, items, totals, and form answers, so apply your host's retention policy. -## When to use this instead of Bell's browser +## Verify -For merchants that support an agentic commerce protocol, Agent Checkouts is a pure API call with no -browser session anywhere. For other merchants Crossmint runs its own browser and per-merchant -behavior in its service, so fixes land without a change in Bell. Bell's own browser tools and -`link__checkout` remain the path when the purchase has to happen inside this conversation's -Browserbase session, for example after Baselayer-verified access or in a saved Context. +`pnpm check` runs mock provider tests. They pin request bodies and headers to the documented API, +prove no provider body leaks, exercise the merchant allowlist and the ceiling, project form fields +with their option values and protected handling, run the payment cross-check through every refusal +reason, cover polling with an answered request skipped, the timeout and cancellation paths, +per-conversation run isolation, and both tools up to `payment_not_configured`. No test calls +Crossmint. -## Verify +For a live smoke test without Bell, start one run from the command line: + +```sh +node scripts/demo-crossmint.mjs https://shop.example/products/sticker-pack 20.00 USD +``` -`pnpm check` runs mock provider tests: request shapes and headers against the documented API, -sanitized errors, the merchant allowlist and spending ceiling, snapshot projection including -protected fields and payment interactions, the payment cross-check with one case per refusal -reason, polling with an answered request skipped, the timeout and cancellation paths, and -per-conversation run isolation. No test calls Crossmint. +The command loads `.env`, then `.env.local` when present. It starts the checkout with the key and +buyer id, prints the run id and each status change, and stops at the first question or the first +terminal state. It answers nothing, so nothing is bought, and it prints no secrets. Cancel the run in +the Crossmint console afterwards. Crossmint bills the run. -For a live smoke test, set the key and buyer id, pick a merchant test checkout or an item under a -few dollars, and run the four steps above. Watch the run in the Crossmint console and compare the -receipt with the merchant's confirmation before trusting the flow for anything larger. +For the full flow, follow [Try it in five minutes](#try-it-in-five-minutes). Watch the run in the +Crossmint console and compare the receipt with the store's confirmation before trusting the flow for +anything larger. References: [Agent Checkouts overview](https://docs.crossmint.com/agents/checkouts/overview), [quickstart](https://docs.crossmint.com/agents/agent-checkouts-quickstart), [pay for a checkout](https://docs.crossmint.com/agents/checkouts/payments), -[API reference](https://docs.crossmint.com/api-reference/agent-checkouts/create-agent-checkout). +[statuses and codes](https://docs.crossmint.com/agents/checkouts/statuses), +[API reference](https://docs.crossmint.com/api-reference/agent-checkouts). diff --git a/docs/repository.md b/docs/repository.md index f75be39..47eb6ce 100644 --- a/docs/repository.md +++ b/docs/repository.md @@ -33,7 +33,7 @@ lifecycle; channel callbacks also handle terminal-session cleanup. Restart Bell | Link by Stripe | [Eve extension and tools](../agent/extensions/link/), [authorization](../agent/lib/link-auth.ts), [server implementation](../server/link/) | [Sandbox and wallet setup](link.md) | | 1Password | [Operator SDK/CLI access](../server/browser/vault/onepassword.ts), [personal authorization](../agent/lib/onepassword-auth.ts), [personal server implementation](../server/onepassword/) | [Operator credentials](browser-runtime.md#credentials-and-otp), [personal access status](onepassword.md) | | Baselayer | [Agent tool](../agent/tools/merchant_access.ts), [credential minting](../server/baselayer.ts), [merchant verification](../server/verified-merchant.ts) | [Merchant access](baselayer.md) | -| Crossmint | [Checkout tool](../agent/tools/crossmint_checkout.ts), [approved payment tool](../agent/tools/crossmint_pay.ts), [server client](../server/crossmint/client.ts), [payment cross-check](../server/crossmint/payment.ts) | [Agent checkouts](crossmint.md) | +| Crossmint | [Checkout tool](../agent/tools/crossmint_checkout.ts), [approved payment tool](../agent/tools/crossmint_pay.ts), [shared tool helpers](../agent/lib/crossmint.ts), [server client](../server/crossmint/client.ts), [payment cross-check](../server/crossmint/payment.ts) | [Agent checkouts](crossmint.md) | Personal 1Password Agentic Autofill is implemented but disabled by default pending hosted extension support and live verification. Keep `ONEPASSWORD_ENABLED=false` and the extension ID unset as diff --git a/scripts/demo-crossmint.mjs b/scripts/demo-crossmint.mjs new file mode 100644 index 0000000..818bdc2 --- /dev/null +++ b/scripts/demo-crossmint.mjs @@ -0,0 +1,75 @@ +import { readFileSync } from "node:fs"; +import { parseEnv } from "node:util"; + +// Opt-in: starts one real Crossmint Agent Checkout and watches it. Answers nothing, so it stops at +// the first question or the first terminal state. Crossmint bills the run. Cancel it in the console. +// Usage: node scripts/demo-crossmint.mjs [currency] +const preset = new Set(Object.keys(process.env)); +for (const file of [".env", ".env.local"]) { + let text; + try { text = readFileSync(file, "utf8"); } catch { continue; } + for (const [key, value] of Object.entries(parseEnv(text))) if (!preset.has(key)) process.env[key] = value; +} + +const [startUrl, amount, currency = "USD"] = process.argv.slice(2); +if (!startUrl || !amount) throw new Error("Usage: node scripts/demo-crossmint.mjs [currency]"); +if (!URL.canParse(startUrl) || new URL(startUrl).protocol !== "https:") throw new Error("The product URL must be https."); +if (!/^(?:[1-9]\d{0,14}(?:\.\d{1,2})?|0\.(?=\d*[1-9])\d{1,2})$/.test(amount)) throw new Error("The cap must be a decimal such as 20.00."); +if (!/^[A-Z]{3}$/.test(currency)) throw new Error("The currency must be an ISO 4217 code such as USD."); +const apiKey = process.env.CROSSMINT_SERVER_API_KEY?.trim(); +const userId = process.env.CROSSMINT_USER_ID?.trim(); +if (!apiKey?.startsWith("sk_") || !userId) throw new Error("Set CROSSMINT_SERVER_API_KEY (sk_...) and CROSSMINT_USER_ID."); +const baseUrl = (process.env.CROSSMINT_API_BASE_URL?.trim() || "https://www.crossmint.com/api/unstable").replace(/\/$/, ""); +const buyerProfileId = process.env.CROSSMINT_BUYER_PROFILE_ID?.trim(); +const headers = { "X-API-KEY": apiKey, "x-crossmint-user-id": userId, "Content-Type": "application/json" }; + +// Errors never include the response body: it can echo the request, the key prefix, or merchant data. +async function call(path, init = {}) { + const response = await fetch(`${baseUrl}${path}`, { ...init, headers, redirect: "error", signal: AbortSignal.timeout(20_000) }); + if (!response.ok) throw new Error(`Crossmint returned HTTP ${response.status} for ${init.method ?? "GET"} ${path}.`); + return response.json(); +} + +const describe = (run) => { + const action = run.requiredAction?.request; + if (!action) return ""; + const { interaction } = action; + if (interaction.kind === "form") { + const fields = interaction.fields.map((field) => `${field.key} (${field.handling}, ${field.input.kind})`).join(", "); + return `\n question: ${action.question}\n fields: ${fields}`; + } + if (interaction.kind === "payment") { + return `\n question: ${action.question}\n payment: ${interaction.method} ${interaction.amount.kind} ${interaction.amount.value} ${interaction.amount.currency} at ${interaction.merchant?.url ?? "unknown merchant"}`; + } + return `\n question: ${action.question}`; +}; + +const { runId } = await call("/agent-checkouts", { + method: "POST", + body: JSON.stringify({ + request: { startUrl, task: `Go to the checkout for this product with standard delivery and pay by card.` }, + constraints: { maxCost: { amount, currency } }, + ...(buyerProfileId ? { buyerProfileId } : {}), + }), +}); +console.log(`run ${runId}`); +console.log(`console https://www.crossmint.com/console (Agent Checkouts, search for the run id)`); + +const deadline = Date.now() + 10 * 60_000; +let last = ""; +let run; +do { + run = await call(`/agent-checkouts/${encodeURIComponent(runId)}`); + const line = `${run.status} (revision ${run.revision})${describe(run)}`; + if (line !== last) console.log(`${new Date().toISOString().slice(11, 19)} ${line}`); + last = line; + if (run.status === "awaiting_input" || ["succeeded", "failed", "cancelled", "blocked"].includes(run.status)) break; + await new Promise((resolve) => setTimeout(resolve, 2_000)); +} while (Date.now() < deadline); + +if (run.status === "awaiting_input") console.log("Stopped at the first question. Nothing was answered and nothing was bought. Cancel the run in the console when done."); +else if (run.status === "blocked") console.log(`Blocked with ${run.result?.code ?? "no code"}: ${run.result?.summary ?? ""}`); +else if (run.status === "failed") console.log(`Failed with reason ${run.reason ?? "unknown"}.`); +else if (run.status === "succeeded") console.log(`Succeeded: ${run.result?.summary ?? ""}`); +else if (run.status === "cancelled") console.log("Cancelled."); +else { console.log("Still running after ten minutes. Watch it in the console."); process.exitCode = 1; } diff --git a/server/crossmint/client.ts b/server/crossmint/client.ts index e2881a7..fdb84c4 100644 --- a/server/crossmint/client.ts +++ b/server/crossmint/client.ts @@ -3,9 +3,9 @@ import { randomUUID } from "node:crypto"; /** * Crossmint Agent Checkouts, server side. * - * Crossmint runs the merchant checkout in its own service and exposes it as a run with status - * snapshots. Bell holds the API key, the buyer id, the optional buyer profile, and the order - * intent on the server. The model sees a projection of each snapshot and nothing else. + * Crossmint runs the checkout at any store and exposes it as a run with status snapshots. Bell + * holds the API key, the buyer id, the optional buyer profile, and the order intent on the server. + * The model sees a projection of each snapshot and nothing else. * API reference: https://docs.crossmint.com/api-reference/agent-checkouts */ @@ -19,32 +19,23 @@ export class CrossmintSetupError extends Error { } } -export type CrossmintRequestReason = - | "unauthorized" - | "not_found" - | "rate_limited" - | "transport" - | "invalid_response" - | "http_error"; +/** Fixed messages. Provider bodies can echo the request, the key prefix, or merchant data. */ +const REQUEST_MESSAGES = { + unauthorized: "Crossmint rejected the API key or its scopes.", + not_found: "Crossmint has no checkout with that id for this buyer.", + rate_limited: "Crossmint rate limited the request. Retry shortly.", + transport: "Crossmint request failed. Check connectivity and retry.", + invalid_response: "Crossmint returned an unexpected response.", +}; + +export type CrossmintRequestReason = keyof typeof REQUEST_MESSAGES | "http_error"; export class CrossmintRequestError extends Error { constructor( readonly reason: CrossmintRequestReason, readonly status?: number, ) { - super( - reason === "unauthorized" - ? "Crossmint rejected the API key or its scopes." - : reason === "not_found" - ? "Crossmint has no checkout with that id for this buyer." - : reason === "rate_limited" - ? "Crossmint rate limited the request. Retry shortly." - : reason === "transport" - ? "Crossmint request failed. Check connectivity and retry." - : reason === "invalid_response" - ? "Crossmint returned an unexpected response." - : `Crossmint returned HTTP ${status}.`, - ); + super(reason === "http_error" ? `Crossmint returned HTTP ${status}.` : REQUEST_MESSAGES[reason]); this.name = "CrossmintRequestError"; } } @@ -81,64 +72,44 @@ export interface CrossmintConfig { export const DEFAULT_BASE_URL = "https://www.crossmint.com/api/unstable"; -const DECIMAL = /^\d+(\.\d{1,2})?$/; -const CURRENCY = /^[A-Z]{3}$/; +/** Crossmint's amount pattern, capped at two decimals. No zero, no leading zeros. */ +export const AMOUNT = /^(?:[1-9]\d{0,14}(?:\.\d{1,2})?|0\.(?=\d*[1-9])\d{1,2})$/; +export const CURRENCY = /^[A-Z]{3}$/; -export function isCrossmintConfigured( - env: Record = process.env, -): boolean { +export function isCrossmintConfigured(env: Record = process.env): boolean { return Boolean(env.CROSSMINT_SERVER_API_KEY?.trim() && env.CROSSMINT_USER_ID?.trim()); } -export function crossmintConfig( - env: Record = process.env, -): CrossmintConfig { +export function crossmintConfig(env: Record = process.env): CrossmintConfig { const required = (name: string) => { const value = env[name]?.trim(); if (!value) throw new CrossmintSetupError("missing_configuration", name); return value; }; const invalid = (name: string) => new CrossmintSetupError("invalid_configuration", name); + const httpsUrl = (value: string, name: string) => { + const url = URL.parse(value); + if (!url || url.protocol !== "https:" || url.username || url.password) throw invalid(name); + return url; + }; const apiKey = required("CROSSMINT_SERVER_API_KEY"); if (!apiKey.startsWith("sk_")) throw invalid("CROSSMINT_SERVER_API_KEY"); const userId = required("CROSSMINT_USER_ID"); - - const baseUrl = env.CROSSMINT_API_BASE_URL?.trim() || DEFAULT_BASE_URL; - let base: URL; - try { - base = new URL(baseUrl); - } catch { - throw invalid("CROSSMINT_API_BASE_URL"); - } - if (base.protocol !== "https:" || base.username || base.password || base.search || base.hash) { - throw invalid("CROSSMINT_API_BASE_URL"); - } + const base = httpsUrl(env.CROSSMINT_API_BASE_URL?.trim() || DEFAULT_BASE_URL, "CROSSMINT_API_BASE_URL"); + if (base.search || base.hash) throw invalid("CROSSMINT_API_BASE_URL"); let maxCost: MaxCost | undefined; const cap = env.CROSSMINT_MAX_COST?.trim(); if (cap) { - const [amount, currency] = cap.split(/\s+/); - if (!amount || !currency || !DECIMAL.test(amount) || !CURRENCY.test(currency)) { - throw invalid("CROSSMINT_MAX_COST"); - } + const [amount = "", currency = ""] = cap.split(/\s+/); + if (!AMOUNT.test(amount) || !CURRENCY.test(currency)) throw invalid("CROSSMINT_MAX_COST"); maxCost = { amount, currency }; } - const allowedMerchants = - env.CROSSMINT_ALLOWED_MERCHANTS?.split(",") - .map((value) => value.trim()) - .filter(Boolean) ?? []; + const allowedMerchants = env.CROSSMINT_ALLOWED_MERCHANTS?.split(",").map((value) => value.trim()).filter(Boolean) ?? []; for (const origin of allowedMerchants) { - let url: URL; - try { - url = new URL(origin); - } catch { - throw invalid("CROSSMINT_ALLOWED_MERCHANTS"); - } - if (url.protocol !== "https:" || url.origin !== origin || url.username || url.password) { - throw invalid("CROSSMINT_ALLOWED_MERCHANTS"); - } + if (httpsUrl(origin, "CROSSMINT_ALLOWED_MERCHANTS").origin !== origin) throw invalid("CROSSMINT_ALLOWED_MERCHANTS"); } return { @@ -152,11 +123,11 @@ export function crossmintConfig( }; } -/** Compare two decimal strings without floating point. Returns -1, 0, or 1. */ +/** Compare two decimal strings at Crossmint's six-decimal precision. Returns -1, 0, or 1. */ export function compareAmounts(a: string, b: string): number { const scale = (value: string) => { const [whole, fraction = ""] = value.split("."); - return BigInt(whole + fraction.padEnd(2, "0").slice(0, 2)); + return BigInt(whole + fraction.padEnd(6, "0").slice(0, 6)); }; const left = scale(a); const right = scale(b); @@ -164,42 +135,19 @@ export function compareAmounts(a: string, b: string): number { } /** Enforce the operator's merchant allowlist and spending ceiling before anything is created. */ -export function assertCheckoutPolicy( - startUrl: string, - maxCost: MaxCost, - config: CrossmintConfig, -): void { +export function assertCheckoutPolicy(startUrl: string, maxCost: MaxCost, config: CrossmintConfig): void { if (config.allowedMerchants.length) { - let url: URL; - try { - url = new URL(startUrl); - } catch { - throw new CrossmintPolicyError("merchant_not_allowed", "The start URL is not a valid HTTPS URL."); - } - if ( - url.protocol !== "https:" || - url.username || - url.password || - !config.allowedMerchants.includes(url.origin) - ) { - throw new CrossmintPolicyError( - "merchant_not_allowed", - "This merchant is not in CROSSMINT_ALLOWED_MERCHANTS.", - ); + const url = URL.parse(startUrl); + if (!url || url.protocol !== "https:" || url.username || url.password || !config.allowedMerchants.includes(url.origin)) { + throw new CrossmintPolicyError("merchant_not_allowed", "This merchant is not in CROSSMINT_ALLOWED_MERCHANTS."); } } if (config.maxCost) { if (maxCost.currency !== config.maxCost.currency) { - throw new CrossmintPolicyError( - "currency_mismatch", - `Checkouts are limited to ${config.maxCost.currency} by CROSSMINT_MAX_COST.`, - ); + throw new CrossmintPolicyError("currency_mismatch", `Checkouts are limited to ${config.maxCost.currency} by CROSSMINT_MAX_COST.`); } if (compareAmounts(maxCost.amount, config.maxCost.amount) > 0) { - throw new CrossmintPolicyError( - "cap_exceeded", - `The spending cap exceeds the operator ceiling of ${config.maxCost.amount} ${config.maxCost.currency}.`, - ); + throw new CrossmintPolicyError("cap_exceeded", `The spending cap exceeds the operator ceiling of ${config.maxCost.amount} ${config.maxCost.currency}.`); } } } @@ -212,21 +160,11 @@ export interface CreateCheckoutInput { countryCode?: string; } -export type CheckoutStatus = - | "queued" - | "running" - | "awaiting_input" - | "succeeded" - | "failed" - | "cancelled" - | "blocked"; - -export const TERMINAL_STATUSES: ReadonlySet = new Set([ - "succeeded", - "failed", - "cancelled", - "blocked", -]); +export type CheckoutStatus = "queued" | "running" | "awaiting_input" | "succeeded" | "failed" | "cancelled" | "blocked"; + +const STATUSES: ReadonlySet = new Set(["queued", "running", "awaiting_input", "succeeded", "failed", "cancelled", "blocked"]); + +export const TERMINAL_STATUSES: ReadonlySet = new Set(["succeeded", "failed", "cancelled", "blocked"]); /** Model-safe view of a form field. `protected` fields cannot be answered through the model. */ export interface CheckoutFormField { @@ -234,8 +172,11 @@ export interface CheckoutFormField { label: string; required: boolean; handling: "standard" | "protected"; - type: string; - choices?: string[]; + /** Crossmint's input kind: text, multiline, boolean, choice, integer, or number. */ + kind: string; + /** For a choice field, the values the model may answer with. Placeholder and disabled options are left out. */ + options?: { value: string; label: string }[]; + selection?: "one" | "many"; } export interface CheckoutAmount { @@ -272,10 +213,7 @@ export interface CheckoutSnapshot { outcome?: string; summary?: string; code?: string; - purchase?: { - kind: string; - receipt?: { total?: MaxCost; merchantOrderId?: string }; - }; + purchase?: { kind: string; receipt?: { total?: MaxCost; merchantOrderId?: string } }; } | null; failureReason: string | null; } @@ -288,11 +226,7 @@ export interface CrossmintClientOptions { const REQUEST_TIMEOUT_MS = 20_000; -async function request( - path: string, - init: { method: "GET" | "POST"; body?: unknown }, - options: CrossmintClientOptions, -): Promise { +async function request(path: string, init: { method: "GET" | "POST"; body?: unknown }, options: CrossmintClientOptions): Promise { const config = options.config ?? crossmintConfig(); const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS); const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout; @@ -311,17 +245,16 @@ async function request( signal, }); } catch { - signal.throwIfAborted(); + options.signal?.throwIfAborted(); throw new CrossmintRequestError("transport"); } if (!response.ok) { - // Provider bodies can echo the request, the key prefix, or merchant data. Drop them. - if (response.status === 401 || response.status === 403) { - throw new CrossmintRequestError("unauthorized", response.status); - } - if (response.status === 404) throw new CrossmintRequestError("not_found", 404); - if (response.status === 429) throw new CrossmintRequestError("rate_limited", 429); - throw new CrossmintRequestError("http_error", response.status); + const reason: CrossmintRequestReason = + response.status === 401 || response.status === 403 ? "unauthorized" + : response.status === 404 ? "not_found" + : response.status === 429 ? "rate_limited" + : "http_error"; + throw new CrossmintRequestError(reason, response.status); } const text = await response.text().catch(() => ""); if (!text.trim()) return null; @@ -332,247 +265,161 @@ async function request( } } -function isRecord(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - -function asString(value: unknown): string | undefined { - return typeof value === "string" ? value : undefined; -} - -function projectAmount(value: unknown): MaxCost | undefined { - if (!isRecord(value)) return undefined; - const amount = asString(value.amount); - const currency = asString(value.currency); - return amount && currency ? { amount, currency } : undefined; +type Json = Record; + +const record = (value: unknown): Json => (typeof value === "object" && value !== null && !Array.isArray(value) ? (value as Json) : {}); +const string = (value: unknown): string | undefined => (typeof value === "string" ? value : undefined); +const present = (value: T): Partial => + Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined)) as Partial; + +function projectField(raw: unknown): CheckoutFormField | undefined { + const field = record(raw); + const key = string(field.key); + if (!key) return undefined; + const input = record(field.input); + const selectionKind = string(record(input.selection).kind); + const selection = selectionKind === "one" || selectionKind === "many" ? selectionKind : undefined; + const options = Array.isArray(input.options) + ? input.options.flatMap((option) => { + const { value, label, placeholder, disabled } = record(option); + const v = string(value); + return v === undefined || placeholder === true || disabled === true ? [] : [{ value: v, label: string(label) ?? v }]; + }) + : undefined; + return { + key, + label: string(field.label) ?? key, + required: field.required === true, + handling: field.handling === "protected" ? "protected" : "standard", + kind: string(input.kind) ?? "text", + ...(options ? { options } : {}), + ...(selection ? { selection } : {}), + }; } -function projectInteraction(value: unknown): CheckoutInteraction { - if (!isRecord(value)) return { kind: "unsupported" }; +function projectInteraction(raw: unknown): CheckoutInteraction { + const value = record(raw); if (value.kind === "form" && Array.isArray(value.fields)) { - const fields: CheckoutFormField[] = []; - for (const field of value.fields) { - if (!isRecord(field)) continue; - const key = asString(field.key); - if (!key) continue; - const input = isRecord(field.input) ? field.input : {}; - const choices = Array.isArray(input.choices) - ? input.choices - .map((choice) => { - if (typeof choice === "string") return choice; - if (isRecord(choice)) return asString(choice.value) ?? asString(choice.label); - return undefined; - }) - .filter((choice): choice is string => Boolean(choice)) - : undefined; - fields.push({ - key, - label: asString(field.label) ?? key, - required: field.required === true, - handling: field.handling === "protected" ? "protected" : "standard", - type: asString(input.type) ?? "text", - ...(choices?.length ? { choices } : {}), - }); - } - return { kind: "form", fields }; + return { kind: "form", fields: value.fields.flatMap((field) => projectField(field) ?? []) }; } if (value.kind === "payment") { - const amount = isRecord(value.amount) ? value.amount : {}; - const merchant = isRecord(value.merchant) ? value.merchant : {}; + const amount = record(value.amount); + const merchant = record(value.merchant); return { kind: "payment", - method: asString(value.method) ?? "unknown", - amount: { - kind: amount.kind === "maximum" ? "maximum" : "exact", - value: asString(amount.value) ?? "", - currency: asString(amount.currency) ?? "", - }, - merchant: { - ...(asString(merchant.name) ? { name: asString(merchant.name) } : {}), - ...(asString(merchant.url) ? { url: asString(merchant.url) } : {}), - ...(asString(merchant.countryCode) ? { countryCode: asString(merchant.countryCode) } : {}), - }, + method: string(value.method) ?? "unknown", + amount: { kind: amount.kind === "maximum" ? "maximum" : "exact", value: string(amount.value) ?? "", currency: string(amount.currency) ?? "" }, + merchant: present({ name: string(merchant.name), url: string(merchant.url), countryCode: string(merchant.countryCode) }), }; } return { kind: "unsupported" }; } -const STATUSES: ReadonlySet = new Set([ - "queued", - "running", - "awaiting_input", - "succeeded", - "failed", - "cancelled", - "blocked", -]); - /** Project a raw snapshot to the fields the model may see. Anything unlisted is discarded. */ export function projectCheckout(raw: unknown): CheckoutSnapshot { - if (!isRecord(raw)) throw new CrossmintRequestError("invalid_response"); - const runId = asString(raw.runId); - const status = asString(raw.status); - if (!runId || !status || !STATUSES.has(status)) { - throw new CrossmintRequestError("invalid_response"); - } - const revision = typeof raw.revision === "number" ? raw.revision : 0; + const run = record(raw); + const runId = string(run.runId); + const status = string(run.status); + if (!runId || !status || !STATUSES.has(status)) throw new CrossmintRequestError("invalid_response"); + let requiredAction: CheckoutRequiredAction | null = null; - if (status === "awaiting_input" && isRecord(raw.requiredAction)) { - const action = raw.requiredAction; - const requestId = asString(action.requestId); - const req = isRecord(action.request) ? action.request : {}; - if (requestId) { - requiredAction = { - requestId, - question: asString(req.question) ?? "", - ...(asString(req.expiresAt) ? { expiresAt: asString(req.expiresAt) } : {}), - interaction: projectInteraction(req.interaction), - }; - } + const action = record(run.requiredAction); + const requestId = string(action.requestId); + if (status === "awaiting_input" && requestId) { + const req = record(action.request); + requiredAction = { + requestId, + question: string(req.question) ?? "", + ...present({ expiresAt: string(req.expiresAt) }), + interaction: projectInteraction(req.interaction), + }; } + let result: CheckoutSnapshot["result"] = null; - if (isRecord(raw.result)) { - const purchase = isRecord(raw.result.purchase) ? raw.result.purchase : undefined; - const receipt = purchase && isRecord(purchase.receipt) ? purchase.receipt : undefined; - const kind = purchase ? asString(purchase.kind) : undefined; - result = { - ...(asString(raw.result.outcome) ? { outcome: asString(raw.result.outcome) } : {}), - ...(asString(raw.result.summary) ? { summary: asString(raw.result.summary) } : {}), - ...(asString(raw.result.code) ? { code: asString(raw.result.code) } : {}), - ...(kind + if (run.result !== undefined && run.result !== null) { + const raw = record(run.result); + const purchase = record(raw.purchase); + const receipt = record(purchase.receipt); + const total = record(receipt.total); + const kind = string(purchase.kind); + result = present({ + outcome: string(raw.outcome), + summary: string(raw.summary), + code: string(raw.code), + purchase: kind ? { - purchase: { - kind, - ...(receipt - ? { - receipt: { - ...(projectAmount(receipt.total) ? { total: projectAmount(receipt.total) } : {}), - ...(asString(receipt.merchantOrderId) - ? { merchantOrderId: asString(receipt.merchantOrderId) } - : {}), - }, - } - : {}), - }, + kind, + ...(purchase.receipt !== undefined + ? { + receipt: present({ + total: string(total.amount) && string(total.currency) ? { amount: total.amount as string, currency: total.currency as string } : undefined, + merchantOrderId: string(receipt.merchantOrderId), + }), + } + : {}), } - : {}), - }; + : undefined, + }); } + return { runId, status: status as CheckoutStatus, - revision, + revision: typeof run.revision === "number" ? run.revision : 0, requiredAction, result, - failureReason: status === "failed" ? (asString(raw.reason) ?? "unknown") : null, + failureReason: status === "failed" ? (string(run.reason) ?? "unknown") : null, }; } -export async function createCheckout( - input: CreateCheckoutInput, - options: CrossmintClientOptions = {}, -): Promise<{ runId: string }> { +export async function createCheckout(input: CreateCheckoutInput, options: CrossmintClientOptions = {}): Promise<{ runId: string }> { const config = options.config ?? crossmintConfig(); assertCheckoutPolicy(input.startUrl, input.maxCost, config); const body = { request: { startUrl: input.startUrl, task: input.task }, constraints: { maxCost: input.maxCost }, - ...(config.buyerProfileId ? { buyerProfileId: config.buyerProfileId } : {}), - ...(input.merchantGuidance ? { merchantGuidance: input.merchantGuidance } : {}), - ...(input.countryCode - ? { browser: { location: { type: "country", countryCode: input.countryCode } } } - : {}), + ...present({ + buyerProfileId: config.buyerProfileId, + merchantGuidance: input.merchantGuidance, + browser: input.countryCode ? { location: { type: "country", countryCode: input.countryCode } } : undefined, + }), }; - const raw = await request("/agent-checkouts", { method: "POST", body }, { ...options, config }); - const runId = isRecord(raw) ? asString(raw.runId) : undefined; + const runId = string(record(await request("/agent-checkouts", { method: "POST", body }, { ...options, config })).runId); if (!runId) throw new CrossmintRequestError("invalid_response"); return { runId }; } -export async function getCheckout( - runId: string, - options: CrossmintClientOptions = {}, -): Promise { - const raw = await request( - `/agent-checkouts/${encodeURIComponent(runId)}`, - { method: "GET" }, - options, - ); - return projectCheckout(raw); +export async function getCheckout(runId: string, options: CrossmintClientOptions = {}): Promise { + return projectCheckout(await request(`/agent-checkouts/${encodeURIComponent(runId)}`, { method: "GET" }, options)); } export type FormAnswer = string | number | boolean | string[]; -function message(parts: unknown[]) { - return { id: `bell_${randomUUID()}`, parts }; -} - -export async function answerForm( - runId: string, - requestId: string, - answers: Record, - options: CrossmintClientOptions = {}, -): Promise { +/** One `input_response` part per message, with a fresh message id. */ +async function respond(runId: string, part: Json, options: CrossmintClientOptions): Promise { await request( `/agent-checkouts/${encodeURIComponent(runId)}/messages`, - { - method: "POST", - body: message([ - { - type: "input_response", - requestId, - action: "submit", - response: { kind: "form", answers }, - }, - ]), - }, + { method: "POST", body: { id: `bell_${randomUUID()}`, parts: [{ type: "input_response", ...part }] } }, options, ); } +export function answerForm(runId: string, requestId: string, answers: Record, options: CrossmintClientOptions = {}): Promise { + return respond(runId, { requestId, action: "submit", response: { kind: "form", answers } }, options); +} + /** Pay with the operator's order intent. The id is read from configuration and never returned. */ -export async function payWithOrderIntent( - runId: string, - requestId: string, - options: CrossmintClientOptions = {}, -): Promise { +export async function payWithOrderIntent(runId: string, requestId: string, options: CrossmintClientOptions = {}): Promise { const config = options.config ?? crossmintConfig(); - if (!config.orderIntentId) { - throw new CrossmintSetupError("missing_configuration", "CROSSMINT_ORDER_INTENT_ID"); - } - await request( - `/agent-checkouts/${encodeURIComponent(runId)}/messages`, - { - method: "POST", - body: message([ - { - type: "input_response", - requestId, - action: "submit", - response: { kind: "payment", orderIntentId: config.orderIntentId }, - }, - ]), - }, - { ...options, config }, - ); + if (!config.orderIntentId) throw new CrossmintSetupError("missing_configuration", "CROSSMINT_ORDER_INTENT_ID"); + await respond(runId, { requestId, action: "submit", response: { kind: "payment", orderIntentId: config.orderIntentId } }, { ...options, config }); } -export async function declineRequest( - runId: string, - requestId: string, - options: CrossmintClientOptions = {}, -): Promise { - await request( - `/agent-checkouts/${encodeURIComponent(runId)}/messages`, - { method: "POST", body: message([{ type: "input_response", requestId, action: "decline" }]) }, - options, - ); +export function declineRequest(runId: string, requestId: string, options: CrossmintClientOptions = {}): Promise { + return respond(runId, { requestId, action: "decline" }, options); } -export async function cancelCheckout( - runId: string, - options: CrossmintClientOptions = {}, -): Promise { +export async function cancelCheckout(runId: string, options: CrossmintClientOptions = {}): Promise { await request(`/agent-checkouts/${encodeURIComponent(runId)}/cancel`, { method: "POST" }, options); } @@ -599,20 +446,14 @@ function sleep(ms: number, signal?: AbortSignal): Promise { } /** Poll until the checkout needs input or ends, or until the timeout. Always returns a snapshot. */ -export async function waitForCheckout( - runId: string, - options: WaitOptions = {}, -): Promise { - const timeoutMs = options.timeoutMs ?? 90_000; +export async function waitForCheckout(runId: string, options: WaitOptions = {}): Promise { const intervalMs = options.intervalMs ?? 2_000; - const deadline = Date.now() + timeoutMs; + const deadline = Date.now() + (options.timeoutMs ?? 90_000); let snapshot = await getCheckout(runId, options); for (;;) { const settled = TERMINAL_STATUSES.has(snapshot.status) || - (snapshot.status === "awaiting_input" && - snapshot.requiredAction !== null && - snapshot.requiredAction.requestId !== options.skipRequestId); + (snapshot.status === "awaiting_input" && snapshot.requiredAction !== null && snapshot.requiredAction.requestId !== options.skipRequestId); if (settled || Date.now() >= deadline) return snapshot; options.signal?.throwIfAborted(); await sleep(Math.min(intervalMs, Math.max(0, deadline - Date.now())), options.signal); diff --git a/server/crossmint/payment.ts b/server/crossmint/payment.ts index f8b3c2b..bcff283 100644 --- a/server/crossmint/payment.ts +++ b/server/crossmint/payment.ts @@ -14,11 +14,12 @@ export class PaymentMismatchError extends Error { readonly reason: | "no_payment_request" | "request_changed" - | "amount_mismatch" + | "unsupported_method" + | "unsupported_amount" | "currency_mismatch" + | "amount_mismatch" | "merchant_mismatch" - | "cap_exceeded" - | "unsupported_amount", + | "cap_exceeded", message: string, ) { super(message); @@ -27,11 +28,7 @@ export class PaymentMismatchError extends Error { } function hostOf(value: string): string | undefined { - try { - return new URL(value.includes("://") ? value : `https://${value}`).hostname.toLowerCase(); - } catch { - return undefined; - } + return URL.parse(value.includes("://") ? value : `https://${value}`)?.hostname.toLowerCase(); } /** @@ -39,53 +36,34 @@ function hostOf(value: string): string | undefined { * the run was created under. Anything that differs refuses the payment. The approval dialog shows * the person the model's numbers; this check makes sure those are also Crossmint's numbers. */ -export function assertPaymentMatches( - approved: ApprovedPayment, - live: CheckoutSnapshot, - record: CheckoutRecord, -): { amount: MaxCost; merchant: string } { +export function assertPaymentMatches(approved: ApprovedPayment, live: CheckoutSnapshot, record: CheckoutRecord): { amount: MaxCost; merchant: string } { + const refuse = (reason: PaymentMismatchError["reason"], message: string) => new PaymentMismatchError(reason, message); const action = live.requiredAction; if (live.status !== "awaiting_input" || !action || action.interaction.kind !== "payment") { - throw new PaymentMismatchError( - "no_payment_request", - "Crossmint is not waiting for a payment on this checkout.", - ); + throw refuse("no_payment_request", "Crossmint is not waiting for a payment on this checkout."); } if (action.requestId !== approved.requestId) { - throw new PaymentMismatchError( - "request_changed", - "The payment request changed since approval. Show the person the new request.", - ); + throw refuse("request_changed", "The payment request changed since approval. Show the person the new request."); + } + const { method, amount, merchant } = action.interaction; + if (method !== "card") { + throw refuse("unsupported_method", `Crossmint is asking for a ${method} payment, which an order intent cannot pay. Decline and tell the person.`); } - const { amount, merchant } = action.interaction; if (amount.kind !== "exact") { - throw new PaymentMismatchError( - "unsupported_amount", - "Crossmint sent a maximum rather than an exact total. Decline and ask the person how to proceed.", - ); + throw refuse("unsupported_amount", "Crossmint sent a maximum rather than an exact total. Decline and ask the person how to proceed."); } if (amount.currency !== approved.currency) { - throw new PaymentMismatchError("currency_mismatch", "The approved currency differs from Crossmint's."); + throw refuse("currency_mismatch", "The approved currency differs from Crossmint's."); } if (compareAmounts(amount.value, approved.amount) !== 0) { - throw new PaymentMismatchError( - "amount_mismatch", - `Crossmint is asking for ${amount.value} ${amount.currency}, not the approved amount.`, - ); + throw refuse("amount_mismatch", `Crossmint is asking for ${amount.value} ${amount.currency}, not the approved amount.`); } const liveHost = merchant.url ? hostOf(merchant.url) : undefined; - const approvedHost = hostOf(approved.merchant); - if (!liveHost || !approvedHost || liveHost !== approvedHost) { - throw new PaymentMismatchError( - "merchant_mismatch", - "The approved merchant differs from the one Crossmint is checking out at.", - ); + if (!liveHost || liveHost !== hostOf(approved.merchant)) { + throw refuse("merchant_mismatch", "The approved merchant differs from the one Crossmint is checking out at."); } if (record.maxCost.currency !== amount.currency || compareAmounts(amount.value, record.maxCost.amount) > 0) { - throw new PaymentMismatchError( - "cap_exceeded", - `The total exceeds the ${record.maxCost.amount} ${record.maxCost.currency} cap this checkout was started with.`, - ); + throw refuse("cap_exceeded", `The total exceeds the ${record.maxCost.amount} ${record.maxCost.currency} cap this checkout was started with.`); } return { amount: { amount: amount.value, currency: amount.currency }, merchant: liveHost }; } diff --git a/server/crossmint/runs.ts b/server/crossmint/runs.ts index 485e824..2b03103 100644 --- a/server/crossmint/runs.ts +++ b/server/crossmint/runs.ts @@ -5,8 +5,8 @@ import type { MaxCost } from "./client"; * pay for, or cancel a checkout it started, so a model-supplied id cannot reach another buyer's * run. The cap each run was created with is kept here and checked again at payment time. * - * The registry lives in process memory, like the Link sandbox request set. After a restart or a - * worker change an unfinished checkout is reconciled in the Crossmint console, not retried here. + * The registry lives in process memory. After a restart or a worker change an unfinished checkout + * is reconciled in the Crossmint console, not retried here. */ export interface CheckoutRecord { runId: string; diff --git a/tests/crossmint.test.ts b/tests/crossmint.test.ts index 8944b21..38b8ad5 100644 --- a/tests/crossmint.test.ts +++ b/tests/crossmint.test.ts @@ -1,5 +1,6 @@ -import { describe, expect, it, vi } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { + AMOUNT, answerForm, assertCheckoutPolicy, cancelCheckout, @@ -19,6 +20,8 @@ import { } from "../server/crossmint/client.js"; import { assertPaymentMatches, PaymentMismatchError } from "../server/crossmint/payment.js"; import { assertSessionCheckout, rememberCheckout, sessionCheckout } from "../server/crossmint/runs.js"; +import checkoutTool from "../agent/tools/crossmint_checkout.js"; +import payTool from "../agent/tools/crossmint_pay.js"; const config = { apiKey: "sk_unit_test_only", @@ -39,24 +42,30 @@ const snapshot = (overrides: Record) => ({ ...overrides, }); -const paymentRequest = (amount = "12.49", currency = "USD", url = "https://shop.example") => +const paymentRequest = (amount = "12.49", currency = "USD", url = "https://shop.example", method: Record = { method: "card" }) => snapshot({ status: "awaiting_input", requiredAction: { + messageId: "m", requestId: "req_pay", + type: "input_response", request: { question: `Authorize a card payment of ${amount} ${currency}.`, + expiresAt: "2026-10-28T12:10:00.000Z", interaction: { kind: "payment", - method: "card", purpose: "checkout_payment", amount: { kind: "exact", value: amount, currency }, merchant: { name: "Example Shop", url, countryCode: "US" }, + ...method, }, }, }, }); +const formRequest = (requestId: string, fields: unknown[]) => + snapshot({ status: "awaiting_input", requiredAction: { requestId, request: { question: "Which size?", interaction: { kind: "form", fields } } } }); + describe("Crossmint configuration", () => { it("is optional until used", () => { expect(isCrossmintConfigured({})).toBe(false); @@ -70,6 +79,7 @@ describe("Crossmint configuration", () => { expect(() => crossmintConfig({ ...base, CROSSMINT_SERVER_API_KEY: "ck_client_key" })).toThrow("CROSSMINT_SERVER_API_KEY"); expect(() => crossmintConfig({ ...base, CROSSMINT_API_BASE_URL: "http://insecure.example" })).toThrow("CROSSMINT_API_BASE_URL"); expect(() => crossmintConfig({ ...base, CROSSMINT_MAX_COST: "50 dollars" })).toThrow("CROSSMINT_MAX_COST"); + expect(() => crossmintConfig({ ...base, CROSSMINT_MAX_COST: "0.00 EUR" })).toThrow("CROSSMINT_MAX_COST"); expect(() => crossmintConfig({ ...base, CROSSMINT_ALLOWED_MERCHANTS: "https://shop.example/path" })).toThrow("CROSSMINT_ALLOWED_MERCHANTS"); expect(() => crossmintConfig({ ...base, CROSSMINT_ALLOWED_MERCHANTS: "http://shop.example" })).toThrow("CROSSMINT_ALLOWED_MERCHANTS"); @@ -90,11 +100,17 @@ describe("Crossmint configuration", () => { }); describe("Crossmint checkout policy", () => { - it("compares decimal amounts without floating point", () => { + it("accepts the amounts Crossmint accepts", () => { + for (const value of ["20", "20.00", "0.50", "999999999999999.99"]) expect(AMOUNT.test(value)).toBe(true); + for (const value of ["0", "0.00", "020", "1.234", "-1", "1,00", ""]) expect(AMOUNT.test(value)).toBe(false); + }); + + it("compares decimal amounts without floating point, at six decimals", () => { expect(compareAmounts("20", "20.00")).toBe(0); expect(compareAmounts("19.99", "20.00")).toBe(-1); expect(compareAmounts("20.01", "20.00")).toBe(1); expect(compareAmounts("0.1", "0.10")).toBe(0); + expect(compareAmounts("12.49", "12.491")).toBe(-1); }); it("allows any merchant and any cap when no policy is set", () => { @@ -104,7 +120,7 @@ describe("Crossmint checkout policy", () => { it("refuses merchants outside the allowlist before any request is made", () => { const policy = { ...config, allowedMerchants: ["https://shop.example"] }; expect(() => assertCheckoutPolicy("https://shop.example/p/1", { amount: "1.00", currency: "USD" }, policy)).not.toThrow(); - for (const url of ["https://evil.example/p", "http://shop.example/p", "https://shop.example.evil.example/p", "https://user:pw@shop.example/p"]) { + for (const url of ["https://evil.example/p", "http://shop.example/p", "https://shop.example.evil.example/p", "https://user:pw@shop.example/p", "not a url"]) { expect(() => assertCheckoutPolicy(url, { amount: "1.00", currency: "USD" }, policy)).toThrow(CrossmintPolicyError); } }); @@ -134,11 +150,7 @@ describe("Crossmint client", () => { expect(String(url)).toBe("https://www.crossmint.com/api/unstable/agent-checkouts"); expect(init?.method).toBe("POST"); expect(init?.redirect).toBe("error"); - expect(init?.headers).toMatchObject({ - "X-API-KEY": config.apiKey, - "x-crossmint-user-id": config.userId, - "Content-Type": "application/json", - }); + expect(init?.headers).toMatchObject({ "X-API-KEY": config.apiKey, "x-crossmint-user-id": config.userId, "Content-Type": "application/json" }); expect(JSON.parse(init!.body as string)).toEqual({ request: { startUrl: "https://shop.example/p/1", task: "One sticker pack" }, constraints: { maxCost: { amount: "20.00", currency: "USD" } }, @@ -172,13 +184,11 @@ describe("Crossmint client", () => { it("pays with the server-side order intent only", async () => { const fetcher = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => { const body = JSON.parse(init!.body as string); - expect(body.parts[0].response).toEqual({ kind: "payment", orderIntentId: "oi_test_secret" }); + expect(body.parts[0]).toEqual({ type: "input_response", requestId: "req_pay", action: "submit", response: { kind: "payment", orderIntentId: "oi_test_secret" } }); return Response.json({ messageId: "msg_2", status: "accepted" }, { status: 202 }); }); await payWithOrderIntent("run_1", "req_pay", { config, fetch: fetcher }); - await expect( - payWithOrderIntent("run_1", "req_pay", { config: { ...config, orderIntentId: undefined }, fetch: fetcher }), - ).rejects.toThrow("CROSSMINT_ORDER_INTENT_ID"); + await expect(payWithOrderIntent("run_1", "req_pay", { config: { ...config, orderIntentId: undefined }, fetch: fetcher })).rejects.toThrow("CROSSMINT_ORDER_INTENT_ID"); expect(fetcher).toHaveBeenCalledOnce(); }); @@ -186,7 +196,7 @@ describe("Crossmint client", () => { const calls: string[] = []; const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { calls.push(`${init?.method} ${String(url).replace(config.baseUrl, "")}`); - if (init?.body) expect(JSON.parse(init.body as string).parts[0]).toMatchObject({ action: "decline", requestId: "req_1" }); + if (init?.body) expect(JSON.parse(init.body as string).parts[0]).toEqual({ type: "input_response", action: "decline", requestId: "req_1" }); return new Response(null, { status: 202 }); }); await declineRequest("run_1", "req_1", { config, fetch: fetcher }); @@ -197,9 +207,11 @@ describe("Crossmint client", () => { it("does not expose provider error bodies", async () => { const run = (status: number) => getCheckout("run_1", { config, fetch: async () => new Response("private merchant data", { status }) }); await expect(run(401)).rejects.toThrow(/^Crossmint rejected the API key or its scopes\.$/); + await expect(run(403)).rejects.toThrow(/^Crossmint rejected the API key or its scopes\.$/); await expect(run(404)).rejects.toThrow(/^Crossmint has no checkout with that id for this buyer\.$/); await expect(run(429)).rejects.toThrow(/rate limited/); await expect(run(500)).rejects.toThrow(/^Crossmint returned HTTP 500\.$/); + await expect(getCheckout("run_1", { config, fetch: async () => new Response("private") })).rejects.toThrow(/^Crossmint returned an unexpected response\.$/); await expect( getCheckout("run_1", { config, fetch: async () => { throw new Error("private request details"); } }), ).rejects.toThrow(/^Crossmint request failed\. Check connectivity and retry\.$/); @@ -219,7 +231,7 @@ describe("Crossmint snapshot projection", () => { expect(JSON.stringify(projected)).not.toContain("browser.example"); }); - it("projects a form request and keeps protected handling", () => { + it("projects form fields with Crossmint's input kinds, choice options, and protected handling", () => { const projected = projectCheckout( snapshot({ status: "awaiting_input", @@ -233,8 +245,24 @@ describe("Crossmint snapshot projection", () => { interaction: { kind: "form", fields: [ - { key: "size", label: "Size", required: true, handling: "standard", input: { type: "choice", choices: [{ value: "M", label: "Medium" }, "L"] } }, - { key: "otp", label: "Code", required: true, handling: "protected", input: { type: "text" } }, + { + key: "size", + label: "Size", + required: true, + handling: "standard", + input: { + kind: "choice", + selection: { kind: "one" }, + options: [ + { value: "", label: "Choose a size", placeholder: true, disabled: false, selected: false }, + { value: "M", label: "Medium", placeholder: false, disabled: false, selected: false }, + { value: "XL", label: "XL", placeholder: false, disabled: true, selected: false }, + ], + }, + }, + { key: "quantity", label: "Quantity", required: false, handling: "standard", input: { kind: "integer" } }, + { key: "otp", label: "Code", required: true, handling: "protected", input: { kind: "text", display: "masked", autoComplete: "one-time-code" } }, + { label: "no key", handling: "standard", input: { kind: "text" } }, ], }, }, @@ -248,14 +276,15 @@ describe("Crossmint snapshot projection", () => { interaction: { kind: "form", fields: [ - { key: "size", label: "Size", required: true, handling: "standard", type: "choice", choices: ["M", "L"] }, - { key: "otp", label: "Code", required: true, handling: "protected", type: "text" }, + { key: "size", label: "Size", required: true, handling: "standard", kind: "choice", options: [{ value: "M", label: "Medium" }], selection: "one" }, + { key: "quantity", label: "Quantity", required: false, handling: "standard", kind: "integer" }, + { key: "otp", label: "Code", required: true, handling: "protected", kind: "text" }, ], }, }); }); - it("projects a payment request to amount and merchant only", () => { + it("projects a payment request to method, amount, and merchant only", () => { const raw = paymentRequest(); (raw.requiredAction as unknown as { request: { interaction: Record } }).request.interaction.card = { number: "4242" }; const projected = projectCheckout(raw); @@ -266,6 +295,9 @@ describe("Crossmint snapshot projection", () => { merchant: { name: "Example Shop", url: "https://shop.example", countryCode: "US" }, }); expect(JSON.stringify(projected)).not.toContain("4242"); + const klarna = projectCheckout(paymentRequest("12.49", "USD", "https://shop.example", { method: "klarna", authorizationUrl: "https://uc.example/pay/secret" })); + expect(klarna.requiredAction?.interaction).toMatchObject({ kind: "payment", method: "klarna" }); + expect(JSON.stringify(klarna)).not.toContain("uc.example"); }); it("keeps receipt metadata on success and codes on blocked or failed runs", () => { @@ -277,6 +309,8 @@ describe("Crossmint snapshot projection", () => { }), ).result, ).toEqual({ outcome: "succeeded", summary: "Ordered one sticker pack.", purchase: { kind: "receipt_captured", receipt: { total: { amount: "12.49", currency: "USD" }, merchantOrderId: "A-100" } } }); + expect(projectCheckout(snapshot({ status: "succeeded", result: { outcome: "succeeded", summary: "Confirmed.", purchase: { kind: "confirmed_without_receipt" } } })).result) + .toEqual({ outcome: "succeeded", summary: "Confirmed.", purchase: { kind: "confirmed_without_receipt" } }); expect(projectCheckout(snapshot({ status: "blocked", result: { outcome: "blocked", code: "merchant.payment_declined", summary: "Declined." } })).result) .toEqual({ outcome: "blocked", code: "merchant.payment_declined", summary: "Declined." }); expect(projectCheckout(snapshot({ status: "failed", reason: "cost_limit" })).failureReason).toBe("cost_limit"); @@ -285,6 +319,7 @@ describe("Crossmint snapshot projection", () => { it("rejects malformed snapshots", () => { expect(() => projectCheckout({ status: "running" })).toThrow(CrossmintRequestError); expect(() => projectCheckout(snapshot({ status: "exploded" }))).toThrow(CrossmintRequestError); + expect(() => projectCheckout("not json")).toThrow(CrossmintRequestError); }); }); @@ -301,8 +336,10 @@ describe("Crossmint payment cross-check", () => { it.each([ ["no_payment_request", approved, snapshot({ status: "running" })], ["request_changed", { ...approved, requestId: "req_old" }, paymentRequest()], - ["amount_mismatch", { ...approved, amount: "12.48" }, paymentRequest()], + ["unsupported_method", approved, paymentRequest("12.49", "USD", "https://shop.example", { method: "klarna", authorizationUrl: "https://uc.example/pay" })], + ["unsupported_amount", approved, paymentRequest("12.49", "USD", "https://shop.example", { method: "card", amount: { kind: "maximum", value: "12.49", currency: "USD" } })], ["currency_mismatch", { ...approved, currency: "EUR" }, paymentRequest()], + ["amount_mismatch", { ...approved, amount: "12.48" }, paymentRequest()], ["merchant_mismatch", { ...approved, merchant: "evil.example" }, paymentRequest()], ["cap_exceeded", { ...approved, amount: "20.01" }, paymentRequest("20.01")], ] as const)("refuses on %s", (reason, input, raw) => { @@ -315,20 +352,14 @@ describe("Crossmint payment cross-check", () => { expect(caught).toBeInstanceOf(PaymentMismatchError); expect((caught as PaymentMismatchError).reason).toBe(reason); }); - - it("refuses a maximum amount, which cannot be shown to the person as an exact total", () => { - const raw = paymentRequest(); - (raw.requiredAction as unknown as { request: { interaction: { amount: { kind: string } } } }).request.interaction.amount.kind = "maximum"; - expect(() => assertPaymentMatches(approved, live(raw), record)).toThrow(/maximum rather than an exact total/); - }); }); describe("Crossmint polling", () => { it("waits through running states, skips an answered request, and stops on new input or a terminal state", async () => { const sequence = [ snapshot({ status: "running", revision: 1 }), - snapshot({ status: "awaiting_input", revision: 2, requiredAction: { requestId: "answered", request: { question: "old", interaction: { kind: "form", fields: [] } } } }), - snapshot({ status: "awaiting_input", revision: 3, requiredAction: { requestId: "req_new", request: { question: "new", interaction: { kind: "form", fields: [] } } } }), + formRequest("answered", []), + { ...formRequest("req_new", []), revision: 3 }, ]; const fetcher = vi.fn(async () => Response.json(sequence.shift() ?? sequence.at(-1))); const result = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, skipRequestId: "answered" }); @@ -365,3 +396,57 @@ describe("Crossmint run registry", () => { expect(() => assertSessionCheckout("session-b", "run_a")).toThrow("did not start that checkout"); }); }); + +describe("Crossmint tools", () => { + const principal = { principalId: "linq:1", principalType: "user", authenticator: "linq-message", attributes: {} }; + const ctx = (auth: typeof principal | null, id = "session-tools") => ({ session: { id, auth: { current: auth, initiator: auth } }, abortSignal: new AbortController().signal }); + const configure = () => { + vi.stubEnv("CROSSMINT_SERVER_API_KEY", "sk_unit_test_only"); + vi.stubEnv("CROSSMINT_USER_ID", "operator-1"); + vi.stubEnv("CROSSMINT_ORDER_INTENT_ID", ""); + }; + afterEach(() => vi.unstubAllEnvs()); + + it("answer not_configured until the variables are set", async () => { + vi.stubEnv("CROSSMINT_SERVER_API_KEY", ""); + vi.stubEnv("CROSSMINT_USER_ID", ""); + expect(await checkoutTool.execute({ action: "status", runId: "run_1" }, ctx(principal) as never)).toMatchObject({ status: "not_configured" }); + expect(await payTool.execute({ runId: "run_1", requestId: "req_pay", amount: "12.49", currency: "USD", merchant: "shop.example" }, ctx(principal) as never)).toMatchObject({ status: "not_configured" }); + }); + + it("let only the requesting principal approve a payment", () => { + const policy = (payTool.approval as { response: (ctx: unknown) => { status: string } }).response; + const other = { ...principal, principalId: "linq:2" }; + expect(policy({ request: { principal }, response: { principal } })).toEqual({ status: "allowed" }); + expect(policy({ request: { principal }, response: { principal: other } })).toMatchObject({ status: "rejected" }); + expect(policy({ request: { principal: null }, response: { principal } })).toMatchObject({ status: "rejected" }); + }); + + it("refuse protected form fields before anything is sent", async () => { + configure(); + const fetcher = vi.fn(async () => Response.json(formRequest("req_1", [{ key: "otp", label: "Code", required: true, handling: "protected", input: { kind: "text" } }]))); + vi.stubGlobal("fetch", fetcher); + rememberCheckout("session-tools", { runId: "run_1", maxCost: { amount: "20.00", currency: "USD" }, principalId: "linq:1" }); + expect(await checkoutTool.execute({ action: "answer", runId: "run_1", requestId: "req_1", answers: { otp: "123456" } }, ctx(principal) as never)).toMatchObject({ status: "error", reason: "protected_field" }); + expect(fetcher).toHaveBeenCalledOnce(); + await expect(Promise.resolve(checkoutTool.execute({ action: "status", runId: "run_1" }, ctx(principal, "session-other") as never))).rejects.toThrow("did not start that checkout"); + }); + + it("stop at payment_not_configured after the cross-check when no order intent is set", async () => { + configure(); + const fetcher = vi.fn(async () => Response.json(paymentRequest())); + vi.stubGlobal("fetch", fetcher); + rememberCheckout("session-tools", { runId: "run_1", maxCost: { amount: "20.00", currency: "USD" }, principalId: "linq:1" }); + const input = { runId: "run_1", requestId: "req_pay", amount: "12.49", currency: "USD", merchant: "shop.example" }; + expect(await payTool.execute(input, ctx(null) as never)).toMatchObject({ status: "error", reason: "authentication_required" }); + expect(await payTool.execute(input, ctx({ ...principal, principalId: "linq:2" }) as never)).toMatchObject({ status: "error", reason: "principal_mismatch" }); + expect(await payTool.execute({ ...input, amount: "12.48" }, ctx(principal) as never)).toMatchObject({ status: "error", reason: "amount_mismatch" }); + expect(await payTool.execute(input, ctx(principal) as never)).toEqual({ + status: "payment_not_configured", + runId: "run_1", + requestId: "req_pay", + hint: expect.stringContaining("No order intent"), + }); + expect(fetcher.mock.calls.every((call) => (call as unknown[])[1] === undefined || ((call as unknown[])[1] as RequestInit).method === "GET")).toBe(true); + }); +}); From 8cb036a48beed98d47a35791ce630fdb1f242ddc Mon Sep 17 00:00:00 2001 From: Alejandro Dopico Date: Mon, 2 Nov 2026 14:20:58 +0100 Subject: [PATCH 3/3] Set up Crossmint payments in Bell and show checkout progress Agent Checkouts could not pay on its own: the order intent it needs takes a client key with the user's JWT, and only the card branch could sign one. Move the operator token, the JWKS route, the operator-only proxy, and the Crossmint React SDK here, and add /crossmint/setup, an operator page in Crossmint's styling. It checks the connection live and shows the JWKS endpoint and issuer to paste when Crossmint rejects Bell's token, saves delivery details as a buyer profile, lists budgets with what is left and their card rails, cancels them, and approves new ones in Crossmint's card form after an explicit confirmation, with one idempotency key per draft. It registers the card with the operator's email before creating the order intent, because Crossmint refuses an empty registration and its card component sends one. A card without a Visa or Mastercard agent rail still pays through Crossmint's encrypted card, and the page says so. The proxy forbids framing, and every action checks the operator's credentials and origin again. While a run works, crossmint_checkout returns at each new stage, a fixed phrase chosen from Crossmint's activity kinds, so Bell tells the person what is happening instead of showing "Working" for minutes. Crossmint's own progress text is never passed on, since it can name the buyer and is written while reading merchant pages. Progress reads stay within the wait and stop on cancel. The approval names the payee in plain words, "Pay 16.90 EUR at Zara (payments.zara.com) with your saved card?", and the server cross-check now also refuses a store name that is not Crossmint's. Co-Authored-By: Claude Opus 5.5 --- .env.example | 18 +- README.md | 2 +- agent/instructions.md | 9 +- agent/lib/crossmint.ts | 22 + agent/tools/crossmint_checkout.ts | 47 +- agent/tools/crossmint_pay.ts | 16 +- app/api/crossmint/jwks/route.ts | 15 + app/crossmint/setup/actions.ts | 142 + app/crossmint/setup/crossmint-logo.svg | 39 + app/crossmint/setup/page.tsx | 82 + app/crossmint/setup/setup.module.css | 521 ++ app/crossmint/setup/setup.tsx | 466 ++ app/crossmint/setup/view.ts | 56 + docs/crossmint.md | 179 +- docs/repository.md | 2 +- package.json | 2 + pnpm-lock.yaml | 6896 +++++++++++++++++++++++- proxy.ts | 17 + scripts/crossmint-operator-jwt.mjs | 15 + scripts/demo-crossmint.mjs | 27 + server/crossmint/client.ts | 132 +- server/crossmint/operator-jwt.ts | 57 + server/crossmint/operator.ts | 247 + server/crossmint/payment.ts | 9 +- server/crossmint/runs.ts | 2 + tests/crossmint-setup.test.ts | 198 + tests/crossmint.test.ts | 131 + 27 files changed, 9138 insertions(+), 211 deletions(-) create mode 100644 app/api/crossmint/jwks/route.ts create mode 100644 app/crossmint/setup/actions.ts create mode 100644 app/crossmint/setup/crossmint-logo.svg create mode 100644 app/crossmint/setup/page.tsx create mode 100644 app/crossmint/setup/setup.module.css create mode 100644 app/crossmint/setup/setup.tsx create mode 100644 app/crossmint/setup/view.ts create mode 100644 proxy.ts create mode 100644 scripts/crossmint-operator-jwt.mjs create mode 100644 server/crossmint/operator-jwt.ts create mode 100644 server/crossmint/operator.ts create mode 100644 tests/crossmint-setup.test.ts diff --git a/.env.example b/.env.example index 3c884db..4750f06 100644 --- a/.env.example +++ b/.env.example @@ -67,13 +67,19 @@ LINK_TOKEN_ENCRYPTION_KEY= # Exact trusted checkout/frame origins per approved merchant (JSON object). LINK_CHECKOUT_ORIGINS={} -# Optional Crossmint Agent Checkouts. Buy at any store with the person's own card. -# Production server key (sk_) with agent-checkouts.* scopes. See docs/crossmint.md. Leave unset to keep the tools disabled. +# Optional Crossmint Agent Checkouts. Buy at any store with the person's own card. See docs/crossmint.md. +# Production server key (sk_) with agent-checkouts.* scopes. Leave unset to keep the tools disabled. CROSSMINT_SERVER_API_KEY= CROSSMINT_USER_ID= -# The operator's approved order intent id. Required only to pay; never shown to the model. -CROSSMINT_ORDER_INTENT_ID= -# Optional saved buyer profile, per-checkout ceiling ("50.00 EUR"), and exact merchant origins. -CROSSMINT_BUYER_PROFILE_ID= +# Optional per-checkout ceiling ("50.00 EUR") and exact merchant origins. CROSSMINT_MAX_COST= CROSSMINT_ALLOWED_MERCHANTS= +# Set up in Bell at /crossmint/setup (operator only): the saved delivery details and the approved budget. +CROSSMINT_BUYER_PROFILE_ID= +# The budget (order intent) Bell pays with. Required only to pay; never shown to the model. +CROSSMINT_ORDER_INTENT_ID= +# For the setup page: client key (ck_) with payment-methods.* and order-intents.* scopes, the project id, +# and a base64 PEM RSA key that signs the operator token Crossmint checks at /api/crossmint/jwks. +CROSSMINT_CLIENT_API_KEY= +CROSSMINT_PROJECT_ID= +CROSSMINT_JWT_PRIVATE_KEY= diff --git a/README.md b/README.md index 3d03caf..102846f 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ pnpm dev | Link by Stripe | Wallet authorization, spend approval, and checkout through Linq | [Sandbox and wallet setup](docs/link.md) | | 1Password | Operator credentials and OTP; personal Agentic Autofill is disabled by default | [Operator access](docs/browser-runtime.md#credentials-and-otp) ยท [Personal access status](docs/onepassword.md) | | Baselayer | Verified access to approved merchants using short-lived credentials | [Merchant access](docs/baselayer.md) | -| Crossmint | Buy at any store with the person's own card, worldwide, under a spending cap the person approves | [Agent checkouts](docs/crossmint.md) | +| Crossmint | Buy at any store with the person's own card, worldwide, under a spending cap the person approves on Bell's setup page | [Agent checkouts](docs/crossmint.md) | See the [repository layout and implementation map](docs/repository.md) to extend Bell. diff --git a/agent/instructions.md b/agent/instructions.md index dd99a2e..78d84c6 100644 --- a/agent/instructions.md +++ b/agent/instructions.md @@ -42,9 +42,12 @@ For private Linq senders, use `onepassword_connect`, `onepassword_status`, `onep Use crossmint_checkout when Crossmint Agent Checkouts is configured and the user wants a purchase completed by Crossmint rather than in this conversation's browser. It works at any store, pays with the user's own card, and the card number never reaches you. Start with the product URL, the request, -and the user's spending cap. Answer form questions from what the user said, using option values for -choice fields, and never fill protected fields. At a payment request, call crossmint_pay with the -amount, currency, and merchant copied from the request. Eve asks the person to approve, and the +and the user's spending cap. The checkout runs in Crossmint's browser, so this conversation's browser +stays idle. While it runs, each result can carry progress: tell the user in one short sentence what +Crossmint is doing, in your own words and without ids, then call crossmint_checkout status again. Do +not repeat a stage you already reported. Answer form questions from what the user said, using option +values for choice fields, and never fill protected fields. At a payment request, call crossmint_pay +with the amount, currency, merchant, and merchant name copied from the request. Eve asks the person to approve, and the server verifies those values against Crossmint before paying. Call crossmint_checkout decline if the person says no. Only a succeeded result with purchase.kind receipt_captured is a placed order. Report any other outcome as what it is. Never start a second checkout for the same request while one is diff --git a/agent/lib/crossmint.ts b/agent/lib/crossmint.ts index 87cb67d..f5eacc5 100644 --- a/agent/lib/crossmint.ts +++ b/agent/lib/crossmint.ts @@ -1,3 +1,4 @@ +import type { ApprovalResponseContext, ApprovalResponseDecision } from "eve/tools/approval"; import { z } from "zod"; import { AMOUNT, @@ -7,9 +8,15 @@ import { isCrossmintConfigured, type CheckoutSnapshot, } from "../../server/crossmint/client"; +import { hostOf } from "../../server/crossmint/payment"; /** How long one tool call waits for Crossmint before returning the latest snapshot. */ export const WAIT_MS = 90_000; +/** After starting a run, return at the first progress so the person hears back within seconds. */ +export const FIRST_UPDATE_MS = 25_000; +/** While a run works, return at most this late, and no sooner than MIN_UPDATE_MS unless it settles. */ +export const UPDATE_MS = 60_000; +export const MIN_UPDATE_MS = 15_000; export const amount = z.string().regex(AMOUNT, "Decimal string such as 20.00"); export const currency = z.string().length(3).toUpperCase().describe("ISO 4217 code, such as USD or EUR."); @@ -26,6 +33,21 @@ export function notConfigured(): CheckoutToolOutput | undefined { return { status: "not_configured", hint: "Set CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID on the server. See docs/crossmint.md." }; } +/** "Zara (payments.zara.com)" or just the host: the approval names who is paid in plain words. */ +export function payee(input: { merchant: string; merchantName?: string }): string { + const host = hostOf(input.merchant) ?? input.merchant; + const name = input.merchantName?.trim(); + return name && name.toLowerCase() !== host ? `${name} (${host})` : host; +} + +/** Approval response policy for payments: only the authenticated sender who asked can approve. */ +export function requesterOnly({ request, response }: Pick, "request" | "response">): ApprovalResponseDecision { + const requester = request.principal; + if (!requester) return { status: "rejected", reason: "Payments need an authenticated sender." }; + const same = response.principal.principalId === requester.principalId && response.principal.authenticator === requester.authenticator; + return same ? { status: "allowed" } : { status: "rejected", reason: "Only the person who requested this payment can approve it." }; +} + /** Crossmint errors carry fixed, sanitized messages the model may see. Anything else is rethrown. */ export function errorOutput(error: unknown): CheckoutToolOutput { if (error instanceof CrossmintSetupError || error instanceof CrossmintRequestError || error instanceof CrossmintPolicyError) { diff --git a/agent/tools/crossmint_checkout.ts b/agent/tools/crossmint_checkout.ts index a024df4..7fa5898 100644 --- a/agent/tools/crossmint_checkout.ts +++ b/agent/tools/crossmint_checkout.ts @@ -1,8 +1,35 @@ import { defineTool, toolOutput } from "eve/tools"; import { z } from "zod"; -import { amount, currency, errorOutput, notConfigured, requestId, runId, WAIT_MS, type CheckoutToolOutput } from "../lib/crossmint"; -import { answerForm, cancelCheckout, createCheckout, declineRequest, getCheckout, waitForCheckout } from "../../server/crossmint/client"; -import { assertSessionCheckout, rememberCheckout } from "../../server/crossmint/runs"; +import { + amount, + currency, + errorOutput, + FIRST_UPDATE_MS, + MIN_UPDATE_MS, + notConfigured, + requestId, + runId, + UPDATE_MS, + type CheckoutToolOutput, +} from "../lib/crossmint"; +import { + answerForm, + cancelCheckout, + createCheckout, + declineRequest, + getCheckout, + waitForCheckout, + type CheckoutSnapshot, + type WaitOptions, +} from "../../server/crossmint/client"; +import { assertSessionCheckout, rememberCheckout, type CheckoutRecord } from "../../server/crossmint/runs"; + +/** Wait for the next step or, while the run works, the next new stage, and remember what was reported. */ +async function nextUpdate(record: CheckoutRecord, options: WaitOptions): Promise { + const snapshot = await waitForCheckout(record.runId, { progressSince: record.lastStage ?? null, ...options }); + if (snapshot.progress) record.lastStage = snapshot.progress.stage; + return snapshot; +} const inputSchema = z.discriminatedUnion("action", [ z.object({ @@ -28,7 +55,7 @@ const inputSchema = z.discriminatedUnion("action", [ export default defineTool({ description: - "Buy at any store through Crossmint Agent Checkouts under a hard spending cap. Crossmint picks the fastest path for the store, the merchant API, an agent protocol, or its own checkout browser, so nothing runs in this conversation's browser. The person pays with their own card, worldwide, and the card number never reaches this assistant. Call start with the product URL, a plain-language task, and maxCost, then follow requiredAction. For a form, call answer with one value per field key. For a payment, call crossmint_pay. decline refuses a request and cancel stops the run. Each call returns a status snapshot and waits up to ninety seconds for the next step. A succeeded result with purchase.kind receipt_captured is the only proof of a placed order. Never start a second checkout for the same request while one is unresolved.", + "Buy at any store through Crossmint Agent Checkouts under a hard spending cap. Crossmint picks the fastest path for the store, the merchant API, an agent protocol, or its own checkout browser, so nothing runs in this conversation's browser. The person pays with their own card, worldwide, and the card number never reaches this assistant. Call start with the product URL, a plain-language task, and maxCost, then follow requiredAction. For a form, call answer with one value per field key. For a payment, call crossmint_pay. decline refuses a request and cancel stops the run. Each call returns a status snapshot: start returns within about twenty-five seconds, and status waits for the next step or, while the run works, the next progress stage, up to a minute. When the snapshot carries progress, tell the person in one short sentence what Crossmint is doing, then call status again. A succeeded result with purchase.kind receipt_captured is the only proof of a placed order. Never start a second checkout for the same request while one is unresolved.", inputSchema, label: { start: (input) => @@ -44,14 +71,14 @@ export default defineTool({ switch (input.action) { case "start": { const { runId } = await createCheckout(input, { signal }); - rememberCheckout(sessionId, { runId, maxCost: input.maxCost, principalId: ctx.session.auth.current?.principalId ?? null }); - return await waitForCheckout(runId, { signal, timeoutMs: WAIT_MS }); + const record = { runId, maxCost: input.maxCost, principalId: ctx.session.auth.current?.principalId ?? null }; + rememberCheckout(sessionId, record); + return await nextUpdate(record, { signal, timeoutMs: FIRST_UPDATE_MS }); } case "status": - assertSessionCheckout(sessionId, input.runId); - return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS }); + return await nextUpdate(assertSessionCheckout(sessionId, input.runId), { signal, timeoutMs: UPDATE_MS, minProgressMs: MIN_UPDATE_MS }); case "answer": { - assertSessionCheckout(sessionId, input.runId); + const record = assertSessionCheckout(sessionId, input.runId); const current = await getCheckout(input.runId, { signal }); const action = current.requiredAction; if (!action || action.requestId !== input.requestId) return current; @@ -67,7 +94,7 @@ export default defineTool({ }; } await answerForm(input.runId, input.requestId, input.answers, { signal }); - return await waitForCheckout(input.runId, { signal, timeoutMs: WAIT_MS, skipRequestId: input.requestId }); + return await nextUpdate(record, { signal, timeoutMs: UPDATE_MS, minProgressMs: MIN_UPDATE_MS, skipRequestId: input.requestId }); } case "decline": assertSessionCheckout(sessionId, input.runId); diff --git a/agent/tools/crossmint_pay.ts b/agent/tools/crossmint_pay.ts index 6c2c2c1..d087ff1 100644 --- a/agent/tools/crossmint_pay.ts +++ b/agent/tools/crossmint_pay.ts @@ -1,7 +1,7 @@ import { defineTool, toolOutput } from "eve/tools"; import { always } from "eve/tools/approval"; import { z } from "zod"; -import { amount, currency, errorOutput, notConfigured, requestId, runId, WAIT_MS, type CheckoutToolOutput } from "../lib/crossmint"; +import { amount, currency, errorOutput, notConfigured, payee, requestId, requesterOnly, runId, WAIT_MS, type CheckoutToolOutput } from "../lib/crossmint"; import { CrossmintSetupError, getCheckout, payWithOrderIntent, waitForCheckout } from "../../server/crossmint/client"; import { assertPaymentMatches, PaymentMismatchError } from "../../server/crossmint/payment"; import { assertSessionCheckout } from "../../server/crossmint/runs"; @@ -12,6 +12,7 @@ const inputSchema = z.object({ amount: amount.describe("The exact total Crossmint is asking for, copied from the payment request."), currency, merchant: z.string().min(1).max(255).describe("The merchant URL or host from the payment request."), + merchantName: z.string().min(1).max(120).optional().describe("The merchant's name from the payment request, when it has one."), }); type Input = z.infer; @@ -20,20 +21,15 @@ type PayOutput = CheckoutToolOutput | { status: "payment_not_configured"; runId: export default defineTool({ description: - "Pay the open payment request of a Crossmint checkout with the person's own card, through the order intent held on the server. Copy amount, currency, and merchant exactly from the payment request. Eve stops and asks the person to approve this call. The server then compares those three values with the live request and with the cap the run started with, and refuses on any difference. The card number never reaches this assistant. Needs an authenticated sender. Call once per payment request. Use crossmint_checkout decline if the person says no.", + "Pay the open payment request of a Crossmint checkout with the person's own card, through the order intent held on the server. Copy amount, currency, and merchant exactly from the payment request, and its merchant name when it has one. Eve stops and asks the person to approve this call. The server then compares those three values with the live request and with the cap the run started with, and refuses on any difference. The card number never reaches this assistant. Needs an authenticated sender. Call once per payment request. Use crossmint_checkout decline if the person says no.", inputSchema, label: { - start: (input: Readonly) => `Paying ${input.amount} ${input.currency} at ${input.merchant} through Crossmint`, + start: (input: Readonly) => `Paying ${input.amount} ${input.currency} at ${payee(input)} through Crossmint`, }, approval: { request: always(), - prompt: ({ input }) => `Pay ${input.amount} ${input.currency} to ${input.merchant} with your Crossmint order intent?`, - response: ({ request, response }) => { - const requester = request.principal; - if (!requester) return { status: "rejected", reason: "Payments need an authenticated sender." }; - const same = response.principal.principalId === requester.principalId && response.principal.authenticator === requester.authenticator; - return same ? { status: "allowed" } : { status: "rejected", reason: "Only the person who requested this payment can approve it." }; - }, + prompt: ({ input }) => `Pay ${input.amount} ${input.currency} at ${payee(input)} with your saved card?`, + response: requesterOnly, }, async execute(input, ctx): Promise { ctx.abortSignal.throwIfAborted(); diff --git a/app/api/crossmint/jwks/route.ts b/app/api/crossmint/jwks/route.ts new file mode 100644 index 0000000..6d9636e --- /dev/null +++ b/app/api/crossmint/jwks/route.ts @@ -0,0 +1,15 @@ +import { operatorJwks, parseRsaPrivateKey } from "../../../../server/crossmint/operator-jwt"; + +export const runtime = "nodejs"; +export const dynamic = "force-dynamic"; + +const headers = { "cache-control": "no-store", "x-content-type-options": "nosniff" }; + +// Public by design: Crossmint fetches this to check the operator JWTs Bell signs. +export function GET() { + const configured = process.env.CROSSMINT_JWT_PRIVATE_KEY?.trim(); + if (!configured) return new Response("Not found.", { status: 404, headers }); + const key = parseRsaPrivateKey(configured); + if (!key) return new Response("Check CROSSMINT_JWT_PRIVATE_KEY in the server configuration.", { status: 500, headers }); + return Response.json(operatorJwks(key), { headers: { ...headers, "cache-control": "public, max-age=300" } }); +} diff --git a/app/crossmint/setup/actions.ts b/app/crossmint/setup/actions.ts new file mode 100644 index 0000000..405cfd1 --- /dev/null +++ b/app/crossmint/setup/actions.ts @@ -0,0 +1,142 @@ +"use server"; + +import { routeAuth } from "eve/channels/auth"; +import { headers } from "next/headers"; +import { z } from "zod"; +import { AMOUNT, createBuyerProfile, CrossmintRequestError, CrossmintSetupError } from "../../../server/crossmint/client"; +import { + cancelOrderIntent, + createOrderIntent, + CrossmintOperatorError, + getRegistration, + operatorConfig, + registerCard, +} from "../../../server/crossmint/operator"; +import { operatorJwt } from "../../../server/crossmint/operator-jwt"; +import { operatorAuth } from "../../../server/operator-auth"; +import { budgetView, type Budget, type ProfileView, profileView } from "./view"; + +export type ActionResult = ({ ok: true } & T) | { ok: false; message: string }; + +/** + * The proxy already asked for the operator's credentials; every action checks them again, as the + * POST it is, so the same-origin guard for writes runs here too. + */ +async function requireOperator(): Promise { + const incoming = await headers(); + const host = incoming.get("x-forwarded-host") ?? incoming.get("host") ?? "localhost"; + const protocol = incoming.get("x-forwarded-proto") ?? "http"; + const request = new Request(`${protocol}://${host}/crossmint/setup`, { method: "POST", headers: incoming }); + const auth = await routeAuth(request, [operatorAuth]); + if (auth instanceof Response) throw new Error("Sign in as the Bell operator."); +} + +/** Operator-facing messages. Crossmint's own message is kept when it names the fix. */ +function failure(error: unknown): { ok: false; message: string } { + if (error instanceof CrossmintOperatorError) { + return { ok: false, message: error.detail ? `${error.message} Crossmint says: ${error.detail}` : error.message }; + } + if (error instanceof CrossmintSetupError || error instanceof CrossmintRequestError) return { ok: false, message: error.message }; + if (error instanceof z.ZodError) return { ok: false, message: error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ") }; + throw error; +} + +/** A fresh ten-minute operator token for Crossmint's card form. */ +export async function refreshToken(): Promise> { + await requireOperator(); + try { + return { ok: true, jwt: operatorJwt(operatorConfig()) }; + } catch (error) { + return failure(error); + } +} + +const country = z.string().trim().regex(/^[A-Za-z]{2}$/, "two-letter country code").transform((value) => value.toUpperCase()); + +const profileInput = z.object({ + first: z.string().trim().min(1).max(100), + last: z.string().trim().min(1).max(100), + email: z.string().trim().email().max(254), + phone: z.string().trim().min(5).max(40), + street: z.string().trim().min(1).max(200), + street2: z.string().trim().max(200).optional(), + postalCode: z.string().trim().min(1).max(40), + locality: z.string().trim().min(1).max(120), + region: z.string().trim().max(10).optional(), + countryCode: country, +}); + +/** Save the delivery details checkouts use instead of asking. No payment data is stored. */ +export async function saveBuyerProfile(input: z.input): Promise> { + await requireOperator(); + try { + const value = profileInput.parse(input); + const saved = await createBuyerProfile({ + label: "Bell", + name: { first: value.first, last: value.last }, + contact: { email: value.email, phone: value.phone }, + shipping: { + addressLines: [value.street, value.street2].filter((line): line is string => Boolean(line)), + locality: value.locality, + countryCode: value.countryCode, + administrativeAreaCode: value.region ? value.region.toUpperCase() : null, + postalCode: value.postalCode, + }, + }); + return { ok: true, id: saved.id, profile: profileView(saved) }; + } catch (error) { + return failure(error); + } +} + +const budgetInput = z.object({ + paymentMethodId: z.string().min(1).max(200), + /** One per draft, so a repeated or retried approval never creates a second budget. */ + idempotencyKey: z.string().regex(/^[A-Za-z0-9-]{16,64}$/), + amount: z.string().regex(AMOUNT, "decimal amount such as 30.00"), + currency: z.string().trim().regex(/^[A-Za-z]{3}$/, "three-letter currency code").transform((value) => value.toUpperCase()), + days: z.coerce.number().int().min(1).max(365), + description: z.string().trim().min(1).max(200), + merchant: z.object({ + name: z.string().trim().min(1).max(200), + url: z.string().trim().url().refine((value) => value.startsWith("https://"), "an HTTPS URL"), + countryCode: country, + }), + consumer: z.object({ email: z.string().trim().email(), countryCode: country, languageCode: z.string().trim().min(2).max(35) }), +}); + +/** + * Register the saved card with the person's email, then approve the budget. Crossmint refuses an + * empty registration, and Crossmint's card component sends one, so Bell registers first. + */ +export async function approveBudget(input: z.input): Promise> { + await requireOperator(); + try { + const value = budgetInput.parse(input); + const registration = await getRegistration(value.paymentMethodId); + if (!registration || !registration.rails.some((rail) => rail.status === "enabled")) { + await registerCard(value.paymentMethodId, value.consumer); + } + const intent = await createOrderIntent({ + paymentMethodId: value.paymentMethodId, + amount: { value: value.amount, currency: value.currency }, + merchant: value.merchant, + description: value.description, + expiresAt: new Date(Date.now() + value.days * 86_400_000).toISOString(), + }, { idempotencyKey: `bell-budget-${value.idempotencyKey}` }); + return { ok: true, budget: budgetView(intent, process.env.CROSSMINT_ORDER_INTENT_ID?.trim()) }; + } catch (error) { + return failure(error); + } +} + +/** Cancel a budget. Nothing more can be spent from it. */ +export async function cancelBudget(orderIntentId: string): Promise> { + await requireOperator(); + try { + await cancelOrderIntent(z.string().min(1).max(200).parse(orderIntentId)); + return { ok: true }; + } catch (error) { + return failure(error); + } +} diff --git a/app/crossmint/setup/crossmint-logo.svg b/app/crossmint/setup/crossmint-logo.svg new file mode 100644 index 0000000..a86ea1a --- /dev/null +++ b/app/crossmint/setup/crossmint-logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/crossmint/setup/page.tsx b/app/crossmint/setup/page.tsx new file mode 100644 index 0000000..b0943f7 --- /dev/null +++ b/app/crossmint/setup/page.tsx @@ -0,0 +1,82 @@ +import { routeAuth } from "eve/channels/auth"; +import type { Metadata } from "next"; +import { headers } from "next/headers"; +import { crossmintConfig, CrossmintSetupError, getBuyerProfile, isCrossmintConfigured } from "../../../server/crossmint/client"; +import { CrossmintOperatorError, listOrderIntents, operatorConfig, type OperatorConfig } from "../../../server/crossmint/operator"; +import { operatorAuth } from "../../../server/operator-auth"; +import Setup, { type Check, type SetupProps } from "./setup"; +import { budgetView, profileView } from "./view"; + +export const dynamic = "force-dynamic"; +export const metadata: Metadata = { title: "Payments setup | Bell" }; + +const message = (error: unknown) => (error instanceof Error ? error.message : "Unexpected error."); + +// Operator only. proxy.ts asks for the credentials; this checks again before signing a token. +export default async function CrossmintSetupPage() { + const incoming = await headers(); + const host = incoming.get("x-forwarded-host") ?? incoming.get("host") ?? "localhost"; + const protocol = incoming.get("x-forwarded-proto") ?? "http"; + const auth = await routeAuth(new Request(`${protocol}://${host}/crossmint/setup`, { headers: incoming }), [operatorAuth]); + if (auth instanceof Response) { + return

Sign in as the Bell operator to set up payments.

; + } + + const props: SetupProps = { + checks: { server: { state: "todo", text: "" }, operator: { state: "todo", text: "" }, token: { state: "todo", text: "" } }, + budgets: [], + defaults: {}, + configured: { profile: Boolean(process.env.CROSSMINT_BUYER_PROFILE_ID?.trim()), orderIntent: Boolean(process.env.CROSSMINT_ORDER_INTENT_ID?.trim()) }, + }; + + // 1. The server key runs checkouts. + let serverReady = false; + try { + if (!isCrossmintConfigured()) throw new CrossmintSetupError("missing_configuration", "CROSSMINT_SERVER_API_KEY and CROSSMINT_USER_ID"); + crossmintConfig(); + serverReady = true; + props.checks.server = { state: "ok", text: "Server key and operator id are set." }; + } catch (error) { + props.checks.server = { state: "error", text: message(error) } satisfies Check; + } + + // 2. The client key and Bell's operator token approve budgets. + let config: OperatorConfig | undefined; + try { + config = operatorConfig(); + props.checks.operator = { state: "ok", text: "Client key, project id, and signing key are set." }; + const loopback = new URL(config.origin).protocol === "http:"; + props.jwks = { url: `${config.origin}/api/crossmint/jwks`, issuer: config.projectId, loopback }; + } catch (error) { + props.checks.operator = { state: serverReady ? "error" : "todo", text: message(error) }; + } + + // 3. Crossmint accepts Bell's token: listing budgets proves it. + if (config) { + try { + const configured = process.env.CROSSMINT_ORDER_INTENT_ID?.trim(); + props.budgets = (await listOrderIntents({ config })).map((intent) => budgetView(intent, configured)); + props.checks.token = { state: "ok", text: "Crossmint accepts Bell's operator token." }; + props.apiKey = config.clientApiKey; + } catch (error) { + props.checks.token = + error instanceof CrossmintOperatorError && error.reason === "unauthorized" + ? { state: "error", text: "Crossmint rejected Bell's operator token. Point the project's custom JWT settings at Bell below." } + : { state: "error", text: message(error) }; + } + } + + // Delivery details, read with the server key. + const profileId = process.env.CROSSMINT_BUYER_PROFILE_ID?.trim(); + if (serverReady && profileId) { + try { + const profile = profileView(await getBuyerProfile(profileId)); + props.profile = profile; + props.defaults = { email: profile.email, countryCode: profile.countryCode }; + } catch (error) { + props.profileError = `CROSSMINT_BUYER_PROFILE_ID: ${message(error)}`; + } + } + + return ; +} diff --git a/app/crossmint/setup/setup.module.css b/app/crossmint/setup/setup.module.css new file mode 100644 index 0000000..c01725d --- /dev/null +++ b/app/crossmint/setup/setup.module.css @@ -0,0 +1,521 @@ +/* Crossmint styling for the operator setup page. Bell's global stylesheet targets bare elements, + so every element here carries a class, which wins over those rules. */ +.page { + --xm-green: #00c768; + --xm-green-dark: #00a846; + --xm-dark: #0a1825; + --xm-grey-bg: #f9fafa; + --xm-grey-mid: #e5e7eb; + --xm-grey-text: #6b7280; + --xm-tint: #e8f8ef; + --xm-tint-soft: #f5fbf8; + --xm-amber: #b45309; + --xm-amber-bg: #fef3c7; + --xm-red: #dc2626; + --xm-red-bg: #fef2f2; + --xm-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + min-height: 100vh; + background: var(--xm-grey-bg); + color: var(--xm-dark); + font-family: var(--xm-font); + font-size: 15px; + line-height: 1.55; +} + +.shell { + max-width: 920px; + margin: 0 auto; + padding: 28px 24px 64px; +} + +.top { + display: flex; + align-items: center; + gap: 14px; + margin: 0 0 40px; +} + +.divider { + width: 1px; + height: 22px; + background: var(--xm-grey-mid); +} + +.product { + font-weight: 600; + font-size: 16px; +} + +.spacer { + flex: 1; +} + +.operator { + font-size: 12px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--xm-grey-text); + border: 1px solid var(--xm-grey-mid); + border-radius: 999px; + padding: 4px 10px; + background: #fff; +} + +.hero { + margin: 0 0 28px; +} + +.h1 { + font-size: 40px; + line-height: 1.1; + letter-spacing: -0.02em; + font-weight: 700; + margin: 0 0 10px; +} + +.heroText { + max-width: 620px; + margin: 0; + color: var(--xm-grey-text); + font-size: 17px; +} + +.card { + background: #fff; + border: 1px solid var(--xm-grey-mid); + border-radius: 12px; + margin: 0 0 18px; + box-shadow: 0 1px 2px rgba(10, 24, 37, 0.04); +} + +.cardHead { + display: flex; + align-items: center; + gap: 12px; + padding: 20px 24px; + border-bottom: 1px solid var(--xm-grey-mid); +} + +.number { + display: grid; + place-items: center; + width: 28px; + height: 28px; + border-radius: 999px; + background: var(--xm-tint); + color: var(--xm-green-dark); + font-weight: 700; + font-size: 14px; +} + +.h2 { + margin: 0; + font-size: 19px; + font-weight: 600; + letter-spacing: -0.01em; +} + +.cardBody { + padding: 20px 24px 24px; +} + +.lead { + margin: 0 0 16px; + color: var(--xm-grey-text); +} + +.muted { + color: var(--xm-grey-text); + font-size: 14px; +} + +.strong { + font-weight: 600; +} + +.pill { + display: inline-flex; + align-items: center; + border-radius: 999px; + padding: 3px 10px; + font-size: 12px; + font-weight: 600; + white-space: nowrap; +} + +.ok { + background: var(--xm-tint); + color: var(--xm-green-dark); +} + +.todo { + background: #f3f4f6; + color: var(--xm-grey-text); +} + +.error { + background: var(--xm-red-bg); + color: var(--xm-red); +} + +p.error { + border-radius: 8px; + padding: 10px 12px; + font-size: 14px; +} + +.checks { + list-style: none; + margin: 0; + padding: 0; +} + +.checkRow { + display: grid; + grid-template-columns: 14px 190px 1fr; + align-items: baseline; + gap: 12px; + padding: 10px 0; + border-bottom: 1px solid #f0f1f3; +} + +.checkRow:last-child { + border-bottom: 0; +} + +.dot { + width: 10px; + height: 10px; + border-radius: 999px; + transform: translateY(1px); +} + +.dot.ok { + background: var(--xm-green); +} + +.dot.todo { + background: #d1d5db; +} + +.dot.error { + background: var(--xm-red); +} + +.checkName { + font-weight: 600; +} + +.callout { + margin: 18px 0 0; + padding: 16px 18px; + border-radius: 10px; + background: var(--xm-tint-soft); + border: 1px solid var(--xm-tint); +} + +.calloutTitle { + margin: 0 0 8px; + font-weight: 600; +} + +.ordered { + margin: 0 0 8px; + padding-left: 20px; +} + +.ordered li { + margin: 6px 0; +} + +.copyLine { + display: flex; + align-items: center; + gap: 10px; + margin: 8px 0; + padding: 6px 6px 6px 12px; + border: 1px solid var(--xm-grey-mid); + border-radius: 8px; + background: #fff; +} + +.copyLabel { + font-size: 12px; + font-weight: 600; + color: var(--xm-grey-text); + white-space: nowrap; +} + +.code { + flex: 1; + overflow-x: auto; + white-space: nowrap; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + font-size: 13px; +} + +.summary { + display: flex; + align-items: center; + gap: 16px; + justify-content: space-between; + padding: 14px 16px; + border: 1px solid var(--xm-grey-mid); + border-radius: 10px; + margin: 0 0 12px; +} + +.summary p { + margin: 0; +} + +.summaryTitle { + margin: 0 0 4px; + font-weight: 600; +} + +.next { + margin: 12px 0 0; +} + +.form { + display: grid; + gap: 14px; + margin: 8px 0 0; +} + +.grid2, +.grid3, +.grid4 { + display: grid; + gap: 14px; +} + +.grid2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.grid3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid4 { + grid-template-columns: 1fr 1.6fr 1fr 0.8fr; +} + +.label { + display: grid; + gap: 6px; + margin: 0; + font-size: 13px; + font-weight: 500; + color: var(--xm-dark); +} + +.input { + width: 100%; + font: inherit; + font-size: 15px; + color: var(--xm-dark); + background: #fff; + border: 1px solid var(--xm-grey-mid); + border-radius: 8px; + padding: 10px 12px; + outline: none; + transition: border-color 0.15s, box-shadow 0.15s; +} + +.input:focus { + border-color: var(--xm-green); + box-shadow: 0 0 0 3px rgba(0, 199, 104, 0.18); +} + +.actions { + display: flex; + gap: 10px; + justify-content: flex-end; + margin: 16px 0 0; +} + +.primaryButton, +.secondaryButton, +.ghostButton, +.dangerButton { + font: inherit; + font-weight: 600; + border-radius: 8px; + cursor: pointer; + transition: background 0.15s, border-color 0.15s, color 0.15s; +} + +.primaryButton { + background: var(--xm-green); + color: #fff; + border: 0; + padding: 11px 18px; + font-size: 15px; +} + +.primaryButton:hover { + background: var(--xm-green-dark); +} + +.primaryButton:disabled { + opacity: 0.6; + cursor: default; +} + +.secondaryButton { + background: transparent; + color: var(--xm-green-dark); + border: 1.5px solid var(--xm-green); + padding: 9.5px 16px; + font-size: 15px; +} + +.ghostButton, +.dangerButton { + background: transparent; + border: 1px solid var(--xm-grey-mid); + color: var(--xm-dark); + padding: 6px 12px; + font-size: 13px; +} + +.ghostButton:hover { + border-color: var(--xm-green); + color: var(--xm-green-dark); +} + +.dangerButton:hover { + border-color: var(--xm-red); + color: var(--xm-red); +} + +.primaryButton:focus-visible, +.secondaryButton:focus-visible, +.ghostButton:focus-visible, +.dangerButton:focus-visible { + outline: 3px solid rgba(0, 199, 104, 0.35); + outline-offset: 2px; +} + +.tableWrap { + overflow-x: auto; + margin: 0 0 4px; + border: 1px solid var(--xm-grey-mid); + border-radius: 10px; +} + +.table { + width: 100%; + border-collapse: collapse; + font-size: 14px; +} + +.table th { + text-align: left; + font-weight: 600; + color: var(--xm-green-dark); + background: var(--xm-tint); + padding: 10px 14px; +} + +.row td { + padding: 12px 14px; + border-top: 1px solid #e6e6e6; + vertical-align: top; +} + +.num { + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.chips { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.chip { + font-size: 12px; + border-radius: 6px; + padding: 2px 8px; + background: #f3f4f6; + color: var(--xm-dark); + white-space: nowrap; +} + +.rowActions { + display: flex; + gap: 8px; + justify-content: flex-end; + align-items: center; + flex-wrap: wrap; +} + +.useRow { + padding: 0 14px 12px; + font-size: 14px; + color: var(--xm-grey-text); +} + +.cardForm { + margin: 12px 0 0; + padding: 18px; + border: 1px solid var(--xm-grey-mid); + border-radius: 10px; + background: var(--xm-tint-soft); +} + +.success { + margin: 12px 0 0; + padding: 18px; + border-radius: 10px; + background: var(--xm-tint-soft); + border: 1px solid var(--xm-tint); +} + +.success p { + margin: 0 0 8px; +} + +.footer { + margin: 24px 0 0; + text-align: center; + font-size: 13px; + color: var(--xm-grey-text); +} + +@media (max-width: 720px) { + .shell { + padding: 20px 16px 48px; + } + + .h1 { + font-size: 32px; + } + + .grid2, + .grid3, + .grid4 { + grid-template-columns: 1fr; + } + + .checkRow { + grid-template-columns: 14px 1fr; + } + + .checkRow .muted { + grid-column: 2; + } +} + +.link { + color: var(--xm-green-dark); + font-weight: 600; + text-decoration: underline; + text-underline-offset: 2px; +} diff --git a/app/crossmint/setup/setup.tsx b/app/crossmint/setup/setup.tsx new file mode 100644 index 0000000..873c012 --- /dev/null +++ b/app/crossmint/setup/setup.tsx @@ -0,0 +1,466 @@ +"use client"; + +import { CrossmintPaymentMethodManagement, CrossmintProvider } from "@crossmint/client-sdk-react-ui"; +import Image from "next/image"; +import { useRouter } from "next/navigation"; +import { useRef, useState, useTransition, type FormEvent, type InputHTMLAttributes, type ReactNode } from "react"; +import { approveBudget, cancelBudget, refreshToken, saveBuyerProfile } from "./actions"; +import logo from "./crossmint-logo.svg"; +import styles from "./setup.module.css"; +import type { Budget, ProfileView } from "./view"; + +export interface Check { + state: "ok" | "todo" | "error"; + text: string; +} + +export interface SetupProps { + checks: { server: Check; operator: Check; token: Check }; + jwks?: { url: string; issuer: string; loopback: boolean }; + /** Only when Crossmint accepted Bell's token. The card form asks for a ten-minute token itself. */ + apiKey?: string; + profile?: ProfileView; + profileError?: string; + budgets: Budget[]; + defaults: { email?: string; countryCode?: string }; + configured: { profile: boolean; orderIntent: boolean }; +} + +// Crossmint's card form in Crossmint's colors, with the page's font stack. No web font is fetched. +const cardAppearance = { + variables: { + fontFamily: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", + borderRadius: "8px", + colors: { + accent: "#00C768", + textPrimary: "#0A1825", + textSecondary: "#6B7280", + borderPrimary: "#E5E7EB", + backgroundPrimary: "#FFFFFF", + danger: "#DC2626", + }, + }, +}; + +const language = () => (typeof navigator !== "undefined" && navigator.language) || "en-US"; +const field = (form: FormData, name: string) => String(form.get(name) ?? "").trim(); + +function Pill({ check }: { check: Check }) { + const label = check.state === "ok" ? "Ready" : check.state === "error" ? "Needs attention" : "To do"; + return {label}; +} + +function CopyLine({ value, label }: { value: string; label?: string }) { + const [copied, setCopied] = useState(false); + return ( +
+ {label ? {label} : null} + {value} + +
+ ); +} + +function Step({ number, title, aside, children }: { number: number; title: string; aside?: ReactNode; children: ReactNode }) { + return ( +
+
+ {number} +

{title}

+ + {aside} +
+
{children}
+
+ ); +} + +function CheckRow({ name, check }: { name: string; check: Check }) { + return ( +
  • + + {name} + {check.text} +
  • + ); +} + +function Connect({ checks, jwks }: Pick) { + const state: Check = Object.values(checks).every((check) => check.state === "ok") + ? { state: "ok", text: "" } + : Object.values(checks).some((check) => check.state === "error") ? { state: "error", text: "" } : { state: "todo", text: "" }; + return ( + }> +
      + + + +
    + {jwks && checks.token.state !== "ok" ? ( +
    +

    Let Crossmint verify Bell's token

    +
      +
    1. In the Crossmint console, open the project, then Integrate, API Keys, JWT authentication.
    2. +
    3. + Choose Custom tokens and set the JWKS endpoint. + + {jwks.loopback ? ( + + Crossmint cannot reach this address. Expose only this path over HTTPS, for example with a Cloudflare quick + tunnel, and paste the tunnel URL followed by /api/crossmint/jwks. A tunnel URL changes on every start, so + for a stable setup download the public key + file and host it at any HTTPS address you control. It holds only the public key. + + ) : null} +
    4. +
    5. + Set the issuer to the project id and the verifier id to sub. + +
    6. +
    7. Save, reload the console page to confirm Custom tokens stayed selected, then reload this page.
    8. +
    +

    A project has one sign-in method, so give Bell a Crossmint project of its own.

    +
    + ) : null} +
    + ); +} + +function DeliveryDetails({ profile, profileError, configured, countryCode }: { profile?: ProfileView; profileError?: string; configured: boolean; countryCode?: string }) { + const [saved, setSaved] = useState<{ id: string; profile: ProfileView }>(); + const [error, setError] = useState(""); + const [pending, start] = useTransition(); + const shown = saved?.profile ?? profile; + + function submit(event: FormEvent) { + event.preventDefault(); + const form = new FormData(event.currentTarget); + setError(""); + start(async () => { + const result = await saveBuyerProfile({ + first: field(form, "first"), + last: field(form, "last"), + email: field(form, "email"), + phone: field(form, "phone"), + street: field(form, "street"), + street2: field(form, "street2") || undefined, + postalCode: field(form, "postalCode"), + locality: field(form, "locality"), + region: field(form, "region") || undefined, + countryCode: field(form, "countryCode"), + }); + if (result.ok) setSaved({ id: result.id, profile: result.profile }); + else setError(result.message); + }); + } + + const pill: Check = shown ? { state: "ok", text: "" } : { state: "todo", text: "" }; + return ( + }> +

    + Checkouts fill these in instead of asking you in chat, so names and addresses stay out of the conversation. No + payment data is stored here. +

    + {profileError ?

    {profileError}

    : null} + {shown ? ( +
    +
    +

    {shown.name ?? "Saved delivery details"}

    +

    + {shown.place}, {shown.countryCode} + {shown.email ? ` ยท ${shown.email}` : ""} +

    +
    + {configured && !saved ? In use : null} +
    + ) : null} + {saved ? ( +
    +

    Add this line to .env.local and restart Bell:

    + +
    + ) : null} + {!shown ? ( +
    +
    + + + + +
    + + +
    + + + + +
    + {error ?

    {error}

    : null} +
    + +
    +
    + ) : null} +
    + ); +} + +function Input({ label, name, ...rest }: { label: string; name: string } & InputHTMLAttributes) { + return ( + + ); +} + +function BudgetRow({ budget, onCancel }: { budget: Budget; onCancel: (id: string) => void }) { + const [show, setShow] = useState(false); + const live = budget.live; + return ( + <> + + + {budget.merchantName ?? "Any merchant"} + {budget.merchantHost ? ยท {budget.merchantHost} : null} + + + {budget.available} + {budget.total ? ` of ${budget.total}` : ""} {budget.currency} + + {new Date(budget.expiresAt).toLocaleDateString()} + +
    + {budget.rails.map((rail) => {rail})} +
    + + + {budget.inUse ? In use : null} + {!live ? {budget.status} : null} + {live && !budget.inUse ? : null} + {live ? : null} + + + {show ? ( + + + Add this line to .env.local and restart Bell: + + + + ) : null} + + ); +} + +type Draft = Parameters[0]; + +function CardAndBudget({ apiKey, budgets, defaults, ready }: { apiKey?: string; budgets: Budget[]; defaults: SetupProps["defaults"]; ready: boolean }) { + const router = useRouter(); + const [stage, setStage] = useState<"list" | "form" | "card" | "done">("list"); + const [draft, setDraft] = useState>(); + const [card, setCard] = useState<{ id: string; label: string }>(); + // One approval at a time; the draft's idempotency key covers retries that reach Crossmint. + const approving = useRef(false); + const [jwt, setJwt] = useState(); + const [result, setResult] = useState(); + const [error, setError] = useState(""); + const [pending, start] = useTransition(); + + function toCard(event: FormEvent) { + event.preventDefault(); + const form = new FormData(event.currentTarget); + setError(""); + setDraft({ + amount: field(form, "amount"), + currency: field(form, "currency"), + days: Number(field(form, "days")), + description: field(form, "description"), + merchant: { name: field(form, "merchantName"), url: field(form, "merchantUrl"), countryCode: field(form, "merchantCountry") }, + consumer: { email: field(form, "email"), countryCode: field(form, "consumerCountry"), languageCode: language() }, + idempotencyKey: crypto.randomUUID(), + }); + setCard(undefined); + start(async () => { + const token = await refreshToken(); + if (!token.ok) return setError(token.message); + setJwt(token.jwt); + setStage("card"); + }); + } + + function approve() { + if (!draft || !card || approving.current) return; + approving.current = true; + setError(""); + start(async () => { + try { + const outcome = await approveBudget({ ...draft, paymentMethodId: card.id }); + if (!outcome.ok) return setError(outcome.message); + setResult(outcome.budget); + setStage("done"); + router.refresh(); + } finally { + approving.current = false; + } + }); + } + + function cancel(id: string) { + if (!window.confirm("Cancel this budget? Nothing more can be spent from it.")) return; + start(async () => { + const outcome = await cancelBudget(id); + if (!outcome.ok) setError(outcome.message); + router.refresh(); + }); + } + + const pill: Check = budgets.some((budget) => budget.inUse && budget.live) + ? { state: "ok", text: "" } + : { state: ready ? "todo" : "error", text: "" }; + return ( + }> +

    + Approve how much Bell may spend, at which store, and until when. You still approve every payment in chat, and Bell + checks it against this budget before paying. +

    + {!ready ?

    Connect Bell to Crossmint first.

    : null} + {ready && budgets.length ? ( +
    + + + + + {budgets.map((budget) => )} +
    StoreLeftExpiresCard rails
    +
    + ) : null} + {error ?

    {error}

    : null} + + {ready && stage === "list" ? ( +
    + +
    + ) : null} + + {stage === "form" ? ( +
    +
    + + + +
    +
    + + + +
    + +
    + + +
    +
    + + +
    +
    + ) : null} + + {stage === "card" && apiKey && jwt && draft ? ( +
    + {!card ? ( + <> +

    + Pick a saved card or add one. Card details go straight to Crossmint's vault and never reach Bell. +

    + + { + if ("paymentMethodId" in method && method.type === "card") { + setError(""); + setCard({ id: method.paymentMethodId, label: `${method.card.brand} ending ${method.card.last4}` }); + } else setError("Choose a card. Bank accounts cannot back a budget."); + }} + /> + + + ) : ( +
    +
    +

    + Approve {draft.amount} {draft.currency.toUpperCase()} at {draft.merchant.name} for {String(draft.days)} days? +

    +

    On your {card.label}. You still approve every payment in chat.

    +
    + +
    + )} +
    + +
    +
    + ) : null} + + {stage === "done" && result ? ( +
    +

    + Budget approved: {result.available} {result.currency} + {result.merchantName ? ` at ${result.merchantName}` : ""} until {new Date(result.expiresAt).toLocaleDateString()} +

    +

    + {result.networkRail + ? "The card has a Visa or Mastercard agent rail, so Bell can also pay in its own browser." + : "Crossmint checkouts pay this card through Crossmint's encrypted card, so no network rail is needed."} +

    +

    Add this line to .env.local and restart Bell:

    + +
    + +
    +
    + ) : null} +
    + ); +} + +export default function Setup(props: SetupProps) { + const ready = props.checks.token.state === "ok" && Boolean(props.apiKey); + return ( +
    +
    +
    + Crossmint + + Bell + + Operator +
    +
    +

    Payments setup

    +

    + Let Bell buy at any store with your own card. Crossmint runs the checkout, and you approve every payment in chat. +

    +
    + + + +

    Restart Bell after changing .env.local. This page signs in to Crossmint for ten minutes; reload it to continue.

    +
    +
    + ); +} diff --git a/app/crossmint/setup/view.ts b/app/crossmint/setup/view.ts new file mode 100644 index 0000000..c9dbad5 --- /dev/null +++ b/app/crossmint/setup/view.ts @@ -0,0 +1,56 @@ +import type { BuyerProfile } from "../../../server/crossmint/client"; +import { describeRail, type OrderIntentSummary } from "../../../server/crossmint/operator"; + +/** What the setup page shows about a budget (an order intent). */ +export interface Budget { + id: string; + status: string; + available: string; + total?: string; + currency: string; + merchantName?: string; + merchantHost?: string; + expiresAt: string; + rails: string[]; + /** A Visa or Mastercard agent rail is active, so Bell's own browser can pay with it too. */ + networkRail: boolean; + /** CROSSMINT_ORDER_INTENT_ID names this budget. */ + inUse: boolean; + /** Active and not yet expired when the page was rendered. */ + live: boolean; +} + +export function budgetView(intent: OrderIntentSummary, configuredId?: string, now = Date.now()): Budget { + const host = intent.merchant?.url ? URL.parse(intent.merchant.url)?.hostname : undefined; + return { + id: intent.orderIntentId, + status: intent.status, + available: intent.amount.available, + ...(intent.amount.total ? { total: intent.amount.total } : {}), + currency: intent.amount.currency.toUpperCase(), + ...(intent.merchant?.name ? { merchantName: intent.merchant.name } : {}), + ...(host ? { merchantHost: host } : {}), + expiresAt: intent.expiresAt, + rails: intent.rails.map(describeRail), + networkRail: intent.rails.some((rail) => rail.rail === "agentic-token" && rail.status === "active"), + inUse: Boolean(configuredId) && intent.orderIntentId === configuredId, + live: intent.status === "active" && Date.parse(intent.expiresAt) > now, + }; +} + +/** What the setup page shows about the saved delivery details. */ +export interface ProfileView { + name?: string; + place: string; + email?: string; + countryCode: string; +} + +export function profileView(profile: BuyerProfile): ProfileView { + return { + ...(profile.name ? { name: `${profile.name.first} ${profile.name.last}` } : {}), + place: [profile.shipping.postalCode, profile.shipping.locality].filter(Boolean).join(" "), + ...(profile.contact?.email ? { email: profile.contact.email } : {}), + countryCode: profile.shipping.countryCode, + }; +} diff --git a/docs/crossmint.md b/docs/crossmint.md index d3ef6f5..a31b248 100644 --- a/docs/crossmint.md +++ b/docs/crossmint.md @@ -9,15 +9,17 @@ card, at stores worldwide. The card number never reaches Bell or the model. ```text Bell -> create run (URL, task, cap) -> Crossmint works through the store's checkout + -> running (progress) -> Bell tells the person what Crossmint is doing -> awaiting_input (form) -> Bell answers from the conversation -> awaiting_input (payment) -> Eve asks the person to approve the exact total -> server checks total, currency, merchant, cap -> pays -> succeeded (receipt) -> Bell reports the order ``` -The checkout runs in Crossmint's service, not in this conversation's browser. Nothing in the Link -integration, the browser runtime, or the hooks changes. With the Crossmint variables unset, both -tools answer `not_configured`. +The checkout runs in Crossmint's service, not in this conversation's browser, so it needs no +Browserbase plan and works the same with Bell's local browser. Nothing in the Link integration, the +browser runtime, or the hooks changes. With the Crossmint variables unset, both tools answer +`not_configured`. ## Configure @@ -26,74 +28,129 @@ Set these server-only values in Bell's ignored `.env.local`: ```dotenv CROSSMINT_SERVER_API_KEY= CROSSMINT_USER_ID= -# Needed only to pay. The operator's approved order intent id. -CROSSMINT_ORDER_INTENT_ID= -# Optional. Saved buyer profile (name, email, shipping) so checkouts ask fewer questions. -CROSSMINT_BUYER_PROFILE_ID= # Optional. Ceiling for any single checkout's cap, "amount currency". CROSSMINT_MAX_COST=50.00 EUR # Optional. Exact HTTPS origins a checkout may start from. Empty allows any store. CROSSMINT_ALLOWED_MERCHANTS=https://shop.example +# Written by the setup page below. +CROSSMINT_BUYER_PROFILE_ID= +CROSSMINT_ORDER_INTENT_ID= ``` Create the key in the [Crossmint console](https://www.crossmint.com/console) with the `agent-checkouts.create`, `agent-checkouts.read`, `agent-checkouts.update`, and -`agent-checkouts.cancel` scopes. Agent Checkouts runs in production only, so a staging key answers -`unauthorized`. A client key (`ck_`) is rejected at startup. +`agent-checkouts.cancel` scopes, plus `agent-checkouts.buyer-profiles.create` and +`agent-checkouts.buyer-profiles.read` for the setup page. Agent Checkouts runs in production only, +so a staging key answers `unauthorized`. A client key (`ck_`) is rejected at startup. `CROSSMINT_USER_ID` identifies the buyer to Crossmint. Bell serves one trusted operator, so a fixed -value is enough. Every run, order intent, and receipt is scoped to it. - -`CROSSMINT_ORDER_INTENT_ID` is the budget the person approved in Crossmint beforehand. It names a -saved card, an amount, a merchant scope, and an expiry. The card can be a Crossmint agent card, a card -on file, or an agent card from another provider. The -[cards quickstart](https://docs.crossmint.com/agents/cards-quickstart) walks through saving a card -and approving an order intent. Only the pay path on the server reads this id. Without it, checkouts -run up to the payment step and `crossmint_pay` answers `payment_not_configured`. +value is enough. Every run, buyer profile, order intent, and receipt is scoped to it. `CROSSMINT_MAX_COST` and `CROSSMINT_ALLOWED_MERCHANTS` are checked before a run exists, so a refused request is never billed. They bound what a prompt can ask for. The order intent bounds what can be paid. -Restart Bell after changing these values. No database, migration, or browser setting is involved. +Restart Bell after changing these values. No database or migration is involved. + +## Set up payments in Bell + +Two things make checkouts pay without questions: saved delivery details (a buyer profile) and an +approved budget on the person's card (an order intent). Bell's operator page at +`/crossmint/setup` sets up both. It asks for `BELL_OPERATOR_USERNAME` and `BELL_OPERATOR_PASSWORD`, +also when Bell runs locally. + +Approving a budget is a call Crossmint accepts only for a signed-in user: a client key together with +that user's JWT, never a server key. Bell serves one operator, so it signs that JWT itself: RS256, +issuer the project id, subject `CROSSMINT_USER_ID`, audience `crossmint.com`, valid ten minutes. +Crossmint checks it against the public key Bell serves at `/api/crossmint/jwks`. Add to `.env.local`: + +```dotenv +# Client key (ck_) with the payment-methods.* and order-intents.* scopes. BELL_PUBLIC_URL must be an allowed origin. +CROSSMINT_CLIENT_API_KEY= +# The Crossmint project id. Bell's operator token carries it as the issuer. +CROSSMINT_PROJECT_ID= +# Base64-encoded PEM RSA private key, 2048 bits or more, that signs the operator token. +CROSSMINT_JWT_PRIVATE_KEY= +``` + +Generate the private key once and keep it stable across restarts: + +```sh +openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 | base64 | tr -d '\n' +``` + +Then open `/crossmint/setup`. It checks each step live and says what is missing: + +1. **Connect Bell to Crossmint.** The page lists Crossmint's budgets with Bell's token, which proves + the whole chain. If Crossmint rejects the token, the page shows the two values to paste in the + console under Integrate, API Keys, JWT authentication: choose Custom tokens, set the JWKS endpoint + and the issuer, keep the verifier id `sub`, save, and reload the console page to confirm Custom + tokens stayed selected. Crossmint fetches the JWKS endpoint over HTTPS. A deployed Bell serves it + at `/api/crossmint/jwks`. A Bell on your laptop needs that one path exposed, for + example through a Cloudflare quick tunnel, whose URL changes on every start. For a stable setup, + download the public key file from the page and host it at any HTTPS address you control; it holds + only the public key. A project has one sign-in method, so give Bell a Crossmint project of its own. +2. **Delivery details.** Save the name, email, phone, and shipping address checkouts use instead of + asking in chat. No payment data is stored. The page shows the `CROSSMINT_BUYER_PROFILE_ID` line + to add. +3. **Card and budget.** Enter the amount, currency, how many days it lasts, and the store's name, + HTTPS URL, and country. Then pick a saved card or add one in Crossmint's card form, whose fields + go straight to Crossmint's vault, and confirm the budget on that card. Bell registers the card for + order intents with your email, country, and language, which Crossmint requires and its card + component does not send, and then approves the budget once: each draft carries its own + idempotency key. The page lists every budget with what is left, its expiry, and its card + rails, marks the one `CROSSMINT_ORDER_INTENT_ID` names, and cancels budgets you no longer need. + +Agent Checkouts pays with any card Crossmint can save. A card without a Visa Intelligent Commerce or +Mastercard Agent Pay rail, such as a Visa issued outside the United States, is paid through +Crossmint's encrypted card inside its vault, so the budget's rail list can show no active card rail +and the checkout still pays. + +Add both lines the page shows to `.env.local` and restart Bell. ## Try it in five minutes -This run needs only `CROSSMINT_SERVER_API_KEY` and `CROSSMINT_USER_ID`. It reaches the payment step -and stops there, so nothing is bought. Pick a product under a few dollars at a store that ships to -you. +This run needs only `CROSSMINT_SERVER_API_KEY` and `CROSSMINT_USER_ID`. Without a budget it reaches +the payment step and stops there, so nothing is bought. Pick a product under a few dollars at a store +that ships to you. 1. Start Bell with `pnpm dev` and open `http://127.0.0.1:4320`. Local development auth signs the web conversation in, which the payment step requires. 2. Send "Buy one of https://shop.example/products/sticker-pack with standard delivery, max 20 USD". - Bell starts the run and waits up to ninety seconds for the next step. -3. Answer the questions Bell relays, such as a size or an email. With a buyer profile configured - most of them do not come up. -4. At the payment step Bell calls `crossmint_pay`. Eve pauses and shows "Pay 12.49 USD to - shop.example with your Crossmint order intent?". Approve it. The server fetches the live request, - checks it, finds no order intent, and answers `payment_not_configured`. + Bell starts the run and, within seconds, says what Crossmint is doing. It posts a short line at + each new stage, such as finding the product or filling in the delivery details. +3. Answer the questions Bell relays, such as a size or an email. With delivery details saved, most of + them do not come up. +4. At the payment step Bell calls `crossmint_pay`. Eve pauses and shows "Pay 12.49 USD at Example + Shop (shop.example) with your saved card?". Approve it. The server fetches the live request, + checks it, finds no budget, and answers `payment_not_configured`. 5. Say "Cancel it". Bell cancels the run and the status becomes `cancelled`. Crossmint bills each run that starts, including runs that end `blocked`. The first thousand runs a month are free. The run appears in the Crossmint console under Agent Checkouts with the same id Bell -reports. To buy for real, set `CROSSMINT_ORDER_INTENT_ID` and repeat the steps. The approval is the -same. The server then pays, and `succeeded` with `purchase.kind` `receipt_captured` carries -`receipt.total` and `receipt.merchantOrderId`. +reports. To buy for real, approve a budget on the setup page, set `CROSSMINT_ORDER_INTENT_ID`, and +repeat the steps. The approval is the same. The server then pays, and `succeeded` with +`purchase.kind` `receipt_captured` carries `receipt.total` and `receipt.merchantOrderId`. ## Use With `pnpm dev` running, in a web conversation or a Linq chat, give Bell the product URL, what to buy, and the cap. Bell starts the run with `crossmint_checkout` and follows `requiredAction`. +While the run works, `start` returns within about twenty-five seconds and each `status` call returns +at the next new stage, at least fifteen seconds and at most a minute later. Bell tells you each new +stage in one short sentence and calls `status` again, so the conversation never sits on "Working" +for minutes. + When Crossmint asks a form question, Bell answers from what you said or asks you, then calls `answer` with one value per field key. A choice field lists its option values. Fields marked `protected`, such as one-time codes, passwords, and card data, cannot be answered through the model. Bell declines or asks you to finish in Crossmint's hosted flow. -At the payment step Bell calls `crossmint_pay` with the amount, currency, and merchant copied from -the request. Eve pauses and asks you to approve. Approving runs the tool and cancelling does not. -Only the authenticated sender who asked for the purchase can approve. A payment request for a method -other than a card, such as Klarna, is refused, because an order intent cannot pay it. +At the payment step Bell calls `crossmint_pay` with the amount, currency, merchant, and merchant name +copied from the request. Eve pauses and asks you to approve. Approving runs the tool and cancelling +does not. Only the authenticated sender who asked for the purchase can approve. A payment request for +a method other than a card, such as Klarna, is refused, because an order intent cannot pay it. `succeeded` with `purchase.kind` `receipt_captured` is the only result Bell reports as a placed order. `confirmed_without_receipt` and `nothing_placed` are reported as what they are. `blocked` carries a @@ -106,25 +163,34 @@ a second run for the same request while one is unresolved. Approval in chat is not the control. Eve's tool approval is. `crossmint_pay` is declared with `approval: always()`, so the runtime stops before executing it and shows the person the amount, -currency, and merchant the model put in the call. After approval the server fetches the live payment -request from Crossmint and compares it with those three values and with the cap the run started -with. Any difference, an expired or replaced request, a method other than a card, a `maximum` instead -of an `exact` amount, or a run this conversation did not start refuses the payment and answers the -reason. The approval dialog shows the model's numbers. The cross-check makes sure they are -Crossmint's numbers. +currency, and payee the model put in the call, in plain words such as "Pay 16.90 EUR at Zara +(payments.zara.com) with your saved card?". After approval the server fetches the live payment +request from Crossmint and compares it with the amount, currency, merchant, and store name and with +the cap the run started with. Any difference, an expired or replaced request, a method other than a card, a +`maximum` instead of an `exact` amount, or a run this conversation did not start refuses the payment +and answers the reason. The approval dialog shows the model's numbers. The cross-check makes sure +they are Crossmint's numbers. Payments need an authenticated sender, which is a verified Linq number, the HTTP Basic operator, or local development auth. The anonymous web demo can start and inspect runs but cannot pay, and the approval response policy rejects anyone other than the principal who requested the call. +The setup page is for the operator only. A root proxy asks for the HTTP Basic credentials, refuses +cross-origin writes, and forbids other sites to frame the page. The page and every action check the +credentials and the origin again before signing a token or calling Crossmint. The browser receives +only the client key, and a ten-minute operator token when it opens Crossmint's card form. + ## Transcript boundary Only a projection of each snapshot reaches the model. That is the run id, status, revision, the open -question with its form fields or payment amount and merchant, and the result summary with receipt -metadata. Browser embed URLs, payment authorization links, the echoed input, provider error bodies, -and any unexpected field are dropped before Eve can persist them. The API key, buyer id, buyer -profile, and order intent id are read from the server environment inside the tools and never appear -in tool arguments or output. +question with its form fields or payment amount and merchant, the result summary with receipt +metadata, and, while the run works, its progress as a fixed stage phrase chosen from Crossmint's +activity kinds. Crossmint's own progress text is never passed on: it can name the buyer while the +delivery details are applied, and it is written while reading merchant pages. Browser +embed URLs, payment authorization links, the echoed input, provider error bodies, and any unexpected +field are dropped before Eve can persist them. The API key, buyer id, buyer profile, and order intent +id are read from the server environment inside the tools and never appear in tool arguments or +output. Nothing the setup page reads or saves reaches the model. Runs are registered per conversation in process memory. After a restart or worker change an unfinished run cannot be resumed from chat. Reconcile it in the Crossmint console before starting @@ -138,9 +204,14 @@ store, items, totals, and form answers, so apply your host's retention policy. `pnpm check` runs mock provider tests. They pin request bodies and headers to the documented API, prove no provider body leaks, exercise the merchant allowlist and the ceiling, project form fields with their option values and protected handling, run the payment cross-check through every refusal -reason, cover polling with an answered request skipped, the timeout and cancellation paths, -per-conversation run isolation, and both tools up to `payment_not_configured`. No test calls -Crossmint. +reason, including a store name that is not Crossmint's, cover polling with an answered request +skipped, the timeout and cancellation paths, progress stages without Crossmint's free text, the +minimum wait between updates and a cancellation during a progress read, per-conversation run +isolation, the approval wording, buyer profiles, and both tools up to `payment_not_configured`. The +setup tests cover the operator-only proxy with its framing headers, the page and actions refusing +missing credentials and other origins, the token the card form receives, the state when Crossmint +rejects the token, a missing setting, and a budget approval that registers the card with an email +and sends one idempotency key before creating the order intent. No test calls Crossmint. For a live smoke test without Bell, start one run from the command line: @@ -148,10 +219,10 @@ For a live smoke test without Bell, start one run from the command line: node scripts/demo-crossmint.mjs https://shop.example/products/sticker-pack 20.00 USD ``` -The command loads `.env`, then `.env.local` when present. It starts the checkout with the key and -buyer id, prints the run id and each status change, and stops at the first question or the first -terminal state. It answers nothing, so nothing is bought, and it prints no secrets. Cancel the run in -the Crossmint console afterwards. Crossmint bills the run. +The command loads `.env`, then `.env.local` when present. It starts the checkout with the key, buyer +id, and buyer profile, prints the run id, each status change and each new progress stage, and stops at +the first question or the first terminal state. It answers nothing, so nothing is bought, and it +prints no secrets. Cancel the run in the Crossmint console afterwards. Crossmint bills the run. For the full flow, follow [Try it in five minutes](#try-it-in-five-minutes). Watch the run in the Crossmint console and compare the receipt with the store's confirmation before trusting the flow for @@ -159,6 +230,10 @@ anything larger. References: [Agent Checkouts overview](https://docs.crossmint.com/agents/checkouts/overview), [quickstart](https://docs.crossmint.com/agents/agent-checkouts-quickstart), +[follow a checkout](https://docs.crossmint.com/agents/checkouts/follow-run), [pay for a checkout](https://docs.crossmint.com/agents/checkouts/payments), +[buyer profiles](https://docs.crossmint.com/agents/checkouts/configure), +[register a card](https://docs.crossmint.com/agents/payment-methods/cards/register-card), +[custom JWT authentication](https://docs.crossmint.com/introduction/platform/api-keys/custom-jwt-auth-guide), [statuses and codes](https://docs.crossmint.com/agents/checkouts/statuses), [API reference](https://docs.crossmint.com/api-reference/agent-checkouts). diff --git a/docs/repository.md b/docs/repository.md index 47eb6ce..e30f27f 100644 --- a/docs/repository.md +++ b/docs/repository.md @@ -33,7 +33,7 @@ lifecycle; channel callbacks also handle terminal-session cleanup. Restart Bell | Link by Stripe | [Eve extension and tools](../agent/extensions/link/), [authorization](../agent/lib/link-auth.ts), [server implementation](../server/link/) | [Sandbox and wallet setup](link.md) | | 1Password | [Operator SDK/CLI access](../server/browser/vault/onepassword.ts), [personal authorization](../agent/lib/onepassword-auth.ts), [personal server implementation](../server/onepassword/) | [Operator credentials](browser-runtime.md#credentials-and-otp), [personal access status](onepassword.md) | | Baselayer | [Agent tool](../agent/tools/merchant_access.ts), [credential minting](../server/baselayer.ts), [merchant verification](../server/verified-merchant.ts) | [Merchant access](baselayer.md) | -| Crossmint | [Checkout tool](../agent/tools/crossmint_checkout.ts), [approved payment tool](../agent/tools/crossmint_pay.ts), [shared tool helpers](../agent/lib/crossmint.ts), [server client](../server/crossmint/client.ts), [payment cross-check](../server/crossmint/payment.ts) | [Agent checkouts](crossmint.md) | +| Crossmint | [Checkout tool](../agent/tools/crossmint_checkout.ts), [approved payment tool](../agent/tools/crossmint_pay.ts), [shared tool helpers](../agent/lib/crossmint.ts), [server client](../server/crossmint/client.ts), [payment cross-check](../server/crossmint/payment.ts), [operator calls](../server/crossmint/operator.ts), [operator token](../server/crossmint/operator-jwt.ts), [setup page](../app/crossmint/setup/page.tsx) | [Agent checkouts](crossmint.md) | Personal 1Password Agentic Autofill is implemented but disabled by default pending hosted extension support and live verification. Keep `ONEPASSWORD_ENABLED=false` and the extension ID unset as diff --git a/package.json b/package.json index 9d283d3..cbd3a88 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "lint": "eslint . --max-warnings=0", "check": "pnpm test && pnpm typecheck && pnpm lint && pnpm build", "baselayer:mint": "node --env-file-if-exists=.env --env-file-if-exists=.env.local scripts/mint-baselayer-credential.mjs", + "crossmint:operator-jwt": "node --env-file-if-exists=.env --env-file-if-exists=.env.local scripts/crossmint-operator-jwt.mjs", "test:retirement:live": "node --env-file-if-exists=.env --env-file-if-exists=.env.local scripts/test-session-retirement.mjs" }, "dependencies": { @@ -25,6 +26,7 @@ "@ai-sdk/openai": "4.0.46", "@browserbasehq/sdk": "2.18.0", "@browserbasehq/stagehand": "4.3.0", + "@crossmint/client-sdk-react-ui": "4.12.1", "@stripe/link-integrations-eve": "0.3.4", "ai": "7.0.137", "eve": "0.79.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e71bd2c..8323077 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,6 +25,9 @@ importers: '@browserbasehq/stagehand': specifier: 4.3.0 version: 4.3.0 + '@crossmint/client-sdk-react-ui': + specifier: 4.12.1 + version: 4.12.1(@dynamic-labs-wallet/primitives@1.1.33)(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) '@stripe/link-integrations-eve': specifier: 0.3.4 version: 0.3.4(eve@0.79.1(@opentelemetry/api@1.9.1)(ai@7.0.137(zod@4.6.7))(microsandbox@0.5.10)) @@ -80,12 +83,32 @@ importers: packages: + '@0no-co/graphql.web@1.3.4': + resolution: {integrity: sha512-imSwulOeDQodRy/olQmVEo2PiY6ntjkZ9eiGdw6lMYylh/tay9b7MusyJBmEnkL8GiKRKr6ltr+D42mY5bd8Bg==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + peerDependenciesMeta: + graphql: + optional: true + + '@0no-co/graphqlsp@1.18.0': + resolution: {integrity: sha512-A6ZId4J6l4KxN5ZtTFZaPtZcU0ikx9mB3kTzEVP3ui5c8srtPA1cGXqjhHFBsKt1ZP839RIHy//LrZMmbE4VAw==} + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 + '@1password/sdk-core@0.5.0': resolution: {integrity: sha512-9g7LWOKRKdePZ85evVgE9xEom3DAg3hRIyQdOwLPvpL/F7KpDXmUHMi72rsqJxKaDbWApXmrYjDExMSPqUg7xw==} '@1password/sdk@0.5.0': resolution: {integrity: sha512-k6kov3pcA7PRg2tev9CgTfEf/3JSyAp11BPQNCEsqAD32QbqM032OXC1rfjyC8Ba0sfH+NHYZxcifUZToyGyYA==} + '@ably/msgpack-js@0.4.1': + resolution: {integrity: sha512-Sjxj6SOr17hExAVrsycN7u6oV4PhZcK7Z2S8dM71CH/butgO47cSo/TL6FJPCXUyDAzKkOWjMUpJGyZkEpyu4Q==} + + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + '@ai-sdk/gateway@4.0.110': resolution: {integrity: sha512-5IwnOR6v7KC+D9eddUqsCobXl/FbLUVb2LaQc/uyuQdpP3/n9s0YLc9zl4/W3IS/R2pjHrqUfCzEAeOu7bFLoQ==} engines: {node: '>=22'} @@ -173,6 +196,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/runtime@7.29.10': + resolution: {integrity: sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==} + engines: {node: '>=6.9.0'} + '@babel/template@7.29.7': resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} @@ -185,6 +212,13 @@ packages: resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} + '@base-org/account@1.1.1': + resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} + + '@basis-theory/web-agentic@1.2.2': + resolution: {integrity: sha512-YipoQlOxPoU1gAUNr6ULs9Fngm9LGekNnD80yOyarfTVB55oIEYF/zCvdscNz0zCK43R0sIeGV9tarum8uiP7g==} + engines: {node: '>=18'} + '@browserbasehq/sdk@2.18.0': resolution: {integrity: sha512-uX1kiOB3lBWvt0sdIszGZkroLj+xvo7d6CC8ORn1mqPLq76Y4fJFDGdbdLWggDF3LxtnmwJCRVgSrLo3V9RctQ==} @@ -192,6 +226,258 @@ packages: resolution: {integrity: sha512-LDiAvJKkpcm2I/NP1B94DC/0hnjJ0NL7kjSKDeyXXyehISKuNRjwOpA2r3PXwmxmMz/o6DMFF4TJcYlsrMWXoA==} engines: {node: '>=22.18.0'} + '@coinbase/wallet-sdk@4.3.7': + resolution: {integrity: sha512-z6e5XDw6EF06RqkeyEa+qD0dZ2ZbLci99vx3zwDY//XO8X7166tqKJrR2XlQnzVmtcUuJtCd5fCvr9Cu6zzX7w==} + + '@crossmint/client-sdk-auth@1.3.31': + resolution: {integrity: sha512-Z1vl+brIW8hvYMvZK13nNYq8iYezX6BqOZdgaziww7D2dLl+qteoEgD6U8mTOalOidjG8acfFT59qVj607aXfw==} + + '@crossmint/client-sdk-base@4.6.1': + resolution: {integrity: sha512-5LtY0ilZXnVxPJxP/1Nq4/SpuF3SlhhVpoxEpuXM2rwvVOowGcn+Wf2dVeOjqmyUPayX6ZRLrF86W8202FOwgg==} + + '@crossmint/client-sdk-react-base@2.4.6': + resolution: {integrity: sha512-j0R/G9e6LXotDt2yNCPWWw6mv1m6zw2iLM4ODC4fXvnrTSY9Wje+5ghSE2LGl7Iz/akj2G/sjHTQHOv5s8UTZg==} + peerDependencies: + react: '>=17.0.2' + + '@crossmint/client-sdk-react-ui@4.12.1': + resolution: {integrity: sha512-7WxlhCTjejycerTtQbuvYP4ngiJPgp5HEj3kt8vDFa+21E5epDGQm6qmdZlALP0rgScC5OiTMtbpYs7v818ZXQ==} + peerDependencies: + '@solana/web3.js': ^1.98.1 + react: '>=17.0.2' + react-dom: '>=17.0.2' + + '@crossmint/client-sdk-window@1.2.0': + resolution: {integrity: sha512-cKBvTjs/mPt/HthK/5hIhGpjIDM/kl1T/1Xb7QjI4rrC/1O0fUEXASz3vCxPB1R8Dxm/5gFM3EX0qAS+g9gQIw==} + + '@crossmint/client-signers-cryptography@0.0.5': + resolution: {integrity: sha512-wS2MLFthBrOOkpwh344iSTTLXOVmLE3vy/rB7oBe9fqDFIQ1QLh2+QWw/D/n4OfVMo8kmImK3XnO+XM1xtAPKg==} + + '@crossmint/client-signers@0.3.1': + resolution: {integrity: sha512-86gCuNQlJ2baNMyISUBWmU6vmnQ/5f0wetBq8td0W5Rr/KG5T37PD69vtejX0CDOgfZm3eX519Dv+Hc6bJflUg==} + + '@crossmint/common-sdk-auth@1.1.29': + resolution: {integrity: sha512-4AnPaWDnxmPV8vsj6B9hwMDBiBgRGoM3gv1S0lzm2rDO7Uod9nqzolk8FNtLNYXUZzADxdlsbkCuG/fNbwEADg==} + + '@crossmint/common-sdk-base@0.13.0': + resolution: {integrity: sha512-ReY//P8DZszmVBDXs4saV/1U4f414l7wDpGUAMGRNWllZceQ8s3t+WCT/hghz46eg/ZzS1VVcwdFbugLgk9hew==} + + '@crossmint/wallets-sdk@1.20.6': + resolution: {integrity: sha512-R2KvFAaK4DXSv++vwnv3LkETdzH9CN2kFwdsGi885ItkXC22UVf+P/1NCsblt00DJhFEMgm8CjajrNBwPA9z1w==} + peerDependencies: + '@solana/web3.js': ^1.98.1 + + '@datadog/browser-core@6.24.1': + resolution: {integrity: sha512-ViLqvvCrZtKRCrSCcrZmSbc4Th7Y0rUQ7PruP1KGNgmE2fY4rrRP/n77zXuF8y/bmBce0na8kCdoCUkKzl/xuQ==} + + '@datadog/browser-logs@6.24.1': + resolution: {integrity: sha512-SmqUVzif6IRrdkhh8mewfFa64IfcnkPXLgMYigJDzo7O1f8PEuHF63sDJ2/x2hTXR68e2JKBKE/ooFpAmtCnYw==} + peerDependencies: + '@datadog/browser-rum': 6.24.1 + peerDependenciesMeta: + '@datadog/browser-rum': + optional: true + + '@dynamic-labs-connectors/base-account-evm@4.7.1': + resolution: {integrity: sha512-cltg1IBdcbJt+fgoBLH86AfmNlgurWOllLZ6ngcmvSlebNvaCmXc2yvhUCrr4YKpwqkmGUdt+5RQdNJYkXb9MA==} + peerDependencies: + '@dynamic-labs/ethereum-core': ^4.88.7 + '@dynamic-labs/wallet-connector-core': ^4.88.7 + viem: ^2.21.55 + + '@dynamic-labs-connectors/metamask-evm@4.7.1': + resolution: {integrity: sha512-/7CaVI53j6FB2HBppM/97TreQ/tq7pSRqA8SACZeI0myXm2wMQgn3dptNH2g/bBZ+KohUHO7CdIEaeQ1jFl7Ng==} + peerDependencies: + '@dynamic-labs/ethereum': ^4.88.7 || ^5.0.0 + '@dynamic-labs/ethereum-core': ^4.88.7 || ^5.0.0 + '@dynamic-labs/wallet-connector-core': ^4.88.7 || ^5.0.0 + viem: ^2.21.55 + + '@dynamic-labs-connectors/metamask-solana@4.7.1': + resolution: {integrity: sha512-u+Kp/gwL/7kIrhWt+MzRzDZu8JF40Tox5EFMLMDnCKbdP9MSMQ8ckMBiQUkBRulC6nGfN3Gut4bpiwdWpQHzKQ==} + peerDependencies: + '@dynamic-labs/solana-core': ^4.88.7 + '@dynamic-labs/wallet-connector-core': ^4.88.7 + '@solana/web3.js': '>=1.0.0' + + '@dynamic-labs-sdk/assert-package-version@1.39.1': + resolution: {integrity: sha512-QiQKcJPK4piu+WdmZTnk8qTgPhcUuCKmNqd32RgBNLwn8AEQ36FWsPE+y7RXPg7yO3u67QokKUKHkrV3lxDstA==} + + '@dynamic-labs-sdk/client@1.39.1': + resolution: {integrity: sha512-h+5t9g9t+rqMkhC8kgrgscAlIZTmyUwvMRbiQEGZidLLqFBd5M6qoYmOr9p6wnD2g389eSpYlNfLh7lJwkhlRg==} + peerDependencies: + '@react-native-async-storage/async-storage': ^2.2.0 + react-native: '>=0.73.6' + react-native-inappbrowser-reborn: ^3.7.0 + react-native-keychain: ^10.0.0 + react-native-passkey: '>=3.3.2' + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + react-native: + optional: true + react-native-inappbrowser-reborn: + optional: true + react-native-keychain: + optional: true + react-native-passkey: + optional: true + + '@dynamic-labs-wallet/browser-wallet-client@1.1.33': + resolution: {integrity: sha512-YEDQFnlDnnNdY8gGDmLgFlhe39PpPbArqPN7aZkDU0SE9M11NbSdSZdV7diDAi8x+4db+DUKW0ke6oUE3+N62A==} + + '@dynamic-labs-wallet/core@1.1.33': + resolution: {integrity: sha512-NehhQyiR9Xl9AkfhmNcLtyR54J0CKva5Rfn6RWit1juODbLfZLsh4o6BWUy6zG23rIsj50FTAEpZCi5bIIN2ew==} + peerDependencies: + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2 + + '@dynamic-labs-wallet/forward-mpc-client@2.0.2': + resolution: {integrity: sha512-DUdwqhYTEGoz3wMW4PmOl4tyw5IkTGB3n3KAgLMM6UkDWPsYzH5C4hkjbb6ZQdsHqF99kmoU5gsMcylJ41bYLA==} + peerDependencies: + '@dynamic-labs-wallet/primitives': '>=0.0.336 || 0.0.1' + + '@dynamic-labs-wallet/forward-mpc-shared@0.7.2': + resolution: {integrity: sha512-C5ugG0QNL1FNoFNCo3A2Hz3h1boycoC6S5jh5GoQmVTz7/MNKAgsnYRyd/xC7a9UIiZtwr6vttXvTLxMnx/q4A==} + peerDependencies: + '@dynamic-labs-wallet/primitives': '>=0.0.336 || 0.0.1' + + '@dynamic-labs-wallet/primitives@1.1.33': + resolution: {integrity: sha512-RAgm/QL10EZ4RjJSehgf2OzUe0heAvp9SF9FJKL0eqiwjLWjsAfOh3Pl8cGpgw1bzyPGnoxr07qY8DkXaXtpFA==} + + '@dynamic-labs/assert-package-version@4.100.5': + resolution: {integrity: sha512-bST4as2Y/t46xUnLz/FvX/S9UJPL0WOo825Jm3Fjt4IbLBKK8OurCwK1NSTpiliRtC6LMCngWAXhCHS3WQTv3A==} + + '@dynamic-labs/assert-package-version@5.13.0': + resolution: {integrity: sha512-Yz8nUpsH/IT4lmQmqaeknP1DGVd5cm4Y7lqumh1MIZ6969eAirz3z0dE7DI8LGltcQSizGUWhDdqux3d9x+k7Q==} + + '@dynamic-labs/embedded-wallet-evm@4.100.5': + resolution: {integrity: sha512-9OgkJxb1l6d4oHwiG9DepqOYtJiSFfLYagHe8ENSoSEAd0cKlRcmoSWsGoUHCtMd1v7uavL+Dx9ajjW8ebmQrA==} + peerDependencies: + viem: ^2.45.3 + + '@dynamic-labs/embedded-wallet-solana@4.100.5': + resolution: {integrity: sha512-utaN4ke1cBOVZVTLqp0Rz7NzEt7JhG3F6cnL0dwAR7u2bVMxmkKRi5BzvkPmhQenZMGwJwQLOfv4nMrwYJxEsg==} + + '@dynamic-labs/embedded-wallet@4.100.5': + resolution: {integrity: sha512-LU8S+aa9qeIbZCZ6Pxn4hIcRnGuscXhsQBVzTAYm3nLcvmUYAhJRsvlyFscMughb2Ox3zIQVc1M+8IPaQzhrJQ==} + + '@dynamic-labs/ethereum-core@4.100.5': + resolution: {integrity: sha512-rzk2d6eHpgq1k8Qqz1kDRjrlG6kIbhFKO1QRuX+GthHgsyDePpm+ddi7oBQPfr6iX408iCzlU4Om/U1Yw9O4RA==} + peerDependencies: + viem: ^2.45.3 + + '@dynamic-labs/ethereum-gasless-core@4.100.5': + resolution: {integrity: sha512-5iw5s5gdfPCqFO/t6630S7HLm9enRFU8+fPEk9QLZuxkRql0zZHxqmiiSHTe2VH6J2oWk5ihbikIlxaTZY4m4w==} + peerDependencies: + viem: ^2.45.3 + + '@dynamic-labs/ethereum@4.100.5': + resolution: {integrity: sha512-H1iaR4QUOL56xS7kJ98gjdcgHpAO2TemFdjrZcgEYhIwZT7UaeyiwQdch7aJufDtt86881NYRwe/xVdGcZvYfQ==} + peerDependencies: + viem: ^2.45.3 + + '@dynamic-labs/iconic@4.100.5': + resolution: {integrity: sha512-/IbtQXavqfDGYVFVMfYeWBOjJKEIARYEU7NBya1En0odmIqDi2ka1G9kAHdhoqkyzxYHa8YXaBbbMrcquGII9A==} + peerDependencies: + react: '>=18.0.0 <20.0.0' + react-dom: '>=18.0.0 <20.0.0' + + '@dynamic-labs/locale@4.100.5': + resolution: {integrity: sha512-z2H1gXVtX17ZqFUu51GXkbDjLTiGu9EPqN3WqD39DGA7Z91d0OE9Pn6k0tRm+fGBKiH+OtoMr/4ZIiwC9diRyg==} + + '@dynamic-labs/logger@4.100.5': + resolution: {integrity: sha512-eOK1cI5wQ20DAul499k1rOV89w5MN6+T7E9RPpGxXQ80ZhqOspqGiQK/H+Yh7XxjqVMbZ4EJIy0k8VeNwHuSew==} + + '@dynamic-labs/logger@5.13.0': + resolution: {integrity: sha512-UkX7DmFGPVcxpeHflg5cv8O9TtheGRq6kKMYK53lNMAqDsuTIdlaWStRWB2jJCpWF4Cj7MQkLGGTNoVVIi0ZeQ==} + + '@dynamic-labs/message-transport@5.13.0': + resolution: {integrity: sha512-hZ2aPBMebKQL0/gTiXnyIHU8GPU+C+m73VzrZHCQ4xoJ0sxoZTja/jtnbvCUfPsLtMfdHrrv2tTUGWA5GAHceg==} + + '@dynamic-labs/multi-wallet@4.100.5': + resolution: {integrity: sha512-qgvKdWLW85YdOlwqfZcSB0fSBvGuNryE0pv+zVoU6R+mRpm9gAMQ9zFZhnP54pvBpyZGnhKcBS9MkU1QhFu2PA==} + + '@dynamic-labs/redaction@1.1.0': + resolution: {integrity: sha512-y3ixDtS4N+ZEgQC17k3d3oyxZ5BJ+sAGvQRklXCilwYkWOMwtMc6QEx/5uHz1PS/rxWYuZk+Egr1AC5NuzZLrg==} + + '@dynamic-labs/rpc-providers@4.100.5': + resolution: {integrity: sha512-HyQQTRVvFNFohUgDqQ1cqeyX6xIDknsEVlbx0xnvx4OwhkNHYyAdZP42AfkyDaTE8uXhf/JA1qFk4Gj3URIi3g==} + + '@dynamic-labs/sdk-api-core@0.136.0': + resolution: {integrity: sha512-dQwmQQQeYGcPgk53lGfnghVC9QMK5BxOA5LPHVn5+HjebuDClq8QWTYoihY0dM3bX8xf68R2W4dgRvh4B3VcvA==} + + '@dynamic-labs/sdk-api-core@0.50.0': + resolution: {integrity: sha512-qdOdnBDB/q8zfe22jQr+4wBiKcawaLNxYJGNxMs5n+tF4jh2F98ZMv0JiJXPRc/W4jpnjgTNfEAfQErcpaxoOQ==} + + '@dynamic-labs/sdk-api-core@0.92.0': + resolution: {integrity: sha512-5ABRxs5KLbdKZ9yA/kF7wa7rimKMQLxr5yz6bwFW+L0k7quUepYFwKQeIxgqecVuGmnq3WeFoc/l9MY90s3XKw==} + + '@dynamic-labs/sdk-react-core@4.100.5': + resolution: {integrity: sha512-ckDYKc2zeGadng5WMBUFYyXiqqEdSm17gYwMoseqRkfjCPatQBG6QvkUzKVx1gSPP16CayUX3aORhByZkPOriw==} + peerDependencies: + react: '>=18.0.0 <20.0.0' + react-dom: '>=18.0.0 <20.0.0' + + '@dynamic-labs/solana-core@4.100.5': + resolution: {integrity: sha512-5qNrLlUtFW0L1sLhi6vuLvwnyUCCuqw2eyRLrH0Q9ZWpvYT3pevdCYAS5aoL55aKzZ1H+kGMAphxdzKfKzrCjw==} + + '@dynamic-labs/solana@4.100.5': + resolution: {integrity: sha512-0mr1zd05BLQgmAYwpAQuqqtu/a/cFeT/aq0j6abJFrP30Nnm3xeAQejgP9HpEhVQPIzOEHb9K6Wzs40E46oeDg==} + + '@dynamic-labs/store@4.100.5': + resolution: {integrity: sha512-pfHZ9efW4uP+0ANSUwo0t2xWD2IIDyY0dqhMfBmnmM7Jh5JD4GUwssZi8C7cGAkpVhSd9MKV3S1vhmpI59UhTA==} + + '@dynamic-labs/sui-core@4.100.5': + resolution: {integrity: sha512-H+qEl7fDQ9uCpOpSve1B1nglGjZR1nQxZvSg0WfAYRftU3TKTBu+zzCEcO0HEQFBYc18OxHujc6e5ECHXKvTvQ==} + + '@dynamic-labs/sui@4.100.5': + resolution: {integrity: sha512-CKXi+71KNAITi8eayK/VCztgTGNtbqR2KM4AK7cvrWH6Tp16gp/J2KSkQX37nzwbqpO62croKjkXHarJVa7E8w==} + + '@dynamic-labs/types@4.100.5': + resolution: {integrity: sha512-2F1CSxfYxNxkpdwJ+Hlr2/O/P/vYHb7KBi1xOg7FZizVq8zOx0YCW8iEtQ4z1SuCzZ5gac4lSRs2uuOj2D2+Zg==} + + '@dynamic-labs/types@5.13.0': + resolution: {integrity: sha512-qVZV0vKOlOY4zzOcpPyu23FJ3LQpidNIvdQ23TV4EeWSXbk3snRYTUz3DPVJ8h6/P/8K8SxDiAZY4GP4NzNM6A==} + + '@dynamic-labs/utils@4.100.5': + resolution: {integrity: sha512-3csnU31aISjwgA1QXRtcvOqak/82SC5oQFHj4uvktfLjPMqSzg83C11d0X/1WD9S2K3XhqPEWqDxFfpxwCxvvw==} + + '@dynamic-labs/utils@5.13.0': + resolution: {integrity: sha512-F5yZD6gUEuHO7rAhLSkcQAkLbh8idQid6bYp8Pxo+mgLOQ83pPb7v8lacvi5BLh59nWmbASGNyt65FPrpelJnw==} + + '@dynamic-labs/waas-evm@4.100.5': + resolution: {integrity: sha512-EEHG226vDKsx1/b2qD+P8oYQwybLSg2+ej/Ars70Rt4hu3Cx1os+8db3dShc4BeHznQkPn/vwi53nuAJxy8OwA==} + + '@dynamic-labs/waas-sui@4.100.5': + resolution: {integrity: sha512-ABSuP2WHUAhJdI2fGE7TbjJyKNWQY7/Z+rBfvyzaiGngvZ9Tt+8aPjL4No8ksTa+mb7BF2qoKBCQfLNs54DPvA==} + + '@dynamic-labs/waas-svm@4.100.5': + resolution: {integrity: sha512-fz+JVc+VRpCyq+VsrJY5txwAZcx/ducsGLkSUioCsRwhmZOF5Yjo1TD/eenkEMAti9B3FDQtkWurdRu4MxoFsQ==} + + '@dynamic-labs/waas@4.100.5': + resolution: {integrity: sha512-oOUBfDde1Nw4kDtToecaBkrR9MLMXANGcAcYzjzaCbgMHMp9j8cNAOZ2pgV9JPG2C6iHTfJAAeaOk+GXopWq1w==} + + '@dynamic-labs/wallet-book@4.100.5': + resolution: {integrity: sha512-cXtNumBHNa6A6g1ktDn0wsl2EXAnkwoX43ufGquyP9Rszw7k3/BwTrCW+81+lAQ3oQV48fumk9CX1zpthUlOIg==} + peerDependencies: + react: '>=18.0.0 <20.0.0' + react-dom: '>=18.0.0 <20.0.0' + + '@dynamic-labs/wallet-connect@4.100.5': + resolution: {integrity: sha512-lfkLYbJaV9R3K2TN8Mozd+Q/60iGTLYLpe4F/7iMSrbEIjlyGX6wLBEGD18DlL+AdYAgkefAgmgcqLKPzfj1dA==} + + '@dynamic-labs/wallet-connector-core@4.100.5': + resolution: {integrity: sha512-i+jQioIUvbo0DbQXowU+RYfmZEwfGP8lBLGSMUwq/i6/HH54Ojqg1cl800AFJVW6ntSUWMbjWk/SE+oSvZ7g5A==} + + '@dynamic-labs/webauthn@4.100.5': + resolution: {integrity: sha512-DZSbprKmmcOMmefP/Msc1xfauNfPypwb5o0aJ1nKkNhkv2MRxk8zrNfprzhVtp/u/Gy3YrAdGWywVgZX1H+TvA==} + + '@ecies/ciphers@0.2.6': + resolution: {integrity: sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==} + engines: {bun: '>=1', deno: '>=2.7.10', node: '>=16'} + peerDependencies: + '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -204,6 +490,60 @@ packages: '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/is-prop-valid@1.4.0': + resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/styled@11.14.1': + resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==} + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@esbuild/aix-ppc64@0.28.2': resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} @@ -404,6 +744,80 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ethereumjs/common@3.2.0': + resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} + + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + + '@ethereumjs/tx@4.2.0': + resolution: {integrity: sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==} + engines: {node: '>=14'} + + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + + '@evervault/wasm-attestation-bindings@0.3.1': + resolution: {integrity: sha512-pJsbax/pEPdRXSnFKahzGZeq2CNTZ0skAPWpnEZK/8vdcvlan7LE7wMSOVr+Z+MqTBnVEnS7O80TKpXKU5Rsbw==} + + '@gql.tada/cli-utils@1.9.4': + resolution: {integrity: sha512-xQ9M+2Xxjxhz9IJi+7IMU/aOsEtuSiSNb4OgDMBUC/8AcSpo2vDtx71Aodsaif4qSwuTb0YFVfDwC+ESqiZSHg==} + peerDependencies: + '@0no-co/graphqlsp': ^1.16.0 + '@gql.tada/svelte-support': 1.0.3 + '@gql.tada/vue-support': 1.0.3 + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@gql.tada/svelte-support': + optional: true + '@gql.tada/vue-support': + optional: true + + '@gql.tada/internal@1.2.2': + resolution: {integrity: sha512-4lZcElPP6MC8Ct8KN70LR2WQsHjbAsyAmTGG09VsOPhx738UFIYaL0S1XiI2pqq2tj/sDs/y3b9jvKoWGL7iuQ==} + peerDependencies: + graphql: ^15.5.0 || ^16.0.0 || ^17.0.0 + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@hcaptcha/react-hcaptcha@1.4.4': + resolution: {integrity: sha512-Aen217LDnf5ywbPSwBG5CsoqBLIHIAS9lhj3zQjXJuO13doQ6/ubkCWNuY8jmwYLefoFt3V3MrZmCdKDaFoTuQ==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + + '@hey-api/client-fetch@0.8.1': + resolution: {integrity: sha512-AaVNVLBl7N9Fun7QDnb00YDubAFjB9ICi5U6kmzcJSnnQTQGRMsuBBRupQV5ERdMMFt71zjSDym7Z+gLVe8m3A==} + deprecated: Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts. + + '@hpke/chacha20poly1305@1.8.0': + resolution: {integrity: sha512-FcBfAQ+Y99vMNJP2yrZ9wpL8V0GOwp1+zMyzvc6alasrBygfFjFm1yeUtyADJCu/27C3Lm5mJzx6u7pwg+cX5w==} + engines: {node: '>=16.0.0'} + + '@hpke/common@1.10.1': + resolution: {integrity: sha512-moJwhmtLtuxiUzzNp1jpfBfx8yefKoO9D/RCR9dmwrnc7qjJqId1rEtQz+lSlU5cabX8daToMSx/7HayXOiaFw==} + engines: {node: '>=16.0.0'} + + '@hpke/core@1.9.0': + resolution: {integrity: sha512-pFxWl1nNJeQCSUFs7+GAblHvXBCjn9EPN65vdKlYQil2aURaRxfGMO6vBKGqm1YHTKwiAxJQNEI70PbSowMP9Q==} + engines: {node: '>=16.0.0'} + + '@hpke/dhkem-x25519@1.8.0': + resolution: {integrity: sha512-S1MWWkAfu+TFxySgv5+2P3O4Mx/jk7BsoplzQaA1s3sfUJVJ2UsZsSzSsMc+FXJumLXncoJFlO6mK6mDGspfmA==} + engines: {node: '>=16.0.0'} + + '@hpke/dhkem-x448@1.8.0': + resolution: {integrity: sha512-mFfnZfgp4OKkUIS/FKikfUgdnDKRy25ytCKBQiV+N+HbYy3I4v4ZCPBQ69QL+TYmKmCZJeUEnYeS5K+OBRP+Eg==} + engines: {node: '>=16.0.0'} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -428,81 +842,163 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} + '@img/sharp-darwin-arm64@0.35.0': + resolution: {integrity: sha512-ZgaYEwaj+lx/5n4W8GmZ2IYz0PQHjN5eqRcfijWGB+2Aq7ZInZGa0qJyAn6DEtyLuWHRSrmWOqT9q3qqTBvmUQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [darwin] + '@img/sharp-darwin-arm64@0.35.5': resolution: {integrity: sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] + '@img/sharp-darwin-x64@0.35.0': + resolution: {integrity: sha512-c1z9LFpKB0slQW3RchwBE8iSVzGp70TNjUUO9k4BZwwW4HH7JBGHeIy4b+kk4n/kcBASb9evKCE3/7Slmslgiw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [darwin] + '@img/sharp-darwin-x64@0.35.5': resolution: {integrity: sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] + '@img/sharp-freebsd-wasm32@0.35.0': + resolution: {integrity: sha512-Li2KTev0H90kEtnJHkI9xQojXt1AqWmFBMXiPw5kqd1jQgP7gi5HVK/qC5Rmh/59NuAwUuPzzPITmX22NomYYQ==} + engines: {node: '>=20.9.0'} + os: [freebsd] + '@img/sharp-freebsd-wasm32@0.35.5': resolution: {integrity: sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==} engines: {node: '>=20.9.0'} os: [freebsd] + '@img/sharp-libvips-darwin-arm64@1.3.0': + resolution: {integrity: sha512-EKbmBKtyTH+GPFDRw2TgK2oV6hyxxlJVIar4hoTYSNmIwipgMFdxPQqR392GmfdsPGWga0mCFN1cCKjRb9cljw==} + cpu: [arm64] + os: [darwin] + '@img/sharp-libvips-darwin-arm64@1.3.4': resolution: {integrity: sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==} cpu: [arm64] os: [darwin] + '@img/sharp-libvips-darwin-x64@1.3.0': + resolution: {integrity: sha512-Pl2OmOvrJ42adUllESxBsG54PfXLo1OYg9i3c5/5Ln/qJ0gZuTM9YMhQJPIbXqwidLRc/c2zuHt4RsrymmNv7A==} + cpu: [x64] + os: [darwin] + '@img/sharp-libvips-darwin-x64@1.3.4': resolution: {integrity: sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==} cpu: [x64] os: [darwin] + '@img/sharp-libvips-linux-arm64@1.3.0': + resolution: {integrity: sha512-C0SqjoFKnszqa44EQ7xoaT48nnO0lOyXEULfXMWi8krrjOPGYkeK30Okzla6ATbBYsyZ0ySinK0FVkpv3DwzfQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-arm64@1.3.4': resolution: {integrity: sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==} cpu: [arm64] os: [linux] libc: [glibc] + '@img/sharp-libvips-linux-arm@1.3.0': + resolution: {integrity: sha512-A8UpHoUDW4DwnXoV6+q3C1s7QLRAHtPDEjWuNZjwHMyoCNZnm0GeNN8ls9f/bsEYTRQRW96C/n34XJQHJ2fT7A==} + cpu: [arm] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-arm@1.3.4': resolution: {integrity: sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==} cpu: [arm] os: [linux] libc: [glibc] + '@img/sharp-libvips-linux-ppc64@1.3.0': + resolution: {integrity: sha512-WOpkVxAjFd369iaIzEgNRreFD+gWdUMIGD5zplhNKNeqS6mm5dac3q2AFyCBmzYoAdouzZvRBgxy4z8QHZb4/A==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-ppc64@1.3.4': resolution: {integrity: sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==} cpu: [ppc64] os: [linux] libc: [glibc] + '@img/sharp-libvips-linux-riscv64@1.3.0': + resolution: {integrity: sha512-DRWw0mOHusrCCuw2rqP87oLg6PGlkomVDFqw2hIwsSfwWpu4k3XLcBPaKKl6ct/GtL/cwNkgwjV/tc0Mqht3VA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-riscv64@1.3.4': resolution: {integrity: sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==} cpu: [riscv64] os: [linux] libc: [glibc] + '@img/sharp-libvips-linux-s390x@1.3.0': + resolution: {integrity: sha512-9APy+nFWhHS+kzLgWZfLcyrUd7YqnAQVa4BPOo4xkoHpdoktOAPG4cEr9+Jpl0TtqfVmcMJimNL5qNTyyOHZNA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-s390x@1.3.4': resolution: {integrity: sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==} cpu: [s390x] os: [linux] libc: [glibc] + '@img/sharp-libvips-linux-x64@1.3.0': + resolution: {integrity: sha512-y9RNUYDe2A1UAdhLyfeOodGRszQdaEoe4nfOpp/sNVPl2CWIcUyFaDoCh4vPLPxu19803j2naLqZup2WxDXCLA==} + cpu: [x64] + os: [linux] + libc: [glibc] + '@img/sharp-libvips-linux-x64@1.3.4': resolution: {integrity: sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==} cpu: [x64] os: [linux] libc: [glibc] + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + resolution: {integrity: sha512-cC1wkC0Mlucd0KSiGrLkJnB/ZqPvZCntc/Lk7ZnYO5ZSbF2euNek4Xvxafojq+wN1q/W0eprdpUIjUr/EV2PBg==} + cpu: [arm64] + os: [linux] + libc: [musl] + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': resolution: {integrity: sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==} cpu: [arm64] os: [linux] libc: [musl] + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + resolution: {integrity: sha512-LiYMhUZicB1QG//+RvmYZpXJO8fYRENfp+MZUCnG9aw+AKvGAy9gPaCnuwsPcBFs8EV66M0NNxj9VHcNklE8zw==} + cpu: [x64] + os: [linux] + libc: [musl] + '@img/sharp-libvips-linuxmusl-x64@1.3.4': resolution: {integrity: sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==} cpu: [x64] os: [linux] libc: [musl] + '@img/sharp-linux-arm64@0.35.0': + resolution: {integrity: sha512-4+4XHLNT5wDT0roYlHTEmH9lDKt0acf9Tv+3hM3iceOirkxrR404/3WjAYZ9F9CkHrxeRcGLJXbi4vluMZ9O+A==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@img/sharp-linux-arm64@0.35.5': resolution: {integrity: sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==} engines: {node: '>=20.9.0'} @@ -510,6 +1006,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linux-arm@0.35.0': + resolution: {integrity: sha512-VVlpEWwizEFIOom0zdoeKuO5nuTswzVE5uHcBNvHzmeHUpNFajY3HFfbQ+zIH4E2kVaZ/yVxmsShW56TtEy4uA==} + engines: {node: '>=20.9.0'} + cpu: [arm] + os: [linux] + libc: [glibc] + '@img/sharp-linux-arm@0.35.5': resolution: {integrity: sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==} engines: {node: '>=20.9.0'} @@ -517,6 +1020,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linux-ppc64@0.35.0': + resolution: {integrity: sha512-N3hzbEpUTJC8pWpPVJvgzGxM+so/MAXc8O2s/53B0LL9ZGpfXpME7Wizkc5d/8fRBlBtkDjzoZGDCqqNDHqLEw==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@img/sharp-linux-ppc64@0.35.5': resolution: {integrity: sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==} engines: {node: '>=20.9.0'} @@ -524,6 +1034,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linux-riscv64@0.35.0': + resolution: {integrity: sha512-l6vmKVPnbS0RhVMbyxP5meAARsbhCnBN4fy31qz0+3a6Rv4jEqfzDrT89y6ZPkCi0AJGnwp2En528yXo401Hpw==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] + os: [linux] + libc: [glibc] + '@img/sharp-linux-riscv64@0.35.5': resolution: {integrity: sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==} engines: {node: '>=20.9.0'} @@ -531,6 +1048,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linux-s390x@0.35.0': + resolution: {integrity: sha512-MYlMiPFiv/EKPAHnp3yNZ9AAWFsxga9c5Bkc6wkar6bqzHLlkGVJHRm0u1ei+VXnZxp3Mz9MG9ZIsI8vSOf3sQ==} + engines: {node: '>=20.9.0'} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@img/sharp-linux-s390x@0.35.5': resolution: {integrity: sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==} engines: {node: '>=20.9.0'} @@ -538,6 +1062,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linux-x64@0.35.0': + resolution: {integrity: sha512-TYaItB5oj1ioXjhyn2xrR208vf+YuIIcHptQWRRaBmFhvIvL9D72DXN8w75xup0KXA8UdEAhQ9Qb2S49FD/9Cw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + '@img/sharp-linux-x64@0.35.5': resolution: {integrity: sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==} engines: {node: '>=20.9.0'} @@ -545,6 +1076,13 @@ packages: os: [linux] libc: [glibc] + '@img/sharp-linuxmusl-arm64@0.35.0': + resolution: {integrity: sha512-DSTb6ijQzqe6DdAaOBVqJ/SYf1vO8EW5bK6X6LRXufEBebf2722VCdvBUtZ3rtV0x2ApfPNDy/p7LrrjaWjiyQ==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + '@img/sharp-linuxmusl-arm64@0.35.5': resolution: {integrity: sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==} engines: {node: '>=20.9.0'} @@ -552,6 +1090,13 @@ packages: os: [linux] libc: [musl] + '@img/sharp-linuxmusl-x64@0.35.0': + resolution: {integrity: sha512-K7ykQ+26Rt6+4BTU80AuGgTPIYX86UxiAKT4rcXX/WNTo7k1ZxpKz+TguHnwVpCqQK3B5PK0vZ0ZBe6nz/ib1w==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [linux] + libc: [musl] + '@img/sharp-linuxmusl-x64@0.35.5': resolution: {integrity: sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==} engines: {node: '>=20.9.0'} @@ -559,27 +1104,54 @@ packages: os: [linux] libc: [musl] + '@img/sharp-wasm32@0.35.0': + resolution: {integrity: sha512-9woLIFORERCr+6cWu87dQ22J34EExkhc73U1kZW0c+RclQqWetoodByp4dWZ/hN8/KVmTRAx2HOnUwib8AwZdA==} + engines: {node: '>=20.9.0'} + '@img/sharp-wasm32@0.35.5': resolution: {integrity: sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==} engines: {node: '>=20.9.0'} + '@img/sharp-webcontainers-wasm32@0.35.0': + resolution: {integrity: sha512-t+kie1TOyaDM6Dho+f+y0VqIUNhYQaKCUahuZVi0E0frgdiaOaPsDxDW3wfKacUdaNBCnK/ZDBMg33ydvHj8uA==} + engines: {node: '>=20.9.0'} + cpu: [wasm32] + '@img/sharp-webcontainers-wasm32@0.35.5': resolution: {integrity: sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==} engines: {node: '>=20.9.0'} cpu: [wasm32] + '@img/sharp-win32-arm64@0.35.0': + resolution: {integrity: sha512-M5eKxug0dabbaWgFKvPa3odNs2OpaP+81NASfGKkt4GcYXpNhSu7CaeYxWkLNV6vHmUp4hnCxnxrUyhUJhXbKA==} + engines: {node: '>=20.9.0'} + cpu: [arm64] + os: [win32] + '@img/sharp-win32-arm64@0.35.5': resolution: {integrity: sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] + '@img/sharp-win32-ia32@0.35.0': + resolution: {integrity: sha512-z0+pZ03QCDvdVN0Ez9IX/yjWC19ikMlXrmdYMwYNLTh2BLPx3hXWPvyqWfquZ0BTO9O6GVOjIVoTcyyacMnWlQ==} + engines: {node: ^20.9.0} + cpu: [ia32] + os: [win32] + '@img/sharp-win32-ia32@0.35.5': resolution: {integrity: sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==} engines: {node: ^20.9.0} cpu: [ia32] os: [win32] + '@img/sharp-win32-x64@0.35.0': + resolution: {integrity: sha512-feNnlz5ZHKr0MY1LPHvZQyJeBkbo4ctsn0D8FvA53VTw5TC63rfEL2UrWbkSBR19htSE7Mw78xYVwdJqoMWVHw==} + engines: {node: '>=20.9.0'} + cpu: [x64] + os: [win32] + '@img/sharp-win32-x64@0.35.5': resolution: {integrity: sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==} engines: {node: '>=20.9.0'} @@ -602,6 +1174,113 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@lit-labs/ssr-dom-shim@1.6.0': + resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==} + + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} + peerDependencies: + '@types/react': 17 || 18 || 19 + + '@lit/reactive-element@2.1.2': + resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + + '@marsidev/react-turnstile@1.5.2': + resolution: {integrity: sha512-+3aBPxp86JzSC0ZmgyonoGoUEENcUkH3LGahXSpkV87ArvD2DzRCmPgh0FyQk6PQRmJwQJDAfwNavFsxUxMQWA==} + peerDependencies: + react: ^17.0.2 || ^18.0.0 || ^19.0 + react-dom: ^17.0.2 || ^18.0.0 || ^19.0 + + '@metamask/analytics@0.6.0': + resolution: {integrity: sha512-L250lV3PANTcKqhZkmRV1Obkyddm6JDQvDBuUVAi+7TmPdOVdpavWNXyEh7ErscjwG0z2wiF9Ne0ihK/nCdX0w==} + engines: {node: '>=20.19.0'} + + '@metamask/connect-evm@2.1.0': + resolution: {integrity: sha512-u0eYWPGWOk9w7ne+dAynO0saN2mCXfkt1QLGo829kiDLO0YGuFSNXWpRxnIygm6j9s9NOVLkL7+tkyZCR755Jw==} + engines: {node: '>=20.19.0'} + + '@metamask/connect-multichain@1.1.0': + resolution: {integrity: sha512-PywCTfcSkLHTkEYhnrQbQPv/6laXTPKLmVlJnCAkqFon0jxX6ETCthZcA30fwUQhiOONmG5/MZano3imH+K5dA==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@react-native-async-storage/async-storage': ^1.23 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@metamask/connect-multichain@1.2.0': + resolution: {integrity: sha512-EoRXtP8cpLhY/YRlQ8rSjzYrc+ykJjMYPL6sF2U9b8Ron9yAVjZCPfSftBjee/tXxQDJ8BupmZbkv4af/vVuSQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@react-native-async-storage/async-storage': ^1.23 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@metamask/connect-solana@2.1.0': + resolution: {integrity: sha512-cse70fsY0ObINGytj2bskx25Xb6pOKJAGBO/PW1jAMEFI+xijlHznGo1vsON14dUKJKyiZyCoTSxrA40NlNB8w==} + engines: {node: '>=20.19.0'} + + '@metamask/mobile-wallet-protocol-core@0.4.0': + resolution: {integrity: sha512-rB1wMogvSUsFaxyH/eVUCczIkTxVaPPETlD/wgm+gw7EbWP0LlZPY7Bh+DICSfUCJ0zqnoFuwr77WNJvZ6ZiWw==} + engines: {node: '>=20'} + + '@metamask/mobile-wallet-protocol-dapp-client@0.3.0': + resolution: {integrity: sha512-rXStrvIa57a8OaeM+3HeR6Z9ETHOvmQi/9s6CLplDwH2hn2MWjI6WW3EUrxq2KGmGuhbO5Oo21ANnD23QKfduw==} + engines: {node: '>=20'} + + '@metamask/multichain-api-client@0.10.1': + resolution: {integrity: sha512-LsqO2SiDcTgOuXyVYEB0zgBaVNhryhP2tYI3L7tLa7PoeDqMkNIreFhDeu8jM5tPWkCimQvMwCkG3DF4P5dD3A==} + engines: {node: ^18.20 || ^20.17 || >=22} + + '@metamask/multichain-ui@0.4.1': + resolution: {integrity: sha512-tJgTot8Pfkda895A6biJu7rE+jlQdVCNVzGgW+2wM9aFG20G+GEbQy3KO7uC4ImUvaKV4SyJ45r6Ir/Yf55mqw==} + engines: {node: '>=20.19.0'} + + '@metamask/onboarding@1.0.1': + resolution: {integrity: sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==} + + '@metamask/rpc-errors@7.0.3': + resolution: {integrity: sha512-nrEaeBawm8yFU7hetJKok/CUs0tQsWtTqp3OLbFhPUMXYqU7uI5LAV5vi9o7rTjFkUyof7Nzbw5bea5+1ou+dg==} + engines: {node: ^18.20 || ^20.17 || >=22} + + '@metamask/scure-bip39@2.1.1': + resolution: {integrity: sha512-1K8aBsAqr6+8jWhguVl06n8e+zjV9sUnys+5PLyVU4mb8LbulQ60F6cq7iQys3xX/yCwKt1+7c7j2nuTEpW+ZQ==} + engines: {node: ^16.20 || ^18.16 || >=20} + + '@metamask/solana-wallet-standard@0.6.0': + resolution: {integrity: sha512-gF763JvLIywPttw+vfRdZx0uHlB0sEbxOGFedblMk78SbQ/KyQrmjHRkFVVrG21oLZgCNEh3uQpCWBdW2+eUzw==} + engines: {node: ^18.20 || ^20.17 || >=22} + + '@metamask/superstruct@3.4.1': + resolution: {integrity: sha512-caTaaBUcwBGbUNf3r0uT48upX4nECRbKhQ9pPOfW4sIkfcIUUDV4S9DZxq/5fuNPVt5KWpyd5xIIz0sP+iWLlg==} + engines: {node: '>=16.0.0'} + + '@metamask/utils@11.12.1': + resolution: {integrity: sha512-X97J5AEcaKDTIAfKb4X93ZTLfvOahzDVadlveQW+7OZ7yhXjMxXoFmhX2d9UKv48iS2Dxq9kbGJ1lUfphu9ebQ==} + engines: {node: ^18.18 || ^20.14 || >=22} + + '@metamask/utils@9.3.0': + resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==} + engines: {node: '>=16.0.0'} + + '@msgpack/msgpack@3.1.2': + resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==} + engines: {node: '>= 18'} + + '@mysten/bcs@1.9.2': + resolution: {integrity: sha512-kBk5xrxV9OWR7i+JhL/plQrgQ2/KJhB2pB5gj+w6GXhbMQwS3DPpOvi/zN0Tj84jwPvHMllpEl0QHj6ywN7/eQ==} + + '@mysten/sui@1.45.2': + resolution: {integrity: sha512-gftf7fNpFSiXyfXpbtP2afVEnhc7p2m/MEYc/SO5pov92dacGKOpQIF7etZsGDI1Wvhv+dpph+ulRNpnYSs7Bg==} + engines: {node: '>=18'} + + '@mysten/utils@0.2.0': + resolution: {integrity: sha512-CM6kJcJHX365cK6aXfFRLBiuyXc5WSBHQ43t94jqlCAIRw8umgNcTb5EnEA9n31wPAQgLDGgbG/rCUISCTJ66w==} + + '@mysten/wallet-standard@0.19.9': + resolution: {integrity: sha512-jHFt+62os7x7y+4ZVMLck8WSanEO9b8deCD+VApUQkdAHA99TuxbREaujQTjnGQN5DaGEz8wQgeBPqxRY/vKQA==} + '@napi-rs/wasm-runtime@1.2.5': resolution: {integrity: sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==} engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} @@ -667,6 +1346,72 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@0.4.1': + resolution: {integrity: sha512-QCOA9cgf3Rc33owG0AYBB9wszz+Ul2kramWN8tXG44Gyciud/tbkEqvxRF/IpqQaBpRBNi9f4jdNxqB2CQCIXg==} + + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} + + '@noble/curves@1.8.0': + resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.0': + resolution: {integrity: sha512-7YDlXiNMdO1YZeH6t/kvopHHbIZzlxrCV9WLqCY6QhcXOoXiNCMDqJIglZ9Yjx5+w7Dz30TITFrlTjnRg7sKEg==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.2': + resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.4': + resolution: {integrity: sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@2.0.1': + resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} + engines: {node: '>= 20.19.0'} + + '@noble/hashes@1.3.3': + resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} + engines: {node: '>= 16'} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@noble/hashes@1.7.0': + resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} + engines: {node: '>= 20.19.0'} + + '@noble/post-quantum@0.5.4': + resolution: {integrity: sha512-leww0zzIirrvwaYMPI9fj6aRIlA/c6Y0/lifQQ1YOOyHEr0MNH3yYpjXeiVG+tWdPps4XxGclFWX2INPO3Yo5w==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -697,9 +1442,84 @@ packages: resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} + '@openzeppelin/contracts@4.9.6': + resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} + '@oxc-project/types@0.153.0': resolution: {integrity: sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==} + '@paulmillr/qr@0.2.1': + resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} + deprecated: 'Switch to "qr" (new package name) for security updates: npm install qr' + + '@phosphor-icons/webcomponents@2.1.5': + resolution: {integrity: sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q==} + + '@protobuf-ts/grpcweb-transport@2.11.1': + resolution: {integrity: sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==} + + '@protobuf-ts/runtime-rpc@2.11.1': + resolution: {integrity: sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==} + + '@protobuf-ts/runtime@2.11.1': + resolution: {integrity: sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + + '@reown/appkit-common@1.8.11': + resolution: {integrity: sha512-rRcxrah6uouqEo/VbniVH11Y3H27BsP+Psv2+Usic+3Rt4kiSImIyeDG1YBV0gZNmME9N3sXHK8Bt7iqkxdOWw==} + + '@reown/appkit-controllers@1.8.11': + resolution: {integrity: sha512-V3hPB6NE7kM+7pS8n4ygZWbMh/XoHYxdPWxH3qtDlvYlH9Rgc3yvU8+IFWdB79Ta0lyJIbGqVlQeH5sQe4QOsw==} + + '@reown/appkit-pay@1.8.11': + resolution: {integrity: sha512-68IB3sKfxlCwLz44jvWWpULnmyIGHwnItojrr/PRXUof3z9t/nV8G7FiRY4ZDIo75EkabcIguhtYNSQ7R3vZbA==} + + '@reown/appkit-polyfills@1.8.11': + resolution: {integrity: sha512-pP9k5dvtWil88Zv3UgGurtbUmTx47z/5eriClGf8JI0VjBu/IExbAHg2gIZNEFdvkFD5/fIqIg8zno46SKbCKQ==} + + '@reown/appkit-scaffold-ui@1.8.11': + resolution: {integrity: sha512-oCEhNdUh2d59UHp/rLwfzv5odWg0pw000fg4Z53orjnKzcZfBpBDM00I9hu2pijnaYitJVqwsqCQ1F1q6hju/Q==} + + '@reown/appkit-ui@1.8.11': + resolution: {integrity: sha512-kBWZCiGaB/M2exIiDglsaTWYsWR0L89WXi7IFA6RgW0B0piYv5eiS3l/KPNj9/zxK8UnKsGsMefxl/UK/QqMng==} + + '@reown/appkit-utils@1.8.11': + resolution: {integrity: sha512-6Wplz7LNe2HoxHmGGYT6FIp8saa0DzVP/427jlNuWpkL65/azPyYjA8tKptxbFWViQ4VYBsqLoQxivXC/xNMBg==} + peerDependencies: + valtio: 2.1.7 + + '@reown/appkit-wallet@1.8.11': + resolution: {integrity: sha512-tCzrieMuOD4tDcNQjMe83T38tJUfRdv4LG+cYGyGK1RpPGaszbq06TQVbCPkRrGiTELwkrKwXjSg1XAuHktS2w==} + + '@reown/appkit@1.8.11': + resolution: {integrity: sha512-G96zt1P3ASrivV7HRrFQuzkCEzSmy3ca7cSQxaLeIS+P2VVhjE5YAyINArGVbooY0heHCPvQuTNM+YgK4oBmfg==} + '@rolldown/binding-android-arm-eabi@1.2.13': resolution: {integrity: sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -802,6 +1622,128 @@ packages: '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} + + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} + + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} + + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + + '@simplewebauthn/browser@13.1.0': + resolution: {integrity: sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==} + + '@simplewebauthn/types@12.0.0': + resolution: {integrity: sha512-q6y8MkoV8V8jB4zzp18Uyj2I7oFp2/ONL8c3j8uT06AOWu3cIChc1au71QYHrP2b+xDapkGTiv+9lX7xkTlAsA==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@solana/buffer-layout-utils@0.2.0': + resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} + engines: {node: '>= 10'} + + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + + '@solana/codecs-core@2.0.0-rc.1': + resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-core@2.3.0': + resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-data-structures@2.0.0-rc.1': + resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-numbers@2.0.0-rc.1': + resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} + peerDependencies: + typescript: '>=5' + + '@solana/codecs-numbers@2.3.0': + resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-strings@2.0.0-rc.1': + resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5' + + '@solana/codecs@2.0.0-rc.1': + resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==} + peerDependencies: + typescript: '>=5' + + '@solana/errors@2.0.0-rc.1': + resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} + hasBin: true + peerDependencies: + typescript: '>=5' + + '@solana/errors@2.3.0': + resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/options@2.0.0-rc.1': + resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==} + peerDependencies: + typescript: '>=5' + + '@solana/spl-token-group@0.0.7': + resolution: {integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + + '@solana/spl-token-metadata@0.1.6': + resolution: {integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.3 + + '@solana/spl-token@0.4.14': + resolution: {integrity: sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.95.5 + + '@solana/wallet-standard-chains@1.1.2': + resolution: {integrity: sha512-EZobEGclDBAFplpJC5F3d/s8Xnlqc5isNKuPrd5o9ZPZ7tWN84O0e68yIZ8MAOj9V7ieRadNiHtql7uIXCTyXg==} + engines: {node: '>=22'} + + '@solana/wallet-standard-features@1.5.0': + resolution: {integrity: sha512-gxlLaEfPAqbhd3LNkK0Ks2pbVvDm1SDGqBK/ynDQy13Gu+qiURLpRCfSPjbtrw5bmqQsZ6rS2YJHL31bY/Koag==} + engines: {node: '>=22'} + + '@solana/web3.js@1.98.1': + resolution: {integrity: sha512-gRAq1YPbfSDAbmho4kY7P/8iLIjMWXAzBJdP9iENFR+dFQSBSueHzjK/ou8fxhqHP9j+J4Msl4p/oDemFcIjlg==} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -838,33 +1780,121 @@ packages: '@swc/helpers@0.5.23': resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@thumbmarkjs/thumbmarkjs@0.16.0': + resolution: {integrity: sha512-NKyqCvP6DZKlRf6aGfnKS6Kntn2gnuBxa/ztstjy+oo1t23EHzQ54shtli0yV5WAtygmK1tti/uL2C2p/kW3HQ==} + deprecated: Please upgrade to v1 + + '@turnkey/api-key-stamper@0.4.7': + resolution: {integrity: sha512-/0/kW7v+uCnmHnGMoHSXn4Vb/MxLAIivGxX/T0L4vVoIiJalQmqcCtgiWnPWZDiJNGjMKp+jd/8j6VXgbVVozg==} + engines: {node: '>=18.0.0'} + + '@turnkey/crypto@2.5.0': + resolution: {integrity: sha512-aeYPO9rPFlM6eG+hjDiE6BKi9O6xcSDSIoq3mlw6KaaDgg6T2wFVapquIhAvwdTn+SMemDhcw2XaK5jsrQvsdQ==} + engines: {node: '>=18.0.0'} + + '@turnkey/encoding@0.5.0': + resolution: {integrity: sha512-nRlKRQa6B5/xltGUKN1iKo4h4YC/0iFz0fAuFFZevc+YGDj7ddAP/3HkWmVvLmdoicUgs9rxvWbLRlgqPkbwzQ==} + engines: {node: '>=18.0.0'} + + '@turnkey/http@3.10.0': + resolution: {integrity: sha512-PSOZV6HzpH39Wt0tILMOUgdq3wZw1jmBcbEWHDJDelCYPCLO1X7XAGGmxZliQ5y8IKzlp3DCI/qkkxswmDlDlg==} + engines: {node: '>=18.0.0'} + + '@turnkey/iframe-stamper@2.5.0': + resolution: {integrity: sha512-XjntbA5CNjxGRH+loceAlVLL9PG9Q4Y7p5zjBm4DeKclhD6lpUl9h8INArMEXIFbfLwLjjS6Q+SmQG4BHvNY6A==} + engines: {node: '>=18.0.0'} + + '@turnkey/indexed-db-stamper@1.1.1': + resolution: {integrity: sha512-pKEMTCTg6Kn76nvYu3vq3HfsdkZ7BmO5MSrXqk7K2TJ4griL/oEzIhlSNAnihpohIRTmIkSCxOAgyIe43oB+Cg==} + engines: {node: '>=18.0.0'} + + '@turnkey/sdk-browser@5.8.0': + resolution: {integrity: sha512-FnpOur2fzsnGSxiAFl8fvCqoSsD7EvOV+fPvxFofxICYrb/S1K3DcTRz7BxGvi4tPWFbYHZVqquYKzGs+SHeFw==} + engines: {node: '>=18.0.0'} + + '@turnkey/sdk-server@4.7.0': + resolution: {integrity: sha512-xgDV5aTtBNPu/0eEx6d5CoW8klgvajXBdkROphFnMcZlVq8YutVJP7tgECpuvJTYe0Cc6zvKHNoNQCJZ082bYw==} + engines: {node: '>=18.0.0'} + + '@turnkey/sdk-types@0.3.0': + resolution: {integrity: sha512-w9WLK8rMBLMIQNtaEriW2mQRuRxWu5GCOZatReaB5FRrtUFJroXjB3V8C+wUER02w3znyZzklQGPL1P32n6iuA==} + engines: {node: '>=18.0.0'} + + '@turnkey/solana@1.0.42': + resolution: {integrity: sha512-+SxerY0mAfdoak61biZxr7D+izqnYLrhfCfXxHcHG1lp+cG1u22eyx4zcrjLbzwmUBQ30Iu32kLMTVu+/b5AzA==} + engines: {node: '>=18.0.0'} + + '@turnkey/viem@0.13.0': + resolution: {integrity: sha512-l0PngrJlCgRvnuahYxPOhTB0SfiIAMHpX8fZOC3f7hEa1g1p4sN2RUAAm5rHI0KCXuLf5j4YWRUI6p6q2QC8tw==} + engines: {node: '>=18.0.0'} + peerDependencies: + viem: ^1.16.6 || ^2.24.2 + + '@turnkey/wallet-stamper@1.0.8': + resolution: {integrity: sha512-MgXYt5/ROvnkwC/hZyMMqPcOmENuYDq+Efyf0ipCX09Q3NfM6TLJvR3AgJuVN6WrDO8GNcpQQTBdy8kbAXMlLQ==} + + '@turnkey/webauthn-stamper@0.5.1': + resolution: {integrity: sha512-eBwceTStSSettBQsLo3X5eJEarcK9f20cGUdi6jOesXOP86iYEIgR4+aH2qyCQ3eaovj+Hl44UGngXueIm/tKg==} + engines: {node: '>=18.0.0'} + '@tybys/wasm-util@0.10.4': resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/lodash@4.17.27': + resolution: {integrity: sha512-VenMRv/eKNrspX9v3H4dbmjsrnCOYdYBG3kxXKk3dG6X+urBGcj2Prww3xw1U5K4FV/mE4h5GbWd0szEKf+9ew==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@types/node@18.19.130': resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} '@types/node@24.19.0': resolution: {integrity: sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/pg@8.23.1': resolution: {integrity: sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==} @@ -876,6 +1906,21 @@ packages: '@types/react@19.3.0': resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + + '@types/ws@8.18.2': + resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} + '@typescript-eslint/eslint-plugin@8.71.1': resolution: {integrity: sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1088,93 +2133,316 @@ packages: '@vitest/utils@4.1.12': resolution: {integrity: sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==} - '@workflow/serde@4.1.0': - resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + '@vue/reactivity@3.5.44': + resolution: {integrity: sha512-u+QJdKeBBEADkPdevsL+6E12QlYVfBD8Zcw5qjDQKtamI6l14KyqazJMobhCKelhWN5zpyKUiEDoTyHE93cqWw==} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} + '@vue/shared@3.5.44': + resolution: {integrity: sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg==} - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@wallet-standard/app@1.0.1': + resolution: {integrity: sha512-LnLYq2Vy2guTZ8GQKKSXQK3+FRGPil75XEdkZqE6fiLixJhZJoJa5hT7lXxwe0ykVTt9LEThdTbOpT7KadS26Q==} + engines: {node: '>=16'} - acorn@8.19.0: - resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} - engines: {node: '>=0.4.0'} - hasBin: true + '@wallet-standard/app@1.1.1': + resolution: {integrity: sha512-WDGwoByhP5gwHH01r5EaLgQdLVkACPCdOMQhmhn8rsm10h/siSgTorShzBxrn0ExSPof+Lu+C3TfgqBrPa1xoQ==} + engines: {node: '>=22'} - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} + '@wallet-standard/base@1.0.1': + resolution: {integrity: sha512-1To3ekMfzhYxe0Yhkpri+Fedq0SYcfrOfJi3vbLjMwF2qiKPjTGLwZkf2C9ftdQmxES+hmxhBzTwF4KgcOwf8w==} + engines: {node: '>=16'} - ai@7.0.137: - resolution: {integrity: sha512-JxrPkSQknxIN/gYqS3UQksExS6eWI23QMPBrKMGXeeFHhru6xFtF4MuMq17WaHD+lXPh0lne6H0BM2Z2VMW9EQ==} + '@wallet-standard/base@1.1.1': + resolution: {integrity: sha512-gggIHTtxicF9XFMQ12DkfS6NAG92Ak795JeSA7f2whAQ6Y3AkMWWuCMxSZXG2NIPN42kEaZSNVjqMsJRaJRxMQ==} engines: {node: '>=22'} - peerDependencies: - zod: 4.6.7 - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + '@wallet-standard/core@1.1.1': + resolution: {integrity: sha512-5Xmjc6+Oe0hcPfVc5n8F77NVLwx1JVAoCVgQpLyv/43/bhtIif+Gx3WUrDlaSDoM8i2kA2xd6YoFbHCxs+e0zA==} + engines: {node: '>=16'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + '@wallet-standard/errors@0.1.2': + resolution: {integrity: sha512-oEzKUqJefKby6wcIvaJgrSEe/uNn/rnqkJ0P/85K+h0i5Tdo9E3L22VWq/j5K1e8hHMnZd6LgaIr8m/Wn7X/Ng==} + engines: {node: '>=22'} + hasBin: true - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + '@wallet-standard/experimental-features@0.1.1': + resolution: {integrity: sha512-WKtnET1okeDACTbxmePGOGaIUrGvlu/DestLZvZ/ddFpUKw7nokkbinX/gHzsuAC9WGtLyhqLSppAHzN+vAAaQ==} + engines: {node: '>=16'} - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} + '@wallet-standard/features@1.0.3': + resolution: {integrity: sha512-m8475I6W5LTatTZuUz5JJNK42wFRgkJTB0I9tkruMwfqBF2UN2eomkYNVf9RbrsROelCRzSFmugqjKZBFaubsA==} + engines: {node: '>=16'} - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + '@wallet-standard/features@1.1.1': + resolution: {integrity: sha512-aCWYmVeSCGViyEU5k7GMoW8zxE4Gs+C1s1Pp2XLesvSNlnZ4PMES9HUnTB3hl0b3RVj7C61yze3IWyrncqg4MA==} + engines: {node: '>=22'} - array-includes@3.2.0: - resolution: {integrity: sha512-VXY5eFRarnXcYxwBjJzPmEhH55+rmP79/+ueDhi0F+TuqfHCItagIHqxeUZrmgrOPa31QTh9H85DjX3FfJ0FTg==} - engines: {node: '>= 0.4'} + '@wallet-standard/wallet@1.1.0': + resolution: {integrity: sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==} + engines: {node: '>=16'} - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} + '@wallet-standard/wallet@1.1.1': + resolution: {integrity: sha512-8WiRPaKk/wNNRZhB2eVhpR/JW7/aqTCMoZhgVUCujuzDmxxmGvsosMxdCG4NAdYkoyozAHCX8/xLtlWUn5mNdQ==} + engines: {node: '>=22'} - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} + '@walletconnect/core@2.21.5': + resolution: {integrity: sha512-CxGbio1TdCkou/TYn8X6Ih1mUX3UtFTk+t618/cIrT3VX5IjQW09n9I/pVafr7bQbBtm9/ATr7ugUEMrLu5snA==} + engines: {node: '>=18'} - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + '@walletconnect/core@2.22.4': + resolution: {integrity: sha512-ZQnyDDpqDPAk5lyLV19BRccQ3wwK3LmAwibuIv3X+44aT/dOs2kQGu9pla3iW2LgZ5qRMYvgvvfr5g3WlDGceQ==} + engines: {node: '>=18.20.8'} - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} + '@walletconnect/core@2.23.2': + resolution: {integrity: sha512-KkaTELRu8t/mt3J9doCQ1fBGCbYsCNfpo2JpKdCwKQR7PVjVKeVpYQK/blVkA5m6uLPpBtVRbOMKjnHW1m7JLw==} + engines: {node: '>=18.20.8'} - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + '@walletconnect/environment@1.0.1': + resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} + '@walletconnect/ethereum-provider@2.23.2': + resolution: {integrity: sha512-/JQTTs3bPNatEjWr82p4EAstFAntL85grNhSmpdJxxpEvFcWHMqtrK+ozIy4jBiDZpuVasvL5yjcl5oPQC3r8Q==} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} + '@walletconnect/events@1.0.1': + resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} - ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + '@walletconnect/heartbeat@1.2.2': + resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + '@walletconnect/jsonrpc-http-connection@1.0.8': + resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} + + '@walletconnect/jsonrpc-provider@1.0.14': + resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} + + '@walletconnect/jsonrpc-types@1.0.4': + resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} + + '@walletconnect/jsonrpc-utils@1.0.8': + resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} + + '@walletconnect/jsonrpc-ws-connection@1.0.16': + resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==} + + '@walletconnect/keyvaluestorage@1.1.1': + resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + peerDependencies: + '@react-native-async-storage/async-storage': 1.x + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@walletconnect/logger@2.1.2': + resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + + '@walletconnect/logger@3.0.0': + resolution: {integrity: sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==} + + '@walletconnect/logger@3.0.2': + resolution: {integrity: sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==} + + '@walletconnect/relay-api@1.0.11': + resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} + + '@walletconnect/relay-auth@1.1.0': + resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} + + '@walletconnect/safe-json@1.0.2': + resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} + + '@walletconnect/sign-client@2.21.5': + resolution: {integrity: sha512-IAs/IqmE1HVL9EsvqkNRU4NeAYe//h9NwqKi7ToKYZv4jhcC3BBemUD1r8iQJSTHMhO41EKn1G9/DiBln3ZiwQ==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/sign-client@2.22.4': + resolution: {integrity: sha512-la+sol0KL33Fyx5DRlupHREIv8wA6W33bRfuLAfLm8pINRTT06j9rz0IHIqJihiALebFxVZNYzJnF65PhV0q3g==} + + '@walletconnect/sign-client@2.23.2': + resolution: {integrity: sha512-LL5KgmJHvY5NqQn+ZHQJLia1p6fpUWXHtiG97S5rNfyuPx6gT/Jkkwqc2LwdmAjFkr61t8zTagHC9ETq203mNA==} + + '@walletconnect/time@1.0.2': + resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + + '@walletconnect/types@2.21.5': + resolution: {integrity: sha512-kpTXbenKeMdaz6mgMN/jKaHHbu6mdY3kyyrddzE/mthOd2KLACVrZr7hrTf+Fg2coPVen5d1KKyQjyECEdzOCw==} + + '@walletconnect/types@2.22.4': + resolution: {integrity: sha512-KJdiS9ezXzx1uASanldYaaenDwb42VOQ6Rj86H7FRwfYddhNnYnyEaDjDKOdToGRGcpt5Uzom6qYUOnrWEbp5g==} + + '@walletconnect/types@2.23.2': + resolution: {integrity: sha512-5dxBCdUM+4Dqe1/A7uqkm2tWPXce4UUGSr+ImfI0YjwEExQS8+TzdOlhMt3n32ncnBCllU5paG+fsndT06R0iw==} + + '@walletconnect/universal-provider@2.22.4': + resolution: {integrity: sha512-TF2RNX13qxa0rrBAhVDs5+C2G8CHX7L0PH5hF2uyQHdGyxZ3pFbXf8rxmeW1yKlB76FSbW80XXNrUes6eK/xHg==} + + '@walletconnect/universal-provider@2.23.2': + resolution: {integrity: sha512-vs9iorPUAiVesFJ95O6XvLjmRgF+B2TspxJNL90ZULbrkRw4JFsmaRdb965PZKc+s182k1MkS/MQ0o964xRcEw==} + + '@walletconnect/utils@2.21.5': + resolution: {integrity: sha512-RSPSxPvGMuvfGhd5au1cf9cmHB/KVVLFotJR9ltisjFABGtH2215U5oaVp+a7W18QX37aemejRkvacqOELVySA==} + + '@walletconnect/utils@2.22.4': + resolution: {integrity: sha512-coAPrNiTiD+snpiXQyXakMVeYcddqVqII7aLU39TeILdPoXeNPc2MAja+MF7cKNM/PA3tespljvvxck/oTm4+Q==} + + '@walletconnect/utils@2.23.2': + resolution: {integrity: sha512-ReSjU3kX+3i3tYJQZbVfetY5SSUL+iM6uiIVVD1PJalePa/5A40VgLVRTF7sDCJTIFfpf3Mt4bFjeaYuoxWtIw==} + + '@walletconnect/window-getters@1.0.1': + resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + + '@walletconnect/window-metadata@1.0.1': + resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} + + '@workflow/serde@4.1.0': + resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} + + abitype@1.0.8: + resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: 4.6.7 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + abitype@1.3.0: + resolution: {integrity: sha512-fk6Te+bojIFrMvMZrnOO+SxCB+RUksTGOzq/60ZRvs1L+BVzvi2bqt9L3W/17ZLdZsyM1FuYf65P5nlmoiH1Bg==} + peerDependencies: + typescript: '>=5.0.4' + zod: 4.6.7 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + + ably@2.17.1: + resolution: {integrity: sha512-70yfXHoM7JtJD/8FCtPD1gkWW0f+AJqbJp0PsqDAqiyxFB8cPFY+FuKHgNTYb8eRHKXq8hT1xiDphUcY0+GHnA==} + engines: {node: '>=16'} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.19.0: + resolution: {integrity: sha512-oJlA3XiRm7Cyk6qFD2Jn8ak9B7jSy0qy00ADO3+8dpT0LSjFihQYv4C02LFCSYJV3Q37xYwwRy5m+IpIiUzqWw==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ai@7.0.137: + resolution: {integrity: sha512-JxrPkSQknxIN/gYqS3UQksExS6eWI23QMPBrKMGXeeFHhru6xFtF4MuMq17WaHD+lXPh0lne6H0BM2Z2VMW9EQ==} + engines: {node: '>=22'} + peerDependencies: + zod: 4.6.7 + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.2.0: + resolution: {integrity: sha512-VXY5eFRarnXcYxwBjJzPmEhH55+rmP79/+ueDhi0F+TuqfHCItagIHqxeUZrmgrOPa31QTh9H85DjX3FfJ0FTg==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1183,10 +2451,17 @@ packages: resolution: {integrity: sha512-9WTZxEjsZ7b13TH8JPmbV2z8CHbl80/2hm3XPEG4JgNdQLK81IBRXmSxHfMAOkSqQeRxT/0dwNDz2GOm3zzpcQ==} engines: {node: '>=4'} + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1194,11 +2469,59 @@ packages: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + base-x@3.0.11: + resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} + + base-x@4.0.1: + resolution: {integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==} + + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + + base32.js@0.1.0: + resolution: {integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==} + engines: {node: '>=0.12.0'} + + base64-js@1.0.2: + resolution: {integrity: sha512-ZXBDPMt/v/8fsIqn+Z5VwrhdR6jVka0bYobHdGia0Nxi7BJ9i/Uvml3AocHIBtIIBhZjBw5MR0aR4ROs/8+SNg==} + engines: {node: '>= 0.4'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.11.27: resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==} engines: {node: '>=6.0.0'} hasBin: true + big.js@6.2.2: + resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} + + bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@5.2.5: + resolution: {integrity: sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==} + + bops@1.0.1: + resolution: {integrity: sha512-qCMBuZKP36tELrrgXpAfM+gHzqa0nLsWZ+L37ncsb8txYlnAoxOPpVp+g7fK0sGkMXfA0wl8uQkESqw3v4HNag==} + + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + + bowser@2.15.0: + resolution: {integrity: sha512-xic6KSZglg/I4ymp45fdM4GWfYpBK79Fxd/TOvJktlaPgQqqDxvmGwOPZl2V0dyeS3Lj5c180bLhXF43iyAjZQ==} + brace-expansion@1.1.21: resolution: {integrity: sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==} @@ -1215,6 +2538,33 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + + bs58check@4.0.0: + resolution: {integrity: sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bufferutil@4.1.0: + resolution: {integrity: sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==} + engines: {node: '>=6.14.2'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1231,9 +2581,16 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + caniuse-lite@1.0.30001815: resolution: {integrity: sha512-uDybUEyfgbyJJ93J1vikTylBX31AkdVYeVPeffMQpf8XN7hSfr0oZOn4VFOIMNvtU5+rHvC5Udg2TgtJKHm23Q==} + centrifuge@5.8.0: + resolution: {integrity: sha512-ENH1jz6VeRuGb3yHNhgB0V0SqRKX+iYdtM9Du/E59m484epjNPfsgJw4UbmOmjgSXGEita1UoOXlZ6Ba1ooT1g==} + chai@6.3.0: resolution: {integrity: sha512-XWAtwJ6OHO+tj0EKCs0Y2UamnyOxseZWltU4x2U2wh8g4AigdjwvtUjvLP2tqkA/avxHEtzxNaqGq/YGNwckKg==} engines: {node: '>=18'} @@ -1242,9 +2599,31 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1252,10 +2631,32 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1263,13 +2664,40 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-es@1.2.3: + resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + country-list@2.3.0: + resolution: {integrity: sha512-qZk66RlmQm7fQjMYWku1AyjlKPogjPEorAZJG88owPExoPV8EsyCcuFLvO2afTXHEhi9liVOoyd+5A6ZS5QwaA==} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + cross-fetch@3.2.0: + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} + + cross-fetch@4.1.0: + resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + crossws@0.4.15: resolution: {integrity: sha512-NsUOpDZosz7nyI+qEIl05yaiXOWaXH2oTeM+XBWtiSWZtb5rzcIsl1AST/HzM2jzUn76eFuyrkn83E6iSBRUvw==} peerDependencies: @@ -1296,6 +2724,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + db0@0.4.1: resolution: {integrity: sha512-6RBY/bSn42UrqATwsiULj2uYFyEykB3XeA/NLIVQeHNXlYV6D4Idxx3/aa6k5Y45Dwzx7sygeLotnqHWSeURYA==} @@ -1316,9 +2747,29 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@2.2.1: + resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==} + engines: {node: '>=0.10.0'} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -1327,32 +2778,77 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + + eciesjs@0.4.17: + resolution: {integrity: sha512-TOOURki4G7sD1wDCjj7NfLaXZZ49dFOeEb5y39IXpb8p0hRzVvfvzZHOi5JcT+PpyAbi/Y+lxPb8eTag2WYH8w==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} + electron-to-chromium@1.5.451: resolution: {integrity: sha512-vUNKPrUzw8ByEMOxloq0a71iD/mPuPxVkbDm3G5YhnxTzOw/I6qAg2MUS0cYj/c267lWmw26yW4Vv7foxTxPLg==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + env-runner@0.2.3: resolution: {integrity: sha512-S8EFBKyznRwPVwayK187cYjvnpgC92xy+q0BIF++V965pfjMVVRbQ/HoTYGA/1EHmZ7E68k6Heq+4WnvVhOL5w==} hasBin: true + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-abstract-get@1.0.0: resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} engines: {node: '>= 0.4'} @@ -1392,6 +2888,15 @@ packages: resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} + es-toolkit@1.39.3: + resolution: {integrity: sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==} + + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + esbuild@0.28.2: resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} @@ -1529,6 +3034,9 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + eve@0.79.1: resolution: {integrity: sha512-7hbpSi6mCqsrq3W7C9Y8Z2vTny01hunaNilEFj2qy/DkotztaW+KD4BNwut3oz2iSQ8yryyl46XhOspQ6PmZOg==} engines: {node: '>=24'} @@ -1559,6 +3067,13 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + eventsource-parser@3.1.1: resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} @@ -1567,9 +3082,16 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} + exponential-backoff@3.1.1: + resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + exsolve@1.1.3: resolution: {integrity: sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==} + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1583,6 +3105,19 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + fastq@1.20.3: resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} @@ -1599,10 +3134,24 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1614,7 +3163,20 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} - for-each@0.3.5: + focus-lock@1.3.6: + resolution: {integrity: sha512-Ik/6OCk9RQQ0T5Xw+hKNLWrjSMtv51dD4GRmJjbD5a58TIEpI5a5iXagKVl3Z5UuyslMCA8Xwnu76jQob62Yhg==} + engines: {node: '>=10'} + + follow-redirects@1.16.2: + resolution: {integrity: sha512-/kVP2U8z596Ia0gwFrwyIeo74ta5aVmSeU1FfAUMAmcEP5EP7zydmag3SLiN64NaRKef3lxsq7i/g7ltJQDGow==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -1629,6 +3191,14 @@ packages: resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} engines: {node: '>= 12.20'} + formik@2.2.9: + resolution: {integrity: sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==} + peerDependencies: + react: '>=16.8.0' + + fp-ts@2.16.11: + resolution: {integrity: sha512-LaI+KaX2NFkfn1ZGHoKCmcfv7yrZsC3b8NtWsTVQeHkq4F27vI5igUuO53sxqDEa2gNQMHFPmpojDw/1zmUK7w==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1652,6 +3222,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1660,6 +3234,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -1691,6 +3269,23 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + gql.tada@1.11.4: + resolution: {integrity: sha512-UQnhJUhSM0MV8cpcgjci/7ET8LnmHx9o9FtZqU4sH+ILiBVG5rnfXJzNdzTN+Y7MuCz6Pp3XE/VPEVqmO969jw==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + graphql@16.14.2: + resolution: {integrity: sha512-Chq1s4CY7jmh8gO2qvLIJyfCDIN+EHLFW/9iShnp1z8FjBQMoodWP1kDC36VAMXXIvAjj4ARa7ntfAV2BrjsbA==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + h3@1.15.11: + resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} + h3@2.0.2: resolution: {integrity: sha512-+/zvHSNldYpNURuUUG+y1KzdASUhNnSd1VpqxYFVY40ov3YzuBnCETaUQaT+QbKkoxhh9LRa6AEQdB14LALwdA==} engines: {node: '>=20.19.0'} @@ -1737,15 +3332,48 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hookable@6.1.2: resolution: {integrity: sha512-+abwxtiEA52GCVIsQqut3S/uKTbUwYIp4Pe/vv+6py5XiXBCqMZHg6pA6Y5qhgLSEys0/cYuPbO0z1QFj5ZCmg==} + hpke-js@1.8.0: + resolution: {integrity: sha512-N0PFQlUQsIPS9++nUNn2ZsxTPSv8pONyyrXIGZl0iiherRfS0XW1SvTd+RmepD0TN1S9zzTJkEutMIWWYt0/4w==} + engines: {node: '>=16.0.0'} + + html-parse-stringify@3.1.0: + resolution: {integrity: sha512-E0oAXcELOtsXe+BmpJ2EZyedbldPpriV5vICzEuo6xjC/D1lDukOI7KrpfQGF2Qc4wWEy0nk3bFORS2K5ZAhFQ==} + + http-cache-semantics@4.3.0: + resolution: {integrity: sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + httpxy@0.5.5: resolution: {integrity: sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==} humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + i18next@23.4.6: + resolution: {integrity: sha512-jBE8bui969Ygv7TVYp0pwDZB7+he0qsU+nz7EcfdqSh+QvKjEfl9YPRQd/KrGiMhTYFGkeuPaeITenKK/bSFDg==} + + idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + + idb-keyval@6.3.0: + resolution: {integrity: sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1762,14 +3390,41 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + input-otp@1.4.2: + resolution: {integrity: sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + io-ts@2.2.22: + resolution: {integrity: sha512-FHCCztTkHoV9mdBsHpocLpdTAfh956ZQcIkWQxxS0U5HT53vtrcuYdQneEJKH6xILaLNzXVl2Cvwtoy8XNN0AA==} + peerDependencies: + fp-ts: ^2.5.0 + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -1813,6 +3468,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-generator-function@1.1.2: resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} @@ -1879,10 +3538,25 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' + iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} + jayson@4.3.0: + resolution: {integrity: sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ==} + engines: {node: '>=8'} + hasBin: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1898,6 +3572,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1907,6 +3584,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -1920,9 +3600,16 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyvaluestorage-interface@1.0.0: + resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -2008,17 +3695,57 @@ packages: resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lit-element@4.2.2: + resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} + + lit-html@3.3.3: + resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==} + + lit@3.3.0: + resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -2033,6 +3760,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -2050,6 +3780,14 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -2063,6 +3801,12 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + + nanoclone@0.2.1: + resolution: {integrity: sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==} + nanoid@3.3.20: resolution: {integrity: sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -2114,6 +3858,9 @@ packages: resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} engines: {node: '>= 0.4'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2123,10 +3870,25 @@ packages: encoding: optional: true + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + node-mock-http@1.0.5: + resolution: {integrity: sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==} + node-releases@2.0.57: resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==} engines: {node: '>=18'} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2166,6 +3928,25 @@ packages: ocache@0.3.0: resolution: {integrity: sha512-RS/9P0zeBb0gDJmadGERLH8lZNXK7xbufTDhclkXGvFGTsj0G4M5/cLk+mizcERH29mLXNnocfB5wjcK70wGJg==} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + on-exit-leak-free@0.2.0: + resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + openapi-fetch@0.13.8: + resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2174,18 +3955,81 @@ packages: resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} + ox@0.12.4: + resolution: {integrity: sha512-+P+C7QzuwPV8lu79dOwjBKfB2CbnbEXe/hfyyrff1drrO1nOOj3Hc87svHfcW1yneRr3WXaKr6nz11nq+/DF9Q==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.14.56: + resolution: {integrity: sha512-Feinlj+deWEam6RIwurRE+eHZ2N3hoUb3AAjQ10BmxRCYIymfqNkv0eZ+4ln4GkgDmSGLD2rGtTMqsFYSVDC6w==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.6.9: + resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.7.1: + resolution: {integrity: sha512-+k9fY9PRNuAMHRFIUbiK9Nt5seYHHzSQs9Bj+iMETcGtlpS7SmBzcGSVUQO3+nqGLEiNK4598pHNFlVRaZbRsg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + ox@0.9.3: + resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + pako@2.2.0: + resolution: {integrity: sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2197,6 +4041,10 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2245,11 +4093,42 @@ packages: resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-std-serializers@4.0.0: + resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} + hasBin: true + + pino@7.11.0: + resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + hasBin: true + playwright-core@1.62.1: resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} engines: {node: '>=20'} hasBin: true + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + pony-cause@2.1.11: + resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} + engines: {node: '>=12.0.0'} + + poseidon-lite@0.2.1: + resolution: {integrity: sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -2278,32 +4157,162 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + preact@10.24.2: + resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} + + preact@10.29.8: + resolution: {integrity: sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==} + peerDependencies: + preact-render-to-string: '>=5' + peerDependenciesMeta: + preact-render-to-string: + optional: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + + process-warning@5.1.1: + resolution: {integrity: sha512-oCkNVj4OKnKEcocVBcDfiIugN1/cE6rgfT3nCtzeqZPA8+rIxMaQ0xXzIkGP8Gj2qUaP1UR7uhJ1VD8lUCpzCg==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + + protobufjs@7.6.6: + resolution: {integrity: sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==} + engines: {node: '>=12.0.0'} + + proxy-compare@3.0.1: + resolution: {integrity: sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + punycode@1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qr-code-styling@1.9.2: + resolution: {integrity: sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==} + engines: {node: '>=18.18.0'} + + qrcode-generator@1.5.2: + resolution: {integrity: sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==} + + qrcode@1.5.1: + resolution: {integrity: sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==} + engines: {node: '>=10.13.0'} + hasBin: true + + qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + querystring@0.2.0: + resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + react-clientside-effect@1.2.8: + resolution: {integrity: sha512-ma2FePH0z3px2+WOu6h+YycZcEvFmmxIlAb62cF52bG86eMySciO/EQZeQMXd07kPCYB0a1dWDT5J+KE9mCDUw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom@19.3.0: resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} peerDependencies: react: ^19.3.0 + react-fast-compare@2.0.4: + resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==} + + react-focus-lock@2.13.6: + resolution: {integrity: sha512-ehylFFWyYtBKXjAO9+3v8d0i+cnc1trGS0vlTGhzFW1vbFXVUTmR8s2tt/ZQG8x5hElg6rhENlLG1H3EZK0Llg==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-i18next@13.5.0: + resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==} + peerDependencies: + i18next: '>= 23.2.3' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + + react-international-phone@4.5.0: + resolution: {integrity: sha512-wjwHv+VfiwM49B5/6El4Z5vZKmf3ILpUeiOCI9X+b0Dq4g5nL8gROcwCdVcTXywxznbDSoxSassBX3i9tPZX6g==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.3.0: resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==} engines: {node: '>=0.10.0'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + real-require@0.1.0: + resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + engines: {node: '>= 12.13.0'} + + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -2312,6 +4321,16 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2319,11 +4338,19 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.13: + resolution: {integrity: sha512-Dj/cW9zBV2aRj6XzCxuGIs3ESZKv02jixne3q6jFZYZ3/Tg09gHHviSMDL4kObh9pqSahdRHEnDoaP2gn8YLhA==} + engines: {node: '>= 0.4'} + hasBin: true + resolve@2.0.0-next.7: resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} engines: {node: '>= 0.4'} hasBin: true + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -2340,6 +4367,9 @@ packages: resolution: {integrity: sha512-ySeaQkSrua+ut9g+65I7FHqOFBaY8tV0FmccXItoq0q21se32Q3u4YiW7/RqXSosWgYJaaKwRHXy3BST9PeCNQ==} engines: {node: '>=20.19.0'} + rpc-websockets@9.3.9: + resolution: {integrity: sha512-2iQDaTB4g5fDB2ihrTFSJSibCEuxaRi1q7qTW7ZO9/M5/TC+ToHA4D9/ffNLEbAoHNNrcdeP05oATNk44SKZXA==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2347,6 +4377,9 @@ packages: resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -2355,6 +4388,10 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + scheduler@0.28.0: resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} @@ -2362,11 +4399,19 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2379,6 +4424,13 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} + sha256-uint8array@0.10.7: + resolution: {integrity: sha512-1Q6JQU4tX9NqsDGodej6pkrUVQVNapLZnvkwIhddH/JqzBZF1fSaxSWNY6sziXBE8aEa2twtGkXUrwzGeZCMpQ==} + + sharp@0.35.0: + resolution: {integrity: sha512-BqvG5XbwPZ4NV0DK90d86leEECMsoa8bO0nqnKWlBDYxri4GJ7c4EDInaF6q20lTh/mATmnDIKWJFfXnoVfH5g==} + engines: {node: '>=20.9.0'} + sharp@0.35.5: resolution: {integrity: sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==} engines: {node: '>=20.9.0'} @@ -2415,10 +4467,30 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} + + sonic-boom@2.8.0: + resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + source-map-js@1.2.2: resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} engines: {node: '>=0.10.0'} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -2441,6 +4513,23 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} + stream-chain@2.2.5: + resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} + + stream-json@1.9.1: + resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string.prototype.includes@2.0.1: resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} engines: {node: '>= 0.4'} @@ -2464,6 +4553,13 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -2485,6 +4581,13 @@ packages: babel-plugin-macros: optional: true + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2493,6 +4596,22 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + + text-encoding@0.7.0: + resolution: {integrity: sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==} + deprecated: no longer maintained + + thread-stream@0.15.2: + resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + + thread-stream@3.2.0: + resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -2508,10 +4627,23 @@ packages: resolution: {integrity: sha512-LgO3D9yZJjApUiuUfl9iFAwrtaX4+lok3wJIqttGoKCHlWUqHqbQpnxCf82L8FjgKsh4iGo78hqJwgL8F6To2A==} engines: {node: '>=14.0.0'} + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.0.16: + resolution: {integrity: sha512-TkEq38COU640mzOKPk4D1oH3FFVvwEtMaKIfw/+F/umVsy7ONWu8PPQH0c11qJ/Jq/zbcQGprXGsT8GcaDSmJg==} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + to-utf8@0.0.1: + resolution: {integrity: sha512-zks18/TWT1iHO3v0vFp5qLKOG27m67ycq/Y7a7cTiRuUNlc4gf3HGnkRgMv0NyhnfTamtkYBJl+YeD1/j07gBQ==} + + toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -2524,9 +4656,18 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2559,10 +4700,23 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + + ulid@2.4.0: + resolution: {integrity: sha512-fIRiVTJNcSRmXKPZtGzFQv9WRrZ3M9eoptl/teFJvjOzmpU+/K/JH6HZ8deBfb5vMEpicJcLn7JmvdknlMq7Zg==} + hasBin: true + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -2583,6 +4737,68 @@ packages: unrs-resolver@1.12.2: resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + unstorage@1.17.6: + resolution: {integrity: sha512-gjKtcmn/KwZuJZO9o2sc0esAQnhmTw0LviDHwevTXbJMYs0dRTp8ZEEWXHU0vTpzbN3cA0yxlTeyXssMp3zDqw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + unstorage@2.0.0-alpha.11: resolution: {integrity: sha512-4rDO/NjgnkbVvWAPpxugX7YI/xVpC74NLrmAbH6I0D4hcSVq/1m5q2pSfQjP/ABs+7EsRtP/ZjyYMD9bEBgeTw==} @@ -2595,6 +4811,105 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url@0.11.0: + resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + utf-8-validate@6.0.6: + resolution: {integrity: sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==} + engines: {node: '>=6.14.2'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + uuid@11.1.1: + resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} + hasBin: true + + uuid@14.0.3: + resolution: {integrity: sha512-Sc5u1VVln93y1Xnz4R+CunOZc7R9LUcTmhj7Rc7Eg3HVcf7rVn2FOoa812fe0W8p3jD7xeoGSYbfqCGGH2B6xw==} + hasBin: true + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + valibot@1.5.0: + resolution: {integrity: sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + + valtio@2.1.7: + resolution: {integrity: sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + react: '>=18.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + viem@2.31.0: + resolution: {integrity: sha512-U7OMQ6yqK+bRbEIarf2vqxL7unSEQvNxvML/1zG7suAmKuJmipqdVTVJGKBCJiYsm/EremyO2FS4dHIPpGv+eA==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + viem@2.46.3: + resolution: {integrity: sha512-2LJS+Hyh2sYjHXQtzfv1kU9pZx9dxFzvoU/ZKIcn0FNtOU0HQuIICuYdWtUDFHaGXbAdVo8J1eCvmjkL9JVGwg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + + viem@2.57.7: + resolution: {integrity: sha512-x3UqqrcQuESaRVK6a0BvNmoNP0SVhu913uxEAxYLJx1lNYnj6ylTntfUdakCUKjk1+T+63gkdwFGJQ2O5C/nRw==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + vite@8.3.3: resolution: {integrity: sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2679,6 +4994,10 @@ packages: jsdom: optional: true + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + web-streams-polyfill@4.0.0-beta.3: resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} engines: {node: '>= 14'} @@ -2701,6 +5020,9 @@ packages: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which-typed-array@1.1.24: resolution: {integrity: sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==} engines: {node: '>= 0.4'} @@ -2719,34 +5041,157 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.5.13: + resolution: {integrity: sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.2: + resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.22.0: + resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} + engines: {node: '>= 6'} + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yup@0.32.11: + resolution: {integrity: sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==} + engines: {node: '>=10'} + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} peerDependencies: zod: 4.6.7 + zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + zod@4.6.7: resolution: {integrity: sha512-g8W2D2kU6a8untc053fX1uVBKzM7yqAxW/3zwk83+6RyF2+SKOuV+c0wBDhUwzV1PaGapmZH+rmcUzPf+3CGwg==} + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: + '@0no-co/graphql.web@1.3.4(graphql@16.14.2)': + optionalDependencies: + graphql: 16.14.2 + + '@0no-co/graphqlsp@1.18.0(graphql@16.14.2)(typescript@6.0.3)': + dependencies: + '@gql.tada/internal': 1.2.2(graphql@16.14.2)(typescript@6.0.3) + graphql: 16.14.2 + typescript: 6.0.3 + '@1password/sdk-core@0.5.0': {} '@1password/sdk@0.5.0': dependencies: '@1password/sdk-core': 0.5.0 + '@ably/msgpack-js@0.4.1': + dependencies: + bops: 1.0.1 + + '@adraffy/ens-normalize@1.11.1': {} + '@ai-sdk/gateway@4.0.110(zod@4.6.7)': dependencies: '@ai-sdk/provider': 4.0.26 @@ -2863,6 +5308,8 @@ snapshots: dependencies: '@babel/types': 7.29.8 + '@babel/runtime@7.29.10': {} + '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 @@ -2886,6 +5333,28 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@base-org/account@1.1.1(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@6.0.3)(zod@3.22.4) + preact: 10.24.2 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + zustand: 5.0.3(@types/react@19.3.0)(react@19.3.0) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@basis-theory/web-agentic@1.2.2': {} + '@browserbasehq/sdk@2.18.0': dependencies: '@types/node': 18.19.130 @@ -2907,89 +5376,1189 @@ snapshots: transitivePeerDependencies: - encoding - '@emnapi/core@1.10.0': + '@coinbase/wallet-sdk@4.3.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true + '@noble/hashes': 1.8.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + preact: 10.29.8 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - bufferutil + - preact-render-to-string + - typescript + - utf-8-validate + - zod + + '@crossmint/client-sdk-auth@1.3.31': + dependencies: + '@crossmint/client-sdk-base': 4.6.1 + '@crossmint/common-sdk-auth': 1.1.29 + '@crossmint/common-sdk-base': 0.13.0 + jwt-decode: 4.0.0 + transitivePeerDependencies: + - '@datadog/browser-rum' - '@emnapi/runtime@1.10.0': + '@crossmint/client-sdk-base@4.6.1': dependencies: - tslib: 2.8.1 - optional: true + '@crossmint/client-sdk-window': 1.2.0 + '@crossmint/common-sdk-base': 0.13.0 + '@datadog/browser-logs': 6.24.1 + exponential-backoff: 3.1.1 + uuid: 11.1.1 + zod: 3.22.4 + transitivePeerDependencies: + - '@datadog/browser-rum' + + '@crossmint/client-sdk-react-base@2.4.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@crossmint/client-sdk-auth': 1.3.31 + '@crossmint/client-sdk-base': 4.6.1 + '@crossmint/client-sdk-window': 1.2.0 + '@crossmint/client-signers': 0.3.1 + '@crossmint/common-sdk-auth': 1.1.29 + '@crossmint/common-sdk-base': 0.13.0 + '@crossmint/wallets-sdk': 1.20.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + react: 19.3.0 + transitivePeerDependencies: + - '@datadog/browser-rum' + - '@solana/web3.js' + - bufferutil + - typescript + - utf-8-validate + - zod + + '@crossmint/client-sdk-react-ui@4.12.1(@dynamic-labs-wallet/primitives@1.1.33)(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@basis-theory/web-agentic': 1.2.2 + '@crossmint/client-sdk-base': 4.6.1 + '@crossmint/client-sdk-react-base': 2.4.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@crossmint/client-sdk-window': 1.2.0 + '@crossmint/client-signers': 0.3.1 + '@crossmint/common-sdk-auth': 1.1.29 + '@crossmint/common-sdk-base': 0.13.0 + '@crossmint/wallets-sdk': 1.20.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/ethereum': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@4.6.7) + '@dynamic-labs/sdk-react-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/solana': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4) + '@dynamic-labs/sui': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@emotion/react': 11.14.0(@types/react@19.3.0)(react@19.3.0) + '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.3.0)(react@19.3.0))(@types/react@19.3.0)(react@19.3.0) + '@mysten/sui': 1.45.2(typescript@6.0.3) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + bs58: 5.0.0 + clsx: 2.1.1 + color: 4.2.3 + input-otp: 1.4.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + lodash.isequal: 4.5.0 + ox: 0.6.9(typescript@6.0.3)(zod@3.22.4) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-transition-group: 4.4.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + zod: 3.22.4 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@datadog/browser-rum' + - '@deno/kv' + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - preact-render-to-string + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate - '@emnapi/runtime@1.11.3': + '@crossmint/client-sdk-window@1.2.0': dependencies: - tslib: 2.8.1 - optional: true + zod: 3.22.4 - '@emnapi/wasi-threads@1.2.1': + '@crossmint/client-signers-cryptography@0.0.5': dependencies: - tslib: 2.8.1 - optional: true + '@noble/ciphers': 1.3.0 + bs58: 6.0.0 + zod: 3.22.4 - '@esbuild/aix-ppc64@0.28.2': - optional: true + '@crossmint/client-signers@0.3.1': + dependencies: + zod: 3.22.4 - '@esbuild/android-arm64@0.28.2': - optional: true + '@crossmint/common-sdk-auth@1.1.29': + dependencies: + '@crossmint/client-sdk-base': 4.6.1 + '@crossmint/common-sdk-base': 0.13.0 + transitivePeerDependencies: + - '@datadog/browser-rum' + + '@crossmint/common-sdk-base@0.13.0': + dependencies: + '@noble/hashes': 1.8.0 + bs58: 5.0.0 + + '@crossmint/wallets-sdk@1.20.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@crossmint/client-sdk-window': 1.2.0 + '@crossmint/client-signers': 0.3.1 + '@crossmint/client-signers-cryptography': 0.0.5 + '@crossmint/common-sdk-auth': 1.1.29 + '@crossmint/common-sdk-base': 0.13.0 + '@hey-api/client-fetch': 0.8.1 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + abitype: 1.0.8(typescript@6.0.3)(zod@3.22.4) + base32.js: 0.1.0 + bs58: 5.0.0 + ox: 0.6.9(typescript@6.0.3)(zod@3.22.4) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - '@datadog/browser-rum' + - bufferutil + - typescript + - utf-8-validate + - zod - '@esbuild/android-arm@0.28.2': - optional: true + '@datadog/browser-core@6.24.1': {} - '@esbuild/android-x64@0.28.2': - optional: true + '@datadog/browser-logs@6.24.1': + dependencies: + '@datadog/browser-core': 6.24.1 - '@esbuild/darwin-arm64@0.28.2': - optional: true + '@dynamic-labs-connectors/base-account-evm@4.7.1(@dynamic-labs/ethereum-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4)': + dependencies: + '@base-org/account': 1.1.1(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@dynamic-labs-connectors/metamask-evm@4.7.1(@dynamic-labs/ethereum-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)))(@dynamic-labs/ethereum@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs/ethereum': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@4.6.7) + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@metamask/connect-evm': 2.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@metamask/connect-multichain': 1.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + - bufferutil + - encoding + - supports-color + - utf-8-validate - '@esbuild/darwin-x64@0.28.2': - optional: true + '@dynamic-labs-connectors/metamask-solana@4.7.1(@dynamic-labs/solana-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs/solana-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@metamask/connect-solana': 2.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + bs58: 6.0.0 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + - bufferutil + - encoding + - supports-color + - utf-8-validate - '@esbuild/freebsd-arm64@0.28.2': - optional: true + '@dynamic-labs-sdk/assert-package-version@1.39.1': {} - '@esbuild/freebsd-x64@0.28.2': - optional: true + '@dynamic-labs-sdk/client@1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs-sdk/assert-package-version': 1.39.1 + '@dynamic-labs-wallet/browser-wallet-client': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/sdk-api-core': 0.92.0 + '@simplewebauthn/browser': 13.1.0 + ably: 2.17.1(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + buffer: 6.0.3 + eventemitter3: 5.0.1 + zod: 4.6.7 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - bufferutil + - debug + - react + - react-dom + - supports-color + - utf-8-validate - '@esbuild/linux-arm64@0.28.2': - optional: true + '@dynamic-labs-wallet/browser-wallet-client@1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6))': + dependencies: + '@dynamic-labs-wallet/core': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs/logger': 5.13.0 + '@dynamic-labs/message-transport': 5.13.0 + transitivePeerDependencies: + - '@dynamic-labs-wallet/forward-mpc-client' + - debug + - supports-color - '@esbuild/linux-arm@0.28.2': - optional: true + '@dynamic-labs-wallet/core@1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6))': + dependencies: + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs-wallet/primitives': 1.1.33 + '@dynamic-labs/sdk-api-core': 0.50.0 + axios: 1.20.0 + uuid: 11.1.0 + transitivePeerDependencies: + - debug + - supports-color - '@esbuild/linux-ia32@0.28.2': - optional: true + '@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs-wallet/forward-mpc-shared': 0.7.2(@dynamic-labs-wallet/primitives@1.1.33) + '@dynamic-labs-wallet/primitives': 1.1.33 + '@evervault/wasm-attestation-bindings': 0.3.1 + '@noble/hashes': 2.4.0 + eventemitter3: 5.0.1 + fp-ts: 2.16.11 + isows: 1.0.7(ws@8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - utf-8-validate - '@esbuild/linux-loong64@0.28.2': - optional: true + '@dynamic-labs-wallet/forward-mpc-shared@0.7.2(@dynamic-labs-wallet/primitives@1.1.33)': + dependencies: + '@dynamic-labs-wallet/primitives': 1.1.33 + '@noble/ciphers': 0.4.1 + '@noble/hashes': 2.4.0 + '@noble/post-quantum': 0.5.4 + fp-ts: 2.16.11 + io-ts: 2.2.22(fp-ts@2.16.11) - '@esbuild/linux-mips64el@0.28.2': - optional: true + '@dynamic-labs-wallet/primitives@1.1.33': {} - '@esbuild/linux-ppc64@0.28.2': - optional: true + '@dynamic-labs/assert-package-version@4.100.5': + dependencies: + '@dynamic-labs/logger': 4.100.5 - '@esbuild/linux-riscv64@0.28.2': - optional: true + '@dynamic-labs/assert-package-version@5.13.0': + dependencies: + '@dynamic-labs/logger': 5.13.0 - '@esbuild/linux-s390x@0.28.2': - optional: true + '@dynamic-labs/embedded-wallet-evm@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/embedded-wallet': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/webauthn': 4.100.5 + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/iframe-stamper': 2.5.0 + '@turnkey/viem': 0.13.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4) + '@turnkey/webauthn-stamper': 0.5.1 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - zod + + '@dynamic-labs/embedded-wallet-solana@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@dynamic-labs-sdk/client': 1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/embedded-wallet': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/solana-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/webauthn': 4.100.5 + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@turnkey/iframe-stamper': 2.5.0 + '@turnkey/solana': 1.0.42(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@turnkey/webauthn-stamper': 0.5.1 + viem: 2.46.3(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - zod + + '@dynamic-labs/embedded-wallet@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/webauthn': 4.100.5 + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/http': 3.10.0 + '@turnkey/iframe-stamper': 2.5.0 + '@turnkey/webauthn-stamper': 0.5.1 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - utf-8-validate + + '@dynamic-labs/ethereum-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - utf-8-validate + + '@dynamic-labs/ethereum-gasless-core@4.100.5(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + + '@dynamic-labs/ethereum@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@4.6.7)': + dependencies: + '@coinbase/wallet-sdk': 4.3.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs-connectors/base-account-evm': 4.7.1(@dynamic-labs/ethereum-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4) + '@dynamic-labs-connectors/metamask-evm': 4.7.1(@dynamic-labs/ethereum-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)))(@dynamic-labs/ethereum@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/embedded-wallet-evm': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4) + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/waas-evm': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@walletconnect/ethereum-provider': 2.23.2(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + buffer: 6.0.3 + eventemitter3: 5.0.1 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - preact-render-to-string + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod - '@esbuild/linux-x64@0.28.2': - optional: true + '@dynamic-labs/iconic@4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + sharp: 0.35.0 + url: 0.11.0 - '@esbuild/netbsd-arm64@0.28.2': - optional: true + '@dynamic-labs/locale@4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + i18next: 23.4.6 + react-i18next: 13.5.0(i18next@23.4.6)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + transitivePeerDependencies: + - react + - react-dom + - react-native - '@esbuild/netbsd-x64@0.28.2': - optional: true + '@dynamic-labs/logger@4.100.5': + dependencies: + eventemitter3: 5.0.1 - '@esbuild/openbsd-arm64@0.28.2': - optional: true + '@dynamic-labs/logger@5.13.0': + dependencies: + '@dynamic-labs/redaction': 1.1.0 + eventemitter3: 5.0.1 - '@esbuild/openbsd-x64@0.28.2': - optional: true + '@dynamic-labs/message-transport@5.13.0': + dependencies: + '@dynamic-labs/assert-package-version': 5.13.0 + '@dynamic-labs/logger': 5.13.0 + '@dynamic-labs/utils': 5.13.0 + '@vue/reactivity': 3.5.44 + eventemitter3: 5.0.1 + + '@dynamic-labs/multi-wallet@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + tslib: 2.4.1 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - utf-8-validate + + '@dynamic-labs/redaction@1.1.0': {} + + '@dynamic-labs/rpc-providers@4.100.5': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/types': 4.100.5 + + '@dynamic-labs/sdk-api-core@0.136.0': {} + + '@dynamic-labs/sdk-api-core@0.50.0': {} + + '@dynamic-labs/sdk-api-core@0.92.0': {} + + '@dynamic-labs/sdk-react-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(@types/react@19.3.0)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs-sdk/client': 1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs-wallet/browser-wallet-client': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/iconic': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/locale': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/multi-wallet': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/store': 4.100.5 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@hcaptcha/react-hcaptcha': 1.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@marsidev/react-turnstile': 1.5.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@thumbmarkjs/thumbmarkjs': 0.16.0 + bs58: 5.0.0 + country-list: 2.3.0 + eventemitter3: 5.0.1 + formik: 2.2.9(react@19.3.0) + i18next: 23.4.6 + qrcode: 1.5.1 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-focus-lock: 2.13.6(@types/react@19.3.0)(react@19.3.0) + react-i18next: 13.5.0(i18next@23.4.6)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react-international-phone: 4.5.0(react@19.3.0) + yup: 0.32.11 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - '@types/react' + - bufferutil + - debug + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - utf-8-validate + + '@dynamic-labs/solana-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@solana/spl-token': 0.4.14(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + eventemitter3: 5.0.1 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + + '@dynamic-labs/solana@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(db0@0.4.1)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4)': + dependencies: + '@dynamic-labs-connectors/metamask-solana': 4.7.1(@dynamic-labs/solana-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6))(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/embedded-wallet-solana': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/solana-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/waas-svm': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4) + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connect': 4.100.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@wallet-standard/app': 1.0.1 + '@wallet-standard/base': 1.0.1 + '@wallet-standard/experimental-features': 0.1.1 + '@wallet-standard/features': 1.0.3 + '@walletconnect/sign-client': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/types': 2.21.5(db0@0.4.1) + '@walletconnect/utils': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + bs58: 5.0.0 + eventemitter3: 5.0.1 + tweetnacl: 1.0.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - ioredis + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - uploadthing + - utf-8-validate + - viem + - zod + + '@dynamic-labs/store@4.100.5': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + + '@dynamic-labs/sui-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@mysten/sui': 1.45.2(typescript@6.0.3) + '@mysten/wallet-standard': 0.19.9(typescript@6.0.3) + text-encoding: 0.7.0 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + + '@dynamic-labs/sui@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/sui-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/waas-sui': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + text-encoding: 0.7.0 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - viem + + '@dynamic-labs/types@4.100.5': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + + '@dynamic-labs/types@5.13.0': + dependencies: + '@dynamic-labs/assert-package-version': 5.13.0 + '@dynamic-labs/sdk-api-core': 0.136.0 + + '@dynamic-labs/utils@4.100.5': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + buffer: 6.0.3 + eventemitter3: 5.0.1 + tldts: 6.0.16 + + '@dynamic-labs/utils@5.13.0': + dependencies: + '@dynamic-labs/assert-package-version': 5.13.0 + '@dynamic-labs/logger': 5.13.0 + '@dynamic-labs/sdk-api-core': 0.136.0 + '@dynamic-labs/types': 5.13.0 + buffer: 6.0.3 + eventemitter3: 5.0.1 + tldts: 6.0.16 + + '@dynamic-labs/waas-evm@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/ethereum-gasless-core': 4.100.5(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/waas': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - zod + + '@dynamic-labs/waas-sui@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs-sdk/client': 1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs-wallet/browser-wallet-client': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/sui-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/waas': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@mysten/sui': 1.45.2(typescript@6.0.3) + '@mysten/wallet-standard': 0.19.9(typescript@6.0.3) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - viem + + '@dynamic-labs/waas-svm@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/embedded-wallet-solana': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/solana-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/waas': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + bs58: 5.0.0 + eventemitter3: 5.0.1 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - viem + - zod + + '@dynamic-labs/waas@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))': + dependencies: + '@dynamic-labs-sdk/client': 1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs-wallet/browser-wallet-client': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/core': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/ethereum-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/solana-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/sui-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/wallet-connector-core': 4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - typescript + - utf-8-validate + - viem + + '@dynamic-labs/wallet-book@4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/iconic': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + eventemitter3: 5.0.1 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + util: 0.12.5 + zod: 4.6.7 + + '@dynamic-labs/wallet-connect@4.100.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/sign-client': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@dynamic-labs/wallet-connector-core@4.100.5(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6)': + dependencies: + '@dynamic-labs-sdk/client': 1.39.1(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6) + '@dynamic-labs-wallet/browser-wallet-client': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/core': 1.1.33(@dynamic-labs-wallet/forward-mpc-client@2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@dynamic-labs-wallet/forward-mpc-client': 2.0.2(@dynamic-labs-wallet/primitives@1.1.33)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@dynamic-labs/rpc-providers': 4.100.5 + '@dynamic-labs/sdk-api-core': 0.92.0 + '@dynamic-labs/types': 4.100.5 + '@dynamic-labs/utils': 4.100.5 + '@dynamic-labs/wallet-book': 4.100.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + eventemitter3: 5.0.1 + transitivePeerDependencies: + - '@dynamic-labs-wallet/primitives' + - '@react-native-async-storage/async-storage' + - bufferutil + - debug + - react + - react-dom + - react-native + - react-native-inappbrowser-reborn + - react-native-keychain + - react-native-passkey + - supports-color + - utf-8-validate + + '@dynamic-labs/webauthn@4.100.5': + dependencies: + '@dynamic-labs/assert-package-version': 4.100.5 + '@dynamic-labs/logger': 4.100.5 + '@simplewebauthn/browser': 13.1.0 + '@simplewebauthn/types': 12.0.0 + + '@ecies/ciphers@0.2.6(@noble/ciphers@1.3.0)': + dependencies: + '@noble/ciphers': 1.3.0 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.29.7 + '@babel/runtime': 7.29.10 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.4.0': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.3.0)(react@19.3.0)': + dependencies: + '@babel/runtime': 7.29.10 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.3.0) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.3.0)(react@19.3.0))(@types/react@19.3.0)(react@19.3.0)': + dependencies: + '@babel/runtime': 7.29.10 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.4.0 + '@emotion/react': 11.14.0(@types/react@19.3.0)(react@19.3.0) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.3.0) + '@emotion/utils': 1.4.2 + react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 + transitivePeerDependencies: + - supports-color + + '@emotion/unitless@0.10.0': {} + + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.3.0)': + dependencies: + react: 19.3.0 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true '@esbuild/openharmony-arm64@0.28.2': optional: true @@ -3057,6 +6626,71 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@ethereumjs/common@3.2.0': + dependencies: + '@ethereumjs/util': 8.1.0 + crc-32: 1.2.2 + + '@ethereumjs/rlp@4.0.1': {} + + '@ethereumjs/tx@4.2.0': + dependencies: + '@ethereumjs/common': 3.2.0 + '@ethereumjs/rlp': 4.0.1 + '@ethereumjs/util': 8.1.0 + ethereum-cryptography: 2.2.1 + + '@ethereumjs/util@8.1.0': + dependencies: + '@ethereumjs/rlp': 4.0.1 + ethereum-cryptography: 2.2.1 + micro-ftch: 0.3.1 + + '@evervault/wasm-attestation-bindings@0.3.1': {} + + '@gql.tada/cli-utils@1.9.4(@0no-co/graphqlsp@1.18.0(graphql@16.14.2)(typescript@6.0.3))(graphql@16.14.2)(typescript@6.0.3)': + dependencies: + '@0no-co/graphqlsp': 1.18.0(graphql@16.14.2)(typescript@6.0.3) + '@gql.tada/internal': 1.2.2(graphql@16.14.2)(typescript@6.0.3) + graphql: 16.14.2 + typescript: 6.0.3 + + '@gql.tada/internal@1.2.2(graphql@16.14.2)(typescript@6.0.3)': + dependencies: + '@0no-co/graphql.web': 1.3.4(graphql@16.14.2) + graphql: 16.14.2 + typescript: 6.0.3 + + '@graphql-typed-document-node/core@3.2.0(graphql@16.14.2)': + dependencies: + graphql: 16.14.2 + + '@hcaptcha/react-hcaptcha@1.4.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@babel/runtime': 7.29.10 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + + '@hey-api/client-fetch@0.8.1': {} + + '@hpke/chacha20poly1305@1.8.0': + dependencies: + '@hpke/common': 1.10.1 + + '@hpke/common@1.10.1': {} + + '@hpke/core@1.9.0': + dependencies: + '@hpke/common': 1.10.1 + + '@hpke/dhkem-x25519@1.8.0': + dependencies: + '@hpke/common': 1.10.1 + + '@hpke/dhkem-x448@1.8.0': + dependencies: + '@hpke/common': 1.10.1 + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -3073,7 +6707,11 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@img/colour@1.1.0': + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.3.0 optional: true '@img/sharp-darwin-arm64@0.35.5': @@ -3081,102 +6719,201 @@ snapshots: '@img/sharp-libvips-darwin-arm64': 1.3.4 optional: true + '@img/sharp-darwin-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.3.0 + optional: true + '@img/sharp-darwin-x64@0.35.5': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.3.4 optional: true + '@img/sharp-freebsd-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + '@img/sharp-freebsd-wasm32@0.35.5': dependencies: '@img/sharp-wasm32': 0.35.5 optional: true + '@img/sharp-libvips-darwin-arm64@1.3.0': + optional: true + '@img/sharp-libvips-darwin-arm64@1.3.4': optional: true + '@img/sharp-libvips-darwin-x64@1.3.0': + optional: true + '@img/sharp-libvips-darwin-x64@1.3.4': optional: true + '@img/sharp-libvips-linux-arm64@1.3.0': + optional: true + '@img/sharp-libvips-linux-arm64@1.3.4': optional: true + '@img/sharp-libvips-linux-arm@1.3.0': + optional: true + '@img/sharp-libvips-linux-arm@1.3.4': optional: true + '@img/sharp-libvips-linux-ppc64@1.3.0': + optional: true + '@img/sharp-libvips-linux-ppc64@1.3.4': optional: true + '@img/sharp-libvips-linux-riscv64@1.3.0': + optional: true + '@img/sharp-libvips-linux-riscv64@1.3.4': optional: true + '@img/sharp-libvips-linux-s390x@1.3.0': + optional: true + '@img/sharp-libvips-linux-s390x@1.3.4': optional: true + '@img/sharp-libvips-linux-x64@1.3.0': + optional: true + '@img/sharp-libvips-linux-x64@1.3.4': optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.3.0': + optional: true + '@img/sharp-libvips-linuxmusl-arm64@1.3.4': optional: true + '@img/sharp-libvips-linuxmusl-x64@1.3.0': + optional: true + '@img/sharp-libvips-linuxmusl-x64@1.3.4': optional: true + '@img/sharp-linux-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.3.0 + optional: true + '@img/sharp-linux-arm64@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.3.4 optional: true + '@img/sharp-linux-arm@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.3.0 + optional: true + '@img/sharp-linux-arm@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.3.4 optional: true + '@img/sharp-linux-ppc64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.3.0 + optional: true + '@img/sharp-linux-ppc64@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-ppc64': 1.3.4 optional: true + '@img/sharp-linux-riscv64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.3.0 + optional: true + '@img/sharp-linux-riscv64@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-riscv64': 1.3.4 optional: true + '@img/sharp-linux-s390x@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.3.0 + optional: true + '@img/sharp-linux-s390x@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.3.4 optional: true + '@img/sharp-linux-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.3.0 + optional: true + '@img/sharp-linux-x64@0.35.5': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.3.4 optional: true + '@img/sharp-linuxmusl-arm64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + optional: true + '@img/sharp-linuxmusl-arm64@0.35.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.3.4 optional: true + '@img/sharp-linuxmusl-x64@0.35.0': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + optional: true + '@img/sharp-linuxmusl-x64@0.35.5': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.3.4 optional: true + '@img/sharp-wasm32@0.35.0': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + '@img/sharp-wasm32@0.35.5': dependencies: '@emnapi/runtime': 1.11.3 optional: true + '@img/sharp-webcontainers-wasm32@0.35.0': + dependencies: + '@img/sharp-wasm32': 0.35.0 + optional: true + '@img/sharp-webcontainers-wasm32@0.35.5': dependencies: '@img/sharp-wasm32': 0.35.5 optional: true + '@img/sharp-win32-arm64@0.35.0': + optional: true + '@img/sharp-win32-arm64@0.35.5': optional: true + '@img/sharp-win32-ia32@0.35.0': + optional: true + '@img/sharp-win32-ia32@0.35.5': optional: true + '@img/sharp-win32-x64@0.35.0': + optional: true + '@img/sharp-win32-x64@0.35.5': optional: true @@ -3199,6 +6936,225 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.6.0 + '@lit-labs/ssr-dom-shim@1.6.0': {} + + '@lit/react@1.0.8(@types/react@19.3.0)': + dependencies: + '@types/react': 19.3.0 + optional: true + + '@lit/reactive-element@2.1.2': + dependencies: + '@lit-labs/ssr-dom-shim': 1.6.0 + + '@marsidev/react-turnstile@1.5.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + + '@metamask/analytics@0.6.0': + dependencies: + openapi-fetch: 0.13.8 + + '@metamask/connect-evm@2.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@metamask/analytics': 0.6.0 + '@metamask/connect-multichain': 1.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@metamask/utils': 11.12.1 + semver: 7.8.5 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metamask/connect-multichain@1.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@metamask/analytics': 0.6.0 + '@metamask/mobile-wallet-protocol-core': 0.4.0 + '@metamask/mobile-wallet-protocol-dapp-client': 0.3.0 + '@metamask/multichain-api-client': 0.10.1 + '@metamask/multichain-ui': 0.4.1 + '@metamask/onboarding': 1.0.1 + '@metamask/rpc-errors': 7.0.3 + '@metamask/utils': 11.12.1 + '@paulmillr/qr': 0.2.1 + bowser: 2.15.0 + buffer: 6.0.3 + cross-fetch: 4.1.0 + eciesjs: 0.4.17 + eventemitter3: 5.0.1 + pako: 2.2.0 + uuid: 11.1.1 + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metamask/connect-multichain@1.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@metamask/analytics': 0.6.0 + '@metamask/mobile-wallet-protocol-core': 0.4.0 + '@metamask/mobile-wallet-protocol-dapp-client': 0.3.0 + '@metamask/multichain-api-client': 0.10.1 + '@metamask/multichain-ui': 0.4.1 + '@metamask/onboarding': 1.0.1 + '@metamask/rpc-errors': 7.0.3 + '@metamask/utils': 11.12.1 + '@paulmillr/qr': 0.2.1 + bowser: 2.15.0 + buffer: 6.0.3 + cross-fetch: 4.1.0 + eciesjs: 0.4.17 + eventemitter3: 5.0.1 + pako: 2.2.0 + uuid: 11.1.1 + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metamask/connect-solana@2.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@metamask/connect-multichain': 1.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@metamask/solana-wallet-standard': 0.6.0 + '@wallet-standard/app': 1.1.1 + '@wallet-standard/base': 1.1.1 + semver: 7.8.5 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@metamask/mobile-wallet-protocol-core@0.4.0': + dependencies: + async-mutex: 0.5.0 + centrifuge: 5.8.0 + eventemitter3: 5.0.1 + uuid: 11.1.1 + + '@metamask/mobile-wallet-protocol-dapp-client@0.3.0': + dependencies: + '@metamask/mobile-wallet-protocol-core': 0.4.0 + '@metamask/utils': 9.3.0 + uuid: 11.1.1 + transitivePeerDependencies: + - supports-color + + '@metamask/multichain-api-client@0.10.1': {} + + '@metamask/multichain-ui@0.4.1': + dependencies: + '@paulmillr/qr': 0.2.1 + qr-code-styling: 1.9.2 + + '@metamask/onboarding@1.0.1': + dependencies: + bowser: 2.15.0 + + '@metamask/rpc-errors@7.0.3': + dependencies: + '@metamask/utils': 11.12.1 + fast-safe-stringify: 2.1.1 + transitivePeerDependencies: + - supports-color + + '@metamask/scure-bip39@2.1.1': + dependencies: + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.9 + + '@metamask/solana-wallet-standard@0.6.0': + dependencies: + '@solana/wallet-standard-chains': 1.1.2 + '@solana/wallet-standard-features': 1.5.0 + '@wallet-standard/base': 1.1.1 + '@wallet-standard/features': 1.1.1 + '@wallet-standard/wallet': 1.1.1 + bs58: 6.0.0 + + '@metamask/superstruct@3.4.1': {} + + '@metamask/utils@11.12.1': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@metamask/scure-bip39': 2.1.1 + '@metamask/superstruct': 3.4.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@types/debug': 4.1.13 + '@types/lodash': 4.17.27 + debug: 4.4.3 + lodash: 4.18.1 + pony-cause: 2.1.11 + semver: 7.8.5 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + + '@metamask/utils@9.3.0': + dependencies: + '@ethereumjs/tx': 4.2.0 + '@metamask/superstruct': 3.4.1 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@types/debug': 4.1.13 + debug: 4.4.3 + pony-cause: 2.1.11 + semver: 7.8.5 + uuid: 9.0.1 + transitivePeerDependencies: + - supports-color + + '@msgpack/msgpack@3.1.2': {} + + '@mysten/bcs@1.9.2': + dependencies: + '@mysten/utils': 0.2.0 + '@scure/base': 1.2.6 + + '@mysten/sui@1.45.2(typescript@6.0.3)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.14.2) + '@mysten/bcs': 1.9.2 + '@mysten/utils': 0.2.0 + '@noble/curves': 1.9.4 + '@noble/hashes': 1.8.0 + '@protobuf-ts/grpcweb-transport': 2.11.1 + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + '@scure/base': 1.2.6 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + gql.tada: 1.11.4(graphql@16.14.2)(typescript@6.0.3) + graphql: 16.14.2 + poseidon-lite: 0.2.1 + valibot: 1.5.0(typescript@6.0.3) + transitivePeerDependencies: + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - typescript + + '@mysten/utils@0.2.0': + dependencies: + '@scure/base': 1.2.6 + + '@mysten/wallet-standard@0.19.9(typescript@6.0.3)': + dependencies: + '@mysten/sui': 1.45.2(typescript@6.0.3) + '@wallet-standard/core': 1.1.1 + transitivePeerDependencies: + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - typescript + '@napi-rs/wasm-runtime@1.2.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -3239,6 +7195,59 @@ snapshots: '@next/swc-win32-x64-msvc@16.4.3': optional: true + '@noble/ciphers@0.4.1': {} + + '@noble/ciphers@1.3.0': {} + + '@noble/curves@1.4.2': + dependencies: + '@noble/hashes': 1.4.0 + + '@noble/curves@1.8.0': + dependencies: + '@noble/hashes': 1.7.0 + + '@noble/curves@1.9.0': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.2': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.4': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@2.0.1': + dependencies: + '@noble/hashes': 2.0.1 + + '@noble/hashes@1.3.3': {} + + '@noble/hashes@1.4.0': {} + + '@noble/hashes@1.7.0': {} + + '@noble/hashes@1.8.0': {} + + '@noble/hashes@2.0.1': {} + + '@noble/hashes@2.4.0': {} + + '@noble/post-quantum@0.5.4': + dependencies: + '@noble/curves': 2.0.1 + '@noble/hashes': 2.0.1 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3262,8 +7271,301 @@ snapshots: '@opentelemetry/semantic-conventions@1.43.0': {} + '@openzeppelin/contracts@4.9.6': {} + '@oxc-project/types@0.153.0': {} + '@paulmillr/qr@0.2.1': {} + + '@phosphor-icons/webcomponents@2.1.5': + dependencies: + lit: 3.3.0 + + '@protobuf-ts/grpcweb-transport@2.11.1': + dependencies: + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + + '@protobuf-ts/runtime-rpc@2.11.1': + dependencies: + '@protobuf-ts/runtime': 2.11.1 + + '@protobuf-ts/runtime@2.11.1': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + + '@reown/appkit-common@1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-wallet': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + valtio: 2.1.7(@types/react@19.3.0)(react@19.3.0) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-pay@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-controllers': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-ui': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-utils': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4) + lit: 3.3.0 + valtio: 2.1.7(@types/react@19.3.0)(react@19.3.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-polyfills@1.8.11': + dependencies: + buffer: 6.0.3 + + '@reown/appkit-scaffold-ui@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-controllers': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-ui': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-utils': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4) + '@reown/appkit-wallet': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + + '@reown/appkit-ui@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@phosphor-icons/webcomponents': 2.1.5 + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-controllers': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-wallet': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-utils@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-controllers': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-polyfills': 1.8.11 + '@reown/appkit-wallet': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@wallet-standard/wallet': 1.1.0 + '@walletconnect/logger': 3.0.2 + '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + valtio: 2.1.7(@types/react@19.3.0)(react@19.3.0) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-wallet@1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-polyfills': 1.8.11 + '@walletconnect/logger': 3.0.2 + zod: 3.22.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@reown/appkit@1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@reown/appkit-common': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-controllers': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-pay': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-polyfills': 1.8.11 + '@reown/appkit-scaffold-ui': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4) + '@reown/appkit-ui': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@reown/appkit-utils': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(valtio@2.1.7(@types/react@19.3.0)(react@19.3.0))(zod@3.22.4) + '@reown/appkit-wallet': 1.8.11(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@walletconnect/universal-provider': 2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + bs58: 6.0.0 + semver: 7.7.2 + valtio: 2.1.7(@types/react@19.3.0)(react@19.3.0) + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + optionalDependencies: + '@lit/react': 1.0.8(@types/react@19.3.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@rolldown/binding-android-arm-eabi@1.2.13': optional: true @@ -3313,6 +7615,188 @@ snapshots: '@rtsao/scc@1.1.0': {} + '@scure/base@1.1.9': {} + + '@scure/base@1.2.6': {} + + '@scure/bip32@1.4.0': + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip32@1.7.0': + dependencies: + '@noble/curves': 1.9.4 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@scure/bip39@1.3.0': + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.9 + + '@scure/bip39@1.6.0': + dependencies: + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + + '@simplewebauthn/browser@13.1.0': {} + + '@simplewebauthn/types@12.0.0': {} + + '@sindresorhus/is@4.6.0': {} + + '@solana/buffer-layout-utils@0.2.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + bigint-buffer: 1.1.5 + bignumber.js: 9.3.1 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + + '@solana/buffer-layout@4.0.1': + dependencies: + buffer: 6.0.3 + + '@solana/codecs-core@2.0.0-rc.1(typescript@6.0.3)': + dependencies: + '@solana/errors': 2.0.0-rc.1(typescript@6.0.3) + typescript: 6.0.3 + + '@solana/codecs-core@2.3.0(typescript@6.0.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@6.0.3) + typescript: 6.0.3 + + '@solana/codecs-data-structures@2.0.0-rc.1(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@6.0.3) + '@solana/errors': 2.0.0-rc.1(typescript@6.0.3) + typescript: 6.0.3 + + '@solana/codecs-numbers@2.0.0-rc.1(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@6.0.3) + '@solana/errors': 2.0.0-rc.1(typescript@6.0.3) + typescript: 6.0.3 + + '@solana/codecs-numbers@2.3.0(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@6.0.3) + '@solana/errors': 2.3.0(typescript@6.0.3) + typescript: 6.0.3 + + '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@6.0.3) + '@solana/errors': 2.0.0-rc.1(typescript@6.0.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 6.0.3 + + '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@2.0.0-rc.1(typescript@6.0.3)': + dependencies: + chalk: 5.6.2 + commander: 12.1.0 + typescript: 6.0.3 + + '@solana/errors@2.3.0(typescript@6.0.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.3 + typescript: 6.0.3 + + '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)': + dependencies: + '@solana/codecs-core': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-numbers': 2.0.0-rc.1(typescript@6.0.3) + '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/errors': 2.0.0-rc.1(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)': + dependencies: + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)': + dependencies: + '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/spl-token@0.4.14(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@6.0.3) + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + + '@solana/wallet-standard-chains@1.1.2': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@solana/wallet-standard-features@1.5.0': + dependencies: + '@wallet-standard/base': 1.1.1 + '@wallet-standard/features': 1.1.1 + + '@solana/web3.js@1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)': + dependencies: + '@babel/runtime': 7.29.10 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@solana/buffer-layout': 4.0.1 + '@solana/codecs-numbers': 2.3.0(typescript@6.0.3) + agentkeepalive: 4.6.0 + bn.js: 5.2.5 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.3.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + node-fetch: 2.7.0 + rpc-websockets: 9.3.9 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + '@standard-schema/spec@1.1.0': {} '@stripe/link-integrations-eve@0.3.4(eve@0.79.1(@opentelemetry/api@1.9.1)(ai@7.0.137(zod@4.6.7))(microsandbox@0.5.10))': @@ -3338,29 +7822,179 @@ snapshots: dependencies: tslib: 2.8.1 + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@thumbmarkjs/thumbmarkjs@0.16.0': {} + + '@turnkey/api-key-stamper@0.4.7': + dependencies: + '@noble/curves': 1.9.7 + '@turnkey/encoding': 0.5.0 + sha256-uint8array: 0.10.7 + + '@turnkey/crypto@2.5.0': + dependencies: + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.0 + '@noble/hashes': 1.8.0 + '@turnkey/encoding': 0.5.0 + bs58: 6.0.0 + bs58check: 4.0.0 + + '@turnkey/encoding@0.5.0': {} + + '@turnkey/http@3.10.0': + dependencies: + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/encoding': 0.5.0 + '@turnkey/webauthn-stamper': 0.5.1 + cross-fetch: 3.2.0 + transitivePeerDependencies: + - encoding + + '@turnkey/iframe-stamper@2.5.0': {} + + '@turnkey/indexed-db-stamper@1.1.1': + dependencies: + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/encoding': 0.5.0 + + '@turnkey/sdk-browser@5.8.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/crypto': 2.5.0 + '@turnkey/encoding': 0.5.0 + '@turnkey/http': 3.10.0 + '@turnkey/iframe-stamper': 2.5.0 + '@turnkey/indexed-db-stamper': 1.1.1 + '@turnkey/sdk-types': 0.3.0 + '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@turnkey/webauthn-stamper': 0.5.1 + bs58check: 4.0.0 + buffer: 6.0.3 + cross-fetch: 3.2.0 + hpke-js: 1.8.0 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + - zod + + '@turnkey/sdk-server@4.7.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/http': 3.10.0 + '@turnkey/wallet-stamper': 1.0.8(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + buffer: 6.0.3 + cross-fetch: 3.2.0 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + - zod + + '@turnkey/sdk-types@0.3.0': {} + + '@turnkey/solana@1.0.42(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@solana/web3.js': 1.98.1(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6) + '@turnkey/http': 3.10.0 + '@turnkey/sdk-browser': 5.8.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@turnkey/sdk-server': 4.7.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + - zod + + '@turnkey/viem@0.13.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4))(zod@3.22.4)': + dependencies: + '@noble/curves': 1.8.0 + '@openzeppelin/contracts': 4.9.6 + '@turnkey/api-key-stamper': 0.4.7 + '@turnkey/http': 3.10.0 + '@turnkey/sdk-browser': 5.8.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@turnkey/sdk-server': 4.7.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + cross-fetch: 4.1.0 + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate + - zod + + '@turnkey/wallet-stamper@1.0.8(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@turnkey/crypto': 2.5.0 + '@turnkey/encoding': 0.5.0 + optionalDependencies: + viem: 2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@turnkey/webauthn-stamper@0.5.1': + dependencies: + sha256-uint8array: 0.10.7 + '@tybys/wasm-util@0.10.4': dependencies: tslib: 2.8.1 optional: true + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.2.0 + '@types/keyv': 3.1.4 + '@types/node': 24.19.0 + '@types/responselike': 1.0.3 + '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/connect@3.4.38': + dependencies: + '@types/node': 24.19.0 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.9': {} + '@types/http-cache-semantics@4.2.0': {} + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} + '@types/keyv@3.1.4': + dependencies: + '@types/node': 24.19.0 + + '@types/lodash@4.17.27': {} + + '@types/ms@2.1.0': {} + '@types/node-fetch@2.6.13': dependencies: '@types/node': 24.19.0 form-data: 4.0.6 + '@types/node@12.20.55': {} + '@types/node@18.19.130': dependencies: undici-types: 5.26.5 @@ -3369,6 +8003,8 @@ snapshots: dependencies: undici-types: 7.24.6 + '@types/parse-json@4.0.2': {} + '@types/pg@8.23.1': dependencies: '@types/node': 24.19.0 @@ -3383,6 +8019,22 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/responselike@1.0.3': + dependencies: + '@types/node': 24.19.0 + + '@types/trusted-types@2.0.7': {} + + '@types/uuid@10.0.0': {} + + '@types/ws@7.4.7': + dependencies: + '@types/node': 24.19.0 + + '@types/ws@8.18.2': + dependencies: + '@types/node': 24.19.0 + '@typescript-eslint/eslint-plugin@8.71.1(@typescript-eslint/parser@8.71.1(eslint@9.39.5)(typescript@6.0.3))(eslint@9.39.5)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -3587,8 +8239,800 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.2.0 + '@vue/reactivity@3.5.44': + dependencies: + '@vue/shared': 3.5.44 + + '@vue/shared@3.5.44': {} + + '@wallet-standard/app@1.0.1': + dependencies: + '@wallet-standard/base': 1.0.1 + + '@wallet-standard/app@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/base@1.0.1': {} + + '@wallet-standard/base@1.1.1': {} + + '@wallet-standard/core@1.1.1': + dependencies: + '@wallet-standard/app': 1.1.1 + '@wallet-standard/base': 1.1.1 + '@wallet-standard/errors': 0.1.2 + '@wallet-standard/features': 1.1.1 + '@wallet-standard/wallet': 1.1.1 + + '@wallet-standard/errors@0.1.2': + dependencies: + chalk: 5.6.2 + commander: 13.1.0 + + '@wallet-standard/experimental-features@0.1.1': + dependencies: + '@wallet-standard/base': 1.0.1 + + '@wallet-standard/features@1.0.3': + dependencies: + '@wallet-standard/base': 1.0.1 + + '@wallet-standard/features@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/wallet@1.1.0': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/wallet@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@walletconnect/core@2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.5(db0@0.4.1) + '@walletconnect/utils': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.39.3 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.0 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4(db0@0.4.1) + '@walletconnect/utils': 2.22.4(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.39.3 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.2(db0@0.4.1) + '@walletconnect/utils': 2.23.2(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.39.3 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/environment@1.0.1': + dependencies: + tslib: 1.14.1 + + '@walletconnect/ethereum-provider@2.23.2(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@reown/appkit': 1.8.11(@types/react@19.3.0)(bufferutil@4.1.0)(db0@0.4.1)(react@19.3.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.2 + '@walletconnect/sign-client': 2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/types': 2.23.2(db0@0.4.1) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/utils': 2.23.2(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/events@1.0.1': + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + + '@walletconnect/heartbeat@1.2.2': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + events: 3.3.0 + + '@walletconnect/jsonrpc-http-connection@1.0.8': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + cross-fetch: 3.2.0 + events: 3.3.0 + transitivePeerDependencies: + - encoding + + '@walletconnect/jsonrpc-provider@1.0.14': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + + '@walletconnect/jsonrpc-types@1.0.4': + dependencies: + events: 3.3.0 + keyvaluestorage-interface: 1.0.0 + + '@walletconnect/jsonrpc-utils@1.0.8': + dependencies: + '@walletconnect/environment': 1.0.1 + '@walletconnect/jsonrpc-types': 1.0.4 + tslib: 1.14.1 + + '@walletconnect/jsonrpc-ws-connection@1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + ws: 7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/keyvaluestorage@1.1.1(db0@0.4.1)': + dependencies: + '@walletconnect/safe-json': 1.0.2 + idb-keyval: 6.3.0 + unstorage: 1.17.6(db0@0.4.1)(idb-keyval@6.3.0) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/logger@2.1.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 7.11.0 + + '@walletconnect/logger@3.0.0': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/logger@3.0.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/relay-api@1.0.11': + dependencies: + '@walletconnect/jsonrpc-types': 1.0.4 + + '@walletconnect/relay-auth@1.1.0': + dependencies: + '@noble/curves': 1.8.0 + '@noble/hashes': 1.7.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + uint8arrays: 3.1.1 + + '@walletconnect/safe-json@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/sign-client@2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/core': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.5(db0@0.4.1) + '@walletconnect/utils': 2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/core': 2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 3.0.0 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4(db0@0.4.1) + '@walletconnect/utils': 2.22.4(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/core': 2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 3.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.2(db0@0.4.1) + '@walletconnect/utils': 2.23.2(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/time@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/types@2.21.5(db0@0.4.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.22.4(db0@0.4.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.23.2(db0@0.4.1)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/universal-provider@2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.0 + '@walletconnect/sign-client': 2.22.4(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/types': 2.22.4(db0@0.4.1) + '@walletconnect/utils': 2.22.4(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + es-toolkit: 1.39.3 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/universal-provider@2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.2 + '@walletconnect/sign-client': 2.23.2(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + '@walletconnect/types': 2.23.2(db0@0.4.1) + '@walletconnect/utils': 2.23.2(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4) + es-toolkit: 1.39.3 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.21.5(bufferutil@4.1.0)(db0@0.4.1)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4)': + dependencies: + '@msgpack/msgpack': 3.1.2 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.2 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.5(db0@0.4.1) + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.1 + viem: 2.31.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.22.4(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4)': + dependencies: + '@msgpack/msgpack': 3.1.2 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.0 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.22.4(db0@0.4.1) + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + ox: 0.9.3(typescript@6.0.3)(zod@3.22.4) + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - typescript + - uploadthing + - zod + + '@walletconnect/utils@2.23.2(db0@0.4.1)(typescript@6.0.3)(zod@3.22.4)': + dependencies: + '@msgpack/msgpack': 3.1.2 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(db0@0.4.1) + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.2(db0@0.4.1) + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + ox: 0.9.3(typescript@6.0.3)(zod@3.22.4) + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - typescript + - uploadthing + - zod + + '@walletconnect/window-getters@1.0.1': + dependencies: + tslib: 1.14.1 + + '@walletconnect/window-metadata@1.0.1': + dependencies: + '@walletconnect/window-getters': 1.0.1 + tslib: 1.14.1 + '@workflow/serde@4.1.0': {} + abitype@1.0.8(typescript@6.0.3)(zod@3.22.4): + optionalDependencies: + typescript: 6.0.3 + zod: 3.22.4 + + abitype@1.2.3(typescript@6.0.3)(zod@3.22.4): + optionalDependencies: + typescript: 6.0.3 + zod: 3.22.4 + + abitype@1.2.3(typescript@6.0.3)(zod@4.6.7): + optionalDependencies: + typescript: 6.0.3 + zod: 4.6.7 + + abitype@1.3.0(typescript@6.0.3)(zod@3.22.4): + optionalDependencies: + typescript: 6.0.3 + zod: 3.22.4 + + ably@2.17.1(bufferutil@4.1.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(utf-8-validate@6.0.6): + dependencies: + '@ably/msgpack-js': 0.4.1 + dequal: 2.0.3 + fastestsmallesttextencoderdecoder: 1.0.22 + got: 11.8.6 + ulid: 2.4.0 + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -3599,6 +9043,12 @@ snapshots: acorn@8.19.0: {} + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 @@ -3617,10 +9067,17 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-regex@5.0.1: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + argparse@2.0.1: {} aria-query@5.3.2: {} @@ -3698,22 +9155,87 @@ snapshots: async-function@1.0.0: {} + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 axe-core@4.14.0: {} + axios@1.20.0: + dependencies: + follow-redirects: 1.16.2 + form-data: 4.0.6 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + axobject-query@4.1.0: {} + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.29.10 + cosmiconfig: 7.1.0 + resolve: 1.22.13 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} + base-x@3.0.11: + dependencies: + safe-buffer: 5.2.1 + + base-x@4.0.1: {} + + base-x@5.0.1: {} + + base32.js@0.1.0: {} + + base64-js@1.0.2: {} + + base64-js@1.5.1: {} + baseline-browser-mapping@2.11.27: {} + big.js@6.2.2: {} + + bigint-buffer@1.1.5: + dependencies: + bindings: 1.5.0 + + bignumber.js@9.3.1: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + blakejs@1.2.1: {} + + bn.js@5.2.5: {} + + bops@1.0.1: + dependencies: + base64-js: 1.0.2 + to-utf8: 0.0.1 + + borsh@0.7.0: + dependencies: + bn.js: 5.2.5 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + + bowser@2.15.0: {} + brace-expansion@1.1.21: dependencies: balanced-match: 1.0.2 @@ -3735,6 +9257,45 @@ snapshots: node-releases: 2.0.57 update-browserslist-db: 1.3.4(browserslist@4.29.3) + bs58@4.0.1: + dependencies: + base-x: 3.0.11 + + bs58@5.0.0: + dependencies: + base-x: 4.0.1 + + bs58@6.0.0: + dependencies: + base-x: 5.0.1 + + bs58check@4.0.0: + dependencies: + '@noble/hashes': 1.8.0 + bs58: 6.0.0 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bufferutil@4.1.0: + dependencies: + node-gyp-build: 4.8.4 + optional: true + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.3.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3754,8 +9315,15 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + caniuse-lite@1.0.30001815: {} + centrifuge@5.8.0: + dependencies: + events: 3.3.0 + protobufjs: 7.6.6 + chai@6.3.0: {} chalk@4.1.2: @@ -3763,30 +9331,100 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + + chokidar@5.0.0: + dependencies: + readdirp: 5.1.1 + client-only@0.0.1: {} + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + clsx@1.2.1: {} + + clsx@2.1.1: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 + commander@12.1.0: {} + + commander@13.1.0: {} + + commander@14.0.3: {} + + commander@2.20.3: {} + concat-map@0.0.1: {} consola@3.4.2: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} + cookie-es@1.2.3: {} + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.3 + + country-list@2.3.0: {} + + crc-32@1.2.2: {} + + cross-fetch@3.2.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cross-fetch@4.1.0: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + crossws@0.4.15(srvx@1.0.5): optionalDependencies: srvx: 1.0.5 @@ -3813,6 +9451,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + dayjs@1.11.13: {} + db0@0.4.1: {} debug@3.2.7: @@ -3823,8 +9463,20 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + + decode-uri-component@0.2.2: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + deep-is@0.1.4: {} + deepmerge@2.2.1: {} + + defer-to-connect@2.0.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 @@ -3837,24 +9489,65 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.7: {} + + delay@5.0.0: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-browser@5.3.0: {} + detect-libc@2.1.2: {} + detect-node-es@1.1.0: {} + + dijkstrajs@1.0.3: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.29.10 + csstype: 3.2.3 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 + duplexify@4.1.3: + dependencies: + end-of-stream: 1.4.5 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + + eciesjs@0.4.17: + dependencies: + '@ecies/ciphers': 0.2.6(@noble/ciphers@1.3.0) + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + electron-to-chromium@1.5.451: {} + emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + encode-utf8@1.0.3: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + env-runner@0.2.3: dependencies: crossws: 0.4.15(srvx@1.0.5) @@ -3862,6 +9555,10 @@ snapshots: httpxy: 0.5.5 srvx: 1.0.5 + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + es-abstract-get@1.0.0: dependencies: es-errors: 1.3.0 @@ -3975,6 +9672,14 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.39.3: {} + + es6-promise@4.2.8: {} + + es6-promisify@5.0.0: + dependencies: + es6-promise: 4.2.8 + esbuild@0.28.2: optionalDependencies: '@esbuild/aix-ppc64': 0.28.2 @@ -4216,6 +9921,13 @@ snapshots: esutils@2.0.3: {} + ethereum-cryptography@2.2.1: + dependencies: + '@noble/curves': 1.4.2 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + eve@0.79.1(@opentelemetry/api@1.9.1)(ai@7.0.137(zod@4.6.7))(microsandbox@0.5.10): dependencies: ai: 7.0.137(zod@4.6.7) @@ -4227,12 +9939,20 @@ snapshots: event-target-shim@5.0.1: {} + eventemitter3@5.0.1: {} + + events@3.3.0: {} + eventsource-parser@3.1.1: {} expect-type@1.4.0: {} + exponential-backoff@3.1.1: {} + exsolve@1.1.3: {} + eyes@0.1.8: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.1: @@ -4247,6 +9967,14 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-redact@3.5.0: {} + + fast-safe-stringify@2.1.1: {} + + fast-stable-stringify@1.0.0: {} + + fastestsmallesttextencoderdecoder@1.0.22: {} + fastq@1.20.3: dependencies: reusify: 1.1.0 @@ -4259,10 +9987,21 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-uri-to-path@1.0.0: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 + filter-obj@1.1.0: {} + + find-root@1.1.0: {} + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4275,6 +10014,12 @@ snapshots: flatted@3.4.4: {} + focus-lock@1.3.6: + dependencies: + tslib: 2.8.1 + + follow-redirects@1.16.2: {} + for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -4294,6 +10039,19 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 + formik@2.2.9(react@19.3.0): + dependencies: + deepmerge: 2.2.1 + hoist-non-react-statics: 3.3.2 + lodash: 4.18.1 + lodash-es: 4.18.1 + react: 19.3.0 + react-fast-compare: 2.0.4 + tiny-warning: 1.0.3 + tslib: 1.14.1 + + fp-ts@2.16.11: {} + fsevents@2.3.3: optional: true @@ -4317,6 +10075,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4335,6 +10095,10 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.2 + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -4364,6 +10128,46 @@ snapshots: gopd@1.2.0: {} + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + gql.tada@1.11.4(graphql@16.14.2)(typescript@6.0.3): + dependencies: + '@0no-co/graphql.web': 1.3.4(graphql@16.14.2) + '@0no-co/graphqlsp': 1.18.0(graphql@16.14.2)(typescript@6.0.3) + '@gql.tada/cli-utils': 1.9.4(@0no-co/graphqlsp@1.18.0(graphql@16.14.2)(typescript@6.0.3))(graphql@16.14.2)(typescript@6.0.3) + '@gql.tada/internal': 1.2.2(graphql@16.14.2)(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - '@gql.tada/svelte-support' + - '@gql.tada/vue-support' + - graphql + + graphql@16.14.2: {} + + h3@1.15.11: + dependencies: + cookie-es: 1.2.3 + crossws: 0.3.5 + defu: 6.1.7 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.5 + radix3: 1.1.2 + ufo: 1.6.4 + uncrypto: 0.1.3 + h3@2.0.2(crossws@0.4.15(srvx@1.0.5))(ocache@0.3.0): dependencies: rou3: 1.0.0 @@ -4400,14 +10204,54 @@ snapshots: dependencies: hermes-estree: 0.25.1 + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + hookable@6.1.2: {} + hpke-js@1.8.0: + dependencies: + '@hpke/chacha20poly1305': 1.8.0 + '@hpke/common': 1.10.1 + '@hpke/core': 1.9.0 + '@hpke/dhkem-x25519': 1.8.0 + '@hpke/dhkem-x448': 1.8.0 + + html-parse-stringify@3.1.0: + dependencies: + void-elements: 3.1.0 + + http-cache-semantics@4.3.0: {} + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + httpxy@0.5.5: {} humanize-ms@1.2.1: dependencies: ms: 2.1.3 + i18next@23.4.6: + dependencies: + '@babel/runtime': 7.29.10 + + idb-keyval@6.2.1: {} + + idb-keyval@6.3.0: {} + + ieee754@1.2.1: {} + ignore@5.3.2: {} ignore@7.0.12: {} @@ -4419,18 +10263,40 @@ snapshots: imurmurhash@0.1.4: {} + inherits@2.0.4: {} + + input-otp@1.4.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.4 side-channel: 1.1.1 + io-ts@2.2.22(fp-ts@2.16.11): + dependencies: + fp-ts: 2.16.11 + + iron-webcrypto@1.2.1: {} + + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-arrayish@0.2.1: {} + + is-arrayish@0.3.4: {} + is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -4479,6 +10345,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.2: dependencies: call-bound: 1.0.4 @@ -4545,6 +10413,26 @@ snapshots: isexe@2.0.0: {} + isomorphic-ws@4.0.1(ws@7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + ws: 7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6) + + isows@1.0.7(ws@8.18.2(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + ws: 8.18.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) + + isows@1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + + isows@1.0.7(ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + + isows@1.0.7(ws@8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)): + dependencies: + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -4554,6 +10442,24 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 + jayson@4.3.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + json-stringify-safe: 5.0.1 + stream-json: 1.9.1 + uuid: 8.3.2 + ws: 7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + js-tokens@4.0.0: {} js-yaml@4.3.2: @@ -4564,12 +10470,16 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-safe@5.0.1: {} + json5@1.0.2: dependencies: minimist: 1.2.8 @@ -4583,10 +10493,14 @@ snapshots: object.assign: 4.1.7 object.values: 1.2.1 + jwt-decode@4.0.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 + keyvaluestorage-interface@1.0.0: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -4647,16 +10561,52 @@ snapshots: lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 + lines-and-columns@1.2.4: {} + + lit-element@4.2.2: + dependencies: + '@lit-labs/ssr-dom-shim': 1.6.0 + '@lit/reactive-element': 2.1.2 + lit-html: 3.3.3 + + lit-html@3.3.3: + dependencies: + '@types/trusted-types': 2.0.7 + + lit@3.3.0: + dependencies: + '@lit/reactive-element': 2.1.2 + lit-element: 4.2.2 + lit-html: 3.3.3 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash-es@4.18.1: {} + + lodash.clonedeep@4.5.0: {} + + lodash.isequal@4.5.0: {} + lodash.merge@4.6.2: {} + lodash@4.18.1: {} + + long@5.3.2: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lowercase-keys@2.0.0: {} + + lru-cache@11.5.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -4669,6 +10619,8 @@ snapshots: merge2@1.4.1: {} + micro-ftch@0.3.1: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 @@ -4687,6 +10639,10 @@ snapshots: dependencies: mime-db: 1.52.0 + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + minimatch@10.2.6: dependencies: brace-expansion: 5.0.12 @@ -4699,6 +10655,10 @@ snapshots: ms@2.1.3: {} + multiformats@9.9.0: {} + + nanoclone@0.2.1: {} + nanoid@3.3.20: {} napi-postinstall@0.3.4: {} @@ -4758,12 +10718,23 @@ snapshots: object.entries: 1.1.9 semver: 6.3.1 + node-fetch-native@1.6.7: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-gyp-build@4.8.4: + optional: true + + node-mock-http@1.0.5: {} + node-releases@2.0.57: {} + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -4801,14 +10772,34 @@ snapshots: object.values@1.2.1: dependencies: - call-bind: 1.0.9 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.2 + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + obug@2.2.1: {} + + ocache@0.3.0: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + on-exit-leak-free@0.2.0: {} + + on-exit-leak-free@2.1.2: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 - obug@2.2.1: {} + openapi-fetch@0.13.8: + dependencies: + openapi-typescript-helpers: 0.0.15 - ocache@0.3.0: {} + openapi-typescript-helpers@0.0.15: {} optionator@0.9.4: dependencies: @@ -4826,24 +10817,136 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + ox@0.12.4(typescript@6.0.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + ox@0.14.56(typescript@6.0.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + ox@0.14.56(typescript@6.0.3)(zod@4.6.7): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@4.6.7) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + ox@0.6.9(typescript@6.0.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.3.0(typescript@6.0.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + ox@0.7.1(typescript@6.0.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.2 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.0.8(typescript@6.0.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + ox@0.9.3(typescript@6.0.3)(zod@3.22.4): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.3.0(typescript@6.0.3)(zod@3.22.4) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - zod + + p-cancelable@2.1.1: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + + pako@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + path-exists@4.0.0: {} path-key@3.1.1: {} path-parse@1.0.7: {} + path-type@4.0.0: {} + pathe@2.0.3: {} pg-cloudflare@1.4.1: @@ -4887,8 +10990,55 @@ snapshots: picomatch@4.0.7: {} + pino-abstract-transport@0.5.0: + dependencies: + duplexify: 4.1.3 + split2: 4.2.0 + + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@4.0.0: {} + + pino-std-serializers@7.1.0: {} + + pino@10.0.0: + dependencies: + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.1.1 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + slow-redact: 0.3.2 + sonic-boom: 4.2.1 + thread-stream: 3.2.0 + + pino@7.11.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 0.2.0 + pino-abstract-transport: 0.5.0 + pino-std-serializers: 4.0.0 + process-warning: 1.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.1.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 2.8.0 + thread-stream: 0.15.2 + playwright-core@1.62.1: {} + pngjs@5.0.0: {} + + pony-cause@2.1.11: {} + + poseidon-lite@0.2.1: {} + possible-typed-array-names@1.1.0: {} postcss@8.5.23: @@ -4913,27 +11063,150 @@ snapshots: dependencies: xtend: 4.0.2 + preact@10.24.2: {} + + preact@10.29.8: {} + prelude-ls@1.2.1: {} + process-warning@1.0.0: {} + + process-warning@5.1.1: {} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + property-expr@2.0.6: {} + + protobufjs@7.6.6: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 24.19.0 + long: 5.3.2 + + proxy-compare@3.0.1: {} + + proxy-from-env@2.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@1.3.2: {} + punycode@2.3.1: {} + qr-code-styling@1.9.2: + dependencies: + qrcode-generator: 1.5.2 + + qrcode-generator@1.5.2: {} + + qrcode@1.5.1: + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + qrcode@1.5.3: + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + query-string@7.1.3: + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + + querystring@0.2.0: {} + queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + + quick-lru@5.1.1: {} + + radix3@1.1.2: {} + + react-clientside-effect@1.2.8(react@19.3.0): + dependencies: + '@babel/runtime': 7.29.10 + react: 19.3.0 + react-dom@19.3.0(react@19.3.0): dependencies: react: 19.3.0 scheduler: 0.28.0 + react-fast-compare@2.0.4: {} + + react-focus-lock@2.13.6(@types/react@19.3.0)(react@19.3.0): + dependencies: + '@babel/runtime': 7.29.10 + focus-lock: 1.3.6 + prop-types: 15.8.1 + react: 19.3.0 + react-clientside-effect: 1.2.8(react@19.3.0) + use-callback-ref: 1.3.3(@types/react@19.3.0)(react@19.3.0) + use-sidecar: 1.1.3(@types/react@19.3.0)(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + + react-i18next@13.5.0(i18next@23.4.6)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + '@babel/runtime': 7.29.10 + html-parse-stringify: 3.1.0 + i18next: 23.4.6 + react: 19.3.0 + optionalDependencies: + react-dom: 19.3.0(react@19.3.0) + + react-international-phone@4.5.0(react@19.3.0): + dependencies: + react: 19.3.0 + react-is@16.13.1: {} + react-transition-group@4.4.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + '@babel/runtime': 7.29.10 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react@19.3.0: {} + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@5.1.1: {} + + real-require@0.1.0: {} + + real-require@0.2.0: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.9 @@ -4954,10 +11227,23 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + resolve-alpn@1.2.1: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} + resolve@1.22.13: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.17.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + resolve@2.0.0-next.7: dependencies: es-errors: 1.3.0 @@ -4967,6 +11253,10 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + reusify@1.1.0: {} rolldown@1.2.13: @@ -4994,6 +11284,19 @@ snapshots: rou3@1.0.0: {} + rpc-websockets@9.3.9: + dependencies: + '@swc/helpers': 0.5.23 + '@types/uuid': 10.0.0 + '@types/ws': 8.18.2 + buffer: 6.0.3 + eventemitter3: 5.0.1 + uuid: 14.0.3 + ws: 8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -5006,6 +11309,8 @@ snapshots: has-symbols: 1.1.0 isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -5017,12 +11322,18 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safe-stable-stringify@2.5.0: {} + scheduler@0.28.0: {} semver@6.3.1: {} + semver@7.7.2: {} + semver@7.8.5: {} + set-blocking@2.0.0: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5045,6 +11356,40 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 + sha256-uint8array@0.10.7: {} + + sharp@0.35.0: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.0 + '@img/sharp-darwin-x64': 0.35.0 + '@img/sharp-freebsd-wasm32': 0.35.0 + '@img/sharp-libvips-darwin-arm64': 1.3.0 + '@img/sharp-libvips-darwin-x64': 1.3.0 + '@img/sharp-libvips-linux-arm': 1.3.0 + '@img/sharp-libvips-linux-arm64': 1.3.0 + '@img/sharp-libvips-linux-ppc64': 1.3.0 + '@img/sharp-libvips-linux-riscv64': 1.3.0 + '@img/sharp-libvips-linux-s390x': 1.3.0 + '@img/sharp-libvips-linux-x64': 1.3.0 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.0 + '@img/sharp-libvips-linuxmusl-x64': 1.3.0 + '@img/sharp-linux-arm': 0.35.0 + '@img/sharp-linux-arm64': 0.35.0 + '@img/sharp-linux-ppc64': 0.35.0 + '@img/sharp-linux-riscv64': 0.35.0 + '@img/sharp-linux-s390x': 0.35.0 + '@img/sharp-linux-x64': 0.35.0 + '@img/sharp-linuxmusl-arm64': 0.35.0 + '@img/sharp-linuxmusl-x64': 0.35.0 + '@img/sharp-webcontainers-wasm32': 0.35.0 + '@img/sharp-win32-arm64': 0.35.0 + '@img/sharp-win32-ia32': 0.35.0 + '@img/sharp-win32-x64': 0.35.0 + sharp@0.35.5(@types/node@24.19.0): dependencies: '@img/colour': 1.1.0 @@ -5115,8 +11460,26 @@ snapshots: siginfo@2.0.0: {} + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + slow-redact@0.3.2: {} + + sonic-boom@2.8.0: + dependencies: + atomic-sleep: 1.0.0 + + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.2: {} + source-map@0.5.7: {} + + split-on-first@1.1.0: {} + split2@4.2.0: {} srvx@1.0.5: {} @@ -5132,6 +11495,22 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 + stream-chain@2.2.5: {} + + stream-json@1.9.1: + dependencies: + stream-chain: 2.2.5 + + stream-shift@1.0.3: {} + + strict-uri-encode@2.0.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string.prototype.includes@2.0.1: dependencies: call-bind: 1.0.9 @@ -5183,6 +11562,14 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.2 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -5194,12 +11581,30 @@ snapshots: optionalDependencies: '@babel/core': 7.29.7 + stylis@4.2.0: {} + + superstruct@2.0.2: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} + text-encoding-utf-8@1.0.2: {} + + text-encoding@0.7.0: {} + + thread-stream@0.15.2: + dependencies: + real-require: 0.1.0 + + thread-stream@3.2.0: + dependencies: + real-require: 0.2.0 + + tiny-warning@1.0.3: {} + tinybench@2.9.0: {} tinyexec@1.3.1: {} @@ -5211,10 +11616,20 @@ snapshots: tinyrainbow@3.2.0: {} + tldts-core@6.1.86: {} + + tldts@6.0.16: + dependencies: + tldts-core: 6.1.86 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + to-utf8@0.0.1: {} + + toposort@2.0.2: {} + tr46@0.0.3: {} ts-api-utils@2.5.0(typescript@6.0.3): @@ -5228,8 +11643,14 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tslib@1.14.1: {} + + tslib@2.4.1: {} + tslib@2.8.1: {} + tweetnacl@1.0.3: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -5279,6 +11700,14 @@ snapshots: typescript@6.0.3: {} + ufo@1.6.4: {} + + uint8arrays@3.1.1: + dependencies: + multiformats: 9.9.0 + + ulid@2.4.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -5286,6 +11715,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + uncrypto@0.1.3: {} + undici-types@5.26.5: {} undici-types@7.24.6: {} @@ -5325,6 +11756,20 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + unstorage@1.17.6(db0@0.4.1)(idb-keyval@6.3.0): + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.11 + lru-cache: 11.5.3 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.4 + optionalDependencies: + db0: 0.4.1 + idb-keyval: 6.3.0 + unstorage@2.0.0-alpha.11: {} update-browserslist-db@1.3.4(browserslist@4.29.3): @@ -5337,6 +11782,130 @@ snapshots: dependencies: punycode: 2.3.1 + url@0.11.0: + dependencies: + punycode: 1.3.2 + querystring: 0.2.0 + + use-callback-ref@1.3.3(@types/react@19.3.0)(react@19.3.0): + dependencies: + react: 19.3.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + use-sidecar@1.1.3(@types/react@19.3.0)(react@19.3.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.3.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.3.0 + + utf-8-validate@6.0.6: + dependencies: + node-gyp-build: 4.8.4 + optional: true + + util-deprecate@1.0.2: {} + + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.24 + + uuid@11.1.0: {} + + uuid@11.1.1: {} + + uuid@14.0.3: {} + + uuid@8.3.2: {} + + uuid@9.0.1: {} + + valibot@1.5.0(typescript@6.0.3): + optionalDependencies: + typescript: 6.0.3 + + valtio@2.1.7(@types/react@19.3.0)(react@19.3.0): + dependencies: + proxy-compare: 3.0.1 + optionalDependencies: + '@types/react': 19.3.0 + react: 19.3.0 + + viem@2.31.0(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.0.8(typescript@6.0.3)(zod@3.22.4) + isows: 1.0.7(ws@8.18.2(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ox: 0.7.1(typescript@6.0.3)(zod@3.22.4) + ws: 8.18.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.46.3(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@3.22.4) + isows: 1.0.7(ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ox: 0.12.4(typescript@6.0.3)(zod@3.22.4) + ws: 8.18.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@3.22.4): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@3.22.4) + isows: 1.0.7(ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ox: 0.14.56(typescript@6.0.3)(zod@3.22.4) + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.57.7(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@6.0.6)(zod@4.6.7): + dependencies: + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@6.0.3)(zod@4.6.7) + isows: 1.0.7(ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ox: 0.14.56(typescript@6.0.3)(zod@4.6.7) + ws: 8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + vite@8.3.3(@types/node@24.19.0)(esbuild@0.28.2): dependencies: lightningcss: 1.33.0 @@ -5377,6 +11946,8 @@ snapshots: transitivePeerDependencies: - msw + void-elements@3.1.0: {} + web-streams-polyfill@4.0.0-beta.3: {} webidl-conversions@3.0.1: {} @@ -5417,6 +11988,8 @@ snapshots: is-weakmap: 2.0.2 is-weakset: 2.0.4 + which-module@2.0.1: {} + which-typed-array@1.1.24: dependencies: available-typed-arrays: 1.0.7 @@ -5438,14 +12011,87 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@7.5.13(bufferutil@4.1.0)(utf-8-validate@6.0.6): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + + ws@8.18.2(bufferutil@4.1.0)(utf-8-validate@6.0.6): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + + ws@8.18.3(bufferutil@4.1.0)(utf-8-validate@6.0.6): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + + ws@8.21.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + + ws@8.22.0(bufferutil@4.1.0)(utf-8-validate@6.0.6): + optionalDependencies: + bufferutil: 4.1.0 + utf-8-validate: 6.0.6 + xtend@4.0.2: {} + y18n@4.0.3: {} + yallist@3.1.1: {} + yaml@1.10.3: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + yocto-queue@0.1.0: {} + yup@0.32.11: + dependencies: + '@babel/runtime': 7.29.10 + '@types/lodash': 4.17.27 + lodash: 4.18.1 + lodash-es: 4.18.1 + nanoclone: 0.2.1 + property-expr: 2.0.6 + toposort: 2.0.2 + zod-validation-error@4.0.2(zod@4.6.7): dependencies: zod: 4.6.7 + zod@3.22.4: {} + zod@4.6.7: {} + + zustand@5.0.3(@types/react@19.3.0)(react@19.3.0): + optionalDependencies: + '@types/react': 19.3.0 + react: 19.3.0 diff --git a/proxy.ts b/proxy.ts new file mode 100644 index 0000000..309492c --- /dev/null +++ b/proxy.ts @@ -0,0 +1,17 @@ +import { routeAuth } from "eve/channels/auth"; +import { NextResponse } from "next/server"; +import { operatorAuth } from "./server/operator-auth"; + +// No other site may frame these pages, so a hostile page cannot trick the operator into a click. +const FRAME_HEADERS = { "Content-Security-Policy": "frame-ancestors 'none'", "X-Frame-Options": "DENY" }; + +// The Crossmint setup page is for the operator only. Asking here lets the browser show its HTTP +// Basic prompt; the page and every action check again. +export async function proxy(request: Request) { + const auth = await routeAuth(request, [operatorAuth]); + const response = auth instanceof Response ? auth : NextResponse.next(); + for (const [name, value] of Object.entries(FRAME_HEADERS)) response.headers.set(name, value); + return response; +} + +export const config = { matcher: ["/crossmint/:path*"] }; diff --git a/scripts/crossmint-operator-jwt.mjs b/scripts/crossmint-operator-jwt.mjs new file mode 100644 index 0000000..6dbc569 --- /dev/null +++ b/scripts/crossmint-operator-jwt.mjs @@ -0,0 +1,15 @@ +import { operatorJwt, parseRsaPrivateKey, JWT_TTL_SECONDS } from "../server/crossmint/operator-jwt.ts"; + +// Prints a ten-minute operator JWT for Crossmint Agent Cards, signed with CROSSMINT_JWT_PRIVATE_KEY. +// Use it to sign in to a card setup app, or to call the order intent API by hand. Treat it like a +// password until it expires: it can create order intents and mint cards for the operator. +// Usage: pnpm crossmint:operator-jwt +const projectId = process.env.CROSSMINT_PROJECT_ID?.trim(); +const userId = process.env.CROSSMINT_USER_ID?.trim(); +const configured = process.env.CROSSMINT_JWT_PRIVATE_KEY?.trim(); +if (!projectId || !userId || !configured) throw new Error("Set CROSSMINT_PROJECT_ID, CROSSMINT_USER_ID, and CROSSMINT_JWT_PRIVATE_KEY."); +const privateKey = parseRsaPrivateKey(configured); +if (!privateKey) throw new Error("CROSSMINT_JWT_PRIVATE_KEY must be a base64-encoded PEM RSA private key of at least 2048 bits."); + +console.log(operatorJwt({ projectId, userId, privateKey })); +console.error(`Valid for ${JWT_TTL_SECONDS / 60} minutes.`); diff --git a/scripts/demo-crossmint.mjs b/scripts/demo-crossmint.mjs index 818bdc2..7589d94 100644 --- a/scripts/demo-crossmint.mjs +++ b/scripts/demo-crossmint.mjs @@ -55,14 +55,41 @@ const { runId } = await call("/agent-checkouts", { console.log(`run ${runId}`); console.log(`console https://www.crossmint.com/console (Agent Checkouts, search for the run id)`); +// The same fixed stage phrases Bell reports, from the activity kinds in the run's messages. +const STAGES = [ + [["apply_payment"], "Applying the payment"], + [["apply_buyer_information"], "Filling in the delivery details"], + [["create_checkout"], "Starting the store's checkout"], + [["call_webmcp_tool"], "Using the store's checkout tools"], + [["lookup_product", "search_catalog"], "Finding the product"], + [["navigate", "read_playbook"], "Opening the store"], +]; +async function stage() { + const { data = [] } = await call(`/agent-checkouts/${encodeURIComponent(runId)}/messages?limit=100`); + const activities = data + .filter((message) => message.role === "assistant") + .sort((a, b) => Date.parse(a.createdAt) - Date.parse(b.createdAt)) + .flatMap((message) => message.parts ?? []) + .filter((part) => part.type === "activity"); + if (!activities.length) return ""; + const kinds = new Set((activities.at(-1).operations ?? []).map((operation) => operation.kind)); + return STAGES.find(([candidates]) => candidates.some((kind) => kinds.has(kind)))?.[1] ?? "Working through the store's checkout"; +} + const deadline = Date.now() + 10 * 60_000; let last = ""; +let lastStage = ""; let run; do { run = await call(`/agent-checkouts/${encodeURIComponent(runId)}`); const line = `${run.status} (revision ${run.revision})${describe(run)}`; if (line !== last) console.log(`${new Date().toISOString().slice(11, 19)} ${line}`); last = line; + if (run.status === "running") { + const current = await stage().catch(() => lastStage); + if (current && current !== lastStage) console.log(`${new Date().toISOString().slice(11, 19)} ${current}`); + lastStage = current; + } if (run.status === "awaiting_input" || ["succeeded", "failed", "cancelled", "blocked"].includes(run.status)) break; await new Promise((resolve) => setTimeout(resolve, 2_000)); } while (Date.now() < deadline); diff --git a/server/crossmint/client.ts b/server/crossmint/client.ts index fdb84c4..6cf5c63 100644 --- a/server/crossmint/client.ts +++ b/server/crossmint/client.ts @@ -216,6 +216,17 @@ export interface CheckoutSnapshot { purchase?: { kind: string; receipt?: { total?: MaxCost; merchantOrderId?: string } }; } | null; failureReason: string | null; + /** While the run works, what Crossmint is doing. Only polls that ask for progress fill it. */ + progress?: CheckoutProgress; +} + +/** + * What a running checkout is doing, for a short update to the person: a fixed phrase chosen from + * Crossmint's activity kinds. Crossmint's own progress text is never passed on. It can name the + * buyer while the profile is applied, and it is written while reading merchant pages. + */ +export interface CheckoutProgress { + stage: string; } export interface CrossmintClientOptions { @@ -423,12 +434,111 @@ export async function cancelCheckout(runId: string, options: CrossmintClientOpti await request(`/agent-checkouts/${encodeURIComponent(runId)}/cancel`, { method: "POST" }, options); } +/** + * Saved name, contact, and shipping address that checkouts use instead of asking. It holds no + * payment data. Only the operator setup page reads or writes it; the model never sees it. + */ +export interface BuyerProfile { + id: string; + label?: string; + name?: { first: string; last: string }; + contact?: { email?: string; phone?: string }; + shipping: { addressLines: string[]; locality: string; countryCode: string; administrativeAreaCode?: string | null; postalCode?: string | null }; +} + +export type NewBuyerProfile = Omit; + +function projectBuyerProfile(raw: unknown): BuyerProfile { + const body = record(raw); + const shipping = record(body.shipping); + const id = string(body.id); + const lines = Array.isArray(shipping.addressLines) ? shipping.addressLines.filter((line): line is string => typeof line === "string") : []; + if (!id || !lines.length || !string(shipping.locality) || !string(shipping.countryCode)) throw new CrossmintRequestError("invalid_response"); + const name = record(body.name); + const contact = record(body.contact); + return { + id, + ...present({ label: string(body.label) }), + ...(string(name.first) && string(name.last) ? { name: { first: string(name.first)!, last: string(name.last)! } } : {}), + ...(string(contact.email) || string(contact.phone) ? { contact: present({ email: string(contact.email), phone: string(contact.phone) }) } : {}), + shipping: { + addressLines: lines, + locality: string(shipping.locality)!, + countryCode: string(shipping.countryCode)!, + administrativeAreaCode: string(shipping.administrativeAreaCode) ?? null, + postalCode: string(shipping.postalCode) ?? null, + }, + }; +} + +export async function getBuyerProfile(id: string, options: CrossmintClientOptions = {}): Promise { + return projectBuyerProfile(await request(`/agent-checkouts/buyer-profiles/${encodeURIComponent(id)}`, { method: "GET" }, options)); +} + +export async function createBuyerProfile(profile: NewBuyerProfile, options: CrossmintClientOptions = {}): Promise { + return projectBuyerProfile(await request("/agent-checkouts/buyer-profiles", { method: "POST", body: profile }, options)); +} + +/** Activity kinds, most telling first, and the phrase the person sees for them. */ +const STAGES: ReadonlyArray<[readonly string[], string]> = [ + [["apply_payment"], "Applying the payment"], + [["apply_buyer_information"], "Filling in the delivery details"], + [["create_checkout"], "Starting the store's checkout"], + [["call_webmcp_tool"], "Using the store's checkout tools"], + [["lookup_product", "search_catalog"], "Finding the product"], + [["navigate", "read_playbook"], "Opening the store"], +]; +const DEFAULT_STAGE = "Working through the store's checkout"; + +/** The latest stage in a run's messages, in any order Crossmint returns them. */ +export function projectProgress(messages: unknown[]): CheckoutProgress | undefined { + const latest = new Map(); + for (const raw of messages) { + const message = record(raw); + const id = string(message.id); + if (!id) continue; + const previous = latest.get(id); + if (!previous || Number(message.revision) >= Number(previous.revision)) latest.set(id, message); + } + const ordered = [...latest.values()].sort((a, b) => Date.parse(String(a.createdAt)) - Date.parse(String(b.createdAt))); + let stage: string | undefined; + for (const message of ordered) { + if (message.role !== "assistant" || !Array.isArray(message.parts)) continue; + for (const part of message.parts.map(record)) { + if (part.type !== "activity" || !Array.isArray(part.operations)) continue; + const kinds = new Set(part.operations.map((operation) => string(record(operation).kind)).filter(Boolean)); + stage = STAGES.find(([candidates]) => candidates.some((kind) => kinds.has(kind)))?.[1] ?? DEFAULT_STAGE; + } + } + return stage ? { stage } : undefined; +} + +/** Read the run's messages, at most five pages, and project its latest progress. */ +export async function getCheckoutProgress(runId: string, options: CrossmintClientOptions = {}): Promise { + const messages: unknown[] = []; + let cursor: string | undefined; + for (let page = 0; page < 5; page++) { + const query = `limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ""}`; + const body = record(await request(`/agent-checkouts/${encodeURIComponent(runId)}/messages?${query}`, { method: "GET" }, options)); + if (Array.isArray(body.data)) messages.push(...body.data); + cursor = string(body.nextCursor); + if (!cursor) break; + } + return projectProgress(messages); +} + export interface WaitOptions extends CrossmintClientOptions { /** Stop waiting after this many milliseconds and return the latest snapshot. */ timeoutMs?: number; intervalMs?: number; /** A request id already answered. Crossmint can keep showing it briefly. */ skipRequestId?: string; + /** + * Report progress while the run works: return early once the stage differs from this one (null + * means any stage), but not before `minProgressMs`, so the person gets one update per step. + */ + progressSince?: string | null; + minProgressMs?: number; } function sleep(ms: number, signal?: AbortSignal): Promise { @@ -448,13 +558,31 @@ function sleep(ms: number, signal?: AbortSignal): Promise { /** Poll until the checkout needs input or ends, or until the timeout. Always returns a snapshot. */ export async function waitForCheckout(runId: string, options: WaitOptions = {}): Promise { const intervalMs = options.intervalMs ?? 2_000; - const deadline = Date.now() + (options.timeoutMs ?? 90_000); + const started = Date.now(); + const deadline = started + (options.timeoutMs ?? 90_000); + const watchProgress = options.progressSince !== undefined; let snapshot = await getCheckout(runId, options); + let progress: CheckoutProgress | undefined; + let progressReadAt = 0; for (;;) { const settled = TERMINAL_STATUSES.has(snapshot.status) || (snapshot.status === "awaiting_input" && snapshot.requiredAction !== null && snapshot.requiredAction.requestId !== options.skipRequestId); - if (settled || Date.now() >= deadline) return snapshot; + if (settled) return snapshot; + const working = snapshot.status === "running" || snapshot.status === "queued"; + if (watchProgress && working && Date.now() - progressReadAt >= intervalMs * 3) { + progressReadAt = Date.now(); + // Progress is a courtesy: it never outlasts the wait, and only a cancellation stops it. + const remaining = AbortSignal.timeout(Math.max(1, deadline - Date.now())); + const signal = options.signal ? AbortSignal.any([options.signal, remaining]) : remaining; + progress = await getCheckoutProgress(runId, { ...options, signal }).catch((error: unknown) => { + if (options.signal?.aborted) throw error; + return progress; + }); + const changed = progress !== undefined && progress.stage !== options.progressSince; + if (changed && Date.now() - started >= (options.minProgressMs ?? 0)) return { ...snapshot, progress }; + } + if (Date.now() >= deadline) return watchProgress && working && progress ? { ...snapshot, progress } : snapshot; options.signal?.throwIfAborted(); await sleep(Math.min(intervalMs, Math.max(0, deadline - Date.now())), options.signal); const next = await getCheckout(runId, options); diff --git a/server/crossmint/operator-jwt.ts b/server/crossmint/operator-jwt.ts new file mode 100644 index 0000000..24773aa --- /dev/null +++ b/server/crossmint/operator-jwt.ts @@ -0,0 +1,57 @@ +import { createHash, createPrivateKey, createPublicKey, sign, type KeyObject } from "node:crypto"; + +/** + * The operator's JWT for Crossmint Agent Cards. + * + * Crossmint accepts order intent calls only with the user's JWT. Bell serves one trusted operator, + * so it issues that JWT itself as the project's custom JWT provider: RS256, `iss` the Crossmint + * project id, `sub` the operator's CROSSMINT_USER_ID, `aud` crossmint.com, ten minutes. Crossmint + * checks the signature against the JWKS Bell serves at /api/crossmint/jwks. + * Guide: https://docs.crossmint.com/introduction/platform/api-keys/custom-jwt-auth-guide + * + * This file uses only erasable TypeScript, so scripts/crossmint-operator-jwt.mjs can load it. + */ + +export const JWT_TTL_SECONDS = 600; +const AUDIENCE = "crossmint.com"; + +export interface OperatorJwtConfig { + projectId: string; + userId: string; + privateKey: KeyObject; +} + +/** Read CROSSMINT_JWT_PRIVATE_KEY: a PEM RSA private key, base64 encoded as in Crossmint's guide, or plain. */ +export function parseRsaPrivateKey(value: string): KeyObject | undefined { + const text = value.includes("-----BEGIN") ? value : Buffer.from(value, "base64").toString("utf8"); + try { + const key = createPrivateKey(text); + const bits = key.asymmetricKeyDetails?.modulusLength ?? 0; + return key.asymmetricKeyType === "rsa" && bits >= 2048 ? key : undefined; + } catch { + return undefined; + } +} + +function publicJwk(privateKey: KeyObject): { kty: "RSA"; n: string; e: string; kid: string } { + const { n, e } = createPublicKey(privateKey).export({ format: "jwk" }); + if (typeof n !== "string" || typeof e !== "string") throw new Error("The operator key is not an RSA key."); + // RFC 7638 thumbprint: the required members in lexicographic order. + const kid = createHash("sha256").update(JSON.stringify({ e, kty: "RSA", n })).digest("base64url"); + return { kty: "RSA", n, e, kid }; +} + +/** The public half of the operator key, as the JWKS Crossmint fetches. */ +export function operatorJwks(privateKey: KeyObject) { + return { keys: [{ ...publicJwk(privateKey), alg: "RS256", use: "sig" }] }; +} + +/** Sign a short-lived operator JWT. It stays on the server, except on the operator-only setup page. */ +export function operatorJwt(config: OperatorJwtConfig, now = Date.now()): string { + const iat = Math.floor(now / 1000); + const encode = (value: object) => Buffer.from(JSON.stringify(value)).toString("base64url"); + const header = encode({ alg: "RS256", typ: "JWT", kid: publicJwk(config.privateKey).kid }); + const payload = encode({ iss: config.projectId, sub: config.userId, aud: AUDIENCE, iat, exp: iat + JWT_TTL_SECONDS }); + const signature = sign("sha256", Buffer.from(`${header}.${payload}`), config.privateKey).toString("base64url"); + return `${header}.${payload}.${signature}`; +} diff --git a/server/crossmint/operator.ts b/server/crossmint/operator.ts new file mode 100644 index 0000000..ba0dd31 --- /dev/null +++ b/server/crossmint/operator.ts @@ -0,0 +1,247 @@ +import type { KeyObject } from "node:crypto"; +import { z } from "zod"; +import { crossmintConfig, CrossmintRequestError, CrossmintSetupError, type CrossmintConfig } from "./client"; +import { operatorJwt, parseRsaPrivateKey } from "./operator-jwt"; + +/** + * Calls Crossmint makes only for a signed-in user: saving and registering cards, and approving, + * listing, and cancelling order intents. They take a client key with the user's JWT, never a server + * key. Bell serves one operator, so it signs that JWT itself (operator-jwt.ts) and sends Bell's + * origin, which must be an allowed origin of the client key. + * + * These calls serve the operator setup page. None of their results reach the model. + * API reference: https://docs.crossmint.com/api-reference/agentic-commerce/order-intents/list-order-intents + */ + +export interface OperatorConfig extends CrossmintConfig { + /** Client key (ck_). */ + clientApiKey: string; + /** Crossmint project id, the `iss` of the operator JWT. */ + projectId: string; + privateKey: KeyObject; + /** Bell's origin, sent with every call. */ + origin: string; +} + +export const OPERATOR_SETTINGS = ["CROSSMINT_CLIENT_API_KEY", "CROSSMINT_PROJECT_ID", "CROSSMINT_JWT_PRIVATE_KEY"] as const; + +export function isOperatorConfigured(env: Record = process.env): boolean { + return OPERATOR_SETTINGS.every((name) => Boolean(env[name]?.trim())); +} + +export function operatorConfig(env: Record = process.env): OperatorConfig { + const base = crossmintConfig(env); + const required = (name: string) => { + const value = env[name]?.trim(); + if (!value) throw new CrossmintSetupError("missing_configuration", name); + return value; + }; + const invalid = (name: string) => new CrossmintSetupError("invalid_configuration", name); + + const clientApiKey = required("CROSSMINT_CLIENT_API_KEY"); + const production = new URL(base.baseUrl).hostname === "www.crossmint.com"; + if (!clientApiKey.startsWith("ck_") || clientApiKey.startsWith("ck_production_") !== production) throw invalid("CROSSMINT_CLIENT_API_KEY"); + const projectId = required("CROSSMINT_PROJECT_ID"); + const privateKey = parseRsaPrivateKey(required("CROSSMINT_JWT_PRIVATE_KEY")); + if (!privateKey) throw invalid("CROSSMINT_JWT_PRIVATE_KEY"); + + const publicUrl = URL.parse(required("BELL_PUBLIC_URL")); + const loopback = publicUrl?.protocol === "http:" && /^(?:localhost|127\.0\.0\.1|\[::1\])$/.test(publicUrl.hostname); + if (!publicUrl || publicUrl.username || publicUrl.password || (publicUrl.protocol !== "https:" && !loopback)) throw invalid("BELL_PUBLIC_URL"); + + return { ...base, clientApiKey, projectId, privateKey, origin: publicUrl.origin }; +} + +/** + * A refused operator call. `detail` is Crossmint's own message, shown to the operator on the setup + * page because it names the fix (for example a missing consumer email). It never reaches the model. + */ +export class CrossmintOperatorError extends Error { + constructor( + readonly reason: "unauthorized" | "not_found" | "rejected", + readonly status: number, + readonly detail?: string, + ) { + super( + reason === "unauthorized" + ? "Crossmint rejected the client key, its allowed origins, or Bell's operator token." + : reason === "not_found" + ? "Crossmint found nothing with that id for this operator." + : `Crossmint refused the request (HTTP ${status}).`, + ); + this.name = "CrossmintOperatorError"; + } +} + +export interface OperatorClientOptions { + config?: OperatorConfig; + fetch?: typeof fetch; + signal?: AbortSignal; +} + +const REQUEST_TIMEOUT_MS = 20_000; + +/** One call with the client key, the operator JWT, and Bell's origin. */ +export async function operatorRequest( + path: string, + init: { method: "GET" | "POST" | "PUT" | "DELETE"; body?: unknown; idempotencyKey?: string }, + options: OperatorClientOptions = {}, +): Promise { + const config = options.config ?? operatorConfig(); + const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS); + const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout; + signal.throwIfAborted(); + try { + return await (options.fetch ?? fetch)(`${config.baseUrl}${path}`, { + method: init.method, + headers: { + "X-API-KEY": config.clientApiKey, + Authorization: `Bearer ${operatorJwt(config)}`, + Origin: config.origin, + ...(init.body !== undefined ? { "Content-Type": "application/json" } : {}), + ...(init.idempotencyKey ? { "Idempotency-Key": init.idempotencyKey } : {}), + }, + body: init.body !== undefined ? JSON.stringify(init.body) : undefined, + redirect: "error", + signal, + }); + } catch { + options.signal?.throwIfAborted(); + throw new CrossmintRequestError("transport"); + } +} + +async function json(response: Response): Promise { + if (!response.ok) { + let detail: string | undefined; + try { + const body = (await response.json()) as { message?: unknown; error?: unknown }; + const text = (value: unknown) => + typeof value === "string" ? value : Array.isArray(value) ? value.filter((item) => typeof item === "string").join("; ") : undefined; + detail = (text(body.message) || text(body.error))?.slice(0, 300) || undefined; + } catch { + detail = undefined; + } + const reason = response.status === 401 || response.status === 403 ? "unauthorized" : response.status === 404 ? "not_found" : "rejected"; + throw new CrossmintOperatorError(reason, response.status, detail); + } + if (response.status === 204) return null; + const text = await response.text().catch(() => ""); + if (!text.trim()) return null; + try { + return JSON.parse(text) as unknown; + } catch { + throw new CrossmintRequestError("invalid_response", response.status); + } +} + +const railSchema = z.object({ + rail: z.string(), + provider: z.string().optional(), + status: z.string(), + credentialFormats: z.array(z.string()).optional(), + error: z.object({ code: z.string().optional() }).nullish(), +}); + +const merchantSchema = z.object({ name: z.string().optional(), url: z.string(), countryCode: z.string().optional() }); + +const decimal = z.string().regex(/^\d+(?:\.\d+)?$/); + +export const orderIntentSchema = z.object({ + orderIntentId: z.string(), + paymentMethodId: z.string().optional(), + status: z.string(), + amount: z.object({ total: decimal.optional(), spent: decimal.optional(), available: decimal, currency: z.string() }), + merchant: merchantSchema.nullish(), + description: z.string().optional(), + expiresAt: z.string(), + rails: z.array(railSchema), + verificationConfig: z.unknown().optional(), +}); + +export type OrderIntentSummary = z.infer; + +const registrationSchema = z.object({ + paymentMethodId: z.string(), + rails: z.array(railSchema), +}); + +export type CardRegistration = z.infer; + +/** What a card-network rail needs to know about the person, sent once per saved card. */ +export interface Consumer { + email: string; + /** ISO 3166-1 alpha-2. */ + countryCode: string; + /** BCP 47, such as en-US or es-ES. */ + languageCode: string; +} + +/** The card's order-intent registration, or null when the card was never registered. */ +export async function getRegistration(paymentMethodId: string, options: OperatorClientOptions = {}): Promise { + const path = `/payment-methods/${encodeURIComponent(paymentMethodId)}/order-intent-registration`; + try { + const parsed = registrationSchema.safeParse(await json(await operatorRequest(path, { method: "GET" }, options))); + if (!parsed.success) throw new CrossmintRequestError("invalid_response"); + return parsed.data; + } catch (error) { + if (error instanceof CrossmintOperatorError && error.reason === "not_found") return null; + throw error; + } +} + +/** + * Register a saved card for order intents with the person's email, country, and language. Crossmint + * needs the email to provision card-network rails, and Bell's operator JWT carries none, so an + * empty registration is refused. Registering is idempotent and grants no spending. + */ +export async function registerCard(paymentMethodId: string, consumer: Consumer, options: OperatorClientOptions = {}): Promise { + const path = `/payment-methods/${encodeURIComponent(paymentMethodId)}/order-intent-registration`; + const body = { email: consumer.email, countryCode: consumer.countryCode.toUpperCase(), languageCode: consumer.languageCode }; + const parsed = registrationSchema.safeParse(await json(await operatorRequest(path, { method: "PUT", body }, options))); + if (!parsed.success) throw new CrossmintRequestError("invalid_response"); + return parsed.data; +} + +/** Every order intent of the operator, newest expiry first. */ +export async function listOrderIntents(options: OperatorClientOptions = {}): Promise { + const raw = await json(await operatorRequest("/order-intents", { method: "GET" }, options)); + const parsed = z.array(orderIntentSchema).safeParse(Array.isArray(raw) ? raw : (raw as { data?: unknown } | null)?.data); + if (!parsed.success) throw new CrossmintRequestError("invalid_response"); + return parsed.data.sort((a, b) => Date.parse(b.expiresAt) - Date.parse(a.expiresAt)); +} + +export interface NewOrderIntent { + paymentMethodId: string; + amount: { value: string; currency: string }; + merchant: { name: string; url: string; countryCode: string }; + description: string; + expiresAt: string; +} + +/** Approve a budget on a saved, registered card for one merchant. */ +export async function createOrderIntent( + input: NewOrderIntent, + options: OperatorClientOptions & { idempotencyKey?: string } = {}, +): Promise { + const body = { ...input, amount: { value: input.amount.value, currency: input.amount.currency.toUpperCase() } }; + const init = { method: "POST" as const, body, ...(options.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}) }; + const parsed = orderIntentSchema.safeParse(await json(await operatorRequest("/order-intents", init, options))); + if (!parsed.success) throw new CrossmintRequestError("invalid_response"); + return parsed.data; +} + +/** Cancel an order intent. Later reads show it as cancelled and nothing more can be spent. */ +export async function cancelOrderIntent(orderIntentId: string, options: OperatorClientOptions = {}): Promise { + await json(await operatorRequest(`/order-intents/${encodeURIComponent(orderIntentId)}`, { method: "DELETE" }, options)); +} + +/** Rails as the setup page shows them. Agent Checkouts can pay even when none is active. */ +export function describeRail(rail: z.infer): string { + const name = + rail.rail === "agentic-token" + ? rail.provider === "vic" ? "Visa Intelligent Commerce" : rail.provider === "agentpay" ? "Mastercard Agent Pay" : "Card network token" + : rail.rail === "encrypted-card" ? "Encrypted card" + : rail.rail === "spt" ? "Stripe shared payment token" : rail.rail; + return `${name}: ${rail.status.replaceAll("_", " ")}`; +} diff --git a/server/crossmint/payment.ts b/server/crossmint/payment.ts index bcff283..678cdfa 100644 --- a/server/crossmint/payment.ts +++ b/server/crossmint/payment.ts @@ -7,6 +7,8 @@ export interface ApprovedPayment { amount: string; currency: string; merchant: string; + /** The store name the approval dialog showed, when the model gave one. */ + merchantName?: string; } export class PaymentMismatchError extends Error { @@ -27,7 +29,7 @@ export class PaymentMismatchError extends Error { } } -function hostOf(value: string): string | undefined { +export function hostOf(value: string): string | undefined { return URL.parse(value.includes("://") ? value : `https://${value}`)?.hostname.toLowerCase(); } @@ -62,6 +64,11 @@ export function assertPaymentMatches(approved: ApprovedPayment, live: CheckoutSn if (!liveHost || liveHost !== hostOf(approved.merchant)) { throw refuse("merchant_mismatch", "The approved merchant differs from the one Crossmint is checking out at."); } + // The dialog showed this name to the person, so it must be Crossmint's name, not the model's. + const shownName = approved.merchantName?.trim().toLowerCase(); + if (shownName && shownName !== merchant.name?.trim().toLowerCase()) { + throw refuse("merchant_mismatch", "The approved store name differs from the one Crossmint is checking out at."); + } if (record.maxCost.currency !== amount.currency || compareAmounts(amount.value, record.maxCost.amount) > 0) { throw refuse("cap_exceeded", `The total exceeds the ${record.maxCost.amount} ${record.maxCost.currency} cap this checkout was started with.`); } diff --git a/server/crossmint/runs.ts b/server/crossmint/runs.ts index 2b03103..9fa18d4 100644 --- a/server/crossmint/runs.ts +++ b/server/crossmint/runs.ts @@ -13,6 +13,8 @@ export interface CheckoutRecord { maxCost: MaxCost; /** Authenticated principal that started the run, when the channel provided one. */ principalId: string | null; + /** The last progress stage reported to the person, so each update says something new. */ + lastStage?: string; } const runs = new Map>(); diff --git a/tests/crossmint-setup.test.ts b/tests/crossmint-setup.test.ts new file mode 100644 index 0000000..d8223e3 --- /dev/null +++ b/tests/crossmint-setup.test.ts @@ -0,0 +1,198 @@ +import { createPublicKey, generateKeyPairSync, verify } from "node:crypto"; +import { isValidElement, type ReactElement, type ReactNode } from "react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { config as proxyConfig, proxy } from "../proxy.js"; +import CrossmintSetupPage from "../app/crossmint/setup/page.js"; +import { approveBudget, refreshToken } from "../app/crossmint/setup/actions.js"; +import { operatorJwks, parseRsaPrivateKey } from "../server/crossmint/operator-jwt.js"; + +const incoming = vi.hoisted(() => ({ headers: new Headers() })); +vi.mock("next/headers", () => ({ headers: async () => incoming.headers })); +vi.mock("../app/crossmint/setup/setup", () => ({ default: function Setup() { return null; } })); + +const { privateKey } = generateKeyPairSync("rsa", { modulusLength: 2048 }); +const password = "a-synthetic-operator-password-of-32-bytes"; +const basic = `Basic ${Buffer.from(`operator:${password}`).toString("base64")}`; +const env = { + BELL_OPERATOR_USERNAME: "operator", + BELL_OPERATOR_PASSWORD: password, + CROSSMINT_SERVER_API_KEY: "sk_unit_test_only", + CROSSMINT_USER_ID: "operator-1", + CROSSMINT_CLIENT_API_KEY: "ck_production_unit_test_only", + CROSSMINT_PROJECT_ID: "project-1", + CROSSMINT_JWT_PRIVATE_KEY: Buffer.from(privateKey.export({ type: "pkcs8", format: "pem" })).toString("base64"), + CROSSMINT_BUYER_PROFILE_ID: "", + CROSSMINT_ORDER_INTENT_ID: "oi_in_use", + BELL_PUBLIC_URL: "https://bell.example", +}; + +const intent = (id: string, expiresAt: string, rails: unknown[] = [{ rail: "spt", provider: "stripe", status: "active" }]) => ({ + orderIntentId: id, + paymentMethodId: "pm_1", + status: "active", + amount: { total: "30.00", spent: "0.00", reserved: "0.00", available: "30.00", currency: "eur" }, + merchant: { name: "Zara", url: "https://www.zara.com", countryCode: "ES" }, + description: "Demo", + expiresAt, + rails, +}); + +function setupProps(node: ReactNode): Record | undefined { + if (Array.isArray(node)) return node.map(setupProps).find(Boolean); + if (!isValidElement<{ children?: ReactNode }>(node)) return undefined; + if (typeof node.type === "function" && node.type.name === "Setup") return (node as ReactElement>).props; + return setupProps(node.props.children); +} + +beforeEach(() => { + for (const [name, value] of Object.entries(env)) vi.stubEnv(name, value); + incoming.headers = new Headers({ host: "bell.example", "x-forwarded-proto": "https" }); +}); +afterEach(() => { + vi.unstubAllEnvs(); + vi.unstubAllGlobals(); +}); + +describe("Crossmint setup access", () => { + it("covers only the Crossmint pages", () => { + expect(proxyConfig.matcher).toEqual(["/crossmint/:path*"]); + }); + + it("asks for the operator's credentials and refuses cross-origin writes", async () => { + const challenge = await proxy(new Request("https://bell.example/crossmint/setup")); + expect(challenge.status).toBe(401); + expect(challenge.headers.get("www-authenticate")).toContain('Basic realm="Bell"'); + const allowed = await proxy(new Request("https://bell.example/crossmint/setup", { headers: { authorization: basic } })); + expect(allowed.headers.get("x-middleware-next")).toBe("1"); + for (const response of [challenge, allowed]) { + expect(response.headers.get("content-security-policy")).toBe("frame-ancestors 'none'"); + expect(response.headers.get("x-frame-options")).toBe("DENY"); + } + const crossOrigin = await proxy(new Request("https://bell.example/crossmint/setup", { method: "POST", headers: { authorization: basic, origin: "https://evil.example" } })); + expect(crossOrigin.status).toBe(403); + }); + + it("checks again in the page and signs nothing for an unauthenticated request", async () => { + const page = await CrossmintSetupPage(); + expect(setupProps(page)).toBeUndefined(); + expect(JSON.stringify(page)).not.toContain("ck_production_unit_test_only"); + }); + + it("refuses actions without the operator's credentials or from another origin, before calling Crossmint", async () => { + const fetcher = vi.fn(); + vi.stubGlobal("fetch", fetcher); + await expect(approveBudget({} as never)).rejects.toThrow("Sign in as the Bell operator"); + incoming.headers.set("authorization", basic); + incoming.headers.set("origin", "https://evil.example"); + await expect(refreshToken()).rejects.toThrow(); + expect(fetcher).not.toHaveBeenCalled(); + }); +}); + +describe("Crossmint setup page", () => { + it("lists budgets, marks the one in use, and gives the browser only the client key", async () => { + incoming.headers.set("authorization", basic); + const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + expect(String(url)).toBe("https://www.crossmint.com/api/unstable/order-intents"); + expect(init?.headers).toMatchObject({ "X-API-KEY": "ck_production_unit_test_only", Origin: "https://bell.example" }); + return Response.json([intent("oi_old", "2026-11-03T00:00:00.000Z"), intent("oi_in_use", "2026-11-08T00:00:00.000Z")]); + }); + vi.stubGlobal("fetch", fetcher); + const props = setupProps(await CrossmintSetupPage())!; + expect(props.checks).toMatchObject({ server: { state: "ok" }, operator: { state: "ok" }, token: { state: "ok" } }); + const budgets = props.budgets as { id: string; inUse: boolean; currency: string; merchantHost: string; rails: string[] }[]; + expect(budgets.map((budget) => [budget.id, budget.inUse])).toEqual([["oi_in_use", true], ["oi_old", false]]); + expect(budgets[0]).toMatchObject({ currency: "EUR", merchantHost: "www.zara.com", rails: ["Stripe shared payment token: active"] }); + expect(props.apiKey).toBe("ck_production_unit_test_only"); + expect(props.jwt).toBeUndefined(); + expect(JSON.stringify(props)).not.toContain("sk_unit_test_only"); + }); + + it("signs a ten-minute operator token for the card form on request", async () => { + incoming.headers.set("authorization", basic); + const token = await refreshToken(); + expect(token.ok).toBe(true); + const [header, payload, signature] = (token as { jwt: string }).jwt.split("."); + const claims = JSON.parse(Buffer.from(payload, "base64url").toString()); + expect(claims).toMatchObject({ iss: "project-1", sub: "operator-1", aud: "crossmint.com" }); + expect(claims.exp - claims.iat).toBe(600); + const publicKey = createPublicKey({ key: operatorJwks(parseRsaPrivateKey(env.CROSSMINT_JWT_PRIVATE_KEY)!).keys[0], format: "jwk" }); + expect(verify("sha256", Buffer.from(`${header}.${payload}`), publicKey, Buffer.from(signature, "base64url"))).toBe(true); + }); + + it("shows where to point Crossmint, and no token, when Crossmint rejects Bell's token", async () => { + incoming.headers.set("authorization", basic); + vi.stubGlobal("fetch", vi.fn(async () => Response.json({ message: "Invalid JWT" }, { status: 401 }))); + const props = setupProps(await CrossmintSetupPage())!; + expect(props.checks).toMatchObject({ token: { state: "error", text: expect.stringContaining("rejected Bell's operator token") } }); + expect(props.jwks).toEqual({ url: "https://bell.example/api/crossmint/jwks", issuer: "project-1", loopback: false }); + expect(props.apiKey).toBeUndefined(); + expect(props.jwt).toBeUndefined(); + }); + + it("names a missing setting instead of calling Crossmint", async () => { + incoming.headers.set("authorization", basic); + vi.stubEnv("CROSSMINT_PROJECT_ID", ""); + const fetcher = vi.fn(); + vi.stubGlobal("fetch", fetcher); + const props = setupProps(await CrossmintSetupPage())!; + expect(props.checks).toMatchObject({ operator: { state: "error", text: expect.stringContaining("CROSSMINT_PROJECT_ID") } }); + expect(props.jwt).toBeUndefined(); + expect(fetcher).not.toHaveBeenCalled(); + }); +}); + +describe("Crossmint budget approval", () => { + const draft = { + paymentMethodId: "pm_1", + idempotencyKey: "2f1c8e7a-5b3d-4c2e-9a1f-0d6b7e8c9a10", + amount: "30.00", + currency: "eur", + days: 7, + description: "Demo", + merchant: { name: "Zara", url: "https://www.zara.com", countryCode: "es" }, + consumer: { email: "person@example.com", countryCode: "es", languageCode: "es-ES" }, + }; + + it("registers the card with the person's email before creating the order intent", async () => { + incoming.headers.set("authorization", basic); + const calls: { method: string; path: string; body?: unknown; key?: string }[] = []; + vi.stubGlobal("fetch", vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + const path = new URL(String(url)).pathname.replace("/api/unstable", ""); + const key = (init?.headers as Record | undefined)?.["Idempotency-Key"]; + calls.push({ method: init?.method ?? "GET", path, ...(init?.body ? { body: JSON.parse(init.body as string) } : {}), ...(key ? { key } : {}) }); + if (init?.method === "GET") return Response.json({ message: "not found" }, { status: 404 }); + if (init?.method === "PUT") return Response.json({ paymentMethodId: "pm_1", rails: [{ rail: "spt", provider: "stripe", status: "enabled" }] }); + return Response.json(intent("oi_new", "2026-11-09T00:00:00.000Z")); + })); + const result = await approveBudget(draft); + expect(result).toMatchObject({ ok: true, budget: { id: "oi_new", currency: "EUR", networkRail: false } }); + expect(calls.map((call) => `${call.method} ${call.path}`)).toEqual([ + "GET /payment-methods/pm_1/order-intent-registration", + "PUT /payment-methods/pm_1/order-intent-registration", + "POST /order-intents", + ]); + expect(calls[1].body).toEqual({ email: "person@example.com", countryCode: "ES", languageCode: "es-ES" }); + expect(calls[2].key).toBe("bell-budget-2f1c8e7a-5b3d-4c2e-9a1f-0d6b7e8c9a10"); + expect(calls[2].body).toMatchObject({ + paymentMethodId: "pm_1", + amount: { value: "30.00", currency: "EUR" }, + merchant: { name: "Zara", url: "https://www.zara.com", countryCode: "ES" }, + description: "Demo", + }); + }); + + it("returns Crossmint's reason to the operator and refuses a merchant without HTTPS before any call", async () => { + incoming.headers.set("authorization", basic); + const fetcher = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => + init?.method === "GET" + ? Response.json({ message: "not found" }, { status: 404 }) + : Response.json({ message: ["A consumer email is required to register this payment method for order intents"] }, { status: 400 }), + ); + vi.stubGlobal("fetch", fetcher); + expect(await approveBudget(draft)).toEqual({ ok: false, message: expect.stringContaining("A consumer email is required") }); + fetcher.mockClear(); + expect(await approveBudget({ ...draft, merchant: { ...draft.merchant, url: "http://www.zara.com" } })).toMatchObject({ ok: false, message: expect.stringContaining("HTTPS") }); + expect(fetcher).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/crossmint.test.ts b/tests/crossmint.test.ts index 38b8ad5..95ffd55 100644 --- a/tests/crossmint.test.ts +++ b/tests/crossmint.test.ts @@ -5,16 +5,19 @@ import { assertCheckoutPolicy, cancelCheckout, compareAmounts, + createBuyerProfile, createCheckout, crossmintConfig, CrossmintPolicyError, CrossmintRequestError, CrossmintSetupError, declineRequest, + getBuyerProfile, getCheckout, isCrossmintConfigured, payWithOrderIntent, projectCheckout, + projectProgress, waitForCheckout, type CheckoutSnapshot, } from "../server/crossmint/client.js"; @@ -22,6 +25,7 @@ import { assertPaymentMatches, PaymentMismatchError } from "../server/crossmint/ import { assertSessionCheckout, rememberCheckout, sessionCheckout } from "../server/crossmint/runs.js"; import checkoutTool from "../agent/tools/crossmint_checkout.js"; import payTool from "../agent/tools/crossmint_pay.js"; +import { payee } from "../agent/lib/crossmint.js"; const config = { apiKey: "sk_unit_test_only", @@ -450,3 +454,130 @@ describe("Crossmint tools", () => { expect(fetcher.mock.calls.every((call) => (call as unknown[])[1] === undefined || ((call as unknown[])[1] as RequestInit).method === "GET")).toBe(true); }); }); + +describe("Crossmint progress", () => { + const activity = (id: string, createdAt: string, kinds: string[], revision = 1) => ({ + id, + revision, + role: "assistant", + createdAt, + parts: [{ type: "activity", status: "running", operations: kinds.map((kind) => ({ kind, count: 1 })) }], + }); + const progressText = (id: string, createdAt: string, text: string) => ({ id, revision: 1, role: "assistant", createdAt, parts: [{ type: "progress", text }] }); + + it("maps the latest activity to a fixed stage, in createdAt order and at the latest revision", () => { + const messages = [ + activity("m2", "2026-11-02T12:00:02Z", ["apply_buyer_information", "fill"]), + activity("m1", "2026-11-02T12:00:01Z", ["navigate"]), + activity("m2", "2026-11-02T12:00:02Z", ["apply_payment"], 2), + { id: "u1", revision: 1, role: "user", createdAt: "2026-11-02T12:00:03Z", parts: [{ type: "activity", operations: [{ kind: "navigate" }] }] }, + ]; + expect(projectProgress(messages)).toEqual({ stage: "Applying the payment" }); + expect(projectProgress([activity("m1", "2026-11-02T12:00:01Z", ["click", "scroll"])])).toEqual({ stage: "Working through the store's checkout" }); + expect(projectProgress([])).toBeUndefined(); + }); + + it("never passes on Crossmint's own progress text, which can name the buyer", () => { + const messages = [ + activity("m1", "2026-11-02T12:00:01Z", ["lookup_product"]), + progressText("p1", "2026-11-02T12:00:02Z", "Filling shipping for Ada Lovelace, Calle Mayor 1, 28013 Madrid"), + ]; + expect(projectProgress(messages)).toEqual({ stage: "Finding the product" }); + expect(projectProgress([progressText("p1", "2026-11-02T12:00:02Z", "Opening the store")])).toBeUndefined(); + }); + + it("returns early with progress once the stage changes, but not before the minimum wait", async () => { + const fetcher = vi.fn(async (url: string | URL | Request) => + String(url).includes("/messages") + ? Response.json({ data: [activity("m1", "2026-11-02T12:00:01Z", ["apply_buyer_information"])], nextCursor: null }) + : Response.json(snapshot({ status: "running" })), + ); + const early = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 1_000, progressSince: null }); + expect(early).toMatchObject({ status: "running", progress: { stage: "Filling in the delivery details" } }); + const unchanged = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 20, progressSince: "Filling in the delivery details" }); + expect(unchanged.progress).toEqual({ stage: "Filling in the delivery details" }); + const started = Date.now(); + await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 1_000, progressSince: "Opening the store", minProgressMs: 60 }); + expect(Date.now() - started).toBeGreaterThanOrEqual(55); + }); + + it("rethrows a cancellation that lands during a progress read", async () => { + const controller = new AbortController(); + const fetcher = vi.fn(async (url: string | URL | Request) => { + if (String(url).includes("/messages")) { + controller.abort(); + throw new Error("aborted"); + } + return Response.json(snapshot({ status: "running" })); + }); + await expect(waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 1_000, progressSince: null, signal: controller.signal })).rejects.toThrow(); + }); + + it("never lets a failed progress read stop the wait, and never adds progress unless asked", async () => { + const fetcher = vi.fn(async (url: string | URL | Request) => + String(url).includes("/messages") ? new Response("nope", { status: 500 }) : Response.json(snapshot({ status: "running" })), + ); + const result = await waitForCheckout("run_1", { config, fetch: fetcher, intervalMs: 1, timeoutMs: 10, progressSince: null }); + expect(result.status).toBe("running"); + expect(result.progress).toBeUndefined(); + const plain = vi.fn(async () => Response.json(snapshot({ status: "running" }))); + expect((await waitForCheckout("run_1", { config, fetch: plain, intervalMs: 1, timeoutMs: 5 })).progress).toBeUndefined(); + expect(plain.mock.calls.every((call) => !String((call as unknown[])[0]).includes("/messages"))).toBe(true); + }); +}); + +describe("Crossmint buyer profiles", () => { + const profile = { + id: "bp_1", + label: "Bell", + name: { first: "Ada", last: "Lovelace" }, + contact: { email: "ada@example.com", phone: "+34600000000" }, + shipping: { addressLines: ["Calle Mayor 1"], locality: "Madrid", countryCode: "ES", administrativeAreaCode: "ES-M", postalCode: "28013" }, + createdAt: "2026-11-02T12:00:00Z", + }; + + it("creates and reads a profile with the server key and the operator id", async () => { + const fetcher = vi.fn(async (url: string | URL | Request, init?: RequestInit) => { + expect(init?.headers).toMatchObject({ "X-API-KEY": config.apiKey, "x-crossmint-user-id": config.userId }); + if (init?.method === "POST") { + expect(String(url)).toBe("https://www.crossmint.com/api/unstable/agent-checkouts/buyer-profiles"); + expect(JSON.parse(init.body as string)).toEqual({ label: profile.label, name: profile.name, contact: profile.contact, shipping: profile.shipping }); + } else { + expect(String(url)).toBe("https://www.crossmint.com/api/unstable/agent-checkouts/buyer-profiles/bp_1"); + } + return Response.json(profile); + }); + const input = { label: profile.label, name: profile.name, contact: profile.contact, shipping: profile.shipping }; + const created = await createBuyerProfile(input, { config, fetch: fetcher }); + expect(created).toEqual({ id: "bp_1", label: "Bell", name: profile.name, contact: profile.contact, shipping: profile.shipping }); + await expect(getBuyerProfile("bp_1", { config, fetch: fetcher })).resolves.toEqual(created); + }); + + it("rejects a profile without a shipping address", async () => { + const fetcher = vi.fn(async () => Response.json({ id: "bp_1", shipping: { addressLines: [] } })); + await expect(getBuyerProfile("bp_1", { config, fetch: fetcher })).rejects.toThrow(CrossmintRequestError); + }); +}); + +describe("Crossmint payment store name", () => { + it("refuses when the store name in the approval is not Crossmint's", () => { + const record = { runId: "run_1", maxCost: { amount: "20.00", currency: "USD" }, principalId: "linq:1" }; + const live = projectCheckout(paymentRequest()); + const approved = { requestId: "req_pay", amount: "12.49", currency: "USD", merchant: "shop.example" }; + expect(() => assertPaymentMatches({ ...approved, merchantName: "example shop " }, live, record)).not.toThrow(); + expect(() => assertPaymentMatches({ ...approved, merchantName: "Zara" }, live, record)).toThrow(PaymentMismatchError); + expect(() => assertPaymentMatches({ ...approved, merchantName: "Example Shop: test charge, refunded" }, live, record)).toThrow("store name"); + }); +}); + +describe("Crossmint payment approval wording", () => { + it("names the payee by store name and host, and never shows ids", () => { + expect(payee({ merchant: "https://payments.zara.com/", merchantName: "Zara" })).toBe("Zara (payments.zara.com)"); + expect(payee({ merchant: "shop.example" })).toBe("shop.example"); + expect(payee({ merchant: "https://shop.example", merchantName: "shop.example" })).toBe("shop.example"); + const prompt = (payTool.approval as unknown as { prompt: (ctx: { input: Record }) => string }).prompt; + expect(prompt({ input: { runId: "run_1", requestId: "req_pay", amount: "16.90", currency: "EUR", merchant: "https://payments.zara.com/", merchantName: "Zara" } })).toBe( + "Pay 16.90 EUR at Zara (payments.zara.com) with your saved card?", + ); + }); +});