@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,19 +0,0 @@
|
|
|
1
|
-
import { HTTPMethod } from '../../core/types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function generateSummary(method: HTTPMethod, path: string): string {
|
|
6
|
-
const parts = path.split('/').filter(Boolean);
|
|
7
|
-
const resource = parts.find(p => !p.startsWith(':')) || 'resource';
|
|
8
|
-
const hasId = parts.some(p => p.startsWith(':'));
|
|
9
|
-
const actions: Record<HTTPMethod, string> = {
|
|
10
|
-
'GET': hasId ? `Get ${resource}` : `List ${resource}`,
|
|
11
|
-
'POST': `Create ${resource}`,
|
|
12
|
-
'PUT': `Update ${resource}`,
|
|
13
|
-
'PATCH': `Patch ${resource}`,
|
|
14
|
-
'DELETE': `Delete ${resource}`,
|
|
15
|
-
'HEAD': `Head ${resource}`,
|
|
16
|
-
'OPTIONS': `Options ${resource}`
|
|
17
|
-
};
|
|
18
|
-
return actions[method] || `${method} ${path}`;
|
|
19
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function getTagFromPath(path: string): string {
|
|
4
|
-
const firstSegment = path.split('/').filter(Boolean)[0];
|
|
5
|
-
if (firstSegment && !firstSegment.startsWith(':')) {
|
|
6
|
-
return firstSegment.charAt(0).toUpperCase() + firstSegment.slice(1);
|
|
7
|
-
}
|
|
8
|
-
return 'General';
|
|
9
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { extractPathParams } from './extractPathParams';
|
|
2
|
-
import { zodToParams } from './zodToParams';
|
|
3
|
-
import { zodToExample } from './zodToExample';
|
|
4
|
-
import { getTagFromPath } from './getTagFromPath';
|
|
5
|
-
import { generateSummary } from './generateSummary';
|
|
6
|
-
import { generatePlaygroundHTML } from './generatePlaygroundHTML';
|
|
7
|
-
import { Application } from '../../core/application';
|
|
8
|
-
import { RouteConfig, HTTPMethod, Context, Plugin, SchemaConfig, RouteMeta } from '../../core/types';
|
|
9
|
-
import { PlaygroundConfig, StoredRoute } from './types';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* API Playground Plugin
|
|
14
|
-
* Provides an interactive API explorer with authentication and development-mode security
|
|
15
|
-
*
|
|
16
|
-
* @param config - Configuration options for the playground
|
|
17
|
-
* @returns Plugin instance
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```typescript
|
|
21
|
-
* app.use(playground({
|
|
22
|
-
* path: '/playground',
|
|
23
|
-
* developmentOnly: true,
|
|
24
|
-
* auth: {
|
|
25
|
-
* username: 'admin',
|
|
26
|
-
* password: 'secret123'
|
|
27
|
-
* }
|
|
28
|
-
* }));
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export function playground(config: PlaygroundConfig = {}): Plugin {
|
|
32
|
-
const resolvedConfig: PlaygroundConfig = {
|
|
33
|
-
path: '/playground',
|
|
34
|
-
title: 'API Playground',
|
|
35
|
-
theme: 'dark',
|
|
36
|
-
enableHistory: true,
|
|
37
|
-
maxHistory: 50,
|
|
38
|
-
enableVariables: true,
|
|
39
|
-
developmentOnly: true,
|
|
40
|
-
defaultHeaders: { 'Content-Type': 'application/json' },
|
|
41
|
-
variables: { baseUrl: 'http://localhost:3000', token: '' },
|
|
42
|
-
...config
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const routes: StoredRoute[] = [];
|
|
46
|
-
let detectedBaseUrl = '';
|
|
47
|
-
let appInstance: Application | null = null;
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
name: 'playground',
|
|
51
|
-
version: '1.0.0',
|
|
52
|
-
|
|
53
|
-
install(app: Application) {
|
|
54
|
-
// Check if playground should be disabled in production
|
|
55
|
-
if (resolvedConfig.developmentOnly && process.env.NODE_ENV === 'production') {
|
|
56
|
-
console.warn('⚠️ API Playground is disabled in production mode');
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
appInstance = app;
|
|
61
|
-
const originalRoute = app.route.bind(app);
|
|
62
|
-
const originalGet = app.get.bind(app);
|
|
63
|
-
const originalPost = app.post.bind(app);
|
|
64
|
-
const originalPut = app.put.bind(app);
|
|
65
|
-
const originalDelete = app.delete.bind(app);
|
|
66
|
-
const originalPatch = app.patch.bind(app);
|
|
67
|
-
|
|
68
|
-
app.route = function (routeConfig: RouteConfig) {
|
|
69
|
-
routes.push({
|
|
70
|
-
method: routeConfig.method,
|
|
71
|
-
path: routeConfig.path,
|
|
72
|
-
schema: routeConfig.schema,
|
|
73
|
-
meta: routeConfig.meta
|
|
74
|
-
});
|
|
75
|
-
return originalRoute(routeConfig);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const wrapMethod = (method: HTTPMethod, original: Function) => {
|
|
79
|
-
return function (pathOrRoute: string | any, handlerOrConfig?: any) {
|
|
80
|
-
// Class-based routing
|
|
81
|
-
if (typeof pathOrRoute === 'object' && 'pathName' in pathOrRoute) {
|
|
82
|
-
const route = pathOrRoute;
|
|
83
|
-
routes.push({
|
|
84
|
-
method,
|
|
85
|
-
path: route.pathName,
|
|
86
|
-
schema: route.schema?.(),
|
|
87
|
-
meta: route.meta?.()
|
|
88
|
-
});
|
|
89
|
-
return original(pathOrRoute);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const path = pathOrRoute;
|
|
93
|
-
if (typeof handlerOrConfig !== 'function' && handlerOrConfig) {
|
|
94
|
-
routes.push({ method, path, schema: handlerOrConfig.schema, meta: handlerOrConfig.meta });
|
|
95
|
-
} else {
|
|
96
|
-
routes.push({ method, path });
|
|
97
|
-
}
|
|
98
|
-
return original(path, handlerOrConfig);
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
app.get = wrapMethod('GET', originalGet);
|
|
103
|
-
app.post = wrapMethod('POST', originalPost);
|
|
104
|
-
app.put = wrapMethod('PUT', originalPut);
|
|
105
|
-
app.delete = wrapMethod('DELETE', originalDelete);
|
|
106
|
-
app.patch = wrapMethod('PATCH', originalPatch);
|
|
107
|
-
|
|
108
|
-
const basePath = resolvedConfig.path!;
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Authentication middleware for playground routes
|
|
112
|
-
* Implements HTTP Basic Authentication when auth config is provided
|
|
113
|
-
*/
|
|
114
|
-
const authMiddleware = (ctx: any) => {
|
|
115
|
-
if (!resolvedConfig.auth) {
|
|
116
|
-
return true; // No auth required
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const authHeader = ctx.raw?.req?.headers?.authorization || ctx.headers?.get?.('authorization');
|
|
120
|
-
|
|
121
|
-
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
|
122
|
-
return false;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const base64Credentials = authHeader.substring(6);
|
|
127
|
-
const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');
|
|
128
|
-
const [username, password] = credentials.split(':');
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
username === resolvedConfig.auth.username &&
|
|
132
|
-
password === resolvedConfig.auth.password
|
|
133
|
-
);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
return false;
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Returns 401 Unauthorized response with WWW-Authenticate header
|
|
141
|
-
* This triggers the browser's native authentication dialog
|
|
142
|
-
*/
|
|
143
|
-
const unauthorizedResponse = () => {
|
|
144
|
-
return {
|
|
145
|
-
statusCode: 401,
|
|
146
|
-
headers: {
|
|
147
|
-
'WWW-Authenticate': 'Basic realm="API Playground"',
|
|
148
|
-
'Content-Type': 'text/plain'
|
|
149
|
-
},
|
|
150
|
-
body: 'Unauthorized'
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
originalGet(basePath, async (ctx: any) => {
|
|
155
|
-
// Check authentication
|
|
156
|
-
if (!authMiddleware(ctx)) {
|
|
157
|
-
return unauthorizedResponse();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (!detectedBaseUrl && ctx.raw?.req) {
|
|
161
|
-
const req = ctx.raw.req;
|
|
162
|
-
const protocol = req.headers['x-forwarded-proto'] || 'http';
|
|
163
|
-
const host = req.headers.host || 'localhost:3000';
|
|
164
|
-
detectedBaseUrl = `${protocol}://${host}`;
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
statusCode: 200,
|
|
168
|
-
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
169
|
-
body: generatePlaygroundHTML(resolvedConfig, detectedBaseUrl)
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
originalGet(basePath + '/api/routes', async (ctx: Context) => {
|
|
174
|
-
// Check authentication
|
|
175
|
-
if (!authMiddleware(ctx)) {
|
|
176
|
-
return unauthorizedResponse();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Combine intercepted routes with routes from router (for file-based routing)
|
|
180
|
-
const allRoutes = getAllRoutes(routes, appInstance, basePath);
|
|
181
|
-
|
|
182
|
-
const routesData = allRoutes.map(r => ({
|
|
183
|
-
method: r.method,
|
|
184
|
-
path: r.path,
|
|
185
|
-
summary: r.meta?.summary || generateSummary(r.method as HTTPMethod, r.path),
|
|
186
|
-
description: r.meta?.description,
|
|
187
|
-
tags: r.meta?.tags || [getTagFromPath(r.path)],
|
|
188
|
-
deprecated: r.meta?.deprecated,
|
|
189
|
-
responses: r.meta?.responses,
|
|
190
|
-
example: r.meta?.example,
|
|
191
|
-
schema: {
|
|
192
|
-
body: r.schema?.body ? zodToExample(r.schema.body) : null,
|
|
193
|
-
query: r.schema?.query ? zodToParams(r.schema.query) : null,
|
|
194
|
-
params: extractPathParams(r.path)
|
|
195
|
-
}
|
|
196
|
-
}));
|
|
197
|
-
return ctx.json(routesData);
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Get all routes by combining intercepted routes with routes from the router
|
|
205
|
-
* This ensures file-based routes are also included
|
|
206
|
-
*/
|
|
207
|
-
function getAllRoutes(
|
|
208
|
-
interceptedRoutes: StoredRoute[],
|
|
209
|
-
app: Application | null,
|
|
210
|
-
basePath: string
|
|
211
|
-
): StoredRoute[] {
|
|
212
|
-
// Create a Set of already tracked route keys (method + path)
|
|
213
|
-
const trackedKeys = new Set(
|
|
214
|
-
interceptedRoutes.map(r => `${r.method}:${r.path}`)
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
// Start with intercepted routes (filtered)
|
|
218
|
-
const allRoutes: StoredRoute[] = interceptedRoutes.filter(
|
|
219
|
-
r => !r.path.startsWith(basePath)
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
// Get routes from router (includes file-based routes)
|
|
223
|
-
if (app) {
|
|
224
|
-
const routerRoutes = app.getRoutes() as Array<{
|
|
225
|
-
method: string;
|
|
226
|
-
path: string;
|
|
227
|
-
schema?: SchemaConfig;
|
|
228
|
-
meta?: RouteMeta;
|
|
229
|
-
}>;
|
|
230
|
-
|
|
231
|
-
for (const route of routerRoutes) {
|
|
232
|
-
const key = `${route.method}:${route.path}`;
|
|
233
|
-
|
|
234
|
-
// Skip if already tracked or is playground route
|
|
235
|
-
if (trackedKeys.has(key) || route.path.startsWith(basePath)) {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
allRoutes.push({
|
|
240
|
-
method: route.method as HTTPMethod,
|
|
241
|
-
path: route.path,
|
|
242
|
-
schema: route.schema,
|
|
243
|
-
meta: route.meta
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Sort routes by path for consistent ordering
|
|
249
|
-
return allRoutes.sort((a, b) => a.path.localeCompare(b.path));
|
|
250
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { HTTPMethod, RouteMeta, SchemaConfig } from "../../core/types";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configuration options for the API Playground
|
|
5
|
-
*/
|
|
6
|
-
export interface PlaygroundConfig {
|
|
7
|
-
/** URL path where the playground will be accessible (default: '/playground') */
|
|
8
|
-
path?: string;
|
|
9
|
-
|
|
10
|
-
/** Title displayed in the playground UI (default: 'API Playground') */
|
|
11
|
-
title?: string;
|
|
12
|
-
|
|
13
|
-
/** Color theme for the playground interface (default: 'dark') */
|
|
14
|
-
theme?: 'dark' | 'light';
|
|
15
|
-
|
|
16
|
-
/** Default HTTP headers to include in API requests */
|
|
17
|
-
defaultHeaders?: Record<string, string>;
|
|
18
|
-
|
|
19
|
-
/** Enable/disable request history tracking (default: true) */
|
|
20
|
-
enableHistory?: boolean;
|
|
21
|
-
|
|
22
|
-
/** Maximum number of requests to keep in history (default: 50) */
|
|
23
|
-
maxHistory?: number;
|
|
24
|
-
|
|
25
|
-
/** Enable/disable variable substitution in requests (default: true) */
|
|
26
|
-
enableVariables?: boolean;
|
|
27
|
-
|
|
28
|
-
/** Predefined variables for use in requests (e.g., {{baseUrl}}, {{token}}) */
|
|
29
|
-
variables?: Record<string, string>;
|
|
30
|
-
|
|
31
|
-
/** Enable only in development mode (default: true) */
|
|
32
|
-
developmentOnly?: boolean;
|
|
33
|
-
|
|
34
|
-
/** Basic authentication configuration to protect playground access */
|
|
35
|
-
auth?: {
|
|
36
|
-
/** Username for basic authentication */
|
|
37
|
-
username: string;
|
|
38
|
-
/** Password for basic authentication */
|
|
39
|
-
password: string;
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export interface StoredRoute {
|
|
45
|
-
method: HTTPMethod;
|
|
46
|
-
path: string;
|
|
47
|
-
schema?: SchemaConfig;
|
|
48
|
-
meta?: RouteMeta;
|
|
49
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { generateFieldExample } from './generateFieldExample';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function zodToExample(schema: any): any {
|
|
6
|
-
if (!schema?._def) return {};
|
|
7
|
-
try {
|
|
8
|
-
const shape = schema._def?.shape?.() || schema.shape;
|
|
9
|
-
if (!shape) return {};
|
|
10
|
-
const example: Record<string, any> = {};
|
|
11
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
12
|
-
example[key] = generateFieldExample(value, key);
|
|
13
|
-
}
|
|
14
|
-
return example;
|
|
15
|
-
} catch { return {}; }
|
|
16
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function zodToParams(schema: any): Array<{ name: string; optional: boolean; }> {
|
|
4
|
-
const params: Array<{ name: string; optional: boolean; }> = [];
|
|
5
|
-
try {
|
|
6
|
-
const shape = schema._def?.shape?.() || schema.shape;
|
|
7
|
-
if (shape) {
|
|
8
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
9
|
-
const def = (value as any)?._def;
|
|
10
|
-
params.push({ name: key, optional: def?.typeName === 'ZodOptional' });
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
} catch { }
|
|
14
|
-
return params;
|
|
15
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { PostmanAuth } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export function buildAuth(auth: PostmanAuth): any {
|
|
5
|
-
switch (auth.type) {
|
|
6
|
-
case 'bearer':
|
|
7
|
-
return {
|
|
8
|
-
type: 'bearer',
|
|
9
|
-
bearer: [{ key: 'token', value: auth.bearer?.token || '{{token}}', type: 'string' }]
|
|
10
|
-
};
|
|
11
|
-
case 'apikey':
|
|
12
|
-
return {
|
|
13
|
-
type: 'apikey',
|
|
14
|
-
apikey: [
|
|
15
|
-
{ key: 'key', value: auth.apikey?.key || 'X-API-Key', type: 'string' },
|
|
16
|
-
{ key: 'value', value: auth.apikey?.value || '{{apiKey}}', type: 'string' },
|
|
17
|
-
{ key: 'in', value: auth.apikey?.in || 'header', type: 'string' }
|
|
18
|
-
]
|
|
19
|
-
};
|
|
20
|
-
case 'basic':
|
|
21
|
-
return {
|
|
22
|
-
type: 'basic',
|
|
23
|
-
basic: [
|
|
24
|
-
{ key: 'username', value: auth.basic?.username || '{{username}}', type: 'string' },
|
|
25
|
-
{ key: 'password', value: auth.basic?.password || '{{password}}', type: 'string' }
|
|
26
|
-
]
|
|
27
|
-
};
|
|
28
|
-
default:
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { generateExampleFromZod } from './generateExampleFromZod';
|
|
2
|
-
import { PostmanBody } from './types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export function buildBody(bodySchema: any): PostmanBody {
|
|
6
|
-
const example = generateExampleFromZod(bodySchema);
|
|
7
|
-
|
|
8
|
-
return {
|
|
9
|
-
mode: 'raw',
|
|
10
|
-
raw: JSON.stringify(example, null, 2),
|
|
11
|
-
options: {
|
|
12
|
-
raw: { language: 'json' }
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { PostmanQuery } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export function buildQueryParams(querySchema: any): PostmanQuery[] {
|
|
5
|
-
const params: PostmanQuery[] = [];
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const shape = querySchema._def?.shape?.() || querySchema.shape;
|
|
9
|
-
if (shape) {
|
|
10
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
11
|
-
const def = (value as any)?._def;
|
|
12
|
-
const isOptional = def?.typeName === 'ZodOptional';
|
|
13
|
-
|
|
14
|
-
params.push({
|
|
15
|
-
key,
|
|
16
|
-
value: '',
|
|
17
|
-
disabled: isOptional,
|
|
18
|
-
description: isOptional ? '(optional)' : undefined
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
} catch {
|
|
23
|
-
// Ignore errors
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return params;
|
|
27
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { buildBody } from './buildBody';
|
|
2
|
-
import { buildResponses } from './buildResponses';
|
|
3
|
-
import { buildUrl } from './buildUrl';
|
|
4
|
-
import { generateName } from './generateName';
|
|
5
|
-
import { StoredRoute, PostmanConfig, PostmanItem } from './types';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export function buildRequestItem(route: StoredRoute, config: PostmanConfig): PostmanItem {
|
|
9
|
-
const meta = route.meta || {};
|
|
10
|
-
const name = meta.summary || generateName(route.method, route.path);
|
|
11
|
-
|
|
12
|
-
const item: PostmanItem = {
|
|
13
|
-
name,
|
|
14
|
-
request: {
|
|
15
|
-
method: route.method,
|
|
16
|
-
header: [
|
|
17
|
-
{ key: 'Content-Type', value: 'application/json', type: 'text' },
|
|
18
|
-
{ key: 'Accept', value: 'application/json', type: 'text' }
|
|
19
|
-
],
|
|
20
|
-
url: buildUrl(route),
|
|
21
|
-
description: meta.description
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Add request body for POST/PUT/PATCH
|
|
26
|
-
if (route.schema?.body && ['POST', 'PUT', 'PATCH'].includes(route.method)) {
|
|
27
|
-
item.request!.body = buildBody(route.schema.body);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Add example responses
|
|
31
|
-
if (config.includeExamples && meta.responses) {
|
|
32
|
-
item.response = buildResponses(meta.responses, name);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return item;
|
|
36
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { PostmanResponse } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export function buildResponses(responses: Record<number, string>, requestName: string): PostmanResponse[] {
|
|
5
|
-
return Object.entries(responses).map(([code, description]) => ({
|
|
6
|
-
name: `${requestName} - ${description}`,
|
|
7
|
-
status: description,
|
|
8
|
-
code: parseInt(code),
|
|
9
|
-
body: JSON.stringify({ message: description }, null, 2)
|
|
10
|
-
}));
|
|
11
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { buildQueryParams } from './buildQueryParams';
|
|
2
|
-
import { capitalize } from './capitalize';
|
|
3
|
-
import { StoredRoute, PostmanUrl } from './types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export function buildUrl(route: StoredRoute): PostmanUrl {
|
|
7
|
-
// Convert :param to {{param}} for Postman
|
|
8
|
-
const pathWithVars = route.path.replace(/:(\w+)/g, '{{$1}}');
|
|
9
|
-
const pathParts = pathWithVars.split('/').filter(Boolean);
|
|
10
|
-
|
|
11
|
-
const url: PostmanUrl = {
|
|
12
|
-
raw: '{{baseUrl}}' + pathWithVars,
|
|
13
|
-
host: ['{{baseUrl}}'],
|
|
14
|
-
path: pathParts
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// Add path variables
|
|
18
|
-
const pathParams = route.path.match(/:(\w+)/g);
|
|
19
|
-
if (pathParams) {
|
|
20
|
-
url.variable = pathParams.map(p => ({
|
|
21
|
-
key: p.slice(1),
|
|
22
|
-
value: '',
|
|
23
|
-
description: `${capitalize(p.slice(1))} parameter`
|
|
24
|
-
}));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Add query parameters from schema
|
|
28
|
-
if (route.schema?.query) {
|
|
29
|
-
url.query = buildQueryParams(route.schema.query);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return url;
|
|
33
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { buildAuth } from './buildAuth';
|
|
2
|
-
import { buildRequestItem } from './buildRequestItem';
|
|
3
|
-
import { generateUUID } from './generateUUID';
|
|
4
|
-
import { getTagFromPath } from './getTagFromPath';
|
|
5
|
-
import { StoredRoute, PostmanConfig, PostmanCollection, PostmanItem } from './types';
|
|
6
|
-
|
|
7
|
-
// ============================================
|
|
8
|
-
// COLLECTION GENERATION
|
|
9
|
-
// ============================================
|
|
10
|
-
|
|
11
|
-
export function generateCollection(
|
|
12
|
-
routes: StoredRoute[],
|
|
13
|
-
config: PostmanConfig,
|
|
14
|
-
baseUrl: string
|
|
15
|
-
): PostmanCollection {
|
|
16
|
-
const collection: PostmanCollection = {
|
|
17
|
-
info: {
|
|
18
|
-
_postman_id: generateUUID(),
|
|
19
|
-
name: config.name!,
|
|
20
|
-
description: config.description,
|
|
21
|
-
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
|
22
|
-
},
|
|
23
|
-
item: [],
|
|
24
|
-
variable: [
|
|
25
|
-
{ key: 'baseUrl', value: baseUrl, type: 'string' }
|
|
26
|
-
]
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Add auth if configured
|
|
30
|
-
if (config.auth) {
|
|
31
|
-
collection.auth = buildAuth(config.auth);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Group routes by tags
|
|
35
|
-
const grouped = new Map<string, StoredRoute[]>();
|
|
36
|
-
|
|
37
|
-
for (const route of routes) {
|
|
38
|
-
// Skip postman's own endpoints
|
|
39
|
-
if (route.path.startsWith(config.path!)) continue;
|
|
40
|
-
|
|
41
|
-
const tag = route.meta?.tags?.[0] || getTagFromPath(route.path);
|
|
42
|
-
|
|
43
|
-
if (!grouped.has(tag)) {
|
|
44
|
-
grouped.set(tag, []);
|
|
45
|
-
}
|
|
46
|
-
grouped.get(tag)!.push(route);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Build folder structure
|
|
50
|
-
for (const [tag, tagRoutes] of grouped) {
|
|
51
|
-
const folder: PostmanItem = {
|
|
52
|
-
name: tag,
|
|
53
|
-
item: tagRoutes.map(route => buildRequestItem(route, config))
|
|
54
|
-
};
|
|
55
|
-
collection.item.push(folder);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return collection;
|
|
59
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { generateUUID } from './generateUUID';
|
|
2
|
-
import { PostmanConfig, PostmanEnvironment, PostmanEnvVariable } from './types';
|
|
3
|
-
|
|
4
|
-
// ============================================
|
|
5
|
-
// ENVIRONMENT GENERATION
|
|
6
|
-
// ============================================
|
|
7
|
-
|
|
8
|
-
export function generateEnvironment(config: PostmanConfig, baseUrl: string): PostmanEnvironment {
|
|
9
|
-
const variables: PostmanEnvVariable[] = [
|
|
10
|
-
{ key: 'baseUrl', value: baseUrl, type: 'default', enabled: true },
|
|
11
|
-
{ key: 'token', value: '', type: 'secret', enabled: true },
|
|
12
|
-
{ key: 'apiKey', value: '', type: 'secret', enabled: true }
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
// Add custom variables
|
|
16
|
-
if (config.variables) {
|
|
17
|
-
for (const [key, value] of Object.entries(config.variables)) {
|
|
18
|
-
variables.push({
|
|
19
|
-
key,
|
|
20
|
-
value,
|
|
21
|
-
type: key.toLowerCase().includes('secret') || key.toLowerCase().includes('key')
|
|
22
|
-
? 'secret' : 'default',
|
|
23
|
-
enabled: true
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
id: generateUUID(),
|
|
30
|
-
name: config.environmentName!,
|
|
31
|
-
values: variables,
|
|
32
|
-
_postman_variable_scope: 'environment'
|
|
33
|
-
};
|
|
34
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { generateFieldExample } from './generateFieldExample';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export function generateExampleFromZod(schema: any): any {
|
|
5
|
-
if (!schema?._def) return {};
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const shape = schema._def?.shape?.() || schema.shape;
|
|
9
|
-
if (!shape) return {};
|
|
10
|
-
|
|
11
|
-
const example: Record<string, any> = {};
|
|
12
|
-
|
|
13
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
14
|
-
example[key] = generateFieldExample(value, key);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return example;
|
|
18
|
-
} catch {
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
|
-
}
|