@veloxts/router 0.6.85 → 0.6.86
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/CHANGELOG.md +9 -0
- package/GUIDE.md +51 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -2
- package/dist/openapi/generator.js +10 -0
- package/dist/openapi/html-generator.d.ts +66 -0
- package/dist/openapi/html-generator.js +116 -0
- package/dist/openapi/index.d.ts +1 -0
- package/dist/openapi/index.js +4 -0
- package/dist/openapi/plugin.js +7 -90
- package/dist/procedure/builder.js +14 -0
- package/dist/procedure/types.d.ts +27 -0
- package/dist/types.d.ts +4 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
package/GUIDE.md
CHANGED
|
@@ -134,19 +134,38 @@ await registerRestRoutes(app.server, {
|
|
|
134
134
|
});
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### REST Route Options
|
|
138
|
+
|
|
139
|
+
| Option | Type | Default | Description |
|
|
140
|
+
|--------|------|---------|-------------|
|
|
141
|
+
| `prefix` | `string` | `'/api'` | URL prefix for all routes |
|
|
142
|
+
| `procedures` | `Record<string, ProcedureCollection>` | required | Procedure collections to register |
|
|
143
|
+
| `shortcuts` | `boolean` | `false` | Generate flat shortcut routes in addition to nested routes |
|
|
144
|
+
| `nestingWarnings` | `boolean` | `true` | Warn when nesting depth exceeds 3 levels |
|
|
145
|
+
|
|
146
|
+
When `shortcuts: true`, deeply nested resources also get flat access routes:
|
|
147
|
+
```typescript
|
|
148
|
+
// With shortcuts enabled:
|
|
149
|
+
// GET /organizations/:orgId/projects/:projectId/tasks/:id (nested)
|
|
150
|
+
// GET /tasks/:id (flat shortcut)
|
|
151
|
+
```
|
|
152
|
+
|
|
137
153
|
## tRPC Adapter
|
|
138
154
|
|
|
139
155
|
```typescript
|
|
140
|
-
import { trpc, appRouter, registerTRPCPlugin } from '@veloxts/router';
|
|
156
|
+
import { trpc, appRouter, registerTRPCPlugin, type TRPCRouter } from '@veloxts/router';
|
|
141
157
|
|
|
142
158
|
const t = trpc();
|
|
143
159
|
const router = appRouter(t, [userProcedures]);
|
|
144
160
|
|
|
145
161
|
await registerTRPCPlugin(app.server, { router, prefix: '/trpc' });
|
|
146
162
|
|
|
147
|
-
|
|
163
|
+
// Use TRPCRouter for @trpc/react-query compatibility
|
|
164
|
+
export type AppRouter = TRPCRouter<typeof router>;
|
|
148
165
|
```
|
|
149
166
|
|
|
167
|
+
> **Note**: `AsTRPCRouter` is deprecated. Use `TRPCRouter` instead.
|
|
168
|
+
|
|
150
169
|
## OpenAPI Documentation
|
|
151
170
|
|
|
152
171
|
Auto-generate OpenAPI 3.0.3 specifications from your procedure definitions and serve interactive Swagger UI documentation.
|
|
@@ -221,14 +240,17 @@ await registerDocs(app.server, {
|
|
|
221
240
|
});
|
|
222
241
|
```
|
|
223
242
|
|
|
224
|
-
### CLI
|
|
243
|
+
### CLI Commands
|
|
225
244
|
|
|
226
|
-
Generate OpenAPI specs from the command line:
|
|
245
|
+
Generate and serve OpenAPI specs from the command line:
|
|
227
246
|
|
|
228
247
|
```bash
|
|
229
248
|
# Basic generation
|
|
230
249
|
velox openapi generate --output ./openapi.json
|
|
231
250
|
|
|
251
|
+
# YAML output (auto-detected from extension)
|
|
252
|
+
velox openapi generate -o ./docs/api.yaml
|
|
253
|
+
|
|
232
254
|
# Full options
|
|
233
255
|
velox openapi generate \
|
|
234
256
|
--path ./src/procedures \
|
|
@@ -236,14 +258,36 @@ velox openapi generate \
|
|
|
236
258
|
--title "My API" \
|
|
237
259
|
--version "1.0.0" \
|
|
238
260
|
--description "API documentation" \
|
|
239
|
-
--server http://localhost:3030 \
|
|
240
|
-
--server https://api.example.com \
|
|
241
|
-
--prefix /api
|
|
261
|
+
--server "http://localhost:3030|Development" \
|
|
262
|
+
--server "https://api.example.com|Production" \
|
|
263
|
+
--prefix /api \
|
|
264
|
+
--recursive \
|
|
265
|
+
--pretty
|
|
242
266
|
|
|
243
267
|
# Serve documentation locally
|
|
244
268
|
velox openapi serve --port 8080
|
|
269
|
+
|
|
270
|
+
# Serve with hot-reload on file changes
|
|
271
|
+
velox openapi serve --watch -f ./docs/api.yaml
|
|
245
272
|
```
|
|
246
273
|
|
|
274
|
+
**Available Options:**
|
|
275
|
+
|
|
276
|
+
`velox openapi generate`:
|
|
277
|
+
- `-p, --path <path>` - Procedures directory (default: `./src/procedures`)
|
|
278
|
+
- `-o, --output <file>` - Output file path (default: `./openapi.json`)
|
|
279
|
+
- `-f, --format <format>` - Output format: `json` or `yaml` (auto-detected from extension)
|
|
280
|
+
- `-s, --server <url>` - Server URL (format: `url|description`, repeatable)
|
|
281
|
+
- `--prefix <prefix>` - API route prefix (default: `/api`)
|
|
282
|
+
- `-r, --recursive` - Scan subdirectories for procedures
|
|
283
|
+
- `-q, --quiet` - Suppress output except errors
|
|
284
|
+
|
|
285
|
+
`velox openapi serve`:
|
|
286
|
+
- `-f, --file <file>` - OpenAPI spec file (default: `./openapi.json`)
|
|
287
|
+
- `--port <port>` - Server port (default: `8080`)
|
|
288
|
+
- `--host <host>` - Host to bind (default: `localhost`)
|
|
289
|
+
- `-w, --watch` - Watch for file changes and hot-reload
|
|
290
|
+
|
|
247
291
|
### Security Schemes
|
|
248
292
|
|
|
249
293
|
Guards are automatically mapped to OpenAPI security requirements:
|
package/dist/index.d.ts
CHANGED
|
@@ -105,5 +105,5 @@ export { APP_ROUTER, PROCEDURE_COLLECTIONS, REST_ADAPTER_CONFIG, ROUTER_CONFIG,
|
|
|
105
105
|
* });
|
|
106
106
|
* ```
|
|
107
107
|
*/
|
|
108
|
-
export type { BuildParametersOptions, BuildParametersResult, GuardMappingOptions, JSONSchema, OpenAPIComponents, OpenAPIContact, OpenAPIEncoding, OpenAPIExample, OpenAPIExternalDocs, OpenAPIGeneratorOptions, OpenAPIHeader, OpenAPIHttpMethod, OpenAPIInfo, OpenAPILicense, OpenAPILink, OpenAPIMediaType, OpenAPIOAuthFlow, OpenAPIOAuthFlows, OpenAPIOperation, OpenAPIParameter, OpenAPIPathItem, OpenAPIRequestBody, OpenAPIResponse, OpenAPISecurityRequirement, OpenAPISecurityScheme, OpenAPIServer, OpenAPISpec, OpenAPITag, ParameterIn, QueryParamExtractionOptions, RouteInfo, SchemaConversionOptions, SecuritySchemeType, SwaggerUIConfig, SwaggerUIPluginOptions, } from './openapi/index.js';
|
|
109
|
-
export { buildParameters, convertFromOpenAPIPath, convertToOpenAPIPath, createSecurityRequirement, createStringSchema, createSwaggerUI, DEFAULT_GUARD_MAPPINGS, DEFAULT_SECURITY_SCHEMES, extractGuardScopes, extractPathParamNames, extractQueryParameters, extractResourceFromPath, extractSchemaProperties, extractUsedSecuritySchemes, filterUsedSecuritySchemes, generateOpenApiSpec, getOpenApiRouteSummary, getOpenApiSpec, guardsRequireAuth, guardsToSecurity, hasPathParameters, joinPaths, mapGuardToSecurity, mergeSchemas, mergeSecuritySchemes, normalizePath, parsePathParameters, registerDocs, removeSchemaProperties, schemaHasProperties, swaggerUIPlugin, validateOpenApiSpec, zodSchemaToJsonSchema, } from './openapi/index.js';
|
|
108
|
+
export type { BuildParametersOptions, BuildParametersResult, GuardMappingOptions, JSONSchema, OpenAPIComponents, OpenAPIContact, OpenAPIEncoding, OpenAPIExample, OpenAPIExternalDocs, OpenAPIGeneratorOptions, OpenAPIHeader, OpenAPIHttpMethod, OpenAPIInfo, OpenAPILicense, OpenAPILink, OpenAPIMediaType, OpenAPIOAuthFlow, OpenAPIOAuthFlows, OpenAPIOperation, OpenAPIParameter, OpenAPIPathItem, OpenAPIRequestBody, OpenAPIResponse, OpenAPISecurityRequirement, OpenAPISecurityScheme, OpenAPIServer, OpenAPISpec, OpenAPITag, ParameterIn, QueryParamExtractionOptions, RouteInfo, SchemaConversionOptions, SecuritySchemeType, SwaggerUIConfig, SwaggerUIHtmlOptions, SwaggerUIPluginOptions, } from './openapi/index.js';
|
|
109
|
+
export { buildParameters, convertFromOpenAPIPath, convertToOpenAPIPath, createSecurityRequirement, createStringSchema, createSwaggerUI, DEFAULT_GUARD_MAPPINGS, DEFAULT_SECURITY_SCHEMES, DEFAULT_UI_CONFIG, escapeHtml, extractGuardScopes, extractPathParamNames, extractQueryParameters, extractResourceFromPath, extractSchemaProperties, extractUsedSecuritySchemes, filterUsedSecuritySchemes, generateOpenApiSpec, generateSwaggerUIHtml, getOpenApiRouteSummary, getOpenApiSpec, guardsRequireAuth, guardsToSecurity, hasPathParameters, joinPaths, mapGuardToSecurity, mergeSchemas, mergeSecuritySchemes, normalizePath, parsePathParameters, registerDocs, removeSchemaProperties, SWAGGER_UI_CDN, schemaHasProperties, swaggerUIPlugin, validateOpenApiSpec, zodSchemaToJsonSchema, } from './openapi/index.js';
|
package/dist/index.js
CHANGED
|
@@ -98,6 +98,8 @@ createSecurityRequirement,
|
|
|
98
98
|
// Schema converter
|
|
99
99
|
createStringSchema,
|
|
100
100
|
// Plugin
|
|
101
|
-
createSwaggerUI, DEFAULT_GUARD_MAPPINGS, DEFAULT_SECURITY_SCHEMES, extractGuardScopes, extractPathParamNames, extractQueryParameters, extractResourceFromPath, extractSchemaProperties, extractUsedSecuritySchemes, filterUsedSecuritySchemes,
|
|
101
|
+
createSwaggerUI, DEFAULT_GUARD_MAPPINGS, DEFAULT_SECURITY_SCHEMES, DEFAULT_UI_CONFIG, escapeHtml, extractGuardScopes, extractPathParamNames, extractQueryParameters, extractResourceFromPath, extractSchemaProperties, extractUsedSecuritySchemes, filterUsedSecuritySchemes,
|
|
102
102
|
// Generator
|
|
103
|
-
generateOpenApiSpec,
|
|
103
|
+
generateOpenApiSpec,
|
|
104
|
+
// HTML Generator
|
|
105
|
+
generateSwaggerUIHtml, getOpenApiRouteSummary, getOpenApiSpec, guardsRequireAuth, guardsToSecurity, hasPathParameters, joinPaths, mapGuardToSecurity, mergeSchemas, mergeSecuritySchemes, normalizePath, parsePathParameters, registerDocs, removeSchemaProperties, SWAGGER_UI_CDN, schemaHasProperties, swaggerUIPlugin, validateOpenApiSpec, zodSchemaToJsonSchema, } from './openapi/index.js';
|
|
@@ -147,6 +147,16 @@ function generateOperation(route, namespace, options) {
|
|
|
147
147
|
if (security.length > 0) {
|
|
148
148
|
operation.security = security;
|
|
149
149
|
}
|
|
150
|
+
// Add deprecation flag
|
|
151
|
+
if (procedure.deprecated) {
|
|
152
|
+
operation.deprecated = true;
|
|
153
|
+
// Add deprecation message as description suffix if present
|
|
154
|
+
if (procedure.deprecationMessage) {
|
|
155
|
+
operation.description = operation.description
|
|
156
|
+
? `${operation.description}\n\n**Deprecated:** ${procedure.deprecationMessage}`
|
|
157
|
+
: `**Deprecated:** ${procedure.deprecationMessage}`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
150
160
|
return operation;
|
|
151
161
|
}
|
|
152
162
|
// ============================================================================
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swagger UI HTML Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates standalone Swagger UI HTML pages for displaying OpenAPI specifications.
|
|
5
|
+
* This module is used by both the Fastify plugin and CLI serve command.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/router/openapi/html-generator
|
|
8
|
+
*/
|
|
9
|
+
import type { SwaggerUIConfig } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Default Swagger UI configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEFAULT_UI_CONFIG: SwaggerUIConfig;
|
|
14
|
+
/**
|
|
15
|
+
* Swagger UI CDN URLs
|
|
16
|
+
*/
|
|
17
|
+
export declare const SWAGGER_UI_CDN: {
|
|
18
|
+
css: string;
|
|
19
|
+
bundle: string;
|
|
20
|
+
standalonePreset: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Options for generating Swagger UI HTML
|
|
24
|
+
*/
|
|
25
|
+
export interface SwaggerUIHtmlOptions {
|
|
26
|
+
/**
|
|
27
|
+
* URL where the OpenAPI spec can be fetched
|
|
28
|
+
*/
|
|
29
|
+
specUrl: string;
|
|
30
|
+
/**
|
|
31
|
+
* Page title
|
|
32
|
+
* @default 'API Documentation'
|
|
33
|
+
*/
|
|
34
|
+
title?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Custom favicon URL
|
|
37
|
+
*/
|
|
38
|
+
favicon?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Swagger UI configuration options
|
|
41
|
+
*/
|
|
42
|
+
config?: Partial<SwaggerUIConfig>;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generates a standalone Swagger UI HTML page
|
|
46
|
+
*
|
|
47
|
+
* @param options - HTML generation options
|
|
48
|
+
* @returns Complete HTML document as string
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const html = generateSwaggerUIHtml({
|
|
53
|
+
* specUrl: '/openapi.json',
|
|
54
|
+
* title: 'My API Documentation',
|
|
55
|
+
* config: { tryItOutEnabled: true },
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateSwaggerUIHtml(options: SwaggerUIHtmlOptions): string;
|
|
60
|
+
/**
|
|
61
|
+
* Escapes HTML special characters to prevent XSS
|
|
62
|
+
*
|
|
63
|
+
* @param text - Text to escape
|
|
64
|
+
* @returns Escaped text
|
|
65
|
+
*/
|
|
66
|
+
export declare function escapeHtml(text: string): string;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swagger UI HTML Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates standalone Swagger UI HTML pages for displaying OpenAPI specifications.
|
|
5
|
+
* This module is used by both the Fastify plugin and CLI serve command.
|
|
6
|
+
*
|
|
7
|
+
* @module @veloxts/router/openapi/html-generator
|
|
8
|
+
*/
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Constants
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Default Swagger UI configuration
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_UI_CONFIG = {
|
|
16
|
+
deepLinking: true,
|
|
17
|
+
displayOperationId: false,
|
|
18
|
+
defaultModelsExpandDepth: 1,
|
|
19
|
+
defaultModelExpandDepth: 1,
|
|
20
|
+
docExpansion: 'list',
|
|
21
|
+
filter: false,
|
|
22
|
+
showExtensions: false,
|
|
23
|
+
tryItOutEnabled: true,
|
|
24
|
+
persistAuthorization: false,
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Swagger UI CDN URLs
|
|
28
|
+
*/
|
|
29
|
+
export const SWAGGER_UI_CDN = {
|
|
30
|
+
css: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui.css',
|
|
31
|
+
bundle: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js',
|
|
32
|
+
standalonePreset: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js',
|
|
33
|
+
};
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// HTML Generation
|
|
36
|
+
// ============================================================================
|
|
37
|
+
/**
|
|
38
|
+
* Generates a standalone Swagger UI HTML page
|
|
39
|
+
*
|
|
40
|
+
* @param options - HTML generation options
|
|
41
|
+
* @returns Complete HTML document as string
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* const html = generateSwaggerUIHtml({
|
|
46
|
+
* specUrl: '/openapi.json',
|
|
47
|
+
* title: 'My API Documentation',
|
|
48
|
+
* config: { tryItOutEnabled: true },
|
|
49
|
+
* });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function generateSwaggerUIHtml(options) {
|
|
53
|
+
const { specUrl, title = 'API Documentation', favicon, config = {} } = options;
|
|
54
|
+
// Merge config with defaults
|
|
55
|
+
const mergedConfig = {
|
|
56
|
+
...DEFAULT_UI_CONFIG,
|
|
57
|
+
...config,
|
|
58
|
+
};
|
|
59
|
+
const configJson = JSON.stringify({
|
|
60
|
+
url: specUrl,
|
|
61
|
+
dom_id: '#swagger-ui',
|
|
62
|
+
deepLinking: mergedConfig.deepLinking,
|
|
63
|
+
displayOperationId: mergedConfig.displayOperationId,
|
|
64
|
+
defaultModelsExpandDepth: mergedConfig.defaultModelsExpandDepth,
|
|
65
|
+
defaultModelExpandDepth: mergedConfig.defaultModelExpandDepth,
|
|
66
|
+
docExpansion: mergedConfig.docExpansion,
|
|
67
|
+
filter: mergedConfig.filter,
|
|
68
|
+
showExtensions: mergedConfig.showExtensions,
|
|
69
|
+
tryItOutEnabled: mergedConfig.tryItOutEnabled,
|
|
70
|
+
persistAuthorization: mergedConfig.persistAuthorization,
|
|
71
|
+
presets: ['SwaggerUIBundle.presets.apis', 'SwaggerUIStandalonePreset'],
|
|
72
|
+
plugins: ['SwaggerUIBundle.plugins.DownloadUrl'],
|
|
73
|
+
layout: 'StandaloneLayout',
|
|
74
|
+
});
|
|
75
|
+
const faviconTag = favicon ? `<link rel="icon" type="image/x-icon" href="${favicon}">` : '';
|
|
76
|
+
return `<!DOCTYPE html>
|
|
77
|
+
<html lang="en">
|
|
78
|
+
<head>
|
|
79
|
+
<meta charset="UTF-8">
|
|
80
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
81
|
+
<title>${escapeHtml(title)}</title>
|
|
82
|
+
${faviconTag}
|
|
83
|
+
<link rel="stylesheet" href="${SWAGGER_UI_CDN.css}">
|
|
84
|
+
<style>
|
|
85
|
+
html { box-sizing: border-box; overflow-y: scroll; }
|
|
86
|
+
*, *:before, *:after { box-sizing: inherit; }
|
|
87
|
+
body { margin: 0; background: #fafafa; }
|
|
88
|
+
.swagger-ui .topbar { display: none; }
|
|
89
|
+
</style>
|
|
90
|
+
</head>
|
|
91
|
+
<body>
|
|
92
|
+
<div id="swagger-ui"></div>
|
|
93
|
+
<script src="${SWAGGER_UI_CDN.bundle}"></script>
|
|
94
|
+
<script src="${SWAGGER_UI_CDN.standalonePreset}"></script>
|
|
95
|
+
<script>
|
|
96
|
+
window.onload = function() {
|
|
97
|
+
window.ui = SwaggerUIBundle(${configJson.replace(/"(SwaggerUIBundle\.presets\.apis|SwaggerUIStandalonePreset|SwaggerUIBundle\.plugins\.DownloadUrl)"/g, '$1')});
|
|
98
|
+
};
|
|
99
|
+
</script>
|
|
100
|
+
</body>
|
|
101
|
+
</html>`;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Escapes HTML special characters to prevent XSS
|
|
105
|
+
*
|
|
106
|
+
* @param text - Text to escape
|
|
107
|
+
* @returns Escaped text
|
|
108
|
+
*/
|
|
109
|
+
export function escapeHtml(text) {
|
|
110
|
+
return text
|
|
111
|
+
.replace(/&/g, '&')
|
|
112
|
+
.replace(/</g, '<')
|
|
113
|
+
.replace(/>/g, '>')
|
|
114
|
+
.replace(/"/g, '"')
|
|
115
|
+
.replace(/'/g, ''');
|
|
116
|
+
}
|
package/dist/openapi/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
export { generateOpenApiSpec, getOpenApiRouteSummary, validateOpenApiSpec, } from './generator.js';
|
|
33
33
|
export { createSwaggerUI, getOpenApiSpec, registerDocs, swaggerUIPlugin, } from './plugin.js';
|
|
34
|
+
export { DEFAULT_UI_CONFIG, escapeHtml, generateSwaggerUIHtml, SWAGGER_UI_CDN, type SwaggerUIHtmlOptions, } from './html-generator.js';
|
|
34
35
|
export { createStringSchema, extractSchemaProperties, mergeSchemas, removeSchemaProperties, type SchemaConversionOptions, schemaHasProperties, zodSchemaToJsonSchema, } from './schema-converter.js';
|
|
35
36
|
export { type BuildParametersOptions, type BuildParametersResult, buildParameters, convertFromOpenAPIPath, convertToOpenAPIPath, extractPathParamNames, extractQueryParameters, extractResourceFromPath, hasPathParameters, joinPaths, normalizePath, parsePathParameters, type QueryParamExtractionOptions, } from './path-extractor.js';
|
|
36
37
|
export { createSecurityRequirement, DEFAULT_GUARD_MAPPINGS, DEFAULT_SECURITY_SCHEMES, extractGuardScopes, extractUsedSecuritySchemes, filterUsedSecuritySchemes, type GuardMappingOptions, guardsRequireAuth, guardsToSecurity, mapGuardToSecurity, mergeSecuritySchemes, } from './security-mapper.js';
|
package/dist/openapi/index.js
CHANGED
|
@@ -38,6 +38,10 @@ export { generateOpenApiSpec, getOpenApiRouteSummary, validateOpenApiSpec, } fro
|
|
|
38
38
|
// ============================================================================
|
|
39
39
|
export { createSwaggerUI, getOpenApiSpec, registerDocs, swaggerUIPlugin, } from './plugin.js';
|
|
40
40
|
// ============================================================================
|
|
41
|
+
// HTML Generator
|
|
42
|
+
// ============================================================================
|
|
43
|
+
export { DEFAULT_UI_CONFIG, escapeHtml, generateSwaggerUIHtml, SWAGGER_UI_CDN, } from './html-generator.js';
|
|
44
|
+
// ============================================================================
|
|
41
45
|
// Schema Converter
|
|
42
46
|
// ============================================================================
|
|
43
47
|
export { createStringSchema, extractSchemaProperties, mergeSchemas, removeSchemaProperties, schemaHasProperties, zodSchemaToJsonSchema, } from './schema-converter.js';
|
package/dist/openapi/plugin.js
CHANGED
|
@@ -6,90 +6,7 @@
|
|
|
6
6
|
* @module @veloxts/router/openapi/plugin
|
|
7
7
|
*/
|
|
8
8
|
import { generateOpenApiSpec } from './generator.js';
|
|
9
|
-
|
|
10
|
-
// Swagger UI HTML Generation
|
|
11
|
-
// ============================================================================
|
|
12
|
-
/**
|
|
13
|
-
* Default Swagger UI configuration
|
|
14
|
-
*/
|
|
15
|
-
const DEFAULT_UI_CONFIG = {
|
|
16
|
-
deepLinking: true,
|
|
17
|
-
displayOperationId: false,
|
|
18
|
-
defaultModelsExpandDepth: 1,
|
|
19
|
-
defaultModelExpandDepth: 1,
|
|
20
|
-
docExpansion: 'list',
|
|
21
|
-
filter: false,
|
|
22
|
-
showExtensions: false,
|
|
23
|
-
tryItOutEnabled: true,
|
|
24
|
-
persistAuthorization: false,
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Swagger UI CDN URLs
|
|
28
|
-
*/
|
|
29
|
-
const SWAGGER_UI_CDN = {
|
|
30
|
-
css: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui.css',
|
|
31
|
-
bundle: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js',
|
|
32
|
-
standalonePreset: 'https://unpkg.com/swagger-ui-dist@5/swagger-ui-standalone-preset.js',
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Generates the Swagger UI HTML page
|
|
36
|
-
*/
|
|
37
|
-
function generateSwaggerUIHtml(specUrl, config, title, favicon) {
|
|
38
|
-
const configJson = JSON.stringify({
|
|
39
|
-
url: specUrl,
|
|
40
|
-
dom_id: '#swagger-ui',
|
|
41
|
-
deepLinking: config.deepLinking,
|
|
42
|
-
displayOperationId: config.displayOperationId,
|
|
43
|
-
defaultModelsExpandDepth: config.defaultModelsExpandDepth,
|
|
44
|
-
defaultModelExpandDepth: config.defaultModelExpandDepth,
|
|
45
|
-
docExpansion: config.docExpansion,
|
|
46
|
-
filter: config.filter,
|
|
47
|
-
showExtensions: config.showExtensions,
|
|
48
|
-
tryItOutEnabled: config.tryItOutEnabled,
|
|
49
|
-
persistAuthorization: config.persistAuthorization,
|
|
50
|
-
presets: ['SwaggerUIBundle.presets.apis', 'SwaggerUIStandalonePreset'],
|
|
51
|
-
plugins: ['SwaggerUIBundle.plugins.DownloadUrl'],
|
|
52
|
-
layout: 'StandaloneLayout',
|
|
53
|
-
});
|
|
54
|
-
const faviconTag = favicon ? `<link rel="icon" type="image/x-icon" href="${favicon}">` : '';
|
|
55
|
-
return `<!DOCTYPE html>
|
|
56
|
-
<html lang="en">
|
|
57
|
-
<head>
|
|
58
|
-
<meta charset="UTF-8">
|
|
59
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
60
|
-
<title>${escapeHtml(title)}</title>
|
|
61
|
-
${faviconTag}
|
|
62
|
-
<link rel="stylesheet" href="${SWAGGER_UI_CDN.css}">
|
|
63
|
-
<style>
|
|
64
|
-
html { box-sizing: border-box; overflow-y: scroll; }
|
|
65
|
-
*, *:before, *:after { box-sizing: inherit; }
|
|
66
|
-
body { margin: 0; background: #fafafa; }
|
|
67
|
-
.swagger-ui .topbar { display: none; }
|
|
68
|
-
</style>
|
|
69
|
-
</head>
|
|
70
|
-
<body>
|
|
71
|
-
<div id="swagger-ui"></div>
|
|
72
|
-
<script src="${SWAGGER_UI_CDN.bundle}"></script>
|
|
73
|
-
<script src="${SWAGGER_UI_CDN.standalonePreset}"></script>
|
|
74
|
-
<script>
|
|
75
|
-
window.onload = function() {
|
|
76
|
-
window.ui = SwaggerUIBundle(${configJson.replace(/"(SwaggerUIBundle\.presets\.apis|SwaggerUIStandalonePreset|SwaggerUIBundle\.plugins\.DownloadUrl)"/g, '$1')});
|
|
77
|
-
};
|
|
78
|
-
</script>
|
|
79
|
-
</body>
|
|
80
|
-
</html>`;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Escapes HTML special characters
|
|
84
|
-
*/
|
|
85
|
-
function escapeHtml(text) {
|
|
86
|
-
return text
|
|
87
|
-
.replace(/&/g, '&')
|
|
88
|
-
.replace(/</g, '<')
|
|
89
|
-
.replace(/>/g, '>')
|
|
90
|
-
.replace(/"/g, '"')
|
|
91
|
-
.replace(/'/g, ''');
|
|
92
|
-
}
|
|
9
|
+
import { generateSwaggerUIHtml } from './html-generator.js';
|
|
93
10
|
// ============================================================================
|
|
94
11
|
// Fastify Plugin
|
|
95
12
|
// ============================================================================
|
|
@@ -118,11 +35,6 @@ function escapeHtml(text) {
|
|
|
118
35
|
*/
|
|
119
36
|
export const swaggerUIPlugin = async (fastify, options) => {
|
|
120
37
|
const { routePrefix = '/docs', specRoute = `${routePrefix}/openapi.json`, uiConfig = {}, openapi, collections, title = 'API Documentation', favicon, } = options;
|
|
121
|
-
// Merge UI config with defaults
|
|
122
|
-
const mergedConfig = {
|
|
123
|
-
...DEFAULT_UI_CONFIG,
|
|
124
|
-
...uiConfig,
|
|
125
|
-
};
|
|
126
38
|
// Generate the OpenAPI specification
|
|
127
39
|
let spec;
|
|
128
40
|
try {
|
|
@@ -137,7 +49,12 @@ export const swaggerUIPlugin = async (fastify, options) => {
|
|
|
137
49
|
return reply.header('Content-Type', 'application/json').send(spec);
|
|
138
50
|
});
|
|
139
51
|
// Register Swagger UI HTML route
|
|
140
|
-
const htmlContent = generateSwaggerUIHtml(
|
|
52
|
+
const htmlContent = generateSwaggerUIHtml({
|
|
53
|
+
specUrl: specRoute,
|
|
54
|
+
title,
|
|
55
|
+
favicon,
|
|
56
|
+
config: uiConfig,
|
|
57
|
+
});
|
|
141
58
|
fastify.get(routePrefix, async (_request, reply) => {
|
|
142
59
|
return reply.header('Content-Type', 'text/html; charset=utf-8').send(htmlContent);
|
|
143
60
|
});
|
|
@@ -117,6 +117,8 @@ export function procedure() {
|
|
|
117
117
|
restOverride: undefined,
|
|
118
118
|
parentResource: undefined,
|
|
119
119
|
parentResources: undefined,
|
|
120
|
+
deprecated: undefined,
|
|
121
|
+
deprecationMessage: undefined,
|
|
120
122
|
});
|
|
121
123
|
}
|
|
122
124
|
// ============================================================================
|
|
@@ -210,6 +212,16 @@ function createBuilder(state) {
|
|
|
210
212
|
restOverride: config,
|
|
211
213
|
});
|
|
212
214
|
},
|
|
215
|
+
/**
|
|
216
|
+
* Marks the procedure as deprecated
|
|
217
|
+
*/
|
|
218
|
+
deprecated(message) {
|
|
219
|
+
return createBuilder({
|
|
220
|
+
...state,
|
|
221
|
+
deprecated: true,
|
|
222
|
+
deprecationMessage: message,
|
|
223
|
+
});
|
|
224
|
+
},
|
|
213
225
|
/**
|
|
214
226
|
* Declares a parent resource for nested routes (single level)
|
|
215
227
|
*/
|
|
@@ -275,6 +287,8 @@ function compileProcedure(type, handler, state) {
|
|
|
275
287
|
middlewares: typedMiddlewares,
|
|
276
288
|
guards: state.guards,
|
|
277
289
|
restOverride: state.restOverride,
|
|
290
|
+
deprecated: state.deprecated,
|
|
291
|
+
deprecationMessage: state.deprecationMessage,
|
|
278
292
|
parentResource: state.parentResource,
|
|
279
293
|
parentResources: state.parentResources,
|
|
280
294
|
// Store pre-compiled executor for performance
|
|
@@ -248,6 +248,29 @@ export interface ProcedureBuilder<TInput = unknown, TOutput = unknown, TContext
|
|
|
248
248
|
* ```
|
|
249
249
|
*/
|
|
250
250
|
rest(config: RestRouteOverride): ProcedureBuilder<TInput, TOutput, TContext>;
|
|
251
|
+
/**
|
|
252
|
+
* Marks the procedure as deprecated
|
|
253
|
+
*
|
|
254
|
+
* Deprecated procedures will be marked in OpenAPI documentation with the
|
|
255
|
+
* deprecated flag, helping API consumers know they should migrate to alternatives.
|
|
256
|
+
*
|
|
257
|
+
* @param message - Optional message explaining the deprecation and suggesting alternatives
|
|
258
|
+
* @returns Same builder (no type changes)
|
|
259
|
+
*
|
|
260
|
+
* @example
|
|
261
|
+
* ```typescript
|
|
262
|
+
* // Simple deprecation
|
|
263
|
+
* procedure()
|
|
264
|
+
* .deprecated()
|
|
265
|
+
* .query(handler);
|
|
266
|
+
*
|
|
267
|
+
* // With migration message
|
|
268
|
+
* procedure()
|
|
269
|
+
* .deprecated('Use getUserById instead. This endpoint will be removed in v2.0.')
|
|
270
|
+
* .query(handler);
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
deprecated(message?: string): ProcedureBuilder<TInput, TOutput, TContext>;
|
|
251
274
|
/**
|
|
252
275
|
* Declares a parent resource for nested routes (single level)
|
|
253
276
|
*
|
|
@@ -368,6 +391,10 @@ export interface BuilderRuntimeState {
|
|
|
368
391
|
parentResource?: ParentResourceConfig;
|
|
369
392
|
/** Multi-level parent resource configuration for deeply nested routes */
|
|
370
393
|
parentResources?: ParentResourceConfig[];
|
|
394
|
+
/** Whether this procedure is deprecated */
|
|
395
|
+
deprecated?: boolean;
|
|
396
|
+
/** Deprecation message */
|
|
397
|
+
deprecationMessage?: string;
|
|
371
398
|
}
|
|
372
399
|
/**
|
|
373
400
|
* Type for the procedures object passed to defineProcedures
|
package/dist/types.d.ts
CHANGED
|
@@ -271,6 +271,10 @@ export interface CompiledProcedure<TInput = unknown, TOutput = unknown, TContext
|
|
|
271
271
|
readonly guards: ReadonlyArray<GuardLike<TContext>>;
|
|
272
272
|
/** REST route override (if specified) */
|
|
273
273
|
readonly restOverride?: RestRouteOverride;
|
|
274
|
+
/** Whether this procedure is deprecated */
|
|
275
|
+
readonly deprecated?: boolean;
|
|
276
|
+
/** Deprecation message explaining why and what to use instead */
|
|
277
|
+
readonly deprecationMessage?: string;
|
|
274
278
|
/**
|
|
275
279
|
* Parent resource configuration for nested routes (single level)
|
|
276
280
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veloxts/router",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.86",
|
|
4
4
|
"description": "Procedure definitions with tRPC and REST routing for VeloxTS framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"@trpc/server": "11.8.0",
|
|
41
41
|
"fastify": "5.6.2",
|
|
42
42
|
"zod-to-json-schema": "3.24.5",
|
|
43
|
-
"@veloxts/
|
|
44
|
-
"@veloxts/
|
|
43
|
+
"@veloxts/validation": "0.6.86",
|
|
44
|
+
"@veloxts/core": "0.6.86"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@vitest/coverage-v8": "4.0.16",
|