diff --git a/apps/dev-playground/.gitignore b/apps/dev-playground/.gitignore index d79530cf5..91142ff84 100644 --- a/apps/dev-playground/.gitignore +++ b/apps/dev-playground/.gitignore @@ -1,6 +1,7 @@ # Playwright test-results/ playwright-report/ +.e2e/ # Auto-generated types (regenerated on `pnpm dev` by appKitTypesPlugin) shared/appkit-types/serving.d.ts \ No newline at end of file diff --git a/apps/dev-playground/e2e.config.ts b/apps/dev-playground/e2e.config.ts new file mode 100644 index 000000000..1aacfb1f5 --- /dev/null +++ b/apps/dev-playground/e2e.config.ts @@ -0,0 +1,28 @@ +import { web } from "@e2edev/web"; +import type { E2EConfig } from "e2e"; + +import { appEnv, userHeaders } from "./e2e/identity/env"; + +export default { + tests: "e2e/**/*.e2e.ts", + targets: [ + { + engine: web({ + url: "http://127.0.0.1:0", + readyUrl: "http://127.0.0.1:{port}/health", + // Every browser request carries the signed-in user, as the Apps proxy would. + headers: userHeaders, + command: { + executable: "node", + args: ["--import", "tsx", "server.ts"], + cwd: "e2e/identity/app", + env: appEnv, + startupTimeout: 120_000, + log: ".e2e/logs/identity-app.log", + }, + }), + }, + ], + // Identity checks share one SP and one user; keep the order and the log readable. + workers: 1, +} satisfies E2EConfig; diff --git a/apps/dev-playground/e2e/identity/README.md b/apps/dev-playground/e2e/identity/README.md new file mode 100644 index 000000000..9980a042b --- /dev/null +++ b/apps/dev-playground/e2e/identity/README.md @@ -0,0 +1,74 @@ +# Execution identity e2e suite + +End-to-end checks that AppKit runs each call as the right principal: the app +service principal (SP) by default, the signed-in user on the on-behalf-of (OBO) +path. Built on [`e2e`](https://www.npmjs.com/package/e2e) with the +`@e2edev/web` engine. + +Requires the execution-identity stack (#592, #594, #595, #597, #601). On `main` +without it, the `appkit.asUser(req)` routes in `app/server.ts` do not exist. + +## How identity is injected + +The runner starts `app/server.ts` as a production server (`NODE_ENV=production`; +development mode would turn a missing user token into a silent SP run). Requests +carry the headers the Databricks Apps proxy forwards for a signed-in user: +`x-forwarded-access-token`, `x-forwarded-user`, `x-forwarded-email`. API checks +send them with `fetch`; browser steps get them from `web({ headers })` in +`e2e.config.ts`. The server authenticates as a real SP through +`DATABRICKS_CLIENT_ID` / `DATABRICKS_CLIENT_SECRET`, so the SP and the user are +different principals and every check can fail. + +All assertions are deterministic. B5 sends a chat turn to the app's own agent; +its serving-endpoint model picks the tools, and the test reads the tool outputs +from the SSE stream, never the model's text. No e2e model provider is needed. + +## Run + +```sh +cd apps/dev-playground +export DATABRICKS_HOST=https:// +export E2E_SP_CLIENT_ID= E2E_SP_CLIENT_SECRET= +export E2E_USER_EMAIL= +export E2E_USER_TOKEN=$(databricks auth token --profile | jq -r .access_token) +export DATABRICKS_WAREHOUSE_ID= DATABRICKS_SERVING_ENDPOINT_NAME= +export LAKEBASE_ENDPOINT= PGHOST= PGDATABASE= +pnpm test:e2e # all tests +pnpm test:e2e analytics # one file +``` + +**Local mode (no SP secret).** Leave `E2E_SP_CLIENT_ID` / `E2E_SP_CLIENT_SECRET` +unset and the server runs on `E2E_USER_TOKEN`. SP and user are then the same +principal, so the 7 tests that compare them skip with +`needs a distinct SP`; the principal-kind, fail-closed, app-only, and +deprecation checks still run. + +The SP needs `CAN USE` on the warehouse, `CAN QUERY` on the endpoint, and a +Lakebase role. The app log is `.e2e/logs/identity-app.log`. + +## Checklist mapping + +| Checklist row | File | Test | +| --- | --- | --- | +| B1 `.sql` runs as SP | `analytics.e2e.ts` | B1: a .sql query runs as the app service principal | +| B2 `.obo.sql` runs as user | `analytics.e2e.ts` | B2: a .obo.sql query runs as the signed-in user | +| B3 `asUser(req).run(...)` | `as-user.e2e.ts` | B3: asUser(req).run(...) runs as the user | +| B3 one-call form | `as-user.e2e.ts` | B3: the one-call asUser(req).plugin.method() form runs as the user | +| B4 plain call runs as SP | `as-user.e2e.ts` | B4: a plain plugin call runs as the SP even with user headers | +| B5 toolkit tool as user | `agents.e2e.ts` | B5: a plugin-toolkit tool runs as the user | +| B5 hand-rolled tool and model as SP | `agents.e2e.ts` | B5: a hand-rolled tool and the model call run as the SP | +| B7 Lakebase always SP | `lakebase.e2e.ts` | B7: a Lakebase query connects as the SP even with user headers | +| B7 Lakebase is app-only | `lakebase.e2e.ts` | B7: asUser(req).lakebase is refused, never run as the user | +| Guardrail: fail-closed (asUser) | `as-user.e2e.ts` | fail-closed: asUser with no user token rejects instead of running as the SP | +| Guardrail: fail-closed (agent tool) | `agents.e2e.ts` | fail-closed: a plugin tool call with no user token never runs as the SP | +| Guardrail: no `Plugin.asUser` deprecation from core plugins | `deprecation.e2e.ts` | core plugins on the OBO path log no Plugin.asUser deprecation warning | + +B6 (unbound-warehouse OBO) and Part A (provisioning) need a deployed app or the +CLI and are not covered here. + +## How this differs from `server/testing-kit.integration.test.ts` + +That suite runs in-process against a mocked workspace client: it proves AppKit +routes a call to the user or SP context. This suite sends real HTTP through the +proxy-header path to a real workspace, so it proves which principal the +warehouse, Lakebase, and the agent's tools actually see. diff --git a/apps/dev-playground/e2e/identity/agents.e2e.ts b/apps/dev-playground/e2e/identity/agents.e2e.ts new file mode 100644 index 000000000..f397c5dbc --- /dev/null +++ b/apps/dev-playground/e2e/identity/agents.e2e.ts @@ -0,0 +1,83 @@ +import { expect, test } from "e2e"; + +import { + DISTINCT_SP, + NEEDS_DISTINCT_SP, + postSse, + SERVER_IDENTITY, + type SseEvent, + SP_CLIENT_ID, + USER_EMAIL, + userHeaders, +} from "./env"; + +// The app's own model decides to call the tools; the assertions only read tool outputs. +const PROMPT = "Who am I? Prove identity with both tools."; + +/** Tool name -> parsed output, joined from function_call and function_call_output items. */ +function toolOutputs(events: SseEvent[]): Record { + const items = events + .filter((e) => e.data?.type === "response.output_item.done") + .map((e) => e.data.item); + const names = new Map( + items + .filter((i) => i?.type === "function_call") + .map((i) => [i.call_id, i.name]), + ); + const outputs: Record = {}; + for (const item of items.filter((i) => i?.type === "function_call_output")) { + try { + outputs[names.get(item.call_id)] = JSON.parse(item.output); + } catch { + outputs[names.get(item.call_id)] = item.output; + } + } + return outputs; +} + +async function chat( + baseUrl: string | undefined, + headers?: Record, +) { + const res = await postSse( + new URL("/api/agents/chat", baseUrl), + { message: PROMPT }, + headers, + ); + return { ...res, outputs: toolOutputs(res.events) }; +} + +test.describe("agents execution identity", () => { + test("B5: a plugin-toolkit tool runs as the user", async ({ app }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + const { status, outputs } = await chat(app.baseUrl, userHeaders); + expect(status).toBe(200); + expect(JSON.stringify(outputs["analytics.query"])).toContain(USER_EMAIL); + expect(JSON.stringify(outputs["analytics.query"])).not.toContain( + SP_CLIENT_ID, + ); + }); + + test("B5: a hand-rolled tool and the model call run as the SP", async ({ + app, + }) => { + const { status, outputs, text } = await chat(app.baseUrl, userHeaders); + expect(status).toBe(200); + expect(outputs.whoami_sp).toMatchObject({ principal: "app" }); + // The model call ran (it chose the tools) with no model-serving user scope: SP. + expect(text).not.toMatch(/^event: error$/m); + }); + + test("fail-closed: a plugin tool call with no user token never runs as the SP", async ({ + app, + }) => { + // A signed-in user whose token did not arrive: only the token is missing. + const { "x-forwarded-access-token": _, ...noToken } = userHeaders; + const { status, outputs } = await chat(app.baseUrl, noToken); + expect(status).toBe(200); + // The tool was called and answered with the token error, not with the server's rows. + const query = JSON.stringify(outputs["analytics.query"]); + expect(query).toMatch(/token/i); + expect(query).not.toContain(SERVER_IDENTITY); + }); +}); diff --git a/apps/dev-playground/e2e/identity/analytics.e2e.ts b/apps/dev-playground/e2e/identity/analytics.e2e.ts new file mode 100644 index 000000000..a55c0798c --- /dev/null +++ b/apps/dev-playground/e2e/identity/analytics.e2e.ts @@ -0,0 +1,37 @@ +import { expect, test } from "e2e"; + +import { + DISTINCT_SP, + identityFromQuery, + NEEDS_DISTINCT_SP, + postSse, + SP_CLIENT_ID, + USER_EMAIL, + userHeaders, +} from "./env"; + +test.describe("analytics query files", () => { + test("B1: a .sql query runs as the app service principal", async ({ + app, + }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + const { status, events } = await postSse( + new URL("/api/analytics/query/whoami", app.baseUrl), + { parameters: {} }, + userHeaders, + ); + expect(status).toBe(200); + expect(identityFromQuery(events)).toBe(SP_CLIENT_ID); + }); + + test("B2: a .obo.sql query runs as the signed-in user", async ({ app }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + const { status, events } = await postSse( + new URL("/api/analytics/query/whoami_obo", app.baseUrl), + { parameters: {} }, + userHeaders, + ); + expect(status).toBe(200); + expect(identityFromQuery(events)).toBe(USER_EMAIL); + }); +}); diff --git a/apps/dev-playground/e2e/identity/app/config/queries/whoami.sql b/apps/dev-playground/e2e/identity/app/config/queries/whoami.sql new file mode 100644 index 000000000..c88ff5d3b --- /dev/null +++ b/apps/dev-playground/e2e/identity/app/config/queries/whoami.sql @@ -0,0 +1 @@ +SELECT current_user() AS identity diff --git a/apps/dev-playground/e2e/identity/app/config/queries/whoami_obo.obo.sql b/apps/dev-playground/e2e/identity/app/config/queries/whoami_obo.obo.sql new file mode 100644 index 000000000..c88ff5d3b --- /dev/null +++ b/apps/dev-playground/e2e/identity/app/config/queries/whoami_obo.obo.sql @@ -0,0 +1 @@ +SELECT current_user() AS identity diff --git a/apps/dev-playground/e2e/identity/app/server.ts b/apps/dev-playground/e2e/identity/app/server.ts new file mode 100644 index 000000000..7683aef8d --- /dev/null +++ b/apps/dev-playground/e2e/identity/app/server.ts @@ -0,0 +1,58 @@ +import { analytics, createApp, lakebase, server } from "@databricks/appkit"; +import { agents } from "@databricks/appkit/beta"; + +const WHOAMI_SQL = "SELECT current_user() AS identity"; + +// The e2e runner appends to one log across runs; tests read from the last marker. +console.log("e2e-identity-app: boot"); + +/** Identity probes for the execution-identity e2e suite. Every route answers `{ identity }`. */ +createApp({ + plugins: [agents(), analytics(), lakebase(), server()], + async onPluginsReady(appkit) { + appkit.server.extend((app) => { + type Req = Parameters[0]; + const probe = (path: string, fn: (req: Req) => Promise) => + app.get(path, async (req, res) => { + try { + res.json({ identity: await fn(req) }); + } catch (error) { + const err = error as Error & { code?: string }; + res.status(500).json({ code: err.code, error: err.message }); + } + }); + const identity = (rows: unknown) => + (rows as { identity: string }[])[0]?.identity; + + probe("/e2e/default", async () => + identity(await appkit.analytics.query(WHOAMI_SQL)), + ); + probe("/e2e/as-user-block", (req) => + appkit + .asUser(req) + .run(async (kit) => identity(await kit.analytics.query(WHOAMI_SQL))), + ); + probe("/e2e/as-user-oneshot", async (req) => + identity(await appkit.asUser(req).analytics.query(WHOAMI_SQL)), + ); + probe( + "/e2e/lakebase", + async () => + (await appkit.lakebase.query("SELECT current_user AS identity")) + .rows[0]?.identity, + ); + probe( + "/e2e/lakebase-as-user", + async (req) => + ( + await appkit + .asUser(req) + .lakebase.query("SELECT current_user AS identity") + ).rows[0]?.identity, + ); + }); + }, +}).catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/apps/dev-playground/e2e/identity/app/server/agents/identity/agent.ts b/apps/dev-playground/e2e/identity/app/server/agents/identity/agent.ts new file mode 100644 index 000000000..eaf569d0e --- /dev/null +++ b/apps/dev-playground/e2e/identity/app/server/agents/identity/agent.ts @@ -0,0 +1,65 @@ +import { getCurrentPrincipalKey } from "@databricks/appkit"; +import { createAgent, tool } from "@databricks/appkit/beta"; +import { z } from "zod"; + +/** + * B5 runtime-identity probe agent (default chat agent, id = folder "identity"). + * + * Two tools make the execution identity observable in one chat turn: + * + * - `analytics.query` is a PLUGIN-TOOLKIT tool. The agents plugin dispatches + * it through `executeTool`, which opens the request's user scope, so the + * SQL runs on behalf of the signed-in USER (OBO). `current_user()` returns + * the user's email. + * + * - `whoami_sp` is a HAND-ROLLED tool({ execute }). `execute` receives only + * its arguments and runs in the ambient app context, never a user scope. + * `getCurrentPrincipalKey()` therefore returns "app" (the service + * principal), the direct complement of the OBO tool's "user:". We also + * surface the SP client id from the platform-injected env so the SP has a + * concrete identifier alongside the principal kind. + * + * Why the accessor and not a SQL round-trip: inside an agent `tools(plugins)` + * builder, `plugins.` is a toolkit provider (it only exposes + * `toolkit()`), not the service-principal exports, so a hand-rolled execute + * cannot call `plugins.analytics.query`. `getCurrentPrincipalKey()` is the + * simplest correct way for a hand-rolled execute to prove its principal. + * + * The agent model (serving endpoint) call also runs as the service principal: + * the endpoint is bound to the app SP and the app declares no `model-serving` + * user scope, so a working chat proves the model call does not use the user + * token. + */ +const WHOAMI_SQL = "SELECT current_user() AS identity"; + +export default createAgent({ + default: true, + instructions: [ + "You are a runtime identity probe.", + "When the user asks who they are, who is running, or to prove identity,", + "you MUST call BOTH tools, each exactly once, then report both results.", + `1. call \`analytics.query\` with the query "${WHOAMI_SQL}" to get the`, + "on-behalf-of USER identity (read the `identity` column from the result).", + "2. call `whoami_sp` to get the app SERVICE PRINCIPAL identity.", + "Reply with exactly these two lines:", + "USER (OBO): ", + "SERVICE PRINCIPAL: ", + ].join(" "), + tools: (plugins) => ({ + // Plugin-toolkit tool: dispatched via executeTool, runs OBO (user). + ...plugins.analytics.toolkit({ only: ["query"] }), + // Hand-rolled tool: runs in the ambient app context (service principal). + whoami_sp: tool({ + description: + "Return the running principal for a hand-rolled tool: the principal kind and the app service principal client id.", + schema: z.object({}), + annotations: { effect: "read" }, + execute: async () => ({ + // "app" when running as the service principal; "user:" would mean + // a user scope leaked into a hand-rolled tool (it must not). + principal: getCurrentPrincipalKey(), + servicePrincipalClientId: process.env.DATABRICKS_CLIENT_ID ?? null, + }), + }), + }), +}); diff --git a/apps/dev-playground/e2e/identity/as-user.e2e.ts b/apps/dev-playground/e2e/identity/as-user.e2e.ts new file mode 100644 index 000000000..de0ad800e --- /dev/null +++ b/apps/dev-playground/e2e/identity/as-user.e2e.ts @@ -0,0 +1,66 @@ +import { expect, test } from "e2e"; + +import { + DISTINCT_SP, + NEEDS_DISTINCT_SP, + SP_CLIENT_ID, + USER_EMAIL, + userHeaders, +} from "./env"; + +async function probe( + baseUrl: string | undefined, + path: string, + headers: Record = {}, +) { + const res = await fetch(new URL(path, baseUrl), { headers }); + return { + status: res.status, + body: (await res.json()) as Record, + }; +} + +test.describe("appkit.asUser(req)", () => { + test("B3: asUser(req).run(...) runs as the user", async ({ app }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + expect(await probe(app.baseUrl, "/e2e/as-user-block", userHeaders)).toEqual( + { + status: 200, + body: { identity: USER_EMAIL }, + }, + ); + }); + + test("B3: the one-call asUser(req).plugin.method() form runs as the user", async ({ + app, + }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + expect( + await probe(app.baseUrl, "/e2e/as-user-oneshot", userHeaders), + ).toEqual({ + status: 200, + body: { identity: USER_EMAIL }, + }); + }); + + test("B4: a plain plugin call runs as the SP even with user headers", async ({ + app, + }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + expect(await probe(app.baseUrl, "/e2e/default", userHeaders)).toEqual({ + status: 200, + body: { identity: SP_CLIENT_ID }, + }); + }); + + test("fail-closed: asUser with no user token rejects instead of running as the SP", async ({ + app, + }) => { + for (const path of ["/e2e/as-user-block", "/e2e/as-user-oneshot"]) { + const { status, body } = await probe(app.baseUrl, path); + expect(status).toBe(500); + expect(body.code).toBe("AUTHENTICATION_ERROR"); + expect(body.identity).toBeUndefined(); + } + }); +}); diff --git a/apps/dev-playground/e2e/identity/deprecation.e2e.ts b/apps/dev-playground/e2e/identity/deprecation.e2e.ts new file mode 100644 index 000000000..71c2f974d --- /dev/null +++ b/apps/dev-playground/e2e/identity/deprecation.e2e.ts @@ -0,0 +1,25 @@ +import { readFile } from "node:fs/promises"; + +import { expect, test } from "e2e"; + +import { postSse, userHeaders } from "./env"; + +const LOG = new URL("../../.e2e/logs/identity-app.log", import.meta.url); + +test("core plugins on the OBO path log no Plugin.asUser deprecation warning", async ({ + app, +}) => { + await postSse( + new URL("/api/analytics/query/whoami_obo", app.baseUrl), + { parameters: {} }, + userHeaders, + ); + await fetch(new URL("/e2e/as-user-oneshot", app.baseUrl), { + headers: userHeaders, + }); + + const log = await readFile(LOG, "utf8"); + const thisRun = log.slice(log.lastIndexOf("e2e-identity-app: boot")); + expect(thisRun).toContain("e2e-identity-app: boot"); + expect(thisRun).not.toContain("Plugin.asUser is deprecated"); +}); diff --git a/apps/dev-playground/e2e/identity/env.ts b/apps/dev-playground/e2e/identity/env.ts new file mode 100644 index 000000000..5ca975d62 --- /dev/null +++ b/apps/dev-playground/e2e/identity/env.ts @@ -0,0 +1,85 @@ +function need(name: string): string { + const value = process.env[name]; + if (!value) + throw new Error(`${name} is required (see e2e/identity/README.md)`); + return value; +} + +/** The signed-in user the forwarded token belongs to. */ +export const USER_EMAIL = need("E2E_USER_EMAIL"); +const USER_TOKEN = need("E2E_USER_TOKEN"); + +/** + * With an SP secret the server runs as that SP. Without one (local mode) it runs + * on the user's own token, so SP and user are the same principal and the tests + * that compare them skip with this reason instead of passing for nothing. + */ +export const DISTINCT_SP = Boolean(process.env.E2E_SP_CLIENT_SECRET); +export const NEEDS_DISTINCT_SP = + "needs a distinct SP (set E2E_SP_CLIENT_ID and E2E_SP_CLIENT_SECRET)"; + +/** The app service principal the server runs as; `current_user()` returns its client id. */ +export const SP_CLIENT_ID = DISTINCT_SP ? need("E2E_SP_CLIENT_ID") : ""; +/** What `current_user()` returns for a call that ran on the server's own credentials. */ +export const SERVER_IDENTITY = DISTINCT_SP ? SP_CLIENT_ID : USER_EMAIL; + +/** The headers the Databricks Apps proxy forwards for a signed-in user. */ +export const userHeaders = { + "x-forwarded-access-token": USER_TOKEN, + "x-forwarded-user": USER_EMAIL, + "x-forwarded-email": USER_EMAIL, +}; + +export const appEnv = { + // Not "development": dev mode turns a missing user token into a silent SP run. + NODE_ENV: "production", + DATABRICKS_APP_PORT: "{port}", + DATABRICKS_HOST: need("DATABRICKS_HOST"), + ...(DISTINCT_SP + ? { + DATABRICKS_CLIENT_ID: SP_CLIENT_ID, + DATABRICKS_CLIENT_SECRET: need("E2E_SP_CLIENT_SECRET"), + } + : { DATABRICKS_TOKEN: USER_TOKEN }), + DATABRICKS_WAREHOUSE_ID: need("DATABRICKS_WAREHOUSE_ID"), + DATABRICKS_SERVING_ENDPOINT_NAME: need("DATABRICKS_SERVING_ENDPOINT_NAME"), + LAKEBASE_ENDPOINT: need("LAKEBASE_ENDPOINT"), + PGHOST: need("PGHOST"), + PGDATABASE: need("PGDATABASE"), + PGPORT: process.env.PGPORT ?? "5432", + PGSSLMODE: process.env.PGSSLMODE ?? "require", +}; + +export type SseEvent = { event: string; data: any }; + +/** POST a JSON body and collect every SSE event the route streams. */ +export async function postSse( + url: URL, + body: unknown, + headers: Record = {}, +): Promise<{ status: number; events: SseEvent[]; text: string }> { + const res = await fetch(url, { + method: "POST", + headers: { "content-type": "application/json", ...headers }, + body: JSON.stringify(body), + }); + const text = await res.text(); + const events: SseEvent[] = []; + for (const block of text.split("\n\n")) { + const event = /^event: (.*)$/m.exec(block)?.[1] ?? "message"; + const data = /^data: (.*)$/m.exec(block)?.[1]; + if (data === undefined) continue; + try { + events.push({ event, data: JSON.parse(data) }); + } catch { + events.push({ event, data }); + } + } + return { status: res.status, events, text }; +} + +/** `current_user()` from an analytics query stream, or undefined when it errored. */ +export function identityFromQuery(events: SseEvent[]): string | undefined { + return events.find((e) => e.data?.type === "result")?.data.data?.[0] + ?.identity; +} diff --git a/apps/dev-playground/e2e/identity/lakebase.e2e.ts b/apps/dev-playground/e2e/identity/lakebase.e2e.ts new file mode 100644 index 000000000..0b3d9e700 --- /dev/null +++ b/apps/dev-playground/e2e/identity/lakebase.e2e.ts @@ -0,0 +1,31 @@ +import { expect, test } from "e2e"; + +import { + DISTINCT_SP, + NEEDS_DISTINCT_SP, + SP_CLIENT_ID, + userHeaders, +} from "./env"; + +test.describe("lakebase is app-only", () => { + test("B7: a Lakebase query connects as the SP even with user headers", async ({ + app, + }) => { + test.skip(!DISTINCT_SP, NEEDS_DISTINCT_SP); + const res = await fetch(new URL("/e2e/lakebase", app.baseUrl), { + headers: userHeaders, + }); + expect(res.status).toBe(200); + expect(await res.json()).toEqual({ identity: SP_CLIENT_ID }); + }); + + test("B7: asUser(req).lakebase is refused, never run as the user", async ({ + app, + }) => { + const res = await fetch(new URL("/e2e/lakebase-as-user", app.baseUrl), { + headers: userHeaders, + }); + expect(res.status).toBe(500); + expect(await res.json()).toMatchObject({ code: "APP_ONLY_RESOURCE" }); + }); +}); diff --git a/apps/dev-playground/package.json b/apps/dev-playground/package.json index d07afce6d..f39bdee37 100644 --- a/apps/dev-playground/package.json +++ b/apps/dev-playground/package.json @@ -17,7 +17,8 @@ "clean:full": "rm -rf build node_modules && cd client && rm -rf dist node_modules", "test:integration": "playwright test", "test:integration:ui": "playwright test --ui", - "test:integration:headed": "playwright test --headed" + "test:integration:headed": "playwright test --headed", + "test:e2e": "e2e run" }, "keywords": [], "author": "", @@ -34,9 +35,12 @@ "typeorm": "0.3.28" }, "devDependencies": { - "@playwright/test": "1.61.0", + "@e2edev/web": "0.11.0-canary-20260925150007", + "@playwright/test": "1.63.0", "@types/node": "20.19.21", "dotenv": "16.6.1", + "e2e": "0.15.0-canary-20260925150007", + "playwright": "1.63.0", "tsdown": "0.20.3", "tsx": "4.20.6", "vite": "npm:rolldown-vite@7.1.14" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ced623e4..4af343b52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -132,7 +132,7 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitejs/plugin-react': specifier: 5.1.1 - version: 5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2)) + version: 5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2)) eslint: specifier: 9.39.1 version: 9.39.1(jiti@2.6.1) @@ -153,7 +153,7 @@ importers: version: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) vite: specifier: 7.2.4 - version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) apps/dev-playground: dependencies: @@ -173,15 +173,24 @@ importers: specifier: 0.3.28 version: 0.3.28(pg@8.18.0) devDependencies: + '@e2edev/web': + specifier: 0.11.0-canary-20260925150007 + version: 0.11.0-canary-20260925150007(e2e@0.15.0-canary-20260925150007)(playwright@1.63.0) '@playwright/test': - specifier: 1.61.0 - version: 1.61.0 + specifier: 1.63.0 + version: 1.63.0 '@types/node': specifier: 20.19.21 version: 20.19.21 dotenv: specifier: 16.6.1 version: 16.6.1 + e2e: + specifier: 0.15.0-canary-20260925150007 + version: 0.15.0-canary-20260925150007 + playwright: + specifier: 1.63.0 + version: 1.63.0 tsdown: specifier: 0.20.3 version: 0.20.3(@arethetypeswrong/core@0.18.4)(oxc-resolver@11.19.1)(publint@0.3.15)(typescript@5.9.3) @@ -368,7 +377,7 @@ importers: version: link:../shared vite: specifier: npm:rolldown-vite@7.1.14 - version: rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + version: rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) ws: specifier: 8.21.0 version: 8.21.0 @@ -399,13 +408,13 @@ importers: version: 8.18.1 '@vitejs/plugin-react': specifier: 5.1.1 - version: 5.1.1(rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2)) + version: 5.1.1(rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2)) autoevals: specifier: 0.3.0 version: 0.3.0(ws@8.21.0)(zod@4.3.6) vitest: specifier: 3.2.4 - version: 3.2.4(@types/debug@4.1.12)(@types/node@25.2.3)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + version: 3.2.4(@types/debug@4.1.12)(@types/node@25.2.3)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) packages/appkit-ui: dependencies: @@ -656,6 +665,10 @@ packages: resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} + '@ai-sdk/provider@4.0.17': + resolution: {integrity: sha512-VYMBxIQdcHqbIf1j+YZlI9Ati6LZ4wJe0GGd4z4a5H/KxTggjeOiyaVYTnfF7LHZK5jMQ+rofmzz4QPqf++NUw==} + engines: {node: '>=22'} + '@ai-sdk/react@2.0.115': resolution: {integrity: sha512-Etu7gWSEi2dmXss1PoR5CAZGwGShXsF9+Pon1eRO6EmatjYaBMhq1CfHPyYhGzWrint8jJIK2VaAhiMef29qZw==} engines: {node: '>=18'} @@ -1572,9 +1585,17 @@ packages: '@clack/core@1.0.1': resolution: {integrity: sha512-WKeyK3NOBwDOzagPR5H08rFk9D/WuN705yEbuZvKqlkmoLM2woKtXb10OO2k1NoSU4SFG947i2/SCYh+2u5e4g==} + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} + engines: {node: '>= 20.12.0'} + '@clack/prompts@1.0.1': resolution: {integrity: sha512-/42G73JkuYdyWZ6m8d/CJtBrGl1Hegyc7Fy78m5Ob+jF85TOUmLR5XLce/U3LxYAw0kJ8CT5aI99RIvPHcGp/Q==} + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} + engines: {node: '>= 20.12.0'} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -2189,6 +2210,14 @@ packages: resolution: {integrity: sha512-lBSBiRruFurFKXr5Hbsl2thmGweAPmddhF3jb99U4EMDA5L+e5Y1rAkOS07Nvrup7HUMBDrCV45meaxZnt28nQ==} engines: {node: '>=20.0'} + '@e2edev/web@0.11.0-canary-20260925150007': + resolution: {integrity: sha512-PLLCM8ZXw2vpP7fqps2EfA1gRBOvhfEDrRmOCQIzn1D8yq89JC/BivuLoWLvW40uGuvVT2UIsMUGceWwvvErvQ==} + engines: {node: '>=22.12.0'} + deprecated: Moved to @e2e-dev/web + peerDependencies: + e2e: 0.15.0-canary-20260925150007 + playwright: '>=1.63.0 <2' + '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -2204,156 +2233,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.10': resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.10': resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.10': resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.10': resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.10': resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.10': resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.10': resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.10': resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.10': resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.10': resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.10': resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.10': resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.10': resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.10': resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.10': resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.10': resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.10': resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.10': resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.10': resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.10': resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.10': resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.10': resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.10': resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.10': resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.10': resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2429,6 +2614,12 @@ packages: '@hapi/topo@5.1.0': resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@hono/node-server@2.1.1': + resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -2713,6 +2904,16 @@ packages: engines: {node: '>=18'} hasBin: true + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} @@ -3803,9 +4004,9 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.61.0': - resolution: {integrity: sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==} - engines: {node: '>=18'} + '@playwright/test@1.63.0': + resolution: {integrity: sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==} + engines: {node: '>=20'} hasBin: true '@pnpm/config.env-replace@1.1.0': @@ -5628,6 +5829,9 @@ packages: '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@5.0.1': + resolution: {integrity: sha512-U4YclNr7ds8kqZdtLcoVCYTaLRmaKeyjRjQHQ2We5iY0ZjegavIeBWJOr2F4pgUFuN0tO0bz/cVa4ERwKhf1Hg==} + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: @@ -5642,6 +5846,9 @@ packages: '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@5.0.1': + resolution: {integrity: sha512-6guWwj5d9bguuefTOvJoq387tfpkzSv554YdUEGzjJH2PnnmvzTLQ1UQSuAk5wBFVhf2CUmy/S/palOcb6dmpA==} + '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} @@ -5651,9 +5858,15 @@ packages: '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@5.0.1': + resolution: {integrity: sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==} + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@5.0.1': + resolution: {integrity: sha512-E9+yEA+jsfaoxZcUHFzEqUrQcoNh2EwrPT5efIqkUPUwD5Ua2Li9BRWaYeRwvzvdLgTSVrre8oKNeyrfg7KkdQ==} + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -5720,6 +5933,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -6227,6 +6444,10 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chalk-template@0.4.0: resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} engines: {node: '>=12'} @@ -6440,6 +6661,10 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -6524,6 +6749,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -6579,6 +6808,10 @@ packages: cookie-signature@1.0.7: resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -6601,6 +6834,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -7282,6 +7519,25 @@ packages: duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + e2e@0.15.0-canary-20260925150007: + resolution: {integrity: sha512-vMlKmliBKdHDfSJMXWIHT6+Z49FEuDmDdDrFxzamp03ue1+QJkksox+fM/7YT1uMvK1oN/cCaKDgonidp8tMWA==} + engines: {node: '>=22.12.0'} + hasBin: true + peerDependencies: + '@ai-sdk/openai': ^4.0.0 + '@ai-sdk/openai-compatible': ^3.0.0 + '@ai-sdk/xai': ^5.0.0 + ai: ^7.0.0 + peerDependenciesMeta: + '@ai-sdk/openai': + optional: true + '@ai-sdk/openai-compatible': + optional: true + '@ai-sdk/xai': + optional: true + ai: + optional: true + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -7420,6 +7676,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -7572,6 +7833,10 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -7591,10 +7856,20 @@ packages: exponential-backoff@3.1.3: resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + express-rate-limit@8.7.0: + resolution: {integrity: sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + express@4.22.2: resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} engines: {node: '>= 0.10.0'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -7627,9 +7902,18 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -7692,6 +7976,10 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-cache-dir@4.0.0: resolution: {integrity: sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==} engines: {node: '>=14.16'} @@ -7790,6 +8078,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -7801,11 +8093,6 @@ packages: resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -8145,6 +8432,10 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.13.10: + resolution: {integrity: sha512-dQuLsa5oO+47QVMVMaaD9cIv8ctmVtK1iRvwWngkfloFJMeFeuoUFDswIqZGxmGX3hrRzREgEArjkK9OgsQEhA==} + engines: {node: '>=16.9.0'} + hookable@6.0.1: resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==} @@ -8407,6 +8698,10 @@ packages: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} + ip-address@10.7.2: + resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -8543,6 +8838,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regexp@1.0.0: resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} engines: {node: '>=0.10.0'} @@ -8726,6 +9024,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -9185,6 +9486,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -9956,6 +10261,9 @@ packages: path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -10020,6 +10328,10 @@ packages: engines: {node: '>=0.10'} hasBin: true + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@7.0.0: resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} engines: {node: '>=14.16'} @@ -10030,16 +10342,20 @@ packages: pkg-types@2.3.0: resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} - playwright-core@1.61.0: - resolution: {integrity: sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==} - engines: {node: '>=18'} + playwright-core@1.63.0: + resolution: {integrity: sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==} + engines: {node: '>=20'} hasBin: true - playwright@1.61.0: - resolution: {integrity: sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==} - engines: {node: '>=18'} + playwright@1.63.0: + resolution: {integrity: sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==} + engines: {node: '>=20'} hasBin: true + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + points-on-curve@0.2.0: resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} @@ -10988,6 +11304,10 @@ packages: roughjs@4.6.6: resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -11087,6 +11407,10 @@ packages: resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sequelize-pool@7.1.0: resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} engines: {node: '>= 10.0.0'} @@ -11138,6 +11462,10 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -11609,6 +11937,10 @@ packages: resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} engines: {node: '>=14.0.0'} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} + engines: {node: '>=14.0.0'} + tinyspy@4.0.4: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} @@ -11736,6 +12068,11 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tsx@4.23.14: + resolution: {integrity: sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w==} + engines: {node: '>=18.0.0'} + hasBin: true + tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} @@ -12567,6 +12904,11 @@ packages: peerDependencies: zod: ^3.25 || ^4 + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -12579,6 +12921,9 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.6.1: + resolution: {integrity: sha512-341aRWQsve0rvronKNTqZpjmzdbUDlFuzHaI/XLg/Ej82qffDJRRfBTCuv7+9q/rMjB6LSLyEBnW4InJeMtt/Q==} + zrender@6.0.0: resolution: {integrity: sha512-41dFXEEXuJpNecuUQq6JlbybmnHaqqpGlbH1yxnA5V9MMP4SbohSVZsJIwz+zdjQXSSlR1Vc34EgH1zxyTDvhg==} @@ -12608,6 +12953,10 @@ snapshots: dependencies: json-schema: 0.4.0 + '@ai-sdk/provider@4.0.17': + dependencies: + json-schema: 0.4.0 + '@ai-sdk/react@2.0.115(react@19.2.0)(zod@4.3.6)': dependencies: '@ai-sdk/provider-utils': 3.0.19(zod@4.3.6) @@ -13734,12 +14083,24 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 + '@clack/core@1.5.1': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + '@clack/prompts@1.0.1': dependencies: '@clack/core': 1.0.1 picocolors: 1.1.1 sisteransi: 1.0.5 + '@clack/prompts@1.8.1': + dependencies: + '@clack/core': 1.5.1 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + '@colors/colors@1.5.0': optional: true @@ -15057,6 +15418,11 @@ snapshots: - uglify-js - webpack-cli + '@e2edev/web@0.11.0-canary-20260925150007(e2e@0.15.0-canary-20260925150007)(playwright@1.63.0)': + dependencies: + e2e: 0.15.0-canary-20260925150007 + playwright: 1.63.0 + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -15076,81 +15442,159 @@ snapshots: '@esbuild/aix-ppc64@0.25.10': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.25.10': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.25.10': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.25.10': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.25.10': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.25.10': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.25.10': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.25.10': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.25.10': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.25.10': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.25.10': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.25.10': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.25.10': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.25.10': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.25.10': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.25.10': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.25.10': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.25.10': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.25.10': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.25.10': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.25.10': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.25.10': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.25.10': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.25.10': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.25.10': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.25.10': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -15242,6 +15686,10 @@ snapshots: dependencies: '@hapi/hoek': 9.3.0 + '@hono/node-server@2.1.1(hono@4.13.10)': + dependencies: + hono: 4.13.10 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -15594,6 +16042,28 @@ snapshots: - supports-color - utf-8-validate + '@modelcontextprotocol/sdk@1.30.0(zod@4.6.1)': + dependencies: + '@hono/node-server': 2.1.1(hono@4.13.10) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.7.0(express@5.2.1) + hono: 4.13.10 + jose: 6.2.10 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.6.1 + zod-to-json-schema: 3.25.2(zod@4.6.1) + transitivePeerDependencies: + - supports-color + '@napi-rs/wasm-runtime@1.1.1': dependencies: '@emnapi/core': 1.8.1 @@ -16829,9 +17299,9 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.61.0': + '@playwright/test@1.63.0': dependencies: - playwright: 1.61.0 + playwright: 1.63.0 '@pnpm/config.env-replace@1.1.0': {} @@ -18601,7 +19071,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@5.1.1(rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.1(rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -18609,11 +19079,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.47 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + vite: rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2))': + '@vitejs/plugin-react@5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -18621,7 +19091,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.47 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) transitivePeerDependencies: - supports-color @@ -18649,6 +19119,15 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 + '@vitest/expect@5.0.1': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.2 + '@vitest/spy': 5.0.1 + '@vitest/utils': 5.0.1 + chai: 6.2.2 + tinyrainbow: 3.1.1 + '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 @@ -18657,18 +19136,22 @@ snapshots: optionalDependencies: vite: 7.2.4(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) - '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: tinyrainbow: 2.0.0 + '@vitest/pretty-format@5.0.1': + dependencies: + tinyrainbow: 3.1.1 + '@vitest/runner@3.2.4': dependencies: '@vitest/utils': 3.2.4 @@ -18685,12 +19168,20 @@ snapshots: dependencies: tinyspy: 4.0.4 + '@vitest/spy@5.0.1': {} + '@vitest/utils@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 loupe: 3.2.1 tinyrainbow: 2.0.0 + '@vitest/utils@5.0.1': + dependencies: + '@vitest/pretty-format': 5.0.1 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.1 + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -18786,6 +19277,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -19178,7 +19674,6 @@ snapshots: type-is: 2.0.1 transitivePeerDependencies: - supports-color - optional: true bonjour-service@1.3.0: dependencies: @@ -19371,6 +19866,8 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chai@6.2.2: {} + chalk-template@0.4.0: dependencies: chalk: 4.1.2 @@ -19590,6 +20087,8 @@ snapshots: commander@13.1.0: {} + commander@15.0.0: {} + commander@2.20.3: {} commander@5.1.0: {} @@ -19688,6 +20187,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.1.0: {} + content-type@1.0.5: {} conventional-changelog-angular@7.0.0: @@ -19749,6 +20250,8 @@ snapshots: cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} + cookie@0.7.2: {} copy-webpack-plugin@11.0.0(webpack@5.103.0(esbuild@0.25.10)): @@ -19771,6 +20274,11 @@ snapshots: core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -20391,6 +20899,21 @@ snapshots: duplexer@0.1.2: {} + e2e@0.15.0-canary-20260925150007: + dependencies: + '@ai-sdk/provider': 4.0.17 + '@clack/prompts': 1.8.1 + '@modelcontextprotocol/sdk': 1.30.0(zod@4.6.1) + '@vitest/expect': 5.0.1 + commander: 15.0.0 + picocolors: 1.1.1 + pngjs: 7.0.0 + tsx: 4.23.14 + zod: 4.6.1 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + eastasianwidth@0.2.0: {} ecdsa-sig-formatter@1.0.11: @@ -20539,6 +21062,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.10 '@esbuild/win32-x64': 0.25.10 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-goat@4.0.0: {} @@ -20714,6 +21266,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@5.1.1: dependencies: cross-spawn: 7.0.6 @@ -20746,6 +21302,14 @@ snapshots: exponential-backoff@3.1.3: optional: true + express-rate-limit@8.7.0(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.7.2 + transitivePeerDependencies: + - supports-color + express@4.22.2: dependencies: accepts: 1.3.8 @@ -20782,6 +21346,39 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.8: {} extend-shallow@2.0.1: @@ -20811,8 +21408,18 @@ snapshots: fast-safe-stringify@2.1.1: {} + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + fast-uri@3.1.0: {} + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -20889,6 +21496,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-cache-dir@4.0.0: dependencies: common-path-prefix: 3.0.0 @@ -20967,6 +21585,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + fs-constants@1.0.0: optional: true @@ -20981,9 +21601,6 @@ snapshots: minipass: 7.1.2 optional: true - fsevents@2.3.2: - optional: true - fsevents@2.3.3: optional: true @@ -21547,6 +22164,8 @@ snapshots: dependencies: react-is: 16.13.1 + hono@4.13.10: {} + hookable@6.0.1: {} hosted-git-info@8.1.0: @@ -21810,6 +22429,8 @@ snapshots: ip-address@10.1.0: {} + ip-address@10.7.2: {} + ipaddr.js@1.9.1: {} ipaddr.js@2.3.0: {} @@ -21900,6 +22521,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-regexp@1.0.0: {} is-ssh@1.4.1: @@ -22030,8 +22653,7 @@ snapshots: '@sideway/formula': 3.0.1 '@sideway/pinpoint': 2.0.0 - jose@6.2.10: - optional: true + jose@6.2.10: {} js-levenshtein@1.1.6: {} @@ -22097,6 +22719,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -22649,8 +23273,7 @@ snapshots: media-typer@0.3.0: {} - media-typer@1.1.0: - optional: true + media-typer@1.1.0: {} memfs@4.51.1: dependencies: @@ -22667,6 +23290,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -23170,8 +23795,7 @@ snapshots: negotiator@0.6.4: {} - negotiator@1.0.0: - optional: true + negotiator@1.0.0: {} neo-async@2.6.2: {} @@ -23354,7 +23978,6 @@ snapshots: once@1.4.0: dependencies: wrappy: 1.0.2 - optional: true onetime@5.1.2: dependencies: @@ -23660,6 +24283,8 @@ snapshots: path-to-regexp@3.3.0: {} + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} pathe@2.0.3: {} @@ -23711,6 +24336,8 @@ snapshots: pidtree@0.6.0: {} + pkce-challenge@5.0.1: {} + pkg-dir@7.0.0: dependencies: find-up: 6.3.0 @@ -23727,13 +24354,13 @@ snapshots: exsolve: 1.0.8 pathe: 2.0.3 - playwright-core@1.61.0: {} + playwright-core@1.63.0: {} - playwright@1.61.0: + playwright@1.63.0: dependencies: - playwright-core: 1.61.0 - optionalDependencies: - fsevents: 2.3.2 + playwright-core: 1.63.0 + + pngjs@7.0.0: {} points-on-curve@0.2.0: {} @@ -24351,7 +24978,6 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 unpipe: 1.0.0 - optional: true rc9@2.1.2: dependencies: @@ -24809,7 +25435,7 @@ snapshots: tsx: 4.20.6 yaml: 2.8.2 - rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): + rolldown-vite@7.1.14(@types/node@25.2.3)(esbuild@0.25.10)(jiti@2.6.1)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2): dependencies: '@oxc-project/runtime': 0.92.0 fdir: 6.5.0(picomatch@4.0.3) @@ -24824,7 +25450,7 @@ snapshots: fsevents: 2.3.3 jiti: 2.6.1 terser: 5.44.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.8.2 rolldown@1.0.0-beta.41: @@ -24921,6 +25547,16 @@ snapshots: points-on-curve: 0.2.0 points-on-path: 0.2.1 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.8.0: {} rtlcss@4.3.0: @@ -25037,6 +25673,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + sequelize-pool@7.1.0: {} sequelize@6.37.7(pg@8.18.0): @@ -25097,6 +25749,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -25605,6 +26266,8 @@ snapshots: tinyrainbow@2.0.0: {} + tinyrainbow@3.1.1: {} + tinyspy@4.0.4: {} tldts-core@7.0.17: {} @@ -25711,6 +26374,12 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tsx@4.23.14: + dependencies: + esbuild: 0.28.2 + optionalDependencies: + fsevents: 2.3.3 + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 @@ -25767,7 +26436,6 @@ snapshots: content-type: 1.0.5 media-typer: 1.1.0 mime-types: 3.0.2 - optional: true typed-array-buffer@1.0.3: dependencies: @@ -26121,13 +26789,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): + vite-node@3.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -26153,7 +26821,7 @@ snapshots: - supports-color - typescript - vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): + vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2): dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) @@ -26167,7 +26835,7 @@ snapshots: jiti: 2.6.1 lightningcss: 1.30.2 terser: 5.44.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.8.2 vite@7.2.4(@types/node@24.7.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): @@ -26187,7 +26855,7 @@ snapshots: tsx: 4.20.6 yaml: 2.8.2 - vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): + vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2): dependencies: esbuild: 0.25.10 fdir: 6.5.0(picomatch@4.0.3) @@ -26201,7 +26869,7 @@ snapshots: jiti: 2.6.1 lightningcss: 1.30.2 terser: 5.44.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.8.2 vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.7.2)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): @@ -26247,11 +26915,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/debug@4.1.12)(@types/node@25.2.3)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@25.2.3)(jiti@2.6.1)(jsdom@27.0.0(postcss@8.5.6))(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -26269,8 +26937,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.2) + vite: 7.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.23.14)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 @@ -26556,8 +27224,7 @@ snapshots: string-width: 7.2.0 strip-ansi: 7.1.2 - wrappy@1.0.2: - optional: true + wrappy@1.0.2: {} write-file-atomic@3.0.3: dependencies: @@ -26636,6 +27303,10 @@ snapshots: dependencies: zod: 4.3.6 + zod-to-json-schema@3.25.2(zod@4.6.1): + dependencies: + zod: 4.6.1 + zod-validation-error@4.0.2(zod@4.1.13): dependencies: zod: 4.1.13 @@ -26644,6 +27315,8 @@ snapshots: zod@4.3.6: {} + zod@4.6.1: {} + zrender@6.0.0: dependencies: tslib: 2.3.0