@actuate-media/cli 0.11.2 โ 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +34 -34
- package/CHANGELOG.md +16 -0
- package/dist/commands/migrate-meta.d.ts +3 -0
- package/dist/commands/migrate-meta.d.ts.map +1 -0
- package/dist/commands/migrate-meta.js +81 -0
- package/dist/commands/migrate-meta.js.map +1 -0
- package/dist/commands/migrate-schema.d.ts +3 -0
- package/dist/commands/migrate-schema.d.ts.map +1 -0
- package/dist/commands/migrate-schema.js +84 -0
- package/dist/commands/migrate-schema.js.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/commands/migrate-meta.ts +107 -0
- package/src/commands/migrate-schema.ts +110 -0
- package/src/index.ts +4 -0
package/.turbo/turbo-build.log
CHANGED
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
1
1
|
|
|
2
|
-
> @actuate-media/cli@0.
|
|
2
|
+
> @actuate-media/cli@0.12.0 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
|
|
13
|
-
[32mโ[39m src/__tests__/deployment-diagnostics.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m
|
|
8
|
+
[32mโ[39m dist/__tests__/db-sync.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m 233[2mms[22m[39m
|
|
9
|
+
[32mโ[39m dist/__tests__/seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m 128[2mms[22m[39m
|
|
10
|
+
[32mโ[39m src/__tests__/db-sync.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 219[2mms[22m[39m
|
|
11
|
+
[32mโ[39m dist/__tests__/deployment-diagnostics.test.js [2m([22m[2m9 tests[22m[2m)[22m[32m 35[2mms[22m[39m
|
|
12
|
+
[32mโ[39m src/__tests__/seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 164[2mms[22m[39m
|
|
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
|
-
[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
15
|
โ Actuate CMS models added to schema.
|
|
17
16
|
- Running prisma generate...
|
|
17
|
+
[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
|
|
18
18
|
[22m[39mโ Prisma client generated.
|
|
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`.
|
|
23
22
|
- Reading canonical Actuate schema...
|
|
24
|
-
|
|
25
23
|
โ Could not locate @actuate-media/cms-core.
|
|
24
|
+
[22m[39mโน Install it first: `npm install @actuate-media/cms-core`.
|
|
25
|
+
|
|
26
26
|
- Reading canonical Actuate schema...
|
|
27
27
|
โ Actuate CMS models added to schema.
|
|
28
|
-
- Running prisma generate...
|
|
29
28
|
[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
|
|
30
29
|
[22m[39mโ Prisma client generated.
|
|
30
|
+
- Running prisma generate...
|
|
31
31
|
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
32
32
|
|
|
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[32m
|
|
35
|
+
[32mโ[39m dist/__tests__/db-init.test.js [2m([22m[2m4 tests[22m[2m)[22m[32m 228[2mms[22m[39m
|
|
36
36
|
- Reading canonical Actuate schema...
|
|
37
|
-
โ Actuate CMS models added to schema.
|
|
38
|
-
- Running prisma generate...
|
|
39
37
|
[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
|
|
40
38
|
[22m[39mโ Prisma client generated.
|
|
41
39
|
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
42
40
|
|
|
41
|
+
โ Actuate CMS models added to schema.
|
|
42
|
+
- Running prisma generate...
|
|
43
|
+
- Reading canonical Actuate schema...
|
|
43
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
|
+
โ Could not locate @actuate-media/cms-core.
|
|
44
46
|
[22m[39mโน Install it first: `npm install @actuate-media/cms-core`.
|
|
45
|
-
- Reading canonical Actuate schema...
|
|
46
47
|
|
|
47
|
-
โ Could not locate @actuate-media/cms-core.
|
|
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
|
-
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
52
|
-
|
|
53
51
|
โ Actuate CMS models added to schema.
|
|
52
|
+
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
54
53
|
- Running prisma generate...
|
|
54
|
+
|
|
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 246[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[32m 249[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,13 +312,13 @@ 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__/vercel-env-matrix.test.js [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
319
|
-
[32mโ[39m src/__tests__/vercel-env-matrix.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m
|
|
320
|
-
[32mโ[39m dist/__tests__/load-dotenv.test.js [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
321
|
-
[32mโ[39m src/__tests__/load-dotenv.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m
|
|
315
|
+
[32mโ[39m src/__tests__/mcp-init.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 134[2mms[22m[39m
|
|
316
|
+
[32mโ[39m dist/__tests__/form-seed.test.js [2m([22m[2m10 tests[22m[2m)[22m[32m 31[2mms[22m[39m
|
|
317
|
+
[32mโ[39m src/__tests__/form-seed.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 34[2mms[22m[39m
|
|
318
|
+
[32mโ[39m dist/__tests__/vercel-env-matrix.test.js [2m([22m[2m6 tests[22m[2m)[22m[32m 28[2mms[22m[39m
|
|
319
|
+
[32mโ[39m src/__tests__/vercel-env-matrix.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 30[2mms[22m[39m
|
|
320
|
+
[32mโ[39m dist/__tests__/load-dotenv.test.js [2m([22m[2m3 tests[22m[2m)[22m[32m 37[2mms[22m[39m
|
|
321
|
+
[32mโ[39m src/__tests__/load-dotenv.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 44[2mms[22m[39m
|
|
322
322
|
- Reading canonical Actuate schema...
|
|
323
323
|
โ Actuate CMS models added to schema.
|
|
324
324
|
- Running prisma generate...
|
|
@@ -326,20 +326,20 @@ Next steps
|
|
|
326
326
|
[22m[39mโ Prisma client generated.
|
|
327
327
|
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
328
328
|
|
|
329
|
-
[32mโ[39m dist/__tests__/schema-fragment.test.js [2m([22m[2m1 test[22m[2m)[22m[32m
|
|
329
|
+
[32mโ[39m dist/__tests__/schema-fragment.test.js [2m([22m[2m1 test[22m[2m)[22m[32m 80[2mms[22m[39m
|
|
330
330
|
- Reading canonical Actuate schema...
|
|
331
331
|
โ Actuate CMS models added to schema.
|
|
332
|
-
- Running prisma generate...
|
|
333
332
|
[90mstdout[2m | src/__tests__/schema-fragment.test.ts[2m > [22m[2mdb:init schema fragment[2m > [22m[2minjects all deploy-critical Actuate models
|
|
334
333
|
[22m[39mโ Prisma client generated.
|
|
334
|
+
- Running prisma generate...
|
|
335
335
|
โน Run `npx prisma migrate dev --name actuate-cms` to create the migration.
|
|
336
336
|
|
|
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
|
|
337
|
+
[32mโ[39m src/__tests__/schema-fragment.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 66[2mms[22m[39m
|
|
338
|
+
[32mโ[39m dist/__tests__/init.test.js [2m([22m[2m2 tests[22m[2m)[22m[32m 16[2mms[22m[39m
|
|
339
|
+
[32mโ[39m src/__tests__/init.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 15[2mms[22m[39m
|
|
340
340
|
|
|
341
341
|
[2m Test Files [22m [1m[32m20 passed[39m[22m[90m (20)[39m
|
|
342
342
|
[2m Tests [22m [1m[32m122 passed[39m[22m[90m (122)[39m
|
|
343
|
-
[2m Start at [22m
|
|
344
|
-
[2m Duration [22m
|
|
343
|
+
[2m Start at [22m 05:27:27
|
|
344
|
+
[2m Duration [22m 21.87s[2m (transform 2.20s, setup 0ms, import 5.83s, tests 2.07s, environment 21ms)[22m
|
|
345
345
|
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @actuate-media/cli
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- bc51a1d: Align SEO audit with live page meta output, expand audit checks, wire redirect/link signals, and add `actuate migrate:meta` for bulk meta backfill.
|
|
8
|
+
|
|
9
|
+
## 0.11.3
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 9d4e24c: Hide the redundant site name headline on the login screen and in the admin sidebar when a logo image is displayed.
|
|
14
|
+
|
|
15
|
+
Serve favicons as properly sized 32ร32 PNGs (and 180ร180 apple-touch icons) from dedicated public routes so SVG and oversized sources render correctly in browser tabs.
|
|
16
|
+
|
|
17
|
+
Align SEO audit schema/canonical detection with public page rendering, add `actuate migrate:schema` to backfill structuredDataType on existing content, and fix route-contract tests for new favicon endpoints.
|
|
18
|
+
|
|
3
19
|
## 0.11.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-meta.d.ts","sourceRoot":"","sources":["../../src/commands/migrate-meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAgGnC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAUjE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { connectProjectDatabase } from '../utils/database.js';
|
|
5
|
+
import { loadProjectEnv } from '../utils/load-dotenv.js';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
async function loadProjectConfig(configPath) {
|
|
8
|
+
try {
|
|
9
|
+
const { setActuateConfig } = await import('@actuate-media/cms-core');
|
|
10
|
+
const { tsImport } = await import('tsx/esm/api');
|
|
11
|
+
const abs = pathToFileURL(resolve(configPath)).href;
|
|
12
|
+
const mod = (await tsImport(abs, import.meta.url));
|
|
13
|
+
const config = mod.default ?? mod.config;
|
|
14
|
+
if (config && typeof config === 'object') {
|
|
15
|
+
setActuateConfig(config);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
logger.warn(`Could not load ${configPath} โ meta defaults will use collection slug heuristics only.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** `actuate migrate:meta` โ backfill metaTitle/metaDescription on content documents. */
|
|
23
|
+
async function runMigrateMeta(options) {
|
|
24
|
+
const dryRun = options.dryRun ?? false;
|
|
25
|
+
const batchSize = options.batchSize ? Number.parseInt(options.batchSize, 10) : undefined;
|
|
26
|
+
if (batchSize !== undefined && (!Number.isFinite(batchSize) || batchSize <= 0)) {
|
|
27
|
+
logger.error('--batch-size must be a positive integer.');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
await loadProjectEnv(process.cwd()).then((env) => {
|
|
31
|
+
for (const [key, value] of Object.entries(env)) {
|
|
32
|
+
if (value !== undefined && process.env[key] === undefined) {
|
|
33
|
+
process.env[key] = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
await loadProjectConfig(options.config ?? 'actuate.config.ts');
|
|
38
|
+
let connection = null;
|
|
39
|
+
const spinner = ora(dryRun ? 'Scanning content documents (dry run)โฆ' : 'Backfilling meta title/descriptionโฆ').start();
|
|
40
|
+
try {
|
|
41
|
+
connection = await connectProjectDatabase();
|
|
42
|
+
const db = connection.db;
|
|
43
|
+
const { migrateMetaFields } = await import('@actuate-media/cms-core');
|
|
44
|
+
const admin = await db.user.findFirst({ where: { role: 'ADMIN' } });
|
|
45
|
+
if (!admin) {
|
|
46
|
+
spinner.fail('No ADMIN user found. Create an admin (setup wizard or seed) first.');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const ctx = { userId: admin.id, role: 'ADMIN', db: connection.db, locale: 'en' };
|
|
50
|
+
const result = await migrateMetaFields(ctx, { dryRun, batchSize });
|
|
51
|
+
spinner.succeed(dryRun
|
|
52
|
+
? `Dry run complete โ ${result.migrated} document(s) would be updated.`
|
|
53
|
+
: `Updated ${result.migrated} document(s).`);
|
|
54
|
+
logger.info(` Scanned: ${result.scanned}`);
|
|
55
|
+
logger.info(` Migrated: ${result.migrated}`);
|
|
56
|
+
logger.info(` Skipped: ${result.skipped}`);
|
|
57
|
+
if (result.migratedIds.length > 0) {
|
|
58
|
+
logger.info(` IDs: ${result.migratedIds.join(', ')}`);
|
|
59
|
+
}
|
|
60
|
+
logger.info('');
|
|
61
|
+
logger.info('Next: re-run the SEO audit in Settings โ SEO โ Audit.');
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
65
|
+
spinner.fail(`Meta migration failed: ${message}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await connection?.disconnect();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function registerMigrateMetaCommand(program) {
|
|
73
|
+
program
|
|
74
|
+
.command('migrate:meta')
|
|
75
|
+
.description('Backfill metaTitle/metaDescription from title templates and key takeaways. Idempotent.')
|
|
76
|
+
.option('--dry-run', 'Report what would change without writing')
|
|
77
|
+
.option('--batch-size <n>', 'Documents to scan per DB page (default 100)')
|
|
78
|
+
.option('--config <path>', 'Path to actuate.config.ts', 'actuate.config.ts')
|
|
79
|
+
.action(runMigrateMeta);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=migrate-meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-meta.js","sourceRoot":"","sources":["../../src/commands/migrate-meta.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,GAAG,MAAM,KAAK,CAAA;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAQ3C,KAAK,UAAU,iBAAiB,CAAC,UAAkB;IACjD,IAAI,CAAC;QACH,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;QACpE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;QAChD,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;QACnD,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAGhD,CAAA;QACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAA;QACxC,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YACzC,gBAAgB,CAAC,MAAe,CAAC,CAAA;QACnC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,CACT,kBAAkB,UAAU,4DAA4D,CACzF,CAAA;IACH,CAAC;AACH,CAAC;AAED,wFAAwF;AACxF,KAAK,UAAU,cAAc,CAAC,OAA2B;IACvD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAA;IACtC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACxF,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAA;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC1D,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;YAC1B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,iBAAiB,CAAC,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAAC,CAAA;IAE9D,IAAI,UAAU,GAA4D,IAAI,CAAA;IAC9E,MAAM,OAAO,GAAG,GAAG,CACjB,MAAM,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,qCAAqC,CACzF,CAAC,KAAK,EAAE,CAAA;IAET,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,sBAAsB,EAAE,CAAA;QAC3C,MAAM,EAAE,GAAG,UAAU,CAAC,EAErB,CAAA;QAED,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAA;QAErE,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACnE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAA;YAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;QAChF,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAA;QAElE,OAAO,CAAC,OAAO,CACb,MAAM;YACJ,CAAC,CAAC,sBAAsB,MAAM,CAAC,QAAQ,gCAAgC;YACvE,CAAC,CAAC,WAAW,MAAM,CAAC,QAAQ,eAAe,CAC9C,CAAA;QACD,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;QAC5C,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7C,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;QAC5C,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAC7D,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACf,MAAM,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAA;IACtE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,OAAO,CAAC,IAAI,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAA;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,MAAM,UAAU,EAAE,UAAU,EAAE,CAAA;IAChC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAgB;IACzD,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CACV,wFAAwF,CACzF;SACA,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;SAC/D,MAAM,CAAC,kBAAkB,EAAE,6CAA6C,CAAC;SACzE,MAAM,CAAC,iBAAiB,EAAE,2BAA2B,EAAE,mBAAmB,CAAC;SAC3E,MAAM,CAAC,cAAc,CAAC,CAAA;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-schema.d.ts","sourceRoot":"","sources":["../../src/commands/migrate-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAmGnC,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAUnE"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { connectProjectDatabase } from '../utils/database.js';
|
|
5
|
+
import { loadProjectEnv } from '../utils/load-dotenv.js';
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
async function loadProjectConfig(configPath) {
|
|
8
|
+
try {
|
|
9
|
+
const { setActuateConfig } = await import('@actuate-media/cms-core');
|
|
10
|
+
const { tsImport } = await import('tsx/esm/api');
|
|
11
|
+
const abs = pathToFileURL(resolve(configPath)).href;
|
|
12
|
+
const mod = (await tsImport(abs, import.meta.url));
|
|
13
|
+
const config = mod.default ?? mod.config;
|
|
14
|
+
if (config && typeof config === 'object') {
|
|
15
|
+
setActuateConfig(config);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
logger.warn(`Could not load ${configPath} โ schema defaults will use collection slug heuristics only.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `actuate migrate:schema` โ backfill structuredDataType/schemaType and JSON-LD
|
|
24
|
+
* on published content documents. Idempotent.
|
|
25
|
+
*/
|
|
26
|
+
async function runMigrateSchema(options) {
|
|
27
|
+
const dryRun = options.dryRun ?? false;
|
|
28
|
+
const batchSize = options.batchSize ? Number.parseInt(options.batchSize, 10) : undefined;
|
|
29
|
+
if (batchSize !== undefined && (!Number.isFinite(batchSize) || batchSize <= 0)) {
|
|
30
|
+
logger.error('--batch-size must be a positive integer.');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
await loadProjectEnv(process.cwd()).then((env) => {
|
|
34
|
+
for (const [key, value] of Object.entries(env)) {
|
|
35
|
+
if (value !== undefined && process.env[key] === undefined) {
|
|
36
|
+
process.env[key] = value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
await loadProjectConfig(options.config ?? 'actuate.config.ts');
|
|
41
|
+
let connection = null;
|
|
42
|
+
const spinner = ora(dryRun ? 'Scanning content documents (dry run)โฆ' : 'Backfilling structured data fieldsโฆ').start();
|
|
43
|
+
try {
|
|
44
|
+
connection = await connectProjectDatabase();
|
|
45
|
+
const db = connection.db;
|
|
46
|
+
const { migrateStructuredDataFields } = await import('@actuate-media/cms-core');
|
|
47
|
+
const admin = await db.user.findFirst({ where: { role: 'ADMIN' } });
|
|
48
|
+
if (!admin) {
|
|
49
|
+
spinner.fail('No ADMIN user found. Create an admin (setup wizard or seed) first.');
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const ctx = { userId: admin.id, role: 'ADMIN', db: connection.db, locale: 'en' };
|
|
53
|
+
const result = await migrateStructuredDataFields(ctx, { dryRun, batchSize });
|
|
54
|
+
spinner.succeed(dryRun
|
|
55
|
+
? `Dry run complete โ ${result.migrated} document(s) would be updated.`
|
|
56
|
+
: `Updated ${result.migrated} document(s).`);
|
|
57
|
+
logger.info(` Scanned: ${result.scanned}`);
|
|
58
|
+
logger.info(` Migrated: ${result.migrated}`);
|
|
59
|
+
logger.info(` Skipped: ${result.skipped}`);
|
|
60
|
+
if (result.migratedIds.length > 0) {
|
|
61
|
+
logger.info(` IDs: ${result.migratedIds.join(', ')}`);
|
|
62
|
+
}
|
|
63
|
+
logger.info('');
|
|
64
|
+
logger.info('Next: re-run the SEO audit in Settings โ SEO โ Audit.');
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
68
|
+
spinner.fail(`Schema migration failed: ${message}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
await connection?.disconnect();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function registerMigrateSchemaCommand(program) {
|
|
76
|
+
program
|
|
77
|
+
.command('migrate:schema')
|
|
78
|
+
.description('Backfill structuredDataType/schemaType (and published JSON-LD) on content documents. Idempotent.')
|
|
79
|
+
.option('--dry-run', 'Report what would change without writing')
|
|
80
|
+
.option('--batch-size <n>', 'Documents to scan per DB page (default 100)')
|
|
81
|
+
.option('--config <path>', 'Path to actuate.config.ts', 'actuate.config.ts')
|
|
82
|
+
.action(runMigrateSchema);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=migrate-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-schema.js","sourceRoot":"","sources":["../../src/commands/migrate-schema.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { registerMigrateCommand } from './commands/migrate.js';
|
|
4
4
|
import { registerMigrateSectionsCommand } from './commands/migrate-sections.js';
|
|
5
|
+
import { registerMigrateSchemaCommand } from './commands/migrate-schema.js';
|
|
6
|
+
import { registerMigrateMetaCommand } from './commands/migrate-meta.js';
|
|
5
7
|
import { registerGenerateCommand } from './commands/generate.js';
|
|
6
8
|
import { registerSeedCommand } from './commands/seed.js';
|
|
7
9
|
import { registerImportCommand } from './commands/import.js';
|
|
@@ -22,6 +24,8 @@ program
|
|
|
22
24
|
.version('0.1.0');
|
|
23
25
|
registerMigrateCommand(program);
|
|
24
26
|
registerMigrateSectionsCommand(program);
|
|
27
|
+
registerMigrateSchemaCommand(program);
|
|
28
|
+
registerMigrateMetaCommand(program);
|
|
25
29
|
registerGenerateCommand(program);
|
|
26
30
|
registerSeedCommand(program);
|
|
27
31
|
registerImportCommand(program);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAA;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,8BAA8B,CAAC,OAAO,CAAC,CAAA;AACvC,uBAAuB,CAAC,OAAO,CAAC,CAAA;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,0BAA0B,CAAC,OAAO,CAAC,CAAA;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAA;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,0BAA0B,CAAC,OAAO,CAAC,CAAA;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,6BAA6B,CAAC,OAAO,CAAC,CAAA;AACtC,kBAAkB,CAAC,OAAO,CAAC,CAAA;AAE3B,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAA;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EACL,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAA;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAEtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,SAAS,CAAC;KACf,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,8BAA8B,CAAC,OAAO,CAAC,CAAA;AACvC,4BAA4B,CAAC,OAAO,CAAC,CAAA;AACrC,0BAA0B,CAAC,OAAO,CAAC,CAAA;AACnC,uBAAuB,CAAC,OAAO,CAAC,CAAA;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAA;AAC/B,0BAA0B,CAAC,OAAO,CAAC,CAAA;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,uBAAuB,CAAC,OAAO,CAAC,CAAA;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAA;AAC5B,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,0BAA0B,CAAC,OAAO,CAAC,CAAA;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAA;AAC9B,6BAA6B,CAAC,OAAO,CAAC,CAAA;AACtC,kBAAkB,CAAC,OAAO,CAAC,CAAA;AAE3B,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@actuate-media/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "CLI for Actuate CMS โ migrations, codegen, imports, exports, and upgrades",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"typescript": "^5.7.0",
|
|
30
30
|
"vitest": "^4.1.0",
|
|
31
|
-
"@actuate-media/cms-core": "0.
|
|
31
|
+
"@actuate-media/cms-core": "0.78.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "tsc",
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
import ora from 'ora'
|
|
5
|
+
import { connectProjectDatabase } from '../utils/database.js'
|
|
6
|
+
import { loadProjectEnv } from '../utils/load-dotenv.js'
|
|
7
|
+
import { logger } from '../utils/logger.js'
|
|
8
|
+
|
|
9
|
+
interface MigrateMetaOptions {
|
|
10
|
+
dryRun?: boolean
|
|
11
|
+
batchSize?: string
|
|
12
|
+
config?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function loadProjectConfig(configPath: string): Promise<void> {
|
|
16
|
+
try {
|
|
17
|
+
const { setActuateConfig } = await import('@actuate-media/cms-core')
|
|
18
|
+
const { tsImport } = await import('tsx/esm/api')
|
|
19
|
+
const abs = pathToFileURL(resolve(configPath)).href
|
|
20
|
+
const mod = (await tsImport(abs, import.meta.url)) as {
|
|
21
|
+
default?: unknown
|
|
22
|
+
config?: unknown
|
|
23
|
+
}
|
|
24
|
+
const config = mod.default ?? mod.config
|
|
25
|
+
if (config && typeof config === 'object') {
|
|
26
|
+
setActuateConfig(config as never)
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
logger.warn(
|
|
30
|
+
`Could not load ${configPath} โ meta defaults will use collection slug heuristics only.`,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** `actuate migrate:meta` โ backfill metaTitle/metaDescription on content documents. */
|
|
36
|
+
async function runMigrateMeta(options: MigrateMetaOptions): Promise<void> {
|
|
37
|
+
const dryRun = options.dryRun ?? false
|
|
38
|
+
const batchSize = options.batchSize ? Number.parseInt(options.batchSize, 10) : undefined
|
|
39
|
+
if (batchSize !== undefined && (!Number.isFinite(batchSize) || batchSize <= 0)) {
|
|
40
|
+
logger.error('--batch-size must be a positive integer.')
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await loadProjectEnv(process.cwd()).then((env) => {
|
|
45
|
+
for (const [key, value] of Object.entries(env)) {
|
|
46
|
+
if (value !== undefined && process.env[key] === undefined) {
|
|
47
|
+
process.env[key] = value
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
await loadProjectConfig(options.config ?? 'actuate.config.ts')
|
|
52
|
+
|
|
53
|
+
let connection: { db: unknown; disconnect: () => Promise<void> } | null = null
|
|
54
|
+
const spinner = ora(
|
|
55
|
+
dryRun ? 'Scanning content documents (dry run)โฆ' : 'Backfilling meta title/descriptionโฆ',
|
|
56
|
+
).start()
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
connection = await connectProjectDatabase()
|
|
60
|
+
const db = connection.db as {
|
|
61
|
+
user: { findFirst: (args: unknown) => Promise<{ id: string } | null> }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { migrateMetaFields } = await import('@actuate-media/cms-core')
|
|
65
|
+
|
|
66
|
+
const admin = await db.user.findFirst({ where: { role: 'ADMIN' } })
|
|
67
|
+
if (!admin) {
|
|
68
|
+
spinner.fail('No ADMIN user found. Create an admin (setup wizard or seed) first.')
|
|
69
|
+
process.exit(1)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const ctx = { userId: admin.id, role: 'ADMIN', db: connection.db, locale: 'en' }
|
|
73
|
+
const result = await migrateMetaFields(ctx, { dryRun, batchSize })
|
|
74
|
+
|
|
75
|
+
spinner.succeed(
|
|
76
|
+
dryRun
|
|
77
|
+
? `Dry run complete โ ${result.migrated} document(s) would be updated.`
|
|
78
|
+
: `Updated ${result.migrated} document(s).`,
|
|
79
|
+
)
|
|
80
|
+
logger.info(` Scanned: ${result.scanned}`)
|
|
81
|
+
logger.info(` Migrated: ${result.migrated}`)
|
|
82
|
+
logger.info(` Skipped: ${result.skipped}`)
|
|
83
|
+
if (result.migratedIds.length > 0) {
|
|
84
|
+
logger.info(` IDs: ${result.migratedIds.join(', ')}`)
|
|
85
|
+
}
|
|
86
|
+
logger.info('')
|
|
87
|
+
logger.info('Next: re-run the SEO audit in Settings โ SEO โ Audit.')
|
|
88
|
+
} catch (err) {
|
|
89
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
90
|
+
spinner.fail(`Meta migration failed: ${message}`)
|
|
91
|
+
process.exit(1)
|
|
92
|
+
} finally {
|
|
93
|
+
await connection?.disconnect()
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function registerMigrateMetaCommand(program: Command): void {
|
|
98
|
+
program
|
|
99
|
+
.command('migrate:meta')
|
|
100
|
+
.description(
|
|
101
|
+
'Backfill metaTitle/metaDescription from title templates and key takeaways. Idempotent.',
|
|
102
|
+
)
|
|
103
|
+
.option('--dry-run', 'Report what would change without writing')
|
|
104
|
+
.option('--batch-size <n>', 'Documents to scan per DB page (default 100)')
|
|
105
|
+
.option('--config <path>', 'Path to actuate.config.ts', 'actuate.config.ts')
|
|
106
|
+
.action(runMigrateMeta)
|
|
107
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
import { pathToFileURL } from 'node:url'
|
|
4
|
+
import ora from 'ora'
|
|
5
|
+
import { connectProjectDatabase } from '../utils/database.js'
|
|
6
|
+
import { loadProjectEnv } from '../utils/load-dotenv.js'
|
|
7
|
+
import { logger } from '../utils/logger.js'
|
|
8
|
+
|
|
9
|
+
interface MigrateSchemaOptions {
|
|
10
|
+
dryRun?: boolean
|
|
11
|
+
batchSize?: string
|
|
12
|
+
config?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function loadProjectConfig(configPath: string): Promise<void> {
|
|
16
|
+
try {
|
|
17
|
+
const { setActuateConfig } = await import('@actuate-media/cms-core')
|
|
18
|
+
const { tsImport } = await import('tsx/esm/api')
|
|
19
|
+
const abs = pathToFileURL(resolve(configPath)).href
|
|
20
|
+
const mod = (await tsImport(abs, import.meta.url)) as {
|
|
21
|
+
default?: unknown
|
|
22
|
+
config?: unknown
|
|
23
|
+
}
|
|
24
|
+
const config = mod.default ?? mod.config
|
|
25
|
+
if (config && typeof config === 'object') {
|
|
26
|
+
setActuateConfig(config as never)
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
logger.warn(
|
|
30
|
+
`Could not load ${configPath} โ schema defaults will use collection slug heuristics only.`,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* `actuate migrate:schema` โ backfill structuredDataType/schemaType and JSON-LD
|
|
37
|
+
* on published content documents. Idempotent.
|
|
38
|
+
*/
|
|
39
|
+
async function runMigrateSchema(options: MigrateSchemaOptions): Promise<void> {
|
|
40
|
+
const dryRun = options.dryRun ?? false
|
|
41
|
+
const batchSize = options.batchSize ? Number.parseInt(options.batchSize, 10) : undefined
|
|
42
|
+
if (batchSize !== undefined && (!Number.isFinite(batchSize) || batchSize <= 0)) {
|
|
43
|
+
logger.error('--batch-size must be a positive integer.')
|
|
44
|
+
process.exit(1)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await loadProjectEnv(process.cwd()).then((env) => {
|
|
48
|
+
for (const [key, value] of Object.entries(env)) {
|
|
49
|
+
if (value !== undefined && process.env[key] === undefined) {
|
|
50
|
+
process.env[key] = value
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
await loadProjectConfig(options.config ?? 'actuate.config.ts')
|
|
55
|
+
|
|
56
|
+
let connection: { db: unknown; disconnect: () => Promise<void> } | null = null
|
|
57
|
+
const spinner = ora(
|
|
58
|
+
dryRun ? 'Scanning content documents (dry run)โฆ' : 'Backfilling structured data fieldsโฆ',
|
|
59
|
+
).start()
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
connection = await connectProjectDatabase()
|
|
63
|
+
const db = connection.db as {
|
|
64
|
+
user: { findFirst: (args: unknown) => Promise<{ id: string } | null> }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { migrateStructuredDataFields } = await import('@actuate-media/cms-core')
|
|
68
|
+
|
|
69
|
+
const admin = await db.user.findFirst({ where: { role: 'ADMIN' } })
|
|
70
|
+
if (!admin) {
|
|
71
|
+
spinner.fail('No ADMIN user found. Create an admin (setup wizard or seed) first.')
|
|
72
|
+
process.exit(1)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const ctx = { userId: admin.id, role: 'ADMIN', db: connection.db, locale: 'en' }
|
|
76
|
+
const result = await migrateStructuredDataFields(ctx, { dryRun, batchSize })
|
|
77
|
+
|
|
78
|
+
spinner.succeed(
|
|
79
|
+
dryRun
|
|
80
|
+
? `Dry run complete โ ${result.migrated} document(s) would be updated.`
|
|
81
|
+
: `Updated ${result.migrated} document(s).`,
|
|
82
|
+
)
|
|
83
|
+
logger.info(` Scanned: ${result.scanned}`)
|
|
84
|
+
logger.info(` Migrated: ${result.migrated}`)
|
|
85
|
+
logger.info(` Skipped: ${result.skipped}`)
|
|
86
|
+
if (result.migratedIds.length > 0) {
|
|
87
|
+
logger.info(` IDs: ${result.migratedIds.join(', ')}`)
|
|
88
|
+
}
|
|
89
|
+
logger.info('')
|
|
90
|
+
logger.info('Next: re-run the SEO audit in Settings โ SEO โ Audit.')
|
|
91
|
+
} catch (err) {
|
|
92
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
93
|
+
spinner.fail(`Schema migration failed: ${message}`)
|
|
94
|
+
process.exit(1)
|
|
95
|
+
} finally {
|
|
96
|
+
await connection?.disconnect()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function registerMigrateSchemaCommand(program: Command): void {
|
|
101
|
+
program
|
|
102
|
+
.command('migrate:schema')
|
|
103
|
+
.description(
|
|
104
|
+
'Backfill structuredDataType/schemaType (and published JSON-LD) on content documents. Idempotent.',
|
|
105
|
+
)
|
|
106
|
+
.option('--dry-run', 'Report what would change without writing')
|
|
107
|
+
.option('--batch-size <n>', 'Documents to scan per DB page (default 100)')
|
|
108
|
+
.option('--config <path>', 'Path to actuate.config.ts', 'actuate.config.ts')
|
|
109
|
+
.action(runMigrateSchema)
|
|
110
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { Command } from 'commander'
|
|
3
3
|
import { registerMigrateCommand } from './commands/migrate.js'
|
|
4
4
|
import { registerMigrateSectionsCommand } from './commands/migrate-sections.js'
|
|
5
|
+
import { registerMigrateSchemaCommand } from './commands/migrate-schema.js'
|
|
6
|
+
import { registerMigrateMetaCommand } from './commands/migrate-meta.js'
|
|
5
7
|
import { registerGenerateCommand } from './commands/generate.js'
|
|
6
8
|
import { registerSeedCommand } from './commands/seed.js'
|
|
7
9
|
import { registerImportCommand } from './commands/import.js'
|
|
@@ -29,6 +31,8 @@ program
|
|
|
29
31
|
|
|
30
32
|
registerMigrateCommand(program)
|
|
31
33
|
registerMigrateSectionsCommand(program)
|
|
34
|
+
registerMigrateSchemaCommand(program)
|
|
35
|
+
registerMigrateMetaCommand(program)
|
|
32
36
|
registerGenerateCommand(program)
|
|
33
37
|
registerSeedCommand(program)
|
|
34
38
|
registerImportCommand(program)
|