@podosoft/podokit 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +56 -2
- package/dist/deploy-schema.js +130 -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 +28 -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 +5 -1
- 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 +118 -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 +29 -0
- package/dist/templates/fullstack/apps/api/src/core/api-contract.ts +39 -2
- 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 +12 -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 +40 -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/package.json +2 -2
- package/dist/templates/fullstack/tests/playwright.config.ts +7 -3
- package/dist/templates/fullstack/tests/playwright.extensions.ts +88 -1
- 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 +39 -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/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/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 +11 -5
- 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 +29 -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 +57 -1
- package/dist/templates/modules/bullmq/files/apps/api/src/jobs/bullmq-job.queue.ts +93 -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 +87 -1
- package/dist/templates/modules/jobs-local/files/apps/api/src/jobs-local/local-job.queue.ts +93 -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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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/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
|
+
}
|
|
@@ -54,7 +54,20 @@ Merge added module settings from `.env.example` into an existing `.env`.
|
|
|
54
54
|
`apps/web/src/lib/server/proxy-timeouts.ts` (`APP_PROXY_TIMEOUTS`, `null` for
|
|
55
55
|
none); never edit the managed deadline. Both lists take path prefixes with
|
|
56
56
|
`:name` parameters, such as `/api/hosts/:hostId/file-transfers`, and the most
|
|
57
|
-
specific prefix wins.
|
|
57
|
+
specific prefix wins. The proxy and `serverApiClient` send the request's public
|
|
58
|
+
origin to the API in `x-forwarded-host`/`x-forwarded-proto` only when
|
|
59
|
+
`CORS_ORIGIN` lists it; an API route may use them to choose among its configured
|
|
60
|
+
origins, never as a new origin.
|
|
61
|
+
- `apps/web/src/app.css` is managed. Put application styles (theme variable
|
|
62
|
+
overrides, `@theme` entries, fonts, base styles, and `@source` for packages
|
|
63
|
+
whose built components use Tailwind classes) in the app-owned
|
|
64
|
+
`apps/web/src/app.extensions.css`, which `app.css` imports last.
|
|
65
|
+
- `apps/web/vite.config.ts` is managed. Put Vite options (warmup, `optimizeDeps`,
|
|
66
|
+
`define`, plugins, allowed hosts) in `appViteConfig` and SvelteKit options
|
|
67
|
+
(`alias`, `csrf`) in `appSvelteKitConfig` of the app-owned
|
|
68
|
+
`apps/web/vite.extensions.ts`. `bun run dev` proxies the exact
|
|
69
|
+
`webSocketPaths` of `.podokit/dev.json` to the API like the `podo dev` gateway,
|
|
70
|
+
so do not add a WebSocket proxy of your own.
|
|
58
71
|
- Server-side API calls (`serverApiClient`) give up after `BACKEND_TIMEOUT_MS`
|
|
59
72
|
(2000), and the proxy answers 504 `BACKEND_TIMEOUT` when the API sends no
|
|
60
73
|
response headers within `BACKEND_PROXY_TIMEOUT_MS` (30000). Once the API's
|
|
@@ -86,7 +99,17 @@ Merge added module settings from `.env.example` into an existing `.env`.
|
|
|
86
99
|
Better Auth schema before the application migrations. `{{apiRun}} migration:run` runs
|
|
87
100
|
only the application migrations and never creates Better Auth tables;
|
|
88
101
|
`{{apiRun}} migration:revert` reverts the latest application migration.
|
|
89
|
-
-
|
|
102
|
+
- Name a migration `apps/api/src/migrations/<timestamp>-<Name>.ts` with exactly one exported
|
|
103
|
+
migration class. The build lists compiled migrations in `dist/migrations/migrations.json` and
|
|
104
|
+
fails when one is lost; `{{apiRun}} migrate:list` prints what a build would run.
|
|
105
|
+
- e2e (Playwright, ships in `tests/`): `{{rootRun}} test:e2e`. Run the whole suite on more
|
|
106
|
+
workers with `E2E_WORKERS=2`, never `--workers`. Tag a test `{ tag: "@exclusive" }` when
|
|
107
|
+
it changes state other tests rely on (a server-wide setting, a seeded account's profile);
|
|
108
|
+
tagged tests run alone after the rest. Give each test its own mail and SMS recipients and
|
|
109
|
+
never empty the shared Mailpit inbox or SMS sink. See `tests/README.md`. The managed specs
|
|
110
|
+
read the app's first screen, public pages, and seeded accounts from the owned
|
|
111
|
+
`tests/helpers/app-paths.ts` (and `app-accounts.ts` with admin-dashboard): change those
|
|
112
|
+
instead of editing or ejecting a managed spec, and test the app's own screens in specs of its own.
|
|
90
113
|
- Playwright officially runs on Node, so `bunx playwright` respects its Node
|
|
91
114
|
shebang. Node LTS is a test-tool dependency only; API, web, worker, migrations,
|
|
92
115
|
builds, and unit tests run on Bun.
|
|
@@ -121,7 +144,7 @@ changes need an e2e/unit test.
|
|
|
121
144
|
This project is managed by the `podo` CLI. Files have an ownership tier recorded
|
|
122
145
|
in `.podokit/files.lock` — respect it:
|
|
123
146
|
|
|
124
|
-
- **owned** (your code: `apps/web/src/routes/**`, your components/services, `apps/api/src/app.extensions.ts`, and this `AGENTS.md`) — edit freely. Add application-owned services or module descriptors through `app.extensions.ts` instead of changing toolkit registrations. Set Bun server options (`maxRequestBodySize`, `idleTimeout`) with its `apiServerOptions` export rather than editing `main.ts`; `API_MAX_REQUEST_BODY_SIZE` and `API_IDLE_TIMEOUT` apply when the export leaves them out.
|
|
147
|
+
- **owned** (your code: `apps/web/src/routes/**`, your components/services, `apps/api/src/app.extensions.ts`, and this `AGENTS.md`) — edit freely. Add application-owned services or module descriptors through `app.extensions.ts` instead of changing toolkit registrations. Set Bun server options (`maxRequestBodySize`, `idleTimeout`) with its `apiServerOptions` export rather than editing `main.ts`; `API_MAX_REQUEST_BODY_SIZE` and `API_IDLE_TIMEOUT` apply when the export leaves them out. Declare application environment variables in the owned `apps/api/src/config/env.extensions.ts` (`appEnvShape`, `refineAppEnv`) instead of editing `env.validation.ts`, and TypeORM entities in `APP_ENTITIES` of the owned `apps/api/src/database/entities.ts` instead of editing `data-source.ts`. List the operations your API must keep in `APP_DOCUMENTED_ROUTES` of the owned `apps/api/src/core/api-contract.extensions.ts`; `{{apiRun}} contract` checks they are registered and documented. With `auth`, declare app on/off settings in `APP_FLAG_DEFAULTS` of the owned `apps/api/src/settings/app-flags.ts` instead of editing `flag-defaults.ts`.
|
|
125
148
|
- **assembled** (e.g. `apps/api/src/app.ts`, `auth.ts`) — contain `// podokit:begin:… / …:end` fenced regions that the toolkit recomputes. Edit outside the fences only; **never hand-edit inside the fences**.
|
|
126
149
|
- **managed** (bootstrap/config like `main.ts`) — the toolkit may update these; avoid gratuitous edits.
|
|
127
150
|
|
|
@@ -140,7 +163,8 @@ Useful commands:
|
|
|
140
163
|
- `podo add <module>` — add a feature (auth, admin-dashboard, redis, bullmq, …). It wires itself into the app; run `podo add` with no argument to list modules.
|
|
141
164
|
- `podo remove <module>` — un-apply a module (inverse of add; refuses if another module needs it, keeps files you edited).
|
|
142
165
|
- `podo provider list` / `podo provider set <capability> <provider> [--apply]` — inspect or switch database, cache, object storage, events, and jobs. Set is dry-run by default and never migrates or deletes provider data. Local providers require one API process.
|
|
143
|
-
- `podo status` / `podo diff` — see your local edits vs. what PodoKit generated.
|
|
166
|
+
- `podo status` / `podo diff` — see your local edits vs. what PodoKit generated; `podo diff <path>` shows a file's line diff against the template, owned files included.
|
|
167
|
+
- `podo restore <path>` — rewrite a managed file from the template, or hand an ejected file back to PodoKit.
|
|
144
168
|
- `podo update` — pull in template/module improvements (3-way merges your edits; never touches owned files).
|
|
145
169
|
- `podo deploy` — plan, apply, verify, or roll back an immutable release on Kubernetes or one Docker host. Production API WebSocket paths belong in the deployment profile's exact `exposure.webSocketPaths` allowlist, and API routes that take bodies above the web server's `BODY_SIZE_LIMIT` (file uploads) in `exposure.apiPaths` (and `.podokit/dev.json` `apiPaths` for `podo dev`; `podo add` and `podo deploy init` fill in the paths modules declare), which reach the API without the web proxy, so the API must check their size, session, and `Origin` itself; Compose trusts forwarding headers only from `exposure.trustedProxyCidrs`. Tag `vX.Y.Z` to build and push the images (`.github/workflows/release.yml`; check its runner — GitHub-hosted minutes are free for public repositories only). Use `.agents/skills/podokit-deploy`.
|
|
146
170
|
- `podo deploy sync` — copy local build output into a running Compose deployment and restart it, for iterating without a release. Not a release: no image is published and the next `apply` discards it. Use `.agents/skills/podokit-deploy-fast`.
|
|
@@ -55,8 +55,9 @@ cp .env.example .env
|
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
Open the URL printed by the command; a new project defaults to
|
|
58
|
-
**http://{{
|
|
59
|
-
source of truth if you change the hostname
|
|
58
|
+
**http://{{devHostname}}**. The committed `.podokit/dev.json` is the
|
|
59
|
+
source of truth if you change the hostname: `podo dev` sets `CORS_ORIGIN` and
|
|
60
|
+
`BETTER_AUTH_URL` for the web and API containers from it. The first running PodoKit project starts
|
|
60
61
|
one user-level Traefik gateway on `127.0.0.1:80`; additional projects reuse it and
|
|
61
62
|
route by that hostname. Even a single app uses
|
|
62
63
|
the same topology, with one route and no project-specific host port.
|
|
@@ -188,11 +189,11 @@ HTTP, fix its public origin at build time instead:
|
|
|
188
189
|
docker build --build-arg PODOKIT_BUILD_ORIGIN=https://example.com -f apps/web/Dockerfile -t {{projectName}}-web .
|
|
189
190
|
```
|
|
190
191
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
`exposure.trustedProxyCidrs`. Never
|
|
195
|
-
|
|
192
|
+
Set `exposure.edgeProxies` in the deployment profile to the number of reverse
|
|
193
|
+
proxies in front of the deployment; PodoKit derives which forwarded headers web and
|
|
194
|
+
API trust from it, and trusts none when it is `0`. With a Compose gateway, also list
|
|
195
|
+
the proxy's direct CIDR blocks in `exposure.trustedProxyCidrs`. Never count a proxy
|
|
196
|
+
that clients can bypass.
|
|
196
197
|
|
|
197
198
|
If the production API exposes WebSocket endpoints, list their exact paths under
|
|
198
199
|
`exposure.webSocketPaths` in the deployment profile. The Compose driver then keeps a
|
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
"test": "bun test src",
|
|
11
11
|
"contract": "bun scripts/verify-api-contract.ts",
|
|
12
12
|
"migrate:all": "bun scripts/run-migrations.mjs",
|
|
13
|
-
"
|
|
13
|
+
"migrate:list": "bun scripts/run-migrations.mjs --list",
|
|
14
|
+
"typeorm": "bunx --bun typeorm -d src/database/data-source.ts",
|
|
14
15
|
"migration:run": "bun src/database/migrate.ts",
|
|
15
16
|
"migration:revert": "bun src/database/migrate.ts --revert",
|
|
16
17
|
"migration:generate": "bun run typeorm -- migration:generate"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@podosoft/podokit-contracts": "^0.
|
|
20
|
-
"@podosoft/podokit-runtime": "^0.
|
|
20
|
+
"@podosoft/podokit-contracts": "^0.6.0",
|
|
21
|
+
"@podosoft/podokit-runtime": "^0.5.0",
|
|
21
22
|
"@elysia/cors": "^1.4.2",
|
|
22
23
|
"@elysia/openapi": "^1.4.15",
|
|
23
24
|
"dotenv": "^16.4.5",
|
|
@@ -30,7 +31,6 @@
|
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/bun": "^1.3.9",
|
|
32
33
|
"@types/node": "^20.17.0",
|
|
33
|
-
"ts-node": "^10.9.2",
|
|
34
34
|
"typescript": "^6.0.3"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// This owned file is never overwritten by `podo update`. List entry points the
|
|
2
|
+
// API build bundles next to PodoKit's, such as a maintenance command run from
|
|
3
|
+
// the image. Each must exist. For example:
|
|
4
|
+
//
|
|
5
|
+
// export const appBuildTargets = [{ entrypoint: "scripts/repair-data.ts", outdir: "dist/scripts" }];
|
|
6
|
+
export const appBuildTargets = [];
|