@workos/oagen 0.0.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/.claude-plugin/plugin.json +12 -0
- package/LICENSE.txt +21 -0
- package/README.md +197 -0
- package/dist/chunk-CIX5NOBF.js +263 -0
- package/dist/chunk-IJ5E5AE7.js +1040 -0
- package/dist/chunk-P5XUDUGY.js +1748 -0
- package/dist/cli/index.js +5603 -0
- package/dist/compat/index.d.ts +195 -0
- package/dist/compat/index.js +4453 -0
- package/dist/index.d.ts +300 -0
- package/dist/index.js +1733 -0
- package/dist/scripts/smoke/baseline.js +1751 -0
- package/dist/scripts/smoke/sdk-test.js +93 -0
- package/dist/smoke.js +1963 -0
- package/dist/types-B5t9O9Wm.d.ts +367 -0
- package/dist/verify/index.d.ts +76 -0
- package/dist/verify/index.js +336 -0
- package/docs/advanced/index.md +11 -0
- package/docs/advanced/oagen-ignore.md +144 -0
- package/docs/agents/architecture.md +53 -0
- package/docs/agents/emitters.md +69 -0
- package/docs/agents/testing.md +60 -0
- package/docs/architecture/dependency-layers.md +75 -0
- package/docs/architecture/emitter-contract.md +160 -0
- package/docs/architecture/extractor-contract.md +227 -0
- package/docs/architecture/ir-types.md +275 -0
- package/docs/architecture/non-additive-changes.md +76 -0
- package/docs/architecture/pipeline.md +110 -0
- package/docs/architecture/workflows.md +215 -0
- package/docs/cli.md +156 -0
- package/docs/contributor/index.md +10 -0
- package/docs/contributor/public-api.md +59 -0
- package/docs/contributor/versioning.md +48 -0
- package/docs/core/index.md +12 -0
- package/docs/core/minimal-emitter.md +134 -0
- package/docs/core/quickstart.md +142 -0
- package/docs/diagrams/generate-sdk-workflow.md +50 -0
- package/docs/index.md +40 -0
- package/examples/reference-emitter/README.md +41 -0
- package/examples/reference-emitter/oagen.config.ts +7 -0
- package/examples/reference-emitter/spec/github-subset.yml +400 -0
- package/examples/reference-emitter/src/emitter.ts +52 -0
- package/examples/reference-emitter/src/generators/client.ts +37 -0
- package/examples/reference-emitter/src/generators/config.ts +19 -0
- package/examples/reference-emitter/src/generators/enums.ts +16 -0
- package/examples/reference-emitter/src/generators/errors.ts +39 -0
- package/examples/reference-emitter/src/generators/models.ts +29 -0
- package/examples/reference-emitter/src/generators/resources.ts +60 -0
- package/examples/reference-emitter/src/generators/tests.ts +7 -0
- package/examples/reference-emitter/src/index.ts +1 -0
- package/examples/reference-emitter/src/naming.ts +21 -0
- package/examples/reference-emitter/src/type-mapper.ts +39 -0
- package/examples/reference-emitter/tsconfig.json +19 -0
- package/package.json +102 -0
- package/skills/generate-emitter/SKILL.md +393 -0
- package/skills/generate-emitter/references/common-pitfalls.md +23 -0
- package/skills/generate-emitter/references/generator-guide.md +201 -0
- package/skills/generate-emitter/references/project-scaffold.md +138 -0
- package/skills/generate-extractor/SKILL.md +200 -0
- package/skills/generate-sdk/SKILL.md +155 -0
- package/skills/generate-smoke-test/SKILL.md +185 -0
- package/skills/integrate/SKILL.md +108 -0
- package/skills/verify-compat/SKILL.md +151 -0
- package/skills/verify-smoke-test/SKILL.md +176 -0
package/docs/cli.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
All commands support `--help` for full usage details.
|
|
4
|
+
|
|
5
|
+
## `oagen generate`
|
|
6
|
+
|
|
7
|
+
Generate SDK code from an OpenAPI spec.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
oagen generate --spec openapi.yml --lang node --output ./sdk --namespace WorkOS
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| Argument | Required | Default | Description |
|
|
14
|
+
| ---------------------- | -------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| `--spec <path>` | No | `OPENAPI_SPEC_PATH` env | Path to an OpenAPI 3.x spec file. |
|
|
16
|
+
| `--lang <language>` | Yes | | Target language — must have a registered emitter (via `oagen.config.ts`) |
|
|
17
|
+
| `--output <dir>` | Yes | | Directory to write generated files into |
|
|
18
|
+
| `--namespace <name>` | No | Spec's `info.title` | SDK namespace in PascalCase — used directly for code identifiers (e.g., `WorkOS::Client`) and converted to `snake_case` for file paths (e.g., `lib/work_os/`). Use PascalCase with the exact casing you want (e.g., `WorkOS` not `work_os`). |
|
|
19
|
+
| `--dry-run` | No | `false` | Print the list of file paths that would be generated, without writing anything to disk |
|
|
20
|
+
| `--api-surface <path>` | No | | Path to baseline API surface JSON for compat overlay |
|
|
21
|
+
| `--manifest <path>` | No | `<output>/smoke-manifest.json` | Path to smoke-manifest.json for method overlay (auto-discovered in output dir if present) |
|
|
22
|
+
| `--no-compat-check` | No | `false` | Skip compat overlay even if `--api-surface` is provided |
|
|
23
|
+
|
|
24
|
+
## `oagen diff`
|
|
25
|
+
|
|
26
|
+
Review or apply spec changes. Use `--report` to see what changed, or pass `--lang` and `--output` to incrementally regenerate affected files.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
oagen diff --old v1.yml --new v2.yml --report # review changes
|
|
30
|
+
oagen diff --old v1.yml --new v2.yml --lang node --output ./sdk # regenerate
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Argument | Required | Description |
|
|
34
|
+
| ---------------------- | -------- | ------------------------------------------------------- |
|
|
35
|
+
| `--old <path>` | Yes | Path to the old/previous spec |
|
|
36
|
+
| `--new <path>` | Yes | Path to the new/current spec |
|
|
37
|
+
| `--lang <language>` | No | Target language (required unless `--report`) |
|
|
38
|
+
| `--output <dir>` | No | Output directory for regenerated files |
|
|
39
|
+
| `--report` | No | Output a diff report as JSON instead of generating code |
|
|
40
|
+
| `--force` | No | Allow file deletions without confirmation |
|
|
41
|
+
| `--api-surface <path>` | No | Path to baseline API surface JSON for compat overlay |
|
|
42
|
+
| `--manifest <path>` | No | Path to smoke-manifest.json for method overlay |
|
|
43
|
+
|
|
44
|
+
## `oagen extract`
|
|
45
|
+
|
|
46
|
+
Extract the public API surface from an existing SDK. Produces a JSON file used as input for compat overlay and verification.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
oagen extract --sdk-path ./existing-sdk --lang ruby --output ./sdk/sdk-ruby-surface.json
|
|
50
|
+
oagen extract --sdk-path ./existing-sdk --lang ruby --output my-surface.json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Argument | Required | Default | Description |
|
|
54
|
+
| ------------------- | -------- | ------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `--sdk-path <path>` | Yes | | Path to the live SDK |
|
|
56
|
+
| `--lang <language>` | Yes | | Target language |
|
|
57
|
+
| `--output <path>` | No | `sdk-{lang}-surface.json` | Output file path (recommend writing to your output dir, e.g. `./sdk/sdk-ruby-surface.json`, and gitignoring it) |
|
|
58
|
+
|
|
59
|
+
## `oagen verify`
|
|
60
|
+
|
|
61
|
+
Verify an already-generated SDK — run smoke tests and optional compat checks. Use after `oagen generate` or `oagen diff`.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
oagen verify --lang node --output ./sdk --spec openapi.yml
|
|
65
|
+
|
|
66
|
+
# With compat check
|
|
67
|
+
oagen verify --lang node --output ./sdk --spec openapi.yml \
|
|
68
|
+
--api-surface ./sdk/sdk-node-surface.json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Argument | Required | Default | Description |
|
|
72
|
+
| ----------------------- | -------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `--lang <language>` | Yes | | Target language |
|
|
74
|
+
| `--output <dir>` | Yes | | Path to the generated SDK |
|
|
75
|
+
| `--spec <path>` | No | `OPENAPI_SPEC_PATH` env | Path to an OpenAPI 3.x spec file |
|
|
76
|
+
| `--api-surface <path>` | No | | Baseline API surface JSON — enables compat verification |
|
|
77
|
+
| `--raw-results <path>` | No | auto-generated | Path to an existing smoke baseline file to diff against |
|
|
78
|
+
| `--smoke-config <path>` | No | | Smoke config JSON for skip lists and service mappings |
|
|
79
|
+
| `--smoke-runner <path>` | No | | Custom smoke runner script (overrides built-in `sdk-test.ts`) |
|
|
80
|
+
| `--scope <mode>` | No | `spec-only` when `--spec` given | Compat scope: `full` compares all baseline symbols, `spec-only` only compares symbols derivable from the spec |
|
|
81
|
+
| `--diagnostics` | No | `false` | Output `verify-diagnostics.json` with structured violation breakdown |
|
|
82
|
+
| `--max-retries <n>` | No | `3` | Max retry iterations for self-correcting overlay loop (set to 0 for single-pass) |
|
|
83
|
+
|
|
84
|
+
**Exit codes:**
|
|
85
|
+
|
|
86
|
+
| Code | Meaning | Details |
|
|
87
|
+
| ---- | ----------------------------------------------------------------------- | --------------------------- |
|
|
88
|
+
| 0 | Clean — all checks passed | |
|
|
89
|
+
| 1 | Findings — CRITICAL smoke mismatches, compat violations, or missing ops | `smoke-diff-findings.json` |
|
|
90
|
+
| 2 | Compile error — SDK failed type check | `smoke-compile-errors.json` |
|
|
91
|
+
|
|
92
|
+
## `oagen init`
|
|
93
|
+
|
|
94
|
+
Scaffold a new emitter project with all boilerplate files and a compilable stub emitter.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
oagen init --lang ruby
|
|
98
|
+
oagen init --lang go --project ./my-emitter
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| Argument | Required | Default | Description |
|
|
102
|
+
| ------------------- | -------- | ------- | ------------------------------------ |
|
|
103
|
+
| `--lang <language>` | Yes | | Target language (e.g., `ruby`, `go`) |
|
|
104
|
+
| `--project <dir>` | No | `.` | Directory to create the project in |
|
|
105
|
+
|
|
106
|
+
Creates:
|
|
107
|
+
|
|
108
|
+
- `package.json` with `@workos/oagen` dependency and `sdk:generate`/`sdk:verify`/`sdk:extract` scripts
|
|
109
|
+
- `tsconfig.json`, `vitest.config.ts`, `tsup.config.ts` — build/test tooling
|
|
110
|
+
- `oagen.config.ts` — registers the stub emitter
|
|
111
|
+
- `src/{language}/index.ts` — stub emitter implementing the full `Emitter` interface
|
|
112
|
+
- `src/index.ts` — barrel export
|
|
113
|
+
- Empty directories: `test/`, `smoke/`, `docs/sdk-architecture/`
|
|
114
|
+
|
|
115
|
+
After initialization, `npm run typecheck` passes immediately. Implement your emitter methods in `src/{language}/` to start generating SDK code.
|
|
116
|
+
|
|
117
|
+
## `oagen parse`
|
|
118
|
+
|
|
119
|
+
Parse an OpenAPI spec and output the IR as JSON to stdout. Useful for inspecting what the parser extracts.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
oagen parse --spec openapi.yml
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
| Argument | Required | Default | Description |
|
|
126
|
+
| --------------- | -------- | ----------------------- | ------------------------------------------------ |
|
|
127
|
+
| `--spec <path>` | No | `OPENAPI_SPEC_PATH` env | Path to an OpenAPI 3.x spec file (YAML or JSON). |
|
|
128
|
+
|
|
129
|
+
## Configuration (`oagen.config.ts`)
|
|
130
|
+
|
|
131
|
+
Place an `oagen.config.ts` (or `.js`/`.mjs`) in your project root to register emitters, extractors, and customize pipeline behavior. The CLI loads this file at startup before any command runs.
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import type { OagenConfig } from "@workos/oagen";
|
|
135
|
+
import { nodeEmitter } from "./src/node/index.js";
|
|
136
|
+
import { nodeExtractor } from "./src/node/extractor.js";
|
|
137
|
+
|
|
138
|
+
const config: OagenConfig = {
|
|
139
|
+
emitters: [nodeEmitter],
|
|
140
|
+
extractors: [nodeExtractor],
|
|
141
|
+
docUrl: "https://workos.com/docs",
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default config;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Options
|
|
148
|
+
|
|
149
|
+
| Key | Type | Description |
|
|
150
|
+
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `emitters` | `Emitter[]` | Language emitters to register. Each emitter implements the `Emitter` interface and generates SDK files for one target language. |
|
|
152
|
+
| `extractors` | `Extractor[]` | API surface extractors to register. Each extractor parses a live SDK and produces an `ApiSurface` JSON used for compat verification. |
|
|
153
|
+
| `emitterProject` | `string` | Path to the emitter project directory. Used by skills to scaffold new emitters, tests, and smoke runners in the correct location. |
|
|
154
|
+
| `smokeRunners` | `Record<string, string>` | Map from language key to custom smoke runner script path. Overrides the built-in `sdk-test.ts` for `oagen verify`. Can also be set per-invocation with `--smoke-runner`. |
|
|
155
|
+
| `operationIdTransform` | `(id: string) => string` | Custom transform for operation IDs. Receives the raw `operationId` from the spec; return the desired operation name. No additional casing conversion is applied. When omitted, `operationId` values are converted to `camelCase`. |
|
|
156
|
+
| `docUrl` | `string` | Base URL for documentation links. When set, relative markdown paths in descriptions (e.g. `[User](/reference/authkit/user)`) are expanded to full URLs (e.g. `[User](https://workos.com/docs/reference/authkit/user)`). |
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Contributor Docs
|
|
2
|
+
|
|
3
|
+
These documents describe the maintenance rules for oagen itself and the guarantees made to consumers of the public API. If you are modifying oagen core (the parser, engine, IR types, compat system, or CLI), start here to understand what contracts you must preserve.
|
|
4
|
+
|
|
5
|
+
## Key Documents
|
|
6
|
+
|
|
7
|
+
- [Public API Policy](public-api.md) — three-tier public surface (core default export, advanced subpaths, internal) and what constitutes a breaking change
|
|
8
|
+
- [Versioning and Migration](versioning.md) — IR version bumping rules, package versioning, and advanced workflow compatibility
|
|
9
|
+
- [Dependency Layers](../architecture/dependency-layers.md) — one-way import matrix (`ir → utils → parser → engine/differ/compat → cli`) enforced by structural linter
|
|
10
|
+
- [Pipeline Architecture](../architecture/pipeline.md) — three-stage parse/emit/write flow with orchestrator details
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Public API Policy
|
|
2
|
+
|
|
3
|
+
This document defines what oagen treats as public API for OSS consumers.
|
|
4
|
+
|
|
5
|
+
## Core Public API
|
|
6
|
+
|
|
7
|
+
The default `@workos/oagen` entrypoint is the core public API.
|
|
8
|
+
|
|
9
|
+
It includes:
|
|
10
|
+
|
|
11
|
+
- IR types
|
|
12
|
+
- parser entrypoints such as `parseSpec`
|
|
13
|
+
- emitter-facing types such as `Emitter`, `EmitterContext`, and `GeneratedFile`
|
|
14
|
+
- generation runtime entrypoints such as `generate`, `generateFiles`, and `generateIncremental`
|
|
15
|
+
- spec diffing APIs such as `diffSpecs` and `mapChangesToFiles`
|
|
16
|
+
- naming utilities used by emitters
|
|
17
|
+
- `planOperation`
|
|
18
|
+
- config typing needed by emitter projects
|
|
19
|
+
|
|
20
|
+
Changes to this surface require a deliberate compatibility review.
|
|
21
|
+
|
|
22
|
+
## Advanced Public API
|
|
23
|
+
|
|
24
|
+
The following APIs are public, but not part of the default entrypoint:
|
|
25
|
+
|
|
26
|
+
- `@workos/oagen/compat`
|
|
27
|
+
- `@workos/oagen/verify`
|
|
28
|
+
|
|
29
|
+
These modules cover compatibility overlays, extractor registration, built-in extractors, and verification helpers. They are supported, but they are more opinionated and may evolve faster than the core framework surface.
|
|
30
|
+
|
|
31
|
+
## Internal API
|
|
32
|
+
|
|
33
|
+
Anything not exported from a package entrypoint should be treated as internal implementation detail, including:
|
|
34
|
+
|
|
35
|
+
- deep imports into `src/*`
|
|
36
|
+
- CLI implementation modules
|
|
37
|
+
- parser internals below `parseSpec`
|
|
38
|
+
- compat internals below the documented compat entrypoint
|
|
39
|
+
- verify internals below the documented verify entrypoint
|
|
40
|
+
|
|
41
|
+
Internal APIs may change without notice.
|
|
42
|
+
|
|
43
|
+
## Documentation Rule
|
|
44
|
+
|
|
45
|
+
If an API is intended for external use, it must satisfy all of the following:
|
|
46
|
+
|
|
47
|
+
1. It is exported from a package entrypoint.
|
|
48
|
+
2. It is documented in user-facing docs.
|
|
49
|
+
3. It has tests that reflect the intended behavior.
|
|
50
|
+
|
|
51
|
+
If one of those is missing, the API should be considered provisional at best.
|
|
52
|
+
|
|
53
|
+
## Stability Rule
|
|
54
|
+
|
|
55
|
+
When in doubt:
|
|
56
|
+
|
|
57
|
+
- keep the default entrypoint small
|
|
58
|
+
- prefer adding advanced capabilities behind explicit subpaths
|
|
59
|
+
- avoid promoting internal helpers into the public surface unless they are needed by emitter authors
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Versioning and Migration
|
|
2
|
+
|
|
3
|
+
oagen has two different compatibility concerns. They should not be treated as interchangeable.
|
|
4
|
+
|
|
5
|
+
## 1. Package Version
|
|
6
|
+
|
|
7
|
+
The npm package version communicates overall release maturity and changelog history.
|
|
8
|
+
|
|
9
|
+
## 2. Advanced Workflow Compatibility
|
|
10
|
+
|
|
11
|
+
Compat extraction, overlays, smoke verification, and target integration are higher-level workflows built on top of the core framework. They may require narrower migration guidance than the core parser/emitter contract.
|
|
12
|
+
|
|
13
|
+
Treat changes here as public if they affect:
|
|
14
|
+
|
|
15
|
+
- documented CLI flags
|
|
16
|
+
- documented subpath exports
|
|
17
|
+
- persisted file formats such as extracted API surfaces or diagnostics files
|
|
18
|
+
|
|
19
|
+
## Compile-Time Safety
|
|
20
|
+
|
|
21
|
+
The primary compatibility mechanism is `assertNever`, which enforces exhaustive `switch` statements over `TypeRef.kind` at compile time. Adding a new IR variant causes build failures in any emitter that doesn't handle it.
|
|
22
|
+
|
|
23
|
+
## Migration Guidance
|
|
24
|
+
|
|
25
|
+
Every release that changes public behavior should describe:
|
|
26
|
+
|
|
27
|
+
1. what changed
|
|
28
|
+
2. who is affected
|
|
29
|
+
3. whether the change is core or advanced
|
|
30
|
+
4. what users need to update
|
|
31
|
+
|
|
32
|
+
At minimum, migration notes should call out:
|
|
33
|
+
|
|
34
|
+
- IR shape changes
|
|
35
|
+
- emitter contract changes
|
|
36
|
+
- config shape changes
|
|
37
|
+
- CLI flag changes
|
|
38
|
+
- compat JSON format changes
|
|
39
|
+
|
|
40
|
+
## Release Discipline
|
|
41
|
+
|
|
42
|
+
Before broadening the public surface:
|
|
43
|
+
|
|
44
|
+
1. decide whether the API belongs in the core entrypoint or an advanced subpath
|
|
45
|
+
2. document it
|
|
46
|
+
3. add tests that exercise its intended use by external consumers
|
|
47
|
+
|
|
48
|
+
If that discipline is too expensive, the API is not ready to be public.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Core Docs
|
|
2
|
+
|
|
3
|
+
These documents define the stable center of oagen as an OSS framework.
|
|
4
|
+
|
|
5
|
+
- [Minimal Quickstart](quickstart.md)
|
|
6
|
+
- [Minimal Emitter](minimal-emitter.md)
|
|
7
|
+
- [CLI Reference](../cli.md)
|
|
8
|
+
- [Pipeline Architecture](../architecture/pipeline.md)
|
|
9
|
+
- [IR Type System Reference](../architecture/ir-types.md)
|
|
10
|
+
- [Emitter Contract](../architecture/emitter-contract.md)
|
|
11
|
+
|
|
12
|
+
Read the quickstart first. The goal is to get from a spec to generated files without learning compatibility overlays, extractors, or smoke workflows.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Minimal Emitter
|
|
2
|
+
|
|
3
|
+
This guide shows the smallest useful emitter shape in oagen.
|
|
4
|
+
|
|
5
|
+
Use it when you want to understand the minimum contract quickly. If you need the full interface details, overlay behavior, and versioning rules, read the [Emitter Contract](../architecture/emitter-contract.md).
|
|
6
|
+
|
|
7
|
+
## Goal
|
|
8
|
+
|
|
9
|
+
A minimal emitter should:
|
|
10
|
+
|
|
11
|
+
- declare a `language`
|
|
12
|
+
- return files from at least one generator method
|
|
13
|
+
- return `[]` from methods the language does not use yet
|
|
14
|
+
|
|
15
|
+
That is enough to prove the parser, runtime, and file-writing loop are working.
|
|
16
|
+
|
|
17
|
+
## Smallest Practical Skeleton
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import type {
|
|
21
|
+
ApiSpec,
|
|
22
|
+
Emitter,
|
|
23
|
+
Enum,
|
|
24
|
+
GeneratedFile,
|
|
25
|
+
Model,
|
|
26
|
+
Service,
|
|
27
|
+
} from "@workos/oagen";
|
|
28
|
+
|
|
29
|
+
function namesFile(path: string, values: string[]): GeneratedFile[] {
|
|
30
|
+
if (values.length === 0) return [];
|
|
31
|
+
return [{ path, content: values.join("\n") }];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const demoEmitter: Emitter = {
|
|
35
|
+
language: "demo",
|
|
36
|
+
|
|
37
|
+
generateModels(models: Model[]): GeneratedFile[] {
|
|
38
|
+
return namesFile(
|
|
39
|
+
"models.txt",
|
|
40
|
+
models.map((model) => model.name),
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
generateEnums(enums: Enum[]): GeneratedFile[] {
|
|
45
|
+
return namesFile(
|
|
46
|
+
"enums.txt",
|
|
47
|
+
enums.map((entry) => entry.name),
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
generateResources(services: Service[]): GeneratedFile[] {
|
|
52
|
+
return namesFile(
|
|
53
|
+
"services.txt",
|
|
54
|
+
services.map((service) => service.name),
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
generateClient(spec: ApiSpec): GeneratedFile[] {
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
path: "summary.txt",
|
|
62
|
+
content: [
|
|
63
|
+
`name: ${spec.name}`,
|
|
64
|
+
`services: ${spec.services.length}`,
|
|
65
|
+
].join("\n"),
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
generateErrors(): GeneratedFile[] {
|
|
71
|
+
return [];
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
generateConfig(): GeneratedFile[] {
|
|
75
|
+
return [];
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
generateTypeSignatures(): GeneratedFile[] {
|
|
79
|
+
return [];
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
generateTests(): GeneratedFile[] {
|
|
83
|
+
return [];
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
fileHeader(): string {
|
|
87
|
+
return "# Generated by oagen";
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## What This Proves
|
|
93
|
+
|
|
94
|
+
With just this emitter, you can verify:
|
|
95
|
+
|
|
96
|
+
- the spec parses into IR
|
|
97
|
+
- the emitter is registered correctly
|
|
98
|
+
- the generation runtime calls each method in the expected order
|
|
99
|
+
- output files are written to disk
|
|
100
|
+
|
|
101
|
+
## What It Does Not Cover Yet
|
|
102
|
+
|
|
103
|
+
This is intentionally incomplete. It does not try to solve:
|
|
104
|
+
|
|
105
|
+
- language-specific naming conventions
|
|
106
|
+
- request/response rendering
|
|
107
|
+
- operation planning
|
|
108
|
+
- compatibility overlays
|
|
109
|
+
- smoke verification
|
|
110
|
+
- integration into an existing SDK
|
|
111
|
+
|
|
112
|
+
## The First Real Upgrade
|
|
113
|
+
|
|
114
|
+
After the minimal emitter works, the next step is usually to make `generateResources()` and `generateClient()` understand operations rather than only names.
|
|
115
|
+
|
|
116
|
+
That is when `planOperation()` becomes useful:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { planOperation } from "@workos/oagen";
|
|
120
|
+
|
|
121
|
+
for (const service of services) {
|
|
122
|
+
for (const operation of service.operations) {
|
|
123
|
+
const plan = planOperation(operation);
|
|
124
|
+
// render using plan.hasBody, plan.isPaginated, plan.responseModelName, ...
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Recommended Path
|
|
130
|
+
|
|
131
|
+
1. Start with this minimal emitter.
|
|
132
|
+
2. Make generation deterministic and add golden tests.
|
|
133
|
+
3. Add real model and operation rendering.
|
|
134
|
+
4. Only then add advanced features like compat overlays or smoke verification.
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Minimal Quickstart
|
|
2
|
+
|
|
3
|
+
This guide takes you from an OpenAPI spec to a tiny working emitter with the fewest moving parts possible.
|
|
4
|
+
|
|
5
|
+
## What You Will Build
|
|
6
|
+
|
|
7
|
+
- parse an OpenAPI spec into oagen's IR
|
|
8
|
+
- scaffold an emitter project
|
|
9
|
+
- replace the stub emitter with a minimal implementation
|
|
10
|
+
- generate a few files
|
|
11
|
+
|
|
12
|
+
This quickstart intentionally ignores advanced features like API-surface extraction, compatibility overlays, smoke verification, and live-SDK integration.
|
|
13
|
+
|
|
14
|
+
## 1. Install oagen
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @workos/oagen
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 2. Inspect Your Spec
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
oagen parse --spec openapi.yml
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This prints the parsed IR as JSON. Before writing an emitter, confirm the parser is extracting the services, models, and enums you expect.
|
|
27
|
+
|
|
28
|
+
## 3. Scaffold an Emitter Project
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
oagen init --lang demo --project ./demo-emitter
|
|
32
|
+
cd ./demo-emitter
|
|
33
|
+
npm install
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The scaffold gives you:
|
|
37
|
+
|
|
38
|
+
- `oagen.config.ts`
|
|
39
|
+
- `src/demo/index.ts`
|
|
40
|
+
- build/test tooling
|
|
41
|
+
- `sdk:generate` and related package scripts
|
|
42
|
+
|
|
43
|
+
## 4. Replace the Stub Emitter
|
|
44
|
+
|
|
45
|
+
Edit `src/demo/index.ts` to return a few simple files:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import type {
|
|
49
|
+
ApiSpec,
|
|
50
|
+
Emitter,
|
|
51
|
+
Enum,
|
|
52
|
+
GeneratedFile,
|
|
53
|
+
Model,
|
|
54
|
+
Service,
|
|
55
|
+
} from "@workos/oagen";
|
|
56
|
+
|
|
57
|
+
function renderSummary(spec: ApiSpec): string {
|
|
58
|
+
return [
|
|
59
|
+
`name: ${spec.name}`,
|
|
60
|
+
`services: ${spec.services.length}`,
|
|
61
|
+
`models: ${spec.models.length}`,
|
|
62
|
+
`enums: ${spec.enums.length}`,
|
|
63
|
+
].join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function renderModels(models: Model[]): GeneratedFile[] {
|
|
67
|
+
if (models.length === 0) return [];
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
path: "models.txt",
|
|
71
|
+
content: models.map((model) => model.name).join("\n"),
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function renderEnums(enums: Enum[]): GeneratedFile[] {
|
|
77
|
+
if (enums.length === 0) return [];
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
path: "enums.txt",
|
|
81
|
+
content: enums.map((entry) => entry.name).join("\n"),
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function renderServices(services: Service[]): GeneratedFile[] {
|
|
87
|
+
if (services.length === 0) return [];
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
path: "services.txt",
|
|
91
|
+
content: services.map((service) => service.name).join("\n"),
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const demoEmitter: Emitter = {
|
|
97
|
+
language: "demo",
|
|
98
|
+
generateModels: (models) => renderModels(models),
|
|
99
|
+
generateEnums: (enums) => renderEnums(enums),
|
|
100
|
+
generateResources: (services) => renderServices(services),
|
|
101
|
+
generateClient: (spec) => [
|
|
102
|
+
{
|
|
103
|
+
path: "summary.txt",
|
|
104
|
+
content: renderSummary(spec),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
generateErrors: () => [],
|
|
108
|
+
generateConfig: () => [],
|
|
109
|
+
generateTypeSignatures: () => [],
|
|
110
|
+
generateTests: () => [],
|
|
111
|
+
fileHeader: () => "# Generated by oagen",
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## 5. Generate Files
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run sdk:generate -- --spec ../openapi.yml --namespace DemoSdk
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Expected result:
|
|
122
|
+
|
|
123
|
+
- `sdk/summary.txt`
|
|
124
|
+
- `sdk/models.txt` when the spec has models
|
|
125
|
+
- `sdk/enums.txt` when the spec has enums
|
|
126
|
+
- `sdk/services.txt` when the spec has services
|
|
127
|
+
|
|
128
|
+
## 6. Grow from Here
|
|
129
|
+
|
|
130
|
+
Once the minimal loop works:
|
|
131
|
+
|
|
132
|
+
1. Replace text files with real language output.
|
|
133
|
+
2. Use [`planOperation`](../../src/engine/operation-plan.ts) via `@workos/oagen` to share operation decision logic.
|
|
134
|
+
3. Add emitter tests with fixture specs and golden files.
|
|
135
|
+
4. Only then consider advanced workflows like `oagen verify` or compatibility overlays.
|
|
136
|
+
|
|
137
|
+
## Next Reads
|
|
138
|
+
|
|
139
|
+
- [Reference Emitter](../../examples/reference-emitter/) — a working TypeScript emitter you can study and copy
|
|
140
|
+
- [Emitter Contract](../architecture/emitter-contract.md)
|
|
141
|
+
- [IR Type System Reference](../architecture/ir-types.md)
|
|
142
|
+
- [CLI Reference](../cli.md)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# /generate-sdk Workflow
|
|
2
|
+
|
|
3
|
+
```mermaid
|
|
4
|
+
---
|
|
5
|
+
config:
|
|
6
|
+
layout: elk
|
|
7
|
+
---
|
|
8
|
+
flowchart TD
|
|
9
|
+
start([/generate-sdk]) --> existingSDK{Existing SDK?}
|
|
10
|
+
|
|
11
|
+
existingSDK -- "Yes: Scenario A" --> a_emitter["/generate-emitter"]
|
|
12
|
+
existingSDK -- "No: Scenario B" --> b_emitter["/generate-emitter"]
|
|
13
|
+
|
|
14
|
+
a_emitter --> a_extractor["/generate-extractor
|
|
15
|
+
extract live SDK public API
|
|
16
|
+
into api-surface.json"]
|
|
17
|
+
|
|
18
|
+
a_extractor --> a_compat["/verify-compat
|
|
19
|
+
diff generated SDK
|
|
20
|
+
against api-surface.json"]
|
|
21
|
+
|
|
22
|
+
a_compat --> overlay_gen
|
|
23
|
+
|
|
24
|
+
subgraph overlay loop
|
|
25
|
+
overlay_gen["generate with overlay"]
|
|
26
|
+
overlay_gen --> overlay_diff["diff against baseline"]
|
|
27
|
+
overlay_diff --> violations{violations?}
|
|
28
|
+
violations -- yes --> patch["patchOverlay"]
|
|
29
|
+
patch --> overlay_gen
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
violations -- no --> smoke["/generate-smoke-test
|
|
33
|
+
scaffold HTTP interception
|
|
34
|
+
+ wire-level parity tests"]
|
|
35
|
+
|
|
36
|
+
b_emitter --> smoke
|
|
37
|
+
|
|
38
|
+
smoke --> loop_start
|
|
39
|
+
|
|
40
|
+
subgraph emitter-fixing loop
|
|
41
|
+
loop_start["oagen generate"]
|
|
42
|
+
loop_start --> loop_verify["oagen verify"]
|
|
43
|
+
loop_verify --> exitcode{exit code?}
|
|
44
|
+
exitcode -- "1 or 2" --> fix["read findings, fix emitter"]
|
|
45
|
+
fix --> loop_start
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
exitcode -- 0 --> final(["final validation
|
|
49
|
+
tsc + vitest + tsup + lint"])
|
|
50
|
+
```
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Docs Overview
|
|
2
|
+
|
|
3
|
+
oagen documentation is organized by adoption stage.
|
|
4
|
+
|
|
5
|
+
## Core
|
|
6
|
+
|
|
7
|
+
Start here if you want to understand or use the framework itself:
|
|
8
|
+
|
|
9
|
+
- [Core Index](core/index.md)
|
|
10
|
+
- [Minimal Quickstart](core/quickstart.md)
|
|
11
|
+
- [CLI Reference](cli.md)
|
|
12
|
+
- [Emitter Contract](architecture/emitter-contract.md)
|
|
13
|
+
- [IR Type System Reference](architecture/ir-types.md)
|
|
14
|
+
- [Pipeline Architecture](architecture/pipeline.md)
|
|
15
|
+
|
|
16
|
+
## Advanced
|
|
17
|
+
|
|
18
|
+
Read these when you need migration or verification workflows beyond basic generation:
|
|
19
|
+
|
|
20
|
+
- [Advanced Index](advanced/index.md)
|
|
21
|
+
- [Workflows](architecture/workflows.md)
|
|
22
|
+
- [Extractor Contract](architecture/extractor-contract.md)
|
|
23
|
+
- [Non-Additive Changes](architecture/non-additive-changes.md)
|
|
24
|
+
|
|
25
|
+
## Agent Task Guides
|
|
26
|
+
|
|
27
|
+
Focused guides for AI agents working on specific areas of the codebase:
|
|
28
|
+
|
|
29
|
+
- [Architecture & Core Contracts](agents/architecture.md)
|
|
30
|
+
- [Emitter Implementation](agents/emitters.md)
|
|
31
|
+
- [Testing & Smoke Validation](agents/testing.md)
|
|
32
|
+
|
|
33
|
+
## Contributor
|
|
34
|
+
|
|
35
|
+
Read these if you are maintaining oagen itself or depending on its public API surface:
|
|
36
|
+
|
|
37
|
+
- [Contributor Index](contributor/index.md)
|
|
38
|
+
- [Public API Policy](contributor/public-api.md)
|
|
39
|
+
- [Versioning and Migration](contributor/versioning.md)
|
|
40
|
+
- [Dependency Layers](architecture/dependency-layers.md)
|