@zerotal/core 1.8.0 → 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/api-surface.md CHANGED
@@ -512,20 +512,6 @@ class ResponseBuilder = {
512
512
  withWarning: (message: string) => ResponseBuilder
513
513
  }
514
514
 
515
- class RouterState = {
516
- new (): RouterState
517
- domain: string | undefined
518
- groupMiddleware: MiddlewareClass[]
519
- implicitModelResolver: ((paramName: string) => ModelBindingResolver | undefined) | null
520
- markdownDirs: MarkdownDir[]
521
- middlewareGroups: Map<string, MiddlewareClass[]>
522
- namedRoutes: Map<string, string>
523
- prefix: string
524
- rawRoutes: Map<string, (req: Request) => Response | Promise<Response>>
525
- routes: Map<string, RouteDefinition>
526
- staticDirs: StaticDir[]
527
- }
528
-
529
515
  class ScopedResolver = {
530
516
  new (_container?: Container | undefined): ScopedResolver
531
517
  acquire: () => void
@@ -576,13 +562,6 @@ class ServiceUnavailableError = {
576
562
  readonly status: number
577
563
  }
578
564
 
579
- class TerminalWriter = {
580
- new (): TerminalWriter
581
- write: (message: string) => void
582
- writeError: (message: string) => void
583
- writeLine: (message: string) => void
584
- }
585
-
586
565
  class ThrottleMiddleware = {
587
566
  new (options?: Partial<ThrottleOptions>): ThrottleMiddleware
588
567
  static with: <T extends new (...args: any[]) => BaseMiddleware<any>, Opts = T extends new (...args: any[]) => BaseMiddleware<infer U> ? U : object>(this: T, options: DeepPartial<NoInfer<Opts>>) => new () => InstanceType<T>
@@ -648,8 +627,6 @@ const App = { readonly container: Container; readonly instance: () => Appl
648
627
 
649
628
  const Artisan = { call(commandName: string, parameters?: Record<string, string | boolean | number>): Promise<ArtisanResult>;}
650
629
 
651
- const builtinDoctorChecks = DoctorCheck[]
652
-
653
630
  const Config = ConfigManager
654
631
 
655
632
  const Events = Emitter
@@ -668,8 +645,6 @@ function app = { (): Application; <T>(token: BindingToken<T>): Promise<T>;
668
645
 
669
646
  function basePath = (...segments: string[]) => string
670
647
 
671
- function buildCookie = (options: CookieOptions) => string
672
-
673
648
  function camelCase = (value: string) => string
674
649
 
675
650
  function collect = <T>(items: T[]) => Collection<T>
@@ -708,10 +683,6 @@ function make = <T>(token: BindingToken<T>) => Promise<T>
708
683
 
709
684
  function markdown = (content: string, options?: BunMarkdownOptions & { title?: string;}, status?: number) => MarkdownBuilder
710
685
 
711
- function pageElements = (current: number, last: number, each?: number) => (number | '...')[]
712
-
713
- function parseCookieHeader = (header: string, name: string) => string | undefined
714
-
715
686
  function pipe = <T, R>(value: T, fn: (val: T) => R) => R
716
687
 
717
688
  function pipeAsync = <T, R>(value: T, fn: (val: T) => Promise<R>) => Promise<R>
@@ -726,8 +697,6 @@ function redirectTo = <N extends RouteTarget>(name: N, params?: RouteParamsArg<N
726
697
 
727
698
  function registerErrorDiagnoser = (diagnoser: ErrorDiagnoser) => void
728
699
 
729
- function registerFileRouteResolver = (resolver: FileRouteResolver) => void
730
-
731
700
  function request = { (): HttpContext; <T = string>(key: string, fallback?: T): T | undefined;}
732
701
 
733
702
  function requireEnv = (key: string) => string
@@ -740,14 +709,8 @@ function runDoctor = (app: Application, extraChecks?: DoctorCheck[]) => Promise<
740
709
 
741
710
  function safeEqual = (a: string, b: string) => boolean
742
711
 
743
- function safeRedirectPath = (url: string | null | undefined, origin: string) => string | undefined
744
-
745
- function scanFileRoutes = (baseDir: string, reloadId?: string) => Promise<number>
746
-
747
712
  function setAppEnv = (command?: string) => void
748
713
 
749
- function setCurrentPageResolver = (resolver: CurrentPageResolver) => void
750
-
751
714
  function sha256Hex = (input: string | Uint8Array) => string
752
715
 
753
716
  function singularize = (value: string) => string
@@ -762,12 +725,8 @@ function tap = <T>(value: T, callback: (val: T) => void) => T
762
725
 
763
726
  function tapAsync = <T>(value: T, callback: (val: T) => Promise<void>) => Promise<T>
764
727
 
765
- function tryCurrentApp = () => Application | undefined
766
-
767
728
  function view = { (markup: string | { toString(): string; }, status?: number): void; <P extends Record<string, unknown> = Record<string, never>>(component: (ctx: HttpContext, props: P) => ViewMarkup | Promise<ViewMarkup>, props?: P, status?: number): void | Promise<void>;}
768
729
 
769
- function withApp = <T>(app: Application, fn: () => T) => T
770
-
771
730
  function withHeaders = (res: Response, headers: Record<string, string>) => Response
772
731
 
773
732
  interface ArtisanResult = {
@@ -777,18 +736,6 @@ interface ArtisanResult = {
777
736
 
778
737
  interface AuthenticatedUser = {}
779
738
 
780
- interface CompiledDomain = {
781
- params: string[]
782
- regex: RegExp
783
- source: string
784
- }
785
-
786
- interface ConcernContext = {
787
- app: Application
788
- env: AppEnvironment
789
- resolve: <T = unknown>(token: string) => T | undefined
790
- }
791
-
792
739
  interface ConcernDescriptor = {
793
740
  dir?: string
794
741
  envs?: AppEnvironment[]
@@ -860,8 +807,6 @@ interface ContainerBindings = {
860
807
  two_factor: TwoFactorService
861
808
  }
862
809
 
863
- interface ContextRegistry = {}
864
-
865
810
  interface CookieOptions = {
866
811
  domain?: string
867
812
  httpOnly?: boolean
@@ -882,11 +827,6 @@ interface CorsOptions = {
882
827
  origin?: string | string[] | ((origin: string) => boolean)
883
828
  }
884
829
 
885
- interface DevConfigShape = {
886
- disable?: string[]
887
- processes?: DevProcessDefinition[]
888
- }
889
-
890
830
  interface DevProcessDefinition = {
891
831
  after?: 'server' | 'none'
892
832
  color?: DevProcessColor
@@ -929,30 +869,12 @@ interface ErrorDiagnosis = {
929
869
  title: string
930
870
  }
931
871
 
932
- interface FileRouteContext = {
933
- filePath: string
934
- isIndex: boolean
935
- layout?: ViewComponent | undefined
936
- middleware: MiddlewareClass[]
937
- module: Record<string, unknown>
938
- name: string
939
- urlPath: string
940
- }
941
-
942
872
  interface GroupOptions = {
943
873
  domain?: string
944
874
  middleware?: string | string[] | MiddlewareClass | MiddlewareClass[]
945
875
  prefix?: string
946
876
  }
947
877
 
948
- interface HasResponse = {
949
- response: Response | undefined
950
- }
951
-
952
- interface MiddlewareModule = {
953
- middleware: MiddlewareClass[]
954
- }
955
-
956
878
  interface ModelClass = {
957
879
  findOrFail: (id: number | string) => Promise<unknown>
958
880
  }
@@ -973,28 +895,6 @@ interface ProviderReport = {
973
895
  name: string
974
896
  }
975
897
 
976
- interface QueuedListener = {
977
- handle: (event: T) => Promise<void> | void
978
- maxAttempts?: number
979
- queue: string | boolean
980
- retryDelay?: number
981
- }
982
-
983
- interface RequestIPProvider = {
984
- requestIP: (req: Request) => { address: string; family: string; port: number;} | null
985
- }
986
-
987
- interface ResolvedDevProcess = {
988
- after: 'server' | 'none'
989
- argv?: string[]
990
- color: DevProcessColor
991
- label: string
992
- name: string
993
- registrant: string
994
- restart: 'always' | 'on-failure' | 'never'
995
- run?: (signal: AbortSignal) => Promise<void>
996
- }
997
-
998
898
  interface RouteBuilder = {
999
899
  <N extends RouteTarget>(name: N, params?: RouteParamValues | undefined, query?: RouteQuery | undefined): string
1000
900
  dynamic: (name: string, params?: RouteParamValues, query?: RouteQuery) => string
@@ -1011,34 +911,6 @@ interface RouteDefinition = {
1011
911
  path: string
1012
912
  }
1013
913
 
1014
- interface RouteFileMeta = {
1015
- DELETE?: { name?: string;}
1016
- GET?: { name?: string;}
1017
- PATCH?: { name?: string;}
1018
- POST?: { name?: string;}
1019
- PUT?: { name?: string;}
1020
- }
1021
-
1022
- interface RouteMethodMiddleware = {
1023
- ALL?: MiddlewareClass[]
1024
- DELETE?: MiddlewareClass[]
1025
- GET?: MiddlewareClass[]
1026
- PATCH?: MiddlewareClass[]
1027
- POST?: MiddlewareClass[]
1028
- PUT?: MiddlewareClass[]
1029
- }
1030
-
1031
- interface RouteModule = {
1032
- DELETE?: FileHandler
1033
- GET?: FileHandler
1034
- PATCH?: FileHandler
1035
- POST?: FileHandler
1036
- PUT?: FileHandler
1037
- default?: ViewComponent | FileHandler
1038
- layout?: ViewComponent | null
1039
- middleware?: RouteMiddleware
1040
- }
1041
-
1042
914
  interface RouteRegistration = {
1043
915
  bind: (paramName: string, model: ModelClass | ModelBindingResolver) => RouteRegistration
1044
916
  name: (routeName: string) => RouteRegistration
@@ -1100,38 +972,20 @@ interface WebSocketHandlers = {
1100
972
 
1101
973
  type AppEnvironment = 'web' | 'console' | 'worker' | 'test' | 'repl'
1102
974
 
1103
- type AppScopeInstaller = () => () => void
1104
-
1105
975
  type ArgDef = { name: string; required?: boolean; default?: string;}
1106
976
 
1107
977
  type BindingToken = ClassToken<T> | AbstractToken<T> | keyof ContainerBindings
1108
978
 
1109
- type ContextKey = never
1110
-
1111
- type ContextValue = ContextRegistry[K]
1112
-
1113
979
  type ControllerResponse = void | ResponseBuilder | MarkdownBuilder
1114
980
 
1115
- type CurrentPageResolver = (pageName: string) => number | undefined
1116
-
1117
981
  type DeepPartial = { [K in keyof T]?: (NonNullable<T[K]> extends _Atomic ? T[K] : NonNullable<T[K]> extends object ? DeepPartial<NonNullable<T[K]>> : T[K]) | undefined; }
1118
982
 
1119
- type DevProcessColor = 'cyan' | 'magenta' | 'yellow' | 'green' | 'blue' | 'red'
1120
-
1121
983
  type ErrorDiagnoser = (error: Error, ctx?: HttpContext) => ErrorDiagnosis | null | Promise<ErrorDiagnosis | null>
1122
984
 
1123
985
  type Factory = (container: Container) => T | Promise<T>
1124
986
 
1125
- type FileHandler = (ctx: HttpContext) => void | Response | Promise<void | Response>
1126
-
1127
- type FileRouteHandler = (ctx: HttpContext) => void | Response | Promise<void | Response>
1128
-
1129
- type FileRouteResolver = (ctx: FileRouteContext) => boolean
1130
-
1131
987
  type FileRoutingConfig = { [x: string]: FileRoutingEntry;}
1132
988
 
1133
- type FileRoutingEntry = string | { dir: string; prefix?: string; middleware?: MiddlewareInput }
1134
-
1135
989
  type FlagDef = { name: string; short?: string; type: 'string' | 'boolean' | 'number'; description?: string; default?: unknown;}
1136
990
 
1137
991
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
@@ -1140,8 +994,6 @@ type HttpResponse = Promise<void>
1140
994
 
1141
995
  type MiddlewareClass = new (...args: any[]) => Pipe<HttpContext>
1142
996
 
1143
- type ModelBindingResolver = (value: string, ctx: HttpContext) => Promise<unknown>
1144
-
1145
997
  type NextFn = () => Promise<Response | void>
1146
998
 
1147
999
  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>
@@ -1154,22 +1006,14 @@ type RouteName = never
1154
1006
 
1155
1007
  type RouteParams = { [K in keyof ParamsOf<RoutePattern<N>>]: ParamsOf<RoutePattern<N>>[K]; }
1156
1008
 
1157
- type RouteParamsArg = { [x: string]: RouteParamValue | readonly RouteParamValue[];}
1158
-
1159
- type RouteParamValue = string | number
1160
-
1161
1009
  type RouteParamValues = { [x: string]: RouteParamValue | readonly RouteParamValue[];}
1162
1010
 
1163
- type RoutePattern = N extends never ? RouteRegistry[N] extends string ? RouteRegistry[N] : string : string
1164
-
1165
1011
  type RouteQuery = { [x: string]: string | number | boolean | readonly (string | number | boolean)[] | null | undefined;}
1166
1012
 
1167
1013
  type RouteTarget = string
1168
1014
 
1169
1015
  type RoutingConfig = { [x: string]: RoutingEntry;}
1170
1016
 
1171
- type RoutingEntry = string | { file: string; prefix?: string; middleware?: MiddlewareInput }
1172
-
1173
1017
  type SameSite = 'Strict' | 'Lax' | 'None'
1174
1018
 
1175
1019
  type ViewComponent = (ctx: HttpContext, props: P) => unknown
@@ -2333,6 +2177,8 @@ class ConfigValidationError = {
2333
2177
  readonly status: number
2334
2178
  }
2335
2179
 
2180
+ const CONVENTIONAL_PREFLIGHT_COMMAND = 'release:check'
2181
+
2336
2182
  const DEFAULT_DEPLOY_STEPS = readonly string[]
2337
2183
 
2338
2184
  const DEFAULT_DEPLOY_TARGETS = Record<string, DeployTarget>
@@ -2391,12 +2237,6 @@ interface ConfigRegistry = {
2391
2237
  logging: LoggingConfigShape
2392
2238
  }
2393
2239
 
2394
- interface ConfigValidationContext = {
2395
- config: ConfigManager
2396
- isProduction: boolean
2397
- namespace: string
2398
- }
2399
-
2400
2240
  interface ConventionsConfig = {
2401
2241
  enabled: boolean
2402
2242
  paths: { providers: string; middleware: string; models: string; observers: string; policies: string; listeners: string; events: string; jobs: string; schedules: string; validators: string; commands: string;}
@@ -2407,23 +2247,15 @@ interface DeployConfigShape = {
2407
2247
  }
2408
2248
 
2409
2249
  interface DeployTarget = {
2250
+ preflight?: readonly string[]
2410
2251
  steps?: readonly string[]
2411
2252
  url?: string
2412
2253
  }
2413
2254
 
2414
- interface RegisteredConfigValidator = {
2415
- namespace: string
2416
- validate: ConfigValidator
2417
- }
2418
-
2419
2255
  type AssetLoaderKind = 'file' | 'dataurl' | 'base64' | 'text' | 'json' | 'toml'
2420
2256
 
2421
2257
  type ConfigIssueLevel = 'error' | 'warning'
2422
2258
 
2423
- type ConfigMap = { [x: string]: Record<string, unknown>;}
2424
-
2425
- type ConfigPath = 'lock' | 'app' | 'deploy' | 'health' | 'logging' | 'lock.driver' | 'lock.sqlite' | 'lock.prefix' | 'lock.sqlite.path' | 'app.url' | 'app.name' | 'app.dev' | 'app.port' | 'app.health' | 'app.env' | 'app.key' | 'app.debug' | 'app.locale' | 'app.timezone' | 'app.http3' | 'app.tls' | 'app.maxRequestBodySize' | 'app.allowedOrigins' | 'app.cors' | 'app.throttle' | 'app.secureHeaders' | 'app.assets' | 'app.conventions' | 'app.cors.credentials' | 'app.cors.origin' | 'app.throttle.maxAttempts' | 'app.throttle.windowSeconds' | 'app.secureHeaders.referrerPolicy' | 'app.secureHeaders.frameOptions' | 'app.secureHeaders.secure' | 'app.secureHeaders.hstsMaxAge' | 'app.secureHeaders.hstsIncludeSubDomains' | 'app.secureHeaders.hstsPreload' | 'app.secureHeaders.contentSecurityPolicy' | 'app.conventions.paths' | 'app.conventions.enabled' | 'app.conventions.paths.events' | 'app.conventions.paths.commands' | 'app.conventions.paths.providers' | 'app.conventions.paths.middleware' | 'app.conventions.paths.models' | 'app.conventions.paths.observers' | 'app.conventions.paths.policies' | 'app.conventions.paths.listeners' | 'app.conventions.paths.jobs' | 'app.conventions.paths.schedules' | 'app.conventions.paths.validators' | 'deploy.targets' | `deploy.targets.${string}` | 'health.path' | 'health.enabled' | 'health.secret' | 'health.showDetails' | 'logging.default' | 'logging.file' | 'logging.console' | 'logging.channels' | 'logging.slowQueryMs' | 'logging.requests' | `logging.channels.${string}`
2426
-
2427
2259
  type ConfigValidator = (value: unknown, ctx: ConfigValidationContext) => ConfigIssue[] | void
2428
2260
 
2429
2261
  type ConfigValue = P extends `${infer Head}.${infer Rest}` ? Head extends keyof ConfigRegistry ? ValueAt<ConfigRegistry[Head], Rest> : unknown : P extends keyof ConfigRegistry ? ConfigRegistry[P] : unknown
@@ -2465,75 +2297,6 @@ class DevReloadMiddleware = {
2465
2297
  onError?: (ctx: HttpContext, error: Error) => Promise<void>
2466
2298
  }
2467
2299
 
2468
- class DevSupervisor = {
2469
- new (options: DevSupervisorOptions): DevSupervisor
2470
- definitions: () => ResolvedDevProcess[]
2471
- restart: (name: string) => Promise<void>
2472
- start: (definitions: ResolvedDevProcess[]) => void
2473
- statuses: () => DevProcessStatus[]
2474
- stopAll: () => Promise<void>
2475
- }
2476
-
2477
- class StreamDeck = {
2478
- new (_writer: OutputWriter, _color: boolean): StreamDeck
2479
- line: (name: string, text: string, stream: 'stdout' | 'stderr') => void
2480
- notice: (text: string) => void
2481
- start: (statuses: DevProcessStatus[]) => void
2482
- state: (status: DevProcessStatus) => void
2483
- stop: () => void
2484
- }
2485
-
2486
- class TabsDeck = {
2487
- new (_options: DeckOptions, _stdout: DeckStdout, _stdin: DeckStdin): TabsDeck
2488
- line: (name: string, text: string, stream: 'stdout' | 'stderr') => void
2489
- notice: (text: string) => void
2490
- start: (statuses: DevProcessStatus[]) => void
2491
- state: (status: DevProcessStatus) => void
2492
- stop: () => void
2493
- }
2494
-
2495
- const DEV_RELOAD_CLIENT = string
2496
-
2497
- const SERVER_PROCESS_NAME = 'server'
2498
-
2499
- function bootBuildDecision = (outDirs: string[], env: string | undefined) => Promise<BootBuildDecision>
2500
-
2501
- function buildCssBundle = (input: string, outdir: string, minify?: boolean, loader?: Record<string, string>) => Promise<BundleResult>
2502
-
2503
- function buildJsBundle = (input: string, outdir: string, minify?: boolean) => Promise<BundleResult>
2504
-
2505
- function collectDevProcesses = (app: ProviderHost, config?: ConfigReader) => Promise<ResolvedDevProcess[]>
2506
-
2507
- function createDeck = (options: DeckOptions) => Deck
2508
-
2509
- function detectCssPlugins = (cwd: string) => Promise<BunPlugin[]>
2510
-
2511
- function isWritableDir = (dir: string) => Promise<boolean>
2512
-
2513
- function registerDevHtmlSnippet = (name: string, fn: DevHtmlSnippet) => void
2514
-
2515
- function startDevMode = (options: StartDevModeOptions) => Promise<void>
2516
-
2517
- interface AssetBuildConfig = {
2518
- clean?: boolean
2519
- entrypoint: string | string[]
2520
- loader?: Record<string, string>
2521
- minify: boolean
2522
- outDir: string
2523
- prefix: string
2524
- }
2525
-
2526
- interface BootBuildDecision = {
2527
- build: boolean
2528
- reason?: string
2529
- }
2530
-
2531
- interface BuildResult = {
2532
- logs?: unknown[]
2533
- skipped?: boolean
2534
- success: boolean
2535
- }
2536
-
2537
2300
  interface Deck = {
2538
2301
  line: (name: string, text: string, stream: 'stdout' | 'stderr') => void
2539
2302
  notice: (text: string) => void
@@ -2542,57 +2305,6 @@ interface Deck = {
2542
2305
  stop: () => void
2543
2306
  }
2544
2307
 
2545
- interface DeckOptions = {
2546
- mode?: 'tabs' | 'stream'
2547
- onQuit: () => void
2548
- onRestart: (name: string) => void
2549
- stdin?: DeckStdin
2550
- stdout?: DeckStdout
2551
- writer: OutputWriter
2552
- }
2553
-
2554
- interface DevChild = {
2555
- kill: (signal?: number | NodeJS.Signals) => void
2556
- readonly exited: Promise<number>
2557
- readonly stderr: ReadableStream<Uint8Array<ArrayBufferLike>> | null
2558
- readonly stdout: ReadableStream<Uint8Array<ArrayBufferLike>> | null
2559
- }
2560
-
2561
- interface DevOrchestratorHooks = {
2562
- onCleanup?: () => void | Promise<void>
2563
- onNotice?: (text: string, level: 'info' | 'warn' | 'error') => void
2564
- onServerLine?: (line: string, stream: 'stdout' | 'stderr') => void
2565
- onServerReady?: () => void | Promise<void>
2566
- onServerState?: (state: 'starting' | 'running' | 'restarting' | 'parked') => void
2567
- }
2568
-
2569
- interface DevProcessStatus = {
2570
- attempts: number
2571
- color: DevProcessColor
2572
- exitCode?: number
2573
- label: string
2574
- name: string
2575
- state: DevProcessState
2576
- }
2577
-
2578
- interface DevSupervisorOptions = {
2579
- backoffMs?: number[]
2580
- cwd: string
2581
- env?: Record<string, string | undefined>
2582
- healthyAfterMs?: number
2583
- onLine?: (name: string, line: string, stream: 'stdout' | 'stderr') => void
2584
- onState?: (status: DevProcessStatus) => void
2585
- spawn?: DevSpawnFn
2586
- }
2587
-
2588
- type BuildHookFn = () => Promise<BuildResult>
2589
-
2590
- type DevHtmlSnippet = (ctx: HttpContext) => string
2591
-
2592
- type DevProcessState = 'starting' | 'running' | 'restarting' | 'exited' | 'parked'
2593
-
2594
- type DevSpawnFn = (argv: string[], options: { cwd: string; env: Record<string, string | undefined>;}) => DevChild
2595
-
2596
2308
  ## ./env `(./src/env/index.ts)`
2597
2309
 
2598
2310
  class Def = {
@@ -2754,6 +2466,14 @@ class NotFoundError = {
2754
2466
  readonly status: number
2755
2467
  }
2756
2468
 
2469
+ class RuntimeMismatchError = {
2470
+ new (message: string, mismatch: RuntimeMismatch): RuntimeMismatchError
2471
+ readonly code: string
2472
+ readonly context?: Record<string, unknown> | undefined
2473
+ readonly mismatch: RuntimeMismatch
2474
+ readonly status: number
2475
+ }
2476
+
2757
2477
  class ScopedAfterFlushError = {
2758
2478
  new (message: string): ScopedAfterFlushError
2759
2479
  readonly code: string
@@ -2902,12 +2622,6 @@ function deepMerge = <T extends object>(base: T, override: DeepPartial<T>) => T
2902
2622
 
2903
2623
  function env = { (key: string): string | undefined; (key: string, fallback: string): string; (key: string, fallback: boolean): boolean; (key: string, fallback: number): number;}
2904
2624
 
2905
- function escapeHtml = (value: string) => string
2906
-
2907
- function markdownPage = (title: string, body: string) => string
2908
-
2909
- function parseCookieHeader = (header: string, name: string) => string | undefined
2910
-
2911
2625
  function pipe = <T, R>(value: T, fn: (val: T) => R) => R
2912
2626
 
2913
2627
  function pipeAsync = <T, R>(value: T, fn: (val: T) => Promise<R>) => Promise<R>
@@ -2930,24 +2644,6 @@ function tap = <T>(value: T, callback: (val: T) => void) => T
2930
2644
 
2931
2645
  function tapAsync = <T>(value: T, callback: (val: T) => Promise<void>) => Promise<T>
2932
2646
 
2933
- interface BunMarkdownOptions = {
2934
- autolinks?: boolean | { url?: boolean; www?: boolean; email?: boolean;}
2935
- collapseWhitespace?: boolean
2936
- hardSoftBreaks?: boolean
2937
- headings?: boolean | { ids?: boolean;}
2938
- latexMath?: boolean
2939
- noHtmlBlocks?: boolean
2940
- noHtmlSpans?: boolean
2941
- noIndentedCodeBlocks?: boolean
2942
- permissiveAtxHeaders?: boolean
2943
- strikethrough?: boolean
2944
- tables?: boolean
2945
- tagFilter?: boolean
2946
- tasklists?: boolean
2947
- underline?: boolean
2948
- wikiLinks?: boolean
2949
- }
2950
-
2951
2647
  ## ./http `(./src/http/index.ts)`
2952
2648
 
2953
2649
  class Http = {
@@ -3081,12 +2777,8 @@ class UrlKeyMissingError = {
3081
2777
 
3082
2778
  const Url = UrlGenerator
3083
2779
 
3084
- function isAllowedOrigin = (request: Request, allowedOrigins?: string[]) => boolean
3085
-
3086
2780
  function negotiate = (ctx: HttpContext) => <TWeb = void, TJson = void, TCli = void>(map: NegotiateMap<TWeb, TJson, TCli>) => Promise<TWeb | TJson | TCli | void>
3087
2781
 
3088
- function sniffContentType = (bytes: Uint8Array) => SniffedType
3089
-
3090
2782
  function uri = (value?: string | Uri) => Uri
3091
2783
 
3092
2784
  function url = { (): UrlGenerator; (path: string, extra?: (string | number)[], secure?: boolean): string;}
@@ -3109,13 +2801,6 @@ interface CliContext = {
3109
2801
  writeln: (content: string) => void
3110
2802
  }
3111
2803
 
3112
- interface FakeStub = {
3113
- body?: unknown
3114
- headers?: Record<string, string>
3115
- status?: number
3116
- url: string
3117
- }
3118
-
3119
2804
  interface FileValidationOptions = {
3120
2805
  maxSize?: number
3121
2806
  mimes?: string[]
@@ -3137,20 +2822,6 @@ interface PaginatedData = {
3137
2822
  total: number
3138
2823
  }
3139
2824
 
3140
- interface SniffedType = {
3141
- contentType: string
3142
- extension: string
3143
- recognised: boolean
3144
- }
3145
-
3146
- interface UriQueryString = {
3147
- all: () => Record<string, QueryValue>
3148
- get: (key: string) => string | undefined
3149
- getAll: (key: string) => string[]
3150
- has: (key: string) => boolean
3151
- toString: () => string
3152
- }
3153
-
3154
2825
  interface UrlGenerator = {
3155
2826
  current: () => string
3156
2827
  full: () => string
@@ -3177,8 +2848,6 @@ interface WebContext = {
3177
2848
  view: (markup: string | { toString(): string;}, status?: number) => void
3178
2849
  }
3179
2850
 
3180
- type AnsiColor = 'red' | 'green' | 'yellow' | 'blue' | 'cyan' | 'dim'
3181
-
3182
2851
  type Channel = 'web' | 'json' | 'cli'
3183
2852
 
3184
2853
  type QueryInput = { [x: string]: string | number | boolean | string[];}
@@ -3444,14 +3113,10 @@ type TableData = Record<string, unknown> | ReadonlyArray<Record<string, unknown>
3444
3113
 
3445
3114
  ## ./macros/config `(./src/macros/config.macro.ts)`
3446
3115
 
3447
- function loadConfigsSync = (configDir: string) => Record<string, Record<string, unknown>>
3116
+ _(no exports)_
3448
3117
 
3449
3118
  ## ./metrics `(./src/metrics/index.ts)`
3450
3119
 
3451
- function beginHttp = () => void
3452
-
3453
- function endHttp = () => void
3454
-
3455
3120
  function httpMetrics = () => HttpMetricsSnapshot
3456
3121
 
3457
3122
  function recordHttp = (status: number, ms: number) => void
@@ -3538,6 +3203,50 @@ interface RedactGraphOptions = {
3538
3203
 
3539
3204
  type HashAlgorithm = 'argon2id' | 'argon2i' | 'argon2d' | 'bcrypt'
3540
3205
 
3206
+ ## ./shared `(./src/shared/index.ts)`
3207
+
3208
+ const Str = { camelCase(value: string): string; snakeCase(value: string): string; slugify(value: string): string; titleCase(value: string): string; pascalCase(value: string): string; capitalize(value: string): string; lcfirst(value: string): string; truncate(value: string, maxLength: number, suffix?: string): string; isAlphanumeric(value: string): boolean; padLeft(value: string, length: number, char?: string): string; kebab(value: string): string; squish(value: string): string; finish(value: string, cap: string): string; start(value: string, prefix: string): string; after(value: string, needle: string): string; before(value: string, needle: string): string; afterLast(value: string, needle: string): string; beforeLast(value: string, needle: string): string; contains(value: string, substring: string): boolean; random(length?: number): string; replaceFirst(value: string, search: string, replace: string): string; replaceLast(value: string, search: string, replace: string): string; reverse(value: string): string; words(value: string, maxWords: number, suffix?: string): string; macro(name: string, fn: (...args: unknown[]) => unknown): void;}
3209
+
3210
+ function camelCase = (value: string) => string
3211
+
3212
+ function formatDate = (value: Date | number | string, options?: DateOptions) => string
3213
+
3214
+ function formatMoney = (amount: number, options: MoneyOptions) => string
3215
+
3216
+ function formatNumber = (value: number, options?: NumberOptions) => string
3217
+
3218
+ function pluralize = (value: string) => string
3219
+
3220
+ function singularize = (value: string) => string
3221
+
3222
+ function snakeCase = (value: string) => string
3223
+
3224
+ function tableNameFor = (className: string) => string
3225
+
3226
+ interface DateOptions = {
3227
+ dateStyle?: 'medium' | 'short' | 'full' | 'long'
3228
+ locale?: string
3229
+ timeStyle?: 'medium' | 'short' | 'full' | 'long'
3230
+ timeZone?: string
3231
+ }
3232
+
3233
+ interface FormatOptions = {
3234
+ locale?: string
3235
+ }
3236
+
3237
+ interface MoneyOptions = {
3238
+ currency: string
3239
+ fractionDigits?: number
3240
+ locale?: string
3241
+ minorUnits?: boolean
3242
+ }
3243
+
3244
+ interface NumberOptions = {
3245
+ locale?: string
3246
+ maximumFractionDigits?: number
3247
+ minimumFractionDigits?: number
3248
+ }
3249
+
3541
3250
  ## ./storage `(./src/storage/index.ts)`
3542
3251
 
3543
3252
  class DiskNotConfiguredError = {
@@ -3699,8 +3408,6 @@ class UnsupportedOperationError = {
3699
3408
 
3700
3409
  const Storage = StorageManager
3701
3410
 
3702
- function mountsFrom = (config: StorageConfigShape) => Mount[]
3703
-
3704
3411
  function StorageConfig = (options?: Partial<StorageConfigShape>) => StorageConfigShape
3705
3412
 
3706
3413
  interface DiskServeConfig = {
@@ -3783,10 +3490,6 @@ class SafeHtml = {
3783
3490
  toString: () => string
3784
3491
  }
3785
3492
 
3786
- const VIEW_COMPONENT_PROP = '__zerotalViewComponent'
3787
-
3788
- const VIEW_COMPONENT_SYMBOL = typeof VIEW_COMPONENT_SYMBOL
3789
-
3790
3493
  function defineLayout = <LP extends Record<string, unknown>>(Layout: (props: LP & { children?: unknown;}) => SafeHtml) => <PP extends Record<string, unknown> = Record<string, never>>(Page: (props: PP & { children?: unknown;}) => SafeHtml) => (props: LP & PP) => SafeHtml
3791
3494
 
3792
3495
  function definePage = <P extends Record<string, unknown> = Record<string, unknown>>(component: (ctx: HttpContext, params: P) => SafeHtml | string | Promise<SafeHtml | string>) => typeof component
@@ -3797,8 +3500,6 @@ function Fragment = ({ children }: { children?: unknown;}) => SafeHtml
3797
3500
 
3798
3501
  function Raw = ({ html }: { html: string;}) => SafeHtml
3799
3502
 
3800
- function registerViewFileRouteResolver = () => void
3801
-
3802
3503
  function safe = (html: string) => SafeHtml
3803
3504
 
3804
3505
  type Children = unknown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zerotal/core",
3
- "version": "1.8.0",
3
+ "version": "1.9.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
+ "./shared": "./src/shared/index.ts",
19
20
  "./facades": "./src/facade/facades/index.ts",
20
21
  "./carbon": "./src/datetime/index.ts",
21
22
  "./http": "./src/http/index.ts",