@erenthedeveloper0/zen-openapi 0.1.0-alpha.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/LICENSE +9 -0
- package/README.md +76 -0
- package/dist/diff.d.ts +37 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +320 -0
- package/dist/diff.js.map +1 -0
- package/dist/document.d.ts +75 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +689 -0
- package/dist/document.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +29 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +84 -0
- package/dist/plugin.js.map +1 -0
- package/dist/schema.d.ts +103 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +434 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +154 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/ui.d.ts +19 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +192 -0
- package/dist/ui.js.map +1 -0
- package/package.json +65 -0
- package/src/diff.ts +439 -0
- package/src/document.ts +882 -0
- package/src/index.ts +20 -0
- package/src/plugin.ts +135 -0
- package/src/schema.ts +497 -0
- package/src/types.ts +166 -0
- package/src/ui.ts +198 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eren Sümer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/erenthedeveloper0/zen/main/.github/images/logo-with-text-white.png">
|
|
4
|
+
<img alt="zen.js" src="https://raw.githubusercontent.com/erenthedeveloper0/zen/main/.github/images/logo-with-text-black.png" width="220">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
# @erenthedeveloper0/zen-openapi
|
|
9
|
+
|
|
10
|
+
OpenAPI 3.1 for [Zen](https://github.com/erenthedeveloper0/zen), generated from the
|
|
11
|
+
same schemas the framework validates requests and serializes responses with —
|
|
12
|
+
so the document says exactly what the wire carries.
|
|
13
|
+
|
|
14
|
+
> **Alpha.**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @erenthedeveloper0/zen-openapi@alpha
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { zen, registerSchemaConverter } from '@erenthedeveloper0/zen'
|
|
22
|
+
import { openapiPlugin } from '@erenthedeveloper0/zen-openapi'
|
|
23
|
+
import { z } from 'zod'
|
|
24
|
+
|
|
25
|
+
// Once, before the app boots: how to read a Zod schema as JSON Schema.
|
|
26
|
+
registerSchemaConverter('zod', (schema, io) => z.toJSONSchema(schema as z.ZodType, { io }))
|
|
27
|
+
|
|
28
|
+
const app = zen()
|
|
29
|
+
app.use(openapiPlugin, {
|
|
30
|
+
title: 'Acme API',
|
|
31
|
+
version: '2.0.0',
|
|
32
|
+
json: '/openapi.json', // the document
|
|
33
|
+
ui: '/docs', // a built-in viewer with no external requests
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Why the document cannot drift
|
|
38
|
+
|
|
39
|
+
The generator is a pure function from the frozen application graph to a
|
|
40
|
+
document, run once at boot — the endpoint serves a pre-encoded string with an
|
|
41
|
+
`ETag`, and costs nothing per request.
|
|
42
|
+
|
|
43
|
+
Response schemas are published **closed** (`additionalProperties: false`),
|
|
44
|
+
because Zen's serializer drops any field a response schema does not declare: a
|
|
45
|
+
document generated from the raw schema would promise clients fields that can
|
|
46
|
+
never arrive. Parameter serialization follows the route's actual coercion
|
|
47
|
+
settings, and a negotiated route publishes one `content` entry per media type,
|
|
48
|
+
in the server's preference order.
|
|
49
|
+
|
|
50
|
+
## Breaking-change detection
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { diffDocuments } from '@erenthedeveloper0/zen-openapi'
|
|
54
|
+
|
|
55
|
+
const { breaking, compatible } = diffDocuments(committedBaseline, currentDocument)
|
|
56
|
+
if (breaking.length > 0) process.exitCode = 1
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Requests are contravariant and responses covariant: removing a response field,
|
|
60
|
+
narrowing a request type or renaming an `operationId` is breaking; adding an
|
|
61
|
+
optional response field is not. Run it in CI against a committed baseline and an
|
|
62
|
+
API change is reviewed as an API change.
|
|
63
|
+
|
|
64
|
+
## Options
|
|
65
|
+
|
|
66
|
+
`title` and `version` are required. Also: `servers`, `tags`, `security`,
|
|
67
|
+
`securitySchemes`, `license`, `contact`, `json` / `ui` (paths, or `false`),
|
|
68
|
+
`strict` (turn documentation warnings into boot errors — worth enabling once an
|
|
69
|
+
API is public), and `onDocument` (receives the finished document at boot).
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
[ARCHITECTURE.md §29](https://github.com/erenthedeveloper0/zen/blob/main/ARCHITECTURE.md#29-openapi--code-generation) ·
|
|
74
|
+
[`examples/openapi`](https://github.com/erenthedeveloper0/zen/tree/main/examples/openapi).
|
|
75
|
+
|
|
76
|
+
[MIT](https://github.com/erenthedeveloper0/zen/blob/main/LICENSE) © [Eren Sümer](https://github.com/erenthedeveloper0) · [contributors](https://github.com/erenthedeveloper0/zen/blob/main/CONTRIBUTORS.md)
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { OpenApiDocument } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* API change detection — rfcs/0001 §29.5.
|
|
4
|
+
*
|
|
5
|
+
* A governance feature disguised as tooling. The point is not the diff; it is
|
|
6
|
+
* that an API change stops being "a diff in a routes file" and becomes a
|
|
7
|
+
* reviewable statement about compatibility, on the pull request, before it
|
|
8
|
+
* ships.
|
|
9
|
+
*
|
|
10
|
+
* Two asymmetries drive every rule here, and they are the whole model:
|
|
11
|
+
*
|
|
12
|
+
* - **Requests are contravariant.** Accepting *less* breaks callers. Removing
|
|
13
|
+
* a field, adding a required one, or narrowing a type are all breaking.
|
|
14
|
+
* - **Responses are covariant.** Returning *less* breaks callers. Removing a
|
|
15
|
+
* field, dropping a status, or widening a type (a value the client's
|
|
16
|
+
* exhaustive switch has never seen) are all breaking.
|
|
17
|
+
*
|
|
18
|
+
* The classification is deliberately conservative: when a change could break a
|
|
19
|
+
* reasonable consumer, it is reported as breaking. A tool that under-reports is
|
|
20
|
+
* worse than no tool, because it is trusted.
|
|
21
|
+
*/
|
|
22
|
+
export type ChangeKind = 'breaking' | 'compatible' | 'documentation';
|
|
23
|
+
export interface ApiChange {
|
|
24
|
+
readonly kind: ChangeKind;
|
|
25
|
+
readonly code: string;
|
|
26
|
+
readonly message: string;
|
|
27
|
+
/** `GET /users/{id} → response 200 → users[].email` */
|
|
28
|
+
readonly location: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DiffResult {
|
|
31
|
+
readonly changes: readonly ApiChange[];
|
|
32
|
+
readonly breaking: readonly ApiChange[];
|
|
33
|
+
readonly compatible: readonly ApiChange[];
|
|
34
|
+
readonly documentation: readonly ApiChange[];
|
|
35
|
+
}
|
|
36
|
+
export declare function diffDocuments(before: OpenApiDocument, after: OpenApiDocument): DiffResult;
|
|
37
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACK,eAAe,EAC/B,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,eAAe,CAAA;AAEpE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAA;IACvC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,EAAE,SAAS,SAAS,EAAE,CAAA;CAC7C;AAID,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,GAAG,UAAU,CAuCzF"}
|
package/dist/diff.js
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
const METHODS = ['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace'];
|
|
2
|
+
export function diffDocuments(before, after) {
|
|
3
|
+
const changes = [];
|
|
4
|
+
const context = { before: new Resolver(before), after: new Resolver(after), changes };
|
|
5
|
+
const paths = new Set([...Object.keys(before.paths), ...Object.keys(after.paths)]);
|
|
6
|
+
for (const path of [...paths].sort()) {
|
|
7
|
+
const beforeItem = before.paths[path];
|
|
8
|
+
const afterItem = after.paths[path];
|
|
9
|
+
if (beforeItem !== undefined && afterItem === undefined) {
|
|
10
|
+
changes.push(breaking('OAS_PATH_REMOVED', `Path ${path} was removed.`, path));
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (beforeItem === undefined && afterItem !== undefined) {
|
|
14
|
+
changes.push(compatible('OAS_PATH_ADDED', `Path ${path} was added.`, path));
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (beforeItem === undefined || afterItem === undefined)
|
|
18
|
+
continue;
|
|
19
|
+
for (const method of METHODS) {
|
|
20
|
+
const from = beforeItem[method];
|
|
21
|
+
const to = afterItem[method];
|
|
22
|
+
const location = `${method.toUpperCase()} ${path}`;
|
|
23
|
+
if (from !== undefined && to === undefined) {
|
|
24
|
+
changes.push(breaking('OAS_OPERATION_REMOVED', `${location} was removed.`, location));
|
|
25
|
+
}
|
|
26
|
+
else if (from === undefined && to !== undefined) {
|
|
27
|
+
changes.push(compatible('OAS_OPERATION_ADDED', `${location} was added.`, location));
|
|
28
|
+
}
|
|
29
|
+
else if (from !== undefined && to !== undefined) {
|
|
30
|
+
diffOperation(from, to, location, context);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
changes,
|
|
36
|
+
breaking: changes.filter((c) => c.kind === 'breaking'),
|
|
37
|
+
compatible: changes.filter((c) => c.kind === 'compatible'),
|
|
38
|
+
documentation: changes.filter((c) => c.kind === 'documentation'),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function diffOperation(from, to, where, ctx) {
|
|
42
|
+
if (from.operationId !== to.operationId) {
|
|
43
|
+
// Generated clients name their methods from this. Renaming it is a source
|
|
44
|
+
// break in every SDK even when the wire format is untouched.
|
|
45
|
+
ctx.changes.push(breaking('OAS_OPERATION_ID_CHANGED', `operationId changed from "${from.operationId}" to "${to.operationId}".`, where));
|
|
46
|
+
}
|
|
47
|
+
if (from.summary !== to.summary || from.description !== to.description) {
|
|
48
|
+
ctx.changes.push(documentation('OAS_DESCRIPTION_CHANGED', 'Summary or description changed.', where));
|
|
49
|
+
}
|
|
50
|
+
if (from.deprecated !== true && to.deprecated === true) {
|
|
51
|
+
ctx.changes.push(documentation('OAS_OPERATION_DEPRECATED', 'Operation was marked deprecated.', where));
|
|
52
|
+
}
|
|
53
|
+
if ((from.security?.length ?? 0) === 0 && (to.security?.length ?? 0) > 0) {
|
|
54
|
+
ctx.changes.push(breaking('OAS_SECURITY_ADDED', 'Operation now requires authentication.', where));
|
|
55
|
+
}
|
|
56
|
+
diffParameters(from.parameters ?? [], to.parameters ?? [], where, ctx);
|
|
57
|
+
diffRequestBody(from, to, where, ctx);
|
|
58
|
+
diffResponses(from.responses, to.responses, where, ctx);
|
|
59
|
+
}
|
|
60
|
+
function diffParameters(from, to, where, ctx) {
|
|
61
|
+
const key = (p) => `${p.in}:${p.name}`;
|
|
62
|
+
const beforeMap = new Map(from.map((p) => [key(p), p]));
|
|
63
|
+
const afterMap = new Map(to.map((p) => [key(p), p]));
|
|
64
|
+
for (const [id, parameter] of beforeMap) {
|
|
65
|
+
const next = afterMap.get(id);
|
|
66
|
+
const at = `${where} → ${id}`;
|
|
67
|
+
if (next === undefined) {
|
|
68
|
+
ctx.changes.push(breaking('OAS_PARAM_REMOVED', `Parameter ${id} was removed.`, at));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (parameter.required !== true && next.required === true) {
|
|
72
|
+
ctx.changes.push(breaking('OAS_PARAM_NOW_REQUIRED', `Parameter ${id} became required.`, at));
|
|
73
|
+
}
|
|
74
|
+
else if (parameter.required === true && next.required !== true) {
|
|
75
|
+
ctx.changes.push(compatible('OAS_PARAM_NOW_OPTIONAL', `Parameter ${id} became optional.`, at));
|
|
76
|
+
}
|
|
77
|
+
diffSchema(parameter.schema, next.schema, 'request', at, ctx, new Set());
|
|
78
|
+
}
|
|
79
|
+
for (const [id, parameter] of afterMap) {
|
|
80
|
+
if (beforeMap.has(id))
|
|
81
|
+
continue;
|
|
82
|
+
const at = `${where} → ${id}`;
|
|
83
|
+
ctx.changes.push(parameter.required === true
|
|
84
|
+
? breaking('OAS_PARAM_ADDED_REQUIRED', `Required parameter ${id} was added.`, at)
|
|
85
|
+
: compatible('OAS_PARAM_ADDED', `Optional parameter ${id} was added.`, at));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function diffRequestBody(from, to, where, ctx) {
|
|
89
|
+
const beforeBody = from.requestBody;
|
|
90
|
+
const afterBody = to.requestBody;
|
|
91
|
+
if (beforeBody === undefined && afterBody === undefined)
|
|
92
|
+
return;
|
|
93
|
+
if (beforeBody === undefined && afterBody !== undefined) {
|
|
94
|
+
ctx.changes.push(afterBody.required === false
|
|
95
|
+
? compatible('OAS_BODY_ADDED', 'An optional request body was added.', where)
|
|
96
|
+
: breaking('OAS_BODY_ADDED_REQUIRED', 'A required request body was added.', where));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (beforeBody !== undefined && afterBody === undefined) {
|
|
100
|
+
ctx.changes.push(compatible('OAS_BODY_REMOVED', 'The request body is no longer read.', where));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (beforeBody === undefined || afterBody === undefined)
|
|
104
|
+
return;
|
|
105
|
+
const media = new Set([...Object.keys(beforeBody.content), ...Object.keys(afterBody.content)]);
|
|
106
|
+
for (const type of [...media].sort()) {
|
|
107
|
+
const beforeMedia = beforeBody.content[type];
|
|
108
|
+
const afterMedia = afterBody.content[type];
|
|
109
|
+
const at = `${where} → body (${type})`;
|
|
110
|
+
if (beforeMedia === undefined) {
|
|
111
|
+
ctx.changes.push(compatible('OAS_BODY_MEDIA_ADDED', `Media type ${type} is now accepted.`, at));
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (afterMedia === undefined) {
|
|
115
|
+
ctx.changes.push(breaking('OAS_BODY_MEDIA_REMOVED', `Media type ${type} is no longer accepted.`, at));
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
diffSchema(beforeMedia.schema, afterMedia.schema, 'request', at, ctx, new Set());
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function diffResponses(from, to, where, ctx) {
|
|
122
|
+
const statuses = new Set([...Object.keys(from), ...Object.keys(to)]);
|
|
123
|
+
for (const status of [...statuses].sort()) {
|
|
124
|
+
const beforeResponse = from[status];
|
|
125
|
+
const afterResponse = to[status];
|
|
126
|
+
const at = `${where} → response ${status}`;
|
|
127
|
+
if (beforeResponse !== undefined && afterResponse === undefined) {
|
|
128
|
+
ctx.changes.push(breaking('OAS_STATUS_REMOVED', `Status ${status} is no longer returned.`, at));
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (beforeResponse === undefined && afterResponse !== undefined) {
|
|
132
|
+
ctx.changes.push(compatible('OAS_STATUS_ADDED', `Status ${status} was added.`, at));
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (beforeResponse === undefined || afterResponse === undefined)
|
|
136
|
+
continue;
|
|
137
|
+
const beforeContent = beforeResponse.content ?? {};
|
|
138
|
+
const afterContent = afterResponse.content ?? {};
|
|
139
|
+
const media = new Set([...Object.keys(beforeContent), ...Object.keys(afterContent)]);
|
|
140
|
+
for (const type of [...media].sort()) {
|
|
141
|
+
const beforeMedia = beforeContent[type];
|
|
142
|
+
const afterMedia = afterContent[type];
|
|
143
|
+
const mediaAt = `${at} (${type})`;
|
|
144
|
+
if (beforeMedia === undefined) {
|
|
145
|
+
ctx.changes.push(compatible('OAS_RESPONSE_MEDIA_ADDED', `Media type ${type} was added.`, mediaAt));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (afterMedia === undefined) {
|
|
149
|
+
ctx.changes.push(breaking('OAS_RESPONSE_MEDIA_REMOVED', `Media type ${type} is no longer returned.`, mediaAt));
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
diffSchema(beforeMedia.schema, afterMedia.schema, 'response', mediaAt, ctx, new Set());
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function diffSchema(rawBefore, rawAfter, direction, where, ctx, seen) {
|
|
157
|
+
const guard = `${rawBefore.$ref ?? ''}|${rawAfter.$ref ?? ''}|${where}`;
|
|
158
|
+
if (rawBefore.$ref !== undefined || rawAfter.$ref !== undefined) {
|
|
159
|
+
if (seen.has(guard))
|
|
160
|
+
return;
|
|
161
|
+
seen.add(guard);
|
|
162
|
+
}
|
|
163
|
+
const before = ctx.before.resolve(rawBefore);
|
|
164
|
+
const after = ctx.after.resolve(rawAfter);
|
|
165
|
+
diffTypes(before, after, direction, where, ctx);
|
|
166
|
+
diffEnum(before, after, direction, where, ctx);
|
|
167
|
+
if (before.format !== after.format) {
|
|
168
|
+
ctx.changes.push(breaking('OAS_FORMAT_CHANGED', `Format changed from ${before.format ?? 'none'} to ${after.format ?? 'none'}.`, where));
|
|
169
|
+
}
|
|
170
|
+
diffProperties(before, after, direction, where, ctx, seen);
|
|
171
|
+
const beforeItems = typeof before.items === 'object' ? before.items : undefined;
|
|
172
|
+
const afterItems = typeof after.items === 'object' ? after.items : undefined;
|
|
173
|
+
if (beforeItems !== undefined && afterItems !== undefined) {
|
|
174
|
+
diffSchema(beforeItems, afterItems, direction, `${where}[]`, ctx, seen);
|
|
175
|
+
}
|
|
176
|
+
if (direction === 'request' && before.additionalProperties !== false && after.additionalProperties === false) {
|
|
177
|
+
ctx.changes.push(breaking('OAS_ADDITIONAL_PROPERTIES_CLOSED', 'Extra properties are no longer accepted.', where));
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function diffProperties(before, after, direction, where, ctx, seen) {
|
|
181
|
+
const beforeProps = before.properties;
|
|
182
|
+
const afterProps = after.properties;
|
|
183
|
+
if (beforeProps === undefined && afterProps === undefined)
|
|
184
|
+
return;
|
|
185
|
+
const beforeRequired = new Set(before.required ?? []);
|
|
186
|
+
const afterRequired = new Set(after.required ?? []);
|
|
187
|
+
const names = new Set([...Object.keys(beforeProps ?? {}), ...Object.keys(afterProps ?? {})]);
|
|
188
|
+
for (const name of [...names].sort()) {
|
|
189
|
+
const from = asSchema(beforeProps?.[name]);
|
|
190
|
+
const to = asSchema(afterProps?.[name]);
|
|
191
|
+
const at = `${where}.${name}`;
|
|
192
|
+
if (from !== undefined && to === undefined) {
|
|
193
|
+
ctx.changes.push(direction === 'response'
|
|
194
|
+
? breaking('OAS_RESPONSE_FIELD_REMOVED', `Response field "${name}" was removed.`, at)
|
|
195
|
+
: breaking('OAS_REQUEST_FIELD_REMOVED', `Request field "${name}" is no longer accepted.`, at));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (from === undefined && to !== undefined) {
|
|
199
|
+
if (direction === 'response') {
|
|
200
|
+
ctx.changes.push(compatible('OAS_RESPONSE_FIELD_ADDED', `Response field "${name}" was added.`, at));
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
ctx.changes.push(afterRequired.has(name)
|
|
204
|
+
? breaking('OAS_REQUEST_FIELD_ADDED_REQUIRED', `Required request field "${name}" was added.`, at)
|
|
205
|
+
: compatible('OAS_REQUEST_FIELD_ADDED', `Optional request field "${name}" was added.`, at));
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (from === undefined || to === undefined)
|
|
210
|
+
continue;
|
|
211
|
+
const wasRequired = beforeRequired.has(name);
|
|
212
|
+
const isRequired = afterRequired.has(name);
|
|
213
|
+
if (!wasRequired && isRequired) {
|
|
214
|
+
ctx.changes.push(direction === 'request'
|
|
215
|
+
? breaking('OAS_REQUEST_FIELD_NOW_REQUIRED', `Request field "${name}" became required.`, at)
|
|
216
|
+
: compatible('OAS_RESPONSE_FIELD_NOW_GUARANTEED', `Response field "${name}" is now always present.`, at));
|
|
217
|
+
}
|
|
218
|
+
else if (wasRequired && !isRequired) {
|
|
219
|
+
ctx.changes.push(direction === 'response'
|
|
220
|
+
? breaking('OAS_RESPONSE_FIELD_NOW_OPTIONAL', `Response field "${name}" may now be absent.`, at)
|
|
221
|
+
: compatible('OAS_REQUEST_FIELD_NOW_OPTIONAL', `Request field "${name}" became optional.`, at));
|
|
222
|
+
}
|
|
223
|
+
diffSchema(from, to, direction, at, ctx, seen);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function diffTypes(before, after, direction, where, ctx) {
|
|
227
|
+
const from = typeSet(before);
|
|
228
|
+
const to = typeSet(after);
|
|
229
|
+
if (from.size === 0 && to.size === 0)
|
|
230
|
+
return;
|
|
231
|
+
const added = [...to].filter((t) => !from.has(t));
|
|
232
|
+
const removed = [...from].filter((t) => !to.has(t));
|
|
233
|
+
// Widening a response is breaking (a client that exhaustively handles the old
|
|
234
|
+
// types meets one it has never seen); widening a request is a relaxation.
|
|
235
|
+
for (const type of added) {
|
|
236
|
+
ctx.changes.push(direction === 'response'
|
|
237
|
+
? breaking('OAS_TYPE_WIDENED', `Response may now be "${type}".`, where)
|
|
238
|
+
: compatible('OAS_TYPE_WIDENED', `Request now also accepts "${type}".`, where));
|
|
239
|
+
}
|
|
240
|
+
for (const type of removed) {
|
|
241
|
+
ctx.changes.push(direction === 'request'
|
|
242
|
+
? breaking('OAS_TYPE_NARROWED', `Request no longer accepts "${type}".`, where)
|
|
243
|
+
: compatible('OAS_TYPE_NARROWED', `Response is no longer "${type}".`, where));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function diffEnum(before, after, direction, where, ctx) {
|
|
247
|
+
const from = before.enum;
|
|
248
|
+
const to = after.enum;
|
|
249
|
+
if (from === undefined && to === undefined)
|
|
250
|
+
return;
|
|
251
|
+
if (from === undefined || to === undefined) {
|
|
252
|
+
ctx.changes.push(from === undefined
|
|
253
|
+
? (direction === 'request'
|
|
254
|
+
? breaking('OAS_ENUM_INTRODUCED', 'The accepted values are now restricted to an enum.', where)
|
|
255
|
+
: compatible('OAS_ENUM_INTRODUCED', 'The returned values are now restricted to an enum.', where))
|
|
256
|
+
: (direction === 'response'
|
|
257
|
+
? breaking('OAS_ENUM_REMOVED', 'The value is no longer restricted to a known set.', where)
|
|
258
|
+
: compatible('OAS_ENUM_REMOVED', 'Any value is now accepted.', where)));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const beforeValues = new Set(from.map((v) => JSON.stringify(v)));
|
|
262
|
+
const afterValues = new Set(to.map((v) => JSON.stringify(v)));
|
|
263
|
+
for (const value of afterValues) {
|
|
264
|
+
if (beforeValues.has(value))
|
|
265
|
+
continue;
|
|
266
|
+
ctx.changes.push(direction === 'response'
|
|
267
|
+
? breaking('OAS_ENUM_VALUE_ADDED', `Response may now be ${value}.`, where)
|
|
268
|
+
: compatible('OAS_ENUM_VALUE_ADDED', `Request now also accepts ${value}.`, where));
|
|
269
|
+
}
|
|
270
|
+
for (const value of beforeValues) {
|
|
271
|
+
if (afterValues.has(value))
|
|
272
|
+
continue;
|
|
273
|
+
ctx.changes.push(direction === 'request'
|
|
274
|
+
? breaking('OAS_ENUM_VALUE_REMOVED', `Request no longer accepts ${value}.`, where)
|
|
275
|
+
: compatible('OAS_ENUM_VALUE_REMOVED', `Response is no longer ${value}.`, where));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/** `true`/`false` are legal schemas; treat them as "no constraints stated". */
|
|
279
|
+
function asSchema(node) {
|
|
280
|
+
if (node === undefined)
|
|
281
|
+
return undefined;
|
|
282
|
+
return typeof node === 'boolean' ? (node ? {} : { not: {} }) : node;
|
|
283
|
+
}
|
|
284
|
+
function typeSet(schema) {
|
|
285
|
+
const declared = schema.type;
|
|
286
|
+
if (declared === undefined)
|
|
287
|
+
return new Set();
|
|
288
|
+
return new Set(Array.isArray(declared) ? declared : [declared]);
|
|
289
|
+
}
|
|
290
|
+
/** Follows `#/components/schemas/*` so the diff compares shapes, not pointers. */
|
|
291
|
+
class Resolver {
|
|
292
|
+
#schemas;
|
|
293
|
+
constructor(document) {
|
|
294
|
+
this.#schemas = document.components?.schemas ?? {};
|
|
295
|
+
}
|
|
296
|
+
resolve(schema) {
|
|
297
|
+
let current = schema;
|
|
298
|
+
for (let hops = 0; hops < 16; hops++) {
|
|
299
|
+
const ref = current.$ref;
|
|
300
|
+
if (typeof ref !== 'string')
|
|
301
|
+
return current;
|
|
302
|
+
const name = ref.startsWith('#/components/schemas/') ? ref.slice('#/components/schemas/'.length) : null;
|
|
303
|
+
const target = name === null ? undefined : this.#schemas[name];
|
|
304
|
+
if (target === undefined)
|
|
305
|
+
return {};
|
|
306
|
+
current = target;
|
|
307
|
+
}
|
|
308
|
+
return {};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function breaking(code, message, location) {
|
|
312
|
+
return { kind: 'breaking', code, message, location };
|
|
313
|
+
}
|
|
314
|
+
function compatible(code, message, location) {
|
|
315
|
+
return { kind: 'compatible', code, message, location };
|
|
316
|
+
}
|
|
317
|
+
function documentation(code, message, location) {
|
|
318
|
+
return { kind: 'documentation', code, message, location };
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=diff.js.map
|
package/dist/diff.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { AppGraph, PathSegment, RouteRecord } from '@erenthedeveloper0/zen-core';
|
|
2
|
+
import { type DocDiagnostic } from './schema.ts';
|
|
3
|
+
import type { ExternalDocs, OpenApiDocument, SecurityRequirement, SecurityScheme, ServerObject, TagObject } from './types.ts';
|
|
4
|
+
/**
|
|
5
|
+
* `AppGraph → OpenAPIDocument` — rfcs/0001 §29.
|
|
6
|
+
*
|
|
7
|
+
* A pure function, and that is the architectural claim. Every other framework
|
|
8
|
+
* treats OpenAPI as an add-on that *re-describes* what the routes already say,
|
|
9
|
+
* which is why the documentation is always slightly wrong. Here the graph
|
|
10
|
+
* already contains every fact the document needs — paths, methods, param types,
|
|
11
|
+
* request and response schemas per status, tags, collections — so there is
|
|
12
|
+
* nothing to keep in sync because there is nothing duplicated.
|
|
13
|
+
*
|
|
14
|
+
* Nothing in this module runs per request. It is called once, from `onBoot`,
|
|
15
|
+
* against the frozen graph.
|
|
16
|
+
*/
|
|
17
|
+
export interface OpenApiOptions {
|
|
18
|
+
readonly title: string;
|
|
19
|
+
readonly version: string;
|
|
20
|
+
readonly summary?: string | undefined;
|
|
21
|
+
readonly description?: string | undefined;
|
|
22
|
+
readonly servers?: readonly ServerObject[] | undefined;
|
|
23
|
+
readonly tags?: readonly TagObject[] | undefined;
|
|
24
|
+
readonly externalDocs?: ExternalDocs | undefined;
|
|
25
|
+
readonly security?: readonly SecurityRequirement[] | undefined;
|
|
26
|
+
readonly securitySchemes?: Readonly<Record<string, SecurityScheme>> | undefined;
|
|
27
|
+
readonly license?: {
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly identifier?: string;
|
|
30
|
+
readonly url?: string;
|
|
31
|
+
} | undefined;
|
|
32
|
+
readonly contact?: {
|
|
33
|
+
readonly name?: string;
|
|
34
|
+
readonly url?: string;
|
|
35
|
+
readonly email?: string;
|
|
36
|
+
} | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Document the RFC 9457 envelope Zen actually emits on the error path, as
|
|
39
|
+
* `4XX`/`5XX` responses. On by default: the error shape is a real part of the
|
|
40
|
+
* API contract, and leaving it undocumented is how clients end up parsing it
|
|
41
|
+
* by observation.
|
|
42
|
+
*/
|
|
43
|
+
readonly problemDetails?: boolean | undefined;
|
|
44
|
+
/** Routes to leave out. The docs endpoints exclude themselves through this. */
|
|
45
|
+
readonly exclude?: ((route: RouteRecord) => boolean) | undefined;
|
|
46
|
+
}
|
|
47
|
+
export interface OpenApiResult {
|
|
48
|
+
readonly document: OpenApiDocument;
|
|
49
|
+
/**
|
|
50
|
+
* Everything the generator could not state with confidence — an undeclared
|
|
51
|
+
* response schema, an unconvertible library schema, an anonymous schema shared
|
|
52
|
+
* by four operations. Surfaced rather than silently papered over, because a
|
|
53
|
+
* document that quietly describes less than the API does is worse than one
|
|
54
|
+
* that says so.
|
|
55
|
+
*/
|
|
56
|
+
readonly diagnostics: readonly DocDiagnostic[];
|
|
57
|
+
}
|
|
58
|
+
export declare function openapiDocument(graph: AppGraph, options: OpenApiOptions): OpenApiResult;
|
|
59
|
+
export interface PathVariant {
|
|
60
|
+
readonly template: string;
|
|
61
|
+
readonly segments: readonly PathSegment[];
|
|
62
|
+
/** The optional parameter this variant adds, used to keep operationIds unique. */
|
|
63
|
+
readonly suffix: string | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* `/posts/:slug?` becomes two paths, not one path with `required: false`.
|
|
67
|
+
*
|
|
68
|
+
* OpenAPI has no optional path parameter — the spec requires `required: true`
|
|
69
|
+
* for `in: 'path'` — so the only correct representation is two concrete paths,
|
|
70
|
+
* which is also exactly what the router does at build time (`expandOptional`,
|
|
71
|
+
* §5.2). A generated client therefore gets both call shapes instead of one that
|
|
72
|
+
* cannot be expressed.
|
|
73
|
+
*/
|
|
74
|
+
export declare function pathVariants(segments: readonly PathSegment[]): PathVariant[];
|
|
75
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAAqE,WAAW,EACxF,WAAW,EACZ,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,YAAY,EAAiB,eAAe,EAC0B,mBAAmB,EACzF,cAAc,EAAE,YAAY,EAAE,SAAS,EACxC,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,GAAG,SAAS,CAAA;IACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAA;IAChD,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,mBAAmB,EAAE,GAAG,SAAS,CAAA;IAC9D,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,GAAG,SAAS,CAAA;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IAC7G,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;IACzG;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC7C,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,GAAG,SAAS,CAAA;CACjE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,aAAa,EAAE,CAAA;CAC/C;AA+BD,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,GAAG,aAAa,CAEvF;AA0hBD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;IACzC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE,CAkB5E"}
|