@zerotal/core 1.8.1 → 1.9.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 (57) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/api-surface.md +56 -355
  3. package/package.json +2 -1
  4. package/src/application/Application.ts +6 -0
  5. package/src/application/currentApp.ts +7 -1
  6. package/src/command/OutputWriter.ts +5 -1
  7. package/src/command/builtin/DeployCommand.ts +72 -1
  8. package/src/command/builtin/TestCommand.ts +9 -2
  9. package/src/command/startZerotal.ts +34 -0
  10. package/src/config/ConfigLoader.ts +5 -1
  11. package/src/config/DeployConfig.ts +33 -0
  12. package/src/config/index.ts +6 -1
  13. package/src/config/registry.ts +5 -1
  14. package/src/config/validation.ts +10 -2
  15. package/src/conventions/ConventionLoader.ts +5 -1
  16. package/src/dev/CssPlugins.ts +11 -1
  17. package/src/dev/DevBuildHook.ts +10 -2
  18. package/src/dev/DevDeck.ts +6 -0
  19. package/src/dev/DevOrchestrator.ts +2 -0
  20. package/src/dev/DevProcess.ts +17 -3
  21. package/src/dev/DevReloadMiddleware.ts +7 -1
  22. package/src/dev/DevSupervisor.ts +22 -4
  23. package/src/dev/bootBuild.ts +9 -1
  24. package/src/dev/reloadClient.ts +2 -0
  25. package/src/dev/startDevMode.ts +7 -1
  26. package/src/doctor/AppDoctor.ts +43 -1
  27. package/src/doctor/throttleIdentity.ts +114 -0
  28. package/src/errors/RuntimeMismatchError.ts +21 -0
  29. package/src/errors/index.ts +1 -0
  30. package/src/events/Emitter.ts +5 -1
  31. package/src/helpers/html.ts +2 -0
  32. package/src/helpers/markdown.ts +7 -1
  33. package/src/helpers/pageElements.ts +2 -0
  34. package/src/http/HttpClient.ts +5 -1
  35. package/src/http/Uri.ts +5 -1
  36. package/src/http/negotiate.ts +5 -1
  37. package/src/http/originGuard.ts +2 -0
  38. package/src/http/sniffContentType.ts +7 -1
  39. package/src/macros/config.macro.ts +2 -0
  40. package/src/metrics/HttpMetrics.ts +10 -2
  41. package/src/middleware/BaseMiddleware.ts +20 -0
  42. package/src/pipeline/ContextRegistry.ts +12 -2
  43. package/src/pipeline/HttpContext.ts +4 -0
  44. package/src/pipeline/currentPage.ts +4 -0
  45. package/src/pipeline/types.ts +2 -0
  46. package/src/router/FileRouter.ts +20 -2
  47. package/src/router/Route.ts +3 -0
  48. package/src/router/Router.ts +2 -0
  49. package/src/router/domain.ts +1 -0
  50. package/src/router/registry.ts +12 -2
  51. package/src/shared/format.ts +135 -0
  52. package/src/shared/index.ts +34 -0
  53. package/src/storage/StorageFilesMiddleware.ts +2 -0
  54. package/src/support/cookie.ts +7 -1
  55. package/src/support/runtime.ts +136 -0
  56. package/src/view/FileRouteResolver.ts +2 -0
  57. package/src/view/jsx-runtime.ts +4 -0
package/CHANGELOG.md CHANGED
@@ -8,6 +8,93 @@ follows the Zerotal monorepo's unified versioning.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.9.0] — 2026-08-29
12
+
13
+ ### Added
14
+
15
+ - **`@zerotal/core/env` is documented.** A whole subpath — a strict, fully typed environment
16
+ schema — had no page. `EnvSchema.define()` with the `t` field builders reports **every**
17
+ failing variable at once rather than one per restart, which is the difference between one fix
18
+ and three round trips through a deploy. See
19
+ [Configuration](/docs/config-system#declaring-the-whole-environment--envschema).
20
+
21
+ - **`negotiate()` is documented.** One route, three audiences: a browser, an API client and the
22
+ console, without three copies of the logic. It is what the framework's own error handler uses,
23
+ which is why a 422 is a redirect-with-errors for a form post and a JSON body for a fetch.
24
+
25
+ - **The hashing helpers get the paragraph `safeEqual` deserves.** `a === b` on a token returns as
26
+ soon as two bytes differ, and how long it took measures how much of the prefix was right —
27
+ enough, over many attempts, to recover a secret a character at a time.
28
+
29
+ - Routing, config, cookie, view, storage and Carbon types are named.
30
+
31
+ ### Changed
32
+
33
+ - **INTERNAL: 58 exports are marked `@internal`** — the file-routing internals, the router's
34
+ compiled state, the context registry, the metrics instrumentation hooks, the view component
35
+ symbols, and the config map/path types. Still exported, still working; none is something an
36
+ app constructs.
37
+
38
+ ### Changed
39
+
40
+ - **INTERNAL: the dev orchestrator's 26 exports are marked `@internal`.** `DevSupervisor`,
41
+ `DevChild`, `DevSpawnFn`, `StreamDeck`, `TabsDeck`, `createDeck`, `collectDevProcesses`,
42
+ `buildCssBundle`, `buildJsBundle`, `bootBuildDecision`, `detectCssPlugins`, `isWritableDir`,
43
+ `startDevMode`, `registerDevHtmlSnippet`, `DEV_RELOAD_CLIENT`, `SERVER_PROCESS_NAME` and their
44
+ option/result types.
45
+
46
+ **Nothing is removed and nothing breaks** — they are still exported and still work. What
47
+ changes is the promise: they leave the recorded API surface, because an app never constructs
48
+ any of them and the only callers outside `@zerotal/core` are sibling framework packages wiring
49
+ their own dev-time build. `DevProcessDefinition` — the one a package author actually writes —
50
+ is unaffected and stays documented.
51
+
52
+ ### Added
53
+
54
+ - **One project, one Bun.** `engines.bun` is a floor and nothing enforces it, so a project
55
+ can end up serving its app with one runtime and running its suite with another — the
56
+ shell's `bun` and a `node_modules/bun` put there by a transitive peer dependency nobody
57
+ declared. Nothing announces that, and a green suite is then evidence about a binary the app
58
+ is not served by. `startZerotal()` now compares `Bun.version` against the installed
59
+ manifest and refuses on a mismatch, naming both versions and the two ways out. It is not a
60
+ pin: the version to agree on is whichever one the project installed, so `bun update bun`
61
+ moves it. `ZT_ALLOW_RUNTIME_MISMATCH=1` downgrades the refusal to a warning.
62
+
63
+ - **`DeployTarget.preflight`** — a slot for the app's own release gate, run after the config
64
+ validators and `doctor` and before anything is built or migrated. A command named
65
+ `release:check` is found by convention with nothing to wire up. A declared name that is not
66
+ registered **fails** the deploy rather than being skipped: a missing `inertia:build` means
67
+ the app has no Inertia, but a missing gate means the gate is not running, which is the
68
+ state the feature exists to prevent.
69
+
70
+ - **`zerotal/shared`** — the helpers that are safe to import from a browser bundle:
71
+ `pluralize`, `singularize`, `snakeCase`, `camelCase`, `tableNameFor`, `Str`, and new
72
+ `formatMoney` / `formatNumber` / `formatDate`. Everything reachable from it is pure, and a
73
+ test bundles the entry point for the browser to keep it that way. Without it a page that
74
+ wants the framework's `pluralize` gets a second implementation written by hand, and the
75
+ second copy is always the worse one — `"supplier line"` pluralises to `"supplier lines"`,
76
+ and the naive rule gives `"suppliers line"`.
77
+
78
+ - **`doctor` check: rate-limit identity.** `ThrottleMiddleware` keys on the socket address
79
+ unless told how many proxies sit in front of the app. That default is right and it is the
80
+ wrong answer the moment you deploy behind one: the socket address is then the proxy's for
81
+ every request, everybody shares a bucket, and the limiter inverts into a way for one
82
+ attacker to lock out the rest. Nothing observable says so. A production-like deployment
83
+ with a registered throttle and no `trustedProxies` is now reported.
84
+
85
+ ### Changed
86
+
87
+ - **`zt test` spawns the binary running it**, not the name `bun` for the OS to resolve
88
+ against `PATH`. A command whose job is to run this app's tests was handing them to whatever
89
+ the shell happened to offer, so `node_modules/.bin/bun zt test` satisfied every check in
90
+ the parent process and still ran the suite on a different runtime.
91
+
92
+ - **`BaseMiddleware.with()`** now documents that each call creates a distinct class and any
93
+ per-class state goes with it — so re-using one `.with()` export on two routes shares that
94
+ state. For `ThrottleMiddleware` that state is the hit counter, and on a sign-in flow it
95
+ means a handful of fumbled passwords can spend the allowance a legitimate person needs to
96
+ answer their second factor.
97
+
11
98
  ## [1.8.0] — 2026-08-24
12
99
 
13
100
  ### Added