@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
package/README.md CHANGED
@@ -8,6 +8,8 @@ A reusable Node.js mock server for simulating backend APIs during local microfro
8
8
  - 🔄 **Hot reload** - Automatic config reloading on file changes
9
9
  - 🎭 **Scenarios** - Define multiple response scenarios per endpoint
10
10
  - 🌊 **Flows** - Activate groups of scenarios to simulate user journeys
11
+ - 📁 **File download** - Serve binary files (PDFs, images, CSVs) from scenarios
12
+ - 📤 **File upload** - Accept `multipart/form-data` upload requests out of the box
11
13
  - 🎨 **Admin UI** - Visual dashboard at `/mock-admin` to control the server
12
14
  - 🔌 **REST API** - Programmatic control via admin endpoints
13
15
  - 📦 **Single package** - Everything bundled, no external dependencies needed
@@ -138,12 +140,15 @@ interface ScenarioConfig {
138
140
  id: string; // Unique within endpoint
139
141
  name: string; // Display name in admin UI
140
142
  status: number; // HTTP status code (100-599)
141
- body?: any; // Response body (JSON or function)
143
+ body?: any; // Response body (JSON or function) — mutually exclusive with file
144
+ file?: string; // File path relative to configPath — mutually exclusive with body
142
145
  headers?: Record<string, string>; // Custom response headers
143
146
  delay?: number; // Response delay in ms
144
147
  }
145
148
  ```
146
149
 
150
+ > **Note:** `body` and `file` are mutually exclusive. Setting both will cause a validation error at startup.
151
+
147
152
  ### Flow Config
148
153
 
149
154
  Flows activate multiple scenarios at once to simulate complex user journeys.
@@ -177,6 +182,107 @@ interface FlowConfig {
177
182
 
178
183
  ---
179
184
 
185
+ ## File Download
186
+
187
+ A scenario can serve a file instead of JSON by specifying a `file` path relative to `configPath`:
188
+
189
+ **mock-config/endpoints/reports.json**
190
+ ```json
191
+ {
192
+ "id": "get-report",
193
+ "path": "/reports/:id",
194
+ "method": "GET",
195
+ "defaultScenarioId": "pdf",
196
+ "scenarios": [
197
+ {
198
+ "id": "pdf",
199
+ "name": "PDF Report",
200
+ "status": 200,
201
+ "file": "./assets/sample-report.pdf",
202
+ "headers": { "Content-Disposition": "attachment; filename=report.pdf" }
203
+ },
204
+ {
205
+ "id": "not-found",
206
+ "name": "Not Found",
207
+ "status": 404,
208
+ "body": { "error": "Report not found" }
209
+ }
210
+ ]
211
+ }
212
+ ```
213
+
214
+ Place the file at `mock-config/assets/sample-report.pdf`. The `Content-Type` header is inferred automatically from the file extension if not set explicitly.
215
+
216
+ > `body` and `file` are mutually exclusive — setting both causes a validation error at startup.
217
+
218
+ ---
219
+
220
+ ## File Upload
221
+
222
+ Upload endpoints work out of the box — no special configuration needed. The server accepts `multipart/form-data` requests, discards the uploaded files, and returns the active scenario response:
223
+
224
+ **mock-config/endpoints/avatar.json**
225
+ ```json
226
+ {
227
+ "id": "upload-avatar",
228
+ "path": "/users/:id/avatar",
229
+ "method": "POST",
230
+ "defaultScenarioId": "success",
231
+ "scenarios": [
232
+ {
233
+ "id": "success",
234
+ "name": "Upload OK",
235
+ "status": 200,
236
+ "body": { "url": "/cdn/avatar.jpg" }
237
+ },
238
+ {
239
+ "id": "too-large",
240
+ "name": "File Too Large",
241
+ "status": 413,
242
+ "body": { "error": "File exceeds maximum size" }
243
+ }
244
+ ]
245
+ }
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Global Delay
251
+
252
+ Add a baseline latency to every response without modifying individual scenarios:
253
+
254
+ ```typescript
255
+ const server = new MockServer({
256
+ configPath: './mock-config',
257
+ globalDelay: 200, // every response waits 200 ms
258
+ });
259
+ ```
260
+
261
+ Or use a random range to simulate variable network conditions:
262
+
263
+ ```typescript
264
+ const server = new MockServer({
265
+ configPath: './mock-config',
266
+ globalDelay: [100, 500], // each response waits a random 100–500 ms
267
+ });
268
+ ```
269
+
270
+ **Priority:** a scenario's own `delay` field always takes precedence. `globalDelay` is only used when the resolved scenario has no `delay` set.
271
+
272
+ ```json
273
+ {
274
+ "id": "fast-scenario",
275
+ "name": "Always fast",
276
+ "status": 200,
277
+ "delay": 0,
278
+ "body": { "ok": true }
279
+ }
280
+ ```
281
+
282
+ In the example above, `delay: 0` overrides any `globalDelay` — the response is immediate.
283
+
284
+ ---
285
+
180
286
  ## TypeScript Configs
181
287
 
182
288
  You can write configs in TypeScript for type safety and dynamic responses:
@@ -218,9 +324,6 @@ export default endpoint;
218
324
  The built-in admin UI is available at `/mock-admin` and provides:
219
325
 
220
326
  - **Endpoints Panel**: View all endpoints, expand to see scenarios, click to activate
221
- - Create new endpoints with the JSON editor
222
- - Edit existing endpoint configurations
223
- - Delete endpoints with confirmation
224
327
  - **Flows Panel**: View and activate user flows with category grouping
225
328
  - Create new flows with the endpoint/scenario picker
226
329
  - Edit or duplicate existing flows
@@ -248,13 +351,6 @@ Control the mock server programmatically:
248
351
  | POST | `/mock-admin/api/flows/activate` | Activate/deactivate a flow |
249
352
  | POST | `/mock-admin/api/reset` | Reset to default state |
250
353
 
251
- ### Endpoint CRUD
252
-
253
- | Method | Endpoint | Description |
254
- |--------|----------|-------------|
255
- | POST | `/mock-admin/api/endpoints` | Create a new endpoint |
256
- | PUT | `/mock-admin/api/endpoints/:id` | Update an existing endpoint |
257
- | DELETE | `/mock-admin/api/endpoints/:id` | Delete an endpoint |
258
354
 
259
355
  ### Flow CRUD
260
356
 
@@ -289,19 +385,6 @@ curl -X POST http://localhost:3001/mock-admin/api/flows/activate \
289
385
  # Reset to defaults
290
386
  curl -X POST http://localhost:3001/mock-admin/api/reset
291
387
 
292
- # Create a new endpoint
293
- curl -X POST http://localhost:3001/mock-admin/api/endpoints \
294
- -H "Content-Type: application/json" \
295
- -d '{"endpoint": {"id": "new-endpoint", "method": "GET", "path": "/api/test", "scenarios": [{"id": "default", "name": "Default", "response": {"status": 200, "body": {}}}]}}'
296
-
297
- # Update an endpoint
298
- curl -X PUT http://localhost:3001/mock-admin/api/endpoints/new-endpoint \
299
- -H "Content-Type: application/json" \
300
- -d '{"endpoint": {"id": "new-endpoint", "method": "GET", "path": "/api/test-updated", "scenarios": [{"id": "default", "name": "Default", "response": {"status": 200, "body": {"updated": true}}}]}}'
301
-
302
- # Delete an endpoint
303
- curl -X DELETE http://localhost:3001/mock-admin/api/endpoints/new-endpoint
304
-
305
388
  # Create a new flow
306
389
  curl -X POST http://localhost:3001/mock-admin/api/flows \
307
390
  -H "Content-Type: application/json" \
@@ -328,13 +411,13 @@ curl -X DELETE http://localhost:3001/mock-admin/api/flows/my-flow
328
411
  ### MockServer Class
329
412
 
330
413
  ```typescript
331
- import { MockServer } from '@zze/mock-server';
332
-
333
414
  const server = new MockServer({
334
- configPath: './mock-config', // Required
415
+ configPath: './mock-config',
335
416
  port: 3001, // Default: 3001
336
417
  apiPrefix: '/api', // Default: '/api'
337
- hotReload: true // Default: true
418
+ hotReload: true, // Default: true
419
+ globalDelay: 200 // Optional: add 200 ms to every response (unless scenario overrides)
420
+ // globalDelay: [100, 500] // Or a random range in ms
338
421
  });
339
422
  ```
340
423
 
@@ -592,6 +675,12 @@ interface MockServerOptions {
592
675
  apiPrefix?: string;
593
676
  hotReload?: boolean;
594
677
  watcherOptions?: WatcherOptions;
678
+ /**
679
+ * Global delay fallback for all responses.
680
+ * Scenario-level `delay` always overrides this.
681
+ * A number is a fixed ms value; a tuple is a [min, max] random range.
682
+ */
683
+ globalDelay?: number | [number, number];
595
684
  }
596
685
 
597
686
  // Server state
@@ -231,7 +231,10 @@ const supertest_1 = __importDefault(require("supertest"));
231
231
  }
232
232
  });
233
233
  (0, vitest_1.it)('should reload configuration manually', async () => {
234
- await createEndpoint('test1', '/test1');
234
+ await createEndpoint('test1', '/test1', 'GET', [
235
+ { id: 'success', name: 'Success', status: 200, body: { message: 'ok' }, isDefault: true },
236
+ { id: 'error', name: 'Error', status: 500, body: { error: 'failed' } },
237
+ ]);
235
238
  server = new mock_server_js_1.MockServer({
236
239
  configPath: configDir,
237
240
  port: 3015,
@@ -239,10 +242,12 @@ const supertest_1 = __importDefault(require("supertest"));
239
242
  });
240
243
  await server.start();
241
244
  (0, vitest_1.expect)(server.getEndpoints().length).toBe(1);
245
+ server.activateScenario('test1', 'error');
242
246
  // Add another endpoint
243
247
  await createEndpoint('test2', '/test2');
244
248
  await server.reload();
245
249
  (0, vitest_1.expect)(server.getEndpoints().length).toBe(2);
250
+ (0, vitest_1.expect)(server.getState().activeScenarios.test1).toBe('error');
246
251
  });
247
252
  (0, vitest_1.it)('should throw if server is not running', async () => {
248
253
  server = new mock_server_js_1.MockServer({
@@ -596,4 +601,56 @@ const supertest_1 = __importDefault(require("supertest"));
596
601
  (0, vitest_1.expect)(mockResponse.status).toBe(500);
597
602
  });
598
603
  });
604
+ (0, vitest_1.describe)('globalDelay option', () => {
605
+ let server;
606
+ (0, vitest_1.afterEach)(async () => {
607
+ if (server?.getState().running) {
608
+ await server.stop();
609
+ }
610
+ });
611
+ (0, vitest_1.it)('should apply static globalDelay to responses', async () => {
612
+ await createEndpoint('delay-ep', '/delay-ep', 'GET', [
613
+ { id: 'default', name: 'Default', status: 200, body: { ok: true }, isDefault: true },
614
+ ]);
615
+ server = new mock_server_js_1.MockServer({
616
+ configPath: configDir,
617
+ port: 3040,
618
+ hotReload: false,
619
+ globalDelay: 80,
620
+ });
621
+ await server.start();
622
+ const app = server.getApp();
623
+ const start = Date.now();
624
+ const res = await (0, supertest_1.default)(app).get('/api/delay-ep');
625
+ const elapsed = Date.now() - start;
626
+ (0, vitest_1.expect)(res.status).toBe(200);
627
+ (0, vitest_1.expect)(elapsed).toBeGreaterThanOrEqual(70); // 80 ms with small margin
628
+ });
629
+ (0, vitest_1.it)('scenario-level delay should take precedence over globalDelay', async () => {
630
+ await createEndpoint('prio-ep', '/prio-ep', 'GET', [
631
+ {
632
+ id: 'fast',
633
+ name: 'Fast',
634
+ status: 200,
635
+ body: { ok: true },
636
+ // @ts-ignore - delay is valid in EndpointConfig scenarios
637
+ delay: 0,
638
+ isDefault: true,
639
+ },
640
+ ]);
641
+ server = new mock_server_js_1.MockServer({
642
+ configPath: configDir,
643
+ port: 3041,
644
+ hotReload: false,
645
+ globalDelay: 5000, // would time out the test if used
646
+ });
647
+ await server.start();
648
+ const app = server.getApp();
649
+ const start = Date.now();
650
+ const res = await (0, supertest_1.default)(app).get('/api/prio-ep');
651
+ const elapsed = Date.now() - start;
652
+ (0, vitest_1.expect)(res.status).toBe(200);
653
+ (0, vitest_1.expect)(elapsed).toBeLessThan(300); // scenario delay=0 wins, should be fast
654
+ });
655
+ });
599
656
  });
@@ -10,6 +10,7 @@ const mock_server_app_js_1 = require("../../server/mock-server-app.js");
10
10
  const mockEndpoints = [
11
11
  {
12
12
  id: 'get-users',
13
+ sourceFile: 'accounts/users.ts',
13
14
  path: '/users',
14
15
  method: 'GET',
15
16
  scenarios: [
@@ -74,6 +75,7 @@ const mockFlows = [
74
75
  (0, vitest_1.expect)(usersEndpoint).toBeDefined();
75
76
  (0, vitest_1.expect)(usersEndpoint.path).toBe('/users');
76
77
  (0, vitest_1.expect)(usersEndpoint.method).toBe('GET');
78
+ (0, vitest_1.expect)(usersEndpoint.sourceFile).toBe('accounts/users.ts');
77
79
  (0, vitest_1.expect)(usersEndpoint.scenarios).toHaveLength(2);
78
80
  (0, vitest_1.expect)(usersEndpoint.defaultScenarioId).toBe('success');
79
81
  });
@@ -281,131 +283,6 @@ const mockFlows = [
281
283
  .expect(200);
282
284
  });
283
285
  });
284
- (0, vitest_1.describe)('Endpoint CRUD operations', () => {
285
- let mockConfigWriter;
286
- let onConfigChangeCalled;
287
- (0, vitest_1.beforeEach)(() => {
288
- onConfigChangeCalled = false;
289
- mockConfigWriter = {
290
- writeEndpoint: vitest_1.vi.fn().mockResolvedValue({ success: true, filePath: '/test/endpoint.json' }),
291
- writeFlow: vitest_1.vi.fn().mockResolvedValue({ success: true, filePath: '/test/flow.json' }),
292
- deleteEndpoint: vitest_1.vi.fn().mockResolvedValue({ success: true }),
293
- deleteFlow: vitest_1.vi.fn().mockResolvedValue({ success: true }),
294
- getEndpointFilePath: vitest_1.vi.fn().mockReturnValue('/test/endpoint.json'),
295
- getFlowFilePath: vitest_1.vi.fn().mockReturnValue('/test/flow.json'),
296
- findEndpointFile: vitest_1.vi.fn().mockResolvedValue(null),
297
- findFlowFile: vitest_1.vi.fn().mockResolvedValue(null),
298
- };
299
- serverApp.setConfigWriter(mockConfigWriter, async () => {
300
- onConfigChangeCalled = true;
301
- });
302
- });
303
- (0, vitest_1.describe)('POST /mock-admin/api/endpoints', () => {
304
- (0, vitest_1.it)('should create a new endpoint', async () => {
305
- const newEndpoint = {
306
- id: 'new-endpoint',
307
- path: '/new',
308
- method: 'POST',
309
- scenarios: [
310
- { id: 'success', name: 'Success', status: 201, body: { created: true } },
311
- ],
312
- defaultScenarioId: 'success',
313
- };
314
- const res = await (0, supertest_1.default)(serverApp.getApp())
315
- .post('/mock-admin/api/endpoints')
316
- .send(newEndpoint)
317
- .expect(201);
318
- (0, vitest_1.expect)(res.body.id).toBe('new-endpoint');
319
- (0, vitest_1.expect)(res.body.filePath).toBeDefined();
320
- (0, vitest_1.expect)(mockConfigWriter.writeEndpoint).toHaveBeenCalledWith(newEndpoint);
321
- (0, vitest_1.expect)(onConfigChangeCalled).toBe(true);
322
- });
323
- (0, vitest_1.it)('should return 409 if endpoint already exists', async () => {
324
- const existingEndpoint = {
325
- id: 'get-users',
326
- path: '/users',
327
- method: 'GET',
328
- scenarios: [{ id: 's', name: 'S', status: 200, body: {} }],
329
- defaultScenarioId: 's',
330
- };
331
- const res = await (0, supertest_1.default)(serverApp.getApp())
332
- .post('/mock-admin/api/endpoints')
333
- .send(existingEndpoint)
334
- .expect(409);
335
- (0, vitest_1.expect)(res.body.error).toContain('already exists');
336
- });
337
- (0, vitest_1.it)('should return 400 for invalid endpoint', async () => {
338
- const res = await (0, supertest_1.default)(serverApp.getApp())
339
- .post('/mock-admin/api/endpoints')
340
- .send({ id: 'test' }) // Missing required fields
341
- .expect(400);
342
- (0, vitest_1.expect)(res.body.error).toBe('Invalid request body');
343
- });
344
- });
345
- (0, vitest_1.describe)('PUT /mock-admin/api/endpoints/:id', () => {
346
- (0, vitest_1.it)('should update an existing endpoint', async () => {
347
- const updatedEndpoint = {
348
- id: 'get-users',
349
- path: '/users/updated',
350
- method: 'GET',
351
- scenarios: [
352
- { id: 'success', name: 'Success', status: 200, body: { updated: true } },
353
- ],
354
- defaultScenarioId: 'success',
355
- };
356
- const res = await (0, supertest_1.default)(serverApp.getApp())
357
- .put('/mock-admin/api/endpoints/get-users')
358
- .send(updatedEndpoint)
359
- .expect(200);
360
- (0, vitest_1.expect)(res.body.id).toBe('get-users');
361
- (0, vitest_1.expect)(mockConfigWriter.writeEndpoint).toHaveBeenCalledWith(updatedEndpoint);
362
- (0, vitest_1.expect)(onConfigChangeCalled).toBe(true);
363
- });
364
- (0, vitest_1.it)('should return 404 if endpoint not found', async () => {
365
- const endpoint = {
366
- id: 'nonexistent',
367
- path: '/test',
368
- method: 'GET',
369
- scenarios: [{ id: 's', name: 'S', status: 200, body: {} }],
370
- defaultScenarioId: 's',
371
- };
372
- const res = await (0, supertest_1.default)(serverApp.getApp())
373
- .put('/mock-admin/api/endpoints/nonexistent')
374
- .send(endpoint)
375
- .expect(404);
376
- (0, vitest_1.expect)(res.body.error).toContain('not found');
377
- });
378
- (0, vitest_1.it)('should return 400 if ID in body does not match URL', async () => {
379
- const endpoint = {
380
- id: 'different-id',
381
- path: '/users',
382
- method: 'GET',
383
- scenarios: [{ id: 's', name: 'S', status: 200, body: {} }],
384
- defaultScenarioId: 's',
385
- };
386
- const res = await (0, supertest_1.default)(serverApp.getApp())
387
- .put('/mock-admin/api/endpoints/get-users')
388
- .send(endpoint)
389
- .expect(400);
390
- (0, vitest_1.expect)(res.body.error).toContain('must match');
391
- });
392
- });
393
- (0, vitest_1.describe)('DELETE /mock-admin/api/endpoints/:id', () => {
394
- (0, vitest_1.it)('should delete an existing endpoint', async () => {
395
- await (0, supertest_1.default)(serverApp.getApp())
396
- .delete('/mock-admin/api/endpoints/get-users')
397
- .expect(204);
398
- (0, vitest_1.expect)(mockConfigWriter.deleteEndpoint).toHaveBeenCalledWith('get-users');
399
- (0, vitest_1.expect)(onConfigChangeCalled).toBe(true);
400
- });
401
- (0, vitest_1.it)('should return 404 if endpoint not found', async () => {
402
- const res = await (0, supertest_1.default)(serverApp.getApp())
403
- .delete('/mock-admin/api/endpoints/nonexistent')
404
- .expect(404);
405
- (0, vitest_1.expect)(res.body.error).toContain('not found');
406
- });
407
- });
408
- });
409
286
  (0, vitest_1.describe)('Flow CRUD operations', () => {
410
287
  let mockConfigWriter;
411
288
  let onConfigChangeCalled;
@@ -561,32 +438,6 @@ const mockFlows = [
561
438
  });
562
439
  });
563
440
  (0, vitest_1.describe)('CRUD operations without ConfigWriter', () => {
564
- (0, vitest_1.it)('should return 501 for endpoint CRUD when ConfigWriter not configured', async () => {
565
- const endpoint = {
566
- id: 'test',
567
- path: '/test',
568
- method: 'GET',
569
- scenarios: [{ id: 's', name: 'S', status: 200, body: {} }],
570
- defaultScenarioId: 's',
571
- };
572
- // POST
573
- let res = await (0, supertest_1.default)(serverApp.getApp())
574
- .post('/mock-admin/api/endpoints')
575
- .send(endpoint)
576
- .expect(501);
577
- (0, vitest_1.expect)(res.body.error).toContain('not available');
578
- // PUT
579
- res = await (0, supertest_1.default)(serverApp.getApp())
580
- .put('/mock-admin/api/endpoints/get-users')
581
- .send({ ...endpoint, id: 'get-users' })
582
- .expect(501);
583
- (0, vitest_1.expect)(res.body.error).toContain('not available');
584
- // DELETE
585
- res = await (0, supertest_1.default)(serverApp.getApp())
586
- .delete('/mock-admin/api/endpoints/get-users')
587
- .expect(501);
588
- (0, vitest_1.expect)(res.body.error).toContain('not available');
589
- });
590
441
  (0, vitest_1.it)('should return 501 for flow CRUD when ConfigWriter not configured', async () => {
591
442
  const flow = {
592
443
  id: 'test',
@@ -1,12 +1,12 @@
1
1
  import { Router } from 'express';
2
- import type { EndpointConfig, FlowConfig } from '../schemas/index.js';
2
+ import type { FlowConfig } from '../schemas/index.js';
3
3
  import type { StateManager } from '../state/index.js';
4
- import type { ConfigWriter } from '../config/index.js';
4
+ import type { ConfigWriter, RuntimeEndpointConfig } from '../config/index.js';
5
5
  /**
6
6
  * Options for creating the admin router
7
7
  */
8
8
  export interface AdminRouterOptions {
9
- getEndpoints: () => EndpointConfig[];
9
+ getEndpoints: () => RuntimeEndpointConfig[];
10
10
  getFlows: () => FlowConfig[];
11
11
  stateManager: StateManager;
12
12
  getConfigWriter?: () => ConfigWriter | undefined;
@@ -19,7 +19,7 @@ export declare function createAdminRouter(options: AdminRouterOptions): Router;
19
19
  /**
20
20
  * @deprecated Use options object instead
21
21
  */
22
- export declare function createAdminRouter(getEndpoints: () => EndpointConfig[], getFlows: () => FlowConfig[], stateManager: StateManager): Router;
22
+ export declare function createAdminRouter(getEndpoints: () => RuntimeEndpointConfig[], getFlows: () => FlowConfig[], stateManager: StateManager): Router;
23
23
  /**
24
24
  * Admin API path constant
25
25
  */
@@ -1 +1 @@
1
- {"version":3,"file":"admin-router.d.ts","sourceRoot":"","sources":["../../src/admin/admin-router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAYvD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,cAAc,EAAE,CAAC;IACrC,QAAQ,EAAE,MAAM,UAAU,EAAE,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,YAAY,GAAG,SAAS,CAAC;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAAC;AACvE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,cAAc,EAAE,EACpC,QAAQ,EAAE,MAAM,UAAU,EAAE,EAC5B,YAAY,EAAE,YAAY,GACzB,MAAM,CAAC;AAkrBV;;GAEG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"admin-router.d.ts","sourceRoot":"","sources":["../../src/admin/admin-router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmC,MAAM,SAAS,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAW9E;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,qBAAqB,EAAE,CAAC;IAC5C,QAAQ,EAAE,MAAM,UAAU,EAAE,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,YAAY,GAAG,SAAS,CAAC;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAAC;AACvE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,qBAAqB,EAAE,EAC3C,QAAQ,EAAE,MAAM,UAAU,EAAE,EAC5B,YAAY,EAAE,YAAY,GACzB,MAAM,CAAC;AA2cV;;GAEG;AACH,eAAO,MAAM,cAAc,oBAAoB,CAAC"}