@katajs/drizzle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yaseer A. Okino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # @katajs/drizzle
2
+
3
+ Drizzle adapter for [katajs](https://github.com/ookino/katajs) — wires [Drizzle ORM](https://orm.drizzle.team) to [Cloudflare Hyperdrive](https://developers.cloudflare.com/hyperdrive/) for Postgres.
4
+
5
+ ```bash
6
+ pnpm add @katajs/drizzle drizzle-orm pg
7
+ ```
8
+
9
+ ## Usage
10
+
11
+ ```ts
12
+ import { createApp } from '@katajs/core';
13
+ import { drizzleAdapter } from '@katajs/drizzle';
14
+ import * as schema from './db/schema';
15
+
16
+ type Bindings = {
17
+ HYPERDRIVE: Hyperdrive;
18
+ };
19
+
20
+ const { app } = createApp({
21
+ bindings: {} as Bindings,
22
+ db: drizzleAdapter({ schema }),
23
+ modules: [/* ... */],
24
+ });
25
+ ```
26
+
27
+ `drizzleAdapter` returns a `DbAdapter` that katajs's container middleware uses to construct a per-request `db` client backed by `env.HYPERDRIVE.connectionString`.
28
+
29
+ ## Transactions
30
+
31
+ ```ts
32
+ // inside a service
33
+ async create(input: CreatePostInput) {
34
+ return c.withTransaction(async (tx) => {
35
+ const post = await tx.resolve('postRepository').insert(input);
36
+ await tx.resolve('auditService').log({ action: 'post.create', id: post.id });
37
+ return post;
38
+ });
39
+ }
40
+ ```
41
+
42
+ `withTransaction` wraps `db.transaction(...)` and rebuilds a sub-container where every repository uses the transaction-bound `tx` client. Non-repository services are reused from the outer container. Nested calls reuse the outer transaction (no savepoints in v0.1).
43
+
44
+ ## Public API
45
+
46
+ ```ts
47
+ export { drizzleAdapter } from '@katajs/drizzle';
48
+ export type {
49
+ DrizzleAdapterConfig,
50
+ DrizzleClient,
51
+ DrizzleClientOrTx,
52
+ DrizzleTx,
53
+ HyperdriveBinding,
54
+ } from '@katajs/drizzle';
55
+ ```
56
+
57
+ ## Local development
58
+
59
+ When developing locally with `wrangler dev`, configure `wrangler.jsonc` with a `localConnectionString` for the Hyperdrive binding:
60
+
61
+ ```jsonc
62
+ {
63
+ "hyperdrive": [
64
+ {
65
+ "binding": "HYPERDRIVE",
66
+ "id": "<your-hyperdrive-id>",
67
+ "localConnectionString": "postgres://postgres:postgres@localhost:5432/myapp"
68
+ }
69
+ ]
70
+ }
71
+ ```
72
+
73
+ The binding `id` is required even locally; use any UUID until you've created the real Hyperdrive resource.
74
+
75
+ ## License
76
+
77
+ [MIT](./LICENSE) © Yaseer A. Okino
@@ -0,0 +1,49 @@
1
+ import { NodePgDatabase } from 'drizzle-orm/node-postgres';
2
+ import { ExtractTablesWithRelations } from 'drizzle-orm';
3
+ import { PgTransaction, PgQueryResultHKT } from 'drizzle-orm/pg-core';
4
+
5
+ /** Drizzle client bound to node-postgres against a Hyperdrive connection. */
6
+ type DrizzleClient<TSchema extends Record<string, unknown> = Record<string, never>> = NodePgDatabase<TSchema>;
7
+ /** Drizzle transaction handle (same query API as the client). */
8
+ type DrizzleTx<TSchema extends Record<string, unknown> = Record<string, never>> = PgTransaction<PgQueryResultHKT, TSchema, ExtractTablesWithRelations<TSchema>>;
9
+ type DrizzleClientOrTx<TSchema extends Record<string, unknown> = Record<string, never>> = DrizzleClient<TSchema> | DrizzleTx<TSchema>;
10
+
11
+ /** Cloudflare Hyperdrive binding shape (per `env.HYPERDRIVE`). */
12
+ type HyperdriveBinding = {
13
+ connectionString: string;
14
+ };
15
+ type DrizzleAdapterConfig<TSchema extends Record<string, unknown> = Record<string, never>> = {
16
+ /** Drizzle relational schema. Required for `db.query.<table>` API. */
17
+ schema?: TSchema;
18
+ /**
19
+ * Override the Hyperdrive binding key on `env`. Default `HYPERDRIVE`.
20
+ * Useful when a project uses multiple bindings or a non-conventional name.
21
+ */
22
+ bindingName?: string;
23
+ /**
24
+ * Inject a custom client factory. When provided, `bindingName` is ignored.
25
+ * Primarily for tests; production code should let the adapter build the pool.
26
+ */
27
+ makeClient?: (env: unknown) => DrizzleClient<TSchema>;
28
+ };
29
+ /**
30
+ * Drizzle adapter targeting Cloudflare Hyperdrive (Postgres). Per spec §6.2
31
+ * uses `pg` (`node-postgres`) with `nodejs_compat`.
32
+ *
33
+ * const { app } = createApp({
34
+ * bindings: {} as Bindings,
35
+ * db: drizzleAdapter({ schema }),
36
+ * modules: [...],
37
+ * });
38
+ */
39
+ declare function drizzleAdapter<TSchema extends Record<string, unknown> = Record<string, never>>(config?: DrizzleAdapterConfig<TSchema>): {
40
+ create(env: unknown): DrizzleClient<TSchema>;
41
+ /**
42
+ * Run a function inside a Drizzle transaction. Surfaces the txDb to the
43
+ * caller via Drizzle's native `db.transaction(...)`. v0.1 has no
44
+ * savepoints — nested calls reuse the outer transaction (handled by core).
45
+ */
46
+ runTransaction<T>(db: DrizzleClient<TSchema>, fn: (txDb: DrizzleTx<TSchema>) => Promise<T>): Promise<T>;
47
+ };
48
+
49
+ export { type DrizzleAdapterConfig, type DrizzleClient, type DrizzleClientOrTx, type DrizzleTx, type HyperdriveBinding, drizzleAdapter };
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ // src/adapter.ts
2
+ import { drizzle } from "drizzle-orm/node-postgres";
3
+ import { Pool } from "pg";
4
+ function drizzleAdapter(config = {}) {
5
+ const bindingName = config.bindingName ?? "HYPERDRIVE";
6
+ return {
7
+ create(env) {
8
+ if (config.makeClient) return config.makeClient(env);
9
+ const binding = env?.[bindingName];
10
+ if (!binding?.connectionString) {
11
+ throw new Error(
12
+ `[katajs] Missing '${bindingName}' binding or its connectionString. Add a Hyperdrive binding to wrangler.jsonc, or pass 'makeClient' for tests.`
13
+ );
14
+ }
15
+ const pool = new Pool({ connectionString: binding.connectionString });
16
+ return drizzle(pool, { schema: config.schema });
17
+ },
18
+ /**
19
+ * Run a function inside a Drizzle transaction. Surfaces the txDb to the
20
+ * caller via Drizzle's native `db.transaction(...)`. v0.1 has no
21
+ * savepoints — nested calls reuse the outer transaction (handled by core).
22
+ */
23
+ async runTransaction(db, fn) {
24
+ return db.transaction(async (txDb) => fn(txDb));
25
+ }
26
+ };
27
+ }
28
+ export {
29
+ drizzleAdapter
30
+ };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts"],"sourcesContent":["import { drizzle } from 'drizzle-orm/node-postgres';\nimport { Pool } from 'pg';\nimport type { DrizzleClient, DrizzleTx } from './types';\n\n/** Cloudflare Hyperdrive binding shape (per `env.HYPERDRIVE`). */\nexport type HyperdriveBinding = {\n connectionString: string;\n};\n\nexport type DrizzleAdapterConfig<\n TSchema extends Record<string, unknown> = Record<string, never>,\n> = {\n /** Drizzle relational schema. Required for `db.query.<table>` API. */\n schema?: TSchema;\n /**\n * Override the Hyperdrive binding key on `env`. Default `HYPERDRIVE`.\n * Useful when a project uses multiple bindings or a non-conventional name.\n */\n bindingName?: string;\n /**\n * Inject a custom client factory. When provided, `bindingName` is ignored.\n * Primarily for tests; production code should let the adapter build the pool.\n */\n makeClient?: (env: unknown) => DrizzleClient<TSchema>;\n};\n\n/**\n * Drizzle adapter targeting Cloudflare Hyperdrive (Postgres). Per spec §6.2\n * uses `pg` (`node-postgres`) with `nodejs_compat`.\n *\n * const { app } = createApp({\n * bindings: {} as Bindings,\n * db: drizzleAdapter({ schema }),\n * modules: [...],\n * });\n */\nexport function drizzleAdapter<\n TSchema extends Record<string, unknown> = Record<string, never>,\n>(config: DrizzleAdapterConfig<TSchema> = {}) {\n const bindingName = config.bindingName ?? 'HYPERDRIVE';\n\n return {\n create(env: unknown): DrizzleClient<TSchema> {\n if (config.makeClient) return config.makeClient(env);\n\n const binding = (env as Record<string, unknown> | null | undefined)?.[\n bindingName\n ] as HyperdriveBinding | undefined;\n\n if (!binding?.connectionString) {\n throw new Error(\n `[katajs] Missing '${bindingName}' binding or its connectionString. ` +\n `Add a Hyperdrive binding to wrangler.jsonc, or pass 'makeClient' for tests.`,\n );\n }\n\n const pool = new Pool({ connectionString: binding.connectionString });\n return drizzle(pool, { schema: config.schema }) as DrizzleClient<TSchema>;\n },\n\n /**\n * Run a function inside a Drizzle transaction. Surfaces the txDb to the\n * caller via Drizzle's native `db.transaction(...)`. v0.1 has no\n * savepoints — nested calls reuse the outer transaction (handled by core).\n */\n async runTransaction<T>(\n db: DrizzleClient<TSchema>,\n fn: (txDb: DrizzleTx<TSchema>) => Promise<T>,\n ): Promise<T> {\n return db.transaction(async (txDb) => fn(txDb as DrizzleTx<TSchema>));\n },\n };\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AAmCd,SAAS,eAEd,SAAwC,CAAC,GAAG;AAC5C,QAAM,cAAc,OAAO,eAAe;AAE1C,SAAO;AAAA,IACL,OAAO,KAAsC;AAC3C,UAAI,OAAO,WAAY,QAAO,OAAO,WAAW,GAAG;AAEnD,YAAM,UAAW,MACf,WACF;AAEA,UAAI,CAAC,SAAS,kBAAkB;AAC9B,cAAM,IAAI;AAAA,UACR,qBAAqB,WAAW;AAAA,QAElC;AAAA,MACF;AAEA,YAAM,OAAO,IAAI,KAAK,EAAE,kBAAkB,QAAQ,iBAAiB,CAAC;AACpE,aAAO,QAAQ,MAAM,EAAE,QAAQ,OAAO,OAAO,CAAC;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,MAAM,eACJ,IACA,IACY;AACZ,aAAO,GAAG,YAAY,OAAO,SAAS,GAAG,IAA0B,CAAC;AAAA,IACtE;AAAA,EACF;AACF;","names":[]}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@katajs/drizzle",
3
+ "version": "0.1.0",
4
+ "description": "Drizzle adapter for katajs — Hyperdrive-backed Postgres on Cloudflare Workers.",
5
+ "keywords": [
6
+ "katajs",
7
+ "drizzle",
8
+ "drizzle-orm",
9
+ "hyperdrive",
10
+ "cloudflare",
11
+ "workers",
12
+ "postgres"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "Yaseer A. Okino <yaseerokino@gmail.com>",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/ookino/katajs.git",
19
+ "directory": "packages/drizzle"
20
+ },
21
+ "homepage": "https://github.com/ookino/katajs/tree/main/packages/drizzle#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/ookino/katajs/issues"
24
+ },
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "peerDependencies": {
42
+ "drizzle-orm": ">=0.36.0",
43
+ "pg": "^8.13.0",
44
+ "@katajs/core": "^0.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/pg": "^8.11.10",
48
+ "drizzle-orm": "^0.36.4",
49
+ "pg": "^8.13.1",
50
+ "tsup": "^8.3.5",
51
+ "typescript": "^5.6.3",
52
+ "vitest": "^2.1.5",
53
+ "@katajs/core": "0.1.0"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "scripts": {
59
+ "build": "tsup",
60
+ "dev": "tsup --watch",
61
+ "test": "vitest run",
62
+ "test:watch": "vitest",
63
+ "typecheck": "tsc --noEmit"
64
+ }
65
+ }