@databehave/server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.md +87 -0
  4. package/dist/admin/admin-routes.d.ts +42 -0
  5. package/dist/admin/admin-routes.d.ts.map +1 -0
  6. package/dist/admin/admin-routes.js +472 -0
  7. package/dist/admin/admin-routes.js.map +1 -0
  8. package/dist/admin/admin-types.d.ts +170 -0
  9. package/dist/admin/admin-types.d.ts.map +1 -0
  10. package/dist/admin/admin-types.js +30 -0
  11. package/dist/admin/admin-types.js.map +1 -0
  12. package/dist/admin/banner.d.ts +11 -0
  13. package/dist/admin/banner.d.ts.map +1 -0
  14. package/dist/admin/banner.js +5 -0
  15. package/dist/admin/banner.js.map +1 -0
  16. package/dist/admin/header-parser.d.ts +14 -0
  17. package/dist/admin/header-parser.d.ts.map +1 -0
  18. package/dist/admin/header-parser.js +171 -0
  19. package/dist/admin/header-parser.js.map +1 -0
  20. package/dist/admin/inject.d.ts +48 -0
  21. package/dist/admin/inject.d.ts.map +1 -0
  22. package/dist/admin/inject.js +167 -0
  23. package/dist/admin/inject.js.map +1 -0
  24. package/dist/admin/overrides-store.d.ts +18 -0
  25. package/dist/admin/overrides-store.d.ts.map +1 -0
  26. package/dist/admin/overrides-store.js +100 -0
  27. package/dist/admin/overrides-store.js.map +1 -0
  28. package/dist/admin/resolve-cors.d.ts +22 -0
  29. package/dist/admin/resolve-cors.d.ts.map +1 -0
  30. package/dist/admin/resolve-cors.js +28 -0
  31. package/dist/admin/resolve-cors.js.map +1 -0
  32. package/dist/admin/scenarios-store.d.ts +15 -0
  33. package/dist/admin/scenarios-store.d.ts.map +1 -0
  34. package/dist/admin/scenarios-store.js +109 -0
  35. package/dist/admin/scenarios-store.js.map +1 -0
  36. package/dist/admin/ui.css +2 -0
  37. package/dist/admin/ui.html +13 -0
  38. package/dist/admin/ui.js +240 -0
  39. package/dist/bin-helpers.d.ts +46 -0
  40. package/dist/bin-helpers.d.ts.map +1 -0
  41. package/dist/bin-helpers.js +61 -0
  42. package/dist/bin-helpers.js.map +1 -0
  43. package/dist/bin.d.ts +3 -0
  44. package/dist/bin.d.ts.map +1 -0
  45. package/dist/bin.js +57 -0
  46. package/dist/bin.js.map +1 -0
  47. package/dist/cors.d.ts +57 -0
  48. package/dist/cors.d.ts.map +1 -0
  49. package/dist/cors.js +167 -0
  50. package/dist/cors.js.map +1 -0
  51. package/dist/define.d.ts +26 -0
  52. package/dist/define.d.ts.map +1 -0
  53. package/dist/define.js +55 -0
  54. package/dist/define.js.map +1 -0
  55. package/dist/index.d.ts +21 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +19 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/json-config.d.ts +170 -0
  60. package/dist/json-config.d.ts.map +1 -0
  61. package/dist/json-config.js +684 -0
  62. package/dist/json-config.js.map +1 -0
  63. package/dist/jsonc.d.ts +24 -0
  64. package/dist/jsonc.d.ts.map +1 -0
  65. package/dist/jsonc.js +125 -0
  66. package/dist/jsonc.js.map +1 -0
  67. package/dist/log.d.ts +57 -0
  68. package/dist/log.d.ts.map +1 -0
  69. package/dist/log.js +103 -0
  70. package/dist/log.js.map +1 -0
  71. package/dist/middleware/request-validation.d.ts +58 -0
  72. package/dist/middleware/request-validation.d.ts.map +1 -0
  73. package/dist/middleware/request-validation.js +328 -0
  74. package/dist/middleware/request-validation.js.map +1 -0
  75. package/dist/mock-mode.d.ts +95 -0
  76. package/dist/mock-mode.d.ts.map +1 -0
  77. package/dist/mock-mode.js +95 -0
  78. package/dist/mock-mode.js.map +1 -0
  79. package/dist/openapi/auto-schema.d.ts +83 -0
  80. package/dist/openapi/auto-schema.d.ts.map +1 -0
  81. package/dist/openapi/auto-schema.js +232 -0
  82. package/dist/openapi/auto-schema.js.map +1 -0
  83. package/dist/openapi/generate.d.ts +20 -0
  84. package/dist/openapi/generate.d.ts.map +1 -0
  85. package/dist/openapi/generate.js +121 -0
  86. package/dist/openapi/generate.js.map +1 -0
  87. package/dist/openapi/loader.d.ts +18 -0
  88. package/dist/openapi/loader.d.ts.map +1 -0
  89. package/dist/openapi/loader.js +25 -0
  90. package/dist/openapi/loader.js.map +1 -0
  91. package/dist/openapi/register.d.ts +58 -0
  92. package/dist/openapi/register.d.ts.map +1 -0
  93. package/dist/openapi/register.js +166 -0
  94. package/dist/openapi/register.js.map +1 -0
  95. package/dist/openapi/seed.d.ts +16 -0
  96. package/dist/openapi/seed.d.ts.map +1 -0
  97. package/dist/openapi/seed.js +58 -0
  98. package/dist/openapi/seed.js.map +1 -0
  99. package/dist/openapi/translate.d.ts +55 -0
  100. package/dist/openapi/translate.d.ts.map +1 -0
  101. package/dist/openapi/translate.js +319 -0
  102. package/dist/openapi/translate.js.map +1 -0
  103. package/dist/openapi/walker.d.ts +44 -0
  104. package/dist/openapi/walker.d.ts.map +1 -0
  105. package/dist/openapi/walker.js +15 -0
  106. package/dist/openapi/walker.js.map +1 -0
  107. package/dist/request.d.ts +19 -0
  108. package/dist/request.d.ts.map +1 -0
  109. package/dist/request.js +66 -0
  110. package/dist/request.js.map +1 -0
  111. package/dist/response.d.ts +13 -0
  112. package/dist/response.d.ts.map +1 -0
  113. package/dist/response.js +43 -0
  114. package/dist/response.js.map +1 -0
  115. package/dist/route-key.d.ts +60 -0
  116. package/dist/route-key.d.ts.map +1 -0
  117. package/dist/route-key.js +105 -0
  118. package/dist/route-key.js.map +1 -0
  119. package/dist/run.d.ts +27 -0
  120. package/dist/run.d.ts.map +1 -0
  121. package/dist/run.js +87 -0
  122. package/dist/run.js.map +1 -0
  123. package/dist/server.d.ts +60 -0
  124. package/dist/server.d.ts.map +1 -0
  125. package/dist/server.js +497 -0
  126. package/dist/server.js.map +1 -0
  127. package/dist/types.d.ts +274 -0
  128. package/dist/types.d.ts.map +1 -0
  129. package/dist/types.js +9 -0
  130. package/dist/types.js.map +1 -0
  131. package/dist/validation/validate.d.ts +38 -0
  132. package/dist/validation/validate.d.ts.map +1 -0
  133. package/dist/validation/validate.js +372 -0
  134. package/dist/validation/validate.js.map +1 -0
  135. package/docs/admin/error-mode.md +14 -0
  136. package/docs/admin/headers.md +63 -0
  137. package/docs/admin/index.md +111 -0
  138. package/docs/admin/overrides.md +23 -0
  139. package/docs/admin/rest-api.md +90 -0
  140. package/docs/admin/scenarios.md +28 -0
  141. package/docs/cli.md +76 -0
  142. package/docs/config/admin.md +62 -0
  143. package/docs/config/cors.md +72 -0
  144. package/docs/config/endpoints.md +162 -0
  145. package/docs/config/index.md +107 -0
  146. package/docs/config/log.md +43 -0
  147. package/docs/config/mock-mode.md +84 -0
  148. package/docs/config/openapi.md +8 -0
  149. package/docs/config/schema.md +34 -0
  150. package/docs/config/server.md +32 -0
  151. package/docs/config/validation.md +161 -0
  152. package/docs/design.md +517 -0
  153. package/docs/errors.md +192 -0
  154. package/docs/getting-started.md +146 -0
  155. package/docs/index.md +23 -0
  156. package/docs/openapi/auto-schema.md +146 -0
  157. package/docs/openapi/fallback.md +242 -0
  158. package/docs/openapi/keywords.md +78 -0
  159. package/docs/recipes.md +258 -0
  160. package/docs/stability.md +118 -0
  161. package/docs/troubleshooting.md +191 -0
  162. package/package.json +80 -0
package/dist/server.js ADDED
@@ -0,0 +1,497 @@
1
+ import { createServer as createNodeHttpServer, } from 'node:http';
2
+ import { Readable } from 'node:stream';
3
+ import { createAdminRoutes } from './admin/admin-routes.js';
4
+ import { AdminDestroySocketSignal, } from './admin/admin-types.js';
5
+ import { emitAdminBanner } from './admin/banner.js';
6
+ import { createInjectHook, isDestroySocketSentinel } from './admin/inject.js';
7
+ import { createOverridesStore } from './admin/overrides-store.js';
8
+ import { resolveAdminCors } from './admin/resolve-cors.js';
9
+ import { createScenariosStore } from './admin/scenarios-store.js';
10
+ import { buildCorsResponseHeaders, buildPreflightResponse, mergeVary } from './cors.js';
11
+ import { createAccessLogger } from './log.js';
12
+ import { createRequestValidationContext, validateRequest, } from './middleware/request-validation.js';
13
+ import { parseOpenApi } from './openapi/loader.js';
14
+ import { buildOpenApiRoutes } from './openapi/register.js';
15
+ import { buildRequest } from './request.js';
16
+ import { buildResponse } from './response.js';
17
+ import { matchPattern, parseRouteKey, parseRoutePattern } from './route-key.js';
18
+ const LOOPBACK_HOSTS = new Set(['127.0.0.1', '::1', 'localhost']);
19
+ /**
20
+ * Resolve admin config defaults + validate inputs that don't
21
+ * depend on listen() host. Returns `null` when admin is absent or
22
+ * `enabled !== true`. Pure — no side effects.
23
+ */
24
+ export const resolveAdminMode = (cfg) => {
25
+ if (!cfg || cfg.enabled !== true)
26
+ return null;
27
+ const path = cfg.path ?? '/databehave';
28
+ if (!path.startsWith('/')) {
29
+ throw new Error(`@databehave/server: admin.path must start with "/" (got ${JSON.stringify(path)})`);
30
+ }
31
+ return {
32
+ path,
33
+ ui: cfg.ui !== false,
34
+ headers: cfg.headers !== false,
35
+ bind: cfg.bind ?? 'loopback-only',
36
+ cors: cfg.cors ?? 'auto',
37
+ allowDestroy: cfg.allowDestroy !== false,
38
+ openapiBody: cfg.openapiBody,
39
+ scenariosDir: cfg.scenariosDir ?? `${process.cwd()}/mock-scenarios`,
40
+ };
41
+ };
42
+ /**
43
+ * Compose two onRequest hooks (user-first per spec H13): if the user
44
+ * hook returned a response, skip the admin inject hook; else call
45
+ * inject. Exported for unit testability.
46
+ */
47
+ export const composeAdminOnRequest = (userHook, adminHook) => {
48
+ if (!userHook)
49
+ return adminHook;
50
+ return async (req) => {
51
+ const first = await userHook(req);
52
+ if (first)
53
+ return first;
54
+ return adminHook(req);
55
+ };
56
+ };
57
+ const buildRouteIndex = (config) => {
58
+ const statik = new Map();
59
+ const dynamic = [];
60
+ const declared = new Set();
61
+ const declaredKeys = new Set();
62
+ const entries = Object.entries(config.routes ?? {});
63
+ for (const [key, handler] of entries) {
64
+ if (!handler)
65
+ continue;
66
+ const { method, path } = parseRouteKey(key);
67
+ const pattern = parseRoutePattern(path);
68
+ const dispatchKey = `${method} ${path}`;
69
+ if (declared.has(dispatchKey)) {
70
+ throw new Error(`@databehave/server: duplicate route declared: ${dispatchKey}`);
71
+ }
72
+ declared.add(dispatchKey);
73
+ declaredKeys.add(`${method.toUpperCase()} ${path}`);
74
+ if (pattern.isStatic) {
75
+ statik.set(dispatchKey, handler);
76
+ }
77
+ else {
78
+ dynamic.push({ method, pattern, handler });
79
+ }
80
+ }
81
+ // OpenAPI walker fills only the gaps the user did NOT declare.
82
+ // Declared (hand-written) routes always win — no error, just skip.
83
+ if (config.openapi !== undefined) {
84
+ const doc = parseOpenApi(config.openapi);
85
+ const oasRoutes = buildOpenApiRoutes(doc, {
86
+ skip: declaredKeys,
87
+ ...(config.onOpenApiWalkError !== undefined
88
+ ? { onWalkError: config.onOpenApiWalkError }
89
+ : {}),
90
+ ...(config.onOpenApiEmptySchema !== undefined
91
+ ? { onEmptySchema: config.onOpenApiEmptySchema }
92
+ : {}),
93
+ });
94
+ for (const [key, handler] of oasRoutes) {
95
+ const { method, path } = parseRouteKey(key);
96
+ const pattern = parseRoutePattern(path);
97
+ const dispatchKey = `${method} ${path}`;
98
+ if (declared.has(dispatchKey))
99
+ continue;
100
+ declared.add(dispatchKey);
101
+ if (pattern.isStatic) {
102
+ statik.set(dispatchKey, handler);
103
+ }
104
+ else {
105
+ dynamic.push({ method, pattern, handler });
106
+ }
107
+ }
108
+ }
109
+ return { statik, dynamic };
110
+ };
111
+ const dispatch = (index, method, path) => {
112
+ const staticHit = index.statik.get(`${method} ${path}`);
113
+ if (staticHit)
114
+ return { handler: staticHit, params: {} };
115
+ for (const route of index.dynamic) {
116
+ if (route.method !== method)
117
+ continue;
118
+ const params = matchPattern(route.pattern, path);
119
+ if (params)
120
+ return { handler: route.handler, params };
121
+ }
122
+ return null;
123
+ };
124
+ /**
125
+ * Build a @databehave/server server.
126
+ *
127
+ * Construction validates every route key and pre-computes a dispatch
128
+ * index (static lookups are O(1), `:param` patterns are linear). The
129
+ * returned object exposes:
130
+ *
131
+ * - `fetch(Request)` for in-process testing — no socket is opened.
132
+ * - `listen({port, host})` to bind a Node HTTP server. Port `0`
133
+ * asks the OS for a free port; the resolved port/host come back in
134
+ * the handle.
135
+ *
136
+ * Request flow per call:
137
+ * 1. CORS preflight (OPTIONS) → short-circuit when `cors` is set
138
+ * 2. `hooks.onRequest` → may short-circuit
139
+ * 3. Route dispatch → handler / OAS walker / 404
140
+ * 4. `hooks.onResponse` → may replace the result
141
+ * 5. CORS response headers merged on top (don't override the user)
142
+ * 6. Handler errors funnel through `hooks.onError` or fall back
143
+ * to a 500 JSON envelope.
144
+ */
145
+ /**
146
+ * Route a runtime `'error'` event from a bound Node `http.Server` to
147
+ * the user-supplied `onServerError` hook (when present), with a
148
+ * `console.error` fallback. Exported so the branching is unit-testable
149
+ * without standing up a real socket and provoking EMFILE/EACCES.
150
+ *
151
+ * Branch contract:
152
+ * - no hook → log via `console.error`
153
+ * - hook returns → silent (hook owns reporting)
154
+ * - hook itself throws → log the *hook* failure AND the original
155
+ * error, so a misbehaving logger never
156
+ * silently swallows a real server fault.
157
+ */
158
+ export const handleRuntimeServerError = (err, onServerError) => {
159
+ if (onServerError) {
160
+ try {
161
+ onServerError(err);
162
+ return;
163
+ }
164
+ catch (hookErr) {
165
+ // eslint-disable-next-line no-console
166
+ console.error('[@databehave/server] onServerError hook threw:', hookErr);
167
+ }
168
+ }
169
+ // eslint-disable-next-line no-console
170
+ console.error('[@databehave/server] server error:', err);
171
+ };
172
+ export const createServer = (config) => {
173
+ const admin = resolveAdminMode(config.admin);
174
+ let effectiveConfig = config;
175
+ if (admin) {
176
+ const store = createOverridesStore({
177
+ warn: (m) => console.warn(m),
178
+ });
179
+ const corsHeaders = resolveAdminCors(admin.bind, admin.cors);
180
+ const scenarios = createScenariosStore({ dir: admin.scenariosDir });
181
+ // Surface hand-written routes to the admin UI so handler-only
182
+ // endpoints (those not in the OAS doc, or projects without one)
183
+ // still appear in the operation list. OAS entries win on dedupe
184
+ // inside `buildAdminRoutesList`; admin's own routes are filtered
185
+ // there too. OAS-walker output is already covered by `openapiBody`.
186
+ const handlerRoutes = [];
187
+ for (const key of Object.keys(config.routes ?? {})) {
188
+ try {
189
+ const { method, path } = parseRouteKey(key);
190
+ handlerRoutes.push({ method: method.toUpperCase(), path });
191
+ }
192
+ catch {
193
+ // buildRouteIndex below will surface invalid keys with a real error.
194
+ }
195
+ }
196
+ const adminRouteEntries = createAdminRoutes({
197
+ store,
198
+ basePath: admin.path,
199
+ ui: admin.ui,
200
+ corsHeaders,
201
+ scenarios,
202
+ handlerRoutes,
203
+ ...(admin.openapiBody !== undefined
204
+ ? { openapiBody: admin.openapiBody }
205
+ : {}),
206
+ });
207
+ // Fail-fast on conflict between admin routes and user routes —
208
+ // duplicates would silently shadow each other otherwise.
209
+ const userRoutes = config.routes ?? {};
210
+ for (const key of Object.keys(adminRouteEntries)) {
211
+ if (Object.prototype.hasOwnProperty.call(userRoutes, key)) {
212
+ throw new Error(`@databehave/server: admin route ${key} collides with a user-declared route. ` +
213
+ `Move admin.path to a free prefix or rename the user route.`);
214
+ }
215
+ }
216
+ // Inject hook is only registered when `headers` is true OR there
217
+ // can be sticky overrides — and stickies require the admin REST
218
+ // endpoints, which are always present, so the hook is always
219
+ // useful here. The `headers` flag is honored inside the inject
220
+ // hook by feeding it an empty-header view when disabled.
221
+ const adminHookCore = createInjectHook({
222
+ store,
223
+ allowDestroy: admin.allowDestroy,
224
+ // Bypass both the bare base path (admin HTML) and any descendant
225
+ // (`/overrides`, `/ui.js`, …) so the inject hook never injects on
226
+ // admin-owned URLs.
227
+ bypassPathPrefixes: [admin.path],
228
+ logger: { warn: (m) => console.warn(m) },
229
+ });
230
+ const adminHook = admin.headers
231
+ ? adminHookCore
232
+ : async (req) => adminHookCore({ ...req, headers: {} });
233
+ const userHook = config.hooks?.onRequest;
234
+ const composed = composeAdminOnRequest(userHook, adminHook);
235
+ effectiveConfig = {
236
+ ...config,
237
+ routes: { ...userRoutes, ...adminRouteEntries },
238
+ hooks: { ...(config.hooks ?? {}), onRequest: composed },
239
+ };
240
+ }
241
+ const index = buildRouteIndex(effectiveConfig);
242
+ const hooks = effectiveConfig.hooks ?? {};
243
+ const cors = effectiveConfig.cors;
244
+ const accessLogger = createAccessLogger(effectiveConfig.log, admin?.path);
245
+ // Build the request-validation context once per server boot. When
246
+ // `validation.request !== true` (the default) the context is null
247
+ // and the per-request hot path short-circuits.
248
+ //
249
+ // Schema-level errors (unsupported keyword, $ref cycle, ReDoS-sized
250
+ // pattern, depth-cap exceeded) throw at boot from
251
+ // `createRequestValidationContext` so a misconfigured spec is a
252
+ // fail-fast — never a silent runtime degradation.
253
+ let validationCtx = null;
254
+ if (effectiveConfig.validation?.request === true && effectiveConfig.openapi !== undefined) {
255
+ const doc = parseOpenApi(effectiveConfig.openapi);
256
+ const maxBodyBytes = effectiveConfig.validation?.maxBodyBytes;
257
+ validationCtx = createRequestValidationContext(doc, maxBodyBytes !== undefined ? { maxBodyBytes } : {});
258
+ }
259
+ const decorateWithCors = (res, req) => {
260
+ if (!cors)
261
+ return res;
262
+ const corsHeaders = buildCorsResponseHeaders(cors, req);
263
+ // Handler-supplied headers win — CORS only fills the gaps. `Vary`
264
+ // is the deliberate exception: HTTP semantics require it to be
265
+ // additive, so a handler-set `Vary: Accept-Encoding` is merged
266
+ // with the CORS `Vary: Origin` (case-insensitive dedupe) rather
267
+ // than silently replacing it.
268
+ const merged = { ...corsHeaders };
269
+ if (res.headers) {
270
+ for (const [k, v] of Object.entries(res.headers)) {
271
+ const lk = k.toLowerCase();
272
+ if (lk === 'vary') {
273
+ merged.vary = mergeVary(merged.vary, v);
274
+ }
275
+ else {
276
+ merged[lk] = v;
277
+ }
278
+ }
279
+ }
280
+ return { ...res, headers: merged };
281
+ };
282
+ const fetchImpl = async (req, suppressLog = false) => {
283
+ const probe = buildRequest(req);
284
+ const logStart = accessLogger && !suppressLog ? Date.now() : 0;
285
+ const finalize = (res, errorMsg) => {
286
+ if (!accessLogger || suppressLog)
287
+ return res;
288
+ accessLogger.emit({
289
+ method: probe.method.toUpperCase(),
290
+ path: probe.path,
291
+ status: res.status,
292
+ ms: Date.now() - logStart,
293
+ bytes: res.headers.get('content-length') ?? '-',
294
+ override: res.headers.get('x-mock-injected')?.split(':')[0],
295
+ error: errorMsg,
296
+ });
297
+ return res;
298
+ };
299
+ // 1. CORS preflight bypasses everything below.
300
+ if (cors && req.method.toUpperCase() === 'OPTIONS') {
301
+ return finalize(buildResponse(buildPreflightResponse(cors, probe)));
302
+ }
303
+ // 1a. Inbound request validation (opt-in via
304
+ // `config.validation.request`). Runs BEFORE mock/handler
305
+ // resolution so a request that fails the OAS contract is rejected
306
+ // with an RFC 7807 envelope without invoking handlers, hooks, or
307
+ // mock-mode injection. When `validationCtx` is null (the default)
308
+ // the function short-circuits and behaviour is byte-identical to
309
+ // pre-validation builds.
310
+ if (validationCtx) {
311
+ const violation = await validateRequest(req, validationCtx);
312
+ if (violation)
313
+ return finalize(violation);
314
+ }
315
+ // 1b. RFC 7231 HEAD semantics: if the HEAD route is not declared,
316
+ // run the GET pipeline once and strip the body from the response.
317
+ // Hooks (`onRequest`, `onResponse`, mock-mode) fire on the inner
318
+ // GET call only — the outer HEAD short-circuits here before the
319
+ // `try` block, so they aren't observed twice for one logical
320
+ // request. Explicit `head` routes still take precedence (handled
321
+ // by `dispatch` for the original method).
322
+ if (req.method.toUpperCase() === 'HEAD' &&
323
+ !dispatch(index, 'head', probe.path)) {
324
+ const asGet = new Request(req.url, {
325
+ method: 'GET',
326
+ headers: req.headers,
327
+ });
328
+ // Inner GET is recursed with logging suppressed so the access
329
+ // logger emits one line per logical request — for the outer
330
+ // HEAD method, not the synthetic GET probe.
331
+ const fullResponse = await fetchImpl(asGet, true);
332
+ return finalize(new Response(null, {
333
+ status: fullResponse.status,
334
+ headers: fullResponse.headers,
335
+ }));
336
+ }
337
+ try {
338
+ // 2. onRequest may short-circuit (e.g. mock-mode error injection).
339
+ if (hooks.onRequest) {
340
+ const short = await hooks.onRequest(probe);
341
+ if (short) {
342
+ // admin destroy sentinel: bubble up so `listen()` can drop the
343
+ // underlying socket. `server.fetch()` callers observe the
344
+ // throw — destroy is a transport-level signal, not a body.
345
+ if (isDestroySocketSentinel(short)) {
346
+ throw new AdminDestroySocketSignal();
347
+ }
348
+ const final = hooks.onResponse
349
+ ? (await hooks.onResponse(probe, short)) ?? short
350
+ : short;
351
+ return finalize(buildResponse(decorateWithCors(final, probe)));
352
+ }
353
+ }
354
+ // 3. Dispatch.
355
+ const matched = dispatch(index, probe.method, probe.path);
356
+ if (!matched) {
357
+ const notFound = {
358
+ status: 404,
359
+ json: { error: 'not_found', method: probe.method, path: probe.path },
360
+ };
361
+ const final = hooks.onResponse
362
+ ? (await hooks.onResponse(probe, notFound)) ?? notFound
363
+ : notFound;
364
+ return finalize(buildResponse(decorateWithCors(final, probe)));
365
+ }
366
+ const kitReq = Object.keys(matched.params).length === 0
367
+ ? probe
368
+ : buildRequest(req, matched.params);
369
+ const raw = await matched.handler(kitReq);
370
+ // 4. onResponse may replace the body / status / headers.
371
+ const final = hooks.onResponse
372
+ ? (await hooks.onResponse(kitReq, raw)) ?? raw
373
+ : raw;
374
+ return finalize(buildResponse(decorateWithCors(final, kitReq)));
375
+ }
376
+ catch (err) {
377
+ // Admin destroy signal must escape — hooks.onError must NOT see
378
+ // it (it's transport-level, not a user error). `listen()` catches
379
+ // it specifically. `server.fetch()` callers also receive the throw.
380
+ if (err instanceof AdminDestroySocketSignal)
381
+ throw err;
382
+ const errMsg = err instanceof Error ? err.message : String(err);
383
+ const errRes = hooks.onError
384
+ ? await hooks.onError(probe, err)
385
+ : {
386
+ status: 500,
387
+ json: {
388
+ error: 'internal_error',
389
+ message: errMsg,
390
+ },
391
+ };
392
+ return finalize(buildResponse(decorateWithCors(errRes, probe)), errMsg);
393
+ }
394
+ };
395
+ const fetch = (req) => fetchImpl(req);
396
+ const listen = async (opts = {}) => {
397
+ const requestedPort = opts.port ?? 0;
398
+ const requestedHost = opts.host ?? '127.0.0.1';
399
+ // Admin bind-policy: refuse non-loopback hosts unless explicitly
400
+ // opted in. Host comes from listen options (not config), so the
401
+ // check belongs here rather than at server construction time.
402
+ if (admin && admin.bind !== 'any' && !LOOPBACK_HOSTS.has(requestedHost)) {
403
+ throw new Error(`@databehave/server: admin is enabled and server.host=${JSON.stringify(requestedHost)} — set admin.bind: "any" to confirm this is intentional, or bind to loopback (127.0.0.1, ::1, localhost). See README "Admin mode".`);
404
+ }
405
+ // Tiny Node `http` ↔ Web Fetch adapter. Node ≥ 18.17 provides
406
+ // `Request`, `Response`, `Headers`, and `Readable.{toWeb,fromWeb}`
407
+ // as built-ins, so no polyfill or extra runtime dependency is needed.
408
+ const server = createNodeHttpServer((req, res) => {
409
+ // Build a Web Request out of the IncomingMessage.
410
+ const host = req.headers.host ?? `${requestedHost}:${requestedPort}`;
411
+ const url = `http://${host}${req.url ?? '/'}`;
412
+ const method = (req.method ?? 'GET').toUpperCase();
413
+ const headers = new Headers();
414
+ for (const [k, v] of Object.entries(req.headers)) {
415
+ if (v === undefined)
416
+ continue;
417
+ if (Array.isArray(v)) {
418
+ for (const value of v)
419
+ headers.append(k, value);
420
+ }
421
+ else {
422
+ headers.set(k, v);
423
+ }
424
+ }
425
+ const init = { method, headers };
426
+ if (method !== 'GET' && method !== 'HEAD') {
427
+ init.body = Readable.toWeb(req);
428
+ // Required when sending a stream body in undici/fetch.
429
+ init.duplex = 'half';
430
+ }
431
+ Promise.resolve()
432
+ .then(() => fetch(new Request(url, init)))
433
+ .then(async (webRes) => {
434
+ res.statusCode = webRes.status;
435
+ webRes.headers.forEach((value, key) => {
436
+ res.setHeader(key, value);
437
+ });
438
+ if (!webRes.body) {
439
+ res.end();
440
+ return;
441
+ }
442
+ const nodeStream = Readable.fromWeb(webRes.body);
443
+ await new Promise((resolveStream, rejectStream) => {
444
+ nodeStream.on('error', rejectStream);
445
+ res.on('error', rejectStream);
446
+ res.on('finish', () => resolveStream());
447
+ nodeStream.pipe(res);
448
+ });
449
+ })
450
+ .catch((err) => {
451
+ // Admin destroy: drop the socket without a response.
452
+ if (err instanceof AdminDestroySocketSignal) {
453
+ try {
454
+ req.socket.destroy();
455
+ }
456
+ catch {
457
+ /* socket may already be gone */
458
+ }
459
+ return;
460
+ }
461
+ if (!res.headersSent) {
462
+ res.statusCode = 500;
463
+ res.setHeader('content-type', 'application/json');
464
+ }
465
+ const message = err instanceof Error ? err.message : String(err);
466
+ res.end(JSON.stringify({ error: 'internal_error', message }));
467
+ });
468
+ });
469
+ return new Promise((resolve, reject) => {
470
+ const onBindError = (err) => {
471
+ reject(err);
472
+ };
473
+ server.once('error', onBindError);
474
+ server.listen(requestedPort, requestedHost, () => {
475
+ // Bind succeeded — detach the bind-time rejector so subsequent
476
+ // runtime errors (EMFILE, accept errors, etc.) don't try to
477
+ // resolve an already-settled promise. Surface them on stderr
478
+ // instead so they're not swallowed silently.
479
+ server.removeListener('error', onBindError);
480
+ server.on('error', (err) => handleRuntimeServerError(err, hooks.onServerError));
481
+ const info = server.address();
482
+ if (admin) {
483
+ emitAdminBanner(info.address, info.port, admin.path);
484
+ }
485
+ resolve({
486
+ port: info.port,
487
+ host: info.address,
488
+ close: () => new Promise((res, rej) => {
489
+ server.close((err) => (err ? rej(err) : res()));
490
+ }),
491
+ });
492
+ });
493
+ });
494
+ };
495
+ return { fetch, listen };
496
+ };
497
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,IAAI,oBAAoB,GAIrC,MAAM,WAAW,CAAA;AAElB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EACL,wBAAwB,GAEzB,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,EACL,8BAA8B,EAC9B,eAAe,GAEhB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAe/E,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAA;AAEjE;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,GAAgC,EAUzB,EAAE;IACT,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC7C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,aAAa,CAAA;IACtC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,2DAA2D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CACnF,CAAA;IACH,CAAC;IACD,OAAO;QACL,IAAI;QACJ,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,KAAK;QACpB,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,KAAK;QAC9B,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,eAAe;QACjC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,MAAM;QACxB,YAAY,EAAE,GAAG,CAAC,YAAY,KAAK,KAAK;QACxC,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,iBAAiB;KACpE,CAAA;AACH,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAIa,EACb,SAEiC,EAGA,EAAE;IACnC,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC/B,OAAO,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAA;QACjC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;QACvB,OAAO,SAAS,CAAC,GAAG,CAAC,CAAA;IACvB,CAAC,CAAA;AACH,CAAC,CAAA;AAmBD,MAAM,eAAe,GAAG,CAAC,MAAc,EAAc,EAAE;IACrD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAmB,CAAA;IACzC,MAAM,OAAO,GAAmB,EAAE,CAAA;IAClC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAY,CAAA;IAExC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAEjD,CAAA;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO;YAAE,SAAQ;QACtB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAC3C,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACvC,MAAM,WAAW,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAA;QACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,iDAAiD,WAAW,EAAE,CAAC,CAAA;QACjF,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QACzB,YAAY,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,IAAI,IAAI,EAAc,CAAC,CAAA;QAC/D,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC;IAED,+DAA+D;IAC/D,mEAAmE;IACnE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QACxC,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,EAAE;YACxC,IAAI,EAAE,YAAY;YAClB,GAAG,CAAC,MAAM,CAAC,kBAAkB,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,kBAAkB,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,MAAM,CAAC,oBAAoB,KAAK,SAAS;gBAC3C,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,oBAAoB,EAAE;gBAChD,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;QACF,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;YACvC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;YAC3C,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAA;YACvC,MAAM,WAAW,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAA;YACvC,IAAI,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;gBAAE,SAAQ;YACvC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;YACzB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;YAClC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AAC5B,CAAC,CAAA;AAOD,MAAM,QAAQ,GAAG,CACf,KAAiB,EACjB,MAAsB,EACtB,IAAY,EACI,EAAE;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC,CAAA;IACvD,IAAI,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;IACxD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM;YAAE,SAAQ;QACrC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAChD,IAAI,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;IACvD,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CACtC,GAAU,EACV,aAAiD,EAC3C,EAAE;IACR,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,aAAa,CAAC,GAAG,CAAC,CAAA;YAClB,OAAM;QACR,CAAC;QAAC,OAAO,OAAO,EAAE,CAAC;YACjB,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,gDAAgD,EAAE,OAAO,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IACD,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAA;AAC1D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAU,EAAE;IACrD,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,eAAe,GAAW,MAAM,CAAA;IAEpC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,GAAG,oBAAoB,CAAC;YACjC,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;SACrC,CAAC,CAAA;QACF,MAAM,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5D,MAAM,SAAS,GAAG,oBAAoB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAA;QACnE,8DAA8D;QAC9D,gEAAgE;QAChE,gEAAgE;QAChE,iEAAiE;QACjE,oEAAoE;QACpE,MAAM,aAAa,GAA4C,EAAE,CAAA;QACjE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAe,EAAE,CAAC;YACjE,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;gBAC3C,aAAa,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YAC5D,CAAC;YAAC,MAAM,CAAC;gBACP,qEAAqE;YACvE,CAAC;QACH,CAAC;QACD,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;YAC1C,KAAK;YACL,QAAQ,EAAE,KAAK,CAAC,IAAI;YACpB,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,WAAW;YACX,SAAS;YACT,aAAa;YACb,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS;gBACjC,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE;gBACpC,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;QAEF,+DAA+D;QAC/D,yDAAyD;QACzD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAA;QACtC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACjD,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CACb,mCAAmC,GAAG,wCAAwC;oBAC5E,4DAA4D,CAC/D,CAAA;YACH,CAAC;QACH,CAAC;QAED,iEAAiE;QACjE,gEAAgE;QAChE,6DAA6D;QAC7D,+DAA+D;QAC/D,yDAAyD;QACzD,MAAM,aAAa,GAAG,gBAAgB,CAAC;YACrC,KAAK;YACL,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,iEAAiE;YACjE,kEAAkE;YAClE,oBAAoB;YACpB,kBAAkB,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;YAChC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;SACjD,CAAC,CAAA;QACF,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO;YAC7B,CAAC,CAAC,aAAa;YACf,CAAC,CAAC,KAAK,EAAE,GAAgB,EAAE,EAAE,CACzB,aAAa,CAAC,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,EAAE,EAAiB,CAAC,CAAA;QAE3D,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,SAAS,CAAA;QACxC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;QAE3D,eAAe,GAAG;YAChB,GAAG,MAAM;YACT,MAAM,EAAE,EAAE,GAAG,UAAU,EAAE,GAAG,iBAAiB,EAAE;YAC/C,KAAK,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE;SACxD,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,eAAe,CAAC,eAAe,CAAC,CAAA;IAC9C,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,IAAI,EAAE,CAAA;IACzC,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAA;IACjC,MAAM,YAAY,GAAG,kBAAkB,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;IAEzE,kEAAkE;IAClE,kEAAkE;IAClE,+CAA+C;IAC/C,EAAE;IACF,oEAAoE;IACpE,kDAAkD;IAClD,gEAAgE;IAChE,kDAAkD;IAClD,IAAI,aAAa,GAAoC,IAAI,CAAA;IACzD,IAAI,eAAe,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,IAAI,eAAe,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1F,MAAM,GAAG,GAAG,YAAY,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QACjD,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,EAAE,YAAY,CAAA;QAC7D,aAAa,GAAG,8BAA8B,CAC5C,GAA2D,EAC3D,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CACnD,CAAA;IACH,CAAC;IAED,MAAM,gBAAgB,GAAG,CACvB,GAAiB,EACjB,GAAgB,EACF,EAAE;QAChB,IAAI,CAAC,IAAI;YAAE,OAAO,GAAG,CAAA;QACrB,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QACvD,kEAAkE;QAClE,+DAA+D;QAC/D,+DAA+D;QAC/D,gEAAgE;QAChE,8BAA8B;QAC9B,MAAM,MAAM,GAA2B,EAAE,GAAG,WAAW,EAAE,CAAA;QACzD,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChB,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjD,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,CAAA;gBAC1B,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;oBAClB,MAAM,CAAC,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;gBACzC,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;IACpC,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,KAAK,EACrB,GAAuB,EACvB,WAAW,GAAG,KAAK,EACW,EAAE;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;QAC/B,MAAM,QAAQ,GACZ,YAAY,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,QAAQ,GAAG,CAAC,GAAwB,EAAE,QAAiB,EAAuB,EAAE;YACpF,IAAI,CAAC,YAAY,IAAI,WAAW;gBAAE,OAAO,GAAG,CAAA;YAC5C,YAAY,CAAC,IAAI,CAAC;gBAChB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE;gBAClC,IAAI,EAAE,KAAK,CAAC,IAAI;gBAChB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ;gBACzB,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,GAAG;gBAC/C,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC3D,KAAK,EAAE,QAAQ;aAChB,CAAC,CAAA;YACF,OAAO,GAAG,CAAA;QACZ,CAAC,CAAA;QAED,+CAA+C;QAC/C,IAAI,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,SAAS,EAAE,CAAC;YACnD,OAAO,QAAQ,CAAC,aAAa,CAAC,sBAAsB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;QACrE,CAAC;QAED,6CAA6C;QAC7C,yDAAyD;QACzD,kEAAkE;QAClE,iEAAiE;QACjE,kEAAkE;QAClE,iEAAiE;QACjE,yBAAyB;QACzB,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,CAAA;YAC3D,IAAI,SAAS;gBAAE,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAA;QAC3C,CAAC;QAED,kEAAkE;QAClE,kEAAkE;QAClE,iEAAiE;QACjE,gEAAgE;QAChE,6DAA6D;QAC7D,iEAAiE;QACjE,0CAA0C;QAC1C,IACE,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM;YACnC,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EACpC,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;gBACjC,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAA;YACF,8DAA8D;YAC9D,4DAA4D;YAC5D,4CAA4C;YAC5C,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YACjD,OAAO,QAAQ,CACb,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACjB,MAAM,EAAE,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,YAAY,CAAC,OAAO;aAC9B,CAAC,CACH,CAAA;QACH,CAAC;QAED,IAAI,CAAC;YACH,mEAAmE;YACnE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;gBAC1C,IAAI,KAAK,EAAE,CAAC;oBACV,+DAA+D;oBAC/D,0DAA0D;oBAC1D,2DAA2D;oBAC3D,IAAI,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;wBACnC,MAAM,IAAI,wBAAwB,EAAE,CAAA;oBACtC,CAAC;oBACD,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU;wBAC5B,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,KAAK;wBACjD,CAAC,CAAC,KAAK,CAAA;oBACT,OAAO,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;gBAChE,CAAC;YACH,CAAC;YAED,eAAe;YACf,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YACzD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,QAAQ,GAAiB;oBAC7B,MAAM,EAAE,GAAG;oBACX,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;iBACrE,CAAA;gBACD,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU;oBAC5B,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,IAAI,QAAQ;oBACvD,CAAC,CAAC,QAAQ,CAAA;gBACZ,OAAO,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAA;YAChE,CAAC;YACD,MAAM,MAAM,GACV,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC;gBACtC,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;YACvC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAEzC,yDAAyD;YACzD,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU;gBAC5B,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG;gBAC9C,CAAC,CAAC,GAAG,CAAA;YAEP,OAAO,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,gEAAgE;YAChE,kEAAkE;YAClE,oEAAoE;YACpE,IAAI,GAAG,YAAY,wBAAwB;gBAAE,MAAM,GAAG,CAAA;YACtD,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO;gBAC1B,CAAC,CAAC,MAAM,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;gBACjC,CAAC,CAAE;oBACC,MAAM,EAAE,GAAG;oBACX,IAAI,EAAE;wBACJ,KAAK,EAAE,gBAAgB;wBACvB,OAAO,EAAE,MAAM;qBAChB;iBACsB,CAAA;YAC7B,OAAO,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;QACzE,CAAC;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,CAAC,GAAuB,EAAgC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IAEvF,MAAM,MAAM,GAAG,KAAK,EAClB,OAAsB,EAAE,EACD,EAAE;QACzB,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAA;QACpC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAA;QAE9C,iEAAiE;QACjE,gEAAgE;QAChE,8DAA8D;QAC9D,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CACb,wDAAwD,IAAI,CAAC,SAAS,CACpE,aAAa,CACd,oIAAoI,CACtI,CAAA;QACH,CAAC;QAED,8DAA8D;QAC9D,mEAAmE;QACnE,sEAAsE;QACtE,MAAM,MAAM,GAAG,oBAAoB,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;YAChF,kDAAkD;YAClD,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,aAAa,IAAI,aAAa,EAAE,CAAA;YACpE,MAAM,GAAG,GAAG,UAAU,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,CAAA;YAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAA;YAClD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;YAC7B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjD,IAAI,CAAC,KAAK,SAAS;oBAAE,SAAQ;gBAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrB,KAAK,MAAM,KAAK,IAAI,CAAC;wBAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAA;gBACjD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBACnB,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAsC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;YACnE,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC1C,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAA;gBACtD,uDAAuD;gBACvD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;YACtB,CAAC;YAED,OAAO,CAAC,OAAO,EAAE;iBACd,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;iBACzC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBACrB,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAA;gBAC9B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;oBACpC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;gBAC3B,CAAC,CAAC,CAAA;gBACF,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;oBACjB,GAAG,CAAC,GAAG,EAAE,CAAA;oBACT,OAAM;gBACR,CAAC;gBACD,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CACjC,MAAM,CAAC,IAA8C,CACtD,CAAA;gBACD,MAAM,IAAI,OAAO,CAAO,CAAC,aAAa,EAAE,YAAY,EAAE,EAAE;oBACtD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;oBACpC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;oBAC7B,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAA;oBACvC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;gBACtB,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBACtB,qDAAqD;gBACrD,IAAI,GAAG,YAAY,wBAAwB,EAAE,CAAC;oBAC5C,IAAI,CAAC;wBACH,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;oBACtB,CAAC;oBAAC,MAAM,CAAC;wBACP,gCAAgC;oBAClC,CAAC;oBACD,OAAM;gBACR,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;oBACrB,GAAG,CAAC,UAAU,GAAG,GAAG,CAAA;oBACpB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAA;gBACnD,CAAC;gBACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBAChE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;YAC/D,CAAC,CAAC,CAAA;QACN,CAAC,CAAC,CAAA;QAEF,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,MAAM,WAAW,GAAG,CAAC,GAAU,EAAQ,EAAE;gBACvC,MAAM,CAAC,GAAG,CAAC,CAAA;YACb,CAAC,CAAA;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;YACjC,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,GAAG,EAAE;gBAC/C,+DAA+D;gBAC/D,4DAA4D;gBAC5D,6DAA6D;gBAC7D,6CAA6C;gBAC7C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,WAAW,CAAC,CAAA;gBAC3C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,wBAAwB,CAAC,GAAG,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAA;gBAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAiB,CAAA;gBAC5C,IAAI,KAAK,EAAE,CAAC;oBACV,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;gBACtD,CAAC;gBACD,OAAO,CAAC;oBACN,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,IAAI,EAAE,IAAI,CAAC,OAAO;oBAClB,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;wBAC7B,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;oBACjD,CAAC,CAAC;iBACL,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC1B,CAAC,CAAA"}