@actuate-media/cli 0.4.1 → 0.5.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 (92) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +69 -12
  3. package/CHANGELOG.md +58 -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__/deployment-diagnostics.test.js.map +1 -1
  13. package/dist/__tests__/init.test.js.map +1 -1
  14. package/dist/__tests__/schema-fragment.test.js +1 -1
  15. package/dist/__tests__/schema-fragment.test.js.map +1 -1
  16. package/dist/__tests__/seed.test.js.map +1 -1
  17. package/dist/commands/db-init.d.ts +19 -2
  18. package/dist/commands/db-init.d.ts.map +1 -1
  19. package/dist/commands/db-init.js +128 -306
  20. package/dist/commands/db-init.js.map +1 -1
  21. package/dist/commands/db-status.d.ts +1 -1
  22. package/dist/commands/db-status.d.ts.map +1 -1
  23. package/dist/commands/db-status.js +33 -33
  24. package/dist/commands/db-status.js.map +1 -1
  25. package/dist/commands/db-sync.d.ts +31 -0
  26. package/dist/commands/db-sync.d.ts.map +1 -0
  27. package/dist/commands/db-sync.js +195 -0
  28. package/dist/commands/db-sync.js.map +1 -0
  29. package/dist/commands/doctor.d.ts +1 -1
  30. package/dist/commands/doctor.d.ts.map +1 -1
  31. package/dist/commands/doctor.js +48 -41
  32. package/dist/commands/doctor.js.map +1 -1
  33. package/dist/commands/export.d.ts +1 -1
  34. package/dist/commands/export.d.ts.map +1 -1
  35. package/dist/commands/export.js +32 -32
  36. package/dist/commands/export.js.map +1 -1
  37. package/dist/commands/generate.d.ts +1 -1
  38. package/dist/commands/generate.d.ts.map +1 -1
  39. package/dist/commands/generate.js +8 -8
  40. package/dist/commands/generate.js.map +1 -1
  41. package/dist/commands/import.d.ts +1 -1
  42. package/dist/commands/import.d.ts.map +1 -1
  43. package/dist/commands/import.js +55 -58
  44. package/dist/commands/import.js.map +1 -1
  45. package/dist/commands/init.d.ts.map +1 -1
  46. package/dist/commands/init.js.map +1 -1
  47. package/dist/commands/migrate.d.ts +1 -1
  48. package/dist/commands/migrate.d.ts.map +1 -1
  49. package/dist/commands/migrate.js +18 -24
  50. package/dist/commands/migrate.js.map +1 -1
  51. package/dist/commands/seed.d.ts +1 -1
  52. package/dist/commands/seed.d.ts.map +1 -1
  53. package/dist/commands/seed.js +156 -157
  54. package/dist/commands/seed.js.map +1 -1
  55. package/dist/commands/update-check.d.ts +1 -1
  56. package/dist/commands/update-check.d.ts.map +1 -1
  57. package/dist/commands/update-check.js +34 -27
  58. package/dist/commands/update-check.js.map +1 -1
  59. package/dist/commands/upgrade.d.ts +1 -1
  60. package/dist/commands/upgrade.d.ts.map +1 -1
  61. package/dist/commands/upgrade.js +46 -34
  62. package/dist/commands/upgrade.js.map +1 -1
  63. package/dist/deployment/diagnostics.d.ts.map +1 -1
  64. package/dist/deployment/diagnostics.js +7 -2
  65. package/dist/deployment/diagnostics.js.map +1 -1
  66. package/dist/index.js +17 -15
  67. package/dist/index.js.map +1 -1
  68. package/dist/utils/logger.d.ts.map +1 -1
  69. package/dist/utils/logger.js +5 -5
  70. package/dist/utils/logger.js.map +1 -1
  71. package/package.json +3 -3
  72. package/src/__tests__/db-init.test.ts +155 -0
  73. package/src/__tests__/db-sync.test.ts +167 -0
  74. package/src/__tests__/deployment-diagnostics.test.ts +68 -60
  75. package/src/__tests__/init.test.ts +17 -17
  76. package/src/__tests__/schema-fragment.test.ts +29 -25
  77. package/src/__tests__/seed.test.ts +25 -25
  78. package/src/commands/db-init.ts +146 -319
  79. package/src/commands/db-status.ts +70 -68
  80. package/src/commands/db-sync.ts +227 -0
  81. package/src/commands/doctor.ts +102 -88
  82. package/src/commands/export.ts +65 -75
  83. package/src/commands/generate.ts +14 -16
  84. package/src/commands/import.ts +125 -140
  85. package/src/commands/init.ts +14 -14
  86. package/src/commands/migrate.ts +29 -35
  87. package/src/commands/seed.ts +294 -300
  88. package/src/commands/update-check.ts +77 -72
  89. package/src/commands/upgrade.ts +100 -85
  90. package/src/deployment/diagnostics.ts +86 -72
  91. package/src/index.ts +32 -30
  92. package/src/utils/logger.ts +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/commands/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkLpC,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,sBAAsB,EAAE,CAAC;IACpC,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAyBD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,qBAAqB,CAgC7E;AA2HD,wBAAsB,eAAe,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBtE;AAoBD,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,GAAG,EACP,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAgCf;AA0GD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe1D"}
1
+ {"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/commands/seed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuKnC,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,sBAAsB,EAAE,CAAA;IACnC,OAAO,EAAE,oBAAoB,EAAE,CAAA;CAChC;AAyBD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,qBAAqB,CAkC7E;AA8HD,wBAAsB,eAAe,CAAC,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBtE;AAoBD,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,GAAG,EACP,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,sBAAsB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAgCf;AA0GD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe1D"}
@@ -1,163 +1,163 @@
1
- import { readFile } from "node:fs/promises";
2
- import { existsSync } from "node:fs";
3
- import { createRequire } from "node:module";
4
- import path from "node:path";
5
- import { createInterface } from "node:readline/promises";
6
- import { pathToFileURL } from "node:url";
7
- import ora from "ora";
8
- import { logger } from "../utils/logger.js";
1
+ import { readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import path from 'node:path';
5
+ import { createInterface } from 'node:readline/promises';
6
+ import { pathToFileURL } from 'node:url';
7
+ import ora from 'ora';
8
+ import { logger } from '../utils/logger.js';
9
9
  async function confirm(question) {
10
10
  const rl = createInterface({ input: process.stdin, output: process.stdout });
11
11
  const answer = await rl.question(`${question} (y/N) `);
12
12
  rl.close();
13
- return answer.trim().toLowerCase() === "y";
13
+ return answer.trim().toLowerCase() === 'y';
14
14
  }
15
15
  const DEMO_PAGES = [
16
16
  {
17
- title: "Home",
18
- slug: "home",
19
- content: "<h1>Welcome</h1><p>Your homepage content goes here.</p>",
17
+ title: 'Home',
18
+ slug: 'home',
19
+ content: '<h1>Welcome</h1><p>Your homepage content goes here.</p>',
20
20
  },
21
21
  {
22
- title: "About",
23
- slug: "about",
24
- content: "<h1>About Us</h1><p>Learn more about our team and mission.</p>",
22
+ title: 'About',
23
+ slug: 'about',
24
+ content: '<h1>About Us</h1><p>Learn more about our team and mission.</p>',
25
25
  },
26
26
  {
27
- title: "Contact",
28
- slug: "contact",
29
- content: "<h1>Contact</h1><p>Get in touch with us via the form below.</p>",
27
+ title: 'Contact',
28
+ slug: 'contact',
29
+ content: '<h1>Contact</h1><p>Get in touch with us via the form below.</p>',
30
30
  },
31
31
  {
32
- title: "Privacy Policy",
33
- slug: "privacy-policy",
34
- content: "<h1>Privacy Policy</h1><p>Your privacy matters to us. Read our full policy.</p>",
32
+ title: 'Privacy Policy',
33
+ slug: 'privacy-policy',
34
+ content: '<h1>Privacy Policy</h1><p>Your privacy matters to us. Read our full policy.</p>',
35
35
  },
36
36
  {
37
- title: "Terms of Service",
38
- slug: "terms",
39
- content: "<h1>Terms of Service</h1><p>Please read the following terms carefully.</p>",
37
+ title: 'Terms of Service',
38
+ slug: 'terms',
39
+ content: '<h1>Terms of Service</h1><p>Please read the following terms carefully.</p>',
40
40
  },
41
41
  ];
42
42
  const DEMO_POSTS = [
43
43
  {
44
- title: "Getting Started with Actuate CMS",
45
- slug: "getting-started",
46
- excerpt: "Learn how to set up and configure your new CMS.",
47
- content: "<h1>Getting Started</h1><p>Welcome to Actuate CMS. This guide walks you through initial setup.</p>",
48
- status: "PUBLISHED",
44
+ title: 'Getting Started with Actuate CMS',
45
+ slug: 'getting-started',
46
+ excerpt: 'Learn how to set up and configure your new CMS.',
47
+ content: '<h1>Getting Started</h1><p>Welcome to Actuate CMS. This guide walks you through initial setup.</p>',
48
+ status: 'PUBLISHED',
49
49
  },
50
50
  {
51
- title: "Content Modeling Best Practices",
52
- slug: "content-modeling",
53
- excerpt: "Design your collections and fields for maximum flexibility.",
54
- content: "<h1>Content Modeling</h1><p>Effective content modeling is the foundation of a great CMS.</p>",
55
- status: "PUBLISHED",
51
+ title: 'Content Modeling Best Practices',
52
+ slug: 'content-modeling',
53
+ excerpt: 'Design your collections and fields for maximum flexibility.',
54
+ content: '<h1>Content Modeling</h1><p>Effective content modeling is the foundation of a great CMS.</p>',
55
+ status: 'PUBLISHED',
56
56
  },
57
57
  {
58
- title: "Working with Media",
59
- slug: "working-with-media",
60
- excerpt: "Upload, organize, and optimize your media assets.",
61
- content: "<h1>Working with Media</h1><p>Actuate CMS provides powerful media management.</p>",
62
- status: "PUBLISHED",
58
+ title: 'Working with Media',
59
+ slug: 'working-with-media',
60
+ excerpt: 'Upload, organize, and optimize your media assets.',
61
+ content: '<h1>Working with Media</h1><p>Actuate CMS provides powerful media management.</p>',
62
+ status: 'PUBLISHED',
63
63
  },
64
64
  {
65
- title: "SEO Optimization Tips",
66
- slug: "seo-optimization",
67
- excerpt: "Boost your search rankings with built-in SEO tools.",
68
- content: "<h1>SEO Optimization</h1><p>Follow these tips to improve your site visibility.</p>",
69
- status: "PUBLISHED",
65
+ title: 'SEO Optimization Tips',
66
+ slug: 'seo-optimization',
67
+ excerpt: 'Boost your search rankings with built-in SEO tools.',
68
+ content: '<h1>SEO Optimization</h1><p>Follow these tips to improve your site visibility.</p>',
69
+ status: 'PUBLISHED',
70
70
  },
71
71
  {
72
- title: "Building Custom Plugins",
73
- slug: "building-plugins",
74
- excerpt: "Extend Actuate CMS with your own plugins.",
75
- content: "<h1>Building Plugins</h1><p>The plugin system lets you add custom functionality.</p>",
76
- status: "PUBLISHED",
72
+ title: 'Building Custom Plugins',
73
+ slug: 'building-plugins',
74
+ excerpt: 'Extend Actuate CMS with your own plugins.',
75
+ content: '<h1>Building Plugins</h1><p>The plugin system lets you add custom functionality.</p>',
76
+ status: 'PUBLISHED',
77
77
  },
78
78
  {
79
- title: "API Reference Overview",
80
- slug: "api-reference",
81
- excerpt: "A comprehensive guide to the Actuate CMS REST API.",
82
- content: "<h1>API Reference</h1><p>Use the API to integrate your content anywhere.</p>",
83
- status: "PUBLISHED",
79
+ title: 'API Reference Overview',
80
+ slug: 'api-reference',
81
+ excerpt: 'A comprehensive guide to the Actuate CMS REST API.',
82
+ content: '<h1>API Reference</h1><p>Use the API to integrate your content anywhere.</p>',
83
+ status: 'PUBLISHED',
84
84
  },
85
85
  {
86
- title: "Deployment Guide",
87
- slug: "deployment-guide",
88
- excerpt: "Deploy Actuate CMS to Vercel, AWS, or self-hosted.",
89
- content: "<h1>Deployment Guide</h1><p>Multiple deployment options for every use case.</p>",
90
- status: "PUBLISHED",
86
+ title: 'Deployment Guide',
87
+ slug: 'deployment-guide',
88
+ excerpt: 'Deploy Actuate CMS to Vercel, AWS, or self-hosted.',
89
+ content: '<h1>Deployment Guide</h1><p>Multiple deployment options for every use case.</p>',
90
+ status: 'PUBLISHED',
91
91
  },
92
92
  {
93
- title: "Multi-language Content",
94
- slug: "multi-language",
95
- excerpt: "Set up localization and manage translated content.",
96
- content: "<h1>Multi-language Content</h1><p>Reach a global audience with localized content.</p>",
97
- status: "PUBLISHED",
93
+ title: 'Multi-language Content',
94
+ slug: 'multi-language',
95
+ excerpt: 'Set up localization and manage translated content.',
96
+ content: '<h1>Multi-language Content</h1><p>Reach a global audience with localized content.</p>',
97
+ status: 'PUBLISHED',
98
98
  },
99
99
  {
100
- title: "Webhooks and Integrations",
101
- slug: "webhooks-integrations",
102
- excerpt: "Connect Actuate CMS to external services with webhooks.",
103
- content: "<h1>Webhooks</h1><p>Automate workflows by connecting to third-party services.</p>",
104
- status: "DRAFT",
100
+ title: 'Webhooks and Integrations',
101
+ slug: 'webhooks-integrations',
102
+ excerpt: 'Connect Actuate CMS to external services with webhooks.',
103
+ content: '<h1>Webhooks</h1><p>Automate workflows by connecting to third-party services.</p>',
104
+ status: 'DRAFT',
105
105
  },
106
106
  {
107
- title: "Advanced Access Control",
108
- slug: "access-control",
109
- excerpt: "Fine-tune permissions with role-based access control.",
110
- content: "<h1>Access Control</h1><p>Protect your content with granular permissions.</p>",
111
- status: "DRAFT",
107
+ title: 'Advanced Access Control',
108
+ slug: 'access-control',
109
+ excerpt: 'Fine-tune permissions with role-based access control.',
110
+ content: '<h1>Access Control</h1><p>Protect your content with granular permissions.</p>',
111
+ status: 'DRAFT',
112
112
  },
113
113
  ];
114
114
  const DEMO_FORMS = [
115
115
  {
116
- title: "Contact Form",
117
- slug: "contact-form",
116
+ title: 'Contact Form',
117
+ slug: 'contact-form',
118
118
  fields: [
119
- { name: "name", type: "text", required: true },
120
- { name: "email", type: "email", required: true },
121
- { name: "message", type: "textarea", required: true },
119
+ { name: 'name', type: 'text', required: true },
120
+ { name: 'email', type: 'email', required: true },
121
+ { name: 'message', type: 'textarea', required: true },
122
122
  ],
123
- submitLabel: "Send Message",
123
+ submitLabel: 'Send Message',
124
124
  successMessage: "Thanks for reaching out! We'll get back to you soon.",
125
125
  },
126
126
  {
127
- title: "Newsletter Signup",
128
- slug: "newsletter",
127
+ title: 'Newsletter Signup',
128
+ slug: 'newsletter',
129
129
  fields: [
130
- { name: "email", type: "email", required: true },
131
- { name: "firstName", type: "text", required: false },
130
+ { name: 'email', type: 'email', required: true },
131
+ { name: 'firstName', type: 'text', required: false },
132
132
  ],
133
- submitLabel: "Subscribe",
133
+ submitLabel: 'Subscribe',
134
134
  successMessage: "You're subscribed! Check your inbox for confirmation.",
135
135
  },
136
136
  {
137
- title: "Feedback Form",
138
- slug: "feedback",
137
+ title: 'Feedback Form',
138
+ slug: 'feedback',
139
139
  fields: [
140
- { name: "name", type: "text", required: false },
141
- { name: "rating", type: "select", options: ["1", "2", "3", "4", "5"], required: true },
142
- { name: "comments", type: "textarea", required: false },
140
+ { name: 'name', type: 'text', required: false },
141
+ { name: 'rating', type: 'select', options: ['1', '2', '3', '4', '5'], required: true },
142
+ { name: 'comments', type: 'textarea', required: false },
143
143
  ],
144
- submitLabel: "Submit Feedback",
145
- successMessage: "Thank you for your feedback!",
144
+ submitLabel: 'Submit Feedback',
145
+ successMessage: 'Thank you for your feedback!',
146
146
  },
147
147
  ];
148
148
  const DEMO_USERS = [
149
- { email: "editor@example.com", name: "Demo Editor", role: "EDITOR" },
150
- { email: "author@example.com", name: "Demo Author", role: "AUTHOR" },
149
+ { email: 'editor@example.com', name: 'Demo Editor', role: 'EDITOR' },
150
+ { email: 'author@example.com', name: 'Demo Author', role: 'AUTHOR' },
151
151
  ];
152
152
  const SEED_FILE_CANDIDATES = [
153
- "actuate.seed.json",
154
- "actuate.seed.ts",
155
- "actuate.seed.js",
156
- "actuate.seed.mjs",
157
- "cms.seed.json",
153
+ 'actuate.seed.json',
154
+ 'actuate.seed.ts',
155
+ 'actuate.seed.js',
156
+ 'actuate.seed.mjs',
157
+ 'cms.seed.json',
158
158
  ];
159
159
  function asRecord(value) {
160
- return value && typeof value === "object" && !Array.isArray(value)
160
+ return value && typeof value === 'object' && !Array.isArray(value)
161
161
  ? value
162
162
  : {};
163
163
  }
@@ -166,7 +166,7 @@ function normalizeDocument(collection, doc) {
166
166
  return {
167
167
  collection,
168
168
  data: asRecord(record.data ?? record),
169
- status: typeof record.status === "string" ? record.status : "DRAFT",
169
+ status: typeof record.status === 'string' ? record.status : 'DRAFT',
170
170
  };
171
171
  }
172
172
  export function normalizeSeedPayload(seedData) {
@@ -175,7 +175,7 @@ export function normalizeSeedPayload(seedData) {
175
175
  if (Array.isArray(seedData)) {
176
176
  for (const doc of seedData) {
177
177
  const record = asRecord(doc);
178
- documents.push(normalizeDocument(typeof record.collection === "string" ? record.collection : "imported", record.data ? record : { data: record }));
178
+ documents.push(normalizeDocument(typeof record.collection === 'string' ? record.collection : 'imported', record.data ? record : { data: record }));
179
179
  }
180
180
  return { documents, globals };
181
181
  }
@@ -186,7 +186,7 @@ export function normalizeSeedPayload(seedData) {
186
186
  }
187
187
  const collections = root.collections ? asRecord(root.collections) : root;
188
188
  for (const [collection, docs] of Object.entries(collections)) {
189
- if (collection === "globals" || collection === "collections")
189
+ if (collection === 'globals' || collection === 'collections')
190
190
  continue;
191
191
  if (!Array.isArray(docs))
192
192
  continue;
@@ -205,22 +205,21 @@ function findConventionSeedFile() {
205
205
  }
206
206
  async function loadSeedFile(filePath) {
207
207
  const extension = path.extname(filePath);
208
- if (extension === ".json" || extension === "") {
209
- const raw = await readFile(filePath, "utf-8");
208
+ if (extension === '.json' || extension === '') {
209
+ const raw = await readFile(filePath, 'utf-8');
210
210
  return JSON.parse(raw);
211
211
  }
212
212
  const fileUrl = pathToFileURL(path.resolve(filePath)).href;
213
- const mod = extension === ".ts"
214
- ? await import("tsx/esm/api").then(({ tsImport }) => tsImport(fileUrl, import.meta.url))
213
+ const mod = extension === '.ts'
214
+ ? await import('tsx/esm/api').then(({ tsImport }) => tsImport(fileUrl, import.meta.url))
215
215
  : await import(fileUrl);
216
- return mod.default
217
- ?? mod.seed;
216
+ return mod.default ?? mod.seed;
218
217
  }
219
218
  async function runSeed(options) {
220
219
  const conventionFile = !options.demo && !options.file ? findConventionSeedFile() : null;
221
220
  const file = options.file ?? conventionFile ?? undefined;
222
221
  if (!options.demo && !file) {
223
- logger.error("Specify --demo, --file <path>, or add actuate.seed.json in the project root.");
222
+ logger.error('Specify --demo, --file <path>, or add actuate.seed.json in the project root.');
224
223
  process.exit(1);
225
224
  }
226
225
  let seededDb = null;
@@ -228,18 +227,18 @@ async function runSeed(options) {
228
227
  seededDb = await getSeedDatabase();
229
228
  const db = seededDb.db;
230
229
  if (options.reset) {
231
- const yes = await confirm("This will delete ALL existing documents and versions. Continue?");
230
+ const yes = await confirm('This will delete ALL existing documents and versions. Continue?');
232
231
  if (!yes) {
233
- logger.warn("Seed cancelled.");
232
+ logger.warn('Seed cancelled.');
234
233
  return;
235
234
  }
236
- const resetSpinner = ora("Clearing existing data…").start();
235
+ const resetSpinner = ora('Clearing existing data…').start();
237
236
  await db.version.deleteMany({});
238
237
  if (db.mediaUsage?.deleteMany) {
239
238
  await db.mediaUsage.deleteMany({});
240
239
  }
241
240
  await db.document.deleteMany({});
242
- resetSpinner.succeed("Existing data cleared.");
241
+ resetSpinner.succeed('Existing data cleared.');
243
242
  }
244
243
  if (options.demo) {
245
244
  await seedDemoData(db);
@@ -258,7 +257,7 @@ async function runSeed(options) {
258
257
  }
259
258
  }
260
259
  async function getSeedDatabase() {
261
- const { getDB, initDB, isDBInitialized } = await import("@actuate-media/cms-core");
260
+ const { getDB, initDB, isDBInitialized } = await import('@actuate-media/cms-core');
262
261
  if (isDBInitialized()) {
263
262
  return { db: getDB(), disconnect: async () => { } };
264
263
  }
@@ -267,7 +266,7 @@ async function getSeedDatabase() {
267
266
  return {
268
267
  db,
269
268
  disconnect: async () => {
270
- if (typeof db.$disconnect === "function") {
269
+ if (typeof db.$disconnect === 'function') {
271
270
  await db.$disconnect();
272
271
  }
273
272
  },
@@ -275,40 +274,40 @@ async function getSeedDatabase() {
275
274
  }
276
275
  async function createProjectPrismaClient() {
277
276
  if (!process.env.DATABASE_URL) {
278
- throw new Error("DATABASE_URL is required to run seed/populate.");
277
+ throw new Error('DATABASE_URL is required to run seed/populate.');
279
278
  }
280
- const requireFromProject = createRequire(path.join(process.cwd(), "package.json"));
281
- const generatedClient = path.resolve("generated", "prisma", "client.ts");
279
+ const requireFromProject = createRequire(path.join(process.cwd(), 'package.json'));
280
+ const generatedClient = path.resolve('generated', 'prisma', 'client.ts');
282
281
  if (existsSync(generatedClient)) {
283
282
  const [{ tsImport }, adapterModule, pgModule] = await Promise.all([
284
- import("tsx/esm/api"),
285
- import(pathToFileURL(requireFromProject.resolve("@prisma/adapter-pg")).href),
286
- import(pathToFileURL(requireFromProject.resolve("pg")).href),
283
+ import('tsx/esm/api'),
284
+ import(pathToFileURL(requireFromProject.resolve('@prisma/adapter-pg')).href),
285
+ import(pathToFileURL(requireFromProject.resolve('pg')).href),
287
286
  ]);
288
- const { PrismaClient } = await tsImport(pathToFileURL(generatedClient).href, import.meta.url);
287
+ const { PrismaClient } = (await tsImport(pathToFileURL(generatedClient).href, import.meta.url));
289
288
  const { PrismaPg } = adapterModule;
290
289
  const pg = pgModule.default ?? pgModule;
291
290
  const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
292
291
  const adapter = new PrismaPg(pool);
293
292
  return new PrismaClient({ adapter });
294
293
  }
295
- const clientModule = await import(pathToFileURL(requireFromProject.resolve("@prisma/client")).href);
294
+ const clientModule = (await import(pathToFileURL(requireFromProject.resolve('@prisma/client')).href));
296
295
  return new clientModule.PrismaClient();
297
296
  }
298
297
  export async function ensureSeedAdmin(db) {
299
- const existing = await db.user.findFirst({ where: { role: "ADMIN" } });
298
+ const existing = await db.user.findFirst({ where: { role: 'ADMIN' } });
300
299
  if (existing)
301
300
  return existing;
302
301
  const email = process.env.CMS_ADMIN_EMAIL;
303
302
  const password = process.env.CMS_ADMIN_PASSWORD;
304
- const name = process.env.CMS_ADMIN_NAME ?? "Admin";
303
+ const name = process.env.CMS_ADMIN_NAME ?? 'Admin';
305
304
  if (!email || !password) {
306
- throw new Error("No admin user exists. Set CMS_ADMIN_EMAIL and CMS_ADMIN_PASSWORD before running seed, or complete the setup wizard first.");
305
+ throw new Error('No admin user exists. Set CMS_ADMIN_EMAIL and CMS_ADMIN_PASSWORD before running seed, or complete the setup wizard first.');
307
306
  }
308
- const { createInitialAdmin } = await import("@actuate-media/cms-core");
307
+ const { createInitialAdmin } = await import('@actuate-media/cms-core');
309
308
  const result = await createInitialAdmin(db, { email, password, name });
310
309
  if (!result.success || !result.userId) {
311
- throw new Error(result.error ?? "Failed to create initial admin user");
310
+ throw new Error(result.error ?? 'Failed to create initial admin user');
312
311
  }
313
312
  return { id: result.userId };
314
313
  }
@@ -316,19 +315,19 @@ function sanitizeSeedData(value, sanitizeHtml) {
316
315
  if (Array.isArray(value)) {
317
316
  return value.map((item) => sanitizeSeedData(item, sanitizeHtml));
318
317
  }
319
- if (value && typeof value === "object") {
318
+ if (value && typeof value === 'object') {
320
319
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [
321
320
  key,
322
321
  sanitizeSeedData(item, sanitizeHtml),
323
322
  ]));
324
323
  }
325
- if (typeof value === "string" && /<[a-z][\s\S]*>/i.test(value)) {
324
+ if (typeof value === 'string' && /<[a-z][\s\S]*>/i.test(value)) {
326
325
  return sanitizeHtml(value);
327
326
  }
328
327
  return value;
329
328
  }
330
329
  export async function createSeedDocument(db, userId, doc) {
331
- const { extractPlainText, hashContent, sanitizeHtml } = await import("@actuate-media/cms-core");
330
+ const { extractPlainText, hashContent, sanitizeHtml } = await import('@actuate-media/cms-core');
332
331
  const data = sanitizeSeedData(doc.data, sanitizeHtml);
333
332
  const serialized = JSON.stringify(data);
334
333
  const plainText = extractPlainText(serialized);
@@ -337,11 +336,11 @@ export async function createSeedDocument(db, userId, doc) {
337
336
  const created = await tx.document.create({
338
337
  data: {
339
338
  collection: doc.collection,
340
- title: typeof data.title === "string" ? data.title : null,
341
- slug: typeof data.slug === "string" ? data.slug : null,
339
+ title: typeof data.title === 'string' ? data.title : null,
340
+ slug: typeof data.slug === 'string' ? data.slug : null,
342
341
  data,
343
342
  status: doc.status,
344
- publishedAt: doc.status === "PUBLISHED" ? new Date() : null,
343
+ publishedAt: doc.status === 'PUBLISHED' ? new Date() : null,
345
344
  createdById: userId,
346
345
  updatedById: userId,
347
346
  plainText,
@@ -353,28 +352,28 @@ export async function createSeedDocument(db, userId, doc) {
353
352
  documentId: created.id,
354
353
  data,
355
354
  changedById: userId,
356
- changeType: "CREATE",
355
+ changeType: 'CREATE',
357
356
  },
358
357
  });
359
358
  });
360
359
  }
361
360
  async function seedDemoData(db) {
362
- const spinner = ora("Seeding demo data…").start();
361
+ const spinner = ora('Seeding demo data…').start();
363
362
  const adminUser = await ensureSeedAdmin(db);
364
363
  const userId = adminUser.id;
365
364
  let pagesCreated = 0;
366
365
  for (const page of DEMO_PAGES) {
367
366
  await createSeedDocument(db, userId, {
368
- collection: "pages",
367
+ collection: 'pages',
369
368
  data: page,
370
- status: "PUBLISHED",
369
+ status: 'PUBLISHED',
371
370
  });
372
371
  pagesCreated++;
373
372
  }
374
373
  let postsCreated = 0;
375
374
  for (const post of DEMO_POSTS) {
376
375
  await createSeedDocument(db, userId, {
377
- collection: "posts",
376
+ collection: 'posts',
378
377
  data: post,
379
378
  status: post.status,
380
379
  });
@@ -383,9 +382,9 @@ async function seedDemoData(db) {
383
382
  let formsCreated = 0;
384
383
  for (const form of DEMO_FORMS) {
385
384
  await createSeedDocument(db, userId, {
386
- collection: "forms",
385
+ collection: 'forms',
387
386
  data: form,
388
- status: "PUBLISHED",
387
+ status: 'PUBLISHED',
389
388
  });
390
389
  formsCreated++;
391
390
  }
@@ -406,7 +405,7 @@ async function seedDemoData(db) {
406
405
  usersCreated++;
407
406
  }
408
407
  }
409
- spinner.succeed("Demo data seeded successfully.");
408
+ spinner.succeed('Demo data seeded successfully.');
410
409
  logger.info(` Pages: ${pagesCreated}`);
411
410
  logger.info(` Posts: ${postsCreated}`);
412
411
  logger.info(` Forms: ${formsCreated}`);
@@ -423,18 +422,18 @@ async function seedFromFile(db, filePath) {
423
422
  seedData = await loadSeedFile(filePath);
424
423
  }
425
424
  catch {
426
- spinner.fail("Invalid seed file.");
425
+ spinner.fail('Invalid seed file.');
427
426
  process.exit(1);
428
427
  }
429
- if (!Array.isArray(seedData) && typeof seedData !== "object") {
430
- spinner.fail("Seed file must contain a JSON array or an object with collection keys.");
428
+ if (!Array.isArray(seedData) && typeof seedData !== 'object') {
429
+ spinner.fail('Seed file must contain a JSON array or an object with collection keys.');
431
430
  process.exit(1);
432
431
  }
433
432
  const adminUser = await ensureSeedAdmin(db);
434
433
  const userId = adminUser.id;
435
434
  const normalized = normalizeSeedPayload(seedData);
436
- const { updateGlobal } = await import("@actuate-media/cms-core");
437
- const ctx = { userId, role: "ADMIN", db };
435
+ const { updateGlobal } = await import('@actuate-media/cms-core');
436
+ const ctx = { userId, role: 'ADMIN', db };
438
437
  let documentCount = 0;
439
438
  for (const doc of normalized.documents) {
440
439
  await createSeedDocument(db, userId, doc);
@@ -449,17 +448,17 @@ async function seedFromFile(db, filePath) {
449
448
  }
450
449
  export function registerSeedCommand(program) {
451
450
  program
452
- .command("seed")
453
- .description("Seed the database with demo or custom data")
454
- .option("--demo", "Seed demo content (pages, posts, forms, users)")
455
- .option("--file <path>", "Seed from a JSON, JavaScript, or TypeScript file")
456
- .option("--reset", "Clear existing data before seeding")
451
+ .command('seed')
452
+ .description('Seed the database with demo or custom data')
453
+ .option('--demo', 'Seed demo content (pages, posts, forms, users)')
454
+ .option('--file <path>', 'Seed from a JSON, JavaScript, or TypeScript file')
455
+ .option('--reset', 'Clear existing data before seeding')
457
456
  .action(runSeed);
458
457
  program
459
- .command("populate")
460
- .description("Populate the database from actuate.seed.json or a custom seed file")
461
- .option("--file <path>", "Seed from a JSON, JavaScript, or TypeScript file")
462
- .option("--reset", "Clear existing data before seeding")
458
+ .command('populate')
459
+ .description('Populate the database from actuate.seed.json or a custom seed file')
460
+ .option('--file <path>', 'Seed from a JSON, JavaScript, or TypeScript file')
461
+ .option('--reset', 'Clear existing data before seeding')
463
462
  .action(runSeed);
464
463
  }
465
464
  //# sourceMappingURL=seed.js.map