@parsrun/database 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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @parsrun/database
2
+
3
+ Database utilities for Pars with Drizzle ORM helpers and multi-runtime support.
4
+
5
+ ## Features
6
+
7
+ - **Drizzle ORM**: Type-safe database operations
8
+ - **Multi-Adapter**: PostgreSQL, Neon, Cloudflare D1
9
+ - **Edge-Compatible**: Works on Cloudflare Workers, Deno
10
+ - **Migrations**: Schema migration utilities
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pnpm add @parsrun/database drizzle-orm
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```typescript
21
+ import { createDatabase } from '@parsrun/database';
22
+
23
+ const db = createDatabase({
24
+ adapter: 'postgres',
25
+ connectionString: process.env.DATABASE_URL,
26
+ });
27
+ ```
28
+
29
+ ## API Overview
30
+
31
+ ### Adapters
32
+
33
+ #### PostgreSQL
34
+
35
+ ```typescript
36
+ import { createPostgresAdapter } from '@parsrun/database/adapters/postgres';
37
+
38
+ const db = createPostgresAdapter({
39
+ connectionString: 'postgres://...',
40
+ });
41
+ ```
42
+
43
+ #### Neon (Serverless PostgreSQL)
44
+
45
+ ```typescript
46
+ import { createNeonAdapter } from '@parsrun/database/adapters/neon';
47
+
48
+ const db = createNeonAdapter({
49
+ connectionString: process.env.DATABASE_URL,
50
+ });
51
+ ```
52
+
53
+ #### Cloudflare D1
54
+
55
+ ```typescript
56
+ import { createD1Adapter } from '@parsrun/database/adapters/d1';
57
+
58
+ // In Cloudflare Worker
59
+ const db = createD1Adapter({
60
+ database: env.DB,
61
+ });
62
+ ```
63
+
64
+ ### Database Operations
65
+
66
+ ```typescript
67
+ import { users } from './schema';
68
+
69
+ // Insert
70
+ await db.insert(users).values({ name: 'John' });
71
+
72
+ // Select
73
+ const allUsers = await db.select().from(users);
74
+
75
+ // Update
76
+ await db.update(users).set({ name: 'Jane' }).where(eq(users.id, 1));
77
+
78
+ // Delete
79
+ await db.delete(users).where(eq(users.id, 1));
80
+ ```
81
+
82
+ ### With Multi-Tenancy
83
+
84
+ ```typescript
85
+ import { withTenant } from '@parsrun/database';
86
+
87
+ // Automatically filter by tenant
88
+ const tenantDb = withTenant(db, tenantId);
89
+ const users = await tenantDb.select().from(users);
90
+ ```
91
+
92
+ ## Exports
93
+
94
+ ```typescript
95
+ import { ... } from '@parsrun/database'; // Main exports
96
+ import { ... } from '@parsrun/database/adapters/postgres'; // PostgreSQL
97
+ import { ... } from '@parsrun/database/adapters/neon'; // Neon
98
+ import { ... } from '@parsrun/database/adapters/d1'; // Cloudflare D1
99
+ ```
100
+
101
+ ## License
102
+
103
+ MIT
@@ -0,0 +1,56 @@
1
+ import { drizzle } from 'drizzle-orm/d1';
2
+ import { a as DatabaseAdapter, c as D1Config, f as DatabaseHealth, d as D1Database } from '../types-DgBIyTeZ.js';
3
+
4
+ /**
5
+ * @parsrun/database - Cloudflare D1 Adapter
6
+ * Cloudflare D1 (SQLite) adapter - native edge database
7
+ */
8
+
9
+ /**
10
+ * Cloudflare D1 Database Adapter
11
+ * Native SQLite database for Cloudflare Workers
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // In Cloudflare Worker
16
+ * export default {
17
+ * async fetch(request, env) {
18
+ * const db = createD1Adapter({
19
+ * type: 'd1',
20
+ * binding: env.DB, // D1 binding from wrangler.toml
21
+ * });
22
+ *
23
+ * const users = await db.drizzle().select().from(usersTable);
24
+ * return new Response(JSON.stringify(users));
25
+ * }
26
+ * }
27
+ * ```
28
+ */
29
+ declare class D1Adapter implements DatabaseAdapter {
30
+ readonly type: "d1";
31
+ private binding;
32
+ private db;
33
+ constructor(config: D1Config);
34
+ execute<T = unknown>(sql: string): Promise<T[]>;
35
+ ping(): Promise<boolean>;
36
+ health(): Promise<DatabaseHealth>;
37
+ drizzle(): ReturnType<typeof drizzle>;
38
+ close(): Promise<void>;
39
+ /**
40
+ * Get the raw D1 binding
41
+ */
42
+ getBinding(): D1Database;
43
+ /**
44
+ * Execute a batch of statements
45
+ */
46
+ batch<T = unknown>(statements: Array<{
47
+ sql: string;
48
+ params?: unknown[];
49
+ }>): Promise<T[][]>;
50
+ }
51
+ /**
52
+ * Create a D1 adapter
53
+ */
54
+ declare function createD1Adapter(config: D1Config): D1Adapter;
55
+
56
+ export { D1Adapter, createD1Adapter };
@@ -0,0 +1,115 @@
1
+ // src/adapters/d1.ts
2
+ import { drizzle } from "drizzle-orm/d1";
3
+
4
+ // src/types.ts
5
+ var DatabaseError = class extends Error {
6
+ constructor(message, code, cause) {
7
+ super(message);
8
+ this.code = code;
9
+ this.cause = cause;
10
+ this.name = "DatabaseError";
11
+ }
12
+ };
13
+ var DatabaseErrorCodes = {
14
+ CONNECTION_FAILED: "CONNECTION_FAILED",
15
+ QUERY_FAILED: "QUERY_FAILED",
16
+ TRANSACTION_FAILED: "TRANSACTION_FAILED",
17
+ MIGRATION_FAILED: "MIGRATION_FAILED",
18
+ INVALID_CONFIG: "INVALID_CONFIG",
19
+ ADAPTER_NOT_AVAILABLE: "ADAPTER_NOT_AVAILABLE",
20
+ TIMEOUT: "TIMEOUT",
21
+ CONSTRAINT_VIOLATION: "CONSTRAINT_VIOLATION",
22
+ NOT_FOUND: "NOT_FOUND"
23
+ };
24
+
25
+ // src/adapters/d1.ts
26
+ var D1Adapter = class {
27
+ type = "d1";
28
+ binding;
29
+ db;
30
+ constructor(config) {
31
+ this.binding = config.binding;
32
+ const drizzleConfig = {};
33
+ if (config.logging !== void 0) {
34
+ drizzleConfig.logger = config.logging;
35
+ }
36
+ this.db = drizzle(this.binding, drizzleConfig);
37
+ }
38
+ async execute(sql) {
39
+ try {
40
+ const result = await this.binding.exec(sql);
41
+ return result.results ?? [];
42
+ } catch (err) {
43
+ throw new DatabaseError(
44
+ `Query failed: ${err instanceof Error ? err.message : "Unknown error"}`,
45
+ DatabaseErrorCodes.QUERY_FAILED,
46
+ err
47
+ );
48
+ }
49
+ }
50
+ async ping() {
51
+ try {
52
+ await this.binding.prepare("SELECT 1").first();
53
+ return true;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+ async health() {
59
+ const start = Date.now();
60
+ try {
61
+ await this.binding.prepare("SELECT 1").first();
62
+ const latencyMs = Date.now() - start;
63
+ const versionResult = await this.binding.prepare("SELECT sqlite_version() as version").first();
64
+ return {
65
+ healthy: true,
66
+ latencyMs,
67
+ version: versionResult ? `SQLite ${versionResult.version}` : void 0
68
+ };
69
+ } catch (err) {
70
+ return {
71
+ healthy: false,
72
+ latencyMs: Date.now() - start,
73
+ error: err instanceof Error ? err.message : "Unknown error"
74
+ };
75
+ }
76
+ }
77
+ drizzle() {
78
+ return this.db;
79
+ }
80
+ async close() {
81
+ }
82
+ /**
83
+ * Get the raw D1 binding
84
+ */
85
+ getBinding() {
86
+ return this.binding;
87
+ }
88
+ /**
89
+ * Execute a batch of statements
90
+ */
91
+ async batch(statements) {
92
+ try {
93
+ const prepared = statements.map((stmt) => {
94
+ const p = this.binding.prepare(stmt.sql);
95
+ return stmt.params ? p.bind(...stmt.params) : p;
96
+ });
97
+ const results = await this.binding.batch(prepared);
98
+ return results.map((r) => r.results ?? []);
99
+ } catch (err) {
100
+ throw new DatabaseError(
101
+ `Batch execution failed: ${err instanceof Error ? err.message : "Unknown error"}`,
102
+ DatabaseErrorCodes.QUERY_FAILED,
103
+ err
104
+ );
105
+ }
106
+ }
107
+ };
108
+ function createD1Adapter(config) {
109
+ return new D1Adapter(config);
110
+ }
111
+ export {
112
+ D1Adapter,
113
+ createD1Adapter
114
+ };
115
+ //# sourceMappingURL=d1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/d1.ts","../../src/types.ts"],"sourcesContent":["/**\n * @parsrun/database - Cloudflare D1 Adapter\n * Cloudflare D1 (SQLite) adapter - native edge database\n */\n\nimport { drizzle } from \"drizzle-orm/d1\";\nimport type {\n D1Config,\n D1Database,\n DatabaseAdapter,\n DatabaseHealth,\n} from \"../types.js\";\nimport { DatabaseError, DatabaseErrorCodes } from \"../types.js\";\n\n/**\n * Cloudflare D1 Database Adapter\n * Native SQLite database for Cloudflare Workers\n *\n * @example\n * ```typescript\n * // In Cloudflare Worker\n * export default {\n * async fetch(request, env) {\n * const db = createD1Adapter({\n * type: 'd1',\n * binding: env.DB, // D1 binding from wrangler.toml\n * });\n *\n * const users = await db.drizzle().select().from(usersTable);\n * return new Response(JSON.stringify(users));\n * }\n * }\n * ```\n */\nexport class D1Adapter implements DatabaseAdapter {\n readonly type = \"d1\" as const;\n\n private binding: D1Database;\n private db: ReturnType<typeof drizzle>;\n\n constructor(config: D1Config) {\n this.binding = config.binding;\n\n const drizzleConfig: Parameters<typeof drizzle>[1] = {};\n if (config.logging !== undefined) {\n drizzleConfig.logger = config.logging;\n }\n\n this.db = drizzle(this.binding as Parameters<typeof drizzle>[0], drizzleConfig);\n }\n\n async execute<T = unknown>(sql: string): Promise<T[]> {\n try {\n const result = await this.binding.exec<T>(sql);\n return result.results ?? [];\n } catch (err) {\n throw new DatabaseError(\n `Query failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n DatabaseErrorCodes.QUERY_FAILED,\n err\n );\n }\n }\n\n async ping(): Promise<boolean> {\n try {\n await this.binding.prepare(\"SELECT 1\").first();\n return true;\n } catch {\n return false;\n }\n }\n\n async health(): Promise<DatabaseHealth> {\n const start = Date.now();\n\n try {\n await this.binding.prepare(\"SELECT 1\").first();\n const latencyMs = Date.now() - start;\n\n // Get SQLite version\n const versionResult = await this.binding\n .prepare(\"SELECT sqlite_version() as version\")\n .first<{ version: string }>();\n\n return {\n healthy: true,\n latencyMs,\n version: versionResult ? `SQLite ${versionResult.version}` : undefined,\n };\n } catch (err) {\n return {\n healthy: false,\n latencyMs: Date.now() - start,\n error: err instanceof Error ? err.message : \"Unknown error\",\n };\n }\n }\n\n drizzle(): ReturnType<typeof drizzle> {\n return this.db;\n }\n\n async close(): Promise<void> {\n // D1 bindings are managed by Cloudflare, nothing to close\n }\n\n /**\n * Get the raw D1 binding\n */\n getBinding(): D1Database {\n return this.binding;\n }\n\n /**\n * Execute a batch of statements\n */\n async batch<T = unknown>(\n statements: Array<{ sql: string; params?: unknown[] }>\n ): Promise<T[][]> {\n try {\n const prepared = statements.map((stmt) => {\n const p = this.binding.prepare(stmt.sql);\n return stmt.params ? p.bind(...stmt.params) : p;\n });\n\n const results = await this.binding.batch<T>(prepared);\n return results.map((r) => r.results ?? []);\n } catch (err) {\n throw new DatabaseError(\n `Batch execution failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n DatabaseErrorCodes.QUERY_FAILED,\n err\n );\n }\n }\n}\n\n/**\n * Create a D1 adapter\n */\nexport function createD1Adapter(config: D1Config): D1Adapter {\n return new D1Adapter(config);\n}\n","/**\n * @parsrun/database - Type Definitions\n * Database types and interfaces\n */\n\n/**\n * Database adapter type\n */\nexport type DatabaseAdapterType = \"postgres\" | \"neon\" | \"d1\" | \"custom\";\n\n/**\n * Base database configuration\n */\nexport interface BaseDatabaseConfig {\n /** Adapter type */\n type: DatabaseAdapterType;\n /** Enable query logging */\n logging?: boolean | undefined;\n /** Connection pool size */\n poolSize?: number | undefined;\n}\n\n/**\n * PostgreSQL configuration\n */\nexport interface PostgresConfig extends BaseDatabaseConfig {\n type: \"postgres\";\n /** Database host */\n host: string;\n /** Database port */\n port: number;\n /** Database user */\n user: string;\n /** Database password */\n password: string;\n /** Database name */\n database: string;\n /** SSL configuration */\n ssl?: boolean | { rejectUnauthorized: boolean } | undefined;\n}\n\n/**\n * Neon serverless configuration\n */\nexport interface NeonConfig extends BaseDatabaseConfig {\n type: \"neon\";\n /** Connection string */\n connectionString: string;\n /** Use pooled connection */\n pooled?: boolean | undefined;\n}\n\n/**\n * Cloudflare D1 configuration\n */\nexport interface D1Config extends BaseDatabaseConfig {\n type: \"d1\";\n /** D1 binding */\n binding: D1Database;\n}\n\n/**\n * Cloudflare D1 Database binding type\n */\nexport interface D1Database {\n prepare(query: string): D1PreparedStatement;\n batch<T>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;\n dump(): Promise<ArrayBuffer>;\n exec<T>(query: string): Promise<D1Result<T>>;\n}\n\ninterface D1PreparedStatement {\n bind(...values: unknown[]): D1PreparedStatement;\n first<T = unknown>(column?: string): Promise<T | null>;\n run<T = unknown>(): Promise<D1Result<T>>;\n all<T = unknown>(): Promise<D1Result<T>>;\n raw<T = unknown>(): Promise<T[]>;\n}\n\ninterface D1Result<T> {\n results?: T[];\n success: boolean;\n error?: string;\n meta?: D1Meta;\n}\n\ninterface D1Meta {\n duration: number;\n rows_read: number;\n rows_written: number;\n}\n\n/**\n * Combined database configuration\n */\nexport type DatabaseConfig = PostgresConfig | NeonConfig | D1Config;\n\n/**\n * Migration status\n */\nexport interface MigrationStatus {\n /** Whether migrations need to be run */\n needsMigration: boolean;\n /** Whether database is up to date */\n upToDate: boolean;\n /** Number of pending migrations */\n pendingCount: number;\n /** Number of applied migrations */\n appliedCount: number;\n /** Error message if check failed */\n error?: string | undefined;\n}\n\n/**\n * Migration result\n */\nexport interface MigrationResult {\n /** Whether migration succeeded */\n success: boolean;\n /** Number of migrations applied */\n appliedCount?: number | undefined;\n /** Error message if migration failed */\n error?: string | undefined;\n}\n\n/**\n * Transaction options\n */\nexport interface TransactionOptions {\n /** Isolation level */\n isolationLevel?: \"read uncommitted\" | \"read committed\" | \"repeatable read\" | \"serializable\" | undefined;\n /** Access mode */\n accessMode?: \"read only\" | \"read write\" | undefined;\n /** Deferrable (PostgreSQL) */\n deferrable?: boolean | undefined;\n}\n\n/**\n * Query options\n */\nexport interface QueryOptions {\n /** Query timeout in milliseconds */\n timeout?: number | undefined;\n /** Transform result rows */\n transform?: \"camelCase\" | \"snakeCase\" | undefined;\n}\n\n/**\n * Database health status\n */\nexport interface DatabaseHealth {\n /** Whether database is healthy */\n healthy: boolean;\n /** Connection latency in milliseconds */\n latencyMs: number;\n /** Database version */\n version?: string | undefined;\n /** Error message if unhealthy */\n error?: string | undefined;\n}\n\n/**\n * Database adapter interface\n */\nexport interface DatabaseAdapter {\n /** Adapter type */\n readonly type: DatabaseAdapterType;\n\n /**\n * Execute raw SQL query\n */\n execute<T = unknown>(sql: string): Promise<T[]>;\n\n /**\n * Check connection health\n */\n ping(): Promise<boolean>;\n\n /**\n * Get connection health with details\n */\n health(): Promise<DatabaseHealth>;\n\n /**\n * Get the underlying Drizzle instance\n */\n drizzle(): unknown;\n\n /**\n * Close database connection\n */\n close(): Promise<void>;\n}\n\n/**\n * Database error\n */\nexport class DatabaseError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"DatabaseError\";\n }\n}\n\n/**\n * Common database error codes\n */\nexport const DatabaseErrorCodes = {\n CONNECTION_FAILED: \"CONNECTION_FAILED\",\n QUERY_FAILED: \"QUERY_FAILED\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n MIGRATION_FAILED: \"MIGRATION_FAILED\",\n INVALID_CONFIG: \"INVALID_CONFIG\",\n ADAPTER_NOT_AVAILABLE: \"ADAPTER_NOT_AVAILABLE\",\n TIMEOUT: \"TIMEOUT\",\n CONSTRAINT_VIOLATION: \"CONSTRAINT_VIOLATION\",\n NOT_FOUND: \"NOT_FOUND\",\n} as const;\n"],"mappings":";AAKA,SAAS,eAAe;;;ACgMjB,IAAM,gBAAN,cAA4B,MAAM;AAAA,EACvC,YACE,SACgB,MACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAKO,IAAM,qBAAqB;AAAA,EAChC,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,uBAAuB;AAAA,EACvB,SAAS;AAAA,EACT,sBAAsB;AAAA,EACtB,WAAW;AACb;;;AD3LO,IAAM,YAAN,MAA2C;AAAA,EACvC,OAAO;AAAA,EAER;AAAA,EACA;AAAA,EAER,YAAY,QAAkB;AAC5B,SAAK,UAAU,OAAO;AAEtB,UAAM,gBAA+C,CAAC;AACtD,QAAI,OAAO,YAAY,QAAW;AAChC,oBAAc,SAAS,OAAO;AAAA,IAChC;AAEA,SAAK,KAAK,QAAQ,KAAK,SAA0C,aAAa;AAAA,EAChF;AAAA,EAEA,MAAM,QAAqB,KAA2B;AACpD,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,KAAQ,GAAG;AAC7C,aAAO,OAAO,WAAW,CAAC;AAAA,IAC5B,SAAS,KAAK;AACZ,YAAM,IAAI;AAAA,QACR,iBAAiB,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,QACrE,mBAAmB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,OAAyB;AAC7B,QAAI;AACF,YAAM,KAAK,QAAQ,QAAQ,UAAU,EAAE,MAAM;AAC7C,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,SAAkC;AACtC,UAAM,QAAQ,KAAK,IAAI;AAEvB,QAAI;AACF,YAAM,KAAK,QAAQ,QAAQ,UAAU,EAAE,MAAM;AAC7C,YAAM,YAAY,KAAK,IAAI,IAAI;AAG/B,YAAM,gBAAgB,MAAM,KAAK,QAC9B,QAAQ,oCAAoC,EAC5C,MAA2B;AAE9B,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,SAAS,gBAAgB,UAAU,cAAc,OAAO,KAAK;AAAA,MAC/D;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW,KAAK,IAAI,IAAI;AAAA,QACxB,OAAO,eAAe,QAAQ,IAAI,UAAU;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAsC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MACJ,YACgB;AAChB,QAAI;AACF,YAAM,WAAW,WAAW,IAAI,CAAC,SAAS;AACxC,cAAM,IAAI,KAAK,QAAQ,QAAQ,KAAK,GAAG;AACvC,eAAO,KAAK,SAAS,EAAE,KAAK,GAAG,KAAK,MAAM,IAAI;AAAA,MAChD,CAAC;AAED,YAAM,UAAU,MAAM,KAAK,QAAQ,MAAS,QAAQ;AACpD,aAAO,QAAQ,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAAA,IAC3C,SAAS,KAAK;AACZ,YAAM,IAAI;AAAA,QACR,2BAA2B,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,QAC/E,mBAAmB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,gBAAgB,QAA6B;AAC3D,SAAO,IAAI,UAAU,MAAM;AAC7B;","names":[]}
@@ -0,0 +1,49 @@
1
+ import * as _neondatabase_serverless from '@neondatabase/serverless';
2
+ import { a as DatabaseAdapter, N as NeonConfig, f as DatabaseHealth } from '../types-DgBIyTeZ.js';
3
+
4
+ type NeonClient = ReturnType<typeof _neondatabase_serverless.neon>;
5
+ /**
6
+ * Neon Serverless Database Adapter
7
+ * Optimized for edge environments (Cloudflare Workers, Vercel Edge, etc.)
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const db = await createNeonAdapter({
12
+ * type: 'neon',
13
+ * connectionString: process.env.DATABASE_URL,
14
+ * });
15
+ *
16
+ * // Execute queries
17
+ * const users = await db.drizzle().select().from(usersTable);
18
+ * ```
19
+ */
20
+ declare class NeonAdapter implements DatabaseAdapter {
21
+ readonly type: "neon";
22
+ private client;
23
+ private db;
24
+ private config;
25
+ constructor(config: NeonConfig);
26
+ /**
27
+ * Initialize the connection
28
+ */
29
+ connect(): Promise<void>;
30
+ execute<T = unknown>(sql: string): Promise<T[]>;
31
+ ping(): Promise<boolean>;
32
+ health(): Promise<DatabaseHealth>;
33
+ drizzle(): any;
34
+ close(): Promise<void>;
35
+ /**
36
+ * Get the raw Neon client
37
+ */
38
+ getClient(): NeonClient | null;
39
+ }
40
+ /**
41
+ * Create a Neon adapter
42
+ */
43
+ declare function createNeonAdapter(config: NeonConfig): Promise<NeonAdapter>;
44
+ /**
45
+ * Create a Neon adapter from connection string
46
+ */
47
+ declare function createNeonFromUrl(connectionString: string, options?: Omit<NeonConfig, "type" | "connectionString">): Promise<NeonAdapter>;
48
+
49
+ export { NeonAdapter, createNeonAdapter, createNeonFromUrl };
@@ -0,0 +1,145 @@
1
+ // src/adapters/neon.ts
2
+ import { drizzle } from "drizzle-orm/neon-http";
3
+
4
+ // src/types.ts
5
+ var DatabaseError = class extends Error {
6
+ constructor(message, code, cause) {
7
+ super(message);
8
+ this.code = code;
9
+ this.cause = cause;
10
+ this.name = "DatabaseError";
11
+ }
12
+ };
13
+ var DatabaseErrorCodes = {
14
+ CONNECTION_FAILED: "CONNECTION_FAILED",
15
+ QUERY_FAILED: "QUERY_FAILED",
16
+ TRANSACTION_FAILED: "TRANSACTION_FAILED",
17
+ MIGRATION_FAILED: "MIGRATION_FAILED",
18
+ INVALID_CONFIG: "INVALID_CONFIG",
19
+ ADAPTER_NOT_AVAILABLE: "ADAPTER_NOT_AVAILABLE",
20
+ TIMEOUT: "TIMEOUT",
21
+ CONSTRAINT_VIOLATION: "CONSTRAINT_VIOLATION",
22
+ NOT_FOUND: "NOT_FOUND"
23
+ };
24
+
25
+ // src/adapters/neon.ts
26
+ var NeonAdapter = class {
27
+ type = "neon";
28
+ client = null;
29
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
30
+ db = null;
31
+ config;
32
+ constructor(config) {
33
+ this.config = config;
34
+ }
35
+ /**
36
+ * Initialize the connection
37
+ */
38
+ async connect() {
39
+ if (this.client) return;
40
+ try {
41
+ const { neon } = await import("@neondatabase/serverless");
42
+ this.client = neon(this.config.connectionString, {
43
+ fetchOptions: {
44
+ cache: "no-store"
45
+ }
46
+ });
47
+ const drizzleOpts = {};
48
+ if (this.config.logging !== void 0) {
49
+ drizzleOpts.logger = this.config.logging;
50
+ }
51
+ this.db = drizzle(this.client, drizzleOpts);
52
+ } catch (err) {
53
+ throw new DatabaseError(
54
+ `Failed to connect to Neon: ${err instanceof Error ? err.message : "Unknown error"}`,
55
+ DatabaseErrorCodes.CONNECTION_FAILED,
56
+ err
57
+ );
58
+ }
59
+ }
60
+ async execute(sql) {
61
+ if (!this.client) {
62
+ await this.connect();
63
+ }
64
+ try {
65
+ const result = await this.client(sql);
66
+ if (Array.isArray(result) && result.rows) {
67
+ return result.rows;
68
+ }
69
+ return result;
70
+ } catch (err) {
71
+ throw new DatabaseError(
72
+ `Query failed: ${err instanceof Error ? err.message : "Unknown error"}`,
73
+ DatabaseErrorCodes.QUERY_FAILED,
74
+ err
75
+ );
76
+ }
77
+ }
78
+ async ping() {
79
+ try {
80
+ await this.execute("SELECT 1");
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+ async health() {
87
+ const start = Date.now();
88
+ try {
89
+ if (!this.client) {
90
+ await this.connect();
91
+ }
92
+ const result = await this.execute("SELECT version()");
93
+ const latencyMs = Date.now() - start;
94
+ return {
95
+ healthy: true,
96
+ latencyMs,
97
+ version: result[0]?.version
98
+ };
99
+ } catch (err) {
100
+ return {
101
+ healthy: false,
102
+ latencyMs: Date.now() - start,
103
+ error: err instanceof Error ? err.message : "Unknown error"
104
+ };
105
+ }
106
+ }
107
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
+ drizzle() {
109
+ if (!this.db) {
110
+ throw new DatabaseError(
111
+ "Database not connected. Call connect() first.",
112
+ DatabaseErrorCodes.CONNECTION_FAILED
113
+ );
114
+ }
115
+ return this.db;
116
+ }
117
+ async close() {
118
+ this.client = null;
119
+ this.db = null;
120
+ }
121
+ /**
122
+ * Get the raw Neon client
123
+ */
124
+ getClient() {
125
+ return this.client;
126
+ }
127
+ };
128
+ async function createNeonAdapter(config) {
129
+ const adapter = new NeonAdapter(config);
130
+ await adapter.connect();
131
+ return adapter;
132
+ }
133
+ async function createNeonFromUrl(connectionString, options) {
134
+ return createNeonAdapter({
135
+ type: "neon",
136
+ connectionString,
137
+ ...options
138
+ });
139
+ }
140
+ export {
141
+ NeonAdapter,
142
+ createNeonAdapter,
143
+ createNeonFromUrl
144
+ };
145
+ //# sourceMappingURL=neon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/neon.ts","../../src/types.ts"],"sourcesContent":["/**\n * @parsrun/database - Neon Serverless Adapter\n * Neon serverless PostgreSQL adapter - perfect for edge environments\n */\n\nimport { drizzle } from \"drizzle-orm/neon-http\";\nimport type {\n DatabaseAdapter,\n DatabaseHealth,\n NeonConfig,\n} from \"../types.js\";\nimport { DatabaseError, DatabaseErrorCodes } from \"../types.js\";\n\n// Type for Neon client\ntype NeonClient = ReturnType<typeof import(\"@neondatabase/serverless\").neon>;\n\n/**\n * Neon Serverless Database Adapter\n * Optimized for edge environments (Cloudflare Workers, Vercel Edge, etc.)\n *\n * @example\n * ```typescript\n * const db = await createNeonAdapter({\n * type: 'neon',\n * connectionString: process.env.DATABASE_URL,\n * });\n *\n * // Execute queries\n * const users = await db.drizzle().select().from(usersTable);\n * ```\n */\nexport class NeonAdapter implements DatabaseAdapter {\n readonly type = \"neon\" as const;\n\n private client: NeonClient | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private db: any = null;\n private config: NeonConfig;\n\n constructor(config: NeonConfig) {\n this.config = config;\n }\n\n /**\n * Initialize the connection\n */\n async connect(): Promise<void> {\n if (this.client) return;\n\n try {\n const { neon } = await import(\"@neondatabase/serverless\");\n\n this.client = neon(this.config.connectionString, {\n fetchOptions: {\n cache: \"no-store\",\n },\n });\n\n // Build drizzle config - use any to avoid complex type issues\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const drizzleOpts: any = {};\n if (this.config.logging !== undefined) {\n drizzleOpts.logger = this.config.logging;\n }\n\n this.db = drizzle(this.client, drizzleOpts);\n } catch (err) {\n throw new DatabaseError(\n `Failed to connect to Neon: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n DatabaseErrorCodes.CONNECTION_FAILED,\n err\n );\n }\n }\n\n async execute<T = unknown>(sql: string): Promise<T[]> {\n if (!this.client) {\n await this.connect();\n }\n\n try {\n const result = await this.client!(sql);\n // Neon can return different formats depending on how it's called\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (Array.isArray(result) && (result as any).rows) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (result as any).rows as T[];\n }\n return result as T[];\n } catch (err) {\n throw new DatabaseError(\n `Query failed: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n DatabaseErrorCodes.QUERY_FAILED,\n err\n );\n }\n }\n\n async ping(): Promise<boolean> {\n try {\n await this.execute(\"SELECT 1\");\n return true;\n } catch {\n return false;\n }\n }\n\n async health(): Promise<DatabaseHealth> {\n const start = Date.now();\n\n try {\n if (!this.client) {\n await this.connect();\n }\n\n const result = await this.execute<{ version: string }>(\"SELECT version()\");\n const latencyMs = Date.now() - start;\n\n return {\n healthy: true,\n latencyMs,\n version: result[0]?.version,\n };\n } catch (err) {\n return {\n healthy: false,\n latencyMs: Date.now() - start,\n error: err instanceof Error ? err.message : \"Unknown error\",\n };\n }\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n drizzle(): any {\n if (!this.db) {\n throw new DatabaseError(\n \"Database not connected. Call connect() first.\",\n DatabaseErrorCodes.CONNECTION_FAILED\n );\n }\n return this.db;\n }\n\n async close(): Promise<void> {\n // Neon serverless connections are stateless, nothing to close\n this.client = null;\n this.db = null;\n }\n\n /**\n * Get the raw Neon client\n */\n getClient(): NeonClient | null {\n return this.client;\n }\n}\n\n/**\n * Create a Neon adapter\n */\nexport async function createNeonAdapter(\n config: NeonConfig\n): Promise<NeonAdapter> {\n const adapter = new NeonAdapter(config);\n await adapter.connect();\n return adapter;\n}\n\n/**\n * Create a Neon adapter from connection string\n */\nexport async function createNeonFromUrl(\n connectionString: string,\n options?: Omit<NeonConfig, \"type\" | \"connectionString\">\n): Promise<NeonAdapter> {\n return createNeonAdapter({\n type: \"neon\",\n connectionString,\n ...options,\n });\n}\n","/**\n * @parsrun/database - Type Definitions\n * Database types and interfaces\n */\n\n/**\n * Database adapter type\n */\nexport type DatabaseAdapterType = \"postgres\" | \"neon\" | \"d1\" | \"custom\";\n\n/**\n * Base database configuration\n */\nexport interface BaseDatabaseConfig {\n /** Adapter type */\n type: DatabaseAdapterType;\n /** Enable query logging */\n logging?: boolean | undefined;\n /** Connection pool size */\n poolSize?: number | undefined;\n}\n\n/**\n * PostgreSQL configuration\n */\nexport interface PostgresConfig extends BaseDatabaseConfig {\n type: \"postgres\";\n /** Database host */\n host: string;\n /** Database port */\n port: number;\n /** Database user */\n user: string;\n /** Database password */\n password: string;\n /** Database name */\n database: string;\n /** SSL configuration */\n ssl?: boolean | { rejectUnauthorized: boolean } | undefined;\n}\n\n/**\n * Neon serverless configuration\n */\nexport interface NeonConfig extends BaseDatabaseConfig {\n type: \"neon\";\n /** Connection string */\n connectionString: string;\n /** Use pooled connection */\n pooled?: boolean | undefined;\n}\n\n/**\n * Cloudflare D1 configuration\n */\nexport interface D1Config extends BaseDatabaseConfig {\n type: \"d1\";\n /** D1 binding */\n binding: D1Database;\n}\n\n/**\n * Cloudflare D1 Database binding type\n */\nexport interface D1Database {\n prepare(query: string): D1PreparedStatement;\n batch<T>(statements: D1PreparedStatement[]): Promise<D1Result<T>[]>;\n dump(): Promise<ArrayBuffer>;\n exec<T>(query: string): Promise<D1Result<T>>;\n}\n\ninterface D1PreparedStatement {\n bind(...values: unknown[]): D1PreparedStatement;\n first<T = unknown>(column?: string): Promise<T | null>;\n run<T = unknown>(): Promise<D1Result<T>>;\n all<T = unknown>(): Promise<D1Result<T>>;\n raw<T = unknown>(): Promise<T[]>;\n}\n\ninterface D1Result<T> {\n results?: T[];\n success: boolean;\n error?: string;\n meta?: D1Meta;\n}\n\ninterface D1Meta {\n duration: number;\n rows_read: number;\n rows_written: number;\n}\n\n/**\n * Combined database configuration\n */\nexport type DatabaseConfig = PostgresConfig | NeonConfig | D1Config;\n\n/**\n * Migration status\n */\nexport interface MigrationStatus {\n /** Whether migrations need to be run */\n needsMigration: boolean;\n /** Whether database is up to date */\n upToDate: boolean;\n /** Number of pending migrations */\n pendingCount: number;\n /** Number of applied migrations */\n appliedCount: number;\n /** Error message if check failed */\n error?: string | undefined;\n}\n\n/**\n * Migration result\n */\nexport interface MigrationResult {\n /** Whether migration succeeded */\n success: boolean;\n /** Number of migrations applied */\n appliedCount?: number | undefined;\n /** Error message if migration failed */\n error?: string | undefined;\n}\n\n/**\n * Transaction options\n */\nexport interface TransactionOptions {\n /** Isolation level */\n isolationLevel?: \"read uncommitted\" | \"read committed\" | \"repeatable read\" | \"serializable\" | undefined;\n /** Access mode */\n accessMode?: \"read only\" | \"read write\" | undefined;\n /** Deferrable (PostgreSQL) */\n deferrable?: boolean | undefined;\n}\n\n/**\n * Query options\n */\nexport interface QueryOptions {\n /** Query timeout in milliseconds */\n timeout?: number | undefined;\n /** Transform result rows */\n transform?: \"camelCase\" | \"snakeCase\" | undefined;\n}\n\n/**\n * Database health status\n */\nexport interface DatabaseHealth {\n /** Whether database is healthy */\n healthy: boolean;\n /** Connection latency in milliseconds */\n latencyMs: number;\n /** Database version */\n version?: string | undefined;\n /** Error message if unhealthy */\n error?: string | undefined;\n}\n\n/**\n * Database adapter interface\n */\nexport interface DatabaseAdapter {\n /** Adapter type */\n readonly type: DatabaseAdapterType;\n\n /**\n * Execute raw SQL query\n */\n execute<T = unknown>(sql: string): Promise<T[]>;\n\n /**\n * Check connection health\n */\n ping(): Promise<boolean>;\n\n /**\n * Get connection health with details\n */\n health(): Promise<DatabaseHealth>;\n\n /**\n * Get the underlying Drizzle instance\n */\n drizzle(): unknown;\n\n /**\n * Close database connection\n */\n close(): Promise<void>;\n}\n\n/**\n * Database error\n */\nexport class DatabaseError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"DatabaseError\";\n }\n}\n\n/**\n * Common database error codes\n */\nexport const DatabaseErrorCodes = {\n CONNECTION_FAILED: \"CONNECTION_FAILED\",\n QUERY_FAILED: \"QUERY_FAILED\",\n TRANSACTION_FAILED: \"TRANSACTION_FAILED\",\n MIGRATION_FAILED: \"MIGRATION_FAILED\",\n INVALID_CONFIG: \"INVALID_CONFIG\",\n ADAPTER_NOT_AVAILABLE: \"ADAPTER_NOT_AVAILABLE\",\n TIMEOUT: \"TIMEOUT\",\n CONSTRAINT_VIOLATION: \"CONSTRAINT_VIOLATION\",\n NOT_FOUND: \"NOT_FOUND\",\n} as const;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,59 @@
1
+ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
2
+ import { a as DatabaseAdapter, P as PostgresConfig, f as DatabaseHealth } from '../types-DgBIyTeZ.js';
3
+
4
+ /**
5
+ * @parsrun/database - PostgreSQL Adapter
6
+ * PostgreSQL adapter using postgres.js
7
+ */
8
+
9
+ /**
10
+ * PostgreSQL Database Adapter
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const db = await createPostgresAdapter({
15
+ * type: 'postgres',
16
+ * host: 'localhost',
17
+ * port: 5432,
18
+ * user: 'postgres',
19
+ * password: 'password',
20
+ * database: 'mydb',
21
+ * });
22
+ *
23
+ * // Execute queries
24
+ * const users = await db.drizzle().select().from(usersTable);
25
+ *
26
+ * // Close when done
27
+ * await db.close();
28
+ * ```
29
+ */
30
+ declare class PostgresAdapter implements DatabaseAdapter {
31
+ readonly type: "postgres";
32
+ private client;
33
+ private db;
34
+ private config;
35
+ constructor(config: PostgresConfig);
36
+ /**
37
+ * Initialize the connection
38
+ */
39
+ connect(): Promise<void>;
40
+ execute<T = unknown>(sql: string): Promise<T[]>;
41
+ ping(): Promise<boolean>;
42
+ health(): Promise<DatabaseHealth>;
43
+ drizzle(): PostgresJsDatabase<any>;
44
+ close(): Promise<void>;
45
+ /**
46
+ * Get the raw postgres client
47
+ */
48
+ getClient(): unknown;
49
+ }
50
+ /**
51
+ * Create a PostgreSQL adapter
52
+ */
53
+ declare function createPostgresAdapter(config: PostgresConfig): Promise<PostgresAdapter>;
54
+ /**
55
+ * Create a PostgreSQL adapter from connection string
56
+ */
57
+ declare function createPostgresFromUrl(connectionString: string, options?: Omit<PostgresConfig, "type" | "host" | "port" | "user" | "password" | "database">): Promise<PostgresAdapter>;
58
+
59
+ export { PostgresAdapter, createPostgresAdapter, createPostgresFromUrl };