@forinda/kickjs 5.16.0 → 5.18.0-alpha.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-D_uzU-QA.d.mts +2121 -0
- package/dist/adapter-D_uzU-QA.d.mts.map +1 -0
- package/dist/{context-decorator-DDZ30BIW.d.mts → app-module-CuAS6hJC.d.mts} +184 -4
- package/dist/app-module-CuAS6hJC.d.mts.map +1 -0
- package/dist/application-BU5N6o_M.mjs +12 -0
- package/dist/application-BU5N6o_M.mjs.map +1 -0
- package/dist/{application-CAnpDQ8d.d.mts → application-pbx53JnX.d.mts} +31 -5
- package/dist/application-pbx53JnX.d.mts.map +1 -0
- package/dist/{bootstrap-CFK2aAjA.mjs → bootstrap-CFog4v_L.mjs} +3 -3
- package/dist/{bootstrap-CFK2aAjA.mjs.map → bootstrap-CFog4v_L.mjs.map} +1 -1
- package/dist/{bootstrap-8DDzBjhx.d.mts → bootstrap-DzfBj6Ja.d.mts} +2 -2
- package/dist/{bootstrap-8DDzBjhx.d.mts.map → bootstrap-DzfBj6Ja.d.mts.map} +1 -1
- package/dist/config/index.mjs +2 -2
- package/dist/{config-BW5taOVX.mjs → config-Di3HlRTS.mjs} +3 -3
- package/dist/{config-BW5taOVX.mjs.map → config-Di3HlRTS.mjs.map} +1 -1
- package/dist/{container-D1gfs6__.mjs → container-BiGimG12.mjs} +3 -3
- package/dist/{container-D1gfs6__.mjs.map → container-BiGimG12.mjs.map} +1 -1
- package/dist/context-leZajQAj.mjs +12 -0
- package/dist/context-leZajQAj.mjs.map +1 -0
- 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.d.mts +1 -1
- package/dist/core/errors.mjs +2 -2
- package/dist/core/errors.mjs.map +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-Db2uyqtM.mjs → core-Y_xSqZ7v.mjs} +3 -3
- package/dist/{core-Db2uyqtM.mjs.map → core-Y_xSqZ7v.mjs.map} +1 -1
- package/dist/{env-nwsfCpdy.mjs → env-BoMBrGWs.mjs} +3 -3
- package/dist/{env-nwsfCpdy.mjs.map → env-BoMBrGWs.mjs.map} +1 -1
- package/dist/{errors-CRCTjEUK.d.mts → errors-n0H96eEz.d.mts} +3 -1
- package/dist/errors-n0H96eEz.d.mts.map +1 -0
- 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.mjs +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.mjs +1 -1
- package/dist/http/middleware/request-id.mjs +1 -1
- package/dist/http/middleware/request-logger.mjs +2 -2
- package/dist/http/middleware/session.mjs +1 -1
- package/dist/http/middleware/spa.d.mts +1 -1
- package/dist/http/middleware/spa.mjs +2 -2
- package/dist/http/middleware/upload.d.mts +2 -2
- package/dist/http/middleware/upload.mjs +3 -3
- package/dist/http/middleware/upload.mjs.map +1 -1
- package/dist/http/middleware/validate.mjs +2 -2
- package/dist/http/middleware/views.d.mts +1 -1
- package/dist/http/middleware/views.mjs +2 -2
- package/dist/http/query/index.d.mts +2 -2
- package/dist/http/query/index.mjs +2 -2
- package/dist/http/router-builder.d.mts +2 -2
- package/dist/http/router-builder.mjs +2 -2
- package/dist/http/router-builder.mjs.map +1 -1
- package/dist/http/runtimes/fastify.d.mts +66 -0
- package/dist/http/runtimes/fastify.d.mts.map +1 -0
- package/dist/http/runtimes/fastify.mjs +13 -0
- package/dist/http/runtimes/fastify.mjs.map +1 -0
- package/dist/http/runtimes/h3.d.mts +29 -0
- package/dist/http/runtimes/h3.d.mts.map +1 -0
- package/dist/http/runtimes/h3.mjs +12 -0
- package/dist/http/runtimes/h3.mjs.map +1 -0
- package/dist/{index-kEmG8nWU.d.mts → index-BtWJ9SLP.d.mts} +53 -7
- package/dist/{index-kEmG8nWU.d.mts.map → index-BtWJ9SLP.d.mts.map} +1 -1
- package/dist/index.d.mts +12 -17
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/{metadata-Cll3P0N0.mjs → metadata-Pvgc-K8a.mjs} +2 -2
- package/dist/{metadata-Cll3P0N0.mjs.map → metadata-Pvgc-K8a.mjs.map} +1 -1
- package/dist/query-B3PhfU6M.mjs +12 -0
- package/dist/query-B3PhfU6M.mjs.map +1 -0
- package/dist/request-scope-BaM8_e_8.mjs +12 -0
- package/dist/request-scope-BaM8_e_8.mjs.map +1 -0
- package/dist/router-builder-Bh3qSiDz.d.mts +39 -0
- package/dist/router-builder-Bh3qSiDz.d.mts.map +1 -0
- package/dist/{spa-IRFC2eMN.d.mts → spa-BdvZFXJz.d.mts} +3 -2
- package/dist/spa-BdvZFXJz.d.mts.map +1 -0
- package/dist/{upload-D6edAELH.d.mts → upload-Bc_rBRtE.d.mts} +37 -2
- package/dist/upload-Bc_rBRtE.d.mts.map +1 -0
- package/dist/{views-BCl-mETX.d.mts → views-DcTVDiOh.d.mts} +31 -7
- package/dist/views-DcTVDiOh.d.mts.map +1 -0
- package/package.json +29 -1
- package/dist/adapter-CkpcZwzZ.d.mts +0 -407
- package/dist/adapter-CkpcZwzZ.d.mts.map +0 -1
- package/dist/app-module-BTzb-Vd6.d.mts +0 -92
- package/dist/app-module-BTzb-Vd6.d.mts.map +0 -1
- package/dist/application-CAnpDQ8d.d.mts.map +0 -1
- package/dist/application-DnnqoDWx.mjs +0 -12
- package/dist/application-DnnqoDWx.mjs.map +0 -1
- package/dist/context-Dnt2Di7p.d.mts +0 -434
- package/dist/context-Dnt2Di7p.d.mts.map +0 -1
- package/dist/context-MD7Mc_o_.mjs +0 -12
- package/dist/context-MD7Mc_o_.mjs.map +0 -1
- package/dist/context-decorator-DDZ30BIW.d.mts.map +0 -1
- package/dist/errors-CRCTjEUK.d.mts.map +0 -1
- package/dist/execution-context-B4cfhivz.d.mts +0 -98
- package/dist/execution-context-B4cfhivz.d.mts.map +0 -1
- package/dist/index-frSEHiL_.d.mts +0 -796
- package/dist/index-frSEHiL_.d.mts.map +0 -1
- package/dist/plugin-BQCn6zyj.d.mts +0 -260
- package/dist/plugin-BQCn6zyj.d.mts.map +0 -1
- package/dist/query-D-FiLfmd.mjs +0 -12
- package/dist/query-D-FiLfmd.mjs.map +0 -1
- package/dist/router-builder-oQpcQMWl.d.mts +0 -31
- package/dist/router-builder-oQpcQMWl.d.mts.map +0 -1
- package/dist/spa-IRFC2eMN.d.mts.map +0 -1
- package/dist/upload-D6edAELH.d.mts.map +0 -1
- package/dist/views-BCl-mETX.d.mts.map +0 -1
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { i as Constructor, o as MaybePromise } from "./interfaces-DbTyKGdS.mjs";
|
|
3
|
-
import { t as Container } from "./container-TWOUyR_0.mjs";
|
|
4
|
-
import { s as ContributorRegistrations } from "./context-decorator-DDZ30BIW.mjs";
|
|
5
|
-
import http from "node:http";
|
|
6
|
-
import { ErrorRequestHandler, Express, RequestHandler } from "express";
|
|
7
|
-
|
|
8
|
-
//#region src/core/introspect.d.ts
|
|
9
|
-
/**
|
|
10
|
-
* Per-primitive introspection snapshot — the JSON shape an adapter or
|
|
11
|
-
* plugin's optional `introspect()` hook returns for DevTools.
|
|
12
|
-
*
|
|
13
|
-
* Lives in `@forinda/kickjs` (not `@forinda/kickjs-devtools-kit`) so
|
|
14
|
-
* adopters can type their `introspect()` return without taking on a
|
|
15
|
-
* dep on the kit just to satisfy the contract. The kit's own
|
|
16
|
-
* `IntrospectionSnapshot` type is structurally identical and continues
|
|
17
|
-
* to be the canonical doc location for DevTools-side consumers; the
|
|
18
|
-
* two stay in lockstep — if a field is added on one side it MUST be
|
|
19
|
-
* added on the other (covered by the type-equivalence test in the
|
|
20
|
-
* devtools-kit package).
|
|
21
|
-
*
|
|
22
|
-
* Cheap-by-default principle: `state` and `metrics` should be O(1) to
|
|
23
|
-
* compute (counters, flags, recent samples). Anything that requires a
|
|
24
|
-
* DB round trip or a full DI graph walk belongs behind a separate
|
|
25
|
-
* explicit RPC — DevTools polls topology aggressively.
|
|
26
|
-
*/
|
|
27
|
-
interface IntrospectionSnapshot {
|
|
28
|
-
/**
|
|
29
|
-
* Wire-protocol version this snapshot conforms to. The kit ships a
|
|
30
|
-
* `PROTOCOL_VERSION` constant typed as the literal `1`; we mirror
|
|
31
|
-
* that literal here so structural parity is enforced both ways —
|
|
32
|
-
* an adopter who writes `protocolVersion: 1` satisfies both this
|
|
33
|
-
* type and the kit's `IntrospectionSnapshot`. Bumping is a
|
|
34
|
-
* coordinated kit + framework release; widen this literal in
|
|
35
|
-
* lockstep.
|
|
36
|
-
*/
|
|
37
|
-
protocolVersion: 1;
|
|
38
|
-
/** Stable identity matching the `name` from `definePlugin` / `defineAdapter`. */
|
|
39
|
-
name: string;
|
|
40
|
-
/** Discriminator for what kind of primitive this is. */
|
|
41
|
-
kind: IntrospectionKind;
|
|
42
|
-
/** Optional version string from the plugin / adapter metadata. */
|
|
43
|
-
version?: string;
|
|
44
|
-
/**
|
|
45
|
-
* Reactive state surface — JSON-serialisable snapshot. Keep small
|
|
46
|
-
* (under a few KB) so polling stays cheap.
|
|
47
|
-
*/
|
|
48
|
-
state?: Record<string, unknown>;
|
|
49
|
-
/** DI tokens this primitive registers (`provides`) or consumes (`requires`). */
|
|
50
|
-
tokens?: {
|
|
51
|
-
provides: readonly string[];
|
|
52
|
-
requires: readonly string[];
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Per-instance counters — active connections, in-flight jobs, cached
|
|
56
|
-
* items, etc. Numbers only so the DevTools panel can chart trends.
|
|
57
|
-
*/
|
|
58
|
-
metrics?: Record<string, number>;
|
|
59
|
-
/** Self-reported memory footprint estimate, in bytes. Optional. */
|
|
60
|
-
memoryBytes?: number;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* What kind of primitive an introspection snapshot describes. Matches
|
|
64
|
-
* the kit's `IntrospectionKind` and the routing the topology aggregator
|
|
65
|
-
* does when bucketing adapters vs plugins vs middleware vs contributor
|
|
66
|
-
* primitives.
|
|
67
|
-
*/
|
|
68
|
-
type IntrospectionKind = 'plugin' | 'adapter' | 'middleware' | 'contributor';
|
|
69
|
-
/**
|
|
70
|
-
* Convenience function signature for adopter-side helpers that return
|
|
71
|
-
* a complete snapshot. Used by the optional `introspect?()` hook on
|
|
72
|
-
* `AppAdapter` and `KickPlugin`.
|
|
73
|
-
*/
|
|
74
|
-
type IntrospectFn = () => IntrospectionSnapshot | Promise<IntrospectionSnapshot>;
|
|
75
|
-
//#endregion
|
|
76
|
-
//#region src/core/augmentation.d.ts
|
|
77
|
-
/**
|
|
78
|
-
* Augmentation registry — runtime no-op + the canonical
|
|
79
|
-
* `KickJsPluginRegistry` interface that `kick typegen` augments.
|
|
80
|
-
*
|
|
81
|
-
* See `architecture.md` §21.2.1 (typegen for `dependsOn`) and §21.3.3
|
|
82
|
-
* (standardized augmentation registry) for the design rationale.
|
|
83
|
-
*
|
|
84
|
-
* @module @forinda/kickjs/core/augmentation
|
|
85
|
-
*/
|
|
86
|
-
/**
|
|
87
|
-
* Marker interface that lists every plugin/adapter in the project. The
|
|
88
|
-
* keys are the literal `name` field passed to `defineAdapter` /
|
|
89
|
-
* `definePlugin` (or declared on a `class implements AppAdapter`); the
|
|
90
|
-
* values are the kind tag (`'plugin' | 'adapter'`).
|
|
91
|
-
*
|
|
92
|
-
* The framework ships this empty. `kick typegen` augments it from
|
|
93
|
-
* source so `keyof KickJsPluginRegistry` resolves to a string-literal
|
|
94
|
-
* union of every name in scope — and therefore so do `dependsOn`
|
|
95
|
-
* declarations on plugins/adapters.
|
|
96
|
-
*/
|
|
97
|
-
interface KickJsPluginRegistry {}
|
|
98
|
-
/**
|
|
99
|
-
* Resolves to a string-literal union of every registered plugin/adapter
|
|
100
|
-
* name when the project's typegen has populated `KickJsPluginRegistry`,
|
|
101
|
-
* or to `string` when the registry is empty (no typegen pass yet).
|
|
102
|
-
*
|
|
103
|
-
* Falling back to `string` keeps fresh projects compiling — the typegen
|
|
104
|
-
* narrowing is a progressive enhancement, not a hard prerequisite.
|
|
105
|
-
*/
|
|
106
|
-
type KickJsPluginName = keyof KickJsPluginRegistry extends never ? string : keyof KickJsPluginRegistry & string;
|
|
107
|
-
/**
|
|
108
|
-
* Metadata attached to a `defineAugmentation` call. The fields are
|
|
109
|
-
* documentation-only — `kick typegen` surfaces them in the generated
|
|
110
|
-
* `.kickjs/types/augmentations.d.ts` so adopters can browse every
|
|
111
|
-
* augmentable interface from one place.
|
|
112
|
-
*
|
|
113
|
-
* `description` and `example` may both be multi-line — typegen preserves
|
|
114
|
-
* line breaks when rendering them as JSDoc. There is no upper limit on
|
|
115
|
-
* the example size; entire shape definitions or worked snippets are fine.
|
|
116
|
-
*/
|
|
117
|
-
interface AugmentationMeta {
|
|
118
|
-
/**
|
|
119
|
-
* Free-form description of what the augmentation customises. May be
|
|
120
|
-
* multi-line — newlines are preserved in the generated JSDoc.
|
|
121
|
-
*/
|
|
122
|
-
description?: string;
|
|
123
|
-
/**
|
|
124
|
-
* TS snippet showing a typical shape. May be multi-line; rendered
|
|
125
|
-
* inside a fenced code block in the generated catalogue. Use this
|
|
126
|
-
* for anything from `'{ foo: string }'` up to a full interface body
|
|
127
|
-
* — typegen no longer flattens newlines.
|
|
128
|
-
*/
|
|
129
|
-
example?: string;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Advertise an augmentable interface so `kick typegen` can list it in
|
|
133
|
-
* `.kickjs/types/augmentations.d.ts` for project-wide discovery.
|
|
134
|
-
*
|
|
135
|
-
* **This function is a runtime AND type-level no-op.** It does NOT
|
|
136
|
-
* augment the interface for TypeScript. The actual augmentation is
|
|
137
|
-
* the `declare module` block — `defineAugmentation` only adds an
|
|
138
|
-
* entry to the typegen catalogue so other contributors / adopters
|
|
139
|
-
* can find the interface and know its expected shape.
|
|
140
|
-
*
|
|
141
|
-
* Both calls are needed:
|
|
142
|
-
*
|
|
143
|
-
* ```ts
|
|
144
|
-
* import { defineAugmentation } from '@forinda/kickjs'
|
|
145
|
-
*
|
|
146
|
-
* // (1) The actual TS augmentation — what `ctx.get('tenant')` reads.
|
|
147
|
-
* declare module '@forinda/kickjs' {
|
|
148
|
-
* interface ContextMeta {
|
|
149
|
-
* tenant: { id: string; name: string }
|
|
150
|
-
* }
|
|
151
|
-
* }
|
|
152
|
-
*
|
|
153
|
-
* // (2) Catalogue entry — what `kick typegen` lists in
|
|
154
|
-
* // `.kickjs/types/augmentations.d.ts` for browseability.
|
|
155
|
-
* defineAugmentation('ContextMeta', {
|
|
156
|
-
* description: 'Tenant resolved from x-tenant-id by TenantAdapter',
|
|
157
|
-
* example: `{
|
|
158
|
-
* tenant: {
|
|
159
|
-
* id: string
|
|
160
|
-
* name: string
|
|
161
|
-
* plan: 'free' | 'pro' | 'enterprise'
|
|
162
|
-
* featureFlags: Record<string, boolean>
|
|
163
|
-
* }
|
|
164
|
-
* }`,
|
|
165
|
-
* })
|
|
166
|
-
* ```
|
|
167
|
-
*
|
|
168
|
-
* Skip `defineAugmentation` if you don't care about the catalogue — the
|
|
169
|
-
* `declare module` block alone is enough for runtime + type behaviour.
|
|
170
|
-
*
|
|
171
|
-
* @deprecated Low value in practice: it does nothing at runtime or at
|
|
172
|
-
* the type level — the `declare module` block alone gives you the
|
|
173
|
-
* augmentation, and the generated `.kickjs/types/kick__augmentations.d.ts`
|
|
174
|
-
* catalogue it feeds is documentation-only. Prefer a plain
|
|
175
|
-
* `declare module '@forinda/kickjs' { ... }` block and (optionally) a
|
|
176
|
-
* JSDoc comment on your own interface. `defineAugmentation` and the
|
|
177
|
-
* `kick/augmentations` typegen plugin will be removed in a future major.
|
|
178
|
-
*/
|
|
179
|
-
declare function defineAugmentation(name: string, meta?: AugmentationMeta): void;
|
|
180
|
-
//#endregion
|
|
181
|
-
//#region src/core/adapter.d.ts
|
|
182
|
-
/**
|
|
183
|
-
* Where in the middleware pipeline an adapter's middleware should be inserted.
|
|
184
|
-
*
|
|
185
|
-
* - `beforeGlobal` — runs **before** any user-defined global middleware.
|
|
186
|
-
* Suitable for transport-level concerns (request tagging, low-level
|
|
187
|
-
* request rewriting). Fires on every request.
|
|
188
|
-
* - `afterGlobal` — runs **after** global middleware, **before** module
|
|
189
|
-
* routes are matched. Default for most adapter middleware (auth pre-checks,
|
|
190
|
-
* tenant resolution, body shaping). Fires on every request.
|
|
191
|
-
* - `beforeRoutes` — runs just before module routes are mounted. Functionally
|
|
192
|
-
* equivalent to `afterGlobal` for most cases; the explicit phase exists so
|
|
193
|
-
* adapters that *must* sit at the very end of the pre-route stack can
|
|
194
|
-
* declare intent. Fires on every request.
|
|
195
|
-
* - `afterRoutes` — sits **after** module routes but **before** error
|
|
196
|
-
* handlers. **Fires only on fall-through** — when no route matched (404
|
|
197
|
-
* path) or a route handler called `next()` without ending the response.
|
|
198
|
-
* Controllers that respond with `ctx.json(...)` end the chain and skip
|
|
199
|
-
* this phase, so it is *not* a "post-response" hook. For per-response
|
|
200
|
-
* work (logging, metrics) use `res.on('finish', ...)` from inside an
|
|
201
|
-
* earlier-phase middleware instead.
|
|
202
|
-
*/
|
|
203
|
-
type MiddlewarePhase = 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes';
|
|
204
|
-
/**
|
|
205
|
-
* Path scope for an {@link AdapterMiddleware} entry. Mirrors what
|
|
206
|
-
* Express's `app.use(path, handler)` accepts so adapters get the full
|
|
207
|
-
* range without learning a new mini-language:
|
|
208
|
-
*
|
|
209
|
-
* - A `string` prefix — `'/api'` matches `/api`, `/api/v1`, `/api/v1/x`.
|
|
210
|
-
* - A `RegExp` — `/^\/api\/v\d+/` matches `/api/v1`, `/api/v42`.
|
|
211
|
-
* - An array of either — `['/api', '/admin']` matches either prefix;
|
|
212
|
-
* `['/api', /^\/internal\//]` mixes shapes.
|
|
213
|
-
*
|
|
214
|
-
* Omit to apply the middleware unconditionally (Express `app.use(handler)`).
|
|
215
|
-
*/
|
|
216
|
-
type MiddlewarePath = string | RegExp | ReadonlyArray<string | RegExp>;
|
|
217
|
-
/** A middleware entry contributed by an adapter */
|
|
218
|
-
interface AdapterMiddleware {
|
|
219
|
-
/**
|
|
220
|
-
* Express handler: either a `RequestHandler` (`(req, res, next) => …`)
|
|
221
|
-
* or an `ErrorRequestHandler` (`(err, req, res, next) => …`).
|
|
222
|
-
* Express dispatches based on arity, so the same field accepts both
|
|
223
|
-
* without a discriminant.
|
|
224
|
-
*/
|
|
225
|
-
handler: RequestHandler | ErrorRequestHandler;
|
|
226
|
-
/** Which phase to insert into (default: 'afterGlobal') */
|
|
227
|
-
phase?: MiddlewarePhase;
|
|
228
|
-
/**
|
|
229
|
-
* Optional path scope. See {@link MiddlewarePath} for the accepted
|
|
230
|
-
* shapes (string prefix, RegExp, or an array mixing both). Omit to
|
|
231
|
-
* apply the middleware to every request that reaches this phase.
|
|
232
|
-
*/
|
|
233
|
-
path?: MiddlewarePath;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Context passed to adapter lifecycle hooks.
|
|
237
|
-
* Populated by the Application — provides access to the Express app,
|
|
238
|
-
* DI container, http.Server, and environment info without requiring
|
|
239
|
-
* external type imports. Cast `app` or `server` if you need specific types.
|
|
240
|
-
*
|
|
241
|
-
* @example
|
|
242
|
-
* ```ts
|
|
243
|
-
* beforeMount({ app, container }: AdapterContext) {
|
|
244
|
-
* app.use(myMiddleware())
|
|
245
|
-
* }
|
|
246
|
-
* ```
|
|
247
|
-
*/
|
|
248
|
-
interface AdapterContext {
|
|
249
|
-
/** Express application instance — fully typed */
|
|
250
|
-
app: Express;
|
|
251
|
-
/** DI container */
|
|
252
|
-
container: Container;
|
|
253
|
-
/** Node.js http.Server — only available in afterStart */
|
|
254
|
-
server?: http.Server;
|
|
255
|
-
/** Current NODE_ENV value (default: 'development') */
|
|
256
|
-
env: string;
|
|
257
|
-
/** true when NODE_ENV === 'production' */
|
|
258
|
-
isProduction: boolean;
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Adapters plug into the Application lifecycle.
|
|
262
|
-
* Implement this to add WebSocket, database, rate limiting, docs, etc.
|
|
263
|
-
*
|
|
264
|
-
* All hooks receive an `AdapterContext` populated by the framework.
|
|
265
|
-
* No external type imports needed — the context is fully typed from KickJS internals.
|
|
266
|
-
*
|
|
267
|
-
* @example
|
|
268
|
-
* ```ts
|
|
269
|
-
* import type { AppAdapter, AdapterContext } from '@forinda/kickjs/adapter'
|
|
270
|
-
*
|
|
271
|
-
* class SentryAdapter implements AppAdapter {
|
|
272
|
-
* name = 'SentryAdapter'
|
|
273
|
-
*
|
|
274
|
-
* beforeMount({ app, container }: AdapterContext) {
|
|
275
|
-
* app.use(Sentry.expressRequestHandler())
|
|
276
|
-
* }
|
|
277
|
-
*
|
|
278
|
-
* afterStart({ server }: AdapterContext) {
|
|
279
|
-
* // server is the http.Server — available after listen()
|
|
280
|
-
* }
|
|
281
|
-
*
|
|
282
|
-
* async shutdown() {
|
|
283
|
-
* await Sentry.close(2000)
|
|
284
|
-
* }
|
|
285
|
-
* }
|
|
286
|
-
* ```
|
|
287
|
-
*/
|
|
288
|
-
interface AppAdapter {
|
|
289
|
-
/**
|
|
290
|
-
* Human-readable name for logging and `dependsOn` resolution.
|
|
291
|
-
* Required when the adapter (or any other in the same set) declares
|
|
292
|
-
* `dependsOn` — sort errors will reference adapters by name.
|
|
293
|
-
*/
|
|
294
|
-
name?: string;
|
|
295
|
-
/**
|
|
296
|
-
* Other adapter names that must mount before this one. The framework
|
|
297
|
-
* topologically sorts adapters at boot — cycles or unknown names throw
|
|
298
|
-
* via `MountCycleError` / `MissingMountDepError` so bad configurations
|
|
299
|
-
* fail boot rather than corrupt live traffic.
|
|
300
|
-
*
|
|
301
|
-
* Common pattern: `TenantAdapter` populates `req.tenant` and
|
|
302
|
-
* `AuthAdapter` reads it for tenant-scoped RBAC, so AuthAdapter
|
|
303
|
-
* declares `dependsOn = ['TenantAdapter']`. Adapters without
|
|
304
|
-
* `dependsOn` retain their declaration order.
|
|
305
|
-
*
|
|
306
|
-
* @example
|
|
307
|
-
* ```ts
|
|
308
|
-
* class AuthAdapter implements AppAdapter {
|
|
309
|
-
* name = 'AuthAdapter'
|
|
310
|
-
* dependsOn = ['TenantAdapter']
|
|
311
|
-
* }
|
|
312
|
-
* ```
|
|
313
|
-
*/
|
|
314
|
-
dependsOn?: readonly KickJsPluginName[];
|
|
315
|
-
/**
|
|
316
|
-
* Return middleware entries to be inserted into the pipeline.
|
|
317
|
-
* The `phase` controls ordering relative to global middleware and routes.
|
|
318
|
-
*/
|
|
319
|
-
middleware?(): AdapterMiddleware[];
|
|
320
|
-
/**
|
|
321
|
-
* Return Context Contributors (#107) that apply to every route in the
|
|
322
|
-
* application. Adapter-level contributors merge into the per-route
|
|
323
|
-
* pipeline at the `'adapter'` precedence level — they win over global
|
|
324
|
-
* contributors but lose to module, class, and method decorators.
|
|
325
|
-
*
|
|
326
|
-
* Useful for cross-cutting concerns: an auth adapter contributing
|
|
327
|
-
* `user`, a multi-tenant adapter contributing `tenant`, etc. Optional.
|
|
328
|
-
*/
|
|
329
|
-
contributors?(): ContributorRegistrations;
|
|
330
|
-
/**
|
|
331
|
-
* Called before global middleware — register early routes (docs UI, health).
|
|
332
|
-
* May return a Promise — async rejections are caught and logged.
|
|
333
|
-
*/
|
|
334
|
-
beforeMount?(ctx: AdapterContext): void | Promise<void>;
|
|
335
|
-
/**
|
|
336
|
-
* Called for each module route that gets mounted.
|
|
337
|
-
* Use this to collect route metadata (e.g. for OpenAPI spec generation).
|
|
338
|
-
*/
|
|
339
|
-
onRouteMount?(controllerClass: Constructor, mountPath: string): void;
|
|
340
|
-
/**
|
|
341
|
-
* Called after modules are registered and the DI container is bootstrapped,
|
|
342
|
-
* before the HTTP server starts listening. **This is the correct hook for
|
|
343
|
-
* adapters that register DI bindings, resolve services, or otherwise prepare
|
|
344
|
-
* container-side state** (e.g. `container.registerInstance(MAILER, ...)`).
|
|
345
|
-
*
|
|
346
|
-
* `beforeStart` runs inside `app.setup()`, which means it also fires under
|
|
347
|
-
* `createTestApp` — adapters using this hook work in unit tests without
|
|
348
|
-
* needing a live HTTP server. See {@link afterStart} for the contrast.
|
|
349
|
-
*
|
|
350
|
-
* May return a Promise — async rejections are caught and logged.
|
|
351
|
-
*/
|
|
352
|
-
beforeStart?(ctx: AdapterContext): void | Promise<void>;
|
|
353
|
-
/**
|
|
354
|
-
* Called after the HTTP server is listening — `ctx.server` is the live
|
|
355
|
-
* `http.Server`. **Use this hook only for work that genuinely needs a
|
|
356
|
-
* listening server**: attaching Socket.IO / WS upgrades, reading the bound
|
|
357
|
-
* port via `server.address()`, dispatching to the local server over HTTP,
|
|
358
|
-
* etc.
|
|
359
|
-
*
|
|
360
|
-
* `afterStart` does NOT fire under `createTestApp`, since tests call
|
|
361
|
-
* `app.setup()` and never `app.start()`. If your adapter only registers DI
|
|
362
|
-
* bindings or resolves services, use {@link beforeStart} — that hook runs
|
|
363
|
-
* in both production (`start()`) and tests (`setup()`).
|
|
364
|
-
*
|
|
365
|
-
* May return a Promise — async rejections are caught and logged.
|
|
366
|
-
*/
|
|
367
|
-
afterStart?(ctx: AdapterContext): void | Promise<void>;
|
|
368
|
-
/**
|
|
369
|
-
* Called by the /health/ready endpoint. Return the health status of your adapter's
|
|
370
|
-
* backing service (database, Redis, queue, etc.).
|
|
371
|
-
*/
|
|
372
|
-
onHealthCheck?(): Promise<{
|
|
373
|
-
name: string;
|
|
374
|
-
status: 'up' | 'down';
|
|
375
|
-
}>;
|
|
376
|
-
/** Called on shutdown — clean up connections */
|
|
377
|
-
shutdown?(): MaybePromise;
|
|
378
|
-
/**
|
|
379
|
-
* Optional DevTools introspection hook (architecture.md §23). Returns
|
|
380
|
-
* a snapshot describing this adapter's current state, metrics, and DI
|
|
381
|
-
* tokens. DevTools awaits the result, so async work is fine — but keep
|
|
382
|
-
* the implementation cheap (counters + flags, no DB round trips) since
|
|
383
|
-
* the topology endpoint polls on a short interval.
|
|
384
|
-
*
|
|
385
|
-
* The return type lives in `@forinda/kickjs` itself ({@link IntrospectionSnapshot})
|
|
386
|
-
* so adopters can author `introspect()` without importing the kit just
|
|
387
|
-
* to satisfy the contract. The kit's own `IntrospectionSnapshot` type
|
|
388
|
-
* stays structurally identical; either import works.
|
|
389
|
-
*/
|
|
390
|
-
introspect?(): IntrospectionSnapshot | Promise<IntrospectionSnapshot>;
|
|
391
|
-
/**
|
|
392
|
-
* Optional DevTools tabs this adapter contributes (architecture.md §23).
|
|
393
|
-
* Returns an array of `DevtoolsTabDescriptor` shapes — typically one
|
|
394
|
-
* entry per adapter-owned panel (iframe / launch / html view).
|
|
395
|
-
*
|
|
396
|
-
* Same untyped-at-this-layer convention as {@link introspect}: adapter
|
|
397
|
-
* authors import `defineDevtoolsTab` (or the bare type) from
|
|
398
|
-
* `@forinda/kickjs-devtools-kit` so `@forinda/kickjs` doesn't take on
|
|
399
|
-
* a runtime dep on the kit.
|
|
400
|
-
*/
|
|
401
|
-
devtoolsTabs?(): readonly unknown[];
|
|
402
|
-
}
|
|
403
|
-
/** Constructor type for AppAdapter classes */
|
|
404
|
-
type AppAdapterClass = new () => AppAdapter;
|
|
405
|
-
//#endregion
|
|
406
|
-
export { MiddlewarePath as a, KickJsPluginName as c, IntrospectFn as d, IntrospectionKind as f, AppAdapterClass as i, KickJsPluginRegistry as l, AdapterMiddleware as n, MiddlewarePhase as o, IntrospectionSnapshot as p, AppAdapter as r, AugmentationMeta as s, AdapterContext as t, defineAugmentation as u };
|
|
407
|
-
//# sourceMappingURL=adapter-CkpcZwzZ.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter-CkpcZwzZ.d.mts","names":[],"sources":["../src/core/introspect.ts","../src/core/augmentation.ts","../src/core/adapter.ts"],"mappings":";;;;;;;;;;;;;;;AAkBA;;;;;;;;;;;UAAiB,qBAAA;EAgBf;;;;;;;;;EANA,eAAA;EAoBW;EAlBX,IAAA;EA2B2B;EAzB3B,IAAA,EAAM,iBAAA;EAyBqB;EAvB3B,OAAA;EA8BU;;;;EAzBV,KAAA,GAAQ,MAAA;EAyB+C;EAvBvD,MAAA;IAAW,QAAA;IAA6B,QAAA;EAAA;EAuBuB;;AAAqB;;EAlBpF,OAAA,GAAU,MAAA;;EAEV,WAAA;AAAA;;;AC3BmC;AAUrC;;;KD0BY,iBAAA;ACxBkB;AAY9B;;;;AAZ8B,KD+BlB,YAAA,SAAqB,qBAAA,GAAwB,OAAA,CAAQ,qBAAA;;;;;;;;;;AA9CjE;;;;;;;;;;;;;UCGiB,oBAAA;;;;;;;;AD2BJ;KCjBD,gBAAA,SAAyB,oBAAA,gCAE3B,oBAAoB;;;;ADwBD;AAO7B;;;;;;UCnBiB,gBAAA;EDmB+C;;;;ECd9D,WAAA;EDcoF;;;;AC3CtF;;EAoCE,OAAO;AAAA;AApC4B;AAUrC;;;;AAE8B;AAY9B;;;;AAYS;AAmDT;;;;;;;;AAAwE;;;;AC/ExE;;;;AAA2B;AAc3B;;;;;;;;;;;;AAA4E;AAG5E;;;;;;;ADzBqC,iBAuFrB,kBAAA,CAAmB,IAAA,UAAc,IAAA,GAAO,gBAAgB;;;AD1FxE;;;;;;;;;;;;;;;;;;;;;AAAA,KEWY,eAAA;AFmBC;AASb;;;;AAA6B;AAO7B;;;;;;AAhBa,KELD,cAAA,YAA0B,MAAA,GAAS,aAAA,UAAuB,MAAA;;UAGrD,iBAAA;EFkBwC;;;AAA6B;;;EEXpF,OAAA,EAAS,cAAA,GAAiB,mBAAA;EDhCX;ECkCf,KAAA,GAAQ,eAAA;;;ADlC2B;AAUrC;;EC8BE,IAAA,GAAO,cAAA;AAAA;AD5BqB;AAY9B;;;;AAYS;AAmDT;;;;;;;AA3E8B,UC4Cb,cAAA;ED+BuD;EC7BtE,GAAA,EAAK,OAAA;;EAEL,SAAA,EAAW,SAAA;EApDD;EAsDV,MAAA,GAAS,IAAA,CAAK,MAAA;;EAEd,GAAA;EAxDyB;EA0DzB,YAAA;AAAA;;;;;;;;;;;AA5C0E;AAG5E;;;;;;;;;;;;;;;;;UAwEiB,UAAA;EAzCA;;;;;EA+Cf,IAAA;EAzCoB;;;;;;;;;;;;AAIR;AA+Bd;;;;;;EA2BE,SAAA,YAAqB,gBAAA;EAuBqB;;;;EAjB1C,UAAA,KAAe,iBAAA;EAqD0B;;;;;;;;;EA1CzC,YAAA,KAAiB,wBAAA;EAjBI;;;;EAuBrB,WAAA,EAAa,GAAA,EAAK,cAAA,UAAwB,OAAA;EAA1C;;;;EAMA,YAAA,EAAc,eAAA,EAAiB,WAAA,EAAa,SAAA;EAAb;;;;;;;;;;;;EAc/B,WAAA,EAAa,GAAA,EAAK,cAAA,UAAwB,OAAA;EAsBd;;;;;;;;;;AA6BhB;AAId;;;EAvCE,UAAA,EAAY,GAAA,EAAK,cAAA,UAAwB,OAAA;EAuCO;;;;EAjChD,aAAA,KAAkB,OAAA;IAAU,IAAA;IAAc,MAAA;EAAA;;EAG1C,QAAA,KAAa,YAAA;;;;;;;;;;;;;EAcb,UAAA,KAAe,qBAAA,GAAwB,OAAA,CAAQ,qBAAA;;;;;;;;;;;EAY/C,YAAA;AAAA;;KAIU,eAAA,aAA4B,UAAU"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { t as Container } from "./container-TWOUyR_0.mjs";
|
|
3
|
-
import { s as ContributorRegistrations } from "./context-decorator-DDZ30BIW.mjs";
|
|
4
|
-
|
|
5
|
-
//#region src/core/app-module.d.ts
|
|
6
|
-
/**
|
|
7
|
-
* Route set returned by a module's routes() method.
|
|
8
|
-
* Combined with versioning: /{apiPrefix}/v{version}{path}
|
|
9
|
-
*
|
|
10
|
-
* **Either** `controller` or `router` is required. Pass `controller`
|
|
11
|
-
* for the common case — the framework calls `buildRoutes(controller)`
|
|
12
|
-
* internally to derive the Express Router. Pass `router` directly
|
|
13
|
-
* only when you need to compose multiple controllers under one path
|
|
14
|
-
* or hand-build the router yourself.
|
|
15
|
-
*/
|
|
16
|
-
interface ModuleRoutes {
|
|
17
|
-
/** URL prefix (e.g. '/users') */
|
|
18
|
-
path: string;
|
|
19
|
-
/**
|
|
20
|
-
* Express Router instance. Optional — when omitted, the framework
|
|
21
|
-
* builds one from `controller` via `buildRoutes(controller)`. Pass
|
|
22
|
-
* an explicit router only when you need to compose multiple
|
|
23
|
-
* controllers or hand-roll the router shape.
|
|
24
|
-
*/
|
|
25
|
-
router?: any;
|
|
26
|
-
/** Optional API version override (defaults to Application.defaultVersion) */
|
|
27
|
-
version?: number;
|
|
28
|
-
/**
|
|
29
|
-
* Controller class. Required unless `router` is provided. Used both
|
|
30
|
-
* for the auto-derived router (via `buildRoutes(controller)`) and
|
|
31
|
-
* for OpenAPI spec generation via `SwaggerAdapter`.
|
|
32
|
-
*/
|
|
33
|
-
controller?: any;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Interface that every feature module must implement.
|
|
37
|
-
* Modules register their DI bindings and declare their routes.
|
|
38
|
-
*
|
|
39
|
-
* `register` is **optional**. Modules that only contain decorated classes
|
|
40
|
-
* (`@Service`, `@Controller`, `@Repository`, `@Component`) don't need it
|
|
41
|
-
* because the decorators handle DI registration automatically. Implement
|
|
42
|
-
* `register(container)` only when you need to bind a token (typically a
|
|
43
|
-
* repository interface symbol) to a concrete implementation via
|
|
44
|
-
* `container.registerFactory()` / `container.registerInstance()`.
|
|
45
|
-
*/
|
|
46
|
-
interface AppModule {
|
|
47
|
-
/** Optional — bind interfaces to implementations in the container */
|
|
48
|
-
register?(container: Container): void;
|
|
49
|
-
/**
|
|
50
|
-
* Return Context Contributors (#107) that apply to every route this
|
|
51
|
-
* module mounts. Module-level contributors are merged into the per-route
|
|
52
|
-
* pipeline at the `'module'` precedence level — they win over adapter
|
|
53
|
-
* and global contributors but lose to method and class decorators.
|
|
54
|
-
*
|
|
55
|
-
* Optional — modules without per-module contributors omit this hook.
|
|
56
|
-
*/
|
|
57
|
-
contributors?(): ContributorRegistrations;
|
|
58
|
-
/** Return route definitions for this module, or null for non-HTTP modules */
|
|
59
|
-
routes(): ModuleRoutes | ModuleRoutes[] | null;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Constructor type for the legacy `class FooModule implements AppModule`
|
|
63
|
-
* pattern. The framework still accepts these — bootstrap discriminates
|
|
64
|
-
* class vs instance at boot — but new code should prefer
|
|
65
|
-
* {@link defineModule} for parity with {@link defineAdapter} and
|
|
66
|
-
* {@link definePlugin}, plus typed config + `.scoped()` / `.definition`.
|
|
67
|
-
*
|
|
68
|
-
* @deprecated Use `defineModule({ ... })` and `AppModuleEntry` for the
|
|
69
|
-
* `bootstrap({ modules })` array. The class form continues to work
|
|
70
|
-
* through v5 and is not slated for removal in any specific release —
|
|
71
|
-
* this annotation is a soft "prefer the factory form" hint, not an
|
|
72
|
-
* imminent deprecation.
|
|
73
|
-
*/
|
|
74
|
-
type AppModuleClass = new () => AppModule;
|
|
75
|
-
/**
|
|
76
|
-
* Either form accepted by `bootstrap({ modules })` and
|
|
77
|
-
* `KickPlugin.modules?()`:
|
|
78
|
-
*
|
|
79
|
-
* - **Class** — the legacy form. Bootstrap calls `new ModuleClass()`.
|
|
80
|
-
* - **Instance** — produced by {@link defineModule}'s factory call
|
|
81
|
-
* (e.g. `TasksModule({ scope: 'admin' })`). Bootstrap uses it
|
|
82
|
-
* directly without `new`.
|
|
83
|
-
*
|
|
84
|
-
* Both shapes route through the same lifecycle (`register`,
|
|
85
|
-
* `contributors`, `routes`) — the only difference is who owns
|
|
86
|
-
* instantiation. defineModule callers use this union so adopters can
|
|
87
|
-
* mix-and-match in the same `modules` array.
|
|
88
|
-
*/
|
|
89
|
-
type AppModuleEntry = AppModuleClass | AppModule;
|
|
90
|
-
//#endregion
|
|
91
|
-
export { ModuleRoutes as i, AppModuleClass as n, AppModuleEntry as r, AppModule as t };
|
|
92
|
-
//# sourceMappingURL=app-module-BTzb-Vd6.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"app-module-BTzb-Vd6.d.mts","names":[],"sources":["../src/core/app-module.ts"],"mappings":";;;;;;;AAaA;;;;;;;;UAAiB,YAAA;EAiBL;EAfV,IAAA;EA6BwB;;;;;;EAtBxB,MAAA;EAmCqC;EAjCrC,OAAA;EAsBqB;;;;;EAhBrB,UAAA;AAAA;;AA2BqC;AAgBvC;;;;AAAgD;AAgBhD;;;;UA7CiB,SAAA;;EAEf,QAAA,EAAU,SAAA,EAAW,SAAA;;;;;;;;;EASrB,YAAA,KAAiB,wBAAA;;EAEjB,MAAA,IAAU,YAAA,GAAe,YAAA;AAAA;;;;;;;;;;;;;;KAgBf,cAAA,aAA2B,SAAS;;;;;;;;;;;;;;;KAgBpC,cAAA,GAAiB,cAAA,GAAiB,SAAS"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"application-CAnpDQ8d.d.mts","names":[],"sources":["../src/http/application.ts"],"mappings":";;;;;;;;;;;;;;KAqCY,eAAA,GAAkB,cAAA;EAAmB,IAAA;EAAc,OAAA,EAAS,cAAc;AAAA;AAAA,UAErE,kBAAA;;;;;;;;AAFqE;AAEtF;;EAWE,OAAA,EAAS,cAAA;EAAA;;;;;;;;;;;;;;;;;EAmBT,KAAA,EAAO,QAAA,EAAU,cAAA;EAQjB;EANA,QAAA,GAAW,UAAA;EA6BG;EA3Bd,IAAA;EAiCa;EA/Bb,SAAA;EAkCU;EAhCV,cAAA;EAsDe;;;;;;;;;;;;;;;;;;;;;EA/Bf,WAAA,GAAc,eAAA;EAiLZ;;AAAM;AAQV;;EAnLE,UAAA,GAAa,eAAA;EAqNyB;EAlNtC,OAAA,GAAU,UAAA;EAmRE;;;;;;;;;;;;;;;;;;;;EA7PZ,YAAA,GAAe,wBAAA;EAoLP;;;;;;;;;;;;;;;;;;EAhKR,YAAA;EAyO4D;;;;;;;;;;;;;;;;;;;;;;;;;EA9M5D,YAAA;EAy0BiB;EAt0BjB,UAAA,iCAA2C,EAAA,UAAY,QAAA;EAy1B/C;EAv1BR,SAAA;EAq3BQ;;;;;AA+CoB;;EA55B5B,aAAA;;;;;EAKA,cAAA;;;;;EAKA,eAAA;;;;;;;;;;;;;;;;;;;EAoBA,OAAA;IAAsB,OAAA;EAAA;;;;;;;;;;;;;;;;EAiBtB,UAAA,IAAc,GAAA,OAAU,GAAA,OAAU,IAAA;;;;;;;;;;;;;;;;;EAkBlC,OAAA,IAAW,GAAA,OAAU,GAAA,OAAU,GAAA,OAAU,IAAA;;;;;;;;;;;;;;;;;;EAmBzC,QAAA;6DAEE,MAAA;EAAA;AAAA;;;;;cAQS,WAAA;EAAA,iBAkCkB,OAAA;EAAA,QAjCrB,GAAA;EAAA,QACA,SAAA;EAAA,QACA,UAAA;EAAA,iBACS,QAAA;EAAA,iBAEA,OAAA;;;;;;;;;;;;;UAcT,mBAAA;;UAMA,iBAAA;;UAEA,SAAA;;UAEA,kBAAA;;UAEA,eAAA;EAER,WAAA,CAA6B,OAAA,EAAS,kBAAA;;MAqClC,UAAA;;MAKA,gBAAA;;EAKJ,YAAA,IAAgB,SAAA;;;;;;;;;;;;;;;EAkBhB,MAAA,CAAO,GAAA,EAAK,IAAA,CAAK,eAAA,EAAiB,GAAA,EAAK,IAAA,CAAK,cAAA,EAAgB,IAAA,IAAQ,GAAA;;;;;;;;;;;;;;;UAsB5D,UAAA;;UAYM,QAAA;EAeR,KAAA,IAAS,OAAA;;EA0TT,YAAA,IAAgB,OAAA;;;;;;;;;;EAahB,KAAA,IAAS,OAAA;;EA0ET,OAAA,IAAW,OAAA;;;;;;;;;;;EAoCX,QAAA,IAAY,OAAA;EAgElB,aAAA,IAAiB,OAAA;;EAKjB,WAAA,IAAe,UAAA;;;;;;EASf,UAAA,aAAuB,UAAA;;;;;;;;;;;;;;;;;;;EAsBvB,eAAA,IAAmB,aAAA;IACjB,GAAA;IACA,MAAA;IACA,KAAA;IACA,SAAA;EAAA;EA6CF,aAAA,IAAiB,IAAA,CAAK,MAAA;;;;;;;;;;;;;;UAmBd,2BAAA;EAAA,QAWA,wBAAA;EAAA,QAmBA,mBAAA;EAAA,QAgBA,oBAAA;;UASA,yBAAA;;UAsBA,oBAAA;AAAA"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @forinda/kickjs v5.16.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{n as tokenName,r as moduleRouteMissingControllerError,t as Container}from"./container-D1gfs6__.mjs";import{METADATA}from"./core/interfaces.mjs";import{Logger,createLogger}from"./core/logger.mjs";import{t as getClassMeta}from"./metadata-Cll3P0N0.mjs";import{g as MutableModuleRegistry,s as mountSort}from"./core-Db2uyqtM.mjs";import{normalizePath}from"./core/path.mjs";import{requestId}from"./http/middleware/request-id.mjs";import{errorHandler,notFoundHandler}from"./http/middleware/error-handler.mjs";import{i as requestStore}from"./context-MD7Mc_o_.mjs";import{_setExternalContributorSources,buildRoutes}from"./http/router-builder.mjs";import http from"node:http";import express from"express";import crypto from"node:crypto";const REQUEST_SCOPE_MIDDLEWARE_MARKER=Symbol.for(`@kickjs/requestScopeMiddleware`);function requestScopeMiddleware(){let mw=(req,_res,next)=>{let requestIdHeader=req.headers[`x-request-id`],requestId=(Array.isArray(requestIdHeader)?requestIdHeader[0]:requestIdHeader)||crypto.randomUUID(),store={requestId,instances:new Map,values:new Map};req.requestId=requestId,requestStore.run(store,()=>next())};return mw[REQUEST_SCOPE_MIDDLEWARE_MARKER]=!0,mw}function isRequestScopeMiddleware(value){return typeof value==`function`?value[REQUEST_SCOPE_MIDDLEWARE_MARKER]===!0:!1}const log=createLogger(`Application`);var Application=class{options;app;container;httpServer=null;adapters;plugins;_moduleContributors=[];_inFlightRequests=0;_draining=!1;_shutdownInitiated=!1;_drainResolvers=[];constructor(options){this.options=options,this.app=express(),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){next?this.app(req,res,next):this.app(req,res)}adapterCtx(server){let env=process.env.NODE_ENV??`development`;return{app:this.app,container:this.container,server,env,isProduction:env===`production`}}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.app.disable(`x-powered-by`),this.app.set(`trust proxy`,this.options.trustProxy??!1),this.app.use(this.requestTrackingMiddleware()),this.mountHealthEndpoints(),this.shouldAutoMountRequestScope()&&this.app.use(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.app.use(handler)}catch(err){log.error(err,`Plugin middleware failed: ${plugin.name??`unknown`}`)}if(this.options.security?.helmet!==!1)try{let{helmet:helmetFn}=await import(`./http/middleware/helmet.mjs`);this.app.use(helmetFn())}catch{}let userMiddlewares=this.options.middlewares??this.options.middleware;if(userMiddlewares)for(let entry of userMiddlewares)this.mountMiddlewareEntry(entry);else this.app.use(requestId()),this.app.use(express.json({limit:this.options.jsonLimit??`1mb`}));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);let modules=moduleRegistry.entries.map(entry=>{let mod=typeof entry==`function`?new entry: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=[];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 mountPath=`${apiPrefix}/v${route.version??defaultVersion}${normalizePath(route.path)}`,router=route.router??buildRoutes(route.controller);if(!router)throw moduleRouteMissingControllerError(mountPath);if(this.app.use(mountPath,router),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);this.app.use(this.options.onNotFound??notFoundHandler()),this.app.use(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.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;try{Container.reset(),this.container=Container.getInstance(),this.app=express(),await this.setup()}catch(err){log.error(err,`HMR rebuild failed, keeping previous app`),this.app=prevApp,this.container=prevContainer;return}this.httpServer&&(this.httpServer.removeAllListeners(`request`),this.httpServer.on(`request`,this.app),log.debug(`HMR: Express app rebuilt and swapped`))}async shutdown(){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(this.httpServer&&this.httpServer.close(()=>{}),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 results=await Promise.allSettled([...this.plugins.map(plugin=>Promise.resolve(plugin.shutdown?.())),...this.adapters.map(adapter=>Promise.resolve(adapter.shutdown?.()))]);for(let result of results)result.status===`rejected`&&log.error({err:result.reason},`Adapter shutdown failed`)}finally{timer&&clearTimeout(timer)}}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??this.options.middleware??[];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.app.use(entry.handler);continue}let path=Array.isArray(entry.path)?[...entry.path]:entry.path;this.app.use(path,entry.handler)}}mountMiddlewareEntry(entry){typeof entry==`function`?this.app.use(entry):this.app.use(entry.path,entry.handler)}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()}}mountHealthEndpoints(){this.app.get(`/health/live`,(_req,res)=>{this._draining?res.status(503).json({status:`draining`,uptime:process.uptime()}):res.json({status:`ok`,uptime:process.uptime()})}),this.app.get(`/health/ready`,async(_req,res)=>{if(this._draining){res.status(503).json({status:`draining`,checks:[]});return}let adaptersWithHealth=this.adapters.filter(a=>a.onHealthCheck),results=(await Promise.allSettled(adaptersWithHealth.map(a=>a.onHealthCheck()))).map((c,i)=>c.status===`fulfilled`?c.value:{name:adaptersWithHealth[i].name??`unknown`,status:`down`}),healthy=results.every(r=>r.status===`up`);res.status(healthy?200:503).json({status:healthy?`ready`:`degraded`,checks:results})})}};export{requestScopeMiddleware as n,Application as t};
|
|
12
|
-
//# sourceMappingURL=application-DnnqoDWx.mjs.map
|