@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.
Files changed (156) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +85 -83
  3. package/dist/cors.d.ts +1 -1
  4. package/dist/cors.js +1 -1
  5. package/dist/cors.js.map +1 -1
  6. package/dist/http.d.ts +94 -0
  7. package/dist/http.d.ts.map +1 -0
  8. package/dist/http.js +23 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +10 -20
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +8 -18
  13. package/dist/index.js.map +1 -1
  14. package/dist/log.d.ts +9 -49
  15. package/dist/log.d.ts.map +1 -1
  16. package/dist/log.js +16 -92
  17. package/dist/log.js.map +1 -1
  18. package/dist/node-authority.d.ts +12 -0
  19. package/dist/node-authority.d.ts.map +1 -0
  20. package/dist/node-authority.js +72 -0
  21. package/dist/node-authority.js.map +1 -0
  22. package/dist/node-body.d.ts +11 -0
  23. package/dist/node-body.d.ts.map +1 -0
  24. package/dist/node-body.js +61 -0
  25. package/dist/node-body.js.map +1 -0
  26. package/dist/node-http.d.ts +19 -0
  27. package/dist/node-http.d.ts.map +1 -0
  28. package/dist/node-http.js +210 -0
  29. package/dist/node-http.js.map +1 -0
  30. package/dist/plugins/access-log.d.ts +11 -0
  31. package/dist/plugins/access-log.d.ts.map +1 -0
  32. package/dist/plugins/access-log.js +27 -0
  33. package/dist/plugins/access-log.js.map +1 -0
  34. package/dist/plugins/cors.d.ts +5 -0
  35. package/dist/plugins/cors.d.ts.map +1 -0
  36. package/dist/plugins/cors.js +35 -0
  37. package/dist/plugins/cors.js.map +1 -0
  38. package/dist/plugins/routes.d.ts +5 -0
  39. package/dist/plugins/routes.d.ts.map +1 -0
  40. package/dist/plugins/routes.js +10 -0
  41. package/dist/plugins/routes.js.map +1 -0
  42. package/dist/request.d.ts +2 -2
  43. package/dist/request.d.ts.map +1 -1
  44. package/dist/request.js +6 -4
  45. package/dist/request.js.map +1 -1
  46. package/dist/route-key.d.ts +2 -0
  47. package/dist/route-key.d.ts.map +1 -1
  48. package/dist/route-key.js +5 -1
  49. package/dist/route-key.js.map +1 -1
  50. package/dist/server.d.ts +7 -59
  51. package/dist/server.d.ts.map +1 -1
  52. package/dist/server.js +289 -466
  53. package/dist/server.js.map +1 -1
  54. package/dist/types.d.ts +10 -156
  55. package/dist/types.d.ts.map +1 -1
  56. package/dist/types.js +1 -1
  57. package/package.json +11 -24
  58. package/dist/admin/admin-routes.d.ts +0 -42
  59. package/dist/admin/admin-routes.d.ts.map +0 -1
  60. package/dist/admin/admin-routes.js +0 -472
  61. package/dist/admin/admin-routes.js.map +0 -1
  62. package/dist/admin/admin-types.d.ts +0 -170
  63. package/dist/admin/admin-types.d.ts.map +0 -1
  64. package/dist/admin/admin-types.js +0 -30
  65. package/dist/admin/admin-types.js.map +0 -1
  66. package/dist/admin/banner.d.ts +0 -11
  67. package/dist/admin/banner.d.ts.map +0 -1
  68. package/dist/admin/banner.js +0 -5
  69. package/dist/admin/banner.js.map +0 -1
  70. package/dist/admin/header-parser.d.ts +0 -14
  71. package/dist/admin/header-parser.d.ts.map +0 -1
  72. package/dist/admin/header-parser.js +0 -171
  73. package/dist/admin/header-parser.js.map +0 -1
  74. package/dist/admin/inject.d.ts +0 -48
  75. package/dist/admin/inject.d.ts.map +0 -1
  76. package/dist/admin/inject.js +0 -167
  77. package/dist/admin/inject.js.map +0 -1
  78. package/dist/admin/overrides-store.d.ts +0 -18
  79. package/dist/admin/overrides-store.d.ts.map +0 -1
  80. package/dist/admin/overrides-store.js +0 -100
  81. package/dist/admin/overrides-store.js.map +0 -1
  82. package/dist/admin/resolve-cors.d.ts +0 -22
  83. package/dist/admin/resolve-cors.d.ts.map +0 -1
  84. package/dist/admin/resolve-cors.js +0 -28
  85. package/dist/admin/resolve-cors.js.map +0 -1
  86. package/dist/admin/scenarios-store.d.ts +0 -15
  87. package/dist/admin/scenarios-store.d.ts.map +0 -1
  88. package/dist/admin/scenarios-store.js +0 -109
  89. package/dist/admin/scenarios-store.js.map +0 -1
  90. package/dist/admin/ui.css +0 -1
  91. package/dist/admin/ui.html +0 -13
  92. package/dist/admin/ui.js +0 -240
  93. package/dist/bin-helpers.d.ts +0 -46
  94. package/dist/bin-helpers.d.ts.map +0 -1
  95. package/dist/bin-helpers.js +0 -61
  96. package/dist/bin-helpers.js.map +0 -1
  97. package/dist/bin.d.ts +0 -3
  98. package/dist/bin.d.ts.map +0 -1
  99. package/dist/bin.js +0 -86
  100. package/dist/bin.js.map +0 -1
  101. package/dist/define.d.ts +0 -26
  102. package/dist/define.d.ts.map +0 -1
  103. package/dist/define.js +0 -55
  104. package/dist/define.js.map +0 -1
  105. package/dist/json-config.d.ts +0 -170
  106. package/dist/json-config.d.ts.map +0 -1
  107. package/dist/json-config.js +0 -684
  108. package/dist/json-config.js.map +0 -1
  109. package/dist/jsonc.d.ts +0 -24
  110. package/dist/jsonc.d.ts.map +0 -1
  111. package/dist/jsonc.js +0 -125
  112. package/dist/jsonc.js.map +0 -1
  113. package/dist/middleware/request-validation.d.ts +0 -58
  114. package/dist/middleware/request-validation.d.ts.map +0 -1
  115. package/dist/middleware/request-validation.js +0 -328
  116. package/dist/middleware/request-validation.js.map +0 -1
  117. package/dist/mock-mode.d.ts +0 -95
  118. package/dist/mock-mode.d.ts.map +0 -1
  119. package/dist/mock-mode.js +0 -95
  120. package/dist/mock-mode.js.map +0 -1
  121. package/dist/openapi/auto-schema.d.ts +0 -83
  122. package/dist/openapi/auto-schema.d.ts.map +0 -1
  123. package/dist/openapi/auto-schema.js +0 -232
  124. package/dist/openapi/auto-schema.js.map +0 -1
  125. package/dist/openapi/generate.d.ts +0 -20
  126. package/dist/openapi/generate.d.ts.map +0 -1
  127. package/dist/openapi/generate.js +0 -121
  128. package/dist/openapi/generate.js.map +0 -1
  129. package/dist/openapi/loader.d.ts +0 -18
  130. package/dist/openapi/loader.d.ts.map +0 -1
  131. package/dist/openapi/loader.js +0 -25
  132. package/dist/openapi/loader.js.map +0 -1
  133. package/dist/openapi/register.d.ts +0 -58
  134. package/dist/openapi/register.d.ts.map +0 -1
  135. package/dist/openapi/register.js +0 -166
  136. package/dist/openapi/register.js.map +0 -1
  137. package/dist/openapi/seed.d.ts +0 -16
  138. package/dist/openapi/seed.d.ts.map +0 -1
  139. package/dist/openapi/seed.js +0 -58
  140. package/dist/openapi/seed.js.map +0 -1
  141. package/dist/openapi/translate.d.ts +0 -55
  142. package/dist/openapi/translate.d.ts.map +0 -1
  143. package/dist/openapi/translate.js +0 -319
  144. package/dist/openapi/translate.js.map +0 -1
  145. package/dist/openapi/walker.d.ts +0 -44
  146. package/dist/openapi/walker.d.ts.map +0 -1
  147. package/dist/openapi/walker.js +0 -15
  148. package/dist/openapi/walker.js.map +0 -1
  149. package/dist/run.d.ts +0 -27
  150. package/dist/run.d.ts.map +0 -1
  151. package/dist/run.js +0 -87
  152. package/dist/run.js.map +0 -1
  153. package/dist/validation/validate.d.ts +0 -38
  154. package/dist/validation/validate.d.ts.map +0 -1
  155. package/dist/validation/validate.js +0 -372
  156. package/dist/validation/validate.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"admin-types.d.ts","sourceRoot":"","sources":["../../src/admin/admin-types.ts"],"names":[],"mappings":"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"}
@@ -1,30 +0,0 @@
1
- /**
2
- * Admin-mode types & internal sentinel.
3
- *
4
- * `admin` is an opt-in extension of `Config` that
5
- * mounts an in-memory error-injection panel + `x-mock-*` headers
6
- * under a configurable mount path (default `/databehave`). See
7
- * {@link AdminModeConfig} on `Config.admin`.
8
- */
9
- /**
10
- * Internal symbol attached to the response object returned by
11
- * {@link createInjectHook} when an `x-mock-destroy` is honored. The
12
- * kit's `server.listen()` http adapter recognizes this property and
13
- * drops the underlying socket without writing a response. Hidden
14
- * from {@link MockResponse} on purpose — destroy is not a
15
- * normal HTTP response shape.
16
- */
17
- export const DESTROY_SOCKET_SENTINEL = Symbol.for('@databehave/server:admin:destroy-socket');
18
- /**
19
- * Thrown internally by `server.fetch` when the admin inject hook
20
- * surfaced a {@link DESTROY_SOCKET_SENTINEL} response. `server.listen()`
21
- * catches it and destroys the socket; callers of `server.fetch()`
22
- * outside a listening server will observe the throw.
23
- */
24
- export class AdminDestroySocketSignal extends Error {
25
- name = 'AdminDestroySocketSignal';
26
- constructor() {
27
- super('@databehave/server: admin x-mock-destroy requested');
28
- }
29
- }
30
- //# sourceMappingURL=admin-types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"admin-types.js","sourceRoot":"","sources":["../../src/admin/admin-types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAkB,MAAM,CAAC,GAAG,CAC9D,yCAAyC,CAC1C,CAAA;AAGD;;;;;GAKG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,GAAG,0BAA0B,CAAA;IAC1C;QACE,KAAK,CAAC,oDAAoD,CAAC,CAAA;IAC7D,CAAC;CACF"}
@@ -1,11 +0,0 @@
1
- /**
2
- * stdout notice emitted at `server.listen()` start when admin is
3
- * enabled. Splitting it out keeps the banner format unit-testable
4
- * (no need to spin up a real http server just to assert a string).
5
- */
6
- export interface AdminBannerLogger {
7
- info(message: string): void;
8
- }
9
- export declare const formatAdminBanner: (host: string, port: number, path: string) => string;
10
- export declare const emitAdminBanner: (host: string, port: number, path: string, logger?: AdminBannerLogger) => void;
11
- //# sourceMappingURL=banner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../../src/admin/banner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,MAAM,MAAM,KACX,MAC2G,CAAA;AAE9G,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,MAAM,MAAM,EACZ,SAAQ,iBAA2B,KAClC,IAEF,CAAA"}
@@ -1,5 +0,0 @@
1
- export const formatAdminBanner = (host, port, path) => `[@databehave/server] admin panel ready at http://${host}:${port}${path} (dev mock — disable in production)`;
2
- export const emitAdminBanner = (host, port, path, logger = console) => {
3
- logger.info(formatAdminBanner(host, port, path));
4
- };
5
- //# sourceMappingURL=banner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"banner.js","sourceRoot":"","sources":["../../src/admin/banner.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,IAAY,EACZ,IAAY,EACZ,IAAY,EACJ,EAAE,CACV,oDAAoD,IAAI,IAAI,IAAI,GAAG,IAAI,qCAAqC,CAAA;AAE9G,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,SAA4B,OAAO,EAC7B,EAAE;IACR,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;AAClD,CAAC,CAAA"}
@@ -1,14 +0,0 @@
1
- import type { ErrorMode } from './admin-types.js';
2
- export type HeaderParseResult = {
3
- kind: 'none';
4
- } | {
5
- kind: 'mode';
6
- mode: ErrorMode;
7
- } | {
8
- kind: 'error';
9
- message: string;
10
- };
11
- export declare const parseHeaderMode: (headers: Readonly<Record<string, string>>) => HeaderParseResult;
12
- /** Public alias of {@link parseHeaderMode}. */
13
- export declare const parseMockHeaders: (headers: Readonly<Record<string, string>>) => HeaderParseResult;
14
- //# sourceMappingURL=header-parser.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"header-parser.d.ts","sourceRoot":"","sources":["../../src/admin/header-parser.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAkJtC,eAAO,MAAM,eAAe,GAC1B,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KACxC,iBAqCF,CAAA;AAGD,+CAA+C;AAC/C,eAAO,MAAM,gBAAgB,YA1ClB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KACxC,iBAyC4C,CAAA"}
@@ -1,171 +0,0 @@
1
- /**
2
- * Parse `x-mock-*` request headers into an `ErrorMode` (or surface a
3
- * conflict error). One header set ↔ one ErrorMode. Multiple terminal
4
- * modes (e.g. both `x-mock-status` and `x-mock-business-failure`) are
5
- * rejected with `kind: 'conflict'` so the caller can return 400.
6
- *
7
- * Base64 inputs (`x-mock-body`, `x-mock-business-failure-extra`) use
8
- * standard base64 (NOT url-safe), per the README contract.
9
- */
10
- import { Buffer } from 'node:buffer';
11
- // Note: `x-mock-business-failure-b64` is an alternative to
12
- // `x-mock-business-failure` that accepts a base64-UTF8 message so
13
- // non-ASCII strings can travel through an HTTP header — Node's fetch
14
- // rejects non-ASCII byte values in header values.
15
- const TERMINAL_HEADERS = [
16
- 'x-mock-status',
17
- 'x-mock-business-failure',
18
- 'x-mock-business-failure-b64',
19
- 'x-mock-body',
20
- 'x-mock-empty',
21
- 'x-mock-malformed',
22
- 'x-mock-hang',
23
- 'x-mock-destroy',
24
- ];
25
- const get = (h, name) => h[name];
26
- const decodeBase64Json = (raw, headerName) => {
27
- let decoded;
28
- try {
29
- decoded = Buffer.from(raw, 'base64').toString('utf8');
30
- }
31
- catch (err) {
32
- throw new Error(`invalid ${headerName} header: base64 decode failed (${err instanceof Error ? err.message : String(err)})`);
33
- }
34
- try {
35
- return JSON.parse(decoded);
36
- }
37
- catch (err) {
38
- throw new Error(`invalid ${headerName} header: JSON parse failed (${err instanceof Error ? err.message : String(err)})`);
39
- }
40
- };
41
- const parseIntStrict = (raw, headerName) => {
42
- const n = Number.parseInt(raw, 10);
43
- if (!Number.isFinite(n)) {
44
- throw new Error(`invalid ${headerName} header: not an integer (${JSON.stringify(raw)})`);
45
- }
46
- return n;
47
- };
48
- const parseTerminal = (h) => {
49
- const present = TERMINAL_HEADERS.filter((name) => get(h, name) !== undefined);
50
- if (present.length === 0)
51
- return null;
52
- if (present.length > 1) {
53
- throw new Error(`conflicting x-mock-* headers: ${present.join(', ')} — pick exactly one terminal mode`);
54
- }
55
- const [only] = present;
56
- switch (only) {
57
- case 'x-mock-status': {
58
- const status = parseIntStrict(get(h, 'x-mock-status'), 'x-mock-status');
59
- return { kind: 'http-status', status };
60
- }
61
- case 'x-mock-business-failure':
62
- case 'x-mock-business-failure-b64': {
63
- let message;
64
- if (only === 'x-mock-business-failure-b64') {
65
- const raw = get(h, 'x-mock-business-failure-b64');
66
- try {
67
- message = Buffer.from(raw, 'base64').toString('utf8');
68
- }
69
- catch (err) {
70
- throw new Error(`invalid x-mock-business-failure-b64 header: base64 decode failed (${err instanceof Error ? err.message : String(err)})`);
71
- }
72
- }
73
- else {
74
- message = get(h, 'x-mock-business-failure');
75
- }
76
- const extraRaw = get(h, 'x-mock-business-failure-extra');
77
- if (extraRaw === undefined)
78
- return { kind: 'business-failure', message };
79
- const extra = decodeBase64Json(extraRaw, 'x-mock-business-failure-extra');
80
- if (extra === null || typeof extra !== 'object' || Array.isArray(extra)) {
81
- throw new Error('invalid x-mock-business-failure-extra header: decoded value must be a JSON object');
82
- }
83
- return {
84
- kind: 'business-failure',
85
- message,
86
- extra: extra,
87
- };
88
- }
89
- case 'x-mock-body': {
90
- const body = decodeBase64Json(get(h, 'x-mock-body'), 'x-mock-body');
91
- const statusRaw = get(h, 'x-mock-body-status');
92
- const contentType = get(h, 'x-mock-body-content-type');
93
- const mode = { kind: 'custom-body', body };
94
- if (statusRaw !== undefined) {
95
- ;
96
- mode.status = parseIntStrict(statusRaw, 'x-mock-body-status');
97
- }
98
- if (contentType !== undefined) {
99
- ;
100
- mode.contentType = contentType;
101
- }
102
- return mode;
103
- }
104
- case 'x-mock-empty': {
105
- const statusRaw = get(h, 'x-mock-empty-status');
106
- if (statusRaw === undefined)
107
- return { kind: 'empty-body' };
108
- return {
109
- kind: 'empty-body',
110
- status: parseIntStrict(statusRaw, 'x-mock-empty-status'),
111
- };
112
- }
113
- case 'x-mock-malformed': {
114
- const statusRaw = get(h, 'x-mock-malformed-status');
115
- if (statusRaw === undefined)
116
- return { kind: 'malformed-json' };
117
- return {
118
- kind: 'malformed-json',
119
- status: parseIntStrict(statusRaw, 'x-mock-malformed-status'),
120
- };
121
- }
122
- case 'x-mock-hang':
123
- return { kind: 'hang' };
124
- case 'x-mock-destroy':
125
- return { kind: 'destroy' };
126
- /* v8 ignore next 3 -- exhaustiveness: unreachable */
127
- default:
128
- // exhaustiveness — unreachable.
129
- return null;
130
- }
131
- };
132
- export const parseHeaderMode = (headers) => {
133
- try {
134
- const terminal = parseTerminal(headers);
135
- const delayRaw = get(headers, 'x-mock-delay');
136
- if (terminal === null && delayRaw === undefined) {
137
- return { kind: 'none' };
138
- }
139
- if (delayRaw === undefined) {
140
- return { kind: 'mode', mode: terminal };
141
- }
142
- const ms = parseIntStrict(delayRaw, 'x-mock-delay');
143
- if (ms < 0) {
144
- return {
145
- kind: 'error',
146
- message: 'invalid x-mock-delay header: must be >= 0',
147
- };
148
- }
149
- if (terminal === null) {
150
- return { kind: 'mode', mode: { kind: 'delay', ms } };
151
- }
152
- if (terminal.kind === 'delay' ||
153
- terminal.kind === 'hang' ||
154
- terminal.kind === 'destroy') {
155
- return {
156
- kind: 'error',
157
- message: `x-mock-delay cannot wrap kind=${terminal.kind}`,
158
- };
159
- }
160
- return { kind: 'mode', mode: { kind: 'delay', ms, then: terminal } };
161
- }
162
- catch (err) {
163
- return {
164
- kind: 'error',
165
- message: err instanceof Error ? err.message : String(err),
166
- };
167
- }
168
- };
169
- /** Public alias of {@link parseHeaderMode}. */
170
- export const parseMockHeaders = parseHeaderMode;
171
- //# sourceMappingURL=header-parser.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"header-parser.js","sourceRoot":"","sources":["../../src/admin/header-parser.ts"],"names":[],"mappings":"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"}
@@ -1,48 +0,0 @@
1
- /**
2
- * onRequest hook that consults `x-mock-*` headers + sticky overrides
3
- * and produces a `MockResponse` short-circuit. Header-derived
4
- * modes always beat sticky modes (per-request scoping > sticky rules).
5
- *
6
- * Modes handled directly here:
7
- * - http-status, business-failure, custom-body, empty-body,
8
- * malformed-json, delay (recursive), hang
9
- *
10
- * `destroy` is signalled via a sentinel response (see
11
- * {@link DESTROY_SOCKET_SENTINEL}) so the kit's `server.listen()` http
12
- * adapter can drop the socket without writing a body. When
13
- * `allowDestroy: false`, destroy resolves to a normal 503 response
14
- * instead.
15
- */
16
- import type { MockRequest, MockResponse } from '../types.js';
17
- import type { OverridesStore } from './overrides-store.js';
18
- import { type ErrorMode } from './admin-types.js';
19
- export type ResolveResult = {
20
- kind: 'mode';
21
- mode: ErrorMode;
22
- source: 'header' | 'sticky';
23
- } | {
24
- kind: 'error';
25
- message: string;
26
- } | {
27
- kind: 'none';
28
- };
29
- /**
30
- * Pure resolver: header overrides beat sticky overrides. Returns
31
- * `'none'` when nothing applies and `'error'` for malformed headers.
32
- */
33
- export declare const resolveMode: (store: OverridesStore, method: string, path: string, headers: Readonly<Record<string, string>>) => ResolveResult;
34
- export interface InjectHookOptions {
35
- readonly store: OverridesStore;
36
- /** Paths matching any of these prefixes are passed through (no injection). */
37
- readonly bypassPathPrefixes?: readonly string[];
38
- /** When false, destroy mode resolves to a 503 instead of dropping the socket. */
39
- readonly allowDestroy?: boolean;
40
- readonly logger?: {
41
- warn(message: string): void;
42
- info?(message: string): void;
43
- };
44
- }
45
- export declare const createInjectHook: (opts: InjectHookOptions) => (req: MockRequest) => Promise<MockResponse | void>;
46
- /** True when the response carries the internal destroy-socket sentinel. */
47
- export declare const isDestroySocketSentinel: (res: MockResponse | undefined | null) => boolean;
48
- //# sourceMappingURL=inject.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inject.d.ts","sourceRoot":"","sources":["../../src/admin/inject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EACV,WAAW,EACX,YAAY,EACb,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAI1E,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpB;;;GAGG;AACH,eAAO,MAAM,WAAW,GACtB,OAAO,cAAc,EACrB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,SAAS,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KACxC,aAUF,CAAA;AAuGD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,8EAA8E;IAC9E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/C,iFAAiF;IACjF,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE;QAChB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3B,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B,CAAA;CACF;AAED,eAAO,MAAM,gBAAgB,GAAI,MAAM,iBAAiB,MAUpD,KAAK,WAAW,KACf,OAAO,CAAC,YAAY,GAAG,IAAI,CA+C/B,CAAA;AAED,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,GAClC,KAAK,YAAY,GAAG,SAAS,GAAG,IAAI,KACnC,OAGF,CAAA"}
@@ -1,167 +0,0 @@
1
- import { parseHeaderMode } from './header-parser.js';
2
- import { DESTROY_SOCKET_SENTINEL } from './admin-types.js';
3
- const TAG_HEADER = 'x-mock-injected';
4
- /**
5
- * Pure resolver: header overrides beat sticky overrides. Returns
6
- * `'none'` when nothing applies and `'error'` for malformed headers.
7
- */
8
- export const resolveMode = (store, method, path, headers) => {
9
- const fromHeader = parseHeaderMode(headers);
10
- if (fromHeader.kind === 'error')
11
- return { kind: 'error', message: fromHeader.message };
12
- if (fromHeader.kind === 'mode') {
13
- return { kind: 'mode', mode: fromHeader.mode, source: 'header' };
14
- }
15
- const sticky = store.resolve(method, path);
16
- if (sticky)
17
- return { kind: 'mode', mode: sticky.mode, source: 'sticky' };
18
- return { kind: 'none' };
19
- };
20
- const buildResponse = (mode, source) => {
21
- const tagHeaders = {
22
- [TAG_HEADER]: `${mode.kind}:${source}`,
23
- };
24
- switch (mode.kind) {
25
- case 'http-status':
26
- return {
27
- status: mode.status,
28
- json: { error: true, status: mode.status, injected: mode.kind },
29
- headers: tagHeaders,
30
- };
31
- case 'business-failure':
32
- return {
33
- status: 200,
34
- json: {
35
- success: false,
36
- message: mode.message,
37
- ...(mode.extra ?? {}),
38
- },
39
- headers: { ...tagHeaders, 'content-type': 'application/json' },
40
- };
41
- case 'custom-body': {
42
- const status = mode.status ?? 200;
43
- const contentType = mode.contentType ?? 'application/json';
44
- if (typeof mode.body === 'string' && !contentType.includes('json')) {
45
- return {
46
- status,
47
- text: mode.body,
48
- headers: { ...tagHeaders, 'content-type': contentType },
49
- };
50
- }
51
- const payload = typeof mode.body === 'string' ? mode.body : JSON.stringify(mode.body);
52
- return {
53
- status,
54
- raw: payload,
55
- headers: { ...tagHeaders, 'content-type': contentType },
56
- };
57
- }
58
- case 'empty-body':
59
- return {
60
- status: mode.status ?? 204,
61
- empty: true,
62
- headers: tagHeaders,
63
- };
64
- case 'malformed-json':
65
- return {
66
- status: mode.status ?? 200,
67
- raw: '{',
68
- headers: { ...tagHeaders, 'content-type': 'application/json' },
69
- };
70
- /* v8 ignore start -- defensive: delay/hang/destroy never reach here */
71
- case 'delay':
72
- case 'hang':
73
- case 'destroy':
74
- // delay/hang are handled before this function; destroy is dispatched
75
- // through the sentinel branch. Reaching here is a bug.
76
- return {
77
- status: 500,
78
- json: {
79
- error: true,
80
- message: `inject: ${mode.kind} should be handled before buildResponse`,
81
- },
82
- headers: tagHeaders,
83
- };
84
- /* v8 ignore stop */
85
- }
86
- };
87
- const buildDestroyDisabledResponse = () => ({
88
- status: 503,
89
- json: {
90
- error: 'x-mock-destroy disabled by admin.allowDestroy:false',
91
- },
92
- headers: { [TAG_HEADER]: 'destroy-disabled' },
93
- });
94
- /**
95
- * Sentinel response: shaped as a normal empty 204 so anything that
96
- * inspects the public type sees a valid response, but tagged with
97
- * {@link DESTROY_SOCKET_SENTINEL} so `server.listen()` can drop the
98
- * socket instead of writing the body.
99
- */
100
- const buildDestroySentinel = () => {
101
- const base = {
102
- status: 204,
103
- empty: true,
104
- headers: { [TAG_HEADER]: 'destroy' },
105
- };
106
- Object.defineProperty(base, DESTROY_SOCKET_SENTINEL, {
107
- value: true,
108
- enumerable: false,
109
- writable: false,
110
- configurable: false,
111
- });
112
- return base;
113
- };
114
- export const createInjectHook = (opts) => {
115
- const { store } = opts;
116
- const bypass = opts.bypassPathPrefixes ?? ['/databehave'];
117
- const allowDestroy = opts.allowDestroy !== false;
118
- const logger = opts.logger ?? console;
119
- const shouldBypass = (path) => bypass.some((p) => path.startsWith(p));
120
- return async (req) => {
121
- if (shouldBypass(req.path))
122
- return undefined;
123
- const resolved = resolveMode(store, req.method, req.path, req.headers);
124
- if (resolved.kind === 'none')
125
- return undefined;
126
- if (resolved.kind === 'error') {
127
- return {
128
- status: 400,
129
- json: { error: 'invalid x-mock-* header', detail: resolved.message },
130
- headers: { [TAG_HEADER]: 'header-error' },
131
- };
132
- }
133
- const { mode, source } = resolved;
134
- if (mode.kind === 'hang') {
135
- logger.warn(`[@databehave/server/admin] hang triggered on ${req.method} ${req.path} ` +
136
- `(source=${source}) — request will never resolve; close the client to recover.`);
137
- /* v8 ignore start -- promise never resolves; return is unreachable */
138
- await new Promise(() => {
139
- /* never resolves */
140
- });
141
- return undefined;
142
- /* v8 ignore stop */
143
- }
144
- if (mode.kind === 'destroy') {
145
- if (!allowDestroy) {
146
- logger.warn(`[@databehave/server/admin] destroy requested on ${req.method} ${req.path} ` +
147
- `(source=${source}) but admin.allowDestroy:false — responding 503.`);
148
- return buildDestroyDisabledResponse();
149
- }
150
- return buildDestroySentinel();
151
- }
152
- if (mode.kind === 'delay') {
153
- await new Promise((r) => setTimeout(r, mode.ms));
154
- if (mode.then === undefined)
155
- return undefined;
156
- return buildResponse(mode.then, source);
157
- }
158
- return buildResponse(mode, source);
159
- };
160
- };
161
- /** True when the response carries the internal destroy-socket sentinel. */
162
- export const isDestroySocketSentinel = (res) => {
163
- if (!res)
164
- return false;
165
- return res[DESTROY_SOCKET_SENTINEL] === true;
166
- };
167
- //# sourceMappingURL=inject.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/admin/inject.ts"],"names":[],"mappings":"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"}
@@ -1,18 +0,0 @@
1
- import type { ErrorMode, StickyMatcher, StickyOverride } from './admin-types.js';
2
- export interface OverridesStoreLogger {
3
- warn(message: string): void;
4
- info?(message: string): void;
5
- }
6
- export interface OverridesStore {
7
- add(input: {
8
- matcher: StickyMatcher;
9
- mode: ErrorMode;
10
- description?: string;
11
- }): StickyOverride;
12
- remove(id: string): boolean;
13
- list(): readonly StickyOverride[];
14
- clear(): number;
15
- resolve(method: string, path: string): StickyOverride | undefined;
16
- }
17
- export declare const createOverridesStore: (logger?: OverridesStoreLogger) => OverridesStore;
18
- //# sourceMappingURL=overrides-store.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"overrides-store.d.ts","sourceRoot":"","sources":["../../src/admin/overrides-store.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEhF,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,KAAK,EAAE;QACT,OAAO,EAAE,aAAa,CAAA;QACtB,IAAI,EAAE,SAAS,CAAA;QACf,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,GAAG,cAAc,CAAA;IAClB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,IAAI,IAAI,SAAS,cAAc,EAAE,CAAA;IACjC,KAAK,IAAI,MAAM,CAAA;IACf,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAA;CAClE;AAED,eAAO,MAAM,oBAAoB,GAC/B,SAAQ,oBAA8B,KACrC,cAkGF,CAAA"}
@@ -1,100 +0,0 @@
1
- /**
2
- * In-memory sticky overrides registry. Lost on process restart by
3
- * design — this tool is for ad-hoc dev sessions, not persistence.
4
- *
5
- * Resolution priority (first hit wins): `exact` > `path` > `global`.
6
- * When two stickies live at the same priority level, the **last** one
7
- * added wins (and a warning is logged) so the dev's most-recent click
8
- * in the UI is always the active rule.
9
- */
10
- import { randomUUID } from 'node:crypto';
11
- export const createOverridesStore = (logger = console) => {
12
- // Insertion-ordered. `Map.values()` yields oldest → newest, so
13
- // when iterating we keep track of the *last* hit per priority bucket.
14
- const byId = new Map();
15
- const sameMatcher = (a, b) => {
16
- if (a.kind !== b.kind)
17
- return false;
18
- if (a.kind === 'exact' && b.kind === 'exact') {
19
- return (a.method.toUpperCase() === b.method.toUpperCase() && a.path === b.path);
20
- }
21
- if (a.kind === 'path' && b.kind === 'path')
22
- return a.path === b.path;
23
- return a.kind === 'global' && b.kind === 'global';
24
- };
25
- const describeMatcher = (m) => {
26
- if (m.kind === 'exact')
27
- return `${m.method.toUpperCase()} ${m.path}`;
28
- if (m.kind === 'path')
29
- return `* ${m.path}`;
30
- return '* (global)';
31
- };
32
- const add = ({ matcher, mode, description }) => {
33
- // Detect same-matcher collision so the warning is informative.
34
- for (const existing of byId.values()) {
35
- if (sameMatcher(existing.matcher, matcher)) {
36
- logger.warn(`[mock-server/overrides] duplicate matcher ${describeMatcher(matcher)} ` +
37
- `— new rule shadows ${existing.id} (last-wins). Remove the old one if unintended.`);
38
- }
39
- }
40
- const override = {
41
- id: randomUUID(),
42
- matcher: matcher.kind === 'exact'
43
- ? {
44
- kind: 'exact',
45
- method: matcher.method.toUpperCase(),
46
- path: matcher.path,
47
- }
48
- : matcher.kind === 'global' && matcher.methods && matcher.methods.length > 0
49
- ? {
50
- kind: 'global',
51
- methods: matcher.methods.map((m) => m.toUpperCase()),
52
- }
53
- : matcher.kind === 'global'
54
- ? { kind: 'global' }
55
- : matcher,
56
- mode,
57
- createdAt: new Date().toISOString(),
58
- ...(description !== undefined ? { description } : {}),
59
- };
60
- byId.set(override.id, override);
61
- return override;
62
- };
63
- const remove = (id) => byId.delete(id);
64
- const list = () => [...byId.values()];
65
- const clear = () => {
66
- const n = byId.size;
67
- byId.clear();
68
- return n;
69
- };
70
- const resolve = (method, path) => {
71
- const m = method.toUpperCase();
72
- // Walk newest → oldest so the last-added rule wins per bucket.
73
- const all = [...byId.values()].reverse();
74
- let exactHit;
75
- let pathHit;
76
- let globalHit;
77
- for (const o of all) {
78
- if (o.matcher.kind === 'exact') {
79
- if (!exactHit && o.matcher.method === m && o.matcher.path === path) {
80
- exactHit = o;
81
- }
82
- }
83
- else if (o.matcher.kind === 'path') {
84
- if (!pathHit && o.matcher.path === path)
85
- pathHit = o;
86
- }
87
- else {
88
- if (!globalHit
89
- && (!o.matcher.methods
90
- || o.matcher.methods.length === 0
91
- || o.matcher.methods.includes(m))) {
92
- globalHit = o;
93
- }
94
- }
95
- }
96
- return exactHit ?? pathHit ?? globalHit;
97
- };
98
- return { add, remove, list, clear, resolve };
99
- };
100
- //# sourceMappingURL=overrides-store.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"overrides-store.js","sourceRoot":"","sources":["../../src/admin/overrides-store.ts"],"names":[],"mappings":"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"}