@podosoft/podokit 0.11.2 → 0.12.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 (81) hide show
  1. package/README.md +7 -3
  2. package/dist/dev.d.ts +26 -0
  3. package/dist/dev.js +297 -0
  4. package/dist/index.d.ts +4 -0
  5. package/dist/index.js +82 -2
  6. package/dist/lib.d.ts +2 -0
  7. package/dist/lib.js +7 -1
  8. package/dist/locale.d.ts +22 -0
  9. package/dist/locale.js +184 -0
  10. package/dist/lockfile.js +4 -0
  11. package/dist/templates/fullstack-nest-svelte/README.md +42 -0
  12. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/README.md +7 -5
  13. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/catalogs/app/en.json +1 -0
  14. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/catalogs/app/ko.json +1 -0
  15. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/locales/en.json +6 -0
  16. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/locales/ko.json +6 -0
  17. package/dist/templates/fullstack-nest-svelte/apps/web/vite.config.ts +3 -9
  18. package/dist/templates/fullstack-nest-svelte/compose.dev.yaml +6 -11
  19. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-add-locale/SKILL.md +63 -0
  20. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-add-locale/agents/openai.yaml +4 -0
  21. package/dist/templates/fullstack-nest-svelte/dot-claude/skills/podokit-add-locale/references/catalog-format.md +49 -0
  22. package/dist/templates/fullstack-nest-svelte/dot-env.docker +2 -2
  23. package/dist/templates/fullstack-nest-svelte/dot-gitignore +3 -0
  24. package/dist/templates/fullstack-nest-svelte/dot-podokit/dev.json +4 -0
  25. package/dist/templates/fullstack-nest-svelte/tests/README.md +10 -4
  26. package/dist/templates/modules/admin-dashboard/files/apps/api/src/site-settings/site-settings.controller.ts +9 -0
  27. package/dist/templates/modules/admin-dashboard/files/apps/web/src/hooks.server.ts +5 -1
  28. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/auth-errors.ts +3 -0
  29. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/auth-redirect.ts +27 -0
  30. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/account-menu.svelte +8 -3
  31. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/components/sidebar-user-menu.svelte +1 -1
  32. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/en.json +564 -0
  33. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/catalogs/admin-dashboard/ko.json +564 -0
  34. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/index.ts +13 -12
  35. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/i18n/messages.ts +90 -722
  36. package/dist/templates/modules/admin-dashboard/files/apps/web/src/lib/site.svelte.ts +8 -1
  37. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/audit/+page.svelte +4 -4
  38. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/organizations/+page.svelte +2 -2
  39. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/sessions/+page.svelte +4 -4
  40. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/settings/+page.svelte +8 -2
  41. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/settings/general-settings.svelte +15 -4
  42. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(app)/admin/users/+page.svelte +4 -4
  43. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/login/+page.svelte +32 -35
  44. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/(auth)/signup/+page.svelte +10 -3
  45. package/dist/templates/modules/admin-dashboard/files/apps/web/src/routes/+layout.server.ts +11 -7
  46. package/dist/templates/modules/admin-dashboard/files/tests/api/auth-config.api.spec.ts +78 -0
  47. package/dist/templates/modules/admin-dashboard/files/tests/ui/auth.ui.spec.ts +28 -1
  48. package/dist/templates/modules/admin-dashboard/files/tests/ui/email.ui.spec.ts +1 -1
  49. package/dist/templates/modules/admin-dashboard/files/tests/ui/general-effects.ui.spec.ts +15 -0
  50. package/dist/templates/modules/admin-dashboard/files/tests/ui/i18n.ui.spec.ts +59 -6
  51. package/dist/templates/modules/admin-dashboard/files/tests/ui/login-methods.ui.spec.ts +1 -1
  52. package/dist/templates/modules/admin-dashboard/files/tests/ui/passkey.ui.spec.ts +1 -1
  53. package/dist/templates/modules/admin-dashboard/files/tests/ui/settings-dialogs.ui.spec.ts +5 -0
  54. package/dist/templates/modules/admin-dashboard/files/tests/ui/two-factor.ui.spec.ts +2 -2
  55. package/dist/templates/modules/admin-dashboard/module.manifest.json +4 -0
  56. package/dist/templates/modules/auth/files/apps/api/scripts/configure-auth.mjs +22 -11
  57. package/dist/templates/modules/auth/files/apps/api/src/auth/auth.ts +6 -2
  58. package/dist/templates/modules/auth/files/apps/api/src/auth/feature-gate.ts +50 -25
  59. package/dist/templates/modules/auth/files/dot-claude/skills/podokit-configure-auth/SKILL.md +1 -1
  60. package/dist/templates/modules/auth/files/dot-claude/skills/podokit-configure-auth/references/google.md +44 -0
  61. package/dist/templates/todo/README.md +42 -0
  62. package/dist/templates/todo/apps/web/src/lib/i18n/README.md +7 -5
  63. package/dist/templates/todo/apps/web/src/lib/i18n/catalogs/app/en.json +1 -0
  64. package/dist/templates/todo/apps/web/src/lib/i18n/catalogs/app/ko.json +1 -0
  65. package/dist/templates/todo/apps/web/src/lib/i18n/locales/en.json +6 -0
  66. package/dist/templates/todo/apps/web/src/lib/i18n/locales/ko.json +6 -0
  67. package/dist/templates/todo/apps/web/vite.config.ts +3 -9
  68. package/dist/templates/todo/compose.dev.yaml +6 -11
  69. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/SKILL.md +63 -0
  70. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/agents/openai.yaml +4 -0
  71. package/dist/templates/todo/dot-claude/skills/podokit-add-locale/references/catalog-format.md +49 -0
  72. package/dist/templates/todo/dot-env.docker +2 -2
  73. package/dist/templates/todo/dot-gitignore +3 -0
  74. package/dist/templates/todo/dot-podokit/dev.json +4 -0
  75. package/dist/templates/todo/tests/README.md +10 -4
  76. package/dist/update.js +23 -5
  77. package/package.json +1 -1
  78. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/en.ts +0 -10
  79. package/dist/templates/fullstack-nest-svelte/apps/web/src/lib/i18n/ko.ts +0 -11
  80. package/dist/templates/todo/apps/web/src/lib/i18n/en.ts +0 -10
  81. package/dist/templates/todo/apps/web/src/lib/i18n/ko.ts +0 -11
@@ -0,0 +1,49 @@
1
+ # JSON Catalog Format
2
+
3
+ ## Directory Layout
4
+
5
+ ```text
6
+ apps/web/src/lib/i18n/
7
+ ├── locales/
8
+ │ ├── en.json
9
+ │ ├── ko.json
10
+ │ └── pt-BR.json
11
+ └── catalogs/
12
+ ├── admin-dashboard/ # PodoKit-managed module messages
13
+ ├── blog/ # module-managed messages when installed
14
+ └── app/ # app-owned product messages and overrides
15
+ ```
16
+
17
+ Each locale definition has this shape:
18
+
19
+ ```json
20
+ {
21
+ "code": "pt-BR",
22
+ "name": "Português (Brasil)",
23
+ "direction": "ltr",
24
+ "enabled": false
25
+ }
26
+ ```
27
+
28
+ `code` must be a canonical BCP 47 tag and must match the filename. `direction` is `ltr` or `rtl`. Newly added locales stay inactive until explicitly activated.
29
+
30
+ ## Catalog Composition
31
+
32
+ Catalogs are nested JSON objects with strings at their leaves:
33
+
34
+ ```json
35
+ {
36
+ "common": {
37
+ "save": "Save",
38
+ "welcome": "Welcome, {name}"
39
+ }
40
+ }
41
+ ```
42
+
43
+ The runtime lazily loads every `catalogs/*/<locale>.json` file. Module catalogs are merged first in stable name order; the `app` catalog is merged last, so the consuming app may intentionally override module copy without modifying managed files.
44
+
45
+ English defines the complete key and value-type contract. Other locales may omit keys, but translated values must retain the English type and all `{placeholder}` names. JSON objects and arrays are supported; executable expressions are not.
46
+
47
+ ## Development Reloading
48
+
49
+ Catalog imports use Vite's `import.meta.glob`. Changes to an existing JSON dependency participate in Vite HMR and must appear without restarting the development container. A new file changes the glob membership and may cause Vite to reload the page automatically. If neither occurs, confirm that the app source directory, including `apps/web/src`, is mounted or synced by the development compose configuration.
@@ -6,11 +6,11 @@ POSTGRES_USER=podokit
6
6
  POSTGRES_PASSWORD=podokit
7
7
  POSTGRES_DB=podokit
8
8
  BACKEND_INTERNAL_URL=http://api:5002
9
- CORS_ORIGIN=http://app.localhost
9
+ CORS_ORIGIN=http://{{projectName}}.localhost,http://localhost
10
10
  REDIS_HOST=redis
11
11
  REDIS_PORT=6379
12
12
  BETTER_AUTH_SECRET=change-me-in-container-min-32-characters
13
- BETTER_AUTH_URL=http://app.localhost
13
+ BETTER_AUTH_URL=http://{{projectName}}.localhost
14
14
  ADMIN_EMAILS=admin@example.com
15
15
  AUDIT_LOG_ENABLED=true
16
16
  RATE_LIMIT_TTL=60
@@ -18,3 +18,6 @@ test-results/
18
18
 
19
19
  # local performance reports
20
20
  output/lighthouse/
21
+
22
+ # podo dev generated compose overlay
23
+ .podokit/runtime/
@@ -0,0 +1,4 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "hostname": "{{projectName}}.localhost"
4
+ }
@@ -9,7 +9,13 @@ npm run test:e2e:ui # pages (chromium)
9
9
  npm run test:e2e:report # open the HTML report
10
10
  ```
11
11
 
12
- The suite runs against a live stack (web on `E2E_BASE_URL`, default
13
- `http://localhost:5001`, proxying `/api/*` to the API). Start PostgreSQL, run the
14
- auth migration, and start the API + web first. Files ending in `*.api.spec.ts` run
15
- in the request-only `api` project; `*.ui.spec.ts` run in the chromium `ui` project.
12
+ The suite runs against a live stack (web on `E2E_BASE_URL`, proxying `/api/*` to
13
+ the API). With the recommended containerized loop, start `podo dev watch` and run:
14
+
15
+ ```bash
16
+ E2E_BASE_URL=http://{{projectName}}.localhost npm run test:e2e
17
+ ```
18
+
19
+ The default `http://localhost:5001` is for the alternative `npm run dev`
20
+ host-process loop. Files ending in `*.api.spec.ts` run in the request-only `api`
21
+ project; `*.ui.spec.ts` run in the chromium `ui` project.
package/dist/update.js CHANGED
@@ -32,6 +32,18 @@ function targetManagedOverrides(projectRoot, templatesDir, modules, current = []
32
32
  }
33
33
  return [...overrides];
34
34
  }
35
+ function targetOwnedGlobs(projectRoot, templatesDir, modules, current) {
36
+ const owned = new Set([...lockfile_1.DEFAULT_OWNED_GLOBS, ...current]);
37
+ const modulesDir = (0, node_path_1.join)(templatesDir, "modules");
38
+ for (const module of modules) {
39
+ const resolved = (0, add_1.resolveModule)(module.packageName ?? module.name, modulesDir, projectRoot);
40
+ if (!resolved)
41
+ continue;
42
+ for (const glob of (0, add_1.readModuleManifest)(resolved.dir).ownedGlobs ?? [])
43
+ owned.add(glob);
44
+ }
45
+ return [...owned];
46
+ }
35
47
  /**
36
48
  * Build the update plan. `templatesDir` is the installed CLI's template set (the
37
49
  * new version); the lock records what PodoKit last wrote (to detect user edits).
@@ -49,6 +61,7 @@ function planUpdate(projectRoot, templatesDir) {
49
61
  projectRoot,
50
62
  });
51
63
  const managedOverrides = targetManagedOverrides(projectRoot, templatesDir, manifest.modules, manifest.managedOverrides);
64
+ const ownedGlobs = targetOwnedGlobs(projectRoot, templatesDir, manifest.modules, manifest.ownedGlobs);
52
65
  const changes = [];
53
66
  const paths = new Set([...newTree.keys(), ...Object.keys(lock.files)]);
54
67
  for (const path of [...paths].sort()) {
@@ -58,12 +71,15 @@ function planUpdate(projectRoot, templatesDir) {
58
71
  // A newer module can explicitly take responsibility for a path that older
59
72
  // projects classified under a broad owned glob (notably generated skills).
60
73
  const managedByTarget = managedOverrides.some((glob) => (0, lockfile_1.matchGlob)(path, glob));
74
+ const ownedByTarget = ownedGlobs.some((glob) => (0, lockfile_1.matchGlob)(path, glob));
61
75
  const tier = managedByTarget
62
76
  ? "managed"
63
- : locked?.tier ??
64
- (newText !== null
65
- ? (0, lockfile_1.classifyTier)(path, newText, manifest.ownedGlobs, managedOverrides)
66
- : "managed");
77
+ : ownedByTarget
78
+ ? "owned"
79
+ : locked?.tier ??
80
+ (newText !== null
81
+ ? (0, lockfile_1.classifyTier)(path, newText, ownedGlobs, managedOverrides)
82
+ : "managed");
67
83
  if (tier === "owned") {
68
84
  changes.push({ path, tier, action: "skip", note: "owned — never modified" });
69
85
  continue;
@@ -171,6 +187,7 @@ function applyUpdate(projectRoot, templatesDir, options = {}) {
171
187
  projectRoot,
172
188
  });
173
189
  const managedOverrides = targetManagedOverrides(projectRoot, templatesDir, modules, manifest.managedOverrides);
190
+ const ownedGlobs = targetOwnedGlobs(projectRoot, templatesDir, modules, manifest.ownedGlobs);
174
191
  const oldTree = options.oldTemplatesDir
175
192
  ? (0, assemble_1.assembleProject)({
176
193
  templatesDir: options.oldTemplatesDir,
@@ -210,7 +227,7 @@ function applyUpdate(projectRoot, templatesDir, options = {}) {
210
227
  // Keep the assembled target as the managed baseline. A merged working file
211
228
  // intentionally remains drifted so a future update performs another 3-way
212
229
  // merge instead of treating the user's lines as clean generated output.
213
- (0, lockfile_1.writeFilesLock)(projectRoot, updatedFilesLock(projectRoot, newTree, previousLock, manifest.ownedGlobs, managedOverrides));
230
+ (0, lockfile_1.writeFilesLock)(projectRoot, updatedFilesLock(projectRoot, newTree, previousLock, ownedGlobs, managedOverrides));
214
231
  const modulesDir = (0, node_path_1.join)(templatesDir, "modules");
215
232
  const refreshedModules = manifest.modules.map((module) => {
216
233
  const resolved = (0, add_1.resolveModule)(module.packageName ?? module.name, modulesDir, projectRoot);
@@ -224,6 +241,7 @@ function applyUpdate(projectRoot, templatesDir, options = {}) {
224
241
  });
225
242
  (0, lockfile_1.writeManifest)(projectRoot, {
226
243
  ...manifest,
244
+ ownedGlobs,
227
245
  managedOverrides,
228
246
  modules: refreshedModules,
229
247
  podokitVersion: (0, lockfile_1.podokitVersion)(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@podosoft/podokit",
3
- "version": "0.11.2",
3
+ "version": "0.12.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": {
@@ -1,10 +0,0 @@
1
- import type { BaseTranslation } from "typesafe-i18n";
2
-
3
- // Base locale. Run `npx typesafe-i18n` to generate the typed runtime,
4
- // then access strings as `$LL.appTitle()` in components.
5
- const en = {
6
- appTitle: "{{projectName}}",
7
- checkHealth: "Check API health",
8
- } satisfies BaseTranslation;
9
-
10
- export default en;
@@ -1,11 +0,0 @@
1
- import type { BaseTranslation } from "typesafe-i18n";
2
-
3
- // Uses BaseTranslation until you generate typed runtimes with `npx typesafe-i18n`.
4
- // After generating, switch to `import type { Translation } from "../i18n-types"`
5
- // so this locale is checked against the base locale's keys.
6
- const ko = {
7
- appTitle: "{{projectName}}",
8
- checkHealth: "API 상태 확인",
9
- } satisfies BaseTranslation;
10
-
11
- export default ko;
@@ -1,10 +0,0 @@
1
- import type { BaseTranslation } from "typesafe-i18n";
2
-
3
- // Base locale. Run `npx typesafe-i18n` to generate the typed runtime,
4
- // then access strings as `$LL.appTitle()` in components.
5
- const en = {
6
- appTitle: "{{projectName}}",
7
- checkHealth: "Check API health",
8
- } satisfies BaseTranslation;
9
-
10
- export default en;
@@ -1,11 +0,0 @@
1
- import type { BaseTranslation } from "typesafe-i18n";
2
-
3
- // Uses BaseTranslation until you generate typed runtimes with `npx typesafe-i18n`.
4
- // After generating, switch to `import type { Translation } from "../i18n-types"`
5
- // so this locale is checked against the base locale's keys.
6
- const ko = {
7
- appTitle: "{{projectName}}",
8
- checkHealth: "API 상태 확인",
9
- } satisfies BaseTranslation;
10
-
11
- export default ko;