@voltro/plugin-openapi 0.85.0 → 0.87.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/dist/index.js CHANGED
@@ -1,497 +1,10 @@
1
- import { Effect as e } from "effect";
2
- import { definePlugin as t, jsonSchemaDocumentOf as n } from "@voltro/protocol";
3
- import { pluginEnv as r } from "@voltro/env";
4
- import { publicSurfaceDigest as i } from "@voltro/protocol/rest";
5
- //#region src/rpc.ts
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
- let { kind: n, name: r } = e, i = {
8
- required: !0,
9
- content: { "application/json": { schema: m(e.input, t) } }
10
- }, a = (() => {
11
- if (n === "stream") return {
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: m(e.element, t) } }
14
- };
15
- let r = m(e.output, t);
16
- return {
17
- description: n === "query" ? "OK — the query snapshot (the first/initial snapshot over `POST /rpc`; the WebSocket channel then pushes reactive updates)." : "OK",
18
- content: { "application/json": { schema: r } }
19
- };
20
- })(), u = s(e.error) ? {} : { 422: {
21
- description: "A typed error from the procedure — one of its declared error variants (the rpc failure channel).",
22
- content: { "application/json": { schema: m(e.error, t) } }
23
- } };
24
- return {
25
- tags: [o],
26
- summary: c(n, r),
27
- description: l(n),
28
- "x-voltro-rpc": {
29
- kind: n,
30
- procedure: r
31
- },
32
- requestBody: i,
33
- responses: {
34
- 200: a,
35
- ...u,
36
- 500: y("Internal Server Error — an untyped defect.")
37
- }
38
- };
39
- }, d = (e, t) => {
40
- let n = {};
41
- for (let r of e) {
42
- let e = `${a}/${r.name}`;
43
- n[e] = { post: u(r, t) };
44
- }
45
- return n;
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);
57
- if (e && typeof e == "object") {
58
- let t = {};
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);
60
- return t;
61
- }
62
- return e;
63
- }, g = (e, t) => {
64
- if (!e) return {
65
- parameters: [],
66
- requestBody: void 0
67
- };
68
- let n = m(e, t), r = n.properties ?? {}, i = new Set(n.required ?? []), a = [];
69
- for (let [e, t] of [["query", "query"], ["params", "path"]]) {
70
- let n = r[e];
71
- if (!n || typeof n != "object") continue;
72
- let i = n.properties ?? {}, o = new Set(n.required ?? []);
73
- for (let [e, n] of Object.entries(i)) a.push({
74
- name: e,
75
- in: t,
76
- required: t === "path" || o.has(e),
77
- schema: n
78
- });
79
- }
80
- let o = r.body;
81
- return {
82
- parameters: a,
83
- requestBody: o && typeof o == "object" ? {
84
- required: i.has("body"),
85
- content: { "application/json": { schema: o } }
86
- } : void 0
87
- };
88
- }, _ = "VoltroHttpError", v = {
89
- type: "object",
90
- description: "The serve pipeline's error envelope.",
91
- properties: {
92
- error: {
93
- type: "string",
94
- description: "Human-readable error message."
95
- },
96
- detail: {
97
- type: "string",
98
- description: "Decode failure detail (400 only)."
99
- },
100
- replacement: {
101
- type: "string",
102
- description: "Replacement endpoint hint (410 only)."
103
- }
104
- },
105
- required: ["error"]
106
- }, y = (e) => ({
107
- description: e,
108
- content: { "application/json": { schema: { $ref: `#/components/schemas/${_}` } } }
109
- }), b = "ProblemDetails", x = {
110
- type: "object",
111
- description: "RFC 9457 Problem Details. Extension members carry the error's own fields.",
112
- properties: {
113
- type: {
114
- type: "string",
115
- format: "uri",
116
- description: "The error type — `urn:voltro:error:<Tag>`."
117
- },
118
- title: { type: "string" },
119
- status: { type: "integer" },
120
- detail: { type: "string" }
121
- },
122
- required: [
123
- "type",
124
- "title",
125
- "status"
126
- ],
127
- additionalProperties: !0
128
- }, S = (e, t, n = 0) => {
129
- if (n > 6) return null;
130
- let r = e.$ref;
131
- if (typeof r == "string") {
132
- let e = t[r.split("/").pop() ?? ""];
133
- return e !== void 0 && typeof e == "object" ? S(e, t, n + 1) : null;
134
- }
135
- if (e.example !== void 0) return e.example;
136
- if (Array.isArray(e.examples) && e.examples.length > 0) return e.examples[0];
137
- if (e.const !== void 0) return e.const;
138
- if (Array.isArray(e.enum) && e.enum.length > 0) return e.enum[0];
139
- let i = e.anyOf ?? e.oneOf;
140
- if (Array.isArray(i) && i.length > 0) return S(i.find((e) => e.type !== "null") ?? i[0], t, n + 1);
141
- let a = e.allOf;
142
- if (Array.isArray(a) && a.length > 0) {
143
- let e = a.map((e) => S(e, t, n + 1));
144
- return e.every((e) => typeof e == "object" && !!e && !Array.isArray(e)) ? Object.assign({}, ...e) : e[0];
145
- }
146
- let o = e.type;
147
- switch (Array.isArray(o) ? o.find((e) => e !== "null") : o) {
148
- case "string": {
149
- let t = e.format;
150
- if (t === "date-time") return "2026-01-01T00:00:00.000Z";
151
- if (t === "date") return "2026-01-01";
152
- if (t === "email") return "user@example.com";
153
- if (t === "uri" || t === "url") return "https://example.com";
154
- if (t === "uuid") return "00000000-0000-4000-8000-000000000000";
155
- let n = typeof e.minLength == "number" ? e.minLength : 0;
156
- return "string".padEnd(Math.max(n, 6), "x");
157
- }
158
- case "integer": return typeof e.minimum == "number" ? e.minimum : 1;
159
- case "number": return typeof e.minimum == "number" ? e.minimum : 1;
160
- case "boolean": return !0;
161
- case "null": return null;
162
- case "array": {
163
- let r = e.items;
164
- return r !== void 0 && typeof r == "object" && !Array.isArray(r) ? [S(r, t, n + 1)] : [];
165
- }
166
- case "object": {
167
- let r = e.properties ?? {}, i = {};
168
- for (let [e, a] of Object.entries(r)) i[e] = S(a, t, n + 1);
169
- return i;
170
- }
171
- default: return typeof e.properties == "object" ? S({
172
- ...e,
173
- type: "object"
174
- }, t, n) : null;
175
- }
176
- }, C = {
177
- 400: {
178
- tag: "InvalidRequest",
179
- detail: "Invalid request"
180
- },
181
- 401: {
182
- tag: "Unauthorized",
183
- detail: "Authentication required"
184
- },
185
- 403: {
186
- tag: "Forbidden",
187
- detail: "Missing required scope: <scope>"
188
- },
189
- 410: {
190
- tag: "Gone",
191
- detail: "Gone"
192
- },
193
- 500: {
194
- tag: "InternalServerError",
195
- detail: "Internal Server Error"
196
- }
197
- }, w = {
198
- 400: "Bad Request",
199
- 401: "Unauthorized",
200
- 403: "Forbidden",
201
- 404: "Not Found",
202
- 409: "Conflict",
203
- 410: "Gone",
204
- 422: "Unprocessable Content",
205
- 429: "Too Many Requests",
206
- 500: "Internal Server Error"
207
- }, T = (e, t, n) => {
208
- let r = t.format.errors === "problem-details" && t.format.encodeError === void 0, i = r ? "application/problem+json" : "application/json", a = /* @__PURE__ */ new Map();
209
- for (let e of t.errorResponses) {
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 ? {
211
- type: `urn:voltro:error:${e.tag}`,
212
- title: e.tag.replace(/([a-z0-9])([A-Z])/g, "$1 $2"),
213
- status: e.status,
214
- ...c
215
- } : {
216
- error: e.tag,
217
- ...c
218
- };
219
- t.push({
220
- tag: e.tag,
221
- example: l,
222
- schema: r ? { allOf: [{ $ref: `#/components/schemas/${b}` }, {
223
- type: "object",
224
- properties: { type: { const: `urn:voltro:error:${e.tag}` } }
225
- }] } : i
226
- }), a.set(e.status, t);
227
- }
228
- let o = (e, t) => {
229
- if (!r) return y(t);
230
- let n = C[e], a = n === void 0 ? {} : { example: {
231
- type: `urn:voltro:error:${n.tag}`,
232
- title: n.tag.replace(/([a-z])([A-Z])/g, "$1 $2"),
233
- status: e,
234
- detail: n.detail
235
- } };
236
- return {
237
- description: t,
238
- content: { [i]: {
239
- schema: { $ref: `#/components/schemas/${b}` },
240
- ...a
241
- } }
242
- };
243
- }, s = {};
244
- s[400] = o(400, "Invalid request — the input failed schema decode."), t.security !== "none" && (s[401] = o(401, "Unauthorized — no valid bearer.")), (t.security === "required" || (e.guards?.length ?? 0) > 0) && (s[403] = o(403, "Forbidden — the caller lacks a required scope."));
245
- for (let [e, t] of [...a.entries()].sort((e, t) => e[0] - t[0])) {
246
- let n = t.map((e) => e.tag);
247
- s[String(e)] = {
248
- description: `${w[e] ?? "Error"} — ${n.join(" | ")}`,
249
- content: { [i]: {
250
- schema: t.length === 1 ? t[0].schema : { oneOf: t.map((e) => e.schema) },
251
- example: t[0].example
252
- } }
253
- };
254
- }
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;
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
- }
274
- return {
275
- parameters: s,
276
- requestBody: e.method !== "GET" && Object.keys(c).length > 0 ? {
277
- required: l.length > 0,
278
- content: {
279
- "application/json": { schema: {
280
- ...r,
281
- properties: c,
282
- required: l
283
- } },
284
- "application/x-www-form-urlencoded": { schema: {
285
- ...r,
286
- properties: c,
287
- required: l
288
- } }
289
- }
290
- } : void 0
291
- };
292
- }, D = (e, t, n) => {
293
- if (e.streaming === !0) return {
294
- description: "Server-Sent Events stream (`snapshot`, then `delta` per change)",
295
- content: { "text/event-stream": { schema: { type: "string" } } }
296
- };
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" ? {
298
- type: "object",
299
- properties: {
300
- data: r,
301
- ...a ? { next: {
302
- type: "string",
303
- description: "The next page's cursor, when there is one."
304
- } } : {}
305
- },
306
- required: ["data"]
307
- } : i.envelope === "jsonapi" ? {
308
- type: "object",
309
- properties: {
310
- data: { description: "One resource or an array of resources — `{ type, id, attributes }`." },
311
- links: {
312
- type: "object",
313
- properties: { next: { type: "string" } }
314
- }
315
- },
316
- required: ["data"]
317
- } : r : { description: `Encoded by the '${i.name}' format.` }, s = i.envelope === "jsonapi" ? "application/vnd.api+json" : "application/json", c = {
318
- ...a ? { Link: {
319
- description: "RFC 8288 — `<url>; rel=\"next\"` when there is a next page.",
320
- schema: { type: "string" }
321
- } } : {},
322
- ...e.etag === !0 ? { ETag: {
323
- description: "Weak validator; send it back as `If-None-Match` for a 304.",
324
- schema: { type: "string" }
325
- } } : {},
326
- ...e.cache !== void 0 && e.method === "GET" ? {
327
- "Cache-Control": {
328
- description: `\`public, max-age=${e.cache.maxAge}\` for a request without a credential; \`private, no-cache\` for one with \`Authorization\` or a cookie.`,
329
- schema: { type: "string" }
330
- },
331
- ...e.cache.tags === void 0 ? {} : {
332
- "Cache-Tag": {
333
- description: "Purge tags, comma-separated (only on a public answer).",
334
- schema: { type: "string" }
335
- },
336
- "Surrogate-Key": {
337
- description: "The same purge tags, space-separated (only on a public answer).",
338
- schema: { type: "string" }
339
- }
340
- }
341
- } : {}
342
- };
343
- return {
344
- description: "OK",
345
- ...Object.keys(c).length > 0 ? { headers: c } : {},
346
- content: { [s]: {
347
- schema: o,
348
- ...k(e.example?.response, o, n)
349
- } }
350
- };
351
- }, O = (e, t, n) => {
352
- let r = e.$ref, i = (typeof r == "string" ? t[r.split("/").pop() ?? ""] : e)?.properties;
353
- return typeof i == "object" && !!i && n in i;
354
- }, k = (e, t, n) => e === void 0 ? {
355
- example: S(t, n),
356
- "x-voltro-example": "derived"
357
- } : { example: e }, A = (e) => ({
358
- ...e.input === void 0 ? {} : { 400: y("Invalid request — the input failed schema decode.") },
359
- ...e.guards !== void 0 && e.guards.length > 0 ? {
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).")
362
- } : {},
363
- ...e.sunset === void 0 ? {} : { 410: y(`Gone — the route is past its sunset date (${e.sunset}).`) },
364
- 500: y("Internal Server Error.")
365
- });
366
- function j(e, t = {}, n = {}, r = {}) {
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();
368
- for (let t of e) {
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, {
370
- name: "If-None-Match",
371
- in: "header",
372
- required: !1,
373
- description: "A previously returned ETag. A matching validator returns 304 without a body.",
374
- schema: { type: "string" }
375
- }] : n, c = i ? { 304: {
376
- description: "Not Modified",
377
- headers: { ETag: {
378
- description: "The current representation validator.",
379
- schema: { type: "string" }
380
- } }
381
- } } : {}, l = t.guards !== void 0 && t.guards.length > 0;
382
- if (r !== void 0) {
383
- let e = r.content;
384
- e["application/json"] = {
385
- ...e["application/json"],
386
- ...k(t.example?.request, e["application/json"].schema, o)
387
- };
388
- }
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, _ = {
392
- ...t.operationId === void 0 ? {} : { operationId: t.operationId },
393
- ...t.summary ? { summary: t.summary } : {},
394
- ...t.description ? { description: t.description } : {},
395
- ...t.deprecated === void 0 ? {} : { deprecated: !0 },
396
- ...t.sunset === void 0 ? {} : { "x-sunset": t.sunset },
397
- ...p === void 0 ? {} : { tags: p },
398
- ...h === void 0 ? {} : { "x-voltro-api-version": h },
399
- ...s.length > 0 ? { parameters: s } : {},
400
- ...r ? { requestBody: r } : {},
401
- ...d,
402
- responses: e === void 0 ? {
403
- 200: t.streaming === !0 ? {
404
- description: "Server-Sent Events stream (`snapshot`, then `delta` per change)",
405
- content: { "text/event-stream": { schema: { type: "string" } } }
406
- } : {
407
- description: "OK",
408
- content: { "application/json": {
409
- schema: m(t.output, o),
410
- ...k(t.example?.response, m(t.output, o), o)
411
- } }
412
- },
413
- ...A(t),
414
- ...c
415
- } : {
416
- 200: D(t, e, o),
417
- ...c,
418
- ...T(t, e, o)
419
- }
420
- };
421
- e?.format.describe !== void 0 && (_ = e.format.describe(_, {
422
- tag: e.tag,
423
- method: t.method,
424
- path: t.path
425
- }));
426
- let v = f(t.path), y = a[v] ?? {};
427
- y[t.method.toLowerCase()] = _, a[v] = y;
428
- }
429
- let p = n.procedures ?? [];
430
- if (p.length > 0) {
431
- let e = d(p, o);
432
- for (let [t, n] of Object.entries(e)) a[t] = {
433
- ...n,
434
- ...a[t] ?? {}
435
- };
436
- }
437
- let y = [...u].sort().map((e) => ({
438
- name: e,
439
- ...r.tagDescriptions?.[e] === void 0 ? {} : { description: r.tagDescriptions[e] },
440
- ...r.tagExternalDocs?.[e] === void 0 ? {} : { externalDocs: r.tagExternalDocs[e] }
441
- })), S = (r.servers ?? []).map((e) => ({
442
- url: e.url,
443
- ...e.description === void 0 ? {} : { description: e.description },
444
- ...e.environment === void 0 ? {} : { "x-voltro-environment": e.environment }
445
- }));
446
- return {
447
- openapi: "3.1.0",
448
- info: {
449
- title: t.title ?? "API",
450
- version: t.version ?? "1.0.0",
451
- ...t.description ? { description: t.description } : {},
452
- ...t.contact === void 0 ? {} : { contact: t.contact },
453
- ...t.license === void 0 ? {} : { license: t.license },
454
- ...t.termsOfService === void 0 ? {} : { termsOfService: t.termsOfService },
455
- ...t.logo === void 0 ? {} : { "x-logo": t.logo }
456
- },
457
- ...S.length > 0 ? { servers: S } : {},
458
- ...r.externalDocs === void 0 ? {} : { externalDocs: r.externalDocs },
459
- ...r.environment === void 0 ? {} : { "x-voltro-environment": r.environment },
460
- ...e.some((e) => e.projection !== void 0) ? { "x-voltro-surface-digest": i(e) } : {},
461
- ...y.length > 0 ? { tags: y } : {},
462
- paths: h(a),
463
- components: {
464
- schemas: {
465
- ...h(o),
466
- [_]: v,
467
- ...l ? { [b]: x } : {}
468
- },
469
- ...s || c ? { securitySchemes: { bearerAuth: {
470
- type: "http",
471
- scheme: "bearer"
472
- } } } : {}
473
- }
474
- };
475
- }
476
- //#endregion
477
- //#region src/swaggerUi.ts
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>
479
- <html lang="en">
480
- <head>
481
- <meta charset="utf-8" />
482
- <meta name="viewport" content="width=device-width, initial-scale=1" />
483
- <title>${t}</title>
484
- <link rel="stylesheet" href="${F}" integrity="${N}" crossorigin="anonymous" />
485
- <style>body { margin: 0 }</style>
486
- </head>
487
- <body>
488
- <div id="swagger-ui"></div>
489
- <script src="${I}" integrity="${P}" crossorigin="anonymous"><\/script>
490
- <script>
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 });
492
- <\/script>
493
- </body>
494
- </html>`, R = r([
1
+ import { PROBLEM_DETAILS_SCHEMA_NAME as e, deriveExample as t, generateOpenApiSpec as n } from "./generate.js";
2
+ import { swaggerUiHtml as r } from "./swaggerUi.js";
3
+ import { Effect as i } from "effect";
4
+ import { definePlugin as a } from "@voltro/protocol";
5
+ import { pluginEnv as o } from "@voltro/env";
6
+ //#region src/index.ts
7
+ var s = o([
495
8
  {
496
9
  name: "OPENAPI_DOCS_TOKEN",
497
10
  required: !1,
@@ -510,132 +23,136 @@ var M = "5.17.14", N = "sha384-wxLW6kwyHktdDGr6Pv1zgm/VGJh99lfUbzSn6HNHBENZlCN7W
510
23
  secret: !1,
511
24
  description: "The environment this instance serves (dev | staging | production) — x-voltro-environment on the spec."
512
25
  }
513
- ]), z = (e, t) => {
26
+ ]), c = (e, t) => {
514
27
  if (e) return (t.headers.authorization ?? t.headers.Authorization) === `Bearer ${e}` ? void 0 : {
515
28
  status: 401,
516
29
  body: "unauthorized",
517
30
  contentType: "text/plain"
518
31
  };
519
- }, B = (e) => e.projection?.version ?? e.version, V = (e) => {
32
+ }, l = (e) => e.projection?.version ?? e.version, u = (e) => {
520
33
  let t = /^v(\d+)$/.exec(e);
521
34
  return t === null ? -1 : Number(t[1]);
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) => {
35
+ }, d = (e) => [...new Set(e.map(l).filter((e) => e !== void 0))].sort((e, t) => u(t) - u(e) || t.localeCompare(e)), f = (e, t) => {
523
36
  let n;
524
37
  for (let r of t) {
525
- if (B(r) !== e) continue;
38
+ if (l(r) !== e) continue;
526
39
  let t = r.sunset;
527
40
  t !== void 0 && (n === void 0 || t < n) && (n = t);
528
41
  }
529
42
  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 ? [] : [{
532
- url: m,
533
- description: `${p} — this instance`,
534
- environment: p
535
- }]), g = {
536
- ...n.tagDescriptions === void 0 ? {} : { tagDescriptions: n.tagDescriptions },
537
- ...n.tagExternalDocs === void 0 ? {} : { tagExternalDocs: n.tagExternalDocs },
538
- ...n.externalDocs === void 0 ? {} : { externalDocs: n.externalDocs },
539
- ...h.length > 0 ? { servers: h } : {},
540
- environment: p
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);
43
+ }, p = (e) => {
44
+ let t = e.specPath ?? "/openapi.json", o = e.docsPath ?? "/docs", f = s.read("OPENAPI_DOCS_TOKEN", e.token), p = e.name ? `@voltro/plugin-openapi#${e.name}` : "@voltro/plugin-openapi", m = e.routes ?? [], h = e.procedures ?? [], g = h, _ = e.includeAppRoutes ?? !0, v = e.includeAppProcedures ?? !1, y = m, b = e.environment ?? s.read("VOLTRO_ENVIRONMENT", void 0) ?? (process.env.NODE_ENV === "production" ? "production" : "dev"), x = s.read("VOLTRO_PUBLIC_API_ORIGIN", void 0), S = e.servers ?? (x === void 0 ? [] : [{
45
+ url: x,
46
+ description: `${b} — this instance`,
47
+ environment: b
48
+ }]), C = {
49
+ ...e.tagDescriptions === void 0 ? {} : { tagDescriptions: e.tagDescriptions },
50
+ ...e.tagExternalDocs === void 0 ? {} : { tagExternalDocs: e.tagExternalDocs },
51
+ ...e.externalDocs === void 0 ? {} : { externalDocs: e.externalDocs },
52
+ ...S.length > 0 ? { servers: S } : {},
53
+ environment: b
54
+ }, w = (t, r, i) => JSON.stringify(n(t, e.info ?? {}, r ? { procedures: i } : {}, C), null, 2), T = t.endsWith(".json") ? t.slice(0, -5) : `${t}/versions`, E = (e) => `${T}/${e}.json`, D = /* @__PURE__ */ new Map(), O = [], k = "", A = (n = y, i = g) => {
55
+ let a = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map();
56
+ for (let e of n) {
57
+ let t = l(e);
58
+ if (t === void 0) continue;
59
+ let n = a.get(t);
60
+ n === void 0 && (n = [], a.set(t, n)), n.push(e);
61
+ let r = e.sunset, i = s.get(t);
62
+ r !== void 0 && (i === void 0 || r < i) && s.set(t, r);
550
63
  }
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
64
+ let c = [...a.keys()].sort((e, t) => u(t) - u(e) || t.localeCompare(e)), d = new Map([["", w(n, !0, i)], ...c.map((e) => [e, w(a.get(e), !1, i)])]), f = c.length > 1 ? [...c.map((e) => ({
65
+ url: E(e),
66
+ name: s.has(e) ? `${e} — sunset ${s.get(e)}` : e
554
67
  })), {
555
- url: r,
68
+ url: t,
556
69
  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
70
+ }] : void 0, p = o === !1 ? "" : r(t, e.info?.title ?? "API docs", f === void 0 ? {} : {
71
+ urls: f,
72
+ primaryName: f[0].name
560
73
  });
561
- b = c, x = s, S = d, f = e, l = t;
74
+ D = d, O = c, k = p, y = n, g = i;
562
75
  };
563
- C();
564
- let w = (e) => {
565
- if (!u) return;
566
- let t = new Set(s.map((e) => `${e.method} ${e.path}`)), n = e.filter((e) => !t.has(`${e.method} ${e.path}`));
567
- C([...s, ...n]);
568
- }, T = (e) => {
569
- if (!d) return;
570
- let t = new Set(c.map((e) => e.name));
571
- C(f, [...c, ...e.filter((e) => !t.has(e.name))]);
572
- }, E = (e) => ({
76
+ A();
77
+ let j = (e) => {
78
+ if (!_) return;
79
+ let t = new Set(m.map((e) => `${e.method} ${e.path}`)), n = e.filter((e) => !t.has(`${e.method} ${e.path}`));
80
+ A([...m, ...n]);
81
+ }, M = (e) => {
82
+ if (!v) return;
83
+ let t = new Set(h.map((e) => e.name));
84
+ A(y, [...h, ...e.filter((e) => !t.has(e.name))]);
85
+ }, N = (e) => ({
573
86
  status: 404,
574
87
  contentType: "application/json",
575
88
  body: JSON.stringify({
576
89
  error: `no API version '${e}' is mounted`,
577
- versions: x
90
+ versions: O
578
91
  })
579
- }), D = [{
92
+ }), P = [{
93
+ workload: "rest",
580
94
  method: "GET",
581
- path: r,
95
+ path: t,
582
96
  match: "exact",
583
97
  handle: async (e) => {
584
- let t = z(a, e);
98
+ let t = c(f, e);
585
99
  if (t) return t;
586
100
  let n = new URLSearchParams(e.query).get("version") ?? void 0;
587
- return n !== void 0 && !b.has(n) ? E(n) : {
101
+ return n !== void 0 && !D.has(n) ? N(n) : {
588
102
  status: 200,
589
- body: b.get(n ?? ""),
103
+ body: D.get(n ?? ""),
590
104
  contentType: "application/json"
591
105
  };
592
106
  }
593
107
  }, {
108
+ workload: "rest",
594
109
  method: "GET",
595
- path: v,
110
+ path: T,
596
111
  handle: async (e) => {
597
- let t = z(a, e);
112
+ let t = c(f, e);
598
113
  if (t) return t;
599
114
  let n = /\/([^/]+)\.json$/.exec(e.path)?.[1];
600
- return n === void 0 || n === "" || !b.has(n) ? E(n ?? "") : {
115
+ return n === void 0 || n === "" || !D.has(n) ? N(n ?? "") : {
601
116
  status: 200,
602
- body: b.get(n),
117
+ body: D.get(n),
603
118
  contentType: "application/json"
604
119
  };
605
120
  }
606
121
  }];
607
- return i !== !1 && D.push({
122
+ return o !== !1 && P.push({
123
+ workload: "rest",
608
124
  method: "GET",
609
- path: i,
125
+ path: o,
610
126
  match: "exact",
611
- handle: async (e) => z(a, e) || {
127
+ handle: async (e) => c(f, e) || {
612
128
  status: 200,
613
- body: S,
129
+ body: k,
614
130
  contentType: "text/html; charset=utf-8"
615
131
  }
616
- }), t({
617
- name: o,
132
+ }), a({
133
+ name: p,
134
+ workloads: ["rest"],
618
135
  description: "OpenAPI 3.1 spec + Swagger-UI docs from defineRestRoute descriptors + rpc procedures.",
619
136
  permissions: [],
620
- declaredEnv: R.declared,
621
- httpRoutes: D,
622
- onRestSurface: w,
623
- onProcedureSurface: T,
624
- onActivate: (t) => e.sync(() => {
625
- t.logger.info("openapi docs active", {
626
- specPath: r,
627
- docsPath: i,
628
- routes: f.length,
629
- appRoutes: u ? "included once mounted" : "excluded",
630
- procedures: l.length,
631
- appProcedures: d ? "included once discovered" : "excluded",
632
- environment: p,
633
- servers: h.map((e) => e.url),
634
- versions: H(f),
635
- tokenGated: !!a
137
+ declaredEnv: s.declared,
138
+ httpRoutes: P,
139
+ onRestSurface: j,
140
+ onProcedureSurface: M,
141
+ onActivate: (e) => i.sync(() => {
142
+ e.logger.info("openapi docs active", {
143
+ specPath: t,
144
+ docsPath: o,
145
+ routes: y.length,
146
+ appRoutes: _ ? "included once mounted" : "excluded",
147
+ procedures: g.length,
148
+ appProcedures: v ? "included once discovered" : "excluded",
149
+ environment: b,
150
+ servers: S.map((e) => e.url),
151
+ versions: d(y),
152
+ tokenGated: !!f
636
153
  });
637
154
  })
638
155
  });
639
156
  };
640
157
  //#endregion
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 };
158
+ export { e as PROBLEM_DETAILS_SCHEMA_NAME, t as deriveExample, n as generateOpenApiSpec, d as mountedVersions, p as openapiPlugin, r as swaggerUiHtml, f as versionLabel };