@engjts/nexus 0.1.7 → 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.
- package/dist/advanced/playground/generatePlaygroundHTML.d.ts.map +1 -1
- package/dist/advanced/playground/generatePlaygroundHTML.js +107 -0
- package/dist/advanced/playground/generatePlaygroundHTML.js.map +1 -1
- package/dist/advanced/playground/playground.d.ts +19 -0
- package/dist/advanced/playground/playground.d.ts.map +1 -1
- package/dist/advanced/playground/playground.js +70 -0
- package/dist/advanced/playground/playground.js.map +1 -1
- package/dist/advanced/playground/types.d.ts +20 -0
- package/dist/advanced/playground/types.d.ts.map +1 -1
- package/dist/core/application.d.ts +14 -0
- package/dist/core/application.d.ts.map +1 -1
- package/dist/core/application.js +173 -71
- package/dist/core/application.js.map +1 -1
- package/dist/core/context-pool.d.ts +2 -13
- package/dist/core/context-pool.d.ts.map +1 -1
- package/dist/core/context-pool.js +7 -45
- package/dist/core/context-pool.js.map +1 -1
- package/dist/core/context.d.ts +108 -5
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +449 -53
- package/dist/core/context.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/middleware.d.ts +6 -0
- package/dist/core/middleware.d.ts.map +1 -1
- package/dist/core/middleware.js +83 -84
- package/dist/core/middleware.js.map +1 -1
- package/dist/core/performance/fast-json.d.ts +149 -0
- package/dist/core/performance/fast-json.d.ts.map +1 -0
- package/dist/core/performance/fast-json.js +473 -0
- package/dist/core/performance/fast-json.js.map +1 -0
- package/dist/core/router/file-router.d.ts +20 -7
- package/dist/core/router/file-router.d.ts.map +1 -1
- package/dist/core/router/file-router.js +41 -13
- package/dist/core/router/file-router.js.map +1 -1
- package/dist/core/router/index.d.ts +6 -0
- package/dist/core/router/index.d.ts.map +1 -1
- package/dist/core/router/index.js +33 -6
- package/dist/core/router/index.js.map +1 -1
- package/dist/core/router/radix-tree.d.ts +4 -1
- package/dist/core/router/radix-tree.d.ts.map +1 -1
- package/dist/core/router/radix-tree.js +7 -3
- package/dist/core/router/radix-tree.js.map +1 -1
- package/dist/core/serializer.d.ts +251 -0
- package/dist/core/serializer.d.ts.map +1 -0
- package/dist/core/serializer.js +290 -0
- package/dist/core/serializer.js.map +1 -0
- package/dist/core/types.d.ts +39 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/documentation/01-getting-started.md +0 -240
- package/documentation/02-context.md +0 -335
- package/documentation/03-routing.md +0 -397
- package/documentation/04-middleware.md +0 -483
- package/documentation/05-validation.md +0 -514
- package/documentation/06-error-handling.md +0 -465
- package/documentation/07-performance.md +0 -364
- package/documentation/08-adapters.md +0 -470
- package/documentation/09-api-reference.md +0 -548
- package/documentation/10-examples.md +0 -582
- package/documentation/11-deployment.md +0 -477
- package/documentation/12-sentry.md +0 -620
- package/documentation/13-sentry-data-storage.md +0 -996
- package/documentation/14-sentry-data-reference.md +0 -457
- package/documentation/15-sentry-summary.md +0 -409
- package/documentation/16-alerts-system.md +0 -745
- package/documentation/17-alert-adapters.md +0 -696
- package/documentation/18-alerts-implementation-summary.md +0 -385
- package/documentation/19-class-based-routing.md +0 -840
- package/documentation/20-websocket-realtime.md +0 -813
- package/documentation/21-cache-system.md +0 -510
- package/documentation/22-job-queue.md +0 -772
- package/documentation/23-sentry-plugin.md +0 -551
- package/documentation/24-testing-utilities.md +0 -1287
- package/documentation/25-api-versioning.md +0 -533
- package/documentation/26-context-store.md +0 -607
- package/documentation/27-dependency-injection.md +0 -329
- package/documentation/28-lifecycle-hooks.md +0 -521
- package/documentation/29-package-structure.md +0 -196
- package/documentation/30-plugin-system.md +0 -414
- package/documentation/31-jwt-authentication.md +0 -597
- package/documentation/32-cli.md +0 -268
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +0 -429
- package/documentation/ALERTS-INDEX.md +0 -330
- package/documentation/ALERTS-QUICK-REFERENCE.md +0 -286
- package/documentation/README.md +0 -178
- package/documentation/index.html +0 -34
- package/modern_framework_paper.md +0 -1870
- package/public/css/style.css +0 -87
- package/public/index.html +0 -34
- package/public/js/app.js +0 -27
- package/src/advanced/cache/InMemoryCacheStore.ts +0 -68
- package/src/advanced/cache/MultiTierCache.ts +0 -194
- package/src/advanced/cache/RedisCacheStore.ts +0 -341
- package/src/advanced/cache/index.ts +0 -5
- package/src/advanced/cache/types.ts +0 -40
- package/src/advanced/graphql/SimpleDataLoader.ts +0 -42
- package/src/advanced/graphql/index.ts +0 -22
- package/src/advanced/graphql/server.ts +0 -252
- package/src/advanced/graphql/types.ts +0 -42
- package/src/advanced/jobs/InMemoryQueueStore.ts +0 -68
- package/src/advanced/jobs/JobQueue.ts +0 -556
- package/src/advanced/jobs/RedisQueueStore.ts +0 -367
- package/src/advanced/jobs/index.ts +0 -5
- package/src/advanced/jobs/types.ts +0 -70
- package/src/advanced/observability/APMManager.ts +0 -163
- package/src/advanced/observability/AlertManager.ts +0 -109
- package/src/advanced/observability/MetricRegistry.ts +0 -151
- package/src/advanced/observability/ObservabilityCenter.ts +0 -304
- package/src/advanced/observability/StructuredLogger.ts +0 -154
- package/src/advanced/observability/TracingManager.ts +0 -117
- package/src/advanced/observability/adapters.ts +0 -304
- package/src/advanced/observability/createObservabilityMiddleware.ts +0 -63
- package/src/advanced/observability/index.ts +0 -11
- package/src/advanced/observability/types.ts +0 -174
- package/src/advanced/playground/extractPathParams.ts +0 -6
- package/src/advanced/playground/generateFieldExample.ts +0 -31
- package/src/advanced/playground/generatePlaygroundHTML.ts +0 -1849
- package/src/advanced/playground/generateSummary.ts +0 -19
- package/src/advanced/playground/getTagFromPath.ts +0 -9
- package/src/advanced/playground/index.ts +0 -8
- package/src/advanced/playground/playground.ts +0 -170
- package/src/advanced/playground/types.ts +0 -20
- package/src/advanced/playground/zodToExample.ts +0 -16
- package/src/advanced/playground/zodToParams.ts +0 -15
- package/src/advanced/postman/buildAuth.ts +0 -31
- package/src/advanced/postman/buildBody.ts +0 -15
- package/src/advanced/postman/buildQueryParams.ts +0 -27
- package/src/advanced/postman/buildRequestItem.ts +0 -36
- package/src/advanced/postman/buildResponses.ts +0 -11
- package/src/advanced/postman/buildUrl.ts +0 -33
- package/src/advanced/postman/capitalize.ts +0 -4
- package/src/advanced/postman/generateCollection.ts +0 -59
- package/src/advanced/postman/generateEnvironment.ts +0 -34
- package/src/advanced/postman/generateExampleFromZod.ts +0 -21
- package/src/advanced/postman/generateFieldExample.ts +0 -45
- package/src/advanced/postman/generateName.ts +0 -20
- package/src/advanced/postman/generateUUID.ts +0 -11
- package/src/advanced/postman/getTagFromPath.ts +0 -10
- package/src/advanced/postman/index.ts +0 -28
- package/src/advanced/postman/postman.ts +0 -156
- package/src/advanced/postman/slugify.ts +0 -7
- package/src/advanced/postman/types.ts +0 -140
- package/src/advanced/realtime/index.ts +0 -18
- package/src/advanced/realtime/websocket.ts +0 -231
- package/src/advanced/sentry/index.ts +0 -1236
- package/src/advanced/sentry/types.ts +0 -355
- package/src/advanced/static/generateDirectoryListing.ts +0 -47
- package/src/advanced/static/generateETag.ts +0 -7
- package/src/advanced/static/getMimeType.ts +0 -9
- package/src/advanced/static/index.ts +0 -32
- package/src/advanced/static/isSafePath.ts +0 -13
- package/src/advanced/static/publicDir.ts +0 -21
- package/src/advanced/static/serveStatic.ts +0 -225
- package/src/advanced/static/spa.ts +0 -24
- package/src/advanced/static/types.ts +0 -159
- package/src/advanced/swagger/SwaggerGenerator.ts +0 -66
- package/src/advanced/swagger/buildOperation.ts +0 -61
- package/src/advanced/swagger/buildParameters.ts +0 -61
- package/src/advanced/swagger/buildRequestBody.ts +0 -21
- package/src/advanced/swagger/buildResponses.ts +0 -54
- package/src/advanced/swagger/capitalize.ts +0 -5
- package/src/advanced/swagger/convertPath.ts +0 -9
- package/src/advanced/swagger/createSwagger.ts +0 -12
- package/src/advanced/swagger/generateOperationId.ts +0 -21
- package/src/advanced/swagger/generateSpec.ts +0 -105
- package/src/advanced/swagger/generateSummary.ts +0 -24
- package/src/advanced/swagger/generateSwaggerUI.ts +0 -70
- package/src/advanced/swagger/generateThemeCss.ts +0 -53
- package/src/advanced/swagger/index.ts +0 -25
- package/src/advanced/swagger/swagger.ts +0 -237
- package/src/advanced/swagger/types.ts +0 -206
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +0 -94
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +0 -50
- package/src/advanced/swagger/zodToOpenAPI.ts +0 -22
- package/src/advanced/testing/factory.ts +0 -509
- package/src/advanced/testing/harness.ts +0 -612
- package/src/advanced/testing/index.ts +0 -430
- package/src/advanced/testing/load-test.ts +0 -618
- package/src/advanced/testing/mock-server.ts +0 -498
- package/src/advanced/testing/mock.ts +0 -670
- package/src/cli/bin.ts +0 -9
- package/src/cli/cli.ts +0 -158
- package/src/cli/commands/add.ts +0 -178
- package/src/cli/commands/build.ts +0 -73
- package/src/cli/commands/create.ts +0 -166
- package/src/cli/commands/dev.ts +0 -85
- package/src/cli/commands/generate.ts +0 -99
- package/src/cli/commands/help.ts +0 -95
- package/src/cli/commands/init.ts +0 -91
- package/src/cli/commands/version.ts +0 -38
- package/src/cli/index.ts +0 -6
- package/src/cli/templates/generators.ts +0 -359
- package/src/cli/templates/index.ts +0 -680
- package/src/cli/utils/exec.ts +0 -52
- package/src/cli/utils/file-system.ts +0 -78
- package/src/cli/utils/logger.ts +0 -111
- package/src/core/adapter.ts +0 -88
- package/src/core/application.ts +0 -1335
- package/src/core/context-pool.ts +0 -127
- package/src/core/context.ts +0 -412
- package/src/core/index.ts +0 -80
- package/src/core/middleware.ts +0 -262
- package/src/core/performance/buffer-pool.ts +0 -108
- package/src/core/performance/middleware-optimizer.ts +0 -162
- package/src/core/plugin/PluginManager.ts +0 -435
- package/src/core/plugin/builder.ts +0 -358
- package/src/core/plugin/index.ts +0 -50
- package/src/core/plugin/types.ts +0 -214
- package/src/core/router/file-router.ts +0 -594
- package/src/core/router/index.ts +0 -227
- package/src/core/router/radix-tree.ts +0 -226
- package/src/core/store/index.ts +0 -30
- package/src/core/store/registry.ts +0 -178
- package/src/core/store/request-store.ts +0 -240
- package/src/core/store/types.ts +0 -233
- package/src/core/types.ts +0 -574
- package/src/database/adapter.ts +0 -35
- package/src/database/adapters/index.ts +0 -1
- package/src/database/adapters/mysql.ts +0 -669
- package/src/database/database.ts +0 -70
- package/src/database/dialect.ts +0 -388
- package/src/database/index.ts +0 -12
- package/src/database/migrations.ts +0 -86
- package/src/database/optimizer.ts +0 -125
- package/src/database/query-builder.ts +0 -404
- package/src/database/realtime.ts +0 -53
- package/src/database/schema.ts +0 -71
- package/src/database/transactions.ts +0 -56
- package/src/database/types.ts +0 -87
- package/src/deployment/cluster.ts +0 -471
- package/src/deployment/config.ts +0 -454
- package/src/deployment/docker.ts +0 -599
- package/src/deployment/graceful-shutdown.ts +0 -373
- package/src/deployment/index.ts +0 -56
- package/src/index.ts +0 -264
- package/src/security/adapter.ts +0 -318
- package/src/security/auth/JWTPlugin.ts +0 -234
- package/src/security/auth/JWTProvider.ts +0 -316
- package/src/security/auth/adapter.ts +0 -12
- package/src/security/auth/jwt.ts +0 -234
- package/src/security/auth/middleware.ts +0 -188
- package/src/security/csrf.ts +0 -220
- package/src/security/headers.ts +0 -108
- package/src/security/index.ts +0 -60
- package/src/security/rate-limit/adapter.ts +0 -7
- package/src/security/rate-limit/memory.ts +0 -108
- package/src/security/rate-limit/middleware.ts +0 -181
- package/src/security/sanitization.ts +0 -75
- package/src/security/types.ts +0 -240
- package/src/security/utils.ts +0 -52
- 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();
|