@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.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +38 -36
- package/CHANGELOG.md +6 -0
- package/dist/__tests__/prisma-client-path.test.d.ts +2 -0
- package/dist/__tests__/prisma-client-path.test.d.ts.map +1 -0
- package/dist/__tests__/prisma-client-path.test.js +66 -0
- package/dist/__tests__/prisma-client-path.test.js.map +1 -0
- package/dist/utils/database.d.ts +5 -3
- package/dist/utils/database.d.ts.map +1 -1
- package/dist/utils/database.js +50 -10
- package/dist/utils/database.js.map +1 -1
- package/dist/utils/prisma-client-path.d.ts +20 -0
- package/dist/utils/prisma-client-path.d.ts.map +1 -0
- package/dist/utils/prisma-client-path.js +77 -0
- package/dist/utils/prisma-client-path.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/prisma-client-path.test.ts +87 -0
- package/src/utils/database.ts +61 -12
- package/src/utils/prisma-client-path.ts +81 -0
package/.turbo/turbo-build.log
CHANGED
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
|
|
2
|
-
> @actuate-media/cli@0.12.
|
|
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
|
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.8 [39m[90m/home/runner/work/actuatecms/actuatecms/packages/cli[39m
|
|
7
7
|
|
|
8
|
-
[32m✓[39m dist/__tests__/db-sync.test.js [2m([22m[2m10 tests[22m[2m)[22m[
|
|
9
|
-
[32m✓[39m dist/__tests__/seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
10
|
-
[32m✓[39m src/__tests__/db-sync.test.ts [2m([22m[2m10 tests[22m[2m)[22m[
|
|
11
|
-
[32m✓[39m dist/__tests__/deployment-diagnostics.test.js [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
12
|
-
[32m✓[39m src/__tests__/seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
8
|
+
[32m✓[39m dist/__tests__/db-sync.test.js [2m([22m[2m10 tests[22m[2m)[22m[33m 460[2mms[22m[39m
|
|
9
|
+
[32m✓[39m dist/__tests__/seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m 199[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/__tests__/db-sync.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 394[2mms[22m[39m
|
|
11
|
+
[32m✓[39m dist/__tests__/deployment-diagnostics.test.js [2m([22m[2m9 tests[22m[2m)[22m[32m 62[2mms[22m[39m
|
|
12
|
+
[32m✓[39m src/__tests__/seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 166[2mms[22m[39m
|
|
13
13
|
[32m✓[39m src/__tests__/deployment-diagnostics.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 49[2mms[22m[39m
|
|
14
14
|
- Reading canonical Actuate schema...
|
|
15
|
-
✔ Actuate CMS models added to schema.
|
|
16
|
-
- Running prisma generate...
|
|
17
15
|
[90mstdout[2m | dist/__tests__/db-init.test.js[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2minjects canonical models with @@map and no duplicate datasource/generator
|
|
16
|
+
✔ Actuate CMS models added to schema.
|
|
18
17
|
[22m[39m✔ 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
|
[90mstdout[2m | dist/__tests__/db-init.test.js[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2mfails clearly when cms-core cannot be located
|
|
22
|
+
[22m[39mℹ 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
|
-
[22m[39mℹ 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
|
[90mstdout[2m | dist/__tests__/db-init.test.js[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2mis idempotent without --force
|
|
29
28
|
[22m[39m✔ 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
|
-
[32m✓[39m dist/__tests__/db-init.test.js [2m([22m[2m4 tests[22m[2m)[22m[
|
|
35
|
+
[32m✓[39m dist/__tests__/db-init.test.js [2m([22m[2m4 tests[22m[2m)[22m[33m 340[2mms[22m[39m
|
|
36
36
|
- Reading canonical Actuate schema...
|
|
37
|
+
✔ Actuate CMS models added to schema.
|
|
38
|
+
- Running prisma generate...
|
|
37
39
|
[90mstdout[2m | src/__tests__/db-init.test.ts[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2minjects canonical models with @@map and no duplicate datasource/generator
|
|
38
40
|
[22m[39m✔ 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
|
-
[90mstdout[2m | src/__tests__/db-init.test.ts[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2mfails clearly when cms-core cannot be located
|
|
45
44
|
✖ Could not locate @actuate-media/cms-core.
|
|
45
|
+
[90mstdout[2m | src/__tests__/db-init.test.ts[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2mfails clearly when cms-core cannot be located
|
|
46
46
|
[22m[39mℹ Install it first: `npm install @actuate-media/cms-core`.
|
|
47
47
|
|
|
48
48
|
- Reading canonical Actuate schema...
|
|
49
49
|
[90mstdout[2m | src/__tests__/db-init.test.ts[2m > [22m[2mdb:init (WS-D D5 — canonical schema, no stale fragment)[2m > [22m[2mcommand[2m > [22m[2mis idempotent without --force
|
|
50
50
|
[22m[39m✔ 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
|
-
|
|
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
|
-
[32m✓[39m src/__tests__/db-init.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m
|
|
57
|
+
[32m✓[39m src/__tests__/db-init.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 127[2mms[22m[39m
|
|
58
58
|
[90mstdout[2m | dist/__tests__/mcp-init.test.js[2m > [22m[2mmcp:init[2m > [22m[2mcreates both editor configs with placeholder key and git-ignores them
|
|
59
59
|
[22m[39m✔ 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
|
-
[32m✓[39m dist/__tests__/mcp-init.test.js [2m([22m[2m6 tests[22m[2m)[22m[
|
|
186
|
+
[32m✓[39m dist/__tests__/mcp-init.test.js [2m([22m[2m6 tests[22m[2m)[22m[33m 484[2mms[22m[39m
|
|
187
187
|
[90mstdout[2m | src/__tests__/mcp-init.test.ts[2m > [22m[2mmcp:init[2m > [22m[2mcreates both editor configs with placeholder key and git-ignores them
|
|
188
188
|
[22m[39m✔ 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
|
-
[32m✓[39m src/__tests__/mcp-init.test.ts [2m([22m[2m6 tests[22m[2m)[22m[
|
|
316
|
-
[32m✓[39m dist/__tests__/form-seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
317
|
-
[32m✓[39m src/__tests__/form-seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m
|
|
318
|
-
[32m✓[39m dist/__tests__/
|
|
319
|
-
[32m✓[39m src/__tests__/
|
|
320
|
-
[32m✓[39m dist/__tests__/
|
|
321
|
-
[32m✓[39m src/__tests__/
|
|
315
|
+
[32m✓[39m src/__tests__/mcp-init.test.ts [2m([22m[2m6 tests[22m[2m)[22m[33m 429[2mms[22m[39m
|
|
316
|
+
[32m✓[39m dist/__tests__/form-seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m 60[2mms[22m[39m
|
|
317
|
+
[32m✓[39m src/__tests__/form-seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 70[2mms[22m[39m
|
|
318
|
+
[32m✓[39m dist/__tests__/prisma-client-path.test.js [2m([22m[2m6 tests[22m[2m)[22m[32m 68[2mms[22m[39m
|
|
319
|
+
[32m✓[39m src/__tests__/prisma-client-path.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 81[2mms[22m[39m
|
|
320
|
+
[32m✓[39m dist/__tests__/vercel-env-matrix.test.js [2m([22m[2m6 tests[22m[2m)[22m[32m 95[2mms[22m[39m
|
|
321
|
+
[32m✓[39m src/__tests__/vercel-env-matrix.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 58[2mms[22m[39m
|
|
322
|
+
[32m✓[39m dist/__tests__/load-dotenv.test.js [2m([22m[2m3 tests[22m[2m)[22m[32m 105[2mms[22m[39m
|
|
323
|
+
[32m✓[39m src/__tests__/load-dotenv.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 116[2mms[22m[39m
|
|
322
324
|
- Reading canonical Actuate schema...
|
|
323
325
|
✔ Actuate CMS models added to schema.
|
|
324
|
-
- Running prisma generate...
|
|
325
326
|
[90mstdout[2m | dist/__tests__/schema-fragment.test.js[2m > [22m[2mdb:init schema fragment[2m > [22m[2minjects all deploy-critical Actuate models
|
|
326
327
|
[22m[39m✔ Prisma client generated.
|
|
327
328
|
ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
328
329
|
|
|
329
|
-
|
|
330
|
+
- Running prisma generate...
|
|
331
|
+
[32m✓[39m dist/__tests__/schema-fragment.test.js [2m([22m[2m1 test[22m[2m)[22m[32m 132[2mms[22m[39m
|
|
330
332
|
- Reading canonical Actuate schema...
|
|
331
333
|
✔ Actuate CMS models added to schema.
|
|
334
|
+
- Running prisma generate...
|
|
332
335
|
[90mstdout[2m | src/__tests__/schema-fragment.test.ts[2m > [22m[2mdb:init schema fragment[2m > [22m[2minjects all deploy-critical Actuate models
|
|
333
336
|
[22m[39m✔ Prisma client generated.
|
|
334
|
-
- Running prisma generate...
|
|
335
337
|
ℹ Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
336
338
|
|
|
337
|
-
[32m✓[39m src/__tests__/schema-fragment.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
338
|
-
[32m✓[39m dist/__tests__/init.test.js [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
339
|
-
[32m✓[39m src/__tests__/init.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m
|
|
339
|
+
[32m✓[39m src/__tests__/schema-fragment.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 123[2mms[22m[39m
|
|
340
|
+
[32m✓[39m dist/__tests__/init.test.js [2m([22m[2m2 tests[22m[2m)[22m[32m 36[2mms[22m[39m
|
|
341
|
+
[32m✓[39m src/__tests__/init.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 48[2mms[22m[39m
|
|
340
342
|
|
|
341
|
-
[2m Test Files [22m [1m[
|
|
342
|
-
[2m Tests [22m [1m[
|
|
343
|
-
[2m Start at [22m
|
|
344
|
-
[2m Duration [22m
|
|
343
|
+
[2m Test Files [22m [1m[32m22 passed[39m[22m[90m (22)[39m
|
|
344
|
+
[2m Tests [22m [1m[32m134 passed[39m[22m[90m (134)[39m
|
|
345
|
+
[2m Start at [22m 17:49:50
|
|
346
|
+
[2m Duration [22m 37.73s[2m (transform 3.12s, setup 0ms, import 8.53s, tests 3.70s, environment 22ms)[22m
|
|
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 @@
|
|
|
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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"}
|
package/dist/utils/database.d.ts
CHANGED
|
@@ -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
|
|
9
|
-
* (
|
|
10
|
-
* 3.
|
|
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":"
|
|
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"}
|
package/dist/utils/database.js
CHANGED
|
@@ -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
|
|
13
|
-
* (
|
|
14
|
-
* 3.
|
|
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 =
|
|
42
|
-
if (
|
|
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
|
-
|
|
46
|
-
|
|
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:
|
|
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
|
|
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,
|
|
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":"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"}
|
package/package.json
CHANGED
|
@@ -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
|
+
})
|
package/src/utils/database.ts
CHANGED
|
@@ -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
|
|
14
|
-
* (
|
|
15
|
-
* 3.
|
|
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 =
|
|
83
|
+
const generatedClient = resolveProjectPrismaClientModule()
|
|
51
84
|
|
|
52
|
-
if (
|
|
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
|
-
|
|
56
|
-
|
|
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:
|
|
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
|
|
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
|
+
}
|