@engjts/nexus 0.1.8 → 0.1.9

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 (205) hide show
  1. package/package.json +1 -1
  2. package/BENCHMARK_REPORT.md +0 -343
  3. package/documentation/01-getting-started.md +0 -240
  4. package/documentation/02-context.md +0 -335
  5. package/documentation/03-routing.md +0 -397
  6. package/documentation/04-middleware.md +0 -483
  7. package/documentation/05-validation.md +0 -514
  8. package/documentation/06-error-handling.md +0 -465
  9. package/documentation/07-performance.md +0 -364
  10. package/documentation/08-adapters.md +0 -470
  11. package/documentation/09-api-reference.md +0 -548
  12. package/documentation/10-examples.md +0 -582
  13. package/documentation/11-deployment.md +0 -477
  14. package/documentation/12-sentry.md +0 -620
  15. package/documentation/13-sentry-data-storage.md +0 -996
  16. package/documentation/14-sentry-data-reference.md +0 -457
  17. package/documentation/15-sentry-summary.md +0 -409
  18. package/documentation/16-alerts-system.md +0 -745
  19. package/documentation/17-alert-adapters.md +0 -696
  20. package/documentation/18-alerts-implementation-summary.md +0 -385
  21. package/documentation/19-class-based-routing.md +0 -840
  22. package/documentation/20-websocket-realtime.md +0 -813
  23. package/documentation/21-cache-system.md +0 -510
  24. package/documentation/22-job-queue.md +0 -772
  25. package/documentation/23-sentry-plugin.md +0 -551
  26. package/documentation/24-testing-utilities.md +0 -1287
  27. package/documentation/25-api-versioning.md +0 -533
  28. package/documentation/26-context-store.md +0 -607
  29. package/documentation/27-dependency-injection.md +0 -329
  30. package/documentation/28-lifecycle-hooks.md +0 -521
  31. package/documentation/29-package-structure.md +0 -196
  32. package/documentation/30-plugin-system.md +0 -414
  33. package/documentation/31-jwt-authentication.md +0 -597
  34. package/documentation/32-cli.md +0 -268
  35. package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
  36. package/documentation/ALERTS-INDEX.md +0 -330
  37. package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
  38. package/documentation/README.md +0 -178
  39. package/documentation/index.html +0 -34
  40. package/modern_framework_paper.md +0 -1870
  41. package/public/css/style.css +0 -87
  42. package/public/index.html +0 -34
  43. package/public/js/app.js +0 -27
  44. package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
  45. package/src/advanced/cache/MultiTierCache.ts +0 -194
  46. package/src/advanced/cache/RedisCacheStore.ts +0 -341
  47. package/src/advanced/cache/index.ts +0 -5
  48. package/src/advanced/cache/types.ts +0 -40
  49. package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
  50. package/src/advanced/graphql/index.ts +0 -22
  51. package/src/advanced/graphql/server.ts +0 -252
  52. package/src/advanced/graphql/types.ts +0 -42
  53. package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
  54. package/src/advanced/jobs/JobQueue.ts +0 -556
  55. package/src/advanced/jobs/RedisQueueStore.ts +0 -367
  56. package/src/advanced/jobs/index.ts +0 -5
  57. package/src/advanced/jobs/types.ts +0 -70
  58. package/src/advanced/observability/APMManager.ts +0 -163
  59. package/src/advanced/observability/AlertManager.ts +0 -109
  60. package/src/advanced/observability/MetricRegistry.ts +0 -151
  61. package/src/advanced/observability/ObservabilityCenter.ts +0 -304
  62. package/src/advanced/observability/StructuredLogger.ts +0 -154
  63. package/src/advanced/observability/TracingManager.ts +0 -117
  64. package/src/advanced/observability/adapters.ts +0 -304
  65. package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
  66. package/src/advanced/observability/index.ts +0 -11
  67. package/src/advanced/observability/types.ts +0 -174
  68. package/src/advanced/playground/extractPathParams.ts +0 -6
  69. package/src/advanced/playground/generateFieldExample.ts +0 -31
  70. package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1956
  71. package/src/advanced/playground/generateSummary.ts +0 -19
  72. package/src/advanced/playground/getTagFromPath.ts +0 -9
  73. package/src/advanced/playground/index.ts +0 -8
  74. package/src/advanced/playground/playground.ts +0 -250
  75. package/src/advanced/playground/types.ts +0 -49
  76. package/src/advanced/playground/zodToExample.ts +0 -16
  77. package/src/advanced/playground/zodToParams.ts +0 -15
  78. package/src/advanced/postman/buildAuth.ts +0 -31
  79. package/src/advanced/postman/buildBody.ts +0 -15
  80. package/src/advanced/postman/buildQueryParams.ts +0 -27
  81. package/src/advanced/postman/buildRequestItem.ts +0 -36
  82. package/src/advanced/postman/buildResponses.ts +0 -11
  83. package/src/advanced/postman/buildUrl.ts +0 -33
  84. package/src/advanced/postman/capitalize.ts +0 -4
  85. package/src/advanced/postman/generateCollection.ts +0 -59
  86. package/src/advanced/postman/generateEnvironment.ts +0 -34
  87. package/src/advanced/postman/generateExampleFromZod.ts +0 -21
  88. package/src/advanced/postman/generateFieldExample.ts +0 -45
  89. package/src/advanced/postman/generateName.ts +0 -20
  90. package/src/advanced/postman/generateUUID.ts +0 -11
  91. package/src/advanced/postman/getTagFromPath.ts +0 -10
  92. package/src/advanced/postman/index.ts +0 -28
  93. package/src/advanced/postman/postman.ts +0 -156
  94. package/src/advanced/postman/slugify.ts +0 -7
  95. package/src/advanced/postman/types.ts +0 -140
  96. package/src/advanced/realtime/index.ts +0 -18
  97. package/src/advanced/realtime/websocket.ts +0 -231
  98. package/src/advanced/sentry/index.ts +0 -1236
  99. package/src/advanced/sentry/types.ts +0 -355
  100. package/src/advanced/static/generateDirectoryListing.ts +0 -47
  101. package/src/advanced/static/generateETag.ts +0 -7
  102. package/src/advanced/static/getMimeType.ts +0 -9
  103. package/src/advanced/static/index.ts +0 -32
  104. package/src/advanced/static/isSafePath.ts +0 -13
  105. package/src/advanced/static/publicDir.ts +0 -21
  106. package/src/advanced/static/serveStatic.ts +0 -225
  107. package/src/advanced/static/spa.ts +0 -24
  108. package/src/advanced/static/types.ts +0 -159
  109. package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
  110. package/src/advanced/swagger/buildOperation.ts +0 -61
  111. package/src/advanced/swagger/buildParameters.ts +0 -61
  112. package/src/advanced/swagger/buildRequestBody.ts +0 -21
  113. package/src/advanced/swagger/buildResponses.ts +0 -54
  114. package/src/advanced/swagger/capitalize.ts +0 -5
  115. package/src/advanced/swagger/convertPath.ts +0 -9
  116. package/src/advanced/swagger/createSwagger.ts +0 -12
  117. package/src/advanced/swagger/generateOperationId.ts +0 -21
  118. package/src/advanced/swagger/generateSpec.ts +0 -105
  119. package/src/advanced/swagger/generateSummary.ts +0 -24
  120. package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
  121. package/src/advanced/swagger/generateThemeCss.ts +0 -53
  122. package/src/advanced/swagger/index.ts +0 -25
  123. package/src/advanced/swagger/swagger.ts +0 -237
  124. package/src/advanced/swagger/types.ts +0 -206
  125. package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
  126. package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
  127. package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
  128. package/src/advanced/testing/factory.ts +0 -509
  129. package/src/advanced/testing/harness.ts +0 -612
  130. package/src/advanced/testing/index.ts +0 -430
  131. package/src/advanced/testing/load-test.ts +0 -618
  132. package/src/advanced/testing/mock-server.ts +0 -498
  133. package/src/advanced/testing/mock.ts +0 -670
  134. package/src/cli/bin.ts +0 -9
  135. package/src/cli/cli.ts +0 -158
  136. package/src/cli/commands/add.ts +0 -178
  137. package/src/cli/commands/build.ts +0 -73
  138. package/src/cli/commands/create.ts +0 -166
  139. package/src/cli/commands/dev.ts +0 -85
  140. package/src/cli/commands/generate.ts +0 -99
  141. package/src/cli/commands/help.ts +0 -95
  142. package/src/cli/commands/init.ts +0 -91
  143. package/src/cli/commands/version.ts +0 -38
  144. package/src/cli/index.ts +0 -6
  145. package/src/cli/templates/generators.ts +0 -359
  146. package/src/cli/templates/index.ts +0 -680
  147. package/src/cli/utils/exec.ts +0 -52
  148. package/src/cli/utils/file-system.ts +0 -78
  149. package/src/cli/utils/logger.ts +0 -111
  150. package/src/core/adapter.ts +0 -88
  151. package/src/core/application.ts +0 -1453
  152. package/src/core/context-pool.ts +0 -79
  153. package/src/core/context.ts +0 -856
  154. package/src/core/index.ts +0 -94
  155. package/src/core/middleware.ts +0 -272
  156. package/src/core/performance/buffer-pool.ts +0 -108
  157. package/src/core/performance/middleware-optimizer.ts +0 -162
  158. package/src/core/plugin/PluginManager.ts +0 -435
  159. package/src/core/plugin/builder.ts +0 -358
  160. package/src/core/plugin/index.ts +0 -50
  161. package/src/core/plugin/types.ts +0 -214
  162. package/src/core/router/file-router.ts +0 -623
  163. package/src/core/router/index.ts +0 -260
  164. package/src/core/router/radix-tree.ts +0 -242
  165. package/src/core/serializer.ts +0 -397
  166. package/src/core/store/index.ts +0 -30
  167. package/src/core/store/registry.ts +0 -178
  168. package/src/core/store/request-store.ts +0 -240
  169. package/src/core/store/types.ts +0 -233
  170. package/src/core/types.ts +0 -616
  171. package/src/database/adapter.ts +0 -35
  172. package/src/database/adapters/index.ts +0 -1
  173. package/src/database/adapters/mysql.ts +0 -669
  174. package/src/database/database.ts +0 -70
  175. package/src/database/dialect.ts +0 -388
  176. package/src/database/index.ts +0 -12
  177. package/src/database/migrations.ts +0 -86
  178. package/src/database/optimizer.ts +0 -125
  179. package/src/database/query-builder.ts +0 -404
  180. package/src/database/realtime.ts +0 -53
  181. package/src/database/schema.ts +0 -71
  182. package/src/database/transactions.ts +0 -56
  183. package/src/database/types.ts +0 -87
  184. package/src/deployment/cluster.ts +0 -471
  185. package/src/deployment/config.ts +0 -454
  186. package/src/deployment/docker.ts +0 -599
  187. package/src/deployment/graceful-shutdown.ts +0 -373
  188. package/src/deployment/index.ts +0 -56
  189. package/src/index.ts +0 -281
  190. package/src/security/adapter.ts +0 -318
  191. package/src/security/auth/JWTPlugin.ts +0 -234
  192. package/src/security/auth/JWTProvider.ts +0 -316
  193. package/src/security/auth/adapter.ts +0 -12
  194. package/src/security/auth/jwt.ts +0 -234
  195. package/src/security/auth/middleware.ts +0 -188
  196. package/src/security/csrf.ts +0 -220
  197. package/src/security/headers.ts +0 -108
  198. package/src/security/index.ts +0 -60
  199. package/src/security/rate-limit/adapter.ts +0 -7
  200. package/src/security/rate-limit/memory.ts +0 -108
  201. package/src/security/rate-limit/middleware.ts +0 -181
  202. package/src/security/sanitization.ts +0 -75
  203. package/src/security/types.ts +0 -240
  204. package/src/security/utils.ts +0 -52
  205. package/tsconfig.json +0 -39
@@ -1,670 +0,0 @@
1
- /**
2
- * Mock utilities for testing - database mocks, fetch mocks, and more
3
- */
4
-
5
- import { EventEmitter } from 'events';
6
-
7
- export type MockFn<T = any> = {
8
- (...args: any[]): T;
9
- calls: any[][];
10
- results: T[];
11
- mockReturnValue(value: T): MockFn<T>;
12
- mockReturnValueOnce(value: T): MockFn<T>;
13
- mockResolvedValue(value: T): MockFn<Promise<T>>;
14
- mockResolvedValueOnce(value: T): MockFn<Promise<T>>;
15
- mockRejectedValue(error: Error): MockFn<Promise<never>>;
16
- mockRejectedValueOnce(error: Error): MockFn<Promise<never>>;
17
- mockImplementation(fn: (...args: any[]) => T): MockFn<T>;
18
- mockImplementationOnce(fn: (...args: any[]) => T): MockFn<T>;
19
- mockClear(): void;
20
- mockReset(): void;
21
- toHaveBeenCalled(): boolean;
22
- toHaveBeenCalledTimes(count: number): boolean;
23
- toHaveBeenCalledWith(...args: any[]): boolean;
24
- toHaveBeenLastCalledWith(...args: any[]): boolean;
25
- };
26
-
27
- /**
28
- * Create a mock function
29
- */
30
- export function createMockFn<T = any>(defaultImpl?: (...args: any[]) => T): MockFn<T> {
31
- let returnValue: T | undefined;
32
- let returnQueue: T[] = [];
33
- let implementation: ((...args: any[]) => T) | undefined = defaultImpl;
34
- let implementationQueue: Array<(...args: any[]) => T> = [];
35
-
36
- const fn = ((...args: any[]): T => {
37
- fn.calls.push(args);
38
-
39
- // Check implementation queue first
40
- if (implementationQueue.length > 0) {
41
- const impl = implementationQueue.shift()!;
42
- const result = impl(...args);
43
- fn.results.push(result);
44
- return result;
45
- }
46
-
47
- // Check return value queue
48
- if (returnQueue.length > 0) {
49
- const result = returnQueue.shift()!;
50
- fn.results.push(result);
51
- return result;
52
- }
53
-
54
- // Use implementation if set
55
- if (implementation) {
56
- const result = implementation(...args);
57
- fn.results.push(result);
58
- return result;
59
- }
60
-
61
- // Return static value
62
- fn.results.push(returnValue as T);
63
- return returnValue as T;
64
- }) as MockFn<T>;
65
-
66
- fn.calls = [];
67
- fn.results = [];
68
-
69
- fn.mockReturnValue = (value: T) => {
70
- returnValue = value;
71
- return fn;
72
- };
73
-
74
- fn.mockReturnValueOnce = (value: T) => {
75
- returnQueue.push(value);
76
- return fn;
77
- };
78
-
79
- fn.mockResolvedValue = (value: T) => {
80
- returnValue = Promise.resolve(value) as any;
81
- return fn as any;
82
- };
83
-
84
- fn.mockResolvedValueOnce = (value: T) => {
85
- returnQueue.push(Promise.resolve(value) as any);
86
- return fn as any;
87
- };
88
-
89
- fn.mockRejectedValue = (error: Error) => {
90
- returnValue = Promise.reject(error) as any;
91
- return fn as any;
92
- };
93
-
94
- fn.mockRejectedValueOnce = (error: Error) => {
95
- returnQueue.push(Promise.reject(error) as any);
96
- return fn as any;
97
- };
98
-
99
- fn.mockImplementation = (impl: (...args: any[]) => T) => {
100
- implementation = impl;
101
- return fn;
102
- };
103
-
104
- fn.mockImplementationOnce = (impl: (...args: any[]) => T) => {
105
- implementationQueue.push(impl);
106
- return fn;
107
- };
108
-
109
- fn.mockClear = () => {
110
- fn.calls = [];
111
- fn.results = [];
112
- };
113
-
114
- fn.mockReset = () => {
115
- fn.mockClear();
116
- returnValue = undefined;
117
- returnQueue = [];
118
- implementation = defaultImpl;
119
- implementationQueue = [];
120
- };
121
-
122
- fn.toHaveBeenCalled = () => fn.calls.length > 0;
123
- fn.toHaveBeenCalledTimes = (count: number) => fn.calls.length === count;
124
- fn.toHaveBeenCalledWith = (...args: any[]) =>
125
- fn.calls.some(call => JSON.stringify(call) === JSON.stringify(args));
126
- fn.toHaveBeenLastCalledWith = (...args: any[]) =>
127
- fn.calls.length > 0 && JSON.stringify(fn.calls[fn.calls.length - 1]) === JSON.stringify(args);
128
-
129
- return fn;
130
- }
131
-
132
- /**
133
- * Mock database for testing
134
- */
135
- export interface MockRecord {
136
- id: string | number;
137
- [key: string]: any;
138
- }
139
-
140
- export interface MockTableOptions {
141
- autoIncrement?: boolean;
142
- primaryKey?: string;
143
- }
144
-
145
- export class MockTable<T extends MockRecord = MockRecord> {
146
- private records: Map<string | number, T> = new Map();
147
- private autoIncrementId = 1;
148
- private options: MockTableOptions;
149
- private primaryKey: string;
150
-
151
- // Mock functions for assertion
152
- insert = createMockFn<Promise<T>>();
153
- update = createMockFn<Promise<T | undefined>>();
154
- delete = createMockFn<Promise<boolean>>();
155
- find = createMockFn<Promise<T | undefined>>();
156
- findMany = createMockFn<Promise<T[]>>();
157
-
158
- constructor(options: MockTableOptions = {}) {
159
- this.options = options;
160
- this.primaryKey = options.primaryKey ?? 'id';
161
-
162
- // Set up real implementations
163
- this.insert.mockImplementation(async (data: Partial<T>) => {
164
- const record = { ...data } as T;
165
- if (this.options.autoIncrement !== false && !record[this.primaryKey]) {
166
- (record as any)[this.primaryKey] = this.autoIncrementId++;
167
- }
168
- this.records.set(record[this.primaryKey], record);
169
- return record;
170
- });
171
-
172
- this.update.mockImplementation(async (id: string | number, data: Partial<T>) => {
173
- const existing = this.records.get(id);
174
- if (!existing) return undefined;
175
- const updated = { ...existing, ...data };
176
- this.records.set(id, updated);
177
- return updated;
178
- });
179
-
180
- this.delete.mockImplementation(async (id: string | number) => {
181
- return this.records.delete(id);
182
- });
183
-
184
- this.find.mockImplementation(async (id: string | number) => {
185
- return this.records.get(id);
186
- });
187
-
188
- this.findMany.mockImplementation(async (filter?: Partial<T>) => {
189
- const all = Array.from(this.records.values());
190
- if (!filter) return all;
191
- return all.filter(record => {
192
- for (const [key, value] of Object.entries(filter)) {
193
- if (record[key] !== value) return false;
194
- }
195
- return true;
196
- });
197
- });
198
- }
199
-
200
- /**
201
- * Get all records (for assertions)
202
- */
203
- getAll(): T[] {
204
- return Array.from(this.records.values());
205
- }
206
-
207
- /**
208
- * Seed the table with data
209
- */
210
- seed(records: T[]): void {
211
- for (const record of records) {
212
- this.records.set(record[this.primaryKey], record);
213
- if (typeof record[this.primaryKey] === 'number') {
214
- this.autoIncrementId = Math.max(this.autoIncrementId, record[this.primaryKey] as number + 1);
215
- }
216
- }
217
- }
218
-
219
- /**
220
- * Clear all records
221
- */
222
- clear(): void {
223
- this.records.clear();
224
- this.autoIncrementId = 1;
225
- }
226
-
227
- /**
228
- * Reset everything including mock calls
229
- */
230
- reset(): void {
231
- this.clear();
232
- this.insert.mockClear();
233
- this.update.mockClear();
234
- this.delete.mockClear();
235
- this.find.mockClear();
236
- this.findMany.mockClear();
237
- }
238
- }
239
-
240
- export class MockDatabase {
241
- private tables: Map<string, MockTable> = new Map();
242
-
243
- /**
244
- * Get or create a mock table
245
- */
246
- table<T extends MockRecord = MockRecord>(name: string, options?: MockTableOptions): MockTable<T> {
247
- if (!this.tables.has(name)) {
248
- this.tables.set(name, new MockTable<T>(options));
249
- }
250
- return this.tables.get(name) as MockTable<T>;
251
- }
252
-
253
- /**
254
- * Reset all tables
255
- */
256
- reset(): void {
257
- for (const table of this.tables.values()) {
258
- table.reset();
259
- }
260
- }
261
-
262
- /**
263
- * Clear all data but keep mock tracking
264
- */
265
- clear(): void {
266
- for (const table of this.tables.values()) {
267
- table.clear();
268
- }
269
- }
270
-
271
- /**
272
- * Transaction mock
273
- */
274
- transaction = createMockFn<Promise<any>>().mockImplementation(async (callback: (trx: MockDatabase) => Promise<any>) => {
275
- return callback(this);
276
- });
277
- }
278
-
279
- /**
280
- * Mock HTTP fetch with pattern matching
281
- */
282
- export interface MockRoute {
283
- method: string;
284
- pattern: RegExp | string;
285
- handler: (url: string, options?: RequestInit) => Promise<MockResponse> | MockResponse;
286
- }
287
-
288
- export interface MockResponse {
289
- status: number;
290
- statusText?: string;
291
- headers?: Record<string, string>;
292
- body?: any;
293
- }
294
-
295
- export class MockFetch {
296
- private routes: MockRoute[] = [];
297
- private calls: Array<{ url: string; options?: RequestInit }> = [];
298
- private originalFetch?: typeof fetch;
299
-
300
- /**
301
- * Register a mock route
302
- */
303
- mock(pattern: string | RegExp, method: string = 'GET'): MockRouteBuilder {
304
- return new MockRouteBuilder(this, pattern, method);
305
- }
306
-
307
- /**
308
- * Register GET mock
309
- */
310
- get(pattern: string | RegExp): MockRouteBuilder {
311
- return this.mock(pattern, 'GET');
312
- }
313
-
314
- /**
315
- * Register POST mock
316
- */
317
- post(pattern: string | RegExp): MockRouteBuilder {
318
- return this.mock(pattern, 'POST');
319
- }
320
-
321
- /**
322
- * Register PUT mock
323
- */
324
- put(pattern: string | RegExp): MockRouteBuilder {
325
- return this.mock(pattern, 'PUT');
326
- }
327
-
328
- /**
329
- * Register DELETE mock
330
- */
331
- delete(pattern: string | RegExp): MockRouteBuilder {
332
- return this.mock(pattern, 'DELETE');
333
- }
334
-
335
- /**
336
- * Add a route handler
337
- */
338
- addRoute(route: MockRoute): void {
339
- this.routes.push(route);
340
- }
341
-
342
- /**
343
- * Install mock fetch globally
344
- */
345
- install(): void {
346
- this.originalFetch = globalThis.fetch;
347
- globalThis.fetch = this.createFetch();
348
- }
349
-
350
- /**
351
- * Restore original fetch
352
- */
353
- restore(): void {
354
- if (this.originalFetch) {
355
- globalThis.fetch = this.originalFetch;
356
- this.originalFetch = undefined;
357
- }
358
- }
359
-
360
- /**
361
- * Get all calls made
362
- */
363
- getCalls(): Array<{ url: string; options?: RequestInit }> {
364
- return [...this.calls];
365
- }
366
-
367
- /**
368
- * Check if a URL was called
369
- */
370
- wasCalled(pattern: string | RegExp): boolean {
371
- return this.calls.some(call => {
372
- if (typeof pattern === 'string') {
373
- return call.url.includes(pattern);
374
- }
375
- return pattern.test(call.url);
376
- });
377
- }
378
-
379
- /**
380
- * Clear all routes and calls
381
- */
382
- reset(): void {
383
- this.routes = [];
384
- this.calls = [];
385
- }
386
-
387
- /**
388
- * Create the mock fetch function
389
- */
390
- private createFetch(): typeof fetch {
391
- return async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {
392
- const url = typeof input === 'string' ? input : input.toString();
393
- const method = init?.method ?? 'GET';
394
-
395
- this.calls.push({ url, options: init });
396
-
397
- // Find matching route
398
- for (const route of this.routes) {
399
- if (route.method.toUpperCase() !== method.toUpperCase()) continue;
400
-
401
- const matches = typeof route.pattern === 'string'
402
- ? url.includes(route.pattern)
403
- : route.pattern.test(url);
404
-
405
- if (matches) {
406
- const mockResponse = await route.handler(url, init);
407
- return this.createResponse(mockResponse);
408
- }
409
- }
410
-
411
- // No match found - throw error or return 404
412
- throw new Error(`No mock found for ${method} ${url}`);
413
- };
414
- }
415
-
416
- private createResponse(mock: MockResponse): Response {
417
- const body = typeof mock.body === 'string' ? mock.body : JSON.stringify(mock.body);
418
- return new Response(body, {
419
- status: mock.status,
420
- statusText: mock.statusText ?? 'OK',
421
- headers: new Headers(mock.headers ?? { 'Content-Type': 'application/json' })
422
- });
423
- }
424
- }
425
-
426
- class MockRouteBuilder {
427
- private parent: MockFetch;
428
- private pattern: string | RegExp;
429
- private method: string;
430
-
431
- constructor(parent: MockFetch, pattern: string | RegExp, method: string) {
432
- this.parent = parent;
433
- this.pattern = pattern;
434
- this.method = method;
435
- }
436
-
437
- /**
438
- * Reply with static response
439
- */
440
- reply(status: number, body?: any, headers?: Record<string, string>): MockFetch {
441
- this.parent.addRoute({
442
- method: this.method,
443
- pattern: this.pattern,
444
- handler: () => ({ status, body, headers })
445
- });
446
- return this.parent;
447
- }
448
-
449
- /**
450
- * Reply with dynamic handler
451
- */
452
- replyWith(handler: (url: string, options?: RequestInit) => Promise<MockResponse> | MockResponse): MockFetch {
453
- this.parent.addRoute({
454
- method: this.method,
455
- pattern: this.pattern,
456
- handler
457
- });
458
- return this.parent;
459
- }
460
-
461
- /**
462
- * Simulate network error
463
- */
464
- networkError(message: string = 'Network error'): MockFetch {
465
- this.parent.addRoute({
466
- method: this.method,
467
- pattern: this.pattern,
468
- handler: () => { throw new Error(message); }
469
- });
470
- return this.parent;
471
- }
472
-
473
- /**
474
- * Simulate timeout
475
- */
476
- timeout(ms: number = 5000): MockFetch {
477
- this.parent.addRoute({
478
- method: this.method,
479
- pattern: this.pattern,
480
- handler: async () => {
481
- await new Promise(resolve => setTimeout(resolve, ms));
482
- throw new Error('Request timeout');
483
- }
484
- });
485
- return this.parent;
486
- }
487
- }
488
-
489
- /**
490
- * Mock timer utilities
491
- */
492
- export class MockTimers {
493
- private originalSetTimeout?: typeof setTimeout;
494
- private originalSetInterval?: typeof setInterval;
495
- private originalClearTimeout?: typeof clearTimeout;
496
- private originalClearInterval?: typeof clearInterval;
497
- private originalDateNow?: typeof Date.now;
498
- private currentTime: number = 0;
499
- private timers: Map<number, { callback: () => void; time: number; interval?: number }> = new Map();
500
- private nextId = 1;
501
-
502
- /**
503
- * Install mock timers
504
- */
505
- install(startTime: number = Date.now()): void {
506
- this.currentTime = startTime;
507
- this.originalSetTimeout = globalThis.setTimeout;
508
- this.originalSetInterval = globalThis.setInterval;
509
- this.originalClearTimeout = globalThis.clearTimeout;
510
- this.originalClearInterval = globalThis.clearInterval;
511
- this.originalDateNow = Date.now;
512
-
513
- (globalThis as any).setTimeout = (callback: () => void, delay: number = 0) => {
514
- const id = this.nextId++;
515
- this.timers.set(id, { callback, time: this.currentTime + delay });
516
- return id;
517
- };
518
-
519
- (globalThis as any).setInterval = (callback: () => void, delay: number) => {
520
- const id = this.nextId++;
521
- this.timers.set(id, { callback, time: this.currentTime + delay, interval: delay });
522
- return id;
523
- };
524
-
525
- (globalThis as any).clearTimeout = (id: number) => {
526
- this.timers.delete(id);
527
- };
528
-
529
- (globalThis as any).clearInterval = (id: number) => {
530
- this.timers.delete(id);
531
- };
532
-
533
- Date.now = () => this.currentTime;
534
- }
535
-
536
- /**
537
- * Advance time and run pending timers
538
- */
539
- async tick(ms: number): Promise<void> {
540
- const targetTime = this.currentTime + ms;
541
-
542
- while (this.currentTime < targetTime) {
543
- // Find next timer
544
- let nextTimer: { id: number; entry: { callback: () => void; time: number; interval?: number } } | undefined;
545
-
546
- for (const [id, entry] of this.timers.entries()) {
547
- if (entry.time <= targetTime) {
548
- if (!nextTimer || entry.time < nextTimer.entry.time) {
549
- nextTimer = { id, entry };
550
- }
551
- }
552
- }
553
-
554
- if (!nextTimer || nextTimer.entry.time > targetTime) {
555
- this.currentTime = targetTime;
556
- break;
557
- }
558
-
559
- this.currentTime = nextTimer.entry.time;
560
- const { id, entry } = nextTimer;
561
-
562
- if (entry.interval) {
563
- // Reschedule interval
564
- entry.time = this.currentTime + entry.interval;
565
- } else {
566
- this.timers.delete(id);
567
- }
568
-
569
- entry.callback();
570
- }
571
- }
572
-
573
- /**
574
- * Run all pending timers
575
- */
576
- async runAll(): Promise<void> {
577
- let iterations = 0;
578
- const maxIterations = 1000;
579
-
580
- while (this.timers.size > 0 && iterations < maxIterations) {
581
- const nextTime = Math.min(...Array.from(this.timers.values()).map(t => t.time));
582
- await this.tick(nextTime - this.currentTime + 1);
583
- iterations++;
584
- }
585
- }
586
-
587
- /**
588
- * Get current mocked time
589
- */
590
- now(): number {
591
- return this.currentTime;
592
- }
593
-
594
- /**
595
- * Set current time
596
- */
597
- setTime(time: number): void {
598
- this.currentTime = time;
599
- }
600
-
601
- /**
602
- * Restore original timers
603
- */
604
- restore(): void {
605
- if (this.originalSetTimeout) globalThis.setTimeout = this.originalSetTimeout;
606
- if (this.originalSetInterval) globalThis.setInterval = this.originalSetInterval;
607
- if (this.originalClearTimeout) globalThis.clearTimeout = this.originalClearTimeout;
608
- if (this.originalClearInterval) globalThis.clearInterval = this.originalClearInterval;
609
- if (this.originalDateNow) Date.now = this.originalDateNow;
610
- this.timers.clear();
611
- }
612
- }
613
-
614
- /**
615
- * Event spy for testing event emitters
616
- */
617
- export class EventSpy {
618
- private events: Map<string, any[][]> = new Map();
619
- private emitter: EventEmitter;
620
-
621
- constructor(emitter: EventEmitter) {
622
- this.emitter = emitter;
623
- }
624
-
625
- /**
626
- * Start spying on an event
627
- */
628
- on(event: string): this {
629
- this.events.set(event, []);
630
- this.emitter.on(event, (...args: any[]) => {
631
- this.events.get(event)?.push(args);
632
- });
633
- return this;
634
- }
635
-
636
- /**
637
- * Get calls for an event
638
- */
639
- getCalls(event: string): any[][] {
640
- return this.events.get(event) ?? [];
641
- }
642
-
643
- /**
644
- * Check if event was emitted
645
- */
646
- wasEmitted(event: string): boolean {
647
- return (this.events.get(event)?.length ?? 0) > 0;
648
- }
649
-
650
- /**
651
- * Get count of event emissions
652
- */
653
- count(event: string): number {
654
- return this.events.get(event)?.length ?? 0;
655
- }
656
-
657
- /**
658
- * Clear all tracked events
659
- */
660
- clear(): void {
661
- for (const calls of this.events.values()) {
662
- calls.length = 0;
663
- }
664
- }
665
- }
666
-
667
- // Export convenience singleton
668
- export const mockDb = new MockDatabase();
669
- export const mockFetch = new MockFetch();
670
- export const mockTimers = new MockTimers();
package/src/cli/bin.ts DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { CLI } from './cli';
4
-
5
- const cli = new CLI();
6
- cli.run(process.argv.slice(2)).catch((error) => {
7
- console.error('Fatal error:', error);
8
- process.exit(1);
9
- });