@zze/mock-server 0.5.0 → 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.
@@ -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({
@@ -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
  });
@@ -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;AAWvD;;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;AA0cV;;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"}
@@ -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) => ({
@@ -67,6 +67,7 @@ export type DuplicateFlowRequest = z.infer<typeof DuplicateFlowRequestSchema>;
67
67
  export interface ConfigResponse {
68
68
  endpoints: Array<{
69
69
  id: string;
70
+ sourceFile?: string;
70
71
  path: string;
71
72
  method: string;
72
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,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"}
@@ -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,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"}
@@ -1,4 +1,12 @@
1
1
  import type { EndpointConfig, FlowConfig } from '../schemas/index.js';
2
+ export type RuntimeEndpointConfig = EndpointConfig & {
3
+ sourceFile?: string;
4
+ };
5
+ /** Validated endpoint config with loader-derived metadata */
6
+ export type LoadedEndpointConfig = RuntimeEndpointConfig & {
7
+ /** Path relative to the endpoints directory, normalized for API consumers */
8
+ sourceFile: string;
9
+ };
2
10
  /**
3
11
  * Options for initializing the MockServer
4
12
  */
@@ -16,7 +24,7 @@ export interface MockServerOptions {
16
24
  * Loaded configuration from disk
17
25
  */
18
26
  export interface LoadedConfig {
19
- endpoints: EndpointConfig[];
27
+ endpoints: LoadedEndpointConfig[];
20
28
  flows: FlowConfig[];
21
29
  }
22
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,kDAAmD,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,oBAAoB,GAAG,qBAAqB,GAAG;IACzD,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,EAAE,KAAK,CAAC;QACZ,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,kDAAmD,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -267,14 +267,13 @@ const mockFlows = [
267
267
  .expect(200);
268
268
  (0, vitest_1.expect)(res.body).toEqual({ new: true });
269
269
  });
270
- (0, vitest_1.it)('should reset state on reload', async () => {
270
+ (0, vitest_1.it)('should preserve valid scenario overrides on reload', async () => {
271
271
  serverApp.getStateManager().activateScenario('get-users', 'error');
272
272
  serverApp.reloadConfig(mockEndpoints, mockFlows);
273
- // State should be reset, so default scenario should be active
274
273
  const res = await (0, supertest_1.default)(serverApp.getApp())
275
274
  .get('/api/users')
276
- .expect(200);
277
- (0, vitest_1.expect)(res.body.length).toBe(2);
275
+ .expect(500);
276
+ (0, vitest_1.expect)(res.body).toEqual({ error: 'Internal Server Error' });
278
277
  });
279
278
  (0, vitest_1.it)('should remove old routes on reload', async () => {
280
279
  serverApp.reloadConfig([], []);
@@ -1,9 +1,9 @@
1
1
  import { Express } from 'express';
2
2
  import type { Server } from 'http';
3
- import type { EndpointConfig, FlowConfig } from '../schemas/index.js';
3
+ import type { FlowConfig } from '../schemas/index.js';
4
4
  import { StateManager } from '../state/index.js';
5
5
  import { ResponseResolver } from '../resolver/index.js';
6
- import type { ConfigWriter } from '../config/index.js';
6
+ import type { ConfigWriter, RuntimeEndpointConfig } from '../config/index.js';
7
7
  import type { ServerOptions, ServerState, RegisteredRoute } from './types.js';
8
8
  export declare const ADMIN_UI_PATH = "/mock-admin";
9
9
  /**
@@ -70,7 +70,7 @@ export declare class MockServerApp {
70
70
  /**
71
71
  * Register endpoints and flows
72
72
  */
73
- registerConfig(endpoints: EndpointConfig[], flows: FlowConfig[]): void;
73
+ registerConfig(endpoints: RuntimeEndpointConfig[], flows: FlowConfig[]): void;
74
74
  /**
75
75
  * Register routes for all endpoints
76
76
  */
@@ -110,7 +110,7 @@ export declare class MockServerApp {
110
110
  /**
111
111
  * Reload configuration (for hot reload support)
112
112
  */
113
- reloadConfig(endpoints: EndpointConfig[], flows: FlowConfig[]): void;
113
+ reloadConfig(endpoints: RuntimeEndpointConfig[], flows: FlowConfig[]): void;
114
114
  }
115
115
  /**
116
116
  * Create a new MockServerApp instance
@@ -1 +1 @@
1
- {"version":3,"file":"mock-server-app.d.ts","sourceRoot":"","sources":["../../src/server/mock-server-app.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAA2C,MAAM,SAAS,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAA0B,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI9E,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,cAAc,CAAC,CAAsB;gBAEjC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;IAahD;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiCpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,eAAe,IAAI,YAAY;IAI/B;;OAEG;IACH,WAAW,IAAI,gBAAgB;IAI/B;;OAEG;IACH,UAAU,IAAI,aAAa;IAI3B;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAIxC;;OAEG;IACH,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAKvF;;OAEG;IACH,QAAQ,IAAI,WAAW;IASvB;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAgBtE;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,GAAG,CACD,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAClC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAI7B;;OAEG;IACG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3C;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAexE;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,cAAc,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;CAKrE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GACnC,aAAa,CAEf"}
1
+ {"version":3,"file":"mock-server-app.d.ts","sourceRoot":"","sources":["../../src/server/mock-server-app.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,OAAO,EAA2C,MAAM,SAAS,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAGnC,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAA0B,MAAM,sBAAsB,CAAC;AAEhF,OAAO,KAAK,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAI9E,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAE3C;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAyB;IACjD,OAAO,CAAC,SAAS,CAA+B;IAChD,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,YAAY,CAAC,CAAe;IACpC,OAAO,CAAC,cAAc,CAAC,CAAsB;gBAEjC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;IAahD;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiCpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,eAAe,IAAI,YAAY;IAI/B;;OAEG;IACH,WAAW,IAAI,gBAAgB;IAI/B;;OAEG;IACH,UAAU,IAAI,aAAa;IAI3B;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAIxC;;OAEG;IACH,eAAe,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAKvF;;OAEG;IACH,QAAQ,IAAI,WAAW;IASvB;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,qBAAqB,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAgB7E;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwBxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;OAEG;IACH,GAAG,CACD,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAClC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAI7B;;OAEG;IACG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3C;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAexE;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB3B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,qBAAqB,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;CAG5E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GACnC,aAAa,CAEf"}
@@ -294,8 +294,6 @@ class MockServerApp {
294
294
  * Reload configuration (for hot reload support)
295
295
  */
296
296
  reloadConfig(endpoints, flows) {
297
- // Reset state before reloading
298
- this.stateManager.reset();
299
297
  this.registerConfig(endpoints, flows);
300
298
  }
301
299
  }
@@ -67,6 +67,39 @@ const mockFlows = [
67
67
  (0, vitest_1.expect)(state.activeScenarios).toEqual({ 'get-users': 'error' });
68
68
  });
69
69
  });
70
+ (0, vitest_1.describe)('configuration reconciliation', () => {
71
+ (0, vitest_1.it)('should preserve a valid scenario override when endpoints are replaced', () => {
72
+ stateManager.activateScenario('get-users', 'error');
73
+ stateManager.setEndpoints(mockEndpoints);
74
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBe('error');
75
+ });
76
+ (0, vitest_1.it)('should remove an override when its endpoint is removed', () => {
77
+ stateManager.activateScenario('get-users', 'error');
78
+ stateManager.setEndpoints([mockEndpoints[1]]);
79
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBeUndefined();
80
+ });
81
+ (0, vitest_1.it)('should remove an override when its scenario is removed', () => {
82
+ stateManager.activateScenario('get-users', 'error');
83
+ const endpointsWithoutError = mockEndpoints.map((endpoint) => endpoint.id === 'get-users'
84
+ ? {
85
+ ...endpoint,
86
+ scenarios: endpoint.scenarios.filter((scenario) => scenario.id !== 'error'),
87
+ }
88
+ : endpoint);
89
+ stateManager.setEndpoints(endpointsWithoutError);
90
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBeUndefined();
91
+ });
92
+ (0, vitest_1.it)('should preserve the active flow when flows are replaced', () => {
93
+ stateManager.activateFlow('admin-flow');
94
+ stateManager.setFlows(mockFlows);
95
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBe('admin-flow');
96
+ });
97
+ (0, vitest_1.it)('should clear the active flow when it is removed', () => {
98
+ stateManager.activateFlow('admin-flow');
99
+ stateManager.setFlows([mockFlows[1]]);
100
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBeNull();
101
+ });
102
+ });
70
103
  (0, vitest_1.describe)('activateScenario', () => {
71
104
  (0, vitest_1.it)('should activate a valid scenario', () => {
72
105
  stateManager.activateScenario('get-users', 'error');
@@ -1 +1 @@
1
- {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../src/state/state-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EACV,oBAAoB,EAEpB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,6DAA6D;IAC7D,OAAO,CAAC,eAAe,CAAkC;IAEzD,+BAA+B;IAC/B,OAAO,CAAC,YAAY,CAAuB;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,SAAS,CAA0C;IAE3D,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAsC;IAEnD,6BAA6B;IAC7B,OAAO,CAAC,SAAS,CAAuC;IAExD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI;IAO/C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAOnC;;OAEG;IACH,QAAQ,IAAI,oBAAoB;IAOhC;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,aAAa,IAAI,UAAU,GAAG,IAAI;IAKlC;;;OAGG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAsBpD;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI;IAU/E;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAkB9D;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAalC;;OAEG;IACH,cAAc,IAAI,IAAI;IAQtB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAIhD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAInD;;OAEG;IACH,OAAO,CAAC,IAAI;CAmBb;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
1
+ {"version":3,"file":"state-manager.d.ts","sourceRoot":"","sources":["../../src/state/state-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EACV,oBAAoB,EAEpB,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,YAAY;IACvB,6DAA6D;IAC7D,OAAO,CAAC,eAAe,CAAkC;IAEzD,+BAA+B;IAC/B,OAAO,CAAC,YAAY,CAAuB;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,SAAS,CAA0C;IAE3D,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAsC;IAEnD,6BAA6B;IAC7B,OAAO,CAAC,SAAS,CAAuC;IAExD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,IAAI;IAW/C;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI;IAQnC;;OAEG;IACH,QAAQ,IAAI,oBAAoB;IAOhC;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,aAAa,IAAI,UAAU,GAAG,IAAI;IAKlC;;;OAGG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D;;;OAGG;IACH,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAsBpD;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI;IAU/E;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAkB9D;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIvC;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAalC;;OAEG;IACH,cAAc,IAAI,IAAI;IAQtB;;;OAGG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAIhD;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAInD;;OAEG;IACH,OAAO,CAAC,IAAI;CAmBb;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD"}
@@ -23,18 +23,21 @@ class StateManager {
23
23
  * Register endpoints for scenario validation
24
24
  */
25
25
  setEndpoints(endpoints) {
26
- this.endpoints.clear();
27
- for (const endpoint of endpoints) {
28
- this.endpoints.set(endpoint.id, endpoint);
26
+ this.endpoints = new Map(endpoints.map((endpoint) => [endpoint.id, endpoint]));
27
+ for (const [endpointId, scenarioId] of this.activeScenarios) {
28
+ const endpoint = this.endpoints.get(endpointId);
29
+ if (!endpoint?.scenarios.some((scenario) => scenario.id === scenarioId)) {
30
+ this.activeScenarios.delete(endpointId);
31
+ }
29
32
  }
30
33
  }
31
34
  /**
32
35
  * Register flows for validation
33
36
  */
34
37
  setFlows(flows) {
35
- this.flows.clear();
36
- for (const flow of flows) {
37
- this.flows.set(flow.id, flow);
38
+ this.flows = new Map(flows.map((flow) => [flow.id, flow]));
39
+ if (this.activeFlowId && !this.flows.has(this.activeFlowId)) {
40
+ this.activeFlowId = null;
38
41
  }
39
42
  }
40
43
  /**
@@ -0,0 +1 @@
1
+ :root{--primary: #4f46e5;--primary-hover: #4338ca;--success: #10b981;--warning: #f59e0b;--error: #ef4444;--bg: #f5f5f5;--card-bg: #ffffff;--border: #e5e7eb;--text: #1f2937;--text-muted: #6b7280}*{box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,sans-serif;background:var(--bg);color:var(--text);margin:0;padding:0}.app{max-width:1200px;margin:0 auto;padding:20px}.header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px;padding-bottom:16px;border-bottom:1px solid var(--border)}.header h1{font-size:24px;font-weight:600;color:var(--text)}.header-actions{display:flex;gap:12px}.btn{padding:8px 16px;border:none;border-radius:6px;font-size:14px;font-weight:500;cursor:pointer;transition:all .15s ease}.btn-primary{background:var(--primary);color:#fff}.btn-primary:hover{background:var(--primary-hover)}.btn-secondary{background:var(--card-bg);color:var(--text);border:1px solid var(--border)}.btn-secondary:hover{background:var(--bg)}.btn-danger{background:var(--error);color:#fff}.btn-danger:hover{background:#dc2626}.btn-sm{padding:4px 10px;font-size:12px}.grid{display:grid;grid-template-columns:1fr 300px;gap:24px}.main-content{display:flex;flex-direction:column;gap:24px}.card{background:var(--card-bg);border-radius:8px;border:1px solid var(--border);overflow:hidden}.card-header{padding:16px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}.card-header h2{font-size:16px;font-weight:600}.card-body{padding:16px}.endpoint-groups{display:flex;flex-direction:column;gap:12px}.endpoints-search{padding:10px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;position:relative}.endpoints-search-input{flex:1;min-width:0;padding:8px 32px 8px 10px;border:1px solid var(--border);border-radius:4px;font-size:13px}.endpoints-search-input:focus{outline:none;border-color:var(--primary)}.endpoints-search-clear{position:absolute;right:146px;border:none;background:none;color:var(--text-muted);cursor:pointer;font-size:18px;line-height:1}.endpoint-filter-toggle{display:flex;align-items:center;gap:6px;white-space:nowrap;color:var(--text-muted);font-size:12px;cursor:pointer}.endpoint-filter-toggle input{accent-color:var(--primary)}.endpoint-group{border:1px solid var(--border);border-radius:6px;overflow:hidden}.endpoint-group-header{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--bg-secondary);cursor:pointer;-webkit-user-select:none;user-select:none}.endpoint-group-header:hover{background:#e5e7eb}.endpoint-group-toggle{width:12px;color:var(--text-muted);font-size:10px}.endpoint-group-name{flex:1;min-width:0;overflow-wrap:anywhere;font-family:SF Mono,Monaco,monospace;font-size:13px;font-weight:600}.endpoint-group-count{padding:2px 6px;border-radius:10px;background:var(--bg-primary);color:var(--text-muted);font-size:11px;font-weight:500}.endpoint-group-overrides{color:#b45309;font-size:11px;font-weight:600}.endpoint-group-items{display:flex;flex-direction:column;gap:8px;padding:8px}.endpoint-item{border:1px solid var(--border);border-radius:6px;overflow:hidden}.endpoint-item.has-override{border-color:var(--warning)}.endpoint-item.has-override .endpoint-header{background:#fffbeb}.endpoint-header{padding:12px 16px;background:var(--bg);display:flex;justify-content:space-between;align-items:center;cursor:pointer}.endpoint-header:hover{background:#e5e7eb}.endpoint-info{display:flex;align-items:center;gap:12px}.method-badge{padding:2px 8px;border-radius:4px;font-size:12px;font-weight:600;text-transform:uppercase}.method-GET{background:#dbeafe;color:#1d4ed8}.method-POST{background:#dcfce7;color:#16a34a}.method-PUT{background:#fef3c7;color:#d97706}.method-DELETE{background:#fee2e2;color:#dc2626}.method-PATCH{background:#f3e8ff;color:#9333ea}.endpoint-path{font-family:SF Mono,Monaco,monospace;font-size:13px}.endpoint-id{font-size:12px;color:var(--text-muted)}.scenarios-list{padding:12px 16px;border-top:1px solid var(--border)}.scenario-item{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}.scenario-item:last-child{border-bottom:none}.scenario-info{display:flex;align-items:center;gap:8px}.scenario-name{font-size:14px}.badge{padding:2px 6px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase}.badge-default{background:#dbeafe;color:#1d4ed8}.badge-active{background:#dcfce7;color:#16a34a}.badge-override{background:#fef3c7;color:#b45309}.sidebar{display:flex;flex-direction:column;gap:24px}.state-panel .state-item{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}.state-panel .state-item:last-child{border-bottom:none}.state-label{font-size:13px;color:var(--text-muted)}.state-value{font-size:13px;font-weight:500}.override-list{display:flex;flex-direction:column;gap:6px;padding-top:10px}.override-empty{color:var(--text-muted);font-size:12px;line-height:1.4}.override-item{width:100%;padding:8px;border:1px solid var(--border);border-radius:4px;background:var(--card-bg);color:var(--text);text-align:left;cursor:pointer}.override-item:hover{border-color:var(--warning);background:#fffbeb}.override-summary,.override-ids{display:block;overflow-wrap:anywhere}.override-summary{display:flex;justify-content:space-between;gap:8px;font-size:12px;font-weight:600}.override-scenario{color:#b45309;text-align:right}.override-ids{margin-top:3px;color:var(--text-muted);font-family:SF Mono,Monaco,monospace;font-size:10px}.flow-list{display:flex;flex-direction:column;gap:8px}.flow-item{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;border:1px solid var(--border);border-radius:6px;cursor:pointer;transition:all .15s ease}.flow-item:hover{border-color:var(--primary)}.flow-item.active{border-color:var(--success);background:#f0fdf4}.flow-name{font-size:14px;font-weight:500}.flow-description{font-size:12px;color:var(--text-muted);margin-top:2px}.flows-card{display:flex;flex-direction:column;max-height:600px}.flows-body{flex:1;overflow-y:auto;min-height:0}.active-flow-banner{padding:8px 12px;background:#f0fdf4;border-bottom:1px solid #bbf7d0;display:flex;align-items:center;gap:8px;font-size:13px}.active-flow-label{color:var(--success);font-weight:600}.active-flow-name{font-weight:500}.active-flow-category{color:var(--text-muted)}.flows-search{padding:8px 12px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;position:relative}.flows-search-input{flex:1;padding:6px 28px 6px 10px;border:1px solid var(--border);border-radius:4px;font-size:13px}.flows-search-input:focus{outline:none;border-color:var(--primary)}.flows-search-clear{position:absolute;right:20px;background:none;border:none;font-size:18px;color:var(--text-muted);cursor:pointer;padding:0 4px;line-height:1}.flows-search-clear:hover{color:var(--text)}.flow-groups{display:flex;flex-direction:column}.flow-group{border-bottom:1px solid var(--border)}.flow-group:last-child{border-bottom:none}.flow-group-header{display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--bg-primary);transition:background .15s ease}.flow-group-header:hover{background:var(--bg-secondary)}.flow-group-header.has-active{background:#f0fdf4}.flow-group-toggle{font-size:10px;color:var(--text-muted);width:12px}.flow-group-name{flex:1;font-weight:600;font-size:13px}.flow-group-count{background:var(--bg-secondary);color:var(--text-muted);font-size:11px;padding:2px 6px;border-radius:10px;font-weight:500}.flow-group-items{display:flex;flex-direction:column;gap:4px;padding:8px 12px;background:var(--bg-secondary)}.flow-group-items .flow-item{background:var(--bg-primary);padding:8px 10px}.flow-item-content{flex:1;min-width:0}.flow-meta{display:flex;gap:8px;margin-top:4px}.flow-endpoints{font-size:11px;color:var(--text-muted)}.loading{display:flex;justify-content:center;align-items:center;padding:40px;color:var(--text-muted)}.error{padding:16px;background:#fef2f2;border:1px solid #fecaca;border-radius:6px;color:var(--error)}.empty{padding:24px;text-align:center;color:var(--text-muted)}@media(max-width:900px){.grid{grid-template-columns:1fr}.sidebar{order:-1}.endpoints-search{flex-wrap:wrap}.endpoints-search-clear{right:24px;top:16px}.endpoint-filter-toggle{width:100%}}.btn:disabled{opacity:.6;cursor:not-allowed}.btn-success{background:var(--success);color:#fff}.btn-success:hover:not(:disabled){background:#059669}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;justify-content:center;align-items:center;z-index:1000;padding:20px}.modal{background:var(--card-bg);border-radius:12px;box-shadow:0 20px 40px #0003;width:100%;max-width:700px;max-height:90vh;display:flex;flex-direction:column;overflow:hidden}.modal-header{padding:16px 20px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center}.modal-header h2{font-size:18px;font-weight:600;margin:0}.modal-close{background:none;border:none;font-size:24px;cursor:pointer;color:var(--text-muted);padding:0;line-height:1}.modal-close:hover{color:var(--text)}.modal-body{padding:20px;overflow-y:auto;flex:1}.modal-footer{padding:16px 20px;border-top:1px solid var(--border);display:flex;justify-content:flex-end;gap:12px}.modal-error{margin-top:12px;padding:10px 12px;background:#fef2f2;border:1px solid #fecaca;border-radius:6px;color:var(--error);font-size:13px}.endpoint-actions{display:flex;gap:6px;margin-left:auto}.btn-icon{padding:4px 8px;font-size:12px;background:transparent;border:1px solid var(--border);border-radius:4px;cursor:pointer;color:var(--text-muted)}.btn-icon:hover{background:var(--bg);color:var(--text)}.btn-icon.btn-danger{border-color:transparent}.btn-icon.btn-danger:hover{background:#fef2f2;color:var(--error);border-color:#fecaca}.confirm-dialog{text-align:center}.confirm-dialog p{margin:0 0 20px;font-size:15px;color:var(--text)}.confirm-dialog .btn-group{display:flex;justify-content:center;gap:12px}.flow-item.has-actions{cursor:default}.flow-item.has-actions .flow-item-content{cursor:pointer}.flow-item-actions{display:flex;align-items:center;gap:8px}.flow-action-buttons{display:flex;gap:4px;opacity:0;transition:opacity .15s ease}.flow-item:hover .flow-action-buttons{opacity:1}.btn-danger-icon:hover{color:var(--error)}.card-header-actions{display:flex;gap:8px}.modal-large{max-width:900px}.flow-editor-modal .modal-body{display:flex;flex-direction:column;gap:20px}.flow-editor-fields{display:flex;flex-direction:column;gap:16px}.form-row{display:flex;gap:16px}.form-group{flex:1;display:flex;flex-direction:column;gap:6px}.form-group-wide{flex:2}.form-group label{font-size:13px;font-weight:500;color:var(--text)}.form-group input{width:100%;padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:14px;transition:border-color .15s ease;box-sizing:border-box}.form-group input:focus{outline:none;border-color:var(--primary)}.form-group input.disabled{background:var(--bg-secondary);color:var(--text-muted);cursor:not-allowed}.form-hint{font-size:11px;color:var(--text-muted)}.required{color:var(--error)}.category-input,.category-input-wrapper{position:relative}.category-input-wrapper input{width:100%}.category-suggestions{position:absolute;top:100%;left:0;right:0;background:var(--card-bg);border:1px solid var(--border);border-radius:6px;box-shadow:0 4px 12px #0000001a;z-index:10;max-height:150px;overflow-y:auto;margin-top:4px}.category-suggestion{display:block;width:100%;text-align:left;padding:8px 12px;background:none;border:none;font-size:13px;cursor:pointer}.category-suggestion:hover{background:var(--bg-secondary)}.flow-editor-picker{border-top:1px solid var(--border);padding-top:20px}.flow-editor-picker h4{margin:0 0 4px;font-size:15px;font-weight:600}.picker-description{font-size:13px;color:var(--text-muted);margin:0 0 12px}.endpoint-scenario-picker{border:1px solid var(--border);border-radius:8px;overflow:hidden}.picker-header{display:flex;justify-content:space-between;align-items:center;padding:10px 12px;background:var(--bg-secondary);border-bottom:1px solid var(--border)}.picker-stats{font-size:13px;color:var(--text-muted)}.picker-actions{display:flex;gap:8px}.picker-search{padding:8px 12px;border-bottom:1px solid var(--border);position:relative}.picker-search-input{width:100%;padding:6px 28px 6px 10px;border:1px solid var(--border);border-radius:4px;font-size:13px}.picker-search-input:focus{outline:none;border-color:var(--primary)}.picker-search-clear{position:absolute;right:20px;top:50%;transform:translateY(-50%);background:none;border:none;font-size:18px;color:var(--text-muted);cursor:pointer;padding:0 4px;line-height:1}.picker-list{max-height:300px;overflow-y:auto}.picker-empty{padding:24px;text-align:center;color:var(--text-muted)}.picker-endpoint{border-bottom:1px solid var(--border)}.picker-endpoint:last-child{border-bottom:none}.picker-endpoint.has-selection{background:#f0fdf4}.picker-endpoint-header{display:flex;align-items:center;gap:8px;padding:10px 12px;cursor:pointer;-webkit-user-select:none;user-select:none}.picker-endpoint-header:hover{background:var(--bg-secondary)}.picker-toggle{font-size:10px;color:var(--text-muted);width:12px}.picker-endpoint-path{font-family:SF Mono,Monaco,monospace;font-size:13px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.picker-selected-badge{font-size:11px;padding:2px 6px;background:var(--success);color:#fff;border-radius:4px}.picker-scenarios{padding:8px 12px 8px 32px;background:var(--bg-secondary);display:flex;flex-direction:column;gap:6px}.picker-scenario{display:flex;align-items:center;gap:8px;padding:6px 10px;background:var(--card-bg);border:1px solid var(--border);border-radius:4px;cursor:pointer;transition:all .15s ease}.picker-scenario:hover{border-color:var(--primary)}.picker-scenario.selected{border-color:var(--success);background:#f0fdf4}.picker-scenario input[type=radio]{margin:0}.picker-scenario-name{font-size:13px;font-weight:500}.picker-scenario-id{font-size:11px;color:var(--text-muted);font-family:SF Mono,Monaco,monospace}.picker-scenario-default{font-size:10px;padding:1px 4px;background:var(--primary);color:#fff;border-radius:3px;margin-left:auto}.picker-remove{padding:4px 8px;color:var(--text-muted);font-size:12px}.btn-link{background:none;border:none;color:var(--primary);cursor:pointer;text-decoration:none}.btn-link:hover{text-decoration:underline}