@veloxts/router 0.6.84 → 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 +18 -0
- package/GUIDE.md +51 -7
- package/dist/expose.d.ts +12 -9
- package/dist/expose.js +13 -9
- package/dist/index.d.ts +10 -6
- package/dist/index.js +6 -3
- package/dist/middleware/chain.d.ts +54 -0
- package/dist/middleware/chain.js +80 -0
- package/dist/middleware/index.d.ts +7 -0
- package/dist/middleware/index.js +6 -0
- 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 +36 -59
- package/dist/procedure/types.d.ts +66 -6
- package/dist/rest/adapter.d.ts +38 -1
- package/dist/rest/adapter.js +94 -27
- package/dist/rest/index.d.ts +2 -2
- package/dist/rest/index.js +1 -1
- package/dist/rest/naming.d.ts +38 -2
- package/dist/rest/naming.js +65 -18
- package/dist/rpc.d.ts +144 -0
- package/dist/rpc.js +127 -0
- package/dist/trpc/adapter.d.ts +139 -10
- package/dist/trpc/adapter.js +33 -61
- package/dist/trpc/index.d.ts +3 -1
- package/dist/types.d.ts +51 -7
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
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
|
+
|
|
12
|
+
## 0.6.85
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- implement missing features from original requirements
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
- @veloxts/core@0.6.85
|
|
19
|
+
- @veloxts/validation@0.6.85
|
|
20
|
+
|
|
3
21
|
## 0.6.84
|
|
4
22
|
|
|
5
23
|
### 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
|
-
|
|
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/expose.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module serve
|
|
8
8
|
*/
|
|
9
9
|
import { type VeloxApp } from '@veloxts/core';
|
|
10
|
-
import { type AnyRouter } from './trpc/index.js';
|
|
10
|
+
import { type AnyRouter, type InferRouterFromCollections } from './trpc/index.js';
|
|
11
11
|
import type { ProcedureCollection } from './types.js';
|
|
12
12
|
/**
|
|
13
13
|
* Options for serving procedures
|
|
@@ -38,38 +38,41 @@ export interface ServeOptions {
|
|
|
38
38
|
* This is the recommended way to register your API.
|
|
39
39
|
* Define your procedures once, serve them everywhere.
|
|
40
40
|
*
|
|
41
|
+
* **IMPORTANT**: Use `as const` on the procedures array to preserve
|
|
42
|
+
* literal types for full type inference on the returned router.
|
|
43
|
+
*
|
|
41
44
|
* @param app - VeloxTS application instance
|
|
42
|
-
* @param procedures - Array of procedure collections to serve
|
|
45
|
+
* @param procedures - Array of procedure collections to serve (use `as const`)
|
|
43
46
|
* @param options - Optional configuration for API and RPC prefixes
|
|
44
|
-
* @returns The tRPC router for type exports
|
|
47
|
+
* @returns The typed tRPC router for type exports
|
|
45
48
|
*
|
|
46
49
|
* @example
|
|
47
50
|
* ```typescript
|
|
48
51
|
* // Both REST (/api) and tRPC (/trpc) with zero config
|
|
49
|
-
* const router = await serve(app, [healthProcedures, userProcedures]);
|
|
50
|
-
* export type AppRouter = typeof router;
|
|
52
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const);
|
|
53
|
+
* export type AppRouter = typeof router; // Fully typed!
|
|
51
54
|
* ```
|
|
52
55
|
*
|
|
53
56
|
* @example
|
|
54
57
|
* ```typescript
|
|
55
58
|
* // REST only (external API)
|
|
56
|
-
* await serve(app, [healthProcedures, userProcedures], { rpc: false });
|
|
59
|
+
* await serve(app, [healthProcedures, userProcedures] as const, { rpc: false });
|
|
57
60
|
* ```
|
|
58
61
|
*
|
|
59
62
|
* @example
|
|
60
63
|
* ```typescript
|
|
61
64
|
* // tRPC only (internal app)
|
|
62
|
-
* const router = await serve(app, [healthProcedures, userProcedures], { api: false });
|
|
65
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const, { api: false });
|
|
63
66
|
* export type AppRouter = typeof router;
|
|
64
67
|
* ```
|
|
65
68
|
*
|
|
66
69
|
* @example
|
|
67
70
|
* ```typescript
|
|
68
71
|
* // Custom prefixes
|
|
69
|
-
* const router = await serve(app, [healthProcedures, userProcedures], {
|
|
72
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const, {
|
|
70
73
|
* api: '/v1',
|
|
71
74
|
* rpc: '/rpc',
|
|
72
75
|
* });
|
|
73
76
|
* ```
|
|
74
77
|
*/
|
|
75
|
-
export declare function serve(app: VeloxApp, procedures:
|
|
78
|
+
export declare function serve<const T extends readonly ProcedureCollection[]>(app: VeloxApp, procedures: T, options?: ServeOptions): Promise<AnyRouter & InferRouterFromCollections<T>>;
|
package/dist/expose.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { fail } from '@veloxts/core';
|
|
10
10
|
import { rest } from './rest/index.js';
|
|
11
|
-
import { appRouter, registerTRPCPlugin, trpc } from './trpc/index.js';
|
|
11
|
+
import { appRouter, registerTRPCPlugin, trpc, } from './trpc/index.js';
|
|
12
12
|
// ============================================================================
|
|
13
13
|
// Main Function
|
|
14
14
|
// ============================================================================
|
|
@@ -18,35 +18,38 @@ import { appRouter, registerTRPCPlugin, trpc } from './trpc/index.js';
|
|
|
18
18
|
* This is the recommended way to register your API.
|
|
19
19
|
* Define your procedures once, serve them everywhere.
|
|
20
20
|
*
|
|
21
|
+
* **IMPORTANT**: Use `as const` on the procedures array to preserve
|
|
22
|
+
* literal types for full type inference on the returned router.
|
|
23
|
+
*
|
|
21
24
|
* @param app - VeloxTS application instance
|
|
22
|
-
* @param procedures - Array of procedure collections to serve
|
|
25
|
+
* @param procedures - Array of procedure collections to serve (use `as const`)
|
|
23
26
|
* @param options - Optional configuration for API and RPC prefixes
|
|
24
|
-
* @returns The tRPC router for type exports
|
|
27
|
+
* @returns The typed tRPC router for type exports
|
|
25
28
|
*
|
|
26
29
|
* @example
|
|
27
30
|
* ```typescript
|
|
28
31
|
* // Both REST (/api) and tRPC (/trpc) with zero config
|
|
29
|
-
* const router = await serve(app, [healthProcedures, userProcedures]);
|
|
30
|
-
* export type AppRouter = typeof router;
|
|
32
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const);
|
|
33
|
+
* export type AppRouter = typeof router; // Fully typed!
|
|
31
34
|
* ```
|
|
32
35
|
*
|
|
33
36
|
* @example
|
|
34
37
|
* ```typescript
|
|
35
38
|
* // REST only (external API)
|
|
36
|
-
* await serve(app, [healthProcedures, userProcedures], { rpc: false });
|
|
39
|
+
* await serve(app, [healthProcedures, userProcedures] as const, { rpc: false });
|
|
37
40
|
* ```
|
|
38
41
|
*
|
|
39
42
|
* @example
|
|
40
43
|
* ```typescript
|
|
41
44
|
* // tRPC only (internal app)
|
|
42
|
-
* const router = await serve(app, [healthProcedures, userProcedures], { api: false });
|
|
45
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const, { api: false });
|
|
43
46
|
* export type AppRouter = typeof router;
|
|
44
47
|
* ```
|
|
45
48
|
*
|
|
46
49
|
* @example
|
|
47
50
|
* ```typescript
|
|
48
51
|
* // Custom prefixes
|
|
49
|
-
* const router = await serve(app, [healthProcedures, userProcedures], {
|
|
52
|
+
* const router = await serve(app, [healthProcedures, userProcedures] as const, {
|
|
50
53
|
* api: '/v1',
|
|
51
54
|
* rpc: '/rpc',
|
|
52
55
|
* });
|
|
@@ -73,7 +76,8 @@ export async function serve(app, procedures, options = {}) {
|
|
|
73
76
|
}
|
|
74
77
|
// Register REST routes if enabled
|
|
75
78
|
if (apiPrefix !== false) {
|
|
76
|
-
|
|
79
|
+
// Need to spread to convert readonly tuple to mutable array for rest()
|
|
80
|
+
app.routes(rest([...procedures], { prefix: apiPrefix }));
|
|
77
81
|
}
|
|
78
82
|
return router;
|
|
79
83
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
*/
|
|
40
40
|
/** Router package version */
|
|
41
41
|
export declare const ROUTER_VERSION: string;
|
|
42
|
-
export type { CompiledProcedure, ContextExtensions, ContextFactory, ExtendedContext, GuardLike, HttpMethod, InferProcedureContext, InferProcedureInput, InferProcedureOutput, InferProcedureTypes, MiddlewareArgs, MiddlewareFunction, MiddlewareNext, MiddlewareResult, ParentResourceConfig, ProcedureCollection, ProcedureHandler, ProcedureHandlerArgs, ProcedureRecord, ProcedureType, RestRouteOverride, } from './types.js';
|
|
42
|
+
export type { CompiledProcedure, ContextExtensions, ContextFactory, ExtendedContext, GuardLike, HttpMethod, InferProcedureContext, InferProcedureInput, InferProcedureOutput, InferProcedureTypes, MiddlewareArgs, MiddlewareFunction, MiddlewareNext, MiddlewareResult, ParentResourceChain, ParentResourceConfig, ProcedureCollection, ProcedureHandler, ProcedureHandlerArgs, ProcedureRecord, ProcedureType, RestRouteOverride, } from './types.js';
|
|
43
43
|
export { PROCEDURE_METHOD_MAP, } from './types.js';
|
|
44
44
|
export type { GuardErrorResponse, RouterErrorCode } from './errors.js';
|
|
45
45
|
export { GuardError, isGuardError } from './errors.js';
|
|
@@ -51,10 +51,14 @@ export type { RouterResult } from './router-utils.js';
|
|
|
51
51
|
export { createRouter, toRouter } from './router-utils.js';
|
|
52
52
|
export type { NamingWarning, NamingWarningType, WarningConfig, WarningOption } from './warnings.js';
|
|
53
53
|
export { analyzeNamingConvention, isDevelopment, normalizeWarningOption } from './warnings.js';
|
|
54
|
-
export type { ExtractRoutesType, RestAdapterOptions, RestMapping, RestRoute, RouteMap, } from './rest/index.js';
|
|
55
|
-
export { buildNestedRestPath, buildRestPath, extractRoutes, followsNamingConvention, generateRestRoutes, getRouteSummary, inferResourceName, parseNamingConvention, registerRestRoutes, rest, } from './rest/index.js';
|
|
56
|
-
export type { AnyRouter,
|
|
54
|
+
export type { ExtractRoutesType, GenerateRestRoutesOptions, RestAdapterOptions, RestMapping, RestRoute, RouteMap, } from './rest/index.js';
|
|
55
|
+
export { buildMultiLevelNestedPath, buildNestedRestPath, buildRestPath, calculateNestingDepth, extractRoutes, followsNamingConvention, generateRestRoutes, getRouteSummary, inferResourceName, parseNamingConvention, registerRestRoutes, rest, } from './rest/index.js';
|
|
56
|
+
export type { AnyRouter,
|
|
57
|
+
/** @deprecated Use `TRPCRouter` instead */
|
|
58
|
+
AsTRPCRouter, CollectionsToRouterRecord, ExtractNamespace, ExtractProcedures, InferAppRouter, InferRouterFromCollections, MapProcedureRecordToTRPC, MapProcedureToTRPC, TRPCInstance, TRPCPluginOptions, TRPCRouter, } from './trpc/index.js';
|
|
57
59
|
export { appRouter, buildTRPCRouter, createTRPCContextFactory, registerTRPCPlugin, trpc, veloxErrorToTRPCError, } from './trpc/index.js';
|
|
60
|
+
export type { RpcOptions, RpcResult } from './rpc.js';
|
|
61
|
+
export { registerRpc, rpc } from './rpc.js';
|
|
58
62
|
export type { DiscoveryOptions, DiscoveryResult, DiscoveryWarning } from './discovery/index.js';
|
|
59
63
|
export { DiscoveryError, DiscoveryErrorCode, directoryNotFound, discoverProcedures, discoverProceduresVerbose, fileLoadError, invalidExport, invalidFileType, isDiscoveryError, noProceduresFound, permissionDenied, } from './discovery/index.js';
|
|
60
64
|
export type { ServeOptions } from './expose.js';
|
|
@@ -101,5 +105,5 @@ export { APP_ROUTER, PROCEDURE_COLLECTIONS, REST_ADAPTER_CONFIG, ROUTER_CONFIG,
|
|
|
101
105
|
* });
|
|
102
106
|
* ```
|
|
103
107
|
*/
|
|
104
|
-
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';
|
|
105
|
-
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
|
@@ -58,10 +58,11 @@ defineProcedures, executeProcedure, isCompiledProcedure, isProcedureCollection,
|
|
|
58
58
|
export { createProcedure, typedProcedure } from './procedure/factory.js';
|
|
59
59
|
export { createRouter, toRouter } from './router-utils.js';
|
|
60
60
|
export { analyzeNamingConvention, isDevelopment, normalizeWarningOption } from './warnings.js';
|
|
61
|
-
export { buildNestedRestPath, buildRestPath, extractRoutes, followsNamingConvention, generateRestRoutes, getRouteSummary, inferResourceName, parseNamingConvention, registerRestRoutes, rest, } from './rest/index.js';
|
|
61
|
+
export { buildMultiLevelNestedPath, buildNestedRestPath, buildRestPath, calculateNestingDepth, extractRoutes, followsNamingConvention, generateRestRoutes, getRouteSummary, inferResourceName, parseNamingConvention, registerRestRoutes, rest, } from './rest/index.js';
|
|
62
62
|
export {
|
|
63
63
|
// tRPC utilities
|
|
64
64
|
appRouter, buildTRPCRouter, createTRPCContextFactory, registerTRPCPlugin, trpc, veloxErrorToTRPCError, } from './trpc/index.js';
|
|
65
|
+
export { registerRpc, rpc } from './rpc.js';
|
|
65
66
|
export { DiscoveryError, DiscoveryErrorCode, directoryNotFound, discoverProcedures, discoverProceduresVerbose, fileLoadError, invalidExport, invalidFileType, isDiscoveryError, noProceduresFound, permissionDenied, } from './discovery/index.js';
|
|
66
67
|
export { serve } from './expose.js';
|
|
67
68
|
// ============================================================================
|
|
@@ -97,6 +98,8 @@ createSecurityRequirement,
|
|
|
97
98
|
// Schema converter
|
|
98
99
|
createStringSchema,
|
|
99
100
|
// Plugin
|
|
100
|
-
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,
|
|
101
102
|
// Generator
|
|
102
|
-
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';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared middleware chain execution utility
|
|
3
|
+
*
|
|
4
|
+
* Provides a single implementation for executing middleware chains,
|
|
5
|
+
* used by both the procedure builder and tRPC adapter.
|
|
6
|
+
*
|
|
7
|
+
* @module middleware/chain
|
|
8
|
+
*/
|
|
9
|
+
import type { BaseContext } from '@veloxts/core';
|
|
10
|
+
import type { MiddlewareFunction } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Result wrapper for middleware chain execution
|
|
13
|
+
*/
|
|
14
|
+
export interface MiddlewareResult<TOutput> {
|
|
15
|
+
output: TOutput;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execute a middleware chain with the given handler
|
|
19
|
+
*
|
|
20
|
+
* Builds the chain from end to start and executes it, allowing each
|
|
21
|
+
* middleware to extend the context before calling the next middleware.
|
|
22
|
+
*
|
|
23
|
+
* @param middlewares - Array of middleware functions to execute
|
|
24
|
+
* @param input - The input to pass to each middleware
|
|
25
|
+
* @param ctx - The context object (will be mutated by middleware)
|
|
26
|
+
* @param handler - The final handler to execute after all middleware
|
|
27
|
+
* @returns The output from the handler
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const result = await executeMiddlewareChain(
|
|
32
|
+
* procedure.middlewares,
|
|
33
|
+
* input,
|
|
34
|
+
* ctx,
|
|
35
|
+
* async () => handler({ input, ctx })
|
|
36
|
+
* );
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function executeMiddlewareChain<TInput, TOutput, TContext extends BaseContext>(middlewares: ReadonlyArray<MiddlewareFunction<TInput, TContext, TContext, TOutput>>, input: TInput, ctx: TContext, handler: () => Promise<TOutput>): Promise<TOutput>;
|
|
40
|
+
/**
|
|
41
|
+
* Create a precompiled middleware executor for a fixed middleware chain
|
|
42
|
+
*
|
|
43
|
+
* This is an optimization that builds the chain structure once during
|
|
44
|
+
* procedure compilation, creating a reusable function that can execute
|
|
45
|
+
* the chain without rebuilding closures on every request.
|
|
46
|
+
*
|
|
47
|
+
* @param middlewares - Array of middleware functions
|
|
48
|
+
* @param handler - The procedure handler (can return sync or async)
|
|
49
|
+
* @returns A function that executes the full chain
|
|
50
|
+
*/
|
|
51
|
+
export declare function createMiddlewareExecutor<TInput, TOutput, TContext extends BaseContext>(middlewares: ReadonlyArray<MiddlewareFunction<TInput, TContext, TContext, TOutput>>, handler: (params: {
|
|
52
|
+
input: TInput;
|
|
53
|
+
ctx: TContext;
|
|
54
|
+
}) => TOutput | Promise<TOutput>): (input: TInput, ctx: TContext) => Promise<TOutput>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared middleware chain execution utility
|
|
3
|
+
*
|
|
4
|
+
* Provides a single implementation for executing middleware chains,
|
|
5
|
+
* used by both the procedure builder and tRPC adapter.
|
|
6
|
+
*
|
|
7
|
+
* @module middleware/chain
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Execute a middleware chain with the given handler
|
|
11
|
+
*
|
|
12
|
+
* Builds the chain from end to start and executes it, allowing each
|
|
13
|
+
* middleware to extend the context before calling the next middleware.
|
|
14
|
+
*
|
|
15
|
+
* @param middlewares - Array of middleware functions to execute
|
|
16
|
+
* @param input - The input to pass to each middleware
|
|
17
|
+
* @param ctx - The context object (will be mutated by middleware)
|
|
18
|
+
* @param handler - The final handler to execute after all middleware
|
|
19
|
+
* @returns The output from the handler
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const result = await executeMiddlewareChain(
|
|
24
|
+
* procedure.middlewares,
|
|
25
|
+
* input,
|
|
26
|
+
* ctx,
|
|
27
|
+
* async () => handler({ input, ctx })
|
|
28
|
+
* );
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export async function executeMiddlewareChain(middlewares, input, ctx, handler) {
|
|
32
|
+
// Build the chain from the end (handler) back to the start
|
|
33
|
+
let next = async () => {
|
|
34
|
+
const output = await handler();
|
|
35
|
+
return { output };
|
|
36
|
+
};
|
|
37
|
+
// Wrap each middleware from last to first
|
|
38
|
+
for (let i = middlewares.length - 1; i >= 0; i--) {
|
|
39
|
+
const middleware = middlewares[i];
|
|
40
|
+
const currentNext = next;
|
|
41
|
+
next = async () => {
|
|
42
|
+
return middleware({
|
|
43
|
+
input,
|
|
44
|
+
ctx,
|
|
45
|
+
next: async (opts) => {
|
|
46
|
+
// Allow middleware to extend context
|
|
47
|
+
if (opts?.ctx) {
|
|
48
|
+
Object.assign(ctx, opts.ctx);
|
|
49
|
+
}
|
|
50
|
+
return currentNext();
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const result = await next();
|
|
56
|
+
return result.output;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a precompiled middleware executor for a fixed middleware chain
|
|
60
|
+
*
|
|
61
|
+
* This is an optimization that builds the chain structure once during
|
|
62
|
+
* procedure compilation, creating a reusable function that can execute
|
|
63
|
+
* the chain without rebuilding closures on every request.
|
|
64
|
+
*
|
|
65
|
+
* @param middlewares - Array of middleware functions
|
|
66
|
+
* @param handler - The procedure handler (can return sync or async)
|
|
67
|
+
* @returns A function that executes the full chain
|
|
68
|
+
*/
|
|
69
|
+
export function createMiddlewareExecutor(middlewares, handler) {
|
|
70
|
+
// If no middlewares, just return a direct handler call
|
|
71
|
+
if (middlewares.length === 0) {
|
|
72
|
+
return async (input, ctx) => {
|
|
73
|
+
return handler({ input, ctx });
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
// Return an executor that uses the shared chain execution
|
|
77
|
+
return async (input, ctx) => {
|
|
78
|
+
return executeMiddlewareChain(middlewares, input, ctx, async () => handler({ input, ctx }));
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -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
|
+
}
|