@podosoft/podokit 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/deploy-compose-exec.d.ts +93 -0
  2. package/dist/deploy-compose-exec.js +198 -0
  3. package/dist/deploy-compose-profile.d.ts +107 -0
  4. package/dist/deploy-compose-profile.js +361 -0
  5. package/dist/deploy-compose-render.d.ts +48 -0
  6. package/dist/deploy-compose-render.js +333 -0
  7. package/dist/deploy-compose-sync.d.ts +144 -0
  8. package/dist/deploy-compose-sync.js +412 -0
  9. package/dist/deploy-compose.d.ts +98 -0
  10. package/dist/deploy-compose.js +667 -0
  11. package/dist/deploy-dispatch.d.ts +33 -0
  12. package/dist/deploy-dispatch.js +58 -0
  13. package/dist/deploy-driver.d.ts +25 -0
  14. package/dist/deploy-driver.js +78 -0
  15. package/dist/deploy-profile.d.ts +4 -7
  16. package/dist/deploy-profile.js +86 -274
  17. package/dist/deploy-render.js +10 -1
  18. package/dist/deploy-schema.d.ts +56 -0
  19. package/dist/deploy-schema.js +261 -0
  20. package/dist/index.d.ts +7 -0
  21. package/dist/index.js +178 -6
  22. package/dist/lib.d.ts +9 -0
  23. package/dist/lib.js +30 -1
  24. package/dist/templates/fullstack-nest-svelte/AGENTS.md +2 -1
  25. package/dist/templates/fullstack-nest-svelte/Dockerfile.dev +34 -3
  26. package/dist/templates/fullstack-nest-svelte/apps/api/Dockerfile +68 -7
  27. package/dist/templates/fullstack-nest-svelte/apps/web/Dockerfile +60 -8
  28. package/dist/templates/fullstack-nest-svelte/apps/web/package.json +2 -1
  29. package/dist/templates/fullstack-nest-svelte/apps/web/server.js +31 -0
  30. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/api.ts +2 -2
  31. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.test.ts +79 -0
  32. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/backend-proxy.ts +24 -1
  33. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/ws-upgrade.js +267 -0
  34. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/server/ws-upgrade.test.js +134 -0
  35. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/[...path]/+server.ts +6 -2
  36. package/dist/templates/fullstack-nest-svelte/apps/web/src/routes/api/auth/[...all]/+server.ts +6 -2
  37. package/dist/templates/fullstack-nest-svelte/apps/web/vite.config.ts +17 -7
  38. package/dist/templates/fullstack-nest-svelte/dot-agents/skills/podokit-deploy/SKILL.md +55 -10
  39. package/dist/templates/fullstack-nest-svelte/dot-agents/skills/podokit-deploy/references/profile.md +50 -1
  40. package/dist/templates/fullstack-nest-svelte/dot-agents/skills/podokit-deploy/references/release.md +64 -0
  41. package/dist/templates/fullstack-nest-svelte/dot-agents/skills/podokit-deploy-fast/SKILL.md +92 -0
  42. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-deploy/SKILL.md +1 -1
  43. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-deploy-fast/SKILL.md +8 -0
  44. package/dist/templates/fullstack-nest-svelte/dot-dockerignore +7 -0
  45. package/dist/templates/fullstack-nest-svelte/dot-env.example +7 -0
  46. package/dist/templates/fullstack-nest-svelte/dot-github/workflows/release.yml +142 -0
  47. package/dist/templates/fullstack-nest-svelte/infra/k3s/README.md +18 -0
  48. package/dist/templates/fullstack-nest-svelte/infra/k3s/api-deployment.yaml +6 -1
  49. package/dist/templates/fullstack-nest-svelte/infra/k3s/ingress.yaml +8 -0
  50. package/dist/templates/fullstack-nest-svelte/infra/k3s/web-deployment.yaml +11 -1
  51. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-page.svelte +3 -2
  52. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/device-label.test.ts +62 -0
  53. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/device-label.ts +50 -0
  54. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/sessions/+page.svelte +3 -2
  55. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(admin)/admin/users/+page.svelte +3 -2
  56. package/dist/templates/modules/bullmq/files/infra/k3s/worker-deployment.yaml +2 -1
  57. package/dist/templates/todo/AGENTS.md +2 -1
  58. package/dist/templates/todo/Dockerfile.dev +34 -3
  59. package/dist/templates/todo/apps/api/Dockerfile +68 -7
  60. package/dist/templates/todo/apps/web/Dockerfile +60 -8
  61. package/dist/templates/todo/apps/web/package.json +2 -1
  62. package/dist/templates/todo/apps/web/server.js +31 -0
  63. package/dist/templates/todo/apps/web/src/lib/server/api.ts +2 -2
  64. package/dist/templates/todo/apps/web/src/lib/server/backend-proxy.test.ts +79 -0
  65. package/dist/templates/todo/apps/web/src/lib/server/backend-proxy.ts +24 -1
  66. package/dist/templates/todo/apps/web/src/lib/server/ws-upgrade.js +267 -0
  67. package/dist/templates/todo/apps/web/src/lib/server/ws-upgrade.test.js +134 -0
  68. package/dist/templates/todo/apps/web/src/routes/api/[...path]/+server.ts +6 -2
  69. package/dist/templates/todo/apps/web/src/routes/api/auth/[...all]/+server.ts +6 -2
  70. package/dist/templates/todo/apps/web/vite.config.ts +17 -7
  71. package/dist/templates/todo/dot-agents/skills/podokit-deploy/SKILL.md +55 -10
  72. package/dist/templates/todo/dot-agents/skills/podokit-deploy/references/profile.md +47 -0
  73. package/dist/templates/todo/dot-agents/skills/podokit-deploy/references/release.md +64 -0
  74. package/dist/templates/todo/dot-agents/skills/podokit-deploy-fast/SKILL.md +92 -0
  75. package/dist/templates/todo/dot-claude/skills/podokit-deploy/SKILL.md +1 -1
  76. package/dist/templates/todo/dot-claude/skills/podokit-deploy-fast/SKILL.md +8 -0
  77. package/dist/templates/todo/dot-dockerignore +7 -0
  78. package/dist/templates/todo/dot-env.example +7 -0
  79. package/dist/templates/todo/dot-github/workflows/release.yml +142 -0
  80. package/dist/templates/todo/infra/k3s/README.md +18 -0
  81. package/dist/templates/todo/infra/k3s/api-deployment.yaml +6 -1
  82. package/dist/templates/todo/infra/k3s/ingress.yaml +8 -0
  83. package/dist/templates/todo/infra/k3s/web-deployment.yaml +11 -1
  84. package/package.json +1 -1
@@ -0,0 +1,142 @@
1
+ # Build and publish the release images for a tag.
2
+ #
3
+ # `podo deploy` consumes images; it does not build them. This is the other half:
4
+ # tagging a commit produces the two images that `podo deploy apply` then rolls out.
5
+ # It stops at the push, because rolling out requires confirming a plan hash and that
6
+ # approval belongs to a person.
7
+ #
8
+ # ── Which runner, and what it costs ──────────────────────────────────────────────
9
+ #
10
+ # GitHub-hosted runners are free for PUBLIC repositories only. In a PRIVATE
11
+ # repository every minute is metered against the account's included Actions minutes
12
+ # and billed beyond them -- and image builds are the most expensive job most
13
+ # projects run. A self-hosted runner consumes no Actions minutes at all, whatever
14
+ # the repository's visibility.
15
+ #
16
+ # So the runner is a variable rather than a constant:
17
+ #
18
+ # PODOKIT_RUNNER repository or organization variable, a JSON array of labels.
19
+ # Unset -> ["ubuntu-latest"], which is right for a public
20
+ # repository and costs money in a private one.
21
+ # Self-hosted example: ["self-hosted","Linux","X64"]
22
+ #
23
+ # Set it before the first tag if this repository is private. Nothing here warns you
24
+ # when you have not: the workflow succeeds either way, and the difference shows up
25
+ # on a bill.
26
+ #
27
+ # ── The other two variables ──────────────────────────────────────────────────────
28
+ #
29
+ # PODOKIT_DEPLOY_PROFILE which .podokit/deploy/<name>.json names the image
30
+ # repositories. Unset -> production.
31
+ # PODOKIT_IMAGE_PLATFORM the architecture the deployment target runs.
32
+ # Unset -> linux/amd64. Building for the wrong one
33
+ # produces "exec format error" at rollout, after the
34
+ # migration has already run.
35
+ #
36
+ # ── Secrets ──────────────────────────────────────────────────────────────────────
37
+ #
38
+ # REGISTRY_USERNAME / REGISTRY_PASSWORD credentials for the registry named by
39
+ # the profile. A robot or deploy account is enough, but note that some registries
40
+ # refuse to let a robot CREATE a repository -- push the first tag of a new
41
+ # repository with an account that can, or create it in the registry first.
42
+
43
+ name: release
44
+
45
+ on:
46
+ push:
47
+ tags:
48
+ - "v*.*.*"
49
+
50
+ concurrency:
51
+ group: release-${{ github.ref }}
52
+ cancel-in-progress: false
53
+
54
+ jobs:
55
+ images:
56
+ # One job builds both images rather than a matrix of two. A self-hosted pool is
57
+ # usually small, and fanning out here takes runners away from every other
58
+ # repository that shares it for no wall-clock gain on a multi-core machine.
59
+ runs-on: ${{ fromJSON(vars.PODOKIT_RUNNER || '["ubuntu-latest"]') }}
60
+ steps:
61
+ - uses: actions/checkout@v5
62
+
63
+ - uses: actions/setup-node@v6
64
+ with:
65
+ node-version: 22
66
+ cache: npm
67
+
68
+ - run: npm ci --no-audit --no-fund
69
+
70
+ # Verify before publishing. An image built from a commit that never passed is
71
+ # indistinguishable from one that did, once it is in the registry.
72
+ - run: npm run lint
73
+ - run: npm test
74
+
75
+ - name: Read the release target from the deployment profile
76
+ id: profile
77
+ run: |
78
+ node --input-type=module -e '
79
+ import { readFileSync } from "node:fs";
80
+ const name = process.env.PROFILE || "production";
81
+ const path = `.podokit/deploy/${name}.json`;
82
+ let profile;
83
+ try {
84
+ profile = JSON.parse(readFileSync(path, "utf8"));
85
+ } catch {
86
+ throw new Error(`No deployment profile at ${path}. Run podo deploy init first.`);
87
+ }
88
+ const { apiRepository, webRepository } = profile.release ?? {};
89
+ if (!apiRepository || !webRepository) {
90
+ throw new Error(`${path} does not declare release.apiRepository and release.webRepository.`);
91
+ }
92
+ // Everything before the first slash is a registry host only when it
93
+ // looks like one; otherwise the reference is a Docker Hub short name.
94
+ const first = apiRepository.split("/")[0];
95
+ const registry = /[.:]/.test(first) ? first : "";
96
+ const out = [
97
+ `api=${apiRepository}`,
98
+ `web=${webRepository}`,
99
+ `registry=${registry}`,
100
+ `tag=${process.env.GITHUB_REF_NAME}`,
101
+ ].join("\n");
102
+ process.stdout.write(out + "\n");
103
+ ' >> "$GITHUB_OUTPUT"
104
+ env:
105
+ PROFILE: ${{ vars.PODOKIT_DEPLOY_PROFILE }}
106
+
107
+ - uses: docker/setup-buildx-action@v3
108
+
109
+ - uses: docker/login-action@v3
110
+ with:
111
+ registry: ${{ steps.profile.outputs.registry }}
112
+ username: ${{ secrets.REGISTRY_USERNAME }}
113
+ password: ${{ secrets.REGISTRY_PASSWORD }}
114
+
115
+ - name: Build and push the API image
116
+ uses: docker/build-push-action@v6
117
+ with:
118
+ context: .
119
+ file: apps/api/Dockerfile
120
+ platforms: ${{ vars.PODOKIT_IMAGE_PLATFORM || 'linux/amd64' }}
121
+ push: true
122
+ tags: ${{ steps.profile.outputs.api }}:${{ steps.profile.outputs.tag }}
123
+ cache-from: type=gha,scope=api
124
+ cache-to: type=gha,scope=api,mode=max
125
+
126
+ - name: Build and push the web image
127
+ uses: docker/build-push-action@v6
128
+ with:
129
+ context: .
130
+ file: apps/web/Dockerfile
131
+ platforms: ${{ vars.PODOKIT_IMAGE_PLATFORM || 'linux/amd64' }}
132
+ push: true
133
+ tags: ${{ steps.profile.outputs.web }}:${{ steps.profile.outputs.tag }}
134
+ cache-from: type=gha,scope=web
135
+ cache-to: type=gha,scope=web,mode=max
136
+
137
+ - name: Report what to deploy
138
+ run: |
139
+ echo "Pushed ${{ steps.profile.outputs.api }}:${{ steps.profile.outputs.tag }}" >> "$GITHUB_STEP_SUMMARY"
140
+ echo "Pushed ${{ steps.profile.outputs.web }}:${{ steps.profile.outputs.tag }}" >> "$GITHUB_STEP_SUMMARY"
141
+ echo "" >> "$GITHUB_STEP_SUMMARY"
142
+ echo 'Roll out with `podo deploy plan --profile <name> --release ${{ steps.profile.outputs.tag }}`, then apply the printed hash.' >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,18 @@
1
+ # Example k3s manifests
2
+
3
+ These are **illustrative**. `podo deploy` does not read or apply them.
4
+
5
+ For a real deployment, initialize a profile and let PodoKit render the manifests it
6
+ will actually apply — with image digests, probes, disruption budgets, a migration
7
+ Job, and a confirmation hash:
8
+
9
+ ```bash
10
+ podo deploy init --profile production --context production --host app.example.com
11
+ podo deploy render --profile production --release v1.2.3
12
+ ```
13
+
14
+ Keep these files if you want a starting point for hand-managed manifests, or delete
15
+ the directory if you deploy with `podo deploy`. If you do apply them by hand, replace
16
+ every `example.com` and `ghcr.io/example/...` placeholder first, and note that the
17
+ image tags below are placeholders too: the deployment tooling rejects `latest`,
18
+ branch tags, and empty tags, and so should you.
@@ -1,3 +1,4 @@
1
+ # Example only. See README.md in this directory; `podo deploy` renders its own.
1
2
  apiVersion: apps/v1
2
3
  kind: Deployment
3
4
  metadata:
@@ -13,7 +14,8 @@ spec:
13
14
  spec:
14
15
  containers:
15
16
  - name: api
16
- image: ghcr.io/example/podokit-api:latest
17
+ # Placeholder. Use one immutable, stable SemVer tag for api and web.
18
+ image: ghcr.io/example/podokit-api:v0.0.0
17
19
  ports:
18
20
  - containerPort: 3000
19
21
  envFrom:
@@ -22,3 +24,6 @@ spec:
22
24
  readinessProbe:
23
25
  httpGet: { path: /health/ready, port: 3000 }
24
26
  initialDelaySeconds: 5
27
+ livenessProbe:
28
+ httpGet: { path: /health, port: 3000 }
29
+ initialDelaySeconds: 15
@@ -1,3 +1,4 @@
1
+ # Example only. See README.md in this directory; `podo deploy` renders its own.
1
2
  apiVersion: traefik.io/v1alpha1
2
3
  kind: Middleware
3
4
  metadata:
@@ -14,6 +15,13 @@ metadata:
14
15
  annotations:
15
16
  traefik.ingress.kubernetes.io/router.middlewares: podokit-compression@kubernetescrd
16
17
  spec:
18
+ # Name the controller explicitly rather than relying on a default IngressClass.
19
+ ingressClassName: traefik
20
+ # app-config sets an https:// origin, so the route has to terminate TLS. Create the
21
+ # Secret out of band (cert-manager, or an existing certificate) and name it here.
22
+ tls:
23
+ - hosts: [example.com]
24
+ secretName: app-tls
17
25
  rules:
18
26
  - host: example.com
19
27
  http:
@@ -1,3 +1,4 @@
1
+ # Example only. See README.md in this directory; `podo deploy` renders its own.
1
2
  apiVersion: apps/v1
2
3
  kind: Deployment
3
4
  metadata:
@@ -13,8 +14,17 @@ spec:
13
14
  spec:
14
15
  containers:
15
16
  - name: web
16
- image: ghcr.io/example/podokit-web:latest
17
+ # Placeholder. Use one immutable, stable SemVer tag for api and web.
18
+ image: ghcr.io/example/podokit-web:v0.0.0
17
19
  ports:
18
20
  - containerPort: 3000
19
21
  envFrom:
20
22
  - configMapRef: { name: app-config }
23
+ # Without these a rolling update sends traffic to a process that has not
24
+ # bound its port yet.
25
+ readinessProbe:
26
+ httpGet: { path: /, port: 3000 }
27
+ initialDelaySeconds: 5
28
+ livenessProbe:
29
+ httpGet: { path: /, port: 3000 }
30
+ initialDelaySeconds: 15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podosoft/podokit",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "An opinionated but extensible starter toolkit and CLI for full-stack TypeScript apps with NestJS, SvelteKit, TailwindCSS, shadcn-svelte, Docker, and k3s.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {