tsoa-next 8.0.4 → 8.0.5-dev.57.84bb4a63

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/README.MD CHANGED
@@ -47,65 +47,22 @@ Where historical release notes or migration references still point upstream, the
47
47
  - Runtime validation of tsoa-next should behave as closely as possible to the specifications that the generated OpenAPI 2/3 schema describes. Any differences in validation logic are clarified by logging warnings during the generation of the OpenAPI Specification (OAS) and/or the routes.
48
48
  - Please note that by enabling OpenAPI 3 you minimize the chances of divergent validation logic since OpenAPI 3 has a more expressive schema syntax.
49
49
 
50
- ## External Validators
51
-
52
- `@Validate(...)` adds opt-in runtime authority for external schemas on supported controller method parameters.
53
-
54
- - Supported forms: `@Validate(schema)`, `@Validate('zod', schema)`, `@Validate({ kind: 'zod', schema })`
55
- - Supported libraries: `zod`, `joi`, `yup`, `superstruct`, `io-ts`
56
- - `io-ts` installs: add `fp-ts`, and add `io-ts-types` as well if you rely on helpers like `withMessage`
57
- - Supported parameter decorators: `@Body`, `@BodyProp`, `@Query`, `@Queries`, `@Path`, `@Header`, and `@FormField` / uploaded file params
58
- - Behavior: TypeScript metadata still drives OpenAPI generation, while the external schema replaces built-in runtime validation for the decorated parameter subtree
59
- - Compatibility: routes without `@Validate(...)` keep their current behavior
60
-
61
- Generated `RegisterRoutes(...)` functions also accept an optional validation context so applications can provide translation or failure-formatting hooks:
62
-
63
- ```ts
64
- RegisterRoutes(app, {
65
- validation: {
66
- translate: (key, params) => translateMessage(key, params),
67
- errorFormatter: failure => failure,
68
- },
69
- })
70
- ```
71
-
72
- ```ts
73
- import * as t from 'io-ts'
74
- import { withMessage } from 'io-ts-types'
75
- import { Body, Controller, Post, Route, Validate } from 'tsoa-next'
76
-
77
- interface PositiveFloatBrand {
78
- readonly PositiveFloat: unique symbol
79
- }
80
-
81
- const PositiveFloat = withMessage(
82
- t.brand(t.number, (n): n is t.Branded<number, PositiveFloatBrand> => Number.isFinite(n) && n > 0, 'PositiveFloat'),
83
- () => 'validation.wager.amount.mustBePositiveFloat',
84
- )
85
-
86
- const WagerCodec = t.type({
87
- amount: PositiveFloat,
88
- outcome: t.Int,
89
- })
90
-
91
- type Wager = t.TypeOf<typeof WagerCodec>
92
-
93
- @Route('wagers')
94
- export class WagersController extends Controller {
95
- @Post()
96
- public createWager(
97
- @Body()
98
- @Validate('io-ts', WagerCodec)
99
- wager: Wager,
100
- ): Wager {
101
- return wager
102
- }
103
- }
104
- ```
105
-
106
- ## Migration Note
107
-
108
- This feature is fully opt-in. If you do not use `@Validate(...)`, existing interface/class models, generated routes, validation behavior, and error responses are unchanged.
50
+ ## Feature List
51
+
52
+ - Generate OpenAPI 2.0, 3.0, or 3.1 documents directly from your TypeScript controllers, models, and JSDoc comments.
53
+ - Treat TypeScript controllers and models as the source of truth for paths, parameters, schemas, examples, tags, and security metadata.
54
+ - Generate framework-specific route handlers for Express, Koa, and Hapi, or supply your own Handlebars templates for custom runtimes.
55
+ - Validate request input at runtime with configurable coercion and additional-property handling that stays aligned with the generated schema.
56
+ - Expose controller-local spec endpoints with `@SpecPath(...)` without reading a generated spec file from local disk at request time.
57
+ - Serve built-in `json`, `yaml`, `swagger`, `redoc`, and `rapidoc` spec targets, with docs UI packages loaded lazily as optional peers when available.
58
+ - Attach multiple `@SpecPath(...)` decorators to the same controller as long as their resolved paths are unique.
59
+ - Cache built-in or custom spec responses with `'none'`, in-process `'memory'`, or a custom cache handler that can read from strings or streams.
60
+ - Return either `string` or `Readable` responses from custom `@SpecPath(...)` handlers for bespoke documentation or downstream integrations.
61
+ - Use `@Validate(...)` to delegate runtime validation to supported external schema libraries such as `zod`, `joi`, `yup`, `superstruct`, or `io-ts`.
62
+ - Customize validation translation and failure formatting through the optional validation context accepted by generated `RegisterRoutes(...)` functions.
63
+ - Support authentication hooks, dependency injection, typed alternate responders, file uploads, custom middleware, and custom validation workflows.
64
+ - Use the `tsoa` CLI for spec and route generation, or call the programmatic APIs from `tsoa-next/cli`.
65
+ - Target modern Node.js releases with the support policy verified in CI across the previous LTS, current LTS, and Node vNext.
109
66
 
110
67
  ## Getting Started
111
68
 
@@ -127,6 +84,8 @@ This feature is fully opt-in. If you do not use `@Validate(...)`, existing inter
127
84
 
128
85
  Check out the [guides](https://tsoa-next.dev/)
129
86
 
87
+ Use the companion [playground repository](https://github.com/tsoa-next/playground) for runnable example apps and server-focused scenarios.
88
+
130
89
  See example controllers in [the tests](https://github.com/tsoa-next/tsoa-next/tree/main/tests/fixtures/controllers)
131
90
 
132
91
  See example models in [the tests](https://github.com/tsoa-next/tsoa-next/blob/main/tests/fixtures/testModel.ts)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const runCLI_1 = require("@tsoa-next/cli/dist/runCLI");
5
+ if (require.main === module) {
6
+ void (async () => {
7
+ try {
8
+ await (0, runCLI_1.runCLI)();
9
+ }
10
+ catch (err) {
11
+ console.error('tsoa cli error:\n', err);
12
+ process.exit(1);
13
+ }
14
+ })();
15
+ }
16
+ //# sourceMappingURL=cli-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-bin.js","sourceRoot":"","sources":["../src/cli-bin.ts"],"names":[],"mappings":";;;AACA,uDAAmD;AAEnD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,IAAI,CAAC;YACH,MAAM,IAAA,eAAM,GAAE,CAAA;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAA;YACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;AACN,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from '@tsoa-next/runtime';
2
+ export * from './spec';
package/dist/index.js CHANGED
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("@tsoa-next/runtime"), exports);
18
+ __exportStar(require("./spec"), exports);
18
19
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAkC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAkC;AAClC,yCAAsB"}
package/dist/spec.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import type { RuntimeSpecConfigSnapshot, SpecGenerator } from '@tsoa-next/runtime';
2
+ export declare function createOpenApiSpecGenerator(config?: RuntimeSpecConfigSnapshot): SpecGenerator;
package/dist/spec.js ADDED
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createOpenApiSpecGenerator = createOpenApiSpecGenerator;
37
+ function assertSpecConfig(config) {
38
+ if (!config) {
39
+ throw new Error('SpecPath requires spec generation settings. Provide spec configuration when generating routes so built-in spec targets can rebuild the OpenAPI document at runtime.');
40
+ }
41
+ return config;
42
+ }
43
+ function createOpenApiSpecGenerator(config) {
44
+ let specPromise;
45
+ const stringCache = new Map();
46
+ const loadCli = async () => await Promise.resolve().then(() => __importStar(require('@tsoa-next/cli')));
47
+ const getSpecObject = async () => {
48
+ specPromise ??= (async () => {
49
+ const runtimeConfig = assertSpecConfig(config);
50
+ const cli = await loadCli();
51
+ return cli.buildSpec(runtimeConfig.spec, runtimeConfig.compilerOptions, runtimeConfig.ignore, undefined, runtimeConfig.defaultNumberType);
52
+ })();
53
+ return specPromise;
54
+ };
55
+ const getSpecString = async (format) => {
56
+ const cached = stringCache.get(format);
57
+ if (cached) {
58
+ return cached;
59
+ }
60
+ const stringPromise = (async () => {
61
+ const cli = await loadCli();
62
+ return cli.serializeSpec(await getSpecObject(), format === 'yaml');
63
+ })();
64
+ stringCache.set(format, stringPromise);
65
+ return stringPromise;
66
+ };
67
+ return {
68
+ getSpecObject,
69
+ getSpecString,
70
+ };
71
+ }
72
+ //# sourceMappingURL=spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec.js","sourceRoot":"","sources":["../src/spec.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,gEAkCC;AA1CD,SAAS,gBAAgB,CAAC,MAAkC;IAC1D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,qKAAqK,CAAC,CAAA;IACxL,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAgB,0BAA0B,CAAC,MAAkC;IAC3E,IAAI,WAA2E,CAAA;IAC/E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoC,CAAA;IAE/D,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC,wDAAa,gBAAgB,GAAC,CAAA;IAC1D,MAAM,aAAa,GAAmC,KAAK,IAAI,EAAE;QAC/D,WAAW,KAAK,CAAC,KAAK,IAAI,EAAE;YAC1B,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;YAC9C,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;YAC3B,OAAO,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,eAAmE,EAAE,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;QAC/L,CAAC,CAAC,EAAE,CAAA;QAEJ,OAAO,WAAW,CAAA;IACpB,CAAC,CAAA;IAED,MAAM,aAAa,GAAmC,KAAK,EAAC,MAAM,EAAC,EAAE;QACnE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAA;QACf,CAAC;QAED,MAAM,aAAa,GAAG,CAAC,KAAK,IAAI,EAAE;YAChC,MAAM,GAAG,GAAG,MAAM,OAAO,EAAE,CAAA;YAC3B,OAAO,GAAG,CAAC,aAAa,CAAC,MAAM,aAAa,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;QACpE,CAAC,CAAC,EAAE,CAAA;QAEJ,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;QACtC,OAAO,aAAa,CAAA;IACtB,CAAC,CAAA;IAED,OAAO;QACL,aAAa;QACb,aAAa;KACd,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsoa-next",
3
- "version": "8.0.4",
3
+ "version": "8.0.5-dev.57.84bb4a63",
4
4
  "description": "Build swagger-compliant REST APIs using TypeScript and Node",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  "tsoa-next-logo-590.png"
10
10
  ],
11
11
  "bin": {
12
- "tsoa": "dist/cli.js"
12
+ "tsoa": "dist/cli-bin.js"
13
13
  },
14
14
  "scripts": {
15
15
  "build": "npm run tsc",
@@ -32,13 +32,37 @@
32
32
  "author": "Vanna DiCatania <vanna@dicatania.me> (http://www.dicatania.me)",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@tsoa-next/cli": "8.0.4",
36
- "@tsoa-next/runtime": "8.0.4"
35
+ "@tsoa-next/cli": "8.0.5-dev.57.84bb4a63",
36
+ "@tsoa-next/runtime": "8.0.5-dev.57.84bb4a63"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "24.12.0",
40
40
  "typescript": "^5.9.3"
41
41
  },
42
+ "peerDependencies": {
43
+ "hapi-swagger": "^17.3.2",
44
+ "rapidoc": "^9.3.8",
45
+ "redoc": "^2.5.2",
46
+ "swagger-ui-express": "^5.0.1",
47
+ "swagger-ui-koa": "^0.0.1"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "hapi-swagger": {
51
+ "optional": true
52
+ },
53
+ "rapidoc": {
54
+ "optional": true
55
+ },
56
+ "redoc": {
57
+ "optional": true
58
+ },
59
+ "swagger-ui-express": {
60
+ "optional": true
61
+ },
62
+ "swagger-ui-koa": {
63
+ "optional": true
64
+ }
65
+ },
42
66
  "repository": {
43
67
  "type": "git",
44
68
  "url": "https://github.com/tsoa-next/tsoa-next.git",