@octalmesh/seagull 0.0.2 → 0.1.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/README.md CHANGED
@@ -1,104 +1,228 @@
1
- # Seagull
2
-
3
- Contract-first OpenAPI SDK, docs, and publishing pipeline - driven by a
4
- single config file. Point it at your `openapi.yaml` files, tell it which SDK
5
- artifacts you want (TypeScript client, Go server stubs, Java client, ...),
6
- and it lints, bundles, generates, documents, and publishes them.
7
-
8
- Built to manage **several services' contracts from one place** - each
9
- service just needs an entry in the config; each artifact is generated by a
10
- reusable, shareable "recipe".
11
-
12
- ## Packages
13
-
14
- This repo is a monorepo, but only **one** package is ever published:
15
- `@octalmesh/seagull`. The three packages under [`packages/`](./packages)
16
- are private and exist purely for internal organization - each is bundled
17
- straight into `@octalmesh/seagull`'s own `dist/` at build time (see the root
18
- [`tsdown.config.ts`](./tsdown.config.ts)), so installing the one package is
19
- installing all of it.
20
-
21
- | Package | Role |
22
- |------------------------------------------------|-------------------------------------------------------------------------|
23
- | **`@octalmesh/seagull`** (this repo's root) | Published. The `seagull` CLI + programmatic API. |
24
- | [`@octalmesh/seagull-core`](./packages/core) | Private. Config loading, the `Generator` primitive, built-in generators. |
25
- | [`@octalmesh/seagull-cli`](./packages/cli) | Private. Pipeline commands + the `commander` program. |
26
- | [`@octalmesh/seagull-docs`](./packages/docs) | Private. Docs-site generation - a Scalar-based placeholder today, a fully custom UI later. |
27
-
28
- If you're just using seagull, none of that matters - `npm install @octalmesh/seagull`
29
- gets you the `seagull` command and the full programmatic API in one package.
30
- The split only matters if you're contributing to seagull itself.
1
+ <!--suppress HtmlDeprecatedAttribute, HtmlUnknownTarget -->
2
+ <div align="center">
3
+ <!--
4
+ =====================
5
+ HEADER
6
+ =====================
7
+ -->
8
+ <br />
9
+ <a rel="noopener noreferrer" href="https://github.com/OctalMesh/Seagull">
10
+ <picture>
11
+ <source media="(prefers-color-scheme: light)" srcset="./.github/assets/svg/seagull_logo.svg">
12
+ <img alt="Seagull" src="./.github/assets/svg/seagull_logo_white.svg">
13
+ </picture>
14
+ </a>
15
+ <br /><br /><br />
16
+ <!--
17
+ =====================
18
+ BADGES
19
+ =====================
20
+ -->
21
+ <div>
22
+ <!-- Repo Stars Badge -->
23
+ <a rel="noopener noreferrer" href="https://github.com/OctalMesh/Seagull/stargazers">
24
+ <picture>
25
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/stars/OctalMesh/Seagull?style=for-the-badge&logo=starship&color=363636&labelColor=464646" />
26
+ <img alt="Stars" src="https://img.shields.io/github/stars/OctalMesh/Seagull?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+DQogIDxwYXRoIGZpbGw9IiMzNjM2MzYiIGQ9Ik04IC4yNWEuNzUuNzUgMCAwIDEgLjY3My40MThsMS44ODIgMy44MTUgNC4yMS42MTJhLjc1Ljc1IDAgMCAxIC40MTYgMS4yNzlsLTMuMDQ2IDIuOTcuNzE5IDQuMTkyYS43NTEuNzUxIDAgMCAxLTEuMDg4Ljc5MUw4IDEyLjM0N2wtMy43NjYgMS45OGEuNzUuNzUgMCAwIDEtMS4wODgtLjc5bC43Mi00LjE5NEwuODE4IDYuMzc0YS43NS43NSAwIDAgMSAuNDE2LTEuMjhsNC4yMS0uNjExTDcuMzI3LjY2OEEuNzUuNzUgMCAwIDEgOCAuMjVabTAgMi40NDVMNi42MTUgNS41YS43NS43NSAwIDAgMS0uNTY0LjQxbC0zLjA5Ny40NSAyLjI0IDIuMTg0YS43NS43NSAwIDAgMSAuMjE2LjY2NGwtLjUyOCAzLjA4NCAyLjc2OS0xLjQ1NmEuNzUuNzUgMCAwIDEgLjY5OCAwbDIuNzcgMS40NTYtLjUzLTMuMDg0YS43NS43NSAwIDAgMSAuMjE2LS42NjRsMi4yNC0yLjE4My0zLjA5Ni0uNDVhLjc1Ljc1IDAgMCAxLS41NjQtLjQxTDggMi42OTRaIi8+DQo8L3N2Zz4=&color=fff&labelColor=eaeaea" />
27
+ </picture>
28
+ </a>
29
+ <!-- Repo Contributors Badge -->
30
+ <a rel="noopener noreferrer" href="https://github.com/OctalMesh/Seagull/contributors">
31
+ <picture>
32
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/contributors/OctalMesh/Seagull?style=for-the-badge&logo=githubsponsors&logoColor=fff&color=363636&labelColor=464646" />
33
+ <img alt="Contributors" src="https://img.shields.io/github/contributors/OctalMesh/Seagull?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+DQogIDxwYXRoIGZpbGw9IiMzNjM2MzYiIGQ9Ik0yIDUuNWEzLjUgMy41IDAgMSAxIDUuOSAyLjU1IDUuNSA1LjUgMCAwIDEgMy4wMyA0LjA4Ljc1Ljc1IDAgMSAxLTEuNDguMjQgNCA0IDAgMCAwLTcuOSAwIC43NS43NSAwIDAgMS0xLjQ4LS4yNEE1LjUgNS41IDAgMCAxIDMuMSA4LjA1IDMuNSAzLjUgMCAwIDEgMiA1LjVaTTExIDRhMyAzIDAgMCAxIDIuMjIgNS4wMiA1LjAxIDUuMDEgMCAwIDEgMi41NiAzLjAxLjc1Ljc1IDAgMCAxLS44OC45NS43NS43NSAwIDAgMS0uNTUtLjUxIDMuNSAzLjUgMCAwIDAtMi41My0yLjM3Ljc1Ljc1IDAgMCAxLS41Ny0uNzN2LS4zNWEuNzUuNzUgMCAwIDEgLjQyLS42OEExLjUgMS41IDAgMCAwIDExIDUuNS43NS43NSAwIDAgMSAxMSA0Wm0tNS41LS41YTIgMiAwIDEgMCAwIDQgMiAyIDAgMCAwIDAtNFoiLz4NCjwvc3ZnPg==&color=fff&labelColor=eaeaea" />
34
+ </picture>
35
+ </a>
36
+ <!-- Repo Views Badge -->
37
+ <a rel="noopener noreferrer" href="https://hits.sh/github.com/OctalMesh/Seagull">
38
+ <picture>
39
+ <source media="(prefers-color-scheme: light)" srcset="https://hits.sh/github.com/OctalMesh/Seagull.svg?style=for-the-badge&label=Views&logo=github&color=363636&labelColor=464646" />
40
+ <img alt="Views" src="https://hits.sh/github.com/OctalMesh/Seagull.svg?style=for-the-badge&label=Views&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDI0IDEwMjQiPjxwYXRoIGZpbGw9IiMzNjM2MzYiIGQ9Ik01MTIgMGE1MTIgNTEyIDAgMCAwLTE2MiA5OThjMjYgNCAzNS0xMSAzNS0yNXYtOTVjLTEyOSAyNC0xNjItMzEtMTczLTYwLTUtMTUtMzAtNjAtNTItNzItMTgtMTAtNDQtMzQtMS0zNCA0MS0xIDY5IDM3IDc5IDUyIDQ2IDc4IDEyMCA1NiAxNDkgNDIgNS0zMyAxOC01NSAzMy02OC0xMTQtMTMtMjMzLTU3LTIzMy0yNTMgMC01NiAyMC0xMDIgNTItMTM3LTUtMTMtMjMtNjYgNS0xMzYgMCAwIDQzLTE0IDE0MSA1MmE0NzUgNDc1IDAgMCAxIDI1NiAwYzk4LTY2IDE0MS01MiAxNDEtNTIgMjggNzAgMTAgMTIzIDUgMTM2IDMzIDM1IDUzIDgxIDUzIDEzNyAwIDE5Ny0xMjAgMjQwLTIzNCAyNTMgMTkgMTYgMzUgNDcgMzUgOTVsLTEgMTQwYzAgMTQgMTAgMzAgMzUgMjVBNTEzIDUxMyAwIDAgMCA1MTIgMFoiLz48L3N2Zz4=&color=fff&labelColor=eaeaea" />
41
+ </picture>
42
+ </a>
43
+ <br />
44
+ <!-- Version Badge -->
45
+ <a rel="noopener noreferrer" href="https://npmjs.com/package/@octalmesh/seagull">
46
+ <picture>
47
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/v/@octalmesh/seagull?style=for-the-badge&label=Version&color=363636&labelColor=464646&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTEgNy44di01UTEuMiAxLjIgMi44IDFoNXEuNyAwIDEuMi41bDYuMyA2LjNhMiAyIDAgMCAxIDAgMi40bC01IDVhMiAyIDAgMCAxLTIuNSAwTDEuNSA5QTIgMiAwIDAgMSAxIDcuOG0xLjUgMFY4bDYuMyA2LjJoLjRsNS01di0uNEw4IDIuNmwtLjItLjFoLTVsLS4zLjNaTTYgNWExIDEgMCAxIDEgMCAyIDEgMSAwIDAgMSAwLTIiLz48L3N2Zz4=" />
48
+ <img alt="Version" src="https://img.shields.io/npm/v/@octalmesh/seagull?style=for-the-badge&label=Version&color=fff&labelColor=eaeaea&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzM2MzYzNiIgZD0iTTEgNy44di01UTEuMiAxLjIgMi44IDFoNXEuNyAwIDEuMi41bDYuMyA2LjNhMiAyIDAgMCAxIDAgMi40bC01IDVhMiAyIDAgMCAxLTIuNSAwTDEuNSA5QTIgMiAwIDAgMSAxIDcuOG0xLjUgMFY4bDYuMyA2LjJoLjRsNS01di0uNEw4IDIuNmwtLjItLjFoLTVsLS4zLjNaTTYgNWExIDEgMCAxIDEgMCAyIDEgMSAwIDAgMSAwLTIiLz48L3N2Zz4=" />
49
+ </picture>
50
+ </a>
51
+ <!-- NPM Downloads Badge -->
52
+ <a rel="noopener noreferrer" href="https://www.npmjs.com/package/@octalmesh/seagull">
53
+ <picture>
54
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/npm/dm/@octalmesh/seagull?style=for-the-badge&logo=npm&color=363636&labelColor=464646" />
55
+ <img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@octalmesh/seagull?style=for-the-badge&logo=npm&logoColor=464646&color=fff&labelColor=eaeaea" />
56
+ </picture>
57
+ </a>
58
+ <!-- License Badge -->
59
+ <a rel="noopener noreferrer" href="LICENSE.md">
60
+ <picture>
61
+ <source media="(prefers-color-scheme: light)" srcset="https://img.shields.io/github/license/OctalMesh/Seagull?style=for-the-badge&color=363636&labelColor=464646&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTguOC44VjJoMXEuMyAwIC44LjJsMS4zLjhoMi40YS44LjggMCAwIDEgMCAxLjVoLS41TDE2IDkuMmExIDEgMCAwIDEtLjEuOGwtLjUtLjUuNS41di4xbC0uOC40cS0uNi41LTIgLjVhNSA1IDAgMCAxLTItLjVsLS43LS40YTEgMSAwIDAgMS0uMi0xbDItNC42cS0uNiAwLTEtLjJMMTAgMy41SDguN1YxM2gyLjZhLjguOCAwIDAgMSAwIDEuNUg0LjhhLjguOCAwIDAgMSAwLTEuNWgyLjVWMy41SDZMNSA0LjNsLTEgLjIgMiA0LjdhMSAxIDAgMCAxLS4xLjhsLS41LS41LjUuNXYuMWwtLjguNHEtLjYuNS0yIC41YTUgNSAwIDAgMS0yLS41bC0uNy0uNEExIDEgMCAwIDEgMCA5bDItNC42aC0uNGEuOC44IDAgMCAxIDAtMS41aDIuNGwxLjMtLjguOS0uMmgxVi44YS44LjggMCAwIDEgMS41IDBtMi45IDguNHEuNC4zIDEuMy4zYy45IDAgMS0uMSAxLjMtLjNMMTMgNi4zWm0tMTAgMHEuNC4zIDEuMy4zYy45IDAgMS0uMSAxLjMtLjNMMyA2LjNaIi8+PC9zdmc+" />
62
+ <img alt="License" src="https://img.shields.io/github/license/OctalMesh/Seagull?style=for-the-badge&color=fff&labelColor=eaeaea&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzM2MzYzNiIgZD0iTTguOC44VjJoMXEuMyAwIC44LjJsMS4zLjhoMi40YS44LjggMCAwIDEgMCAxLjVoLS41TDE2IDkuMmExIDEgMCAwIDEtLjEuOGwtLjUtLjUuNS41di4xbC0uOC40cS0uNi41LTIgLjVhNSA1IDAgMCAxLTItLjVsLS43LS40YTEgMSAwIDAgMS0uMi0xbDItNC42cS0uNiAwLTEtLjJMMTAgMy41SDguN1YxM2gyLjZhLjguOCAwIDAgMSAwIDEuNUg0LjhhLjguOCAwIDAgMSAwLTEuNWgyLjVWMy41SDZMNSA0LjNsLTEgLjIgMiA0LjdhMSAxIDAgMCAxLS4xLjhsLS41LS41LjUuNXYuMWwtLjguNHEtLjYuNS0yIC41YTUgNSAwIDAgMS0yLS41bC0uNy0uNEExIDEgMCAwIDEgMCA5bDItNC42aC0uNGEuOC44IDAgMCAxIDAtMS41aDIuNGwxLjMtLjguOS0uMmgxVi44YS44LjggMCAwIDEgMS41IDBtMi45IDguNHEuNC4zIDEuMy4zYy45IDAgMS0uMSAxLjMtLjNMMTMgNi4zWm0tMTAgMHEuNC4zIDEuMy4zYy45IDAgMS0uMSAxLjMtLjNMMyA2LjNaIi8+PC9zdmc+" />
63
+ </picture>
64
+ </a>
65
+ </div>
66
+ <h1></h1>
67
+ <!--
68
+ =====================
69
+ SOURCES
70
+ =====================
71
+ -->
72
+ <h6>
73
+ <a rel="noopener noreferrer" href="CODE_OF_CONDUCT.md">Code of Conduct</a>
74
+ ·
75
+ <a rel="noopener noreferrer" href="CONTRIBUTING.md">Contributing</a>
76
+ ·
77
+ <a rel="noopener noreferrer" href="SECURITY.md">Security Policy</a>
78
+ ·
79
+ <a rel="noopener noreferrer" href="SUPPORT.md">Support</a>
80
+ ·
81
+ <a rel="noopener noreferrer" href="RELEASING.md">Releasing</a>
82
+ ·
83
+ <a rel="noopener noreferrer" href="LICENSE.md">License</a>
84
+ ·
85
+ <a rel="noopener noreferrer" href="examples/README.md">Examples</a>
86
+ </h6>
87
+ </div>
88
+
89
+ <div align="justify">
90
+ <!--
91
+ =====================
92
+ DESCRIPTION
93
+ =====================
94
+ -->
95
+ <p>
96
+ Seagull is a contract-first OpenAPI SDK, docs, and publishing pipeline -
97
+ driven by a single config file. Point it at your `openapi.yaml` files, tell
98
+ it which SDK artifacts you want and it lints, bundles, generates, documents,
99
+ and publishes them.
100
+ </p>
101
+ </div>
102
+
103
+ <div align="center">
104
+ <h2 id="overview">Overview</h2>
105
+ </div>
106
+
107
+ Built to manage several services' contracts from one place - each service just
108
+ needs an entry in the config; each artifact is generated by a reusable,
109
+ shareable "recipe".
110
+
111
+ | Stage | What it does |
112
+ |--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
113
+ | **Lint** | Validates every contract's OpenAPI spec for structural and style issues |
114
+ | **Bundle** | Dereferences and bundles each spec into `dist/specs` |
115
+ | **Generate** | Runs each configured "recipe" through [`openapi-generator-cli`](https://www.npmjs.com/package/@openapitools/openapi-generator-cli) or [`openapi-typescript`](https://www.npmjs.com/package/openapi-typescript) |
116
+ | **Document** | Builds an interactive docs site across every contract into `dist/docs` |
117
+ | **Publish** | Pushes generated SDKs to orphan git branches/tags, and to artifact registries |
118
+
119
+ ```mermaid
120
+ flowchart LR
121
+ A["Contract"] --> B["Lint"]
122
+ B --> C["Bundle<br/>(spec files)"]
123
+ C --> D["Generate<br/>(SDK artifacts)"]
124
+ C --> E["Docs website"]
125
+ D --> F["Publish SDK<br/>(git branch + tag)"]
126
+ D --> G["Publish registries<br/>(npm / Maven)"]
127
+
128
+ classDef stage fill:#363636,stroke:#666,color:#fff,rx:6,ry:6
129
+ class A,B,C,D,E,F,G stage
130
+ ```
31
131
 
32
- ## Install
132
+ <div align="center">
133
+ <h2 id="packages">Packages</h2>
134
+ </div>
135
+
136
+ This repo is a monorepo of four packages, all versioned and published together
137
+ (see [`.changeset/config.json`](.changeset/config.json)'s `fixed` group and
138
+ [RELEASING.md](RELEASING.md)). Most people only need the first one - it bundles
139
+ the other three straight into its own `dist/` via [`tsdown`](https://tsdown.dev).
140
+ The three internal packages are published independently too, for anyone who
141
+ wants a smaller dependency (e.g. scripting against just
142
+ `@octalmesh/seagull-core`'s config loader without pulling in the CLI or the docs
143
+ generator).
144
+
145
+ | Package | Role |
146
+ |--------------------------------------------|------------------------------------------------------------------------------------------------|
147
+ | [`@octalmesh/seagull`](.) | The `seagull` CLI + programmatic API. What almost everyone should install. |
148
+ | [`@octalmesh/seagull-core`](packages/core) | Config loading, the `Generator` primitive, built-in generators, version/publishing logic, etc. |
149
+ | [`@octalmesh/seagull-cli`](packages/cli) | Pipeline commands (`lint`/`bundle`/`generate`/`publish`/...) + the `commander` program. |
150
+ | [`@octalmesh/seagull-docs`](packages/docs) | Docs-site generation from bundled specs, plus a local dev server for previewing the site. |
151
+
152
+ <div align="center">
153
+ <h2 id="installation">Installation</h2>
154
+ </div>
33
155
 
34
156
  ```bash
35
157
  npm install -D @octalmesh/seagull
36
- # or
37
- pnpm add -D @octalmesh/seagull
38
158
  ```
39
159
 
40
- Under the hood, `generate` shells out to
41
- [`@openapitools/openapi-generator-cli`](https://www.npmjs.com/package/@openapitools/openapi-generator-cli)
42
- (needs a JVM on `PATH`) and
43
- [`openapi-typescript`](https://www.npmjs.com/package/openapi-typescript);
44
- `lint`/`bundle` use [`@redocly/cli`](https://www.npmjs.com/package/@redocly/cli);
45
- `docs` uses [`@scalar/api-reference`](https://www.npmjs.com/package/@scalar/api-reference).
46
- All four are `@octalmesh/seagull`'s own dependencies, resolved via Node's
47
- module resolution (not `npx`/`pnpm exec`) - nothing extra to install, and it
48
- works the same regardless of which package manager you use.
160
+ Under the hood, `generate` shells out to `@openapitools/openapi-generator-cli`
161
+ (needs a JVM on `PATH`) and `openapi-typescript`; `lint`/`bundle` and `docs`
162
+ each rely on their own established OpenAPI tooling under the hood. All of these
163
+ are `@octalmesh/seagull`'s own dependencies, resolved via Node's module
164
+ resolution.
49
165
 
50
- ## Quick start
166
+ <div align="center">
167
+ <h2 id="quick-start">Quick Start</h2>
168
+ </div>
51
169
 
52
- Create a config file at the root of your contracts repo - any of
53
- `.seagull`, `.seagull.yaml`, `.seagull.yml`, `seagull.yaml`, `seagull.yml`:
170
+ Create a config file at the root of your contracts repo (any of
171
+ `.seagull`, `.seagull.yaml`, `.seagull.yml`, `seagull.yaml`, `seagull.yml`):
54
172
 
55
173
  ```yaml
56
- # seagull.yaml
174
+ # Seagull config version
57
175
  configVersion: 1
58
176
 
59
- github:
60
- owner: your-org
61
- repo: your-contracts-repo
62
-
177
+ # Custom variables to use in config
63
178
  vars:
64
- org: your-org
179
+ org: "your-npm-scope"
180
+ repository:
181
+ owner: "your-org"
182
+ repo: "your-contracts-repo"
65
183
 
184
+ # Documentation configuration
66
185
  docs:
67
186
  server:
68
- host: localhost
187
+ host: "localhost"
69
188
  port: 8080
189
+
70
190
  metadata:
71
- title: "API Reference"
72
- description: "..."
73
- favicon: https://your-domain.com/favicon.ico
74
- baseServerUrl: https://api.your-domain.com
191
+ title: "Your API Docs"
192
+ description: "Generated API documentation"
193
+ favicon: "/favicon.ico"
194
+ baseServerUrl: "https://api.example.com"
75
195
 
196
+ # Publishing configuration
76
197
  publishing:
77
198
  branch: "sdk/svc-{service}/{id}"
78
199
  tag: "svc-{service}-{id}-v{version}"
79
- repositoryUrl: "https://github.com/{github.owner}/{github.repo}"
200
+ repositoryUrl: "https://github.com/{vars.repository.owner}/{vars.repository.repo}"
201
+
80
202
  npm:
81
- registry: "https://npm.pkg.github.com"
82
- access: restricted
203
+ registry: "https://registry.npmjs.org"
204
+ access: "public"
205
+
83
206
  maven:
84
- repositoryId: github
85
- repositoryUrl: "https://maven.pkg.github.com/{github.owner}/{github.repo}"
207
+ repositoryId: "github"
208
+ repositoryUrl: "https://maven.pkg.github.com/{vars.repository.owner}/{vars.repository.repo}"
86
209
 
210
+ # Generators configuration used to produce SDK artifacts
87
211
  generators:
88
212
  ts-client:
89
- tool: openapi-generator
90
- generator: typescript-fetch
91
- lang: typescript
92
- kind: client
213
+ tool: "openapi-generator"
214
+ generator: "typescript-fetch"
215
+ lang: "typescript"
216
+ kind: "client"
93
217
  package: "@{vars.org}/{service}-client"
94
- additionalProperties:
95
- supportsES6: true
96
218
 
219
+ # Per-service contract configuration
97
220
  contracts:
98
- - name: auth
99
- title: Auth Service API
100
- entrypoint: specs/auth/openapi.yaml
101
- artifacts: [ts-client]
221
+ - name: "auth"
222
+ title: "Auth Service API"
223
+ entrypoint: "specs/auth/openapi.yaml"
224
+ artifacts:
225
+ - "ts-client"
102
226
  ```
103
227
 
104
228
  Then:
@@ -110,79 +234,133 @@ npx seagull generate
110
234
  npx seagull docs generate && npx seagull docs serve
111
235
  ```
112
236
 
113
- ## Configuration
237
+ See [`examples/`](examples/README.md) for complete, runnable configs covering
238
+ every generator/publishing/docs feature, plus an API walkthrough.
239
+
240
+ <div align="center">
241
+ <h2 id="configuration">Configuration</h2>
242
+ </div>
114
243
 
115
- - **`configVersion:`** (required) - which version of the config *schema*
116
- this file targets, currently always `1`. Decoupled from `@octalmesh/seagull`'s
117
- own npm version on purpose: this only changes if `seagull.yaml`'s shape
118
- changes in a breaking way, so an old config fails with a clear "expected
119
- configVersion 1" error instead of a confusing failure on some unrelated
120
- field once the schema moves on.
121
- - **`generators:`** - reusable recipes: a `tool` (`openapi-generator` or
244
+ - `configVersion:` (required) - which version of the config schema this file
245
+ targets. Decoupled from `@octalmesh/seagull`'s own npm version on purpose:
246
+ this only changes if `seagull.yaml`'s shape changes in a breaking way, so an
247
+ old config fails with a clear "expected configVersion 1" error.
248
+
249
+ - `generators:` - reusable recipes: a `tool` (`openapi-generator` or
122
250
  `openapi-typescript`), which `-g` template to use, and naming templates
123
251
  for the npm package / Go module / Maven coordinates. Any string field may
124
- reference `{vars.some.nested.key}`, `{github.owner}`, `{github.repo}`, or
125
- `{service}` (the current contract's `name`).
126
- - **`contracts:`** - one entry per service (`name`, `title`, `entrypoint`,
127
- and which `generators:` it wants under `artifacts:`, by id). Two services
128
- don't need the same generators - a contract can reference a generator with
129
- a per-contract override instead of duplicating the whole recipe:
252
+ reference `{vars.some.nested.key}` or `{service}` (the current contract's
253
+ `name`).
130
254
 
255
+ - `contracts:` - one entry per service (`name`, `title`, `entrypoint`, and which
256
+ `generators:` it wants under `artifacts:`, by id). Two services don't need the
257
+ same generators - a contract can reference a generator with a per-contract
258
+ override instead of duplicating the whole recipe:
131
259
  ```yaml
132
260
  contracts:
133
- - name: payment
261
+ - name: "payment"
134
262
  artifacts:
135
- - generator: java-client
136
- as: java-client-legacy # renames this artifact's output folder/branch/tag
263
+ - generator: "java-client"
264
+ as: "java-client-legacy" # renames this artifact's output folder/branch/tag
137
265
  overrides:
138
- generator: java-legacy-template
139
- additionalProperties: { library: jersey2 }
266
+ generator: "java-legacy-template"
267
+ additionalProperties:
268
+ library: "jersey2"
140
269
  ```
141
270
 
142
- - **`vars:`** - a free-form tree for anything used in naming templates.
143
- Nest however deep is useful; every leaf is addressable as `{vars.a.b.c}`.
144
- - **`paths:`** - only `dist:` is required; `specs`/`docs`/`sdk` default to
271
+ - `vars:` - a free-form tree for anything used in naming templates. Nest however
272
+ deep is useful; every leaf is addressable as `{vars.a.b.c}`.
273
+
274
+ - `paths:` - only `dist:` is required; `specs`/`docs`/`sdk` default to
145
275
  `<dist>/specs`, `<dist>/docs`, `<dist>/sdk` and only need to be set to
146
- override that.
147
- - **`docs:`** - `server: { host, port }` for `docs serve`, and
276
+ override that. `specFormat:` controls what format(s) `seagull bundle` writes
277
+ specs in - `json` (default), `yaml`, or a list of both
278
+ (`specFormat: [json, yaml]`) to bundle into more than one format at once;
279
+ Redocly infers the output format from the file extension on its own, so
280
+ this is a free choice, not a compatibility trade-off. When more than one
281
+ format is configured, the first one listed is the "primary" format SDK
282
+ generation and the docs site actually read from - the rest are bundled as
283
+ additional static artifacts alongside it.
284
+
285
+ - `docs:` - `server: { host, port }` for `docs serve`, and
148
286
  `metadata: { title, description, favicon, baseServerUrl }` for the
149
287
  generated docs site.
150
- - **`publishing:`** (required) - see below.
151
288
 
152
- A typo or missing field fails immediately with a readable, path-annotated
153
- error - config is validated with [zod](https://zod.dev) on every run.
289
+ - `publishing:` (required) - see below.
290
+
291
+ A typo or missing field fails immediately with a readable, path-annotated error.
292
+ Config is validated on every run.
293
+
294
+ `seagull.yaml` (and `redocly.base.yaml`) also support the YAML `<<: *anchor`
295
+ merge key, so shared fields don't need to be repeated across every entry:
296
+
297
+ ```yaml
298
+ _defaults: &defaults
299
+ lang: "typescript"
300
+
301
+ generators:
302
+ ts-server:
303
+ <<: *defaults
304
+ tool: "openapi-typescript"
305
+ kind: "server"
306
+ package: "@{vars.org}/{service}-server"
307
+
308
+ ts-client:
309
+ <<: *defaults
310
+ tool: "openapi-generator"
311
+ generator: "typescript-fetch"
312
+ kind: "client"
313
+ package: "@{vars.org}/{service}-client"
314
+ ```
154
315
 
155
- ### Publishing
316
+ <h3 id="publishing">Publishing</h3>
156
317
 
157
- `publishing:` controls where things get published to - git branch/tag
158
- naming, and npm/Maven registry URLs. It's required at the root level:
159
- seagull has no built-in convention here, so a config that omits it fails
160
- validation with a message pointing at exactly what's missing, rather than
161
- silently applying an opinionated default nobody chose.
318
+ `publishing:` controls where things get published to - git branch/tag naming,
319
+ and npm/Maven registry URLs. It's required at the root level: seagull has no
320
+ built-in convention here, so a config that omits it fails validation with a
321
+ message pointing at exactly what's missing, rather than silently applying an
322
+ opinionated default nobody chose.
162
323
 
163
324
  ```yaml
164
325
  publishing:
165
- branch: "sdk/svc-{service}/{id}" # git branch each artifact publishes to
166
- tag: "svc-{service}-{id}-v{version}" # git tag - the only field where {version} is available
167
- repositoryUrl: "https://github.com/{github.owner}/{github.repo}"
326
+ branch: "sdk/svc-{service}/{id}" # git branch each artifact publishes to
327
+ tag: "svc-{service}-{id}-v{version}" # git tag - the only field where {version} is available
328
+ repositoryUrl: "https://github.com/{vars.repository.owner}/{vars.repository.repo}" # git remote URL for pushing branches/tags
329
+
168
330
  npm:
169
331
  registry: "https://npm.pkg.github.com"
170
- access: restricted # or "public"
332
+ access: "restricted" # or "public"
333
+
171
334
  maven:
172
- repositoryId: github
173
- repositoryUrl: "https://maven.pkg.github.com/{github.owner}/{github.repo}"
335
+ repositoryId: "github"
336
+ repositoryUrl: "https://maven.pkg.github.com/{vars.repository.owner}/{vars.repository.repo}"
174
337
  ```
175
338
 
176
- Every field is a template - the same `{...}` engine as naming templates,
177
- plus `{id}` (the artifact's id) and, for `tag` only, `{version}` (resolved
178
- once the contract's spec is bundled, since a branch is created before a
179
- version is known but a tag isn't).
339
+ Every field is a template - the same `{...}` engine as naming templates, plus
340
+ `{id}` (the artifact's id) and, for `tag` only, `{version}` (resolved once the
341
+ contract's spec is bundled, since a branch is created before a version is known
342
+ but a tag isn't).
180
343
 
181
344
  Like `additionalProperties` and `readme`, `publishing:` can be overridden
182
345
  per-generator (`generators.<id>.publishing`) or per-contract-artifact
183
346
  (`artifacts[].overrides.publishing`) - only the fields that differ need
184
347
  repeating, the rest fall through to the root-level config:
185
348
 
349
+ ```mermaid
350
+ flowchart TD
351
+ A["Root config<br/>(fallback for everything)"] --> B["Generator override<br/>(per recipe)"]
352
+ B --> C["Artifact override<br/>(per contract)"]
353
+ C --> D(["Effective config<br/>for this artifact"])
354
+
355
+ classDef layer fill:#363636,stroke:#666,color:#fff,rx:6,ry:6
356
+ classDef result fill:#1f6feb,stroke:#1f6feb,color:#fff,rx:20,ry:20
357
+ class A,B,C layer
358
+ class D result
359
+ ```
360
+
361
+ The same three-layer precedence (root -> generator -> artifact `overrides`)
362
+ applies to `additionalProperties` and `readme` too, not just `publishing`.
363
+
186
364
  ```yaml
187
365
  generators:
188
366
  ts-client:
@@ -192,92 +370,159 @@ generators:
192
370
  registry: "https://registry.internal.example.com" # every contract's ts-client uses this registry
193
371
 
194
372
  contracts:
195
- - name: payment
373
+ - name: "payment"
196
374
  artifacts:
197
- - generator: ts-client
375
+ - generator: "ts-client"
198
376
  overrides:
199
377
  publishing:
200
378
  branch: "custom/{service}-{id}-branch" # ...except payment's ts-client, which also uses a different branch
201
379
  ```
202
380
 
203
- ### Custom README templates
381
+ <h3 id="custom-readme-templates">Custom README templates</h3>
204
382
 
205
- Every generated artifact gets a `README.md` - by default a sensible
206
- built-in template for its language/kind. To use your own, point `readme:`
207
- at a template file (path relative to the config file):
383
+ Every generated artifact gets a `README.md` - by default a sensible built-in
384
+ template for its language/kind. To use your own, point `readme:` at a template
385
+ file (path relative to the config file):
208
386
 
209
387
  ```yaml
210
388
  generators:
211
389
  ts-client:
212
390
  # ...
213
- readme: readme-templates/ts-client.md
391
+ readme: "readme-templates/ts-client.md"
214
392
  ```
215
393
 
216
- Template files support the same `{...}` placeholders as naming templates,
217
- plus a few more:
218
-
219
- | Placeholder | Value |
220
- |--------------------------------------------------------------------|-------------------------------------------------|
221
- | `{service}` | The contract's `name` |
222
- | `{title}` | The contract's `title` |
223
- | `{version}` | The resolved SDK version |
224
- | `{vars.*}` | Anything under `vars:` |
225
- | `{github.owner}` / `{github.repo}` | From `github:` |
226
- | `{artifact.id}` | The artifact's id (as listed under `artifacts:`) |
227
- | `{artifact.package}` | Resolved npm package name (TypeScript) |
228
- | `{artifact.goModule}` / `{artifact.goPackageName}` | Resolved Go naming |
229
- | `{artifact.maven.groupId}` / `{artifact.maven.artifactId}` | Resolved Maven coordinates |
230
- | `{artifact.branch}` / `{artifact.tag}` | Resolved publishing branch / tag |
231
- | `{artifact.npmRegistry}` / `{artifact.mavenRepositoryUrl}` | Resolved registry URLs from `publishing:` |
232
-
233
- An unresolvable placeholder fails the build loudly (a typo'd `{vesion}`
234
- won't silently ship as literal text).
235
-
236
- ## Commands
394
+ Template files support the same `{...}` placeholders as naming templates, plus a
395
+ few more:
396
+
397
+ | Placeholder | Value |
398
+ |------------------------------------------------------------|--------------------------------------------------|
399
+ | `{service}` | The contract's `name` |
400
+ | `{title}` | The contract's `title` |
401
+ | `{version}` | The resolved SDK version |
402
+ | `{vars.*}` | Anything under `vars:` |
403
+ | `{artifact.id}` | The artifact's id (as listed under `artifacts:`) |
404
+ | `{artifact.package}` | Resolved npm package name (TypeScript) |
405
+ | `{artifact.goModule}` / `{artifact.goPackageName}` | Resolved Go naming |
406
+ | `{artifact.maven.groupId}` / `{artifact.maven.artifactId}` | Resolved Maven coordinates |
407
+ | `{artifact.branch}` / `{artifact.tag}` | Resolved publishing branch / tag |
408
+ | `{artifact.npmRegistry}` / `{artifact.mavenRepositoryUrl}` | Resolved registry URLs from `publishing:` |
409
+
410
+ An unresolvable placeholder fails the build loudly (a typo'd `{vesion}` won't
411
+ silently ship as literal text).
412
+
413
+ <div align="center">
414
+ <h2 id="commands">Commands</h2>
415
+ </div>
237
416
 
238
417
  ```
239
- seagull lint Lint every contract with Redocly
240
- seagull bundle Bundle every contract's spec into dist/specs
241
- seagull generate Generate every configured SDK artifact into dist/sdk
242
- seagull clean Remove the dist directory
243
- seagull docs generate Generate the documentation site into dist/docs
244
- seagull docs serve Serve the generated documentation site locally
245
- seagull publish sdk [--dry-run] Publish generated SDKs to their git branches/tags
246
- seagull publish registries [--dry-run]
247
- npm publish / mvn deploy the registry-backed artifacts
248
- ```
249
-
250
- Every command accepts `-c, --config <path>` to point at a config file
251
- outside the current directory.
252
-
253
- ## Programmatic API
254
-
255
- ```ts
256
- import { loadConfig, generateSdkCommand } from "@octalmesh/seagull";
257
-
258
- const config = loadConfig("/path/to/seagull.yaml");
259
- await generateSdkCommand(config);
418
+ seagull lint Lint every contract's OpenAPI spec
419
+ seagull bundle Bundle every contract's spec into dist/specs
420
+ seagull generate Generate every configured SDK artifact into dist/sdk
421
+ seagull clean Remove the dist directory
422
+ seagull docs generate Generate the documentation site into dist/docs
423
+ seagull docs serve Serve the generated documentation site locally
424
+ seagull publish sdk [--dry-run] Publish generated SDKs to their git branches/tags
425
+ seagull publish registries [--dry-run] npm publish / mvn deploy the registry-backed artifacts
260
426
  ```
261
427
 
262
- `loadConfig`, every `*Command` function, `createProgram` (the `commander`
263
- program factory), the `Generator`/`GeneratorRegistry` primitives, and the
264
- built-in `OpenApiGeneratorCli`/`OpenApiTypescriptGenerator` generators are
265
- all exported, for anyone who wants to script against seagull directly or
266
- register a custom `Generator` for another tool.
428
+ Every command accepts `-c, --config <path>` to point at a config file outside
429
+ the current directory.
267
430
 
268
- ## Development
431
+ <div align="center">
432
+ <h2 id="development">Development</h2>
433
+ </div>
269
434
 
270
435
  ```bash
271
- pnpm install
272
- pnpm run build # builds packages/* first (topological), then bundles the root package
273
- pnpm run typecheck # run after build - resolves the private packages via their built dist/
274
- pnpm run lint
275
- pnpm run test:run
436
+ pnpm install # install dependencies for all packages
437
+ pnpm run build # builds packages/* first (topological), then bundles the root package
438
+ pnpm run typecheck # run after build - resolves the workspace packages via their built dist/
439
+ pnpm run lint # lint all packages
440
+ pnpm run test # run all tests
276
441
  ```
277
442
 
278
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to propose changes, and
279
- [RELEASING.md](./RELEASING.md) for how versioning and publishing work.
280
-
281
- ## License
282
-
283
- MIT
443
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for how to propose changes, and
444
+ [RELEASING.md](RELEASING.md) for how versioning and publishing work.
445
+
446
+ <div align="center">
447
+ <!--
448
+ =====================
449
+ FOOTER
450
+ =====================
451
+ -->
452
+ <h1></h1>
453
+ <br />
454
+ <!-- OctalMesh Logo -->
455
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com">
456
+ <picture>
457
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/logo/svg/octal_mesh_center.svg" />
458
+ <img alt="OctalMesh" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/logo/svg/octal_mesh_center_white.svg" height="48" />
459
+ </picture>
460
+ </a>
461
+ <br /><br />
462
+ <!-- Socials -->
463
+ <div>
464
+ <!-- Telegram Badge -->
465
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/telegram">
466
+ <picture>
467
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/telegram.svg" />
468
+ <img alt="Telegram" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/telegram_white.svg" width="48" />
469
+ </picture>
470
+ </a>
471
+ &nbsp;
472
+ <!-- YouTube Badge -->
473
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/youtube">
474
+ <picture>
475
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/youtube.svg" />
476
+ <img alt="YouTube" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/youtube_white.svg" width="48" />
477
+ </picture>
478
+ </a>
479
+ &nbsp;
480
+ <!-- TikTok Badge -->
481
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/tiktok">
482
+ <picture>
483
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/tiktok.svg" />
484
+ <img alt="TikTok" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/tiktok_white.svg" width="48" />
485
+ </picture>
486
+ </a>
487
+ &nbsp;
488
+ <!-- Instagram Badge -->
489
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/instagram">
490
+ <picture>
491
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/instagram.svg" />
492
+ <img alt="Instagram" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/instagram_white.svg" width="48" />
493
+ </picture>
494
+ </a>
495
+ &nbsp;
496
+ <!-- X Badge -->
497
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/x">
498
+ <picture>
499
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/x.svg" />
500
+ <img alt="X" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/x_white.svg" width="48" />
501
+ </picture>
502
+ </a>
503
+ &nbsp;
504
+ <!-- Reddit Badge -->
505
+ <a rel="noopener noreferrer" target="_blank" href="https://octalmesh.com/reddit">
506
+ <picture>
507
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/reddit.svg" />
508
+ <img alt="Reddit" src="https://raw.githubusercontent.com/OctalMesh/OctalDesign/release/assets/icon/svg/reddit_white.svg" width="48" />
509
+ </picture>
510
+ </a>
511
+ </div>
512
+ </div>
513
+ <h6>
514
+ <div align="center">
515
+ • • •
516
+ <br /><br />
517
+ This project is licensed under the <a rel="noopener noreferrer" href="../../LICENSE.md">MIT License</a>
518
+ <br /><br />
519
+ </div>
520
+ <div align="justify">
521
+ <ul>
522
+ <li>Feel free to use this project for any purpose, including commercial applications.</li>
523
+ <li>You are permitted to modify, distribute, and include this project in any form, as long as the original copyright notice is retained.</li>
524
+ <li>If you share or publish modified versions, attribution to the original <a rel="noopener noreferrer" href="https://github.com/OctalMesh/Seagull">GitHub repository</a> is appreciated.</li>
525
+ <li>This software is provided "as is", without any warranties or guarantees, as detailed in the license terms.</li>
526
+ </ul>
527
+ </div>
528
+ </h6>