@warlock.js/core 5.35.0 → 5.37.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 (133) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/esm/cli/commands/migrate.command.mjs +10 -0
  3. package/esm/cli/commands/migrate.command.mjs.map +1 -1
  4. package/esm/cli/commands/release/release-command.action.mjs +245 -0
  5. package/esm/cli/commands/release/release-command.action.mjs.map +1 -0
  6. package/esm/cli/commands/release.command.mjs +66 -0
  7. package/esm/cli/commands/release.command.mjs.map +1 -0
  8. package/esm/cli/framework-cli-commands.mjs +2 -0
  9. package/esm/cli/framework-cli-commands.mjs.map +1 -1
  10. package/esm/database/migrate-action.mjs +24 -2
  11. package/esm/database/migrate-action.mjs.map +1 -1
  12. package/esm/dev-server/loader/load-hook.d.mts.map +1 -1
  13. package/esm/dev-server/loader/load-hook.mjs +6 -0
  14. package/esm/dev-server/loader/load-hook.mjs.map +1 -1
  15. package/esm/dev-server/module-loader.mjs +1 -1
  16. package/esm/dev-server/parse-imports.mjs +1 -1
  17. package/esm/dev-server/type-generator.mjs +1 -1
  18. package/esm/e2e/cdp.d.mts.map +1 -1
  19. package/esm/e2e/cdp.mjs +9 -2
  20. package/esm/e2e/cdp.mjs.map +1 -1
  21. package/esm/e2e/page.d.mts +9 -1
  22. package/esm/e2e/page.d.mts.map +1 -1
  23. package/esm/e2e/page.mjs +45 -7
  24. package/esm/e2e/page.mjs.map +1 -1
  25. package/esm/e2e/types.d.mts +18 -0
  26. package/esm/e2e/types.d.mts.map +1 -1
  27. package/esm/e2e/types.mjs.map +1 -1
  28. package/esm/errors/error-codes.d.mts +24 -0
  29. package/esm/errors/error-codes.d.mts.map +1 -1
  30. package/esm/errors/error-codes.mjs +24 -0
  31. package/esm/errors/error-codes.mjs.map +1 -1
  32. package/esm/generations/features/test.feature.mjs +7 -7
  33. package/esm/generations/features/test.feature.mjs.map +1 -1
  34. package/esm/generations/features/web.feature.mjs +3 -3
  35. package/esm/generations/features/web.feature.mjs.map +1 -1
  36. package/esm/index.d.mts +6 -3
  37. package/esm/index.mjs +4 -2
  38. package/esm/localization/index.mjs +3 -1
  39. package/esm/localization/translation-usage-graph.d.mts +49 -0
  40. package/esm/localization/translation-usage-graph.d.mts.map +1 -0
  41. package/esm/localization/translation-usage-graph.mjs +128 -0
  42. package/esm/localization/translation-usage-graph.mjs.map +1 -0
  43. package/esm/localization/translation-usage.d.mts +85 -0
  44. package/esm/localization/translation-usage.d.mts.map +1 -0
  45. package/esm/localization/translation-usage.mjs +307 -0
  46. package/esm/localization/translation-usage.mjs.map +1 -0
  47. package/esm/production/build-budgets.d.mts +18 -0
  48. package/esm/production/build-budgets.d.mts.map +1 -1
  49. package/esm/production/build-budgets.mjs.map +1 -1
  50. package/esm/production/route-registration-snapshot.mjs +12 -3
  51. package/esm/production/route-registration-snapshot.mjs.map +1 -1
  52. package/esm/release/activate.mjs +261 -0
  53. package/esm/release/activate.mjs.map +1 -0
  54. package/esm/release/candidate.mjs +107 -0
  55. package/esm/release/candidate.mjs.map +1 -0
  56. package/esm/release/cascade-migration-provider.mjs +32 -0
  57. package/esm/release/cascade-migration-provider.mjs.map +1 -0
  58. package/esm/release/config.mjs +60 -0
  59. package/esm/release/config.mjs.map +1 -0
  60. package/esm/release/gate.mjs +67 -0
  61. package/esm/release/gate.mjs.map +1 -0
  62. package/esm/release/migrations-proof.mjs +100 -0
  63. package/esm/release/migrations-proof.mjs.map +1 -0
  64. package/esm/release/prune.mjs +42 -0
  65. package/esm/release/prune.mjs.map +1 -0
  66. package/esm/release/report.mjs +25 -0
  67. package/esm/release/report.mjs.map +1 -0
  68. package/esm/release/runner.mjs +55 -0
  69. package/esm/release/runner.mjs.map +1 -0
  70. package/esm/release/semver.mjs +53 -0
  71. package/esm/release/semver.mjs.map +1 -0
  72. package/esm/release/stage.mjs +122 -0
  73. package/esm/release/stage.mjs.map +1 -0
  74. package/esm/release/store.mjs +131 -0
  75. package/esm/release/store.mjs.map +1 -0
  76. package/esm/release/types.d.mts +102 -0
  77. package/esm/release/types.d.mts.map +1 -0
  78. package/esm/release/verify.mjs +94 -0
  79. package/esm/release/verify.mjs.map +1 -0
  80. package/esm/router/index.d.mts +2 -2
  81. package/esm/router/index.mjs +2 -2
  82. package/esm/router/router.d.mts +4 -0
  83. package/esm/router/router.d.mts.map +1 -1
  84. package/esm/router/router.mjs +14 -3
  85. package/esm/router/router.mjs.map +1 -1
  86. package/esm/router/types.d.mts +45 -0
  87. package/esm/router/types.d.mts.map +1 -1
  88. package/esm/router/unguarded-route-diagnostics.d.mts +6 -0
  89. package/esm/router/unguarded-route-diagnostics.d.mts.map +1 -1
  90. package/esm/router/unguarded-route-diagnostics.mjs +10 -2
  91. package/esm/router/unguarded-route-diagnostics.mjs.map +1 -1
  92. package/esm/tooling/check/api-route-references.d.mts +16 -0
  93. package/esm/tooling/check/api-route-references.d.mts.map +1 -0
  94. package/esm/tooling/check/api-route-references.mjs +146 -0
  95. package/esm/tooling/check/api-route-references.mjs.map +1 -0
  96. package/esm/tooling/check/conventions-step.d.mts +6 -3
  97. package/esm/tooling/check/conventions-step.d.mts.map +1 -1
  98. package/esm/tooling/check/conventions-step.mjs +19 -10
  99. package/esm/tooling/check/conventions-step.mjs.map +1 -1
  100. package/esm/tooling/check/run-check.d.mts.map +1 -1
  101. package/esm/tooling/check/run-check.mjs +4 -2
  102. package/esm/tooling/check/run-check.mjs.map +1 -1
  103. package/esm/tooling/check/security-conventions.mjs +19 -1
  104. package/esm/tooling/check/security-conventions.mjs.map +1 -1
  105. package/esm/tooling/check/translation-conventions.mjs +32 -0
  106. package/esm/tooling/check/translation-conventions.mjs.map +1 -0
  107. package/esm/tooling/inspect/collect-files.mjs +1 -1
  108. package/esm/tooling/inspect/collect-routes.mjs +3 -2
  109. package/esm/tooling/inspect/collect-routes.mjs.map +1 -1
  110. package/esm/upgrade/codemods/index.mjs +2 -0
  111. package/esm/upgrade/codemods/index.mjs.map +1 -1
  112. package/esm/upgrade/codemods/vite-vitest.mjs +170 -0
  113. package/esm/upgrade/codemods/vite-vitest.mjs.map +1 -0
  114. package/esm/upgrade/notes.mjs +4 -0
  115. package/esm/upgrade/notes.mjs.map +1 -1
  116. package/esm/validation/init.mjs +11 -4
  117. package/esm/validation/init.mjs.map +1 -1
  118. package/esm/validation/translate-rule.mjs +63 -0
  119. package/esm/validation/translate-rule.mjs.map +1 -0
  120. package/esm/warlock-config/index.d.mts +3 -2
  121. package/esm/warlock-config/types.d.mts +8 -0
  122. package/esm/warlock-config/types.d.mts.map +1 -1
  123. package/llms-full.txt +221 -18
  124. package/llms.txt +1 -0
  125. package/package.json +13 -13
  126. package/skills/deploy-release/SKILL.md +76 -0
  127. package/skills/index.md +1 -1
  128. package/skills/register-route/SKILL.md +25 -0
  129. package/skills/test-service/SKILL.md +8 -8
  130. package/skills/upgrade-from-5-29/SKILL.md +91 -0
  131. package/skills/use-localization/SKILL.md +4 -0
  132. package/skills/warlock-check/SKILL.md +11 -8
  133. package/skills/warlock-conventions/SKILL.md +1 -1
@@ -552,3 +552,94 @@ Root components and providers execute in both realms. Move server-only work into
552
552
  one `#vessel` around `{children}`. Client navigation still swaps layout/page
553
553
  children while preserving the document root. Remove temporary explicit form IDs
554
554
  only when the application does not otherwise depend on those names.
555
+
556
+ ## 5.35 to 5.36 per-page API routes
557
+
558
+ A page document now carries only the named API routes its client code can reach. Before 5.36 every page carried every named route, so a browser call to a name the build cannot see worked on every page by accident. Check each `apiHref()` and `useSubmitForm({ route })` call:
559
+
560
+ - A name written as a string literal, a constant or a template with a static prefix is found automatically.
561
+ - A name computed at run time, or taken from a module the build cannot follow, now throws on the page that calls it. Declare the names in that page's setup file, for example `export const config = { apiRoutes: ["orders.*"] };`, a layout or root `config` covers every page that renders it. Or call the endpoint with an explicit `path` and `method`.
562
+ - `npx warlock check` reports the call sites that need a declaration as `WL9019`.
563
+
564
+ Routes registered with `clientVisible: false` are never embedded, and a browser call to one is an error (`WL9020`). Keep endpoints the browser must not reach on that option. Authorization is unchanged: the server still decides each request.
565
+
566
+ To measure a page's inline payload, set `build.budgets.payload` (default `64kb`). An over-budget route logs one line per process and never fails a request.
567
+
568
+ ## 5.35 to 5.36 translation payloads
569
+
570
+ A page's hydration payload now carries only the translations its client code
571
+ can reach, in route-dictionary (`locales.json`) and global-registry (`extend()`)
572
+ apps alike. The groups every page uses (default `app` and `common`) arrive once
573
+ per locale in a hashed, cached file that the page preloads. Nothing in a page's
574
+ render changes: server output is the full dictionary, as before.
575
+
576
+ Run `warlock build`, then `warlock check`. A `WL9104` warning marks a page that
577
+ renders a translation key computed at runtime. Declare the keys it renders in
578
+ the page's setup file, for example
579
+ `export const config = { translations: ["statuses.*", "members.title"] }`, so the
580
+ page ships only what it uses.
581
+
582
+ In development, a warning names a key the page reads but its payload lacks, and
583
+ resolves it from the full table so the page keeps working. In production the
584
+ key renders as its own text and the miss is reported once through
585
+ `onClientError` with `kind: "translations"`. Declare the key, or set
586
+ `build: { translations: { prune: false } }` in the web connector options while migrating to
587
+ restore the previous per-page payload.
588
+
589
+ Global-registry apps are covered too. Their shared table is served at
590
+ `/__warlock/translations/<locale>.<hash>.json`, which is cached immutable in
591
+ production. A direct `trans()` call from `@mongez/localization` is not checked
592
+ for a pruning miss; the calls through `useTrans()` are.
593
+
594
+ ## 5.35 to 5.36 Vite 8 and Vitest 5
595
+
596
+ `@warlock.js/web` requires Vite 8 (`^8.0.0`) and `@vitejs/plugin-react` 6, and the
597
+ test kit requires Vitest 5. Vite 8 bundles with Rolldown and transforms
598
+ TypeScript with Oxc. Vite 7 is not supported; plugin-react 6 needs Vite 8, so the
599
+ family moves together. Vite 8 needs Node.js 20.19 or 22.12 and newer, Vitest 5
600
+ needs 22.12 or newer; Warlock already requires 22.15.
601
+
602
+ ```bash
603
+ npx warlock upgrade --from 5.35 --to 5.36.0 --dry-run
604
+ npx warlock upgrade --from 5.35 --to 5.36.0
605
+ npm install
606
+ npx warlock check
607
+ ```
608
+
609
+ The `vite-8-vitest-5` codemod:
610
+
611
+ - raises `vite` (8.3.3), `vitest` and `@vitest/*` (5.0.3) and `@vitejs/plugin-react`
612
+ (6.1.2) in `dependencies`, `devDependencies`, `overrides` and `resolutions`,
613
+ keeping `^`, `~` or exact style;
614
+ - rewrites a generated `src/test-runner.ts` from `VitestTestRunner` in
615
+ `vitest/runners` to `TestRunner` from `vitest`, and calls
616
+ `this.onCleanupWorkerContext?.(cleanup)` (the hook is absent in vm pools);
617
+ - lists, without editing, imports of the removed `vitest/coverage`,
618
+ `vitest/reporters`, `vitest/environments`, `vitest/snapshot`, `vitest/suite`,
619
+ `vitest/mocker` and `vitest/internal/module-runner` entry points, other names
620
+ imported from `vitest/runners`, a top-level `esbuild` option in a Vite or
621
+ Vitest config, and object-form `output.manualChunks`.
622
+
623
+ Do these by hand when the codemod lists them:
624
+
625
+ - Move a config's `esbuild: { jsx: "automatic" }` to
626
+ `oxc: { jsx: { runtime: "automatic" } }`. `esbuild.target` is not converted, and
627
+ Oxc does not lower native decorators: keep `lowerStage3Decorators()` from
628
+ `@warlock.js/core/vite` first in `plugins` for decorated modules, as in the
629
+ generated test config.
630
+ - Replace object `manualChunks` with
631
+ `build.rolldownOptions.output.codeSplitting.groups`; `build.rollupOptions` still
632
+ works but is deprecated in favour of `build.rolldownOptions`.
633
+ - A custom bundler `external` list that names Node builtins is still refused by the
634
+ client build.
635
+
636
+ Vitest 5 changes defaults that can alter a green suite: `clearMocks` is true,
637
+ `json` and `junit` reporters write to `.vitest/` instead of stdout, `-t` joins a
638
+ test's names with `>`, `VITEST_POOL_ID` and `VITEST_WORKER_ID` start at 1, nested
639
+ `vi.mock`/`vi.hoisted` calls throw, and an unawaited `resolves` or `rejects`
640
+ assertion fails the test. Vitest also no longer searches parent directories for a
641
+ config file; run it from the package that owns the config. Official guides:
642
+ https://vite.dev/guide/migration and https://vitest.dev/guide/migration.
643
+
644
+ A project that uses `@warlock.js/ai`'s custom matchers needs Vitest 5 for their
645
+ TypeScript types.
@@ -357,3 +357,7 @@ connectors and the file runtime's loader channel, queued work, watchers, health
357
357
  workers, and registered module cleanup hooks, including after partial startup.
358
358
  A Node loader registration is process-scoped; its message channel is closed at
359
359
  teardown. Module-owned timers/listeners must register their cleanup hooks.
360
+
361
+ ## Translation keys in pages (5.36)
362
+
363
+ `warlock check` reports `WL9104` when a page renders a translation key computed at runtime (`trans(key)` with no static prefix, or a translator passed on as a value). Such a page ships every translation group. Declare its keys in the page's setup file, `export const config = { translations: ["statuses.*", "members.title"] }`, to ship only what it uses. The `web` skill `localize-pages` covers the browser side.
@@ -141,14 +141,17 @@ and work through the manual-review list. Use `--lint=oxc` for new apps.
141
141
  The following codes default to **warnings**, so upgrading does not fail existing projects.
142
142
  They parse real TypeScript/JSX syntax with the same oxc-parser adapter as the existing conventions.
143
143
 
144
- | Code | Convention | Remedy |
145
- | -------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
146
- | `WL9013` | A component file exceeds 150 lines | Split components and extract hooks; configure `componentLineLimit`. |
147
- | `WL9014` | More than one component in a file | Move each component into its own TSX file. |
148
- | `WL9015` | State/effects or event-handler functions inside a component | Move `useState`, `useReducer`, `useEffect`, `useLayoutEffect` and handlers into `use-*.ts` hooks. |
149
- | `WL9016` | Native select, checkbox, radio, date, time or datetime-local input | Use the design-system control. Native controls are allowed in `src/web/design-system/**`. |
150
- | `WL9017` | DOM input/textarea/select native validation | Use shared schema validation instead of `required`, `pattern`, `min`, `max`, `minLength`, `maxLength` or input `type="email"`. Custom component props are allowed. |
151
- | `WL9018` | Exported `RequestHandler` in `src/app/**/controllers` lacks `responseSchema` | Assign `handler.responseSchema` to document each response status. |
144
+ | Code | Convention | Remedy |
145
+ | -------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
146
+ | `WL9013` | A component file exceeds 150 lines | Split components and extract hooks; configure `componentLineLimit`. |
147
+ | `WL9014` | More than one component in a file | Move each component into its own TSX file. |
148
+ | `WL9015` | State/effects or event-handler functions inside a component | Move `useState`, `useReducer`, `useEffect`, `useLayoutEffect` and handlers into `use-*.ts` hooks. |
149
+ | `WL9016` | Native select, checkbox, radio, date, time or datetime-local input | Use the design-system control. Native controls are allowed in `src/web/design-system/**`. |
150
+ | `WL9017` | DOM input/textarea/select native validation | Use shared schema validation instead of `required`, `pattern`, `min`, `max`, `minLength`, `maxLength` or input `type="email"`. Custom component props are allowed. |
151
+ | `WL9018` | Exported `RequestHandler` in `src/app/**/controllers` lacks `responseSchema` | Assign `handler.responseSchema` to document each response status. |
152
+ | `WL9019` | Browser route call (`apiHref`, `useSubmitForm({ route })`) takes a run-time name | Pass a string literal or a template with a static prefix, or declare the names with `config.apiRoutes` in a page setup file. |
153
+ | `WL9020` | Browser code names a route registered with `clientVisible: false` (error) | Call the endpoint from the server, or remove `clientVisible: false` from the route. |
154
+ | `WL9104` | Translation key computed at runtime in `src/web` (the page ships every group) | Declare the keys with `config.translations` in the page's setup file, for example `["statuses.*"]`. |
152
155
 
153
156
  Web rules apply to `src/web/**/*.tsx`. Components are top-level JSX-returning functions
154
157
  with a capitalized name (or an anonymous default export). Hook files and ordinary helpers
@@ -186,7 +186,7 @@ router.post("/posts", createPostController, { middleware: [authMiddleware("user"
186
186
  router.post("/contact", contactController, { public: true });
187
187
  ```
188
188
 
189
- A route inside `guarded(() => …)` or `router.group({ middleware: [authMiddleware()] }, …)` is guarded. A middleware counts as a guard when its name contains `auth` or `guard`, or when it is a constant initialised with `markAuthGuard()` in the same file. `warlock dev` warns about the same routes at runtime.
189
+ A route inside `guarded(() => …)` or `router.group({ middleware: [authMiddleware()] }, …)` is guarded. A middleware counts as a guard when its name contains `auth` or `guard`, or when it is a constant initialised with `markAuthGuard()` in the same file, or a local factory that returns `markAuthGuard(fn)` and is called in the `middleware` list. `warlock dev` warns about the same routes at runtime.
190
190
 
191
191
  ### `WL9007` — safe redirects
192
192