@shogo-ai/db 1.4.1

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 Shogo Technologies, Inc.
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,24 @@
1
+ <!-- SPDX-License-Identifier: MIT -->
2
+ <!-- Copyright (C) 2026 Shogo Technologies, Inc. -->
3
+
4
+ # @shogo-ai/db
5
+
6
+ Prisma adapter helpers — auto-detects PostgreSQL/SQLite/libSQL from
7
+ `DATABASE_URL` and wires up the right driver. The actual Prisma client
8
+ generation stays your project's concern; this package just gives you a
9
+ one-line `createPrismaClient(PrismaClient)` factory.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ bun add @shogo-ai/db @prisma/client
15
+ # Plus the adapter you actually use:
16
+ bun add @prisma/adapter-pg # for postgres://...
17
+ bun add @prisma/adapter-libsql # for file://... or libsql://...
18
+ ```
19
+
20
+ Adapters are optional peers — install only the ones you need.
21
+
22
+ ## License
23
+
24
+ MIT — see [LICENSE](./LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ createAdapterSync: () => createAdapterSync,
34
+ createDatabaseAdapter: () => createDatabaseAdapter,
35
+ createPrismaClient: () => createPrismaClient,
36
+ createPrismaClientSync: () => createPrismaClientSync,
37
+ detectProvider: () => detectProvider,
38
+ detectSchemaProvider: () => detectSchemaProvider,
39
+ getCurrentProvider: () => getCurrentProvider,
40
+ getTestDatabaseUrl: () => getTestDatabaseUrl,
41
+ isPostgres: () => isPostgres,
42
+ isTestMode: () => isTestMode,
43
+ restoreSchema: () => restoreSchema,
44
+ transformSchema: () => transformSchema,
45
+ transformSchemaFile: () => transformSchemaFile
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/adapters.ts
50
+ function detectProvider(url) {
51
+ const envProvider = process.env.DATABASE_PROVIDER?.toLowerCase();
52
+ if (envProvider === "sqlite") return "sqlite";
53
+ if (envProvider === "postgresql" || envProvider === "postgres") return "postgresql";
54
+ const connectionUrl = url ?? process.env.DATABASE_URL ?? "";
55
+ if (connectionUrl.startsWith("file:") || connectionUrl.endsWith(".db")) {
56
+ return "sqlite";
57
+ }
58
+ if (connectionUrl.startsWith("postgres://") || connectionUrl.startsWith("postgresql://")) {
59
+ return "postgresql";
60
+ }
61
+ return "postgresql";
62
+ }
63
+ async function createDatabaseAdapter(config = "auto") {
64
+ const options = typeof config === "string" ? { provider: config } : config;
65
+ const url = options.url ?? process.env.DATABASE_URL ?? "";
66
+ const provider = options.provider === "auto" || !options.provider ? detectProvider(url) : options.provider;
67
+ console.log(`[shogo/db] Creating ${provider} adapter`);
68
+ if (provider === "sqlite") {
69
+ return createSqliteAdapter(url || "file:./dev.db");
70
+ } else {
71
+ return createPostgresAdapter(url);
72
+ }
73
+ }
74
+ async function createPostgresAdapter(connectionString) {
75
+ try {
76
+ const module2 = await import("@prisma/adapter-pg");
77
+ const PrismaPg = module2.PrismaPg || module2.default?.PrismaPg;
78
+ return new PrismaPg({ connectionString });
79
+ } catch (error) {
80
+ throw new Error(
81
+ "Failed to create PostgreSQL adapter. Make sure @prisma/adapter-pg is installed.\nRun: bun add @prisma/adapter-pg"
82
+ );
83
+ }
84
+ }
85
+ async function createSqliteAdapter(url) {
86
+ try {
87
+ const module2 = await import("@prisma/adapter-libsql");
88
+ const PrismaLibSql = module2.PrismaLibSql || module2.default?.PrismaLibSql;
89
+ return new PrismaLibSql({ url });
90
+ } catch (error) {
91
+ throw new Error(
92
+ "Failed to create SQLite adapter. Make sure @prisma/adapter-libsql is installed.\nRun: bun add @prisma/adapter-libsql"
93
+ );
94
+ }
95
+ }
96
+ var globalForPrisma = globalThis;
97
+ async function createPrismaClient(PrismaClientClass, config = {}) {
98
+ if (globalForPrisma.__shogo_prisma) {
99
+ return globalForPrisma.__shogo_prisma;
100
+ }
101
+ const adapter = await createDatabaseAdapter(config);
102
+ const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
103
+ const client = new PrismaClientClass({
104
+ adapter,
105
+ log
106
+ });
107
+ if (process.env.NODE_ENV !== "production") {
108
+ globalForPrisma.__shogo_prisma = client;
109
+ }
110
+ return client;
111
+ }
112
+ function createAdapterSync(config = {}) {
113
+ const url = config.url ?? process.env.DATABASE_URL ?? "";
114
+ const provider = config.provider === "auto" || !config.provider ? detectProvider(url) : config.provider;
115
+ console.log(`[shogo/db] Creating ${provider} adapter (sync)`);
116
+ if (provider === "sqlite") {
117
+ try {
118
+ const module2 = require("@prisma/adapter-libsql");
119
+ const PrismaLibSql = module2.PrismaLibSql || module2.default?.PrismaLibSql;
120
+ return new PrismaLibSql({ url: url || "file:./dev.db" });
121
+ } catch {
122
+ throw new Error(
123
+ "SQLite adapter not found. Install it with: bun add @prisma/adapter-libsql"
124
+ );
125
+ }
126
+ } else {
127
+ try {
128
+ const module2 = require("@prisma/adapter-pg");
129
+ const PrismaPg = module2.PrismaPg || module2.default?.PrismaPg;
130
+ return new PrismaPg({ connectionString: url });
131
+ } catch {
132
+ throw new Error(
133
+ "PostgreSQL adapter not found. Install it with: bun add @prisma/adapter-pg"
134
+ );
135
+ }
136
+ }
137
+ }
138
+ function createPrismaClientSync(PrismaClientClass, config = {}) {
139
+ if (globalForPrisma.__shogo_prisma) {
140
+ return globalForPrisma.__shogo_prisma;
141
+ }
142
+ const adapter = createAdapterSync(config);
143
+ const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
144
+ const client = new PrismaClientClass({
145
+ adapter,
146
+ log
147
+ });
148
+ if (process.env.NODE_ENV !== "production") {
149
+ globalForPrisma.__shogo_prisma = client;
150
+ }
151
+ return client;
152
+ }
153
+ function isTestMode() {
154
+ return detectProvider() === "sqlite";
155
+ }
156
+ function isPostgres() {
157
+ return detectProvider() === "postgresql";
158
+ }
159
+ function getTestDatabaseUrl() {
160
+ return "file:./test.db";
161
+ }
162
+ function getCurrentProvider() {
163
+ return detectProvider();
164
+ }
165
+
166
+ // src/schema-transformer.ts
167
+ var import_fs = require("fs");
168
+ var import_child_process = require("child_process");
169
+ var import_path = require("path");
170
+ var POSTGRES_TO_SQLITE_TRANSFORMS = [
171
+ // uuid() is PostgreSQL-specific, use cuid() for compatibility
172
+ { pattern: /@default\(uuid\(\)\)/g, replacement: "@default(cuid())" },
173
+ // dbgenerated() with PostgreSQL-specific functions
174
+ { pattern: /@default\(dbgenerated\("gen_random_uuid\(\)"\)\)/g, replacement: "@default(cuid())" },
175
+ // auto() is PostgreSQL-specific for autoincrement
176
+ { pattern: /@default\(auto\(\)\)/g, replacement: "@default(autoincrement())" },
177
+ // Remove @db.* native type annotations (SQLite doesn't support these)
178
+ { pattern: /@db\.\w+(\([^)]*\))?/g, replacement: "" }
179
+ ];
180
+ var SQLITE_TO_POSTGRES_TRANSFORMS = [
181
+ // autoincrement() is SQLite-specific, use auto() for PostgreSQL
182
+ { pattern: /@default\(autoincrement\(\)\)/g, replacement: "@default(auto())" }
183
+ ];
184
+ function detectSchemaProvider(schemaContent) {
185
+ if (schemaContent.includes('provider = "postgresql"') || schemaContent.includes("provider = 'postgresql'")) {
186
+ return "postgresql";
187
+ }
188
+ if (schemaContent.includes('provider = "sqlite"') || schemaContent.includes("provider = 'sqlite'")) {
189
+ return "sqlite";
190
+ }
191
+ return null;
192
+ }
193
+ function transformSchema(schemaContent, targetProvider) {
194
+ const currentProvider = detectSchemaProvider(schemaContent);
195
+ const warnings = [];
196
+ if (currentProvider === targetProvider) {
197
+ return { content: schemaContent, warnings: [] };
198
+ }
199
+ let result = schemaContent;
200
+ if (targetProvider === "sqlite") {
201
+ result = result.replace(/provider\s*=\s*"postgresql"/g, 'provider = "sqlite"');
202
+ } else {
203
+ result = result.replace(/provider\s*=\s*"sqlite"/g, 'provider = "postgresql"');
204
+ }
205
+ const transforms = targetProvider === "sqlite" ? POSTGRES_TO_SQLITE_TRANSFORMS : SQLITE_TO_POSTGRES_TRANSFORMS;
206
+ for (const { pattern, replacement } of transforms) {
207
+ const matches = result.match(pattern);
208
+ if (matches && matches.length > 0) {
209
+ if (pattern.source.includes("db\\.")) {
210
+ warnings.push(`Removed PostgreSQL-specific @db.* annotations for SQLite`);
211
+ }
212
+ result = result.replace(pattern, replacement);
213
+ }
214
+ }
215
+ result = result.replace(/ +/g, " ");
216
+ return { content: result, warnings };
217
+ }
218
+ async function transformSchemaFile(options) {
219
+ const {
220
+ schemaPath,
221
+ targetProvider,
222
+ generate = true,
223
+ push = false,
224
+ databaseUrl,
225
+ verbose = false
226
+ } = options;
227
+ const absolutePath = (0, import_path.resolve)(process.cwd(), schemaPath);
228
+ if (!(0, import_fs.existsSync)(absolutePath)) {
229
+ throw new Error(`Schema file not found: ${absolutePath}`);
230
+ }
231
+ const originalContent = (0, import_fs.readFileSync)(absolutePath, "utf-8");
232
+ const originalProvider = detectSchemaProvider(originalContent);
233
+ if (!originalProvider) {
234
+ throw new Error("Could not detect database provider in schema");
235
+ }
236
+ const { content: newContent, warnings } = transformSchema(originalContent, targetProvider);
237
+ const modified = newContent !== originalContent;
238
+ if (modified) {
239
+ (0, import_fs.writeFileSync)(absolutePath, newContent, "utf-8");
240
+ if (verbose) {
241
+ console.log(`Transformed schema from ${originalProvider} to ${targetProvider}`);
242
+ }
243
+ } else if (verbose) {
244
+ console.log(`Schema already using ${targetProvider} provider`);
245
+ }
246
+ const env = { ...process.env };
247
+ if (targetProvider === "sqlite") {
248
+ env.DATABASE_URL = databaseUrl || "file:./test.db";
249
+ } else if (databaseUrl) {
250
+ env.DATABASE_URL = databaseUrl;
251
+ }
252
+ const schemaDir = (0, import_path.dirname)(absolutePath);
253
+ if (generate) {
254
+ if (verbose) {
255
+ console.log("Running prisma generate...");
256
+ }
257
+ try {
258
+ (0, import_child_process.execSync)("bun x prisma generate", {
259
+ cwd: schemaDir,
260
+ env,
261
+ stdio: verbose ? "inherit" : "pipe"
262
+ });
263
+ } catch (error) {
264
+ throw new Error(`prisma generate failed: ${error}`);
265
+ }
266
+ }
267
+ if (push) {
268
+ if (verbose) {
269
+ console.log("Running prisma db push...");
270
+ }
271
+ try {
272
+ (0, import_child_process.execSync)("bun x prisma db push", {
273
+ cwd: schemaDir,
274
+ env,
275
+ stdio: verbose ? "inherit" : "pipe"
276
+ });
277
+ } catch (error) {
278
+ throw new Error(`prisma db push failed: ${error}`);
279
+ }
280
+ }
281
+ return {
282
+ modified,
283
+ originalProvider,
284
+ newProvider: targetProvider,
285
+ schemaPath: absolutePath,
286
+ warnings
287
+ };
288
+ }
289
+ async function restoreSchema(schemaPath, verbose = false) {
290
+ await transformSchemaFile({
291
+ schemaPath,
292
+ targetProvider: "postgresql",
293
+ generate: true,
294
+ push: false,
295
+ verbose
296
+ });
297
+ }
298
+ // Annotate the CommonJS export names for ESM import in node:
299
+ 0 && (module.exports = {
300
+ createAdapterSync,
301
+ createDatabaseAdapter,
302
+ createPrismaClient,
303
+ createPrismaClientSync,
304
+ detectProvider,
305
+ detectSchemaProvider,
306
+ getCurrentProvider,
307
+ getTestDatabaseUrl,
308
+ isPostgres,
309
+ isTestMode,
310
+ restoreSchema,
311
+ transformSchema,
312
+ transformSchemaFile
313
+ });
314
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Shogo Database Adapters
3
+ *
4
+ * Provides flexible database adapter support for Prisma.
5
+ * Allows easy switching between PostgreSQL (production) and SQLite (testing/development).
6
+ *
7
+ * The adapter auto-detects the database type from DATABASE_URL or DATABASE_PROVIDER,
8
+ * making it easy to run the same code against different databases.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // In your src/lib/db.ts
13
+ * import { createPrismaClient } from '@shogo-ai/sdk/db'
14
+ * import { PrismaClient } from '../generated/prisma/client'
15
+ *
16
+ * // Auto-detects PostgreSQL vs SQLite based on DATABASE_URL
17
+ * export const prisma = await createPrismaClient(PrismaClient)
18
+ *
19
+ * // For testing with SQLite:
20
+ * // DATABASE_URL=file:./test.db bun test
21
+ * ```
22
+ */
23
+ type DatabaseProvider$1 = 'postgresql' | 'sqlite' | 'auto';
24
+ interface DatabaseAdapterConfig {
25
+ /**
26
+ * Database provider to use
27
+ * - 'postgresql': Use PostgreSQL adapter (requires @prisma/adapter-pg)
28
+ * - 'sqlite': Use SQLite adapter (requires @prisma/adapter-libsql)
29
+ * - 'auto': Auto-detect based on DATABASE_PROVIDER env var or DATABASE_URL format
30
+ */
31
+ provider?: DatabaseProvider$1;
32
+ /**
33
+ * Connection string (defaults to DATABASE_URL env var)
34
+ */
35
+ url?: string;
36
+ /**
37
+ * Prisma log levels
38
+ */
39
+ log?: ('query' | 'info' | 'warn' | 'error')[];
40
+ }
41
+ /**
42
+ * Detect database provider from connection string
43
+ */
44
+ declare function detectProvider(url?: string): 'postgresql' | 'sqlite';
45
+ /**
46
+ * Create a database adapter based on configuration
47
+ *
48
+ * @param config - Configuration options or provider string
49
+ * @returns Promise resolving to the appropriate Prisma adapter
50
+ */
51
+ declare function createDatabaseAdapter(config?: DatabaseAdapterConfig | DatabaseProvider$1): Promise<any>;
52
+ /**
53
+ * Create a Prisma client with auto-detected adapter (async)
54
+ *
55
+ * This is the main entry point for database access. It:
56
+ * 1. Auto-detects PostgreSQL vs SQLite from DATABASE_URL
57
+ * 2. Creates the appropriate adapter
58
+ * 3. Caches the client globally to prevent connection exhaustion
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * import { createPrismaClient } from '@shogo-ai/sdk/db'
63
+ * import { PrismaClient } from '../generated/prisma/client'
64
+ *
65
+ * export const prisma = await createPrismaClient(PrismaClient)
66
+ * ```
67
+ */
68
+ declare function createPrismaClient<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): Promise<T>;
69
+ /**
70
+ * Create a database adapter synchronously (uses require)
71
+ *
72
+ * This is useful when you need synchronous initialization.
73
+ * Falls back gracefully if the adapter package is not installed.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { createAdapterSync } from '@shogo-ai/sdk/db'
78
+ * import { PrismaClient } from '../generated/prisma/client'
79
+ *
80
+ * const adapter = createAdapterSync()
81
+ * export const prisma = new PrismaClient({ adapter })
82
+ * ```
83
+ */
84
+ declare function createAdapterSync(config?: DatabaseAdapterConfig): any;
85
+ /**
86
+ * Create a Prisma client synchronously with auto-detected adapter
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * import { createPrismaClientSync } from '@shogo-ai/sdk/db'
91
+ * import { PrismaClient } from '../generated/prisma/client'
92
+ *
93
+ * export const prisma = createPrismaClientSync(PrismaClient)
94
+ * ```
95
+ */
96
+ declare function createPrismaClientSync<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): T;
97
+ /**
98
+ * Check if running in test/SQLite mode
99
+ */
100
+ declare function isTestMode(): boolean;
101
+ /**
102
+ * Check if running with PostgreSQL
103
+ */
104
+ declare function isPostgres(): boolean;
105
+ /**
106
+ * Get recommended DATABASE_URL for testing with SQLite
107
+ */
108
+ declare function getTestDatabaseUrl(): string;
109
+ /**
110
+ * Get the current database provider
111
+ */
112
+ declare function getCurrentProvider(): DatabaseProvider$1;
113
+
114
+ /**
115
+ * Prisma Schema Transformer
116
+ *
117
+ * Transforms Prisma schemas between PostgreSQL and SQLite providers,
118
+ * handling dialect-specific differences.
119
+ *
120
+ * This enables a workflow where:
121
+ * - Production uses PostgreSQL
122
+ * - Tests can run with SQLite (fast, no infrastructure)
123
+ * - Tests can also run with PostgreSQL (for integration testing)
124
+ */
125
+ type DatabaseProvider = 'postgresql' | 'sqlite';
126
+ interface TransformOptions {
127
+ /** Path to the Prisma schema file */
128
+ schemaPath: string;
129
+ /** Target database provider */
130
+ targetProvider: DatabaseProvider;
131
+ /** Run prisma generate after transformation */
132
+ generate?: boolean;
133
+ /** Run prisma db push after transformation (useful for SQLite) */
134
+ push?: boolean;
135
+ /** DATABASE_URL to use (defaults to file:./test.db for SQLite) */
136
+ databaseUrl?: string;
137
+ /** Print verbose output */
138
+ verbose?: boolean;
139
+ }
140
+ interface TransformResult {
141
+ /** Whether the schema was modified */
142
+ modified: boolean;
143
+ /** The original provider */
144
+ originalProvider: DatabaseProvider;
145
+ /** The new provider */
146
+ newProvider: DatabaseProvider;
147
+ /** Path to the schema file */
148
+ schemaPath: string;
149
+ /** Any warnings generated during transformation */
150
+ warnings: string[];
151
+ }
152
+ /**
153
+ * Detect the current provider in a schema
154
+ */
155
+ declare function detectSchemaProvider(schemaContent: string): DatabaseProvider | null;
156
+ /**
157
+ * Transform a Prisma schema from one provider to another
158
+ */
159
+ declare function transformSchema(schemaContent: string, targetProvider: DatabaseProvider): {
160
+ content: string;
161
+ warnings: string[];
162
+ };
163
+ /**
164
+ * Transform schema and optionally run Prisma commands
165
+ */
166
+ declare function transformSchemaFile(options: TransformOptions): Promise<TransformResult>;
167
+ /**
168
+ * Restore schema to PostgreSQL (the canonical provider)
169
+ */
170
+ declare function restoreSchema(schemaPath: string, verbose?: boolean): Promise<void>;
171
+
172
+ export { type DatabaseAdapterConfig, type DatabaseProvider$1 as DatabaseProvider, type TransformOptions, type TransformResult, createAdapterSync, createDatabaseAdapter, createPrismaClient, createPrismaClientSync, detectProvider, detectSchemaProvider, getCurrentProvider, getTestDatabaseUrl, isPostgres, isTestMode, restoreSchema, transformSchema, transformSchemaFile };
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Shogo Database Adapters
3
+ *
4
+ * Provides flexible database adapter support for Prisma.
5
+ * Allows easy switching between PostgreSQL (production) and SQLite (testing/development).
6
+ *
7
+ * The adapter auto-detects the database type from DATABASE_URL or DATABASE_PROVIDER,
8
+ * making it easy to run the same code against different databases.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // In your src/lib/db.ts
13
+ * import { createPrismaClient } from '@shogo-ai/sdk/db'
14
+ * import { PrismaClient } from '../generated/prisma/client'
15
+ *
16
+ * // Auto-detects PostgreSQL vs SQLite based on DATABASE_URL
17
+ * export const prisma = await createPrismaClient(PrismaClient)
18
+ *
19
+ * // For testing with SQLite:
20
+ * // DATABASE_URL=file:./test.db bun test
21
+ * ```
22
+ */
23
+ type DatabaseProvider$1 = 'postgresql' | 'sqlite' | 'auto';
24
+ interface DatabaseAdapterConfig {
25
+ /**
26
+ * Database provider to use
27
+ * - 'postgresql': Use PostgreSQL adapter (requires @prisma/adapter-pg)
28
+ * - 'sqlite': Use SQLite adapter (requires @prisma/adapter-libsql)
29
+ * - 'auto': Auto-detect based on DATABASE_PROVIDER env var or DATABASE_URL format
30
+ */
31
+ provider?: DatabaseProvider$1;
32
+ /**
33
+ * Connection string (defaults to DATABASE_URL env var)
34
+ */
35
+ url?: string;
36
+ /**
37
+ * Prisma log levels
38
+ */
39
+ log?: ('query' | 'info' | 'warn' | 'error')[];
40
+ }
41
+ /**
42
+ * Detect database provider from connection string
43
+ */
44
+ declare function detectProvider(url?: string): 'postgresql' | 'sqlite';
45
+ /**
46
+ * Create a database adapter based on configuration
47
+ *
48
+ * @param config - Configuration options or provider string
49
+ * @returns Promise resolving to the appropriate Prisma adapter
50
+ */
51
+ declare function createDatabaseAdapter(config?: DatabaseAdapterConfig | DatabaseProvider$1): Promise<any>;
52
+ /**
53
+ * Create a Prisma client with auto-detected adapter (async)
54
+ *
55
+ * This is the main entry point for database access. It:
56
+ * 1. Auto-detects PostgreSQL vs SQLite from DATABASE_URL
57
+ * 2. Creates the appropriate adapter
58
+ * 3. Caches the client globally to prevent connection exhaustion
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * import { createPrismaClient } from '@shogo-ai/sdk/db'
63
+ * import { PrismaClient } from '../generated/prisma/client'
64
+ *
65
+ * export const prisma = await createPrismaClient(PrismaClient)
66
+ * ```
67
+ */
68
+ declare function createPrismaClient<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): Promise<T>;
69
+ /**
70
+ * Create a database adapter synchronously (uses require)
71
+ *
72
+ * This is useful when you need synchronous initialization.
73
+ * Falls back gracefully if the adapter package is not installed.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * import { createAdapterSync } from '@shogo-ai/sdk/db'
78
+ * import { PrismaClient } from '../generated/prisma/client'
79
+ *
80
+ * const adapter = createAdapterSync()
81
+ * export const prisma = new PrismaClient({ adapter })
82
+ * ```
83
+ */
84
+ declare function createAdapterSync(config?: DatabaseAdapterConfig): any;
85
+ /**
86
+ * Create a Prisma client synchronously with auto-detected adapter
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * import { createPrismaClientSync } from '@shogo-ai/sdk/db'
91
+ * import { PrismaClient } from '../generated/prisma/client'
92
+ *
93
+ * export const prisma = createPrismaClientSync(PrismaClient)
94
+ * ```
95
+ */
96
+ declare function createPrismaClientSync<T>(PrismaClientClass: new (options: any) => T, config?: DatabaseAdapterConfig): T;
97
+ /**
98
+ * Check if running in test/SQLite mode
99
+ */
100
+ declare function isTestMode(): boolean;
101
+ /**
102
+ * Check if running with PostgreSQL
103
+ */
104
+ declare function isPostgres(): boolean;
105
+ /**
106
+ * Get recommended DATABASE_URL for testing with SQLite
107
+ */
108
+ declare function getTestDatabaseUrl(): string;
109
+ /**
110
+ * Get the current database provider
111
+ */
112
+ declare function getCurrentProvider(): DatabaseProvider$1;
113
+
114
+ /**
115
+ * Prisma Schema Transformer
116
+ *
117
+ * Transforms Prisma schemas between PostgreSQL and SQLite providers,
118
+ * handling dialect-specific differences.
119
+ *
120
+ * This enables a workflow where:
121
+ * - Production uses PostgreSQL
122
+ * - Tests can run with SQLite (fast, no infrastructure)
123
+ * - Tests can also run with PostgreSQL (for integration testing)
124
+ */
125
+ type DatabaseProvider = 'postgresql' | 'sqlite';
126
+ interface TransformOptions {
127
+ /** Path to the Prisma schema file */
128
+ schemaPath: string;
129
+ /** Target database provider */
130
+ targetProvider: DatabaseProvider;
131
+ /** Run prisma generate after transformation */
132
+ generate?: boolean;
133
+ /** Run prisma db push after transformation (useful for SQLite) */
134
+ push?: boolean;
135
+ /** DATABASE_URL to use (defaults to file:./test.db for SQLite) */
136
+ databaseUrl?: string;
137
+ /** Print verbose output */
138
+ verbose?: boolean;
139
+ }
140
+ interface TransformResult {
141
+ /** Whether the schema was modified */
142
+ modified: boolean;
143
+ /** The original provider */
144
+ originalProvider: DatabaseProvider;
145
+ /** The new provider */
146
+ newProvider: DatabaseProvider;
147
+ /** Path to the schema file */
148
+ schemaPath: string;
149
+ /** Any warnings generated during transformation */
150
+ warnings: string[];
151
+ }
152
+ /**
153
+ * Detect the current provider in a schema
154
+ */
155
+ declare function detectSchemaProvider(schemaContent: string): DatabaseProvider | null;
156
+ /**
157
+ * Transform a Prisma schema from one provider to another
158
+ */
159
+ declare function transformSchema(schemaContent: string, targetProvider: DatabaseProvider): {
160
+ content: string;
161
+ warnings: string[];
162
+ };
163
+ /**
164
+ * Transform schema and optionally run Prisma commands
165
+ */
166
+ declare function transformSchemaFile(options: TransformOptions): Promise<TransformResult>;
167
+ /**
168
+ * Restore schema to PostgreSQL (the canonical provider)
169
+ */
170
+ declare function restoreSchema(schemaPath: string, verbose?: boolean): Promise<void>;
171
+
172
+ export { type DatabaseAdapterConfig, type DatabaseProvider$1 as DatabaseProvider, type TransformOptions, type TransformResult, createAdapterSync, createDatabaseAdapter, createPrismaClient, createPrismaClientSync, detectProvider, detectSchemaProvider, getCurrentProvider, getTestDatabaseUrl, isPostgres, isTestMode, restoreSchema, transformSchema, transformSchemaFile };
package/dist/index.js ADDED
@@ -0,0 +1,272 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/adapters.ts
9
+ function detectProvider(url) {
10
+ const envProvider = process.env.DATABASE_PROVIDER?.toLowerCase();
11
+ if (envProvider === "sqlite") return "sqlite";
12
+ if (envProvider === "postgresql" || envProvider === "postgres") return "postgresql";
13
+ const connectionUrl = url ?? process.env.DATABASE_URL ?? "";
14
+ if (connectionUrl.startsWith("file:") || connectionUrl.endsWith(".db")) {
15
+ return "sqlite";
16
+ }
17
+ if (connectionUrl.startsWith("postgres://") || connectionUrl.startsWith("postgresql://")) {
18
+ return "postgresql";
19
+ }
20
+ return "postgresql";
21
+ }
22
+ async function createDatabaseAdapter(config = "auto") {
23
+ const options = typeof config === "string" ? { provider: config } : config;
24
+ const url = options.url ?? process.env.DATABASE_URL ?? "";
25
+ const provider = options.provider === "auto" || !options.provider ? detectProvider(url) : options.provider;
26
+ console.log(`[shogo/db] Creating ${provider} adapter`);
27
+ if (provider === "sqlite") {
28
+ return createSqliteAdapter(url || "file:./dev.db");
29
+ } else {
30
+ return createPostgresAdapter(url);
31
+ }
32
+ }
33
+ async function createPostgresAdapter(connectionString) {
34
+ try {
35
+ const module = await import("@prisma/adapter-pg");
36
+ const PrismaPg = module.PrismaPg || module.default?.PrismaPg;
37
+ return new PrismaPg({ connectionString });
38
+ } catch (error) {
39
+ throw new Error(
40
+ "Failed to create PostgreSQL adapter. Make sure @prisma/adapter-pg is installed.\nRun: bun add @prisma/adapter-pg"
41
+ );
42
+ }
43
+ }
44
+ async function createSqliteAdapter(url) {
45
+ try {
46
+ const module = await import("@prisma/adapter-libsql");
47
+ const PrismaLibSql = module.PrismaLibSql || module.default?.PrismaLibSql;
48
+ return new PrismaLibSql({ url });
49
+ } catch (error) {
50
+ throw new Error(
51
+ "Failed to create SQLite adapter. Make sure @prisma/adapter-libsql is installed.\nRun: bun add @prisma/adapter-libsql"
52
+ );
53
+ }
54
+ }
55
+ var globalForPrisma = globalThis;
56
+ async function createPrismaClient(PrismaClientClass, config = {}) {
57
+ if (globalForPrisma.__shogo_prisma) {
58
+ return globalForPrisma.__shogo_prisma;
59
+ }
60
+ const adapter = await createDatabaseAdapter(config);
61
+ const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
62
+ const client = new PrismaClientClass({
63
+ adapter,
64
+ log
65
+ });
66
+ if (process.env.NODE_ENV !== "production") {
67
+ globalForPrisma.__shogo_prisma = client;
68
+ }
69
+ return client;
70
+ }
71
+ function createAdapterSync(config = {}) {
72
+ const url = config.url ?? process.env.DATABASE_URL ?? "";
73
+ const provider = config.provider === "auto" || !config.provider ? detectProvider(url) : config.provider;
74
+ console.log(`[shogo/db] Creating ${provider} adapter (sync)`);
75
+ if (provider === "sqlite") {
76
+ try {
77
+ const module = __require("@prisma/adapter-libsql");
78
+ const PrismaLibSql = module.PrismaLibSql || module.default?.PrismaLibSql;
79
+ return new PrismaLibSql({ url: url || "file:./dev.db" });
80
+ } catch {
81
+ throw new Error(
82
+ "SQLite adapter not found. Install it with: bun add @prisma/adapter-libsql"
83
+ );
84
+ }
85
+ } else {
86
+ try {
87
+ const module = __require("@prisma/adapter-pg");
88
+ const PrismaPg = module.PrismaPg || module.default?.PrismaPg;
89
+ return new PrismaPg({ connectionString: url });
90
+ } catch {
91
+ throw new Error(
92
+ "PostgreSQL adapter not found. Install it with: bun add @prisma/adapter-pg"
93
+ );
94
+ }
95
+ }
96
+ }
97
+ function createPrismaClientSync(PrismaClientClass, config = {}) {
98
+ if (globalForPrisma.__shogo_prisma) {
99
+ return globalForPrisma.__shogo_prisma;
100
+ }
101
+ const adapter = createAdapterSync(config);
102
+ const log = config.log ?? (process.env.NODE_ENV === "development" ? ["warn", "error"] : ["error"]);
103
+ const client = new PrismaClientClass({
104
+ adapter,
105
+ log
106
+ });
107
+ if (process.env.NODE_ENV !== "production") {
108
+ globalForPrisma.__shogo_prisma = client;
109
+ }
110
+ return client;
111
+ }
112
+ function isTestMode() {
113
+ return detectProvider() === "sqlite";
114
+ }
115
+ function isPostgres() {
116
+ return detectProvider() === "postgresql";
117
+ }
118
+ function getTestDatabaseUrl() {
119
+ return "file:./test.db";
120
+ }
121
+ function getCurrentProvider() {
122
+ return detectProvider();
123
+ }
124
+
125
+ // src/schema-transformer.ts
126
+ import { readFileSync, writeFileSync, existsSync } from "fs";
127
+ import { execSync } from "child_process";
128
+ import { resolve, dirname } from "path";
129
+ var POSTGRES_TO_SQLITE_TRANSFORMS = [
130
+ // uuid() is PostgreSQL-specific, use cuid() for compatibility
131
+ { pattern: /@default\(uuid\(\)\)/g, replacement: "@default(cuid())" },
132
+ // dbgenerated() with PostgreSQL-specific functions
133
+ { pattern: /@default\(dbgenerated\("gen_random_uuid\(\)"\)\)/g, replacement: "@default(cuid())" },
134
+ // auto() is PostgreSQL-specific for autoincrement
135
+ { pattern: /@default\(auto\(\)\)/g, replacement: "@default(autoincrement())" },
136
+ // Remove @db.* native type annotations (SQLite doesn't support these)
137
+ { pattern: /@db\.\w+(\([^)]*\))?/g, replacement: "" }
138
+ ];
139
+ var SQLITE_TO_POSTGRES_TRANSFORMS = [
140
+ // autoincrement() is SQLite-specific, use auto() for PostgreSQL
141
+ { pattern: /@default\(autoincrement\(\)\)/g, replacement: "@default(auto())" }
142
+ ];
143
+ function detectSchemaProvider(schemaContent) {
144
+ if (schemaContent.includes('provider = "postgresql"') || schemaContent.includes("provider = 'postgresql'")) {
145
+ return "postgresql";
146
+ }
147
+ if (schemaContent.includes('provider = "sqlite"') || schemaContent.includes("provider = 'sqlite'")) {
148
+ return "sqlite";
149
+ }
150
+ return null;
151
+ }
152
+ function transformSchema(schemaContent, targetProvider) {
153
+ const currentProvider = detectSchemaProvider(schemaContent);
154
+ const warnings = [];
155
+ if (currentProvider === targetProvider) {
156
+ return { content: schemaContent, warnings: [] };
157
+ }
158
+ let result = schemaContent;
159
+ if (targetProvider === "sqlite") {
160
+ result = result.replace(/provider\s*=\s*"postgresql"/g, 'provider = "sqlite"');
161
+ } else {
162
+ result = result.replace(/provider\s*=\s*"sqlite"/g, 'provider = "postgresql"');
163
+ }
164
+ const transforms = targetProvider === "sqlite" ? POSTGRES_TO_SQLITE_TRANSFORMS : SQLITE_TO_POSTGRES_TRANSFORMS;
165
+ for (const { pattern, replacement } of transforms) {
166
+ const matches = result.match(pattern);
167
+ if (matches && matches.length > 0) {
168
+ if (pattern.source.includes("db\\.")) {
169
+ warnings.push(`Removed PostgreSQL-specific @db.* annotations for SQLite`);
170
+ }
171
+ result = result.replace(pattern, replacement);
172
+ }
173
+ }
174
+ result = result.replace(/ +/g, " ");
175
+ return { content: result, warnings };
176
+ }
177
+ async function transformSchemaFile(options) {
178
+ const {
179
+ schemaPath,
180
+ targetProvider,
181
+ generate = true,
182
+ push = false,
183
+ databaseUrl,
184
+ verbose = false
185
+ } = options;
186
+ const absolutePath = resolve(process.cwd(), schemaPath);
187
+ if (!existsSync(absolutePath)) {
188
+ throw new Error(`Schema file not found: ${absolutePath}`);
189
+ }
190
+ const originalContent = readFileSync(absolutePath, "utf-8");
191
+ const originalProvider = detectSchemaProvider(originalContent);
192
+ if (!originalProvider) {
193
+ throw new Error("Could not detect database provider in schema");
194
+ }
195
+ const { content: newContent, warnings } = transformSchema(originalContent, targetProvider);
196
+ const modified = newContent !== originalContent;
197
+ if (modified) {
198
+ writeFileSync(absolutePath, newContent, "utf-8");
199
+ if (verbose) {
200
+ console.log(`Transformed schema from ${originalProvider} to ${targetProvider}`);
201
+ }
202
+ } else if (verbose) {
203
+ console.log(`Schema already using ${targetProvider} provider`);
204
+ }
205
+ const env = { ...process.env };
206
+ if (targetProvider === "sqlite") {
207
+ env.DATABASE_URL = databaseUrl || "file:./test.db";
208
+ } else if (databaseUrl) {
209
+ env.DATABASE_URL = databaseUrl;
210
+ }
211
+ const schemaDir = dirname(absolutePath);
212
+ if (generate) {
213
+ if (verbose) {
214
+ console.log("Running prisma generate...");
215
+ }
216
+ try {
217
+ execSync("bun x prisma generate", {
218
+ cwd: schemaDir,
219
+ env,
220
+ stdio: verbose ? "inherit" : "pipe"
221
+ });
222
+ } catch (error) {
223
+ throw new Error(`prisma generate failed: ${error}`);
224
+ }
225
+ }
226
+ if (push) {
227
+ if (verbose) {
228
+ console.log("Running prisma db push...");
229
+ }
230
+ try {
231
+ execSync("bun x prisma db push", {
232
+ cwd: schemaDir,
233
+ env,
234
+ stdio: verbose ? "inherit" : "pipe"
235
+ });
236
+ } catch (error) {
237
+ throw new Error(`prisma db push failed: ${error}`);
238
+ }
239
+ }
240
+ return {
241
+ modified,
242
+ originalProvider,
243
+ newProvider: targetProvider,
244
+ schemaPath: absolutePath,
245
+ warnings
246
+ };
247
+ }
248
+ async function restoreSchema(schemaPath, verbose = false) {
249
+ await transformSchemaFile({
250
+ schemaPath,
251
+ targetProvider: "postgresql",
252
+ generate: true,
253
+ push: false,
254
+ verbose
255
+ });
256
+ }
257
+ export {
258
+ createAdapterSync,
259
+ createDatabaseAdapter,
260
+ createPrismaClient,
261
+ createPrismaClientSync,
262
+ detectProvider,
263
+ detectSchemaProvider,
264
+ getCurrentProvider,
265
+ getTestDatabaseUrl,
266
+ isPostgres,
267
+ isTestMode,
268
+ restoreSchema,
269
+ transformSchema,
270
+ transformSchemaFile
271
+ };
272
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@shogo-ai/db",
3
+ "version": "1.4.1",
4
+ "description": "Shogo DB — Prisma adapter helpers for PostgreSQL/SQLite/libSQL with auto-detection from DATABASE_URL.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.cjs",
8
+ "module": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "sideEffects": false,
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist/**/*.js",
20
+ "dist/**/*.cjs",
21
+ "dist/**/*.d.ts",
22
+ "dist/**/*.d.cts"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "typecheck": "tsc --noEmit",
28
+ "test": "bun --no-env-file test src/"
29
+ },
30
+ "peerDependencies": {
31
+ "@prisma/adapter-pg": "^7.3.0",
32
+ "@prisma/adapter-libsql": ">=0.0.0"
33
+ },
34
+ "peerDependenciesMeta": {
35
+ "@prisma/adapter-pg": {
36
+ "optional": true
37
+ },
38
+ "@prisma/adapter-libsql": {
39
+ "optional": true
40
+ }
41
+ },
42
+ "devDependencies": {
43
+ "@prisma/adapter-libsql": "^7.3.0",
44
+ "@types/node": "^25.5.0",
45
+ "tsup": "^8.0.0",
46
+ "typescript": "^6.0.2"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "keywords": [
52
+ "shogo",
53
+ "prisma",
54
+ "postgres",
55
+ "sqlite",
56
+ "libsql"
57
+ ],
58
+ "author": "Shogo Labs",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "git+https://github.com/shogo-labs/shogo-ai.git",
62
+ "directory": "packages/db"
63
+ },
64
+ "homepage": "https://github.com/shogo-labs/shogo-ai/tree/main/packages/db#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/shogo-labs/shogo-ai/issues"
67
+ }
68
+ }