@databehave/server 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +85 -83
- package/dist/cors.d.ts +1 -1
- package/dist/cors.js +1 -1
- package/dist/cors.js.map +1 -1
- package/dist/http.d.ts +94 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +23 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +10 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -18
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +9 -49
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +16 -92
- package/dist/log.js.map +1 -1
- package/dist/node-authority.d.ts +12 -0
- package/dist/node-authority.d.ts.map +1 -0
- package/dist/node-authority.js +72 -0
- package/dist/node-authority.js.map +1 -0
- package/dist/node-body.d.ts +11 -0
- package/dist/node-body.d.ts.map +1 -0
- package/dist/node-body.js +61 -0
- package/dist/node-body.js.map +1 -0
- package/dist/node-http.d.ts +19 -0
- package/dist/node-http.d.ts.map +1 -0
- package/dist/node-http.js +210 -0
- package/dist/node-http.js.map +1 -0
- package/dist/plugins/access-log.d.ts +11 -0
- package/dist/plugins/access-log.d.ts.map +1 -0
- package/dist/plugins/access-log.js +27 -0
- package/dist/plugins/access-log.js.map +1 -0
- package/dist/plugins/cors.d.ts +5 -0
- package/dist/plugins/cors.d.ts.map +1 -0
- package/dist/plugins/cors.js +35 -0
- package/dist/plugins/cors.js.map +1 -0
- package/dist/plugins/routes.d.ts +5 -0
- package/dist/plugins/routes.d.ts.map +1 -0
- package/dist/plugins/routes.js +10 -0
- package/dist/plugins/routes.js.map +1 -0
- package/dist/request.d.ts +2 -2
- package/dist/request.d.ts.map +1 -1
- package/dist/request.js +6 -4
- package/dist/request.js.map +1 -1
- package/dist/route-key.d.ts +2 -0
- package/dist/route-key.d.ts.map +1 -1
- package/dist/route-key.js +5 -1
- package/dist/route-key.js.map +1 -1
- package/dist/server.d.ts +7 -59
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +289 -466
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +10 -156
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/package.json +11 -24
- package/dist/admin/admin-routes.d.ts +0 -42
- package/dist/admin/admin-routes.d.ts.map +0 -1
- package/dist/admin/admin-routes.js +0 -472
- package/dist/admin/admin-routes.js.map +0 -1
- package/dist/admin/admin-types.d.ts +0 -170
- package/dist/admin/admin-types.d.ts.map +0 -1
- package/dist/admin/admin-types.js +0 -30
- package/dist/admin/admin-types.js.map +0 -1
- package/dist/admin/banner.d.ts +0 -11
- package/dist/admin/banner.d.ts.map +0 -1
- package/dist/admin/banner.js +0 -5
- package/dist/admin/banner.js.map +0 -1
- package/dist/admin/header-parser.d.ts +0 -14
- package/dist/admin/header-parser.d.ts.map +0 -1
- package/dist/admin/header-parser.js +0 -171
- package/dist/admin/header-parser.js.map +0 -1
- package/dist/admin/inject.d.ts +0 -48
- package/dist/admin/inject.d.ts.map +0 -1
- package/dist/admin/inject.js +0 -167
- package/dist/admin/inject.js.map +0 -1
- package/dist/admin/overrides-store.d.ts +0 -18
- package/dist/admin/overrides-store.d.ts.map +0 -1
- package/dist/admin/overrides-store.js +0 -100
- package/dist/admin/overrides-store.js.map +0 -1
- package/dist/admin/resolve-cors.d.ts +0 -22
- package/dist/admin/resolve-cors.d.ts.map +0 -1
- package/dist/admin/resolve-cors.js +0 -28
- package/dist/admin/resolve-cors.js.map +0 -1
- package/dist/admin/scenarios-store.d.ts +0 -15
- package/dist/admin/scenarios-store.d.ts.map +0 -1
- package/dist/admin/scenarios-store.js +0 -109
- package/dist/admin/scenarios-store.js.map +0 -1
- package/dist/admin/ui.css +0 -1
- package/dist/admin/ui.html +0 -13
- package/dist/admin/ui.js +0 -240
- package/dist/bin-helpers.d.ts +0 -46
- package/dist/bin-helpers.d.ts.map +0 -1
- package/dist/bin-helpers.js +0 -61
- package/dist/bin-helpers.js.map +0 -1
- package/dist/bin.d.ts +0 -3
- package/dist/bin.d.ts.map +0 -1
- package/dist/bin.js +0 -86
- package/dist/bin.js.map +0 -1
- package/dist/define.d.ts +0 -26
- package/dist/define.d.ts.map +0 -1
- package/dist/define.js +0 -55
- package/dist/define.js.map +0 -1
- package/dist/json-config.d.ts +0 -170
- package/dist/json-config.d.ts.map +0 -1
- package/dist/json-config.js +0 -684
- package/dist/json-config.js.map +0 -1
- package/dist/jsonc.d.ts +0 -24
- package/dist/jsonc.d.ts.map +0 -1
- package/dist/jsonc.js +0 -125
- package/dist/jsonc.js.map +0 -1
- package/dist/middleware/request-validation.d.ts +0 -58
- package/dist/middleware/request-validation.d.ts.map +0 -1
- package/dist/middleware/request-validation.js +0 -328
- package/dist/middleware/request-validation.js.map +0 -1
- package/dist/mock-mode.d.ts +0 -95
- package/dist/mock-mode.d.ts.map +0 -1
- package/dist/mock-mode.js +0 -95
- package/dist/mock-mode.js.map +0 -1
- package/dist/openapi/auto-schema.d.ts +0 -83
- package/dist/openapi/auto-schema.d.ts.map +0 -1
- package/dist/openapi/auto-schema.js +0 -232
- package/dist/openapi/auto-schema.js.map +0 -1
- package/dist/openapi/generate.d.ts +0 -20
- package/dist/openapi/generate.d.ts.map +0 -1
- package/dist/openapi/generate.js +0 -121
- package/dist/openapi/generate.js.map +0 -1
- package/dist/openapi/loader.d.ts +0 -18
- package/dist/openapi/loader.d.ts.map +0 -1
- package/dist/openapi/loader.js +0 -25
- package/dist/openapi/loader.js.map +0 -1
- package/dist/openapi/register.d.ts +0 -58
- package/dist/openapi/register.d.ts.map +0 -1
- package/dist/openapi/register.js +0 -166
- package/dist/openapi/register.js.map +0 -1
- package/dist/openapi/seed.d.ts +0 -16
- package/dist/openapi/seed.d.ts.map +0 -1
- package/dist/openapi/seed.js +0 -58
- package/dist/openapi/seed.js.map +0 -1
- package/dist/openapi/translate.d.ts +0 -55
- package/dist/openapi/translate.d.ts.map +0 -1
- package/dist/openapi/translate.js +0 -319
- package/dist/openapi/translate.js.map +0 -1
- package/dist/openapi/walker.d.ts +0 -44
- package/dist/openapi/walker.d.ts.map +0 -1
- package/dist/openapi/walker.js +0 -15
- package/dist/openapi/walker.js.map +0 -1
- package/dist/run.d.ts +0 -27
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js +0 -87
- package/dist/run.js.map +0 -1
- package/dist/validation/validate.d.ts +0 -38
- package/dist/validation/validate.d.ts.map +0 -1
- package/dist/validation/validate.js +0 -372
- package/dist/validation/validate.js.map +0 -1
package/dist/mock-mode.d.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in mock-mode middleware.
|
|
3
|
-
*
|
|
4
|
-
* Selects an HTTP *status* per request and either short-circuits the
|
|
5
|
-
* handler with a synthesized response of that status or lets it
|
|
6
|
-
* through. All configuration is declarative — driven entirely by
|
|
7
|
-
* `mockMode` in `databehave.json`.
|
|
8
|
-
*
|
|
9
|
-
* Resolution order per request (first hit wins):
|
|
10
|
-
* 1. `pathOverrides["<METHOD> <path>"]`
|
|
11
|
-
* 2. `pathOverrides["<path>"]`
|
|
12
|
-
* 3. `defaultStatus`
|
|
13
|
-
* 4. passthrough (real handler runs)
|
|
14
|
-
*
|
|
15
|
-
* Body resolution for a non-passthrough status N:
|
|
16
|
-
* 1. status === 204 → empty body
|
|
17
|
-
* 2. `bodyResolver(method, path, N)` returns a body
|
|
18
|
-
* (typically OpenAPI `responses[N]` schema mock)
|
|
19
|
-
* 3. fallback envelope `{ error: true, status: N }`
|
|
20
|
-
*
|
|
21
|
-
* The header `x-mock-status` is always tagged on the final response
|
|
22
|
-
* (configurable via `header`). Health paths bypass everything.
|
|
23
|
-
*/
|
|
24
|
-
import type { MockRequest, MockResponse } from './types.js';
|
|
25
|
-
export type BodyResolver = (method: string, path: string, status: number) => unknown | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Minimal logger interface (compatible with the host server's logger
|
|
28
|
-
* and with `console`). Only `warn` is required by mock-mode today; the
|
|
29
|
-
* shape is kept narrow so callers can pass an existing logger without
|
|
30
|
-
* adapter glue.
|
|
31
|
-
*/
|
|
32
|
-
export interface MockModeLogger {
|
|
33
|
-
warn(message: string): void;
|
|
34
|
-
}
|
|
35
|
-
export interface MockModeConfig {
|
|
36
|
-
/** Master switch. When `false` or absent, the feature is disabled. */
|
|
37
|
-
enabled?: boolean;
|
|
38
|
-
/** MockResponse header that tags every response with the resolved status. */
|
|
39
|
-
header?: string;
|
|
40
|
-
/**
|
|
41
|
-
* When `true`, an incoming request may force the mocked status by
|
|
42
|
-
* sending the same header (default `x-mock-status: 500`). Disabled
|
|
43
|
-
* by default so production-style mock servers don't expose status
|
|
44
|
-
* injection to arbitrary clients. Resolution becomes:
|
|
45
|
-
* 1. request `header` value (when `allowHeaderOverride === true`)
|
|
46
|
-
* 2. `pathOverrides["<METHOD> <path>"]`
|
|
47
|
-
* 3. `pathOverrides["<path>"]`
|
|
48
|
-
* 4. `defaultStatus`
|
|
49
|
-
* 5. passthrough
|
|
50
|
-
*/
|
|
51
|
-
allowHeaderOverride?: boolean;
|
|
52
|
-
/** Paths exempt from status injection (typically health probes). */
|
|
53
|
-
healthPaths?: readonly string[];
|
|
54
|
-
/**
|
|
55
|
-
* Status applied when no `pathOverrides` entry matches. Omit (or set
|
|
56
|
-
* `undefined`) for passthrough (real handler runs). Set to an error
|
|
57
|
-
* code (e.g. `500`) to force every route to that status by default.
|
|
58
|
-
*/
|
|
59
|
-
defaultStatus?: number;
|
|
60
|
-
/**
|
|
61
|
-
* Per-route status overrides. Keys use one of:
|
|
62
|
-
* - `"<METHOD> <path>"` (e.g. `"GET /api/v1/x"`) — method-scoped
|
|
63
|
-
* - `"<path>"` (e.g. `"/api/v1/x"`) — any method
|
|
64
|
-
* Paths must be absolute (start with `/`). Values are HTTP status codes.
|
|
65
|
-
*/
|
|
66
|
-
pathOverrides?: Record<string, number>;
|
|
67
|
-
/**
|
|
68
|
-
* Logger used for non-fatal diagnostics (e.g. out-of-range header
|
|
69
|
-
* overrides). Defaults to the global `console`. Pass the host
|
|
70
|
-
* application's logger to keep mock-server output in one place
|
|
71
|
-
* instead of leaking to stdout/stderr.
|
|
72
|
-
*/
|
|
73
|
-
logger?: MockModeLogger;
|
|
74
|
-
}
|
|
75
|
-
export interface MockModeHooks {
|
|
76
|
-
onRequest: (req: MockRequest) => MockResponse | undefined;
|
|
77
|
-
onResponse: (req: MockRequest, res: MockResponse) => MockResponse;
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Resolve the status code for a request using only the supplied config.
|
|
81
|
-
* Returns `undefined` when the request should pass through.
|
|
82
|
-
* Exported for unit-testing; callers normally use `buildMockModeHooks`.
|
|
83
|
-
*/
|
|
84
|
-
export declare const resolveStatus: (method: string, path: string, config: MockModeConfig) => number | undefined;
|
|
85
|
-
/**
|
|
86
|
-
* Build the onRequest / onResponse hook pair. Returns `undefined`
|
|
87
|
-
* when the feature is disabled (caller may skip wiring entirely).
|
|
88
|
-
*
|
|
89
|
-
* `bodyResolver` is optional. When provided, @databehave/server asks it for a
|
|
90
|
-
* body for the configured status (typically a generator backed by
|
|
91
|
-
* the OpenAPI `responses[N]` schema). When it returns `undefined`,
|
|
92
|
-
* the minimal envelope `{ error: true, status: N }` is used instead.
|
|
93
|
-
*/
|
|
94
|
-
export declare const buildMockModeHooks: (config: MockModeConfig, bodyResolver?: BodyResolver) => MockModeHooks | undefined;
|
|
95
|
-
//# sourceMappingURL=mock-mode.d.ts.map
|
package/dist/mock-mode.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mock-mode.d.ts","sourceRoot":"","sources":["../src/mock-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE3D,MAAM,MAAM,YAAY,GAAG,CACzB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,KACX,OAAO,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,oEAAoE;IACpE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,YAAY,GAAG,SAAS,CAAA;IACzD,UAAU,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,KAAK,YAAY,CAAA;CAClE;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACxB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,cAAc,KACrB,MAAM,GAAG,SAQX,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,cAAc,EACtB,eAAe,YAAY,KAC1B,aAAa,GAAG,SA4ElB,CAAA"}
|
package/dist/mock-mode.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolve the status code for a request using only the supplied config.
|
|
3
|
-
* Returns `undefined` when the request should pass through.
|
|
4
|
-
* Exported for unit-testing; callers normally use `buildMockModeHooks`.
|
|
5
|
-
*/
|
|
6
|
-
export const resolveStatus = (method, path, config) => {
|
|
7
|
-
const overrides = config.pathOverrides ?? {};
|
|
8
|
-
const m = method.toUpperCase();
|
|
9
|
-
const byMethodPath = overrides[`${m} ${path}`];
|
|
10
|
-
if (byMethodPath !== undefined)
|
|
11
|
-
return byMethodPath;
|
|
12
|
-
const byPath = overrides[path];
|
|
13
|
-
if (byPath !== undefined)
|
|
14
|
-
return byPath;
|
|
15
|
-
return config.defaultStatus;
|
|
16
|
-
};
|
|
17
|
-
/**
|
|
18
|
-
* Build the onRequest / onResponse hook pair. Returns `undefined`
|
|
19
|
-
* when the feature is disabled (caller may skip wiring entirely).
|
|
20
|
-
*
|
|
21
|
-
* `bodyResolver` is optional. When provided, @databehave/server asks it for a
|
|
22
|
-
* body for the configured status (typically a generator backed by
|
|
23
|
-
* the OpenAPI `responses[N]` schema). When it returns `undefined`,
|
|
24
|
-
* the minimal envelope `{ error: true, status: N }` is used instead.
|
|
25
|
-
*/
|
|
26
|
-
export const buildMockModeHooks = (config, bodyResolver) => {
|
|
27
|
-
if (config.enabled !== true)
|
|
28
|
-
return undefined;
|
|
29
|
-
const header = config.header ?? 'x-mock-status';
|
|
30
|
-
const healthPaths = new Set(config.healthPaths ?? []);
|
|
31
|
-
const isHealthPath = (p) => healthPaths.has(p);
|
|
32
|
-
const logger = config.logger ?? console;
|
|
33
|
-
const synthesize = (method, path, status) => {
|
|
34
|
-
const headers = { [header]: String(status) };
|
|
35
|
-
if (status === 204) {
|
|
36
|
-
return { status, empty: true, headers };
|
|
37
|
-
}
|
|
38
|
-
const body = bodyResolver?.(method, path, status) ?? {
|
|
39
|
-
error: true,
|
|
40
|
-
status,
|
|
41
|
-
};
|
|
42
|
-
return { status, json: body, headers };
|
|
43
|
-
};
|
|
44
|
-
const onRequest = (req) => {
|
|
45
|
-
if (isHealthPath(req.path))
|
|
46
|
-
return undefined;
|
|
47
|
-
// Header override (opt-in). The header name is the same one used
|
|
48
|
-
// to tag responses so a single curl flag flips both directions.
|
|
49
|
-
// 1xx (informational) responses are rejected: Node's HTTP layer
|
|
50
|
-
// treats them specially and a mock server has no use for them.
|
|
51
|
-
if (config.allowHeaderOverride === true) {
|
|
52
|
-
const raw = req.headers[header.toLowerCase()];
|
|
53
|
-
if (raw !== undefined) {
|
|
54
|
-
const n = Number.parseInt(raw, 10);
|
|
55
|
-
if (Number.isFinite(n) && n >= 200 && n < 600) {
|
|
56
|
-
return synthesize(req.method, req.path, n);
|
|
57
|
-
}
|
|
58
|
-
// Out-of-range or non-numeric values were previously dropped on
|
|
59
|
-
// the floor, which made debugging "why doesn't my override
|
|
60
|
-
// work?" needlessly hard. Emit a single warn line so the typo
|
|
61
|
-
// is visible without escalating to a hard failure (which would
|
|
62
|
-
// break legitimate clients that ship the header for other
|
|
63
|
-
// reasons).
|
|
64
|
-
logger.warn(`@databehave/server/mock-mode: ignored ${header}=${JSON.stringify(raw)} ` +
|
|
65
|
-
`(must be an integer in [200, 600))`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
const status = resolveStatus(req.method, req.path, config);
|
|
69
|
-
if (status === undefined)
|
|
70
|
-
return undefined;
|
|
71
|
-
return synthesize(req.method, req.path, status);
|
|
72
|
-
};
|
|
73
|
-
const onResponse = (req, res) => {
|
|
74
|
-
if (isHealthPath(req.path))
|
|
75
|
-
return res;
|
|
76
|
-
// Skip when the response (synthesised or handler-supplied) already
|
|
77
|
-
// carries the tag header. Header lookup is case-insensitive so
|
|
78
|
-
// `'X-Mock-Status'` from a handler is recognised against the
|
|
79
|
-
// configured (typically lowercase) `header` name.
|
|
80
|
-
if (res.headers) {
|
|
81
|
-
const wanted = header.toLowerCase();
|
|
82
|
-
for (const k of Object.keys(res.headers)) {
|
|
83
|
-
if (k.toLowerCase() === wanted)
|
|
84
|
-
return res;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
const tag = String(res.status ?? 200);
|
|
88
|
-
return {
|
|
89
|
-
...res,
|
|
90
|
-
headers: { ...(res.headers ?? {}), [header]: tag },
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
return { onRequest, onResponse };
|
|
94
|
-
};
|
|
95
|
-
//# sourceMappingURL=mock-mode.js.map
|
package/dist/mock-mode.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mock-mode.js","sourceRoot":"","sources":["../src/mock-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-schema dispatch wiring (Phase 2C / brief item #11).
|
|
3
|
-
*
|
|
4
|
-
* When the JSONC config sets a top-level `schema:` field, this module:
|
|
5
|
-
*
|
|
6
|
-
* 1. Resolves the optional peer `@databehave/schema` via a single
|
|
7
|
-
* `await import('@databehave/schema')` (string literal — never a
|
|
8
|
-
* variable, never a helper). On `ERR_MODULE_NOT_FOUND` / similar
|
|
9
|
-
* "Cannot find module" errors, the native error is suppressed
|
|
10
|
-
* and replaced with the friendly multi-line install-hint
|
|
11
|
-
* template (see `INSTALL_HINT`). Throws fail-fast at server
|
|
12
|
-
* creation; never lazily on first request.
|
|
13
|
-
* 2. Pre-translates every OAS path/method (whose 200 / first 2xx
|
|
14
|
-
* response carries a JSON schema) into a `@databehave/schema`
|
|
15
|
-
* IR node via `translateOasToIR`. Translation errors throw at
|
|
16
|
-
* server-creation time so OAS gaps surface fail-loud — same
|
|
17
|
-
* philosophy as the validator and the OAS-only generator.
|
|
18
|
-
* 3. Synthesizes a per-route handler closing over the cached
|
|
19
|
-
* schema module + IR. At request time the handler derives a
|
|
20
|
-
* seed (per `config.schema.seed`), invokes `mock(ir, { seed })`,
|
|
21
|
-
* and returns `{ json: ... }`.
|
|
22
|
-
*
|
|
23
|
-
* Hand-written `endpoints` always win — auto-mode only fills routes
|
|
24
|
-
* absent from the user's `endpoints` map. Genuine-separation
|
|
25
|
-
* invariant: this file MUST NOT statically value-import
|
|
26
|
-
* `@databehave/schema`. Type-only imports are erased at compile time
|
|
27
|
-
* and are fine.
|
|
28
|
-
*/
|
|
29
|
-
import type { Handler, RouteKey } from '../types.js';
|
|
30
|
-
import type { OasDoc } from './walker.js';
|
|
31
|
-
/** Fully-resolved schema-mode config (after JSONC validation). */
|
|
32
|
-
export interface ResolvedSchemaConfig {
|
|
33
|
-
readonly seed: number | 'stable' | 'random';
|
|
34
|
-
readonly locale?: string;
|
|
35
|
-
readonly arrayCount?: number;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Friendly install-hint emitted when `config.schema.enabled === true`
|
|
39
|
-
* but the `@databehave/schema` peer is not installed. Verbatim from
|
|
40
|
-
* the brief — names the package, the field, the file, all three
|
|
41
|
-
* install commands, the README anchor, and the opt-out instruction.
|
|
42
|
-
*/
|
|
43
|
-
export declare const INSTALL_HINT: string;
|
|
44
|
-
/**
|
|
45
|
-
* Validate the raw JSONC `schema:` value and normalise to the
|
|
46
|
-
* resolved shape. The value MUST be an object with an explicit
|
|
47
|
-
* `enabled: boolean`. The boolean shorthand (`schema: true` /
|
|
48
|
-
* `schema: false`) was removed — callers receive a migration
|
|
49
|
-
* error pointing at the new shape. Returns `null` when
|
|
50
|
-
* `enabled === false` so the caller can short-circuit auto-mode.
|
|
51
|
-
* Unknown keys throw with a message pointing at the offending key.
|
|
52
|
-
*/
|
|
53
|
-
export declare const normaliseSchemaConfig: (raw: unknown) => ResolvedSchemaConfig | null;
|
|
54
|
-
/**
|
|
55
|
-
* Load the optional peer `@databehave/schema` package. On
|
|
56
|
-
* "Cannot find module" failures the native Node error is suppressed
|
|
57
|
-
* and replaced with the friendly install hint above. Other errors
|
|
58
|
-
* (e.g. broken install) re-throw verbatim — those are real bugs.
|
|
59
|
-
*/
|
|
60
|
-
export declare const loadSchemaModule: () => Promise<typeof import("@databehave/schema")>;
|
|
61
|
-
/**
|
|
62
|
-
* FNV-1a 32-bit hash. Tiny, zero-dep, stable across machines —
|
|
63
|
-
* exactly what the per-request `seed: 'stable'` derivation needs.
|
|
64
|
-
*
|
|
65
|
-
* Input format: `${METHOD} ${endpointPath}|${sortedQuery}|${sortedPathParams}`,
|
|
66
|
-
* where sorted means lex-sorted keys joined by `&` as `key=value`.
|
|
67
|
-
*
|
|
68
|
-
* Example input → output (uint32):
|
|
69
|
-
* `GET /users/:id|page=2|id=42` → 0x9b1ed8c5
|
|
70
|
-
*/
|
|
71
|
-
export declare const hashSeed: (input: string) => number;
|
|
72
|
-
/**
|
|
73
|
-
* Build a route-key → handler map for every OAS path/method whose
|
|
74
|
-
* response carries a usable JSON schema and is NOT already covered
|
|
75
|
-
* by hand-written `endpoints`. Each handler is closed over the
|
|
76
|
-
* cached schema module and pre-translated IR.
|
|
77
|
-
*
|
|
78
|
-
* `declaredKeys` is the set of route keys the user already declared
|
|
79
|
-
* via `endpoints`; auto-mode skips those so hand-written routes
|
|
80
|
-
* always win.
|
|
81
|
-
*/
|
|
82
|
-
export declare const buildAutoSchemaRoutes: (doc: OasDoc, cfg: ResolvedSchemaConfig, schemaModule: typeof import("@databehave/schema"), declaredKeys: ReadonlySet<RouteKey>) => Promise<Map<RouteKey, Handler>>;
|
|
83
|
-
//# sourceMappingURL=auto-schema.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-schema.d.ts","sourceRoot":"","sources":["../../src/openapi/auto-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,OAAO,EAAuB,QAAQ,EAAE,MAAM,aAAa,CAAA;AAGzE,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,aAAa,CAAA;AAElD,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B;AAaD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAY6D,CAAA;AAEtF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,GAAI,KAAK,OAAO,KAAG,oBAAoB,GAAG,IA+D3E,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,cAAc,oBAAoB,CAAC,CAmBpF,CAAA;AAiBD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,MAOxC,CAAA;AA+CD;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,GAChC,KAAK,MAAM,EACX,KAAK,oBAAoB,EACzB,cAAc,cAAc,oBAAoB,CAAC,EACjD,cAAc,WAAW,CAAC,QAAQ,CAAC,KAClC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAgChC,CAAA"}
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import { translateOasToIR } from './translate.js';
|
|
2
|
-
/** Single-shot guard for the `schema.locale` no-op soft warn. */
|
|
3
|
-
let localeWarned = false;
|
|
4
|
-
/** Knobs accepted on the `schema:` JSONC object (alongside `enabled`). */
|
|
5
|
-
const KNOWN_SCHEMA_KEYS = new Set([
|
|
6
|
-
'enabled',
|
|
7
|
-
'seed',
|
|
8
|
-
'locale',
|
|
9
|
-
'arrayCount',
|
|
10
|
-
]);
|
|
11
|
-
/**
|
|
12
|
-
* Friendly install-hint emitted when `config.schema.enabled === true`
|
|
13
|
-
* but the `@databehave/schema` peer is not installed. Verbatim from
|
|
14
|
-
* the brief — names the package, the field, the file, all three
|
|
15
|
-
* install commands, the README anchor, and the opt-out instruction.
|
|
16
|
-
*/
|
|
17
|
-
export const INSTALL_HINT = '[@databehave/server] Auto-schema mode is enabled in databehave.jsonc\n' +
|
|
18
|
-
'("schema": { "enabled": true } is set), but the data-generation engine is not installed.\n' +
|
|
19
|
-
'\n' +
|
|
20
|
-
' npm i @databehave/schema\n' +
|
|
21
|
-
' # or: pnpm add @databehave/schema\n' +
|
|
22
|
-
' # or: yarn add @databehave/schema\n' +
|
|
23
|
-
'\n' +
|
|
24
|
-
'This enables realistic, seeded mock data derived from your OpenAPI\n' +
|
|
25
|
-
'document. See: https://github.com/ochairo/databehave/blob/main/packages/server/docs/openapi/auto-schema.md#missing-install-error\n' +
|
|
26
|
-
'\n' +
|
|
27
|
-
'To keep the default zero-dep placeholder mode instead, set\n' +
|
|
28
|
-
'"schema": { "enabled": false } or remove the "schema" field from databehave.jsonc.';
|
|
29
|
-
/**
|
|
30
|
-
* Validate the raw JSONC `schema:` value and normalise to the
|
|
31
|
-
* resolved shape. The value MUST be an object with an explicit
|
|
32
|
-
* `enabled: boolean`. The boolean shorthand (`schema: true` /
|
|
33
|
-
* `schema: false`) was removed — callers receive a migration
|
|
34
|
-
* error pointing at the new shape. Returns `null` when
|
|
35
|
-
* `enabled === false` so the caller can short-circuit auto-mode.
|
|
36
|
-
* Unknown keys throw with a message pointing at the offending key.
|
|
37
|
-
*/
|
|
38
|
-
export const normaliseSchemaConfig = (raw) => {
|
|
39
|
-
if (typeof raw === 'boolean') {
|
|
40
|
-
throw new Error('@databehave/server/config: "schema" must be an object like ' +
|
|
41
|
-
'{ "enabled": true }; the boolean shorthand was removed (got ' +
|
|
42
|
-
JSON.stringify(raw) +
|
|
43
|
-
')');
|
|
44
|
-
}
|
|
45
|
-
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
46
|
-
throw new Error('@databehave/server/config: "schema" must be an object like ' +
|
|
47
|
-
'{ "enabled": true } (got ' +
|
|
48
|
-
(raw === null ? 'null' : Array.isArray(raw) ? 'array' : typeof raw) +
|
|
49
|
-
')');
|
|
50
|
-
}
|
|
51
|
-
const obj = raw;
|
|
52
|
-
for (const k of Object.keys(obj)) {
|
|
53
|
-
if (!KNOWN_SCHEMA_KEYS.has(k)) {
|
|
54
|
-
throw new Error(`@databehave/server/config: unknown key in "schema": ${JSON.stringify(k)} ` +
|
|
55
|
-
`(valid keys: ${[...KNOWN_SCHEMA_KEYS].join(', ')})`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (typeof obj.enabled !== 'boolean') {
|
|
59
|
-
throw new Error('@databehave/server/config: "schema.enabled" must be a boolean ' +
|
|
60
|
-
`(got ${obj.enabled === undefined ? 'undefined' : JSON.stringify(obj.enabled)})`);
|
|
61
|
-
}
|
|
62
|
-
if (obj.enabled === false)
|
|
63
|
-
return null;
|
|
64
|
-
let seed = 'stable';
|
|
65
|
-
if (obj.seed !== undefined) {
|
|
66
|
-
if (typeof obj.seed === 'number' ||
|
|
67
|
-
obj.seed === 'stable' ||
|
|
68
|
-
obj.seed === 'random') {
|
|
69
|
-
seed = obj.seed;
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
throw new Error('@databehave/server/config: "schema.seed" must be a number, "stable", or "random" ' +
|
|
73
|
-
`(got ${JSON.stringify(obj.seed)})`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const out = { seed };
|
|
77
|
-
if (obj.locale !== undefined) {
|
|
78
|
-
if (typeof obj.locale !== 'string') {
|
|
79
|
-
throw new Error('@databehave/server/config: "schema.locale" must be a string');
|
|
80
|
-
}
|
|
81
|
-
out.locale = obj.locale;
|
|
82
|
-
if (!localeWarned) {
|
|
83
|
-
localeWarned = true;
|
|
84
|
-
console.warn(`[@databehave/server] schema.locale (${JSON.stringify(obj.locale)}) is currently parsed but not consumed by the data-generation engine; the value will be ignored.`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (obj.arrayCount !== undefined) {
|
|
88
|
-
if (typeof obj.arrayCount !== 'number' || !Number.isFinite(obj.arrayCount) || obj.arrayCount < 0) {
|
|
89
|
-
throw new Error('@databehave/server/config: "schema.arrayCount" must be a non-negative number');
|
|
90
|
-
}
|
|
91
|
-
out.arrayCount = obj.arrayCount;
|
|
92
|
-
}
|
|
93
|
-
return out;
|
|
94
|
-
};
|
|
95
|
-
/**
|
|
96
|
-
* Load the optional peer `@databehave/schema` package. On
|
|
97
|
-
* "Cannot find module" failures the native Node error is suppressed
|
|
98
|
-
* and replaced with the friendly install hint above. Other errors
|
|
99
|
-
* (e.g. broken install) re-throw verbatim — those are real bugs.
|
|
100
|
-
*/
|
|
101
|
-
export const loadSchemaModule = async () => {
|
|
102
|
-
try {
|
|
103
|
-
return await import('@databehave/schema');
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
107
|
-
const code = err?.code;
|
|
108
|
-
if (code === 'ERR_MODULE_NOT_FOUND' ||
|
|
109
|
-
code === 'MODULE_NOT_FOUND' ||
|
|
110
|
-
msg.includes('Cannot find module') ||
|
|
111
|
-
msg.includes('Cannot find package')) {
|
|
112
|
-
// Suppress the native error — users see only the friendly
|
|
113
|
-
// template. Wrapping `cause: err` would re-leak the native
|
|
114
|
-
// text into Node's default stack-printer; intentionally drop it.
|
|
115
|
-
throw new Error(INSTALL_HINT);
|
|
116
|
-
}
|
|
117
|
-
throw err;
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
const SUPPORTED_METHODS = new Set([
|
|
121
|
-
'get',
|
|
122
|
-
'post',
|
|
123
|
-
'put',
|
|
124
|
-
'delete',
|
|
125
|
-
'patch',
|
|
126
|
-
]);
|
|
127
|
-
/** Convert OAS `/users/{id}` → `/users/:id`. */
|
|
128
|
-
const oasPathToInternal = (oasPath) => oasPath
|
|
129
|
-
.split('/')
|
|
130
|
-
.map((seg) => (seg.startsWith('{') && seg.endsWith('}') ? `:${seg.slice(1, -1)}` : seg))
|
|
131
|
-
.join('/');
|
|
132
|
-
/**
|
|
133
|
-
* FNV-1a 32-bit hash. Tiny, zero-dep, stable across machines —
|
|
134
|
-
* exactly what the per-request `seed: 'stable'` derivation needs.
|
|
135
|
-
*
|
|
136
|
-
* Input format: `${METHOD} ${endpointPath}|${sortedQuery}|${sortedPathParams}`,
|
|
137
|
-
* where sorted means lex-sorted keys joined by `&` as `key=value`.
|
|
138
|
-
*
|
|
139
|
-
* Example input → output (uint32):
|
|
140
|
-
* `GET /users/:id|page=2|id=42` → 0x9b1ed8c5
|
|
141
|
-
*/
|
|
142
|
-
export const hashSeed = (input) => {
|
|
143
|
-
let h = 0x811c9dc5;
|
|
144
|
-
for (let i = 0; i < input.length; i++) {
|
|
145
|
-
h ^= input.charCodeAt(i);
|
|
146
|
-
h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0;
|
|
147
|
-
}
|
|
148
|
-
return h >>> 0;
|
|
149
|
-
};
|
|
150
|
-
const sortedJoin = (record) => Object.keys(record)
|
|
151
|
-
.sort()
|
|
152
|
-
.map((k) => `${k}=${record[k]}`)
|
|
153
|
-
.join('&');
|
|
154
|
-
const deriveSeed = (cfg, method, endpointPath, req) => {
|
|
155
|
-
if (typeof cfg.seed === 'number')
|
|
156
|
-
return cfg.seed >>> 0;
|
|
157
|
-
if (cfg.seed === 'random') {
|
|
158
|
-
return (Math.random() * 0xffffffff) >>> 0;
|
|
159
|
-
}
|
|
160
|
-
// 'stable': hash of `${METHOD} ${endpointPath}|${sortedQuery}|${sortedParams}`
|
|
161
|
-
const key = `${method} ${endpointPath}|${sortedJoin(req.query)}|${sortedJoin(req.params)}`;
|
|
162
|
-
return hashSeed(key);
|
|
163
|
-
};
|
|
164
|
-
/**
|
|
165
|
-
* Find the response schema node that the OAS-only generator would
|
|
166
|
-
* pick: prefer 200, then the smallest declared 2xx, mirroring
|
|
167
|
-
* `register.ts`. 204 → no body (signal via `null`).
|
|
168
|
-
*/
|
|
169
|
-
const pickResponseSchema = (responses) => {
|
|
170
|
-
const twoXx = Object.keys(responses)
|
|
171
|
-
.map((s) => Number.parseInt(s, 10))
|
|
172
|
-
.filter((n) => Number.isFinite(n) && n >= 200 && n < 300)
|
|
173
|
-
.sort((a, b) => (a === 200 ? -1 : b === 200 ? 1 : a - b));
|
|
174
|
-
const status = twoXx[0];
|
|
175
|
-
if (status === undefined)
|
|
176
|
-
return null;
|
|
177
|
-
if (status === 204)
|
|
178
|
-
return 'no-body';
|
|
179
|
-
const schema = responses[String(status)]?.content?.['application/json']?.schema;
|
|
180
|
-
if (!schema || typeof schema !== 'object')
|
|
181
|
-
return null;
|
|
182
|
-
return { schema, status };
|
|
183
|
-
};
|
|
184
|
-
/**
|
|
185
|
-
* Build a route-key → handler map for every OAS path/method whose
|
|
186
|
-
* response carries a usable JSON schema and is NOT already covered
|
|
187
|
-
* by hand-written `endpoints`. Each handler is closed over the
|
|
188
|
-
* cached schema module and pre-translated IR.
|
|
189
|
-
*
|
|
190
|
-
* `declaredKeys` is the set of route keys the user already declared
|
|
191
|
-
* via `endpoints`; auto-mode skips those so hand-written routes
|
|
192
|
-
* always win.
|
|
193
|
-
*/
|
|
194
|
-
export const buildAutoSchemaRoutes = async (doc, cfg, schemaModule, declaredKeys) => {
|
|
195
|
-
const out = new Map();
|
|
196
|
-
const paths = doc.paths;
|
|
197
|
-
if (!paths)
|
|
198
|
-
return out;
|
|
199
|
-
for (const [oasPath, methods] of Object.entries(paths)) {
|
|
200
|
-
if (oasPath === '/')
|
|
201
|
-
continue;
|
|
202
|
-
const kitPath = oasPathToInternal(oasPath);
|
|
203
|
-
for (const [methodName, op] of Object.entries(methods)) {
|
|
204
|
-
const method = methodName.toLowerCase();
|
|
205
|
-
if (!SUPPORTED_METHODS.has(method))
|
|
206
|
-
continue;
|
|
207
|
-
const key = `${method.toUpperCase()} ${kitPath}`;
|
|
208
|
-
if (declaredKeys.has(key))
|
|
209
|
-
continue;
|
|
210
|
-
const responses = op.responses;
|
|
211
|
-
if (!responses)
|
|
212
|
-
continue;
|
|
213
|
-
const picked = pickResponseSchema(responses);
|
|
214
|
-
if (picked === null || picked === 'no-body')
|
|
215
|
-
continue;
|
|
216
|
-
// Translation throws at server-creation on unsupported keywords —
|
|
217
|
-
// FAIL LOUD, never silently fall through to the placeholder
|
|
218
|
-
// generator (the user opted in to auto-schema; downgrading
|
|
219
|
-
// would produce confusing mixed output).
|
|
220
|
-
const ir = await translateOasToIR(picked.schema, doc);
|
|
221
|
-
const upperMethod = method.toUpperCase();
|
|
222
|
-
const handler = (req) => {
|
|
223
|
-
const seed = deriveSeed(cfg, upperMethod, kitPath, req);
|
|
224
|
-
const value = schemaModule.mock(ir, { seed });
|
|
225
|
-
return { json: value };
|
|
226
|
-
};
|
|
227
|
-
out.set(key, handler);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return out;
|
|
231
|
-
};
|
|
232
|
-
//# sourceMappingURL=auto-schema.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-schema.js","sourceRoot":"","sources":["../../src/openapi/auto-schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-server, zero-dep mock-data generator for OpenAPI-driven mocks.
|
|
3
|
-
*
|
|
4
|
-
* OpenAPI node → generateFromOasSchema() → deterministic JSON value
|
|
5
|
-
*
|
|
6
|
-
* `@databehave/server` runs standalone for OAS-only consumers — this
|
|
7
|
-
* file is the entire mock-body engine and pulls no DSL dependency at
|
|
8
|
-
* runtime. Output is deterministic placeholder data so tests can pin
|
|
9
|
-
* exact values (`"string"`, `0`, `false`, …) and OAS gaps surface
|
|
10
|
-
* loudly via `onWalkError` in `register.ts`.
|
|
11
|
-
*
|
|
12
|
-
* Single file. No external imports. Sibling-relative only.
|
|
13
|
-
*/
|
|
14
|
-
import type { OasDoc, OasNode } from './walker.js';
|
|
15
|
-
/** Reserved for a future seeded mode (brief item #11). Currently ignored. */
|
|
16
|
-
export interface GenerateOptions {
|
|
17
|
-
readonly seed?: number;
|
|
18
|
-
}
|
|
19
|
-
export declare const generateFromOasSchema: (node: OasNode, doc?: OasDoc, _opts?: GenerateOptions, seen?: Set<string>) => unknown;
|
|
20
|
-
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/openapi/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAElD,6EAA6E;AAC7E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAsDD,eAAO,MAAM,qBAAqB,GAChC,MAAM,OAAO,EACb,MAAK,MAAW,EAEhB,QAAO,eAAoB,EAC3B,OAAM,GAAG,CAAC,MAAM,CAAqB,KACpC,OAqEF,CAAA"}
|