diff --git a/apps/cloud/.gitignore b/apps/cloud/.gitignore new file mode 100644 index 0000000000..eb1f5c987b --- /dev/null +++ b/apps/cloud/.gitignore @@ -0,0 +1,4 @@ +.env +.env.op +.env.local +.dev-db/ diff --git a/apps/cloud/drizzle.config.ts b/apps/cloud/drizzle.config.ts new file mode 100644 index 0000000000..8d68b0eb79 --- /dev/null +++ b/apps/cloud/drizzle.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "drizzle-kit"; + +export default defineConfig({ + schema: ["./src/services/schema.ts", "../../packages/core/storage-postgres/src/schema.ts"], + out: "./drizzle", + dialect: "postgresql", +}); diff --git a/packages/core/storage-postgres/drizzle/0000_spicy_zemo.sql b/apps/cloud/drizzle/0000_gigantic_terrax.sql similarity index 51% rename from packages/core/storage-postgres/drizzle/0000_spicy_zemo.sql rename to apps/cloud/drizzle/0000_gigantic_terrax.sql index 9a47066b60..801500661b 100644 --- a/packages/core/storage-postgres/drizzle/0000_spicy_zemo.sql +++ b/apps/cloud/drizzle/0000_gigantic_terrax.sql @@ -1,78 +1,65 @@ -CREATE TABLE "invitations" ( +CREATE TABLE "accounts" ( "id" text PRIMARY KEY NOT NULL, - "team_id" text NOT NULL, - "email" text NOT NULL, - "invited_by" text NOT NULL, - "status" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "expires_at" timestamp with time zone NOT NULL + "created_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE "organizations" ( + "id" text PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "plugin_kv" ( - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "namespace" text NOT NULL, "key" text NOT NULL, "value" text NOT NULL, - CONSTRAINT "plugin_kv_team_id_namespace_key_pk" PRIMARY KEY("team_id","namespace","key") + CONSTRAINT "plugin_kv_organization_id_namespace_key_pk" PRIMARY KEY("organization_id","namespace","key") ); --> statement-breakpoint CREATE TABLE "policies" ( "id" text NOT NULL, - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "name" text NOT NULL, "action" text NOT NULL, "match_tool_pattern" text, "match_source_id" text, "priority" integer NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "policies_id_team_id_pk" PRIMARY KEY("id","team_id") + CONSTRAINT "policies_id_organization_id_pk" PRIMARY KEY("id","organization_id") ); --> statement-breakpoint CREATE TABLE "secrets" ( "id" text NOT NULL, - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "name" text NOT NULL, "purpose" text, "encrypted_value" "bytea" NOT NULL, "iv" "bytea" NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "secrets_id_team_id_pk" PRIMARY KEY("id","team_id") + CONSTRAINT "secrets_id_organization_id_pk" PRIMARY KEY("id","organization_id") ); --> statement-breakpoint CREATE TABLE "sources" ( "id" text NOT NULL, - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "name" text NOT NULL, "kind" text NOT NULL, "config" jsonb NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "sources_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "team_members" ( - "team_id" text NOT NULL, - "user_id" text NOT NULL, - "role" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "team_members_team_id_user_id_pk" PRIMARY KEY("team_id","user_id") -); ---> statement-breakpoint -CREATE TABLE "teams" ( - "id" text PRIMARY KEY NOT NULL, - "name" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL + CONSTRAINT "sources_id_organization_id_pk" PRIMARY KEY("id","organization_id") ); --> statement-breakpoint CREATE TABLE "tool_definitions" ( "name" text NOT NULL, - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "schema" jsonb NOT NULL, - CONSTRAINT "tool_definitions_name_team_id_pk" PRIMARY KEY("name","team_id") + CONSTRAINT "tool_definitions_name_organization_id_pk" PRIMARY KEY("name","organization_id") ); --> statement-breakpoint CREATE TABLE "tools" ( "id" text NOT NULL, - "team_id" text NOT NULL, + "organization_id" text NOT NULL, "source_id" text NOT NULL, "plugin_key" text NOT NULL, "name" text NOT NULL, @@ -81,14 +68,5 @@ CREATE TABLE "tools" ( "input_schema" jsonb, "output_schema" jsonb, "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "tools_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "users" ( - "id" text PRIMARY KEY NOT NULL, - "email" text NOT NULL, - "name" text, - "avatar_url" text, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "users_email_unique" UNIQUE("email") + CONSTRAINT "tools_id_organization_id_pk" PRIMARY KEY("id","organization_id") ); diff --git a/apps/cloud/drizzle/meta/0000_snapshot.json b/apps/cloud/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000000..4b4a070f31 --- /dev/null +++ b/apps/cloud/drizzle/meta/0000_snapshot.json @@ -0,0 +1,436 @@ +{ + "id": "54fdb041-bab4-45f5-bb24-5d1c61489dea", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organizations": { + "name": "organizations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.plugin_kv": { + "name": "plugin_kv", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "namespace": { + "name": "namespace", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "plugin_kv_organization_id_namespace_key_pk": { + "name": "plugin_kv_organization_id_namespace_key_pk", + "columns": [ + "organization_id", + "namespace", + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.policies": { + "name": "policies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "match_tool_pattern": { + "name": "match_tool_pattern", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "match_source_id": { + "name": "match_source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "policies_id_organization_id_pk": { + "name": "policies_id_organization_id_pk", + "columns": [ + "id", + "organization_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secrets": { + "name": "secrets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "purpose": { + "name": "purpose", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "bytea", + "primaryKey": false, + "notNull": true + }, + "iv": { + "name": "iv", + "type": "bytea", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "secrets_id_organization_id_pk": { + "name": "secrets_id_organization_id_pk", + "columns": [ + "id", + "organization_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sources": { + "name": "sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "sources_id_organization_id_pk": { + "name": "sources_id_organization_id_pk", + "columns": [ + "id", + "organization_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tool_definitions": { + "name": "tool_definitions", + "schema": "", + "columns": { + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "tool_definitions_name_organization_id_pk": { + "name": "tool_definitions_name_organization_id_pk", + "columns": [ + "name", + "organization_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tools": { + "name": "tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "plugin_key": { + "name": "plugin_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "may_elicit": { + "name": "may_elicit", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "input_schema": { + "name": "input_schema", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "output_schema": { + "name": "output_schema", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "tools_id_organization_id_pk": { + "name": "tools_id_organization_id_pk", + "columns": [ + "id", + "organization_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/cloud/drizzle/meta/_journal.json b/apps/cloud/drizzle/meta/_journal.json new file mode 100644 index 0000000000..b8d1184375 --- /dev/null +++ b/apps/cloud/drizzle/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "postgresql", + "entries": [ + { + "idx": 0, + "version": "7", + "when": 1775718432762, + "tag": "0000_gigantic_terrax", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/apps/cloud/package.json b/apps/cloud/package.json index ba9e31bec8..f4ad659087 100644 --- a/apps/cloud/package.json +++ b/apps/cloud/package.json @@ -28,28 +28,40 @@ "drizzle-orm": "catalog:", "effect": "catalog:", "jose": "^5.6.3", - "pg": "^8.16.0", + "postgres": "^3.4.9", "react": "catalog:", "react-dom": "catalog:" }, "devDependencies": { + "@cloudflare/vitest-pool-workers": "^0.14.3", + "@cloudflare/workers-types": "^4.20250620.0", + "@effect/vitest": "^0.29.0", + "@electric-sql/pglite": "^0.4.3", + "@electric-sql/pglite-socket": "^0.1.3", "@tailwindcss/vite": "catalog:", - "@types/pg": "^8.15.4", "@types/react": "catalog:", "@types/react-dom": "catalog:", "@vitejs/plugin-react": "catalog:", - "@cloudflare/workers-types": "^4.20250620.0", + "concurrently": "^9.2.1", + "drizzle-kit": "^0.31.10", "portless": "^0.10.1", "typescript": "catalog:", "vite": "catalog:", + "vitest": "^4.1.4", "wrangler": "^4.81.0" }, "scripts": { - "dev": "op run --env-file=.env -- portless run --name executor-cloud vite dev", + "dev": "bun run dev:proxy && concurrently -n db,vite -c blue,green \"bun run dev:db\" \"bun run dev:vite\"", + "dev:proxy": "portless proxy start --port 1355 || true", + "dev:db": "bun run scripts/dev-db.ts", + "dev:vite": "CLOUDFLARE_INCLUDE_PROCESS_ENV=true op run --env-file=.env.op -- portless run --name executor-cloud vite dev", + "db:generate": "drizzle-kit generate", "build": "vite build", "preview": "vite preview", "deploy": "vite build && wrangler deploy", "cf-typegen": "wrangler types", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test": "vitest run", + "test:watch": "vitest" } } diff --git a/apps/cloud/scripts/dev-db.ts b/apps/cloud/scripts/dev-db.ts new file mode 100644 index 0000000000..9e490e72aa --- /dev/null +++ b/apps/cloud/scripts/dev-db.ts @@ -0,0 +1,44 @@ +// --------------------------------------------------------------------------- +// Local dev Postgres via PGlite — no Docker, no install +// --------------------------------------------------------------------------- +// +// Exposes an in-process PGlite instance over a TCP socket so Hyperdrive's +// localConnectionString can connect to it like a real Postgres server. +// Runs drizzle migrations on startup so the schema is ready. + +import { PGlite } from "@electric-sql/pglite"; +import { PGLiteSocketServer } from "@electric-sql/pglite-socket"; +import { drizzle } from "drizzle-orm/pglite"; +import { migrate } from "drizzle-orm/pglite/migrator"; +import { resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const PORT = 5433; +const DB_PATH = resolve(__dirname, "../.dev-db"); +const MIGRATIONS_FOLDER = resolve(__dirname, "../drizzle"); + +console.log(`[dev-db] Starting PGlite at ${DB_PATH}`); +const db = await PGlite.create(DB_PATH); + +console.log(`[dev-db] Running migrations from ${MIGRATIONS_FOLDER}`); +await migrate(drizzle(db), { migrationsFolder: MIGRATIONS_FOLDER }); + +const server = new PGLiteSocketServer({ + db, + port: PORT, + host: "127.0.0.1", +}); + +await server.start(); +console.log(`[dev-db] Listening on postgresql://postgres:postgres@127.0.0.1:${PORT}/postgres`); + +const shutdown = async () => { + console.log("\n[dev-db] Shutting down"); + await server.stop(); + await db.close(); + process.exit(0); +}; + +process.on("SIGINT", shutdown); +process.on("SIGTERM", shutdown); diff --git a/apps/cloud/scripts/test-globalsetup.ts b/apps/cloud/scripts/test-globalsetup.ts new file mode 100644 index 0000000000..ddcbb27031 --- /dev/null +++ b/apps/cloud/scripts/test-globalsetup.ts @@ -0,0 +1,34 @@ +// --------------------------------------------------------------------------- +// Vitest globalSetup — starts an in-process PGlite socket server so tests +// running in the Cloudflare Workers runtime can connect to a real Postgres +// via postgres.js. Port must match DATABASE_URL in wrangler.test.jsonc. +// --------------------------------------------------------------------------- + +import { PGlite } from "@electric-sql/pglite"; +import { PGLiteSocketServer } from "@electric-sql/pglite-socket"; +import { drizzle } from "drizzle-orm/pglite"; +import { migrate } from "drizzle-orm/pglite/migrator"; +import { resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const PORT = 5434; +const MIGRATIONS_FOLDER = resolve(__dirname, "../drizzle"); + +let db: PGlite | undefined; +let server: PGLiteSocketServer | undefined; + +export default async function setup() { + db = await PGlite.create(); + await migrate(drizzle(db), { migrationsFolder: MIGRATIONS_FOLDER }); + + server = new PGLiteSocketServer({ db, port: PORT, host: "127.0.0.1" }); + await server.start(); + // eslint-disable-next-line no-console + console.log(`[test-db] PGlite socket server listening on 127.0.0.1:${PORT}`); + + return async () => { + await server?.stop(); + await db?.close(); + }; +} diff --git a/apps/cloud/src/api.ts b/apps/cloud/src/api.ts index 2555215796..0aef8d101a 100644 --- a/apps/cloud/src/api.ts +++ b/apps/cloud/src/api.ts @@ -1,9 +1,9 @@ // --------------------------------------------------------------------------- -// Cloud API — protected core API + public auth endpoints +// Cloud API — non-protected (auth) endpoints + org-protected executor endpoints // --------------------------------------------------------------------------- +import { env } from "cloudflare:workers"; import { - HttpApi, HttpApiBuilder, HttpApiSwagger, HttpMiddleware, @@ -11,57 +11,69 @@ import { HttpServer, } from "@effect/platform"; import { Effect, Layer } from "effect"; -import { setCookie } from "@tanstack/react-start/server"; -import { addGroup } from "@executor/api"; -import { CoreHandlers, ExecutorService, ExecutionEngineService } from "@executor/api/server"; +import { CoreExecutorApi } from "@executor/api"; +import { + CoreHandlers, + ExecutorService, + ExecutionEngineService, +} from "@executor/api/server"; import { createExecutionEngine } from "@executor/execution"; -import { makeDynamicWorkerExecutor, type CodeExecutor } from "@executor/runtime-dynamic-worker"; -import { OpenApiGroup, OpenApiExtensionService, OpenApiHandlers } from "@executor/plugin-openapi/api"; -import { McpGroup, McpExtensionService, McpHandlers } from "@executor/plugin-mcp/api"; +import { + makeDynamicWorkerExecutor, + type CodeExecutor, +} from "@executor/runtime-dynamic-worker"; +import { + OpenApiGroup, + OpenApiExtensionService, + OpenApiHandlers, +} from "@executor/plugin-openapi/api"; +import { + McpGroup, + McpExtensionService, + McpHandlers, +} from "@executor/plugin-mcp/api"; import { GoogleDiscoveryGroup, GoogleDiscoveryExtensionService, GoogleDiscoveryHandlers, } from "@executor/plugin-google-discovery/api"; -import { GraphqlGroup, GraphqlExtensionService, GraphqlHandlers } from "@executor/plugin-graphql/api"; - -import { CloudAuthApi, CloudAuthPublicApi } from "./auth/api"; -import { AuthContext, UserStoreService } from "./auth/context"; -import { CloudAuthHandlers, CloudAuthPublicHandlers } from "./auth/handlers"; +import { + GraphqlGroup, + GraphqlExtensionService, + GraphqlHandlers, +} from "@executor/plugin-graphql/api"; + +import { OrgAuth } from "./auth/middleware"; +import { OrgAuthLive, SessionAuthLive } from "./auth/middleware-live"; +import { UserStoreService } from "./auth/context"; +import { + CloudAuthPublicHandlers, + CloudSessionAuthHandlers, + NonProtectedApi, +} from "./auth/handlers"; import { WorkOSAuth } from "./auth/workos"; import { DbService } from "./services/db"; -import { createTeamExecutor } from "./services/executor"; +import { createOrgExecutor } from "./services/executor"; import { server } from "./env"; -const ProtectedCloudApi = addGroup(OpenApiGroup) +// --------------------------------------------------------------------------- +// API definitions +// --------------------------------------------------------------------------- + +/** Protected (org-required) API — all the executor groups + OrgAuth middleware */ +const ProtectedCloudApi = CoreExecutorApi.add(OpenApiGroup) .add(McpGroup) .add(GoogleDiscoveryGroup) .add(GraphqlGroup) - .add(CloudAuthApi); - -const PublicCloudApi = HttpApi.make("cloudPublic") - .add(CloudAuthPublicApi); - -const ProtectedCloudApiLive = HttpApiBuilder.api(ProtectedCloudApi).pipe( - Layer.provide(CoreHandlers), - Layer.provide(Layer.mergeAll( - OpenApiHandlers, - McpHandlers, - GoogleDiscoveryHandlers, - GraphqlHandlers, - CloudAuthHandlers, - )), -); + .middleware(OrgAuth); -const PublicCloudApiLive = HttpApiBuilder.api(PublicCloudApi).pipe( - Layer.provide(CloudAuthPublicHandlers), -); +// --------------------------------------------------------------------------- +// Layers +// --------------------------------------------------------------------------- const DbLive = DbService.Live; -const UserStoreLive = UserStoreService.Live.pipe( - Layer.provide(DbLive), -); +const UserStoreLive = UserStoreService.Live.pipe(Layer.provide(DbLive)); const SharedServices = Layer.mergeAll( DbLive, @@ -69,178 +81,133 @@ const SharedServices = Layer.mergeAll( WorkOSAuth.Default, HttpServer.layerContext, ); +const ProtectedCloudApiLive = HttpApiBuilder.api(ProtectedCloudApi).pipe( + Layer.provide( + Layer.mergeAll( + CoreHandlers, + OpenApiHandlers, + McpHandlers, + GoogleDiscoveryHandlers, + GraphqlHandlers, + OrgAuthLive, + ), + ), +); -let _publicApiHandler: ReturnType | null = null; -const getPublicApiHandler = () => { - if (!_publicApiHandler) { - _publicApiHandler = HttpApiBuilder.toWebHandler( - PublicCloudApiLive.pipe( - Layer.provideMerge(SharedServices), - Layer.provideMerge(HttpRouter.setRouterConfig({ maxParamLength: 1000 })), - ), - { middleware: HttpMiddleware.logger }, - ); - } - return _publicApiHandler; -}; - -const parseCookie = (cookieHeader: string | null, name: string): string | null => { - if (!cookieHeader) return null; - const match = cookieHeader - .split(";") - .map((value) => value.trim()) - .find((value) => value.startsWith(`${name}=`)); - if (!match) return null; - return match.slice(name.length + 1) || null; -}; - +const NonProtectedApiLive = HttpApiBuilder.api(NonProtectedApi).pipe( + Layer.provide(Layer.mergeAll(CloudAuthPublicHandlers, CloudSessionAuthHandlers)), + Layer.provideMerge(SessionAuthLive), +); -const isPublicPath = (pathname: string): boolean => - pathname === "/auth/login" || pathname === "/auth/callback"; +// --------------------------------------------------------------------------- +// Static web handlers — built once at module load +// --------------------------------------------------------------------------- -const unauthorized = (message: string): Response => - Response.json({ error: message }, { status: 401 }); +const RouterConfig = HttpRouter.setRouterConfig({ maxParamLength: 1000 }); -const COOKIE_OPTIONS = { - path: "/", - httpOnly: true, - sameSite: "lax" as const, - maxAge: 60 * 60 * 24 * 7, - secure: server.NODE_ENV === "production", -}; +const nonProtectedHandler = HttpApiBuilder.toWebHandler( + NonProtectedApiLive.pipe( + Layer.provideMerge(SharedServices), + Layer.provideMerge(RouterConfig), + ), + { middleware: HttpMiddleware.logger }, +); -const resolveAuth = (request: Request) => - Effect.gen(function* () { - const workos = yield* WorkOSAuth; - return yield* workos.authenticateRequest(request); - }); +// --------------------------------------------------------------------------- +// Protected handler — must be built per-request because the executor varies +// --------------------------------------------------------------------------- -const resolveTeamId = ( - userId: string, - cookieTeamId: string | null, +const buildProtectedHandler = ( + organizationId: string, + organizationName: string, + codeExecutor: CodeExecutor, ) => Effect.gen(function* () { - const users = yield* UserStoreService; - const teams = yield* users.use((store) => store.getTeamsForUser(userId)); + const executor = yield* createOrgExecutor( + organizationId, + organizationName, + server.ENCRYPTION_KEY, + ); - if (cookieTeamId) { - const hasAccess = teams.some((t) => t.teamId === cookieTeamId); - if (hasAccess) return cookieTeamId; - } + const engine = createExecutionEngine({ executor, codeExecutor }); - if (teams.length > 0) return teams[0]!.teamId; + const requestServices = Layer.mergeAll( + Layer.succeed(ExecutorService, executor), + Layer.succeed(ExecutionEngineService, engine), + Layer.succeed(OpenApiExtensionService, executor.openapi), + Layer.succeed(McpExtensionService, executor.mcp), + Layer.succeed(GoogleDiscoveryExtensionService, executor.googleDiscovery), + Layer.succeed(GraphqlExtensionService, executor.graphql), + ); - return yield* Effect.fail(new Error("No team found — user may not have completed signup")); + return HttpApiBuilder.toWebHandler( + HttpApiSwagger.layer({ path: "/docs" }).pipe( + Layer.provideMerge(HttpApiBuilder.middlewareOpenApi()), + Layer.provideMerge(ProtectedCloudApiLive), + Layer.provideMerge(requestServices), + Layer.provideMerge(SharedServices), + Layer.provideMerge( + HttpRouter.setRouterConfig({ maxParamLength: 1000 }), + ), + ), + { middleware: HttpMiddleware.logger }, + ); }); -const resolveExecutor = (teamId: string) => +// --------------------------------------------------------------------------- +// Routing +// --------------------------------------------------------------------------- + +const isAuthPath = (pathname: string): boolean => pathname.startsWith("/auth/"); + +/** + * Resolve the user's organization for executor creation. Reads from the + * session cookie via WorkOS — returns null if there's no session or no + * organization yet, so the caller can return a 403. + */ +const lookupOrgForRequest = (request: Request) => Effect.gen(function* () { + const workos = yield* WorkOSAuth; + const result = yield* workos.authenticateRequest(request); + if (!result || !result.organizationId) return null; const users = yield* UserStoreService; - const team = yield* users.use((store) => store.getTeam(teamId)); - const teamName = team?.name ?? "Unknown Team"; - const encryptionKey = server.ENCRYPTION_KEY; - return yield* createTeamExecutor(teamId, teamName, encryptionKey); + return yield* users.use((s) => s.getOrganization(result.organizationId!)); }); -type ResolvedAuth = Exclude>, null>; -type TeamExecutor = Effect.Effect.Success>; - -const createProtectedHandler = ( - auth: ResolvedAuth, - teamId: string, - executor: TeamExecutor, - codeExecutor: CodeExecutor, -) => { - const engine = createExecutionEngine({ executor, codeExecutor }); - - const requestServices = Layer.mergeAll( - Layer.succeed(AuthContext, { - userId: auth.userId, - teamId, - email: auth.email, - name: `${auth.firstName ?? ""} ${auth.lastName ?? ""}`.trim() || null, - avatarUrl: auth.avatarUrl ?? null, - }), - Layer.succeed(ExecutorService, executor), - Layer.succeed(ExecutionEngineService, engine), - Layer.succeed(OpenApiExtensionService, executor.openapi), - Layer.succeed(McpExtensionService, executor.mcp), - Layer.succeed(GoogleDiscoveryExtensionService, executor.googleDiscovery), - Layer.succeed(GraphqlExtensionService, executor.graphql), - ); - - return HttpApiBuilder.toWebHandler( - HttpApiSwagger.layer({ path: "/docs" }).pipe( - Layer.provideMerge(HttpApiBuilder.middlewareOpenApi()), - Layer.provideMerge(ProtectedCloudApiLive), - Layer.provideMerge(requestServices), - Layer.provideMerge(SharedServices), - Layer.provideMerge(HttpRouter.setRouterConfig({ maxParamLength: 1000 })), - ), - { middleware: HttpMiddleware.logger }, - ); -}; - -const closeExecutor = (executor: TeamExecutor) => - executor.close().pipe( - Effect.orElseSucceed(() => undefined), - ); - -type ProtectedHandler = ReturnType; - -const disposeProtectedHandler = (handler: ProtectedHandler) => - Effect.promise(() => handler.dispose()).pipe( - Effect.orElseSucceed(() => undefined), - ); - export const handleApiRequest = async (request: Request): Promise => { const pathname = new URL(request.url).pathname; - if (isPublicPath(pathname)) { - return getPublicApiHandler().handler(request); + if (isAuthPath(pathname)) { + return nonProtectedHandler.handler(request); } - const requestProgram = Effect.gen(function* () { - const auth = yield* resolveAuth(request); - if (!auth) return unauthorized("Unauthorized"); + // Protected path — build the executor lazily for the request's org. + try { + const program = Effect.gen(function* () { + const org = yield* lookupOrgForRequest(request); + if (!org) return null; - const cookieTeamId = parseCookie(request.headers.get("cookie"), "executor_team"); - const teamId = yield* resolveTeamId(auth.userId, cookieTeamId); + const codeExecutor = makeDynamicWorkerExecutor({ loader: env.LOADER }); + const handler = yield* buildProtectedHandler(org.id, org.name, codeExecutor); + return yield* Effect.promise(() => handler.handler(request)); + }); - const executor = yield* Effect.acquireRelease( - resolveExecutor(teamId), - closeExecutor, + const result = await Effect.runPromise( + program.pipe(Effect.provide(SharedServices), Effect.scoped), ); - const handler = yield* Effect.acquireRelease( - Effect.tryPromise(async () => { - const { env } = await import("cloudflare:workers"); - const codeExecutor = makeDynamicWorkerExecutor({ loader: (env as any).LOADER }); - return createProtectedHandler(auth, teamId, executor, codeExecutor); - }), - disposeProtectedHandler, - ); - - const response = yield* Effect.promise(() => handler.handler(request)); - - const refreshedSession = auth.refreshedSession; - if (refreshedSession) { - yield* Effect.sync(() => { - setCookie("wos-session", refreshedSession, COOKIE_OPTIONS); - }); + if (result === null) { + return Response.json( + { error: "No organization in session", code: "no_organization" }, + { status: 403 }, + ); } - if (!cookieTeamId) { - yield* Effect.sync(() => { - setCookie("executor_team", teamId, COOKIE_OPTIONS); - }); - } - return response; - }); - - return Effect.runPromise( - requestProgram.pipe( - Effect.provide(SharedServices), - Effect.scoped, - ), - ); + return result; + } catch (err) { + console.error("[api] request failed:", err instanceof Error ? err.stack : err); + return Response.json( + { error: err instanceof Error ? err.message : "Internal server error" }, + { status: 500 }, + ); + } }; diff --git a/apps/cloud/src/auth/api.ts b/apps/cloud/src/auth/api.ts index afc33d9fe5..1022ba50df 100644 --- a/apps/cloud/src/auth/api.ts +++ b/apps/cloud/src/auth/api.ts @@ -1,6 +1,7 @@ import { HttpApiEndpoint, HttpApiGroup } from "@effect/platform"; import { Schema } from "effect"; import { UserStoreError, WorkOSError } from "./errors"; +import { SessionAuth } from "./middleware"; const AuthUser = Schema.Struct({ id: Schema.String, @@ -9,20 +10,24 @@ const AuthUser = Schema.Struct({ avatarUrl: Schema.NullOr(Schema.String), }); -const AuthTeam = Schema.Struct({ +const AuthOrganization = Schema.Struct({ id: Schema.String, name: Schema.String, }); const AuthMeResponse = Schema.Struct({ user: AuthUser, - team: Schema.NullOr(AuthTeam), + organization: Schema.NullOr(AuthOrganization), }); const AuthCallbackSearch = Schema.Struct({ code: Schema.String, }); +const CreateOrganizationRequest = Schema.Struct({ + name: Schema.String, +}); + export const AUTH_PATHS = { login: "/api/auth/login", logout: "/api/auth/logout", @@ -41,7 +46,7 @@ export class CloudAuthPublicApi extends HttpApiGroup.make("cloudAuthPublic") .addError(WorkOSError), ) {} -/** Protected auth endpoints — require authentication */ +/** Session auth endpoints — require a logged-in user, may not have an org */ export class CloudAuthApi extends HttpApiGroup.make("cloudAuth") .add( HttpApiEndpoint.get("me")`/auth/me` @@ -51,4 +56,11 @@ export class CloudAuthApi extends HttpApiGroup.make("cloudAuth") .add( HttpApiEndpoint.post("logout")`/auth/logout`, ) + .add( + HttpApiEndpoint.post("createOrganization")`/auth/organization` + .setPayload(CreateOrganizationRequest) + .addError(UserStoreError) + .addError(WorkOSError), + ) + .middleware(SessionAuth) {} diff --git a/apps/cloud/src/auth/context.ts b/apps/cloud/src/auth/context.ts index 2a7dd36da1..d25dfdb64a 100644 --- a/apps/cloud/src/auth/context.ts +++ b/apps/cloud/src/auth/context.ts @@ -3,20 +3,8 @@ import { makeUserStore } from "../services/user-store"; import { DbService } from "../services/db"; import { UserStoreError } from "./errors"; -// --------------------------------------------------------------------------- -// AuthContext — resolved per-request from sealed session -// --------------------------------------------------------------------------- - -export class AuthContext extends Context.Tag("@executor/cloud/AuthContext")< - AuthContext, - { - readonly userId: string; - readonly teamId: string; - readonly email: string; - readonly name: string | null; - readonly avatarUrl: string | null; - } ->() {} +// AuthContext is defined in ./middleware.ts to keep middleware-related types together. +export { AuthContext } from "./middleware"; // --------------------------------------------------------------------------- // UserStoreService — wraps the Drizzle-backed user store with Effect diff --git a/apps/cloud/src/auth/handlers.ts b/apps/cloud/src/auth/handlers.ts index 6dc461fc97..13dacac618 100644 --- a/apps/cloud/src/auth/handlers.ts +++ b/apps/cloud/src/auth/handlers.ts @@ -1,10 +1,10 @@ import { HttpApi, HttpApiBuilder, HttpServerRequest, HttpServerResponse } from "@effect/platform"; import { Effect } from "effect"; -import { deleteCookie, setCookie } from "@tanstack/react-start/server"; +import { setCookie, deleteCookie, getCookie } from "@tanstack/react-start/server"; -import { addGroup } from "@executor/api"; import { AUTH_PATHS, CloudAuthApi, CloudAuthPublicApi } from "./api"; -import { AuthContext, UserStoreService } from "./context"; +import { SessionContext } from "./middleware"; +import { UserStoreService } from "./context"; import { WorkOSAuth } from "./workos"; import { server } from "../env"; @@ -17,14 +17,20 @@ const COOKIE_OPTIONS = { }; // --------------------------------------------------------------------------- -// Public auth handlers (no authentication required) +// Single non-protected API surface — public (login/callback) + session +// (me/logout/createOrganization). The session group has SessionAuth on it. // --------------------------------------------------------------------------- -const PublicAuthApi = HttpApi.make("cloudPublic") - .add(CloudAuthPublicApi); +export const NonProtectedApi = HttpApi.make("cloudWeb") + .add(CloudAuthPublicApi) + .add(CloudAuthApi); + +// --------------------------------------------------------------------------- +// Public auth handlers (no authentication required) +// --------------------------------------------------------------------------- export const CloudAuthPublicHandlers = HttpApiBuilder.group( - PublicAuthApi, + NonProtectedApi, "cloudAuthPublic", (handlers) => handlers @@ -32,8 +38,12 @@ export const CloudAuthPublicHandlers = HttpApiBuilder.group( Effect.gen(function* () { const workos = yield* WorkOSAuth; const req = yield* HttpServerRequest.HttpServerRequest; - const proto = req.headers["x-forwarded-proto"] ?? "https"; - const origin = new URL(req.url, `${proto}://${req.headers["host"]}`).origin; + // Prefer APP_URL (set explicitly in dev/prod config) since the + // request's Host header is the internal proxy target in dev, not + // the public URL WorkOS needs to redirect back to. + const origin = server.APP_URL + ? server.APP_URL + : new URL(req.url, `${req.headers["x-forwarded-proto"] ?? "https"}://${req.headers["host"]}`).origin; const url = workos.getAuthorizationUrl(`${origin}${AUTH_PATHS.callback}`); return HttpServerResponse.redirect(url, { status: 302 }); }), @@ -44,83 +54,110 @@ export const CloudAuthPublicHandlers = HttpApiBuilder.group( const users = yield* UserStoreService; const result = yield* workos.authenticateWithCode(urlParams.code); - const workosUser = result.user; - - const user = yield* users.use((s) => - s.upsertUser({ - id: workosUser.id, - email: workosUser.email, - name: `${workosUser.firstName ?? ""} ${workosUser.lastName ?? ""}`.trim() || undefined, - avatarUrl: workosUser.profilePictureUrl ?? undefined, - }), - ); - const resolveTeam = Effect.gen(function* () { - const pending = yield* users.use((s) => s.getPendingInvitations(user.email)); - if (pending.length > 0) { - const invitation = pending[0]!; - yield* users.use((s) => s.acceptInvitation(invitation.id)); - yield* users.use((s) => s.addMember(invitation.teamId, user.id, "member")); - return invitation.teamId; - } - - const teams = yield* users.use((s) => s.getTeamsForUser(user.id)); - if (teams.length > 0) return teams[0]!.teamId; - - const team = yield* users.use((s) => - s.createTeam(`${user.name ?? user.email}'s Team`), + // Mirror the account locally + yield* users.use((s) => s.ensureAccount(result.user.id)); + + let sealedSession = result.sealedSession; + let organizationId = result.organizationId; + + // WorkOS doesn't host an org creation flow — if the user has no + // org yet, create a default one on their behalf and refresh the + // session so it includes the new org_id claim. + if (!organizationId) { + const name = + [result.user.firstName, result.user.lastName] + .filter(Boolean) + .join(" ") || result.user.email; + const org = yield* workos.createOrganization(`${name}'s Workspace`); + yield* workos.createMembership(org.id, result.user.id); + yield* users.use((s) => + s.upsertOrganization({ id: org.id, name: org.name }), ); - yield* users.use((s) => s.addMember(team.id, user.id, "owner")); - return team.id; - }); - const teamId = yield* resolveTeam; + if (sealedSession) { + const refreshed = yield* workos.refreshSession(sealedSession, org.id); + if (refreshed) sealedSession = refreshed; + } + organizationId = org.id; + } else { + yield* users.use((s) => + s.upsertOrganization({ + id: organizationId!, + name: "Organization", + }), + ); + } - const sealedSession = result.sealedSession; if (!sealedSession) { return HttpServerResponse.text("Failed to create session", { status: 500 }); } setCookie("wos-session", sealedSession, COOKIE_OPTIONS); - setCookie("executor_team", teamId, COOKIE_OPTIONS); return HttpServerResponse.redirect("/", { status: 302 }); }), ), ); // --------------------------------------------------------------------------- -// Protected auth handlers (require authentication via middleware) +// Session auth handlers (require session, may or may not have an org) // --------------------------------------------------------------------------- -const ApiWithCloudAuth = addGroup(CloudAuthApi); - -export const CloudAuthHandlers = HttpApiBuilder.group( - ApiWithCloudAuth, +export const CloudSessionAuthHandlers = HttpApiBuilder.group( + NonProtectedApi, "cloudAuth", (handlers) => handlers .handle("me", () => Effect.gen(function* () { - const auth = yield* AuthContext; + const session = yield* SessionContext; const users = yield* UserStoreService; - const team = yield* users.use((s) => s.getTeam(auth.teamId)); + const org = session.organizationId + ? yield* users.use((s) => s.getOrganization(session.organizationId!)) + : null; return { user: { - id: auth.userId, - email: auth.email, - name: auth.name, - avatarUrl: auth.avatarUrl, + id: session.accountId, + email: session.email, + name: session.name, + avatarUrl: session.avatarUrl, }, - team: team ? { id: team.id, name: team.name } : null, + organization: org ? { id: org.id, name: org.name } : null, }; }), ) .handleRaw("logout", () => Effect.sync(() => { deleteCookie("wos-session", { path: "/" }); - deleteCookie("executor_team", { path: "/" }); return HttpServerResponse.redirect("/", { status: 302 }); }), + ) + .handle("createOrganization", ({ payload }) => + Effect.gen(function* () { + const session = yield* SessionContext; + const workos = yield* WorkOSAuth; + const users = yield* UserStoreService; + + // Create the org in WorkOS + const org = yield* workos.createOrganization(payload.name); + + // Add the current user as a member + yield* workos.createMembership(org.id, session.accountId); + + // Mirror locally + yield* users.use((s) => + s.upsertOrganization({ id: org.id, name: org.name }), + ); + + // Refresh the session with the new org context + const currentSession = getCookie("wos-session") ?? null; + if (currentSession) { + const newSession = yield* workos.refreshSession(currentSession, org.id); + if (newSession) { + setCookie("wos-session", newSession, COOKIE_OPTIONS); + } + } + }), ), ); diff --git a/apps/cloud/src/auth/middleware-live.ts b/apps/cloud/src/auth/middleware-live.ts new file mode 100644 index 0000000000..6cf2485f02 --- /dev/null +++ b/apps/cloud/src/auth/middleware-live.ts @@ -0,0 +1,77 @@ +// --------------------------------------------------------------------------- +// HTTP API middleware — live implementations (server-only). +// Imports the WorkOS SDK so it must NOT be pulled into the client bundle. +// --------------------------------------------------------------------------- + +import { Effect, Layer, Redacted } from "effect"; + +import { + NoOrganization, + OrgAuth, + SessionAuth, + Unauthorized, +} from "./middleware"; +import { WorkOSAuth } from "./workos"; + +export const SessionAuthLive = Layer.effect( + SessionAuth, + Effect.gen(function* () { + const workos = yield* WorkOSAuth; + return SessionAuth.of({ + cookie: (sealedSession) => + Effect.gen(function* () { + const result = yield* workos + .authenticateSealedSession(Redacted.value(sealedSession)) + .pipe(Effect.orElseSucceed(() => null)); + + if (!result) { + return yield* new Unauthorized(); + } + + return { + accountId: result.userId, + email: result.email, + name: + `${result.firstName ?? ""} ${result.lastName ?? ""}`.trim() || + null, + avatarUrl: result.avatarUrl ?? null, + organizationId: result.organizationId ?? null, + refreshedSession: result.refreshedSession ?? null, + }; + }), + }); + }), +); + +export const OrgAuthLive = Layer.effect( + OrgAuth, + Effect.gen(function* () { + const workos = yield* WorkOSAuth; + return OrgAuth.of({ + cookie: (sealedSession) => + Effect.gen(function* () { + const result = yield* workos + .authenticateSealedSession(Redacted.value(sealedSession)) + .pipe(Effect.orElseSucceed(() => null)); + + if (!result) { + return yield* new Unauthorized(); + } + + if (!result.organizationId) { + return yield* new NoOrganization(); + } + + return { + accountId: result.userId, + organizationId: result.organizationId, + email: result.email, + name: + `${result.firstName ?? ""} ${result.lastName ?? ""}`.trim() || + null, + avatarUrl: result.avatarUrl ?? null, + }; + }), + }); + }), +); diff --git a/apps/cloud/src/auth/middleware.ts b/apps/cloud/src/auth/middleware.ts new file mode 100644 index 0000000000..7123d9dedb --- /dev/null +++ b/apps/cloud/src/auth/middleware.ts @@ -0,0 +1,82 @@ +// --------------------------------------------------------------------------- +// HTTP API middleware tags — pure tag definitions, no server dependencies. +// Live implementations are in ./middleware-live.ts to keep the WorkOS SDK +// out of the client bundle (this file is imported by `auth/api.ts` which +// the SPA pulls in for typed schemas). +// --------------------------------------------------------------------------- + +import { Context, Schema } from "effect"; +import { HttpApiMiddleware, HttpApiSchema, HttpApiSecurity } from "@effect/platform"; + +// --------------------------------------------------------------------------- +// Session — what every authenticated request gets +// --------------------------------------------------------------------------- + +export type Session = { + readonly accountId: string; + readonly email: string; + readonly name: string | null; + readonly avatarUrl: string | null; + /** May be null if the user hasn't joined an organization yet. */ + readonly organizationId: string | null; + readonly refreshedSession: string | null; +}; + +export class SessionContext extends Context.Tag("@executor/cloud/Session")< + SessionContext, + Session +>() {} + +// --------------------------------------------------------------------------- +// Errors +// --------------------------------------------------------------------------- + +export class Unauthorized extends Schema.TaggedError()( + "Unauthorized", + {}, + HttpApiSchema.annotations({ status: 401 }), +) {} + +export class NoOrganization extends Schema.TaggedError()( + "NoOrganization", + {}, + HttpApiSchema.annotations({ status: 403 }), +) {} + +// --------------------------------------------------------------------------- +// SessionAuth — resolves the WorkOS session cookie, provides SessionContext +// --------------------------------------------------------------------------- + +export class SessionAuth extends HttpApiMiddleware.Tag()( + "SessionAuth", + { + failure: Unauthorized, + provides: SessionContext, + security: { + cookie: HttpApiSecurity.apiKey({ in: "cookie", key: "wos-session" }), + }, + }, +) {} + +// --------------------------------------------------------------------------- +// OrgAuth — like SessionAuth but rejects sessions with no organization +// --------------------------------------------------------------------------- + +export class AuthContext extends Context.Tag("@executor/cloud/AuthContext")< + AuthContext, + { + readonly accountId: string; + readonly organizationId: string; + readonly email: string; + readonly name: string | null; + readonly avatarUrl: string | null; + } +>() {} + +export class OrgAuth extends HttpApiMiddleware.Tag()("OrgAuth", { + failure: Schema.Union(Unauthorized, NoOrganization), + provides: AuthContext, + security: { + cookie: HttpApiSecurity.apiKey({ in: "cookie", key: "wos-session" }), + }, +}) {} diff --git a/apps/cloud/src/auth/workos.ts b/apps/cloud/src/auth/workos.ts index ae7ddc3294..2a9197fce7 100644 --- a/apps/cloud/src/auth/workos.ts +++ b/apps/cloud/src/auth/workos.ts @@ -31,6 +31,51 @@ const make = Effect.gen(function* () { catch: (cause) => new WorkOSError({ cause }), }).pipe(Effect.withSpan("workos")); + const authenticateSealedSession = (sessionData: string) => + Effect.gen(function* () { + if (!sessionData) return null; + + const session = workos.userManagement.loadSealedSession({ + sessionData, + cookiePassword, + }); + + const result = yield* use((wos) => session.authenticate()); + + if (result.authenticated) { + return { + userId: result.user.id, + email: result.user.email, + firstName: result.user.firstName, + lastName: result.user.lastName, + avatarUrl: result.user.profilePictureUrl, + organizationId: result.organizationId, + sessionId: result.sessionId, + refreshedSession: undefined as string | undefined, + }; + } + + if (result.reason === "no_session_cookie_provided") return null; + + // Try refreshing + const refreshed = yield* use((wos) => session.refresh()).pipe( + Effect.orElseSucceed(() => ({ authenticated: false as const })), + ); + + if (!refreshed.authenticated || !("sealedSession" in refreshed) || !refreshed.sealedSession) return null; + + return { + userId: refreshed.user.id, + email: refreshed.user.email, + firstName: refreshed.user.firstName, + lastName: refreshed.user.lastName, + avatarUrl: refreshed.user.profilePictureUrl, + organizationId: refreshed.organizationId, + sessionId: refreshed.sessionId, + refreshedSession: refreshed.sealedSession, + }; + }); + return { getAuthorizationUrl: (redirectUri: string) => workos.userManagement.getAuthorizationUrl({ @@ -48,48 +93,49 @@ const make = Effect.gen(function* () { }), ), - authenticateRequest: (request: Request) => - Effect.gen(function* () { - const sessionData = parseCookie(request.headers.get("cookie"), COOKIE_NAME); - if (!sessionData) return null; + /** Create a new organization in WorkOS. */ + createOrganization: (name: string) => + use((wos) => wos.organizations.createOrganization({ name })), + /** Add a user to an organization as a member. */ + createMembership: (organizationId: string, userId: string) => + use((wos) => + wos.userManagement.createOrganizationMembership({ + organizationId, + userId, + }), + ), + + /** + * Refresh a sealed session, optionally switching to a new organization. + * Returns the new sealed session string or null if refresh failed. + */ + refreshSession: (sessionData: string, organizationId?: string) => + Effect.gen(function* () { const session = workos.userManagement.loadSealedSession({ sessionData, cookiePassword, }); - - const result = yield* use((wos) => session.authenticate()); - - if (result.authenticated) { - return { - userId: result.user.id, - email: result.user.email, - firstName: result.user.firstName, - lastName: result.user.lastName, - avatarUrl: result.user.profilePictureUrl, - sessionId: result.sessionId, - refreshedSession: undefined as string | undefined, - }; - } - - if (result.reason === "no_session_cookie_provided") return null; - - // Try refreshing - const refreshed = yield* use((wos) => session.refresh()).pipe( - Effect.orElseSucceed(() => ({ authenticated: false as const })), + const refreshed = yield* use((wos) => + session.refresh(organizationId ? { organizationId } : undefined), ); + if (!refreshed.authenticated || !("sealedSession" in refreshed)) return null; + return refreshed.sealedSession ?? null; + }), - if (!refreshed.authenticated || !("sealedSession" in refreshed) || !refreshed.sealedSession) return null; + /** + * Authenticate a sealed session string. Returns the user info plus + * any refreshed session that needs to be set on the response. + * Returns null if the session is missing or invalid. + */ + authenticateSealedSession, - return { - userId: refreshed.user.id, - email: refreshed.user.email, - firstName: refreshed.user.firstName, - lastName: refreshed.user.lastName, - avatarUrl: refreshed.user.profilePictureUrl, - sessionId: refreshed.sessionId, - refreshedSession: refreshed.sealedSession, - }; + /** Authenticate from a Request — convenience wrapper around `authenticateSealedSession`. */ + authenticateRequest: (request: Request) => + Effect.gen(function* () { + const sessionData = parseCookie(request.headers.get("cookie"), COOKIE_NAME); + if (!sessionData) return null; + return yield* authenticateSealedSession(sessionData); }), }; }); diff --git a/apps/cloud/src/env.ts b/apps/cloud/src/env.ts index 9dbe865bfd..c089173d9b 100644 --- a/apps/cloud/src/env.ts +++ b/apps/cloud/src/env.ts @@ -19,6 +19,7 @@ const serverShape = { WORKOS_API_KEY: Env.string("WORKOS_API_KEY"), WORKOS_CLIENT_ID: Env.string("WORKOS_CLIENT_ID"), WORKOS_COOKIE_PASSWORD: Env.string("WORKOS_COOKIE_PASSWORD"), + APP_URL: Env.stringOr("APP_URL", ""), }; type SharedEnv = Readonly<{ @@ -31,6 +32,7 @@ type ServerEnv = SharedEnv & Readonly<{ WORKOS_API_KEY: string; WORKOS_CLIENT_ID: string; WORKOS_COOKIE_PASSWORD: string; + APP_URL: string; }>; type WebEnv = Readonly>; diff --git a/apps/cloud/src/mcp-session.ts b/apps/cloud/src/mcp-session.ts index 6f390bae8a..4a7dd381c2 100644 --- a/apps/cloud/src/mcp-session.ts +++ b/apps/cloud/src/mcp-session.ts @@ -12,7 +12,7 @@ import { makeDynamicWorkerExecutor } from "@executor/runtime-dynamic-worker"; import { UserStoreService } from "./auth/context"; import { server } from "./env"; -import { createTeamExecutor } from "./services/executor"; +import { createOrgExecutor } from "./services/executor"; import { DbService } from "./services/db"; // --------------------------------------------------------------------------- @@ -20,7 +20,7 @@ import { DbService } from "./services/db"; // --------------------------------------------------------------------------- export type McpSessionInit = { - userId: string; + organizationId: string; }; // Heartbeat interval — keeps the DO alive by re-scheduling an alarm before @@ -35,29 +35,24 @@ const SESSION_TIMEOUT_MS = 5 * 60 * 1000; // Session initialization effect // --------------------------------------------------------------------------- -const DbLive = DbService.Unscoped; +const DbLive = DbService.Live; const UserStoreLive = UserStoreService.Live.pipe(Layer.provide(DbLive)); const Services = Layer.mergeAll(DbLive, UserStoreLive); -const initSession = (userId: string) => +const initSession = (organizationId: string) => Effect.gen(function* () { const users = yield* UserStoreService; - const teams = yield* users.use((store) => store.getTeamsForUser(userId)); + const org = yield* users.use((store) => store.getOrganization(organizationId)); - if (teams.length === 0) { + if (!org) { return yield* Effect.fail( - new Error("No team found for user — account may not be set up"), + new Error(`Organization ${organizationId} not found`), ); } - const { teamId, teamName } = { - teamId: teams[0]!.teamId, - teamName: teams[0]!.teamName ?? "Team", - }; - - const executor = yield* createTeamExecutor( - teamId, - teamName, + const executor = yield* createOrgExecutor( + org.id, + org.name, server.ENCRYPTION_KEY, ); @@ -103,7 +98,7 @@ export class McpSessionDO extends DurableObject { async init(token: McpSessionInit): Promise { if (this.initialized) return; - this.mcpServer = await Effect.runPromise(initSession(token.userId)); + this.mcpServer = await Effect.runPromise(initSession(token.organizationId)); this.transport = new WorkerTransport({ sessionIdGenerator: () => this.ctx.id.toString(), diff --git a/apps/cloud/src/mcp.ts b/apps/cloud/src/mcp.ts index c7c758d162..a676f70950 100644 --- a/apps/cloud/src/mcp.ts +++ b/apps/cloud/src/mcp.ts @@ -53,10 +53,10 @@ const authorizationServerMetadata = async () => { // --------------------------------------------------------------------------- type VerifiedToken = { - sub: string; - email?: string; - firstName?: string; - lastName?: string; + /** The WorkOS account ID (user ID). */ + accountId: string; + /** The WorkOS organization ID, if the session has org context. */ + organizationId: string | null; }; const BEARER_PREFIX = "Bearer "; @@ -72,10 +72,8 @@ const verifyBearerToken = async (request: Request): Promise => { + if (!token.organizationId) { + return jsonRpcError(403, -32001, "No organization in session — log in via the web app first"); + } + try { const ns = env.MCP_SESSION; const sessionId = request.headers.get("mcp-session-id"); @@ -127,7 +129,7 @@ const handleMcpRequest_POST = async ( const id = ns.newUniqueId(); const stub = ns.get(id); - await stub.init({ userId: token.sub }); + await stub.init({ organizationId: token.organizationId }); return await stub.handleRequest(request); } catch (err) { diff --git a/apps/cloud/src/services/db.test.ts b/apps/cloud/src/services/db.test.ts new file mode 100644 index 0000000000..66135b0ef7 --- /dev/null +++ b/apps/cloud/src/services/db.test.ts @@ -0,0 +1,124 @@ +// --------------------------------------------------------------------------- +// DbService integration test +// --------------------------------------------------------------------------- +// +// Regression coverage for the pg/CloudflareSocket hang (see +// personal-notes/pg-cloudflare-sockets-dev.md). This test: +// +// - Runs inside the Cloudflare Workers runtime via +// @cloudflare/vitest-pool-workers +// - Talks to a real Postgres (PGlite exposed over a TCP socket by +// scripts/test-globalsetup.ts) +// - Constructs DbService.Live across multiple independent Effect scopes, +// the way api.ts does per request +// - Performs real queries against the mirrored accounts/organizations +// tables through drizzle +// +// With the old `pg` + `drizzle-orm/node-postgres` stack, the second scope's +// query would hang indefinitely because CloudflareSocket cannot be reused +// across request contexts and `Client.end()` never resolved. With +// postgres.js the test passes: each scope acquires its own socket and +// releases it cleanly. + +import { describe, it, expect } from "vitest"; +import { Effect, Layer } from "effect"; + +import { DbService } from "./db"; +import { makeUserStore } from "./user-store"; + +const program = (body: Effect.Effect) => + Effect.runPromise( + body.pipe(Effect.provide(DbService.Live), Effect.scoped) as Effect.Effect< + A, + E, + never + >, + ); + +describe("DbService", () => { + it("executes a trivial query end-to-end", async () => { + const result = await program( + Effect.gen(function* () { + const db = yield* DbService; + const rows = yield* Effect.promise(() => db.execute("select 1 as one")); + return rows; + }), + ); + expect(Array.isArray(result) ? result[0] : (result as { rows: unknown[] }).rows[0]).toBeDefined(); + }); + + it("round-trips an account through the user store", async () => { + const id = `user_${crypto.randomUUID()}`; + const account = await program( + Effect.gen(function* () { + const db = yield* DbService; + const store = makeUserStore(db); + return yield* Effect.promise(() => store.ensureAccount(id)); + }), + ); + expect(account.id).toBe(id); + }); + + it("supports multiple sequential scopes (regression: pg socket reuse hang)", async () => { + // With `pg`, the second scope's connect()/query would hang because the + // CloudflareSocket from the first scope cannot be reused and Client.end() + // never completes. postgres.js creates a fresh socket per scope. + const idA = `user_${crypto.randomUUID()}`; + const idB = `user_${crypto.randomUUID()}`; + + await program( + Effect.gen(function* () { + const db = yield* DbService; + yield* Effect.promise(() => makeUserStore(db).ensureAccount(idA)); + }), + ); + + const fetched = await program( + Effect.gen(function* () { + const db = yield* DbService; + const store = makeUserStore(db); + yield* Effect.promise(() => store.ensureAccount(idB)); + return yield* Effect.promise(() => store.getAccount(idA)); + }), + ); + + expect(fetched?.id).toBe(idA); + }, 15_000); + + it("supports nested scopes within a single outer scope (regression: /api/scope pattern)", async () => { + // Mirrors api.ts: an outer scope resolves the org, then an inner scope + // (the HttpApi request handler) re-acquires DbService and queries again. + const orgId = `org_${crypto.randomUUID()}`; + + const outer = Layer.provide( + Layer.effectDiscard( + Effect.gen(function* () { + const db = yield* DbService; + yield* Effect.promise(() => + makeUserStore(db).upsertOrganization({ id: orgId, name: "Acme" }), + ); + }), + ), + DbService.Live, + ); + + const result = await Effect.runPromise( + Effect.gen(function* () { + // Outer "request" scope. + yield* Effect.scoped(Layer.build(outer).pipe(Effect.asVoid)); + // Inner "handler" scope — fresh DbService. + return yield* Effect.scoped( + Effect.gen(function* () { + const db = yield* DbService; + return yield* Effect.promise(() => + makeUserStore(db).getOrganization(orgId), + ); + }).pipe(Effect.provide(DbService.Live)), + ) as Effect.Effect<{ id: string; name: string } | null, never, never>; + }) as Effect.Effect<{ id: string; name: string } | null, never, never>, + ); + + expect(result?.id).toBe(orgId); + expect(result?.name).toBe("Acme"); + }, 15_000); +}); diff --git a/apps/cloud/src/services/db.ts b/apps/cloud/src/services/db.ts index f7f6722f2b..b2a93a5412 100644 --- a/apps/cloud/src/services/db.ts +++ b/apps/cloud/src/services/db.ts @@ -1,14 +1,20 @@ // --------------------------------------------------------------------------- -// Database service — Hyperdrive on Cloudflare, node-postgres for local dev +// Database service — Postgres via postgres.js (porsager) // --------------------------------------------------------------------------- // +// We use `postgres` (not `pg`) because Cloudflare Workers forbids sharing +// I/O objects across request handlers, and `pg`'s CloudflareSocket silently +// hangs when its Client is reused across requests. postgres.js creates a +// fresh TCP socket per Effect scope, which aligns with Workers' per-request +// I/O model. See personal-notes/pg-cloudflare-sockets-dev.md. +// // Migrations are run out-of-band (e.g. via a separate script or CI step), // not at request time — Cloudflare Workers cannot read the filesystem. import { env } from "cloudflare:workers"; import { Context, Effect, Layer } from "effect"; -import { drizzle } from "drizzle-orm/node-postgres"; -import { Client } from "pg"; +import { drizzle } from "drizzle-orm/postgres-js"; +import postgres from "postgres"; import * as sharedSchema from "@executor/storage-postgres/schema"; import * as cloudSchema from "./schema"; import type { DrizzleDb } from "@executor/storage-postgres"; @@ -18,55 +24,42 @@ const schema = { ...sharedSchema, ...cloudSchema }; export type { DrizzleDb }; -// --------------------------------------------------------------------------- -// Connection helpers -// --------------------------------------------------------------------------- - -const resolveConnectionString = () => - env.HYPERDRIVE?.connectionString ?? server.DATABASE_URL; +const resolveConnectionString = () => { + // In local dev prefer an explicit DATABASE_URL (direct connection to + // the PGlite socket server) so we bypass Miniflare's Hyperdrive proxy. + // In production fall back to the Hyperdrive binding. + if (server.DATABASE_URL) { + return server.DATABASE_URL; + } + return env.HYPERDRIVE?.connectionString ?? server.DATABASE_URL; +}; -const acquirePostgres = (connectionString: string) => - Effect.tryPromise(async () => { - const client = new Client({ connectionString }); - await client.connect(); - return { db: drizzle(client, { schema }) as DrizzleDb, client }; +const makeSql = () => + postgres(resolveConnectionString(), { + max: 1, + idle_timeout: 0, + max_lifetime: 60, + connect_timeout: 10, + onnotice: () => undefined, }); -const releasePostgres = ({ - client, -}: { - client: { end: () => Promise }; -}) => - Effect.promise(() => client.end()).pipe( - Effect.orElseSucceed(() => undefined), - ); - -// --------------------------------------------------------------------------- -// Service -// --------------------------------------------------------------------------- - export class DbService extends Context.Tag("@executor/cloud/DbService")< DbService, DrizzleDb >() { - /** Scoped — connection released when the scope closes. Use for request handlers. */ static Live = Layer.scoped( this, - Effect.gen(function* () { - const { db } = yield* Effect.acquireRelease( - acquirePostgres(resolveConnectionString()), - releasePostgres, - ); - return db; - }), - ); - - /** Unscoped — connection stays open. Use for long-lived contexts like Durable Objects. */ - static Unscoped = Layer.effect( - this, - Effect.flatMap( - Effect.sync(resolveConnectionString), - (cs) => acquirePostgres(cs).pipe(Effect.map(({ db }) => db)), - ), + Effect.acquireRelease( + Effect.sync(() => { + const sql = makeSql(); + return { sql, db: drizzle(sql, { schema }) as DrizzleDb }; + }), + ({ sql }) => + // Fire-and-forget: the Terminate round-trip sometimes hangs, and + // we don't need to block scope close waiting for it. + Effect.sync(() => { + sql.end({ timeout: 0 }).catch(() => undefined); + }), + ).pipe(Effect.map(({ db }) => db)), ); } diff --git a/apps/cloud/src/services/executor.ts b/apps/cloud/src/services/executor.ts index e51dc44701..eb912dadd1 100644 --- a/apps/cloud/src/services/executor.ts +++ b/apps/cloud/src/services/executor.ts @@ -25,20 +25,20 @@ import { import { DbService } from "./db"; // --------------------------------------------------------------------------- -// Create a fresh executor for a team (stateless, per-request) +// Create a fresh executor for an organization (stateless, per-request) // --------------------------------------------------------------------------- -export const createTeamExecutor = ( - teamId: string, - teamName: string, +export const createOrgExecutor = ( + organizationId: string, + organizationName: string, encryptionKey: string, ) => Effect.gen(function* () { const db = yield* DbService; - const kv = makePgKv(db, teamId); + const kv = makePgKv(db, organizationId); const config = makePgConfig(db, { - teamId, - teamName, + organizationId, + organizationName, encryptionKey, plugins: [ openApiPlugin({ diff --git a/apps/cloud/src/services/schema.ts b/apps/cloud/src/services/schema.ts index 62776ff326..e4ac375034 100644 --- a/apps/cloud/src/services/schema.ts +++ b/apps/cloud/src/services/schema.ts @@ -1,40 +1,26 @@ // --------------------------------------------------------------------------- // Cloud-specific identity & multi-tenancy tables // --------------------------------------------------------------------------- +// +// AuthKit owns the canonical user/membership data. We mirror minimally: +// +// - `accounts` — login identity (foreign key anchor for created_by, etc.) +// - `organizations` — billing entity, scoping root for all domain data +// +// We do NOT mirror memberships, invitations, or user profile data. +// Those live in WorkOS and are queried via API when needed. -import { pgTable, text, timestamp, primaryKey } from "drizzle-orm/pg-core"; +import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; -export const users = pgTable("users", { +/** Login identity. The `id` is the WorkOS user ID. */ +export const accounts = pgTable("accounts", { id: text("id").primaryKey(), - email: text("email").notNull().unique(), - name: text("name"), - avatarUrl: text("avatar_url"), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); -export const teams = pgTable("teams", { - id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), +/** Organization (billing entity, scoping root). The `id` is the WorkOS organization ID. */ +export const organizations = pgTable("organizations", { + id: text("id").primaryKey(), name: text("name").notNull(), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }); - -export const teamMembers = pgTable( - "team_members", - { - teamId: text("team_id").notNull(), - userId: text("user_id").notNull(), - role: text("role").notNull().$default(() => "member"), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - }, - (table) => [primaryKey({ columns: [table.teamId, table.userId] })], -); - -export const invitations = pgTable("invitations", { - id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), - teamId: text("team_id").notNull(), - email: text("email").notNull(), - invitedBy: text("invited_by").notNull(), - status: text("status").notNull().$default(() => "pending"), - createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), - expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(), -}); diff --git a/apps/cloud/src/services/user-store.ts b/apps/cloud/src/services/user-store.ts index 3e266d6602..5189f393f6 100644 --- a/apps/cloud/src/services/user-store.ts +++ b/apps/cloud/src/services/user-store.ts @@ -1,135 +1,53 @@ // --------------------------------------------------------------------------- -// User / Team / Invitation management +// Account & Organization storage — minimal mirror of WorkOS data // --------------------------------------------------------------------------- +// +// AuthKit owns the canonical data for users, organizations, memberships, +// and invitations. We keep tiny local mirrors of accounts and organizations +// so domain tables can foreign-key against them and so we can resolve org +// metadata without an API call on every request. -import { eq, and } from "drizzle-orm"; +import { eq } from "drizzle-orm"; -import { users, teams, teamMembers, invitations } from "./schema"; +import { accounts, organizations } from "./schema"; import type { DrizzleDb } from "@executor/storage-postgres"; -export type User = typeof users.$inferSelect; -export type Team = typeof teams.$inferSelect; -export type TeamMember = typeof teamMembers.$inferSelect; -export type Invitation = typeof invitations.$inferSelect; +export type Account = typeof accounts.$inferSelect; +export type Organization = typeof organizations.$inferSelect; export const makeUserStore = (db: DrizzleDb) => ({ - // --- Users --- + // --- Accounts --- - upsertUser: async (user: { id: string; email: string; name?: string; avatarUrl?: string }) => { + ensureAccount: async (id: string) => { const [result] = await db - .insert(users) - .values(user) - .onConflictDoUpdate({ - target: users.id, - set: { email: user.email, name: user.name, avatarUrl: user.avatarUrl }, - }) - .returning(); - return result!; - }, - - getUser: async (userId: string) => { - const rows = await db.select().from(users).where(eq(users.id, userId)); - return rows[0] ?? null; - }, - - getUserByEmail: async (email: string) => { - const rows = await db.select().from(users).where(eq(users.email, email)); - return rows[0] ?? null; - }, - - // --- Teams --- - - createTeam: async (name: string) => { - const [team] = await db.insert(teams).values({ name }).returning(); - return team!; - }, - - getTeam: async (teamId: string) => { - const rows = await db.select().from(teams).where(eq(teams.id, teamId)); - return rows[0] ?? null; - }, - - addMember: async (teamId: string, userId: string, role: string = "member") => { - const [member] = await db - .insert(teamMembers) - .values({ teamId, userId, role }) + .insert(accounts) + .values({ id }) .onConflictDoNothing() .returning(); - return member ?? null; + return result ?? (await db.select().from(accounts).where(eq(accounts.id, id)))[0]!; }, - removeMember: async (teamId: string, userId: string) => { - const result = await db - .delete(teamMembers) - .where(and(eq(teamMembers.teamId, teamId), eq(teamMembers.userId, userId))) - .returning(); - return result.length > 0; + getAccount: async (id: string) => { + const rows = await db.select().from(accounts).where(eq(accounts.id, id)); + return rows[0] ?? null; }, - listMembers: async (teamId: string) => { - const rows = await db - .select({ - userId: teamMembers.userId, - role: teamMembers.role, - createdAt: teamMembers.createdAt, - email: users.email, - name: users.name, - avatarUrl: users.avatarUrl, - }) - .from(teamMembers) - .innerJoin(users, eq(teamMembers.userId, users.id)) - .where(eq(teamMembers.teamId, teamId)); - return rows; - }, + // --- Organizations --- - getTeamsForUser: async (userId: string) => { - const rows = await db - .select({ - teamId: teamMembers.teamId, - role: teamMembers.role, - teamName: teams.name, - teamCreatedAt: teams.createdAt, + upsertOrganization: async (org: { id: string; name: string }) => { + const [result] = await db + .insert(organizations) + .values(org) + .onConflictDoUpdate({ + target: organizations.id, + set: { name: org.name }, }) - .from(teamMembers) - .innerJoin(teams, eq(teamMembers.teamId, teams.id)) - .where(eq(teamMembers.userId, userId)); - return rows; - }, - - // --- Invitations --- - - createInvitation: async (teamId: string, email: string, invitedBy: string) => { - const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); // 7 days - const [invitation] = await db - .insert(invitations) - .values({ teamId, email, invitedBy, status: "pending", expiresAt }) .returning(); - return invitation!; - }, - - getPendingInvitations: async (email: string) => { - const rows = await db - .select() - .from(invitations) - .where(and(eq(invitations.email, email), eq(invitations.status, "pending"))); - return rows.filter((r) => r.expiresAt > new Date()); - }, - - getTeamInvitations: async (teamId: string) => { - const rows = await db - .select() - .from(invitations) - .where(and(eq(invitations.teamId, teamId), eq(invitations.status, "pending"))); - return rows.filter((r) => r.expiresAt > new Date()); + return result!; }, - acceptInvitation: async (invitationId: string) => { - const [updated] = await db - .update(invitations) - .set({ status: "accepted" }) - .where(eq(invitations.id, invitationId)) - .returning(); - return updated ?? null; + getOrganization: async (id: string) => { + const rows = await db.select().from(organizations).where(eq(organizations.id, id)); + return rows[0] ?? null; }, - }); diff --git a/apps/cloud/src/start.ts b/apps/cloud/src/start.ts index 89ffce126a..6fca169385 100644 --- a/apps/cloud/src/start.ts +++ b/apps/cloud/src/start.ts @@ -16,6 +16,12 @@ const getMarketingWorker = () => env.MARKETING as { fetch: typeof fetch } | unde const marketingMiddleware = createMiddleware({ type: "request" }).server( async ({ pathname, request, next }) => { + // Only proxy to the marketing worker on the production domain. In local + // dev we don't run `executor-marketing`, so unauthenticated visits fall + // through to the cloud app's routes (which show the sign-in page). + const host = new URL(request.url).hostname; + if (host !== "executor.sh") return next(); + const shouldProxyToMarketing = isMarketingPath(pathname) || (pathname === "/" && !parseCookie(request.headers.get("cookie"), "wos-session")); diff --git a/apps/cloud/src/test-worker.ts b/apps/cloud/src/test-worker.ts new file mode 100644 index 0000000000..3c52434759 --- /dev/null +++ b/apps/cloud/src/test-worker.ts @@ -0,0 +1,8 @@ +// Minimal entrypoint for the vitest-pool-workers test worker. The tests +// run inside this worker's module scope, so all we need is a placeholder +// fetch handler — we don't exercise it directly. +export default { + async fetch(): Promise { + return new Response("test-worker", { status: 200 }); + }, +}; diff --git a/apps/cloud/src/web/auth.tsx b/apps/cloud/src/web/auth.tsx index e746966a97..335ca76053 100644 --- a/apps/cloud/src/web/auth.tsx +++ b/apps/cloud/src/web/auth.tsx @@ -14,7 +14,7 @@ type AuthUser = { avatarUrl: string | null; }; -type AuthTeam = { +type AuthOrganization = { id: string; name: string; }; @@ -35,7 +35,7 @@ export const authAtom = type AuthState = | { status: "loading" } | { status: "unauthenticated" } - | { status: "authenticated"; user: AuthUser; team: AuthTeam | null }; + | { status: "authenticated"; user: AuthUser; organization: AuthOrganization | null }; const AuthContext = createContext({ status: "loading" }); @@ -49,7 +49,7 @@ const AuthProviderClient = ({ children }: { children: React.ReactNode }) => { onSuccess: ({ value }) => ({ status: "authenticated" as const, user: value.user, - team: value.team, + organization: value.organization, }), onFailure: () => ({ status: "unauthenticated" as const }), }); diff --git a/apps/cloud/src/web/shell.tsx b/apps/cloud/src/web/shell.tsx index cf7d45e869..97ccebce69 100644 --- a/apps/cloud/src/web/shell.tsx +++ b/apps/cloud/src/web/shell.tsx @@ -104,9 +104,9 @@ function UserFooter() {

{auth.user.name ?? auth.user.email}

- {auth.team && ( + {auth.organization && (

- {auth.team.name} + {auth.organization.name}

)} diff --git a/apps/cloud/vitest.config.ts b/apps/cloud/vitest.config.ts new file mode 100644 index 0000000000..c93e5aee81 --- /dev/null +++ b/apps/cloud/vitest.config.ts @@ -0,0 +1,14 @@ +import { cloudflareTest } from "@cloudflare/vitest-pool-workers"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [ + cloudflareTest({ + wrangler: { configPath: "./wrangler.test.jsonc" }, + }), + ], + test: { + include: ["src/**/*.test.ts"], + globalSetup: ["./scripts/test-globalsetup.ts"], + }, +}); diff --git a/apps/cloud/wrangler.jsonc b/apps/cloud/wrangler.jsonc index 8421dfa70b..effd17d4b8 100644 --- a/apps/cloud/wrangler.jsonc +++ b/apps/cloud/wrangler.jsonc @@ -36,7 +36,8 @@ "hyperdrive": [ { "binding": "HYPERDRIVE", - "id": "776c27dfec5f47f59343603b35a7b4c2" + "id": "776c27dfec5f47f59343603b35a7b4c2", + "localConnectionString": "postgresql://postgres:postgres@127.0.0.1:5433/postgres" } ], "worker_loaders": [ diff --git a/apps/cloud/wrangler.test.jsonc b/apps/cloud/wrangler.test.jsonc new file mode 100644 index 0000000000..e70b010888 --- /dev/null +++ b/apps/cloud/wrangler.test.jsonc @@ -0,0 +1,23 @@ +{ + // Test-only wrangler config for @cloudflare/vitest-pool-workers. + // Strips everything not needed for DbService tests and points the + // Hyperdrive binding at the in-process PGlite socket server started + // by vitest globalSetup (scripts/test-globalsetup.ts). + "$schema": "node_modules/wrangler/config-schema.json", + "name": "executor-cloud-test", + "compatibility_date": "2025-06-01", + "compatibility_flags": ["nodejs_compat"], + "main": "src/test-worker.ts", + "vars": { + // DbService reads DATABASE_URL first and bypasses Hyperdrive when set. + // The test-globalsetup.ts starts a PGlite socket server on this port. + "DATABASE_URL": "postgresql://postgres:postgres@127.0.0.1:5434/postgres", + // env.ts validates these as required — stub with dummies so module + // import doesn't throw. The DbService tests never touch WorkOS. + "WORKOS_API_KEY": "test_api_key", + "WORKOS_CLIENT_ID": "test_client_id", + "WORKOS_COOKIE_PASSWORD": "test_cookie_password_at_least_32_chars!", + "ENCRYPTION_KEY": "test-encryption-key", + "NODE_ENV": "test" + } +} diff --git a/bun.lock b/bun.lock index 9a92318c64..e082fdaab5 100644 --- a/bun.lock +++ b/bun.lock @@ -67,20 +67,26 @@ "drizzle-orm": "catalog:", "effect": "catalog:", "jose": "^5.6.3", - "pg": "^8.16.0", + "postgres": "^3.4.9", "react": "catalog:", "react-dom": "catalog:", }, "devDependencies": { + "@cloudflare/vitest-pool-workers": "^0.14.3", "@cloudflare/workers-types": "^4.20250620.0", + "@effect/vitest": "^0.29.0", + "@electric-sql/pglite": "^0.4.3", + "@electric-sql/pglite-socket": "^0.1.3", "@tailwindcss/vite": "catalog:", - "@types/pg": "^8.15.4", "@types/react": "catalog:", "@types/react-dom": "catalog:", "@vitejs/plugin-react": "catalog:", + "concurrently": "^9.2.1", + "drizzle-kit": "^0.31.10", "portless": "^0.10.1", "typescript": "catalog:", "vite": "catalog:", + "vitest": "^4.1.4", "wrangler": "^4.81.0", }, }, @@ -602,6 +608,9 @@ }, }, }, + "patchedDependencies": { + "iron-webcrypto@0.2.8": "patches/iron-webcrypto@0.2.8.patch", + }, "catalog": { "@effect/cli": "^0.73.2", "@effect/experimental": "^0.60.0", @@ -804,7 +813,7 @@ "@cloudflare/vite-plugin": ["@cloudflare/vite-plugin@1.31.1", "", { "dependencies": { "@cloudflare/unenv-preset": "2.16.0", "miniflare": "4.20260405.0", "unenv": "2.0.0-rc.24", "wrangler": "4.81.0", "ws": "8.18.0" }, "peerDependencies": { "vite": "^6.1.0 || ^7.0.0 || ^8.0.0" } }, "sha512-vw4pOS8FmODdCeWjAG0gO4OyZ4Bb4GXlET/taaLDRm7gC5uGcH5XRPoTUJPYrs54LbWZxi3e2iWXX3JLRv4Rfg=="], - "@cloudflare/vitest-pool-workers": ["@cloudflare/vitest-pool-workers@0.14.2", "", { "dependencies": { "cjs-module-lexer": "^1.2.3", "esbuild": "0.27.3", "miniflare": "4.20260405.0", "wrangler": "4.81.0", "zod": "^3.25.76" }, "peerDependencies": { "@vitest/runner": "^4.1.0", "@vitest/snapshot": "^4.1.0", "vitest": "^4.1.0" } }, "sha512-LM91FyE/cW8ttUEYTaYZyCzcP/aD5PRAsUUIvfq07xEfpRbooAdF7v+nnDbsJq/gncuWNpPPl0rlNWX4vZleBw=="], + "@cloudflare/vitest-pool-workers": ["@cloudflare/vitest-pool-workers@0.14.3", "", { "dependencies": { "cjs-module-lexer": "^1.2.3", "esbuild": "0.27.3", "miniflare": "4.20260409.0", "wrangler": "4.81.1", "zod": "^3.25.76" }, "peerDependencies": { "@vitest/runner": "^4.1.0", "@vitest/snapshot": "^4.1.0", "vitest": "^4.1.0" } }, "sha512-7J0K3f9iS2u6k2J/bY7/vJJcaLgEGXcfNrs2fSti6vc0l/L/I4XmYtvZ1JwmFa5xqiHG4tF0ktGSKUZbkqvzEw=="], "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260405.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-EbmdBcmeIGogKG4V1odSWQe7z4rHssUD4iaXv0cXA22/MFrzH3iQT0R+FJFyhucGtih/9B9E+6j0QbSQD8xT3w=="], @@ -866,6 +875,8 @@ "@electric-sql/pglite": ["@electric-sql/pglite@0.4.3", "", {}, "sha512-ichuWTgtd4mOM1G4SpyGJa5trT03lWbMypDV0fUXUCXg5hiHqVAz/bZyV68NqmkLB7WcYmj1RMJVSp8HV/v/ZQ=="], + "@electric-sql/pglite-socket": ["@electric-sql/pglite-socket@0.1.3", "", { "peerDependencies": { "@electric-sql/pglite": "0.4.3" }, "bin": { "pglite-server": "dist/scripts/server.js" } }, "sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ=="], + "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], "@electron/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", "minimist": "^1.2.5" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], @@ -892,57 +903,57 @@ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], "@executor/api": ["@executor/api@workspace:packages/core/api"], @@ -1084,7 +1095,7 @@ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], @@ -2038,7 +2049,7 @@ "cli-truncate": ["cli-truncate@2.1.0", "", { "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" } }, "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg=="], - "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], @@ -2064,6 +2075,8 @@ "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], + "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], "console-browserify": ["console-browserify@1.2.0", "", {}, "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="], @@ -2310,7 +2323,7 @@ "embla-carousel-reactive-utils": ["embla-carousel-reactive-utils@8.6.0", "", { "peerDependencies": { "embla-carousel": "8.6.0" } }, "sha512-fMVUDUEx0/uIEDM0Mz3dHznDhfX+znCCDCeIophYb1QGVM7YThSWX+wz11zlYwWFOr74b4QLGg0hrGPJeG2s4A=="], - "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], @@ -2346,7 +2359,7 @@ "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], - "esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -2892,7 +2905,7 @@ "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], - "miniflare": ["miniflare@4.20260405.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260405.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-tpr4XdWMq7zFdsHH+CS0XS47nQzlRZH0rMJ1vobOZbkrs3cIj7qbD40ON616hDnzHxwqwB2qKHzmmuj6oRisSQ=="], + "miniflare": ["miniflare@4.20260409.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260409.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-ayl6To4av0YuXsSivGgWLj+Ug8xZ0Qz3sGV8+Ok2LhNVl6m8m5ktEBM3LX9iT9MtLZRJwBlJrKcraNs/DlZQfA=="], "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], @@ -3314,6 +3327,8 @@ "rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="], + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], @@ -3356,6 +3371,8 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], + "shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="], "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], @@ -3424,7 +3441,7 @@ "streamdown": ["streamdown@2.5.0", "", { "dependencies": { "clsx": "^2.1.1", "hast-util-to-jsx-runtime": "^2.3.6", "html-url-attributes": "^3.0.1", "marked": "^17.0.1", "mermaid": "^11.12.2", "rehype-harden": "^1.1.8", "rehype-raw": "^7.0.0", "rehype-sanitize": "^6.0.0", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remend": "1.3.0", "tailwind-merge": "^3.4.0", "unified": "^11.0.5", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-/tTnURfIOxZK/pqJAxsfCvETG/XCJHoWnk3jq9xLcuz6CSpnjjuxSRBTTL4PKGhxiZQf0lqPxGhImdpwcZ2XwA=="], - "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -3448,7 +3465,7 @@ "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], @@ -3504,6 +3521,8 @@ "toml": ["toml@3.0.0", "", {}, "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], @@ -3662,7 +3681,7 @@ "wrangler": ["wrangler@4.81.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.2", "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", "miniflare": "4.20260405.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260405.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260405.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-9fLPDuDcb8Nu6iXrl5E3HGYt3TVhQr/UvqtTvWr9Nl1X7PlQrmWMwQCfSioqN8VHYyQCyESV5jQsoKg8Sx+sEA=="], - "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -3684,7 +3703,7 @@ "yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], - "yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], @@ -3710,6 +3729,8 @@ "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/generator/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -3720,11 +3741,11 @@ "@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - "@cloudflare/vitest-pool-workers/esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], + "@cloudflare/vite-plugin/miniflare": ["miniflare@4.20260405.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260405.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-tpr4XdWMq7zFdsHH+CS0XS47nQzlRZH0rMJ1vobOZbkrs3cIj7qbD40ON616hDnzHxwqwB2qKHzmmuj6oRisSQ=="], - "@cloudflare/vitest-pool-workers/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@cloudflare/vitest-pool-workers/wrangler": ["wrangler@4.81.1", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.2", "@cloudflare/unenv-preset": "2.16.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.3", "miniflare": "4.20260409.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260409.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20260409.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-fppPXi+W2KJ5bx1zxdUYe1e7CHj5cWPFVBPXy8hSMZhrHeIojMe3ozAktAOw1voVuQjXzbZJf/GVKyVeSjbF8w=="], - "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + "@cloudflare/vitest-pool-workers/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@develar/schema-utils/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], @@ -3750,8 +3771,6 @@ "@electron/rebuild/node-abi": ["node-abi@4.28.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-Qfp5XZL1cJDOabOT8H5gnqMTmM4NjvYzHp4I/Kt/Sl76OVkOBBHRFlPspGV0hYvMoqQsypFjT/Yp7Km0beXW9g=="], - "@electron/rebuild/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], - "@electron/universal/fs-extra": ["fs-extra@11.3.4", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA=="], "@electron/universal/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], @@ -3760,6 +3779,32 @@ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "@executor/cloud/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/codemode-core/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/env/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/execution/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/host-mcp/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/plugin-google-discovery/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/plugin-graphql/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/plugin-mcp/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/plugin-openapi/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/runtime-dynamic-worker/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/runtime-quickjs/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/sdk/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + + "@executor/storage-postgres/vitest": ["vitest@4.1.4", "", { "dependencies": { "@vitest/expect": "4.1.4", "@vitest/mocker": "4.1.4", "@vitest/pretty-format": "4.1.4", "@vitest/runner": "4.1.4", "@vitest/snapshot": "4.1.4", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.4", "@vitest/browser-preview": "4.1.4", "@vitest/browser-webdriverio": "4.1.4", "@vitest/coverage-istanbul": "4.1.4", "@vitest/coverage-v8": "4.1.4", "@vitest/ui": "4.1.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg=="], + "@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -3768,6 +3813,10 @@ "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@jridgewell/gen-mapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@jridgewell/remapping/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], @@ -3874,6 +3923,8 @@ "@secure-exec/nodejs/es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + "@secure-exec/nodejs/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.9.2", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" }, "bundled": true }, "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.9.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw=="], @@ -3900,6 +3951,8 @@ "@vercel/functions/@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="], + "agents/yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], + "ajv-keywords/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], @@ -3914,6 +3967,8 @@ "asn1.js/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], + "astro/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + "astro/package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], "astro/vite": ["vite@7.3.2", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg=="], @@ -3934,9 +3989,7 @@ "cbor-extract/node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.1.1", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-test": "build-test.js", "node-gyp-build-optional-packages-optional": "optional.js" } }, "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw=="], - "cli-truncate/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], @@ -3974,8 +4027,6 @@ "electron-builder/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], - "electron-builder/yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], - "electron-publish/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], "electron-publish/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], @@ -4030,6 +4081,8 @@ "miniflare/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], + "miniflare/workerd": ["workerd@1.20260409.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260409.1", "@cloudflare/workerd-darwin-arm64": "1.20260409.1", "@cloudflare/workerd-linux-64": "1.20260409.1", "@cloudflare/workerd-linux-arm64": "1.20260409.1", "@cloudflare/workerd-windows-64": "1.20260409.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-kuWP20fAaqaLBqLbvUfY9nCF6c3C78L60G9lS6eVwBf+v8trVFIsAdLB/FtrnKm7vgVvpDzvFAfB80VIiVj95w=="], + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], @@ -4082,10 +4135,6 @@ "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - - "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - "tar-fs/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], "temp-file/fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], @@ -4094,6 +4143,8 @@ "to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "tsx/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], + "unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "uri-js/punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -4102,67 +4153,17 @@ "whatwg-encoding/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], - "wrangler/esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], + "wrangler/miniflare": ["miniflare@4.20260405.0", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "sharp": "^0.34.5", "undici": "7.24.4", "workerd": "1.20260405.1", "ws": "8.18.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-tpr4XdWMq7zFdsHH+CS0XS47nQzlRZH0rMJ1vobOZbkrs3cIj7qbD40ON616hDnzHxwqwB2qKHzmmuj6oRisSQ=="], - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@astrojs/cloudflare/vite/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + "@cloudflare/vite-plugin/miniflare/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - - "@cloudflare/vitest-pool-workers/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd": ["workerd@1.20260409.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260409.1", "@cloudflare/workerd-darwin-arm64": "1.20260409.1", "@cloudflare/workerd-linux-64": "1.20260409.1", "@cloudflare/workerd-linux-arm64": "1.20260409.1", "@cloudflare/workerd-windows-64": "1.20260409.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-kuWP20fAaqaLBqLbvUfY9nCF6c3C78L60G9lS6eVwBf+v8trVFIsAdLB/FtrnKm7vgVvpDzvFAfB80VIiVj95w=="], "@develar/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], @@ -4180,12 +4181,6 @@ "@electron/osx-sign/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "@electron/rebuild/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - - "@electron/rebuild/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "@electron/rebuild/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "@electron/universal/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "@electron/universal/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -4240,6 +4235,188 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + "@executor/cloud/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/cloud/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/cloud/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/cloud/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/cloud/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/cloud/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/cloud/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/codemode-core/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/codemode-core/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/codemode-core/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/codemode-core/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/codemode-core/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/codemode-core/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/codemode-core/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/env/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/env/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/env/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/env/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/env/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/env/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/env/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/execution/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/execution/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/execution/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/execution/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/execution/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/execution/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/execution/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/host-mcp/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/host-mcp/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/host-mcp/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/host-mcp/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/host-mcp/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/host-mcp/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/host-mcp/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/plugin-google-discovery/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/plugin-google-discovery/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/plugin-google-discovery/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/plugin-google-discovery/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/plugin-google-discovery/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/plugin-google-discovery/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/plugin-google-discovery/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/plugin-graphql/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/plugin-graphql/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/plugin-graphql/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/plugin-graphql/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/plugin-graphql/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/plugin-graphql/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/plugin-graphql/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/plugin-mcp/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/plugin-mcp/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/plugin-mcp/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/plugin-mcp/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/plugin-mcp/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/plugin-mcp/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/plugin-mcp/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/plugin-openapi/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/plugin-openapi/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/plugin-openapi/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/plugin-openapi/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/plugin-openapi/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/plugin-openapi/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/plugin-openapi/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/runtime-dynamic-worker/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/runtime-quickjs/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/runtime-quickjs/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/runtime-quickjs/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/runtime-quickjs/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/runtime-quickjs/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/runtime-quickjs/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/runtime-quickjs/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/sdk/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/sdk/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/sdk/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/sdk/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/sdk/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/sdk/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/sdk/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + + "@executor/storage-postgres/vitest/@vitest/expect": ["@vitest/expect@4.1.4", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.4", "@vitest/utils": "4.1.4", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww=="], + + "@executor/storage-postgres/vitest/@vitest/mocker": ["@vitest/mocker@4.1.4", "", { "dependencies": { "@vitest/spy": "4.1.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg=="], + + "@executor/storage-postgres/vitest/@vitest/pretty-format": ["@vitest/pretty-format@4.1.4", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A=="], + + "@executor/storage-postgres/vitest/@vitest/runner": ["@vitest/runner@4.1.4", "", { "dependencies": { "@vitest/utils": "4.1.4", "pathe": "^2.0.3" } }, "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ=="], + + "@executor/storage-postgres/vitest/@vitest/snapshot": ["@vitest/snapshot@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "@vitest/utils": "4.1.4", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw=="], + + "@executor/storage-postgres/vitest/@vitest/spy": ["@vitest/spy@4.1.4", "", {}, "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ=="], + + "@executor/storage-postgres/vitest/@vitest/utils": ["@vitest/utils@4.1.4", "", { "dependencies": { "@vitest/pretty-format": "4.1.4", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw=="], + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], @@ -4250,6 +4427,62 @@ "@malept/flatpak-bundler/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "@secure-exec/nodejs/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + + "@secure-exec/nodejs/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + + "@secure-exec/nodejs/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + + "@secure-exec/nodejs/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + + "@secure-exec/nodejs/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + + "@secure-exec/nodejs/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + + "@secure-exec/nodejs/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + + "@secure-exec/nodejs/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + + "@secure-exec/nodejs/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + + "@secure-exec/nodejs/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + + "@secure-exec/nodejs/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + + "agents/yargs/cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + + "agents/yargs/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], @@ -4262,6 +4495,58 @@ "app-builder-lib/which/isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], + "astro/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + + "astro/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + + "astro/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + + "astro/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + + "astro/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + + "astro/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + + "astro/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + + "astro/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + + "astro/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + + "astro/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + + "astro/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + + "astro/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + + "astro/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + + "astro/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + + "astro/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + + "astro/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + + "astro/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + + "astro/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + + "astro/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + + "astro/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + + "astro/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + + "astro/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + + "astro/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + + "astro/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + + "astro/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + + "astro/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + "browserify-sign/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "browserify-sign/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -4272,10 +4557,6 @@ "cacache/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], - "cli-truncate/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], @@ -4350,12 +4631,6 @@ "electron-builder/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], - "electron-builder/yargs/cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], - - "electron-builder/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - - "electron-builder/yargs/yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "electron-publish/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "electron-publish/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -4372,6 +4647,16 @@ "mimetext/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "miniflare/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260409.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-h/bkaC0HJL63aqAGnV0oagqpBiTSstabODThkeMSbG8kctl0Jb4jlq1pNHJPmYGazFNtfyagrUZFb6HN22GX7w=="], + + "miniflare/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260409.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HTAC+B9uSYcm+GjN3UYJjuun19GqYtK1bAFJ0KECXyfsgIDwH1MTzxbTxzJpZUbWLw8s0jcwCU06MWZj6cgnxQ=="], + + "miniflare/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260409.1", "", { "os": "linux", "cpu": "x64" }, "sha512-QIoNq5cgmn1ko8qlngmgZLXQr2KglrjvIwVFOyJI3rbIpt8631n/YMzHPiOWgt38Cb6tcni8fXOzkcvIX2lBDg=="], + + "miniflare/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260409.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-HJGBMTfPDb0GCjwdxWFx63wS20TYDVmtOuA5KVri/CiFnit71y++kmseVmemjsgLFFIzoEAuFG/xUh1FJLo6tg=="], + + "miniflare/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260409.1", "", { "os": "win32", "cpu": "x64" }, "sha512-GttFO0+TvE0rJNQbDlxC6kq2Q7uFxoZRo74Z9d/trUrLgA14HEVTTXobYyiWrDZ9Qp2W5KN1CrXQXiko0zE38Q=="], + "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -4386,85 +4671,143 @@ "ripemd160/hash-base/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], - "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "temp-file/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "temp-file/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], + + "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], + + "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], + + "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], + + "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], + + "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], + + "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], + + "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], + + "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], + + "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], + + "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], + + "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], + + "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], + + "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], + + "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], + + "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], + + "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], + + "tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], + + "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], + + "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], + + "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], + + "tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], + + "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], + + "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], + + "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], + + "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], + "unstorage/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], - "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], + "wrangler/miniflare/undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="], - "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="], - "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="], - "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="], - "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="], - "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="], - "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="], - "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="], - "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="], - "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="], - "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="], - "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="], - "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="], - "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="], - "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="], - "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="], - "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="], - "wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="], - "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="], - "wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="], - "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="], - "wrangler/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="], - "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="], - "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="], - "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="], - "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="], - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@astrojs/cloudflare/vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="], - "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20260409.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-h/bkaC0HJL63aqAGnV0oagqpBiTSstabODThkeMSbG8kctl0Jb4jlq1pNHJPmYGazFNtfyagrUZFb6HN22GX7w=="], - "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20260409.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HTAC+B9uSYcm+GjN3UYJjuun19GqYtK1bAFJ0KECXyfsgIDwH1MTzxbTxzJpZUbWLw8s0jcwCU06MWZj6cgnxQ=="], - "@electron/rebuild/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20260409.1", "", { "os": "linux", "cpu": "x64" }, "sha512-QIoNq5cgmn1ko8qlngmgZLXQr2KglrjvIwVFOyJI3rbIpt8631n/YMzHPiOWgt38Cb6tcni8fXOzkcvIX2lBDg=="], - "@electron/rebuild/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20260409.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-HJGBMTfPDb0GCjwdxWFx63wS20TYDVmtOuA5KVri/CiFnit71y++kmseVmemjsgLFFIzoEAuFG/xUh1FJLo6tg=="], + + "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20260409.1", "", { "os": "win32", "cpu": "x64" }, "sha512-GttFO0+TvE0rJNQbDlxC6kq2Q7uFxoZRo74Z9d/trUrLgA14HEVTTXobYyiWrDZ9Qp2W5KN1CrXQXiko0zE38Q=="], + + "@electron/asar/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "@electron/universal/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.3", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA=="], + "agents/yargs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], - "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "agents/yargs/cliui/wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + + "agents/yargs/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], - "electron-builder/yargs/cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "agents/yargs/string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.3", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA=="], - "electron-builder/yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "dir-compare/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "filelist/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -4478,6 +4821,12 @@ "ripemd160/hash-base/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + "agents/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "agents/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "agents/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "cacache/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], diff --git a/notes/auth.md b/notes/auth.md new file mode 100644 index 0000000000..4a26da2451 --- /dev/null +++ b/notes/auth.md @@ -0,0 +1,92 @@ +https://x.com/thdxr/status/1788284129810772367 +https://x.com/thdxr/status/1651434348174778370 + +i am so tired of SaaS companies getting auth wrong - it's the first thing your users experience please get it right + +i should be able to use a single email and attach multiple workspaces + +i should be able to stay logged in with multiple emails and switch between workspaces +12:05 PM · May 8, 2024 +· +233.1K +Views +Relevant +View quotes + +dax + +@thdxr +· +May 8, 2024 +@StainlessAPI +you force github login...then ask me to associate my work email withit + +i have a single personal github as do most people - if i'm logged into it it's going to be my personal email + +i have no way to now use your product across multiple projects +dax + +@thdxr +· +May 8, 2024 +@tursodatabase +is using +@clerk +so not sure who's at fault here but + +do not ask for usernames in b2b software, this isn't a social network it's a pain in the ass to come up with unique ones for each account i have + +and email validation is rejecting my email +dax + +@thdxr +· +May 8, 2024 +@PlanetScale +you are so close but there's no way to stay logged into multiple emails + +i know one email can have access to many orgs but you usually have an email per org + +pain to log in and out of them instead of a quick switcher - same goes for CLI +dax + +@thdxr +· +May 8, 2024 +wow i already said all this 2 months ago +Quote +dax + +@thdxr +· +Mar 1, 2024 +every six months i come to beg of you + +in your app please support both + +- one email account can access multiple workspaces +- can be signed into multiple email accounts at the same time and switch between them + +if you need a reference implementation check linear + +please +dax + +@thdxr +· +May 8, 2024 +your data model should be + +1. workspace +2. user (belongs to workspace) +3. account (associated with many users) + +when i log in i get a token for the account - if i login multiple times save multiple tokens + +if you don't do this i don't wanna see you post any opinions till you fix +dax + +@thdxr +· +May 8, 2024 +i'm not kidding why should anyone listen to you about anything when you can't get this right diff --git a/package.json b/package.json index e33e2fd0f0..d9b741b015 100644 --- a/package.json +++ b/package.json @@ -88,5 +88,8 @@ "typescript": "^5.9.3", "vitest": "catalog:" }, - "dependencies": {} + "dependencies": {}, + "patchedDependencies": { + "iron-webcrypto@0.2.8": "patches/iron-webcrypto@0.2.8.patch" + } } diff --git a/packages/core/storage-postgres/drizzle/0000_great_speedball.sql b/packages/core/storage-postgres/drizzle/0000_great_speedball.sql deleted file mode 100644 index 0ed611bc71..0000000000 --- a/packages/core/storage-postgres/drizzle/0000_great_speedball.sql +++ /dev/null @@ -1,102 +0,0 @@ -CREATE TABLE "invitations" ( - "id" text PRIMARY KEY NOT NULL, - "team_id" text NOT NULL, - "email" text NOT NULL, - "invited_by" text NOT NULL, - "status" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - "expires_at" timestamp with time zone NOT NULL -); ---> statement-breakpoint -CREATE TABLE "plugin_kv" ( - "team_id" text NOT NULL, - "namespace" text NOT NULL, - "key" text NOT NULL, - "value" text NOT NULL, - CONSTRAINT "plugin_kv_team_id_namespace_key_pk" PRIMARY KEY("team_id","namespace","key") -); ---> statement-breakpoint -CREATE TABLE "policies" ( - "id" text NOT NULL, - "team_id" text NOT NULL, - "name" text NOT NULL, - "action" text NOT NULL, - "match_tool_pattern" text, - "match_source_id" text, - "priority" integer NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "policies_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "secrets" ( - "id" text NOT NULL, - "team_id" text NOT NULL, - "name" text NOT NULL, - "purpose" text, - "encrypted_value" "bytea" NOT NULL, - "iv" "bytea" NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "secrets_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "sessions" ( - "id" text PRIMARY KEY NOT NULL, - "user_id" text NOT NULL, - "team_id" text NOT NULL, - "expires_at" timestamp with time zone NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "sources" ( - "id" text NOT NULL, - "team_id" text NOT NULL, - "name" text NOT NULL, - "kind" text NOT NULL, - "config" jsonb NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "sources_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "team_members" ( - "team_id" text NOT NULL, - "user_id" text NOT NULL, - "role" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "team_members_team_id_user_id_pk" PRIMARY KEY("team_id","user_id") -); ---> statement-breakpoint -CREATE TABLE "teams" ( - "id" text PRIMARY KEY NOT NULL, - "name" text NOT NULL, - "created_at" timestamp with time zone DEFAULT now() NOT NULL -); ---> statement-breakpoint -CREATE TABLE "tool_definitions" ( - "name" text NOT NULL, - "team_id" text NOT NULL, - "schema" jsonb NOT NULL, - CONSTRAINT "tool_definitions_name_team_id_pk" PRIMARY KEY("name","team_id") -); ---> statement-breakpoint -CREATE TABLE "tools" ( - "id" text NOT NULL, - "team_id" text NOT NULL, - "source_id" text NOT NULL, - "plugin_key" text NOT NULL, - "name" text NOT NULL, - "description" text, - "may_elicit" boolean, - "input_schema" jsonb, - "output_schema" jsonb, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "tools_id_team_id_pk" PRIMARY KEY("id","team_id") -); ---> statement-breakpoint -CREATE TABLE "users" ( - "id" text PRIMARY KEY NOT NULL, - "email" text NOT NULL, - "name" text, - "avatar_url" text, - "created_at" timestamp with time zone DEFAULT now() NOT NULL, - CONSTRAINT "users_email_unique" UNIQUE("email") -); diff --git a/packages/core/storage-postgres/drizzle/0000_magical_dreaming_celestial.sql b/packages/core/storage-postgres/drizzle/0000_magical_dreaming_celestial.sql new file mode 100644 index 0000000000..39915946ba --- /dev/null +++ b/packages/core/storage-postgres/drizzle/0000_magical_dreaming_celestial.sql @@ -0,0 +1,61 @@ +CREATE TABLE "plugin_kv" ( + "organization_id" text NOT NULL, + "namespace" text NOT NULL, + "key" text NOT NULL, + "value" text NOT NULL, + CONSTRAINT "plugin_kv_organization_id_namespace_key_pk" PRIMARY KEY("organization_id","namespace","key") +); +--> statement-breakpoint +CREATE TABLE "policies" ( + "id" text NOT NULL, + "organization_id" text NOT NULL, + "name" text NOT NULL, + "action" text NOT NULL, + "match_tool_pattern" text, + "match_source_id" text, + "priority" integer NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "policies_id_organization_id_pk" PRIMARY KEY("id","organization_id") +); +--> statement-breakpoint +CREATE TABLE "secrets" ( + "id" text NOT NULL, + "organization_id" text NOT NULL, + "name" text NOT NULL, + "purpose" text, + "encrypted_value" "bytea" NOT NULL, + "iv" "bytea" NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "secrets_id_organization_id_pk" PRIMARY KEY("id","organization_id") +); +--> statement-breakpoint +CREATE TABLE "sources" ( + "id" text NOT NULL, + "organization_id" text NOT NULL, + "name" text NOT NULL, + "kind" text NOT NULL, + "config" jsonb NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "sources_id_organization_id_pk" PRIMARY KEY("id","organization_id") +); +--> statement-breakpoint +CREATE TABLE "tool_definitions" ( + "name" text NOT NULL, + "organization_id" text NOT NULL, + "schema" jsonb NOT NULL, + CONSTRAINT "tool_definitions_name_organization_id_pk" PRIMARY KEY("name","organization_id") +); +--> statement-breakpoint +CREATE TABLE "tools" ( + "id" text NOT NULL, + "organization_id" text NOT NULL, + "source_id" text NOT NULL, + "plugin_key" text NOT NULL, + "name" text NOT NULL, + "description" text, + "may_elicit" boolean, + "input_schema" jsonb, + "output_schema" jsonb, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "tools_id_organization_id_pk" PRIMARY KEY("id","organization_id") +); diff --git a/packages/core/storage-postgres/drizzle/meta/0000_snapshot.json b/packages/core/storage-postgres/drizzle/meta/0000_snapshot.json index 81a491f634..9443cefbbf 100644 --- a/packages/core/storage-postgres/drizzle/meta/0000_snapshot.json +++ b/packages/core/storage-postgres/drizzle/meta/0000_snapshot.json @@ -1,71 +1,15 @@ { - "id": "ee7b4779-1928-46a3-bcb8-1a48898bec19", + "id": "3f5c8ba8-3276-4ba8-8261-02be1173ea7b", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { - "public.invitations": { - "name": "invitations", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "team_id": { - "name": "team_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "invited_by": { - "name": "invited_by", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "status": { - "name": "status", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, "public.plugin_kv": { "name": "plugin_kv", "schema": "", "columns": { - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -92,10 +36,10 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "plugin_kv_team_id_namespace_key_pk": { - "name": "plugin_kv_team_id_namespace_key_pk", + "plugin_kv_organization_id_namespace_key_pk": { + "name": "plugin_kv_organization_id_namespace_key_pk", "columns": [ - "team_id", + "organization_id", "namespace", "key" ] @@ -116,8 +60,8 @@ "primaryKey": false, "notNull": true }, - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -163,11 +107,11 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "policies_id_team_id_pk": { - "name": "policies_id_team_id_pk", + "policies_id_organization_id_pk": { + "name": "policies_id_organization_id_pk", "columns": [ "id", - "team_id" + "organization_id" ] } }, @@ -186,8 +130,8 @@ "primaryKey": false, "notNull": true }, - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -227,11 +171,11 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "secrets_id_team_id_pk": { - "name": "secrets_id_team_id_pk", + "secrets_id_organization_id_pk": { + "name": "secrets_id_organization_id_pk", "columns": [ "id", - "team_id" + "organization_id" ] } }, @@ -250,8 +194,8 @@ "primaryKey": false, "notNull": true }, - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -285,11 +229,11 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "sources_id_team_id_pk": { - "name": "sources_id_team_id_pk", + "sources_id_organization_id_pk": { + "name": "sources_id_organization_id_pk", "columns": [ "id", - "team_id" + "organization_id" ] } }, @@ -298,84 +242,6 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.team_members": { - "name": "team_members", - "schema": "", - "columns": { - "team_id": { - "name": "team_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "role": { - "name": "role", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": { - "team_members_team_id_user_id_pk": { - "name": "team_members_team_id_user_id_pk", - "columns": [ - "team_id", - "user_id" - ] - } - }, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.teams": { - "name": "teams", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, "public.tool_definitions": { "name": "tool_definitions", "schema": "", @@ -386,8 +252,8 @@ "primaryKey": false, "notNull": true }, - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -402,11 +268,11 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "tool_definitions_name_team_id_pk": { - "name": "tool_definitions_name_team_id_pk", + "tool_definitions_name_organization_id_pk": { + "name": "tool_definitions_name_organization_id_pk", "columns": [ "name", - "team_id" + "organization_id" ] } }, @@ -425,8 +291,8 @@ "primaryKey": false, "notNull": true }, - "team_id": { - "name": "team_id", + "organization_id": { + "name": "organization_id", "type": "text", "primaryKey": false, "notNull": true @@ -484,11 +350,11 @@ "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "tools_id_team_id_pk": { - "name": "tools_id_team_id_pk", + "tools_id_organization_id_pk": { + "name": "tools_id_organization_id_pk", "columns": [ "id", - "team_id" + "organization_id" ] } }, @@ -496,58 +362,6 @@ "policies": {}, "checkConstraints": {}, "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "avatar_url": { - "name": "avatar_url", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp with time zone", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_email_unique": { - "name": "users_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false } }, "enums": {}, diff --git a/packages/core/storage-postgres/drizzle/meta/_journal.json b/packages/core/storage-postgres/drizzle/meta/_journal.json index d9131a2b44..de11da2dbd 100644 --- a/packages/core/storage-postgres/drizzle/meta/_journal.json +++ b/packages/core/storage-postgres/drizzle/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "7", - "when": 1775552333040, - "tag": "0000_spicy_zemo", + "when": 1775718391348, + "tag": "0000_magical_dreaming_celestial", "breakpoints": true } ] diff --git a/packages/core/storage-postgres/src/index.test.ts b/packages/core/storage-postgres/src/index.test.ts index 0804a8e964..77aea7f104 100644 --- a/packages/core/storage-postgres/src/index.test.ts +++ b/packages/core/storage-postgres/src/index.test.ts @@ -27,8 +27,8 @@ import * as schema from "./schema"; // Test setup — in-memory Postgres via PGlite + Drizzle migrations // --------------------------------------------------------------------------- -const TEST_TEAM_ID = "test-team-1"; -const TEST_TEAM_NAME = "Test Team"; +const TEST_ORG_ID = "test-org-1"; +const TEST_ORG_NAME = "Test Org"; const TEST_ENCRYPTION_KEY = "test-encryption-key-for-unit-tests"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -45,7 +45,7 @@ beforeAll(async () => { beforeEach(async () => { await db.execute( - sql`TRUNCATE plugin_kv, policies, secrets, tool_definitions, tools, sources, invitations, team_members, teams, users`, + sql`TRUNCATE plugin_kv, policies, secrets, tool_definitions, tools, sources`, ); }); @@ -59,17 +59,17 @@ afterAll(async () => { const makeTestExecutor = () => { const config = makePgConfig(db, { - teamId: TEST_TEAM_ID, - teamName: TEST_TEAM_NAME, + organizationId: TEST_ORG_ID, + organizationName: TEST_ORG_NAME, encryptionKey: TEST_ENCRYPTION_KEY, }); return createExecutor(config); }; -const makeTestExecutorForTeam = (teamId: string, teamName: string) => { +const makeTestExecutorForOrg = (organizationId: string, organizationName: string) => { const config = makePgConfig(db, { - teamId, - teamName, + organizationId, + organizationName, encryptionKey: TEST_ENCRYPTION_KEY, }); return createExecutor(config); @@ -80,11 +80,11 @@ const makeTestExecutorForTeam = (teamId: string, teamName: string) => { // --------------------------------------------------------------------------- describe("Executor with Postgres storage", () => { - it.effect("scope reflects team", () => + it.effect("scope reflects organization", () => Effect.gen(function* () { const executor = yield* makeTestExecutor(); - expect(executor.scope.id).toBe(TEST_TEAM_ID); - expect(executor.scope.name).toBe(TEST_TEAM_NAME); + expect(executor.scope.id).toBe(TEST_ORG_ID); + expect(executor.scope.name).toBe(TEST_ORG_NAME); }), ); @@ -96,8 +96,8 @@ describe("Executor with Postgres storage", () => { // Register tools via the underlying registry (plugins do this) const config = makePgConfig(db, { - teamId: TEST_TEAM_ID, - teamName: TEST_TEAM_NAME, + organizationId: TEST_ORG_ID, + organizationName: TEST_ORG_NAME, encryptionKey: TEST_ENCRYPTION_KEY, }); yield* config.tools.register([ @@ -129,8 +129,8 @@ describe("Executor with Postgres storage", () => { Effect.gen(function* () { const executor = yield* makeTestExecutor(); const config = makePgConfig(db, { - teamId: TEST_TEAM_ID, - teamName: TEST_TEAM_NAME, + organizationId: TEST_ORG_ID, + organizationName: TEST_ORG_NAME, encryptionKey: TEST_ENCRYPTION_KEY, }); yield* config.tools.register([ @@ -208,7 +208,7 @@ describe("Executor with Postgres storage", () => { it.effect("encryption with wrong key fails to resolve", () => Effect.gen(function* () { - const executor1 = yield* makeTestExecutorForTeam(TEST_TEAM_ID, TEST_TEAM_NAME); + const executor1 = yield* makeTestExecutorForOrg(TEST_ORG_ID, TEST_ORG_NAME); yield* executor1.secrets.set({ id: SecretId.make("enc-test"), name: "Encrypted", @@ -217,8 +217,8 @@ describe("Executor with Postgres storage", () => { // Create executor with different encryption key const config2 = makePgConfig(db, { - teamId: TEST_TEAM_ID, - teamName: TEST_TEAM_NAME, + organizationId: TEST_ORG_ID, + organizationName: TEST_ORG_NAME, encryptionKey: "wrong-key", }); const executor2 = yield* createExecutor(config2); @@ -236,7 +236,7 @@ describe("Executor with Postgres storage", () => { Effect.gen(function* () { const executor = yield* makeTestExecutor(); const policy = yield* executor.policies.add({ - scopeId: ScopeId.make(TEST_TEAM_ID), + scopeId: ScopeId.make(TEST_ORG_ID), name: "allow-t1", action: "allow" as const, match: { toolPattern: "t1" }, @@ -253,7 +253,7 @@ describe("Executor with Postgres storage", () => { Effect.gen(function* () { const executor = yield* makeTestExecutor(); const policy = yield* executor.policies.add({ - scopeId: ScopeId.make(TEST_TEAM_ID), + scopeId: ScopeId.make(TEST_ORG_ID), name: "allow-t1", action: "allow" as const, match: { toolPattern: "t1" }, @@ -267,16 +267,16 @@ describe("Executor with Postgres storage", () => { // --- Team isolation --- - it.effect("team isolation — tools", () => + it.effect("organization isolation — tools", () => Effect.gen(function* () { - const configA = makePgConfig(db, { teamId: "team-a", teamName: "Team A", encryptionKey: TEST_ENCRYPTION_KEY }); - const configB = makePgConfig(db, { teamId: "team-b", teamName: "Team B", encryptionKey: TEST_ENCRYPTION_KEY }); + const configA = makePgConfig(db, { organizationId: "org-a", organizationName: "Org A", encryptionKey: TEST_ENCRYPTION_KEY }); + const configB = makePgConfig(db, { organizationId: "org-b", organizationName: "Org B", encryptionKey: TEST_ENCRYPTION_KEY }); yield* configA.tools.register([ - new ToolRegistration({ id: ToolId.make("t1"), pluginKey: "test", sourceId: "src", name: "team-a-tool" }), + new ToolRegistration({ id: ToolId.make("t1"), pluginKey: "test", sourceId: "src", name: "org-a-tool" }), ]); yield* configB.tools.register([ - new ToolRegistration({ id: ToolId.make("t1"), pluginKey: "test", sourceId: "src", name: "team-b-tool" }), + new ToolRegistration({ id: ToolId.make("t1"), pluginKey: "test", sourceId: "src", name: "org-b-tool" }), ]); const executorA = yield* createExecutor(configA); @@ -284,18 +284,18 @@ describe("Executor with Postgres storage", () => { const aTools = yield* executorA.tools.list(); expect(aTools).toHaveLength(1); - expect(aTools[0]!.name).toBe("team-a-tool"); + expect(aTools[0]!.name).toBe("org-a-tool"); const bTools = yield* executorB.tools.list(); expect(bTools).toHaveLength(1); - expect(bTools[0]!.name).toBe("team-b-tool"); + expect(bTools[0]!.name).toBe("org-b-tool"); }), ); - it.effect("team isolation — secrets", () => + it.effect("organization isolation — secrets", () => Effect.gen(function* () { - const executorA = yield* makeTestExecutorForTeam("team-a", "Team A"); - const executorB = yield* makeTestExecutorForTeam("team-b", "Team B"); + const executorA = yield* makeTestExecutorForOrg("org-a", "Org A"); + const executorB = yield* makeTestExecutorForOrg("org-b", "Org B"); yield* executorA.secrets.set({ id: SecretId.make("shared-id"), @@ -317,7 +317,7 @@ describe("Executor with Postgres storage", () => { it.effect("plugin KV works via scopeKv", () => Effect.gen(function* () { - const kv = makePgKv(db, TEST_TEAM_ID); + const kv = makePgKv(db, TEST_ORG_ID); const scoped = scopeKv(kv, "my-plugin"); yield* scoped.set("k1", "v1"); @@ -331,16 +331,16 @@ describe("Executor with Postgres storage", () => { }), ); - it.effect("plugin KV team isolation", () => + it.effect("plugin KV organization isolation", () => Effect.gen(function* () { - const kv1 = makePgKv(db, "team-a"); - const kv2 = makePgKv(db, "team-b"); + const kv1 = makePgKv(db, "org-a"); + const kv2 = makePgKv(db, "org-b"); - yield* kv1.set("ns", "key", "team-a-value"); - yield* kv2.set("ns", "key", "team-b-value"); + yield* kv1.set("ns", "key", "org-a-value"); + yield* kv2.set("ns", "key", "org-b-value"); - expect(yield* kv1.get("ns", "key")).toBe("team-a-value"); - expect(yield* kv2.get("ns", "key")).toBe("team-b-value"); + expect(yield* kv1.get("ns", "key")).toBe("org-a-value"); + expect(yield* kv2.get("ns", "key")).toBe("org-b-value"); }), ); diff --git a/packages/core/storage-postgres/src/index.ts b/packages/core/storage-postgres/src/index.ts index a7992b6a17..97df189145 100644 --- a/packages/core/storage-postgres/src/index.ts +++ b/packages/core/storage-postgres/src/index.ts @@ -12,7 +12,7 @@ // import * as schema from "@executor/storage-postgres/schema" // // const db = drizzle(pool, { schema }) -// const config = makePgConfig(db, { teamId: "...", teamName: "..." }) +// const config = makePgConfig(db, { organizationId: "...", organizationName: "..." }) // const executor = yield* createExecutor(config) // // --------------------------------------------------------------------------- @@ -41,24 +41,24 @@ export const makePgConfig = < >( db: DrizzleDb, options: { - readonly teamId: string; - readonly teamName: string; + readonly organizationId: string; + readonly organizationName: string; readonly encryptionKey: string; readonly plugins?: TPlugins; }, ): ExecutorConfig => { const scope: Scope = { - id: ScopeId.make(options.teamId), - name: options.teamName, + id: ScopeId.make(options.organizationId), + name: options.organizationName, createdAt: new Date(), }; return { scope, - tools: makePgToolRegistry(db, options.teamId), + tools: makePgToolRegistry(db, options.organizationId), sources: makeInMemorySourceRegistry(), - secrets: makePgSecretStore(db, options.teamId, options.encryptionKey), - policies: makePgPolicyEngine(db, options.teamId), + secrets: makePgSecretStore(db, options.organizationId, options.encryptionKey), + policies: makePgPolicyEngine(db, options.organizationId), plugins: options.plugins, }; }; diff --git a/packages/core/storage-postgres/src/pg-kv.ts b/packages/core/storage-postgres/src/pg-kv.ts index e72b656f73..0df90a6fc9 100644 --- a/packages/core/storage-postgres/src/pg-kv.ts +++ b/packages/core/storage-postgres/src/pg-kv.ts @@ -1,5 +1,5 @@ // --------------------------------------------------------------------------- -// Postgres-backed Kv — uses plugin_kv table, scoped by team_id +// Postgres-backed Kv — uses plugin_kv table, scoped by organization_id // --------------------------------------------------------------------------- import { Effect } from "effect"; @@ -9,7 +9,7 @@ import type { Kv } from "@executor/sdk"; import { pluginKv } from "./schema"; import type { DrizzleDb } from "./types"; -export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ +export const makePgKv = (db: DrizzleDb, organizationId: string): Kv => ({ get: (namespace, key) => Effect.tryPromise(async () => { const rows = await db @@ -17,7 +17,7 @@ export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ .from(pluginKv) .where( and( - eq(pluginKv.teamId, teamId), + eq(pluginKv.organizationId, organizationId), eq(pluginKv.namespace, namespace), eq(pluginKv.key, key), ), @@ -29,9 +29,9 @@ export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ Effect.tryPromise(async () => { await db .insert(pluginKv) - .values({ teamId, namespace, key, value }) + .values({ organizationId, namespace, key, value }) .onConflictDoUpdate({ - target: [pluginKv.teamId, pluginKv.namespace, pluginKv.key], + target: [pluginKv.organizationId, pluginKv.namespace, pluginKv.key], set: { value }, }); }).pipe(Effect.orDie), @@ -42,7 +42,7 @@ export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ .delete(pluginKv) .where( and( - eq(pluginKv.teamId, teamId), + eq(pluginKv.organizationId, organizationId), eq(pluginKv.namespace, namespace), eq(pluginKv.key, key), ), @@ -58,7 +58,7 @@ export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ .from(pluginKv) .where( and( - eq(pluginKv.teamId, teamId), + eq(pluginKv.organizationId, organizationId), eq(pluginKv.namespace, namespace), ), ); @@ -71,7 +71,7 @@ export const makePgKv = (db: DrizzleDb, teamId: string): Kv => ({ .delete(pluginKv) .where( and( - eq(pluginKv.teamId, teamId), + eq(pluginKv.organizationId, organizationId), eq(pluginKv.namespace, namespace), ), ) diff --git a/packages/core/storage-postgres/src/policy-engine.ts b/packages/core/storage-postgres/src/policy-engine.ts index ffe91523f2..3a20bbec48 100644 --- a/packages/core/storage-postgres/src/policy-engine.ts +++ b/packages/core/storage-postgres/src/policy-engine.ts @@ -13,7 +13,7 @@ import { policies } from "./schema"; export const makePgPolicyEngine = ( db: DrizzleDb, - teamId: string, + organizationId: string, ) => { let counter = 0; @@ -23,7 +23,7 @@ export const makePgPolicyEngine = ( const rows = await db .select() .from(policies) - .where(eq(policies.teamId, teamId)); + .where(eq(policies.organizationId, organizationId)); return rows.map( (row) => new Policy({ @@ -50,7 +50,7 @@ export const makePgPolicyEngine = ( const now = new Date(); await db.insert(policies).values({ id, - teamId, + organizationId, name: policy.name, action: policy.action, matchToolPattern: policy.match.toolPattern, @@ -65,7 +65,7 @@ export const makePgPolicyEngine = ( Effect.tryPromise(async () => { const result = await db .delete(policies) - .where(and(eq(policies.id, policyId), eq(policies.teamId, teamId))) + .where(and(eq(policies.id, policyId), eq(policies.organizationId, organizationId))) .returning(); return result.length > 0; }).pipe(Effect.orDie), diff --git a/packages/core/storage-postgres/src/schema.ts b/packages/core/storage-postgres/src/schema.ts index 42c5bd61a0..045a982185 100644 --- a/packages/core/storage-postgres/src/schema.ts +++ b/packages/core/storage-postgres/src/schema.ts @@ -20,27 +20,27 @@ const bytea = customType<{ data: Buffer }>({ }); // --------------------------------------------------------------------------- -// Domain data — all team-scoped +// Domain data — all organization-scoped // --------------------------------------------------------------------------- export const sources = pgTable( "sources", { id: text("id").notNull(), - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), name: text("name").notNull(), kind: text("kind").notNull(), config: jsonb("config").notNull().$default(() => ({})), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }, - (table) => [primaryKey({ columns: [table.id, table.teamId] })], + (table) => [primaryKey({ columns: [table.id, table.organizationId] })], ); export const tools = pgTable( "tools", { id: text("id").notNull(), - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), sourceId: text("source_id").notNull(), pluginKey: text("plugin_key").notNull(), name: text("name").notNull(), @@ -50,38 +50,38 @@ export const tools = pgTable( outputSchema: jsonb("output_schema"), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }, - (table) => [primaryKey({ columns: [table.id, table.teamId] })], + (table) => [primaryKey({ columns: [table.id, table.organizationId] })], ); export const toolDefinitions = pgTable( "tool_definitions", { name: text("name").notNull(), - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), schema: jsonb("schema").notNull(), }, - (table) => [primaryKey({ columns: [table.name, table.teamId] })], + (table) => [primaryKey({ columns: [table.name, table.organizationId] })], ); export const secrets = pgTable( "secrets", { id: text("id").notNull(), - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), name: text("name").notNull(), purpose: text("purpose"), encryptedValue: bytea("encrypted_value").notNull(), iv: bytea("iv").notNull(), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }, - (table) => [primaryKey({ columns: [table.id, table.teamId] })], + (table) => [primaryKey({ columns: [table.id, table.organizationId] })], ); export const policies = pgTable( "policies", { id: text("id").notNull(), - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), name: text("name").notNull(), action: text("action").notNull(), matchToolPattern: text("match_tool_pattern"), @@ -89,7 +89,7 @@ export const policies = pgTable( priority: integer("priority").notNull().$default(() => 0), createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), }, - (table) => [primaryKey({ columns: [table.id, table.teamId] })], + (table) => [primaryKey({ columns: [table.id, table.organizationId] })], ); // --------------------------------------------------------------------------- @@ -99,10 +99,10 @@ export const policies = pgTable( export const pluginKv = pgTable( "plugin_kv", { - teamId: text("team_id").notNull(), + organizationId: text("organization_id").notNull(), namespace: text("namespace").notNull(), key: text("key").notNull(), value: text("value").notNull(), }, - (table) => [primaryKey({ columns: [table.teamId, table.namespace, table.key] })], + (table) => [primaryKey({ columns: [table.organizationId, table.namespace, table.key] })], ); diff --git a/packages/core/storage-postgres/src/secret-store.ts b/packages/core/storage-postgres/src/secret-store.ts index 71ccdff115..b45e723538 100644 --- a/packages/core/storage-postgres/src/secret-store.ts +++ b/packages/core/storage-postgres/src/secret-store.ts @@ -15,7 +15,7 @@ import { encrypt, decrypt } from "./crypto"; export const makePgSecretStore = ( db: DrizzleDb, - teamId: string, + organizationId: string, encryptionKey: string, ) => { // Additional providers can still be registered (e.g. 1Password read-only) @@ -25,7 +25,7 @@ export const makePgSecretStore = ( list: (scopeId: ScopeId) => Effect.gen(function* () { const rows = yield* Effect.tryPromise(() => - db.select().from(secrets).where(eq(secrets.teamId, teamId)), + db.select().from(secrets).where(eq(secrets.organizationId, organizationId)), ).pipe(Effect.orDie); const refs: SecretRef[] = rows.map( @@ -72,14 +72,14 @@ export const makePgSecretStore = ( db .select() .from(secrets) - .where(and(eq(secrets.id, secretId), eq(secrets.teamId, teamId))), + .where(and(eq(secrets.id, secretId), eq(secrets.organizationId, organizationId))), ).pipe(Effect.orDie); const row = rows[0]; if (!row) return yield* new SecretNotFoundError({ secretId }); return new SecretRef({ id: SecretId.make(row.id), - scopeId: ScopeId.make(teamId), + scopeId: ScopeId.make(organizationId), name: row.name, provider: Option.some("postgres-encrypted"), purpose: row.purpose ?? undefined, @@ -94,7 +94,7 @@ export const makePgSecretStore = ( db .select() .from(secrets) - .where(and(eq(secrets.id, secretId), eq(secrets.teamId, teamId))), + .where(and(eq(secrets.id, secretId), eq(secrets.organizationId, organizationId))), ).pipe(Effect.orDie); const row = rows[0]; @@ -128,7 +128,7 @@ export const makePgSecretStore = ( db .select({ id: secrets.id }) .from(secrets) - .where(and(eq(secrets.id, secretId), eq(secrets.teamId, teamId))), + .where(and(eq(secrets.id, secretId), eq(secrets.organizationId, organizationId))), ).pipe(Effect.orDie); if (rows.length > 0) return "resolved" as const; @@ -151,14 +151,14 @@ export const makePgSecretStore = ( .insert(secrets) .values({ id: input.id, - teamId, + organizationId, name: input.name, purpose: input.purpose, encryptedValue: encrypted, iv, }) .onConflictDoUpdate({ - target: [secrets.id, secrets.teamId], + target: [secrets.id, secrets.organizationId], set: { name: input.name, purpose: input.purpose, @@ -183,7 +183,7 @@ export const makePgSecretStore = ( const result = yield* Effect.tryPromise(() => db .delete(secrets) - .where(and(eq(secrets.id, secretId), eq(secrets.teamId, teamId))) + .where(and(eq(secrets.id, secretId), eq(secrets.organizationId, organizationId))) .returning(), ).pipe(Effect.orDie); diff --git a/packages/core/storage-postgres/src/tool-registry.ts b/packages/core/storage-postgres/src/tool-registry.ts index b5cd62ca4e..18f99b8cad 100644 --- a/packages/core/storage-postgres/src/tool-registry.ts +++ b/packages/core/storage-postgres/src/tool-registry.ts @@ -20,7 +20,7 @@ import { tools, toolDefinitions } from "./schema"; export const makePgToolRegistry = ( db: DrizzleDb, - teamId: string, + organizationId: string, ) => { const runtimeTools = new Map(); const runtimeHandlers = new Map(); @@ -32,7 +32,7 @@ export const makePgToolRegistry = ( const rows = await db .select() .from(tools) - .where(and(eq(tools.id, id), eq(tools.teamId, teamId))); + .where(and(eq(tools.id, id), eq(tools.organizationId, organizationId))); const row = rows[0]; if (!row) return null; return new ToolRegistration({ @@ -52,7 +52,7 @@ export const makePgToolRegistry = ( const rows = await db .select() .from(tools) - .where(eq(tools.teamId, teamId)); + .where(eq(tools.organizationId, organizationId)); return rows.map( (row) => new ToolRegistration({ @@ -73,7 +73,7 @@ export const makePgToolRegistry = ( const rows = await db .select() .from(toolDefinitions) - .where(eq(toolDefinitions.teamId, teamId)); + .where(eq(toolDefinitions.organizationId, organizationId)); const defs = new Map( rows.map((r) => [r.name, r.schema]), ); @@ -133,12 +133,12 @@ export const makePgToolRegistry = ( Effect.tryPromise(async () => { const entries = Object.entries(newDefs); if (entries.length === 0) return; - const values = entries.map(([name, schema]) => ({ name, teamId, schema })); + const values = entries.map(([name, schema]) => ({ name, organizationId, schema })); await db .insert(toolDefinitions) .values(values) .onConflictDoUpdate({ - target: [toolDefinitions.name, toolDefinitions.teamId], + target: [toolDefinitions.name, toolDefinitions.organizationId], set: { schema: sql`excluded.schema` }, }); }).pipe(Effect.orDie), @@ -193,7 +193,7 @@ export const makePgToolRegistry = ( if (newTools.length === 0) return; const values = newTools.map((t) => ({ id: t.id, - teamId, + organizationId, sourceId: t.sourceId, pluginKey: t.pluginKey, name: t.name, @@ -206,7 +206,7 @@ export const makePgToolRegistry = ( .insert(tools) .values(values) .onConflictDoUpdate({ - target: [tools.id, tools.teamId], + target: [tools.id, tools.organizationId], set: { sourceId: sql`excluded.source_id`, pluginKey: sql`excluded.plugin_key`, @@ -244,14 +244,14 @@ export const makePgToolRegistry = ( if (toolIds.length === 0) return; await db .delete(tools) - .where(and(inArray(tools.id, [...toolIds]), eq(tools.teamId, teamId))); + .where(and(inArray(tools.id, [...toolIds]), eq(tools.organizationId, organizationId))); }).pipe(Effect.orDie), unregisterBySource: (sourceId: string) => Effect.tryPromise(async () => { await db .delete(tools) - .where(and(eq(tools.sourceId, sourceId), eq(tools.teamId, teamId))); + .where(and(eq(tools.sourceId, sourceId), eq(tools.organizationId, organizationId))); for (const [id, t] of runtimeTools) { if (t.sourceId === sourceId) { runtimeTools.delete(id); diff --git a/patches/iron-webcrypto@0.2.8.patch b/patches/iron-webcrypto@0.2.8.patch new file mode 100644 index 0000000000..ae80c50e66 --- /dev/null +++ b/patches/iron-webcrypto@0.2.8.patch @@ -0,0 +1,24 @@ +diff --git a/dist/index.js b/dist/index.js +index becad9e703ad286f062cb86795382dc97a44062d..d9d56011d7cfb5ebb3359568b3213983640a392f 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -1,6 +1,6 @@ + 'use strict'; + +-var index_js = require('buffer/index.js'); ++var index_js = require('buffer'); + + var x=t=>(index_js.Buffer.isBuffer(t)?t:index_js.Buffer.from(t)).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,""),j={encryption:{saltBits:256,algorithm:"aes-256-cbc",iterations:1,minPasswordlength:32},integrity:{saltBits:256,algorithm:"sha256",iterations:1,minPasswordlength:32},ttl:0,timestampSkewSec:60,localtimeOffsetMsec:0},v=t=>({...t,encryption:{...t.encryption},integrity:{...t.integrity}}),u={"aes-128-ctr":{keyBits:128,ivBits:128,name:"AES-CTR"},"aes-256-cbc":{keyBits:256,ivBits:128,name:"AES-CBC"},sha256:{keyBits:256,name:"SHA-256"}},A="2",K=`Fe26.${A}`,M=(t,n)=>{let e=index_js.Buffer.allocUnsafe(n);return t.getRandomValues(e),e},b=(t,n)=>{if(n<1)throw Error("Invalid random bits count");let e=Math.ceil(n/8);return M(t,e)},H=async(t,n,e,s,r,c)=>{let o=new TextEncoder,i=o.encode(n),a=await t.subtle.importKey("raw",i,"PBKDF2",!1,["deriveBits"]),f=o.encode(e),y={name:"PBKDF2",hash:c,salt:f,iterations:s},d=await t.subtle.deriveBits(y,a,r*8);return index_js.Buffer.from(d)},E=async(t,n,e)=>{var a;if(n==null||!n.length)throw new Error("Empty password");if(e==null||typeof e!="object")throw new Error("Bad options");if(!(e.algorithm in u))throw new Error(`Unknown algorithm: ${e.algorithm}`);let s=u[e.algorithm],r={},c=(a=e.hmac)!=null?a:!1,o=c?{name:"HMAC",hash:s.name}:{name:s.name},i=c?["sign","verify"]:["encrypt","decrypt"];if(typeof n=="string"){if(n.length{let r=await E(t,n,e),o=new TextEncoder().encode(s),i=await t.subtle.encrypt({name:u[e.algorithm].name,iv:r.iv},r.key,o);return {encrypted:index_js.Buffer.from(i),key:r}},R=async(t,n,e,s)=>{let r=await E(t,n,e),c=await t.subtle.decrypt({name:u[e.algorithm].name,iv:r.iv},r.key,index_js.Buffer.isBuffer(s)?s:index_js.Buffer.from(s));return new TextDecoder().decode(c)},k=async(t,n,e,s)=>{let r=await E(t,n,{...e,hmac:!0}),o=new TextEncoder().encode(s),i=await t.subtle.sign({name:"HMAC"},r.key,o);return {digest:x(index_js.Buffer.from(i)),salt:r.salt}},$=t=>typeof t=="object"&&!index_js.Buffer.isBuffer(t)?"secret"in t?{id:t.id,encryption:t.secret,integrity:t.secret}:{id:t.id,encryption:t.encryption,integrity:t.integrity}:{encryption:t,integrity:t},F=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=JSON.stringify(n),i=$(e),{id:a=""}=i;if(a&&!/^\w+$/.test(a))throw new Error("Invalid password id");let{encrypted:f,key:y}=await I(t,i.encryption,r.encryption,o),d=x(f),m=x(y.iv),w=r.ttl?c+r.ttl:"",g=`${K}*${a}*${y.salt}*${m}*${d}*${w}`,h=await k(t,i.integrity,r.integrity,g);return `${g}*${h.salt}*${h.digest}`},D=(t,n)=>{let e=t.length===n.length?0:1;e&&(n=t);for(let s=0;s{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=n.split("*");if(o.length!==8)throw new Error("Incorrect number of sealed components");let i=o[0],a=o[1],f=o[2],y=o[3],d=o[4],m=o[5],w=o[6],g=o[7],h=`${i}*${a}*${f}*${y}*${d}*${m}`;if(K!==i)throw new Error("Wrong mac prefix");if(m){if(!/^\d+$/.exec(m))throw new Error("Invalid expiration");if(parseInt(m,10)<=c-r.timestampSkewSec*1e3)throw new Error("Expired seal")}if(typeof e=="undefined"||typeof e=="string"&&e.length===0)throw new Error("Empty password");let p;if(typeof e=="object"&&!index_js.Buffer.isBuffer(e)){if(!((a||"default")in e))throw new Error(`Cannot find password: ${a}`);p=e[a||"default"];}else p=e;p=$(p);let P=r.integrity;P.salt=w;let O=await k(t,p.integrity,P,h);if(!D(O.digest,g))throw new Error("Bad hmac value");let C=index_js.Buffer.from(d,"base64"),B=r.encryption;B.salt=f,B.iv=index_js.Buffer.from(y,"base64");let S=await R(t,p.encryption,B,C);return S?JSON.parse(S):null}; + +diff --git a/dist/index.mjs b/dist/index.mjs +index 92727fd1e8c4e6fb57eb9370784fa15a2881f53f..388487ab838c99538c895975102426810367ef14 100644 +--- a/dist/index.mjs ++++ b/dist/index.mjs +@@ -1,5 +1,5 @@ +-import { Buffer } from 'buffer/index.js'; +-export { Buffer } from 'buffer/index.js'; ++import { Buffer } from 'buffer'; ++export { Buffer } from 'buffer'; + + var x=t=>(Buffer.isBuffer(t)?t:Buffer.from(t)).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,""),j={encryption:{saltBits:256,algorithm:"aes-256-cbc",iterations:1,minPasswordlength:32},integrity:{saltBits:256,algorithm:"sha256",iterations:1,minPasswordlength:32},ttl:0,timestampSkewSec:60,localtimeOffsetMsec:0},v=t=>({...t,encryption:{...t.encryption},integrity:{...t.integrity}}),u={"aes-128-ctr":{keyBits:128,ivBits:128,name:"AES-CTR"},"aes-256-cbc":{keyBits:256,ivBits:128,name:"AES-CBC"},sha256:{keyBits:256,name:"SHA-256"}},A="2",K=`Fe26.${A}`,M=(t,n)=>{let e=Buffer.allocUnsafe(n);return t.getRandomValues(e),e},b=(t,n)=>{if(n<1)throw Error("Invalid random bits count");let e=Math.ceil(n/8);return M(t,e)},H=async(t,n,e,s,r,c)=>{let o=new TextEncoder,i=o.encode(n),a=await t.subtle.importKey("raw",i,"PBKDF2",!1,["deriveBits"]),f=o.encode(e),y={name:"PBKDF2",hash:c,salt:f,iterations:s},d=await t.subtle.deriveBits(y,a,r*8);return Buffer.from(d)},E=async(t,n,e)=>{var a;if(n==null||!n.length)throw new Error("Empty password");if(e==null||typeof e!="object")throw new Error("Bad options");if(!(e.algorithm in u))throw new Error(`Unknown algorithm: ${e.algorithm}`);let s=u[e.algorithm],r={},c=(a=e.hmac)!=null?a:!1,o=c?{name:"HMAC",hash:s.name}:{name:s.name},i=c?["sign","verify"]:["encrypt","decrypt"];if(typeof n=="string"){if(n.length{let r=await E(t,n,e),o=new TextEncoder().encode(s),i=await t.subtle.encrypt({name:u[e.algorithm].name,iv:r.iv},r.key,o);return {encrypted:Buffer.from(i),key:r}},R=async(t,n,e,s)=>{let r=await E(t,n,e),c=await t.subtle.decrypt({name:u[e.algorithm].name,iv:r.iv},r.key,Buffer.isBuffer(s)?s:Buffer.from(s));return new TextDecoder().decode(c)},k=async(t,n,e,s)=>{let r=await E(t,n,{...e,hmac:!0}),o=new TextEncoder().encode(s),i=await t.subtle.sign({name:"HMAC"},r.key,o);return {digest:x(Buffer.from(i)),salt:r.salt}},$=t=>typeof t=="object"&&!Buffer.isBuffer(t)?"secret"in t?{id:t.id,encryption:t.secret,integrity:t.secret}:{id:t.id,encryption:t.encryption,integrity:t.integrity}:{encryption:t,integrity:t},F=async(t,n,e,s)=>{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=JSON.stringify(n),i=$(e),{id:a=""}=i;if(a&&!/^\w+$/.test(a))throw new Error("Invalid password id");let{encrypted:f,key:y}=await I(t,i.encryption,r.encryption,o),d=x(f),m=x(y.iv),w=r.ttl?c+r.ttl:"",g=`${K}*${a}*${y.salt}*${m}*${d}*${w}`,h=await k(t,i.integrity,r.integrity,g);return `${g}*${h.salt}*${h.digest}`},D=(t,n)=>{let e=t.length===n.length?0:1;e&&(n=t);for(let s=0;s{if(!e)throw Error("Empty password");let r=v(s),c=Date.now()+(r.localtimeOffsetMsec||0),o=n.split("*");if(o.length!==8)throw new Error("Incorrect number of sealed components");let i=o[0],a=o[1],f=o[2],y=o[3],d=o[4],m=o[5],w=o[6],g=o[7],h=`${i}*${a}*${f}*${y}*${d}*${m}`;if(K!==i)throw new Error("Wrong mac prefix");if(m){if(!/^\d+$/.exec(m))throw new Error("Invalid expiration");if(parseInt(m,10)<=c-r.timestampSkewSec*1e3)throw new Error("Expired seal")}if(typeof e=="undefined"||typeof e=="string"&&e.length===0)throw new Error("Empty password");let p;if(typeof e=="object"&&!Buffer.isBuffer(e)){if(!((a||"default")in e))throw new Error(`Cannot find password: ${a}`);p=e[a||"default"];}else p=e;p=$(p);let P=r.integrity;P.salt=w;let O=await k(t,p.integrity,P,h);if(!D(O.digest,g))throw new Error("Bad hmac value");let C=Buffer.from(d,"base64"),B=r.encryption;B.salt=f,B.iv=Buffer.from(y,"base64");let S=await R(t,p.encryption,B,C);return S?JSON.parse(S):null}; +