diff --git a/.claude/reference/feature-flags.md b/.claude/reference/feature-flags.md index 0d74bd969b..dbe9dd3f50 100644 --- a/.claude/reference/feature-flags.md +++ b/.claude/reference/feature-flags.md @@ -33,6 +33,7 @@ if (features.platform) { | `branding` | Rivet branding chrome. | | `datacenter` | Datacenter-related UI. | | `danger-zone` | Destructive settings actions (`features.dangerZone`). | +| `mcp` | MCP connection settings card on the namespace settings drawer. Flavor-dependent content: `platform` renders the hosted `mcp.rivet.dev` endpoint pinned to this namespace, everything else renders the local stdio (`npx @rivet-dev/mcp`) config. | Deployment flavors map to flag sets roughly as: **cloud** = all on; **OSS** = `auth`/`platform`/`acl` off; **enterprise** = `acl` on, `auth`/`platform` off (engine enforces auth without a login UI). Do not treat `platform`/`auth` as "engine requires credentials" — that is `acl`. **`compute` is opt-in even on cloud** — each Railway service adds it to `VITE_FEATURE_FLAGS` per-environment (e.g. staging on, prod off) rather than inheriting the cloud default-on set. @@ -48,15 +49,18 @@ Switch flavors in dev without restarting the server by setting the `localStorage // OSS self-host: everything off localStorage.setItem("FEATURE_FLAGS", ""); location.reload(); +// OSS self-host with the local MCP snippet shown +localStorage.setItem("FEATURE_FLAGS", "mcp"); location.reload(); + // Full cloud: all flags on (see the commented canonical list in frontend/.env.local) localStorage.setItem( "FEATURE_FLAGS", - "compute,platform,acl,auth,captcha,branding,support,billing,datacenter,danger-zone,multitenancy", + "compute,platform,acl,auth,captcha,branding,support,billing,datacenter,danger-zone,multitenancy,mcp", ); location.reload(); // Enterprise: acl on, no login UI -localStorage.setItem("FEATURE_FLAGS", "acl,branding,support,datacenter,danger-zone"); location.reload(); +localStorage.setItem("FEATURE_FLAGS", "acl,branding,support,datacenter,danger-zone,mcp"); location.reload(); ``` In an agent-browser / DevTools session, paste those into the page console. `localStorage` persists across reloads, so run `localStorage.removeItem("FEATURE_FLAGS")` to return to the env default when finished. Confirm the active flavor with `JSON.stringify(features)` after importing, or just observe whether auth/cloud chrome is present. diff --git a/frontend/apps/inspector-ui/mcp-index.html b/frontend/apps/inspector-ui/mcp-index.html new file mode 100644 index 0000000000..0aaa4e8a72 --- /dev/null +++ b/frontend/apps/inspector-ui/mcp-index.html @@ -0,0 +1,57 @@ + + + + + + Rivet Actor Inspector + + + +
+ + + diff --git a/frontend/apps/inspector-ui/src/main.tsx b/frontend/apps/inspector-ui/src/main.tsx index ef56887310..171ecd5588 100644 --- a/frontend/apps/inspector-ui/src/main.tsx +++ b/frontend/apps/inspector-ui/src/main.tsx @@ -62,32 +62,65 @@ function InspectorContent({ actorId, activeTab, bridge, + standalone = false, }: { actorId: ActorId; activeTab: string | undefined; - bridge: BridgeClient; + bridge?: BridgeClient; + standalone?: boolean; }) { const availableTabs = useAvailableInspectorTabs(actorId); + const [standaloneTab, setStandaloneTab] = useState(); useEffect(() => { - if (availableTabs) bridge.sendTabsAvailable(availableTabs); + if (availableTabs) bridge?.sendTabsAvailable(availableTabs); }, [bridge, availableTabs]); - return ; + const selectedTab = activeTab ?? standaloneTab ?? availableTabs?.[0]?.id; + return ( +
+ {standalone && availableTabs ? ( + + ) : null} +
+ +
+
+ ); } -function InspectorApp({ +export function InspectorApp({ actorId, credentials, bridge, activeTab, initialVersion, + standalone, }: { actorId: ActorId; credentials: { url: string; inspectorToken: string; token: string }; - bridge: BridgeClient; + bridge?: BridgeClient; activeTab: string | undefined; initialVersion?: string; + standalone?: boolean; }) { const queryClient = useMemo( () => @@ -123,6 +156,7 @@ function InspectorApp({ actorId={actorId} activeTab={activeTab} bridge={bridge} + standalone={standalone} /> @@ -192,13 +226,15 @@ function BootGate({ bridge }: { bridge: BridgeClient }) { ); } -const bridge = new BridgeClient(); -const rootEl = document.getElementById("root"); -if (!rootEl) throw new Error("Inspector UI: #root element missing"); -ReactDOM.createRoot(rootEl).render( - - - - - , -); +if (!__MCP_APP__) { + const bridge = new BridgeClient(); + const rootEl = document.getElementById("root"); + if (!rootEl) throw new Error("Inspector UI: #root element missing"); + ReactDOM.createRoot(rootEl).render( + + + + + , + ); +} diff --git a/frontend/apps/inspector-ui/src/mcp-main.tsx b/frontend/apps/inspector-ui/src/mcp-main.tsx new file mode 100644 index 0000000000..c84c981474 --- /dev/null +++ b/frontend/apps/inspector-ui/src/mcp-main.tsx @@ -0,0 +1,204 @@ +import { App } from "@modelcontextprotocol/ext-apps"; +import { useEffect, useState } from "react"; +import ReactDOM from "react-dom/client"; +import type { ActorId } from "@/components/actors/queries"; +import "@/index.css"; +import { InspectorApp } from "./main"; + +type ActorTarget = + | { actorId: string } + | { name: string; key?: string[]; method: "get"; skipReadyWait?: boolean } + | { + name: string; + key?: string[]; + method: "getOrCreate"; + pool: string; + input?: unknown; + region?: string; + crashPolicy?: "restart" | "sleep" | "destroy"; + skipReadyWait?: boolean; + }; + +type InspectorGrant = { + token: string; + proxyUrl: string; + expiresAt: string; + actorId: string; + dashboardUrl?: string; +}; + +const app = new App( + { name: "Rivet Actor Inspector", version: "0.1.0" }, + {}, + { strict: true }, +); + +let currentActor: ActorTarget | undefined; +let currentGrant: InspectorGrant | undefined; + +function structuredGrant( + result: Awaited>, +): InspectorGrant { + if (result.isError || !result.structuredContent) { + throw new Error("Could not create the temporary Inspector session"); + } + const value = result.structuredContent as Record; + for (const key of ["token", "proxyUrl", "expiresAt", "actorId"] as const) { + if (typeof value[key] !== "string") + throw new Error("Invalid Inspector session response"); + } + return value as InspectorGrant; +} + +async function createSession(actor: ActorTarget): Promise { + return structuredGrant( + await app.callServerTool({ + name: "rivet.ui.actor.session.create", + arguments: { actor }, + }), + ); +} + +async function renewSession(token: string): Promise { + return structuredGrant( + await app.callServerTool({ + name: "rivet.ui.actor.session.renew", + arguments: { token }, + }), + ); +} + +async function revokeSession(token: string): Promise { + await app.callServerTool({ + name: "rivet.ui.actor.session.revoke", + arguments: { token }, + }); +} + +// `create` mints a new session record rather than rotating the current one, so +// the grant it replaces stays valid until its own TTL and keeps counting +// against the per-principal session limit. `renew` rotates in place and needs +// no revocation. Hosts may fire tool results back to back, so swaps are +// serialized to keep a concurrent pair from both reading the same outgoing +// grant and leaking one of them. +let sessionSwap: Promise = Promise.resolve(); + +function replaceSession(actor: ActorTarget): Promise { + const swap = sessionSwap.then(async () => { + const superseded = currentGrant; + const next = await createSession(actor); + currentGrant = next; + if (superseded) await revokeSession(superseded.token).catch(() => {}); + return next; + }); + sessionSwap = swap.catch(() => {}); + return swap; +} + +function McpInspector() { + const [grant, setGrant] = useState(); + const [error, setError] = useState(); + + useEffect(() => { + const receiveInput = (params: { + arguments?: Record; + }) => { + const actor = params.arguments?.actor; + if (actor && typeof actor === "object") + currentActor = actor as ActorTarget; + }; + const receiveResult = () => { + if (!currentActor) return; + void replaceSession(currentActor) + .then(setGrant) + .catch(() => + setError("Could not authenticate the embedded Inspector."), + ); + }; + app.addEventListener("toolinput", receiveInput); + app.addEventListener("toolresult", receiveResult); + app.onhostcontextchanged = (context) => { + document.documentElement.classList.toggle( + "dark", + context.theme !== "light", + ); + }; + app.onteardown = async () => { + if (currentGrant) await revokeSession(currentGrant.token); + return {}; + }; + void app + .connect() + .catch(() => + setError("This host could not initialize the MCP App."), + ); + return () => { + app.removeEventListener("toolinput", receiveInput); + app.removeEventListener("toolresult", receiveResult); + }; + }, []); + + useEffect(() => { + if (!grant) return; + const renewAt = Math.max( + 1_000, + new Date(grant.expiresAt).getTime() - Date.now() - 30_000, + ); + const timer = window.setTimeout(() => { + void renewSession(grant.token) + .then((next) => { + currentGrant = next; + setGrant(next); + }) + .catch(() => + setError( + "The Inspector session expired. Reopen the Inspector to continue.", + ), + ); + }, renewAt); + return () => window.clearTimeout(timer); + }, [grant]); + + if (error) return

{error}

; + if (!grant) + return ( +

+ Connecting to the Rivet Actor Inspector… +

+ ); + return ( +
+ {grant.dashboardUrl ? ( +
+ Console and custom tabs are available in the{" "} + + full Rivet Inspector + + . +
+ ) : null} +
+ +
+
+ ); +} + +const root = document.getElementById("root"); +if (!root) throw new Error("Inspector UI: #root element missing"); +ReactDOM.createRoot(root).render(); diff --git a/frontend/apps/inspector-ui/src/vite-env.d.ts b/frontend/apps/inspector-ui/src/vite-env.d.ts index de5cc2235c..08f95bb406 100644 --- a/frontend/apps/inspector-ui/src/vite-env.d.ts +++ b/frontend/apps/inspector-ui/src/vite-env.d.ts @@ -1,4 +1,6 @@ /// +declare const __MCP_APP__: boolean; + // rivetkit's package version, baked in at build time. See vite.config.ts. declare const __RIVETKIT_VERSION__: string; diff --git a/frontend/apps/inspector-ui/vite.config.ts b/frontend/apps/inspector-ui/vite.config.ts index aa35a76ed1..e6eb64636a 100644 --- a/frontend/apps/inspector-ui/vite.config.ts +++ b/frontend/apps/inspector-ui/vite.config.ts @@ -31,6 +31,7 @@ export default defineConfig({ envDir: path.resolve(__dirname, "../.."), plugins: [react(), tsconfigPaths()], define: { + __MCP_APP__: JSON.stringify(false), __APP_TYPE__: JSON.stringify("inspector"), __APP_BUILD_ID__: JSON.stringify( `${new Date().toISOString()}@${crypto.randomUUID()}`, diff --git a/frontend/apps/inspector-ui/vite.mcp.config.ts b/frontend/apps/inspector-ui/vite.mcp.config.ts new file mode 100644 index 0000000000..8042047b22 --- /dev/null +++ b/frontend/apps/inspector-ui/vite.mcp.config.ts @@ -0,0 +1,119 @@ +import { readFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import path from "node:path"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; +import { viteSingleFile } from "vite-plugin-singlefile"; +import tsconfigPaths from "vite-tsconfig-paths"; + +const rivetkitVersion = JSON.parse( + readFileSync( + path.resolve( + __dirname, + "../../../rivetkit-typescript/packages/rivetkit/package.json", + ), + "utf8", + ), +).version as string; +const require = createRequire(path.resolve(__dirname, "package.json")); +const WORKER_IMPORT = 'import ActorWorker from "./actor-repl.worker?worker";'; +let sawConsoleWorker = false; + +export default defineConfig({ + root: path.resolve(__dirname), + base: "./", + plugins: [ + { + name: "fallback-unavailable-mcp-icons", + enforce: "pre", + transform(code, id) { + if (!id.endsWith("/packages/icons/src/index.gen.js")) return; + let usedFallback = false; + const transformed = code.replace( + /export \{([^}]+)\} from "([^"]+)";/g, + (statement, names: string, specifier: string) => { + try { + require.resolve(specifier); + return statement; + } catch { + usedFallback = true; + const aliases = names.split(",").map((entry) => { + const parts = entry.trim().split(/\s+as\s+/); + return `__mcpFallbackIcon as ${parts.at(-1)}`; + }); + return `export { ${aliases.join(", ")} };`; + } + }, + ); + if (!usedFallback) return transformed; + return `${transformed}\nconst __mcpFallbackIcon = { prefix: "fas", iconName: "circle", icon: [16, 16, [], "", "M8 1a7 7 0 1 0 0 14A7 7 0 0 0 8 1Z"] };`; + }, + }, + react(), + { + name: "disable-unsupported-mcp-console-worker", + enforce: "pre", + transform(code, id) { + if (!id.endsWith("/actor-worker-container.ts")) return; + // viteSingleFile cannot inline a `?worker` chunk, so a silently + // unmatched import ships a bundle whose console throws at load. + if (!code.includes(WORKER_IMPORT)) { + throw new Error( + `${id} no longer contains ${WORKER_IMPORT}; update the MCP console worker stub`, + ); + } + sawConsoleWorker = true; + return code.replace( + WORKER_IMPORT, + `class ActorWorker extends EventTarget { + constructor() { + super(); + throw new Error("The actor console is unavailable in the embedded Inspector."); + } + postMessage() {} + terminate() {} +}`, + ); + }, + buildEnd() { + if (!sawConsoleWorker) { + throw new Error( + "actor-worker-container.ts was never transformed; the MCP console worker stub did not apply", + ); + } + }, + }, + tsconfigPaths({ projects: [path.resolve(__dirname, "tsconfig.json")] }), + viteSingleFile(), + ], + resolve: { + alias: { + "@rivet-gg/icons": path.resolve( + __dirname, + "../../packages/icons/src/index.gen.js", + ), + "@": path.resolve(__dirname, "../../src"), + }, + }, + define: { + __MCP_APP__: JSON.stringify(true), + __APP_TYPE__: JSON.stringify("inspector"), + __APP_BUILD_ID__: JSON.stringify("mcp-actor-inspector"), + __RIVETKIT_VERSION__: JSON.stringify(rivetkitVersion), + }, + optimizeDeps: { + include: ["@fortawesome/*", "@rivet-gg/icons", "@rivet-gg/cloud"], + }, + worker: { format: "es" }, + build: { + outDir: "../../dist/mcp-inspector-ui", + emptyOutDir: true, + sourcemap: false, + cssCodeSplit: false, + rollupOptions: { + input: path.resolve(__dirname, "mcp-index.html"), + output: { inlineDynamicImports: true }, + }, + commonjsOptions: { include: [/@rivet-gg\/components/, /node_modules/] }, + }, +}); diff --git a/frontend/package.json b/frontend/package.json index cade20f977..f1bb728c7a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "build:ladle": "ladle build" }, "dependencies": { + "@better-auth/oauth-provider": "1.6.23", "@codemirror/autocomplete": "^6.18.7", "@codemirror/commands": "^6.8.1", "@codemirror/lang-javascript": "^6.2.4", @@ -37,6 +38,8 @@ "@ladle/react": "^5.1.1", "@marsidev/react-turnstile": "^1.5.0", "@microsoft/fetch-event-source": "^2.0.1", + "@modelcontextprotocol/ext-apps": "1.7.4", + "@modelcontextprotocol/sdk": "1.29.0", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-avatar": "^1.1.10", "@radix-ui/react-checkbox": "^1.3.3", @@ -117,7 +120,7 @@ "actor-core": "^0.6.3", "autoprefixer": "^10.4.21", "bcryptjs": "^2.4.3", - "better-auth": "^1.5.6", + "better-auth": "1.6.23", "canvas-confetti": "^1.9.3", "cbor-x": "^1.6.0", "class-variance-authority": "^0.7.1", @@ -162,6 +165,7 @@ "usehooks-ts": "^3.1.1", "vite": "^5.4.20", "vite-plugin-favicons-inject": "^2.2.0", + "vite-plugin-singlefile": "2.3.3", "vite-tsconfig-paths": "^5.1.4", "zod": "^3.25.76" }, diff --git a/frontend/src/app/settings-pages/mcp-connection.tsx b/frontend/src/app/settings-pages/mcp-connection.tsx new file mode 100644 index 0000000000..3d07eaf49b --- /dev/null +++ b/frontend/src/app/settings-pages/mcp-connection.tsx @@ -0,0 +1,231 @@ +import { + faChevronRight, + faClaude, + faCursor, + faGemini, + faPlug, + faVscode, + Icon, + type IconProp, +} from "@rivet-gg/icons"; +import { useParams } from "@tanstack/react-router"; +import { useState } from "react"; +import { + CodeFrame, + CodeGroup, + CodePreview, + getConfig, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components"; +import { useEngineCompatDataProvider } from "@/components/actors"; +import { getMcpUrl } from "@/lib/env"; +import { features } from "@/lib/features"; +import { + type HostedTarget, + hostedUrl, + SCOPE_ORDER, + SCOPES, + type Scope, +} from "./mcp-scope"; +import { SettingsCard } from "./settings-card"; + +const DOCS_URL = "https://rivet.dev/mcp"; + +const DESCRIPTION = + "Let AI tools like Claude Code and Cursor read and manage your actors."; + +type Language = "json" | "bash"; + +interface ClientTab { + title: string; + icon: IconProp; + language: Language; + code: string; +} + +function json(value: unknown) { + return JSON.stringify(value, null, 2); +} + +function hostedTabs(url: string): ClientTab[] { + return [ + { + title: "Claude Code", + icon: faClaude, + language: "bash", + code: `claude mcp add --transport http rivet "${url}"`, + }, + { + title: "Cursor", + icon: faCursor, + language: "json", + code: json({ mcpServers: { rivet: { url } } }), + }, + { + title: "VS Code", + icon: faVscode, + language: "bash", + code: `code --add-mcp '${JSON.stringify({ name: "rivet", type: "http", url })}'`, + }, + { + title: "Gemini CLI", + icon: faGemini, + language: "json", + code: json({ mcpServers: { rivet: { httpUrl: url } } }), + }, + { + title: "Other", + icon: faPlug, + language: "json", + code: json({ mcpServers: { rivet: { type: "http", url } } }), + }, + ]; +} + +function localTabs(endpoint: string, namespace: string): ClientTab[] { + const command = "npx"; + const args = ["-y", "@rivet-dev/mcp", "--target", "local"]; + const env = { RIVET_ENDPOINT: endpoint, RIVET_NAMESPACE: namespace }; + const server = { command, args, env }; + + return [ + { + title: "Claude Code", + icon: faClaude, + language: "bash", + code: `claude mcp add rivet \\ + --env RIVET_ENDPOINT=${endpoint} \\ + --env RIVET_NAMESPACE=${namespace} \\ + -- ${command} ${args.join(" ")}`, + }, + { + title: "Cursor", + icon: faCursor, + language: "json", + code: json({ mcpServers: { rivet: server } }), + }, + { + title: "VS Code", + icon: faVscode, + language: "bash", + code: `code --add-mcp '${JSON.stringify({ name: "rivet", ...server })}'`, + }, + { + title: "Gemini CLI", + icon: faGemini, + language: "json", + code: json({ mcpServers: { rivet: server } }), + }, + { + title: "Other", + icon: faPlug, + language: "json", + code: json({ mcpServers: { rivet: server } }), + }, + ]; +} + +function DocsFooter() { + return ( + + + See MCP Documentation{" "} + + + + ); +} + +function ClientTabs({ tabs }: { tabs: ClientTab[] }) { + return ( + + {tabs.map((tab) => ( + tab.code} + footer={} + > + + + ))} + + ); +} + +function ScopeSelect({ + value, + onValueChange, +}: { + value: Scope; + onValueChange: (value: Scope) => void; +}) { + return ( + + ); +} + +function HostedMcp() { + const params = useParams({ strict: false }) as Partial; + const [scope, setScope] = useState("namespace"); + + if (!params.organization || !params.project || !params.namespace) { + return null; + } + + const target: HostedTarget = { + organization: params.organization, + project: params.project, + namespace: params.namespace, + }; + return ( + } + > + + + ); +} + +function LocalMcp() { + const namespace = useEngineCompatDataProvider().engineNamespace; + const endpoint = getConfig().apiUrl; + + return ( + + + + ); +} + +export function McpConnection() { + if (!features.mcp) return null; + return features.platform ? : ; +} diff --git a/frontend/src/app/settings-pages/mcp-scope.test.ts b/frontend/src/app/settings-pages/mcp-scope.test.ts new file mode 100644 index 0000000000..7601e14b8e --- /dev/null +++ b/frontend/src/app/settings-pages/mcp-scope.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from "vitest"; +import { hostedUrl, type Scope } from "./mcp-scope"; + +const BASE = "https://mcp.rivet.dev/mcp"; +const TARGET = { + organization: "acme", + project: "prod", + namespace: "canary", +}; + +function params(scope: Scope) { + return Object.fromEntries( + new URL(hostedUrl(BASE, TARGET, scope)).searchParams, + ); +} + +describe("hostedUrl", () => { + it("pins every level for the namespace scope", () => { + expect(params("namespace")).toEqual(TARGET); + }); + + it("leaves the namespace open for the project scope", () => { + expect(params("project")).toEqual({ + organization: "acme", + project: "prod", + }); + }); + + it("leaves the project open for the organization scope", () => { + expect(params("organization")).toEqual({ organization: "acme" }); + }); + + it("emits no query at all for the account scope", () => { + expect(hostedUrl(BASE, TARGET, "account")).toBe(BASE); + }); +}); diff --git a/frontend/src/app/settings-pages/mcp-scope.ts b/frontend/src/app/settings-pages/mcp-scope.ts new file mode 100644 index 0000000000..edeb46e577 --- /dev/null +++ b/frontend/src/app/settings-pages/mcp-scope.ts @@ -0,0 +1,54 @@ +export type Scope = "namespace" | "project" | "organization" | "account"; + +export interface HostedTarget { + organization: string; + project: string; + namespace: string; +} + +export const SCOPES: Record< + Scope, + { label: string; reach: string; pins: (keyof HostedTarget)[] } +> = { + namespace: { + label: "This namespace", + reach: "only this namespace", + pins: ["organization", "project", "namespace"], + }, + project: { + label: "This project", + reach: "any namespace in this project", + pins: ["organization", "project"], + }, + organization: { + label: "This organization", + reach: "any project in this organization", + pins: ["organization"], + }, + account: { + label: "Entire account", + reach: "any project in your account", + pins: [], + }, +}; + +export const SCOPE_ORDER: Scope[] = [ + "namespace", + "project", + "organization", + "account", +]; + +// Levels left out of the query stay open for the agent to name per call. Every +// level that is present is a hard pin the session cannot move off, so a +// narrower scope is the safer default. +export function hostedUrl( + base: string, + target: HostedTarget, + scope: Scope, +): string { + const query = new URLSearchParams(); + for (const level of SCOPES[scope].pins) query.set(level, target[level]); + const search = query.toString(); + return search ? `${base}?${search}` : base; +} diff --git a/frontend/src/app/settings-pages/namespace-settings.tsx b/frontend/src/app/settings-pages/namespace-settings.tsx index a75967fa7d..a6451a1f80 100644 --- a/frontend/src/app/settings-pages/namespace-settings.tsx +++ b/frontend/src/app/settings-pages/namespace-settings.tsx @@ -24,6 +24,7 @@ import { PublishableToken, SecretToken, } from "@/routes/_context/orgs.$organization/projects.$project/ns.$namespace/tokens"; +import { McpConnection } from "./mcp-connection"; import { SettingsCard } from "./settings-card"; export function NamespaceSettingsContent() { @@ -52,6 +53,7 @@ export function NamespaceAdvancedContent() { {features.auth ? : null} {features.auth ? : null} + {features.dangerZone ? : null} diff --git a/frontend/src/components/actors/actor-inspector-context.tsx b/frontend/src/components/actors/actor-inspector-context.tsx index 67dceaa67b..ebdcf4ec33 100644 --- a/frontend/src/components/actors/actor-inspector-context.tsx +++ b/frontend/src/components/actors/actor-inspector-context.tsx @@ -658,8 +658,11 @@ export const createDefaultActorInspectorContext = ({ }, }); +// The base may carry a path prefix (the MCP Inspector proxy is mounted under +// /mcp/inspector-proxy), so the segment must stay relative. A leading slash +// would resolve against the origin and drop that prefix. const computeActorUrl = ({ url, actorId }: { url: string; actorId: ActorId }) => - new URL(`/gateway/${actorId}`, url).href; + new URL(`gateway/${actorId}`, url.endsWith("/") ? url : `${url}/`).href; function transformWorkflowHistoryFromJson(raw: number[] | null): { history: WorkflowHistory | null; diff --git a/frontend/src/components/actors/inspector-tab-registry.tsx b/frontend/src/components/actors/inspector-tab-registry.tsx index e314dc34ce..d0511f467e 100644 --- a/frontend/src/components/actors/inspector-tab-registry.tsx +++ b/frontend/src/components/actors/inspector-tab-registry.tsx @@ -124,6 +124,12 @@ export const INSPECTOR_TAB_REGISTRATIONS: readonly TabRegistration[] = [ }, ] as const; +const availableInspectorRegistrations = __MCP_APP__ + ? INSPECTOR_TAB_REGISTRATIONS.filter( + (registration) => registration.descriptor.id !== "console", + ) + : INSPECTOR_TAB_REGISTRATIONS; + /** * Returns the descriptors of all inspector tabs available for this actor, * filtered by the live capability flags from the inspector context. Returns @@ -179,12 +185,15 @@ export function useAvailableInspectorTabs( .filter((t) => t.hidden === true) .map((t) => t.id), ); - const builtIns = INSPECTOR_TAB_REGISTRATIONS.filter((t) => + const builtIns = availableInspectorRegistrations.filter((t) => t.available(caps), ) .map((t) => t.descriptor) .filter((d) => !hideSet.has(d.id)); - const customs: InspectorTabDescriptor[] = (tabConfig?.tabs ?? []) + const customs: InspectorTabDescriptor[] = (__MCP_APP__ + ? [] + : (tabConfig?.tabs ?? []) + ) .filter((t) => t.hidden !== true && typeof t.label === "string") .map((t) => ({ id: t.id, @@ -224,7 +233,7 @@ export function InspectorTabContent({ actorId: ActorId; activeTab: string | undefined; }) { - const registration = INSPECTOR_TAB_REGISTRATIONS.find( + const registration = availableInspectorRegistrations.find( (t) => t.descriptor.id === activeTab, ); if (!registration) return null; diff --git a/frontend/src/lib/auth.ts b/frontend/src/lib/auth.ts index bad7a6f077..34c7ea5e13 100644 --- a/frontend/src/lib/auth.ts +++ b/frontend/src/lib/auth.ts @@ -1,4 +1,5 @@ import { notFound, redirect } from "@tanstack/react-router"; +import { oauthProviderClient } from "@better-auth/oauth-provider/client"; import { adminClient, organizationClient } from "better-auth/client/plugins"; import { createAuthClient } from "better-auth/react"; import { cloudEnv } from "./env"; @@ -8,7 +9,7 @@ const createClient = () => createAuthClient({ baseURL: cloudEnv().VITE_APP_CLOUD_API_URL, fetchOptions: { credentials: "include" }, - plugins: [organizationClient(), adminClient()], + plugins: [organizationClient(), adminClient(), oauthProviderClient()], }); type AuthClient = ReturnType; diff --git a/frontend/src/lib/env.ts b/frontend/src/lib/env.ts index 89483f012f..6d4522379d 100644 --- a/frontend/src/lib/env.ts +++ b/frontend/src/lib/env.ts @@ -28,6 +28,9 @@ export const cloudEnvSchema = commonEnvSchema.merge( z.object({ // Cloud API endpoint - direct URL without transformation, used for cloud-specific operations VITE_APP_CLOUD_API_URL: z.string().url(), + // Hosted MCP endpoint. Unset on Rivet Cloud; self-hosted deployments + // point this at their own MCP service. + VITE_APP_MCP_URL: z.string().url().optional(), VITE_APP_SENTRY_TUNNEL: z.string().optional(), VITE_APP_TURNSTILE_SITE_KEY: z.string().optional(), }), @@ -35,6 +38,9 @@ export const cloudEnvSchema = commonEnvSchema.merge( export const cloudEnv = () => cloudEnvSchema.parse(import.meta.env); +export const getMcpUrl = () => + cloudEnv().VITE_APP_MCP_URL ?? "https://mcp.rivet.dev/mcp"; + export const getRivetRunUrl = (engineNsName: string) => { return cloudEnv().VITE_DEPLOYMENT_TYPE === "production" ? `https://${engineNsName}.rivet.run/` diff --git a/frontend/src/lib/features.ts b/frontend/src/lib/features.ts index f111bc9d05..0ba2e5ecf0 100644 --- a/frontend/src/lib/features.ts +++ b/frontend/src/lib/features.ts @@ -37,6 +37,9 @@ export const features = { compute: isEnabled("compute") && platform, // `agentOs` gates the agentOS (coding-agent VM) onboarding template. Beta. agentOs: isEnabled("agent-os"), + // `mcp` gates the MCP connection settings. The snippet differs per flavor: + // platform points at the hosted endpoint, OSS at the local stdio server. + mcp: isEnabled("mcp"), support: isEnabled("support"), branding: isEnabled("branding"), datacenter: isEnabled("datacenter"), diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 301f4ed881..f7754a6c3e 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -18,6 +18,7 @@ import { Route as ForgotPasswordRouteImport } from './routes/forgot-password' import { Route as AcceptInvitationRouteImport } from './routes/accept-invitation' import { Route as ContextRouteImport } from './routes/_context' import { Route as ContextIndexRouteImport } from './routes/_context/index' +import { Route as OauthConsentRouteImport } from './routes/oauth.consent' import { Route as ContextNewIndexRouteImport } from './routes/_context/new/index' import { Route as ContextNewOrgIndexRouteImport } from './routes/_context/new-org/index' import { Route as ContextOrgsOrganizationRouteImport } from './routes/_context/orgs.$organization' @@ -84,6 +85,11 @@ const ContextIndexRoute = ContextIndexRouteImport.update({ path: '/', getParentRoute: () => ContextRoute, } as any) +const OauthConsentRoute = OauthConsentRouteImport.update({ + id: '/oauth/consent', + path: '/oauth/consent', + getParentRoute: () => rootRouteImport, +} as any) const ContextNewIndexRoute = ContextNewIndexRouteImport.update({ id: '/new/', path: '/new/', @@ -224,6 +230,7 @@ export interface FileRoutesByFullPath { '/onboarding': typeof OnboardingRoute '/reset-password': typeof ResetPasswordRoute '/verify-email-pending': typeof VerifyEmailPendingRoute + '/oauth/consent': typeof OauthConsentRoute '/ns/$namespace': typeof ContextNsNamespaceRouteWithChildren '/orgs/$organization': typeof ContextOrgsOrganizationRouteWithChildren '/new-org/': typeof ContextNewOrgIndexRoute @@ -254,6 +261,7 @@ export interface FileRoutesByTo { '/onboarding': typeof OnboardingRoute '/reset-password': typeof ResetPasswordRoute '/verify-email-pending': typeof VerifyEmailPendingRoute + '/oauth/consent': typeof OauthConsentRoute '/': typeof ContextIndexRoute '/new-org': typeof ContextNewOrgIndexRoute '/new': typeof ContextNewIndexRoute @@ -283,6 +291,7 @@ export interface FileRoutesById { '/onboarding': typeof OnboardingRoute '/reset-password': typeof ResetPasswordRoute '/verify-email-pending': typeof VerifyEmailPendingRoute + '/oauth/consent': typeof OauthConsentRoute '/_context/': typeof ContextIndexRoute '/_context/ns/$namespace': typeof ContextNsNamespaceRouteWithChildren '/_context/orgs/$organization': typeof ContextOrgsOrganizationRouteWithChildren @@ -317,6 +326,7 @@ export interface FileRouteTypes { | '/onboarding' | '/reset-password' | '/verify-email-pending' + | '/oauth/consent' | '/ns/$namespace' | '/orgs/$organization' | '/new-org/' @@ -347,6 +357,7 @@ export interface FileRouteTypes { | '/onboarding' | '/reset-password' | '/verify-email-pending' + | '/oauth/consent' | '/' | '/new-org' | '/new' @@ -375,6 +386,7 @@ export interface FileRouteTypes { | '/onboarding' | '/reset-password' | '/verify-email-pending' + | '/oauth/consent' | '/_context/' | '/_context/ns/$namespace' | '/_context/orgs/$organization' @@ -408,6 +420,7 @@ export interface RootRouteChildren { OnboardingRoute: typeof OnboardingRoute ResetPasswordRoute: typeof ResetPasswordRoute VerifyEmailPendingRoute: typeof VerifyEmailPendingRoute + OauthConsentRoute: typeof OauthConsentRoute } declare module '@tanstack/react-router' { @@ -475,6 +488,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof ContextIndexRouteImport parentRoute: typeof ContextRoute } + '/oauth/consent': { + id: '/oauth/consent' + path: '/oauth/consent' + fullPath: '/oauth/consent' + preLoaderRoute: typeof OauthConsentRouteImport + parentRoute: typeof rootRouteImport + } '/_context/new/': { id: '/_context/new/' path: '/new' @@ -746,6 +766,7 @@ const rootRouteChildren: RootRouteChildren = { OnboardingRoute: OnboardingRoute, ResetPasswordRoute: ResetPasswordRoute, VerifyEmailPendingRoute: VerifyEmailPendingRoute, + OauthConsentRoute: OauthConsentRoute, } export const routeTree = rootRouteImport ._addFileChildren(rootRouteChildren) diff --git a/frontend/src/routes/oauth.consent.tsx b/frontend/src/routes/oauth.consent.tsx new file mode 100644 index 0000000000..16d7f19cbf --- /dev/null +++ b/frontend/src/routes/oauth.consent.tsx @@ -0,0 +1,309 @@ +import { useMutation, useQuery } from "@tanstack/react-query"; +import { createFileRoute, redirect } from "@tanstack/react-router"; +import { useMemo } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { z } from "zod"; +import { Logo } from "@/app/logo"; +import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; +import { Skeleton } from "@/components/ui/skeleton"; +import { authClient } from "@/lib/auth"; + +const searchSchema = z.object({ + client_id: z.string(), + scope: z.string(), + oauth_query: z.string().optional(), +}); + +interface ScopeDetail { + title: string; + description: string; +} + +// The MCP entrypoint verifies every request against rivet:cloud:read, so a +// grant without it yields a token that cannot call anything. +const REQUIRED_SCOPES = new Set(["rivet:cloud:read"]); + +const SCOPE_DETAILS: Record = { + openid: { + title: "Confirm your identity", + description: + "Share your Rivet user ID so the client knows who signed in.", + }, + offline_access: { + title: "Stay signed in", + description: + "Reconnect without asking you again. Access tokens expire after 15 minutes.", + }, + "rivet:cloud:read": { + title: "View your organizations and projects", + description: + "List organizations, projects, and namespaces, and read their usage metrics.", + }, + "rivet:cloud:write": { + title: "Manage your organizations and projects", + description: + "Change cloud resources on your behalf. Destructive and credential operations stay unavailable.", + }, + "rivet:actors:read": { + title: "View your actors", + description: + "List actors in the selected namespace and send them read-only requests.", + }, + "rivet:actors:write": { + title: "Modify your actors", + description: "Send requests that change actor state or lifecycle.", + }, + "rivet:inspector:read": { + title: "Inspect actor internals", + description: + "Read actor state, database contents, and logs through the Actor Inspector.", + }, + "rivet:inspector:write": { + title: "Modify actor internals", + description: + "Edit state and run commands against an actor through the Actor Inspector.", + }, +}; + +export const Route = createFileRoute("/oauth/consent")({ + validateSearch: searchSchema, + beforeLoad: async ({ location }) => { + const session = await authClient.getSession(); + if (!session.data) { + throw redirect({ + to: "/login", + search: { from: `${location.pathname}${location.searchStr}` }, + }); + } + }, + component: OAuthConsent, +}); + +interface ConsentFormValues { + scopes: Record; +} + +function OAuthConsent() { + const search = Route.useSearch(); + const requestedScopes = useMemo( + () => search.scope.split(/\s+/).filter(Boolean), + [search.scope], + ); + const { control, handleSubmit, watch } = useForm({ + defaultValues: { + scopes: Object.fromEntries( + requestedScopes.map((scope) => [scope, true]), + ), + }, + }); + const granted = watch("scopes"); + const grantedCount = requestedScopes.filter( + (scope) => granted[scope], + ).length; + + // Dynamically registered clients pick their own opaque client_id, so the + // name they registered under is the only human-readable identifier. + const { data: client, isPending: isClientPending } = useQuery({ + queryKey: ["oauth", "public-client", search.client_id], + queryFn: async () => { + const result = await authClient.oauth2.publicClient({ + query: { client_id: search.client_id }, + }); + if (result.error) { + throw new Error( + result.error.message ?? "Could not load client.", + ); + } + return result.data; + }, + retry: false, + }); + + const consent = useMutation({ + mutationFn: async ({ + accept, + values, + }: { + accept: boolean; + values: ConsentFormValues; + }) => { + const result = await authClient.oauth2.consent({ + accept, + // Only ever a subset of the originally requested scopes; the + // provider rejects anything that was not asked for. + scope: requestedScopes + .filter((scope) => values.scopes[scope]) + .join(" "), + // The provider verifies a signature over the full authorize + // query. validateSearch drops the params it does not declare, + // so the router's searchStr would fail that check. + oauth_query: + search.oauth_query ?? + window.location.search.replace(/^\?/, ""), + }); + if (result.error || !result.data?.url) { + throw new Error( + result.error?.message ?? + "Could not complete OAuth consent.", + ); + } + return result.data.url; + }, + onSuccess: (url) => window.location.assign(url), + }); + + const submit = (accept: boolean) => + handleSubmit((values) => consent.mutate({ accept, values })); + + return ( +
+
+ + +
+ {client?.logo_uri ? ( + + ) : null} +
+

+ Authorize MCP access +

+ {isClientPending ? ( + + ) : ( +

+ {client?.client_name ? ( + <> + + {client.client_name} + {" "} + is requesting access to your Rivet + account. + + ) : ( + "An application is requesting access to your Rivet account." + )} +

+ )} +
+
+ +

+ Choose what to allow +

+
    + {requestedScopes.map((scope) => { + const detail = SCOPE_DETAILS[scope]; + const required = REQUIRED_SCOPES.has(scope); + const id = `scope-${scope}`; + return ( +
  • + ( + + field.onChange(checked === true) + } + className="mt-0.5" + /> + )} + /> +
    + +

    + {detail?.description ?? + "Grants the client additional access to your Rivet account."} +

    +
    +
  • + ); + })} +
+ + {granted["rivet:cloud:write"] || + granted["rivet:actors:write"] || + granted["rivet:inspector:write"] ? ( +

+ Write access also requires the MCP service's write + policy to be enabled, so approving it here does not by + itself allow changes. +

+ ) : null} + + {consent.error ? ( +

+ {consent.error.message} +

+ ) : null} + +
+ + +
+ +
+
+
Client ID
+
+ {search.client_id} +
+
+ {client?.client_uri ? ( +
+
Website
+
+ + {client.client_uri} + +
+
+ ) : null} +
+
+
+ ); +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts index 836993a9ca..c9103c1e03 100644 --- a/frontend/src/vite-env.d.ts +++ b/frontend/src/vite-env.d.ts @@ -1,6 +1,7 @@ /// declare const __APP_BUILD_ID__: string; +declare const __MCP_APP__: boolean; declare module "*.module.css" { const classes: { [key: string]: string }; diff --git a/frontend/vite.base.config.ts b/frontend/vite.base.config.ts index 26f2b53c10..954e5eb25c 100644 --- a/frontend/vite.base.config.ts +++ b/frontend/vite.base.config.ts @@ -11,6 +11,7 @@ export function baseViteConfig(): UserConfig { __APP_BUILD_ID__: JSON.stringify( `${new Date().toISOString()}@${crypto.randomUUID()}`, ), + __MCP_APP__: JSON.stringify(false), }, resolve: { alias: { diff --git a/frontend/vite.mcp-inspector-ui.config.ts b/frontend/vite.mcp-inspector-ui.config.ts new file mode 100644 index 0000000000..fe87901813 --- /dev/null +++ b/frontend/vite.mcp-inspector-ui.config.ts @@ -0,0 +1 @@ +export { default } from "./apps/inspector-ui/vite.mcp.config"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5575a5c5ac..04bcc0581b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -908,7 +908,7 @@ importers: version: 19.2.3(@types/react@19.2.13) drizzle-orm: specifier: ^0.38.0 - version: 0.38.4(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/react@19.2.13)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(react@19.1.0)(sql.js@1.13.0) + version: 0.38.4(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/react@19.2.13)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(react@19.1.0)(sql.js@1.13.0) typescript: specifier: ^5.7.3 version: 5.9.3 @@ -1414,7 +1414,7 @@ importers: version: 4.3.19(react@19.1.0)(zod@3.25.76) drizzle-orm: specifier: ^0.44.2 - version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) + version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0) fdb-tuple: specifier: ^1.0.0 version: 1.0.0 @@ -2042,7 +2042,7 @@ importers: version: 0.31.5 drizzle-orm: specifier: ^0.44.2 - version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) + version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0) devDependencies: '@types/node': specifier: ^22.13.9 @@ -2315,7 +2315,7 @@ importers: version: 4.12.25 nitro: specifier: 3.0.260610-beta - version: 3.0.260610-beta(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(better-sqlite3@12.8.0)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(giget@3.3.0)(ioredis@5.10.1)(jiti@2.7.0)(lru-cache@11.2.6)(miniflare@4.20260611.0)(rollup@4.62.2)(vite@7.3.1(@types/node@24.7.1)(jiti@2.7.0)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0))(wrangler@4.100.0)(xml2js@0.6.2) + version: 3.0.260610-beta(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(better-sqlite3@12.8.0)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0))(giget@3.3.0)(ioredis@5.10.1)(jiti@2.7.0)(lru-cache@11.2.6)(miniflare@4.20260611.0)(rollup@4.62.2)(vite@7.3.1(@types/node@24.7.1)(jiti@2.7.0)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0))(wrangler@4.100.0)(xml2js@0.6.2) rollup: specifier: ^4.62.2 version: 4.62.2 @@ -2341,6 +2341,9 @@ importers: frontend: dependencies: + '@better-auth/oauth-provider': + specifier: 1.6.23 + version: 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)))(better-call@1.3.7(zod@3.25.76)) '@codemirror/autocomplete': specifier: 6.18.7 version: 6.18.7 @@ -2395,6 +2398,12 @@ importers: '@microsoft/fetch-event-source': specifier: ^2.0.1 version: 2.0.1 + '@modelcontextprotocol/ext-apps': + specifier: 1.7.4 + version: 1.7.4(@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(zod@3.25.76) + '@modelcontextprotocol/sdk': + specifier: 1.29.0 + version: 1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) '@radix-ui/react-accordion': specifier: ^1.2.12 version: 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -2636,8 +2645,8 @@ importers: specifier: ^2.4.3 version: 2.4.3 better-auth: - specifier: ^1.5.6 - version: 1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)) + specifier: 1.6.23 + version: 1.6.23(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)) canvas-confetti: specifier: ^1.9.3 version: 1.9.3 @@ -2770,6 +2779,9 @@ importers: vite-plugin-favicons-inject: specifier: ^2.2.0 version: 2.2.0 + vite-plugin-singlefile: + specifier: 2.3.3 + version: 2.3.3(rollup@4.62.2)(vite@5.4.21(@types/node@20.19.13)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)) vite-tsconfig-paths: specifier: ^5.1.4 version: 5.1.4(typescript@5.9.3)(vite@5.4.21(@types/node@20.19.13)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)) @@ -3348,7 +3360,7 @@ importers: devDependencies: '@modelcontextprotocol/inspector': specifier: ^0.14.0 - version: 0.14.3(@cfworker/json-schema@4.1.1)(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@22.19.10)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(hono@4.12.25)(typescript@5.9.3) + version: 0.14.3(@cfworker/json-schema@4.1.1)(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@22.19.10)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(typescript@5.9.3) '@types/node': specifier: ^22.13.1 version: 22.19.10 @@ -3470,7 +3482,7 @@ importers: version: 0.31.5 drizzle-orm: specifier: ^0.44.2 - version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) + version: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0) hono: specifier: ^4.7.0 version: 4.11.9 @@ -4641,62 +4653,73 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@better-auth/core@1.5.6': - resolution: {integrity: sha512-Ez9DZdIMFyxHremmoLz1emFPGNQomDC1jqqBPnZ6Ci+6TiGN3R9w/Y03cJn6I8r1ycKgOzeVMZtJ/erOZ27Gsw==} + '@better-auth/core@1.6.23': + resolution: {integrity: sha512-beEhOs0uVeOxYOZKUfIEBd/nQV2Bd4/6wyLxZ0OFkn6CMTK2Vi+hXuZLnyPBeB6RdHpebEoJWiHqwHxBIxgPDQ==} peerDependencies: - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 '@cloudflare/workers-types': '>=4' '@opentelemetry/api': ^1.9.0 - better-call: 1.3.2 + better-call: 1.3.7 jose: ^6.1.0 - kysely: ^0.28.5 + kysely: ^0.28.5 || ^0.29.0 nanostores: ^1.0.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true + '@opentelemetry/api': + optional: true - '@better-auth/drizzle-adapter@1.5.6': - resolution: {integrity: sha512-VfFFmaoFw3ug12SiSuIwzrMoHyIVmkMGWm9gZ4sXdYYVX4HboCL4m3fjzOhppcmK5OGatRuU+N1UX6wxCITcXw==} + '@better-auth/drizzle-adapter@1.6.23': + resolution: {integrity: sha512-2+/PTVfIP9E7iz6af8TB3lhnowHUj9ljC66kECmHaFEdUqPgzHoWux9epotKwO7XDg2ui4ttWQ8CMeNFLvQeKQ==} peerDependencies: - '@better-auth/core': 1.5.6 - '@better-auth/utils': ^0.3.0 - drizzle-orm: '>=0.41.0' + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 + drizzle-orm: ^0.45.2 peerDependenciesMeta: drizzle-orm: optional: true - '@better-auth/kysely-adapter@1.5.6': - resolution: {integrity: sha512-Fnf+h8WVKtw6lEOmVmiVVzDf3shJtM60AYf9XTnbdCeUd6MxN/KnaJZpkgtYnRs7a+nwtkVB+fg4lGETebGFXQ==} + '@better-auth/kysely-adapter@1.6.23': + resolution: {integrity: sha512-zbNJsMbG09exfkGyvFqBLLqWoMPAUWjxCuUnEK5AsjbYoZeIjj/QGZgdf4CapVWryKxjA9Q6Jlr6fbiPpC3VAg==} peerDependencies: - '@better-auth/core': 1.5.6 - '@better-auth/utils': ^0.3.0 - kysely: ^0.27.0 || ^0.28.0 + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 + kysely: ^0.28.17 || ^0.29.0 peerDependenciesMeta: kysely: optional: true - '@better-auth/memory-adapter@1.5.6': - resolution: {integrity: sha512-rS7ZsrIl5uvloUgNN0u9LOZJMMXnsZXVdUZ3MrTBKWM2KpoJjzPr9yN3Szyma5+0V7SltnzSGHPkYj2bEzzmlA==} + '@better-auth/memory-adapter@1.6.23': + resolution: {integrity: sha512-krIiR0pIVkaKlAzm690n5bcMW4NGbqeMg0HQSD9fz/KcQF/eWLqcq9gG/BhHTj2i/y96qH+W5JWPmaSOS5iTgQ==} peerDependencies: - '@better-auth/core': 1.5.6 - '@better-auth/utils': ^0.3.0 + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 - '@better-auth/mongo-adapter@1.5.6': - resolution: {integrity: sha512-6+M3MS2mor8fTUV3EI1FBLP0cs6QfbN+Ovx9+XxR/GdfKIBoNFzmPEPRbdGt+ft6PvrITsUm+T70+kkHgVSP6w==} + '@better-auth/mongo-adapter@1.6.23': + resolution: {integrity: sha512-7+QdevitGlKBbP6JbiSk5SBnzPsKV/mDrQBGBn8hwByQLeJwqpqbuBPw7ZI8vzUlFfAAnyFiqwP3Eb8mxnp7pA==} peerDependencies: - '@better-auth/core': 1.5.6 - '@better-auth/utils': ^0.3.0 + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 mongodb: ^6.0.0 || ^7.0.0 peerDependenciesMeta: mongodb: optional: true - '@better-auth/prisma-adapter@1.5.6': - resolution: {integrity: sha512-UxY9vQJs1Tt+O+T2YQnseDMlWmUSQvFZSBb5YiFRg7zcm+TEzujh4iX2/csA0YiZptLheovIuVWTP9nriewEBA==} + '@better-auth/oauth-provider@1.6.23': + resolution: {integrity: sha512-1sDN+N4Sztmpk8ziCU3MXicxOTfvYoHvHvhJMQ7PSfr+pLXnYN+dJFI9S3zBRwstmTeJx/OhRIZWrwFJ0TgBnA==} peerDependencies: - '@better-auth/core': 1.5.6 - '@better-auth/utils': ^0.3.0 + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 + better-auth: ^1.6.23 + better-call: 1.3.7 + + '@better-auth/prisma-adapter@1.6.23': + resolution: {integrity: sha512-2qSdzidq4tkb1eS5TTqb4Nzg0mdZWm3Qky9SYeXeb8PpVQbC2sxqJhEM5mK7y12uU6I8hc64wO9f7AFVNL+6UQ==} + peerDependencies: + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 peerDependenciesMeta: @@ -4705,16 +4728,18 @@ packages: prisma: optional: true - '@better-auth/telemetry@1.5.6': - resolution: {integrity: sha512-yXC7NSxnIFlxDkGdpD7KA+J9nqIQAPCJKe77GoaC5bWoe/DALo1MYorZfTgOafS7wrslNtsPT4feV/LJi1ubqQ==} + '@better-auth/telemetry@1.6.23': + resolution: {integrity: sha512-/R2Kb+z2BpDOOWwVHqOk+c0VNpuwfCv4Hp5Yr9003WIZPax/zyNraGLB9CFE8qF2gZW8Dsz419k4I8CPrGzpDA==} peerDependencies: - '@better-auth/core': 1.5.6 + '@better-auth/core': ^1.6.23 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 - '@better-auth/utils@0.3.1': - resolution: {integrity: sha512-+CGp4UmZSUrHHnpHhLPYu6cV+wSUSvVbZbNykxhUDocpVNTo9uFFxw/NqJlh1iC4wQ9HKKWGCKuZ5wUgS0v6Kg==} + '@better-auth/utils@0.4.2': + resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==} - '@better-fetch/fetch@1.1.21': - resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} + '@better-fetch/fetch@1.3.1': + resolution: {integrity: sha512-ABkD1WhyfPZprKRQI3bhATjeiFuNWC9PXhfGWqL+sg/gKrM977oFrYkdb4msM3hgUGonr7KlOsOFT5TU2rht9g==} '@biomejs/biome@2.3.11': resolution: {integrity: sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ==} @@ -6866,6 +6891,20 @@ packages: '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + '@modelcontextprotocol/ext-apps@1.7.4': + resolution: {integrity: sha512-QQqysE549cf/Y0VabBmAACXhj92EhB3t8yVct2BHbkWiPTFA1S91EqTVjYXXcZEefXU0pmHcdObhsNMcomJIOQ==} + engines: {node: '>=20'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.29.0 + react: 19.1.0 + react-dom: 19.1.0 + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + '@modelcontextprotocol/inspector-cli@0.14.3': resolution: {integrity: sha512-cAjCfwJUfN1WHc/sGgY/yAQ7K02WOKIso+LzVoKzEr50Nf4R+WKEuq6lhnLfG3f61sU823V8TxRscc8NTYTgww==} deprecated: 'v1 is deprecated. Upgrade to v2: npm i @modelcontextprotocol/inspector@latest. v1 gets security fixes only, published under the v1-latest tag.' @@ -11008,8 +11047,8 @@ packages: bcryptjs@2.4.3: resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} - better-auth@1.5.6: - resolution: {integrity: sha512-QSpJTqaT1XVfWRQe/fm3PgeuwOIlz1nWX/Dx7nsHStJ382bLzmDbQk2u7IT0IJ6wS5SRxfqEE1Ev9TXontgyAQ==} + better-auth@1.6.23: + resolution: {integrity: sha512-4vOaRd9UiKGKm9R+ej0jjU1es3MiJIiNc9Qq3VCnYqOZ4/nb5272QqTxWYoDxyUXl5x6A2x2we5KZKQO9teTQQ==} peerDependencies: '@lynx-js/react': '*' '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -11018,7 +11057,7 @@ packages: '@tanstack/solid-start': ^1.0.0 better-sqlite3: ^12.0.0 drizzle-kit: '>=0.31.4' - drizzle-orm: '>=0.41.0' + drizzle-orm: ^0.45.2 mongodb: ^6.0.0 || ^7.0.0 mysql2: ^3.0.0 next: ^14.0.0 || ^15.0.0 || ^16.0.0 @@ -11070,8 +11109,8 @@ packages: vue: optional: true - better-call@1.3.2: - resolution: {integrity: sha512-4cZIfrerDsNTn3cm+MhLbUePN0gdwkhSXEuG7r/zuQ8c/H7iU0/jSK5TD3FW7U0MgKHce/8jGpPYNO4Ve+4NBw==} + better-call@1.3.7: + resolution: {integrity: sha512-Al51/hjp2SSp6CRTa3F2ptcx4yQVS1xWKoY6jcVXqNYOap6mHFP2jUBn5EwIL4iIed1/Sq4hlQ+Umm6EflZG+w==} peerDependencies: zod: ^4.0.0 peerDependenciesMeta: @@ -12093,9 +12132,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} @@ -14126,9 +14162,9 @@ packages: kubernetes-types@1.30.0: resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} - kysely@0.28.15: - resolution: {integrity: sha512-r2clcf7HLWvDXaVUEvQymXJY4i3bSOIV3xsL/Upy3ZfSv5HeKsk9tsqbBptLvth5qHEIhxeHTA2jNLyQABkLBA==} - engines: {node: '>=20.0.0'} + kysely@0.29.5: + resolution: {integrity: sha512-ooa+eSbBNPTo3MycPEuW5jdrxQdQwdtB3LC3h43FiXQbIry5tR0C5lDG7eealK0E4D7XjrnOP5DIUg/LyjRMYQ==} + engines: {node: '>=22.0.0'} lan-network@0.1.7: resolution: {integrity: sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==} @@ -15630,9 +15666,6 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - path-to-regexp@8.4.2: resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} @@ -17973,6 +18006,16 @@ packages: vite-plugin-favicons-inject@2.2.0: resolution: {integrity: sha512-MaqZE3IjwFffIED38yKcI5BKGkV039N6ilhPeOfW4TILzSKMBNd8Q0ehu0mwbl1emWH2tGcuwV3ZIzDKfb0vIQ==} + vite-plugin-singlefile@2.3.3: + resolution: {integrity: sha512-XVnGH0QzbOa8fxRSsHdCarVN1BSBXNi7uLMQYlrGRN5apdHkk62XQWRJhVever0lnfuyBkwn+kvVChdm/OoOUg==} + engines: {node: '>18.0.0'} + peerDependencies: + rollup: ^4.59.0 + vite: ^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + rollup: + optional: true + vite-plugin-srvx@1.0.2: resolution: {integrity: sha512-y11gH+CBkbQvfbFE14TJcl7HAkjqaZbGEb3CXnEdu0fXlsPzHJST7Khyq021WKOWbDYb8PaCabjzMQ+pS1oDPw==} peerDependencies: @@ -20190,59 +20233,69 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} - '@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0)': + '@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0)': dependencies: - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 - '@opentelemetry/api': 1.9.0 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 '@opentelemetry/semantic-conventions': 1.40.0 '@standard-schema/spec': 1.1.0 - better-call: 1.3.2(zod@4.3.6) + better-call: 1.3.7(zod@3.25.76) jose: 6.1.3 - kysely: 0.28.15 + kysely: 0.29.5 nanostores: 1.2.0 zod: 4.3.6 optionalDependencies: '@cloudflare/workers-types': 4.20251014.0 + '@opentelemetry/api': 1.9.0 - '@better-auth/drizzle-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))': + '@better-auth/drizzle-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 - optionalDependencies: - drizzle-orm: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 - '@better-auth/kysely-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.15)': + '@better-auth/kysely-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(kysely@0.29.5)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 optionalDependencies: - kysely: 0.28.15 + kysely: 0.29.5 - '@better-auth/memory-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/memory-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 - '@better-auth/mongo-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/mongo-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 - '@better-auth/prisma-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/oauth-provider@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(better-auth@1.6.23(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)))(better-call@1.3.7(zod@3.25.76))': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 + better-auth: 1.6.23(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)) + better-call: 1.3.7(zod@3.25.76) + jose: 6.1.3 + zod: 4.3.6 - '@better-auth/telemetry@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))': + '@better-auth/prisma-adapter@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 - '@better-auth/utils@0.3.1': {} + '@better-auth/telemetry@1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)': + dependencies: + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 - '@better-fetch/fetch@1.1.21': {} + '@better-auth/utils@0.4.2': + dependencies: + '@noble/hashes': 2.0.1 + + '@better-fetch/fetch@1.3.1': {} '@biomejs/biome@2.3.11': optionalDependencies: @@ -22636,6 +22689,15 @@ snapshots: '@mixmark-io/domino@2.2.0': {} + '@modelcontextprotocol/ext-apps@1.7.4(@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(zod@3.25.76)': + dependencies: + '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@standard-schema/spec': 1.1.0 + zod: 3.25.76 + optionalDependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + '@modelcontextprotocol/inspector-cli@0.14.3(@cfworker/json-schema@4.1.1)(zod@3.25.76)': dependencies: '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) @@ -22693,12 +22755,12 @@ snapshots: - supports-color - utf-8-validate - '@modelcontextprotocol/inspector@0.14.3(@cfworker/json-schema@4.1.1)(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@22.19.10)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(hono@4.12.25)(typescript@5.9.3)': + '@modelcontextprotocol/inspector@0.14.3(@cfworker/json-schema@4.1.1)(@swc/core@1.15.11(@swc/helpers@0.5.17))(@types/node@22.19.10)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(typescript@5.9.3)': dependencies: '@modelcontextprotocol/inspector-cli': 0.14.3(@cfworker/json-schema@4.1.1)(zod@3.25.76) '@modelcontextprotocol/inspector-client': 0.14.3(@cfworker/json-schema@4.1.1)(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13) '@modelcontextprotocol/inspector-server': 0.14.3(@cfworker/json-schema@4.1.1) - '@modelcontextprotocol/sdk': 1.25.3(@cfworker/json-schema@4.1.1)(hono@4.12.25)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) concurrently: 9.2.1 open: 10.2.0 shell-quote: 1.8.3 @@ -22713,7 +22775,6 @@ snapshots: - '@types/react' - '@types/react-dom' - bufferutil - - hono - supports-color - tailwindcss - typescript @@ -27768,29 +27829,28 @@ snapshots: bcryptjs@2.4.3: {} - better-auth@1.5.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)): - dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)) - '@better-auth/kysely-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.15) - '@better-auth/memory-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/mongo-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/prisma-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/telemetry': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@3.25.76))(jose@6.1.3)(kysely@0.28.15)(nanostores@1.2.0)) - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 + better-auth@1.6.23(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-sqlite3@12.8.0)(drizzle-kit@0.31.5)(next@16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2))(pg@8.17.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(vitest@4.0.18(@opentelemetry/api@1.9.0)(@types/node@20.19.13)(jiti@1.21.7)(less@4.4.1)(lightningcss@1.32.0)(msw@2.14.4(@types/node@20.19.13)(typescript@5.9.3))(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0)): + dependencies: + '@better-auth/core': 1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0) + '@better-auth/drizzle-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2) + '@better-auth/kysely-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(kysely@0.29.5) + '@better-auth/memory-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.6.23(@better-auth/core@1.6.23(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(better-call@1.3.7(zod@4.3.6))(jose@6.1.3)(kysely@0.29.5)(nanostores@1.2.0))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 '@noble/ciphers': 2.1.1 '@noble/hashes': 2.0.1 - better-call: 1.3.2(zod@4.3.6) - defu: 6.1.4 + better-call: 1.3.7(zod@3.25.76) + defu: 6.1.7 jose: 6.1.3 - kysely: 0.28.15 + kysely: 0.29.5 nanostores: 1.2.0 zod: 4.3.6 optionalDependencies: better-sqlite3: 12.8.0 drizzle-kit: 0.31.5 - drizzle-orm: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) next: 16.1.4(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.93.2) pg: 8.17.2 react: 19.1.0 @@ -27800,14 +27860,14 @@ snapshots: - '@cloudflare/workers-types' - '@opentelemetry/api' - better-call@1.3.2(zod@4.3.6): + better-call@1.3.7(zod@3.25.76): dependencies: - '@better-auth/utils': 0.3.1 - '@better-fetch/fetch': 1.1.21 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.1 rou3: 0.7.12 set-cookie-parser: 3.1.0 optionalDependencies: - zod: 4.3.6 + zod: 3.25.76 better-opn@3.0.2: dependencies: @@ -28829,10 +28889,10 @@ snapshots: dayjs@1.11.19: {} - db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)): + db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0)): optionalDependencies: better-sqlite3: 12.8.0 - drizzle-orm: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0) + drizzle-orm: 0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0) de-indent@1.0.2: {} @@ -28911,8 +28971,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} - defu@6.1.7: {} degenerator@5.0.1: @@ -29018,7 +29076,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.38.4(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/react@19.2.13)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(react@19.1.0)(sql.js@1.13.0): + drizzle-orm@0.38.4(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/react@19.2.13)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(react@19.1.0)(sql.js@1.13.0): optionalDependencies: '@cloudflare/workers-types': 4.20251014.0 '@opentelemetry/api': 1.9.0 @@ -29028,12 +29086,12 @@ snapshots: '@types/sql.js': 1.4.9 better-sqlite3: 12.8.0 bun-types: 1.3.11 - kysely: 0.28.15 + kysely: 0.29.5 pg: 8.17.2 react: 19.1.0 sql.js: 1.13.0 - drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0): + drizzle-orm@0.44.6(@cloudflare/workers-types@4.20251014.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0): optionalDependencies: '@cloudflare/workers-types': 4.20251014.0 '@opentelemetry/api': 1.9.0 @@ -29042,7 +29100,7 @@ snapshots: '@types/sql.js': 1.4.9 better-sqlite3: 12.8.0 bun-types: 1.3.11 - kysely: 0.28.15 + kysely: 0.29.5 pg: 8.17.2 sql.js: 1.13.0 @@ -31136,7 +31194,7 @@ snapshots: kubernetes-types@1.30.0: {} - kysely@0.28.15: {} + kysely@0.29.5: {} lan-network@0.1.7: {} @@ -32712,11 +32770,11 @@ snapshots: nf3@0.3.22: {} - nitro@3.0.260610-beta(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(better-sqlite3@12.8.0)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0))(giget@3.3.0)(ioredis@5.10.1)(jiti@2.7.0)(lru-cache@11.2.6)(miniflare@4.20260611.0)(rollup@4.62.2)(vite@7.3.1(@types/node@24.7.1)(jiti@2.7.0)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0))(wrangler@4.100.0)(xml2js@0.6.2): + nitro@3.0.260610-beta(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(better-sqlite3@12.8.0)(chokidar@5.0.0)(dotenv@17.4.2)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0))(giget@3.3.0)(ioredis@5.10.1)(jiti@2.7.0)(lru-cache@11.2.6)(miniflare@4.20260611.0)(rollup@4.62.2)(vite@7.3.1(@types/node@24.7.1)(jiti@2.7.0)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)(tsx@4.23.1)(yaml@2.9.0))(wrangler@4.100.0)(xml2js@0.6.2): dependencies: consola: 3.4.2 crossws: 0.4.10(srvx@0.11.22) - db0: 0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)) + db0: 0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0)) env-runner: 0.1.16(miniflare@4.20260611.0)(wrangler@4.100.0) h3: 2.0.1-rc.22(crossws@0.4.10(srvx@0.11.22)) hookable: 6.1.1 @@ -32727,7 +32785,7 @@ snapshots: rolldown: 1.2.0 srvx: 0.11.22 unenv: 2.0.0-rc.24 - unstorage: 2.0.0-alpha.7(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(chokidar@5.0.0)(db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)))(ioredis@5.10.1)(lru-cache@11.2.6)(ofetch@2.0.0-alpha.3) + unstorage: 2.0.0-alpha.7(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(chokidar@5.0.0)(db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0)))(ioredis@5.10.1)(lru-cache@11.2.6)(ofetch@2.0.0-alpha.3) optionalDependencies: dotenv: 17.4.2 giget: 3.3.0 @@ -33259,8 +33317,6 @@ snapshots: path-to-regexp@6.3.0: {} - path-to-regexp@8.3.0: {} - path-to-regexp@8.4.2: {} path-type@4.0.0: {} @@ -34426,7 +34482,7 @@ snapshots: depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color @@ -35922,11 +35978,11 @@ snapshots: picomatch: 4.0.3 webpack-virtual-modules: 0.6.2 - unstorage@2.0.0-alpha.7(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(chokidar@5.0.0)(db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)))(ioredis@5.10.1)(lru-cache@11.2.6)(ofetch@2.0.0-alpha.3): + unstorage@2.0.0-alpha.7(@vercel/functions@3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1))(chokidar@5.0.0)(db0@0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0)))(ioredis@5.10.1)(lru-cache@11.2.6)(ofetch@2.0.0-alpha.3): optionalDependencies: '@vercel/functions': 3.7.5(@aws-sdk/credential-provider-web-identity@3.972.49)(ws@8.20.1) chokidar: 5.0.0 - db0: 0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.28.15)(pg@8.17.2)(sql.js@1.13.0)) + db0: 0.3.4(better-sqlite3@12.8.0)(drizzle-orm@0.44.6(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.16.0)(@types/sql.js@1.4.9)(better-sqlite3@12.8.0)(bun-types@1.3.11)(kysely@0.29.5)(pg@8.17.2)(sql.js@1.13.0)) ioredis: 5.10.1 lru-cache: 11.2.6 ofetch: 2.0.0-alpha.3 @@ -36219,6 +36275,13 @@ snapshots: dependencies: favicons: 7.2.0 + vite-plugin-singlefile@2.3.3(rollup@4.62.2)(vite@5.4.21(@types/node@20.19.13)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)): + dependencies: + micromatch: 4.0.8 + vite: 5.4.21(@types/node@20.19.13)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0) + optionalDependencies: + rollup: 4.62.2 + vite-plugin-srvx@1.0.2(srvx@0.10.0)(vite@5.4.21(@types/node@22.19.15)(less@4.4.1)(lightningcss@1.32.0)(sass@1.93.2)(stylus@0.62.0)(terser@5.46.0)): dependencies: srvx: 0.10.0