@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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # @veloxts/router
2
2
 
3
+ ## 0.6.86
4
+
5
+ ### Patch Changes
6
+
7
+ - updated documentation
8
+ - Updated dependencies
9
+ - @veloxts/core@0.6.86
10
+ - @veloxts/validation@0.6.86
11
+
3
12
  ## 0.6.85
4
13
 
5
14
  ### Patch Changes
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
- export type AppRouter = typeof router;
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 Command
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, getOpenApiRouteSummary, getOpenApiSpec, guardsRequireAuth, guardsToSecurity, hasPathParameters, joinPaths, mapGuardToSecurity, mergeSchemas, mergeSecuritySchemes, normalizePath, parsePathParameters, registerDocs, removeSchemaProperties, schemaHasProperties, swaggerUIPlugin, validateOpenApiSpec, zodSchemaToJsonSchema, } from './openapi/index.js';
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, '&amp;')
112
+ .replace(/</g, '&lt;')
113
+ .replace(/>/g, '&gt;')
114
+ .replace(/"/g, '&quot;')
115
+ .replace(/'/g, '&#039;');
116
+ }
@@ -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';
@@ -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';
@@ -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, '&amp;')
88
- .replace(/</g, '&lt;')
89
- .replace(/>/g, '&gt;')
90
- .replace(/"/g, '&quot;')
91
- .replace(/'/g, '&#039;');
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(specRoute, mergedConfig, title, favicon);
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.85",
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/core": "0.6.85",
44
- "@veloxts/validation": "0.6.85"
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",