@sumrco/cli 0.1.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.
- package/README.md +36 -0
- package/ai/modules/kontract/resources/configuration.rf.md +123 -0
- package/ai/modules/kontract/resources/generated-output.rf.md +179 -0
- package/ai/modules/kontract/resources/openapi-generator-lessons.rf.md +61 -0
- package/ai/modules/kontract/resources/overview.md +115 -0
- package/ai/modules/kontract/resources/performance.rf.md +90 -0
- package/ai/modules/kontract/resources/schema-reuse.rf.md +233 -0
- package/ai/modules/kontract/resources/scope-and-splitting.rf.md +147 -0
- package/ai/modules/kontract/resources/spec-layout.rf.md +69 -0
- package/ai/modules/kontract/resources/team-members/contract-author.tm.md +52 -0
- package/ai/modules/kontract/resources/workflows/contract-change.wf.md +60 -0
- package/ai/modules/kontract/sumr.module.yaml +42 -0
- package/ai/modules/mission/resources/flow-actions.rf.md +40 -0
- package/ai/modules/mission/resources/flow-config.rf.md +39 -0
- package/ai/modules/mission/resources/flow-safety-boundaries.rf.md +23 -0
- package/ai/modules/mission/resources/overview.md +69 -0
- package/ai/modules/mission/resources/stage-closeout.rf.md +21 -0
- package/ai/modules/mission/resources/stage-delivery.rf.md +36 -0
- package/ai/modules/mission/resources/stage-intake.rf.md +39 -0
- package/ai/modules/mission/resources/stage-planning.rf.md +21 -0
- package/ai/modules/mission/resources/stage-pull-request.rf.md +50 -0
- package/ai/modules/mission/resources/stage-quality.rf.md +22 -0
- package/ai/modules/mission/resources/team-members/delivery-lead.tm.md +39 -0
- package/ai/modules/mission/resources/team-members/implementer.tm.md +25 -0
- package/ai/modules/mission/resources/team-members/planner.tm.md +102 -0
- package/ai/modules/mission/resources/team-members/pr-writer.tm.md +57 -0
- package/ai/modules/mission/resources/team-members/product-owner.tm.md +37 -0
- package/ai/modules/mission/resources/team-members/quality-lead.tm.md +34 -0
- package/ai/modules/mission/resources/workflows/daily-triage.wf.md +117 -0
- package/ai/modules/mission/resources/workflows/full-delivery.wf.md +18 -0
- package/ai/modules/mission/resources/workflows/mission-cycle.wf.md +30 -0
- package/ai/modules/mission/resources/workflows/planning-only.wf.md +68 -0
- package/ai/modules/mission/resources/workflows/pr-assist.wf.md +21 -0
- package/ai/modules/mission/resources/workflows/standard-delivery.wf.md +18 -0
- package/ai/modules/mission/sumr.module.yaml +78 -0
- package/ai/modules/playbook/resources/authoring/content-structure.rf.md +148 -0
- package/ai/modules/playbook/resources/authoring/cross-referencing.rf.md +57 -0
- package/ai/modules/playbook/resources/authoring/descriptions.rf.md +71 -0
- package/ai/modules/playbook/resources/authoring/extraction.rf.md +81 -0
- package/ai/modules/playbook/resources/authoring/flows.rf.md +55 -0
- package/ai/modules/playbook/resources/authoring/folder-structure.rf.md +148 -0
- package/ai/modules/playbook/resources/authoring/frontmatter.rf.md +251 -0
- package/ai/modules/playbook/resources/authoring/markdown.rf.md +108 -0
- package/ai/modules/playbook/resources/authoring/overview.md +213 -0
- package/ai/modules/playbook/resources/team-members/playbook-technical-writer.tm.md +31 -0
- package/ai/modules/playbook/sumr.module.yaml +47 -0
- package/ai/registry.json +18 -0
- package/bin/_sumr +4 -0
- package/bin/sumr +7 -0
- package/index.js +410 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<p align="center">
|
|
3
|
+
<img src="https://dev.sumr.co/sumr-docs.svg" alt="SUMR" width="250" />
|
|
4
|
+
</p>
|
|
5
|
+
</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>The official SUMR CLI for project setup, account access, and AI workflow tooling.</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@sumrco/cli"><img src="https://img.shields.io/npm/v/@sumrco/cli?color=693776&label=npm" alt="npm version" /></a>
|
|
13
|
+
<img src="https://img.shields.io/badge/runtime-Bun-4d4d4d" alt="Bun runtime" />
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="#-install">Install</a>
|
|
18
|
+
·
|
|
19
|
+
<a href="#-quick-start">Quick start</a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🚀 Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun add -g @sumrco/cli
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ⚡ Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
sumr --help
|
|
34
|
+
sumr login
|
|
35
|
+
sumr init
|
|
36
|
+
```
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: reference
|
|
3
|
+
name: configuration
|
|
4
|
+
title: Kontract Configuration
|
|
5
|
+
description: "How `sumr.yaml` configures Kontract sources, targets, generator types, and NestJS output options."
|
|
6
|
+
label: Configuration
|
|
7
|
+
when: Adding a Kontract target, debugging missing generated files, or comparing generated output across repos
|
|
8
|
+
order: 15
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Kontract Configuration
|
|
12
|
+
|
|
13
|
+
Kontract reads repo-local configuration from `sumr.yaml`. A source points at a
|
|
14
|
+
schema directory; each target chooses an output directory and generator.
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
kontract:
|
|
18
|
+
sources:
|
|
19
|
+
- name: api
|
|
20
|
+
input: schema
|
|
21
|
+
targets:
|
|
22
|
+
- name: backend
|
|
23
|
+
output: backend/src/shared/models
|
|
24
|
+
generator:
|
|
25
|
+
type: typescript-nestjs
|
|
26
|
+
zod: true
|
|
27
|
+
dtos: true
|
|
28
|
+
- name: frontend
|
|
29
|
+
output: frontend/src/shared/api
|
|
30
|
+
generator:
|
|
31
|
+
type: typescript-fetch
|
|
32
|
+
modelPropertyNaming: original
|
|
33
|
+
paramNaming: original
|
|
34
|
+
stringEnums: true
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Sources
|
|
38
|
+
|
|
39
|
+
| Field | Meaning |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `name` | Stable source name used by `--source`. |
|
|
42
|
+
| `input` | Directory scanned recursively for `*.openapi.yml`, `*.openapi.yaml`, `*.asyncapi.yml`, and `*.asyncapi.yaml`. |
|
|
43
|
+
| `targets` | One or more generated outputs. |
|
|
44
|
+
|
|
45
|
+
Use `--source <name>` to scope validation or generation to one source.
|
|
46
|
+
|
|
47
|
+
## Targets
|
|
48
|
+
|
|
49
|
+
| Field | Meaning |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `name` | Stable target name used by `--target`. |
|
|
52
|
+
| `output` | Root directory for generated output. Treat this folder as generated/read-only. |
|
|
53
|
+
| `generator.type` | Generator family. |
|
|
54
|
+
|
|
55
|
+
Use `--target <name>` to scope generation to one target.
|
|
56
|
+
|
|
57
|
+
## Generator types
|
|
58
|
+
|
|
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. |
|
|
67
|
+
|
|
68
|
+
## `typescript-nestjs` options
|
|
69
|
+
|
|
70
|
+
| Option | Output |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `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. |
|
|
74
|
+
|
|
75
|
+
`dtos` is the canonical spelling. `dto: true` is accepted as a compatibility
|
|
76
|
+
alias and is normalized internally to `dtos: true`.
|
|
77
|
+
|
|
78
|
+
Framework-neutral interfaces under `http/models/` and enums under `http/enums/`
|
|
79
|
+
are emitted for OpenAPI object schemas regardless of the Zod/DTO flavor.
|
|
80
|
+
|
|
81
|
+
## Common debugging cases
|
|
82
|
+
|
|
83
|
+
### `http/dto/` or `http/swagger.ts` is missing
|
|
84
|
+
|
|
85
|
+
Check both:
|
|
86
|
+
|
|
87
|
+
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.
|
|
90
|
+
|
|
91
|
+
If two configs generate identical output and both miss `dto/` + `swagger.ts`,
|
|
92
|
+
the likely issue is the generator version being executed, not the consumer
|
|
93
|
+
repo's config.
|
|
94
|
+
|
|
95
|
+
### `http/zod/` is missing
|
|
96
|
+
|
|
97
|
+
Check that the NestJS target has `zod: true` or that Zod generation has not been
|
|
98
|
+
explicitly disabled.
|
|
99
|
+
|
|
100
|
+
### Generated files are stale
|
|
101
|
+
|
|
102
|
+
Run a scoped clean generation:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sumr kontract generate --source api --target backend --clean
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Prefer scoping `--clean` in large repos so only the intended generated output
|
|
109
|
+
and selected Kontract cache are removed before regeneration.
|
|
110
|
+
|
|
111
|
+
### Warm generation is still slow
|
|
112
|
+
|
|
113
|
+
Kontract stores incremental manifests under `.sumr-cache/kontract`. An unchanged
|
|
114
|
+
warm run should skip unchanged services before parse/emit and should not run a
|
|
115
|
+
formatter subprocess.
|
|
116
|
+
|
|
117
|
+
If warm runs regenerate everything, check for:
|
|
118
|
+
|
|
119
|
+
1. generated files being manually edited or deleted;
|
|
120
|
+
2. changing generator config in `sumr.yaml`;
|
|
121
|
+
3. a changed installed `SUMR Kontract module` version;
|
|
122
|
+
4. ambiguous or remote `$ref` usage that forces the safe path;
|
|
123
|
+
5. `--clean`, which intentionally clears selected output and cache state.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: reference
|
|
3
|
+
name: generated-output
|
|
4
|
+
title: Generated Output Contract
|
|
5
|
+
description: "The exact shape of TypeScript files Kontract generates and how to consume them in NestJS."
|
|
6
|
+
label: Generated Output
|
|
7
|
+
when: Importing generated contracts, reviewing a generation diff, or wiring NATS/HTTP clients into a service
|
|
8
|
+
order: 20
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Generated Output Contract
|
|
12
|
+
|
|
13
|
+
Generated files are deterministic outputs. Import them; never edit them.
|
|
14
|
+
Every generated TypeScript file starts with an `<auto-generated>` comment that
|
|
15
|
+
warns users not to edit the file directly.
|
|
16
|
+
|
|
17
|
+
## HTTP output — one folder per OpenAPI service
|
|
18
|
+
|
|
19
|
+
For an OpenAPI service such as `recipes.openapi.yml`, the NestJS target
|
|
20
|
+
emits a service folder:
|
|
21
|
+
|
|
22
|
+
```text
|
|
23
|
+
contracts/recipes/
|
|
24
|
+
index.ts
|
|
25
|
+
http/
|
|
26
|
+
index.ts
|
|
27
|
+
enums/
|
|
28
|
+
models/
|
|
29
|
+
zod/ # when zod generation is enabled
|
|
30
|
+
dto/ # when dtos generation is enabled
|
|
31
|
+
swagger.ts # when dtos generation is enabled
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Shared `$ref` components keep the source spec DRY and semantically consistent.
|
|
35
|
+
Today, supported `allOf` object composition is flattened in the generated
|
|
36
|
+
service output, so some concrete response DTOs may still repeat envelope fields.
|
|
37
|
+
Do not fix that by hand-editing generated files. If generated code repeats too
|
|
38
|
+
much, first improve the spec with shared components; then consider a Kontract
|
|
39
|
+
generator improvement such as preserved composition or shared external
|
|
40
|
+
component output.
|
|
41
|
+
|
|
42
|
+
`http/index.ts` intentionally uses namespace exports for folders that can share
|
|
43
|
+
symbol names:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
export * as Dtos from './dto';
|
|
47
|
+
export * as Models from './models';
|
|
48
|
+
export * as ZodContracts from './zod';
|
|
49
|
+
export * from './enums';
|
|
50
|
+
export * from './swagger';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Do not flatten-import everything blindly when DTO/model/Zod symbols collide.
|
|
54
|
+
Use the namespace exports or import from the leaf folder.
|
|
55
|
+
|
|
56
|
+
## Zod contract — one file per OpenAPI `components/schemas` entry
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// contracts/recipes/http/zod/recipe.contract.ts
|
|
60
|
+
import { z } from 'zod';
|
|
61
|
+
import { createZodDto } from 'nestjs-zod';
|
|
62
|
+
|
|
63
|
+
export const RecipeSchema = z.object({
|
|
64
|
+
id: z.string().uuid(),
|
|
65
|
+
name: z.string().min(1).max(255),
|
|
66
|
+
status: z.enum(['draft', 'published', 'archived']),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export class RecipeDto extends createZodDto(RecipeSchema) {}
|
|
70
|
+
export type Recipe = z.infer<typeof RecipeSchema>;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Every generated Zod contract yields `${Name}Schema` + `${Name}Dto` +
|
|
74
|
+
`type ${Name}`.
|
|
75
|
+
|
|
76
|
+
## Model interface — one file per object schema
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// contracts/recipes/http/models/recipe.ts
|
|
80
|
+
export interface Recipe {
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
status: RecipeStatus;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Model interfaces are framework-neutral and are safe for backend and frontend
|
|
88
|
+
type-only imports.
|
|
89
|
+
|
|
90
|
+
Map-shaped schemas follow OpenAPI `additionalProperties` semantics:
|
|
91
|
+
|
|
92
|
+
- map-only schemas generate index signatures such as `[key: string]: string`;
|
|
93
|
+
- named properties with `additionalProperties: true` preserve the named fields
|
|
94
|
+
and use `[key: string]: unknown`;
|
|
95
|
+
- named properties with typed `additionalProperties` preserve named fields and
|
|
96
|
+
widen the index signature with known property value types, matching the
|
|
97
|
+
practical TypeScript approach used by current OpenAPI TypeScript generators.
|
|
98
|
+
|
|
99
|
+
## Class-validator DTO — when `dtos: true`
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// contracts/recipes/http/dto/recipe.dto.ts
|
|
103
|
+
import { ApiProperty } from '@nestjs/swagger';
|
|
104
|
+
import { Expose } from 'class-transformer';
|
|
105
|
+
import { IsString, IsUUID } from 'class-validator';
|
|
106
|
+
|
|
107
|
+
export class RecipeDto {
|
|
108
|
+
@ApiProperty({ format: 'uuid' })
|
|
109
|
+
@IsUUID()
|
|
110
|
+
@Expose()
|
|
111
|
+
id!: string;
|
|
112
|
+
|
|
113
|
+
@ApiProperty()
|
|
114
|
+
@IsString()
|
|
115
|
+
@Expose()
|
|
116
|
+
name!: string;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
DTO files are generated for NestJS controllers and Swagger decorators. Generated
|
|
121
|
+
properties include `@Expose()` so they remain compatible with class-transformer
|
|
122
|
+
serializers that use `excludeExtraneousValues: true`. Do not hand-write parallel
|
|
123
|
+
DTOs for schemas Kontract owns.
|
|
124
|
+
|
|
125
|
+
## Swagger operation metadata — when `dtos: true`
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// contracts/recipes/http/swagger.ts
|
|
129
|
+
import type { RecipeDto } from './dto/recipe.dto';
|
|
130
|
+
|
|
131
|
+
export const SWG_LIST_RECIPES = {
|
|
132
|
+
method: 'GET',
|
|
133
|
+
path: '/recipes',
|
|
134
|
+
operationId: 'listRecipes',
|
|
135
|
+
responseDto: RecipeDto,
|
|
136
|
+
} as const;
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Controllers can consume `SWG_*` metadata to keep operation IDs, paths, params,
|
|
140
|
+
body DTOs, and response DTOs aligned with OpenAPI.
|
|
141
|
+
|
|
142
|
+
## NATS contract — one `nats/index.ts` per AsyncAPI service
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// contracts/recipes/nats/index.ts
|
|
146
|
+
export namespace Recipes {
|
|
147
|
+
export const CreateRecipeMessage = z.object({ name: z.string(), slug: z.string() });
|
|
148
|
+
export type CreateRecipeMessage = z.infer<typeof CreateRecipeMessage>;
|
|
149
|
+
export type CreateRecipeMessageInput = z.input<typeof CreateRecipeMessage>;
|
|
150
|
+
|
|
151
|
+
export const SUBJECTS = {
|
|
152
|
+
CREATE_RECIPE: 'example.recipes.command.createRecipe',
|
|
153
|
+
} as const;
|
|
154
|
+
|
|
155
|
+
export interface ICommandServer { /* ... */ }
|
|
156
|
+
export class CommandClient { /* validates with .parse() then proxy.send() */ }
|
|
157
|
+
export class QueryClient { /* ... */ }
|
|
158
|
+
export class EventClient { /* ... */ }
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- Namespace name comes from AsyncAPI `info.title`.
|
|
163
|
+
- Every message yields a Zod const + `z.infer<>` type + `z.input<>` input type.
|
|
164
|
+
- Subjects live in a single `SUBJECTS` const used directly by NestJS NATS.
|
|
165
|
+
- Clients validate input with `.parse()` before sending.
|
|
166
|
+
|
|
167
|
+
## Consuming in NestJS
|
|
168
|
+
|
|
169
|
+
- Use `http/zod` `${Name}Dto` classes when you want `nestjs-zod` request/response
|
|
170
|
+
validation.
|
|
171
|
+
- Use `http/dto` classes and `http/swagger.ts` when a controller follows the
|
|
172
|
+
class-validator + Swagger metadata pattern.
|
|
173
|
+
- Use `http/models` interfaces for type-only internal code.
|
|
174
|
+
- Use the generated `*Client` classes and `SUBJECTS` for NATS — do not
|
|
175
|
+
hand-write subjects or message shapes.
|
|
176
|
+
- Each generated directory has a barrel `index.ts` for local aggregation only.
|
|
177
|
+
- Regenerate (`sumr kontract generate`) after any spec change; unchanged
|
|
178
|
+
work items are skipped with `.sumr-cache/kontract` manifests when source,
|
|
179
|
+
config, generator, and output hashes still match.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: reference
|
|
3
|
+
name: openapi-generator-lessons
|
|
4
|
+
title: OpenAPI Generator Bug Lessons
|
|
5
|
+
description: "Hardening lessons Kontract applies from public OpenAPI Generator NestJS/TypeScript bug reports. Use when reviewing generated output risks, query parameters, inline schemas, and strict TypeScript compatibility."
|
|
6
|
+
label: OpenAPI Generator Lessons
|
|
7
|
+
when: Reviewing Kontract specs or generator changes for known OpenAPI/NestJS codegen failure modes
|
|
8
|
+
order: 45
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# OpenAPI Generator Bug Lessons
|
|
12
|
+
|
|
13
|
+
Kontract learns from public OpenAPI/NestJS generator bugs without inheriting their
|
|
14
|
+
architecture. These lessons are guardrails for spec authors, reviewers, and AI agents
|
|
15
|
+
working on generated contracts.
|
|
16
|
+
|
|
17
|
+
## Core lessons
|
|
18
|
+
|
|
19
|
+
- **Preserve query parameter semantics.** Optional query params stay optional, array query
|
|
20
|
+
params serialize as repeated keys, and enum query params use generated enum symbols instead
|
|
21
|
+
of raw literal imports.
|
|
22
|
+
- **Do not let wire names become unsafe local variables.** Parameter names such as `from`,
|
|
23
|
+
`class`, and `default` must remain valid wire keys while generated local identifiers are
|
|
24
|
+
safe TypeScript names.
|
|
25
|
+
- **Prefer component `$ref` schemas over anonymous inline operation models.** Kontract rejects
|
|
26
|
+
inline request/response schemas because anonymous model naming commonly causes duplicate
|
|
27
|
+
`InlineObject` outputs and unstable imports.
|
|
28
|
+
- **Generate maps deliberately.** `additionalProperties` map schemas must preserve named
|
|
29
|
+
properties and typed catch-all/index-signature values consistently across Zod, DTOs, models,
|
|
30
|
+
and SDK output. Unsupported `oneOf`, `anyOf`, `not`, and discriminators should produce clear
|
|
31
|
+
errors instead of partially generated code with missing symbols such as `AnyType` or
|
|
32
|
+
`InnerEnum`.
|
|
33
|
+
- **Keep NestJS ownership boundaries clean.** Kontract emits contracts, DTOs, models, swagger
|
|
34
|
+
metadata, and SDK clients. Application modules, controllers, providers, and DI wiring stay in
|
|
35
|
+
the consuming NestJS app.
|
|
36
|
+
- **Compile generated code under strict TypeScript assumptions.** Generated output should avoid
|
|
37
|
+
dangling imports, deprecated Nest HTTP client imports, stale `basePath` globals, `Map` headers
|
|
38
|
+
where records are expected, and framework symbols that were never emitted.
|
|
39
|
+
- **Stay Bun-native.** Kontract does not depend on Java, Docker images, downloaded generator
|
|
40
|
+
binaries, or template folders at generation time.
|
|
41
|
+
|
|
42
|
+
## Spec authoring rules
|
|
43
|
+
|
|
44
|
+
- Put reusable request/response bodies, parameters, enums, and object fragments under
|
|
45
|
+
`components` and reference them with `$ref`.
|
|
46
|
+
- Encode validation constraints in the OpenAPI schema (`minLength`, `maxLength`, `minimum`,
|
|
47
|
+
`maximum`, `pattern`, `format`) so DTO/Zod output can enforce them.
|
|
48
|
+
- Use `additionalProperties` when the payload is intentionally map-shaped. Prefer typed map values
|
|
49
|
+
over `additionalProperties: true`; Kontract preserves named fields and emits a safe unknown
|
|
50
|
+
catch-all when the spec intentionally allows arbitrary values.
|
|
51
|
+
- For repeated query values, use `type: array` with scalar `items`; generated SDKs must not
|
|
52
|
+
collapse values into comma-separated strings.
|
|
53
|
+
|
|
54
|
+
## Reviewer checklist
|
|
55
|
+
|
|
56
|
+
- Generated files include the auto-generated header and are not hand-edited.
|
|
57
|
+
- Query DTOs and SDK request types preserve optionality from the spec.
|
|
58
|
+
- No generated file contains `any`, `AnyType`, `InlineObject`, `InnerEnum`, `queryParameters`,
|
|
59
|
+
deprecated `HttpService`, stale `basePath`, or unsafe `apiKeys` access.
|
|
60
|
+
- Operation schemas reference named components instead of inline request/response objects.
|
|
61
|
+
- Unsupported schema features fail before any consumer repo is left with partial broken output.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: usage
|
|
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."
|
|
5
|
+
tags: [kontract, contracts, openapi, asyncapi, nestjs, codegen]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Kontract Usage
|
|
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.
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- 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.
|
|
20
|
+
- Refactoring duplicated schema fields into shared `$ref` components.
|
|
21
|
+
- Regenerating contracts after a spec change.
|
|
22
|
+
- Validating specs before committing or in CI.
|
|
23
|
+
- Wiring generated contracts into a NestJS microservice.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
sumr kontract init # activate Kontract AI guidance for this repo
|
|
29
|
+
sumr kontract validate # validate configured OpenAPI/AsyncAPI sources
|
|
30
|
+
sumr kontract generate # generate TypeScript contracts and SDKs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Useful flags:
|
|
34
|
+
|
|
35
|
+
- `--source <name>` — limit to one configured source
|
|
36
|
+
- `--target <name>` — limit to one configured target
|
|
37
|
+
- `-c, --concurrency <n>` — max parallel workers
|
|
38
|
+
- `--verbose` / `--quiet` — log level (`CI=true` implies quiet)
|
|
39
|
+
- `generate` also accepts `-s, --specific <name>` to generate one service spec
|
|
40
|
+
- `generate` also accepts `--clean` to remove selected generated outputs and the
|
|
41
|
+
selected Kontract bundle cache before regenerating
|
|
42
|
+
|
|
43
|
+
## The Model
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
schema/
|
|
47
|
+
recipes.openapi.yml → contracts/recipes/http/
|
|
48
|
+
recipes.asyncapi.yml → contracts/recipes/nats/index.ts
|
|
49
|
+
```
|
|
50
|
+
|
|
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.
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
Kontract is configured from the repo's `sumr.yaml` under `kontract.sources`.
|
|
58
|
+
Each source points at an input directory and one or more targets:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
kontract:
|
|
62
|
+
sources:
|
|
63
|
+
- name: api
|
|
64
|
+
input: schema
|
|
65
|
+
targets:
|
|
66
|
+
- name: backend
|
|
67
|
+
output: backend/src/shared/models
|
|
68
|
+
generator:
|
|
69
|
+
type: typescript-nestjs
|
|
70
|
+
zod: true
|
|
71
|
+
dtos: true
|
|
72
|
+
- name: frontend
|
|
73
|
+
output: frontend/src/shared/api
|
|
74
|
+
generator:
|
|
75
|
+
type: typescript-fetch
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For `typescript-nestjs`:
|
|
79
|
+
|
|
80
|
+
- `zod: true` emits NestJS-Zod contracts under `http/zod/`.
|
|
81
|
+
- `dtos: true` emits class-validator DTOs under `http/dto/` plus
|
|
82
|
+
`http/swagger.ts` operation metadata.
|
|
83
|
+
- `dto: true` is accepted as a compatibility alias for `dtos: true`; prefer
|
|
84
|
+
`dtos` in new config.
|
|
85
|
+
- Framework-neutral model interfaces are emitted under `http/models/`.
|
|
86
|
+
|
|
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.
|
|
90
|
+
|
|
91
|
+
## Core Rules
|
|
92
|
+
|
|
93
|
+
- Validate before you generate: `sumr kontract validate` then `sumr kontract generate`.
|
|
94
|
+
- Treat everything under the generated `contracts/` output as read-only.
|
|
95
|
+
- 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.
|
|
98
|
+
- Design specs for reuse: shared parameters, scalar constraints, error responses,
|
|
99
|
+
response envelope fragments, pagination metadata, schedule/time-slot shapes,
|
|
100
|
+
and common config objects belong in shared components referenced with `$ref`.
|
|
101
|
+
- See the spec layout and generated output references for the exact file shapes.
|
|
102
|
+
- See the scope and splitting reference when a spec or Kontract source file
|
|
103
|
+
crosses the review thresholds, mixes domains, or needs domain/subdomain
|
|
104
|
+
structure.
|
|
105
|
+
- See the schema reuse reference before adding repeated fields or reviewing a
|
|
106
|
+
generated diff with many near-identical DTO/model files.
|
|
107
|
+
- See the OpenAPI generator lessons reference before changing query params,
|
|
108
|
+
inline schemas, SDK serialization, or strict TypeScript compatibility rules.
|
|
109
|
+
- Use scoped flags (`--source`, `--target`, `--specific`) before `--clean` in a
|
|
110
|
+
large consumer repo.
|
|
111
|
+
- Warm generation is manifest-driven. Kontract stores per-service manifests in
|
|
112
|
+
`.sumr-cache/kontract`, skips only when source/config/generator/output hashes
|
|
113
|
+
match, and regenerates if generated files were manually changed or deleted.
|
|
114
|
+
- For large repos, use normal generation first; use `--clean` only when you need
|
|
115
|
+
to intentionally clear selected generated outputs and Kontract cache state.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
category: reference
|
|
3
|
+
name: performance
|
|
4
|
+
title: Kontract Performance and Incremental Generation
|
|
5
|
+
description: "How Kontract uses manifests, bundle cache, workers, and batched formatting to keep large schema generations safe and fast."
|
|
6
|
+
label: Performance
|
|
7
|
+
when: Debugging slow `sumr kontract generate`, deciding whether to use `--clean`, or estimating large schema runs
|
|
8
|
+
order: 30
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Kontract Performance and Incremental Generation
|
|
12
|
+
|
|
13
|
+
Kontract is optimized for safe warm runs in large repos. It prefers correctness over stale output: if a cache state is ambiguous, it regenerates.
|
|
14
|
+
|
|
15
|
+
## Incremental manifests
|
|
16
|
+
|
|
17
|
+
For each configured source/target/service/channel, Kontract writes a manifest under the repo-local cache:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
.sumr-cache/kontract/bundles/<source>/<target>/manifests/<channel>/<service>/manifest.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The manifest records the generator config hash, generator implementation hash, source dependency graph hash, output tree hash, generated files, Bun version, and package version.
|
|
24
|
+
|
|
25
|
+
Warm generation skips a service before parsing/emitting only when all hashes still match. Manual generated-file edits or deletions invalidate the output tree hash and force regeneration.
|
|
26
|
+
|
|
27
|
+
## Clean generation
|
|
28
|
+
|
|
29
|
+
Use scoped clean when the cache or generated output may be stale:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
sumr kontract generate --source api --target backend --clean
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`--clean` removes the selected generated output roots and selected Kontract cache/manifests. It does not remove `.sumr-cache/activations.json`.
|
|
36
|
+
|
|
37
|
+
## Formatting strategy
|
|
38
|
+
|
|
39
|
+
CLI generation does not spawn Biome once per generated file. It writes changed files first, then runs one Biome directory format per changed output root. Unchanged warm runs should have zero formatter subprocesses.
|
|
40
|
+
|
|
41
|
+
## Bundling strategy
|
|
42
|
+
|
|
43
|
+
OpenAPI roots with no `$ref` or only internal `#/...` refs skip bundling. Roots with external
|
|
44
|
+
refs use Redocly's OpenAPI core in-process, and safe bundles are cached under:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
.sumr-cache/kontract/bundles/<source>/source-cache/bundle-cache/
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The source-scoped bundle cache is shared across targets in the same source. A BCHQ-style source
|
|
51
|
+
that generates backend NestJS contracts and frontend models should bundle each unchanged external
|
|
52
|
+
OpenAPI root once, not once per target. Unsafe or ambiguous refs still fall back to target-scoped
|
|
53
|
+
temporary bundling.
|
|
54
|
+
|
|
55
|
+
Ambiguous multiline or remote refs take the safe path and regenerate/bundle rather than trusting a stale cache.
|
|
56
|
+
|
|
57
|
+
Emergency fallback:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
KONTRACT_DISABLE_REDOCLY_CORE=1 sumr kontract generate
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Worker strategy
|
|
64
|
+
|
|
65
|
+
When concurrency is greater than one, Kontract uses a Bun worker pool for parse/extract/emit/write tasks. The main process still owns discovery, manifest validation, final barrels, final formatting, and summaries.
|
|
66
|
+
|
|
67
|
+
Emergency/debug fallbacks:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
KONTRACT_DISABLE_WORKERS=1 sumr kontract generate
|
|
71
|
+
KONTRACT_FORCE_MAIN_THREAD=1 sumr kontract generate
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Benchmarking
|
|
75
|
+
|
|
76
|
+
Use the local synthetic benchmark before changing generation orchestration, formatting, file writing, bundling, or cache behavior:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bun run tools perf generate --count=50 --concurrency=8 --mode=both
|
|
80
|
+
bun run tools perf generate --count=100 --concurrency=8 --mode=both --root=.tmp/kontract-performance-100
|
|
81
|
+
bun run tools perf generate --count=20 --concurrency=8 --mode=both --refs=external --targets=both
|
|
82
|
+
```
|
|
83
|
+
|
|
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
|
+
|
|
86
|
+
Local signal after in-process OpenAPI bundling:
|
|
87
|
+
|
|
88
|
+
- `--count=1000 --refs=external --targets=both --concurrency=8`: cold `8.72s`, warm `0.83s`.
|
|
89
|
+
- Warm manifests skipped all `2000` source/target work items and ran zero formatter/bundler subprocesses.
|
|
90
|
+
- Cold formatting stayed at 2 Biome subprocesses for 2 changed output roots.
|