@forinda/kickjs 8.2.0 → 8.3.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.
- package/dist/{adapter-BxXGuLnW.d.mts → adapter-ByxWutTw.d.mts} +3 -3
- package/dist/{adapter-BxXGuLnW.d.mts.map → adapter-ByxWutTw.d.mts.map} +1 -1
- package/dist/{app-module-DoM8RNZ9.d.mts → app-module--bC2V1yw.d.mts} +18 -2
- package/dist/{app-module-DoM8RNZ9.d.mts.map → app-module--bC2V1yw.d.mts.map} +1 -1
- package/dist/{spa-BBwrECcF.d.mts → application-NBph8Ahc.d.mts} +598 -69
- package/dist/application-NBph8Ahc.d.mts.map +1 -0
- package/dist/application-OZSYZy2Z.mjs +12 -0
- package/dist/application-OZSYZy2Z.mjs.map +1 -0
- package/dist/{bootstrap-YxZ7Xitb.mjs → bootstrap-BQrXS6L1.mjs} +3 -3
- package/dist/{bootstrap-YxZ7Xitb.mjs.map → bootstrap-BQrXS6L1.mjs.map} +1 -1
- package/dist/{client-ip-B6kKJLEJ.mjs → client-ip-D5ZBfP_C.mjs} +2 -2
- package/dist/{client-ip-B6kKJLEJ.mjs.map → client-ip-D5ZBfP_C.mjs.map} +1 -1
- package/dist/config/index.mjs +2 -2
- package/dist/{config-Bwgvk__k.mjs → config-DlAZU1Dm.mjs} +3 -3
- package/dist/{config-Bwgvk__k.mjs.map → config-DlAZU1Dm.mjs.map} +1 -1
- package/dist/{container-BnkQIDQF.mjs → container-DzwyumEo.mjs} +3 -3
- package/dist/{container-BnkQIDQF.mjs.map → container-DzwyumEo.mjs.map} +1 -1
- package/dist/{context-GJc8Pf2d.mjs → context-3SqXUyOr.mjs} +3 -3
- package/dist/{context-GJc8Pf2d.mjs.map → context-3SqXUyOr.mjs.map} +1 -1
- package/dist/{context-errors-Bm1GxsOQ.mjs → context-errors-CpTVAtA_.mjs} +2 -2
- package/dist/{context-errors-Bm1GxsOQ.mjs.map → context-errors-CpTVAtA_.mjs.map} +1 -1
- package/dist/{contributor-runner-CzL4-aIt.mjs → contributor-runner-CX6InEzw.mjs} +3 -3
- package/dist/{contributor-runner-CzL4-aIt.mjs.map → contributor-runner-CX6InEzw.mjs.map} +1 -1
- package/dist/core/adapter.d.mts +1 -1
- package/dist/core/adapter.mjs +1 -1
- package/dist/core/app-module.d.mts +1 -1
- package/dist/core/app-module.mjs +1 -1
- package/dist/core/cache.mjs +1 -1
- package/dist/core/container.mjs +2 -2
- package/dist/core/cron.mjs +2 -2
- package/dist/core/decorators.mjs +2 -2
- package/dist/core/errors.mjs +1 -1
- package/dist/core/interfaces.mjs +1 -1
- package/dist/core/logger.mjs +1 -1
- package/dist/core/path.mjs +1 -1
- package/dist/core/plugin.d.mts +1 -1
- package/dist/core/plugin.mjs +1 -1
- package/dist/core/reactivity.mjs +1 -1
- package/dist/{core-w7s4ntck.mjs → core-CsxP6Jec.mjs} +3 -3
- package/dist/{core-w7s4ntck.mjs.map → core-CsxP6Jec.mjs.map} +1 -1
- package/dist/{csrf-BjmtOJZs.mjs → csrf-BdKFFh14.mjs} +3 -3
- package/dist/{csrf-BjmtOJZs.mjs.map → csrf-BdKFFh14.mjs.map} +1 -1
- package/dist/{csrf-COqPWlMd.d.mts → csrf-DDwUOF45.d.mts} +2 -2
- package/dist/{csrf-COqPWlMd.d.mts.map → csrf-DDwUOF45.d.mts.map} +1 -1
- package/dist/{decorate-CpBbxrvT.mjs → decorate-BGm37ho8.mjs} +1 -1
- package/dist/{define-adapter-whaSQuNs.mjs → define-adapter-CpUxOgQ-.mjs} +2 -2
- package/dist/{define-adapter-whaSQuNs.mjs.map → define-adapter-CpUxOgQ-.mjs.map} +1 -1
- package/dist/{disposables-lWieeJLG.mjs → disposables-Pouc1-v2.mjs} +2 -2
- package/dist/{disposables-lWieeJLG.mjs.map → disposables-Pouc1-v2.mjs.map} +1 -1
- package/dist/{env-Bd6akCGH.mjs → env-BYseGI8D.mjs} +3 -3
- package/dist/{env-Bd6akCGH.mjs.map → env-BYseGI8D.mjs.map} +1 -1
- package/dist/{error-handler-DMUz6X18.d.mts → error-handler-BtTYsKLV.d.mts} +2 -2
- package/dist/{error-handler-DMUz6X18.d.mts.map → error-handler-BtTYsKLV.d.mts.map} +1 -1
- package/dist/{handler-gK6lNZKW.mjs → handler-s-wYH8Kk.mjs} +3 -3
- package/dist/{handler-gK6lNZKW.mjs.map → handler-s-wYH8Kk.mjs.map} +1 -1
- package/dist/http/application.d.mts +1 -1
- package/dist/http/application.mjs +2 -2
- package/dist/http/bootstrap.d.mts +1 -1
- package/dist/http/bootstrap.mjs +2 -2
- package/dist/http/context.d.mts +2 -2
- package/dist/http/context.mjs +2 -2
- package/dist/http/middleware/cors.mjs +1 -1
- package/dist/http/middleware/csrf.d.mts +1 -1
- package/dist/http/middleware/csrf.mjs +2 -2
- package/dist/http/middleware/error-handler.d.mts +1 -1
- package/dist/http/middleware/error-handler.mjs +2 -2
- package/dist/http/middleware/helmet.mjs +1 -1
- package/dist/http/middleware/rate-limit.d.mts +1 -1
- package/dist/http/middleware/rate-limit.mjs +2 -2
- package/dist/http/middleware/request-id.mjs +1 -1
- package/dist/http/middleware/request-logger.mjs +2 -2
- package/dist/http/middleware/session.mjs +2 -2
- package/dist/http/middleware/spa.d.mts +1 -1
- package/dist/http/middleware/spa.mjs +2 -2
- package/dist/http/middleware/upload.d.mts +1 -1
- package/dist/http/middleware/upload.mjs +2 -2
- package/dist/http/middleware/validate.mjs +1 -1
- package/dist/http/middleware/views.d.mts +1 -1
- package/dist/http/middleware/views.mjs +2 -2
- package/dist/http/query/index.mjs +2 -2
- package/dist/http/router-builder.d.mts +1 -1
- package/dist/http/router-builder.mjs +2 -2
- package/dist/http/runtimes/fastify.d.mts +1 -1
- package/dist/http/runtimes/fastify.mjs +2 -2
- package/dist/http/runtimes/h3-web.d.mts +1 -1
- package/dist/http/runtimes/h3-web.mjs +2 -2
- package/dist/http/runtimes/h3.d.mts +1 -1
- package/dist/http/runtimes/h3.mjs +2 -2
- package/dist/index.d.mts +14 -16
- package/dist/index.mjs +2 -2
- package/dist/{kv-stores-Bp4_RP-e.mjs → kv-stores-DClxfUzF.mjs} +3 -3
- package/dist/{kv-stores-Bp4_RP-e.mjs.map → kv-stores-DClxfUzF.mjs.map} +1 -1
- package/dist/{kv-stores-sjVe0MqN.d.mts → kv-stores-DR4ZHDht.d.mts} +4 -4
- package/dist/{kv-stores-sjVe0MqN.d.mts.map → kv-stores-DR4ZHDht.d.mts.map} +1 -1
- package/dist/{metadata-DRRQ0p_l.mjs → metadata-DvU1KnZD.mjs} +2 -2
- package/dist/{metadata-DRRQ0p_l.mjs.map → metadata-DvU1KnZD.mjs.map} +1 -1
- package/dist/{module-registry-C7yEmbZ8.mjs → module-registry-sxthbE3E.mjs} +2 -2
- package/dist/{module-registry-C7yEmbZ8.mjs.map → module-registry-sxthbE3E.mjs.map} +1 -1
- package/dist/{query-BSp_RIR0.mjs → query-BsOSNlUY.mjs} +2 -2
- package/dist/{query-BSp_RIR0.mjs.map → query-BsOSNlUY.mjs.map} +1 -1
- package/dist/{rate-limit-CzFoSCzS.d.mts → rate-limit-D5FHbYKG.d.mts} +2 -2
- package/dist/{rate-limit-CzFoSCzS.d.mts.map → rate-limit-D5FHbYKG.d.mts.map} +1 -1
- package/dist/{respond-BygP3p23.mjs → respond-Bqj4ktsY.mjs} +2 -2
- package/dist/{respond-BygP3p23.mjs.map → respond-Bqj4ktsY.mjs.map} +1 -1
- package/dist/{route-flag-GzEeUmws.d.mts → route-flag-BMlwj3Nk.d.mts} +22 -6
- package/dist/route-flag-BMlwj3Nk.d.mts.map +1 -0
- package/dist/route-flag-BsEtXxzP.mjs +12 -0
- package/dist/route-flag-BsEtXxzP.mjs.map +1 -0
- package/dist/{route-policy-D5lQltyg.mjs → route-policy-TDd9n2Q-.mjs} +2 -2
- package/dist/{route-policy-D5lQltyg.mjs.map → route-policy-TDd9n2Q-.mjs.map} +1 -1
- package/dist/router-builder-CfSWFOxm.mjs +12 -0
- package/dist/router-builder-CfSWFOxm.mjs.map +1 -0
- package/dist/{router-builder-eLpJYyrb.d.mts → router-builder-DZxYbs5I.d.mts} +9 -2
- package/dist/router-builder-DZxYbs5I.d.mts.map +1 -0
- package/dist/{runtime-B3fCMmZW.mjs → runtime-Cn74iFYv.mjs} +3 -3
- package/dist/{runtime-B3fCMmZW.mjs.map → runtime-Cn74iFYv.mjs.map} +1 -1
- package/dist/{upload-yKvKdRWG.d.mts → upload-BjA0m0ov.d.mts} +2 -2
- package/dist/{upload-yKvKdRWG.d.mts.map → upload-BjA0m0ov.d.mts.map} +1 -1
- package/dist/{upload-config-CP5v2Fh-.mjs → upload-config-dNLJaVlD.mjs} +2 -2
- package/dist/{upload-config-CP5v2Fh-.mjs.map → upload-config-dNLJaVlD.mjs.map} +1 -1
- package/dist/web.d.mts +3 -3
- package/dist/web.mjs +2 -2
- package/dist/web.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/application-NjKJPm9r.d.mts +0 -495
- package/dist/application-NjKJPm9r.d.mts.map +0 -1
- package/dist/application-blu78Mlf.mjs +0 -12
- package/dist/application-blu78Mlf.mjs.map +0 -1
- package/dist/bootstrap-Sjn3hPqw.d.mts +0 -27
- package/dist/bootstrap-Sjn3hPqw.d.mts.map +0 -1
- package/dist/route-flag-GzEeUmws.d.mts.map +0 -1
- package/dist/route-flag-vuWGpI1V.mjs +0 -12
- package/dist/route-flag-vuWGpI1V.mjs.map +0 -1
- package/dist/router-builder-HeSJZ2QG.mjs +0 -12
- package/dist/router-builder-HeSJZ2QG.mjs.map +0 -1
- package/dist/router-builder-eLpJYyrb.d.mts.map +0 -1
- package/dist/spa-BBwrECcF.d.mts.map +0 -1
|
@@ -1,495 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { t as Container } from "./container-Dpvd66Yt.mjs";
|
|
3
|
-
import { m as ContributorRegistrations, r as AppModuleEntry } from "./app-module-DoM8RNZ9.mjs";
|
|
4
|
-
import { b as RuntimeCapabilities, f as HttpRuntime, lt as KickPlugin, r as AppAdapter, s as ActiveRuntime, ut as ModuleRegistry, x as RuntimeResponse } from "./adapter-BxXGuLnW.mjs";
|
|
5
|
-
import http from "node:http";
|
|
6
|
-
import { Express, RequestHandler } from "express";
|
|
7
|
-
//#region src/http/application.d.ts
|
|
8
|
-
/**
|
|
9
|
-
* A middleware entry in the declarative pipeline.
|
|
10
|
-
* Can be a bare handler or an object with path scoping.
|
|
11
|
-
*/
|
|
12
|
-
type MiddlewareEntry = RequestHandler | {
|
|
13
|
-
path: string;
|
|
14
|
-
handler: RequestHandler;
|
|
15
|
-
};
|
|
16
|
-
/** Options for {@link Application.shutdown}. */
|
|
17
|
-
interface ShutdownOptions {
|
|
18
|
-
/**
|
|
19
|
-
* Close the HTTP server and drain in-flight requests. Default `true`.
|
|
20
|
-
*
|
|
21
|
-
* Set `false` for a dev HMR rebuild, where the server is shared across
|
|
22
|
-
* reloads — adapters, plugins, and disposables are still torn down, which is
|
|
23
|
-
* the part a reload needs.
|
|
24
|
-
*/
|
|
25
|
-
closeServer?: boolean;
|
|
26
|
-
}
|
|
27
|
-
interface ApplicationOptions {
|
|
28
|
-
/**
|
|
29
|
-
* Feature modules to load. Accepts both class form
|
|
30
|
-
* (`SomeModule extends AppModule`, instantiated via `new`) and
|
|
31
|
-
* instance form (output of {@link defineModule}'s factory call,
|
|
32
|
-
* e.g. `TasksModule({ scope: 'admin' })`) — the loader discriminates
|
|
33
|
-
* and either `new`-s the class or uses the instance directly.
|
|
34
|
-
*
|
|
35
|
-
* Static path — for conditional / dynamic registration, use the
|
|
36
|
-
* {@link ApplicationOptions.setup} callback instead.
|
|
37
|
-
*/
|
|
38
|
-
modules: AppModuleEntry[];
|
|
39
|
-
/**
|
|
40
|
-
* Imperative module registration callback. Receives a
|
|
41
|
-
* {@link ModuleRegistry} you call `.mount(module)` on to register
|
|
42
|
-
* modules conditionally — based on env flags, runtime config, a
|
|
43
|
-
* tenant list, etc. Runs after every plugin's `setup()` hook and
|
|
44
|
-
* after the static `modules: [...]` array is collected.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```ts
|
|
48
|
-
* bootstrap({
|
|
49
|
-
* modules: [HelloModule()],
|
|
50
|
-
* setup(registry) {
|
|
51
|
-
* if (env.ENABLE_ADMIN) registry.mount(AdminModule())
|
|
52
|
-
* },
|
|
53
|
-
* })
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
setup?(registry: ModuleRegistry): void;
|
|
57
|
-
/** Adapters that hook into the lifecycle (DB, Redis, Swagger, etc.) */
|
|
58
|
-
adapters?: AppAdapter[];
|
|
59
|
-
/** Server port (falls back to PORT env var, then 3000) */
|
|
60
|
-
port?: number;
|
|
61
|
-
/** Global API prefix (default: '/api'). Pass `''` to mount at the root. */
|
|
62
|
-
apiPrefix?: string;
|
|
63
|
-
/**
|
|
64
|
-
* Default API version (default: 1) — routes become /{prefix}/v{version}/{path}.
|
|
65
|
-
*
|
|
66
|
-
* `false` opts out of URL versioning: routes mount at /{prefix}/{path}.
|
|
67
|
-
* A module can still version itself by setting `version` on its
|
|
68
|
-
* `ModuleRoutes` — the per-mount value always wins over this default, in
|
|
69
|
-
* either direction.
|
|
70
|
-
*/
|
|
71
|
-
defaultVersion?: number | false;
|
|
72
|
-
/**
|
|
73
|
-
* Global middleware pipeline. Declared in order.
|
|
74
|
-
* Replaces the hardcoded middleware stack — you control exactly what runs.
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* ```ts
|
|
78
|
-
* bootstrap({
|
|
79
|
-
* modules,
|
|
80
|
-
* middlewares: [
|
|
81
|
-
* helmet(),
|
|
82
|
-
* cors(),
|
|
83
|
-
* compression(),
|
|
84
|
-
* morgan('dev'),
|
|
85
|
-
* express.json({ limit: '1mb' }),
|
|
86
|
-
* ],
|
|
87
|
-
* })
|
|
88
|
-
* ```
|
|
89
|
-
*
|
|
90
|
-
* If omitted, a sensible default is applied:
|
|
91
|
-
* requestId(), express.json({ limit: '100kb' })
|
|
92
|
-
*/
|
|
93
|
-
middlewares?: MiddlewareEntry[];
|
|
94
|
-
/** Plugins that bundle modules, adapters, middleware, and DI bindings */
|
|
95
|
-
plugins?: KickPlugin[];
|
|
96
|
-
/**
|
|
97
|
-
* Global Context Contributors (#107) that apply to every route in the
|
|
98
|
-
* application. Merge into the per-route pipeline at the `'global'`
|
|
99
|
-
* precedence level — they lose to module, adapter, class, and method
|
|
100
|
-
* contributors with the same key, providing app-wide defaults that any
|
|
101
|
-
* narrower scope can override.
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* ```ts
|
|
105
|
-
* const StartedAt = defineContextDecorator({
|
|
106
|
-
* key: 'requestStartedAt',
|
|
107
|
-
* resolve: () => Date.now(),
|
|
108
|
-
* })
|
|
109
|
-
*
|
|
110
|
-
* bootstrap({
|
|
111
|
-
* modules,
|
|
112
|
-
* contributors: [StartedAt.registration],
|
|
113
|
-
* })
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
contributors?: ContributorRegistrations;
|
|
117
|
-
/**
|
|
118
|
-
* Backing store strategy for {@link RequestContext} `set/get` and the
|
|
119
|
-
* Context Contributor pipeline (#107).
|
|
120
|
-
*
|
|
121
|
-
* - `'auto'` (default) — Application mounts {@link requestScopeMiddleware}
|
|
122
|
-
* automatically before any user middleware. If the user-supplied
|
|
123
|
-
* `middleware` list already includes `requestScopeMiddleware()`,
|
|
124
|
-
* detection skips the auto-mount so adopters can control its position.
|
|
125
|
-
* - `'manual'` — Application never mounts the wrapper. The Context
|
|
126
|
-
* Contributor pipeline still runs on every route — the runner is
|
|
127
|
-
* inserted by `router-builder` regardless of ALS state. What
|
|
128
|
-
* degrades without an ALS frame is the *backing store*:
|
|
129
|
-
* REQUEST-scoped DI throws (no `requestStore.getStore()` to read
|
|
130
|
-
* from) and `RequestContext.set/get` throws. Use `'manual'` only when you
|
|
131
|
-
* genuinely intend to wrap requests in your own ALS frame (rare —
|
|
132
|
-
* multi-tenant adapters used to do this; post-Phase 3 they share
|
|
133
|
-
* the framework's frame instead).
|
|
134
|
-
*/
|
|
135
|
-
contextStore?: 'auto' | 'manual';
|
|
136
|
-
/**
|
|
137
|
-
* Controls whether KickJS registers process-level handlers at bootstrap.
|
|
138
|
-
*
|
|
139
|
-
* - `'auto'` (default) — register `uncaughtException` /
|
|
140
|
-
* `unhandledRejection` loggers AND `SIGINT` / `SIGTERM` →
|
|
141
|
-
* `app.shutdown()` → `process.exit(0)`.
|
|
142
|
-
* - `'errors-only'` — register the error loggers; skip the signal
|
|
143
|
-
* handlers. Use this when you have your own shutdown choreographer
|
|
144
|
-
* (OpenTelemetry SDK, Sentry, custom orchestrator) that calls
|
|
145
|
-
* `app.shutdown()` itself and you don't want two listeners racing
|
|
146
|
-
* to call `process.exit`.
|
|
147
|
-
* - `'manual'` — skip everything. Adopter is responsible for both
|
|
148
|
-
* error logging and signal-driven shutdown.
|
|
149
|
-
*
|
|
150
|
-
* Background: many observability SDKs install their own SIGTERM
|
|
151
|
-
* handler to flush spans/metrics before the process exits. Two
|
|
152
|
-
* separate handlers calling `process.exit(0)` race each other and
|
|
153
|
-
* can truncate the in-flight flush. Setting this to `'errors-only'`
|
|
154
|
-
* or `'manual'` lets the SDK own the lifecycle while still letting
|
|
155
|
-
* KickJS surface uncaught exceptions / rejections via the logger.
|
|
156
|
-
*
|
|
157
|
-
* The dev mode auto-detect (`__kickjs_httpServer` set by the Vite
|
|
158
|
-
* plugin) suppresses signal registration regardless of this option,
|
|
159
|
-
* since Vite owns the lifecycle in development.
|
|
160
|
-
*/
|
|
161
|
-
processHooks?: 'auto' | 'errors-only' | 'manual';
|
|
162
|
-
/**
|
|
163
|
-
* The HTTP engine driver. Defaults to {@link expressRuntime} — Express stays
|
|
164
|
-
* the zero-config default, so existing apps are unaffected.
|
|
165
|
-
*
|
|
166
|
-
* Any `HttpRuntime` is accepted — pass `fastifyRuntime()` (from
|
|
167
|
-
* `@forinda/kickjs/fastify`) or a custom engine driver. Defaults to
|
|
168
|
-
* {@link expressRuntime}. The engine-native escape hatches
|
|
169
|
-
* (`getRuntimeApp()`, `AdapterContext.app`) follow the active runtime via the
|
|
170
|
-
* registry (`ActiveRuntime`, spec §4.3b) — Express by default, or the augmented
|
|
171
|
-
* engine once the `kick/runtime` typegen output is present.
|
|
172
|
-
*/
|
|
173
|
-
/**
|
|
174
|
-
* Mount the built-in `GET /health/live` and `GET /health/ready`.
|
|
175
|
-
*
|
|
176
|
-
* On by default. Set `false` to take them over completely — supply your own
|
|
177
|
-
* module at `/health` and nothing collides. The built-in is registered last,
|
|
178
|
-
* so an app module claiming the same path already wins without this.
|
|
179
|
-
*
|
|
180
|
-
* They mount as an ordinary module, which means they sit inside the
|
|
181
|
-
* middleware chain: whatever guards the rest of the app guards these too.
|
|
182
|
-
* Exempt the path if your orchestrator must reach them unauthenticated.
|
|
183
|
-
*/
|
|
184
|
-
health?: boolean;
|
|
185
|
-
runtime?: HttpRuntime;
|
|
186
|
-
/** Express `trust proxy` setting */
|
|
187
|
-
trustProxy?: boolean | number | string | ((ip: string, hopIndex: number) => boolean);
|
|
188
|
-
/** Maximum JSON body size (only used when middleware is not provided) */
|
|
189
|
-
jsonLimit?: string | number;
|
|
190
|
-
/**
|
|
191
|
-
* Print the route table on startup. Default: `false`. Set to `true`
|
|
192
|
-
* to log a per-controller summary (method counts + mount paths) once
|
|
193
|
-
* the app has mounted. Emitted at `info` level, so it is still subject
|
|
194
|
-
* to `LOG_LEVEL` filtering (visible at the default `info`; hidden at
|
|
195
|
-
* `warn`/`error`/`silent`).
|
|
196
|
-
*/
|
|
197
|
-
logRouteTable?: boolean;
|
|
198
|
-
/**
|
|
199
|
-
* @deprecated Use {@link ApplicationOptions.logRouteTable}. Kept as an
|
|
200
|
-
* alias for back-compat; `logRouteTable` wins when both are set.
|
|
201
|
-
*/
|
|
202
|
-
logRoutesTable?: boolean;
|
|
203
|
-
/**
|
|
204
|
-
* Maximum time (ms) to wait for graceful shutdown before forcing exit.
|
|
205
|
-
* Default: 30000 (30 seconds). Set to 0 to disable forced exit.
|
|
206
|
-
*/
|
|
207
|
-
shutdownTimeout?: number;
|
|
208
|
-
/**
|
|
209
|
-
* Enable cluster mode for multi-core utilization.
|
|
210
|
-
*
|
|
211
|
-
* When enabled, the primary process forks worker processes that share the
|
|
212
|
-
* same port via Node's built-in `cluster` module (OS load balancing).
|
|
213
|
-
*
|
|
214
|
-
* - `true` — use all available CPU cores
|
|
215
|
-
* - `{ workers: N }` — use exactly N workers
|
|
216
|
-
*
|
|
217
|
-
* Workers are auto-restarted on crash. SIGTERM/SIGINT on the primary is
|
|
218
|
-
* forwarded to all workers.
|
|
219
|
-
*
|
|
220
|
-
* @example
|
|
221
|
-
* ```ts
|
|
222
|
-
* bootstrap({ modules, cluster: true })
|
|
223
|
-
* bootstrap({ modules, cluster: { workers: 4 } })
|
|
224
|
-
* ```
|
|
225
|
-
*/
|
|
226
|
-
cluster?: boolean | {
|
|
227
|
-
workers?: number;
|
|
228
|
-
};
|
|
229
|
-
/**
|
|
230
|
-
* Custom 404 handler for unmatched routes. When omitted, the built-in
|
|
231
|
-
* handler returns `{ message: 'Not Found' }` with status 404.
|
|
232
|
-
*
|
|
233
|
-
* Connect-**shaped**, not Express-**semantic** — see {@link onError} for the
|
|
234
|
-
* per-runtime table. The same two caveats apply: `next()` is inert on
|
|
235
|
-
* Fastify and h3, and Express-only request members (`req.originalUrl`,
|
|
236
|
-
* `req.path`, `req.ip`) are `undefined` there, so read `req.url`.
|
|
237
|
-
*
|
|
238
|
-
* @example
|
|
239
|
-
* ```ts
|
|
240
|
-
* bootstrap({
|
|
241
|
-
* modules,
|
|
242
|
-
* onNotFound: (req, res) => {
|
|
243
|
-
* // `req.originalUrl` is Express-only — use `req.url` for portability.
|
|
244
|
-
* res.status(404).json({ error: 'Route not found', path: req.url })
|
|
245
|
-
* },
|
|
246
|
-
* })
|
|
247
|
-
* ```
|
|
248
|
-
*/
|
|
249
|
-
onNotFound?: (req: any, res: RuntimeResponse, next: (err?: unknown) => void) => void;
|
|
250
|
-
/**
|
|
251
|
-
* Custom global error handler, receiving `(err, req, res, next)`. When
|
|
252
|
-
* omitted, the built-in handler formats ZodError, HttpException, and
|
|
253
|
-
* unexpected errors.
|
|
254
|
-
*
|
|
255
|
-
* The shape is connect-style, but it is NOT "the standard Express error
|
|
256
|
-
* handler" on every engine — what you actually receive differs, and the
|
|
257
|
-
* differences bite:
|
|
258
|
-
*
|
|
259
|
-
* | | `req` | `res` | `next` |
|
|
260
|
-
* | --- | --- | --- | --- |
|
|
261
|
-
* | Express | native `Request` | native `Response` | real `next` |
|
|
262
|
-
* | Fastify | `request.raw` | reply driver | **no-op** |
|
|
263
|
-
* | h3 | `event.node.req` | response driver | no-op (or dev fall-through) |
|
|
264
|
-
*
|
|
265
|
-
* Two consequences worth knowing before you write one:
|
|
266
|
-
*
|
|
267
|
-
* - **`next(err)` does nothing on Fastify and h3.** It is a no-op function
|
|
268
|
-
* there, so delegating to the default handler silently drops the error.
|
|
269
|
-
* Send a response yourself rather than passing it on.
|
|
270
|
-
* - **Express-only request members are `undefined` elsewhere.**
|
|
271
|
-
* `req.originalUrl`, `req.path`, and `req.ip` do not exist on the raw node
|
|
272
|
-
* request — use `req.url` and the `x-forwarded-*` headers, or reach for
|
|
273
|
-
* `ctx.ip` in a contributor / guard where a `RequestContext` is available.
|
|
274
|
-
*
|
|
275
|
-
* `res` is typed {@link RuntimeResponse} because that is what every engine
|
|
276
|
-
* genuinely provides: `status`, `json`, `send`, `setHeader`, `render`,
|
|
277
|
-
* `writeHead`, `end`. Express's own `Response` satisfies it.
|
|
278
|
-
*
|
|
279
|
-
* @example
|
|
280
|
-
* ```ts
|
|
281
|
-
* bootstrap({
|
|
282
|
-
* modules,
|
|
283
|
-
* onError: (err, req, res) => {
|
|
284
|
-
* logger.error(err, `${req.method} ${req.url}`) // not `originalUrl`
|
|
285
|
-
* res.status(err.status ?? 500).json({ error: err.message })
|
|
286
|
-
* },
|
|
287
|
-
* })
|
|
288
|
-
* ```
|
|
289
|
-
*/
|
|
290
|
-
onError?: (err: any, req: any, res: RuntimeResponse, next: (err?: unknown) => void) => void;
|
|
291
|
-
/**
|
|
292
|
-
* Security defaults applied automatically unless opted out.
|
|
293
|
-
*
|
|
294
|
-
* When not specified, secure defaults are applied:
|
|
295
|
-
* - Helmet security headers are auto-injected
|
|
296
|
-
* - JSON body limit defaults to 1MB
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* ```ts
|
|
300
|
-
* bootstrap({
|
|
301
|
-
* modules,
|
|
302
|
-
* security: {
|
|
303
|
-
* helmet: false, // disable auto-helmet
|
|
304
|
-
* },
|
|
305
|
-
* })
|
|
306
|
-
* ```
|
|
307
|
-
*/
|
|
308
|
-
security?: {
|
|
309
|
-
/** Auto-inject helmet security headers. Default: true */
|
|
310
|
-
helmet?: boolean;
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
declare class Application {
|
|
314
|
-
private readonly options;
|
|
315
|
-
private app;
|
|
316
|
-
/** The HTTP engine driver. Defaults to {@link expressRuntime}. */
|
|
317
|
-
private readonly runtime;
|
|
318
|
-
private container;
|
|
319
|
-
private httpServer;
|
|
320
|
-
private readonly adapters;
|
|
321
|
-
/**
|
|
322
|
-
* Flags of every mounted route, for middleware that runs before routing and
|
|
323
|
-
* therefore cannot read `ctx.route` (the connect-style rate limiter). Handed
|
|
324
|
-
* to middleware that declares the slot — see `core/route-policy.ts`.
|
|
325
|
-
*/
|
|
326
|
-
private readonly routePolicy;
|
|
327
|
-
private readonly plugins;
|
|
328
|
-
/**
|
|
329
|
-
* Snapshot of every module-level Context Contributor registration
|
|
330
|
-
* captured during `setup()`. The registrations themselves are
|
|
331
|
-
* frozen by `defineContextDecorator`, so storing references is
|
|
332
|
-
* safe — they outlive the module instances they came from.
|
|
333
|
-
*
|
|
334
|
-
* Used by {@link getContributors} so DevTools and adopter tooling
|
|
335
|
-
* can render the module-level contributors alongside the adapter /
|
|
336
|
-
* plugin / global ones. Populated once per `setup()` call; cleared
|
|
337
|
-
* at the start of each invocation so a re-setup (test harnesses,
|
|
338
|
-
* dev-server restarts) doesn't accumulate stale entries.
|
|
339
|
-
*/
|
|
340
|
-
private _moduleContributors;
|
|
341
|
-
/** Number of HTTP requests currently being processed */
|
|
342
|
-
private _inFlightRequests;
|
|
343
|
-
/** Whether the application is draining (shutting down gracefully) */
|
|
344
|
-
private _draining;
|
|
345
|
-
/** Whether shutdown has already been initiated (prevents double-shutdown) */
|
|
346
|
-
private _shutdownInitiated;
|
|
347
|
-
/** Resolvers waiting for in-flight requests to reach zero */
|
|
348
|
-
private _drainResolvers;
|
|
349
|
-
constructor(options: ApplicationOptions);
|
|
350
|
-
/** Whether the application is currently draining in-flight requests */
|
|
351
|
-
get isDraining(): boolean;
|
|
352
|
-
/** Number of HTTP requests currently being processed */
|
|
353
|
-
get inFlightRequests(): number;
|
|
354
|
-
/** Get the DI container instance */
|
|
355
|
-
getContainer(): Container;
|
|
356
|
-
/**
|
|
357
|
-
* Express request handler — delegates to the internal Express app.
|
|
358
|
-
*
|
|
359
|
-
* Used by the Vite dev-server plugin to route requests through KickJS:
|
|
360
|
-
* ```ts
|
|
361
|
-
* const mod = await ssrLoadModule('virtual:kickjs/app')
|
|
362
|
-
* mod.app.handle(req, res, next)
|
|
363
|
-
* ```
|
|
364
|
-
*
|
|
365
|
-
* Also works as a standard Node.js request handler for production:
|
|
366
|
-
* ```ts
|
|
367
|
-
* http.createServer(app.handle.bind(app))
|
|
368
|
-
* ```
|
|
369
|
-
*/
|
|
370
|
-
handle(req: http.IncomingMessage, res: http.ServerResponse, next?: (err?: any) => void): void;
|
|
371
|
-
/**
|
|
372
|
-
* Full setup pipeline:
|
|
373
|
-
* 1. Adapter beforeMount hooks (early routes — docs, health)
|
|
374
|
-
* 2. Adapter middleware (phase: beforeGlobal)
|
|
375
|
-
* 3. Global middleware (user-declared or defaults)
|
|
376
|
-
* 4. Adapter middleware (phase: afterGlobal)
|
|
377
|
-
* 5. Module registration + DI bootstrap
|
|
378
|
-
* 6. Adapter middleware (phase: beforeRoutes)
|
|
379
|
-
* 7. Module route mounting
|
|
380
|
-
* 8. Adapter middleware (phase: afterRoutes)
|
|
381
|
-
* 9. Error handlers (notFound + global)
|
|
382
|
-
* 10. Adapter beforeStart hooks
|
|
383
|
-
*/
|
|
384
|
-
/** Build the adapter context object (shared across all hooks) */
|
|
385
|
-
private adapterCtx;
|
|
386
|
-
/**
|
|
387
|
-
* The engine-agnostic HTTP surface handed to adapters as `ctx.http`. Each
|
|
388
|
-
* call routes through the active runtime over the current `this.app`, so an
|
|
389
|
-
* adapter written against this works under any runtime.
|
|
390
|
-
*/
|
|
391
|
-
private adapterHttp;
|
|
392
|
-
/** Call an adapter hook, awaiting async hooks and catching errors */
|
|
393
|
-
private callHook;
|
|
394
|
-
setup(): Promise<void>;
|
|
395
|
-
/** Register modules and DI without starting the HTTP server (used by kick tinker) */
|
|
396
|
-
registerOnly(): Promise<void>;
|
|
397
|
-
/**
|
|
398
|
-
* Start the HTTP server.
|
|
399
|
-
*
|
|
400
|
-
* In **dev mode** (Vite plugin active): reuses `globalThis.__kickjs_httpServer`
|
|
401
|
-
* created by Vite. Adapters (WsAdapter, Socket.IO, etc.) receive the real
|
|
402
|
-
* `http.Server` through `afterStart({ server })` — zero adapter changes needed.
|
|
403
|
-
*
|
|
404
|
-
* In **production**: creates its own `http.Server` and binds to the port.
|
|
405
|
-
*/
|
|
406
|
-
start(): Promise<void>;
|
|
407
|
-
/** HMR rebuild: swap Express handler without restarting the server */
|
|
408
|
-
rebuild(): Promise<void>;
|
|
409
|
-
/**
|
|
410
|
-
* Graceful shutdown with request draining.
|
|
411
|
-
*
|
|
412
|
-
* 1. Stops accepting new connections (server.close())
|
|
413
|
-
* 2. Waits for in-flight requests to complete (up to shutdownTimeout)
|
|
414
|
-
* 3. Calls adapter.shutdown() for all registered adapters
|
|
415
|
-
* 4. Force-closes after timeout
|
|
416
|
-
*
|
|
417
|
-
* Safe to call multiple times — subsequent calls return the same promise.
|
|
418
|
-
*/
|
|
419
|
-
shutdown(options?: ShutdownOptions): Promise<void>;
|
|
420
|
-
/**
|
|
421
|
-
* The engine-native app instance, typed from the active runtime
|
|
422
|
-
* ({@link ActiveRuntime} — Express by default). Prefer this over
|
|
423
|
-
* {@link getExpressApp}; under a non-Express runtime the type follows the
|
|
424
|
-
* augmented registry.
|
|
425
|
-
*/
|
|
426
|
-
getRuntimeApp(): ActiveRuntime['app'];
|
|
427
|
-
/**
|
|
428
|
-
* The active HTTP runtime's identity + capabilities — `name` is `'express'`
|
|
429
|
-
* (default), `'fastify'`, or `'h3'`; `capabilities` reports what the engine
|
|
430
|
-
* supports (render / uploads / connectMiddleware / nativeBodyParsing).
|
|
431
|
-
* Surfaced by DevTools and the VS Code extension so tooling can show which
|
|
432
|
-
* engine the app is running on. Cheap, side-effect free.
|
|
433
|
-
*/
|
|
434
|
-
getActiveRuntime(): {
|
|
435
|
-
name: string;
|
|
436
|
-
capabilities: RuntimeCapabilities;
|
|
437
|
-
};
|
|
438
|
-
/** @deprecated Use {@link getRuntimeApp}. Returns the engine-native app. */
|
|
439
|
-
getExpressApp(): Express;
|
|
440
|
-
/** Get registered adapters — used by DevToolsAdapter for peer discovery */
|
|
441
|
-
getAdapters(): AppAdapter[];
|
|
442
|
-
/**
|
|
443
|
-
* Get registered plugins — used by DevToolsAdapter for topology
|
|
444
|
-
* introspection (architecture.md §23). Read-only; returns the
|
|
445
|
-
* already-sorted plugin list (post-`dependsOn` topo-sort).
|
|
446
|
-
*/
|
|
447
|
-
getPlugins(): readonly KickPlugin[];
|
|
448
|
-
/**
|
|
449
|
-
* Snapshot of every Context Contributor reachable from this app —
|
|
450
|
-
* walks **four** registration sites: adapters, plugins, modules,
|
|
451
|
-
* and the bootstrap `contributors` option. The devtools Topology
|
|
452
|
-
* tab consumes this for the Contributors panel; tests + adopters
|
|
453
|
-
* can call it for diagnostics.
|
|
454
|
-
*
|
|
455
|
-
* Per-route (method/class-decorator) registrations are NOT included
|
|
456
|
-
* here — they live on the route registry rather than on any of
|
|
457
|
-
* the four collection sites this method walks. A future RPC will
|
|
458
|
-
* surface them separately.
|
|
459
|
-
*
|
|
460
|
-
* Result shape stays minimal — `{ key, source, label, dependsOn }`
|
|
461
|
-
* — so we don't leak `resolve` closures or other internal fields.
|
|
462
|
-
* `source` matches the five-level precedence union from
|
|
463
|
-
* `ContributorSource` (minus `'method'` / `'class'` which require
|
|
464
|
-
* the per-route walk noted above).
|
|
465
|
-
*/
|
|
466
|
-
getContributors(): ReadonlyArray<{
|
|
467
|
-
key: string;
|
|
468
|
-
source: 'module' | 'adapter' | 'plugin' | 'global';
|
|
469
|
-
label: string;
|
|
470
|
-
dependsOn: readonly string[];
|
|
471
|
-
}>;
|
|
472
|
-
getHttpServer(): http.Server | null;
|
|
473
|
-
/**
|
|
474
|
-
* Decide whether {@link Application} should auto-mount the
|
|
475
|
-
* {@link requestScopeMiddleware} ALS wrapper.
|
|
476
|
-
*
|
|
477
|
-
* Returns `false` when:
|
|
478
|
-
* - `contextStore: 'manual'` was set (caller manages ALS frames), or
|
|
479
|
-
* - the user-supplied `middleware` list already includes a
|
|
480
|
-
* `requestScopeMiddleware()` (detected via the symbol marker stamped
|
|
481
|
-
* in `middleware/request-scope.ts`).
|
|
482
|
-
*
|
|
483
|
-
* Otherwise `true` — preserves the historical default of "always wrap
|
|
484
|
-
* requests in an ALS frame" so existing apps see no behavior change.
|
|
485
|
-
*/
|
|
486
|
-
private shouldAutoMountRequestScope;
|
|
487
|
-
private collectAdapterMiddleware;
|
|
488
|
-
private mountMiddlewareList;
|
|
489
|
-
private mountMiddlewareEntry;
|
|
490
|
-
/** Middleware that tracks in-flight requests for graceful draining */
|
|
491
|
-
private requestTrackingMiddleware;
|
|
492
|
-
}
|
|
493
|
-
//#endregion
|
|
494
|
-
export { ShutdownOptions as i, ApplicationOptions as n, MiddlewareEntry as r, Application as t };
|
|
495
|
-
//# sourceMappingURL=application-NjKJPm9r.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"application-NjKJPm9r.d.mts","names":[],"sources":["../src/http/application.ts"],"mappings":";;;;;;;;;;;KA4DY,kBAAkB;EAAmB;EAAc,SAAS;;;UAGvD;;;;;;;;EAQf;;UAGe;;;;;;;;;;;EAWf,SAAS;;;;;;;;;;;;;;;;;;EAmBT,OAAO,UAAU;;EAEjB,WAAW;;EAEX;;EAEA;;;;;;;;;EASA;;;;;;;;;;;;;;;;;;;;;;EAuBA,cAAc;;EAGd,UAAU;;;;;;;;;;;;;;;;;;;;;EAsBV,eAAe;;;;;;;;;;;;;;;;;;;EAoBf;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BA;;;;;;;;;;;;;;;;;;;;;;;EAwBA;EAEA,UAAU;;EAGV,2CAA2C,YAAY;;EAEvD;;;;;;;;EAQA;;;;;EAKA;;;;;EAKA;;;;;;;;;;;;;;;;;;;EAoBA;IAAsB;;;;;;;;;;;;;;;;;;;;;;EAsBtB,cAAc,UAAU,KAAK,iBAAiB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0CrD,WAAW,UAAU,UAAU,KAAK,iBAAiB,OAAO;;;;;;;;;;;;;;;;;;EAmB5D;;IAEE;;;cAwHS;mBA0CkB;UAzCrB;;mBAES;UACT;UACA;mBACS;;;;;;mBAMA;mBAEA;;;;;;;;;;;;;UAcT;;UAMA;;UAEA;;UAEA;;UAEA;EAER,YAA6B,SAAS;;MAyClC;;MAKA;;EAKJ,gBAAgB;;;;;;;;;;;;;;;EAkBhB,OAAO,KAAK,KAAK,iBAAiB,KAAK,KAAK,gBAAgB,QAAQ;;;;;;;;;;;;;;;UAuB5D;;;;;;UAiBA;;UA0BM;EAeR,SAAS;;EA4YT,gBAAgB;;;;;;;;;;EAahB,SAAS;;EA0ET,WAAW;;;;;;;;;;;EA8CX,SAAS,UAAS,kBAAuB;;;;;;;EAuJ/C,iBAAiB;;;;;;;;EAWjB;IAAsB;IAAc,cAAc;;;EAKlD,iBAAiB;;EAKjB,eAAe;;;;;;EASf,uBAAuB;;;;;;;;;;;;;;;;;;;EAsBvB,mBAAmB;IACjB;IACA;IACA;IACA;;EA6CF,iBAAiB,KAAK;;;;;;;;;;;;;;UAmBd;UAWA;UAmBA;UAUA;;UASA"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @forinda/kickjs v8.2.0
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) Felix Orinda
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
import{METADATA}from"./core/interfaces.mjs";import{i as createToken,n as tokenName,s as moduleRouteMissingControllerError,t as Container}from"./container-BnkQIDQF.mjs";import{Logger,createLogger}from"./core/logger.mjs";import{t as getClassMeta}from"./metadata-DRRQ0p_l.mjs";import{Controller,Get}from"./core/decorators.mjs";import{t as MutableModuleRegistry}from"./module-registry-C7yEmbZ8.mjs";import{i as runDisposables,n as drainDisposables,r as registerDisposable,t as disposeAll}from"./disposables-lWieeJLG.mjs";import{buildMountPath,joinPaths}from"./core/path.mjs";import"./core-w7s4ntck.mjs";import{n as assertRouteUnique,r as buildRouteTable,t as _setExternalContributorSources}from"./router-builder-HeSJZ2QG.mjs";import{r as offerRoutePolicy,t as RoutePolicyTable}from"./route-policy-D5lQltyg.mjs";import{c as requestScopeMiddleware,d as rejectUnsupportedBody,i as reply,l as EXPRESS_JSON_TYPES,n as applyHandlerResult,s as isRequestScopeMiddleware,t as publishMatchedRoute}from"./runtime-B3fCMmZW.mjs";import{requestId}from"./http/middleware/request-id.mjs";import{errorHandler,notFoundHandler}from"./http/middleware/error-handler.mjs";import{i as requestStore,t as RequestContext}from"./context-GJc8Pf2d.mjs";import{t as __decorate}from"./decorate-CpBbxrvT.mjs";import{validate}from"./http/middleware/validate.mjs";import{buildUploadMiddleware}from"./http/middleware/upload.mjs";import http from"node:http";import express,{Router}from"express";const mergeConfig=(defaults={},overrides={})=>({...defaults,...overrides}),composeName=(base,scope)=>`${base}:${scope}`;function defineModule(options){if(typeof options!=`object`||!options)throw TypeError(`defineModule: options must be an object literal. See architecture.md §21 for the spec shape.`);if(typeof options.name!=`string`||options.name.length===0){let got=typeof options.name==`string`?`""`:typeof options.name;throw TypeError(`defineModule: options.name must be a non-empty string (got ${got}). Module names appear in diagnostics and \`.scoped()\` namespacing — anonymous modules make cycle / missing-dep errors hard to localize.`)}if(typeof options.build!=`function`)throw TypeError(`defineModule(${options.name}): options.build is required and must be a function (got ${typeof options.build}). The build function returns the AppModule shape — register() / routes() / contributors() — wired with the resolved config.`);let buildSync=(instanceName,scoped,overrides)=>{let config=mergeConfig(options.defaults,overrides),built=options.build(config,{name:instanceName,scoped});return Object.defineProperty(built,"__moduleName",{value:instanceName,enumerable:!1,writable:!1,configurable:!1}),built},factory=(config=>buildSync(options.name,!1,config));return factory.scoped=(scopeName,config)=>buildSync(composeName(options.name,scopeName),!0,config),Object.defineProperty(factory,"definition",{value:Object.freeze({...options}),writable:!1,enumerable:!0,configurable:!1}),factory}var DuplicateMountNameError=class extends Error{kind;mountName;constructor(kind,mountName){super(`Duplicate ${kind} name '${mountName}' — every ${kind} must declare a unique name`),this.name=`DuplicateMountNameError`,this.kind=kind,this.mountName=mountName}},MissingMountDepError=class extends Error{kind;missing;dependent;constructor(kind,missing,dependent){super(`Missing ${kind} dependency '${missing}' required by '${dependent}' — is the ${kind} installed and named correctly?`),this.name=`MissingMountDepError`,this.kind=kind,this.missing=missing,this.dependent=dependent}},MountCycleError=class extends Error{kind;cycle;constructor(kind,cycle){super(`Cycle in ${kind} dependsOn declarations: ${cycle.join(` → `)}`),this.name=`MountCycleError`,this.kind=kind,this.cycle=Object.freeze([...cycle])}};function mountSort(items,kind){let byName=new Map;for(let item of items){if(byName.has(item.name))throw new DuplicateMountNameError(kind,item.name);byName.set(item.name,item)}let indegree=new Map,dependents=new Map;for(let item of items)indegree.set(item.name,item.dependsOn?.length??0);for(let item of items)for(let dep of item.dependsOn??[]){if(!byName.has(dep))throw new MissingMountDepError(kind,dep,item.name);let list=dependents.get(dep)??[];list.push(item),dependents.set(dep,list)}let queue=[];for(let item of items)indegree.get(item.name)===0&&queue.push(item);let sorted=[];for(;queue.length>0;){let node=queue.shift();sorted.push(node);for(let dependent of dependents.get(node.name)??[]){let next=(indegree.get(dependent.name)??0)-1;indegree.set(dependent.name,next),next===0&&queue.push(dependent)}}if(sorted.length!==items.length)throw new MountCycleError(kind,reconstructCycle(items.filter(it=>(indegree.get(it.name)??0)>0),byName));return sorted}function reconstructCycle(residual,byName){let residualNames=new Set(residual.map(r=>r.name)),start=residual[0].name,path=[start],seen=new Set([start]),cursor=start;for(;;){let nextDep=byName.get(cursor).dependsOn?.find(d=>residualNames.has(d));if(nextDep===void 0)break;if(seen.has(nextDep)){let cycleStart=path.indexOf(nextDep);return[...path.slice(cycleStart),nextDep]}path.push(nextDep),seen.add(nextDep),cursor=nextDep}return path}function __decorateMetadata(k,v){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(k,v)}const HEALTH_PROBE=createToken(`kick/Health/probe`);let HealthController=class{probe;constructor(probe){this.probe=probe}live(){return this.probe.isDraining()?reply(503,{status:`draining`,uptime:process.uptime()}):reply(200,{status:`ok`,uptime:process.uptime()})}async ready(){if(this.probe.isDraining())return reply(503,{status:`draining`,checks:[]});let checks=await this.probe.checks(),healthy=checks.every(c=>c.status===`up`);return reply(healthy?200:503,{status:healthy?`ready`:`degraded`,checks})}};__decorate([Get(`/live`),__decorateMetadata(`design:type`,Function),__decorateMetadata(`design:paramtypes`,[]),__decorateMetadata(`design:returntype`,void 0)],HealthController.prototype,`live`,null),__decorate([Get(`/ready`),__decorateMetadata(`design:type`,Function),__decorateMetadata(`design:paramtypes`,[]),__decorateMetadata(`design:returntype`,Promise)],HealthController.prototype,`ready`,null),HealthController=__decorate([Controller(),__decorateMetadata(`design:paramtypes`,[Object])],HealthController);const healthModule=defineModule({name:`HealthModule`,build:()=>({register(container){container.registerFactory(HealthController,()=>{let probe=container.resolve(HEALTH_PROBE);return new HealthController(probe)})},routes(){return{path:`/health`,controller:HealthController,version:!1,prefix:!1}}})});function materializeRouter(entries){let router=Router();for(let entry of entries){let method=entry.method.toLowerCase(),handlers=[];handlers.push((req,_res,next)=>{publishMatchedRoute(req,entry),next()}),entry.meta.validation&&handlers.push(validate(entry.meta.validation)),entry.meta.upload&&handlers.push(buildUploadMiddleware(entry.meta.upload));for(let mw of entry.middlewares)handlers.push((req,res,next)=>{let ctx=new RequestContext(req,res,next);Promise.resolve(mw(ctx,next)).catch(next)});if(entry.contributorRunner){let run=entry.contributorRunner;handlers.push(async(req,res,next)=>{let ctx=new RequestContext(req,res,next);try{await run(ctx),next()}catch(err){next(err)}})}handlers.push(async(req,res,next)=>{let ctx=new RequestContext(req,res,next);try{let result=await entry.handler(ctx);res.headersSent||applyHandlerResult(ctx,result)}catch(err){next(err)}}),router[method](entry.path,...handlers)}return router}function buildRoutes(controllerClass,options={}){return materializeRouter(buildRouteTable(controllerClass,options))}function expressRuntime(){return{name:`express`,createApp(options={}){let app=express();return app.disable(`x-powered-by`),app.set(`trust proxy`,options.trustProxy??!1),app},nodeHandler(app){return(req,res,next)=>{next?app(req,res,next):app(req,res)}},mountRoutes(app,table){for(let{mountPath,routes}of table)app.use(mountPath,materializeRouter(routes))},useConnect(app,mw,opts={}){opts.path===void 0?app.use(mw):app.use(opts.path,mw)},serveStatic(app,prefix,dir){app.use(prefix,express.static(dir))},setNotFound(app,mw){app.use(mw)},setErrorHandler(app,mw){app.use(mw)},capabilities:{render:!0,uploads:!0,connectMiddleware:!0,nativeBodyParsing:!1}}}const log=createLogger(`Application`);function isModuleFactory(entry){return typeof entry==`function`&&`definition`in entry&&typeof entry.scoped==`function`}function isConfigurable(factory){return factory.definition?.defaults!=null}function toAppModule(entry){if(typeof entry!=`function`)return entry;if(isModuleFactory(entry)){if(isConfigurable(entry)){let name=entry.definition?.name||entry.name||`<anonymous>`;throw TypeError(`bootstrap: module \`${name}\` takes configuration, so it must be invoked.\n Write \`${name}()\` for its defaults, or \`${name}({ … })\` to configure it.\n Passing it bare would have silently selected the defaults.`)}return entry()}let name=entry.name||`<anonymous>`;if(!isConstructible(entry))throw TypeError(`bootstrap: module entry \`${name}\` is a function, but not a module class and not a defineModule() factory (no \`definition\`).\n A defineModule() module is passed as \`${name}\` or \`${name}()\`; a class must implement AppModule.`);let mod=new entry;if(typeof mod?.routes!=`function`)throw TypeError(`bootstrap: module entry \`${name}\` constructed, but the result does not implement AppModule — \`routes()\` is missing.\n A module class needs \`routes()\`; a defineModule() module is passed as \`${name}\` or \`${name}()\`.`);return mod}function isConstructible(fn){try{return Reflect.construct(String,[],fn),!0}catch{return!1}}var Application=class{options;app;runtime;container;httpServer=null;adapters;routePolicy=new RoutePolicyTable;plugins;_moduleContributors=[];_inFlightRequests=0;_draining=!1;_shutdownInitiated=!1;_drainResolvers=[];constructor(options){this.options=options,this.runtime=options.runtime??expressRuntime(),this.app=this.runtime.createApp({trustProxy:options.trustProxy}),this.container=Container.getInstance(),this.plugins=mountSort(options.plugins??[],`plugin`);let allAdapters=[...this.plugins.flatMap(p=>p.adapters?.()??[]),...options.adapters??[]],anonAdapterCount=0,namedAdapters=allAdapters.map(adapter=>{if(!adapter.name){let ctorName=adapter.constructor?.name,fallback=ctorName&&ctorName!==`Object`?ctorName:`AnonymousAdapter#${anonAdapterCount++}`;return Object.assign(adapter,{name:fallback})}return adapter});this.adapters=mountSort(namedAdapters,`adapter`),Container._requestStoreProvider=()=>requestStore.getStore()??null}get isDraining(){return this._draining}get inFlightRequests(){return this._inFlightRequests}getContainer(){return this.container}handle(req,res,next){let handler=this.runtime.nodeHandler(this.app);next?handler(req,res,next):handler(req,res)}adapterCtx(server){let env=process.env.NODE_ENV??`development`;return{http:this.adapterHttp(),app:this.app,container:this.container,server,env,isProduction:env===`production`}}adapterHttp(){return{route:(method,path,handler)=>{let entry={method,path,middlewares:[],contributorRunner:null,handler,meta:{}};this.runtime.mountRoutes(this.app,[{mountPath:`/`,routes:[entry]}])},mount:(prefix,routes)=>{this.runtime.mountRoutes(this.app,[{mountPath:prefix,routes}])},serveStatic:(prefix,dir)=>{this.runtime.serveStatic(this.app,prefix,dir)},use:(mw,opts)=>{this.runtime.useConnect(this.app,mw,opts)}}}async callHook(hook,ctx){if(hook)try{let result=hook(ctx);result&&typeof result.then==`function`&&await result}catch(err){log.error(err,`Adapter hook failed`)}}async setup(){log.debug(`Bootstrapping application...`),this._moduleContributors=[];let adapterMw=this.collectAdapterMiddleware();this.app.__kickApp=this;let ctx=this.adapterCtx();for(let adapter of this.adapters)await this.callHook(adapter.beforeMount?.bind(adapter),ctx);this.runtime.useConnect(this.app,this.requestTrackingMiddleware()),this.shouldAutoMountRequestScope()&&this.runtime.useConnect(this.app,requestScopeMiddleware()),this.mountMiddlewareList(adapterMw.beforeGlobal);for(let plugin of this.plugins)plugin.register?.(this.container);for(let plugin of this.plugins)try{let mw=plugin.middleware?.()??[];for(let handler of mw)this.runtime.useConnect(this.app,handler)}catch(err){log.error(err,`Plugin middleware failed: ${plugin.name??`unknown`}`)}let declaredHelmet=(this.options.middlewares??[]).some(entry=>typeof entry==`function`&&Symbol.for(`kick/http/helmet`)in entry);if(this.options.security?.helmet!==!1&&!declaredHelmet)try{let{helmet:helmetFn}=await import(`./http/middleware/helmet.mjs`);this.runtime.useConnect(this.app,helmetFn())}catch{}let userMiddlewares=this.options.middlewares;if(userMiddlewares)for(let entry of userMiddlewares)this.mountMiddlewareEntry(entry);else if(this.runtime.useConnect(this.app,requestId()),!this.runtime.capabilities.nativeBodyParsing){let limit=this.options.jsonLimit??`1mb`;this.runtime.useConnect(this.app,express.json({limit,type:[...EXPRESS_JSON_TYPES]})),this.runtime.useConnect(this.app,express.urlencoded({extended:!0,limit})),this.runtime.useConnect(this.app,express.text({limit,type:`text/*`})),this.runtime.useConnect(this.app,rejectUnsupportedBody())}this.mountMiddlewareList(adapterMw.afterGlobal);let moduleRegistry=new MutableModuleRegistry;for(let plugin of this.plugins){for(let m of plugin.modules?.()??[])moduleRegistry.mount(m);plugin.setup?.(moduleRegistry)}for(let m of this.options.modules)moduleRegistry.mount(m);this.options.setup?.(moduleRegistry),this.options.health!==!1&&(this.container.registerInstance(HEALTH_PROBE,{isDraining:()=>this._draining,checks:async()=>{let withCheck=this.adapters.filter(a=>a.onHealthCheck);return(await Promise.allSettled(withCheck.map(a=>a.onHealthCheck()))).map((c,i)=>c.status===`fulfilled`?c.value:{name:withCheck[i].name??`unknown`,status:`down`})}}),moduleRegistry.mount(healthModule()));let modules=moduleRegistry.entries.map(entry=>{let mod=toAppModule(entry);return mod.register?.(this.container),mod});this.container.bootstrap(),this.container.has(Logger)||this.container.registerInstance(Logger,new Logger),this.mountMiddlewareList(adapterMw.beforeRoutes);let apiPrefix=this.options.apiPrefix??`/api`,defaultVersion=this.options.defaultVersion??1,shouldLogRoutes=this.options.logRouteTable??this.options.logRoutesTable??!1,mountedRoutes=[],adapterSources=[];for(let adapter of this.adapters){let adapterContribs=adapter.contributors?.()??[],adapterLabel=adapter.name??adapter.constructor.name??`adapter`;for(let registration of adapterContribs)adapterSources.push({source:`adapter`,registration,label:adapterLabel})}for(let plugin of this.plugins){let pluginContribs=plugin.contributors?.()??[],pluginLabel=plugin.name??plugin.constructor?.name??`plugin`;for(let registration of pluginContribs)adapterSources.push({source:`adapter`,registration,label:pluginLabel})}let globalSources=(this.options.contributors??[]).map(registration=>({source:`global`,registration,label:`bootstrap`}));this._moduleContributors=[];let seenRoutes=new Map,mountedPaths=[];for(let mod of modules){let declaredName=mod.name,ctorName=mod.constructor?.name,moduleLabel=typeof declaredName==`string`&&declaredName.length>0?declaredName:ctorName&&ctorName!==`Object`?ctorName:`module`,moduleSources=(mod.contributors?.()??[]).map(registration=>({source:`module`,registration,label:moduleLabel}));for(let src of moduleSources)this._moduleContributors.push({registration:src.registration,label:moduleLabel});_setExternalContributorSources([...moduleSources,...adapterSources,...globalSources]);try{let result=mod.routes();if(!result)continue;let routeSets=Array.isArray(result)?result:[result];for(let route of routeSets){let version=route.version??defaultVersion,mountPath=buildMountPath(route.prefix===!1?``:apiPrefix,version,route.path);if(route.router)this.runtime.useConnect(this.app,route.router,{path:mountPath});else if(route.controller){let routeTable=buildRouteTable(route.controller),ctrl=route.controller.name??`controller`;for(let entry of routeTable){let owner=`${ctrl}.${String(entry.meta.handlerName??`?`)}`,fullPath=joinPaths(mountPath,entry.path);assertRouteUnique(seenRoutes,entry.method,fullPath,owner),mountedPaths.push({method:entry.method,path:fullPath}),this.routePolicy.add(entry.method,fullPath,entry.meta.flags)}this.runtime.mountRoutes(this.app,[{mountPath,routes:routeTable}])}else throw moduleRouteMissingControllerError(mountPath);if(route.controller){for(let adapter of this.adapters)try{adapter.onRouteMount?.(route.controller,mountPath)}catch(err){log.error(err,`adapter.onRouteMount() failed for ${mountPath}`)}shouldLogRoutes&&mountedRoutes.push({controller:route.controller,mountPath})}}}finally{_setExternalContributorSources([])}}if(shouldLogRoutes&&mountedRoutes.length>0){let methodOrder=[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`,`HEAD`,`OPTIONS`],methodRank=m=>{let i=methodOrder.indexOf(m);return i===-1?99:i},totalRoutes=0;log.info(`Routes:`);for(let{controller,mountPath}of mountedRoutes){let defs=getClassMeta(METADATA.ROUTES,controller,[]);if(defs.length===0)continue;let counts={};for(let def of defs){let m=def.method.toUpperCase();counts[m]=(counts[m]||0)+1}totalRoutes+=defs.length;let methods=Object.entries(counts).toSorted(([a],[b])=>methodRank(a)-methodRank(b)).map(([m,n])=>`${n} ${m}`).join(`, `),name=controller.name||`Controller`;log.info(` ${name.padEnd(30)} ${mountPath.padEnd(25)} ${defs.length} routes (${methods})`)}log.info(` Total: ${totalRoutes} routes`)}this.mountMiddlewareList(adapterMw.afterRoutes);for(let adapter of this.adapters)await this.callHook(adapter.beforeStart?.bind(adapter),ctx);for(let entry of this.options.middlewares??[])offerRoutePolicy(typeof entry==`function`?entry:entry.handler,this.routePolicy);for(let adapter of this.adapters)for(let mw of adapter.middleware?.()??[])offerRoutePolicy(mw.handler,this.routePolicy);this.runtime.setNotFound(this.app,this.options.onNotFound??notFoundHandler(mountedPaths)),this.runtime.setErrorHandler(this.app,this.options.onError??errorHandler())}async registerOnly(){await this.setup()}async start(){await this.setup();let g=globalThis;if(g.__kickjs_httpServer){this.httpServer=g.__kickjs_httpServer,log.debug(`Attached to Vite dev server`),g.__kickjs_app_shutdown=()=>this.shutdown();for(let adapter of this.adapters){let ctx=this.adapterCtx(this.httpServer);await this.callHook(adapter.afterStart?.bind(adapter),ctx)}for(let plugin of this.plugins)await plugin.onReady?.(this.container);return}let port=this.options.port??parseInt(process.env.PORT||`3000`,10);this.httpServer=http.createServer(this.runtime.nodeHandler(this.app)),this.httpServer.on(`error`,err=>{throw err.code===`EADDRINUSE`&&(log.error(`Port ${port} is already in use. Kill the existing process or use a different port:\n PORT=${port+1} kick dev\n lsof -i :${port} # find what's using it\n kill <PID> # stop it`),process.exit(1)),err}),await new Promise((resolve,reject)=>{this.httpServer.listen(port,async()=>{try{log.info(`Server running on http://localhost:${port}`);for(let adapter of this.adapters){let afterCtx=this.adapterCtx(this.httpServer);await this.callHook(adapter.afterStart?.bind(adapter),afterCtx)}for(let plugin of this.plugins)await plugin.onReady?.(this.container);resolve()}catch(err){reject(err)}})})}async rebuild(){let prevApp=this.app,prevContainer=this.container,staleDisposables=drainDisposables();try{Container.reset(),this.container=Container.getInstance(),this.app=this.runtime.createApp({trustProxy:this.options.trustProxy}),await this.setup()}catch(err){log.error(err,`HMR rebuild failed, keeping previous app`),await runDisposables(drainDisposables());for(let d of staleDisposables)registerDisposable(d);this.app=prevApp,this.container=prevContainer;return}await runDisposables(staleDisposables),this.httpServer&&(this.httpServer.removeAllListeners(`request`),this.httpServer.on(`request`,this.runtime.nodeHandler(this.app)),log.debug(`HMR: app rebuilt and swapped`))}async shutdown(options={}){let closeServer=options.closeServer??!0;if(this._shutdownInitiated){log.debug(`Shutdown already in progress, skipping duplicate call`);return}this._shutdownInitiated=!0,this._draining=!0,log.debug(`Shutting down — draining in-flight requests...`);let timeoutMs=this.options.shutdownTimeout??3e4,timer,forceExitPromise=timeoutMs>0?new Promise(resolve=>{timer=setTimeout(()=>resolve(`timeout`),timeoutMs),timer.unref()}):new Promise(()=>{});try{if(closeServer&&this.httpServer&&this.httpServer.close(()=>{}),closeServer&&this._inFlightRequests>0){log.debug(`Waiting for ${this._inFlightRequests} in-flight request(s) to complete...`);let drainPromise=new Promise(resolve=>{this._drainResolvers.push(()=>resolve(`drained`))});await Promise.race([drainPromise,forceExitPromise])===`timeout`?log.warn(`Shutdown timeout (${timeoutMs}ms) reached with ${this._inFlightRequests} request(s) still in-flight, forcing shutdown`):log.debug(`All in-flight requests completed`)}let hookTimeoutMs=closeServer?timeoutMs:Math.min(timeoutMs,5e3),timeBoxed=(label,run)=>{let hook=(async()=>run())();return hookTimeoutMs<=0?hook:new Promise((resolve,reject)=>{let t=setTimeout(()=>{log.warn(`${label} did not finish shutting down within ${hookTimeoutMs}ms — continuing without it. Its resources may still be held.`),resolve(void 0)},hookTimeoutMs);t.unref(),hook.then(value=>{clearTimeout(t),resolve(value)},err=>{clearTimeout(t),reject(err)})})},wasListening=this.httpServer?.listening===!0,results=await Promise.allSettled([...this.plugins.map(plugin=>timeBoxed(`Plugin '${plugin.name}'`,()=>plugin.shutdown?.())),...this.adapters.map(adapter=>timeBoxed(`Adapter '${adapter.name}'`,()=>adapter.shutdown?.()))]);!closeServer&&wasListening&&this.httpServer?.listening===!1&&log.error("An adapter or plugin closed the shared HTTP server during an HMR reload. The dev server is now unreachable and will not rebind until you restart it. Close only what you own: socket.io's `io.close()` closes the HTTP server passed to its constructor — on a reload, disconnect the sockets instead.");for(let result of results)result.status===`rejected`&&log.error({err:result.reason},`Adapter shutdown failed`);await disposeAll(),this.container.flushChanges()}finally{timer&&clearTimeout(timer)}}getRuntimeApp(){return this.app}getActiveRuntime(){return{name:this.runtime.name,capabilities:this.runtime.capabilities}}getExpressApp(){return this.app}getAdapters(){return this.adapters}getPlugins(){return this.plugins}getContributors(){let out=[],ingest=(list,source,label)=>{if(list)for(let reg of list){let r=reg;if(r.key===void 0||r.key===null)continue;let key=typeof r.key==`string`?r.key:tokenName(r.key);out.push({key,source,label,dependsOn:Array.isArray(r.dependsOn)?r.dependsOn:[]})}};for(let adapter of this.adapters)ingest(adapter.contributors?.(),`adapter`,adapter.name??`adapter`);for(let plugin of this.plugins)ingest(plugin.contributors?.(),`plugin`,plugin.name??`plugin`);for(let{registration,label}of this._moduleContributors)ingest([registration],`module`,label);return ingest(this.options.contributors,`global`,`bootstrap`),out}getHttpServer(){return this.httpServer}shouldAutoMountRequestScope(){if(this.options.contextStore===`manual`)return!1;let userEntries=this.options.middlewares??[];for(let entry of userEntries)if(isRequestScopeMiddleware(typeof entry==`function`?entry:entry.handler))return!1;return!0}collectAdapterMiddleware(){let result={beforeGlobal:[],afterGlobal:[],beforeRoutes:[],afterRoutes:[]};for(let adapter of this.adapters){let entries=adapter.middleware?.()??[];for(let entry of entries)result[entry.phase??`afterGlobal`].push(entry)}return result}mountMiddlewareList(entries){for(let entry of entries){if(entry.path===void 0){this.runtime.useConnect(this.app,entry.handler);continue}this.runtime.useConnect(this.app,entry.handler,{path:entry.path})}}mountMiddlewareEntry(entry){typeof entry==`function`?this.runtime.useConnect(this.app,entry):this.runtime.useConnect(this.app,entry.handler,{path:entry.path})}requestTrackingMiddleware(){return(_req,res,next)=>{this._inFlightRequests++;let onFinish=()=>{if(res.removeListener(`finish`,onFinish),res.removeListener(`close`,onFinish),this._inFlightRequests--,this._draining&&this._inFlightRequests===0){for(let resolve of this._drainResolvers)resolve();this._drainResolvers=[]}};res.on(`finish`,onFinish),res.on(`close`,onFinish),next()}}};export{HEALTH_PROBE as a,DuplicateMountNameError as c,mountSort as d,defineModule as f,materializeRouter as i,MissingMountDepError as l,buildRoutes as n,HealthController as o,expressRuntime as r,healthModule as s,Application as t,MountCycleError as u};
|
|
12
|
-
//# sourceMappingURL=application-blu78Mlf.mjs.map
|