diff --git a/app/__test__/adapter/adapter.test.ts b/app/__test__/adapter/adapter.test.ts
index 734fb08..f7d623c 100644
--- a/app/__test__/adapter/adapter.test.ts
+++ b/app/__test__/adapter/adapter.test.ts
@@ -3,21 +3,36 @@ import * as adapter from "adapter";
import { disableConsoleLog, enableConsoleLog } from "core/utils";
import { adapterTestSuite } from "adapter/adapter-test-suite";
import { bunTestRunner } from "adapter/bun/test";
+import { omitKeys } from "core/utils";
beforeAll(disableConsoleLog);
afterAll(enableConsoleLog);
describe("adapter", () => {
it("makes config", () => {
- expect(adapter.makeConfig({})).toEqual({});
- expect(adapter.makeConfig({}, { env: { TEST: "test" } })).toEqual({});
+ expect(omitKeys(adapter.makeConfig({}), ["connection"])).toEqual({});
+ expect(omitKeys(adapter.makeConfig({}, { env: { TEST: "test" } }), ["connection"])).toEqual(
+ {},
+ );
// merges everything returned from `app` with the config
- expect(adapter.makeConfig({ app: (a) => a as any }, { env: { TEST: "test" } })).toEqual({
- env: { TEST: "test" },
- } as any);
+ expect(
+ omitKeys(
+ adapter.makeConfig(
+ { app: (a) => ({ initialConfig: { server: { cors: { origin: a.env.TEST } } } }) },
+ { env: { TEST: "test" } },
+ ),
+ ["connection"],
+ ),
+ ).toEqual({
+ initialConfig: { server: { cors: { origin: "test" } } },
+ });
});
+ /* it.only("...", async () => {
+ const app = await adapter.createAdapterApp();
+ }); */
+
it("reuses apps correctly", async () => {
const id = crypto.randomUUID();
diff --git a/app/__test__/app/App.spec.ts b/app/__test__/app/App.spec.ts
index 860258a..a6eb3de 100644
--- a/app/__test__/app/App.spec.ts
+++ b/app/__test__/app/App.spec.ts
@@ -1,6 +1,6 @@
import { describe, expect, mock, test } from "bun:test";
import type { ModuleBuildContext } from "../../src";
-import { App, createApp } from "../../src/App";
+import { App, createApp } from "core/test/utils";
import * as proto from "../../src/data/prototype";
describe("App", () => {
diff --git a/app/__test__/app/repro.spec.ts b/app/__test__/app/repro.spec.ts
index b27aa51..be2da38 100644
--- a/app/__test__/app/repro.spec.ts
+++ b/app/__test__/app/repro.spec.ts
@@ -1,5 +1,6 @@
import { describe, expect, test } from "bun:test";
-import { createApp, registries } from "../../src";
+import { registries } from "../../src";
+import { createApp } from "core/test/utils";
import * as proto from "../../src/data/prototype";
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
diff --git a/app/__test__/integration/config.integration.test.ts b/app/__test__/integration/config.integration.test.ts
index f370e69..7fde411 100644
--- a/app/__test__/integration/config.integration.test.ts
+++ b/app/__test__/integration/config.integration.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, it } from "bun:test";
-import { createApp } from "../../src";
+import { createApp } from "core/test/utils";
import { Api } from "../../src/Api";
describe("integration config", () => {
diff --git a/app/__test__/media/MediaController.spec.ts b/app/__test__/media/MediaController.spec.ts
index d0e56c9..6478072 100644
--- a/app/__test__/media/MediaController.spec.ts
+++ b/app/__test__/media/MediaController.spec.ts
@@ -1,7 +1,8 @@
///
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
-import { createApp, registries } from "../../src";
+import { registries } from "../../src";
+import { createApp } from "core/test/utils";
import { mergeObject, randomString } from "../../src/core/utils";
import type { TAppMediaConfig } from "../../src/media/media-schema";
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
diff --git a/app/__test__/modules/AppAuth.spec.ts b/app/__test__/modules/AppAuth.spec.ts
index 50c38f2..ddbaf3b 100644
--- a/app/__test__/modules/AppAuth.spec.ts
+++ b/app/__test__/modules/AppAuth.spec.ts
@@ -1,5 +1,5 @@
import { afterAll, beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
-import { createApp } from "../../src";
+import { createApp } from "core/test/utils";
import { AuthController } from "../../src/auth/api/AuthController";
import { em, entity, make, text } from "../../src/data";
import { AppAuth, type ModuleBuildContext } from "../../src/modules";
diff --git a/app/__test__/modules/AppMedia.spec.ts b/app/__test__/modules/AppMedia.spec.ts
index 8e6b5b2..bbcc0c2 100644
--- a/app/__test__/modules/AppMedia.spec.ts
+++ b/app/__test__/modules/AppMedia.spec.ts
@@ -1,5 +1,6 @@
import { describe, expect, test } from "bun:test";
-import { createApp, registries } from "../../src";
+import { registries } from "../../src";
+import { createApp } from "core/test/utils";
import { em, entity, text } from "../../src/data";
import { StorageLocalAdapter } from "adapter/node/storage/StorageLocalAdapter";
import { AppMedia } from "../../src/modules";
diff --git a/app/package.json b/app/package.json
index 516d1d9..0e93a59 100644
--- a/app/package.json
+++ b/app/package.json
@@ -31,11 +31,9 @@
"test": "ALL_TESTS=1 bun test --bail",
"test:all": "bun run test && bun run test:node",
"test:bun": "ALL_TESTS=1 bun test --bail",
- "test:node": "tsx --test $(find . -type f -name '*.native-spec.ts')",
+ "test:node": "vitest run",
"test:adapters": "bun test src/adapter/**/*.adapter.spec.ts --bail",
"test:coverage": "ALL_TESTS=1 bun test --bail --coverage",
- "test:vitest": "vitest run",
- "test:vitest:watch": "vitest",
"test:vitest:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"test:e2e:adapters": "bun run e2e/adapters.ts",
@@ -73,14 +71,15 @@
"uuid": "^11.1.0"
},
"devDependencies": {
- "@libsql/client": "^0.15.9",
"@aws-sdk/client-s3": "^3.758.0",
"@bluwy/giget-core": "^0.1.2",
+ "@cloudflare/vitest-pool-workers": "^0.8.38",
"@cloudflare/workers-types": "^4.20250606.0",
"@dagrejs/dagre": "^1.1.4",
"@hono/typebox-validator": "^0.3.3",
"@hono/vite-dev-server": "^0.19.1",
"@hookform/resolvers": "^4.1.3",
+ "@libsql/client": "^0.15.9",
"@libsql/kysely-libsql": "^0.4.1",
"@mantine/modals": "^7.17.1",
"@mantine/notifications": "^7.17.1",
diff --git a/app/src/adapter/bun/bun.adapter.ts b/app/src/adapter/bun/bun.adapter.ts
index 07b778a..5d7c148 100644
--- a/app/src/adapter/bun/bun.adapter.ts
+++ b/app/src/adapter/bun/bun.adapter.ts
@@ -1,17 +1,11 @@
///
import path from "node:path";
-import {
- type RuntimeBkndConfig,
- createRuntimeApp,
- type RuntimeOptions,
- Connection,
-} from "bknd/adapter";
+import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
import { registerLocalMediaAdapter } from ".";
import { config } from "bknd/core";
import type { ServeOptions } from "bun";
import { serveStatic } from "hono/bun";
-import { sqlite } from "bknd/adapter/sqlite";
import type { App } from "App";
type BunEnv = Bun.Env;
@@ -25,17 +19,9 @@ export async function createApp(
const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static");
registerLocalMediaAdapter();
- let connection: Connection | undefined;
- if (Connection.isConnection(config.connection)) {
- connection = config.connection;
- } else {
- connection = sqlite(config.connection ?? { url: ":memory:" });
- }
-
return await createRuntimeApp(
{
...config,
- connection,
serveStatic: serveStatic({ root }),
},
args ?? (process.env as Env),
diff --git a/app/src/adapter/cloudflare/cloudflare-workers.adapter.spec.ts b/app/src/adapter/cloudflare/cloudflare-workers.adapter.spec.ts
index 0c51acb..5cdde1a 100644
--- a/app/src/adapter/cloudflare/cloudflare-workers.adapter.spec.ts
+++ b/app/src/adapter/cloudflare/cloudflare-workers.adapter.spec.ts
@@ -13,30 +13,32 @@ describe("cf adapter", () => {
const DB_URL = ":memory:";
const $ctx = (env?: any, request?: Request, ctx?: ExecutionContext) => ({
request: request ?? (null as any),
- env: env ?? { DB_URL },
+ env: env ?? { url: DB_URL },
ctx: ctx ?? (null as any),
});
it("makes config", async () => {
- expect(
- makeConfig(
- {
- connection: { url: DB_URL },
- },
- $ctx({ DB_URL }),
- ),
- ).toEqual({ connection: { url: DB_URL } });
+ const staticConfig = makeConfig(
+ {
+ connection: { url: DB_URL },
+ initialConfig: { data: { basepath: DB_URL } },
+ },
+ $ctx({ DB_URL }),
+ );
+ expect(staticConfig.initialConfig).toEqual({ data: { basepath: DB_URL } });
+ expect(staticConfig.connection).toBeDefined();
- expect(
- makeConfig(
- {
- app: (env) => ({
- connection: { url: env.DB_URL },
- }),
- },
- $ctx({ DB_URL }),
- ),
- ).toEqual({ connection: { url: DB_URL } });
+ const dynamicConfig = makeConfig(
+ {
+ app: (env) => ({
+ initialConfig: { data: { basepath: env.DB_URL } },
+ connection: { url: env.DB_URL },
+ }),
+ },
+ $ctx({ DB_URL }),
+ );
+ expect(dynamicConfig.initialConfig).toEqual({ data: { basepath: DB_URL } });
+ expect(dynamicConfig.connection).toBeDefined();
});
adapterTestSuite>(bunTestRunner, {
diff --git a/app/src/adapter/cloudflare/config.ts b/app/src/adapter/cloudflare/config.ts
index d6e75b1..6ae89d7 100644
--- a/app/src/adapter/cloudflare/config.ts
+++ b/app/src/adapter/cloudflare/config.ts
@@ -9,6 +9,7 @@ import { makeConfig as makeAdapterConfig } from "bknd/adapter";
import type { Context, ExecutionContext } from "hono";
import { $console } from "core";
import { setCookie } from "hono/cookie";
+import { sqlite } from "bknd/adapter/sqlite";
export const constants = {
exec_async_event_id: "cf_register_waituntil",
@@ -98,54 +99,70 @@ export function makeConfig(
const appConfig = makeAdapterConfig(config, args?.env);
- if (args?.env) {
- const bindings = config.bindings?.(args?.env);
+ // if connection instance is given, don't do anything
+ // other than checking if D1 session is defined
+ if (D1Connection.isConnection(appConfig.connection)) {
+ if (config.d1?.session) {
+ // we cannot guarantee that db was opened with session
+ throw new Error(
+ "D1 session don't work when D1 is directly given as connection. Define it in bindings instead.",
+ );
+ }
+ // if connection is given, try to open with unified sqlite adapter
+ } else if (appConfig.connection) {
+ appConfig.connection = sqlite(appConfig.connection);
+ // if connection is not given, but env is set
+ // try to make D1 from bindings
+ } else if (args?.env) {
+ const bindings = config.bindings?.(args?.env);
const sessionHelper = d1SessionHelper(config);
const sessionId = sessionHelper.get(args.request);
let session: D1DatabaseSession | undefined;
+ let db: D1Database | undefined;
- if (!appConfig.connection) {
- let db: D1Database | undefined;
- if (bindings?.db) {
- $console.log("Using database from bindings");
- db = bindings.db;
- } else if (Object.keys(args).length > 0) {
- const binding = getBinding(args.env, "D1Database");
- if (binding) {
- $console.log(`Using database from env "${binding.key}"`);
- db = binding.value;
- }
- }
+ // if db is given in bindings, use it
+ if (bindings?.db) {
+ $console.log("Using database from bindings");
+ db = bindings.db;
- if (db) {
- if (config.d1?.session) {
- session = db.withSession(sessionId ?? config.d1?.first);
- appConfig.connection = new D1Connection({ binding: session });
- } else {
- appConfig.connection = new D1Connection({ binding: db });
- }
- } else {
- throw new Error("No database connection given");
+ // scan for D1Database in args
+ } else {
+ const binding = getBinding(args.env, "D1Database");
+ if (binding) {
+ $console.log(`Using database from env "${binding.key}"`);
+ db = binding.value;
}
}
- if (config.d1?.session) {
- appConfig.options = {
- ...appConfig.options,
- manager: {
- ...appConfig.options?.manager,
- onServerInit: (server) => {
- server.use(async (c, next) => {
- sessionHelper.set(c, session);
- await next();
- });
+ // if db is found, check if session is requested
+ if (db) {
+ if (config.d1?.session) {
+ session = db.withSession(sessionId ?? config.d1?.first);
+
+ appConfig.connection = new D1Connection({ binding: session });
+ appConfig.options = {
+ ...appConfig.options,
+ manager: {
+ ...appConfig.options?.manager,
+ onServerInit: (server) => {
+ server.use(async (c, next) => {
+ sessionHelper.set(c, session);
+ await next();
+ });
+ },
},
- },
- };
+ };
+ } else {
+ appConfig.connection = new D1Connection({ binding: db });
+ }
}
}
+ if (!D1Connection.isConnection(appConfig.connection)) {
+ throw new Error("Couldn't find database connection");
+ }
+
return appConfig;
}
diff --git a/app/src/adapter/cloudflare/storage/StorageR2Adapter.native-spec.ts b/app/src/adapter/cloudflare/storage/StorageR2Adapter.native-spec.ts
deleted file mode 100644
index ffa98af..0000000
--- a/app/src/adapter/cloudflare/storage/StorageR2Adapter.native-spec.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { createWriteStream, readFileSync } from "node:fs";
-import { test } from "node:test";
-import { Miniflare } from "miniflare";
-import { StorageR2Adapter } from "./StorageR2Adapter";
-import { adapterTestSuite } from "media";
-import { nodeTestRunner } from "adapter/node/test";
-import path from "node:path";
-
-// https://github.com/nodejs/node/issues/44372#issuecomment-1736530480
-console.log = async (message: any) => {
- const tty = createWriteStream("/dev/tty");
- const msg = typeof message === "string" ? message : JSON.stringify(message, null, 2);
- return tty.write(`${msg}\n`);
-};
-
-test("StorageR2Adapter", async () => {
- const mf = new Miniflare({
- modules: true,
- script: "export default { async fetch() { return new Response(null); } }",
- r2Buckets: ["BUCKET"],
- });
-
- const bucket = (await mf.getR2Bucket("BUCKET")) as unknown as R2Bucket;
- const adapter = new StorageR2Adapter(bucket);
-
- const basePath = path.resolve(import.meta.dirname, "../../../../__test__/_assets");
- const buffer = readFileSync(path.join(basePath, "image.png"));
- const file = new File([buffer], "image.png", { type: "image/png" });
-
- await adapterTestSuite(nodeTestRunner, adapter, file);
- await mf.dispose();
-});
diff --git a/app/src/adapter/cloudflare/storage/StorageR2Adapter.vitest.ts b/app/src/adapter/cloudflare/storage/StorageR2Adapter.vitest.ts
new file mode 100644
index 0000000..437ec9b
--- /dev/null
+++ b/app/src/adapter/cloudflare/storage/StorageR2Adapter.vitest.ts
@@ -0,0 +1,32 @@
+import { readFileSync } from "node:fs";
+import { Miniflare } from "miniflare";
+import { StorageR2Adapter } from "./StorageR2Adapter";
+import { adapterTestSuite } from "media/storage/adapters/adapter-test-suite";
+import path from "node:path";
+import { describe, afterAll, test, expect } from "vitest";
+import { viTestRunner } from "adapter/node/vitest";
+
+let mf: Miniflare | undefined;
+describe("StorageR2Adapter", async () => {
+ mf = new Miniflare({
+ modules: true,
+ script: "export default { async fetch() { return new Response(null); } }",
+ r2Buckets: ["BUCKET"],
+ });
+ const bucket = (await mf?.getR2Bucket("BUCKET")) as unknown as R2Bucket;
+
+ test("test", () => {
+ expect(bucket).toBeDefined();
+ });
+ const adapter = new StorageR2Adapter(bucket);
+
+ const basePath = path.resolve(import.meta.dirname, "../../../../__test__/_assets");
+ const buffer = readFileSync(path.join(basePath, "image.png"));
+ const file = new File([buffer], "image.png", { type: "image/png" });
+
+ await adapterTestSuite(viTestRunner, adapter, file);
+});
+
+afterAll(async () => {
+ await mf?.dispose();
+});
diff --git a/app/src/adapter/cloudflare/vitest.config.ts b/app/src/adapter/cloudflare/vitest.config.ts
new file mode 100644
index 0000000..590ee4f
--- /dev/null
+++ b/app/src/adapter/cloudflare/vitest.config.ts
@@ -0,0 +1,14 @@
+import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
+
+export default defineWorkersConfig({
+ test: {
+ poolOptions: {
+ workers: {
+ miniflare: {
+ compatibilityDate: "2025-06-04",
+ },
+ },
+ },
+ include: ["**/*.vi-test.ts", "**/*.vitest.ts"],
+ },
+});
diff --git a/app/src/adapter/index.ts b/app/src/adapter/index.ts
index 569afd6..abd2f8e 100644
--- a/app/src/adapter/index.ts
+++ b/app/src/adapter/index.ts
@@ -1,7 +1,8 @@
import { App, type CreateAppConfig } from "bknd";
-import { config as $config } from "bknd/core";
+import { config as $config, $console } from "bknd/core";
import type { MiddlewareHandler } from "hono";
import type { AdminControllerOptions } from "modules/server/AdminController";
+import { Connection } from "bknd/data";
export { Connection } from "bknd/data";
@@ -61,7 +62,20 @@ export async function createAdapterApp {
adapterTestSuite(bunTestRunner, {
- makeApp: node.createApp,
- makeHandler: node.createHandler,
+ makeApp: createApp,
+ makeHandler: createHandler,
});
});
diff --git a/app/src/adapter/node/node.adapter.ts b/app/src/adapter/node/node.adapter.ts
index 02aa829..9d9d5d5 100644
--- a/app/src/adapter/node/node.adapter.ts
+++ b/app/src/adapter/node/node.adapter.ts
@@ -1,16 +1,10 @@
import path from "node:path";
import { serve as honoServe } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
-import { registerLocalMediaAdapter } from "adapter/node/index";
-import {
- type RuntimeBkndConfig,
- createRuntimeApp,
- type RuntimeOptions,
- Connection,
-} from "bknd/adapter";
+import { registerLocalMediaAdapter } from "adapter/node/storage";
+import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter";
import { config as $config } from "bknd/core";
import { $console } from "core";
-import { sqlite } from "bknd/adapter/sqlite";
import type { App } from "App";
type NodeEnv = NodeJS.ProcessEnv;
@@ -35,18 +29,10 @@ export async function createApp(
console.warn("relativeDistPath is deprecated, please use distPath instead");
}
- let connection: Connection | undefined;
- if (Connection.isConnection(config.connection)) {
- connection = config.connection;
- } else {
- connection = sqlite(config.connection ?? { url: ":memory:" });
- }
-
registerLocalMediaAdapter();
return await createRuntimeApp(
{
...config,
- connection,
serveStatic: serveStatic({ root }),
},
// @ts-ignore
diff --git a/app/src/adapter/node/storage/StorageLocalAdapter.native-spec.ts b/app/src/adapter/node/storage/StorageLocalAdapter.vitest.ts
similarity index 79%
rename from app/src/adapter/node/storage/StorageLocalAdapter.native-spec.ts
rename to app/src/adapter/node/storage/StorageLocalAdapter.vitest.ts
index d237a53..3d13bd5 100644
--- a/app/src/adapter/node/storage/StorageLocalAdapter.native-spec.ts
+++ b/app/src/adapter/node/storage/StorageLocalAdapter.vitest.ts
@@ -1,5 +1,5 @@
-import { describe } from "node:test";
-import { nodeTestRunner } from "adapter/node/test";
+import { describe } from "vitest";
+import { viTestRunner } from "adapter/node/vitest";
import { StorageLocalAdapter } from "adapter/node";
import { adapterTestSuite } from "media/storage/adapters/adapter-test-suite";
import { readFileSync } from "node:fs";
@@ -14,5 +14,5 @@ describe("StorageLocalAdapter (node)", async () => {
path: path.join(basePath, "tmp"),
});
- await adapterTestSuite(nodeTestRunner, adapter, file);
+ await adapterTestSuite(viTestRunner, adapter, file);
});
diff --git a/app/src/adapter/sqlite/bun.ts b/app/src/adapter/sqlite/bun.ts
index 328186c..eaf02c4 100644
--- a/app/src/adapter/sqlite/bun.ts
+++ b/app/src/adapter/sqlite/bun.ts
@@ -1,8 +1,6 @@
import type { Connection } from "bknd/data";
-import { $console } from "bknd/core";
import { bunSqlite } from "../bun/connection/BunSqliteConnection";
export function sqlite(config: { url: string }): Connection {
- $console.info("Using bun-sqlite", config);
return bunSqlite(config);
}
diff --git a/app/src/adapter/sqlite/edge.ts b/app/src/adapter/sqlite/edge.ts
index 996d7f5..97b09ec 100644
--- a/app/src/adapter/sqlite/edge.ts
+++ b/app/src/adapter/sqlite/edge.ts
@@ -1,8 +1,6 @@
-import { $console } from "bknd/core";
import type { Connection } from "bknd/data";
import { libsql } from "../../data/connection/sqlite/LibsqlConnection";
export function sqlite(config: { url: string }): Connection {
- $console.info("Using libsql", config);
return libsql(config);
}
diff --git a/app/src/adapter/sqlite/node.ts b/app/src/adapter/sqlite/node.ts
index 1643cce..7bc6ebd 100644
--- a/app/src/adapter/sqlite/node.ts
+++ b/app/src/adapter/sqlite/node.ts
@@ -1,8 +1,6 @@
-import { $console } from "bknd/core";
import type { Connection } from "bknd/data";
import { nodeSqlite } from "../node/connection/NodeSqliteConnection";
export function sqlite(config: { url: string }): Connection {
- $console.info("Using node-sqlite", config);
return nodeSqlite(config);
}
diff --git a/app/src/core/test/utils.ts b/app/src/core/test/utils.ts
new file mode 100644
index 0000000..d4cefa9
--- /dev/null
+++ b/app/src/core/test/utils.ts
@@ -0,0 +1,12 @@
+import { createApp as createAppInternal, type CreateAppConfig } from "App";
+import { bunSqlite } from "adapter/bun/connection/BunSqliteConnection";
+import { Connection } from "data/connection/Connection";
+
+export { App } from "App";
+
+export function createApp({ connection, ...config }: CreateAppConfig = {}) {
+ return createAppInternal({
+ ...config,
+ connection: Connection.isConnection(connection) ? connection : bunSqlite(connection as any),
+ });
+}
diff --git a/app/src/data/connection/sqlite/GenericSqliteConnection.ts b/app/src/data/connection/sqlite/GenericSqliteConnection.ts
index 3707181..d9abc5f 100644
--- a/app/src/data/connection/sqlite/GenericSqliteConnection.ts
+++ b/app/src/data/connection/sqlite/GenericSqliteConnection.ts
@@ -8,12 +8,14 @@ import {
GenericSqliteDialect,
} from "kysely-generic-sqlite";
import { SqliteConnection } from "./SqliteConnection";
+import type { Features } from "../Connection";
export type GenericSqliteConnectionConfig = {
name: string;
additionalPlugins?: KyselyPlugin[];
excludeTables?: string[];
onCreateConnection?: OnCreateConnection;
+ supports?: Partial;
};
export { parseBigInt, buildQueryFn, GenericSqliteDialect, type IGenericSqlite };
@@ -33,5 +35,15 @@ export class GenericSqliteConnection extends SqliteConnection
excludeTables: config?.excludeTables,
});
this.client = db;
+ if (config?.name) {
+ this.name = config.name;
+ }
+ if (config?.supports) {
+ for (const [key, value] of Object.entries(config.supports)) {
+ if (value) {
+ this.supported[key] = value;
+ }
+ }
+ }
}
}
diff --git a/app/src/data/connection/sqlite/LibsqlConnection.spec.ts b/app/src/data/connection/sqlite/LibsqlConnection.spec.ts
index dde5a84..d6f14d1 100644
--- a/app/src/data/connection/sqlite/LibsqlConnection.spec.ts
+++ b/app/src/data/connection/sqlite/LibsqlConnection.spec.ts
@@ -2,10 +2,11 @@ import { connectionTestSuite } from "../connection-test-suite";
import { LibsqlConnection } from "./LibsqlConnection";
import { bunTestRunner } from "adapter/bun/test";
import { describe } from "bun:test";
+import { createClient } from "@libsql/client";
describe("LibsqlConnection", () => {
connectionTestSuite(bunTestRunner, {
- makeConnection: () => new LibsqlConnection({ url: ":memory:" }),
+ makeConnection: () => new LibsqlConnection(createClient({ url: ":memory:" })),
rawDialectDetails: ["rowsAffected", "lastInsertRowid"],
});
});
diff --git a/app/src/modules/ModuleManager.ts b/app/src/modules/ModuleManager.ts
index d933ceb..3380934 100644
--- a/app/src/modules/ModuleManager.ts
+++ b/app/src/modules/ModuleManager.ts
@@ -11,16 +11,9 @@ import {
stripMark,
transformObject,
} from "core/utils";
-import {
- type Connection,
- EntityManager,
- type Schema,
- datetime,
- entity,
- enumm,
- jsonSchema,
- number,
-} from "data";
+import type { Connection, Schema } from "data";
+import { EntityManager } from "data/entities/EntityManager";
+import * as proto from "data/prototype";
import { TransformPersistFailedException } from "data/errors";
import { Hono } from "hono";
import type { Kysely } from "kysely";
@@ -116,12 +109,12 @@ const configJsonSchema = Type.Union([
}),
),
]);
-export const __bknd = entity(TABLE_NAME, {
- version: number().required(),
- type: enumm({ enum: ["config", "diff", "backup"] }).required(),
- json: jsonSchema({ schema: configJsonSchema }).required(),
- created_at: datetime(),
- updated_at: datetime(),
+export const __bknd = proto.entity(TABLE_NAME, {
+ version: proto.number().required(),
+ type: proto.enumm({ enum: ["config", "diff", "backup"] }).required(),
+ json: proto.jsonSchema({ schema: configJsonSchema }).required(),
+ created_at: proto.datetime(),
+ updated_at: proto.datetime(),
});
type ConfigTable2 = Schema;
interface T_INTERNAL_EM {
diff --git a/app/vitest.config.ts b/app/vitest.config.ts
index f86248a..adc92b7 100644
--- a/app/vitest.config.ts
+++ b/app/vitest.config.ts
@@ -1,18 +1,26 @@
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import tsconfigPaths from "vite-tsconfig-paths";
-
+import path from "node:path";
export default defineConfig({
- plugins: [react(), tsconfigPaths()],
+ plugins: [tsconfigPaths()],
test: {
- globals: true,
- environment: "jsdom",
- setupFiles: ["./__test__/vitest/setup.ts"],
+ projects: ["**/*.vitest.config.ts"],
include: ["**/*.vi-test.ts", "**/*.vitest.ts"],
- coverage: {
- provider: "v8",
- reporter: ["text", "json", "html"],
- exclude: ["node_modules/", "**/*.d.ts", "**/*.test.ts", "**/*.config.ts"],
- },
},
});
+
+// export defineConfig({
+// plugins: [tsconfigPaths()],
+// test: {
+// globals: true,
+// environment: "jsdom",
+// setupFiles: ["./__test__/vitest/setup.ts"],
+// include: ["**/*.vi-test.ts", "**/*.vitest.ts"],
+// coverage: {
+// provider: "v8",
+// reporter: ["text", "json", "html"],
+// exclude: ["node_modules/", "**/*.d.ts", "**/*.test.ts", "**/*.config.ts"],
+// },
+// },
+// });
diff --git a/bun.lock b/bun.lock
index 56fe68e..f442cdd 100644
--- a/bun.lock
+++ b/bun.lock
@@ -34,7 +34,6 @@
"@codemirror/lang-json": "^6.0.1",
"@hello-pangea/dnd": "^18.0.1",
"@hono/swagger-ui": "^0.5.1",
- "@libsql/client": "^0.15.9",
"@mantine/core": "^7.17.1",
"@mantine/hooks": "^7.17.1",
"@sinclair/typebox": "0.34.30",
@@ -60,11 +59,13 @@
"devDependencies": {
"@aws-sdk/client-s3": "^3.758.0",
"@bluwy/giget-core": "^0.1.2",
+ "@cloudflare/vitest-pool-workers": "^0.8.38",
"@cloudflare/workers-types": "^4.20250606.0",
"@dagrejs/dagre": "^1.1.4",
"@hono/typebox-validator": "^0.3.3",
"@hono/vite-dev-server": "^0.19.1",
"@hookform/resolvers": "^4.1.3",
+ "@libsql/client": "^0.15.9",
"@libsql/kysely-libsql": "^0.4.1",
"@mantine/modals": "^7.17.1",
"@mantine/notifications": "^7.17.1",
@@ -520,6 +521,10 @@
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.3.4", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="],
+ "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.2", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-MtUgNl+QkQyhQvv5bbWP+BpBC1N0me4CHHuP2H4ktmOMKdB/6kkz/lo+zqiA4mEazb4y+1cwyNjVrQ2DWeE4mg=="],
+
+ "@cloudflare/vitest-pool-workers": ["@cloudflare/vitest-pool-workers@0.8.38", "", { "dependencies": { "birpc": "0.2.14", "cjs-module-lexer": "^1.2.3", "devalue": "^4.3.0", "miniflare": "4.20250604.1", "semver": "^7.7.1", "wrangler": "4.20.0", "zod": "^3.22.3" }, "peerDependencies": { "@vitest/runner": "2.0.x - 3.2.x", "@vitest/snapshot": "2.0.x - 3.2.x", "vitest": "2.0.x - 3.2.x" } }, "sha512-/eeHW5RbU/eWy5UHOZlYh+7J4DTC5GmMW33Iz7GfKAPBgsNHUqx0/AQotjb4qqB3jW/QvsIQM+jZofmMfdPSZw=="],
+
"@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250224.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-sBbaAF2vgQ9+T50ik1ihekdepStBp0w4fvNghBfXIw1iWqfNWnypcjDMmi/7JhXJt2uBxBrSlXCvE5H7Gz+kbw=="],
"@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250224.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-naetGefgjAaDbEacpwaVruJXNwxmRRL7v3ppStgEiqAlPmTpQ/Edjn2SQ284QwOw3MvaVPHrWcaTBupUpkqCyg=="],
@@ -1592,6 +1597,8 @@
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
+ "birpc": ["birpc@0.2.14", "", {}, "sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA=="],
+
"bknd": ["bknd@workspace:app"],
"bknd-cli": ["bknd-cli@workspace:packages/cli"],
@@ -1682,6 +1689,8 @@
"ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="],
+ "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="],
+
"class-utils": ["class-utils@0.3.6", "", { "dependencies": { "arr-union": "^3.1.0", "define-property": "^0.2.5", "isobject": "^3.0.0", "static-extend": "^0.1.1" } }, "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg=="],
"classcat": ["classcat@5.0.5", "", {}, "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="],
@@ -1886,6 +1895,8 @@
"detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
+ "devalue": ["devalue@4.3.3", "", {}, "sha512-UH8EL6H2ifcY8TbD2QsxwCC/pr5xSwPvv85LrLXVihmHVC3T3YqTCIwnR5ak0yO1KYqlxrPVOA/JVZJYPy2ATg=="],
+
"diff-sequences": ["diff-sequences@29.6.3", "", {}, "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="],
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
@@ -2052,6 +2063,8 @@
"express-rate-limit": ["express-rate-limit@5.5.1", "", {}, "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg=="],
+ "exsolve": ["exsolve@1.0.5", "", {}, "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg=="],
+
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
"extend-shallow": ["extend-shallow@3.0.2", "", { "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" } }, "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q=="],
@@ -3882,6 +3895,12 @@
"@bundled-es-modules/tough-cookie/tough-cookie": ["tough-cookie@4.1.4", "", { "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", "universalify": "^0.2.0", "url-parse": "^1.5.3" } }, "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag=="],
+ "@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare": ["miniflare@4.20250604.1", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "^5.28.5", "workerd": "1.20250604.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-HJQ9YhH0F0fI73Vsdy3PNVau+PfHZYK7trI5WJEcbfl5HzqhMU0DRNtA/G5EXQgiumkjrmbW4Zh1DVTtsqICPg=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler": ["wrangler@4.20.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.4.0", "@cloudflare/unenv-preset": "2.3.2", "blake3-wasm": "2.1.5", "esbuild": "0.25.4", "miniflare": "4.20250604.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.17", "workerd": "1.20250604.0" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@cloudflare/workers-types": "^4.20250604.0" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-gxMLaSnYp3VLdGPZu4fc/9UlB7PnSVwni25v32NM9szG2yTt+gx5RunWzmoLplplIfEMkBuV3wA47vccNu7zcA=="],
+
"@cypress/request/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="],
"@emnapi/runtime/tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
@@ -4744,6 +4763,22 @@
"@bundled-es-modules/tough-cookie/tough-cookie/universalify": ["universalify@0.2.0", "", {}, "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="],
+ "@cloudflare/unenv-preset/unenv/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
+
+ "@cloudflare/unenv-preset/unenv/ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/workerd": ["workerd@1.20250604.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250604.0", "@cloudflare/workerd-darwin-arm64": "1.20250604.0", "@cloudflare/workerd-linux-64": "1.20250604.0", "@cloudflare/workerd-linux-arm64": "1.20250604.0", "@cloudflare/workerd-windows-64": "1.20250604.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-sHz9R1sxPpnyq3ptrI/5I96sYTMA2+Ljm75oJDbmEcZQwNyezpu9Emerzt3kzzjCJQqtdscGOidWv4RKGZXzAA=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "^0.7.1", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/unenv": ["unenv@2.0.0-rc.17", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.4", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-B06u0wXkEd+o5gOCMl/ZHl5cfpYbDZKAT+HWTL+Hws6jWu7dCiqBBXXXzMFcFVJb8D4ytAnYmxJA83uwOQRSsg=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd": ["workerd@1.20250604.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250604.0", "@cloudflare/workerd-darwin-arm64": "1.20250604.0", "@cloudflare/workerd-linux-64": "1.20250604.0", "@cloudflare/workerd-linux-arm64": "1.20250604.0", "@cloudflare/workerd-windows-64": "1.20250604.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-sHz9R1sxPpnyq3ptrI/5I96sYTMA2+Ljm75oJDbmEcZQwNyezpu9Emerzt3kzzjCJQqtdscGOidWv4RKGZXzAA=="],
+
"@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
"@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="],
@@ -5290,6 +5325,82 @@
"@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from/@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
+ "@cloudflare/vitest-pool-workers/miniflare/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250604.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-PI6AWAzhHg75KVhYkSWFBf3HKCHstpaKg4nrx6LYZaEvz0TaTz+JQpYU2fNAgGFmVsK5xEzwFTGh3DAVAKONPw=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250604.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hOiZZSop7QRQgGERtTIy9eU5GvPpIsgE2/BDsUdHMl7OBZ7QLniqvgDzLNDzj0aTkCldm9Yl/Z+C7aUgRdOccw=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250604.0", "", { "os": "linux", "cpu": "x64" }, "sha512-S0R9r7U4nv9qejYygQj01hArC4KUbQQ4u29rvegR0MGoXZY8AHIEuJxon0kE7r7aWFJxvl4W3tOH+5hwW51LYw=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250604.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-BTFU/rXpNy03wpeueI2P7q1vVjbg2V6mCyyFGqDqMn2gSVYXH1G0zFNolV13PQXa0HgaqM6oYnqtAxluqbA+kQ=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250604.0", "", { "os": "win32", "cpu": "x64" }, "sha512-tW/U9/qDmDZBeoEVcK5skb2uouVAMXMzt7o/uGvaIFLeZsQkOp4NBmvoQQd+nbOc7nVCJIwFoSMokd89AhzCkA=="],
+
+ "@cloudflare/vitest-pool-workers/miniflare/youch/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/unenv/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/unenv/ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250604.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-PI6AWAzhHg75KVhYkSWFBf3HKCHstpaKg4nrx6LYZaEvz0TaTz+JQpYU2fNAgGFmVsK5xEzwFTGh3DAVAKONPw=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250604.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hOiZZSop7QRQgGERtTIy9eU5GvPpIsgE2/BDsUdHMl7OBZ7QLniqvgDzLNDzj0aTkCldm9Yl/Z+C7aUgRdOccw=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250604.0", "", { "os": "linux", "cpu": "x64" }, "sha512-S0R9r7U4nv9qejYygQj01hArC4KUbQQ4u29rvegR0MGoXZY8AHIEuJxon0kE7r7aWFJxvl4W3tOH+5hwW51LYw=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250604.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-BTFU/rXpNy03wpeueI2P7q1vVjbg2V6mCyyFGqDqMn2gSVYXH1G0zFNolV13PQXa0HgaqM6oYnqtAxluqbA+kQ=="],
+
+ "@cloudflare/vitest-pool-workers/wrangler/workerd/@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250604.0", "", { "os": "win32", "cpu": "x64" }, "sha512-tW/U9/qDmDZBeoEVcK5skb2uouVAMXMzt7o/uGvaIFLeZsQkOp4NBmvoQQd+nbOc7nVCJIwFoSMokd89AhzCkA=="],
+
"@jest/core/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],