@actuate-media/cli 0.12.0 → 0.12.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @actuate-media/cli@0.12.0 build /home/runner/work/actuatecms/actuatecms/packages/cli
2
+ > @actuate-media/cli@0.12.1 build /home/runner/work/actuatecms/actuatecms/packages/cli
3
3
  > tsc
4
4
 
@@ -1,60 +1,60 @@
1
1
 
2
- > @actuate-media/cli@0.12.0 test /home/runner/work/actuatecms/actuatecms/packages/cli
2
+ > @actuate-media/cli@0.12.1 test /home/runner/work/actuatecms/actuatecms/packages/cli
3
3
  > vitest run
4
4
 
5
5
 
6
6
   RUN  v4.1.8 /home/runner/work/actuatecms/actuatecms/packages/cli
7
7
 
8
- ✓ dist/__tests__/db-sync.test.js (10 tests) 233ms
9
- ✓ dist/__tests__/seed.test.js (10 tests) 128ms
10
- ✓ src/__tests__/db-sync.test.ts (10 tests) 219ms
11
- ✓ dist/__tests__/deployment-diagnostics.test.js (9 tests) 35ms
12
- ✓ src/__tests__/seed.test.ts (10 tests) 164ms
8
+ ✓ dist/__tests__/db-sync.test.js (10 tests) 460ms
9
+ ✓ dist/__tests__/seed.test.js (10 tests) 199ms
10
+ ✓ src/__tests__/db-sync.test.ts (10 tests) 394ms
11
+ ✓ dist/__tests__/deployment-diagnostics.test.js (9 tests) 62ms
12
+ ✓ src/__tests__/seed.test.ts (10 tests) 166ms
13
13
  ✓ src/__tests__/deployment-diagnostics.test.ts (9 tests) 49ms
14
14
  - Reading canonical Actuate schema...
15
- ✔ Actuate CMS models added to schema.
16
- - Running prisma generate...
17
15
  stdout | dist/__tests__/db-init.test.js > db:init (WS-D D5 — canonical schema, no stale fragment) > command > injects canonical models with @@map and no duplicate datasource/generator
16
+ ✔ Actuate CMS models added to schema.
18
17
  ✔ Prisma client generated.
18
+ - Running prisma generate...
19
19
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
20
20
 
21
21
  stdout | dist/__tests__/db-init.test.js > db:init (WS-D D5 — canonical schema, no stale fragment) > command > fails clearly when cms-core cannot be located
22
+ ℹ Install it first: `npm install @actuate-media/cms-core`.
22
23
  - Reading canonical Actuate schema...
23
24
  ✖ Could not locate @actuate-media/cms-core.
24
- ℹ Install it first: `npm install @actuate-media/cms-core`.
25
25
 
26
26
  - Reading canonical Actuate schema...
27
- ✔ Actuate CMS models added to schema.
28
27
  stdout | dist/__tests__/db-init.test.js > db:init (WS-D D5 — canonical schema, no stale fragment) > command > is idempotent without --force
29
28
  ✔ Prisma client generated.
30
- - Running prisma generate...
31
29
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
32
30
 
31
+ ✔ Actuate CMS models added to schema.
32
+ - Running prisma generate...
33
33
  - Reading canonical Actuate schema...
34
34
  ℹ Actuate CMS models already present in schema. Use --force to overwrite.
35
- ✓ dist/__tests__/db-init.test.js (4 tests) 228ms
35
+ ✓ dist/__tests__/db-init.test.js (4 tests) 340ms
36
36
  - Reading canonical Actuate schema...
37
+ ✔ Actuate CMS models added to schema.
38
+ - Running prisma generate...
37
39
  stdout | src/__tests__/db-init.test.ts > db:init (WS-D D5 — canonical schema, no stale fragment) > command > injects canonical models with @@map and no duplicate datasource/generator
38
40
  ✔ Prisma client generated.
39
41
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
40
42
 
41
- ✔ Actuate CMS models added to schema.
42
- - Running prisma generate...
43
43
  - Reading canonical Actuate schema...
44
- stdout | src/__tests__/db-init.test.ts > db:init (WS-D D5 — canonical schema, no stale fragment) > command > fails clearly when cms-core cannot be located
45
44
  ✖ Could not locate @actuate-media/cms-core.
45
+ stdout | src/__tests__/db-init.test.ts > db:init (WS-D D5 — canonical schema, no stale fragment) > command > fails clearly when cms-core cannot be located
46
46
  ℹ Install it first: `npm install @actuate-media/cms-core`.
47
47
 
48
48
  - Reading canonical Actuate schema...
49
49
  stdout | src/__tests__/db-init.test.ts > db:init (WS-D D5 — canonical schema, no stale fragment) > command > is idempotent without --force
50
50
  ✔ Prisma client generated.
51
- ✔ Actuate CMS models added to schema.
52
51
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
53
- - Running prisma generate...
52
+ ✔ Actuate CMS models added to schema.
54
53
 
54
+ - Running prisma generate...
55
55
  - Reading canonical Actuate schema...
56
56
  ℹ Actuate CMS models already present in schema. Use --force to overwrite.
57
- ✓ src/__tests__/db-init.test.ts (4 tests) 246ms
57
+ ✓ src/__tests__/db-init.test.ts (4 tests) 127ms
58
58
  stdout | dist/__tests__/mcp-init.test.js > mcp:init > creates both editor configs with placeholder key and git-ignores them
59
59
  ✔ Created .cursor/mcp.json
60
60
 
@@ -183,7 +183,7 @@ Next steps
183
183
  3. Restart Cursor / VS Code so the MCP server is picked up
184
184
  Tip: pass --url https://your-site.com to target a deployed CMS instead.
185
185
 
186
- ✓ dist/__tests__/mcp-init.test.js (6 tests) 249ms
186
+ ✓ dist/__tests__/mcp-init.test.js (6 tests) 484ms
187
187
  stdout | src/__tests__/mcp-init.test.ts > mcp:init > creates both editor configs with placeholder key and git-ignores them
188
188
  ✔ Created .cursor/mcp.json
189
189
 
@@ -312,34 +312,36 @@ Next steps
312
312
  3. Restart Cursor / VS Code so the MCP server is picked up
313
313
  Tip: pass --url https://your-site.com to target a deployed CMS instead.
314
314
 
315
- ✓ src/__tests__/mcp-init.test.ts (6 tests) 134ms
316
- ✓ dist/__tests__/form-seed.test.js (10 tests) 31ms
317
- ✓ src/__tests__/form-seed.test.ts (10 tests) 34ms
318
- ✓ dist/__tests__/vercel-env-matrix.test.js (6 tests) 28ms
319
- ✓ src/__tests__/vercel-env-matrix.test.ts (6 tests) 30ms
320
- ✓ dist/__tests__/load-dotenv.test.js (3 tests) 37ms
321
- ✓ src/__tests__/load-dotenv.test.ts (3 tests) 44ms
315
+ ✓ src/__tests__/mcp-init.test.ts (6 tests) 429ms
316
+ ✓ dist/__tests__/form-seed.test.js (10 tests) 60ms
317
+ ✓ src/__tests__/form-seed.test.ts (10 tests) 70ms
318
+ ✓ dist/__tests__/prisma-client-path.test.js (6 tests) 68ms
319
+ ✓ src/__tests__/prisma-client-path.test.ts (6 tests) 81ms
320
+ ✓ dist/__tests__/vercel-env-matrix.test.js (6 tests) 95ms
321
+ ✓ src/__tests__/vercel-env-matrix.test.ts (6 tests) 58ms
322
+ ✓ dist/__tests__/load-dotenv.test.js (3 tests) 105ms
323
+ ✓ src/__tests__/load-dotenv.test.ts (3 tests) 116ms
322
324
  - Reading canonical Actuate schema...
323
325
  ✔ Actuate CMS models added to schema.
324
- - Running prisma generate...
325
326
  stdout | dist/__tests__/schema-fragment.test.js > db:init schema fragment > injects all deploy-critical Actuate models
326
327
  ✔ Prisma client generated.
327
328
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
328
329
 
329
- ✓ dist/__tests__/schema-fragment.test.js (1 test) 80ms
330
+ - Running prisma generate...
331
+ ✓ dist/__tests__/schema-fragment.test.js (1 test) 132ms
330
332
  - Reading canonical Actuate schema...
331
333
  ✔ Actuate CMS models added to schema.
334
+ - Running prisma generate...
332
335
  stdout | src/__tests__/schema-fragment.test.ts > db:init schema fragment > injects all deploy-critical Actuate models
333
336
  ✔ Prisma client generated.
334
- - Running prisma generate...
335
337
  ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
336
338
 
337
- ✓ src/__tests__/schema-fragment.test.ts (1 test) 66ms
338
- ✓ dist/__tests__/init.test.js (2 tests) 16ms
339
- ✓ src/__tests__/init.test.ts (2 tests) 15ms
339
+ ✓ src/__tests__/schema-fragment.test.ts (1 test) 123ms
340
+ ✓ dist/__tests__/init.test.js (2 tests) 36ms
341
+ ✓ src/__tests__/init.test.ts (2 tests) 48ms
340
342
 
341
-  Test Files  20 passed (20)
342
-  Tests  122 passed (122)
343
-  Start at  05:27:27
344
-  Duration  21.87s (transform 2.20s, setup 0ms, import 5.83s, tests 2.07s, environment 21ms)
343
+  Test Files  22 passed (22)
344
+  Tests  134 passed (134)
345
+  Start at  17:49:50
346
+  Duration  37.73s (transform 3.12s, setup 0ms, import 8.53s, tests 3.70s, environment 22ms)
345
347
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @actuate-media/cli
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 13aae89: Fix CLI database connection for Prisma 7 projects: resolve custom generator output paths from schema.prisma, prefer lib/prisma.ts getPrisma(), and handle Windows paths for migrate:meta and migrate:schema.
8
+
3
9
  ## 0.12.0
4
10
 
5
11
  ### Minor Changes
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=prisma-client-path.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client-path.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/prisma-client-path.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,66 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import path from 'node:path';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { findPrismaSchemaFile, parsePrismaGeneratorOutputDir, resolveClientEntryInDir, resolveProjectPrismaClientModule, } from '../utils/prisma-client-path.js';
6
+ describe('prisma-client-path', () => {
7
+ let tempDir = null;
8
+ afterEach(() => {
9
+ if (tempDir)
10
+ rmSync(tempDir, { recursive: true, force: true });
11
+ tempDir = null;
12
+ });
13
+ function writeSchema(root, output) {
14
+ mkdirSync(path.join(root, 'prisma'), { recursive: true });
15
+ writeFileSync(path.join(root, 'prisma', 'schema.prisma'), `generator client {
16
+ provider = "prisma-client"
17
+ output = "${output}"
18
+ }
19
+
20
+ datasource db {
21
+ provider = "postgresql"
22
+ }
23
+ `);
24
+ }
25
+ function writeClient(clientPath) {
26
+ mkdirSync(path.dirname(clientPath), { recursive: true });
27
+ writeFileSync(clientPath, 'export class PrismaClient {}');
28
+ }
29
+ it('finds prisma/schema.prisma in the project root', () => {
30
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'));
31
+ writeSchema(tempDir, '../generated/prisma');
32
+ expect(findPrismaSchemaFile(tempDir)).toBe(path.join(tempDir, 'prisma', 'schema.prisma'));
33
+ });
34
+ it('resolves relative generator output from the schema directory', () => {
35
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'));
36
+ writeSchema(tempDir, '../generated/prisma');
37
+ const schemaPath = path.join(tempDir, 'prisma', 'schema.prisma');
38
+ expect(parsePrismaGeneratorOutputDir(schemaPath)).toBe(path.join(tempDir, 'generated', 'prisma'));
39
+ });
40
+ it('resolves custom output paths used by Prisma 7 scaffolds', () => {
41
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'));
42
+ writeSchema(tempDir, '../src/generated/prisma');
43
+ const schemaPath = path.join(tempDir, 'prisma', 'schema.prisma');
44
+ expect(parsePrismaGeneratorOutputDir(schemaPath)).toBe(path.join(tempDir, 'src', 'generated', 'prisma'));
45
+ });
46
+ it('locates client.ts via schema output before default fallbacks', () => {
47
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'));
48
+ writeSchema(tempDir, '../src/generated/prisma');
49
+ const clientPath = path.join(tempDir, 'src', 'generated', 'prisma', 'client.ts');
50
+ writeClient(clientPath);
51
+ expect(resolveProjectPrismaClientModule(tempDir)).toBe(clientPath);
52
+ });
53
+ it('falls back to generated/prisma/client.ts when schema output is missing', () => {
54
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'));
55
+ const clientPath = path.join(tempDir, 'generated', 'prisma', 'client.ts');
56
+ writeClient(clientPath);
57
+ expect(resolveProjectPrismaClientModule(tempDir)).toBe(clientPath);
58
+ });
59
+ it('resolveClientEntryInDir prefers client.ts over index.ts', () => {
60
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-entry-'));
61
+ writeFileSync(path.join(tempDir, 'index.ts'), 'export {}');
62
+ writeFileSync(path.join(tempDir, 'client.ts'), 'export class PrismaClient {}');
63
+ expect(resolveClientEntryInDir(tempDir)).toBe(path.join(tempDir, 'client.ts'));
64
+ });
65
+ });
66
+ //# sourceMappingURL=prisma-client-path.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client-path.test.js","sourceRoot":"","sources":["../../src/__tests__/prisma-client-path.test.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,11 @@
5
5
  * Resolution order mirrors how a scaffolded Actuate project exposes Prisma:
6
6
  * 1. If `cms-core` already has an initialized client (e.g. set up by the host
7
7
  * app in-process), reuse it.
8
- * 2. Otherwise build a client from the project's generated Prisma client
9
- * (`generated/prisma/client.ts`, Prisma 7 + pg driver adapter).
10
- * 3. Fall back to a plain `@prisma/client` resolved from the project.
8
+ * 2. Otherwise call `getPrisma()` from `lib/prisma.ts` when the project ships
9
+ * one (Prisma 7 + pg adapter / Accelerate — same path Next.js uses).
10
+ * 3. Otherwise build a client from the schema's `output` path (custom or
11
+ * default `generated/prisma/client.ts`) via tsx + pg driver adapter.
12
+ * 4. Fall back to a plain `@prisma/client` resolved from the project.
11
13
  *
12
14
  * The returned `disconnect()` only tears down clients this helper created — a
13
15
  * pre-initialized in-process client is left untouched.
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC;IAEtD,EAAE,EAAE,GAAG,CAAA;IACP,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC,CAAC,CAiBD"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC;IAEtD,EAAE,EAAE,GAAG,CAAA;IACP,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAChC,CAAC,CAiBD"}
@@ -1,7 +1,7 @@
1
- import { existsSync } from 'node:fs';
2
1
  import { createRequire } from 'node:module';
3
2
  import path from 'node:path';
4
3
  import { pathToFileURL } from 'node:url';
4
+ import { findLibPrismaHelper, resolveProjectPrismaClientModule } from './prisma-client-path.js';
5
5
  /**
6
6
  * Shared helper for CLI commands that need a live connection to the consumer
7
7
  * project's database (seed, populate, data migrations…).
@@ -9,9 +9,11 @@ import { pathToFileURL } from 'node:url';
9
9
  * Resolution order mirrors how a scaffolded Actuate project exposes Prisma:
10
10
  * 1. If `cms-core` already has an initialized client (e.g. set up by the host
11
11
  * app in-process), reuse it.
12
- * 2. Otherwise build a client from the project's generated Prisma client
13
- * (`generated/prisma/client.ts`, Prisma 7 + pg driver adapter).
14
- * 3. Fall back to a plain `@prisma/client` resolved from the project.
12
+ * 2. Otherwise call `getPrisma()` from `lib/prisma.ts` when the project ships
13
+ * one (Prisma 7 + pg adapter / Accelerate — same path Next.js uses).
14
+ * 3. Otherwise build a client from the schema's `output` path (custom or
15
+ * default `generated/prisma/client.ts`) via tsx + pg driver adapter.
16
+ * 4. Fall back to a plain `@prisma/client` resolved from the project.
15
17
  *
16
18
  * The returned `disconnect()` only tears down clients this helper created — a
17
19
  * pre-initialized in-process client is left untouched.
@@ -32,27 +34,65 @@ export async function connectProjectDatabase() {
32
34
  },
33
35
  };
34
36
  }
37
+ const ACCELERATED_DB_URL_PREFIXES = ['prisma://', 'prisma+postgres://'];
38
+ function isAcceleratedDbUrl(url) {
39
+ const trimmed = url?.trim();
40
+ if (!trimmed)
41
+ return false;
42
+ return ACCELERATED_DB_URL_PREFIXES.some((prefix) => trimmed.startsWith(prefix));
43
+ }
44
+ async function importModule(specifier, requireFromProject) {
45
+ const href = pathToFileURL(requireFromProject.resolve(specifier)).href;
46
+ return import(href);
47
+ }
48
+ async function tryLibPrismaClient() {
49
+ const helperPath = findLibPrismaHelper();
50
+ if (!helperPath)
51
+ return null;
52
+ const { tsImport } = await import('tsx/esm/api');
53
+ const mod = (await tsImport(pathToFileURL(helperPath).href, import.meta.url));
54
+ const getPrisma = mod.getPrisma ?? mod.default?.getPrisma;
55
+ if (typeof getPrisma !== 'function')
56
+ return null;
57
+ return getPrisma();
58
+ }
35
59
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see above.
36
60
  async function createProjectPrismaClient() {
37
61
  if (!process.env.DATABASE_URL) {
38
62
  throw new Error('DATABASE_URL is required to connect to the project database.');
39
63
  }
64
+ const fromLib = await tryLibPrismaClient();
65
+ if (fromLib)
66
+ return fromLib;
40
67
  const requireFromProject = createRequire(path.join(process.cwd(), 'package.json'));
41
- const generatedClient = path.resolve('generated', 'prisma', 'client.ts');
42
- if (existsSync(generatedClient)) {
68
+ const generatedClient = resolveProjectPrismaClientModule();
69
+ if (generatedClient) {
70
+ const url = process.env.DATABASE_URL;
43
71
  const [{ tsImport }, adapterModule, pgModule] = await Promise.all([
44
72
  import('tsx/esm/api'),
45
- import(pathToFileURL(requireFromProject.resolve('@prisma/adapter-pg')).href),
46
- import(pathToFileURL(requireFromProject.resolve('pg')).href),
73
+ importModule('@prisma/adapter-pg', requireFromProject),
74
+ importModule('pg', requireFromProject),
47
75
  ]);
48
76
  const { PrismaClient } = (await tsImport(pathToFileURL(generatedClient).href, import.meta.url));
77
+ if (isAcceleratedDbUrl(url)) {
78
+ let withAccelerate;
79
+ try {
80
+ const ext = (await importModule('@prisma/extension-accelerate', requireFromProject));
81
+ withAccelerate = ext.withAccelerate;
82
+ }
83
+ catch {
84
+ throw new Error('DATABASE_URL uses Prisma Accelerate but @prisma/extension-accelerate is not installed. Run `lib/prisma.ts` via adding it, or install the extension.');
85
+ }
86
+ const client = new PrismaClient({ accelerateUrl: url }).$extends(withAccelerate());
87
+ return client;
88
+ }
49
89
  const { PrismaPg } = adapterModule;
50
90
  const pg = pgModule.default ?? pgModule;
51
- const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
91
+ const pool = new pg.Pool({ connectionString: url });
52
92
  const adapter = new PrismaPg(pool);
53
93
  return new PrismaClient({ adapter });
54
94
  }
55
- const clientModule = (await import(pathToFileURL(requireFromProject.resolve('@prisma/client')).href));
95
+ const clientModule = (await importModule('@prisma/client', requireFromProject));
56
96
  return new clientModule.PrismaClient();
57
97
  }
58
98
  //# sourceMappingURL=database.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAK1C,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;IAElF,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAO,EAAE,UAAU,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,CAAA;IACzD,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,yBAAyB,EAAE,CAAA;IAC5C,MAAM,CAAC,EAAE,CAAC,CAAA;IACV,OAAO;QACL,EAAE;QACF,UAAU,EAAE,KAAK,IAAI,EAAE;YACrB,IAAI,OAAO,EAAE,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBACzC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;YACxB,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,yBAAyB;IACtC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;IACjF,CAAC;IAED,MAAM,kBAAkB,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC,CAAA;IAClF,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;IAExE,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,aAAa,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChE,MAAM,CAAC,aAAa,CAAC;YACrB,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC;YAC5E,MAAM,CAAC,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;SAC7D,CAAC,CAAA;QACF,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,QAAQ,CACtC,aAAa,CAAC,eAAe,CAAC,CAAC,IAAI,EACnC,MAAM,CAAC,IAAI,CAAC,GAAG,CAChB,CAEA,CAAA;QACD,MAAM,EAAE,QAAQ,EAAE,GAAG,aAA6D,CAAA;QAClF,MAAM,EAAE,GAAI,QAA0C,CAAC,OAAO,IAAI,QAAQ,CAAA;QAC1E,MAAM,IAAI,GAAG,IAAK,EAAU,CAAC,IAAI,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAA;QACjF,MAAM,OAAO,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAA;QAClC,OAAO,IAAI,YAAY,CAAC,EAAE,OAAO,EAAS,CAAC,CAAA;IAC7C,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,MAAM,MAAM,CAChC,aAAa,CAAC,kBAAkB,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CACjE,CAEA,CAAA;IACD,OAAO,IAAI,YAAY,CAAC,YAAY,EAAE,CAAA;AACxC,CAAC"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/utils/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /** Locate the consumer project's Prisma schema file. */
2
+ export declare function findPrismaSchemaFile(cwd?: string): string | null;
3
+ /**
4
+ * Parse `generator client { output = "..." }` and return the absolute output
5
+ * directory. Relative paths resolve from the schema file's directory (Prisma
6
+ * convention), including `../generated/prisma` layouts.
7
+ */
8
+ export declare function parsePrismaGeneratorOutputDir(schemaPath: string): string | null;
9
+ /** First existing Prisma client entry file inside `dir`. */
10
+ export declare function resolveClientEntryInDir(dir: string): string | null;
11
+ /**
12
+ * Resolve the generated Prisma client module path for CLI database commands.
13
+ * Reads the schema's custom `output` path before falling back to common
14
+ * scaffold locations (`generated/prisma`, `src/generated`, …).
15
+ */
16
+ export declare function resolveProjectPrismaClientModule(cwd?: string): string | null;
17
+ /** Project helpers that wrap Prisma 7 + driver adapters (preferred when present). */
18
+ export declare const LIB_PRISMA_HELPERS: readonly ["lib/prisma.ts", "lib/prisma.js", "lib/prisma.mjs"];
19
+ export declare function findLibPrismaHelper(cwd?: string): string | null;
20
+ //# sourceMappingURL=prisma-client-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client-path.d.ts","sourceRoot":"","sources":["../../src/utils/prisma-client-path.ts"],"names":[],"mappings":"AASA,wDAAwD;AACxD,wBAAgB,oBAAoB,CAAC,GAAG,SAAgB,GAAG,MAAM,GAAG,IAAI,CAMvE;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAc/E;AAED,4DAA4D;AAC5D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,GAAG,SAAgB,GAAG,MAAM,GAAG,IAAI,CAgBnF;AAED,qFAAqF;AACrF,eAAO,MAAM,kBAAkB,+DAAgE,CAAA;AAE/F,wBAAgB,mBAAmB,CAAC,GAAG,SAAgB,GAAG,MAAM,GAAG,IAAI,CAMtE"}
@@ -0,0 +1,77 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ const SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'schema.prisma'];
4
+ const CLIENT_ENTRY_NAMES = ['client.ts', 'client.js', 'client.mjs', 'index.ts', 'index.js'];
5
+ const OUTPUT_DIR_FALLBACKS = [['generated', 'prisma'], ['src', 'generated'], ['generated']];
6
+ /** Locate the consumer project's Prisma schema file. */
7
+ export function findPrismaSchemaFile(cwd = process.cwd()) {
8
+ for (const rel of SCHEMA_CANDIDATES) {
9
+ const candidate = path.join(cwd, rel);
10
+ if (existsSync(candidate))
11
+ return candidate;
12
+ }
13
+ return null;
14
+ }
15
+ /**
16
+ * Parse `generator client { output = "..." }` and return the absolute output
17
+ * directory. Relative paths resolve from the schema file's directory (Prisma
18
+ * convention), including `../generated/prisma` layouts.
19
+ */
20
+ export function parsePrismaGeneratorOutputDir(schemaPath) {
21
+ let content;
22
+ try {
23
+ content = readFileSync(schemaPath, 'utf8');
24
+ }
25
+ catch {
26
+ return null;
27
+ }
28
+ const match = content.match(/output\s*=\s*"([^"]+)"/);
29
+ if (!match?.[1])
30
+ return null;
31
+ const raw = match[1].replace(/\//g, path.sep);
32
+ if (path.isAbsolute(raw))
33
+ return raw;
34
+ return path.resolve(path.dirname(schemaPath), raw);
35
+ }
36
+ /** First existing Prisma client entry file inside `dir`. */
37
+ export function resolveClientEntryInDir(dir) {
38
+ for (const name of CLIENT_ENTRY_NAMES) {
39
+ const candidate = path.join(dir, name);
40
+ if (existsSync(candidate))
41
+ return candidate;
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * Resolve the generated Prisma client module path for CLI database commands.
47
+ * Reads the schema's custom `output` path before falling back to common
48
+ * scaffold locations (`generated/prisma`, `src/generated`, …).
49
+ */
50
+ export function resolveProjectPrismaClientModule(cwd = process.cwd()) {
51
+ const schemaPath = findPrismaSchemaFile(cwd);
52
+ if (schemaPath) {
53
+ const outputDir = parsePrismaGeneratorOutputDir(schemaPath);
54
+ if (outputDir) {
55
+ const entry = resolveClientEntryInDir(outputDir);
56
+ if (entry)
57
+ return entry;
58
+ }
59
+ }
60
+ for (const parts of OUTPUT_DIR_FALLBACKS) {
61
+ const entry = resolveClientEntryInDir(path.resolve(cwd, ...parts));
62
+ if (entry)
63
+ return entry;
64
+ }
65
+ return null;
66
+ }
67
+ /** Project helpers that wrap Prisma 7 + driver adapters (preferred when present). */
68
+ export const LIB_PRISMA_HELPERS = ['lib/prisma.ts', 'lib/prisma.js', 'lib/prisma.mjs'];
69
+ export function findLibPrismaHelper(cwd = process.cwd()) {
70
+ for (const rel of LIB_PRISMA_HELPERS) {
71
+ const candidate = path.join(cwd, rel);
72
+ if (existsSync(candidate))
73
+ return candidate;
74
+ }
75
+ return null;
76
+ }
77
+ //# sourceMappingURL=prisma-client-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prisma-client-path.js","sourceRoot":"","sources":["../../src/utils/prisma-client-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,iBAAiB,GAAG,CAAC,sBAAsB,EAAE,eAAe,CAAU,CAAA;AAE5E,MAAM,kBAAkB,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,CAAU,CAAA;AAEpG,MAAM,oBAAoB,GAAG,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,CAAU,CAAA;AAEpG,wDAAwD;AACxD,MAAM,UAAU,oBAAoB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACtD,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACrC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAA;IAC7C,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,UAAkB;IAC9D,IAAI,OAAe,CAAA;IACnB,IAAI,CAAC;QACH,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;IACrD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAE5B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAA;IACpC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,CAAA;AACpD,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,uBAAuB,CAAC,GAAW;IACjD,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACtC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAA;IAC7C,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gCAAgC,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IAClE,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAA;IAC5C,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,6BAA6B,CAAC,UAAU,CAAC,CAAA;QAC3D,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,KAAK,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAA;YAChD,IAAI,KAAK;gBAAE,OAAO,KAAK,CAAA;QACzB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAA;QAClE,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;IACzB,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,gBAAgB,CAAU,CAAA;AAE/F,MAAM,UAAU,mBAAmB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACrD,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACrC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAA;IAC7C,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actuate-media/cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "CLI for Actuate CMS — migrations, codegen, imports, exports, and upgrades",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,87 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
2
+ import { tmpdir } from 'node:os'
3
+ import path from 'node:path'
4
+ import { afterEach, describe, expect, it } from 'vitest'
5
+
6
+ import {
7
+ findPrismaSchemaFile,
8
+ parsePrismaGeneratorOutputDir,
9
+ resolveClientEntryInDir,
10
+ resolveProjectPrismaClientModule,
11
+ } from '../utils/prisma-client-path.js'
12
+
13
+ describe('prisma-client-path', () => {
14
+ let tempDir: string | null = null
15
+
16
+ afterEach(() => {
17
+ if (tempDir) rmSync(tempDir, { recursive: true, force: true })
18
+ tempDir = null
19
+ })
20
+
21
+ function writeSchema(root: string, output: string) {
22
+ mkdirSync(path.join(root, 'prisma'), { recursive: true })
23
+ writeFileSync(
24
+ path.join(root, 'prisma', 'schema.prisma'),
25
+ `generator client {
26
+ provider = "prisma-client"
27
+ output = "${output}"
28
+ }
29
+
30
+ datasource db {
31
+ provider = "postgresql"
32
+ }
33
+ `,
34
+ )
35
+ }
36
+
37
+ function writeClient(clientPath: string) {
38
+ mkdirSync(path.dirname(clientPath), { recursive: true })
39
+ writeFileSync(clientPath, 'export class PrismaClient {}')
40
+ }
41
+
42
+ it('finds prisma/schema.prisma in the project root', () => {
43
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'))
44
+ writeSchema(tempDir, '../generated/prisma')
45
+ expect(findPrismaSchemaFile(tempDir)).toBe(path.join(tempDir, 'prisma', 'schema.prisma'))
46
+ })
47
+
48
+ it('resolves relative generator output from the schema directory', () => {
49
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'))
50
+ writeSchema(tempDir, '../generated/prisma')
51
+ const schemaPath = path.join(tempDir, 'prisma', 'schema.prisma')
52
+ expect(parsePrismaGeneratorOutputDir(schemaPath)).toBe(
53
+ path.join(tempDir, 'generated', 'prisma'),
54
+ )
55
+ })
56
+
57
+ it('resolves custom output paths used by Prisma 7 scaffolds', () => {
58
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'))
59
+ writeSchema(tempDir, '../src/generated/prisma')
60
+ const schemaPath = path.join(tempDir, 'prisma', 'schema.prisma')
61
+ expect(parsePrismaGeneratorOutputDir(schemaPath)).toBe(
62
+ path.join(tempDir, 'src', 'generated', 'prisma'),
63
+ )
64
+ })
65
+
66
+ it('locates client.ts via schema output before default fallbacks', () => {
67
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'))
68
+ writeSchema(tempDir, '../src/generated/prisma')
69
+ const clientPath = path.join(tempDir, 'src', 'generated', 'prisma', 'client.ts')
70
+ writeClient(clientPath)
71
+ expect(resolveProjectPrismaClientModule(tempDir)).toBe(clientPath)
72
+ })
73
+
74
+ it('falls back to generated/prisma/client.ts when schema output is missing', () => {
75
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-'))
76
+ const clientPath = path.join(tempDir, 'generated', 'prisma', 'client.ts')
77
+ writeClient(clientPath)
78
+ expect(resolveProjectPrismaClientModule(tempDir)).toBe(clientPath)
79
+ })
80
+
81
+ it('resolveClientEntryInDir prefers client.ts over index.ts', () => {
82
+ tempDir = mkdtempSync(path.join(tmpdir(), 'actuate-cli-prisma-entry-'))
83
+ writeFileSync(path.join(tempDir, 'index.ts'), 'export {}')
84
+ writeFileSync(path.join(tempDir, 'client.ts'), 'export class PrismaClient {}')
85
+ expect(resolveClientEntryInDir(tempDir)).toBe(path.join(tempDir, 'client.ts'))
86
+ })
87
+ })
@@ -1,8 +1,9 @@
1
- import { existsSync } from 'node:fs'
2
1
  import { createRequire } from 'node:module'
3
2
  import path from 'node:path'
4
3
  import { pathToFileURL } from 'node:url'
5
4
 
5
+ import { findLibPrismaHelper, resolveProjectPrismaClientModule } from './prisma-client-path.js'
6
+
6
7
  /**
7
8
  * Shared helper for CLI commands that need a live connection to the consumer
8
9
  * project's database (seed, populate, data migrations…).
@@ -10,9 +11,11 @@ import { pathToFileURL } from 'node:url'
10
11
  * Resolution order mirrors how a scaffolded Actuate project exposes Prisma:
11
12
  * 1. If `cms-core` already has an initialized client (e.g. set up by the host
12
13
  * app in-process), reuse it.
13
- * 2. Otherwise build a client from the project's generated Prisma client
14
- * (`generated/prisma/client.ts`, Prisma 7 + pg driver adapter).
15
- * 3. Fall back to a plain `@prisma/client` resolved from the project.
14
+ * 2. Otherwise call `getPrisma()` from `lib/prisma.ts` when the project ships
15
+ * one (Prisma 7 + pg adapter / Accelerate — same path Next.js uses).
16
+ * 3. Otherwise build a client from the schema's `output` path (custom or
17
+ * default `generated/prisma/client.ts`) via tsx + pg driver adapter.
18
+ * 4. Fall back to a plain `@prisma/client` resolved from the project.
16
19
  *
17
20
  * The returned `disconnect()` only tears down clients this helper created — a
18
21
  * pre-initialized in-process client is left untouched.
@@ -40,20 +43,51 @@ export async function connectProjectDatabase(): Promise<{
40
43
  }
41
44
  }
42
45
 
46
+ const ACCELERATED_DB_URL_PREFIXES = ['prisma://', 'prisma+postgres://'] as const
47
+
48
+ function isAcceleratedDbUrl(url: string | undefined): boolean {
49
+ const trimmed = url?.trim()
50
+ if (!trimmed) return false
51
+ return ACCELERATED_DB_URL_PREFIXES.some((prefix) => trimmed.startsWith(prefix))
52
+ }
53
+
54
+ async function importModule(specifier: string, requireFromProject: NodeRequire): Promise<unknown> {
55
+ const href = pathToFileURL(requireFromProject.resolve(specifier)).href
56
+ return import(href)
57
+ }
58
+
59
+ async function tryLibPrismaClient(): Promise<any | null> {
60
+ const helperPath = findLibPrismaHelper()
61
+ if (!helperPath) return null
62
+
63
+ const { tsImport } = await import('tsx/esm/api')
64
+ const mod = (await tsImport(pathToFileURL(helperPath).href, import.meta.url)) as {
65
+ getPrisma?: () => unknown
66
+ default?: { getPrisma?: () => unknown }
67
+ }
68
+ const getPrisma = mod.getPrisma ?? mod.default?.getPrisma
69
+ if (typeof getPrisma !== 'function') return null
70
+ return getPrisma()
71
+ }
72
+
43
73
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- see above.
44
74
  async function createProjectPrismaClient(): Promise<any> {
45
75
  if (!process.env.DATABASE_URL) {
46
76
  throw new Error('DATABASE_URL is required to connect to the project database.')
47
77
  }
48
78
 
79
+ const fromLib = await tryLibPrismaClient()
80
+ if (fromLib) return fromLib
81
+
49
82
  const requireFromProject = createRequire(path.join(process.cwd(), 'package.json'))
50
- const generatedClient = path.resolve('generated', 'prisma', 'client.ts')
83
+ const generatedClient = resolveProjectPrismaClientModule()
51
84
 
52
- if (existsSync(generatedClient)) {
85
+ if (generatedClient) {
86
+ const url = process.env.DATABASE_URL
53
87
  const [{ tsImport }, adapterModule, pgModule] = await Promise.all([
54
88
  import('tsx/esm/api'),
55
- import(pathToFileURL(requireFromProject.resolve('@prisma/adapter-pg')).href),
56
- import(pathToFileURL(requireFromProject.resolve('pg')).href),
89
+ importModule('@prisma/adapter-pg', requireFromProject),
90
+ importModule('pg', requireFromProject),
57
91
  ])
58
92
  const { PrismaClient } = (await tsImport(
59
93
  pathToFileURL(generatedClient).href,
@@ -61,16 +95,31 @@ async function createProjectPrismaClient(): Promise<any> {
61
95
  )) as {
62
96
  PrismaClient: new (options?: unknown) => any
63
97
  }
98
+
99
+ if (isAcceleratedDbUrl(url)) {
100
+ let withAccelerate: () => unknown
101
+ try {
102
+ const ext = (await importModule('@prisma/extension-accelerate', requireFromProject)) as {
103
+ withAccelerate: () => unknown
104
+ }
105
+ withAccelerate = ext.withAccelerate
106
+ } catch {
107
+ throw new Error(
108
+ 'DATABASE_URL uses Prisma Accelerate but @prisma/extension-accelerate is not installed. Run `lib/prisma.ts` via adding it, or install the extension.',
109
+ )
110
+ }
111
+ const client = new PrismaClient({ accelerateUrl: url } as never).$extends(withAccelerate())
112
+ return client
113
+ }
114
+
64
115
  const { PrismaPg } = adapterModule as { PrismaPg: new (pool: unknown) => unknown }
65
116
  const pg = (pgModule as { default?: typeof pgModule }).default ?? pgModule
66
- const pool = new (pg as any).Pool({ connectionString: process.env.DATABASE_URL })
117
+ const pool = new (pg as any).Pool({ connectionString: url })
67
118
  const adapter = new PrismaPg(pool)
68
119
  return new PrismaClient({ adapter } as any)
69
120
  }
70
121
 
71
- const clientModule = (await import(
72
- pathToFileURL(requireFromProject.resolve('@prisma/client')).href
73
- )) as {
122
+ const clientModule = (await importModule('@prisma/client', requireFromProject)) as {
74
123
  PrismaClient: new () => any
75
124
  }
76
125
  return new clientModule.PrismaClient()
@@ -0,0 +1,81 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ const SCHEMA_CANDIDATES = ['prisma/schema.prisma', 'schema.prisma'] as const
5
+
6
+ const CLIENT_ENTRY_NAMES = ['client.ts', 'client.js', 'client.mjs', 'index.ts', 'index.js'] as const
7
+
8
+ const OUTPUT_DIR_FALLBACKS = [['generated', 'prisma'], ['src', 'generated'], ['generated']] as const
9
+
10
+ /** Locate the consumer project's Prisma schema file. */
11
+ export function findPrismaSchemaFile(cwd = process.cwd()): string | null {
12
+ for (const rel of SCHEMA_CANDIDATES) {
13
+ const candidate = path.join(cwd, rel)
14
+ if (existsSync(candidate)) return candidate
15
+ }
16
+ return null
17
+ }
18
+
19
+ /**
20
+ * Parse `generator client { output = "..." }` and return the absolute output
21
+ * directory. Relative paths resolve from the schema file's directory (Prisma
22
+ * convention), including `../generated/prisma` layouts.
23
+ */
24
+ export function parsePrismaGeneratorOutputDir(schemaPath: string): string | null {
25
+ let content: string
26
+ try {
27
+ content = readFileSync(schemaPath, 'utf8')
28
+ } catch {
29
+ return null
30
+ }
31
+
32
+ const match = content.match(/output\s*=\s*"([^"]+)"/)
33
+ if (!match?.[1]) return null
34
+
35
+ const raw = match[1].replace(/\//g, path.sep)
36
+ if (path.isAbsolute(raw)) return raw
37
+ return path.resolve(path.dirname(schemaPath), raw)
38
+ }
39
+
40
+ /** First existing Prisma client entry file inside `dir`. */
41
+ export function resolveClientEntryInDir(dir: string): string | null {
42
+ for (const name of CLIENT_ENTRY_NAMES) {
43
+ const candidate = path.join(dir, name)
44
+ if (existsSync(candidate)) return candidate
45
+ }
46
+ return null
47
+ }
48
+
49
+ /**
50
+ * Resolve the generated Prisma client module path for CLI database commands.
51
+ * Reads the schema's custom `output` path before falling back to common
52
+ * scaffold locations (`generated/prisma`, `src/generated`, …).
53
+ */
54
+ export function resolveProjectPrismaClientModule(cwd = process.cwd()): string | null {
55
+ const schemaPath = findPrismaSchemaFile(cwd)
56
+ if (schemaPath) {
57
+ const outputDir = parsePrismaGeneratorOutputDir(schemaPath)
58
+ if (outputDir) {
59
+ const entry = resolveClientEntryInDir(outputDir)
60
+ if (entry) return entry
61
+ }
62
+ }
63
+
64
+ for (const parts of OUTPUT_DIR_FALLBACKS) {
65
+ const entry = resolveClientEntryInDir(path.resolve(cwd, ...parts))
66
+ if (entry) return entry
67
+ }
68
+
69
+ return null
70
+ }
71
+
72
+ /** Project helpers that wrap Prisma 7 + driver adapters (preferred when present). */
73
+ export const LIB_PRISMA_HELPERS = ['lib/prisma.ts', 'lib/prisma.js', 'lib/prisma.mjs'] as const
74
+
75
+ export function findLibPrismaHelper(cwd = process.cwd()): string | null {
76
+ for (const rel of LIB_PRISMA_HELPERS) {
77
+ const candidate = path.join(cwd, rel)
78
+ if (existsSync(candidate)) return candidate
79
+ }
80
+ return null
81
+ }