@apollo-deploy/tesseract 0.4.3 → 0.5.0

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.
Files changed (70) hide show
  1. package/README.md +330 -11
  2. package/dist/adapters/types.d.ts +2 -1
  3. package/dist/adapters/types.d.ts.map +1 -1
  4. package/dist/adapters/typescript/index.d.ts +2 -1
  5. package/dist/adapters/typescript/index.d.ts.map +1 -1
  6. package/dist/adapters/typescript/index.js +27 -10
  7. package/dist/adapters/typescript/index.js.map +1 -1
  8. package/dist/cli.js +19 -1
  9. package/dist/cli.js.map +1 -1
  10. package/dist/collector.d.ts +135 -0
  11. package/dist/collector.d.ts.map +1 -0
  12. package/dist/collector.js +159 -0
  13. package/dist/collector.js.map +1 -0
  14. package/dist/elysia.d.ts +65 -0
  15. package/dist/elysia.d.ts.map +1 -0
  16. package/dist/elysia.js +70 -0
  17. package/dist/elysia.js.map +1 -0
  18. package/dist/express.d.ts +74 -0
  19. package/dist/express.d.ts.map +1 -0
  20. package/dist/express.js +73 -0
  21. package/dist/express.js.map +1 -0
  22. package/dist/fastify.d.ts +135 -0
  23. package/dist/fastify.d.ts.map +1 -0
  24. package/dist/fastify.js +188 -0
  25. package/dist/fastify.js.map +1 -0
  26. package/dist/helpers/handlebars.d.ts.map +1 -1
  27. package/dist/helpers/handlebars.js +6 -2
  28. package/dist/helpers/handlebars.js.map +1 -1
  29. package/dist/hono.d.ts +65 -0
  30. package/dist/hono.d.ts.map +1 -0
  31. package/dist/hono.js +64 -0
  32. package/dist/hono.js.map +1 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +4 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/koa.d.ts +69 -0
  38. package/dist/koa.d.ts.map +1 -0
  39. package/dist/koa.js +68 -0
  40. package/dist/koa.js.map +1 -0
  41. package/dist/nestjs.d.ts +107 -0
  42. package/dist/nestjs.d.ts.map +1 -0
  43. package/dist/nestjs.js +143 -0
  44. package/dist/nestjs.js.map +1 -0
  45. package/dist/pipeline/intake.d.ts.map +1 -1
  46. package/dist/pipeline/intake.js +40 -21
  47. package/dist/pipeline/intake.js.map +1 -1
  48. package/dist/pipeline/write.d.ts +1 -0
  49. package/dist/pipeline/write.d.ts.map +1 -1
  50. package/dist/pipeline/write.js +21 -3
  51. package/dist/pipeline/write.js.map +1 -1
  52. package/dist/types/config.d.ts +13 -3
  53. package/dist/types/config.d.ts.map +1 -1
  54. package/dist/types/config.js +5 -2
  55. package/dist/types/config.js.map +1 -1
  56. package/dist/types/ir.d.ts +14 -0
  57. package/dist/types/ir.d.ts.map +1 -1
  58. package/dist/types/manifest.d.ts +5 -23
  59. package/dist/types/manifest.d.ts.map +1 -1
  60. package/dist/types/manifest.js.map +1 -1
  61. package/dist/types/sdk-module.d.ts +128 -0
  62. package/dist/types/sdk-module.d.ts.map +1 -0
  63. package/dist/types/sdk-module.js +50 -0
  64. package/dist/types/sdk-module.js.map +1 -0
  65. package/package.json +63 -1
  66. package/templates/typescript/client-class.hbs +136 -0
  67. package/templates/typescript/domain-class.hbs +188 -0
  68. package/templates/typescript/domain.hbs +10 -6
  69. package/templates/typescript/index-class.hbs +68 -0
  70. package/templates/typescript/transport-sse.hbs +3 -3
package/dist/koa.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Tesseract Koa integration.
3
+ *
4
+ * Re-exports `SDKCollector` and adds a `KoaSDKCollector` subclass with a
5
+ * `.koaMiddleware()` helper that registers a route with the collector and
6
+ * returns a no-op Koa middleware for inline placement with `@koa/router`.
7
+ *
8
+ * Because Koa has no route-registration hook, routes are registered with the
9
+ * collector explicitly. Generation is triggered by calling
10
+ * `collector.tryGenerate()` after all routes are set up.
11
+ *
12
+ * ```ts
13
+ * import Koa from 'koa';
14
+ * import Router from '@koa/router';
15
+ * import { KoaSDKCollector } from '@apollo-deploy/tesseract/koa';
16
+ *
17
+ * const app = new Koa();
18
+ * const router = new Router();
19
+ * const collector = new KoaSDKCollector({
20
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
21
+ * output: './packages/api-sdk',
22
+ * });
23
+ *
24
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
25
+ *
26
+ * router.get('/users/:id',
27
+ * collector.koaMiddleware('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
28
+ * getUserHandler,
29
+ * );
30
+ *
31
+ * app.use(router.routes());
32
+ *
33
+ * // After all routes are registered:
34
+ * if (await collector.tryGenerate()) process.exit(0);
35
+ *
36
+ * app.listen(3000);
37
+ * ```
38
+ *
39
+ * **Triggering generation:**
40
+ * ```bash
41
+ * TESSERACT_GENERATE=1 node dist/app.js
42
+ * ```
43
+ */
44
+ import { SDKCollector } from './collector.js';
45
+ import type { CollectorRouteConfig } from './collector.js';
46
+ export { SDKCollector } from './collector.js';
47
+ export type { CollectorOptions, CollectorRouteConfig } from './collector.js';
48
+ /** Minimal Koa middleware type — avoids a hard import of the `koa` package. */
49
+ type KoaMiddleware = (ctx: unknown, next: () => Promise<void>) => Promise<void> | void;
50
+ /**
51
+ * `SDKCollector` subclass with a Koa-specific `.koaMiddleware()` helper.
52
+ *
53
+ * `.koaMiddleware()` registers a route with the collector **and** returns a
54
+ * no-op Koa middleware for inline placement with `@koa/router`.
55
+ */
56
+ export declare class KoaSDKCollector extends SDKCollector {
57
+ /**
58
+ * Register a route with the collector and return a no-op Koa middleware.
59
+ *
60
+ * ```ts
61
+ * router.get('/users/:id',
62
+ * collector.koaMiddleware('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
63
+ * getUserHandler,
64
+ * );
65
+ * ```
66
+ */
67
+ koaMiddleware(url: string, method: string, config: CollectorRouteConfig): KoaMiddleware;
68
+ }
69
+ //# sourceMappingURL=koa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.d.ts","sourceRoot":"","sources":["../src/koa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,+EAA+E;AAC/E,KAAK,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEvF;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,YAAY;IAC/C;;;;;;;;;OASG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,aAAa;CAIxF"}
package/dist/koa.js ADDED
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Tesseract Koa integration.
3
+ *
4
+ * Re-exports `SDKCollector` and adds a `KoaSDKCollector` subclass with a
5
+ * `.koaMiddleware()` helper that registers a route with the collector and
6
+ * returns a no-op Koa middleware for inline placement with `@koa/router`.
7
+ *
8
+ * Because Koa has no route-registration hook, routes are registered with the
9
+ * collector explicitly. Generation is triggered by calling
10
+ * `collector.tryGenerate()` after all routes are set up.
11
+ *
12
+ * ```ts
13
+ * import Koa from 'koa';
14
+ * import Router from '@koa/router';
15
+ * import { KoaSDKCollector } from '@apollo-deploy/tesseract/koa';
16
+ *
17
+ * const app = new Koa();
18
+ * const router = new Router();
19
+ * const collector = new KoaSDKCollector({
20
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
21
+ * output: './packages/api-sdk',
22
+ * });
23
+ *
24
+ * collector.domain('/users', { domain: 'users', description: 'User management' });
25
+ *
26
+ * router.get('/users/:id',
27
+ * collector.koaMiddleware('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
28
+ * getUserHandler,
29
+ * );
30
+ *
31
+ * app.use(router.routes());
32
+ *
33
+ * // After all routes are registered:
34
+ * if (await collector.tryGenerate()) process.exit(0);
35
+ *
36
+ * app.listen(3000);
37
+ * ```
38
+ *
39
+ * **Triggering generation:**
40
+ * ```bash
41
+ * TESSERACT_GENERATE=1 node dist/app.js
42
+ * ```
43
+ */
44
+ import { SDKCollector } from './collector.js';
45
+ export { SDKCollector } from './collector.js';
46
+ /**
47
+ * `SDKCollector` subclass with a Koa-specific `.koaMiddleware()` helper.
48
+ *
49
+ * `.koaMiddleware()` registers a route with the collector **and** returns a
50
+ * no-op Koa middleware for inline placement with `@koa/router`.
51
+ */
52
+ export class KoaSDKCollector extends SDKCollector {
53
+ /**
54
+ * Register a route with the collector and return a no-op Koa middleware.
55
+ *
56
+ * ```ts
57
+ * router.get('/users/:id',
58
+ * collector.koaMiddleware('/users/:id', 'GET', { sdk: { methodName: 'getUser' } }),
59
+ * getUserHandler,
60
+ * );
61
+ * ```
62
+ */
63
+ koaMiddleware(url, method, config) {
64
+ this.route(url, method, config);
65
+ return (_ctx, next) => next();
66
+ }
67
+ }
68
+ //# sourceMappingURL=koa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"koa.js","sourceRoot":"","sources":["../src/koa.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM9C;;;;;GAKG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAC/C;;;;;;;;;OASG;IACH,aAAa,CAAC,GAAW,EAAE,MAAc,EAAE,MAA4B;QACrE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Tesseract NestJS integration.
3
+ *
4
+ * Provides:
5
+ * - `@SDKMethod(config)` — method decorator to attach SDK metadata to a controller handler
6
+ * - `@SDKDomain(config)` — class decorator to attach domain metadata to a controller
7
+ * - `collectFromNestControllers(controllers, collector)` — reads decorator metadata and
8
+ * registers routes with an `SDKCollector`
9
+ *
10
+ * Requires `reflect-metadata` (already a standard NestJS dependency) and
11
+ * `emitDecoratorMetadata: true` in `tsconfig.json`.
12
+ *
13
+ * ```ts
14
+ * // users.controller.ts
15
+ * import { Controller, Get, Post, Param, Body } from '@nestjs/common';
16
+ * import { SDKMethod, SDKDomain } from '@apollo-deploy/tesseract/nestjs';
17
+ *
18
+ * @Controller('users')
19
+ * @SDKDomain({ domain: 'users', description: 'User management' })
20
+ * export class UsersController {
21
+ * @Get(':id')
22
+ * @SDKMethod({ methodName: 'getUser', schema: { response: { 200: { $ref: 'User' } } } })
23
+ * getUser(@Param('id') id: string) { ... }
24
+ *
25
+ * @Post()
26
+ * @SDKMethod({ methodName: 'createUser' })
27
+ * createUser(@Body() body: CreateUserDto) { ... }
28
+ * }
29
+ *
30
+ * // main.ts
31
+ * import { NestFactory } from '@nestjs/core';
32
+ * import { AppModule } from './app.module';
33
+ * import { SDKCollector, collectFromNestControllers } from '@apollo-deploy/tesseract/nestjs';
34
+ * import { UsersController } from './users/users.controller';
35
+ *
36
+ * async function bootstrap() {
37
+ * const app = await NestFactory.create(AppModule);
38
+ * await app.init();
39
+ *
40
+ * if (process.env.TESSERACT_GENERATE) {
41
+ * const collector = new SDKCollector({
42
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
43
+ * output: './packages/api-sdk',
44
+ * });
45
+ * collectFromNestControllers([UsersController], collector);
46
+ * await collector.generate();
47
+ * await app.close();
48
+ * process.exit(0);
49
+ * }
50
+ *
51
+ * await app.listen(3000);
52
+ * }
53
+ * bootstrap();
54
+ * ```
55
+ *
56
+ * **Triggering generation:**
57
+ * ```bash
58
+ * TESSERACT_GENERATE=1 node dist/main.js
59
+ * ```
60
+ */
61
+ declare global {
62
+ namespace Reflect {
63
+ function defineMetadata(key: unknown, value: unknown, target: object, propertyKey?: string | symbol): void;
64
+ function getMetadata(key: unknown, target: object, propertyKey?: string | symbol): unknown;
65
+ }
66
+ }
67
+ import { SDKCollector } from './collector.js';
68
+ import type { SDKRouteConfig, SDKModuleConfig } from './types/sdk-module.js';
69
+ import type { ManifestRouteSchema } from './types/manifest.js';
70
+ export { SDKCollector } from './collector.js';
71
+ export type { CollectorOptions, CollectorRouteConfig } from './collector.js';
72
+ export interface SDKMethodConfig extends SDKRouteConfig {
73
+ /** Explicit JSON Schema for this route — params, querystring, body, headers, response. */
74
+ schema?: ManifestRouteSchema;
75
+ }
76
+ /**
77
+ * Method decorator — attach SDK generation config to a NestJS controller handler.
78
+ *
79
+ * ```ts
80
+ * @Get(':id')
81
+ * @SDKMethod({ methodName: 'getUser', schema: { response: { 200: { $ref: 'User' } } } })
82
+ * getUser(@Param('id') id: string) { ... }
83
+ * ```
84
+ */
85
+ export declare function SDKMethod(config: SDKMethodConfig): MethodDecorator;
86
+ /**
87
+ * Class decorator — attach domain metadata to a NestJS controller.
88
+ *
89
+ * ```ts
90
+ * @Controller('users')
91
+ * @SDKDomain({ domain: 'users', description: 'User management' })
92
+ * export class UsersController { ... }
93
+ * ```
94
+ */
95
+ export declare function SDKDomain(config: Omit<SDKModuleConfig, 'prefix'>): ClassDecorator;
96
+ /**
97
+ * Read `@SDKMethod` and `@SDKDomain` metadata from the given controller classes
98
+ * and register each decorated route with the provided `SDKCollector`.
99
+ *
100
+ * Pass the controller **classes** (not instances).
101
+ *
102
+ * ```ts
103
+ * collectFromNestControllers([UsersController, OrdersController], collector);
104
+ * ```
105
+ */
106
+ export declare function collectFromNestControllers(controllers: Function[], collector: SDKCollector): void;
107
+ //# sourceMappingURL=nestjs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.d.ts","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAKH,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,OAAO,CAAC;QAChB,SAAS,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;QAC3G,SAAS,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;KAC5F;CACF;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAyB7E,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,0FAA0F;IAC1F,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,eAAe,CAIlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,QAAQ,CAAC,GAAG,cAAc,CAIjF;AAID;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,QAAQ,EAAE,EACvB,SAAS,EAAE,YAAY,GACtB,IAAI,CAkCN"}
package/dist/nestjs.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Tesseract NestJS integration.
3
+ *
4
+ * Provides:
5
+ * - `@SDKMethod(config)` — method decorator to attach SDK metadata to a controller handler
6
+ * - `@SDKDomain(config)` — class decorator to attach domain metadata to a controller
7
+ * - `collectFromNestControllers(controllers, collector)` — reads decorator metadata and
8
+ * registers routes with an `SDKCollector`
9
+ *
10
+ * Requires `reflect-metadata` (already a standard NestJS dependency) and
11
+ * `emitDecoratorMetadata: true` in `tsconfig.json`.
12
+ *
13
+ * ```ts
14
+ * // users.controller.ts
15
+ * import { Controller, Get, Post, Param, Body } from '@nestjs/common';
16
+ * import { SDKMethod, SDKDomain } from '@apollo-deploy/tesseract/nestjs';
17
+ *
18
+ * @Controller('users')
19
+ * @SDKDomain({ domain: 'users', description: 'User management' })
20
+ * export class UsersController {
21
+ * @Get(':id')
22
+ * @SDKMethod({ methodName: 'getUser', schema: { response: { 200: { $ref: 'User' } } } })
23
+ * getUser(@Param('id') id: string) { ... }
24
+ *
25
+ * @Post()
26
+ * @SDKMethod({ methodName: 'createUser' })
27
+ * createUser(@Body() body: CreateUserDto) { ... }
28
+ * }
29
+ *
30
+ * // main.ts
31
+ * import { NestFactory } from '@nestjs/core';
32
+ * import { AppModule } from './app.module';
33
+ * import { SDKCollector, collectFromNestControllers } from '@apollo-deploy/tesseract/nestjs';
34
+ * import { UsersController } from './users/users.controller';
35
+ *
36
+ * async function bootstrap() {
37
+ * const app = await NestFactory.create(AppModule);
38
+ * await app.init();
39
+ *
40
+ * if (process.env.TESSERACT_GENERATE) {
41
+ * const collector = new SDKCollector({
42
+ * info: { title: 'My API', version: '1.0.0', baseUrl: 'https://api.example.com' },
43
+ * output: './packages/api-sdk',
44
+ * });
45
+ * collectFromNestControllers([UsersController], collector);
46
+ * await collector.generate();
47
+ * await app.close();
48
+ * process.exit(0);
49
+ * }
50
+ *
51
+ * await app.listen(3000);
52
+ * }
53
+ * bootstrap();
54
+ * ```
55
+ *
56
+ * **Triggering generation:**
57
+ * ```bash
58
+ * TESSERACT_GENERATE=1 node dist/main.js
59
+ * ```
60
+ */
61
+ export { SDKCollector } from './collector.js';
62
+ // ── Metadata keys ─────────────────────────────────────────────────────────────
63
+ const SDK_METHOD_META = Symbol('tesseract:sdkMethod');
64
+ const SDK_DOMAIN_META = Symbol('tesseract:sdkDomain');
65
+ // NestJS stores route metadata under these well-known string keys
66
+ const NEST_PATH_META = 'path';
67
+ const NEST_METHOD_META = 'method';
68
+ // NestJS RequestMethod enum values
69
+ const NEST_HTTP_METHODS = {
70
+ 0: 'GET',
71
+ 1: 'POST',
72
+ 2: 'PUT',
73
+ 3: 'DELETE',
74
+ 4: 'PATCH',
75
+ 5: 'ALL',
76
+ 6: 'OPTIONS',
77
+ 7: 'HEAD',
78
+ };
79
+ /**
80
+ * Method decorator — attach SDK generation config to a NestJS controller handler.
81
+ *
82
+ * ```ts
83
+ * @Get(':id')
84
+ * @SDKMethod({ methodName: 'getUser', schema: { response: { 200: { $ref: 'User' } } } })
85
+ * getUser(@Param('id') id: string) { ... }
86
+ * ```
87
+ */
88
+ export function SDKMethod(config) {
89
+ return (target, propertyKey) => {
90
+ Reflect.defineMetadata(SDK_METHOD_META, config, target, propertyKey);
91
+ };
92
+ }
93
+ /**
94
+ * Class decorator — attach domain metadata to a NestJS controller.
95
+ *
96
+ * ```ts
97
+ * @Controller('users')
98
+ * @SDKDomain({ domain: 'users', description: 'User management' })
99
+ * export class UsersController { ... }
100
+ * ```
101
+ */
102
+ export function SDKDomain(config) {
103
+ return (target) => {
104
+ Reflect.defineMetadata(SDK_DOMAIN_META, config, target);
105
+ };
106
+ }
107
+ // ── Route collector ───────────────────────────────────────────────────────────
108
+ /**
109
+ * Read `@SDKMethod` and `@SDKDomain` metadata from the given controller classes
110
+ * and register each decorated route with the provided `SDKCollector`.
111
+ *
112
+ * Pass the controller **classes** (not instances).
113
+ *
114
+ * ```ts
115
+ * collectFromNestControllers([UsersController, OrdersController], collector);
116
+ * ```
117
+ */
118
+ export function collectFromNestControllers(controllers, collector) {
119
+ for (const ControllerClass of controllers) {
120
+ // NestJS stores the controller path prefix under 'path' metadata on the class
121
+ const rawPrefix = (Reflect.getMetadata(NEST_PATH_META, ControllerClass) ?? '');
122
+ const prefix = rawPrefix.startsWith('/') ? rawPrefix : '/' + rawPrefix;
123
+ const domainMeta = Reflect.getMetadata(SDK_DOMAIN_META, ControllerClass);
124
+ collector.domain(prefix, domainMeta);
125
+ const prototype = ControllerClass.prototype;
126
+ for (const key of Object.getOwnPropertyNames(prototype)) {
127
+ if (key === 'constructor')
128
+ continue;
129
+ const sdkConfig = Reflect.getMetadata(SDK_METHOD_META, prototype, key);
130
+ if (!sdkConfig || sdkConfig.exclude)
131
+ continue;
132
+ const nestMethod = Reflect.getMetadata(NEST_METHOD_META, prototype, key);
133
+ const nestPath = (Reflect.getMetadata(NEST_PATH_META, prototype, key) ?? '');
134
+ const method = nestMethod !== undefined ? (NEST_HTTP_METHODS[nestMethod] ?? 'GET') : 'GET';
135
+ const rawTail = nestPath.startsWith('/') ? nestPath : '/' + nestPath;
136
+ const url = prefix === '/' ? rawTail : prefix + (rawTail === '/' ? '' : rawTail);
137
+ const { schema, ...routeSdk } = sdkConfig;
138
+ const routeConfig = { sdk: routeSdk, schema };
139
+ collector.route(url, method, routeConfig);
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=nestjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/pipeline/intake.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAIV,UAAU,EACX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,KAAK,EAQN,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKzD,wBAAgB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA4EpD;AA+JD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA2D3D"}
1
+ {"version":3,"file":"intake.d.ts","sourceRoot":"","sources":["../../src/pipeline/intake.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAIV,UAAU,EACX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EACV,KAAK,EAQN,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKzD,wBAAgB,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CA+EpD;AAmKD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA2D3D"}
@@ -10,16 +10,21 @@ import { validateManifest } from '../types/manifest.js';
10
10
  // ── Entry point ──────────────────────────────────────────────────────────────
11
11
  export function intake(config) {
12
12
  let manifest;
13
- try {
14
- const raw = readFileSync(config.input, 'utf-8');
15
- manifest = JSON.parse(raw);
13
+ if (config.manifest) {
14
+ manifest = config.manifest;
16
15
  }
17
- catch (err) {
18
- throw new Error(`Failed to read manifest at "${config.input}": ${err instanceof Error ? err.message : String(err)}`);
19
- }
20
- const validation = validateManifest(manifest);
21
- if (!validation.valid) {
22
- throw new Error(`Invalid manifest:\n ${validation.errors.join('\n ')}`);
16
+ else {
17
+ try {
18
+ const raw = readFileSync(config.input, 'utf-8');
19
+ manifest = JSON.parse(raw);
20
+ }
21
+ catch (err) {
22
+ throw new Error(`Failed to read manifest at "${config.input}": ${err instanceof Error ? err.message : String(err)}`);
23
+ }
24
+ const validation = validateManifest(manifest);
25
+ if (!validation.valid) {
26
+ throw new Error(`Invalid manifest:\n ${validation.errors.join('\n ')}`);
27
+ }
23
28
  }
24
29
  const schemaPackage = manifest.schemaPackage;
25
30
  const importPath = schemaPackage?.importPath ?? schemaPackage?.name;
@@ -47,7 +52,7 @@ export function intake(config) {
47
52
  const schemas = [...externalSchemas, ...buildSchemas(localDefinitions)];
48
53
  const groups = [];
49
54
  const allInlineSchemas = [];
50
- for (const domain of manifest.domains.filter((d) => d.stability !== 'internal')) {
55
+ for (const domain of manifest.domains) {
51
56
  const { group, inlineSchemas } = buildOperationGroup(domain, schemas);
52
57
  groups.push(group);
53
58
  allInlineSchemas.push(...inlineSchemas);
@@ -87,6 +92,10 @@ function collectExternalRefNames(manifest) {
87
92
  scanSchemaForExternalRefs(resp, names);
88
93
  }
89
94
  }
95
+ // Register sseReturnType as an external ref so it gets an import stub
96
+ if (route.sdk?.sseReturnType) {
97
+ names.add(pascalCase(route.sdk.sseReturnType));
98
+ }
90
99
  }
91
100
  }
92
101
  return names;
@@ -176,7 +185,7 @@ function jsonSchemaToDefinition(name, schema) {
176
185
  };
177
186
  }
178
187
  if (s.type === 'object') {
179
- const required = new Set(s.required ?? []);
188
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
180
189
  const rawProps = s.properties ?? {};
181
190
  const properties = Object.entries(rawProps).map(([propName, propSchema]) => {
182
191
  const ps = propSchema;
@@ -226,7 +235,7 @@ export function jsonSchemaToType(schema) {
226
235
  return s.anyOf.map(jsonSchemaToType).join(' | ');
227
236
  const type = s.type;
228
237
  if (type === 'object') {
229
- const required = new Set(s.required ?? []);
238
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
230
239
  const rawProps = s.properties;
231
240
  if (rawProps) {
232
241
  const entries = Object.entries(rawProps)
@@ -298,14 +307,14 @@ function isNullableRefUnion(members) {
298
307
  function buildOperationGroup(domain, _schemas) {
299
308
  const domainName = domain.domain ?? domain.prefix;
300
309
  const name = camelCase(domainName);
301
- const fileName = kebabCase(domainName);
310
+ const fileName = domain.fileName ?? kebabCase(domainName);
302
311
  const allInlineSchemas = [];
303
312
  const operations = [];
304
313
  for (const route of domain.routes) {
305
- if (route.sdk?.exclude || route.sdk?.internal)
314
+ if (route.sdk?.exclude)
306
315
  continue;
307
316
  const { operation, inlineSchemas } = buildOperation(route, name, domain.prefix);
308
- operations.push(operation);
317
+ operations.push({ ...operation, visibility: route.sdk?.internal ? 'internal' : 'public' });
309
318
  for (const s of inlineSchemas) {
310
319
  allInlineSchemas.push({
311
320
  ...s,
@@ -320,6 +329,7 @@ function buildOperationGroup(domain, _schemas) {
320
329
  interfaceName: pascalCase(domainName) + 'API',
321
330
  factoryName: 'create' + pascalCase(domainName) + 'API',
322
331
  description: domain.description,
332
+ visibility: domain.stability === 'internal' ? 'internal' : 'public',
323
333
  operations,
324
334
  },
325
335
  inlineSchemas: allInlineSchemas,
@@ -336,7 +346,7 @@ function buildOperation(route, groupName, domainPrefix) {
336
346
  const inlineSchemas = [];
337
347
  const name = route.sdk?.methodName ??
338
348
  deriveCleanMethodName({
339
- operationId: route.schema?.operationId,
349
+ operationId: route.schema?.operationId ?? route.sdk?.operationId,
340
350
  summary: route.schema?.summary,
341
351
  path: route.url.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, '{$1}'),
342
352
  httpMethod: httpMethod.toLowerCase(),
@@ -379,7 +389,11 @@ function buildOperation(route, groupName, domainPrefix) {
379
389
  requestBody = {
380
390
  type: bodyType,
381
391
  required: true,
382
- contentType: route.sdk?.transport === 'multipart' ? 'multipart/form-data' : 'application/json',
392
+ contentType: route.sdk?.transport === 'multipart'
393
+ ? 'multipart/form-data'
394
+ : route.sdk?.transport === 'binary'
395
+ ? 'application/octet-stream'
396
+ : 'application/json',
383
397
  };
384
398
  }
385
399
  // Query type
@@ -431,7 +445,10 @@ function buildOperation(route, groupName, domainPrefix) {
431
445
  responseType,
432
446
  statusCode,
433
447
  deprecated: route.sdk?.deprecated ? true : undefined,
448
+ deprecationMessage: typeof route.sdk?.deprecated === 'string' ? route.sdk.deprecated : undefined,
449
+ timeout: route.sdk?.timeout,
434
450
  isEventStream: route.sse ?? route.sdk?.transport === 'stream',
451
+ sseReturnType: route.sdk?.sseReturnType,
435
452
  },
436
453
  inlineSchemas,
437
454
  };
@@ -458,8 +475,10 @@ function extractPathParams(url, paramsSchema) {
458
475
  if (urlParams.length === 0)
459
476
  return [];
460
477
  const s = paramsSchema;
461
- const props = s?.properties;
462
- const required = new Set(s?.required ?? []);
478
+ const props = typeof s?.properties === 'object' && !Array.isArray(s?.properties)
479
+ ? s.properties
480
+ : undefined;
481
+ const required = new Set(Array.isArray(s?.required) ? s.required : []);
463
482
  return urlParams.map((paramName) => {
464
483
  const propSchema = props?.[paramName];
465
484
  return {
@@ -479,7 +498,7 @@ function extractQueryParams(querySchema) {
479
498
  const s = querySchema;
480
499
  if (s.type !== 'object' || !s.properties)
481
500
  return [];
482
- const required = new Set(s.required ?? []);
501
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
483
502
  const props = s.properties;
484
503
  return Object.entries(props).map(([name, schema]) => ({
485
504
  name: camelCase(name),
@@ -504,7 +523,7 @@ function extractHeaderParams(headersSchema) {
504
523
  const s = headersSchema;
505
524
  if (s.type !== 'object' || !s.properties)
506
525
  return [];
507
- const required = new Set(s.required ?? []);
526
+ const required = new Set(Array.isArray(s.required) ? s.required : []);
508
527
  const props = s.properties;
509
528
  return Object.entries(props)
510
529
  .filter(([name]) => !SYSTEM_HEADERS.has(name.toLowerCase()))