@zze/mock-server 0.2.6 → 0.6.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 (52) hide show
  1. package/README.md +117 -28
  2. package/dist/__tests__/mock-server.test.js +58 -1
  3. package/dist/admin/__tests__/admin-router.test.js +2 -151
  4. package/dist/admin/admin-router.d.ts +4 -4
  5. package/dist/admin/admin-router.d.ts.map +1 -1
  6. package/dist/admin/admin-router.js +1 -205
  7. package/dist/admin/types.d.ts +1 -84
  8. package/dist/admin/types.d.ts.map +1 -1
  9. package/dist/admin/types.js +1 -5
  10. package/dist/config/__tests__/config-loader.test.js +18 -0
  11. package/dist/config/config-loader.d.ts +3 -3
  12. package/dist/config/config-loader.d.ts.map +1 -1
  13. package/dist/config/config-loader.js +4 -1
  14. package/dist/config/config-writer.d.ts +1 -35
  15. package/dist/config/config-writer.d.ts.map +1 -1
  16. package/dist/config/config-writer.js +0 -103
  17. package/dist/config/index.d.ts +1 -1
  18. package/dist/config/index.d.ts.map +1 -1
  19. package/dist/config/types.d.ts +9 -1
  20. package/dist/config/types.d.ts.map +1 -1
  21. package/dist/mock-server.d.ts +9 -0
  22. package/dist/mock-server.d.ts.map +1 -1
  23. package/dist/mock-server.js +3 -0
  24. package/dist/resolver/__tests__/response-resolver.test.js +134 -0
  25. package/dist/resolver/response-resolver.d.ts +18 -2
  26. package/dist/resolver/response-resolver.d.ts.map +1 -1
  27. package/dist/resolver/response-resolver.js +62 -5
  28. package/dist/resolver/types.d.ts +8 -0
  29. package/dist/resolver/types.d.ts.map +1 -1
  30. package/dist/resolver/types.js +7 -0
  31. package/dist/schemas/__tests__/endpoint.schema.test.js +48 -0
  32. package/dist/schemas/endpoint.schema.d.ts +31 -8
  33. package/dist/schemas/endpoint.schema.d.ts.map +1 -1
  34. package/dist/schemas/scenario.schema.d.ts +28 -4
  35. package/dist/schemas/scenario.schema.d.ts.map +1 -1
  36. package/dist/schemas/scenario.schema.js +23 -3
  37. package/dist/server/__tests__/mock-server-app.test.js +40 -4
  38. package/dist/server/mock-server-app.d.ts +4 -4
  39. package/dist/server/mock-server-app.d.ts.map +1 -1
  40. package/dist/server/mock-server-app.js +5 -3
  41. package/dist/server/types.d.ts +8 -0
  42. package/dist/server/types.d.ts.map +1 -1
  43. package/dist/server/types.js +1 -0
  44. package/dist/state/__tests__/state-manager.test.js +33 -0
  45. package/dist/state/state-manager.d.ts.map +1 -1
  46. package/dist/state/state-manager.js +9 -6
  47. package/dist/ui/assets/index-C2lhc6Pd.css +1 -0
  48. package/dist/ui/assets/index-D8nVOwBC.js +9 -0
  49. package/dist/ui/index.html +2 -2
  50. package/package.json +5 -3
  51. package/dist/ui/assets/index-SADMOgPE.js +0 -10
  52. package/dist/ui/assets/index-rj7m-XdG.css +0 -1
@@ -43,6 +43,7 @@ function createAdminRouter(optionsOrGetEndpoints, getFlowsArg, stateManagerArg)
43
43
  const response = {
44
44
  endpoints: endpoints.map((endpoint) => ({
45
45
  id: endpoint.id,
46
+ sourceFile: endpoint.sourceFile,
46
47
  path: endpoint.path,
47
48
  method: endpoint.method,
48
49
  scenarios: endpoint.scenarios.map((scenario) => ({
@@ -140,211 +141,6 @@ function createAdminRouter(optionsOrGetEndpoints, getFlowsArg, stateManagerArg)
140
141
  res.status(204).end();
141
142
  });
142
143
  // ============================================
143
- // Endpoint CRUD Operations
144
- // ============================================
145
- /**
146
- * GET /endpoints/:id
147
- * Get a single endpoint's full configuration (including scenario bodies)
148
- */
149
- router.get('/endpoints/:id', (req, res) => {
150
- const { id } = req.params;
151
- const endpoints = getEndpoints();
152
- const endpoint = endpoints.find((e) => e.id === id);
153
- if (!endpoint) {
154
- const errorResponse = {
155
- error: 'Endpoint not found',
156
- details: `No endpoint with id "${id}"`,
157
- };
158
- res.status(404).json(errorResponse);
159
- return;
160
- }
161
- res.json({
162
- id: endpoint.id,
163
- path: endpoint.path,
164
- method: endpoint.method,
165
- defaultScenarioId: endpoint.defaultScenarioId,
166
- scenarios: endpoint.scenarios.map((s) => ({
167
- id: s.id,
168
- name: s.name,
169
- status: s.status,
170
- body: s.body,
171
- headers: s.headers,
172
- delay: s.delay,
173
- })),
174
- });
175
- });
176
- /**
177
- * POST /endpoints
178
- * Create a new endpoint
179
- */
180
- router.post('/endpoints', async (req, res) => {
181
- const configWriter = getConfigWriter?.();
182
- if (!configWriter) {
183
- const errorResponse = {
184
- error: 'Endpoint management not available',
185
- details: 'ConfigWriter not configured',
186
- };
187
- res.status(501).json(errorResponse);
188
- return;
189
- }
190
- const parseResult = types_js_1.EndpointRequestSchema.safeParse(req.body);
191
- if (!parseResult.success) {
192
- const errorResponse = {
193
- error: 'Invalid request body',
194
- details: parseResult.error.issues,
195
- };
196
- res.status(400).json(errorResponse);
197
- return;
198
- }
199
- const endpoint = parseResult.data;
200
- // Check if endpoint with this ID already exists
201
- const existingEndpoint = getEndpoints().find((e) => e.id === endpoint.id);
202
- if (existingEndpoint) {
203
- const errorResponse = {
204
- error: `Endpoint with id '${endpoint.id}' already exists`,
205
- };
206
- res.status(409).json(errorResponse);
207
- return;
208
- }
209
- try {
210
- const result = await configWriter.writeEndpoint(endpoint);
211
- if (!result.success) {
212
- const errorResponse = {
213
- error: 'Failed to create endpoint',
214
- details: result.error,
215
- };
216
- res.status(500).json(errorResponse);
217
- return;
218
- }
219
- // Trigger config reload if available
220
- const onConfigChange = getOnConfigChange?.();
221
- if (onConfigChange) {
222
- await onConfigChange();
223
- }
224
- res.status(201).json({ id: endpoint.id, filePath: result.filePath });
225
- }
226
- catch (error) {
227
- const errorResponse = {
228
- error: error instanceof Error ? error.message : 'Unknown error',
229
- };
230
- res.status(500).json(errorResponse);
231
- }
232
- });
233
- /**
234
- * PUT /endpoints/:id
235
- * Update an existing endpoint
236
- */
237
- router.put('/endpoints/:id', async (req, res) => {
238
- const configWriter = getConfigWriter?.();
239
- if (!configWriter) {
240
- const errorResponse = {
241
- error: 'Endpoint management not available',
242
- details: 'ConfigWriter not configured',
243
- };
244
- res.status(501).json(errorResponse);
245
- return;
246
- }
247
- const { id } = req.params;
248
- const parseResult = types_js_1.EndpointRequestSchema.safeParse(req.body);
249
- if (!parseResult.success) {
250
- const errorResponse = {
251
- error: 'Invalid request body',
252
- details: parseResult.error.issues,
253
- };
254
- res.status(400).json(errorResponse);
255
- return;
256
- }
257
- const endpoint = parseResult.data;
258
- // Ensure the ID in the body matches the URL parameter
259
- if (endpoint.id !== id) {
260
- const errorResponse = {
261
- error: 'Endpoint ID in body must match URL parameter',
262
- };
263
- res.status(400).json(errorResponse);
264
- return;
265
- }
266
- // Check if endpoint exists
267
- const existingEndpoint = getEndpoints().find((e) => e.id === id);
268
- if (!existingEndpoint) {
269
- const errorResponse = {
270
- error: `Endpoint with id '${id}' not found`,
271
- };
272
- res.status(404).json(errorResponse);
273
- return;
274
- }
275
- try {
276
- const result = await configWriter.writeEndpoint(endpoint);
277
- if (!result.success) {
278
- const errorResponse = {
279
- error: 'Failed to update endpoint',
280
- details: result.error,
281
- };
282
- res.status(500).json(errorResponse);
283
- return;
284
- }
285
- // Trigger config reload if available
286
- const onConfigChange = getOnConfigChange?.();
287
- if (onConfigChange) {
288
- await onConfigChange();
289
- }
290
- res.status(200).json({ id: endpoint.id, filePath: result.filePath });
291
- }
292
- catch (error) {
293
- const errorResponse = {
294
- error: error instanceof Error ? error.message : 'Unknown error',
295
- };
296
- res.status(500).json(errorResponse);
297
- }
298
- });
299
- /**
300
- * DELETE /endpoints/:id
301
- * Delete an endpoint
302
- */
303
- router.delete('/endpoints/:id', async (req, res) => {
304
- const configWriter = getConfigWriter?.();
305
- if (!configWriter) {
306
- const errorResponse = {
307
- error: 'Endpoint management not available',
308
- details: 'ConfigWriter not configured',
309
- };
310
- res.status(501).json(errorResponse);
311
- return;
312
- }
313
- const { id } = req.params;
314
- // Check if endpoint exists
315
- const existingEndpoint = getEndpoints().find((e) => e.id === id);
316
- if (!existingEndpoint) {
317
- const errorResponse = {
318
- error: `Endpoint with id '${id}' not found`,
319
- };
320
- res.status(404).json(errorResponse);
321
- return;
322
- }
323
- try {
324
- const result = await configWriter.deleteEndpoint(id);
325
- if (!result.success) {
326
- const errorResponse = {
327
- error: 'Failed to delete endpoint',
328
- details: result.error,
329
- };
330
- res.status(500).json(errorResponse);
331
- return;
332
- }
333
- // Trigger config reload if available
334
- const onConfigChange = getOnConfigChange?.();
335
- if (onConfigChange) {
336
- await onConfigChange();
337
- }
338
- res.status(204).end();
339
- }
340
- catch (error) {
341
- const errorResponse = {
342
- error: error instanceof Error ? error.message : 'Unknown error',
343
- };
344
- res.status(500).json(errorResponse);
345
- }
346
- });
347
- // ============================================
348
144
  // Flow CRUD Operations
349
145
  // ============================================
350
146
  /**
@@ -24,90 +24,6 @@ export declare const ActivateFlowRequestSchema: z.ZodObject<{
24
24
  flowId: string | null;
25
25
  }>;
26
26
  export type ActivateFlowRequest = z.infer<typeof ActivateFlowRequestSchema>;
27
- /**
28
- * Request body for creating/updating an endpoint
29
- */
30
- export declare const EndpointRequestSchema: z.ZodEffects<z.ZodObject<{
31
- id: z.ZodString;
32
- path: z.ZodString;
33
- method: z.ZodEnum<["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]>;
34
- scenarios: z.ZodArray<z.ZodObject<{
35
- id: z.ZodString;
36
- name: z.ZodString;
37
- status: z.ZodNumber;
38
- headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
39
- body: z.ZodUnion<[z.ZodRecord<z.ZodString, z.ZodUnknown>, z.ZodArray<z.ZodUnknown, "many">, z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull, z.ZodFunction<z.ZodTuple<[z.ZodAny], z.ZodUnknown>, z.ZodAny>]>;
40
- delay: z.ZodOptional<z.ZodNumber>;
41
- }, "strip", z.ZodTypeAny, {
42
- status: number;
43
- id: string;
44
- name: string;
45
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
46
- headers?: Record<string, string> | undefined;
47
- delay?: number | undefined;
48
- }, {
49
- status: number;
50
- id: string;
51
- name: string;
52
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
53
- headers?: Record<string, string> | undefined;
54
- delay?: number | undefined;
55
- }>, "many">;
56
- defaultScenarioId: z.ZodString;
57
- }, "strip", z.ZodTypeAny, {
58
- path: string;
59
- id: string;
60
- method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
61
- scenarios: {
62
- status: number;
63
- id: string;
64
- name: string;
65
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
66
- headers?: Record<string, string> | undefined;
67
- delay?: number | undefined;
68
- }[];
69
- defaultScenarioId: string;
70
- }, {
71
- path: string;
72
- id: string;
73
- method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
74
- scenarios: {
75
- status: number;
76
- id: string;
77
- name: string;
78
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
79
- headers?: Record<string, string> | undefined;
80
- delay?: number | undefined;
81
- }[];
82
- defaultScenarioId: string;
83
- }>, {
84
- path: string;
85
- id: string;
86
- method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
87
- scenarios: {
88
- status: number;
89
- id: string;
90
- name: string;
91
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
92
- headers?: Record<string, string> | undefined;
93
- delay?: number | undefined;
94
- }[];
95
- defaultScenarioId: string;
96
- }, {
97
- path: string;
98
- id: string;
99
- method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | "HEAD";
100
- scenarios: {
101
- status: number;
102
- id: string;
103
- name: string;
104
- body: string | number | boolean | unknown[] | Record<string, unknown> | ((args_0: any, ...args: unknown[]) => any) | null;
105
- headers?: Record<string, string> | undefined;
106
- delay?: number | undefined;
107
- }[];
108
- defaultScenarioId: string;
109
- }>;
110
- export type EndpointRequest = z.infer<typeof EndpointRequestSchema>;
111
27
  /**
112
28
  * Request body for creating/updating a flow
113
29
  */
@@ -151,6 +67,7 @@ export type DuplicateFlowRequest = z.infer<typeof DuplicateFlowRequestSchema>;
151
67
  export interface ConfigResponse {
152
68
  endpoints: Array<{
153
69
  id: string;
70
+ sourceFile?: string;
154
71
  path: string;
155
72
  method: string;
156
73
  scenarios: Array<{
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;GAEG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;EAGxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;EAEpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAuB,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;EAAmB,CAAC;AAClD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;EAGrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,KAAK,CAAC;YACf,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC,CAAC;QACH,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;IACH,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC3C,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/admin/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;GAEG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;EAGxC,CAAC;AAEH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;EAEpC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;GAEG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;EAAmB,CAAC;AAClD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;GAEG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;EAGrC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,KAAK,CAAC;YACf,EAAE,EAAE,MAAM,CAAC;YACX,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC,CAAC;QACH,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;IACH,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC3C,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DuplicateFlowRequestSchema = exports.FlowRequestSchema = exports.EndpointRequestSchema = exports.ActivateFlowRequestSchema = exports.ActivateScenarioRequestSchema = void 0;
3
+ exports.DuplicateFlowRequestSchema = exports.FlowRequestSchema = exports.ActivateFlowRequestSchema = exports.ActivateScenarioRequestSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const index_js_1 = require("../schemas/index.js");
6
6
  /**
@@ -16,10 +16,6 @@ exports.ActivateScenarioRequestSchema = zod_1.z.object({
16
16
  exports.ActivateFlowRequestSchema = zod_1.z.object({
17
17
  flowId: zod_1.z.string().min(1).nullable(),
18
18
  });
19
- /**
20
- * Request body for creating/updating an endpoint
21
- */
22
- exports.EndpointRequestSchema = index_js_1.EndpointConfigSchema;
23
19
  /**
24
20
  * Request body for creating/updating a flow
25
21
  */
@@ -6,6 +6,7 @@ const config_loader_js_1 = require("../config-loader.js");
6
6
  const fixturesPath = (0, path_1.join)(__dirname, 'fixtures');
7
7
  const validConfigPath = (0, path_1.join)(fixturesPath, 'mock-config');
8
8
  const invalidConfigPath = (0, path_1.join)(fixturesPath, 'invalid-config');
9
+ const groupedConfigPath = (0, path_1.join)(fixturesPath, 'grouped-config');
9
10
  (0, vitest_1.describe)('ConfigLoader', () => {
10
11
  (0, vitest_1.describe)('constructor', () => {
11
12
  (0, vitest_1.it)('should resolve config path', () => {
@@ -49,6 +50,23 @@ const invalidConfigPath = (0, path_1.join)(fixturesPath, 'invalid-config');
49
50
  (0, vitest_1.expect)(ordersEndpoint).toBeDefined();
50
51
  (0, vitest_1.expect)(ordersEndpoint?.path).toBe('/orders');
51
52
  });
53
+ (0, vitest_1.it)('should retain the source file for each endpoint', async () => {
54
+ const loader = new config_loader_js_1.ConfigLoader(validConfigPath);
55
+ const result = await loader.loadEndpoints();
56
+ (0, vitest_1.expect)(result.endpoints.find((endpoint) => endpoint.id === 'get-users')?.sourceFile)
57
+ .toBe('users.json');
58
+ (0, vitest_1.expect)(result.endpoints.find((endpoint) => endpoint.id === 'get-products')?.sourceFile)
59
+ .toBe('products.ts');
60
+ (0, vitest_1.expect)(result.endpoints.find((endpoint) => endpoint.id === 'create-order')?.sourceFile)
61
+ .toBe('orders.js');
62
+ });
63
+ (0, vitest_1.it)('should retain the full relative source path for endpoint arrays', async () => {
64
+ const loader = new config_loader_js_1.ConfigLoader(groupedConfigPath);
65
+ const result = await loader.loadEndpoints();
66
+ (0, vitest_1.expect)(result.endpoints).toHaveLength(2);
67
+ (0, vitest_1.expect)(result.endpoints.map((endpoint) => endpoint.sourceFile))
68
+ .toEqual(['accounts/users.json', 'accounts/users.json']);
69
+ });
52
70
  (0, vitest_1.it)('should return empty array for non-existent directory', async () => {
53
71
  const loader = new config_loader_js_1.ConfigLoader('/non/existent/path');
54
72
  const result = await loader.loadEndpoints();
@@ -1,5 +1,5 @@
1
- import type { EndpointConfig, FlowConfig } from '../schemas/index.js';
2
- import type { ConfigLoadResult } from './types.js';
1
+ import type { FlowConfig } from '../schemas/index.js';
2
+ import type { ConfigLoadResult, LoadedEndpointConfig } from './types.js';
3
3
  /**
4
4
  * Configuration loader that discovers and loads endpoint and flow configs
5
5
  */
@@ -24,7 +24,7 @@ export declare class ConfigLoader {
24
24
  * Load all endpoint configurations from the endpoints directory
25
25
  */
26
26
  loadEndpoints(): Promise<{
27
- endpoints: EndpointConfig[];
27
+ endpoints: LoadedEndpointConfig[];
28
28
  errors: Array<{
29
29
  filePath: string;
30
30
  error: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config/config-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAatE,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,YAAY,CAAC;AAEjE;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEb,UAAU,EAAE,MAAM;IAO9B;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC;QAC7B,SAAS,EAAE,cAAc,EAAE,CAAC;QAC5B,MAAM,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACpD,CAAC;IA4CF;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,KAAK,EAAE,UAAU,EAAE,CAAC;QACpB,MAAM,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACpD,CAAC;IA4CF;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA6CvC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAG1C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAEnE"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/config/config-loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAatE,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEzE;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEb,UAAU,EAAE,MAAM;IAO9B;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,eAAe,IAAI,MAAM;IAIzB;;OAEG;IACH,WAAW,IAAI,MAAM;IAIrB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC;QAC7B,SAAS,EAAE,oBAAoB,EAAE,CAAC;QAClC,MAAM,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACpD,CAAC;IA+CF;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC;QACzB,KAAK,EAAE,UAAU,EAAE,CAAC;QACpB,MAAM,EAAE,KAAK,CAAC;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACpD,CAAC;IA4CF;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA6CvC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;CAG1C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAEnE"}
@@ -66,7 +66,10 @@ class ConfigLoader {
66
66
  });
67
67
  continue;
68
68
  }
69
- endpoints.push(validationResult.data);
69
+ endpoints.push({
70
+ ...validationResult.data,
71
+ sourceFile: (0, path_1.relative)(this.endpointsDir, filePath).split(path_1.sep).join('/'),
72
+ });
70
73
  }
71
74
  }
72
75
  return { endpoints, errors };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Config file writer - handles persisting endpoint and flow configs to disk
3
3
  */
4
- import type { EndpointConfig, FlowConfig } from '../schemas/index.js';
4
+ import type { FlowConfig } from '../schemas/index.js';
5
5
  /**
6
6
  * Result of a write operation
7
7
  */
@@ -26,38 +26,18 @@ export declare class ConfigWriter {
26
26
  private endpointsDir;
27
27
  private flowsDir;
28
28
  constructor(options: ConfigWriterOptions);
29
- /**
30
- * Get the file path for an endpoint config
31
- */
32
- getEndpointFilePath(endpointId: string): string;
33
29
  /**
34
30
  * Get the file path for a flow config
35
31
  */
36
32
  getFlowFilePath(flowId: string): string;
37
- /**
38
- * Check if an endpoint file exists
39
- */
40
- endpointExists(endpointId: string): Promise<boolean>;
41
33
  /**
42
34
  * Check if a flow file exists
43
35
  */
44
36
  flowExists(flowId: string): Promise<boolean>;
45
- /**
46
- * Find an existing endpoint file by ID (could be .json, .js, or .ts)
47
- */
48
- findEndpointFile(endpointId: string): Promise<string | null>;
49
37
  /**
50
38
  * Find an existing flow file by ID (could be .json, .js, or .ts)
51
39
  */
52
40
  findFlowFile(flowId: string): Promise<string | null>;
53
- /**
54
- * Validate an endpoint config
55
- */
56
- validateEndpoint(data: unknown): {
57
- success: boolean;
58
- data?: EndpointConfig;
59
- error?: string;
60
- };
61
41
  /**
62
42
  * Validate a flow config
63
43
  */
@@ -66,28 +46,14 @@ export declare class ConfigWriter {
66
46
  data?: FlowConfig;
67
47
  error?: string;
68
48
  };
69
- /**
70
- * Write an endpoint config to disk
71
- * Creates a new file or overwrites existing .json file
72
- */
73
- writeEndpoint(endpoint: EndpointConfig): Promise<WriteResult>;
74
49
  /**
75
50
  * Write a flow config to disk
76
51
  */
77
52
  writeFlow(flow: FlowConfig): Promise<WriteResult>;
78
- /**
79
- * Delete an endpoint file
80
- */
81
- deleteEndpoint(endpointId: string): Promise<WriteResult>;
82
53
  /**
83
54
  * Delete a flow file
84
55
  */
85
56
  deleteFlow(flowId: string): Promise<WriteResult>;
86
- /**
87
- * Clean endpoint data for JSON serialization
88
- * Converts function bodies to null (they can't be serialized)
89
- */
90
- private cleanEndpointForJson;
91
57
  }
92
58
  /**
93
59
  * Create a ConfigWriter instance
@@ -1 +1 @@
1
- {"version":3,"file":"config-writer.d.ts","sourceRoot":"","sources":["../../src/config/config-writer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,mBAAmB;IAKxC;;OAEG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAI/C;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU1D;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlD;;OAEG;IACG,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAclE;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAc1D;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,cAAc,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAS5F;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IASpF;;;OAGG;IACG,aAAa,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAuBnE;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAoBvD;;OAEG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkB9D;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBtD;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CAU7B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAE7E"}
1
+ {"version":3,"file":"config-writer.d.ts","sourceRoot":"","sources":["../../src/config/config-writer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0CAA0C;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,mBAAmB;IAKxC;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUlD;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAc1D;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,UAAU,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IASpF;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAoBvD;;OAEG;IACG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAkBvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,YAAY,CAE7E"}
@@ -49,31 +49,12 @@ class ConfigWriter {
49
49
  this.endpointsDir = options.endpointsDir;
50
50
  this.flowsDir = options.flowsDir;
51
51
  }
52
- /**
53
- * Get the file path for an endpoint config
54
- */
55
- getEndpointFilePath(endpointId) {
56
- return path.join(this.endpointsDir, `${endpointId}.json`);
57
- }
58
52
  /**
59
53
  * Get the file path for a flow config
60
54
  */
61
55
  getFlowFilePath(flowId) {
62
56
  return path.join(this.flowsDir, `${flowId}.json`);
63
57
  }
64
- /**
65
- * Check if an endpoint file exists
66
- */
67
- async endpointExists(endpointId) {
68
- const filePath = this.getEndpointFilePath(endpointId);
69
- try {
70
- await fs.access(filePath);
71
- return true;
72
- }
73
- catch {
74
- return false;
75
- }
76
- }
77
58
  /**
78
59
  * Check if a flow file exists
79
60
  */
@@ -87,23 +68,6 @@ class ConfigWriter {
87
68
  return false;
88
69
  }
89
70
  }
90
- /**
91
- * Find an existing endpoint file by ID (could be .json, .js, or .ts)
92
- */
93
- async findEndpointFile(endpointId) {
94
- const extensions = ['.json', '.js', '.ts', '.mjs', '.mts'];
95
- for (const ext of extensions) {
96
- const filePath = path.join(this.endpointsDir, `${endpointId}${ext}`);
97
- try {
98
- await fs.access(filePath);
99
- return filePath;
100
- }
101
- catch {
102
- // Continue checking
103
- }
104
- }
105
- return null;
106
- }
107
71
  /**
108
72
  * Find an existing flow file by ID (could be .json, .js, or .ts)
109
73
  */
@@ -121,17 +85,6 @@ class ConfigWriter {
121
85
  }
122
86
  return null;
123
87
  }
124
- /**
125
- * Validate an endpoint config
126
- */
127
- validateEndpoint(data) {
128
- const result = index_js_1.EndpointConfigSchema.safeParse(data);
129
- if (result.success) {
130
- return { success: true, data: result.data };
131
- }
132
- const errors = result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');
133
- return { success: false, error: errors };
134
- }
135
88
  /**
136
89
  * Validate a flow config
137
90
  */
@@ -143,29 +96,6 @@ class ConfigWriter {
143
96
  const errors = result.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`).join('; ');
144
97
  return { success: false, error: errors };
145
98
  }
146
- /**
147
- * Write an endpoint config to disk
148
- * Creates a new file or overwrites existing .json file
149
- */
150
- async writeEndpoint(endpoint) {
151
- const filePath = this.getEndpointFilePath(endpoint.id);
152
- try {
153
- // Ensure directory exists
154
- await fs.mkdir(this.endpointsDir, { recursive: true });
155
- // Prepare clean endpoint data (remove function bodies for JSON)
156
- const cleanEndpoint = this.cleanEndpointForJson(endpoint);
157
- // Write formatted JSON
158
- const content = JSON.stringify(cleanEndpoint, null, 2) + '\n';
159
- await fs.writeFile(filePath, content, 'utf-8');
160
- return { success: true, filePath };
161
- }
162
- catch (error) {
163
- return {
164
- success: false,
165
- error: error instanceof Error ? error.message : 'Unknown error',
166
- };
167
- }
168
- }
169
99
  /**
170
100
  * Write a flow config to disk
171
101
  */
@@ -186,25 +116,6 @@ class ConfigWriter {
186
116
  };
187
117
  }
188
118
  }
189
- /**
190
- * Delete an endpoint file
191
- */
192
- async deleteEndpoint(endpointId) {
193
- const existingFile = await this.findEndpointFile(endpointId);
194
- if (!existingFile) {
195
- return { success: false, error: `Endpoint "${endpointId}" not found` };
196
- }
197
- try {
198
- await fs.unlink(existingFile);
199
- return { success: true, filePath: existingFile };
200
- }
201
- catch (error) {
202
- return {
203
- success: false,
204
- error: error instanceof Error ? error.message : 'Unknown error',
205
- };
206
- }
207
- }
208
119
  /**
209
120
  * Delete a flow file
210
121
  */
@@ -224,20 +135,6 @@ class ConfigWriter {
224
135
  };
225
136
  }
226
137
  }
227
- /**
228
- * Clean endpoint data for JSON serialization
229
- * Converts function bodies to null (they can't be serialized)
230
- */
231
- cleanEndpointForJson(endpoint) {
232
- return {
233
- ...endpoint,
234
- scenarios: endpoint.scenarios.map((scenario) => ({
235
- ...scenario,
236
- // If body is a function, convert to a placeholder or keep as-is for objects
237
- body: typeof scenario.body === 'function' ? { _note: 'Function body - edit in .ts file' } : scenario.body,
238
- })),
239
- };
240
- }
241
138
  }
242
139
  exports.ConfigWriter = ConfigWriter;
243
140
  /**
@@ -1,4 +1,4 @@
1
- export type { MockServerOptions, LoadedConfig, FileLoadResult, ConfigLoadResult, SupportedExtension, } from './types.js';
1
+ export type { MockServerOptions, LoadedConfig, LoadedEndpointConfig, RuntimeEndpointConfig, FileLoadResult, ConfigLoadResult, SupportedExtension, } from './types.js';
2
2
  export { SUPPORTED_EXTENSIONS } from './types.js';
3
3
  export { loadConfigFile, isSupportedExtension, clearModuleCache, } from './file-loader.js';
4
4
  export { discoverConfigFiles, directoryExists, getConfigDirectories, type DiscoveryOptions, } from './config-discovery.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGlD,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGtE,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGlD,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAGtE,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC"}