@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.
- package/package.json +1 -1
- package/BENCHMARK_REPORT.md +0 -343
- 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 -1956
- 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 -250
- package/src/advanced/playground/types.ts +0 -49
- 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 -1453
- package/src/core/context-pool.ts +0 -79
- package/src/core/context.ts +0 -856
- package/src/core/index.ts +0 -94
- package/src/core/middleware.ts +0 -272
- 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 -623
- package/src/core/router/index.ts +0 -260
- package/src/core/router/radix-tree.ts +0 -242
- package/src/core/serializer.ts +0 -397
- 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 -616
- 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 -281
- 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,498 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock server for testing external API calls
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { createServer, IncomingMessage, ServerResponse, Server } from 'http';
|
|
6
|
-
import { parse as parseUrl } from 'url';
|
|
7
|
-
import { EventEmitter } from 'events';
|
|
8
|
-
|
|
9
|
-
export interface MockServerRoute {
|
|
10
|
-
method: string;
|
|
11
|
-
path: string | RegExp;
|
|
12
|
-
handler: MockServerHandler;
|
|
13
|
-
delay?: number;
|
|
14
|
-
times?: number;
|
|
15
|
-
callCount: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface MockServerRequest {
|
|
19
|
-
method: string;
|
|
20
|
-
path: string;
|
|
21
|
-
query: Record<string, string | string[]>;
|
|
22
|
-
headers: Record<string, string | string[] | undefined>;
|
|
23
|
-
body: any;
|
|
24
|
-
params: Record<string, string>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface MockServerResponse {
|
|
28
|
-
status?: number;
|
|
29
|
-
headers?: Record<string, string>;
|
|
30
|
-
body?: any;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export type MockServerHandler = (req: MockServerRequest) => MockServerResponse | Promise<MockServerResponse>;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Mock HTTP server for testing
|
|
37
|
-
*/
|
|
38
|
-
export class MockServer extends EventEmitter {
|
|
39
|
-
private server?: Server;
|
|
40
|
-
private routes: MockServerRoute[] = [];
|
|
41
|
-
private requests: MockServerRequest[] = [];
|
|
42
|
-
private port?: number;
|
|
43
|
-
private host: string = '127.0.0.1';
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Register a GET route
|
|
47
|
-
*/
|
|
48
|
-
get(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
49
|
-
return this.route('GET', path, handler);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Register a POST route
|
|
54
|
-
*/
|
|
55
|
-
post(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
56
|
-
return this.route('POST', path, handler);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Register a PUT route
|
|
61
|
-
*/
|
|
62
|
-
put(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
63
|
-
return this.route('PUT', path, handler);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Register a PATCH route
|
|
68
|
-
*/
|
|
69
|
-
patch(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
70
|
-
return this.route('PATCH', path, handler);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Register a DELETE route
|
|
75
|
-
*/
|
|
76
|
-
delete(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
77
|
-
return this.route('DELETE', path, handler);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Register a route for any method
|
|
82
|
-
*/
|
|
83
|
-
any(path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
84
|
-
return this.route('*', path, handler);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Register a route
|
|
89
|
-
*/
|
|
90
|
-
route(method: string, path: string | RegExp, handler: MockServerHandler): MockRouteConfig {
|
|
91
|
-
const route: MockServerRoute = {
|
|
92
|
-
method: method.toUpperCase(),
|
|
93
|
-
path,
|
|
94
|
-
handler,
|
|
95
|
-
callCount: 0
|
|
96
|
-
};
|
|
97
|
-
this.routes.push(route);
|
|
98
|
-
return new MockRouteConfig(route);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Start the server
|
|
103
|
-
*/
|
|
104
|
-
async start(port: number = 0): Promise<string> {
|
|
105
|
-
return new Promise((resolve, reject) => {
|
|
106
|
-
this.server = createServer(async (req, res) => {
|
|
107
|
-
try {
|
|
108
|
-
await this.handleRequest(req, res);
|
|
109
|
-
} catch (error) {
|
|
110
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
111
|
-
res.end(JSON.stringify({ error: 'Internal server error' }));
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.server.on('error', reject);
|
|
116
|
-
|
|
117
|
-
this.server.listen(port, this.host, () => {
|
|
118
|
-
const addr = this.server!.address();
|
|
119
|
-
if (typeof addr === 'object' && addr) {
|
|
120
|
-
this.port = addr.port;
|
|
121
|
-
resolve(`http://${this.host}:${this.port}`);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Stop the server
|
|
129
|
-
*/
|
|
130
|
-
async stop(): Promise<void> {
|
|
131
|
-
return new Promise((resolve, reject) => {
|
|
132
|
-
if (!this.server) {
|
|
133
|
-
resolve();
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
this.server.close((err) => {
|
|
138
|
-
if (err) reject(err);
|
|
139
|
-
else resolve();
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Get the server URL
|
|
146
|
-
*/
|
|
147
|
-
get url(): string {
|
|
148
|
-
if (!this.port) {
|
|
149
|
-
throw new Error('Server not started');
|
|
150
|
-
}
|
|
151
|
-
return `http://${this.host}:${this.port}`;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get all requests received
|
|
156
|
-
*/
|
|
157
|
-
getRequests(): MockServerRequest[] {
|
|
158
|
-
return [...this.requests];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Check if a path was called
|
|
163
|
-
*/
|
|
164
|
-
wasCalled(path: string | RegExp, method?: string): boolean {
|
|
165
|
-
return this.requests.some(req => {
|
|
166
|
-
if (method && req.method !== method.toUpperCase()) {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
if (typeof path === 'string') {
|
|
170
|
-
return req.path === path;
|
|
171
|
-
}
|
|
172
|
-
return path.test(req.path);
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Get call count for a path
|
|
178
|
-
*/
|
|
179
|
-
callCount(path: string | RegExp, method?: string): number {
|
|
180
|
-
return this.requests.filter(req => {
|
|
181
|
-
if (method && req.method !== method.toUpperCase()) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
if (typeof path === 'string') {
|
|
185
|
-
return req.path === path;
|
|
186
|
-
}
|
|
187
|
-
return path.test(req.path);
|
|
188
|
-
}).length;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Reset all routes and requests
|
|
193
|
-
*/
|
|
194
|
-
reset(): void {
|
|
195
|
-
this.routes = [];
|
|
196
|
-
this.requests = [];
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Clear just the request history
|
|
201
|
-
*/
|
|
202
|
-
clearRequests(): void {
|
|
203
|
-
this.requests = [];
|
|
204
|
-
for (const route of this.routes) {
|
|
205
|
-
route.callCount = 0;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
210
|
-
const parsed = parseUrl(req.url || '', true);
|
|
211
|
-
const path = parsed.pathname || '/';
|
|
212
|
-
const method = req.method?.toUpperCase() || 'GET';
|
|
213
|
-
|
|
214
|
-
// Parse body
|
|
215
|
-
const body = await this.parseBody(req);
|
|
216
|
-
|
|
217
|
-
// Find matching route
|
|
218
|
-
let matchedRoute: MockServerRoute | undefined;
|
|
219
|
-
let params: Record<string, string> = {};
|
|
220
|
-
|
|
221
|
-
for (const route of this.routes) {
|
|
222
|
-
if (route.method !== '*' && route.method !== method) {
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Check times limit
|
|
227
|
-
if (route.times !== undefined && route.callCount >= route.times) {
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (typeof route.path === 'string') {
|
|
232
|
-
const paramMatch = this.matchPath(route.path, path);
|
|
233
|
-
if (paramMatch) {
|
|
234
|
-
matchedRoute = route;
|
|
235
|
-
params = paramMatch;
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
} else if (route.path.test(path)) {
|
|
239
|
-
matchedRoute = route;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const mockRequest: MockServerRequest = {
|
|
245
|
-
method,
|
|
246
|
-
path,
|
|
247
|
-
query: parsed.query as Record<string, string | string[]>,
|
|
248
|
-
headers: req.headers,
|
|
249
|
-
body,
|
|
250
|
-
params
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
this.requests.push(mockRequest);
|
|
254
|
-
this.emit('request', mockRequest);
|
|
255
|
-
|
|
256
|
-
if (!matchedRoute) {
|
|
257
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
258
|
-
res.end(JSON.stringify({ error: 'Not found', path, method }));
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
matchedRoute.callCount++;
|
|
263
|
-
|
|
264
|
-
// Apply delay if configured
|
|
265
|
-
if (matchedRoute.delay) {
|
|
266
|
-
await new Promise(resolve => setTimeout(resolve, matchedRoute.delay));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
try {
|
|
270
|
-
const response = await matchedRoute.handler(mockRequest);
|
|
271
|
-
const status = response.status ?? 200;
|
|
272
|
-
const headers = {
|
|
273
|
-
'Content-Type': 'application/json',
|
|
274
|
-
...response.headers
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
res.writeHead(status, headers);
|
|
278
|
-
|
|
279
|
-
if (response.body !== undefined) {
|
|
280
|
-
const bodyString = typeof response.body === 'string'
|
|
281
|
-
? response.body
|
|
282
|
-
: JSON.stringify(response.body);
|
|
283
|
-
res.end(bodyString);
|
|
284
|
-
} else {
|
|
285
|
-
res.end();
|
|
286
|
-
}
|
|
287
|
-
} catch (error: any) {
|
|
288
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
289
|
-
res.end(JSON.stringify({ error: error.message }));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
private async parseBody(req: IncomingMessage): Promise<any> {
|
|
294
|
-
return new Promise((resolve) => {
|
|
295
|
-
const chunks: Buffer[] = [];
|
|
296
|
-
req.on('data', chunk => chunks.push(chunk));
|
|
297
|
-
req.on('end', () => {
|
|
298
|
-
const raw = Buffer.concat(chunks).toString('utf-8');
|
|
299
|
-
if (!raw) {
|
|
300
|
-
resolve(undefined);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const contentType = req.headers['content-type'] || '';
|
|
305
|
-
if (contentType.includes('application/json')) {
|
|
306
|
-
try {
|
|
307
|
-
resolve(JSON.parse(raw));
|
|
308
|
-
} catch {
|
|
309
|
-
resolve(raw);
|
|
310
|
-
}
|
|
311
|
-
} else {
|
|
312
|
-
resolve(raw);
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
private matchPath(pattern: string, path: string): Record<string, string> | null {
|
|
319
|
-
// Handle exact match
|
|
320
|
-
if (pattern === path) {
|
|
321
|
-
return {};
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
// Handle path parameters like /users/:id
|
|
325
|
-
const patternParts = pattern.split('/');
|
|
326
|
-
const pathParts = path.split('/');
|
|
327
|
-
|
|
328
|
-
if (patternParts.length !== pathParts.length) {
|
|
329
|
-
return null;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const params: Record<string, string> = {};
|
|
333
|
-
|
|
334
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
335
|
-
const patternPart = patternParts[i];
|
|
336
|
-
const pathPart = pathParts[i];
|
|
337
|
-
|
|
338
|
-
if (patternPart.startsWith(':')) {
|
|
339
|
-
params[patternPart.slice(1)] = pathPart;
|
|
340
|
-
} else if (patternPart === '*') {
|
|
341
|
-
// Wildcard matches anything
|
|
342
|
-
continue;
|
|
343
|
-
} else if (patternPart !== pathPart) {
|
|
344
|
-
return null;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return params;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Route configuration builder
|
|
354
|
-
*/
|
|
355
|
-
class MockRouteConfig {
|
|
356
|
-
private route: MockServerRoute;
|
|
357
|
-
|
|
358
|
-
constructor(route: MockServerRoute) {
|
|
359
|
-
this.route = route;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Add delay before responding
|
|
364
|
-
*/
|
|
365
|
-
delay(ms: number): this {
|
|
366
|
-
this.route.delay = ms;
|
|
367
|
-
return this;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Limit how many times this route responds
|
|
372
|
-
*/
|
|
373
|
-
times(count: number): this {
|
|
374
|
-
this.route.times = count;
|
|
375
|
-
return this;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Create a mock server
|
|
381
|
-
*/
|
|
382
|
-
export function createMockServer(): MockServer {
|
|
383
|
-
return new MockServer();
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// ============================================================================
|
|
387
|
-
// Convenience helpers for common mock responses
|
|
388
|
-
// ============================================================================
|
|
389
|
-
|
|
390
|
-
export const mockResponses = {
|
|
391
|
-
/**
|
|
392
|
-
* Return JSON response
|
|
393
|
-
*/
|
|
394
|
-
json: (data: any, status: number = 200): MockServerHandler => {
|
|
395
|
-
return () => ({ status, body: data });
|
|
396
|
-
},
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Return empty success response
|
|
400
|
-
*/
|
|
401
|
-
ok: (): MockServerHandler => {
|
|
402
|
-
return () => ({ status: 200 });
|
|
403
|
-
},
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Return created response
|
|
407
|
-
*/
|
|
408
|
-
created: (data?: any): MockServerHandler => {
|
|
409
|
-
return () => ({ status: 201, body: data });
|
|
410
|
-
},
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Return no content response
|
|
414
|
-
*/
|
|
415
|
-
noContent: (): MockServerHandler => {
|
|
416
|
-
return () => ({ status: 204 });
|
|
417
|
-
},
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Return bad request response
|
|
421
|
-
*/
|
|
422
|
-
badRequest: (message: string = 'Bad request'): MockServerHandler => {
|
|
423
|
-
return () => ({ status: 400, body: { error: message } });
|
|
424
|
-
},
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Return unauthorized response
|
|
428
|
-
*/
|
|
429
|
-
unauthorized: (message: string = 'Unauthorized'): MockServerHandler => {
|
|
430
|
-
return () => ({ status: 401, body: { error: message } });
|
|
431
|
-
},
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* Return forbidden response
|
|
435
|
-
*/
|
|
436
|
-
forbidden: (message: string = 'Forbidden'): MockServerHandler => {
|
|
437
|
-
return () => ({ status: 403, body: { error: message } });
|
|
438
|
-
},
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Return not found response
|
|
442
|
-
*/
|
|
443
|
-
notFound: (message: string = 'Not found'): MockServerHandler => {
|
|
444
|
-
return () => ({ status: 404, body: { error: message } });
|
|
445
|
-
},
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Return internal server error
|
|
449
|
-
*/
|
|
450
|
-
serverError: (message: string = 'Internal server error'): MockServerHandler => {
|
|
451
|
-
return () => ({ status: 500, body: { error: message } });
|
|
452
|
-
},
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Echo the request back
|
|
456
|
-
*/
|
|
457
|
-
echo: (): MockServerHandler => {
|
|
458
|
-
return (req) => ({
|
|
459
|
-
status: 200,
|
|
460
|
-
body: {
|
|
461
|
-
method: req.method,
|
|
462
|
-
path: req.path,
|
|
463
|
-
query: req.query,
|
|
464
|
-
headers: req.headers,
|
|
465
|
-
body: req.body,
|
|
466
|
-
params: req.params
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
},
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Paginated response helper
|
|
473
|
-
*/
|
|
474
|
-
paginated: <T>(
|
|
475
|
-
items: T[],
|
|
476
|
-
pageSize: number = 10
|
|
477
|
-
): MockServerHandler => {
|
|
478
|
-
return (req) => {
|
|
479
|
-
const page = parseInt(req.query.page as string, 10) || 1;
|
|
480
|
-
const start = (page - 1) * pageSize;
|
|
481
|
-
const end = start + pageSize;
|
|
482
|
-
const paginatedItems = items.slice(start, end);
|
|
483
|
-
|
|
484
|
-
return {
|
|
485
|
-
status: 200,
|
|
486
|
-
body: {
|
|
487
|
-
data: paginatedItems,
|
|
488
|
-
meta: {
|
|
489
|
-
page,
|
|
490
|
-
pageSize,
|
|
491
|
-
total: items.length,
|
|
492
|
-
totalPages: Math.ceil(items.length / pageSize)
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
};
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
};
|