@actuate-media/cli 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +64 -18
  3. package/CHANGELOG.md +46 -0
  4. package/dist/__tests__/db-init.test.d.ts +2 -0
  5. package/dist/__tests__/db-init.test.d.ts.map +1 -0
  6. package/dist/__tests__/db-init.test.js +127 -0
  7. package/dist/__tests__/db-init.test.js.map +1 -0
  8. package/dist/__tests__/db-sync.test.d.ts +2 -0
  9. package/dist/__tests__/db-sync.test.d.ts.map +1 -0
  10. package/dist/__tests__/db-sync.test.js +136 -0
  11. package/dist/__tests__/db-sync.test.js.map +1 -0
  12. package/dist/__tests__/seed.test.js +20 -1
  13. package/dist/__tests__/seed.test.js.map +1 -1
  14. package/dist/commands/db-init.d.ts +17 -0
  15. package/dist/commands/db-init.d.ts.map +1 -1
  16. package/dist/commands/db-init.js +100 -278
  17. package/dist/commands/db-init.js.map +1 -1
  18. package/dist/commands/db-sync.d.ts +31 -0
  19. package/dist/commands/db-sync.d.ts.map +1 -0
  20. package/dist/commands/db-sync.js +195 -0
  21. package/dist/commands/db-sync.js.map +1 -0
  22. package/dist/commands/seed.d.ts +10 -0
  23. package/dist/commands/seed.d.ts.map +1 -1
  24. package/dist/commands/seed.js +38 -4
  25. package/dist/commands/seed.js.map +1 -1
  26. package/dist/commands/upgrade.d.ts.map +1 -1
  27. package/dist/commands/upgrade.js +5 -0
  28. package/dist/commands/upgrade.js.map +1 -1
  29. package/dist/index.js +2 -0
  30. package/dist/index.js.map +1 -1
  31. package/package.json +2 -2
  32. package/src/__tests__/db-init.test.ts +155 -0
  33. package/src/__tests__/db-sync.test.ts +167 -0
  34. package/src/__tests__/seed.test.ts +27 -1
  35. package/src/commands/db-init.ts +93 -266
  36. package/src/commands/db-sync.ts +227 -0
  37. package/src/commands/seed.ts +40 -4
  38. package/src/commands/upgrade.ts +8 -0
  39. package/src/index.ts +2 -0
@@ -1,9 +1,11 @@
1
1
  import { readFile, writeFile, access } from 'node:fs/promises';
2
- import { resolve } from 'node:path';
2
+ import { resolve, join, dirname } from 'node:path';
3
+ import { createRequire } from 'node:module';
3
4
  import { execSync } from 'node:child_process';
4
5
  import ora from 'ora';
5
6
  import { logger } from '../utils/logger.js';
6
7
  const CMS_SCHEMA_MARKER = '// ── Actuate CMS models';
8
+ const require = createRequire(import.meta.url);
7
9
  export let runDbInitCommand = (command, options) => {
8
10
  execSync(command, options);
9
11
  };
@@ -14,293 +16,104 @@ export function setDbInitCommandRunner(runner) {
14
16
  export function resetDbInitCommandRunner() {
15
17
  runDbInitCommand = defaultDbInitCommandRunner;
16
18
  }
17
- async function fileExists(filePath) {
19
+ /**
20
+ * Reads the canonical Prisma schema shipped by the installed
21
+ * `@actuate-media/cms-core` package. This is the single source of truth — it has
22
+ * the correct `@@map("actuate_*")` table names and every model the API handlers
23
+ * expect. Previously `db:init` injected a hand-maintained copy that drifted
24
+ * (missing `@@map`, missing models), producing a database the runtime couldn't
25
+ * query. Overridable for tests.
26
+ */
27
+ export let readCanonicalCmsSchema = async () => {
28
+ const candidates = [];
18
29
  try {
19
- await access(filePath);
20
- return true;
30
+ // `./prisma/schema` is an exported subpath, so this resolves inside the
31
+ // package's `prisma/` directory without depending on the build output.
32
+ const exported = require.resolve('@actuate-media/cms-core/prisma/schema');
33
+ candidates.push(join(dirname(exported), 'schema.prisma'));
21
34
  }
22
35
  catch {
23
- return false;
36
+ /* exports map missing the subpath — fall through to the main entry */
37
+ }
38
+ try {
39
+ const mainEntry = require.resolve('@actuate-media/cms-core');
40
+ candidates.push(join(dirname(mainEntry), '..', 'prisma', 'schema.prisma'));
41
+ }
42
+ catch {
43
+ /* package not installed */
44
+ }
45
+ for (const candidate of candidates) {
46
+ try {
47
+ return await readFile(candidate, 'utf-8');
48
+ }
49
+ catch {
50
+ /* try the next candidate */
51
+ }
52
+ }
53
+ return null;
54
+ };
55
+ const defaultSchemaReader = readCanonicalCmsSchema;
56
+ export function setCanonicalSchemaReader(reader) {
57
+ readCanonicalCmsSchema = reader;
58
+ }
59
+ export function resetCanonicalSchemaReader() {
60
+ readCanonicalCmsSchema = defaultSchemaReader;
61
+ }
62
+ function netBraces(line) {
63
+ return (line.match(/\{/g)?.length ?? 0) - (line.match(/\}/g)?.length ?? 0);
64
+ }
65
+ /**
66
+ * Strips the top-level `generator` and `datasource` blocks from a full Prisma
67
+ * schema, leaving only the `enum` and `model` definitions. The consumer keeps
68
+ * their own datasource/generator; we only contribute models.
69
+ */
70
+ export function extractModelsFragment(fullSchema) {
71
+ const lines = fullSchema.split(/\r?\n/);
72
+ const kept = [];
73
+ let skipping = false;
74
+ let depth = 0;
75
+ for (const line of lines) {
76
+ if (!skipping) {
77
+ if (/^\s*(generator|datasource)\s+[A-Za-z0-9_]+\s*\{/.test(line)) {
78
+ skipping = true;
79
+ depth = netBraces(line);
80
+ if (depth <= 0)
81
+ skipping = false;
82
+ continue;
83
+ }
84
+ kept.push(line);
85
+ }
86
+ else {
87
+ depth += netBraces(line);
88
+ if (depth <= 0)
89
+ skipping = false;
90
+ }
24
91
  }
92
+ return kept.join('\n').trim();
25
93
  }
26
- function getCmsSchemaFragment() {
94
+ function wrapFragment(models) {
27
95
  return `
28
- // ── Actuate CMS models ─────────────────────────────────────────────────────
29
- // Auto-injected by \`actuate db:init\`. Do not remove this marker comment.
30
- // Schema version: 1
31
-
32
- enum DocumentStatus {
33
- DRAFT
34
- PUBLISHED
35
- ARCHIVED
36
- SCHEDULED
37
- }
38
-
39
- model User {
40
- id String @id @default(cuid())
41
- email String @unique
42
- name String @default("")
43
- role String @default("EDITOR")
44
- passwordHash String?
45
- isActive Boolean @default(true)
46
- isApproved Boolean @default(false)
47
- emailVerified Boolean @default(false)
48
- totpEnabled Boolean @default(false)
49
- totpSecret String?
50
- backupCodes Json?
51
- oauthProvider String?
52
- oauthId String?
53
- createdAt DateTime @default(now())
54
- updatedAt DateTime @updatedAt
55
-
56
- sessions Session[]
57
- documentsCreated Document[] @relation("DocumentCreatedBy")
58
- documentsUpdated Document[] @relation("DocumentUpdatedBy")
59
- documentsReviewed Document[] @relation("DocumentReviewer")
60
- versions Version[]
61
- mediaUploaded Media[] @relation("MediaUploadedBy")
62
- auditLogs AuditLog[]
63
-
64
- @@index([role])
65
- @@index([isActive])
66
- }
67
-
68
- model Session {
69
- id String @id @default(cuid())
70
- userId String
71
- user User @relation(fields: [userId], references: [id], onDelete: Cascade)
72
- token String? @unique
73
- expiresAt DateTime
74
- revokedAt DateTime?
75
- ipAddress String?
76
- userAgent String?
77
- createdAt DateTime @default(now())
78
-
79
- @@index([userId])
80
- @@index([expiresAt])
81
- }
82
-
83
- model Document {
84
- id String @id @default(cuid())
85
- collection String
86
- slug String?
87
- title String?
88
- data Json
89
- status DocumentStatus @default(DRAFT)
90
- plainText String? @db.Text
91
- locale String?
92
- folderId String?
93
- structuredData Json?
94
- workflowStage String?
95
- reviewerId String?
96
- reviewNote String? @db.Text
97
- publishedAt DateTime?
98
- scheduledAt DateTime?
99
- scheduledUnpublishAt DateTime?
100
- deletedAt DateTime?
101
- contentHash String?
102
- siteId String?
103
- templateId String?
104
- createdById String
105
- updatedById String
106
- createdAt DateTime @default(now())
107
- updatedAt DateTime @updatedAt
108
-
109
- createdBy User @relation("DocumentCreatedBy", fields: [createdById], references: [id], onDelete: Restrict)
110
- updatedBy User @relation("DocumentUpdatedBy", fields: [updatedById], references: [id], onDelete: Restrict)
111
- reviewer User? @relation("DocumentReviewer", fields: [reviewerId], references: [id], onDelete: SetNull)
112
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
113
- versions Version[]
114
- formSubmissions FormSubmission[]
115
-
116
- @@unique([collection, slug], name: "collection_slug")
117
- @@index([collection])
118
- @@index([status])
119
- @@index([deletedAt])
120
- @@index([publishedAt])
121
- @@index([folderId])
122
- @@index([locale])
123
- @@index([scheduledAt])
124
- @@index([scheduledUnpublishAt])
125
- @@index([createdById])
126
- @@index([updatedById])
127
- }
128
-
129
- model Media {
130
- id String @id @default(cuid())
131
- filename String
132
- storageKey String @unique
133
- mimeType String
134
- fileSize Int
135
- width Int?
136
- height Int?
137
- altText String?
138
- title String?
139
- blurHash String?
140
- focalPointX Float?
141
- focalPointY Float?
142
- folderId String?
143
- uploadedById String
144
- createdAt DateTime @default(now())
145
- updatedAt DateTime @updatedAt
146
-
147
- uploadedBy User @relation("MediaUploadedBy", fields: [uploadedById], references: [id], onDelete: Restrict)
148
- folder Folder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
149
-
150
- @@index([folderId])
151
- @@index([mimeType])
152
- @@index([createdAt])
153
- }
154
-
155
- model Version {
156
- id String @id @default(cuid())
157
- documentId String
158
- document Document @relation(fields: [documentId], references: [id], onDelete: Cascade)
159
- data Json
160
- changedById String
161
- changedBy User @relation(fields: [changedById], references: [id], onDelete: Restrict)
162
- changeType String @default("UPDATE")
163
- createdAt DateTime @default(now())
164
-
165
- @@index([documentId])
166
- @@index([createdAt])
167
- }
96
+ ${CMS_SCHEMA_MARKER} ─────────────────────────────────────────────────────────
97
+ // Auto-injected by \`actuate db:init\` from the installed @actuate-media/cms-core
98
+ // package's canonical prisma/schema.prisma (the single source of truth). Do not
99
+ // edit by hand — re-run \`actuate db:init --force\` after upgrading cms-core.
168
100
 
169
- model Folder {
170
- id String @id @default(cuid())
171
- name String
172
- scope String
173
- parentId String?
174
- position Int @default(0)
175
- createdAt DateTime @default(now())
176
-
177
- parent Folder? @relation("FolderTree", fields: [parentId], references: [id], onDelete: Cascade)
178
- children Folder[] @relation("FolderTree")
179
- documents Document[]
180
- media Media[]
181
-
182
- @@index([scope])
183
- @@index([parentId])
184
- @@index([scope, parentId, position])
185
- }
186
-
187
- model Redirect {
188
- id String @id @default(cuid())
189
- source String
190
- destination String
191
- statusCode Int @default(301)
192
- isRegex Boolean @default(false)
193
- notes String?
194
- createdAt DateTime @default(now())
195
- updatedAt DateTime @updatedAt
196
-
197
- @@unique([source])
198
- @@index([createdAt])
199
- }
200
-
201
- model FormSubmission {
202
- id String @id @default(cuid())
203
- formId String
204
- form Document @relation(fields: [formId], references: [id], onDelete: Cascade)
205
- data Json
206
- attribution Json?
207
- submittedAt DateTime @default(now())
208
- createdAt DateTime @default(now())
209
-
210
- @@index([formId])
211
- @@index([submittedAt])
212
- @@index([createdAt])
213
- }
214
-
215
- model AuditLog {
216
- id String @id @default(cuid())
217
- event String
218
- userId String?
219
- user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
220
- details Json?
221
- ipAddress String?
222
- userAgent String?
223
- createdAt DateTime @default(now())
224
-
225
- @@index([event])
226
- @@index([userId])
227
- @@index([createdAt])
228
- }
229
-
230
- model PasswordResetToken {
231
- id String @id @default(cuid())
232
- userId String
233
- tokenHash String
234
- expiresAt DateTime
235
- usedAt DateTime?
236
- createdAt DateTime @default(now())
237
-
238
- @@index([tokenHash])
239
- @@index([userId])
240
- }
241
-
242
- model MediaUsage {
243
- id String @id @default(cuid())
244
- mediaId String
245
- documentId String
246
- fieldPath String?
247
- createdAt DateTime @default(now())
248
-
249
- @@unique([mediaId, documentId, fieldPath])
250
- @@index([mediaId])
251
- @@index([documentId])
252
- }
253
-
254
- model ScriptTag {
255
- id String @id @default(cuid())
256
- name String
257
- code String @db.Text
258
- placement String
259
- scope String
260
- targetPaths String[]
261
- priority Int @default(100)
262
- enabled Boolean @default(true)
263
- createdAt DateTime @default(now())
264
- updatedAt DateTime @updatedAt
265
-
266
- @@index([enabled])
267
- @@index([placement])
268
- }
269
-
270
- model PageTemplate {
271
- id String @id @default(cuid())
272
- name String
273
- description String?
274
- category String @default("content")
275
- tree Json
276
- thumbnail String?
277
- builtIn Boolean @default(false)
278
- createdAt DateTime @default(now())
279
- updatedAt DateTime @updatedAt
280
-
281
- @@index([category])
282
- @@index([builtIn])
283
- }
284
-
285
- model SavedSection {
286
- id String @id @default(cuid())
287
- name String
288
- description String?
289
- category String @default("content")
290
- tree Json
291
- thumbnail String?
292
- usageCount Int @default(0)
293
- createdAt DateTime @default(now())
294
- updatedAt DateTime @updatedAt
295
-
296
- @@index([category])
297
- }
101
+ ${models}
298
102
  `;
299
103
  }
104
+ async function fileExists(filePath) {
105
+ try {
106
+ await access(filePath);
107
+ return true;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
300
113
  export function registerDbInitCommand(program) {
301
114
  program
302
115
  .command('db:init')
303
- .description('Add Actuate CMS models to your Prisma schema and generate the client')
116
+ .description('Add Actuate CMS models (from the installed cms-core) to your Prisma schema')
304
117
  .option('--schema <path>', 'Path to schema.prisma', 'prisma/schema.prisma')
305
118
  .option('--migrate', 'Run prisma migrate dev after adding models')
306
119
  .option('--force', 'Overwrite existing CMS models if present')
@@ -312,7 +125,16 @@ export function registerDbInitCommand(program) {
312
125
  process.exitCode = 1;
313
126
  return;
314
127
  }
315
- const spinner = ora('Reading Prisma schema...').start();
128
+ const spinner = ora('Reading canonical Actuate schema...').start();
129
+ const canonical = await readCanonicalCmsSchema();
130
+ if (!canonical) {
131
+ spinner.fail('Could not locate @actuate-media/cms-core.');
132
+ logger.info('Install it first: `npm install @actuate-media/cms-core`.');
133
+ process.exitCode = 1;
134
+ return;
135
+ }
136
+ const fragment = wrapFragment(extractModelsFragment(canonical));
137
+ spinner.text = 'Reading Prisma schema...';
316
138
  let content;
317
139
  try {
318
140
  content = await readFile(schemaPath, 'utf-8');
@@ -333,7 +155,7 @@ export function registerDbInitCommand(program) {
333
155
  content = content.substring(0, markerIndex).trimEnd() + '\n';
334
156
  }
335
157
  spinner.text = 'Adding Actuate CMS models...';
336
- const updatedContent = content.trimEnd() + '\n' + getCmsSchemaFragment();
158
+ const updatedContent = content.trimEnd() + '\n' + fragment;
337
159
  try {
338
160
  await writeFile(schemaPath, updatedContent);
339
161
  spinner.succeed('Actuate CMS models added to schema.');
@@ -1 +1 @@
1
- {"version":3,"file":"db-init.js","sourceRoot":"","sources":["../../src/commands/db-init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"db-init.js","sourceRoot":"","sources":["../../src/commands/db-init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { Command } from 'commander';
2
+ /**
3
+ * Build the consumer's `schema.prisma` from cms-core's canonical schema: strip
4
+ * cms-core's own generator/datasource blocks and prepend the consumer header
5
+ * (client output `../generated/prisma`, no datasource `url` — supplied by
6
+ * `prisma.config.ts`). Pure for testing. Mirrors the scaffolder's builder.
7
+ */
8
+ export declare function buildConsumerSchema(coreSchemaSource: string): string;
9
+ /**
10
+ * Resolve the installed `@actuate-media/cms-core` package's `prisma/` directory
11
+ * (the source of truth for schema + migrations). Overridable for tests.
12
+ */
13
+ export declare let resolveCmsCorePrismaDir: () => string | null;
14
+ export declare function setCmsCorePrismaDirResolver(resolver: typeof resolveCmsCorePrismaDir): void;
15
+ export declare function resetCmsCorePrismaDirResolver(): void;
16
+ export interface DbSyncResult {
17
+ schemaWritten: boolean;
18
+ migrationsAdded: string[];
19
+ skippedReason?: string;
20
+ }
21
+ /**
22
+ * Core sync logic, separated from CLI plumbing for testing. Additive for
23
+ * migrations (never deletes existing ones — they are immutable history), and
24
+ * guarded for the schema (won't overwrite a non-auto-synced schema without
25
+ * `force`).
26
+ */
27
+ export declare function syncPrismaAssets(consumerSchemaPath: string, corePrismaDir: string, opts?: {
28
+ force?: boolean;
29
+ }): Promise<DbSyncResult>;
30
+ export declare function registerDbSyncCommand(program: Command): void;
31
+ //# sourceMappingURL=db-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-sync.d.ts","sourceRoot":"","sources":["../../src/commands/db-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAmCnC;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAcpE;AAED;;;GAGG;AACH,eAAO,IAAI,uBAAuB,QAAO,MAAM,GAAG,IAajD,CAAA;AAID,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,OAAO,uBAAuB,GAAG,IAAI,CAE1F;AAED,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD;AAgBD,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,OAAO,CAAA;IACtB,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,MAAM,EACrB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,YAAY,CAAC,CAiDvB;AAsDD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAO5D"}
@@ -0,0 +1,195 @@
1
+ import { access, cp, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { createRequire } from 'node:module';
5
+ import ora from 'ora';
6
+ import { logger } from '../utils/logger.js';
7
+ const require = createRequire(import.meta.url);
8
+ // Marker that identifies a schema this CLI/scaffolder owns (auto-synced from
9
+ // cms-core). We refuse to overwrite a schema lacking it unless --force, so a
10
+ // hand-customized schema is never silently clobbered.
11
+ const AUTO_SYNCED_MARKER = 'AUTO-SYNCED from @actuate-media/cms-core';
12
+ // Must match create-actuate-cms/scripts/sync-prisma-assets.ts `SCAFFOLD_SCHEMA_HEADER`
13
+ // so re-syncing a scaffolded project is idempotent (no spurious diffs).
14
+ const SCHEMA_HEADER = `// ─────────────────────────────────────────────────────────────────────────────
15
+ // Actuate CMS — Prisma schema
16
+ //
17
+ // AUTO-SYNCED from @actuate-media/cms-core. Do NOT edit the model definitions
18
+ // by hand — they must match the bundled migrations and cms-core's API layer.
19
+ // (Generated by \`actuate db:sync\`)
20
+ // ─────────────────────────────────────────────────────────────────────────────
21
+
22
+ generator client {
23
+ provider = "prisma-client"
24
+ output = "../generated/prisma"
25
+ previewFeatures = ["fullTextSearchPostgres", "relationJoins"]
26
+ }
27
+
28
+ datasource db {
29
+ provider = "postgresql"
30
+ }`;
31
+ /**
32
+ * Build the consumer's `schema.prisma` from cms-core's canonical schema: strip
33
+ * cms-core's own generator/datasource blocks and prepend the consumer header
34
+ * (client output `../generated/prisma`, no datasource `url` — supplied by
35
+ * `prisma.config.ts`). Pure for testing. Mirrors the scaffolder's builder.
36
+ */
37
+ export function buildConsumerSchema(coreSchemaSource) {
38
+ const datasourceMatch = coreSchemaSource.match(/datasource\s+\w+\s*\{[\s\S]*?\}/);
39
+ if (!datasourceMatch || datasourceMatch.index === undefined) {
40
+ throw new Error('Could not locate the `datasource` block in cms-core schema.prisma');
41
+ }
42
+ const body = coreSchemaSource
43
+ .slice(datasourceMatch.index + datasourceMatch[0].length)
44
+ .replace(/^\s+/, '');
45
+ if (!/@@map\("actuate_users"\)/.test(body)) {
46
+ throw new Error('cms-core schema body is missing `@@map("actuate_users")` — aborting sync');
47
+ }
48
+ return `${SCHEMA_HEADER}\n\n${body.trimEnd()}\n`;
49
+ }
50
+ /**
51
+ * Resolve the installed `@actuate-media/cms-core` package's `prisma/` directory
52
+ * (the source of truth for schema + migrations). Overridable for tests.
53
+ */
54
+ export let resolveCmsCorePrismaDir = () => {
55
+ try {
56
+ const exported = require.resolve('@actuate-media/cms-core/prisma/schema');
57
+ return dirname(exported);
58
+ }
59
+ catch {
60
+ /* exports map missing the subpath — try the main entry */
61
+ }
62
+ try {
63
+ const mainEntry = require.resolve('@actuate-media/cms-core');
64
+ return join(dirname(mainEntry), '..', 'prisma');
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ };
70
+ const defaultPrismaDirResolver = resolveCmsCorePrismaDir;
71
+ export function setCmsCorePrismaDirResolver(resolver) {
72
+ resolveCmsCorePrismaDir = resolver;
73
+ }
74
+ export function resetCmsCorePrismaDirResolver() {
75
+ resolveCmsCorePrismaDir = defaultPrismaDirResolver;
76
+ }
77
+ async function listMigrationDirs(dir) {
78
+ try {
79
+ const entries = await readdir(dir, { withFileTypes: true });
80
+ return entries.filter((e) => e.isDirectory()).map((e) => e.name);
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ }
86
+ /**
87
+ * Core sync logic, separated from CLI plumbing for testing. Additive for
88
+ * migrations (never deletes existing ones — they are immutable history), and
89
+ * guarded for the schema (won't overwrite a non-auto-synced schema without
90
+ * `force`).
91
+ */
92
+ export async function syncPrismaAssets(consumerSchemaPath, corePrismaDir, opts = {}) {
93
+ const coreSchemaPath = join(corePrismaDir, 'schema.prisma');
94
+ const coreSchema = await readFile(coreSchemaPath, 'utf-8');
95
+ const nextSchema = buildConsumerSchema(coreSchema);
96
+ const consumerDir = dirname(consumerSchemaPath);
97
+ const consumerMigrationsDir = join(consumerDir, 'migrations');
98
+ const coreMigrationsDir = join(corePrismaDir, 'migrations');
99
+ // Guard the schema overwrite.
100
+ let schemaWritten = false;
101
+ let skippedReason;
102
+ const existing = existsSync(consumerSchemaPath)
103
+ ? await readFile(consumerSchemaPath, 'utf-8')
104
+ : null;
105
+ if (existing && !existing.includes(AUTO_SYNCED_MARKER) && !opts.force) {
106
+ skippedReason =
107
+ 'schema.prisma is not an auto-synced Actuate schema (no AUTO-SYNCED marker). Re-run with --force to overwrite it.';
108
+ }
109
+ else {
110
+ await mkdir(consumerDir, { recursive: true });
111
+ if (existing !== nextSchema) {
112
+ await writeFile(consumerSchemaPath, nextSchema);
113
+ schemaWritten = true;
114
+ }
115
+ }
116
+ // Additively copy any cms-core migrations the consumer doesn't already have.
117
+ const coreMigrations = await listMigrationDirs(coreMigrationsDir);
118
+ const existingMigrations = new Set(await listMigrationDirs(consumerMigrationsDir));
119
+ const migrationsAdded = [];
120
+ if (coreMigrations.length > 0) {
121
+ await mkdir(consumerMigrationsDir, { recursive: true });
122
+ const lockSrc = join(coreMigrationsDir, 'migration_lock.toml');
123
+ const lockDest = join(consumerMigrationsDir, 'migration_lock.toml');
124
+ if (existsSync(lockSrc) && !existsSync(lockDest)) {
125
+ await cp(lockSrc, lockDest);
126
+ }
127
+ for (const name of coreMigrations) {
128
+ if (existingMigrations.has(name))
129
+ continue;
130
+ await cp(join(coreMigrationsDir, name), join(consumerMigrationsDir, name), {
131
+ recursive: true,
132
+ });
133
+ migrationsAdded.push(name);
134
+ }
135
+ }
136
+ return { schemaWritten, migrationsAdded, skippedReason };
137
+ }
138
+ async function runDbSync(options) {
139
+ const consumerSchemaPath = resolve(process.cwd(), options.schema);
140
+ const spinner = ora('Locating @actuate-media/cms-core…').start();
141
+ const corePrismaDir = resolveCmsCorePrismaDir();
142
+ if (!corePrismaDir) {
143
+ spinner.fail('Could not locate @actuate-media/cms-core.');
144
+ logger.info('Install it first: `npm install @actuate-media/cms-core`.');
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ try {
149
+ await access(join(corePrismaDir, 'schema.prisma'));
150
+ }
151
+ catch {
152
+ spinner.fail(`cms-core does not ship a Prisma schema at ${corePrismaDir}.`);
153
+ process.exitCode = 1;
154
+ return;
155
+ }
156
+ spinner.text = 'Syncing schema + migrations…';
157
+ let result;
158
+ try {
159
+ result = await syncPrismaAssets(consumerSchemaPath, corePrismaDir, { force: options.force });
160
+ }
161
+ catch (err) {
162
+ spinner.fail('Failed to sync Prisma assets.');
163
+ logger.error(err instanceof Error ? err.message : String(err));
164
+ process.exitCode = 1;
165
+ return;
166
+ }
167
+ spinner.succeed('Prisma assets synced from cms-core.');
168
+ if (result.skippedReason) {
169
+ logger.warn(`Schema not updated: ${result.skippedReason}`);
170
+ }
171
+ else if (result.schemaWritten) {
172
+ logger.success('schema.prisma refreshed.');
173
+ }
174
+ else {
175
+ logger.info('schema.prisma already up to date.');
176
+ }
177
+ if (result.migrationsAdded.length > 0) {
178
+ logger.success(`Added ${result.migrationsAdded.length} new migration(s).`);
179
+ }
180
+ else {
181
+ logger.info('No new migrations to add.');
182
+ }
183
+ if (result.schemaWritten || result.migrationsAdded.length > 0) {
184
+ logger.info('Next: run `npx prisma migrate deploy` then `npx prisma generate`.');
185
+ }
186
+ }
187
+ export function registerDbSyncCommand(program) {
188
+ program
189
+ .command('db:sync')
190
+ .description('Sync the canonical Prisma schema + migrations from the installed cms-core')
191
+ .option('--schema <path>', 'Path to schema.prisma', 'prisma/schema.prisma')
192
+ .option('--force', 'Overwrite schema.prisma even if it lacks the AUTO-SYNCED marker')
193
+ .action(runDbSync);
194
+ }
195
+ //# sourceMappingURL=db-sync.js.map