@zze/mock-server 0.2.4

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 (177) hide show
  1. package/README.md +643 -0
  2. package/dist/__tests__/mock-server.test.d.ts +5 -0
  3. package/dist/__tests__/mock-server.test.d.ts.map +1 -0
  4. package/dist/__tests__/mock-server.test.js +599 -0
  5. package/dist/__tests__/mock-server.test.js.map +1 -0
  6. package/dist/admin/__tests__/admin-router.test.d.ts +2 -0
  7. package/dist/admin/__tests__/admin-router.test.d.ts.map +1 -0
  8. package/dist/admin/__tests__/admin-router.test.js +621 -0
  9. package/dist/admin/__tests__/admin-router.test.js.map +1 -0
  10. package/dist/admin/admin-router.d.ts +27 -0
  11. package/dist/admin/admin-router.d.ts.map +1 -0
  12. package/dist/admin/admin-router.js +616 -0
  13. package/dist/admin/admin-router.js.map +1 -0
  14. package/dist/admin/index.d.ts +4 -0
  15. package/dist/admin/index.d.ts.map +1 -0
  16. package/dist/admin/index.js +10 -0
  17. package/dist/admin/index.js.map +1 -0
  18. package/dist/admin/types.d.ts +185 -0
  19. package/dist/admin/types.d.ts.map +1 -0
  20. package/dist/admin/types.js +33 -0
  21. package/dist/admin/types.js.map +1 -0
  22. package/dist/config/__tests__/config-discovery.test.d.ts +2 -0
  23. package/dist/config/__tests__/config-discovery.test.d.ts.map +1 -0
  24. package/dist/config/__tests__/config-discovery.test.js +52 -0
  25. package/dist/config/__tests__/config-discovery.test.js.map +1 -0
  26. package/dist/config/__tests__/config-loader.test.d.ts +2 -0
  27. package/dist/config/__tests__/config-loader.test.d.ts.map +1 -0
  28. package/dist/config/__tests__/config-loader.test.js +124 -0
  29. package/dist/config/__tests__/config-loader.test.js.map +1 -0
  30. package/dist/config/__tests__/file-loader.test.d.ts +2 -0
  31. package/dist/config/__tests__/file-loader.test.d.ts.map +1 -0
  32. package/dist/config/__tests__/file-loader.test.js +63 -0
  33. package/dist/config/__tests__/file-loader.test.js.map +1 -0
  34. package/dist/config/__tests__/fixtures/mock-config/endpoints/products.d.ts +25 -0
  35. package/dist/config/__tests__/fixtures/mock-config/endpoints/products.d.ts.map +1 -0
  36. package/dist/config/__tests__/fixtures/mock-config/endpoints/products.js +25 -0
  37. package/dist/config/__tests__/fixtures/mock-config/endpoints/products.js.map +1 -0
  38. package/dist/config/__tests__/fixtures/mock-config/flows/error-flow.d.ts +11 -0
  39. package/dist/config/__tests__/fixtures/mock-config/flows/error-flow.d.ts.map +1 -0
  40. package/dist/config/__tests__/fixtures/mock-config/flows/error-flow.js +11 -0
  41. package/dist/config/__tests__/fixtures/mock-config/flows/error-flow.js.map +1 -0
  42. package/dist/config/config-discovery.d.ts +23 -0
  43. package/dist/config/config-discovery.d.ts.map +1 -0
  44. package/dist/config/config-discovery.js +60 -0
  45. package/dist/config/config-discovery.js.map +1 -0
  46. package/dist/config/config-loader.d.ts +56 -0
  47. package/dist/config/config-loader.d.ts.map +1 -0
  48. package/dist/config/config-loader.js +162 -0
  49. package/dist/config/config-loader.js.map +1 -0
  50. package/dist/config/config-writer.d.ts +96 -0
  51. package/dist/config/config-writer.d.ts.map +1 -0
  52. package/dist/config/config-writer.js +248 -0
  53. package/dist/config/config-writer.js.map +1 -0
  54. package/dist/config/file-loader.d.ts +16 -0
  55. package/dist/config/file-loader.d.ts.map +1 -0
  56. package/dist/config/file-loader.js +90 -0
  57. package/dist/config/file-loader.js.map +1 -0
  58. package/dist/config/index.d.ts +7 -0
  59. package/dist/config/index.d.ts.map +1 -0
  60. package/dist/config/index.js +23 -0
  61. package/dist/config/index.js.map +1 -0
  62. package/dist/config/types.d.ts +47 -0
  63. package/dist/config/types.d.ts.map +1 -0
  64. package/dist/config/types.js +7 -0
  65. package/dist/config/types.js.map +1 -0
  66. package/dist/index.d.ts +28 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +31 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/mock-server.d.ts +243 -0
  71. package/dist/mock-server.d.ts.map +1 -0
  72. package/dist/mock-server.js +387 -0
  73. package/dist/mock-server.js.map +1 -0
  74. package/dist/resolver/__tests__/response-resolver.test.d.ts +2 -0
  75. package/dist/resolver/__tests__/response-resolver.test.d.ts.map +1 -0
  76. package/dist/resolver/__tests__/response-resolver.test.js +358 -0
  77. package/dist/resolver/__tests__/response-resolver.test.js.map +1 -0
  78. package/dist/resolver/index.d.ts +4 -0
  79. package/dist/resolver/index.d.ts.map +1 -0
  80. package/dist/resolver/index.js +9 -0
  81. package/dist/resolver/index.js.map +1 -0
  82. package/dist/resolver/response-resolver.d.ts +73 -0
  83. package/dist/resolver/response-resolver.d.ts.map +1 -0
  84. package/dist/resolver/response-resolver.js +167 -0
  85. package/dist/resolver/response-resolver.js.map +1 -0
  86. package/dist/resolver/types.d.ts +47 -0
  87. package/dist/resolver/types.d.ts.map +1 -0
  88. package/dist/resolver/types.js +9 -0
  89. package/dist/resolver/types.js.map +1 -0
  90. package/dist/schemas/__tests__/config.validator.test.d.ts +2 -0
  91. package/dist/schemas/__tests__/config.validator.test.d.ts.map +1 -0
  92. package/dist/schemas/__tests__/config.validator.test.js +66 -0
  93. package/dist/schemas/__tests__/config.validator.test.js.map +1 -0
  94. package/dist/schemas/__tests__/endpoint.schema.test.d.ts +2 -0
  95. package/dist/schemas/__tests__/endpoint.schema.test.d.ts.map +1 -0
  96. package/dist/schemas/__tests__/endpoint.schema.test.js +103 -0
  97. package/dist/schemas/__tests__/endpoint.schema.test.js.map +1 -0
  98. package/dist/schemas/__tests__/flow.schema.test.d.ts +2 -0
  99. package/dist/schemas/__tests__/flow.schema.test.d.ts.map +1 -0
  100. package/dist/schemas/__tests__/flow.schema.test.js +92 -0
  101. package/dist/schemas/__tests__/flow.schema.test.js.map +1 -0
  102. package/dist/schemas/config.validator.d.ts +39 -0
  103. package/dist/schemas/config.validator.d.ts.map +1 -0
  104. package/dist/schemas/config.validator.js +117 -0
  105. package/dist/schemas/config.validator.js.map +1 -0
  106. package/dist/schemas/endpoint.schema.d.ts +108 -0
  107. package/dist/schemas/endpoint.schema.d.ts.map +1 -0
  108. package/dist/schemas/endpoint.schema.js +87 -0
  109. package/dist/schemas/endpoint.schema.js.map +1 -0
  110. package/dist/schemas/flow.schema.d.ts +46 -0
  111. package/dist/schemas/flow.schema.d.ts.map +1 -0
  112. package/dist/schemas/flow.schema.js +73 -0
  113. package/dist/schemas/flow.schema.js.map +1 -0
  114. package/dist/schemas/http.schema.d.ts +15 -0
  115. package/dist/schemas/http.schema.d.ts.map +1 -0
  116. package/dist/schemas/http.schema.js +32 -0
  117. package/dist/schemas/http.schema.js.map +1 -0
  118. package/dist/schemas/index.d.ts +6 -0
  119. package/dist/schemas/index.d.ts.map +1 -0
  120. package/dist/schemas/index.js +33 -0
  121. package/dist/schemas/index.js.map +1 -0
  122. package/dist/schemas/scenario.schema.d.ts +54 -0
  123. package/dist/schemas/scenario.schema.d.ts.map +1 -0
  124. package/dist/schemas/scenario.schema.js +75 -0
  125. package/dist/schemas/scenario.schema.js.map +1 -0
  126. package/dist/server/__tests__/mock-server-app.test.d.ts +2 -0
  127. package/dist/server/__tests__/mock-server-app.test.d.ts.map +1 -0
  128. package/dist/server/__tests__/mock-server-app.test.js +296 -0
  129. package/dist/server/__tests__/mock-server-app.test.js.map +1 -0
  130. package/dist/server/index.d.ts +4 -0
  131. package/dist/server/index.d.ts.map +1 -0
  132. package/dist/server/index.js +10 -0
  133. package/dist/server/index.js.map +1 -0
  134. package/dist/server/mock-server-app.d.ts +119 -0
  135. package/dist/server/mock-server-app.d.ts.map +1 -0
  136. package/dist/server/mock-server-app.js +304 -0
  137. package/dist/server/mock-server-app.js.map +1 -0
  138. package/dist/server/types.d.ts +38 -0
  139. package/dist/server/types.d.ts.map +1 -0
  140. package/dist/server/types.js +11 -0
  141. package/dist/server/types.js.map +1 -0
  142. package/dist/state/__tests__/state-manager.test.d.ts +2 -0
  143. package/dist/state/__tests__/state-manager.test.d.ts.map +1 -0
  144. package/dist/state/__tests__/state-manager.test.js +275 -0
  145. package/dist/state/__tests__/state-manager.test.js.map +1 -0
  146. package/dist/state/index.d.ts +3 -0
  147. package/dist/state/index.d.ts.map +1 -0
  148. package/dist/state/index.js +7 -0
  149. package/dist/state/index.js.map +1 -0
  150. package/dist/state/state-manager.d.ts +92 -0
  151. package/dist/state/state-manager.d.ts.map +1 -0
  152. package/dist/state/state-manager.js +198 -0
  153. package/dist/state/state-manager.js.map +1 -0
  154. package/dist/state/types.d.ts +30 -0
  155. package/dist/state/types.d.ts.map +1 -0
  156. package/dist/state/types.js +2 -0
  157. package/dist/state/types.js.map +1 -0
  158. package/dist/ui/assets/index-SADMOgPE.js +10 -0
  159. package/dist/ui/assets/index-rj7m-XdG.css +1 -0
  160. package/dist/ui/index.html +29 -0
  161. package/dist/watcher/__tests__/config-watcher.test.d.ts +2 -0
  162. package/dist/watcher/__tests__/config-watcher.test.d.ts.map +1 -0
  163. package/dist/watcher/__tests__/config-watcher.test.js +372 -0
  164. package/dist/watcher/__tests__/config-watcher.test.js.map +1 -0
  165. package/dist/watcher/config-watcher.d.ts +100 -0
  166. package/dist/watcher/config-watcher.d.ts.map +1 -0
  167. package/dist/watcher/config-watcher.js +358 -0
  168. package/dist/watcher/config-watcher.js.map +1 -0
  169. package/dist/watcher/index.d.ts +7 -0
  170. package/dist/watcher/index.d.ts.map +1 -0
  171. package/dist/watcher/index.js +8 -0
  172. package/dist/watcher/index.js.map +1 -0
  173. package/dist/watcher/types.d.ts +64 -0
  174. package/dist/watcher/types.d.ts.map +1 -0
  175. package/dist/watcher/types.js +15 -0
  176. package/dist/watcher/types.js.map +1 -0
  177. package/package.json +58 -0
@@ -0,0 +1,304 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MockServerApp = exports.ADMIN_UI_PATH = void 0;
7
+ exports.createMockServerApp = createMockServerApp;
8
+ const express_1 = __importDefault(require("express"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const index_js_1 = require("../state/index.js");
11
+ const index_js_2 = require("../resolver/index.js");
12
+ const index_js_3 = require("../admin/index.js");
13
+ const types_js_1 = require("./types.js");
14
+ // UI path constant
15
+ exports.ADMIN_UI_PATH = '/mock-admin';
16
+ /**
17
+ * Mock server that serves configured endpoints
18
+ */
19
+ class MockServerApp {
20
+ constructor(options = {}) {
21
+ this.server = null;
22
+ this.registeredRoutes = [];
23
+ this.endpoints = [];
24
+ this.flows = [];
25
+ this.options = { ...types_js_1.DEFAULT_SERVER_OPTIONS, ...options };
26
+ this.app = (0, express_1.default)();
27
+ this.stateManager = (0, index_js_1.createStateManager)();
28
+ this.resolver = (0, index_js_2.createResponseResolver)(this.stateManager);
29
+ this.mockRouter = express_1.default.Router();
30
+ this.setupMiddleware();
31
+ this.mountAdminRouter();
32
+ this.mountAdminUI();
33
+ this.mountMockRouter();
34
+ }
35
+ /**
36
+ * Setup Express middleware
37
+ */
38
+ setupMiddleware() {
39
+ // Parse JSON bodies
40
+ this.app.use(express_1.default.json());
41
+ // Parse URL-encoded bodies
42
+ this.app.use(express_1.default.urlencoded({ extended: true }));
43
+ }
44
+ /**
45
+ * Mount the admin API router
46
+ */
47
+ mountAdminRouter() {
48
+ const adminRouter = (0, index_js_3.createAdminRouter)({
49
+ getEndpoints: () => this.endpoints,
50
+ getFlows: () => this.flows,
51
+ stateManager: this.stateManager,
52
+ getConfigWriter: () => this.configWriter,
53
+ getOnConfigChange: () => this.onConfigChange,
54
+ });
55
+ this.app.use(index_js_3.ADMIN_API_PATH, adminRouter);
56
+ }
57
+ /**
58
+ * Mount the admin UI static files
59
+ * Serves the built React app at /mock-admin
60
+ */
61
+ mountAdminUI() {
62
+ // Get the directory where this module is located
63
+ const currentDir = __dirname;
64
+ // UI is built to dist/ui relative to package root (2 levels up from src/server)
65
+ const uiDistPath = path_1.default.resolve(currentDir, '../../dist/ui');
66
+ // Serve static files
67
+ this.app.use(exports.ADMIN_UI_PATH, express_1.default.static(uiDistPath));
68
+ // SPA fallback: serve index.html for any non-file requests under /mock-admin
69
+ this.app.get(`${exports.ADMIN_UI_PATH}/*`, (req, res, next) => {
70
+ // Skip API routes
71
+ if (req.path.startsWith(`${exports.ADMIN_UI_PATH}/api`)) {
72
+ return next();
73
+ }
74
+ res.sendFile(path_1.default.join(uiDistPath, 'index.html'), (err) => {
75
+ if (err) {
76
+ // If UI is not built, return helpful message
77
+ res.status(404).send(`
78
+ <html>
79
+ <body style="font-family: sans-serif; padding: 40px;">
80
+ <h1>Admin UI not available</h1>
81
+ <p>The admin UI has not been built yet.</p>
82
+ <p>Run <code>npm run build:ui</code> to build the admin interface.</p>
83
+ <p>You can still use the <a href="${index_js_3.ADMIN_API_PATH}/config">Admin API</a> directly.</p>
84
+ </body>
85
+ </html>
86
+ `);
87
+ }
88
+ });
89
+ });
90
+ }
91
+ /**
92
+ * Mount the mock router at the configured prefix
93
+ */
94
+ mountMockRouter() {
95
+ this.app.use(this.options.apiPrefix, this.mockRouter);
96
+ }
97
+ /**
98
+ * Get the Express app instance
99
+ */
100
+ getApp() {
101
+ return this.app;
102
+ }
103
+ /**
104
+ * Get the state manager
105
+ */
106
+ getStateManager() {
107
+ return this.stateManager;
108
+ }
109
+ /**
110
+ * Get the response resolver
111
+ */
112
+ getResolver() {
113
+ return this.resolver;
114
+ }
115
+ /**
116
+ * Get server options
117
+ */
118
+ getOptions() {
119
+ return { ...this.options };
120
+ }
121
+ /**
122
+ * Get registered routes
123
+ */
124
+ getRegisteredRoutes() {
125
+ return [...this.registeredRoutes];
126
+ }
127
+ /**
128
+ * Set the config writer for endpoint/flow management
129
+ */
130
+ setConfigWriter(configWriter, onConfigChange) {
131
+ this.configWriter = configWriter;
132
+ this.onConfigChange = onConfigChange;
133
+ }
134
+ /**
135
+ * Get current server state
136
+ */
137
+ getState() {
138
+ return {
139
+ running: this.server !== null && this.server.listening,
140
+ port: this.server?.listening ? this.options.port : null,
141
+ endpointCount: this.endpoints.length,
142
+ flowCount: this.flows.length,
143
+ };
144
+ }
145
+ /**
146
+ * Register endpoints and flows
147
+ */
148
+ registerConfig(endpoints, flows) {
149
+ this.endpoints = endpoints;
150
+ this.flows = flows;
151
+ // Update state manager
152
+ this.stateManager.setEndpoints(endpoints);
153
+ this.stateManager.setFlows(flows);
154
+ // Update resolver
155
+ this.resolver.setEndpoints(endpoints);
156
+ // Register routes
157
+ this.registerRoutes(endpoints);
158
+ }
159
+ /**
160
+ * Register routes for all endpoints
161
+ */
162
+ registerRoutes(endpoints) {
163
+ // Clear existing routes by creating a new router
164
+ this.mockRouter = express_1.default.Router();
165
+ this.registeredRoutes = [];
166
+ // Re-mount the router
167
+ // Note: Express doesn't support unmounting, so we need to replace the handler
168
+ this.app._router = undefined;
169
+ this.setupMiddleware();
170
+ this.mountAdminRouter();
171
+ this.mountAdminUI();
172
+ this.app.use(this.options.apiPrefix, this.mockRouter);
173
+ // Register each endpoint
174
+ for (const endpoint of endpoints) {
175
+ this.registerEndpoint(endpoint);
176
+ }
177
+ }
178
+ /**
179
+ * Register a single endpoint
180
+ */
181
+ registerEndpoint(endpoint) {
182
+ const method = endpoint.method.toLowerCase();
183
+ const handler = this.createEndpointHandler(endpoint);
184
+ // Register with Express router
185
+ this.mockRouter[method](endpoint.path, handler);
186
+ // Track registered route
187
+ this.registeredRoutes.push({
188
+ method: endpoint.method,
189
+ path: endpoint.path,
190
+ fullPath: `${this.options.apiPrefix}${endpoint.path}`,
191
+ endpointId: endpoint.id,
192
+ });
193
+ }
194
+ /**
195
+ * Create request handler for an endpoint
196
+ */
197
+ createEndpointHandler(endpoint) {
198
+ return async (req, res, next) => {
199
+ try {
200
+ const handled = await this.resolver.handleRequest(endpoint.id, req, res);
201
+ if (!handled) {
202
+ // This shouldn't happen since we're routing to a known endpoint
203
+ res.status(500).json({ error: 'Failed to resolve response' });
204
+ }
205
+ }
206
+ catch (error) {
207
+ next(error);
208
+ }
209
+ };
210
+ }
211
+ /**
212
+ * Add custom middleware to the Express app
213
+ */
214
+ use(...args) {
215
+ return this.app.use(...args);
216
+ }
217
+ /**
218
+ * Start the server
219
+ */
220
+ async start(port) {
221
+ const listenPort = port ?? this.options.port;
222
+ return new Promise((resolve, reject) => {
223
+ try {
224
+ this.server = this.app.listen(listenPort, () => {
225
+ // Get actual port (important when port 0 is used)
226
+ const address = this.server?.address();
227
+ const actualPort = typeof address === 'object' && address !== null
228
+ ? address.port
229
+ : listenPort;
230
+ this.options.port = actualPort;
231
+ resolve(actualPort);
232
+ });
233
+ this.server.on('error', (error) => {
234
+ reject(error);
235
+ });
236
+ }
237
+ catch (error) {
238
+ reject(error);
239
+ }
240
+ });
241
+ }
242
+ /**
243
+ * Start the server with a callback
244
+ */
245
+ startWithCallback(callback, port) {
246
+ const listenPort = port ?? this.options.port;
247
+ this.server = this.app.listen(listenPort, () => {
248
+ // Get actual port (important when port 0 is used)
249
+ const address = this.server?.address();
250
+ const actualPort = typeof address === 'object' && address !== null
251
+ ? address.port
252
+ : listenPort;
253
+ this.options.port = actualPort;
254
+ callback(actualPort);
255
+ });
256
+ }
257
+ /**
258
+ * Stop the server
259
+ */
260
+ async stop() {
261
+ return new Promise((resolve, reject) => {
262
+ if (!this.server) {
263
+ resolve();
264
+ return;
265
+ }
266
+ this.server.close((error) => {
267
+ if (error) {
268
+ reject(error);
269
+ }
270
+ else {
271
+ this.server = null;
272
+ resolve();
273
+ }
274
+ });
275
+ });
276
+ }
277
+ /**
278
+ * Check if server is running
279
+ */
280
+ isRunning() {
281
+ return this.server !== null && this.server.listening;
282
+ }
283
+ /**
284
+ * Get the HTTP server instance
285
+ */
286
+ getHttpServer() {
287
+ return this.server;
288
+ }
289
+ /**
290
+ * Reload configuration (for hot reload support)
291
+ */
292
+ reloadConfig(endpoints, flows) {
293
+ // Reset state before reloading
294
+ this.stateManager.reset();
295
+ this.registerConfig(endpoints, flows);
296
+ }
297
+ }
298
+ exports.MockServerApp = MockServerApp;
299
+ /**
300
+ * Create a new MockServerApp instance
301
+ */
302
+ function createMockServerApp(options = {}) {
303
+ return new MockServerApp(options);
304
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-server-app.js","sourceRoot":"","sources":["../../src/server/mock-server-app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Server configuration options
3
+ */
4
+ export interface ServerOptions {
5
+ /** Port to run the server on (default: 3001) */
6
+ port: number;
7
+ /** API prefix for mock endpoints (default: '/api') */
8
+ apiPrefix: string;
9
+ /** Enable hot reload (default: true) */
10
+ hotReload: boolean;
11
+ }
12
+ /**
13
+ * Default server options
14
+ */
15
+ export declare const DEFAULT_SERVER_OPTIONS: ServerOptions;
16
+ /**
17
+ * Server state
18
+ */
19
+ export interface ServerState {
20
+ /** Whether the server is currently running */
21
+ running: boolean;
22
+ /** The port the server is listening on */
23
+ port: number | null;
24
+ /** Number of registered endpoints */
25
+ endpointCount: number;
26
+ /** Number of registered flows */
27
+ flowCount: number;
28
+ }
29
+ /**
30
+ * Route registration info
31
+ */
32
+ export interface RegisteredRoute {
33
+ method: string;
34
+ path: string;
35
+ fullPath: string;
36
+ endpointId: string;
37
+ }
38
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,aAIpC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_SERVER_OPTIONS = void 0;
4
+ /**
5
+ * Default server options
6
+ */
7
+ exports.DEFAULT_SERVER_OPTIONS = {
8
+ port: 3001,
9
+ apiPrefix: '/api',
10
+ hotReload: true,
11
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/server/types.ts"],"names":[],"mappings":";;;AAgBA;;GAEG;AACU,QAAA,sBAAsB,GAAkB;IACnD,IAAI,EAAE,IAAI;IACV,SAAS,EAAE,MAAM;IACjB,SAAS,EAAE,IAAI;CAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state-manager.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-manager.test.d.ts","sourceRoot":"","sources":["../../../src/state/__tests__/state-manager.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const state_manager_js_1 = require("../state-manager.js");
5
+ // Test fixtures
6
+ const mockEndpoints = [
7
+ {
8
+ id: 'get-users',
9
+ path: '/users',
10
+ method: 'GET',
11
+ scenarios: [
12
+ { id: 'success', name: 'Success', status: 200, body: [] },
13
+ { id: 'error', name: 'Error', status: 500, body: { error: 'Failed' } },
14
+ { id: 'empty', name: 'Empty', status: 200, body: [] },
15
+ ],
16
+ defaultScenarioId: 'success',
17
+ },
18
+ {
19
+ id: 'get-products',
20
+ path: '/products',
21
+ method: 'GET',
22
+ scenarios: [
23
+ { id: 'list', name: 'Product List', status: 200, body: [] },
24
+ { id: 'not-found', name: 'Not Found', status: 404, body: null },
25
+ ],
26
+ defaultScenarioId: 'list',
27
+ },
28
+ ];
29
+ const mockFlows = [
30
+ {
31
+ id: 'admin-flow',
32
+ name: 'Admin Flow',
33
+ endpointScenarios: {
34
+ 'get-users': 'success',
35
+ 'get-products': 'list',
36
+ },
37
+ },
38
+ {
39
+ id: 'error-flow',
40
+ name: 'Error Flow',
41
+ endpointScenarios: {
42
+ 'get-users': 'error',
43
+ },
44
+ },
45
+ ];
46
+ (0, vitest_1.describe)('StateManager', () => {
47
+ let stateManager;
48
+ (0, vitest_1.beforeEach)(() => {
49
+ stateManager = new state_manager_js_1.StateManager();
50
+ stateManager.setEndpoints(mockEndpoints);
51
+ stateManager.setFlows(mockFlows);
52
+ });
53
+ (0, vitest_1.describe)('getState', () => {
54
+ (0, vitest_1.it)('should return initial state', () => {
55
+ const state = stateManager.getState();
56
+ (0, vitest_1.expect)(state.activeFlowId).toBeNull();
57
+ (0, vitest_1.expect)(state.activeScenarios).toEqual({});
58
+ });
59
+ (0, vitest_1.it)('should return state with active flow', () => {
60
+ stateManager.activateFlow('admin-flow');
61
+ const state = stateManager.getState();
62
+ (0, vitest_1.expect)(state.activeFlowId).toBe('admin-flow');
63
+ });
64
+ (0, vitest_1.it)('should return state with active scenarios', () => {
65
+ stateManager.activateScenario('get-users', 'error');
66
+ const state = stateManager.getState();
67
+ (0, vitest_1.expect)(state.activeScenarios).toEqual({ 'get-users': 'error' });
68
+ });
69
+ });
70
+ (0, vitest_1.describe)('activateScenario', () => {
71
+ (0, vitest_1.it)('should activate a valid scenario', () => {
72
+ stateManager.activateScenario('get-users', 'error');
73
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBe('error');
74
+ });
75
+ (0, vitest_1.it)('should throw for non-existent endpoint', () => {
76
+ (0, vitest_1.expect)(() => {
77
+ stateManager.activateScenario('non-existent', 'success');
78
+ }).toThrow('Endpoint "non-existent" not found');
79
+ });
80
+ (0, vitest_1.it)('should throw for non-existent scenario', () => {
81
+ (0, vitest_1.expect)(() => {
82
+ stateManager.activateScenario('get-users', 'non-existent');
83
+ }).toThrow('Scenario "non-existent" not found');
84
+ });
85
+ (0, vitest_1.it)('should include available scenarios in error message', () => {
86
+ (0, vitest_1.expect)(() => {
87
+ stateManager.activateScenario('get-users', 'non-existent');
88
+ }).toThrow('Available: success, error, empty');
89
+ });
90
+ });
91
+ (0, vitest_1.describe)('clearScenario', () => {
92
+ (0, vitest_1.it)('should clear an active scenario', () => {
93
+ stateManager.activateScenario('get-users', 'error');
94
+ stateManager.clearScenario('get-users');
95
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBeUndefined();
96
+ });
97
+ (0, vitest_1.it)('should be safe to call on non-active scenario', () => {
98
+ (0, vitest_1.expect)(() => {
99
+ stateManager.clearScenario('get-users');
100
+ }).not.toThrow();
101
+ });
102
+ });
103
+ (0, vitest_1.describe)('activateFlow', () => {
104
+ (0, vitest_1.it)('should activate a valid flow', () => {
105
+ stateManager.activateFlow('admin-flow');
106
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBe('admin-flow');
107
+ });
108
+ (0, vitest_1.it)('should return flow config', () => {
109
+ stateManager.activateFlow('admin-flow');
110
+ const flow = stateManager.getActiveFlow();
111
+ (0, vitest_1.expect)(flow?.id).toBe('admin-flow');
112
+ (0, vitest_1.expect)(flow?.name).toBe('Admin Flow');
113
+ });
114
+ (0, vitest_1.it)('should throw for non-existent flow', () => {
115
+ (0, vitest_1.expect)(() => {
116
+ stateManager.activateFlow('non-existent');
117
+ }).toThrow('Flow "non-existent" not found');
118
+ });
119
+ (0, vitest_1.it)('should replace previously active flow', () => {
120
+ stateManager.activateFlow('admin-flow');
121
+ stateManager.activateFlow('error-flow');
122
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBe('error-flow');
123
+ });
124
+ });
125
+ (0, vitest_1.describe)('deactivateFlow', () => {
126
+ (0, vitest_1.it)('should deactivate the active flow', () => {
127
+ stateManager.activateFlow('admin-flow');
128
+ stateManager.deactivateFlow();
129
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBeNull();
130
+ (0, vitest_1.expect)(stateManager.getActiveFlow()).toBeNull();
131
+ });
132
+ (0, vitest_1.it)('should be safe to call when no flow is active', () => {
133
+ (0, vitest_1.expect)(() => {
134
+ stateManager.deactivateFlow();
135
+ }).not.toThrow();
136
+ });
137
+ });
138
+ (0, vitest_1.describe)('resolveScenarioId', () => {
139
+ (0, vitest_1.it)('should return default scenario when nothing is active', () => {
140
+ const scenarioId = stateManager.resolveScenarioId('get-users');
141
+ (0, vitest_1.expect)(scenarioId).toBe('success');
142
+ });
143
+ (0, vitest_1.it)('should return explicit scenario over default', () => {
144
+ stateManager.activateScenario('get-users', 'error');
145
+ const scenarioId = stateManager.resolveScenarioId('get-users');
146
+ (0, vitest_1.expect)(scenarioId).toBe('error');
147
+ });
148
+ (0, vitest_1.it)('should return flow scenario over explicit and default', () => {
149
+ stateManager.activateScenario('get-users', 'empty');
150
+ stateManager.activateFlow('error-flow');
151
+ const scenarioId = stateManager.resolveScenarioId('get-users');
152
+ // Flow takes priority
153
+ (0, vitest_1.expect)(scenarioId).toBe('error');
154
+ });
155
+ (0, vitest_1.it)('should fall back to explicit when flow does not define endpoint', () => {
156
+ stateManager.activateScenario('get-products', 'not-found');
157
+ stateManager.activateFlow('error-flow'); // error-flow doesn't define get-products
158
+ const scenarioId = stateManager.resolveScenarioId('get-products');
159
+ (0, vitest_1.expect)(scenarioId).toBe('not-found');
160
+ });
161
+ (0, vitest_1.it)('should fall back to default when flow does not define endpoint and no explicit', () => {
162
+ stateManager.activateFlow('error-flow'); // error-flow doesn't define get-products
163
+ const scenarioId = stateManager.resolveScenarioId('get-products');
164
+ (0, vitest_1.expect)(scenarioId).toBe('list'); // default
165
+ });
166
+ (0, vitest_1.it)('should return null for non-existent endpoint', () => {
167
+ const scenarioId = stateManager.resolveScenarioId('non-existent');
168
+ (0, vitest_1.expect)(scenarioId).toBeNull();
169
+ });
170
+ });
171
+ (0, vitest_1.describe)('resolveScenario', () => {
172
+ (0, vitest_1.it)('should return full scenario config', () => {
173
+ const scenario = stateManager.resolveScenario('get-users');
174
+ (0, vitest_1.expect)(scenario).toBeDefined();
175
+ (0, vitest_1.expect)(scenario?.id).toBe('success');
176
+ (0, vitest_1.expect)(scenario?.status).toBe(200);
177
+ });
178
+ (0, vitest_1.it)('should return null for non-existent endpoint', () => {
179
+ const scenario = stateManager.resolveScenario('non-existent');
180
+ (0, vitest_1.expect)(scenario).toBeNull();
181
+ });
182
+ });
183
+ (0, vitest_1.describe)('reset', () => {
184
+ (0, vitest_1.it)('should clear active flow', () => {
185
+ stateManager.activateFlow('admin-flow');
186
+ stateManager.reset();
187
+ (0, vitest_1.expect)(stateManager.getActiveFlowId()).toBeNull();
188
+ });
189
+ (0, vitest_1.it)('should clear all active scenarios', () => {
190
+ stateManager.activateScenario('get-users', 'error');
191
+ stateManager.activateScenario('get-products', 'not-found');
192
+ stateManager.reset();
193
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-users')).toBeUndefined();
194
+ (0, vitest_1.expect)(stateManager.getActiveScenarioId('get-products')).toBeUndefined();
195
+ });
196
+ (0, vitest_1.it)('should reset to default scenarios', () => {
197
+ stateManager.activateScenario('get-users', 'error');
198
+ stateManager.activateFlow('admin-flow');
199
+ stateManager.reset();
200
+ (0, vitest_1.expect)(stateManager.resolveScenarioId('get-users')).toBe('success');
201
+ });
202
+ });
203
+ (0, vitest_1.describe)('state change listeners', () => {
204
+ (0, vitest_1.it)('should notify on scenario activation', () => {
205
+ const listener = vitest_1.vi.fn();
206
+ stateManager.addListener(listener);
207
+ stateManager.activateScenario('get-users', 'error');
208
+ (0, vitest_1.expect)(listener).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
209
+ type: 'scenario-activated',
210
+ details: { endpointId: 'get-users', scenarioId: 'error' },
211
+ }));
212
+ });
213
+ (0, vitest_1.it)('should notify on flow activation', () => {
214
+ const listener = vitest_1.vi.fn();
215
+ stateManager.addListener(listener);
216
+ stateManager.activateFlow('admin-flow');
217
+ (0, vitest_1.expect)(listener).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
218
+ type: 'flow-activated',
219
+ details: { flowId: 'admin-flow' },
220
+ }));
221
+ });
222
+ (0, vitest_1.it)('should notify on flow deactivation', () => {
223
+ const listener = vitest_1.vi.fn();
224
+ stateManager.activateFlow('admin-flow');
225
+ stateManager.addListener(listener);
226
+ stateManager.deactivateFlow();
227
+ (0, vitest_1.expect)(listener).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
228
+ type: 'flow-deactivated',
229
+ details: { flowId: 'admin-flow' },
230
+ }));
231
+ });
232
+ (0, vitest_1.it)('should notify on reset', () => {
233
+ const listener = vitest_1.vi.fn();
234
+ stateManager.addListener(listener);
235
+ stateManager.reset();
236
+ (0, vitest_1.expect)(listener).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
237
+ type: 'reset',
238
+ }));
239
+ });
240
+ (0, vitest_1.it)('should remove listener', () => {
241
+ const listener = vitest_1.vi.fn();
242
+ stateManager.addListener(listener);
243
+ stateManager.removeListener(listener);
244
+ stateManager.activateFlow('admin-flow');
245
+ (0, vitest_1.expect)(listener).not.toHaveBeenCalled();
246
+ });
247
+ (0, vitest_1.it)('should include timestamp in events', () => {
248
+ const listener = vitest_1.vi.fn();
249
+ stateManager.addListener(listener);
250
+ const before = Date.now();
251
+ stateManager.reset();
252
+ const after = Date.now();
253
+ const event = listener.mock.calls[0][0];
254
+ (0, vitest_1.expect)(event.timestamp).toBeGreaterThanOrEqual(before);
255
+ (0, vitest_1.expect)(event.timestamp).toBeLessThanOrEqual(after);
256
+ });
257
+ (0, vitest_1.it)('should continue notifying other listeners if one throws', () => {
258
+ const badListener = vitest_1.vi.fn(() => {
259
+ throw new Error('Listener error');
260
+ });
261
+ const goodListener = vitest_1.vi.fn();
262
+ stateManager.addListener(badListener);
263
+ stateManager.addListener(goodListener);
264
+ // Should not throw
265
+ (0, vitest_1.expect)(() => stateManager.reset()).not.toThrow();
266
+ (0, vitest_1.expect)(goodListener).toHaveBeenCalled();
267
+ });
268
+ });
269
+ });
270
+ (0, vitest_1.describe)('createStateManager', () => {
271
+ (0, vitest_1.it)('should create a StateManager instance', () => {
272
+ const manager = (0, state_manager_js_1.createStateManager)();
273
+ (0, vitest_1.expect)(manager).toBeInstanceOf(state_manager_js_1.StateManager);
274
+ });
275
+ });