@sumrco/cli 0.2.0 → 0.3.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.
@@ -25,10 +25,12 @@ kontract:
25
25
  type: typescript-nestjs
26
26
  zod: true
27
27
  dtos: true
28
+ sdk: true
28
29
  - name: frontend
29
30
  output: frontend/src/shared/api
30
31
  generator:
31
32
  type: typescript-fetch
33
+ schemaMode: normalize
32
34
  modelPropertyNaming: original
33
35
  paramNaming: original
34
36
  stringEnums: true
@@ -56,21 +58,27 @@ Use `--target <name>` to scope generation to one target.
56
58
 
57
59
  ## Generator types
58
60
 
59
- | Type | Purpose |
60
- |---|---|
61
- | `typescript-nestjs` | Backend HTTP contracts for NestJS services. |
62
- | `asyncapi-nats` | NATS subjects, message schemas, server interfaces, and clients. |
63
- | `typescript-fetch` | TypeScript fetch SDK. |
64
- | `typescript-axios` | TypeScript axios SDK. |
65
- | `typescript-angular` | Angular SDK. |
66
- | `typescript-models` | Framework-neutral model-only output. |
61
+ | Category | Type | Outputs |
62
+ |---|---|---|
63
+ | Server/framework | `typescript-nestjs` | Zod DTOs, class-validator DTOs, models, Swagger metadata, generated `ApiDoc` decorators. |
64
+ | Messaging | `asyncapi-nats` | NATS subjects, message schemas, server interfaces, and clients. |
65
+ | Client/SDK | `typescript-fetch` | TypeScript fetch SDK. |
66
+ | Client/SDK | `typescript-axios` | TypeScript axios SDK. |
67
+ | Client/SDK | `typescript-angular` | Angular SDK. |
68
+ | Model | `typescript-models` | Framework-neutral model-only output. |
69
+
70
+ Kontract is structured for more generator targets over time: runtime evidence,
71
+ docs-ready OpenAPI artifacts, packaged API contracts, SDKs, mocks, contract
72
+ tests, and breaking-change reports.
67
73
 
68
74
  ## `typescript-nestjs` options
69
75
 
70
76
  | Option | Output |
71
77
  |---|---|
72
78
  | `zod: true` | Emits `http/zod/*.contract.ts` with Zod schemas and `createZodDto()` classes. |
73
- | `dtos: true` | Emits `http/dto/*.dto.ts` plus `http/swagger.ts` operation metadata. |
79
+ | `dtos: true` | Emits `http/dto/*.dto.ts`; also keeps the compatibility behavior of emitting `http/swagger.ts`. |
80
+ | `swagger: true` | Emits per-service `http/swagger.ts` operation metadata and one shared `shared/http/decorators/api-doc.ts` helper for NestJS controllers. |
81
+ | `sdk: true` | Emits a fetch-based `http/sdk/` client that reuses the target's `http/models/` and `http/enums/` types. |
74
82
 
75
83
  `dtos` is the canonical spelling. `dto: true` is accepted as a compatibility
76
84
  alias and is normalized internally to `dtos: true`.
@@ -78,15 +86,59 @@ alias and is normalized internally to `dtos: true`.
78
86
  Framework-neutral interfaces under `http/models/` and enums under `http/enums/`
79
87
  are emitted for OpenAPI object schemas regardless of the Zod/DTO flavor.
80
88
 
89
+ Use `sdk: true` on a NestJS target when a backend service should call another
90
+ generated HTTP API. Use a standalone `typescript-fetch`, `typescript-axios`, or
91
+ `typescript-angular` target when a frontend/admin app should own its SDK output
92
+ separately.
93
+
94
+ ## OpenAPI schema mode
95
+
96
+ Standalone SDK and model targets default to `schemaMode: normalize`. In this
97
+ mode, Kontract accepts real-world OpenAPI specs with inline operation request or
98
+ response schemas, hoists those schemas into generated component names in memory,
99
+ and emits named TypeScript models.
100
+
101
+ Use `schemaMode: strict` when the source spec is product-owned and should fail
102
+ fast unless operation request/response schemas use reusable `$ref` components.
103
+
104
+ ```yaml
105
+ generator:
106
+ type: typescript-fetch
107
+ schemaMode: normalize # default for SDK/model targets
108
+ ```
109
+
110
+ ```yaml
111
+ generator:
112
+ type: typescript-fetch
113
+ schemaMode: strict
114
+ ```
115
+
116
+ Kontract still recommends reusable component schemas for owned APIs because they
117
+ produce stable names and cleaner docs. Normalization exists so customers can
118
+ generate SDKs from external or imperfect OpenAPI specs without rewriting the API
119
+ description first.
120
+
121
+ Use generic OpenAPI metadata for docs/runtime surfaces:
122
+
123
+ ```yaml
124
+ x-kontract-surface: public
125
+ security: []
126
+ ```
127
+
128
+ `x-kontract-surface` values are consumer-defined strings. SUMR uses `public`,
129
+ `app`, `admin`, and `internal`; another product might use `partner`, `mobile`,
130
+ or `marketplace`.
131
+
81
132
  ## Common debugging cases
82
133
 
83
- ### `http/dto/` or `http/swagger.ts` is missing
134
+ ### `http/dto/`, `http/swagger.ts`, or `shared/http/decorators/api-doc.ts` is missing
84
135
 
85
136
  Check both:
86
137
 
87
138
  1. The target config has `generator.type: typescript-nestjs` and `dtos: true`.
88
- `dto: true` is also accepted, but prefer `dtos` in new config.
89
- 2. The installed `SUMR Kontract module` version includes DTO/swagger support.
139
+ `dto: true` is also accepted, but prefer `dtos` in new config. If you use
140
+ Zod without class-validator DTOs, set `swagger: true` explicitly.
141
+ 2. The installed `SUMR Kontract module` version includes Swagger/ApiDoc support.
90
142
 
91
143
  If two configs generate identical output and both miss `dto/` + `swagger.ts`,
92
144
  the likely issue is the generator version being executed, not the consumer
@@ -97,6 +149,13 @@ repo's config.
97
149
  Check that the NestJS target has `zod: true` or that Zod generation has not been
98
150
  explicitly disabled.
99
151
 
152
+ ### `http/sdk/` is missing
153
+
154
+ Check that the NestJS target has `sdk: true`. Standalone SDK generator targets
155
+ emit service folders with `models.ts`, `runtime.ts`, and `api.ts`; the NestJS
156
+ composed SDK emits under `http/sdk/` and imports types from existing
157
+ `http/models/` and `http/enums/`.
158
+
100
159
  ### Generated files are stale
101
160
 
102
161
  Run a scoped clean generation:
@@ -28,7 +28,13 @@ contracts/recipes/
28
28
  models/
29
29
  zod/ # when zod generation is enabled
30
30
  dto/ # when dtos generation is enabled
31
- swagger.ts # when dtos generation is enabled
31
+ sdk/ # when sdk generation is enabled
32
+ swagger.ts # when swagger generation is enabled
33
+
34
+ contracts/shared/
35
+ http/
36
+ decorators/
37
+ api-doc.ts # one shared helper when swagger generation is enabled
32
38
  ```
33
39
 
34
40
  Shared `$ref` components keep the source spec DRY and semantically consistent.
@@ -45,6 +51,7 @@ symbol names:
45
51
  ```typescript
46
52
  export * as Dtos from './dto';
47
53
  export * as Models from './models';
54
+ export * as Sdk from './sdk';
48
55
  export * as ZodContracts from './zod';
49
56
  export * from './enums';
50
57
  export * from './swagger';
@@ -122,29 +129,149 @@ properties include `@Expose()` so they remain compatible with class-transformer
122
129
  serializers that use `excludeExtraneousValues: true`. Do not hand-write parallel
123
130
  DTOs for schemas Kontract owns.
124
131
 
125
- ## Swagger operation metadata — when `dtos: true`
132
+ ## Swagger operation metadata — when `swagger: true`
126
133
 
127
134
  ```typescript
128
135
  // contracts/recipes/http/swagger.ts
129
- import type { RecipeDto } from './dto/recipe.dto';
136
+ import { RecipeDto } from './zod/recipe.contract';
130
137
 
131
138
  export const SWG_LIST_RECIPES = {
139
+ operationId: 'listRecipes',
132
140
  method: 'GET',
133
141
  path: '/recipes',
134
- operationId: 'listRecipes',
142
+ summary: 'List recipes',
143
+ description: 'Returns recipes available to the caller.',
144
+ surface: 'public',
145
+ security: [],
135
146
  responseDto: RecipeDto,
147
+ responseDescription: 'Recipes returned.',
136
148
  } as const;
137
149
  ```
138
150
 
139
- Controllers can consume `SWG_*` metadata to keep operation IDs, paths, params,
140
- body DTOs, and response DTOs aligned with OpenAPI.
151
+ `swagger: true` works with either `zod: true` or `dtos: true`. Generated
152
+ metadata preserves operation IDs, paths, summaries, descriptions, params, query
153
+ params, body DTOs, response DTOs, success response status, `x-kontract-surface`,
154
+ and standard OpenAPI `security`.
155
+
156
+ ## Generated `ApiDoc` decorator — when `swagger: true`
157
+
158
+ ```typescript
159
+ // contracts/shared/http/decorators/api-doc.ts
160
+ export function ApiDoc(operation: ApiDocOperation): MethodDecorator {
161
+ // Applies ApiOperation, ApiParam, ApiQuery, ApiBody, ApiResponse,
162
+ // ApiExtension('x-kontract-surface', ...), and Swagger security metadata.
163
+ }
164
+ ```
165
+
166
+ Controllers can consume `ApiDoc(SWG_*)` metadata to keep runtime Swagger output
167
+ aligned with the OpenAPI design contract:
168
+
169
+ ```typescript
170
+ import { SWG_LIST_RECIPES } from 'SUMR Schemas module/recipes/http';
171
+ import { ApiDoc } from 'SUMR Schemas module/shared/http';
172
+
173
+ @Get()
174
+ @ApiDoc(SWG_LIST_RECIPES)
175
+ async listRecipes() {
176
+ // controller implementation
177
+ }
178
+ ```
179
+
180
+ Generated `ApiDoc` depends only on NestJS and `@nestjs/swagger`; it does not
181
+ import Kontract at runtime.
182
+
183
+ ## NestJS-composed SDK — when `sdk: true`
184
+
185
+ ```typescript
186
+ // contracts/recipes/http/sdk/api.ts
187
+ import type * as Models from '../models';
188
+ import type * as Enums from '../enums';
189
+ import type { RequestConfig } from './runtime';
190
+
191
+ export interface GetRecipeRequest {
192
+ recipeId: string;
193
+ status?: Enums.RecipeStatus;
194
+ }
195
+
196
+ export class RecipesFetchClient {
197
+ constructor(private readonly config: RequestConfig = {}) {}
198
+
199
+ async getRecipe(request: GetRecipeRequest): Promise<Models.Recipe> {
200
+ // fetch call generated from OpenAPI operation metadata
201
+ }
202
+ }
203
+ ```
204
+
205
+ The composed SDK is for NestJS services that call another generated HTTP API.
206
+ It emits `http/sdk/runtime.ts`, `http/sdk/api.ts`, and a local barrel, but it
207
+ does not duplicate the target's models. Component schema references import from
208
+ `http/models/`; component enum references import from `http/enums/`; inline
209
+ operation enums remain local literal unions.
210
+
211
+ Use standalone `typescript-fetch`, `typescript-axios`, or `typescript-angular`
212
+ targets when a frontend/admin application should own a separate SDK package.
213
+
214
+ ## Frontend SDKs — React and Angular apps
215
+
216
+ Standalone SDK targets are meant to remove hand-written API calls from consumer
217
+ apps:
218
+
219
+ - `typescript-fetch` emits a browser-compatible fetch client that can be used
220
+ from React, Vue, Svelte, plain TypeScript, or any runtime with `fetch`.
221
+ - `typescript-axios` emits an axios client for apps that already standardize on
222
+ axios interceptors or shared axios instances.
223
+ - `typescript-angular` emits an Angular service that uses `HttpClient` and
224
+ returns `Observable<T>`.
225
+
226
+ Example React usage with the fetch SDK:
227
+
228
+ ```typescript
229
+ import { ProductsFetchClient } from './generated/api';
230
+
231
+ const api = new ProductsFetchClient({
232
+ baseUrl: '/api',
233
+ decodeJson: (value) => value as never,
234
+ });
235
+
236
+ export async function loadProduct(id: string) {
237
+ return api.getProduct({ id });
238
+ }
239
+ ```
240
+
241
+ Example Angular usage:
242
+
243
+ ```typescript
244
+ import { Component } from '@angular/core';
245
+ import { ProductsApiService } from './generated/api';
246
+
247
+ @Component({ /* ... */ })
248
+ export class ProductPage {
249
+ constructor(private readonly api: ProductsApiService) {}
250
+
251
+ save(name: string) {
252
+ return this.api.createProduct({ name });
253
+ }
254
+ }
255
+ ```
256
+
257
+ The generated SDK owns path interpolation, query serialization, request body
258
+ encoding, response typing, and generated model imports. Consumers call methods
259
+ instead of rewriting API URLs and `fetch`/`HttpClient` calls by hand.
141
260
 
142
261
  ## NATS contract — one `nats/index.ts` per AsyncAPI service
143
262
 
144
263
  ```typescript
145
264
  // contracts/recipes/nats/index.ts
265
+ import { RecipeStatusValues } from './enums';
266
+
267
+ export * from './enums';
268
+
146
269
  export namespace Recipes {
147
- export const CreateRecipeMessage = z.object({ name: z.string(), slug: z.string() });
270
+ export const CreateRecipeMessage = z.object({
271
+ name: z.string(),
272
+ slug: z.string(),
273
+ status: z.enum(RecipeStatusValues),
274
+ });
148
275
  export type CreateRecipeMessage = z.infer<typeof CreateRecipeMessage>;
149
276
  export type CreateRecipeMessageInput = z.input<typeof CreateRecipeMessage>;
150
277
 
@@ -164,13 +291,49 @@ export namespace Recipes {
164
291
  - Subjects live in a single `SUBJECTS` const used directly by NestJS NATS.
165
292
  - Clients validate input with `.parse()` before sending.
166
293
 
294
+ ## NATS enum constants — `nats/enums/` per AsyncAPI service
295
+
296
+ Named `components/schemas` entries that are string or number enums emit one
297
+ constant file each, mirroring `http/enums/`:
298
+
299
+ ```typescript
300
+ // contracts/recipes/nats/enums/recipe-status.enum.ts
301
+ export const RecipeStatusValues = ['draft', 'published', 'archived'] as const;
302
+
303
+ export type RecipeStatus = (typeof RecipeStatusValues)[number];
304
+
305
+ export const RecipeStatusMap = {
306
+ Draft: 'draft',
307
+ Published: 'published',
308
+ Archived: 'archived',
309
+ } as const;
310
+ ```
311
+
312
+ - Message schemas reference shared string enum components as
313
+ `z.enum(<Name>Values)` instead of inlining literals, so wire enums have one
314
+ importable source of truth. This also works for multi-file specs and external
315
+ `$ref` fragments: bundling runs with `--xOrigin`, and the generator resolves
316
+ dereferenced copies back to their named component.
317
+ - `nats/index.ts` re-exports the folder (`export * from './enums';`); import
318
+ constants from the service NATS barrel instead of deriving them from Zod
319
+ internals such as `Schema.shape.field.enum`.
320
+ - Anonymous inline property enums stay inline `z.enum([...])`. Promote an enum
321
+ to `components/schemas` when services need its constants.
322
+ - Number enums get constant files but stay inline literal unions in message
323
+ schemas (`z.enum` accepts strings only).
324
+
167
325
  ## Consuming in NestJS
168
326
 
169
327
  - Use `http/zod` `${Name}Dto` classes when you want `nestjs-zod` request/response
170
328
  validation.
171
- - Use `http/dto` classes and `http/swagger.ts` when a controller follows the
172
- class-validator + Swagger metadata pattern.
329
+ - Use per-service `http/swagger.ts` and the shared
330
+ `shared/http/decorators/api-doc.ts` helper when a controller should prove
331
+ runtime Swagger/OpenAPI behavior from generated metadata.
332
+ - Use `http/dto` classes when a controller follows the class-validator DTO
333
+ pattern.
173
334
  - Use `http/models` interfaces for type-only internal code.
335
+ - Use `http/sdk` clients when a NestJS service needs a generated HTTP client
336
+ without a separate frontend SDK target.
174
337
  - Use the generated `*Client` classes and `SUBJECTS` for NATS — do not
175
338
  hand-write subjects or message shapes.
176
339
  - Each generated directory has a barrel `index.ts` for local aggregation only.
@@ -0,0 +1,62 @@
1
+ ---
2
+ category: reference
3
+ name: language-sdk-generator-extension
4
+ title: Language SDK Generator Extension
5
+ description: "How Kontract should add future non-TypeScript SDK generators such as Java or Rust."
6
+ label: Language SDK Generator Extension
7
+ when: Researching or implementing a new Kontract SDK generator for another language
8
+ order: 47
9
+ ---
10
+
11
+ # Language SDK Generator Extension
12
+
13
+ Kontract can add Java, Rust, or other SDK generators, but only as explicit
14
+ generator types after research and tests prove the output is useful.
15
+
16
+ ## Current support
17
+
18
+ Implemented generators:
19
+
20
+ - `typescript-nestjs`
21
+ - `asyncapi-nats`
22
+ - `typescript-fetch`
23
+ - `typescript-axios`
24
+ - `typescript-angular`
25
+ - `typescript-models`
26
+
27
+ Java and Rust are not implemented yet. Config such as `type: java` or
28
+ `type: rust` must fail until a real generator exists.
29
+
30
+ ## Add a new language generator
31
+
32
+ Use this sequence:
33
+
34
+ 1. Research mature public generators for the target language and record lessons
35
+ in `resources/`.
36
+ 2. Add the generator type to `src/types/contracts.types.ts`.
37
+ 3. Add config parsing and allowed options in `src/lib/sumr-yaml.ts`.
38
+ 4. Add dependency warnings in `src/cli/dependency-check.ts` only when generated
39
+ output requires runtime packages in the consumer repo.
40
+ 5. Add a generator implementation under `src/generators/openapi/<language>/` or
41
+ a shared SDK emitter if the language can reuse one.
42
+ 6. Wire generation planning in `src/cli/generate-plan.ts`.
43
+ 7. Add tests that prove config parsing, output shape, unsafe-schema failures,
44
+ and generated file roots.
45
+ 8. Update `README.md`, `docs/**`, `resources/**`, and regenerate AI resources
46
+ with `bun run sync`.
47
+
48
+ ## Test coverage required
49
+
50
+ Every generator must have at least:
51
+
52
+ - a config parsing test;
53
+ - a direct generation test for expected root files;
54
+ - an edge-case test for reserved names or language keywords;
55
+ - query array serialization coverage for HTTP SDKs;
56
+ - enum and `additionalProperties` coverage where the language supports them;
57
+ - a rejection test for unsupported schema features such as unsafe polymorphism;
58
+ - a catalog coverage test so the documented generator list and implemented list
59
+ stay aligned.
60
+
61
+ Do not add a generator type first and fill behavior later. Unsupported language
62
+ targets should stay rejected until they can generate useful, validated output.
@@ -0,0 +1,59 @@
1
+ ---
2
+ category: reference
3
+ name: openapi-sdk-generator-research
4
+ title: OpenAPI SDK Generator Research
5
+ description: "Public generator lessons Kontract applies when evolving TypeScript SDK output."
6
+ label: OpenAPI SDK Generator Research
7
+ when: Designing or reviewing Kontract SDK output, runtime helpers, config options, or schema preview work
8
+ order: 46
9
+ ---
10
+
11
+ # OpenAPI SDK Generator Research
12
+
13
+ Kontract learns from public OpenAPI generators without inheriting their runtime
14
+ shape, Java dependency chain, or template system.
15
+
16
+ ## References reviewed
17
+
18
+ - OpenAPI Generator `typescript-fetch`:
19
+ <https://openapi-generator.tech/docs/generators/typescript-fetch/>
20
+ - OpenAPI Generator `typescript-axios`:
21
+ <https://openapi-generator.tech/docs/generators/typescript-axios/>
22
+ - OpenAPI Generator `typescript-angular`:
23
+ <https://openapi-generator.tech/docs/generators/typescript-angular/>
24
+ - OpenAPI Generator `typescript-nestjs`:
25
+ <https://openapi-generator.tech/docs/generators/typescript-nestjs/>
26
+ - OpenAPI TypeScript `openapi-fetch`:
27
+ <https://openapi-ts.dev/openapi-fetch/>
28
+
29
+ ## Lessons for Kontract
30
+
31
+ - Keep SDK config options familiar where they are useful:
32
+ `useSingleRequestParameter`, `paramNaming`, `modelPropertyNaming`,
33
+ `enumPropertyNaming`, `stringEnums`, `enumUnknownDefaultCase`,
34
+ `sortParamsByRequiredFlag`, and `sortModelPropertiesByRequiredFlag`.
35
+ - Prefer strict, readable output over broad template compatibility. Public
36
+ generators support many options, but that breadth often creates heavy runtime
37
+ helpers and harder-to-review generated code.
38
+ - Treat query serialization as contract behavior. Array query params should stay
39
+ repeated keys unless the spec says otherwise.
40
+ - Keep reserved-word handling in the SDK path. Wire names such as `from`,
41
+ `class`, and `default` must remain valid request keys while local variables
42
+ stay valid TypeScript identifiers.
43
+ - Preserve OpenAPI `additionalProperties` semantics in models and SDK types.
44
+ - Fail before partial output for unsupported polymorphism rather than generating
45
+ missing or unsafe symbols.
46
+ - Keep the fetch runtime small. `openapi-fetch` is a useful benchmark for a
47
+ low-runtime client; Kontract should avoid pulling in a heavy client runtime
48
+ unless a target explicitly asks for it.
49
+
50
+ ## Product decisions
51
+
52
+ - `typescript-nestjs` remains a server-contract generator. Its `sdk: true`
53
+ option adds a companion fetch client for NestJS consumers; it does not turn
54
+ the target into a standalone frontend package.
55
+ - `typescript-fetch`, `typescript-axios`, and `typescript-angular` remain
56
+ standalone SDK targets with their own generated models.
57
+ - Schema preview HTML needs a separate research spike because bundle size,
58
+ license, and static-output feasibility affect whether the feature belongs in
59
+ Kontract, Website, or both.
@@ -1,22 +1,24 @@
1
1
  ---
2
2
  name: usage
3
3
  title: Kontract Usage
4
- description: "How to use the SUMR Kontract CLI to generate NestJS-ready TypeScript contracts from OpenAPI and AsyncAPI specs. Use when adding, changing, reviewing, validating, or generating API contracts."
4
+ description: "How to use the SUMR Kontract CLI to generate configured contract artifacts from OpenAPI and AsyncAPI sources. Use when adding, changing, reviewing, validating, or generating API contracts."
5
5
  tags: [kontract, contracts, openapi, asyncapi, nestjs, codegen]
6
6
  ---
7
7
 
8
8
  # Kontract Usage
9
9
 
10
- Kontract turns YAML API specs into typed, validated TypeScript: NestJS HTTP
11
- contracts, optional class-validator DTOs, Swagger operation metadata, frontend
12
- SDKs, NATS subjects, server interfaces, and clients — all from a single source
13
- of truth so implementations do not drift from the contract.
10
+ Kontract generates the artifacts that keep APIs honest: validation schemas,
11
+ framework decorators, SDKs, docs inputs, runtime evidence, and message contracts
12
+ from OpenAPI and AsyncAPI sources.
14
13
 
15
14
  ## When to Use
16
15
 
17
16
  - Adding or editing an OpenAPI (`*.openapi.yml`) or AsyncAPI (`*.asyncapi.yml`) spec.
18
- - Reviewing newly written or updated `*.openapi.yml` / `*.asyncapi.yml` files
19
- against Kontract best practices before validation or generation.
17
+ - Adding domain/subdomain specs with the neutral `*.schema.yml` suffix when the
18
+ YAML marker (`openapi:` or `asyncapi:`) should decide the protocol.
19
+ - Reviewing newly written or updated `*.openapi.yml`, `*.asyncapi.yml`, or
20
+ `*.schema.yml` files against Kontract best practices before validation or
21
+ generation.
20
22
  - Refactoring duplicated schema fields into shared `$ref` components.
21
23
  - Regenerating contracts after a spec change.
22
24
  - Validating specs before committing or in CI.
@@ -27,7 +29,7 @@ of truth so implementations do not drift from the contract.
27
29
  ```bash
28
30
  sumr kontract init # activate Kontract AI guidance for this repo
29
31
  sumr kontract validate # validate configured OpenAPI/AsyncAPI sources
30
- sumr kontract generate # generate TypeScript contracts and SDKs
32
+ sumr kontract generate # generate configured contract artifacts
31
33
  ```
32
34
 
33
35
  Useful flags:
@@ -46,11 +48,14 @@ Useful flags:
46
48
  schema/
47
49
  recipes.openapi.yml → contracts/recipes/http/
48
50
  recipes.asyncapi.yml → contracts/recipes/nats/index.ts
51
+ recipes/
52
+ catalog.schema.yml → contracts/recipes/http/
53
+ events.schema.yml → contracts/recipes/nats/index.ts
49
54
  ```
50
55
 
51
- One source of truth (the YAML spec) → many generated, always-consistent
52
- TypeScript artifacts. Generated files are outputs: never hand-edit them — change
53
- the spec and regenerate.
56
+ One OpenAPI or AsyncAPI source → many generated, always-consistent artifacts.
57
+ Generated files are outputs: never hand-edit them — change the spec and
58
+ regenerate.
54
59
 
55
60
  ## Configuration
56
61
 
@@ -68,7 +73,7 @@ kontract:
68
73
  generator:
69
74
  type: typescript-nestjs
70
75
  zod: true
71
- dtos: true
76
+ swagger: true
72
77
  - name: frontend
73
78
  output: frontend/src/shared/api
74
79
  generator:
@@ -79,25 +84,69 @@ For `typescript-nestjs`:
79
84
 
80
85
  - `zod: true` emits NestJS-Zod contracts under `http/zod/`.
81
86
  - `dtos: true` emits class-validator DTOs under `http/dto/` plus
82
- `http/swagger.ts` operation metadata.
87
+ compatibility `http/swagger.ts` operation metadata.
88
+ - `swagger: true` emits per-service `http/swagger.ts` operation metadata and one
89
+ shared `shared/http/decorators/api-doc.ts` helper for NestJS controllers.
90
+ - `sdk: true` emits a fetch-based `http/sdk/` client that reuses the same
91
+ `http/models/` and `http/enums/` generated for the NestJS target.
83
92
  - `dto: true` is accepted as a compatibility alias for `dtos: true`; prefer
84
93
  `dtos` in new config.
85
94
  - Framework-neutral model interfaces are emitted under `http/models/`.
86
95
 
87
- If a consuming repo is missing `http/dto/` or `http/swagger.ts`, first confirm
88
- the target has `dtos: true` (or `dto: true`) and that the installed
89
- `SUMR Kontract module` version contains DTO/swagger support.
96
+ If a consuming repo is missing `http/swagger.ts` or
97
+ `shared/http/decorators/api-doc.ts`, first confirm the target has
98
+ `swagger: true`, and that the installed `SUMR Kontract module` version contains
99
+ Swagger/ApiDoc support.
100
+
101
+ ## Generator Catalog
102
+
103
+ ### Current
104
+
105
+ | Category | Generator | Outputs |
106
+ |---|---|---|
107
+ | Server/framework | `typescript-nestjs` | Zod DTOs, class-validator DTOs, models, Swagger metadata, generated `ApiDoc`, optional SDK. |
108
+ | Messaging | `asyncapi-nats` | NATS subjects, message schemas, client/server interfaces. |
109
+ | Client/SDK | `typescript-fetch` / `typescript-axios` / `typescript-angular` | Standalone TypeScript clients with bundled models. |
110
+ | Model | `typescript-models` | Framework-neutral model-only output. |
111
+
112
+ ### Near-term
113
+
114
+ | Category | Generator | Outputs |
115
+ |---|---|---|
116
+ | Runtime evidence | NestJS Swagger extraction | OpenAPI JSON from real Nest routes. |
117
+ | API package | API contracts package | Packaged OpenAPI artifacts. |
118
+ | Docs | docs-ready OpenAPI | Filtered public/app/admin docs inputs. |
119
+ | Preview | schema preview HTML | Static API reference output after Scalar/free-option research. |
120
+ | SDK | TypeScript SDK | Public/app/admin clients. |
121
+ | Quality | contract tests | Route/spec drift and response-shape tests. |
122
+
123
+ ### Future
124
+
125
+ - Java, Rust, Python, Go, and Swift SDKs.
126
+ - Postman or Bruno collections.
127
+ - mock servers.
128
+ - breaking-change and OpenAPI diff reports.
129
+ - API changelog artifacts.
130
+ - docs snippets and examples.
90
131
 
91
132
  ## Core Rules
92
133
 
93
134
  - Validate before you generate: `sumr kontract validate` then `sumr kontract generate`.
94
135
  - Treat everything under the generated `contracts/` output as read-only.
95
136
  - Keep specs the single source of truth; do not hand-write Zod/DTOs that Kontract owns.
96
- - After writing or updating any `*.openapi.yml` or `*.asyncapi.yml` file, review
97
- the spec for duplicated concepts before generation.
137
+ - After writing or updating any `*.openapi.yml`, `*.asyncapi.yml`, or
138
+ `*.schema.yml` file, review the spec for duplicated concepts before
139
+ generation.
140
+ - Treat `summary`, `description`, `title`, parameter descriptions, response
141
+ descriptions, and message descriptions as user-facing copy when they appear in
142
+ docs, Swagger, Scalar, generated SDKs, or AI answers. Route changed copy
143
+ through the repo's copywriter/microcopy standard before generation.
98
144
  - Design specs for reuse: shared parameters, scalar constraints, error responses,
99
145
  response envelope fragments, pagination metadata, schedule/time-slot shapes,
100
146
  and common config objects belong in shared components referenced with `$ref`.
147
+ - Use compact YAML readability rules for editor navigation: section comments are
148
+ visual landmarks only, naming follows domain meaning, and large files should
149
+ split by domain/subdomain before comments become a table of contents.
101
150
  - See the spec layout and generated output references for the exact file shapes.
102
151
  - See the scope and splitting reference when a spec or Kontract source file
103
152
  crosses the review thresholds, mixes domains, or needs domain/subdomain
@@ -106,6 +155,10 @@ the target has `dtos: true` (or `dto: true`) and that the installed
106
155
  generated diff with many near-identical DTO/model files.
107
156
  - See the OpenAPI generator lessons reference before changing query params,
108
157
  inline schemas, SDK serialization, or strict TypeScript compatibility rules.
158
+ - See the OpenAPI SDK generator research reference before changing SDK runtime
159
+ shape, target defaults, model imports, or preview-docs direction.
160
+ - See the language SDK generator extension reference before adding Java, Rust,
161
+ or any non-TypeScript SDK target.
109
162
  - Use scoped flags (`--source`, `--target`, `--specific`) before `--clean` in a
110
163
  large consumer repo.
111
164
  - Warm generation is manifest-driven. Kontract stores per-service manifests in