@sumrco/cli 0.2.1 → 0.3.1
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/ai/modules/kontract/resources/api-generation-standards.rf.md +83 -0
- package/ai/modules/kontract/resources/authoring/configuration.rf.md +220 -0
- package/ai/modules/kontract/resources/authoring/design-profile/api-styles.rf.md +241 -0
- package/ai/modules/kontract/resources/authoring/design-profile/async-styles.rf.md +134 -0
- package/ai/modules/kontract/resources/authoring/design-profile/overview.md +64 -0
- package/ai/modules/kontract/resources/authoring/design-profile/schema-layout-styles.rf.md +356 -0
- package/ai/modules/kontract/resources/authoring/overview.md +56 -0
- package/ai/modules/kontract/resources/authoring/schema-reuse.rf.md +492 -0
- package/ai/modules/kontract/resources/authoring/scope-and-splitting.rf.md +244 -0
- package/ai/modules/kontract/resources/authoring/spec-layout.rf.md +492 -0
- package/ai/modules/kontract/resources/authoring/team-members/spec-author.tm.md +77 -0
- package/ai/modules/kontract/resources/{workflows/contract-change.wf.md → authoring/workflows/spec-change.wf.md} +24 -16
- package/ai/modules/kontract/resources/generated-output.rf.md +185 -17
- package/ai/modules/kontract/resources/openapi-sdk-generator-research.rf.md +57 -0
- package/ai/modules/kontract/resources/overview.md +130 -44
- package/ai/modules/kontract/resources/performance.rf.md +7 -7
- package/ai/modules/kontract/sumr.module.yaml +5 -2
- package/ai/modules/mission/sumr.module.yaml +6 -0
- package/ai/modules/playbook/resources/authoring/content-structure.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/descriptions.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/extraction.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/flows.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +4 -1
- package/ai/modules/playbook/resources/authoring/markdown.rf.md +1 -1
- package/ai/modules/playbook/resources/authoring/overview.md +1 -1
- package/ai/modules/playbook/resources/team-members/{playbook-technical-writer.tm.md → technical-writer.tm.md} +3 -2
- package/ai/modules/playbook/sumr.module.yaml +7 -2
- package/index.js +486 -284
- package/package.json +1 -1
- package/ai/modules/kontract/resources/configuration.rf.md +0 -123
- package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +0 -61
- package/ai/modules/kontract/resources/schema-reuse.rf.md +0 -233
- package/ai/modules/kontract/resources/scope-and-splitting.rf.md +0 -147
- package/ai/modules/kontract/resources/spec-layout.rf.md +0 -69
- package/ai/modules/kontract/resources/team-members/contract-author.tm.md +0 -52
|
@@ -14,9 +14,9 @@ Generated files are deterministic outputs. Import them; never edit them.
|
|
|
14
14
|
Every generated TypeScript file starts with an `<auto-generated>` comment that
|
|
15
15
|
warns users not to edit the file directly.
|
|
16
16
|
|
|
17
|
-
## HTTP output — one folder per
|
|
17
|
+
## HTTP output — one folder per API schema service
|
|
18
18
|
|
|
19
|
-
For an
|
|
19
|
+
For an API schema service such as `recipes.api.yml`, the NestJS target
|
|
20
20
|
emits a service folder:
|
|
21
21
|
|
|
22
22
|
```text
|
|
@@ -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
|
-
|
|
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';
|
|
@@ -53,7 +60,7 @@ export * from './swagger';
|
|
|
53
60
|
Do not flatten-import everything blindly when DTO/model/Zod symbols collide.
|
|
54
61
|
Use the namespace exports or import from the leaf folder.
|
|
55
62
|
|
|
56
|
-
## Zod contract — one file per
|
|
63
|
+
## Zod contract — one file per API schema `components/schemas` entry
|
|
57
64
|
|
|
58
65
|
```typescript
|
|
59
66
|
// contracts/recipes/http/zod/recipe.contract.ts
|
|
@@ -84,17 +91,17 @@ export interface Recipe {
|
|
|
84
91
|
}
|
|
85
92
|
```
|
|
86
93
|
|
|
87
|
-
Model interfaces are framework-
|
|
94
|
+
Model interfaces are framework-and are safe for backend and frontend
|
|
88
95
|
type-only imports.
|
|
89
96
|
|
|
90
|
-
Map-shaped schemas follow
|
|
97
|
+
Map-shaped schemas follow API schema `additionalProperties` semantics:
|
|
91
98
|
|
|
92
99
|
- map-only schemas generate index signatures such as `[key: string]: string`;
|
|
93
100
|
- named properties with `additionalProperties: true` preserve the named fields
|
|
94
101
|
and use `[key: string]: unknown`;
|
|
95
102
|
- named properties with typed `additionalProperties` preserve named fields and
|
|
96
103
|
widen the index signature with known property value types, matching the
|
|
97
|
-
practical TypeScript approach used by current
|
|
104
|
+
practical TypeScript approach used by current API schema TypeScript generators.
|
|
98
105
|
|
|
99
106
|
## Class-validator DTO — when `dtos: true`
|
|
100
107
|
|
|
@@ -122,29 +129,154 @@ 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 `
|
|
132
|
+
## Swagger operation metadata — when `swagger: true`
|
|
126
133
|
|
|
127
134
|
```typescript
|
|
128
135
|
// contracts/recipes/http/swagger.ts
|
|
129
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
140
|
-
|
|
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 API schema `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 API schema 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 API schema 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
|
+
import { decodeProductApiJson } from './product-api-decoder';
|
|
231
|
+
|
|
232
|
+
const api = new ProductsFetchClient({
|
|
233
|
+
baseUrl: '/api',
|
|
234
|
+
decodeJson: decodeProductApiJson,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
export async function loadProduct(id: string) {
|
|
238
|
+
return api.getProduct({ id });
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Use an application-owned decoder such as a generated Zod schema, Valibot schema,
|
|
243
|
+
or reviewed type guard at the `decodeJson` boundary. Do not cast unknown JSON in
|
|
244
|
+
consumer code.
|
|
141
245
|
|
|
142
|
-
|
|
246
|
+
Example Angular usage:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { Component } from '@angular/core';
|
|
250
|
+
import { ProductsApiService } from './generated/api';
|
|
251
|
+
|
|
252
|
+
@Component({ /* ... */ })
|
|
253
|
+
export class ProductPage {
|
|
254
|
+
constructor(private readonly api: ProductsApiService) {}
|
|
255
|
+
|
|
256
|
+
save(name: string) {
|
|
257
|
+
return this.api.createProduct({ name });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The generated SDK owns path interpolation, query serialization, request body
|
|
263
|
+
encoding, response typing, and generated model imports. Consumers call methods
|
|
264
|
+
instead of rewriting API URLs and `fetch`/`HttpClient` calls by hand.
|
|
265
|
+
|
|
266
|
+
## NATS contract — one `nats/index.ts` per async schema service
|
|
143
267
|
|
|
144
268
|
```typescript
|
|
145
269
|
// contracts/recipes/nats/index.ts
|
|
270
|
+
import { RecipeStatusValues } from './enums';
|
|
271
|
+
|
|
272
|
+
export * from './enums';
|
|
273
|
+
|
|
146
274
|
export namespace Recipes {
|
|
147
|
-
export const CreateRecipeMessage = z.object({
|
|
275
|
+
export const CreateRecipeMessage = z.object({
|
|
276
|
+
name: z.string(),
|
|
277
|
+
slug: z.string(),
|
|
278
|
+
status: z.enum(RecipeStatusValues),
|
|
279
|
+
});
|
|
148
280
|
export type CreateRecipeMessage = z.infer<typeof CreateRecipeMessage>;
|
|
149
281
|
export type CreateRecipeMessageInput = z.input<typeof CreateRecipeMessage>;
|
|
150
282
|
|
|
@@ -159,18 +291,54 @@ export namespace Recipes {
|
|
|
159
291
|
}
|
|
160
292
|
```
|
|
161
293
|
|
|
162
|
-
- Namespace name comes from
|
|
294
|
+
- Namespace name comes from async schema `info.title`.
|
|
163
295
|
- Every message yields a Zod const + `z.infer<>` type + `z.input<>` input type.
|
|
164
296
|
- Subjects live in a single `SUBJECTS` const used directly by NestJS NATS.
|
|
165
297
|
- Clients validate input with `.parse()` before sending.
|
|
166
298
|
|
|
299
|
+
## NATS enum constants — `nats/enums/` per async schema service
|
|
300
|
+
|
|
301
|
+
Named `components/schemas` entries that are string or number enums emit one
|
|
302
|
+
constant file each, mirroring `http/enums/`:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// contracts/recipes/nats/enums/recipe-status.enum.ts
|
|
306
|
+
export const RecipeStatusValues = ['draft', 'published', 'archived'] as const;
|
|
307
|
+
|
|
308
|
+
export type RecipeStatus = (typeof RecipeStatusValues)[number];
|
|
309
|
+
|
|
310
|
+
export const RecipeStatusMap = {
|
|
311
|
+
Draft: 'draft',
|
|
312
|
+
Published: 'published',
|
|
313
|
+
Archived: 'archived',
|
|
314
|
+
} as const;
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
- Message schemas reference shared string enum components as
|
|
318
|
+
`z.enum(<Name>Values)` instead of inlining literals, so wire enums have one
|
|
319
|
+
importable source of truth. This also works for multi-file specs and external
|
|
320
|
+
`$ref` fragments: bundling runs with `--xOrigin`, and the generator resolves
|
|
321
|
+
dereferenced copies back to their named component.
|
|
322
|
+
- `nats/index.ts` re-exports the folder (`export * from './enums';`); import
|
|
323
|
+
constants from the service NATS barrel instead of deriving them from Zod
|
|
324
|
+
internals such as `Schema.shape.field.enum`.
|
|
325
|
+
- Anonymous inline property enums stay inline `z.enum([...])`. Promote an enum
|
|
326
|
+
to `components/schemas` when services need its constants.
|
|
327
|
+
- Number enums get constant files but stay inline literal unions in message
|
|
328
|
+
schemas (`z.enum` accepts strings only).
|
|
329
|
+
|
|
167
330
|
## Consuming in NestJS
|
|
168
331
|
|
|
169
332
|
- Use `http/zod` `${Name}Dto` classes when you want `nestjs-zod` request/response
|
|
170
333
|
validation.
|
|
171
|
-
- Use
|
|
172
|
-
|
|
334
|
+
- Use per-service `http/swagger.ts` and the shared
|
|
335
|
+
`shared/http/decorators/api-doc.ts` helper when a controller should prove
|
|
336
|
+
runtime Swagger/API schema behavior from generated metadata.
|
|
337
|
+
- Use `http/dto` classes when a controller follows the class-validator DTO
|
|
338
|
+
pattern.
|
|
173
339
|
- Use `http/models` interfaces for type-only internal code.
|
|
340
|
+
- Use `http/sdk` clients when a NestJS service needs a generated HTTP client
|
|
341
|
+
without a separate frontend SDK target.
|
|
174
342
|
- Use the generated `*Client` classes and `SUBJECTS` for NATS — do not
|
|
175
343
|
hand-write subjects or message shapes.
|
|
176
344
|
- Each generated directory has a barrel `index.ts` for local aggregation only.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: reference
|
|
3
|
+
name: openapi-sdk-generator-research
|
|
4
|
+
title: API schema SDK Generator Research
|
|
5
|
+
description: "Generator design inputs Kontract uses for current TypeScript SDK output."
|
|
6
|
+
label: API schema SDK Generator Research
|
|
7
|
+
when: Designing or reviewing Kontract SDK output, runtime helpers, config options, or model imports
|
|
8
|
+
order: 46
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# API schema SDK Generator Research
|
|
12
|
+
|
|
13
|
+
Kontract reviews public API schema generator behavior to keep TypeScript SDK output
|
|
14
|
+
familiar, small, and Bun-native without inheriting Java dependency chains or
|
|
15
|
+
template systems.
|
|
16
|
+
|
|
17
|
+
## Reviewed generator inputs
|
|
18
|
+
|
|
19
|
+
- API schema Generator `typescript-fetch`:
|
|
20
|
+
<https://openapi-generator.tech/docs/generators/typescript-fetch/>
|
|
21
|
+
- API schema Generator `typescript-axios`:
|
|
22
|
+
<https://openapi-generator.tech/docs/generators/typescript-axios/>
|
|
23
|
+
- API schema Generator `typescript-angular`:
|
|
24
|
+
<https://openapi-generator.tech/docs/generators/typescript-angular/>
|
|
25
|
+
- API schema Generator `typescript-nestjs`:
|
|
26
|
+
<https://openapi-generator.tech/docs/generators/typescript-nestjs/>
|
|
27
|
+
- API schema TypeScript `openapi-fetch`:
|
|
28
|
+
<https://openapi-ts.dev/openapi-fetch/>
|
|
29
|
+
|
|
30
|
+
## SDK generation standards
|
|
31
|
+
|
|
32
|
+
- Keep SDK config options familiar where they are useful:
|
|
33
|
+
`useSingleRequestParameter`, `paramNaming`, `modelPropertyNaming`,
|
|
34
|
+
`enumPropertyNaming`, `stringEnums`, `enumUnknownDefaultCase`,
|
|
35
|
+
`sortParamsByRequiredFlag`, and `sortModelPropertiesByRequiredFlag`.
|
|
36
|
+
- Prefer strict, readable output over broad template compatibility. Public
|
|
37
|
+
generators support many options, but that breadth often creates heavy runtime
|
|
38
|
+
helpers and harder-to-review generated code.
|
|
39
|
+
- Treat query serialization as contract behavior. Array query params should stay
|
|
40
|
+
repeated keys unless the spec says otherwise.
|
|
41
|
+
- Keep reserved-word handling in the SDK path. Wire names such as `from`,
|
|
42
|
+
`class`, and `default` must remain valid request keys while local variables
|
|
43
|
+
stay valid TypeScript identifiers.
|
|
44
|
+
- Preserve API schema `additionalProperties` semantics in models and SDK types.
|
|
45
|
+
- Fail before partial output for unsupported polymorphism rather than generating
|
|
46
|
+
missing or unsafe symbols.
|
|
47
|
+
- Keep the fetch runtime small. `openapi-fetch` is a useful benchmark for a
|
|
48
|
+
low-runtime client; Kontract should avoid pulling in a heavy client runtime
|
|
49
|
+
unless a target explicitly asks for it.
|
|
50
|
+
|
|
51
|
+
## Current product decisions
|
|
52
|
+
|
|
53
|
+
- `typescript-nestjs` remains a server-contract generator. Its `sdk: true`
|
|
54
|
+
option adds a companion fetch client for NestJS consumers; it does not turn
|
|
55
|
+
the target into a standalone frontend package.
|
|
56
|
+
- `typescript-fetch`, `typescript-axios`, and `typescript-angular` remain
|
|
57
|
+
standalone SDK targets with their own generated models.
|
|
@@ -1,111 +1,197 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: usage
|
|
3
3
|
title: Kontract Usage
|
|
4
|
-
description: "How to use the SUMR
|
|
5
|
-
tags: [kontract, contracts,
|
|
4
|
+
description: "How to use the Kontract module in the SUMR CLI to review, validate, and generate API and microservice contracts from API and async schemas. Use when adding, changing, reviewing, validating, or generating API contracts, validation schemas, DTOs, SDK models, message subjects, or microservice message contracts."
|
|
5
|
+
tags: [kontract, contracts, api, async, microservices, codegen]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Kontract Usage
|
|
9
9
|
|
|
10
|
-
Kontract
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
of truth so implementations do not drift from the contract.
|
|
10
|
+
Kontract generates the artifacts that keep APIs honest: validation schemas,
|
|
11
|
+
SDKs, docs inputs, runtime evidence, and message contracts from API and async
|
|
12
|
+
schemas.
|
|
14
13
|
|
|
15
14
|
## When to Use
|
|
16
15
|
|
|
17
|
-
- Adding or editing an
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
-
|
|
16
|
+
- Adding or editing an API schema (`*.api.yml`) or async schema (`*.async.yml`).
|
|
17
|
+
- Adding product-capability/API-surface schema modules with local `shared/`
|
|
18
|
+
folders only when concepts are reused.
|
|
19
|
+
- Reviewing newly written or updated `*.api.yml` or `*.async.yml` files against
|
|
20
|
+
Kontract best practices before validation or generation.
|
|
21
|
+
- Refactoring duplicated schema fields into shared `$ref` components or
|
|
22
|
+
`kontract.sets` map fragments.
|
|
21
23
|
- Regenerating contracts after a spec change.
|
|
22
24
|
- Validating specs before committing or in CI.
|
|
23
|
-
- Wiring generated contracts into a
|
|
25
|
+
- Wiring generated contracts into a service or client.
|
|
24
26
|
|
|
25
27
|
## Commands
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
30
|
sumr kontract init # activate Kontract AI guidance for this repo
|
|
29
|
-
sumr kontract
|
|
30
|
-
sumr kontract
|
|
31
|
+
sumr kontract config # show or update guidance profile settings
|
|
32
|
+
sumr kontract validate # validate configured schema sources
|
|
33
|
+
sumr kontract generate # generate configured contract artifacts
|
|
31
34
|
```
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
Activation also keeps local VS Code Material Icon associations in sync for
|
|
37
|
+
Kontract API and async YAML source files.
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
For the full current option list, run the CLI help instead of duplicating flags
|
|
40
|
+
across resources:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
sumr kontract help
|
|
44
|
+
sumr kontract <command> --help
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Common workflows:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Review guidance profile settings.
|
|
51
|
+
sumr kontract config
|
|
52
|
+
|
|
53
|
+
# Generate one selected service/schema.
|
|
54
|
+
sumr kontract generate --source api --target backend --specific recipes
|
|
55
|
+
|
|
56
|
+
# Clean and regenerate selected outputs.
|
|
57
|
+
sumr kontract generate --source api --target backend --clean
|
|
58
|
+
```
|
|
42
59
|
|
|
43
60
|
## The Model
|
|
44
61
|
|
|
62
|
+
Choose the protocol scenario first:
|
|
63
|
+
|
|
64
|
+
- API-only: HTTP roots and API schema components.
|
|
65
|
+
- async-only: messaging roots, channels, messages, and payload schemas.
|
|
66
|
+
- API + async: separate roots and protocol layers, with shared neutral
|
|
67
|
+
components only when meanings match, especially enums and scalar value objects.
|
|
68
|
+
- Keep schemas local to the owning surface first. Promote to capability
|
|
69
|
+
`shared/` only after multiple surfaces reuse the same concept; promote to
|
|
70
|
+
`schema/shared/` only after multiple capabilities need it.
|
|
71
|
+
|
|
45
72
|
```text
|
|
46
73
|
schema/
|
|
47
|
-
recipes.
|
|
48
|
-
recipes.
|
|
74
|
+
recipes.api.yml → contracts/recipes/http/
|
|
75
|
+
recipes.async.yml → contracts/recipes/nats/index.ts
|
|
76
|
+
orders/
|
|
77
|
+
main.api.yml → contracts/orders/http/
|
|
78
|
+
public.api.yml → contracts/orders/http/
|
|
79
|
+
lifecycle.api.yml → contracts/orders/http/
|
|
80
|
+
shared/
|
|
81
|
+
enums.yml → reused by multiple orders surfaces
|
|
82
|
+
components.yml → reused by multiple orders surfaces
|
|
83
|
+
shared/
|
|
84
|
+
errors.yml → reused by multiple capabilities
|
|
49
85
|
```
|
|
50
86
|
|
|
51
|
-
One source
|
|
52
|
-
|
|
53
|
-
the spec and regenerate.
|
|
87
|
+
One schema source → many generated, always-consistent artifacts. Generated files
|
|
88
|
+
are outputs: never hand-edit them — change the spec and regenerate.
|
|
54
89
|
|
|
55
90
|
## Configuration
|
|
56
91
|
|
|
57
92
|
Kontract is configured from the repo's `sumr.yaml` under `kontract.sources`.
|
|
58
|
-
|
|
93
|
+
Optional guidance under `kontract.guidance.profile` selects documentation and AI
|
|
94
|
+
examples only; it does not change validation or generation. Each source points
|
|
95
|
+
at an input directory and one or more targets:
|
|
59
96
|
|
|
60
97
|
```yaml
|
|
61
98
|
kontract:
|
|
99
|
+
guidance:
|
|
100
|
+
profile:
|
|
101
|
+
apiStyle: pragmatic-rest
|
|
102
|
+
asyncStyle: command-event
|
|
103
|
+
schemaLayoutStyle: by-product-capability
|
|
62
104
|
sources:
|
|
63
105
|
- name: api
|
|
64
106
|
input: schema
|
|
65
107
|
targets:
|
|
66
|
-
- name:
|
|
108
|
+
- name: service-contracts
|
|
67
109
|
output: backend/src/shared/models
|
|
68
110
|
generator:
|
|
69
111
|
type: typescript-nestjs
|
|
70
112
|
zod: true
|
|
71
|
-
|
|
113
|
+
swagger: true
|
|
72
114
|
- name: frontend
|
|
73
115
|
output: frontend/src/shared/api
|
|
74
116
|
generator:
|
|
75
117
|
type: typescript-fetch
|
|
76
118
|
```
|
|
77
119
|
|
|
78
|
-
For
|
|
120
|
+
For server-contract targets:
|
|
79
121
|
|
|
80
|
-
- `zod: true` emits
|
|
81
|
-
- `dtos: true` emits
|
|
122
|
+
- `zod: true` emits runtime validation contracts under `http/zod/`.
|
|
123
|
+
- `dtos: true` emits DTO classes under `http/dto/` plus compatibility
|
|
82
124
|
`http/swagger.ts` operation metadata.
|
|
125
|
+
- `swagger: true` emits per-service `http/swagger.ts` operation metadata and one
|
|
126
|
+
shared `shared/http/decorators/api-doc.ts` helper.
|
|
127
|
+
- `sdk: true` emits a fetch-based `http/sdk/` client that reuses the same
|
|
128
|
+
`http/models/` and `http/enums/` generated for the target.
|
|
83
129
|
- `dto: true` is accepted as a compatibility alias for `dtos: true`; prefer
|
|
84
130
|
`dtos` in new config.
|
|
85
131
|
- Framework-neutral model interfaces are emitted under `http/models/`.
|
|
86
132
|
|
|
87
|
-
If a consuming repo is missing
|
|
88
|
-
|
|
89
|
-
|
|
133
|
+
If a consuming repo is missing API metadata output, first confirm the target has
|
|
134
|
+
`swagger: true`, and that the installed `SUMR Kontract module` version contains
|
|
135
|
+
the metadata helper.
|
|
136
|
+
|
|
137
|
+
## Generator Catalog
|
|
138
|
+
|
|
139
|
+
| Category | Generator | Outputs |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| Server contracts | `typescript-nestjs` | Runtime validation contracts, DTOs, models, API metadata, optional SDK. |
|
|
142
|
+
| Messaging | `asyncapi-nats` | Message subjects, message schemas, client/server interfaces. |
|
|
143
|
+
| Client/SDK | `typescript-fetch` / `typescript-axios` / `typescript-angular` | Standalone TypeScript clients with bundled models. |
|
|
144
|
+
| Model | `typescript-models` | Framework-model-only output. |
|
|
145
|
+
|
|
146
|
+
Roadmap and future generator ideas live in `docs/internal/generator-roadmap.md`; exported AI resources describe current supported behavior only.
|
|
90
147
|
|
|
91
148
|
## Core Rules
|
|
92
149
|
|
|
93
150
|
- Validate before you generate: `sumr kontract validate` then `sumr kontract generate`.
|
|
94
151
|
- Treat everything under the generated `contracts/` output as read-only.
|
|
95
152
|
- Keep specs the single source of truth; do not hand-write Zod/DTOs that Kontract owns.
|
|
96
|
-
- After writing or updating any `*.
|
|
97
|
-
|
|
153
|
+
- After writing or updating any `*.api.yml` or `*.async.yml` file, review the
|
|
154
|
+
schema for duplicated concepts before generation.
|
|
155
|
+
- Treat `summary`, `description`, `title`, parameter descriptions, response
|
|
156
|
+
descriptions, and message descriptions as user-facing copy when they appear in
|
|
157
|
+
docs, Swagger, Scalar, generated SDKs, or AI answers. Review changed copy
|
|
158
|
+
against the repo's copywriter standard before generation.
|
|
98
159
|
- Design specs for reuse: shared parameters, scalar constraints, error responses,
|
|
99
160
|
response envelope fragments, pagination metadata, schedule/time-slot shapes,
|
|
100
161
|
and common config objects belong in shared components referenced with `$ref`.
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
-
|
|
162
|
+
- Read `kontract.guidance.profile` before writing examples. Align path,
|
|
163
|
+
channel, component, and folder samples to the selected API, async, and schema
|
|
164
|
+
layout styles.
|
|
165
|
+
- Inspect the actual source protocols before writing examples. For an
|
|
166
|
+
API-only repo, do not invent async schema roots, channel examples, or
|
|
167
|
+
`messages/` folders.
|
|
168
|
+
- For an async-only repo, do not invent API schema roots, `paths/` folders, or
|
|
169
|
+
HTTP component examples.
|
|
170
|
+
- When API schema and async schema both exist, keep protocol-specific layers separate
|
|
171
|
+
and share only schemas with identical meaning, especially enums,
|
|
172
|
+
scalar value objects, IDs, and slugs.
|
|
173
|
+
- Keep simple API schema specs simple: use a focused root file with local
|
|
174
|
+
`components.schemas` first, and split into `paths/` fragments only when size,
|
|
175
|
+
ownership, or reuse pressure justifies it.
|
|
176
|
+
- Start from the contract authoring overview before proposing schema files,
|
|
177
|
+
folder moves, or profile-specific examples.
|
|
178
|
+
- Use compact YAML readability rules for editor navigation: section comments are
|
|
179
|
+
visual landmarks only, naming follows product meaning, and large files should
|
|
180
|
+
split by product capability or API surface before comments become a table of
|
|
181
|
+
contents.
|
|
182
|
+
- See the authoring design-profile overview and axis references before choosing
|
|
183
|
+
or explaining HTTP, async schema, and schema layout examples.
|
|
184
|
+
- See the authoring spec layout and generated output references for the exact
|
|
185
|
+
source and output file shapes.
|
|
186
|
+
- See the authoring scope and splitting reference when a spec or Kontract source
|
|
187
|
+
file crosses the review thresholds, mixes product areas, or needs
|
|
188
|
+
capability/surface structure.
|
|
189
|
+
- See the authoring schema reuse reference before adding repeated fields or
|
|
190
|
+
reviewing a generated diff with many near-identical DTO/model files.
|
|
191
|
+
- See the API schema generation standards reference before changing query params,
|
|
108
192
|
inline schemas, SDK serialization, or strict TypeScript compatibility rules.
|
|
193
|
+
- See the API schema SDK generator research reference before changing SDK runtime
|
|
194
|
+
shape, target defaults, or model imports.
|
|
109
195
|
- Use scoped flags (`--source`, `--target`, `--specific`) before `--clean` in a
|
|
110
196
|
large consumer repo.
|
|
111
197
|
- Warm generation is manifest-driven. Kontract stores per-service manifests in
|
|
@@ -40,17 +40,17 @@ CLI generation does not spawn Biome once per generated file. It writes changed f
|
|
|
40
40
|
|
|
41
41
|
## Bundling strategy
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
refs use Redocly's
|
|
43
|
+
API schema roots with no `$ref` or only internal `#/...` refs skip bundling. Roots with external
|
|
44
|
+
refs use Redocly's API schema core in-process, and safe bundles are cached under:
|
|
45
45
|
|
|
46
46
|
```text
|
|
47
47
|
.sumr-cache/kontract/bundles/<source>/source-cache/bundle-cache/
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
The source-scoped bundle cache is shared across targets in the same source. A
|
|
51
|
-
that generates backend
|
|
52
|
-
|
|
53
|
-
temporary bundling.
|
|
50
|
+
The source-scoped bundle cache is shared across targets in the same source. A
|
|
51
|
+
source that generates backend contracts and frontend models should bundle each
|
|
52
|
+
unchanged external API schema root once, not once per target. Unsafe or ambiguous
|
|
53
|
+
refs still fall back to target-scoped temporary bundling.
|
|
54
54
|
|
|
55
55
|
Ambiguous multiline or remote refs take the safe path and regenerate/bundle rather than trusting a stale cache.
|
|
56
56
|
|
|
@@ -83,7 +83,7 @@ bun run tools perf generate --count=20 --concurrency=8 --mode=both --refs=extern
|
|
|
83
83
|
|
|
84
84
|
Benchmark output stays under `.tmp/` and writes both `results.json` and `README.md` with phase timings, counters, and subprocess resource usage. Use `--refs=internal` to confirm bundling is skipped, and `--refs=external --targets=both` to confirm the shared bundle cache keeps cold-run in-process bundling at roughly one per schema root instead of one per target.
|
|
85
85
|
|
|
86
|
-
Local signal after in-process
|
|
86
|
+
Local signal after in-process API schema bundling:
|
|
87
87
|
|
|
88
88
|
- `--count=1000 --refs=external --targets=both --concurrency=8`: cold `8.72s`, warm `0.83s`.
|
|
89
89
|
- Warm manifests skipped all `2000` source/target work items and ran zero formatter/bundler subprocesses.
|
|
@@ -3,7 +3,7 @@ kind: CliModule
|
|
|
3
3
|
metadata:
|
|
4
4
|
name: kontract
|
|
5
5
|
package: "@sumrco/cli"
|
|
6
|
-
description: Generate and validate API contract
|
|
6
|
+
description: Generate and validate API contract artifacts
|
|
7
7
|
owners:
|
|
8
8
|
- team: "@sumr-org/kontract-team"
|
|
9
9
|
tags:
|
|
@@ -20,8 +20,11 @@ spec:
|
|
|
20
20
|
- name: init
|
|
21
21
|
summary: Activate Kontract AI guidance for this workspace
|
|
22
22
|
visibility: public
|
|
23
|
+
- name: config
|
|
24
|
+
summary: Show or update Kontract guidance profile settings
|
|
25
|
+
visibility: public
|
|
23
26
|
- name: generate
|
|
24
|
-
summary: Generate
|
|
27
|
+
summary: Generate configured contract artifacts from API specs
|
|
25
28
|
visibility: public
|
|
26
29
|
- name: validate
|
|
27
30
|
summary: Validate API specifications
|
|
@@ -29,6 +29,9 @@ spec:
|
|
|
29
29
|
- name: next
|
|
30
30
|
summary: Show the next mission action
|
|
31
31
|
visibility: public
|
|
32
|
+
- name: sync
|
|
33
|
+
summary: Fetch issue context and board status from the tracker
|
|
34
|
+
visibility: public
|
|
32
35
|
- name: list
|
|
33
36
|
summary: List missions
|
|
34
37
|
visibility: public
|
|
@@ -44,6 +47,9 @@ spec:
|
|
|
44
47
|
- name: report
|
|
45
48
|
summary: Create a mission report
|
|
46
49
|
visibility: public
|
|
50
|
+
- name: reopen
|
|
51
|
+
summary: Record a QA failure and drive a corrective cycle
|
|
52
|
+
visibility: public
|
|
47
53
|
- name: block
|
|
48
54
|
summary: Mark a mission as blocked
|
|
49
55
|
visibility: public
|