@marvalt/digivalt-core 0.1.7 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +47 -4
  3. package/bin/init.cjs +406 -25
  4. package/dist/config.cjs +520 -0
  5. package/dist/config.cjs.map +1 -0
  6. package/dist/config.d.ts +307 -0
  7. package/dist/config.esm.js +502 -0
  8. package/dist/config.esm.js.map +1 -0
  9. package/dist/generators.cjs +2481 -0
  10. package/dist/generators.cjs.map +1 -0
  11. package/dist/generators.d.ts +19 -0
  12. package/dist/generators.esm.js +2475 -0
  13. package/dist/generators.esm.js.map +1 -0
  14. package/dist/index.cjs +18 -7955
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +18 -1196
  17. package/dist/index.esm.js +13 -7929
  18. package/dist/index.esm.js.map +1 -1
  19. package/dist/runtime/env.d.ts +4 -0
  20. package/dist/runtime/lazy.d.ts +1 -0
  21. package/dist/services/cf-wp-webhook.d.ts +2 -0
  22. package/dist/services/gravityForms.d.ts +3 -0
  23. package/dist/services/mautic.d.ts +5 -1
  24. package/dist/services/suitecrm.d.ts +2 -0
  25. package/dist/services.cjs +1339 -0
  26. package/dist/services.cjs.map +1 -0
  27. package/dist/services.d.ts +432 -0
  28. package/dist/services.esm.js +1322 -0
  29. package/dist/services.esm.js.map +1 -0
  30. package/dist/static/index.d.ts +4 -0
  31. package/dist/static.cjs +997 -0
  32. package/dist/static.cjs.map +1 -0
  33. package/dist/static.d.ts +410 -0
  34. package/dist/static.esm.js +962 -0
  35. package/dist/static.esm.js.map +1 -0
  36. package/dist/types.cjs +3 -0
  37. package/dist/types.cjs.map +1 -0
  38. package/dist/types.d.ts +134 -0
  39. package/dist/types.esm.js +2 -0
  40. package/dist/types.esm.js.map +1 -0
  41. package/package.json +30 -2
  42. package/template/DIGIVALT_SETUP.md +73 -0
  43. package/template/scripts/deploy-secrets.js +55 -23
  44. package/template/scripts/generate.ts +3 -17
package/CHANGELOG.md CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.2.1] - 2026-03-30
9
+
10
+ ### Changed
11
+ - Upgraded `digivalt-init` from a template copier into a preflight tool that inspects DigiVAlt wiring in existing Lovable/Vite apps.
12
+ - Added safe `package.json` patching for `generate`, `build`, and `build:dev` when apps are still on plain Vite scripts.
13
+ - Added stale `scripts/generate.ts` refresh for known DigiVAlt-managed legacy versions.
14
+ - Added warnings for legacy workarounds such as alias-link scripts, old root generator imports, and Vite `noExternal` compatibility hacks.
15
+ - Expanded smoke coverage for fresh installs, upgrades, idempotent reruns, custom build scripts, and dry-run previews.
16
+
17
+ ### Migration Notes
18
+ - Rerun `npx digivalt-init` after upgrading to `0.2.1` so existing apps can pick up the improved build wiring checks and warnings.
19
+
20
+ ## [0.2.0] - 2026-02-19
21
+
22
+ ### Changed
23
+ - Added explicit subpath exports for `generators`, `services`, `config`, `static`, and `types`.
24
+ - Reduced the root package entry to a thin compatibility surface for generator-oriented consumers.
25
+ - Converted Gravity Forms, Mautic, and webhook service initialization to lazy creation instead of import-time setup.
26
+ - Removed automatic Gravity Forms static-data loading on import.
27
+ - Hardened `digivalt-init` with target validation and dry-run support.
28
+ - Hardened Cloudflare secret deployment with an allowlist and fail-loud behavior.
29
+
30
+ ### Migration Notes
31
+ - Prefer `@marvalt/digivalt-core/generators` in build-time scripts instead of importing `generators` from the root entry.
32
+
8
33
  ## [0.1.0] - Initial Release
9
34
 
10
35
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @marvalt/digivalt-core
2
2
 
3
- Core logic and shared context for DigiVAlt frontend applications.
3
+ Core DigiVAlt package for static data generation, runtime service wiring, and Cloudflare Pages bootstrap helpers.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,6 +8,49 @@ Core logic and shared context for DigiVAlt frontend applications.
8
8
  npm install @marvalt/digivalt-core
9
9
  ```
10
10
 
11
- ## Overview
12
- This package contains the shared "glue" code that unifies WordPress headless configurations, Mautic connections, Cloudflare setup, and form integrations for DigiValt static-first applications.
13
- It makes it easy to convert any standard React/Vite app into a full DigiVAlt implementation.
11
+ ## Entry Points
12
+
13
+ Prefer explicit subpath imports so Node/build-time code does not pull browser runtime modules:
14
+
15
+ ```ts
16
+ import { generateAllData } from '@marvalt/digivalt-core/generators';
17
+ import { getIntegrationConfig } from '@marvalt/digivalt-core/config';
18
+ import { loadWordPressData } from '@marvalt/digivalt-core/static';
19
+ import { gravityFormsService } from '@marvalt/digivalt-core/services';
20
+ ```
21
+
22
+ The root package export remains as a thin compatibility layer for generator-focused consumers.
23
+
24
+ ## Init Workflow
25
+
26
+ Run `npx digivalt-init` inside a Vite/Lovable app root. The command now validates the target folder, inspects existing DigiVAlt wiring, and patches safe cases automatically.
27
+
28
+ Useful flags:
29
+
30
+ - `--target <path>` to initialize a different app folder
31
+ - `--dry-run` to preview copied files without writing anything
32
+ - `--force-template` to overwrite DigiVAlt-managed template files intentionally
33
+
34
+ What init now does:
35
+
36
+ - copies missing template files into the app
37
+ - adds or updates `generate`, `build`, and `build:dev` scripts when the app is still on plain Vite wiring
38
+ - refreshes `scripts/generate.ts` when it matches an older DigiVAlt-managed version
39
+ - warns instead of overwriting custom build logic or custom generator scripts
40
+ - reports stale legacy workarounds such as alias-link scripts and old root package generator imports
41
+
42
+ When to rerun it:
43
+
44
+ - after first installing DigiVAlt in a fresh app
45
+ - after upgrading `@marvalt/digivalt-core` when scaffolded build wiring changes
46
+ - before publishing a new app if you want a quick preflight of the DigiVAlt setup
47
+
48
+ ## Cloudflare Secrets
49
+
50
+ Use `node scripts/deploy-secrets.js` after `digivalt-init`.
51
+
52
+ The helper now:
53
+
54
+ - uploads only DigiVAlt-related environment variables
55
+ - skips known local-only variables such as `VITE_LOCAL_DEVELOPMENT`
56
+ - fails with a non-zero exit code when Wrangler or project detection fails
package/bin/init.cjs CHANGED
@@ -4,39 +4,420 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
 
6
6
  const sourceDir = path.join(__dirname, '..', 'template');
7
- const targetDir = process.cwd();
8
-
9
- console.log('šŸš€ Initializing DigiVAlt Cloudflare Proxy Templates...');
10
-
11
- function copyRecursiveSync(src, dest) {
12
- const exists = fs.existsSync(src);
13
- const stats = exists && fs.statSync(src);
14
- const isDirectory = exists && stats.isDirectory();
15
-
16
- if (isDirectory) {
17
- if (!fs.existsSync(dest)) fs.mkdirSync(dest);
18
- fs.readdirSync(src).forEach((childItemName) => {
19
- copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName));
7
+ const args = process.argv.slice(2);
8
+
9
+ const EXPECTED_GENERATE_SCRIPT =
10
+ 'npx vite-node --options.deps.inline="@marvalt/digivalt-core/generators" scripts/generate.ts';
11
+ const EXPECTED_BUILD_SCRIPT = `${EXPECTED_GENERATE_SCRIPT} && vite build`;
12
+ const EXPECTED_BUILD_DEV_SCRIPT = `${EXPECTED_GENERATE_SCRIPT} && vite build --mode development`;
13
+
14
+ const TEMPLATE_MANAGED_FILES = new Set([
15
+ '.dev.vars.example',
16
+ 'DIGIVALT_SETUP.md',
17
+ 'functions/api/fetch-with-access.ts',
18
+ 'functions/api/gravity-forms-submit.ts',
19
+ 'functions/api/mautic-submit.ts',
20
+ 'functions/api/webhook.js',
21
+ 'scripts/deploy-secrets.js',
22
+ 'scripts/generate.ts',
23
+ 'wrangler.toml',
24
+ ]);
25
+
26
+ const LEGACY_GENERATE_MARKERS = [
27
+ "import { generators } from '@marvalt/digivalt-core';",
28
+ 'const gfSuccess = await generators.generateGravityFormsData();',
29
+ 'const mauticSuccess = await generators.generateMauticData();',
30
+ "import dotenv from 'dotenv';",
31
+ 'dotenv.config();',
32
+ ];
33
+
34
+ const LEGACY_BUILD_MARKERS = [
35
+ 'link-digivalt-alias',
36
+ '@marvalt/digivalt-core',
37
+ ];
38
+
39
+ function getArgValue(flag) {
40
+ const index = args.indexOf(flag);
41
+ return index >= 0 ? args[index + 1] : undefined;
42
+ }
43
+
44
+ const dryRun = args.includes('--dry-run');
45
+ const forceTemplate = args.includes('--force-template');
46
+ const explicitTarget = getArgValue('--target');
47
+ const targetDir = path.resolve(explicitTarget || process.cwd());
48
+
49
+ const report = {
50
+ copied: [],
51
+ overwritten: [],
52
+ skipped: [],
53
+ patchedScripts: [],
54
+ refreshedFiles: [],
55
+ warnings: [],
56
+ manualActions: [],
57
+ };
58
+
59
+ function logHeader() {
60
+ console.log('šŸš€ Initializing DigiVAlt Cloudflare Proxy Templates...');
61
+ console.log(`šŸ“ Target directory: ${targetDir}`);
62
+ if (dryRun) {
63
+ console.log('🧪 Dry run enabled. No files will be written.');
64
+ }
65
+ if (forceTemplate) {
66
+ console.log('ā™»ļø Force template mode enabled for DigiVAlt-managed files.');
67
+ }
68
+ }
69
+
70
+ function ensureValidTarget(dir) {
71
+ if (!fs.existsSync(dir)) {
72
+ throw new Error(`Target directory does not exist: ${dir}`);
73
+ }
74
+
75
+ const stats = fs.statSync(dir);
76
+ if (!stats.isDirectory()) {
77
+ throw new Error(`Target path is not a directory: ${dir}`);
78
+ }
79
+
80
+ const packageJsonPath = path.join(dir, 'package.json');
81
+ if (!fs.existsSync(packageJsonPath)) {
82
+ throw new Error(
83
+ 'No package.json found in the target directory. Run `digivalt-init` inside a Vite/Lovable app root, or pass `--target <app-path>`.'
84
+ );
85
+ }
86
+
87
+ return packageJsonPath;
88
+ }
89
+
90
+ function normalizeLineEndings(value) {
91
+ return value.replace(/\r\n/g, '\n').trim();
92
+ }
93
+
94
+ function normalizeScript(value) {
95
+ return String(value || '')
96
+ .replace(/\s+/g, ' ')
97
+ .trim();
98
+ }
99
+
100
+ function readTextIfExists(filePath) {
101
+ return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : null;
102
+ }
103
+
104
+ function writeFileWithMode(filePath, content) {
105
+ if (!dryRun) {
106
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
107
+ fs.writeFileSync(filePath, content);
108
+ }
109
+ }
110
+
111
+ function relativeDisplay(filePath) {
112
+ const relativePath = path.relative(targetDir, filePath).replace(/\\/g, '/');
113
+ return relativePath ? `/${relativePath}` : '/';
114
+ }
115
+
116
+ function listTemplateFiles(dir, baseDir = dir) {
117
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
118
+ const results = [];
119
+
120
+ for (const entry of entries) {
121
+ const fullPath = path.join(dir, entry.name);
122
+ if (entry.isDirectory()) {
123
+ results.push(...listTemplateFiles(fullPath, baseDir));
124
+ continue;
125
+ }
126
+
127
+ results.push({
128
+ src: fullPath,
129
+ relativePath: path.relative(baseDir, fullPath).replace(/\\/g, '/'),
20
130
  });
131
+ }
132
+
133
+ return results;
134
+ }
135
+
136
+ function isKnownLegacyGenerateScript(content) {
137
+ if (!content) return false;
138
+ return LEGACY_GENERATE_MARKERS.some((marker) => content.includes(marker));
139
+ }
140
+
141
+ function isCurrentGenerateScript(content, templateContent) {
142
+ if (!content) return false;
143
+ return normalizeLineEndings(content) === normalizeLineEndings(templateContent);
144
+ }
145
+
146
+ function scriptRunsGenerate(command) {
147
+ const normalized = normalizeScript(command);
148
+ return normalized.includes('scripts/generate.ts') || normalized.includes('npm run generate');
149
+ }
150
+
151
+ function isExpectedBuildScript(command) {
152
+ return normalizeScript(command) === normalizeScript(EXPECTED_BUILD_SCRIPT);
153
+ }
154
+
155
+ function isExpectedBuildDevScript(command) {
156
+ return normalizeScript(command) === normalizeScript(EXPECTED_BUILD_DEV_SCRIPT);
157
+ }
158
+
159
+ function isPlainViteBuild(command) {
160
+ return normalizeScript(command) === 'vite build';
161
+ }
162
+
163
+ function isPlainViteBuildDev(command) {
164
+ return normalizeScript(command) === 'vite build --mode development';
165
+ }
166
+
167
+ function isLegacyGenerateCommand(command) {
168
+ const normalized = normalizeScript(command);
169
+ return normalized === 'vite-node scripts/generate.ts' || normalized === 'npx vite-node scripts/generate.ts';
170
+ }
171
+
172
+ function readJson(filePath) {
173
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
174
+ }
175
+
176
+ function writeJson(filePath, value) {
177
+ const content = `${JSON.stringify(value, null, 2)}\n`;
178
+ if (!dryRun) {
179
+ fs.writeFileSync(filePath, content);
180
+ }
181
+ }
182
+
183
+ function inspectTargetApp(targetPackageJsonPath, templateGenerateScript) {
184
+ const packageJson = readJson(targetPackageJsonPath);
185
+ const scripts = packageJson.scripts || {};
186
+ const deps = packageJson.dependencies || {};
187
+ const devDeps = packageJson.devDependencies || {};
188
+ const generateScriptPath = path.join(targetDir, 'scripts', 'generate.ts');
189
+ const generateScriptContent = readTextIfExists(generateScriptPath);
190
+ const viteConfigCandidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs'];
191
+ const legacyViteConfigs = [];
192
+
193
+ for (const candidate of viteConfigCandidates) {
194
+ const configPath = path.join(targetDir, candidate);
195
+ const content = readTextIfExists(configPath);
196
+ if (!content) continue;
197
+
198
+ if (content.includes('noExternal') && content.includes('@marvalt/digivalt-core')) {
199
+ legacyViteConfigs.push(candidate);
200
+ }
201
+ }
202
+
203
+ const legacyHackFiles = [];
204
+ const aliasLinkPath = path.join(targetDir, 'scripts', 'link-digivalt-alias.cjs');
205
+ if (fs.existsSync(aliasLinkPath)) {
206
+ legacyHackFiles.push('scripts/link-digivalt-alias.cjs');
207
+ }
208
+
209
+ const postinstall = scripts.postinstall || '';
210
+ const generateState = !generateScriptContent
211
+ ? 'missing'
212
+ : isCurrentGenerateScript(generateScriptContent, templateGenerateScript)
213
+ ? 'current'
214
+ : isKnownLegacyGenerateScript(generateScriptContent)
215
+ ? 'legacy'
216
+ : 'custom';
217
+
218
+ return {
219
+ packageJson,
220
+ packageJsonPath: targetPackageJsonPath,
221
+ scripts,
222
+ generateScriptPath,
223
+ generateState,
224
+ hasViteNode: Boolean(deps['vite-node'] || devDeps['vite-node']),
225
+ buildState: isExpectedBuildScript(scripts.build)
226
+ ? 'current'
227
+ : isPlainViteBuild(scripts.build)
228
+ ? 'plain'
229
+ : scriptRunsGenerate(scripts.build)
230
+ ? 'custom-digivalt'
231
+ : scripts.build
232
+ ? 'custom'
233
+ : 'missing',
234
+ buildDevState: isExpectedBuildDevScript(scripts['build:dev'])
235
+ ? 'current'
236
+ : isPlainViteBuildDev(scripts['build:dev'])
237
+ ? 'plain'
238
+ : scriptRunsGenerate(scripts['build:dev'])
239
+ ? 'custom-digivalt'
240
+ : scripts['build:dev']
241
+ ? 'custom'
242
+ : 'missing',
243
+ generateCommandState: normalizeScript(scripts.generate) === normalizeScript(EXPECTED_GENERATE_SCRIPT)
244
+ ? 'current'
245
+ : isLegacyGenerateCommand(scripts.generate)
246
+ ? 'legacy'
247
+ : scripts.generate
248
+ ? 'custom'
249
+ : 'missing',
250
+ legacyHackFiles,
251
+ legacyPostinstall: postinstall.includes('link-digivalt-alias'),
252
+ legacyRootImport: Boolean(generateScriptContent && generateScriptContent.includes("import { generators } from '@marvalt/digivalt-core';")),
253
+ legacyViteConfigs,
254
+ };
255
+ }
256
+
257
+ function printPreflight(status) {
258
+ console.log('\nšŸ”Ž Preflight');
259
+ console.log(`- vite-node installed: ${status.hasViteNode ? 'yes' : 'no'}`);
260
+ console.log(`- scripts.generate: ${status.generateCommandState}`);
261
+ console.log(`- scripts.build: ${status.buildState}`);
262
+ console.log(`- scripts.build:dev: ${status.buildDevState}`);
263
+ console.log(`- scripts/generate.ts: ${status.generateState}`);
264
+
265
+ if (status.legacyHackFiles.length > 0 || status.legacyPostinstall || status.legacyRootImport || status.legacyViteConfigs.length > 0) {
266
+ console.log('- legacy DigiVAlt wiring detected: yes');
21
267
  } else {
22
- // We only copy if it doesn't already exist to prevent overwriting user changes!
23
- if (fs.existsSync(dest)) {
24
- console.log(`āš ļø Skipping ${dest.replace(targetDir, '')} (Already exists)`);
268
+ console.log('- legacy DigiVAlt wiring detected: no');
269
+ }
270
+ }
271
+
272
+ function patchPackageJson(status) {
273
+ const packageJson = status.packageJson;
274
+ const scripts = { ...(packageJson.scripts || {}) };
275
+ let changed = false;
276
+
277
+ if (!status.hasViteNode) {
278
+ report.manualActions.push('Install `vite-node` in the app if it is not already available, because DigiVAlt build wiring depends on it.');
279
+ }
280
+
281
+ if (status.generateCommandState === 'missing') {
282
+ scripts.generate = EXPECTED_GENERATE_SCRIPT;
283
+ report.patchedScripts.push('Added `scripts.generate`.');
284
+ changed = true;
285
+ } else if (status.generateCommandState === 'legacy') {
286
+ scripts.generate = EXPECTED_GENERATE_SCRIPT;
287
+ report.patchedScripts.push('Updated `scripts.generate` to the DigiVAlt generators subpath.');
288
+ changed = true;
289
+ } else if (status.generateCommandState === 'custom') {
290
+ report.manualActions.push('Review `scripts.generate` manually because it does not match the current DigiVAlt command.');
291
+ }
292
+
293
+ if (status.buildState === 'missing' || status.buildState === 'plain') {
294
+ scripts.build = EXPECTED_BUILD_SCRIPT;
295
+ report.patchedScripts.push(status.buildState === 'missing' ? 'Added `scripts.build`.' : 'Updated `scripts.build` to run static generation before `vite build`.');
296
+ changed = true;
297
+ } else if (status.buildState === 'custom') {
298
+ report.manualActions.push('Review `scripts.build` manually because it contains custom logic and was left unchanged.');
299
+ }
300
+
301
+ if (status.buildDevState === 'missing' || status.buildDevState === 'plain') {
302
+ scripts['build:dev'] = EXPECTED_BUILD_DEV_SCRIPT;
303
+ report.patchedScripts.push(status.buildDevState === 'missing' ? 'Added `scripts.build:dev`.' : 'Updated `scripts.build:dev` to run static generation before the development build.');
304
+ changed = true;
305
+ } else if (status.buildDevState === 'custom') {
306
+ report.manualActions.push('Review `scripts.build:dev` manually because it contains custom logic and was left unchanged.');
307
+ }
308
+
309
+ if (changed) {
310
+ packageJson.scripts = scripts;
311
+ writeJson(status.packageJsonPath, packageJson);
312
+ }
313
+ }
314
+
315
+ function reconcileGenerateScript(status, templateGenerateScript) {
316
+ const filePath = status.generateScriptPath;
317
+
318
+ if (status.generateState === 'missing') {
319
+ writeFileWithMode(filePath, templateGenerateScript);
320
+ report.refreshedFiles.push('Created `scripts/generate.ts` from the DigiVAlt template.');
321
+ return;
322
+ }
323
+
324
+ if (status.generateState === 'legacy' || (forceTemplate && TEMPLATE_MANAGED_FILES.has('scripts/generate.ts'))) {
325
+ writeFileWithMode(filePath, templateGenerateScript);
326
+ report.refreshedFiles.push('Refreshed `scripts/generate.ts` to the current DigiVAlt template.');
327
+ return;
328
+ }
329
+
330
+ if (status.generateState === 'custom') {
331
+ report.manualActions.push('Review `scripts/generate.ts` manually because it contains custom logic and was left unchanged.');
332
+ }
333
+ }
334
+
335
+ function copyTemplateFiles() {
336
+ const templateFiles = listTemplateFiles(sourceDir);
337
+
338
+ for (const file of templateFiles) {
339
+ if (file.relativePath === 'scripts/generate.ts') {
340
+ continue;
341
+ }
342
+
343
+ const destination = path.join(targetDir, file.relativePath);
344
+ const alreadyExists = fs.existsSync(destination);
345
+ const shouldOverwrite = alreadyExists && forceTemplate && TEMPLATE_MANAGED_FILES.has(file.relativePath);
346
+
347
+ if (alreadyExists && !shouldOverwrite) {
348
+ report.skipped.push(`Skipped ${relativeDisplay(destination)} (already exists).`);
349
+ continue;
350
+ }
351
+
352
+ const content = fs.readFileSync(file.src, 'utf8');
353
+ writeFileWithMode(destination, content);
354
+
355
+ if (alreadyExists) {
356
+ report.overwritten.push(`${dryRun ? 'Would overwrite' : 'Overwrote'} ${relativeDisplay(destination)}.`);
25
357
  } else {
26
- fs.copyFileSync(src, dest);
27
- console.log(`āœ… Copied ${dest.replace(targetDir, '')}`);
358
+ report.copied.push(`${dryRun ? 'Would copy' : 'Copied'} ${relativeDisplay(destination)}.`);
28
359
  }
29
360
  }
30
361
  }
31
362
 
363
+ function collectLegacyWarnings(status) {
364
+ if (status.legacyHackFiles.length > 0) {
365
+ report.warnings.push(`Legacy alias workaround detected: ${status.legacyHackFiles.join(', ')}.`);
366
+ }
367
+
368
+ if (status.legacyPostinstall) {
369
+ report.warnings.push('`scripts.postinstall` still references `link-digivalt-alias`; review whether that workaround is still needed.');
370
+ }
371
+
372
+ if (status.legacyRootImport) {
373
+ report.warnings.push('`scripts/generate.ts` still imports `generators` from the root package instead of `@marvalt/digivalt-core/generators`.');
374
+ }
375
+
376
+ if (status.legacyViteConfigs.length > 0) {
377
+ report.warnings.push(`Legacy Vite SSR/noExternal workaround detected in: ${status.legacyViteConfigs.join(', ')}.`);
378
+ }
379
+ }
380
+
381
+ function printList(title, items) {
382
+ if (items.length === 0) {
383
+ return;
384
+ }
385
+
386
+ console.log(`\n${title}`);
387
+ for (const item of items) {
388
+ console.log(`- ${item}`);
389
+ }
390
+ }
391
+
392
+ function printSummary() {
393
+ printList('šŸ“¦ Template file actions', [...report.copied, ...report.overwritten, ...report.skipped]);
394
+ printList('šŸ› ļø Package wiring updates', report.patchedScripts);
395
+ printList('šŸ”„ Refreshed DigiVAlt files', report.refreshedFiles);
396
+ printList('āš ļø Warnings', report.warnings);
397
+ printList('šŸ‘‰ Manual follow-up', report.manualActions);
398
+
399
+ console.log('\nšŸŽ‰ DigiVAlt init completed.');
400
+ console.log('Next steps:');
401
+ console.log('1. Review any warnings or manual follow-up items above.');
402
+ console.log('2. Copy `.dev.vars.example` to `.dev.vars` if you need local Wrangler secrets.');
403
+ console.log('3. Confirm `wrangler.toml` matches your Cloudflare Pages project name.');
404
+ console.log('4. Run `npm run build` to verify static generation now runs before `vite build`.');
405
+ console.log('5. Run `node scripts/deploy-secrets.js` when you are ready to sync allowed env vars to Cloudflare.');
406
+ }
407
+
32
408
  try {
33
- copyRecursiveSync(sourceDir, targetDir);
34
- console.log('\nšŸŽ‰ DigiVAlt Cloudflare proxy routes installed successfully!');
35
- console.log('šŸ‘‰ Next Steps:');
36
- console.log('1. Copy .dev.vars.example to .dev.vars and add your API keys.');
37
- console.log("2. Sync your production credentials to Cloudflare by running:");
38
- console.log(" šŸ‘‰ node scripts/deploy-secrets.js");
39
- console.log("3. Run `npx wrangler pages dev` to test your proxy functions locally.");
409
+ logHeader();
410
+ const packageJsonPath = ensureValidTarget(targetDir);
411
+ const templateGeneratePath = path.join(sourceDir, 'scripts', 'generate.ts');
412
+ const templateGenerateScript = fs.readFileSync(templateGeneratePath, 'utf8');
413
+
414
+ const status = inspectTargetApp(packageJsonPath, templateGenerateScript);
415
+ printPreflight(status);
416
+ collectLegacyWarnings(status);
417
+ patchPackageJson(status);
418
+ reconcileGenerateScript(status, templateGenerateScript);
419
+ copyTemplateFiles();
420
+ printSummary();
40
421
  } catch (error) {
41
422
  console.error('āŒ Failed to construct templates:', error);
42
423
  process.exit(1);