@voltro/plugin-openapi 0.84.0 → 0.85.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +549 -0
- package/README.md +6 -0
- package/THIRD-PARTY-NOTICES.md +71 -525
- package/dist/index.js +161 -143
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { Effect as e
|
|
2
|
-
import { definePlugin as n } from "@voltro/protocol";
|
|
1
|
+
import { Effect as e } from "effect";
|
|
2
|
+
import { definePlugin as t, jsonSchemaDocumentOf as n } from "@voltro/protocol";
|
|
3
3
|
import { pluginEnv as r } from "@voltro/env";
|
|
4
4
|
import { publicSurfaceDigest as i } from "@voltro/protocol/rest";
|
|
5
5
|
//#region src/rpc.ts
|
|
6
|
-
var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "
|
|
6
|
+
var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "Never", c = (e, t) => `${e} ${t}`, l = (e) => `Voltro rpc ${e}. This \`/rpc/<name>\` path is a documentation projection of the procedure's input/output schemas — live calls go through ${e === "query" || e === "stream" ? "the batched `POST /rpc` endpoint (first snapshot / element) or the WebSocket rpc channel (reactive/streaming)" : "the batched `POST /rpc` endpoint"}, NOT a REST request to this path. The request body below is the rpc payload.`, u = (e, t) => {
|
|
7
7
|
let { kind: n, name: r } = e, i = {
|
|
8
8
|
required: !0,
|
|
9
|
-
content: { "application/json": { schema:
|
|
9
|
+
content: { "application/json": { schema: m(e.input, t) } }
|
|
10
10
|
}, a = (() => {
|
|
11
11
|
if (n === "stream") return {
|
|
12
12
|
description: "Stream of elements. The rpc transport pushes each element as it is produced (WebSocket) or drains to the first element over `POST /rpc`. The schema below is ONE element, not the whole response.",
|
|
13
|
-
content: { "application/x-ndjson": { schema:
|
|
13
|
+
content: { "application/x-ndjson": { schema: m(e.element, t) } }
|
|
14
14
|
};
|
|
15
|
-
let r =
|
|
15
|
+
let r = m(e.output, t);
|
|
16
16
|
return {
|
|
17
17
|
description: n === "query" ? "OK — the query snapshot (the first/initial snapshot over `POST /rpc`; the WebSocket channel then pushes reactive updates)." : "OK",
|
|
18
18
|
content: { "application/json": { schema: r } }
|
|
19
19
|
};
|
|
20
20
|
})(), u = s(e.error) ? {} : { 422: {
|
|
21
21
|
description: "A typed error from the procedure — one of its declared error variants (the rpc failure channel).",
|
|
22
|
-
content: { "application/json": { schema:
|
|
22
|
+
content: { "application/json": { schema: m(e.error, t) } }
|
|
23
23
|
} };
|
|
24
24
|
return {
|
|
25
25
|
tags: [o],
|
|
@@ -33,7 +33,7 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
33
33
|
responses: {
|
|
34
34
|
200: a,
|
|
35
35
|
...u,
|
|
36
|
-
500:
|
|
36
|
+
500: y("Internal Server Error — an untyped defect.")
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
}, d = (e, t) => {
|
|
@@ -43,24 +43,29 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
43
43
|
n[e] = { post: u(r, t) };
|
|
44
44
|
}
|
|
45
45
|
return n;
|
|
46
|
-
}, f = (e) => e.replace(/:([A-Za-z0-9_]+)/g, "{$1}"), p = (e
|
|
47
|
-
let
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
}, f = (e) => e.replace(/:([A-Za-z0-9_]+)/g, "{$1}"), p = (e) => {
|
|
47
|
+
let t = e.anyOf ?? e.oneOf;
|
|
48
|
+
if (!Array.isArray(t)) return e;
|
|
49
|
+
let n = t.filter((e) => e.type !== "null");
|
|
50
|
+
return n.length === 1 && n.length < t.length ? n[0] : e;
|
|
51
|
+
}, m = (e, t) => {
|
|
52
|
+
let r = n(e, { closed: !1 });
|
|
53
|
+
for (let [e, n] of Object.entries(r.definitions)) t[e] = n;
|
|
54
|
+
return r.schema;
|
|
55
|
+
}, h = (e) => {
|
|
56
|
+
if (Array.isArray(e)) return e.map(h);
|
|
52
57
|
if (e && typeof e == "object") {
|
|
53
58
|
let t = {};
|
|
54
|
-
for (let [n, r] of Object.entries(e)) t[n] = n === "$ref" && typeof r == "string" && r.startsWith("#/$defs/") ? `#/components/schemas/${r.slice(8)}` :
|
|
59
|
+
for (let [n, r] of Object.entries(e)) t[n] = n === "$ref" && typeof r == "string" && r.startsWith("#/$defs/") ? `#/components/schemas/${r.slice(8)}` : h(r);
|
|
55
60
|
return t;
|
|
56
61
|
}
|
|
57
62
|
return e;
|
|
58
|
-
},
|
|
63
|
+
}, g = (e, t) => {
|
|
59
64
|
if (!e) return {
|
|
60
65
|
parameters: [],
|
|
61
66
|
requestBody: void 0
|
|
62
67
|
};
|
|
63
|
-
let n =
|
|
68
|
+
let n = m(e, t), r = n.properties ?? {}, i = new Set(n.required ?? []), a = [];
|
|
64
69
|
for (let [e, t] of [["query", "query"], ["params", "path"]]) {
|
|
65
70
|
let n = r[e];
|
|
66
71
|
if (!n || typeof n != "object") continue;
|
|
@@ -80,7 +85,7 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
80
85
|
content: { "application/json": { schema: o } }
|
|
81
86
|
} : void 0
|
|
82
87
|
};
|
|
83
|
-
},
|
|
88
|
+
}, _ = "VoltroHttpError", v = {
|
|
84
89
|
type: "object",
|
|
85
90
|
description: "The serve pipeline's error envelope.",
|
|
86
91
|
properties: {
|
|
@@ -98,10 +103,10 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
98
103
|
}
|
|
99
104
|
},
|
|
100
105
|
required: ["error"]
|
|
101
|
-
},
|
|
106
|
+
}, y = (e) => ({
|
|
102
107
|
description: e,
|
|
103
|
-
content: { "application/json": { schema: { $ref: `#/components/schemas/${
|
|
104
|
-
}),
|
|
108
|
+
content: { "application/json": { schema: { $ref: `#/components/schemas/${_}` } } }
|
|
109
|
+
}), b = "ProblemDetails", x = {
|
|
105
110
|
type: "object",
|
|
106
111
|
description: "RFC 9457 Problem Details. Extension members carry the error's own fields.",
|
|
107
112
|
properties: {
|
|
@@ -120,22 +125,22 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
120
125
|
"status"
|
|
121
126
|
],
|
|
122
127
|
additionalProperties: !0
|
|
123
|
-
},
|
|
128
|
+
}, S = (e, t, n = 0) => {
|
|
124
129
|
if (n > 6) return null;
|
|
125
130
|
let r = e.$ref;
|
|
126
131
|
if (typeof r == "string") {
|
|
127
132
|
let e = t[r.split("/").pop() ?? ""];
|
|
128
|
-
return e !== void 0 && typeof e == "object" ?
|
|
133
|
+
return e !== void 0 && typeof e == "object" ? S(e, t, n + 1) : null;
|
|
129
134
|
}
|
|
130
135
|
if (e.example !== void 0) return e.example;
|
|
131
136
|
if (Array.isArray(e.examples) && e.examples.length > 0) return e.examples[0];
|
|
132
137
|
if (e.const !== void 0) return e.const;
|
|
133
138
|
if (Array.isArray(e.enum) && e.enum.length > 0) return e.enum[0];
|
|
134
139
|
let i = e.anyOf ?? e.oneOf;
|
|
135
|
-
if (Array.isArray(i) && i.length > 0) return
|
|
140
|
+
if (Array.isArray(i) && i.length > 0) return S(i.find((e) => e.type !== "null") ?? i[0], t, n + 1);
|
|
136
141
|
let a = e.allOf;
|
|
137
142
|
if (Array.isArray(a) && a.length > 0) {
|
|
138
|
-
let e = a.map((e) =>
|
|
143
|
+
let e = a.map((e) => S(e, t, n + 1));
|
|
139
144
|
return e.every((e) => typeof e == "object" && !!e && !Array.isArray(e)) ? Object.assign({}, ...e) : e[0];
|
|
140
145
|
}
|
|
141
146
|
let o = e.type;
|
|
@@ -156,19 +161,19 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
156
161
|
case "null": return null;
|
|
157
162
|
case "array": {
|
|
158
163
|
let r = e.items;
|
|
159
|
-
return r !== void 0 && typeof r == "object" && !Array.isArray(r) ? [
|
|
164
|
+
return r !== void 0 && typeof r == "object" && !Array.isArray(r) ? [S(r, t, n + 1)] : [];
|
|
160
165
|
}
|
|
161
166
|
case "object": {
|
|
162
167
|
let r = e.properties ?? {}, i = {};
|
|
163
|
-
for (let [e, a] of Object.entries(r)) i[e] =
|
|
168
|
+
for (let [e, a] of Object.entries(r)) i[e] = S(a, t, n + 1);
|
|
164
169
|
return i;
|
|
165
170
|
}
|
|
166
|
-
default: return typeof e.properties == "object" ?
|
|
171
|
+
default: return typeof e.properties == "object" ? S({
|
|
167
172
|
...e,
|
|
168
173
|
type: "object"
|
|
169
174
|
}, t, n) : null;
|
|
170
175
|
}
|
|
171
|
-
},
|
|
176
|
+
}, C = {
|
|
172
177
|
400: {
|
|
173
178
|
tag: "InvalidRequest",
|
|
174
179
|
detail: "Invalid request"
|
|
@@ -189,7 +194,7 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
189
194
|
tag: "InternalServerError",
|
|
190
195
|
detail: "Internal Server Error"
|
|
191
196
|
}
|
|
192
|
-
},
|
|
197
|
+
}, w = {
|
|
193
198
|
400: "Bad Request",
|
|
194
199
|
401: "Unauthorized",
|
|
195
200
|
403: "Forbidden",
|
|
@@ -199,10 +204,10 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
199
204
|
422: "Unprocessable Content",
|
|
200
205
|
429: "Too Many Requests",
|
|
201
206
|
500: "Internal Server Error"
|
|
202
|
-
},
|
|
207
|
+
}, T = (e, t, n) => {
|
|
203
208
|
let r = t.format.errors === "problem-details" && t.format.encodeError === void 0, i = r ? "application/problem+json" : "application/json", a = /* @__PURE__ */ new Map();
|
|
204
209
|
for (let e of t.errorResponses) {
|
|
205
|
-
let t = a.get(e.status) ?? [], i =
|
|
210
|
+
let t = a.get(e.status) ?? [], i = m(e.schema, n), o = S(i, n), { _tag: s, ...c } = typeof o == "object" && o ? o : {}, l = r ? {
|
|
206
211
|
type: `urn:voltro:error:${e.tag}`,
|
|
207
212
|
title: e.tag.replace(/([a-z0-9])([A-Z])/g, "$1 $2"),
|
|
208
213
|
status: e.status,
|
|
@@ -214,15 +219,15 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
214
219
|
t.push({
|
|
215
220
|
tag: e.tag,
|
|
216
221
|
example: l,
|
|
217
|
-
schema: r ? { allOf: [{ $ref: `#/components/schemas/${
|
|
222
|
+
schema: r ? { allOf: [{ $ref: `#/components/schemas/${b}` }, {
|
|
218
223
|
type: "object",
|
|
219
224
|
properties: { type: { const: `urn:voltro:error:${e.tag}` } }
|
|
220
225
|
}] } : i
|
|
221
226
|
}), a.set(e.status, t);
|
|
222
227
|
}
|
|
223
228
|
let o = (e, t) => {
|
|
224
|
-
if (!r) return
|
|
225
|
-
let n =
|
|
229
|
+
if (!r) return y(t);
|
|
230
|
+
let n = C[e], a = n === void 0 ? {} : { example: {
|
|
226
231
|
type: `urn:voltro:error:${n.tag}`,
|
|
227
232
|
title: n.tag.replace(/([a-z])([A-Z])/g, "$1 $2"),
|
|
228
233
|
status: e,
|
|
@@ -231,7 +236,7 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
231
236
|
return {
|
|
232
237
|
description: t,
|
|
233
238
|
content: { [i]: {
|
|
234
|
-
schema: { $ref: `#/components/schemas/${
|
|
239
|
+
schema: { $ref: `#/components/schemas/${b}` },
|
|
235
240
|
...a
|
|
236
241
|
} }
|
|
237
242
|
};
|
|
@@ -240,7 +245,7 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
240
245
|
for (let [e, t] of [...a.entries()].sort((e, t) => e[0] - t[0])) {
|
|
241
246
|
let n = t.map((e) => e.tag);
|
|
242
247
|
s[String(e)] = {
|
|
243
|
-
description: `${
|
|
248
|
+
description: `${w[e] ?? "Error"} — ${n.join(" | ")}`,
|
|
244
249
|
content: { [i]: {
|
|
245
250
|
schema: t.length === 1 ? t[0].schema : { oneOf: t.map((e) => e.schema) },
|
|
246
251
|
example: t[0].example
|
|
@@ -248,21 +253,24 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
248
253
|
};
|
|
249
254
|
}
|
|
250
255
|
return e.sunset !== void 0 && (s[410] = o(410, `Gone — the route is past its sunset date (${e.sunset}).`)), s[500] = o(500, "Internal Server Error."), s;
|
|
251
|
-
},
|
|
252
|
-
let r =
|
|
253
|
-
for (let [t, n] of Object.entries(i))
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
256
|
+
}, E = (e, t, n) => {
|
|
257
|
+
let r = m(t.input, n), i = r.properties ?? {}, a = new Set(r.required ?? []), o = new Set(t.pathParams), s = [], c = {}, l = [], u = e.example?.request, d = (e) => typeof u == "object" && u && e in u ? { example: u[e] } : {};
|
|
258
|
+
for (let [t, n] of Object.entries(i)) {
|
|
259
|
+
let r = a.has(t) ? n : p(n);
|
|
260
|
+
o.has(t) ? s.push({
|
|
261
|
+
name: t,
|
|
262
|
+
in: "path",
|
|
263
|
+
required: !0,
|
|
264
|
+
schema: r,
|
|
265
|
+
...d(t)
|
|
266
|
+
}) : e.method === "GET" ? s.push({
|
|
267
|
+
name: t,
|
|
268
|
+
in: "query",
|
|
269
|
+
required: a.has(t),
|
|
270
|
+
schema: r,
|
|
271
|
+
...d(t)
|
|
272
|
+
}) : (c[t] = r, a.has(t) && l.push(t));
|
|
273
|
+
}
|
|
266
274
|
return {
|
|
267
275
|
parameters: s,
|
|
268
276
|
requestBody: e.method !== "GET" && Object.keys(c).length > 0 ? {
|
|
@@ -281,12 +289,12 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
281
289
|
}
|
|
282
290
|
} : void 0
|
|
283
291
|
};
|
|
284
|
-
},
|
|
292
|
+
}, D = (e, t, n) => {
|
|
285
293
|
if (e.streaming === !0) return {
|
|
286
294
|
description: "Server-Sent Events stream (`snapshot`, then `delta` per change)",
|
|
287
295
|
content: { "text/event-stream": { schema: { type: "string" } } }
|
|
288
296
|
};
|
|
289
|
-
let r =
|
|
297
|
+
let r = m(t.output, n), i = t.format, a = i.pagination === "link-header" && O(r, n, i.cursorField), o = i.encodeSuccess === void 0 ? i.envelope === "data" ? {
|
|
290
298
|
type: "object",
|
|
291
299
|
properties: {
|
|
292
300
|
data: r,
|
|
@@ -337,28 +345,28 @@ var a = "/rpc", o = "rpc", s = (e) => e.ast._tag === "NeverKeyword", c = (e, t)
|
|
|
337
345
|
...Object.keys(c).length > 0 ? { headers: c } : {},
|
|
338
346
|
content: { [s]: {
|
|
339
347
|
schema: o,
|
|
340
|
-
...
|
|
348
|
+
...k(e.example?.response, o, n)
|
|
341
349
|
} }
|
|
342
350
|
};
|
|
343
|
-
},
|
|
351
|
+
}, O = (e, t, n) => {
|
|
344
352
|
let r = e.$ref, i = (typeof r == "string" ? t[r.split("/").pop() ?? ""] : e)?.properties;
|
|
345
353
|
return typeof i == "object" && !!i && n in i;
|
|
346
|
-
},
|
|
347
|
-
example:
|
|
354
|
+
}, k = (e, t, n) => e === void 0 ? {
|
|
355
|
+
example: S(t, n),
|
|
348
356
|
"x-voltro-example": "derived"
|
|
349
|
-
} : { example: e },
|
|
350
|
-
...e.input === void 0 ? {} : { 400:
|
|
357
|
+
} : { example: e }, A = (e) => ({
|
|
358
|
+
...e.input === void 0 ? {} : { 400: y("Invalid request — the input failed schema decode.") },
|
|
351
359
|
...e.guards !== void 0 && e.guards.length > 0 ? {
|
|
352
|
-
401:
|
|
353
|
-
403:
|
|
360
|
+
401: y("Unauthorized — a guard rejected the unauthenticated request."),
|
|
361
|
+
403: y("Forbidden — a guard rejected the request (e.g. a required scope is missing).")
|
|
354
362
|
} : {},
|
|
355
|
-
...e.sunset === void 0 ? {} : { 410:
|
|
356
|
-
500:
|
|
363
|
+
...e.sunset === void 0 ? {} : { 410: y(`Gone — the route is past its sunset date (${e.sunset}).`) },
|
|
364
|
+
500: y("Internal Server Error.")
|
|
357
365
|
});
|
|
358
|
-
function
|
|
366
|
+
function j(e, t = {}, n = {}, r = {}) {
|
|
359
367
|
let a = {}, o = {}, s = e.some((e) => e.guards !== void 0 && e.guards.length > 0), c = e.some((e) => e.projection !== void 0 && e.projection.security !== "none"), l = e.some((e) => e.projection?.format.errors === "problem-details" && e.projection.format.encodeError === void 0), u = /* @__PURE__ */ new Set();
|
|
360
368
|
for (let t of e) {
|
|
361
|
-
let e = t.projection, { parameters: n, requestBody: r } = e === void 0 ?
|
|
369
|
+
let e = t.projection, { parameters: n, requestBody: r } = e === void 0 ? g(t.input, o) : E(t, e, o), i = t.etag === !0 && t.method === "GET" && t.streaming !== !0, s = i ? [...n, {
|
|
362
370
|
name: "If-None-Match",
|
|
363
371
|
in: "header",
|
|
364
372
|
required: !1,
|
|
@@ -375,19 +383,19 @@ function A(e, t = {}, n = {}, r = {}) {
|
|
|
375
383
|
let e = r.content;
|
|
376
384
|
e["application/json"] = {
|
|
377
385
|
...e["application/json"],
|
|
378
|
-
...
|
|
386
|
+
...k(t.example?.request, e["application/json"].schema, o)
|
|
379
387
|
};
|
|
380
388
|
}
|
|
381
|
-
let d = e === void 0 ? l ? { security: [{ bearerAuth: [] }] } : {} : e.security === "required" ? { security: [{ bearerAuth: [] }] } : e.security === "optional" ? { security: [{ bearerAuth: [] }, {}] } : {},
|
|
382
|
-
for (let e of
|
|
383
|
-
let
|
|
389
|
+
let d = e === void 0 ? l ? { security: [{ bearerAuth: [] }] } : {} : e.security === "required" ? { security: [{ bearerAuth: [] }] } : e.security === "optional" ? { security: [{ bearerAuth: [] }, {}] } : {}, p = t.tags ?? (t.version === void 0 ? void 0 : [t.version]);
|
|
390
|
+
for (let e of p ?? []) u.add(e);
|
|
391
|
+
let h = e?.version ?? t.version, _ = {
|
|
384
392
|
...t.operationId === void 0 ? {} : { operationId: t.operationId },
|
|
385
393
|
...t.summary ? { summary: t.summary } : {},
|
|
386
394
|
...t.description ? { description: t.description } : {},
|
|
387
395
|
...t.deprecated === void 0 ? {} : { deprecated: !0 },
|
|
388
396
|
...t.sunset === void 0 ? {} : { "x-sunset": t.sunset },
|
|
389
|
-
...
|
|
390
|
-
...
|
|
397
|
+
...p === void 0 ? {} : { tags: p },
|
|
398
|
+
...h === void 0 ? {} : { "x-voltro-api-version": h },
|
|
391
399
|
...s.length > 0 ? { parameters: s } : {},
|
|
392
400
|
...r ? { requestBody: r } : {},
|
|
393
401
|
...d,
|
|
@@ -398,16 +406,16 @@ function A(e, t = {}, n = {}, r = {}) {
|
|
|
398
406
|
} : {
|
|
399
407
|
description: "OK",
|
|
400
408
|
content: { "application/json": {
|
|
401
|
-
schema:
|
|
402
|
-
...
|
|
409
|
+
schema: m(t.output, o),
|
|
410
|
+
...k(t.example?.response, m(t.output, o), o)
|
|
403
411
|
} }
|
|
404
412
|
},
|
|
405
|
-
...
|
|
413
|
+
...A(t),
|
|
406
414
|
...c
|
|
407
415
|
} : {
|
|
408
|
-
200:
|
|
416
|
+
200: D(t, e, o),
|
|
409
417
|
...c,
|
|
410
|
-
...
|
|
418
|
+
...T(t, e, o)
|
|
411
419
|
}
|
|
412
420
|
};
|
|
413
421
|
e?.format.describe !== void 0 && (_ = e.format.describe(_, {
|
|
@@ -418,15 +426,15 @@ function A(e, t = {}, n = {}, r = {}) {
|
|
|
418
426
|
let v = f(t.path), y = a[v] ?? {};
|
|
419
427
|
y[t.method.toLowerCase()] = _, a[v] = y;
|
|
420
428
|
}
|
|
421
|
-
let
|
|
422
|
-
if (
|
|
423
|
-
let e = d(
|
|
429
|
+
let p = n.procedures ?? [];
|
|
430
|
+
if (p.length > 0) {
|
|
431
|
+
let e = d(p, o);
|
|
424
432
|
for (let [t, n] of Object.entries(e)) a[t] = {
|
|
425
433
|
...n,
|
|
426
434
|
...a[t] ?? {}
|
|
427
435
|
};
|
|
428
436
|
}
|
|
429
|
-
let
|
|
437
|
+
let y = [...u].sort().map((e) => ({
|
|
430
438
|
name: e,
|
|
431
439
|
...r.tagDescriptions?.[e] === void 0 ? {} : { description: r.tagDescriptions[e] },
|
|
432
440
|
...r.tagExternalDocs?.[e] === void 0 ? {} : { externalDocs: r.tagExternalDocs[e] }
|
|
@@ -450,13 +458,13 @@ function A(e, t = {}, n = {}, r = {}) {
|
|
|
450
458
|
...r.externalDocs === void 0 ? {} : { externalDocs: r.externalDocs },
|
|
451
459
|
...r.environment === void 0 ? {} : { "x-voltro-environment": r.environment },
|
|
452
460
|
...e.some((e) => e.projection !== void 0) ? { "x-voltro-surface-digest": i(e) } : {},
|
|
453
|
-
...
|
|
454
|
-
paths:
|
|
461
|
+
...y.length > 0 ? { tags: y } : {},
|
|
462
|
+
paths: h(a),
|
|
455
463
|
components: {
|
|
456
464
|
schemas: {
|
|
457
|
-
...
|
|
458
|
-
[
|
|
459
|
-
...l ? { [
|
|
465
|
+
...h(o),
|
|
466
|
+
[_]: v,
|
|
467
|
+
...l ? { [b]: x } : {}
|
|
460
468
|
},
|
|
461
469
|
...s || c ? { securitySchemes: { bearerAuth: {
|
|
462
470
|
type: "http",
|
|
@@ -467,23 +475,23 @@ function A(e, t = {}, n = {}, r = {}) {
|
|
|
467
475
|
}
|
|
468
476
|
//#endregion
|
|
469
477
|
//#region src/swaggerUi.ts
|
|
470
|
-
var
|
|
478
|
+
var M = "5.17.14", N = "sha384-wxLW6kwyHktdDGr6Pv1zgm/VGJh99lfUbzSn6HNHBENZlCN7W602k9VkGdxuFvPn", P = "sha384-wmyclcVGX/WhUkdkATwhaK1X1JtiNrr2EoYJ+diV3vj4v6OC5yCeSu+yW13SYJep", F = `https://unpkg.com/swagger-ui-dist@${M}/swagger-ui.css`, I = `https://unpkg.com/swagger-ui-dist@${M}/swagger-ui-bundle.js`, L = (e, t = "API docs", n = {}) => `<!doctype html>
|
|
471
479
|
<html lang="en">
|
|
472
480
|
<head>
|
|
473
481
|
<meta charset="utf-8" />
|
|
474
482
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
475
483
|
<title>${t}</title>
|
|
476
|
-
<link rel="stylesheet" href="${
|
|
484
|
+
<link rel="stylesheet" href="${F}" integrity="${N}" crossorigin="anonymous" />
|
|
477
485
|
<style>body { margin: 0 }</style>
|
|
478
486
|
</head>
|
|
479
487
|
<body>
|
|
480
488
|
<div id="swagger-ui"></div>
|
|
481
|
-
<script src="${
|
|
489
|
+
<script src="${I}" integrity="${P}" crossorigin="anonymous"><\/script>
|
|
482
490
|
<script>
|
|
483
491
|
window.ui = SwaggerUIBundle({ ${n.urls !== void 0 && n.urls.length > 0 ? `urls: ${JSON.stringify(n.urls)}, ${n.primaryName === void 0 ? "" : `'urls.primaryName': ${JSON.stringify(n.primaryName)}, `}` : `url: ${JSON.stringify(e)}, `}dom_id: '#swagger-ui', deepLinking: true });
|
|
484
492
|
<\/script>
|
|
485
493
|
</body>
|
|
486
|
-
</html>`,
|
|
494
|
+
</html>`, R = r([
|
|
487
495
|
{
|
|
488
496
|
name: "OPENAPI_DOCS_TOKEN",
|
|
489
497
|
required: !1,
|
|
@@ -502,107 +510,117 @@ var j = "5.17.14", M = "sha384-wxLW6kwyHktdDGr6Pv1zgm/VGJh99lfUbzSn6HNHBENZlCN7W
|
|
|
502
510
|
secret: !1,
|
|
503
511
|
description: "The environment this instance serves (dev | staging | production) — x-voltro-environment on the spec."
|
|
504
512
|
}
|
|
505
|
-
]),
|
|
513
|
+
]), z = (e, t) => {
|
|
506
514
|
if (e) return (t.headers.authorization ?? t.headers.Authorization) === `Bearer ${e}` ? void 0 : {
|
|
507
515
|
status: 401,
|
|
508
516
|
body: "unauthorized",
|
|
509
517
|
contentType: "text/plain"
|
|
510
518
|
};
|
|
511
|
-
},
|
|
519
|
+
}, B = (e) => e.projection?.version ?? e.version, V = (e) => {
|
|
512
520
|
let t = /^v(\d+)$/.exec(e);
|
|
513
521
|
return t === null ? -1 : Number(t[1]);
|
|
514
|
-
},
|
|
515
|
-
let n
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
522
|
+
}, H = (e) => [...new Set(e.map(B).filter((e) => e !== void 0))].sort((e, t) => V(t) - V(e) || t.localeCompare(e)), U = (e, t) => {
|
|
523
|
+
let n;
|
|
524
|
+
for (let r of t) {
|
|
525
|
+
if (B(r) !== e) continue;
|
|
526
|
+
let t = r.sunset;
|
|
527
|
+
t !== void 0 && (n === void 0 || t < n) && (n = t);
|
|
528
|
+
}
|
|
529
|
+
return n === void 0 ? e : `${e} — sunset ${n}`;
|
|
530
|
+
}, W = (n) => {
|
|
531
|
+
let r = n.specPath ?? "/openapi.json", i = n.docsPath ?? "/docs", a = R.read("OPENAPI_DOCS_TOKEN", n.token), o = n.name ? `@voltro/plugin-openapi#${n.name}` : "@voltro/plugin-openapi", s = n.routes ?? [], c = n.procedures ?? [], l = c, u = n.includeAppRoutes ?? !0, d = n.includeAppProcedures ?? !1, f = s, p = n.environment ?? R.read("VOLTRO_ENVIRONMENT", void 0) ?? (process.env.NODE_ENV === "production" ? "production" : "dev"), m = R.read("VOLTRO_PUBLIC_API_ORIGIN", void 0), h = n.servers ?? (m === void 0 ? [] : [{
|
|
519
532
|
url: m,
|
|
520
533
|
description: `${p} — this instance`,
|
|
521
534
|
environment: p
|
|
522
535
|
}]), g = {
|
|
523
|
-
...
|
|
524
|
-
...
|
|
525
|
-
...
|
|
536
|
+
...n.tagDescriptions === void 0 ? {} : { tagDescriptions: n.tagDescriptions },
|
|
537
|
+
...n.tagExternalDocs === void 0 ? {} : { tagExternalDocs: n.tagExternalDocs },
|
|
538
|
+
...n.externalDocs === void 0 ? {} : { externalDocs: n.externalDocs },
|
|
526
539
|
...h.length > 0 ? { servers: h } : {},
|
|
527
540
|
environment: p
|
|
528
|
-
}, _ = (e) => JSON.stringify(
|
|
529
|
-
|
|
541
|
+
}, _ = (e, t, r) => JSON.stringify(j(e, n.info ?? {}, t ? { procedures: r } : {}, g), null, 2), v = r.endsWith(".json") ? r.slice(0, -5) : `${r}/versions`, y = (e) => `${v}/${e}.json`, b = /* @__PURE__ */ new Map(), x = [], S = "", C = (e = f, t = l) => {
|
|
542
|
+
let a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
543
|
+
for (let t of e) {
|
|
544
|
+
let e = B(t);
|
|
545
|
+
if (e === void 0) continue;
|
|
546
|
+
let n = a.get(e);
|
|
547
|
+
n === void 0 && (n = [], a.set(e, n)), n.push(t);
|
|
548
|
+
let r = t.sunset, i = o.get(e);
|
|
549
|
+
r !== void 0 && (i === void 0 || r < i) && o.set(e, r);
|
|
550
|
+
}
|
|
551
|
+
let s = [...a.keys()].sort((e, t) => V(t) - V(e) || t.localeCompare(e)), c = new Map([["", _(e, !0, t)], ...s.map((e) => [e, _(a.get(e), !1, t)])]), u = s.length > 1 ? [...s.map((e) => ({
|
|
552
|
+
url: y(e),
|
|
553
|
+
name: o.has(e) ? `${e} — sunset ${o.get(e)}` : e
|
|
554
|
+
})), {
|
|
555
|
+
url: r,
|
|
556
|
+
name: "all versions"
|
|
557
|
+
}] : void 0, d = i === !1 ? "" : L(r, n.info?.title ?? "API docs", u === void 0 ? {} : {
|
|
558
|
+
urls: u,
|
|
559
|
+
primaryName: u[0].name
|
|
560
|
+
});
|
|
561
|
+
b = c, x = s, S = d, f = e, l = t;
|
|
530
562
|
};
|
|
531
|
-
|
|
532
|
-
let
|
|
563
|
+
C();
|
|
564
|
+
let w = (e) => {
|
|
533
565
|
if (!u) return;
|
|
534
566
|
let t = new Set(s.map((e) => `${e.method} ${e.path}`)), n = e.filter((e) => !t.has(`${e.method} ${e.path}`));
|
|
535
|
-
|
|
536
|
-
},
|
|
567
|
+
C([...s, ...n]);
|
|
568
|
+
}, T = (e) => {
|
|
537
569
|
if (!d) return;
|
|
538
570
|
let t = new Set(c.map((e) => e.name));
|
|
539
|
-
|
|
540
|
-
},
|
|
571
|
+
C(f, [...c, ...e.filter((e) => !t.has(e.name))]);
|
|
572
|
+
}, E = (e) => ({
|
|
541
573
|
status: 404,
|
|
542
574
|
contentType: "application/json",
|
|
543
575
|
body: JSON.stringify({
|
|
544
576
|
error: `no API version '${e}' is mounted`,
|
|
545
|
-
versions:
|
|
577
|
+
versions: x
|
|
546
578
|
})
|
|
547
|
-
}),
|
|
579
|
+
}), D = [{
|
|
548
580
|
method: "GET",
|
|
549
581
|
path: r,
|
|
550
582
|
match: "exact",
|
|
551
583
|
handle: async (e) => {
|
|
552
|
-
let t =
|
|
584
|
+
let t = z(a, e);
|
|
553
585
|
if (t) return t;
|
|
554
586
|
let n = new URLSearchParams(e.query).get("version") ?? void 0;
|
|
555
|
-
return n !== void 0 && !
|
|
587
|
+
return n !== void 0 && !b.has(n) ? E(n) : {
|
|
556
588
|
status: 200,
|
|
557
|
-
body:
|
|
589
|
+
body: b.get(n ?? ""),
|
|
558
590
|
contentType: "application/json"
|
|
559
591
|
};
|
|
560
592
|
}
|
|
561
593
|
}, {
|
|
562
594
|
method: "GET",
|
|
563
|
-
path:
|
|
595
|
+
path: v,
|
|
564
596
|
handle: async (e) => {
|
|
565
|
-
let t =
|
|
597
|
+
let t = z(a, e);
|
|
566
598
|
if (t) return t;
|
|
567
599
|
let n = /\/([^/]+)\.json$/.exec(e.path)?.[1];
|
|
568
|
-
return n === void 0 || n === "" || !
|
|
600
|
+
return n === void 0 || n === "" || !b.has(n) ? E(n ?? "") : {
|
|
569
601
|
status: 200,
|
|
570
|
-
body:
|
|
602
|
+
body: b.get(n),
|
|
571
603
|
contentType: "application/json"
|
|
572
604
|
};
|
|
573
605
|
}
|
|
574
606
|
}];
|
|
575
|
-
return i !== !1 &&
|
|
607
|
+
return i !== !1 && D.push({
|
|
576
608
|
method: "GET",
|
|
577
609
|
path: i,
|
|
578
610
|
match: "exact",
|
|
579
|
-
handle: async (e) => {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
url: C(e),
|
|
584
|
-
name: H(e, f)
|
|
585
|
-
})), {
|
|
586
|
-
url: r,
|
|
587
|
-
name: "all versions"
|
|
588
|
-
}] : void 0;
|
|
589
|
-
return {
|
|
590
|
-
status: 200,
|
|
591
|
-
body: I(r, t.info?.title ?? "API docs", o === void 0 ? {} : {
|
|
592
|
-
urls: o,
|
|
593
|
-
primaryName: o[0].name
|
|
594
|
-
}),
|
|
595
|
-
contentType: "text/html; charset=utf-8"
|
|
596
|
-
};
|
|
611
|
+
handle: async (e) => z(a, e) || {
|
|
612
|
+
status: 200,
|
|
613
|
+
body: S,
|
|
614
|
+
contentType: "text/html; charset=utf-8"
|
|
597
615
|
}
|
|
598
|
-
}),
|
|
616
|
+
}), t({
|
|
599
617
|
name: o,
|
|
600
618
|
description: "OpenAPI 3.1 spec + Swagger-UI docs from defineRestRoute descriptors + rpc procedures.",
|
|
601
619
|
permissions: [],
|
|
602
|
-
declaredEnv:
|
|
603
|
-
httpRoutes:
|
|
604
|
-
onRestSurface:
|
|
605
|
-
onProcedureSurface:
|
|
620
|
+
declaredEnv: R.declared,
|
|
621
|
+
httpRoutes: D,
|
|
622
|
+
onRestSurface: w,
|
|
623
|
+
onProcedureSurface: T,
|
|
606
624
|
onActivate: (t) => e.sync(() => {
|
|
607
625
|
t.logger.info("openapi docs active", {
|
|
608
626
|
specPath: r,
|
|
@@ -613,11 +631,11 @@ var j = "5.17.14", M = "sha384-wxLW6kwyHktdDGr6Pv1zgm/VGJh99lfUbzSn6HNHBENZlCN7W
|
|
|
613
631
|
appProcedures: d ? "included once discovered" : "excluded",
|
|
614
632
|
environment: p,
|
|
615
633
|
servers: h.map((e) => e.url),
|
|
616
|
-
versions:
|
|
634
|
+
versions: H(f),
|
|
617
635
|
tokenGated: !!a
|
|
618
636
|
});
|
|
619
637
|
})
|
|
620
638
|
});
|
|
621
639
|
};
|
|
622
640
|
//#endregion
|
|
623
|
-
export {
|
|
641
|
+
export { b as PROBLEM_DETAILS_SCHEMA_NAME, S as deriveExample, j as generateOpenApiSpec, H as mountedVersions, W as openapiPlugin, L as swaggerUiHtml, U as versionLabel };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-openapi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"description": "Generate an OpenAPI 3.1 spec from defineRestRoute descriptors and serve it + a Swagger-UI docs page. Zero hand-maintained API docs — the REST descriptors ARE the source of truth.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/env": "0.
|
|
37
|
-
"@voltro/protocol": "0.
|
|
36
|
+
"@voltro/env": "0.85.0",
|
|
37
|
+
"@voltro/protocol": "0.85.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"effect": "
|
|
40
|
+
"effect": "4.0.1"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|