@voltro/plugin-openapi 0.83.1 → 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/dist/index.js CHANGED
@@ -1,25 +1,25 @@
1
- import { Effect as e, JSONSchema as t } from "effect";
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 === "NeverKeyword", 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) => {
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: p(e.input, t) } }
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: p(e.element, t) } }
13
+ content: { "application/x-ndjson": { schema: m(e.element, t) } }
14
14
  };
15
- let r = p(e.output, t);
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: p(e.error, t) } }
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: v("Internal Server Error — an untyped defect.")
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, n) => {
47
- let { $schema: r, $defs: i, ...a } = t.make(e);
48
- if (i && typeof i == "object") for (let [e, t] of Object.entries(i)) n[e] = t;
49
- return a;
50
- }, m = (e) => {
51
- if (Array.isArray(e)) return e.map(m);
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)}` : m(r);
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
- }, h = (e, t) => {
63
+ }, g = (e, t) => {
59
64
  if (!e) return {
60
65
  parameters: [],
61
66
  requestBody: void 0
62
67
  };
63
- let n = p(e, t), r = n.properties ?? {}, i = new Set(n.required ?? []), a = [];
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
- }, g = "VoltroHttpError", _ = {
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
- }, v = (e) => ({
106
+ }, y = (e) => ({
102
107
  description: e,
103
- content: { "application/json": { schema: { $ref: `#/components/schemas/${g}` } } }
104
- }), y = "ProblemDetails", b = {
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
- }, x = (e, t, n = 0) => {
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" ? x(e, t, n + 1) : null;
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 x(i.find((e) => e.type !== "null") ?? i[0], t, n + 1);
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) => x(e, t, n + 1));
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) ? [x(r, t, n + 1)] : [];
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] = x(a, t, n + 1);
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" ? x({
171
+ default: return typeof e.properties == "object" ? S({
167
172
  ...e,
168
173
  type: "object"
169
174
  }, t, n) : null;
170
175
  }
171
- }, S = {
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
- }, C = {
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
- }, w = (e, t, n) => {
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 = p(e.schema, n), o = x(i, n), { _tag: s, ...c } = typeof o == "object" && o ? o : {}, l = r ? {
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/${y}` }, {
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 v(t);
225
- let n = S[e], a = n === void 0 ? {} : { example: {
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/${y}` },
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: `${C[e] ?? "Error"} — ${n.join(" | ")}`,
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
- }, T = (e, t, n) => {
252
- let r = p(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] } : {};
253
- for (let [t, n] of Object.entries(i)) o.has(t) ? s.push({
254
- name: t,
255
- in: "path",
256
- required: !0,
257
- schema: n,
258
- ...d(t)
259
- }) : e.method === "GET" ? s.push({
260
- name: t,
261
- in: "query",
262
- required: a.has(t),
263
- schema: n,
264
- ...d(t)
265
- }) : (c[t] = n, a.has(t) && l.push(t));
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
- }, E = (e, t, n) => {
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 = p(t.output, n), i = t.format, a = i.pagination === "link-header" && D(r, n, i.cursorField), o = i.encodeSuccess === void 0 ? i.envelope === "data" ? {
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
- ...O(e.example?.response, o, n)
348
+ ...k(e.example?.response, o, n)
341
349
  } }
342
350
  };
343
- }, D = (e, t, n) => {
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
- }, O = (e, t, n) => e === void 0 ? {
347
- example: x(t, n),
354
+ }, k = (e, t, n) => e === void 0 ? {
355
+ example: S(t, n),
348
356
  "x-voltro-example": "derived"
349
- } : { example: e }, k = (e) => ({
350
- ...e.input === void 0 ? {} : { 400: v("Invalid request — the input failed schema decode.") },
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: v("Unauthorized — a guard rejected the unauthenticated request."),
353
- 403: v("Forbidden — a guard rejected the request (e.g. a required scope is missing).")
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: v(`Gone — the route is past its sunset date (${e.sunset}).`) },
356
- 500: v("Internal Server Error.")
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 A(e, t = {}, n = {}, r = {}) {
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 ? h(t.input, o) : T(t, e, o), i = t.etag === !0 && t.method === "GET" && t.streaming !== !0, s = i ? [...n, {
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
- ...O(t.example?.request, e["application/json"].schema, o)
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: [] }, {}] } : {}, m = t.tags ?? (t.version === void 0 ? void 0 : [t.version]);
382
- for (let e of m ?? []) u.add(e);
383
- let g = e?.version ?? t.version, _ = {
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
- ...m === void 0 ? {} : { tags: m },
390
- ...g === void 0 ? {} : { "x-voltro-api-version": g },
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: p(t.output, o),
402
- ...O(t.example?.response, p(t.output, o), o)
409
+ schema: m(t.output, o),
410
+ ...k(t.example?.response, m(t.output, o), o)
403
411
  } }
404
412
  },
405
- ...k(t),
413
+ ...A(t),
406
414
  ...c
407
415
  } : {
408
- 200: E(t, e, o),
416
+ 200: D(t, e, o),
409
417
  ...c,
410
- ...w(t, e, o)
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 v = n.procedures ?? [];
422
- if (v.length > 0) {
423
- let e = d(v, o);
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 x = [...u].sort().map((e) => ({
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
- ...x.length > 0 ? { tags: x } : {},
454
- paths: m(a),
461
+ ...y.length > 0 ? { tags: y } : {},
462
+ paths: h(a),
455
463
  components: {
456
464
  schemas: {
457
- ...m(o),
458
- [g]: _,
459
- ...l ? { [y]: b } : {}
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 j = "5.17.14", M = "sha384-wxLW6kwyHktdDGr6Pv1zgm/VGJh99lfUbzSn6HNHBENZlCN7W602k9VkGdxuFvPn", N = "sha384-wmyclcVGX/WhUkdkATwhaK1X1JtiNrr2EoYJ+diV3vj4v6OC5yCeSu+yW13SYJep", P = `https://unpkg.com/swagger-ui-dist@${j}/swagger-ui.css`, F = `https://unpkg.com/swagger-ui-dist@${j}/swagger-ui-bundle.js`, I = (e, t = "API docs", n = {}) => `<!doctype html>
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="${P}" integrity="${M}" crossorigin="anonymous" />
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="${F}" integrity="${N}" crossorigin="anonymous"><\/script>
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>`, L = r([
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
- ]), R = (e, t) => {
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
- }, z = (e) => e.projection?.version ?? e.version, B = (e) => {
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
- }, V = (e) => [...new Set(e.map(z).filter((e) => e !== void 0))].sort((e, t) => B(t) - B(e) || t.localeCompare(e)), H = (e, t) => {
515
- let n = t.filter((t) => z(t) === e && t.sunset !== void 0).map((e) => e.sunset).sort();
516
- return n.length > 0 ? `${e} — sunset ${n[0]}` : e;
517
- }, U = (t) => {
518
- let r = t.specPath ?? "/openapi.json", i = t.docsPath ?? "/docs", a = L.read("OPENAPI_DOCS_TOKEN", t.token), o = t.name ? `@voltro/plugin-openapi#${t.name}` : "@voltro/plugin-openapi", s = t.routes ?? [], c = t.procedures ?? [], l = c, u = t.includeAppRoutes ?? !0, d = t.includeAppProcedures ?? !1, f = s, p = t.environment ?? L.read("VOLTRO_ENVIRONMENT", void 0) ?? (process.env.NODE_ENV === "production" ? "production" : "dev"), m = L.read("VOLTRO_PUBLIC_API_ORIGIN", void 0), h = t.servers ?? (m === void 0 ? [] : [{
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
- ...t.tagDescriptions === void 0 ? {} : { tagDescriptions: t.tagDescriptions },
524
- ...t.tagExternalDocs === void 0 ? {} : { tagExternalDocs: t.tagExternalDocs },
525
- ...t.externalDocs === void 0 ? {} : { externalDocs: t.externalDocs },
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(A(e === void 0 ? f : f.filter((t) => z(t) === e), t.info ?? {}, e === void 0 ? { procedures: l } : {}, g), null, 2), v = /* @__PURE__ */ new Map(), y = () => {
529
- v = new Map([["", _()], ...V(f).map((e) => [e, _(e)])]);
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
- y();
532
- let b = (e) => {
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
- f = [...s, ...n], y();
536
- }, x = (e) => {
567
+ C([...s, ...n]);
568
+ }, T = (e) => {
537
569
  if (!d) return;
538
570
  let t = new Set(c.map((e) => e.name));
539
- l = [...c, ...e.filter((e) => !t.has(e.name))], y();
540
- }, S = r.endsWith(".json") ? r.slice(0, -5) : `${r}/versions`, C = (e) => `${S}/${e}.json`, w = (e) => ({
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: V(f)
577
+ versions: x
546
578
  })
547
- }), T = [{
579
+ }), D = [{
548
580
  method: "GET",
549
581
  path: r,
550
582
  match: "exact",
551
583
  handle: async (e) => {
552
- let t = R(a, e);
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 && !v.has(n) ? w(n) : {
587
+ return n !== void 0 && !b.has(n) ? E(n) : {
556
588
  status: 200,
557
- body: v.get(n ?? ""),
589
+ body: b.get(n ?? ""),
558
590
  contentType: "application/json"
559
591
  };
560
592
  }
561
593
  }, {
562
594
  method: "GET",
563
- path: S,
595
+ path: v,
564
596
  handle: async (e) => {
565
- let t = R(a, e);
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 === "" || !v.has(n) ? w(n ?? "") : {
600
+ return n === void 0 || n === "" || !b.has(n) ? E(n ?? "") : {
569
601
  status: 200,
570
- body: v.get(n),
602
+ body: b.get(n),
571
603
  contentType: "application/json"
572
604
  };
573
605
  }
574
606
  }];
575
- return i !== !1 && T.push({
607
+ return i !== !1 && D.push({
576
608
  method: "GET",
577
609
  path: i,
578
610
  match: "exact",
579
- handle: async (e) => {
580
- let n = R(a, e);
581
- if (n) return n;
582
- let i = V(f), o = i.length > 1 ? [...i.map((e) => ({
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
- }), n({
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: L.declared,
603
- httpRoutes: T,
604
- onRestSurface: b,
605
- onProcedureSurface: x,
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: V(f),
634
+ versions: H(f),
617
635
  tokenGated: !!a
618
636
  });
619
637
  })
620
638
  });
621
639
  };
622
640
  //#endregion
623
- export { y as PROBLEM_DETAILS_SCHEMA_NAME, x as deriveExample, A as generateOpenApiSpec, V as mountedVersions, U as openapiPlugin, I as swaggerUiHtml, H as versionLabel };
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.83.1",
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.83.1",
37
- "@voltro/protocol": "0.83.1"
36
+ "@voltro/env": "0.85.0",
37
+ "@voltro/protocol": "0.85.0"
38
38
  },
39
39
  "peerDependencies": {
40
- "effect": "^3.22.2"
40
+ "effect": "4.0.1"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public"