@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/cors.js ADDED
@@ -0,0 +1,167 @@
1
+ const DEFAULT_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'];
2
+ const DEFAULT_HEADERS = ['content-type', 'authorization'];
3
+ const resolveOrigin = (cfg, reqOrigin) => {
4
+ if (cfg.origin)
5
+ return cfg.origin(reqOrigin);
6
+ return reqOrigin === '' ? '*' : reqOrigin;
7
+ };
8
+ /**
9
+ * Merge two `Vary` header values, deduplicating tokens
10
+ * case-insensitively while preserving the first occurrence's casing.
11
+ * `Vary: *` short-circuits to `*` (HTTP semantic: “varies on every
12
+ * possible header”, no further tokens add information).
13
+ *
14
+ * Exported so server-level decorators (and tests) can compose the
15
+ * CORS `Vary` onto whatever the handler already declared.
16
+ */
17
+ export const mergeVary = (existing, additional) => {
18
+ if (!existing)
19
+ return additional;
20
+ const seen = new Map();
21
+ for (const raw of [existing, additional]) {
22
+ for (const tok of raw.split(',')) {
23
+ const t = tok.trim();
24
+ if (t === '')
25
+ continue;
26
+ if (t === '*')
27
+ return '*';
28
+ const key = t.toLowerCase();
29
+ if (!seen.has(key))
30
+ seen.set(key, t);
31
+ }
32
+ }
33
+ return Array.from(seen.values()).join(', ');
34
+ };
35
+ /**
36
+ * Build the `Access-Control-*` header bag for a non-preflight
37
+ * response.
38
+ *
39
+ * - `Access-Control-Allow-Origin` is omitted when the resolved origin
40
+ * is an empty string (browsers reject empty header values, and an
41
+ * empty header is the de-facto “reject” signal anyway).
42
+ * - `Vary: Origin` is always added when CORS is enabled so reverse
43
+ * proxies and CDNs don't cache one origin's response and serve it
44
+ * to another. The server-level decorator merges this token with
45
+ * any handler-supplied `Vary` (see {@link mergeVary}).
46
+ */
47
+ export const buildCorsResponseHeaders = (cfg, req) => {
48
+ const headers = {};
49
+ const reqOrigin = req.headers['origin'] ?? '';
50
+ const allowed = resolveOrigin(cfg, reqOrigin);
51
+ if (allowed !== '') {
52
+ headers['access-control-allow-origin'] = allowed;
53
+ }
54
+ headers['vary'] = 'Origin';
55
+ if (cfg.credentials)
56
+ headers['access-control-allow-credentials'] = 'true';
57
+ if (cfg.exposeHeaders && cfg.exposeHeaders.length > 0) {
58
+ headers['access-control-expose-headers'] = cfg.exposeHeaders.join(', ');
59
+ }
60
+ return headers;
61
+ };
62
+ /**
63
+ * Intersect the browser's `Access-Control-Request-Headers` with the
64
+ * configured allowlist. Returns a comma-separated header value.
65
+ *
66
+ * Semantics:
67
+ * - `configured === undefined` → echo the request value verbatim
68
+ * (legacy permissive default for backwards compatibility). If the
69
+ * request also omitted the header, fall back to {@link DEFAULT_HEADERS}.
70
+ * - `configured.length === 0` → deny everything; returns `''`. The
71
+ * caller is expected to treat the empty string as "do not emit the
72
+ * header" (see {@link buildPreflightResponse}). This lets operators
73
+ * express a hard lockdown without inventing a separate flag.
74
+ * - `configured` non-empty → keep only requested tokens whose
75
+ * case-insensitive name appears in the allowlist, preserving input
76
+ * order, de-duplicating case-insensitive repeats. If the request
77
+ * omitted the header, the full allowlist is advertised so a browser
78
+ * that probes without `Access-Control-Request-Headers` still knows
79
+ * what is permitted.
80
+ *
81
+ * Token comparison is case-insensitive. The casing of the **request**
82
+ * is preserved (so a request asking for `Content-Type` gets
83
+ * `Content-Type` back), since browsers compare returned tokens
84
+ * case-insensitively anyway and round-tripping the request casing
85
+ * avoids needless diffs in test snapshots.
86
+ */
87
+ const intersectAllowHeaders = (requested, configured) => {
88
+ if (configured === undefined) {
89
+ return requested ?? DEFAULT_HEADERS.join(', ');
90
+ }
91
+ if (configured.length === 0) {
92
+ // Hard lockdown: empty allowlist means deny all requested headers.
93
+ return '';
94
+ }
95
+ if (requested === undefined || requested === '') {
96
+ // No request header → advertise the full allowlist, deduped by
97
+ // case-insensitive name while preserving the configured casing.
98
+ const seen = new Set();
99
+ const out = [];
100
+ for (const h of configured) {
101
+ const key = h.toLowerCase();
102
+ if (seen.has(key))
103
+ continue;
104
+ seen.add(key);
105
+ out.push(h);
106
+ }
107
+ return out.join(', ');
108
+ }
109
+ const allow = new Set();
110
+ for (const h of configured)
111
+ allow.add(h.toLowerCase());
112
+ const seen = new Set();
113
+ const out = [];
114
+ for (const raw of requested.split(',')) {
115
+ const tok = raw.trim();
116
+ if (tok === '')
117
+ continue;
118
+ const key = tok.toLowerCase();
119
+ if (!allow.has(key))
120
+ continue;
121
+ if (seen.has(key))
122
+ continue;
123
+ seen.add(key);
124
+ out.push(tok);
125
+ }
126
+ return out.join(', ');
127
+ };
128
+ /**
129
+ * Build the preflight (`OPTIONS`) response for a given CORS config.
130
+ * The body is empty (204); headers cover origin, methods, headers,
131
+ * max-age, and `Vary: Origin`.
132
+ *
133
+ * `Access-Control-Allow-Headers` honours `cfg.allowHeaders` as a
134
+ * strict allowlist when it is set — anything off the list is dropped
135
+ * even if the browser requested it. When `cfg.allowHeaders` is unset
136
+ * the request value is echoed verbatim (legacy permissive default).
137
+ *
138
+ * The preflight response body itself does not vary on
139
+ * `Access-Control-Request-Method` / `…-Request-Headers` (we always
140
+ * derive the allow-headers value from the request), so those tokens
141
+ * are intentionally omitted to avoid fragmenting downstream caches.
142
+ */
143
+ export const buildPreflightResponse = (cfg, req) => {
144
+ const reqOrigin = req.headers['origin'] ?? '';
145
+ const allowMethods = (cfg.allowMethods ?? DEFAULT_METHODS).join(', ');
146
+ const requested = req.headers['access-control-request-headers'];
147
+ const allowHeaders = intersectAllowHeaders(requested, cfg.allowHeaders);
148
+ const allowed = resolveOrigin(cfg, reqOrigin);
149
+ const headers = {
150
+ 'access-control-allow-methods': allowMethods,
151
+ 'access-control-max-age': String(cfg.maxAge ?? 86_400),
152
+ vary: 'Origin',
153
+ };
154
+ // Empty string == hard lockdown from intersectAllowHeaders.
155
+ // Emitting `access-control-allow-headers: ` would be a syntactically
156
+ // valid but functionally hostile header; omit it instead so the
157
+ // browser falls back to denying the preflight cleanly.
158
+ if (allowHeaders !== '') {
159
+ headers['access-control-allow-headers'] = allowHeaders;
160
+ }
161
+ if (allowed !== '')
162
+ headers['access-control-allow-origin'] = allowed;
163
+ if (cfg.credentials)
164
+ headers['access-control-allow-credentials'] = 'true';
165
+ return { empty: true, status: 204, headers };
166
+ };
167
+ //# sourceMappingURL=cors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cors.js","sourceRoot":"","sources":["../src/cors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Config } from './types.js';
2
+ /**
3
+ * Identity helper providing TypeScript intellisense at the config
4
+ * call site. Equivalent to `(config: Config) => config`.
5
+ *
6
+ * In non-production environments the returned config is **deep**-frozen
7
+ * so accidental mutation — including `config.routes['GET /x'] = …`
8
+ * or pushing into `cors.allowMethods` — throws loudly in tests instead
9
+ * of corrupting the server silently. Production skips the freeze to
10
+ * avoid breaking callers that legitimately patch the object after
11
+ * `defineConfig()` for env-specific wiring.
12
+ *
13
+ * Handler functions inside `routes` are intentionally left mutable
14
+ * (they're rebuilt per call anyway) — freeze stops at function
15
+ * boundaries.
16
+ *
17
+ * Usage:
18
+ * ```ts
19
+ * import { defineConfig } from '@databehave/server'
20
+ * export default defineConfig({ routes: { ... } })
21
+ * ```
22
+ */
23
+ export declare const defineConfig: (config: Config) => Config;
24
+ /** @internal exported for the JSON config loader to apply the same protection. */
25
+ export declare const _deepFreezeForDev: <T>(value: T) => T;
26
+ //# sourceMappingURL=define.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.d.ts","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAoBxC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,YAAY,GAAI,QAAQ,MAAM,KAAG,MAK7C,CAAA;AAED,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,CAG/C,CAAA"}
package/dist/define.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Recursively freeze a value so mutation throws in strict mode.
3
+ * Skips functions (handlers stay callable, and freezing their
4
+ * own properties is rarely useful) and respects already-frozen
5
+ * branches to avoid revisiting cycles.
6
+ */
7
+ const deepFreeze = (value, seen = new WeakSet()) => {
8
+ if (value === null || typeof value !== 'object')
9
+ return value;
10
+ if (seen.has(value))
11
+ return value;
12
+ seen.add(value);
13
+ if (Object.isFrozen(value))
14
+ return value;
15
+ for (const v of Object.values(value)) {
16
+ if (v !== null && typeof v === 'object')
17
+ deepFreeze(v, seen);
18
+ }
19
+ Object.freeze(value);
20
+ return value;
21
+ };
22
+ /**
23
+ * Identity helper providing TypeScript intellisense at the config
24
+ * call site. Equivalent to `(config: Config) => config`.
25
+ *
26
+ * In non-production environments the returned config is **deep**-frozen
27
+ * so accidental mutation — including `config.routes['GET /x'] = …`
28
+ * or pushing into `cors.allowMethods` — throws loudly in tests instead
29
+ * of corrupting the server silently. Production skips the freeze to
30
+ * avoid breaking callers that legitimately patch the object after
31
+ * `defineConfig()` for env-specific wiring.
32
+ *
33
+ * Handler functions inside `routes` are intentionally left mutable
34
+ * (they're rebuilt per call anyway) — freeze stops at function
35
+ * boundaries.
36
+ *
37
+ * Usage:
38
+ * ```ts
39
+ * import { defineConfig } from '@databehave/server'
40
+ * export default defineConfig({ routes: { ... } })
41
+ * ```
42
+ */
43
+ export const defineConfig = (config) => {
44
+ if (process.env.NODE_ENV !== 'production') {
45
+ deepFreeze(config);
46
+ }
47
+ return config;
48
+ };
49
+ /** @internal exported for the JSON config loader to apply the same protection. */
50
+ export const _deepFreezeForDev = (value) => {
51
+ if (process.env.NODE_ENV !== 'production')
52
+ deepFreeze(value);
53
+ return value;
54
+ };
55
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../src/define.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAI,KAAQ,EAAE,OAAwB,IAAI,OAAO,EAAE,EAAK,EAAE;IAC3E,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAC7D,IAAI,IAAI,CAAC,GAAG,CAAC,KAAe,CAAC;QAAE,OAAO,KAAK,CAAA;IAC3C,IAAI,CAAC,GAAG,CAAC,KAAe,CAAC,CAAA;IACzB,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACpB,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,MAAc,EAAU,EAAE;IACrD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,UAAU,CAAC,MAAM,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAI,KAAQ,EAAK,EAAE;IAClD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAAE,UAAU,CAAC,KAAK,CAAC,CAAA;IAC5D,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Public entry point for `@databehave/server`.
3
+ *
4
+ * Re-exports the surface that consumers are allowed to use. Internal
5
+ * modules (`request`, `response`, `route-key`) are not re-exported on
6
+ * purpose — they are implementation details.
7
+ *
8
+ * `@databehave/server` is standalone — it ships with an in-server
9
+ * OAS-driven mock generator and pulls no DSL dependency at runtime.
10
+ * For richer mock data (distributions, datasets, FK-aware generation)
11
+ * install the DSL package separately and import it directly.
12
+ */
13
+ export { defineConfig } from './define.js';
14
+ export { run, type RunHandle, type RunOptions } from './run.js';
15
+ export { createServer } from './server.js';
16
+ export { seedFor, type SeedInput } from './openapi/seed.js';
17
+ export { loadConfig, type EndpointResponse, type EndpointSpec, type LoadedConfig, type LoadConfigOptions, type JsonConfig, } from './json-config.js';
18
+ export { resolveStatus, type MockModeConfig, type MockModeLogger, } from './mock-mode.js';
19
+ export type { Config, CorsConfig, Handler, ListenHandle, ListenOptions, Method, MockRequest, MockResponse, MockResponseBody, ObservedMethod, RouteKey, Server, } from './types.js';
20
+ export type { AdminModeConfig, ErrorMode, StickyOverride, OverrideMatcher, AdminModeCors, } from './admin/admin-types.js';
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,cAAc,GACpB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,MAAM,EACN,UAAU,EACV,OAAO,EACP,YAAY,EACZ,aAAa,EACb,MAAM,EACN,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,QAAQ,EACR,MAAM,GACP,MAAM,YAAY,CAAA;AAGnB,YAAY,EACV,eAAe,EACf,SAAS,EACT,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,wBAAwB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Public entry point for `@databehave/server`.
3
+ *
4
+ * Re-exports the surface that consumers are allowed to use. Internal
5
+ * modules (`request`, `response`, `route-key`) are not re-exported on
6
+ * purpose — they are implementation details.
7
+ *
8
+ * `@databehave/server` is standalone — it ships with an in-server
9
+ * OAS-driven mock generator and pulls no DSL dependency at runtime.
10
+ * For richer mock data (distributions, datasets, FK-aware generation)
11
+ * install the DSL package separately and import it directly.
12
+ */
13
+ export { defineConfig } from './define.js';
14
+ export { run } from './run.js';
15
+ export { createServer } from './server.js';
16
+ export { seedFor } from './openapi/seed.js';
17
+ export { loadConfig, } from './json-config.js';
18
+ export { resolveStatus, } from './mock-mode.js';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAmC,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAkB,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACL,UAAU,GAMX,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,aAAa,GAGd,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,170 @@
1
+ import { type MockModeConfig } from './mock-mode.js';
2
+ import type { Config, CorsConfig, Handler } from './types.js';
3
+ /**
4
+ * Static response declarable per endpoint. Returned verbatim when the
5
+ * endpoint uses the `{ response }` form. Mirrors the JSON-safe subset
6
+ * of `MockResponse` (no `text` / `html` / `raw`).
7
+ */
8
+ export interface EndpointResponse {
9
+ status: number;
10
+ json?: unknown;
11
+ empty?: boolean;
12
+ headers?: Record<string, string>;
13
+ }
14
+ /**
15
+ * Per-endpoint declaration. Three forms:
16
+ *
17
+ * - **string**: module path to a handler (shorthand for `{ handler }`)
18
+ * - **`{ handler, status? }`**: dynamic-import handler. Optional
19
+ * `status` registers an HTTP status override for this route in
20
+ * the mock-mode `pathOverrides` map (e.g. force 500 for that route).
21
+ * - **`{ response }`**: static response only — no handler module.
22
+ * The handler is synthesized to return the literal response.
23
+ *
24
+ * `handler` and `response` are mutually exclusive.
25
+ */
26
+ export type EndpointSpec = string | {
27
+ handler: string;
28
+ status?: number;
29
+ response?: never;
30
+ } | {
31
+ response: EndpointResponse;
32
+ handler?: never;
33
+ status?: never;
34
+ };
35
+ /**
36
+ * Raw JSON shape declared inside `databehave.json`. Mirrors a
37
+ * narrow subset of `Config` plus the on-disk additions
38
+ * (`endpoints` map of route-key → `EndpointSpec`).
39
+ */
40
+ export interface JsonConfig {
41
+ /** Path to the JSON OpenAPI document, relative to this file. */
42
+ openapi?: string;
43
+ /** Server listen options used by the CLI. */
44
+ server?: {
45
+ host?: string;
46
+ port?: number;
47
+ };
48
+ /**
49
+ * Prefix automatically prepended to every `endpoints` key.
50
+ * Lets callers write `"GET products/list"` instead of
51
+ * repeating the API prefix in every entry. Must start with `/` and
52
+ * must not end with `/` (e.g. `"/api/v1"`). OpenAPI paths are
53
+ * left untouched — they already carry their full path in the OAS document.
54
+ */
55
+ basePath?: string;
56
+ /**
57
+ * CORS knobs. `origin` may be a single allowed origin string or an
58
+ * allowlist of strings (the function form on `CorsConfig`
59
+ * is reserved for the programmatic API). Anything off the allowlist
60
+ * is rejected (empty header) so misconfigured callers fail loudly
61
+ * instead of silently leaking `*`.
62
+ */
63
+ cors?: Omit<CorsConfig, 'origin'> & {
64
+ origin?: string | readonly string[];
65
+ };
66
+ /** Built-in mock-mode behaviour. Disabled by default. */
67
+ mockMode?: MockModeConfig;
68
+ /**
69
+ * Opt-in admin / error-injection panel. Default: disabled.
70
+ * Pass-through to `Config.admin`. The JSON loader
71
+ * automatically supplements `openapiBody` from the resolved OpenAPI
72
+ * document so the UI route picker works without manual wiring.
73
+ */
74
+ admin?: Config['admin'];
75
+ /**
76
+ * Opt-in per-request access logs. Pass-through to
77
+ * `Config.log`. Default: disabled. See README
78
+ * "Access logs" for the shape.
79
+ */
80
+ log?: Config['log'];
81
+ /**
82
+ * Opt-in inbound request validation against the OpenAPI document.
83
+ * Pass-through to `Config.validation`. Default off
84
+ * (`{ request: false }`) — when omitted the runtime behaves
85
+ * byte-identical to a build without the validator.
86
+ */
87
+ validation?: Config['validation'];
88
+ /**
89
+ * Opt-in auto-schema mode (Phase 2C). When `enabled: true`, every
90
+ * OAS path not covered by `endpoints` is served from data
91
+ * generated by `@databehave/schema`'s `mock()` engine, derived
92
+ * from the OpenAPI document. The peer is loaded via dynamic
93
+ * `import()` at server-creation time; install it separately with
94
+ * `npm i @databehave/schema`. See README "Auto-schema mode".
95
+ *
96
+ * Always an object — the legacy boolean shorthand
97
+ * (`schema: true`) was removed. Unknown keys throw at
98
+ * config-load time. Fields:
99
+ *
100
+ * - `enabled` — required boolean. `false` (or omitting the
101
+ * `schema` field entirely) keeps the default JSONC mock-only
102
+ * flow.
103
+ * - `seed` — `number` (fixed), `"stable"` (per-request hash),
104
+ * or `"random"` (fresh per request). Default `"stable"`.
105
+ * - `locale` — optional locale tag (forwarded as a future hint).
106
+ * - `arrayCount` — default array length when OAS lacks `minItems`.
107
+ */
108
+ schema?: {
109
+ enabled: boolean;
110
+ seed?: number | 'stable' | 'random';
111
+ locale?: string;
112
+ arrayCount?: number;
113
+ };
114
+ /**
115
+ * Route-key → endpoint declaration map. Keys may be written
116
+ * relative to `basePath` (e.g. `"GET products/list"`); they
117
+ * may also be absolute (`"GET /health"`) — any key starting with
118
+ * `/` after the method is registered verbatim.
119
+ */
120
+ endpoints?: Partial<Record<string, EndpointSpec>>;
121
+ }
122
+ /** Result of loading a JSON config from disk. */
123
+ export interface LoadedConfig {
124
+ /** Fully-assembled config ready for `createServer`. */
125
+ readonly config: Config;
126
+ /** Server listen options copied verbatim from the JSON. */
127
+ readonly server: {
128
+ host: string;
129
+ port: number;
130
+ };
131
+ }
132
+ /**
133
+ * Options for `loadConfig`.
134
+ */
135
+ export interface LoadConfigOptions {
136
+ /**
137
+ * Pre-resolved handler map. Keys may match the JSONC `endpoints`
138
+ * value either exactly (e.g. `./src/routes/health.js`) or in any
139
+ * canonically equivalent form — leading `./` and the file extension
140
+ * (`.js`/`.mjs`/`.cjs`/`.ts`/`.tsx`/`.mts`/`.cts`) are stripped
141
+ * before comparison. When a key matches, the handler is used
142
+ * directly and the dynamic `import()` for that route is skipped.
143
+ *
144
+ * Use case: test environments (vitest under plain Node 18) that cannot
145
+ * load `.ts` source files through native `import()`. Construct the map
146
+ * via static imports or `import.meta.glob('eager')`, then pass it in.
147
+ *
148
+ * Handlers not present in the map fall back to dynamic import. Values
149
+ * that are not functions raise an error at boot time.
150
+ */
151
+ handlers?: Record<string, Handler>;
152
+ /**
153
+ * Sink for non-fatal warnings emitted while wiring the OpenAPI
154
+ * adapter (walk errors, empty schemas). Defaults to `console.warn`.
155
+ * Inject a no-op logger from tests to silence the output, or a
156
+ * structured logger in production to capture the messages.
157
+ */
158
+ logger?: {
159
+ warn(message: string): void;
160
+ };
161
+ }
162
+ /**
163
+ * Load and fully resolve a `databehave.json`.
164
+ *
165
+ * Returns a ready-to-run `Config` plus the listen options the
166
+ * CLI should bind to. Errors are thrown synchronously after parsing
167
+ * to fail fast on bad configs.
168
+ */
169
+ export declare const loadConfig: (configPath: string, options?: LoadConfigOptions) => Promise<LoadedConfig>;
170
+ //# sourceMappingURL=json-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-config.d.ts","sourceRoot":"","sources":["../src/json-config.ts"],"names":[],"mappings":"AAoBA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAA;AAYvB,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,OAAO,EAGR,MAAM,YAAY,CAAA;AAEnB;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB,MAAM,GACN;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GACtD;IAAE,QAAQ,EAAE,gBAAgB,CAAC;IAAC,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,CAAA;AAEnE;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6CAA6C;IAC7C,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG;QAClC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;KACpC,CAAA;IACD,yDAAyD;IACzD,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IACvB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,CAAA;IACjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,EAAE,OAAO,CAAA;QAChB,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;QACnC,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IACD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;CAClD;AAED,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAChD;AAybD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC;;;;;OAKG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACzC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,YAAY,MAAM,EAClB,UAAU,iBAAiB,KAC1B,OAAO,CAAC,YAAY,CAgUtB,CAAA"}