@zerotal/core 1.9.0 → 1.10.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 (42) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/api-surface.md +148 -81
  3. package/package.json +2 -1
  4. package/src/application/Application.ts +4 -4
  5. package/src/build/codemod.ts +1 -1
  6. package/src/command/CommandRunner.ts +2 -0
  7. package/src/command/builtin/AssetsPruneCommand.ts +138 -0
  8. package/src/command/builtin/DeployCommand.ts +19 -0
  9. package/src/command/builtin/index.ts +1 -0
  10. package/src/command/startZerotal.ts +36 -9
  11. package/src/config/AppConfig.ts +10 -10
  12. package/src/conventions/ConventionLoader.ts +39 -2
  13. package/src/dev/BuildOutput.ts +58 -6
  14. package/src/dev/CssPlugins.ts +2 -2
  15. package/src/dev/DevDeck.ts +3 -3
  16. package/src/dev/DevProcess.ts +2 -2
  17. package/src/dev/DevSupervisor.ts +5 -5
  18. package/src/dev/index.ts +6 -1
  19. package/src/dev/startDevMode.ts +1 -1
  20. package/src/doctor/throttleIdentity.ts +6 -2
  21. package/src/health/Health.ts +5 -5
  22. package/src/helpers/index.ts +2 -1
  23. package/src/helpers/markdown.ts +7 -0
  24. package/src/http/UploadedFile.ts +2 -2
  25. package/src/index.ts +2 -1
  26. package/src/lock/LockManager.ts +4 -4
  27. package/src/logger/LoggerMiddleware.ts +1 -1
  28. package/src/logger/types.ts +4 -4
  29. package/src/middleware/CorsMiddleware.ts +6 -6
  30. package/src/middleware/RateLimiter.ts +105 -22
  31. package/src/middleware/SecureHeadersMiddleware.ts +8 -8
  32. package/src/middleware/ThrottleMiddleware.ts +57 -4
  33. package/src/middleware/WebhookMiddleware.ts +7 -7
  34. package/src/router/RouteHandler.ts +2 -2
  35. package/src/router/Router.ts +5 -5
  36. package/src/security/redactGraph.ts +1 -1
  37. package/src/shared/format.ts +8 -8
  38. package/src/storage/StorageFilesMiddleware.ts +2 -2
  39. package/src/storage/types.ts +10 -10
  40. package/src/support/cookie.ts +6 -6
  41. package/src/support/deepMerge.ts +49 -0
  42. package/src/support/runtime.ts +91 -1
package/CHANGELOG.md CHANGED
@@ -8,6 +8,123 @@ follows the Zerotal monorepo's unified versioning.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [1.10.0] — 2026-08-30
12
+
13
+ ### Changed
14
+
15
+ - **Optional properties in public option shapes are declared `?: T | undefined`.**
16
+ The generated `tsconfig.json` turns on `exactOptionalPropertyTypes`, under which
17
+ `image?: string` and `image?: string | undefined` are different types: only the
18
+ second accepts a key that is present and holds `undefined`. So an app with the
19
+ strictness the framework shipped it could not write the most ordinary thing there
20
+ is — `{ image: candidate ?? undefined }` — and had to spell every conditional field
21
+ `...(x ? { x } : {})` instead. An options bag exists to be spread into; one built by
22
+ spreading has conditionally-absent keys.
23
+
24
+ 438 properties across 115 files, applied by `scripts/exact-optional.ts` and checked
25
+ by `bun run exact:optional:check` so the convention holds for shapes written later.
26
+ Scoped to exported `*Options` / `*Config` shapes — what an app constructs — rather
27
+ than every optional property in the codebase. Nothing changes for a reader: an
28
+ absent optional property already read as `undefined`.
29
+
30
+ ### Added
31
+
32
+ - **`zt assets:prune`** — remove the chunks an earlier release left behind, on the
33
+ machine that never ran a build. `assets:build --clean` cleans the directory it
34
+ _builds into_, which does nothing for the common release shape: build here, tar the
35
+ output, extract it over `public/` there. Extracting merges — nothing removes a file
36
+ the new release does not contain — so every deploy adds another set of
37
+ content-hashed chunks. One app reached 225 chunk files for the 49 its entry point
38
+ references. Ship `.zerotal/` with the release and this removes what the build record
39
+ does not claim; without a record it says so and removes nothing rather than guessing.
40
+
41
+ - **`definedOnly` (`@zerotal/core/helpers`) and the `Resolved<T>` type.** Widening the
42
+ option shapes moves a problem to the merge, and both of these are that problem's
43
+ answer. Object spread copies own properties even when their value is `undefined`,
44
+ so `{ ...DEFAULTS, ...options }` now lets an explicit `undefined` overwrite a
45
+ default; `definedOnly` drops those keys, turning "supplied as undefined" back into
46
+ "not supplied". (`deepMerge` already did this at every depth.)
47
+
48
+ `Resolved<T>` is what a defaults-applied object is. **`Required<T>` is not**, which
49
+ is the trap: `-?` removes the optionality a `?` introduced but not an `undefined`
50
+ written into the type, so `Required<Options>` quietly stopped meaning "the defaults
51
+ have been applied".
52
+
53
+ - **`zt deploy:<env> --check`** — the preflight gate on its own. A release script has a
54
+ moment where the new code is on disk and the service has not restarted yet, and that
55
+ is where a gate belongs: exit 0 and restart, exit non-zero and keep serving the
56
+ previous release. Everything that can refuse already runs by the end of preflight and
57
+ none of it mutates, so stopping there is a complete answer rather than half a deploy.
58
+ A workspace that has lost its banking details, or had its mail driver knocked back to
59
+ `log`, never goes live broken.
60
+
61
+ - **`engines.bun` is enforced.** Every generated app writes a floor and nothing had
62
+ ever read it. `runtimeMismatch` did not cover this: it compares the running Bun
63
+ against an _installed_ one, and most projects do not install Bun as a package, so
64
+ it correctly says nothing about most of them. `startZerotal()` now refuses to run
65
+ below the declared floor, so every `zt` command is covered.
66
+
67
+ The failure it catches is narrow and expensive. `Intl` output moves between Bun
68
+ releases, so a suite with currency or date assertions goes red on a runtime that is
69
+ otherwise fine, the failures name the code they touch, and the version is the last
70
+ thing anyone checks. `ZT_ALLOW_RUNTIME_MISMATCH=1` downgrades it to a warning.
71
+
72
+ - **`@zerotal/core/runtime`** (`zerotal/runtime`) — a subpath exporting the checks
73
+ themselves: `runtimeBelowFloor`, `declaredBunFloor`, `runtimeMismatch`, `bunBinary`
74
+ and the messages that go with them, so a script or a test can make the same
75
+ assertion. A subpath rather than the main barrel, which is deliberately lean.
76
+
77
+ - **A boot line when a convention is skipped in this environment.** An env-restricted
78
+ concern is skipped by _not looking_, which is correct and completely silent: from a
79
+ web process's point of view nothing is wrong, because from a web process's point of
80
+ view nothing exists. An app ran for weeks in production with `app/schedules` full
81
+ and no worker process — no inventory hold released, no payment reminder sent, and
82
+ nothing logged, because there was nothing to log. It was found by going looking.
83
+
84
+ `runConventions` now says so once, at boot, and only when the directory actually
85
+ holds files:
86
+
87
+ Skipping 3 file(s) in app/schedules — the "schedules" convention does not run in env=web (it runs in: worker, console).
88
+
89
+ "Skipping 0 schedules" on every boot of every app would be noise, and noise is how
90
+ the line that matters gets scrolled past.
91
+
92
+ ### Fixed
93
+
94
+ - **Named rate limiters honour `trustedProxies`.** `ThrottleMiddleware` resolves the
95
+ client address from the socket unless told how many proxies sit in front — that was
96
+ fixed, documented and covered by a doctor check. `RateLimiter`'s `.byIp()`,
97
+ `.byUser()` and `.byApiKey()` did not: they used a private resolver that read the
98
+ socket address and fell back to the **leftmost** `X-Forwarded-For` entry, with no
99
+ proxy count anywhere in it. A `keyResolver` replaces the middleware's own
100
+ proxy-aware path entirely, so the sibling API kept the bug the middleware had shed.
101
+
102
+ Two consequences, in opposite directions. Where there was no socket address a client
103
+ picked its own bucket by writing the header, which is the part of it the client
104
+ controls. Behind a real reverse proxy — where there _is_ a socket address — it was
105
+ the proxy's, so **every visitor shared one bucket**: the documented
106
+ `RateLimiter.for("login").limit(5).every(60)` was five attempts a minute across the
107
+ entire user base, and one attacker locked everybody out.
108
+
109
+ All three now resolve through the same proxy-aware function, and
110
+ `.trustedProxies(n)` is on the builder. The strategy is recorded and the resolver
111
+ built at the end, so `.byIp().trustedProxies(1)` and `.trustedProxies(1).byIp()`
112
+ mean the same thing.
113
+
114
+ - **`zt doctor` audits named limiters.** Its `trustedProxies` check exempted any
115
+ throttle with a custom `keyResolver` — right for one keyed on a user id, where no
116
+ proxy can affect the answer, and exactly wrong for `RateLimiter`'s built-ins, which
117
+ _are_ custom resolvers and do key on an address. The check that exists to catch this
118
+ skipped the whole API that still had it. The built-in resolvers mark themselves now;
119
+ an app's own `.by(fn)` stays exempt, which is the point of the exemption.
120
+
121
+ - **The build record is portable.** Its filename was hashed from the output
122
+ directory's _absolute_ path, so the same project built at `/home/me/app` and
123
+ unpacked at `/opt/app` wrote and looked for two different files. A record shipped
124
+ with a release matched nothing at the other end — which is why a server could not
125
+ say which files belonged to the current release — and moving a checkout silently
126
+ orphaned it. It is keyed on the path relative to the project now.
127
+
11
128
  ## [1.9.0] — 2026-08-29
12
129
 
13
130
  ### Added
package/api-surface.md CHANGED
@@ -394,6 +394,7 @@ class LimiterDefinition = {
394
394
  register: () => LimiterDefinition
395
395
  toMiddleware: () => ThrottleMiddleware
396
396
  toMiddlewareClass: () => new () => ThrottleMiddleware
397
+ trustedProxies: (count: number) => LimiterDefinition
397
398
  }
398
399
 
399
400
  class MarkdownBuilder = {
@@ -808,23 +809,23 @@ interface ContainerBindings = {
808
809
  }
809
810
 
810
811
  interface CookieOptions = {
811
- domain?: string
812
- httpOnly?: boolean
813
- maxAge?: number
812
+ domain?: string | undefined
813
+ httpOnly?: boolean | undefined
814
+ maxAge?: number | undefined
814
815
  name: string
815
- path?: string
816
- sameSite?: SameSite
817
- secure?: boolean
816
+ path?: string | undefined
817
+ sameSite?: SameSite | undefined
818
+ secure?: boolean | undefined
818
819
  value: string
819
820
  }
820
821
 
821
822
  interface CorsOptions = {
822
- allowedHeaders?: string[]
823
- credentials?: boolean
824
- exposedHeaders?: string[]
825
- maxAge?: number
826
- methods?: string[]
827
- origin?: string | string[] | ((origin: string) => boolean)
823
+ allowedHeaders?: string[] | undefined
824
+ credentials?: boolean | undefined
825
+ exposedHeaders?: string[] | undefined
826
+ maxAge?: number | undefined
827
+ methods?: string[] | undefined
828
+ origin?: string | string[] | ((origin: string) => boolean) | undefined
828
829
  }
829
830
 
830
831
  interface DevProcessDefinition = {
@@ -870,9 +871,9 @@ interface ErrorDiagnosis = {
870
871
  }
871
872
 
872
873
  interface GroupOptions = {
873
- domain?: string
874
- middleware?: string | string[] | MiddlewareClass | MiddlewareClass[]
875
- prefix?: string
874
+ domain?: string | undefined
875
+ middleware?: string | string[] | MiddlewareClass | MiddlewareClass[] | undefined
876
+ prefix?: string | undefined
876
877
  }
877
878
 
878
879
  interface ModelClass = {
@@ -925,25 +926,25 @@ interface RouterMacros = {
925
926
  }
926
927
 
927
928
  interface SecureHeadersOptions = {
928
- contentSecurityPolicy?: string
929
- frameOptions?: false | 'DENY' | 'SAMEORIGIN'
930
- hstsIncludeSubDomains?: boolean
931
- hstsMaxAge?: number
932
- hstsPreload?: boolean
933
- permissionsPolicy?: string | false
934
- referrerPolicy?: string
935
- secure?: boolean
929
+ contentSecurityPolicy?: string | undefined
930
+ frameOptions?: false | 'DENY' | 'SAMEORIGIN' | undefined
931
+ hstsIncludeSubDomains?: boolean | undefined
932
+ hstsMaxAge?: number | undefined
933
+ hstsPreload?: boolean | undefined
934
+ permissionsPolicy?: string | false | undefined
935
+ referrerPolicy?: string | undefined
936
+ secure?: boolean | undefined
936
937
  }
937
938
 
938
939
  interface StartZerotalOptions = {
939
- configDir?: string
940
+ configDir?: string | undefined
940
941
  }
941
942
 
942
943
  interface ThrottleOptions = {
943
- keyResolver?: (ctx: HttpContext) => string
944
+ keyResolver?: ((ctx: HttpContext) => string) | undefined
944
945
  maxAttempts: number
945
- trustedProxies?: number
946
- windowSeconds?: number
946
+ trustedProxies?: number | undefined
947
+ windowSeconds?: number | undefined
947
948
  }
948
949
 
949
950
  interface ViewRegistration = {
@@ -952,14 +953,14 @@ interface ViewRegistration = {
952
953
  }
953
954
 
954
955
  interface WebhookOptions = {
955
- algorithm?: 'sha256' | 'sha1' | 'sha512'
956
- format?: 'raw' | 'stripe'
957
- header?: string
958
- prefix?: string
956
+ algorithm?: 'sha256' | 'sha1' | 'sha512' | undefined
957
+ format?: 'raw' | 'stripe' | undefined
958
+ header?: string | undefined
959
+ prefix?: string | undefined
959
960
  secret: string
960
- timestampHeader?: string
961
- timestampSeparator?: string
962
- tolerance?: number
961
+ timestampHeader?: string | undefined
962
+ timestampSeparator?: string | undefined
963
+ tolerance?: number | undefined
963
964
  }
964
965
 
965
966
  interface WebSocketHandlers = {
@@ -998,6 +999,8 @@ type NextFn = () => Promise<Response | void>
998
999
 
999
1000
  type ParamsOf = P extends `${string}:${infer Name}/${infer Rest}` ? { [K in Name]: RouteParamValue; } & ParamsOf<`/${Rest}`> : P extends `${string}:${infer Name}` ? { [K in Name]: RouteParamValue; } : P extends `${string}*${string}` ? { "*": RouteParamValue | readonly RouteParamValue[];} : Record<never, never>
1000
1001
 
1002
+ type Resolved = { [K in keyof T]-?: Exclude<T[K], undefined>; }
1003
+
1001
1004
  type RouteArgs = [params?: RouteParamValues, query?: RouteQuery]
1002
1005
 
1003
1006
  type RouteMiddleware = MiddlewareClass[] | RouteMethodMiddleware
@@ -1037,7 +1040,7 @@ function addToDefaultArrayExport = (source: string, identifier: string) => strin
1037
1040
  function registerProvider = (options: RegisterProviderOptions) => Promise<RegisterResult>
1038
1041
 
1039
1042
  interface RegisterProviderOptions = {
1040
- bootstrapPath?: string
1043
+ bootstrapPath?: string | undefined
1041
1044
  className: string
1042
1045
  importPath: string
1043
1046
  }
@@ -1304,6 +1307,34 @@ class AssetsBuildCommand = {
1304
1307
  write: (msg: string) => void
1305
1308
  }
1306
1309
 
1310
+ class AssetsPruneCommand = {
1311
+ new (): AssetsPruneCommand
1312
+ static args: ArgDef[]
1313
+ static commandName: string
1314
+ static description: string
1315
+ static flags: ({ name: string; type: 'string'; description: string; default?: never;} | { name: string; type: 'boolean'; description: string; default: boolean;})[]
1316
+ static needsApp: boolean
1317
+ _readLine: () => Promise<string>
1318
+ _writer: OutputWriter
1319
+ app: unknown
1320
+ args: Record<string, string>
1321
+ ask: (question: string, defaultValue?: string) => Promise<string>
1322
+ choice: (question: string, options: string[]) => Promise<string>
1323
+ confirm: (question: string, defaultValue?: boolean) => Promise<boolean>
1324
+ dim: (msg: string) => void
1325
+ error: (msg: string) => void
1326
+ flags: Record<string, string | number | boolean>
1327
+ info: (msg: string) => void
1328
+ line: (msg: string) => void
1329
+ newLine: () => void
1330
+ run: () => Promise<void>
1331
+ secret: (question: string) => Promise<string>
1332
+ section: (title: string) => void
1333
+ table: (rows: [string, string][], indent?: number) => void
1334
+ warn: (msg: string) => void
1335
+ write: (msg: string) => void
1336
+ }
1337
+
1307
1338
  class CompileCommand = {
1308
1339
  new (): CompileCommand
1309
1340
  static args: ArgDef[]
@@ -2191,7 +2222,7 @@ function DeployConfig = (options?: Partial<DeployConfigShape>) => DeployConfigSh
2191
2222
 
2192
2223
  interface AppAssetsConfig = {
2193
2224
  entrypoint: string | string[]
2194
- loader?: Record<string, AssetLoaderKind>
2225
+ loader?: Record<string, AssetLoaderKind> | undefined
2195
2226
  minify: boolean
2196
2227
  outDir: string
2197
2228
  prefix: string
@@ -2199,11 +2230,11 @@ interface AppAssetsConfig = {
2199
2230
 
2200
2231
  interface AppConfigShape = {
2201
2232
  allowedOrigins: string[]
2202
- assets?: AppAssetsConfig
2233
+ assets?: AppAssetsConfig | undefined
2203
2234
  conventions: ConventionsConfig
2204
2235
  cors: AppCorsConfig
2205
2236
  debug: boolean
2206
- dev?: DevConfigShape
2237
+ dev?: DevConfigShape | undefined
2207
2238
  env: string
2208
2239
  health: boolean | HealthConfigShape
2209
2240
  http3: boolean
@@ -2215,7 +2246,7 @@ interface AppConfigShape = {
2215
2246
  secureHeaders: AppSecureHeadersConfig
2216
2247
  throttle: AppThrottleConfig
2217
2248
  timezone: string
2218
- tls?: AppTlsConfig
2249
+ tls?: AppTlsConfig | undefined
2219
2250
  url: string
2220
2251
  }
2221
2252
 
@@ -2579,10 +2610,10 @@ interface HealthCheckReport = {
2579
2610
  }
2580
2611
 
2581
2612
  interface HealthConfigShape = {
2582
- enabled?: boolean
2583
- path?: string
2584
- secret?: string
2585
- showDetails?: boolean
2613
+ enabled?: boolean | undefined
2614
+ path?: string | undefined
2615
+ secret?: string | undefined
2616
+ showDetails?: boolean | undefined
2586
2617
  }
2587
2618
 
2588
2619
  interface HealthReport = {
@@ -2602,7 +2633,7 @@ interface HealthResult = {
2602
2633
  interface ResolvedHealthConfig = {
2603
2634
  enabled: boolean
2604
2635
  path: string
2605
- secret?: string
2636
+ secret?: string | undefined
2606
2637
  showDetails: boolean
2607
2638
  }
2608
2639
 
@@ -2620,6 +2651,8 @@ function data_get = (target: unknown, key: string, defaultValue?: unknown) => un
2620
2651
 
2621
2652
  function deepMerge = <T extends object>(base: T, override: DeepPartial<T>) => T
2622
2653
 
2654
+ function definedOnly = <T extends object>(value: T) => { [K in keyof T]?: Exclude<T[K], undefined>; }
2655
+
2623
2656
  function env = { (key: string): string | undefined; (key: string, fallback: string): string; (key: string, fallback: boolean): boolean; (key: string, fallback: number): number;}
2624
2657
 
2625
2658
  function pipe = <T, R>(value: T, fn: (val: T) => R) => R
@@ -2644,6 +2677,8 @@ function tap = <T>(value: T, callback: (val: T) => void) => T
2644
2677
 
2645
2678
  function tapAsync = <T>(value: T, callback: (val: T) => Promise<void>) => Promise<T>
2646
2679
 
2680
+ type Resolved = { [K in keyof T]-?: Exclude<T[K], undefined>; }
2681
+
2647
2682
  ## ./http `(./src/http/index.ts)`
2648
2683
 
2649
2684
  class Http = {
@@ -2802,8 +2837,8 @@ interface CliContext = {
2802
2837
  }
2803
2838
 
2804
2839
  interface FileValidationOptions = {
2805
- maxSize?: number
2806
- mimes?: string[]
2840
+ maxSize?: number | undefined
2841
+ mimes?: string[] | undefined
2807
2842
  }
2808
2843
 
2809
2844
  interface NegotiateMap = {
@@ -2955,10 +2990,10 @@ class SqliteLockDriver = {
2955
2990
  function LockConfig = (options?: Partial<LockConfigShape>) => LockConfigShape
2956
2991
 
2957
2992
  interface BlockOptions = {
2958
- refresh?: boolean
2959
- refreshEvery?: number
2960
- retryDelay?: number
2961
- timeout?: number
2993
+ refresh?: boolean | undefined
2994
+ refreshEvery?: number | undefined
2995
+ retryDelay?: number | undefined
2996
+ timeout?: number | undefined
2962
2997
  }
2963
2998
 
2964
2999
  interface LockConfigShape = {
@@ -2977,8 +3012,8 @@ interface LockDriver = {
2977
3012
  }
2978
3013
 
2979
3014
  interface RefreshOptions = {
2980
- refresh?: boolean
2981
- refreshEvery?: number
3015
+ refresh?: boolean | undefined
3016
+ refreshEvery?: number | undefined
2982
3017
  }
2983
3018
 
2984
3019
  type LockedCallback = (lock: ManagedLock, signal: AbortSignal) => Promise<T> | T
@@ -3093,16 +3128,16 @@ interface LogEntry = {
3093
3128
  }
3094
3129
 
3095
3130
  interface LoggerOptions = {
3096
- format?: 'text' | 'json'
3131
+ format?: 'text' | 'json' | undefined
3097
3132
  }
3098
3133
 
3099
3134
  interface LoggingConfigShape = {
3100
3135
  channels: Record<string, ChannelConfig>
3101
- console?: ConsoleSinkConfig
3136
+ console?: ConsoleSinkConfig | undefined
3102
3137
  default: string
3103
- file?: FileSinkConfig
3104
- requests?: boolean
3105
- slowQueryMs?: number
3138
+ file?: FileSinkConfig | undefined
3139
+ requests?: boolean | undefined
3140
+ slowQueryMs?: number | undefined
3106
3141
  }
3107
3142
 
3108
3143
  type ChannelConfig = { driver: 'console'; level?: LogLevel; format?: 'json' | 'pretty' } | { driver: 'single'; level?: LogLevel; path: string } | { driver: 'daily'; level?: LogLevel; path: string; days?: number } | { driver: 'stack'; level?: LogLevel; channels: string[] } | { driver: 'null' }
@@ -3164,6 +3199,38 @@ type RouteTable = Readonly<Record<string, string>> | ReadonlyMap<string, string>
3164
3199
 
3165
3200
  type RouteTarget = string
3166
3201
 
3202
+ ## ./runtime `(./src/support/runtime.ts)`
3203
+
3204
+ const RUNTIME_MISMATCH_ESCAPE = 'ZT_ALLOW_RUNTIME_MISMATCH'
3205
+
3206
+ function bunBinary = () => string
3207
+
3208
+ function declaredBunFloor = (cwd: string) => { range: string; manifest: string;} | null
3209
+
3210
+ function installedBunVersion = (cwd: string) => { version: string; manifest: string;} | null
3211
+
3212
+ function runtimeBelowFloor = (cwd?: string) => RuntimeFloor | null
3213
+
3214
+ function runtimeBelowFloorMessage = (floor: RuntimeFloor) => string
3215
+
3216
+ function runtimeMismatch = (cwd?: string) => RuntimeMismatch | null
3217
+
3218
+ function runtimeMismatchAllowed = () => boolean
3219
+
3220
+ function runtimeMismatchMessage = (mismatch: RuntimeMismatch) => string
3221
+
3222
+ interface RuntimeFloor = {
3223
+ manifest: string
3224
+ required: string
3225
+ running: string
3226
+ }
3227
+
3228
+ interface RuntimeMismatch = {
3229
+ installed: string
3230
+ manifest: string
3231
+ running: string
3232
+ }
3233
+
3167
3234
  ## ./security `(./src/security/index.ts)`
3168
3235
 
3169
3236
  class CryptKeyMissingError = {
@@ -3194,7 +3261,7 @@ function redactGraph = (value: unknown, options: RedactGraphOptions) => unknown
3194
3261
 
3195
3262
  interface RedactGraphOptions = {
3196
3263
  circular: string
3197
- flatten?: (value: unknown) => string | undefined
3264
+ flatten?: ((value: unknown) => string | undefined) | undefined
3198
3265
  mask: string
3199
3266
  maxDepth: number
3200
3267
  sensitive: (key: string) => boolean
@@ -3224,27 +3291,27 @@ function snakeCase = (value: string) => string
3224
3291
  function tableNameFor = (className: string) => string
3225
3292
 
3226
3293
  interface DateOptions = {
3227
- dateStyle?: 'medium' | 'short' | 'full' | 'long'
3228
- locale?: string
3229
- timeStyle?: 'medium' | 'short' | 'full' | 'long'
3230
- timeZone?: string
3294
+ dateStyle?: 'medium' | 'short' | 'full' | 'long' | undefined
3295
+ locale?: string | undefined
3296
+ timeStyle?: 'medium' | 'short' | 'full' | 'long' | undefined
3297
+ timeZone?: string | undefined
3231
3298
  }
3232
3299
 
3233
3300
  interface FormatOptions = {
3234
- locale?: string
3301
+ locale?: string | undefined
3235
3302
  }
3236
3303
 
3237
3304
  interface MoneyOptions = {
3238
3305
  currency: string
3239
- fractionDigits?: number
3240
- locale?: string
3241
- minorUnits?: boolean
3306
+ fractionDigits?: number | undefined
3307
+ locale?: string | undefined
3308
+ minorUnits?: boolean | undefined
3242
3309
  }
3243
3310
 
3244
3311
  interface NumberOptions = {
3245
- locale?: string
3246
- maximumFractionDigits?: number
3247
- minimumFractionDigits?: number
3312
+ locale?: string | undefined
3313
+ maximumFractionDigits?: number | undefined
3314
+ minimumFractionDigits?: number | undefined
3248
3315
  }
3249
3316
 
3250
3317
  ## ./storage `(./src/storage/index.ts)`
@@ -3411,10 +3478,10 @@ const Storage = StorageManager
3411
3478
  function StorageConfig = (options?: Partial<StorageConfigShape>) => StorageConfigShape
3412
3479
 
3413
3480
  interface DiskServeConfig = {
3414
- expiresIn?: number
3415
- headers?: Record<string, string>
3481
+ expiresIn?: number | undefined
3482
+ headers?: Record<string, string> | undefined
3416
3483
  path: string
3417
- signed?: boolean
3484
+ signed?: boolean | undefined
3418
3485
  }
3419
3486
 
3420
3487
  interface FakeStoredFile = {
@@ -3428,24 +3495,24 @@ interface FakeStoredFile = {
3428
3495
  interface LocalDiskConfig = {
3429
3496
  driver: 'local'
3430
3497
  root: string
3431
- serve?: DiskServeConfig
3432
- url?: string
3498
+ serve?: DiskServeConfig | undefined
3499
+ url?: string | undefined
3433
3500
  }
3434
3501
 
3435
3502
  interface PutOptions = {
3436
- contentType?: string
3437
- visibility?: 'public' | 'private'
3503
+ contentType?: string | undefined
3504
+ visibility?: 'public' | 'private' | undefined
3438
3505
  }
3439
3506
 
3440
3507
  interface S3DiskConfig = {
3441
3508
  bucket: string
3442
3509
  driver: 's3'
3443
- endpoint?: string
3510
+ endpoint?: string | undefined
3444
3511
  key: string
3445
3512
  region: string
3446
3513
  secret: string
3447
- serve?: DiskServeConfig
3448
- url?: string
3514
+ serve?: DiskServeConfig | undefined
3515
+ url?: string | undefined
3449
3516
  }
3450
3517
 
3451
3518
  interface StorageConfigShape = {
@@ -3470,8 +3537,8 @@ interface StorageDriver = {
3470
3537
  }
3471
3538
 
3472
3539
  interface StorageFilesOptions = {
3473
- mounts?: Mount[]
3474
- storage?: StorageManager
3540
+ mounts?: Mount[] | undefined
3541
+ storage?: StorageManager | undefined
3475
3542
  }
3476
3543
 
3477
3544
  type DiskConfig = LocalDiskConfig | S3DiskConfig
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/core",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "license": "MIT",
5
5
  "maturity": "stable",
6
6
  "private": false,
@@ -16,6 +16,7 @@
16
16
  "./logger": "./src/logger/index.ts",
17
17
  "./commands": "./src/command/builtin/index.ts",
18
18
  "./helpers": "./src/helpers/index.ts",
19
+ "./runtime": "./src/support/runtime.ts",
19
20
  "./shared": "./src/shared/index.ts",
20
21
  "./facades": "./src/facade/facades/index.ts",
21
22
  "./carbon": "./src/datetime/index.ts",
@@ -182,9 +182,9 @@ type PipeClass = new (...args: any[]) => Pipe<HttpContext>;
182
182
 
183
183
  /** Options form for `Application.create({ ... })`. */
184
184
  export interface CreateOptions {
185
- providers?: ProviderClass[];
186
- env?: Environment;
187
- config?: ConfigLoader | ConfigMap;
185
+ providers?: ProviderClass[] | undefined;
186
+ env?: Environment | undefined;
187
+ config?: ConfigLoader | ConfigMap | undefined;
188
188
  /**
189
189
  * Drop {@link SecureHeadersMiddleware} from the front of the pipeline.
190
190
  *
@@ -194,7 +194,7 @@ export interface CreateOptions {
194
194
  * `config('app.secureHeaders')`; turn it off only when a proxy in front of the app is
195
195
  * already emitting the same headers.
196
196
  */
197
- secureHeaders?: false;
197
+ secureHeaders?: false | undefined;
198
198
  }
199
199
 
200
200
  function _normaliseEnv(raw: string): Environment {
@@ -40,7 +40,7 @@ export interface RegisterProviderOptions {
40
40
  /** Import specifier, e.g. '../app/providers/FooProvider.ts' or '@zerotal/foo'. */
41
41
  importPath: string;
42
42
  /** Bootstrap file. Default: 'bootstrap/providers.ts'. */
43
- bootstrapPath?: string;
43
+ bootstrapPath?: string | undefined;
44
44
  }
45
45
 
46
46
  /**
@@ -363,6 +363,7 @@ export class CommandRunner {
363
363
  MakeProviderCommand,
364
364
  CssBuildCommand,
365
365
  AssetsBuildCommand,
366
+ AssetsPruneCommand,
366
367
  LintPackagesCommand,
367
368
  MakePackageCommand,
368
369
  } = await import("./builtin/index.ts");
@@ -414,6 +415,7 @@ export class CommandRunner {
414
415
  TestCommand,
415
416
  CssBuildCommand,
416
417
  AssetsBuildCommand,
418
+ AssetsPruneCommand,
417
419
  LintPackagesCommand,
418
420
  MakePackageCommand,
419
421
  ]);