@podosoft/podokit 1.5.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/app-proxy-timeouts.d.ts +27 -0
- package/dist/app-proxy-timeouts.js +180 -0
- package/dist/assemble.d.ts +5 -2
- package/dist/assemble.js +14 -4
- package/dist/deploy-checks.d.ts +44 -0
- package/dist/deploy-checks.js +267 -0
- package/dist/deploy-compose-profile.d.ts +6 -2
- package/dist/deploy-compose-profile.js +15 -6
- package/dist/deploy-compose-render.d.ts +12 -4
- package/dist/deploy-compose-render.js +47 -18
- package/dist/deploy-compose.d.ts +2 -5
- package/dist/deploy-compose.js +7 -2
- package/dist/deploy-profile.d.ts +6 -2
- package/dist/deploy-profile.js +11 -7
- package/dist/deploy-render.d.ts +4 -1
- package/dist/deploy-render.js +27 -21
- package/dist/deploy-schema.d.ts +60 -2
- package/dist/deploy-schema.js +141 -14
- package/dist/deploy.d.ts +2 -5
- package/dist/deploy.js +5 -2
- package/dist/dev.d.ts +21 -0
- package/dist/dev.js +78 -3
- package/dist/eject.js +2 -0
- package/dist/index.js +85 -5
- package/dist/lib.d.ts +2 -0
- package/dist/lib.js +5 -2
- package/dist/lockfile.d.ts +24 -0
- package/dist/lockfile.js +74 -4
- package/dist/provider.js +10 -5
- package/dist/remove.js +1 -1
- package/dist/template-files.d.ts +42 -0
- package/dist/template-files.js +102 -0
- package/dist/templates/fullstack/AGENTS.md +30 -4
- package/dist/templates/fullstack/README.md +8 -7
- package/dist/templates/fullstack/apps/api/package.json +4 -4
- package/dist/templates/fullstack/apps/api/scripts/build.extensions.mjs +6 -0
- package/dist/templates/fullstack/apps/api/scripts/build.mjs +65 -16
- package/dist/templates/fullstack/apps/api/scripts/run-migrations.mjs +7 -3
- package/dist/templates/fullstack/apps/api/scripts/verify-api-contract.ts +7 -2
- package/dist/templates/fullstack/apps/api/src/app.spec.ts +22 -0
- package/dist/templates/fullstack/apps/api/src/app.ts +41 -25
- package/dist/templates/fullstack/apps/api/src/build.spec.ts +121 -0
- package/dist/templates/fullstack/apps/api/src/config/env.extensions.ts +20 -0
- package/dist/templates/fullstack/apps/api/src/config/env.validation.spec.ts +76 -0
- package/dist/templates/fullstack/apps/api/src/config/env.validation.ts +18 -3
- package/dist/templates/fullstack/apps/api/src/config/provider-selection.spec.ts +53 -0
- package/dist/templates/fullstack/apps/api/src/config/provider-selection.ts +79 -0
- package/dist/templates/fullstack/apps/api/src/config/providers.ts +7 -3
- package/dist/templates/fullstack/apps/api/src/core/api-contract.extensions.ts +6 -0
- package/dist/templates/fullstack/apps/api/src/core/api-contract.spec.ts +72 -4
- package/dist/templates/fullstack/apps/api/src/core/api-contract.ts +78 -6
- package/dist/templates/fullstack/apps/api/src/core/services.ts +13 -0
- package/dist/templates/fullstack/apps/api/src/database/data-source.spec.ts +27 -0
- package/dist/templates/fullstack/apps/api/src/database/data-source.ts +7 -10
- package/dist/templates/fullstack/apps/api/src/database/database.spec.ts +12 -0
- package/dist/templates/fullstack/apps/api/src/database/database.ts +2 -3
- package/dist/templates/fullstack/apps/api/src/database/entities.ts +12 -0
- package/dist/templates/fullstack/apps/api/src/database/migrate.ts +12 -2
- package/dist/templates/fullstack/apps/api/src/database/migration-files.spec.ts +116 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-files.ts +134 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-readiness.spec.ts +36 -0
- package/dist/templates/fullstack/apps/api/src/database/migration-readiness.ts +25 -0
- package/dist/templates/fullstack/apps/api/src/database/run-migrations.spec.ts +12 -1
- package/dist/templates/fullstack/apps/api/src/database/sqlite-migrator.ts +2 -36
- package/dist/templates/fullstack/apps/api/src/main.ts +2 -2
- package/dist/templates/fullstack/apps/api/tsconfig.json +2 -0
- package/dist/templates/fullstack/apps/web/package.json +1 -1
- package/dist/templates/fullstack/apps/web/src/app.css +3 -0
- package/dist/templates/fullstack/apps/web/src/app.extensions.css +11 -0
- package/dist/templates/fullstack/apps/web/src/lib/components/site-runtime.svelte +3 -1
- package/dist/templates/fullstack/apps/web/src/lib/server/api.test.ts +19 -0
- package/dist/templates/fullstack/apps/web/src/lib/server/api.ts +4 -1
- package/dist/templates/fullstack/apps/web/src/lib/server/backend-proxy.test.ts +79 -0
- package/dist/templates/fullstack/apps/web/src/lib/server/backend-proxy.ts +55 -1
- package/dist/templates/fullstack/apps/web/src/lib/server/proxy-timeouts.ts +2 -1
- package/dist/templates/fullstack/apps/web/tsconfig.json +1 -1
- package/dist/templates/fullstack/apps/web/vite.config.test.ts +33 -0
- package/dist/templates/fullstack/apps/web/vite.config.ts +55 -13
- package/dist/templates/fullstack/apps/web/vite.extensions.ts +23 -0
- package/dist/templates/fullstack/compose.dev.yaml +7 -4
- package/dist/templates/fullstack/dot-agents/skills/podokit-deploy/SKILL.md +2 -2
- package/dist/templates/fullstack/dot-agents/skills/podokit-deploy/references/profile.md +13 -3
- package/dist/templates/fullstack/dot-claude/skills/podokit-update/SKILL.md +5 -2
- package/dist/templates/fullstack/dot-env.docker.example +5 -2
- package/dist/templates/fullstack/dot-env.example +4 -0
- package/dist/templates/fullstack/dot-podokit/dev.json +1 -1
- package/dist/templates/fullstack/infra/k3s/configmap.yaml +1 -0
- package/dist/templates/fullstack/tests/README.md +50 -1
- package/dist/templates/fullstack/tests/helpers/app-paths.ts +18 -0
- package/dist/templates/fullstack/tests/helpers/paths.ts +33 -0
- package/dist/templates/fullstack/tests/helpers/seeded-admin.ts +15 -0
- package/dist/templates/fullstack/tests/package.json +3 -3
- package/dist/templates/fullstack/tests/playwright.config.ts +10 -4
- package/dist/templates/fullstack/tests/playwright.extensions.ts +149 -1
- package/dist/templates/fullstack/tests/run-e2e.ts +28 -0
- package/dist/templates/fullstack/tests/ui/smoke.ui.spec.ts +5 -4
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.test.ts +37 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +15 -6
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flag-settings.test.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flag-settings.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-flags.ts +12 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/app-nav.ts +11 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/nav.test.ts +53 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/nav.ts +35 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/admin/registry.svelte.ts +15 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-page.svelte +11 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/admin-sidebar.svelte +2 -23
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/data-table.svelte +7 -2
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/data-table.test.ts +30 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/impersonation-banner.svelte +3 -2
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/settings/app-flags-settings.svelte +65 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +32 -23
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.test.ts +27 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-footer.svelte +4 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/site-runtime.svelte +3 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/theme-toggle.svelte +1 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/en.json +6 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/ko.json +6 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/app-hooks.ts +11 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/non-indexable-paths.ts +8 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/search-indexing.test.ts +31 -0
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/server/search-indexing.ts +5 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/settings/+page.svelte +1 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.server.ts +2 -1
- package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/account/+page.svelte +1 -5
- package/dist/templates/modules/admin-dashboard/files/dot-claude/skills/podokit-data-table/SKILL.md +2 -0
- package/dist/templates/modules/admin-dashboard/files/tests/api/audit.api.spec.ts +1 -1
- package/dist/templates/modules/admin-dashboard/files/tests/api/auth-config.api.spec.ts +159 -170
- package/dist/templates/modules/admin-dashboard/files/tests/api/auth.api.spec.ts +72 -81
- package/dist/templates/modules/admin-dashboard/files/tests/api/email.api.spec.ts +1 -6
- package/dist/templates/modules/admin-dashboard/files/tests/api/profile-image.api.spec.ts +1 -1
- package/dist/templates/modules/admin-dashboard/files/tests/api/site-settings.api.spec.ts +43 -53
- package/dist/templates/modules/admin-dashboard/files/tests/api/users-admin.api.spec.ts +3 -1
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/accounts.ts +24 -6
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/app-accounts.ts +24 -0
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/devices.ts +41 -11
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/disposable-users.ts +5 -3
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/hydration.ts +13 -4
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/mailpit.ts +3 -9
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/sms.ts +2 -4
- package/dist/templates/modules/admin-dashboard/files/tests/playwright.config.ts +14 -6
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account-flows.ui.spec.ts +4 -5
- package/dist/templates/modules/admin-dashboard/files/tests/ui/account.ui.spec.ts +55 -55
- package/dist/templates/modules/admin-dashboard/files/tests/ui/app-flags.ui.spec.ts +63 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/appearance.ui.spec.ts +12 -16
- package/dist/templates/modules/admin-dashboard/files/tests/ui/audit.ui.spec.ts +3 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +32 -35
- package/dist/templates/modules/admin-dashboard/files/tests/ui/dashboard.ui.spec.ts +4 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/email-admin.ui.spec.ts +1 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/email.ui.spec.ts +1 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/general-effects.ui.spec.ts +82 -91
- package/dist/templates/modules/admin-dashboard/files/tests/ui/guards.ui.spec.ts +6 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/i18n.ui.spec.ts +16 -20
- package/dist/templates/modules/admin-dashboard/files/tests/ui/impersonation.ui.spec.ts +6 -3
- package/dist/templates/modules/admin-dashboard/files/tests/ui/login-methods.ui.spec.ts +2 -3
- package/dist/templates/modules/admin-dashboard/files/tests/ui/oidc.ui.spec.ts +2 -4
- package/dist/templates/modules/admin-dashboard/files/tests/ui/organizations.ui.spec.ts +5 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/passkey.ui.spec.ts +7 -2
- package/dist/templates/modules/admin-dashboard/files/tests/ui/same-origin-requests.ui.spec.ts +89 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/sessions.ui.spec.ts +5 -4
- package/dist/templates/modules/admin-dashboard/files/tests/ui/settings-dialogs.ui.spec.ts +67 -73
- package/dist/templates/modules/admin-dashboard/files/tests/ui/settings.ui.spec.ts +84 -93
- package/dist/templates/modules/admin-dashboard/files/tests/ui/table-toolbar.ui.spec.ts +8 -7
- package/dist/templates/modules/admin-dashboard/files/tests/ui/theme-mode.ui.spec.ts +35 -0
- package/dist/templates/modules/admin-dashboard/files/tests/ui/two-factor.ui.spec.ts +51 -54
- package/dist/templates/modules/admin-dashboard/files/tests/ui/users.ui.spec.ts +10 -9
- package/dist/templates/modules/admin-dashboard/module.manifest.json +7 -2
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.module.ts +5 -1
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.spec.ts +17 -0
- package/dist/templates/modules/audit-log/files/apps/api/src/audit/audit.service.ts +18 -0
- package/dist/templates/modules/audit-log/module.manifest.json +15 -3
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-app-name.spec.ts +21 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-config-store.ts +13 -1
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-environment.ts +9 -2
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth-provider.ts +19 -3
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.module.ts +2 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.runtime.spec.ts +10 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +7 -5
- package/dist/templates/modules/auth/files/apps/api/src/auth/schema-recheck.spec.ts +86 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth/schema-recheck.ts +44 -0
- package/dist/templates/modules/auth/files/apps/api/src/auth-config/auth-config.service.ts +2 -1
- package/dist/templates/modules/auth/files/apps/api/src/migrate.ts +3 -1
- package/dist/templates/modules/auth/files/apps/api/src/settings/app-flags.ts +9 -0
- package/dist/templates/modules/auth/files/apps/api/src/settings/flag-defaults.spec.ts +43 -0
- package/dist/templates/modules/auth/files/apps/api/src/settings/flag-defaults.ts +30 -5
- package/dist/templates/modules/auth/module.manifest.json +8 -2
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/bullmq-job.queue.spec.ts +107 -1
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/bullmq-job.queue.ts +113 -9
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.spec.ts +40 -0
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/worker.module.ts +52 -5
- package/dist/templates/modules/bullmq/files/apps/api/src/main-worker.ts +9 -7
- package/dist/templates/modules/bullmq/files/apps/api/src/worker.extensions.ts +13 -0
- package/dist/templates/modules/bullmq/module.manifest.json +5 -1
- package/dist/templates/modules/job-progress/files/apps/api/src/progress/progress.worker.spec.ts +2 -0
- package/dist/templates/modules/jobs-local/files/apps/api/src/jobs-local/local-job.queue.spec.ts +174 -1
- package/dist/templates/modules/jobs-local/files/apps/api/src/jobs-local/local-job.queue.ts +150 -3
- package/dist/templates/modules/jobs-local/module.manifest.json +3 -0
- package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.spec.ts +16 -0
- package/dist/templates/modules/logging/files/apps/api/src/logging/logging.module.ts +15 -10
- package/dist/templates/modules/mailer/module.manifest.json +1 -1
- package/dist/templates/modules/object-storage-local/files/tests/api/storage-local.api.spec.ts +3 -6
- package/dist/templates/modules/object-storage-s3/files/infra/docker/minio.compose.yml +5 -4
- package/dist/templates/modules/object-storage-s3/files/tests/api/storage.api.spec.ts +3 -6
- package/dist/templates/modules/rate-limit/files/tests/api/rate-limit.api.spec.ts +45 -20
- package/dist/templates/modules/sse/files/tests/api/events.api.spec.ts +3 -6
- package/dist/templates/todo/AGENTS.md +5 -1
- package/dist/templates/todo/README.md +6 -4
- package/dist/text-diff.d.ts +12 -0
- package/dist/text-diff.js +111 -0
- package/dist/update.d.ts +61 -3
- package/dist/update.js +152 -27
- package/package.json +2 -2
- package/dist/templates/modules/admin-dashboard/files/tests/api/exclusive.api.spec.ts +0 -75
- package/dist/templates/modules/admin-dashboard/files/tests/helpers/exclusive.ts +0 -80
package/dist/index.js
CHANGED
|
@@ -12,12 +12,14 @@ const remove_1 = require("./remove");
|
|
|
12
12
|
const inspect_1 = require("./inspect");
|
|
13
13
|
const update_1 = require("./update");
|
|
14
14
|
const eject_1 = require("./eject");
|
|
15
|
+
const template_files_1 = require("./template-files");
|
|
15
16
|
const dev_1 = require("./dev");
|
|
16
17
|
const locale_1 = require("./locale");
|
|
17
18
|
const deploy_1 = require("./deploy");
|
|
18
19
|
const deploy_profile_1 = require("./deploy-profile");
|
|
19
20
|
const deploy_render_1 = require("./deploy-render");
|
|
20
21
|
const deploy_driver_1 = require("./deploy-driver");
|
|
22
|
+
const deploy_checks_1 = require("./deploy-checks");
|
|
21
23
|
const deploy_compose_profile_1 = require("./deploy-compose-profile");
|
|
22
24
|
const deploy_compose_render_1 = require("./deploy-compose-render");
|
|
23
25
|
const deploy_compose_1 = require("./deploy-compose");
|
|
@@ -33,7 +35,7 @@ Usage:
|
|
|
33
35
|
podo provider set <capability> <provider> [--apply]
|
|
34
36
|
podo remove <module> Un-apply a module (inverse of add)
|
|
35
37
|
podo status Show version, modules, file tiers, and local edits
|
|
36
|
-
podo diff
|
|
38
|
+
podo diff [path...] List edited managed files, or diff files against the template
|
|
37
39
|
podo doctor Check framework versions against supported ranges
|
|
38
40
|
podo dev <action> [...] Run the shared, portless container development gateway
|
|
39
41
|
podo deploy <action> Plan, apply, verify, or roll back a deployment
|
|
@@ -41,6 +43,7 @@ Usage:
|
|
|
41
43
|
podo locale <command> Add, validate, activate, or list JSON locales
|
|
42
44
|
podo update [--apply] Preview (or apply) what a version update would change
|
|
43
45
|
podo eject <path...> Take ownership of managed files (update skips them)
|
|
46
|
+
podo restore <path...> Rewrite managed or ejected files from the template
|
|
44
47
|
|
|
45
48
|
Options:
|
|
46
49
|
--template <t> Template to scaffold (see below)
|
|
@@ -220,6 +223,26 @@ function parseArgs(argv) {
|
|
|
220
223
|
parsed.positionals = positionals;
|
|
221
224
|
return parsed;
|
|
222
225
|
}
|
|
226
|
+
/** Explain owned files whose template changed, with the upstream diff when the previous templates are given. */
|
|
227
|
+
function writeOwnedTemplateNotes(plan, templatesDir, from) {
|
|
228
|
+
if (plan.changes.some((change) => change.action === "review")) {
|
|
229
|
+
if (from) {
|
|
230
|
+
process.stdout.write("\nTemplate changes to files you own (not applied):\n");
|
|
231
|
+
for (const change of (0, update_1.upstreamChanges)(process.cwd(), templatesDir, plan, from)) {
|
|
232
|
+
process.stdout.write(change.diff || `${change.path}: new in this version's template.\n`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
process.stdout.write("\nreview: the template changed for a file you own. podo update never writes it; " +
|
|
237
|
+
"podo diff <path> compares it with the new template, and --from <previous templates> shows what changed upstream.\n");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (plan.ownedWithoutTemplate.length) {
|
|
241
|
+
process.stdout.write(`\n${plan.ownedWithoutTemplate.length} owned file(s) differ from this version's templates, and the lock does not record ` +
|
|
242
|
+
"the template they came from. podo diff <path> shows the difference; applying this update records the template " +
|
|
243
|
+
"so the next update reports only real template changes.\n");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
223
246
|
function writeApiPaths(heading, result, verb) {
|
|
224
247
|
const lines = (0, module_api_paths_1.describeApiPaths)(result, verb);
|
|
225
248
|
if (lines.length)
|
|
@@ -258,7 +281,7 @@ async function runComposeDeploy(action, args, profileName) {
|
|
|
258
281
|
const findings = (0, deploy_compose_1.doctorComposeDeployment)(cwd, profileName, undefined, args.release);
|
|
259
282
|
process.stdout.write(args.json
|
|
260
283
|
? `${JSON.stringify(findings, null, 2)}\n`
|
|
261
|
-
: `${findings.map(
|
|
284
|
+
: `${findings.map(deploy_checks_1.formatFinding).join("\n")}\n`);
|
|
262
285
|
if (findings.some((finding) => !finding.ok))
|
|
263
286
|
process.exitCode = 1;
|
|
264
287
|
return;
|
|
@@ -461,7 +484,33 @@ async function main(argv) {
|
|
|
461
484
|
return;
|
|
462
485
|
}
|
|
463
486
|
if (args.command === "diff") {
|
|
487
|
+
const targets = args.positionals.slice(1);
|
|
464
488
|
try {
|
|
489
|
+
if (targets.length) {
|
|
490
|
+
const result = (0, template_files_1.templateDiff)(process.cwd(), (0, node_path_1.join)(__dirname, "templates"), targets);
|
|
491
|
+
if (result.projectVersion !== result.templateVersion) {
|
|
492
|
+
process.stdout.write(`Comparing with PodoKit ${result.templateVersion} templates; this project is on ${result.projectVersion}.\n`);
|
|
493
|
+
}
|
|
494
|
+
for (const file of result.files) {
|
|
495
|
+
const tier = file.tier ? ` (${file.tier})` : "";
|
|
496
|
+
if (file.status === "not-generated") {
|
|
497
|
+
process.stdout.write(`${file.path}: PodoKit does not generate this file.\n`);
|
|
498
|
+
}
|
|
499
|
+
else if (file.status === "missing") {
|
|
500
|
+
process.stdout.write(`${file.path}${tier}: missing; podo restore ${file.path} writes the template's version.\n`);
|
|
501
|
+
}
|
|
502
|
+
else if (file.status === "same") {
|
|
503
|
+
process.stdout.write(`${file.path}${tier}: same as the template.\n`);
|
|
504
|
+
}
|
|
505
|
+
else if (file.binary) {
|
|
506
|
+
process.stdout.write(`${file.path}${tier}: binary file differs from the template.\n`);
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
process.stdout.write(file.diff);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
465
514
|
const { drifted, missing } = (0, inspect_1.diff)(process.cwd());
|
|
466
515
|
if (!drifted.length && !missing.length) {
|
|
467
516
|
process.stdout.write("No local edits to PodoKit-managed files.\n");
|
|
@@ -539,7 +588,7 @@ async function main(argv) {
|
|
|
539
588
|
const findings = (0, deploy_1.doctorDeployment)(process.cwd(), profileName);
|
|
540
589
|
process.stdout.write(args.json
|
|
541
590
|
? `${JSON.stringify(findings, null, 2)}\n`
|
|
542
|
-
: `${findings.map(
|
|
591
|
+
: `${findings.map(deploy_checks_1.formatFinding).join("\n")}\n`);
|
|
543
592
|
if (findings.some((finding) => !finding.ok))
|
|
544
593
|
process.exitCode = 1;
|
|
545
594
|
return;
|
|
@@ -561,7 +610,9 @@ async function main(argv) {
|
|
|
561
610
|
const plan = (0, deploy_1.planDeployment)(process.cwd(), profileName, args.release);
|
|
562
611
|
process.stdout.write(args.json
|
|
563
612
|
? `${JSON.stringify(plan, null, 2)}\n`
|
|
564
|
-
: `${plan.actions.map((entry) => `${entry.order}. ${entry.description}`).join("\n")}\
|
|
613
|
+
: `${plan.actions.map((entry) => `${entry.order}. ${entry.description}`).join("\n")}\n` +
|
|
614
|
+
`${plan.warnings.map((warning) => `warning: ${warning}`).join("\n")}\n` +
|
|
615
|
+
`Plan hash: ${plan.planHash}\n`);
|
|
565
616
|
return;
|
|
566
617
|
}
|
|
567
618
|
if (action === "apply") {
|
|
@@ -672,12 +723,23 @@ async function main(argv) {
|
|
|
672
723
|
result.conflicts.map((f) => ` ${f}`).join("\n") +
|
|
673
724
|
"\n");
|
|
674
725
|
}
|
|
726
|
+
if (result.review.length) {
|
|
727
|
+
process.stdout.write("\nThe template changed for these files you own; they were left as they are. " +
|
|
728
|
+
"Compare each with podo diff <path>:\n" +
|
|
729
|
+
result.review.map((f) => ` ${f}`).join("\n") +
|
|
730
|
+
"\n");
|
|
731
|
+
}
|
|
675
732
|
return;
|
|
676
733
|
}
|
|
677
734
|
const plan = (0, update_1.planUpdate)(process.cwd(), templatesDir);
|
|
678
735
|
const counts = (0, update_1.summarize)(plan);
|
|
679
736
|
const shown = plan.changes.filter((c) => c.action !== "up-to-date" && c.action !== "skip");
|
|
680
737
|
process.stdout.write(`podo update ${plan.fromVersion} -> ${plan.toVersion} (template: ${plan.template}; modules: ${plan.modules.join(", ") || "none"})\n\n`);
|
|
738
|
+
if (plan.moduleDowngrades.length) {
|
|
739
|
+
process.stdout.write("WARN older external modules are installed than this project applied:\n" +
|
|
740
|
+
`${(0, update_1.describeDowngrades)(plan.moduleDowngrades)}\n` +
|
|
741
|
+
"--apply refuses until you install the recorded versions; the plan below would downgrade them.\n\n");
|
|
742
|
+
}
|
|
681
743
|
if (plan.addedModules.length) {
|
|
682
744
|
process.stdout.write("Modules to add:\n" +
|
|
683
745
|
plan.addedModules.map((module) => ` ${module.name} (${(0, update_1.addedModuleReason)(module)})`).join("\n") +
|
|
@@ -696,9 +758,10 @@ async function main(argv) {
|
|
|
696
758
|
process.stdout.write(` ${c.action.padEnd(9)} ${path} (${c.note})\n`);
|
|
697
759
|
}
|
|
698
760
|
process.stdout.write(`${shown.length ? "\n" : ""}${counts.update} update, ${counts.add} add, ${counts.move} move, ` +
|
|
699
|
-
`${counts.remove} remove, ${counts.conflict} conflict. ` +
|
|
761
|
+
`${counts.remove} remove, ${counts.conflict} conflict, ${counts.review} review. ` +
|
|
700
762
|
`Dry-run — nothing was written. Re-run with --apply to write (use --from <dir> for a 3-way merge).\n`);
|
|
701
763
|
}
|
|
764
|
+
writeOwnedTemplateNotes(plan, templatesDir, args.from);
|
|
702
765
|
}
|
|
703
766
|
catch (err) {
|
|
704
767
|
fail(err.message);
|
|
@@ -727,6 +790,23 @@ async function main(argv) {
|
|
|
727
790
|
}
|
|
728
791
|
return;
|
|
729
792
|
}
|
|
793
|
+
if (args.command === "restore") {
|
|
794
|
+
const targets = args.positionals.slice(1);
|
|
795
|
+
if (!targets.length) {
|
|
796
|
+
fail("Usage: podo restore <path...>");
|
|
797
|
+
}
|
|
798
|
+
try {
|
|
799
|
+
const result = (0, template_files_1.restore)(process.cwd(), (0, node_path_1.join)(__dirname, "templates"), targets);
|
|
800
|
+
process.stdout.write(`Restored from the template: ${result.restored.join(", ")}\n`);
|
|
801
|
+
if (result.remanaged.length) {
|
|
802
|
+
process.stdout.write(`Managed by PodoKit again: ${result.remanaged.join(", ")}\n`);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
catch (err) {
|
|
806
|
+
fail(err.message);
|
|
807
|
+
}
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
730
810
|
if (args.command !== "create") {
|
|
731
811
|
fail(`Unknown command "${args.command}". Run "podo --help".`);
|
|
732
812
|
}
|
package/dist/lib.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export { describeApiPaths } from "./module-api-paths";
|
|
|
11
11
|
export { status, diff, doctor, SUPPORTED_FRAMEWORKS } from "./inspect";
|
|
12
12
|
export type { StatusReport, DoctorFinding } from "./inspect";
|
|
13
13
|
export { addedModuleReason, planUpdate, summarize } from "./update";
|
|
14
|
+
export { restore, templateDiff } from "./template-files";
|
|
15
|
+
export type { RestoreResult, TemplateDiffResult, TemplateFileDiff } from "./template-files";
|
|
14
16
|
export type { AddedModule, UpdatePlan, FileChange } from "./update";
|
|
15
17
|
export { readDevConfig, renderRoute, renderRuntimeCompose, resolveDevRuntime, runDevCommand } from "./dev";
|
|
16
18
|
export type { CommandRunner, DevConfig, DevRuntime } from "./dev";
|
package/dist/lib.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.verifyAnyDeployment = exports.planAnyDeployment = exports.getAnyDeploymentStatus = exports.doctorAnyDeployment = exports.describeDeploymentTarget = exports.verifyComposeDeployment = exports.rollbackComposeDeployment = exports.planComposeRollback = exports.planComposeDeployment = exports.inspectComposeEndpointFingerprint = exports.getComposeStatus = exports.doctorComposeDeployment = void 0;
|
|
3
|
+
exports.parseComposeProfile = exports.initializeComposeProfile = exports.readDeploymentDriver = exports.loadKubernetesProfile = exports.loadComposeProfile = exports.loadAnyDeploymentProfile = exports.listAnyDeploymentProfiles = exports.assertAnyReleaseTag = exports.DEPLOY_DRIVERS = exports.renderDeployment = exports.loadDeploymentProfile = exports.listDeploymentProfiles = exports.initializeDeploymentProfile = exports.deploymentProfileDigest = exports.assertReleaseTag = exports.verifyDeployment = exports.rollbackDeployment = exports.planRollback = exports.planDeployment = exports.inspectClusterFingerprint = exports.getDeploymentStatus = exports.doctorDeployment = exports.applyDeployment = exports.runDevCommand = exports.resolveDevRuntime = exports.renderRuntimeCompose = exports.renderRoute = exports.readDevConfig = exports.templateDiff = exports.restore = exports.summarize = exports.planUpdate = exports.addedModuleReason = exports.SUPPORTED_FRAMEWORKS = exports.doctor = exports.diff = exports.status = exports.describeApiPaths = exports.addModule = exports.listModules = exports.isKnownTemplate = exports.TEMPLATE_NAMES = exports.DEFAULT_TEMPLATE = exports.TEMPLATES = exports.PROVIDERS_SOURCE = exports.providerSource = exports.planProviderChange = exports.listProviders = exports.applyProviderChange = exports.create = void 0;
|
|
4
|
+
exports.verifyAnyDeployment = exports.planAnyDeployment = exports.getAnyDeploymentStatus = exports.doctorAnyDeployment = exports.describeDeploymentTarget = exports.verifyComposeDeployment = exports.rollbackComposeDeployment = exports.planComposeRollback = exports.planComposeDeployment = exports.inspectComposeEndpointFingerprint = exports.getComposeStatus = exports.doctorComposeDeployment = exports.applyComposeDeployment = exports.renderComposeDeployment = void 0;
|
|
5
5
|
exports.builtinTemplatesDir = builtinTemplatesDir;
|
|
6
6
|
exports.builtinModulesDir = builtinModulesDir;
|
|
7
7
|
// Library entry point: the reusable functions behind the `podo` CLI, for other
|
|
@@ -34,6 +34,9 @@ var update_1 = require("./update");
|
|
|
34
34
|
Object.defineProperty(exports, "addedModuleReason", { enumerable: true, get: function () { return update_1.addedModuleReason; } });
|
|
35
35
|
Object.defineProperty(exports, "planUpdate", { enumerable: true, get: function () { return update_1.planUpdate; } });
|
|
36
36
|
Object.defineProperty(exports, "summarize", { enumerable: true, get: function () { return update_1.summarize; } });
|
|
37
|
+
var template_files_1 = require("./template-files");
|
|
38
|
+
Object.defineProperty(exports, "restore", { enumerable: true, get: function () { return template_files_1.restore; } });
|
|
39
|
+
Object.defineProperty(exports, "templateDiff", { enumerable: true, get: function () { return template_files_1.templateDiff; } });
|
|
37
40
|
var dev_1 = require("./dev");
|
|
38
41
|
Object.defineProperty(exports, "readDevConfig", { enumerable: true, get: function () { return dev_1.readDevConfig; } });
|
|
39
42
|
Object.defineProperty(exports, "renderRoute", { enumerable: true, get: function () { return dev_1.renderRoute; } });
|
package/dist/lockfile.d.ts
CHANGED
|
@@ -51,6 +51,12 @@ export interface FileEntry {
|
|
|
51
51
|
tier: Tier;
|
|
52
52
|
/** Hash of the exact bytes PodoKit last wrote; user-edit detector. */
|
|
53
53
|
outHash: string;
|
|
54
|
+
/**
|
|
55
|
+
* Owned files only: hash of what the template generated for the path when
|
|
56
|
+
* PodoKit last rendered it, so `podo update` can tell the application that
|
|
57
|
+
* the template changed without touching the file.
|
|
58
|
+
*/
|
|
59
|
+
templateHash?: string;
|
|
54
60
|
}
|
|
55
61
|
export interface FilesLock {
|
|
56
62
|
schemaVersion: number;
|
|
@@ -68,6 +74,12 @@ export interface RecordModulesLockSnapshot {
|
|
|
68
74
|
}
|
|
69
75
|
/** Default user-owned globs seeded into a new project. See ADR-0010. */
|
|
70
76
|
export declare const DEFAULT_OWNED_GLOBS: string[];
|
|
77
|
+
/**
|
|
78
|
+
* PodoKit's own agent skills stay managed inside the owned `.claude/**` and
|
|
79
|
+
* `.agents/**` trees, so updates keep their commands and APIs current. Skills an
|
|
80
|
+
* application adds under other names stay owned.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DEFAULT_MANAGED_OVERRIDES: string[];
|
|
71
83
|
export declare function manifestPath(projectRoot: string): string;
|
|
72
84
|
export declare function filesLockPath(projectRoot: string): string;
|
|
73
85
|
export declare function readManifest(projectRoot: string): PodokitManifest | null;
|
|
@@ -93,6 +105,18 @@ export declare function isLocalEnvFile(relPath: string): boolean;
|
|
|
93
105
|
export declare function walkFiles(projectRoot: string, prefix?: string): string[];
|
|
94
106
|
/** Recompute the files.lock by hashing and classifying every project file. */
|
|
95
107
|
export declare function computeFilesLock(projectRoot: string, ownedGlobs: string[], managedOverrides?: string[]): FilesLock;
|
|
108
|
+
/**
|
|
109
|
+
* The template content an earlier lock knew for a path: the recorded template
|
|
110
|
+
* hash of an owned file, or the generated baseline of a managed one.
|
|
111
|
+
*/
|
|
112
|
+
export declare function recordedTemplateHash(entry: FileEntry | undefined): string | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Carry the template hashes of an earlier lock into a recomputed one for files
|
|
115
|
+
* that are owned now. Paths in `changed` were just rewritten from a different
|
|
116
|
+
* template, such as the files a module added to or removed from, so their old
|
|
117
|
+
* hash would be wrong and is dropped.
|
|
118
|
+
*/
|
|
119
|
+
export declare function keepTemplateHashes(next: FilesLock, previous: FilesLock | null, changed?: Iterable<string>): FilesLock;
|
|
96
120
|
export declare function readFilesLock(projectRoot: string): FilesLock | null;
|
|
97
121
|
export interface Drift {
|
|
98
122
|
/** Managed/assembled files whose content differs from what PodoKit wrote. */
|
package/dist/lockfile.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_OWNED_GLOBS = exports.LOCK_SCHEMA_VERSION = void 0;
|
|
3
|
+
exports.DEFAULT_MANAGED_OVERRIDES = exports.DEFAULT_OWNED_GLOBS = exports.LOCK_SCHEMA_VERSION = void 0;
|
|
4
4
|
exports.manifestPath = manifestPath;
|
|
5
5
|
exports.filesLockPath = filesLockPath;
|
|
6
6
|
exports.readManifest = readManifest;
|
|
@@ -14,6 +14,8 @@ exports.classifyTier = classifyTier;
|
|
|
14
14
|
exports.isLocalEnvFile = isLocalEnvFile;
|
|
15
15
|
exports.walkFiles = walkFiles;
|
|
16
16
|
exports.computeFilesLock = computeFilesLock;
|
|
17
|
+
exports.recordedTemplateHash = recordedTemplateHash;
|
|
18
|
+
exports.keepTemplateHashes = keepTemplateHashes;
|
|
17
19
|
exports.readFilesLock = readFilesLock;
|
|
18
20
|
exports.computeDrift = computeDrift;
|
|
19
21
|
exports.initLockfile = initLockfile;
|
|
@@ -55,11 +57,23 @@ exports.DEFAULT_OWNED_GLOBS = [
|
|
|
55
57
|
"apps/web/src/lib/i18n/catalogs/app/**",
|
|
56
58
|
// Owned Elysia extension slot — register application services and plugins here.
|
|
57
59
|
"apps/api/src/app.extensions.ts",
|
|
60
|
+
// Owned application environment variables, validated with PodoKit's.
|
|
61
|
+
"apps/api/src/config/env.extensions.ts",
|
|
62
|
+
// Owned TypeORM entities the migration data source loads.
|
|
63
|
+
"apps/api/src/database/entities.ts",
|
|
64
|
+
// Owned application operations that `bun run contract` requires.
|
|
65
|
+
"apps/api/src/core/api-contract.extensions.ts",
|
|
66
|
+
// Owned entry points the API build bundles next to PodoKit's.
|
|
67
|
+
"apps/api/scripts/build.extensions.mjs",
|
|
58
68
|
// Owned additions to the managed /api proxy's header lists, body limits, and
|
|
59
69
|
// response deadlines.
|
|
60
70
|
"apps/web/src/lib/server/proxy-headers.ts",
|
|
61
71
|
"apps/web/src/lib/server/body-limits.ts",
|
|
62
72
|
"apps/web/src/lib/server/proxy-timeouts.ts",
|
|
73
|
+
// Owned additions to the managed Vite and SvelteKit configuration.
|
|
74
|
+
"apps/web/vite.extensions.ts",
|
|
75
|
+
// Owned styles the managed app.css imports last.
|
|
76
|
+
"apps/web/src/app.extensions.css",
|
|
63
77
|
// Owned fallback page SvelteKit serves when the root layout or a hook fails.
|
|
64
78
|
"apps/web/src/error.html",
|
|
65
79
|
// AI agent guidance — yours to customize; update never touches it.
|
|
@@ -81,6 +95,27 @@ exports.DEFAULT_OWNED_GLOBS = [
|
|
|
81
95
|
".podokit/dev.json",
|
|
82
96
|
// Optional application-owned Playwright device/browser projects.
|
|
83
97
|
"tests/playwright.projects.cjs",
|
|
98
|
+
// Application screens the managed e2e specs visit.
|
|
99
|
+
"tests/helpers/app-paths.ts",
|
|
100
|
+
// Project documents, ignore rules, environment examples, and example
|
|
101
|
+
// manifests every application rewrites. PodoKit seeds them once, `podo add`
|
|
102
|
+
// still appends module environment lines and wiring, and `podo update`
|
|
103
|
+
// reports their template changes for review instead of merging them.
|
|
104
|
+
"README.md",
|
|
105
|
+
"tests/README.md",
|
|
106
|
+
".gitignore",
|
|
107
|
+
".env.example",
|
|
108
|
+
".env.docker.example",
|
|
109
|
+
"infra/k3s/**",
|
|
110
|
+
];
|
|
111
|
+
/**
|
|
112
|
+
* PodoKit's own agent skills stay managed inside the owned `.claude/**` and
|
|
113
|
+
* `.agents/**` trees, so updates keep their commands and APIs current. Skills an
|
|
114
|
+
* application adds under other names stay owned.
|
|
115
|
+
*/
|
|
116
|
+
exports.DEFAULT_MANAGED_OVERRIDES = [
|
|
117
|
+
".claude/skills/podokit-*/**",
|
|
118
|
+
".agents/skills/podokit-*/**",
|
|
84
119
|
];
|
|
85
120
|
const TEXT_EXT = /\.(json|md|ts|tsx|js|mjs|cjs|css|html|yml|yaml|txt|env|svelte|gitignore|example)$/i;
|
|
86
121
|
function podokitDir(projectRoot) {
|
|
@@ -209,6 +244,34 @@ function computeFilesLock(projectRoot, ownedGlobs, managedOverrides = []) {
|
|
|
209
244
|
}
|
|
210
245
|
return { schemaVersion: exports.LOCK_SCHEMA_VERSION, files };
|
|
211
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* The template content an earlier lock knew for a path: the recorded template
|
|
249
|
+
* hash of an owned file, or the generated baseline of a managed one.
|
|
250
|
+
*/
|
|
251
|
+
function recordedTemplateHash(entry) {
|
|
252
|
+
if (!entry)
|
|
253
|
+
return undefined;
|
|
254
|
+
return entry.tier === "owned" ? entry.templateHash : entry.outHash;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Carry the template hashes of an earlier lock into a recomputed one for files
|
|
258
|
+
* that are owned now. Paths in `changed` were just rewritten from a different
|
|
259
|
+
* template, such as the files a module added to or removed from, so their old
|
|
260
|
+
* hash would be wrong and is dropped.
|
|
261
|
+
*/
|
|
262
|
+
function keepTemplateHashes(next, previous, changed = []) {
|
|
263
|
+
if (!previous)
|
|
264
|
+
return next;
|
|
265
|
+
const skip = new Set(changed);
|
|
266
|
+
for (const [path, entry] of Object.entries(next.files)) {
|
|
267
|
+
if (entry.tier !== "owned" || entry.templateHash || skip.has(path))
|
|
268
|
+
continue;
|
|
269
|
+
const templateHash = recordedTemplateHash(previous.files[path]);
|
|
270
|
+
if (templateHash)
|
|
271
|
+
entry.templateHash = templateHash;
|
|
272
|
+
}
|
|
273
|
+
return next;
|
|
274
|
+
}
|
|
212
275
|
function readFilesLock(projectRoot) {
|
|
213
276
|
const file = filesLockPath(projectRoot);
|
|
214
277
|
if (!(0, node_fs_1.existsSync)(file))
|
|
@@ -246,6 +309,7 @@ function computeDrift(projectRoot) {
|
|
|
246
309
|
/** Write the initial `.podokit/` lockfile for a freshly created project. */
|
|
247
310
|
function initLockfile(projectRoot, options) {
|
|
248
311
|
const ownedGlobs = options.ownedGlobs ?? exports.DEFAULT_OWNED_GLOBS;
|
|
312
|
+
const managedOverrides = [...exports.DEFAULT_MANAGED_OVERRIDES];
|
|
249
313
|
const providers = (0, podokit_runtime_1.resolveProviderSelections)(options.providers ?? podokit_runtime_1.SERVER_PROVIDER_SELECTIONS);
|
|
250
314
|
const manifest = {
|
|
251
315
|
schemaVersion: exports.LOCK_SCHEMA_VERSION,
|
|
@@ -256,10 +320,16 @@ function initLockfile(projectRoot, options) {
|
|
|
256
320
|
providers,
|
|
257
321
|
modules: [],
|
|
258
322
|
ownedGlobs,
|
|
259
|
-
managedOverrides
|
|
323
|
+
managedOverrides,
|
|
260
324
|
};
|
|
261
325
|
writeManifest(projectRoot, manifest);
|
|
262
|
-
|
|
326
|
+
const lock = computeFilesLock(projectRoot, ownedGlobs, managedOverrides);
|
|
327
|
+
// Create wrote every file straight from the template.
|
|
328
|
+
for (const entry of Object.values(lock.files)) {
|
|
329
|
+
if (entry.tier === "owned")
|
|
330
|
+
entry.templateHash = entry.outHash;
|
|
331
|
+
}
|
|
332
|
+
writeFilesLock(projectRoot, lock);
|
|
263
333
|
}
|
|
264
334
|
/** Union two glob lists, preserving order and dropping duplicates. Used to fold
|
|
265
335
|
* module-declared and ejected owned paths into the project's `ownedGlobs`, which
|
|
@@ -359,5 +429,5 @@ insertBefore) {
|
|
|
359
429
|
continue;
|
|
360
430
|
files[path] = current;
|
|
361
431
|
}
|
|
362
|
-
writeFilesLock(projectRoot, { schemaVersion: exports.LOCK_SCHEMA_VERSION, files });
|
|
432
|
+
writeFilesLock(projectRoot, keepTemplateHashes({ schemaVersion: exports.LOCK_SCHEMA_VERSION, files }, lockSnapshot.previous, modulePaths));
|
|
363
433
|
}
|
package/dist/provider.js
CHANGED
|
@@ -29,16 +29,20 @@ function assertProvider(capability, provider) {
|
|
|
29
29
|
}
|
|
30
30
|
/** The managed provider source; it must render byte for byte like the template's copy. */
|
|
31
31
|
function providerSource(providers) {
|
|
32
|
-
return `import type { ProviderSelections } from "@podosoft/podokit-runtime";\n
|
|
33
|
-
|
|
32
|
+
return `import type { ProviderSelections } from "@podosoft/podokit-runtime";\n` +
|
|
33
|
+
`import { providersFromEnvironment } from "./provider-selection";\n\n` +
|
|
34
|
+
`// The providers selected when the project was generated or by \`podo provider\n` +
|
|
35
|
+
`// set\`. Typed with every provider name, not the selected ones: the module of a\n` +
|
|
34
36
|
`// provider that stays installed after a switch compares against its own name.\n` +
|
|
35
|
-
|
|
37
|
+
`// A <CAPABILITY>_PROVIDER variable replaces one at startup; see\n` +
|
|
38
|
+
`// provider-selection.ts.\n` +
|
|
39
|
+
`export const PROVIDERS: Readonly<ProviderSelections> = providersFromEnvironment({\n` +
|
|
36
40
|
` database: "${providers.database}",\n` +
|
|
37
41
|
` cache: "${providers.cache}",\n` +
|
|
38
42
|
` "object-storage": "${providers["object-storage"]}",\n` +
|
|
39
43
|
` events: "${providers.events}",\n` +
|
|
40
44
|
` jobs: "${providers.jobs}",\n` +
|
|
41
|
-
`};\n`;
|
|
45
|
+
`});\n`;
|
|
42
46
|
}
|
|
43
47
|
function listProviders(projectRoot) {
|
|
44
48
|
const manifest = requireManifest(projectRoot);
|
|
@@ -122,6 +126,7 @@ function applyProviderChange(projectRoot, capabilityInput, provider, options = {
|
|
|
122
126
|
[manifestFile, (0, node_fs_1.readFileSync)(manifestFile, "utf8")],
|
|
123
127
|
[lockFile, (0, node_fs_1.existsSync)(lockFile) ? (0, node_fs_1.readFileSync)(lockFile, "utf8") : null],
|
|
124
128
|
]);
|
|
129
|
+
const previousLock = (0, lockfile_1.readFilesLock)(projectRoot);
|
|
125
130
|
const temporary = `${sourcePath}.podokit-provider-${process.pid}`;
|
|
126
131
|
try {
|
|
127
132
|
manifest.providers[plan.capability] = plan.to;
|
|
@@ -129,7 +134,7 @@ function applyProviderChange(projectRoot, capabilityInput, provider, options = {
|
|
|
129
134
|
(0, node_fs_1.writeFileSync)(temporary, providerSource(manifest.providers), { mode: 0o600 });
|
|
130
135
|
(0, node_fs_1.renameSync)(temporary, sourcePath);
|
|
131
136
|
(0, lockfile_1.writeManifest)(projectRoot, manifest);
|
|
132
|
-
(0, lockfile_1.writeFilesLock)(projectRoot, (0, lockfile_1.computeFilesLock)(projectRoot, manifest.ownedGlobs, manifest.managedOverrides ?? []));
|
|
137
|
+
(0, lockfile_1.writeFilesLock)(projectRoot, (0, lockfile_1.keepTemplateHashes)((0, lockfile_1.computeFilesLock)(projectRoot, manifest.ownedGlobs, manifest.managedOverrides ?? []), previousLock));
|
|
133
138
|
}
|
|
134
139
|
catch (error) {
|
|
135
140
|
(0, node_fs_1.rmSync)(temporary, { force: true });
|
package/dist/remove.js
CHANGED
|
@@ -135,7 +135,7 @@ function removeModule(options) {
|
|
|
135
135
|
sharedOwnedGlobs.has(glob) ||
|
|
136
136
|
keptEdited.some((path) => (0, lockfile_1.matchGlob)(path, glob)));
|
|
137
137
|
(0, lockfile_1.writeManifest)(projectRoot, manifest);
|
|
138
|
-
(0, lockfile_1.writeFilesLock)(projectRoot, (0, lockfile_1.computeFilesLock)(projectRoot, manifest.ownedGlobs, manifest.managedOverrides));
|
|
138
|
+
(0, lockfile_1.writeFilesLock)(projectRoot, (0, lockfile_1.keepTemplateHashes)((0, lockfile_1.computeFilesLock)(projectRoot, manifest.ownedGlobs, manifest.managedOverrides), lock, [...unwired, ".env.example"]));
|
|
139
139
|
return { module, removed, keptEdited, keptShared, unwired, apiPaths };
|
|
140
140
|
}
|
|
141
141
|
/** Remove now-empty directories left behind by a deleted file, up to the root. */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type Tier } from "./lockfile";
|
|
2
|
+
/**
|
|
3
|
+
* `podo diff <path>` and `podo restore <path>`: compare a working file with
|
|
4
|
+
* what the installed CLI's templates generate for it, and put a managed or
|
|
5
|
+
* ejected file back to that content.
|
|
6
|
+
*/
|
|
7
|
+
export type TemplateFileStatus = "same" | "differs" | "missing" | "not-generated";
|
|
8
|
+
export interface TemplateFileDiff {
|
|
9
|
+
path: string;
|
|
10
|
+
/** Ownership tier the lock records, or null for a file the lock does not track. */
|
|
11
|
+
tier: Tier | null;
|
|
12
|
+
status: TemplateFileStatus;
|
|
13
|
+
/** Unified diff from the template to the working file; empty unless it differs. */
|
|
14
|
+
diff: string;
|
|
15
|
+
/** Whether either side is binary, so no line diff is shown. */
|
|
16
|
+
binary: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface TemplateDiffResult {
|
|
19
|
+
/** PodoKit version the project was generated or last updated with. */
|
|
20
|
+
projectVersion: string;
|
|
21
|
+
/** Version of the CLI whose templates were rendered. */
|
|
22
|
+
templateVersion: string;
|
|
23
|
+
files: TemplateFileDiff[];
|
|
24
|
+
}
|
|
25
|
+
/** Normalize a user-supplied path to the lock's POSIX project-relative form. */
|
|
26
|
+
export declare function projectPath(path: string): string;
|
|
27
|
+
export declare function templateDiff(projectRoot: string, templatesDir: string, paths: string[]): TemplateDiffResult;
|
|
28
|
+
export interface RestoreResult {
|
|
29
|
+
/** Files rewritten from the template. */
|
|
30
|
+
restored: string[];
|
|
31
|
+
/** Files that were ejected and are managed again. */
|
|
32
|
+
remanaged: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rewrite managed or assembled files with the template's content and record
|
|
36
|
+
* that content as the lock baseline. A file that `podo eject` made owned is
|
|
37
|
+
* handed back to PodoKit: its exact path leaves the manifest's owned paths, so
|
|
38
|
+
* future updates manage it again. Files owned because a template or module
|
|
39
|
+
* declares them owned, such as routes, are refused. Nothing is written unless
|
|
40
|
+
* every path can be restored.
|
|
41
|
+
*/
|
|
42
|
+
export declare function restore(projectRoot: string, templatesDir: string, paths: string[]): RestoreResult;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.projectPath = projectPath;
|
|
4
|
+
exports.templateDiff = templateDiff;
|
|
5
|
+
exports.restore = restore;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const podokit_template_engine_1 = require("@podosoft/podokit-template-engine");
|
|
9
|
+
const lockfile_1 = require("./lockfile");
|
|
10
|
+
const update_1 = require("./update");
|
|
11
|
+
const text_diff_1 = require("./text-diff");
|
|
12
|
+
/** Normalize a user-supplied path to the lock's POSIX project-relative form. */
|
|
13
|
+
function projectPath(path) {
|
|
14
|
+
const normalized = (0, node_path_1.normalize)(path).split(node_path_1.sep).join("/").replace(/^\.\//, "");
|
|
15
|
+
if (normalized.startsWith("../") || normalized === ".." || normalized.startsWith("/")) {
|
|
16
|
+
throw new Error(`${path} is outside the project.`);
|
|
17
|
+
}
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|
|
20
|
+
function isUtf8Text(content) {
|
|
21
|
+
return !content.includes(0) && Buffer.from(content.toString("utf8"), "utf8").equals(content);
|
|
22
|
+
}
|
|
23
|
+
function fileBuffer(file) {
|
|
24
|
+
return typeof file.content === "string" ? Buffer.from(file.content, "utf8") : file.content;
|
|
25
|
+
}
|
|
26
|
+
function templateDiff(projectRoot, templatesDir, paths) {
|
|
27
|
+
const target = (0, update_1.targetProject)(projectRoot, templatesDir);
|
|
28
|
+
const templateVersion = (0, lockfile_1.podokitVersion)();
|
|
29
|
+
const files = paths.map((input) => {
|
|
30
|
+
const path = projectPath(input);
|
|
31
|
+
const tier = target.lock.files[path]?.tier ?? null;
|
|
32
|
+
const generated = target.tree.get(path);
|
|
33
|
+
const abs = (0, node_path_1.join)(projectRoot, path);
|
|
34
|
+
if (!generated) {
|
|
35
|
+
return { path, tier, status: "not-generated", diff: "", binary: false };
|
|
36
|
+
}
|
|
37
|
+
if (!(0, node_fs_1.existsSync)(abs))
|
|
38
|
+
return { path, tier, status: "missing", diff: "", binary: false };
|
|
39
|
+
const templateBytes = fileBuffer(generated);
|
|
40
|
+
const diskBytes = (0, node_fs_1.readFileSync)(abs);
|
|
41
|
+
if (templateBytes.equals(diskBytes)) {
|
|
42
|
+
return { path, tier, status: "same", diff: "", binary: false };
|
|
43
|
+
}
|
|
44
|
+
const binary = !isUtf8Text(templateBytes) || !isUtf8Text(diskBytes);
|
|
45
|
+
return {
|
|
46
|
+
path,
|
|
47
|
+
tier,
|
|
48
|
+
status: "differs",
|
|
49
|
+
binary,
|
|
50
|
+
diff: binary
|
|
51
|
+
? ""
|
|
52
|
+
: (0, text_diff_1.unifiedDiff)(templateBytes.toString("utf8"), diskBytes.toString("utf8"), {
|
|
53
|
+
fromLabel: `podokit-${templateVersion}/${path}`,
|
|
54
|
+
toLabel: path,
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
return { projectVersion: target.manifest.podokitVersion, templateVersion, files };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Rewrite managed or assembled files with the template's content and record
|
|
62
|
+
* that content as the lock baseline. A file that `podo eject` made owned is
|
|
63
|
+
* handed back to PodoKit: its exact path leaves the manifest's owned paths, so
|
|
64
|
+
* future updates manage it again. Files owned because a template or module
|
|
65
|
+
* declares them owned, such as routes, are refused. Nothing is written unless
|
|
66
|
+
* every path can be restored.
|
|
67
|
+
*/
|
|
68
|
+
function restore(projectRoot, templatesDir, paths) {
|
|
69
|
+
const target = (0, update_1.targetProject)(projectRoot, templatesDir);
|
|
70
|
+
const cliVersion = (0, lockfile_1.podokitVersion)();
|
|
71
|
+
if (target.manifest.podokitVersion !== cliVersion) {
|
|
72
|
+
throw new Error(`This project is on PodoKit ${target.manifest.podokitVersion} and this CLI renders ${cliVersion}. ` +
|
|
73
|
+
"Run podo update --apply first, or restore with the CLI version the project is on.");
|
|
74
|
+
}
|
|
75
|
+
const declared = new Set((0, update_1.declaredOwnedGlobs)(projectRoot, templatesDir, target.modules));
|
|
76
|
+
const requested = [...new Set(paths.map(projectPath))];
|
|
77
|
+
const ejected = requested.filter((path) => target.manifest.ownedGlobs.includes(path) && !declared.has(path));
|
|
78
|
+
const ownedGlobs = target.manifest.ownedGlobs.filter((glob) => !ejected.includes(glob));
|
|
79
|
+
const classifyGlobs = [...new Set([...declared, ...ownedGlobs])];
|
|
80
|
+
const writes = [];
|
|
81
|
+
for (const path of requested) {
|
|
82
|
+
const file = target.tree.get(path);
|
|
83
|
+
if (!file)
|
|
84
|
+
throw new Error(`PodoKit does not generate ${path}, so there is nothing to restore.`);
|
|
85
|
+
const tier = (0, lockfile_1.classifyTier)(path, fileBuffer(file), classifyGlobs, target.managedOverrides);
|
|
86
|
+
if (tier === "owned") {
|
|
87
|
+
throw new Error(`${path} is owned by the application through the template or a module, so PodoKit never manages it. ` +
|
|
88
|
+
`Run podo diff ${path} to see the template's version.`);
|
|
89
|
+
}
|
|
90
|
+
writes.push({ path, file, tier });
|
|
91
|
+
}
|
|
92
|
+
for (const { path, file, tier } of writes) {
|
|
93
|
+
const abs = (0, node_path_1.join)(projectRoot, path);
|
|
94
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(abs), { recursive: true });
|
|
95
|
+
(0, node_fs_1.writeFileSync)(abs, file.content);
|
|
96
|
+
target.lock.files[path] = { tier, outHash: (0, podokit_template_engine_1.hashContent)(fileBuffer(file)) };
|
|
97
|
+
}
|
|
98
|
+
(0, lockfile_1.writeFilesLock)(projectRoot, target.lock);
|
|
99
|
+
if (ejected.length)
|
|
100
|
+
(0, lockfile_1.writeManifest)(projectRoot, { ...target.manifest, ownedGlobs });
|
|
101
|
+
return { restored: writes.map((write) => write.path), remanaged: ejected };
|
|
102
|
+
}
|