@voltro/protocol 0.86.0 → 0.88.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.
Files changed (78) hide show
  1. package/CHANGELOG.md +5484 -0
  2. package/THIRD-PARTY-NOTICES.md +3 -227
  3. package/dist/apiRoleEndpoints.js +107 -0
  4. package/dist/apiRoleObservation.js +67 -0
  5. package/dist/apikey.d.ts +10 -0
  6. package/dist/apikey.js +1 -2
  7. package/dist/approval.js +1 -2
  8. package/dist/approvalDescriptors.js +1 -2
  9. package/dist/auth.js +40 -21
  10. package/dist/boundedRing.js +1 -2
  11. package/dist/businessRule.js +1 -2
  12. package/dist/canonicalJson.js +13 -0
  13. package/dist/connection.js +1 -2
  14. package/dist/devActivity.js +1 -2
  15. package/dist/errorSchema.js +23 -0
  16. package/dist/errorValue.js +1 -2
  17. package/dist/event.js +52 -47
  18. package/dist/formCapture.js +11 -0
  19. package/dist/httpStreamMaxDuration.js +8 -0
  20. package/dist/idempotency.js +89 -35
  21. package/dist/idempotencyInput.js +122 -0
  22. package/dist/identity.js +1 -2
  23. package/dist/index.d.ts +876 -124
  24. package/dist/index.js +51 -40
  25. package/dist/inspect.d.ts +1 -1
  26. package/dist/inspect.js +1 -2
  27. package/dist/inspectBackfill.js +1 -2
  28. package/dist/inspectCommandRejection.js +1 -2
  29. package/dist/inspectProjection.js +1 -2
  30. package/dist/inspectStorageProjection.js +1 -2
  31. package/dist/inspectValueIdentity.js +1 -2
  32. package/dist/inspectWorkflowExecution.js +1 -2
  33. package/dist/inspectWorkflowQueuedStart.js +1 -2
  34. package/dist/jsonSchema.js +1 -2
  35. package/dist/jwt.d.ts +10 -0
  36. package/dist/jwt.js +2 -3
  37. package/dist/outbox.js +1 -2
  38. package/dist/pairing.js +1 -2
  39. package/dist/plugin.js +44 -19
  40. package/dist/pluginAccountMerge.js +87 -0
  41. package/dist/pluginNaming.js +1 -2
  42. package/dist/pluginPrivacy.js +165 -0
  43. package/dist/procedure.js +115 -98
  44. package/dist/publicApi.js +191 -211
  45. package/dist/queryOptionalSources.js +13 -0
  46. package/dist/reactivityChannel.js +1 -2
  47. package/dist/rest.d.ts +227 -64
  48. package/dist/rest.js +296 -194
  49. package/dist/restFormat.js +1 -2
  50. package/dist/restReceipt.js +42 -0
  51. package/dist/revalidate.js +12 -0
  52. package/dist/rowEquality.js +1 -2
  53. package/dist/rowPatch.js +1 -2
  54. package/dist/schemaShape.js +1 -2
  55. package/dist/scopes.js +72 -40
  56. package/dist/secretWindows.js +70 -0
  57. package/dist/serverErrorBus.js +1 -2
  58. package/dist/serviceCall.js +1 -2
  59. package/dist/session.d.ts +89 -6
  60. package/dist/session.js +56 -56
  61. package/dist/sessionHeader.js +1 -2
  62. package/dist/ssrfPolicy.js +29 -0
  63. package/dist/storageAccess.js +1 -2
  64. package/dist/storeErrors.js +1 -2
  65. package/dist/storeScreenshots.js +1 -2
  66. package/dist/strictInput.js +1 -2
  67. package/dist/subscriptionEvent.js +1 -2
  68. package/dist/tenantSelection.js +1 -2
  69. package/dist/time.js +1 -2
  70. package/dist/undo.js +1 -2
  71. package/dist/validation.js +1 -2
  72. package/dist/webSocketGateway.js +8 -3
  73. package/dist/workflow.js +1 -2
  74. package/dist/workflowAccess.js +1 -2
  75. package/dist/workflowRestart.js +1 -2
  76. package/dist/workflowRetry.js +1 -2
  77. package/dist/workflowStartOutcome.js +1 -2
  78. package/package.json +7 -5
package/dist/rest.js CHANGED
@@ -1,24 +1,28 @@
1
- import { Unauthenticated as e, anonymousSubject as t } from "./auth.js";
2
- import "./scopes.js";
3
- import { beginIdempotent as n, failIdempotent as r, finishIdempotent as i, holdIdempotentClaim as a, idempotencyScope as o } from "./idempotency.js";
4
- import { publishServerError as s } from "./serverErrorBus.js";
5
- import { JSONAPI_MEDIA_TYPE as c, PROBLEM_JSON as l, REST_PROFILE_NAMES as u, encodeRestError as d, encodeRestSuccess as f, nextLink as p, problemDetails as m, problemTypeOf as h, resolveRestFormat as g, restViewSchema as _, toSnakeCase as v } from "./restFormat.js";
6
- import { coerceQueryObject as y, coerceQueryValue as b, collectPublicApiRoutes as x, declaredErrorTags as S, derivePublicMethod as C, derivePublicPath as w, deriveResource as T, errorMemberSchema as E, normalizePathParams as D, operationIdOf as O, pathParamNames as k, projectedFailure as ee, publicApiRoute as te, publicSurfaceDigest as ne, resourceIdField as re, wireExample as ie } from "./publicApi.js";
7
- import { Effect as A, Schema as j } from "effect";
8
- import * as M from "effect/SchemaAST";
9
- //#region src/rest.ts
10
- var ae = () => (e) => {
1
+ import { Unauthenticated as e, anonymousSubject as t, currentSubjectAuthority as n } from "./auth.js";
2
+ import { effectiveScopes as r, hasEffectiveScope as i, recheckGuardsEffect as a } from "./scopes.js";
3
+ import { beginIdempotent as o, failIdempotent as s, finishIdempotent as c, holdIdempotentClaim as l, idempotencyScope as u } from "./idempotency.js";
4
+ import { declaredErrorTags as d, errorMemberSchema as f } from "./errorSchema.js";
5
+ import { prepareIdempotentInput as p } from "./idempotencyInput.js";
6
+ import { validateHttpStreamMaxDuration as m } from "./httpStreamMaxDuration.js";
7
+ import { publishServerError as h } from "./serverErrorBus.js";
8
+ import { JSONAPI_MEDIA_TYPE as g, PROBLEM_JSON as _, REST_PROFILE_NAMES as v, encodeRestError as y, encodeRestSuccess as b, nextLink as x, problemDetails as S, problemTypeOf as C, resolveRestFormat as w, restViewSchema as T, toSnakeCase as E } from "./restFormat.js";
9
+ import { makeRestReceiptCodec as D } from "./restReceipt.js";
10
+ import { coerceQueryObject as O, coerceQueryValue as k, collectPublicApiRoutes as A, derivePublicMethod as j, derivePublicPath as M, deriveResource as N, normalizePathParams as P, operationIdOf as F, pathParamNames as I, projectedFailure as ee, publicApiRoute as te, publicSurfaceDigest as ne, resourceIdField as re, wireExample as ie } from "./publicApi.js";
11
+ import { Effect as L, Schema as R } from "effect";
12
+ import * as ae from "effect/SchemaAST";
13
+ import { newTraceId as oe } from "@voltro/shared";
14
+ // src/rest.ts
15
+ var se = () => (e) => {
11
16
  if (e.subject.type === "anonymous") return {
12
17
  status: 401,
13
18
  message: e.subject.credentialRejected ?? "Authentication required"
14
19
  };
15
- }, oe = (e) => (t) => {
16
- let n = t.subject.scopes;
17
- if (!(n && (n.includes(e) || n.includes("admin:full")))) return {
20
+ }, ce = (e) => (t) => {
21
+ if (!i(t.subject, e)) return {
18
22
  status: 403,
19
23
  message: `Missing required scope: ${e}`
20
24
  };
21
- }, N = (e) => {
25
+ }, z = (e) => {
22
26
  for (let t of [
23
27
  "includes",
24
28
  "some",
@@ -33,18 +37,18 @@ var ae = () => (e) => {
33
37
  if (n === void 0 || !("value" in n) || typeof n.value != "string") return !1;
34
38
  }
35
39
  return !0;
36
- }, se = (e) => (t) => {
37
- let n = t.subject.scopes;
40
+ }, le = (e) => (t) => {
41
+ let n = r(t.subject);
38
42
  if (n) {
39
43
  if (n.includes("admin:full")) return;
40
- let t = n.length >= 32 && e.length >= 256 && N(n) && N(e) ? new Set(n) : void 0;
44
+ let t = n.length >= 32 && e.length >= 256 && z(n) && z(e) ? new Set(n) : void 0;
41
45
  if (e.some((e) => t === void 0 ? n.includes(e) : t.has(e))) return;
42
46
  }
43
47
  return {
44
48
  status: 403,
45
49
  message: `Missing required scope: one of ${e.join(", ")}`
46
50
  };
47
- }, P = (e, t) => {
51
+ }, B = (e, t) => {
48
52
  if (e === void 0) return {};
49
53
  let n = { vary: "Origin" };
50
54
  return t !== void 0 && (e.origins.includes(t) || e.origins.includes("*")) && (n["access-control-allow-origin"] = e.origins.includes("*") ? "*" : t, n["access-control-expose-headers"] = (e.exposeHeaders ?? [
@@ -53,8 +57,8 @@ var ae = () => (e) => {
53
57
  "ratelimit-remaining",
54
58
  "ratelimit-reset"
55
59
  ]).join(", ")), n;
56
- }, F = (e, t, n) => {
57
- let r = P(e, n.origin), i = e.methods ?? (t === "GET" ? ["GET", "HEAD"] : [t]), a = e.headers ?? ["authorization", "content-type"], o = (n["access-control-request-headers"] ?? "").split(",").map((e) => e.trim().toLowerCase()).filter(Boolean), s = r["access-control-allow-origin"] !== void 0 && i.some((e) => e === n["access-control-request-method"]) && o.every((e) => a.some((t) => t.toLowerCase() === e));
60
+ }, V = (e, t, n) => {
61
+ let r = B(e, n.origin), i = e.methods ?? (t === "GET" ? ["GET", "HEAD"] : [t]), a = e.headers ?? ["authorization", "content-type"], o = (n["access-control-request-headers"] ?? "").split(",").map((e) => e.trim().toLowerCase()).filter(Boolean), s = r["access-control-allow-origin"] !== void 0 && i.some((e) => e === n["access-control-request-method"]) && o.every((e) => a.some((t) => t.toLowerCase() === e));
58
62
  return {
59
63
  status: s ? 204 : 403,
60
64
  headers: {
@@ -67,13 +71,13 @@ var ae = () => (e) => {
67
71
  } : {}
68
72
  }
69
73
  };
70
- }, I = (e, t) => e.method === "GET" && e.cache !== void 0 && t.status !== 200 && t.status !== 304 ? {
74
+ }, H = (e, t) => e.method === "GET" && e.cache !== void 0 && t.status !== 200 && t.status !== 304 ? {
71
75
  ...t,
72
76
  headers: {
73
77
  ...t.headers,
74
78
  "Cache-Control": "private, no-store"
75
79
  }
76
- } : t, ce = (e, t, n, r, i) => {
80
+ } : t, ue = (e, t, n, r, i) => {
77
81
  if (e === void 0) return {};
78
82
  let a = { Vary: e.audience === void 0 ? "Authorization, Cookie" : "Authorization" };
79
83
  if (t.headers.authorization !== void 0 || e.audience === void 0 && t.headers.cookie !== void 0) return {
@@ -99,13 +103,13 @@ var ae = () => (e) => {
99
103
  "Surrogate-Key": c.join(" ")
100
104
  } : {}
101
105
  };
102
- }, L = (e, t = {}) => ({
106
+ }, U = (e, t = {}) => ({
103
107
  __voltroRestResponse: !0,
104
108
  status: t.status ?? 200,
105
109
  body: e,
106
110
  ...t.headers === void 0 ? {} : { headers: t.headers },
107
111
  ...t.contentType === void 0 ? {} : { contentType: t.contentType }
108
- }), R = (e) => typeof e == "object" && !!e && e.__voltroRestResponse === !0, z = class extends Error {
112
+ }), W = (e) => typeof e == "object" && !!e && e.__voltroRestResponse === !0, G = class extends Error {
109
113
  status;
110
114
  body;
111
115
  headers;
@@ -113,7 +117,7 @@ var ae = () => (e) => {
113
117
  constructor(e, t, n, r) {
114
118
  super(`REST ${e}`), this.name = "RestRouteError", this.status = e, this.body = t, this.headers = n, this.contentType = r;
115
119
  }
116
- }, B = (e, t, n) => new z(e, t, n), V = (e) => {
120
+ }, de = (e, t, n) => new G(e, t, n), fe = (e) => {
117
121
  if (e.version === void 0) return e;
118
122
  if (!/^v\d+$/.test(e.version)) throw Error(`defineRestRoute(${e.method} ${e.path}): version "${e.version}" must be 'v' followed by digits — 'v1', 'v2', …`);
119
123
  if ((/* @__PURE__ */ RegExp("^/v\\d+(/|$)")).test(e.path)) throw Error(`defineRestRoute(${e.method} ${e.path}): the path already starts with a version segment AND declares version: '${e.version}'. Pick one spelling — either bake the version into the path, or declare version: and keep the path bare ('/customers'). Both would mount '/${e.version}${e.path}', which is never what the author meant.`);
@@ -121,13 +125,17 @@ var ae = () => (e) => {
121
125
  ...e,
122
126
  path: `/${e.version}${e.path}`
123
127
  };
124
- }, H = (e, t = {}) => ({
125
- __voltroRestStream: !0,
126
- stream: {
127
- subscribe: e,
128
- ...t.keepAliveMs === void 0 ? {} : { keepAliveMs: t.keepAliveMs }
129
- }
130
- }), U = (e, t) => `event: ${e}\n${(typeof t == "string" ? t : JSON.stringify(t)).split("\n").map((e) => `data: ${e}`).join("\n")}\n\n`, W = (e) => typeof e == "object" && !!e && e.__voltroRestStream === !0, le = (e, t = {}) => ({
128
+ }, pe = (e, t = {}) => {
129
+ let n = m(t.maxDurationMs);
130
+ return {
131
+ __voltroRestStream: !0,
132
+ stream: {
133
+ subscribe: e,
134
+ ...t.keepAliveMs === void 0 ? {} : { keepAliveMs: t.keepAliveMs },
135
+ ...n === void 0 ? {} : { maxDurationMs: n }
136
+ }
137
+ };
138
+ }, me = (e, t) => `event: ${e}\n${(typeof t == "string" ? t : JSON.stringify(t)).split("\n").map((e) => `data: ${e}`).join("\n")}\n\n`, K = (e) => typeof e == "object" && !!e && e.__voltroRestStream === !0, he = (e, t = {}) => ({
131
139
  __voltroRestBytes: !0,
132
140
  byteStream: {
133
141
  stream: e,
@@ -137,18 +145,18 @@ var ae = () => (e) => {
137
145
  ...t.contentType === void 0 ? {} : { contentType: t.contentType },
138
146
  ...t.status === void 0 ? {} : { status: t.status },
139
147
  ...t.headers === void 0 ? {} : { headers: t.headers }
140
- }), G = (e) => typeof e == "object" && !!e && e.__voltroRestBytes === !0, ue = async (e) => {
148
+ }), q = (e) => typeof e == "object" && !!e && e.__voltroRestBytes === !0, ge = async (e) => {
141
149
  let t = await globalThis.crypto.subtle.digest("SHA-1", new TextEncoder().encode(e)), n = "";
142
150
  for (let e of new Uint8Array(t)) n += e.toString(16).padStart(2, "0");
143
151
  return n;
144
- }, K = (e, t, n, r = "application/json; charset=utf-8") => ({
152
+ }, J = (e, t, n, r = "application/json; charset=utf-8") => ({
145
153
  status: e,
146
154
  contentType: r,
147
155
  body: JSON.stringify(t),
148
156
  ...n ? { headers: n } : {}
149
- }), q = (e, t, n, r, i, a, o) => {
157
+ }), Y = (e, t, n, r, i, a, o) => {
150
158
  let s = e.projection;
151
- if (s === void 0) return K(n, {
159
+ if (s === void 0) return J(n, {
152
160
  error: i,
153
161
  ...a
154
162
  }, o);
@@ -159,17 +167,17 @@ var ae = () => (e) => {
159
167
  query: t.query,
160
168
  source: s.source,
161
169
  status: n
162
- }, l = d(s.format, {
170
+ }, l = y(s.format, {
163
171
  status: n,
164
172
  tag: r,
165
173
  message: i,
166
174
  fields: a
167
175
  }, c);
168
- return K(n, l.body, {
176
+ return J(n, l.body, {
169
177
  ...o,
170
178
  ...l.headers ?? {}
171
179
  }, l.contentType);
172
- }, J = (e) => (e.headers["content-type"] ?? "application/json").split(";")[0].trim().toLowerCase(), Y = (e, t) => {
180
+ }, X = (e) => (e.headers["content-type"] ?? "application/json").split(";")[0].trim().toLowerCase(), _e = (e, t) => {
173
181
  if (e.length === 0) return;
174
182
  let n = t === "application/x-www-form-urlencoded";
175
183
  if (!n && t !== "application/json" && !/^application\/[^/;\s]+\+json$/.test(t)) return;
@@ -177,21 +185,21 @@ var ae = () => (e) => {
177
185
  if (r.trim() !== "") {
178
186
  if (n) {
179
187
  let e = (e) => decodeURIComponent(e.replace(/\+/g, " "));
180
- return X((r.match(/[^&]+/g) ?? []).map((t) => {
188
+ return Z((r.match(/[^&]+/g) ?? []).map((t) => {
181
189
  let n = t.indexOf("=");
182
190
  return n < 0 ? [e(t), ""] : [e(t.slice(0, n)), e(t.slice(n + 1))];
183
191
  }));
184
192
  }
185
193
  return JSON.parse(r);
186
194
  }
187
- }, de = (e) => X(new URLSearchParams(e)), X = (e) => {
195
+ }, ve = (e) => Z(new URLSearchParams(e)), Z = (e) => {
188
196
  let t = /* @__PURE__ */ new Map();
189
197
  for (let [n, r] of e) {
190
198
  let e = t.get(n);
191
199
  e === void 0 ? t.set(n, r) : Array.isArray(e) ? e.push(r) : t.set(n, [e, r]);
192
200
  }
193
201
  return Object.fromEntries(t);
194
- }, Z = (e, t) => {
202
+ }, ye = (e, t) => {
195
203
  let n = e.match(/[^/]+/g) ?? [], r = t.match(/[^/]+/g) ?? [], i = {};
196
204
  for (let e = 0; e < n.length; e++) {
197
205
  let t = n[e];
@@ -205,7 +213,7 @@ var ae = () => (e) => {
205
213
  }
206
214
  }
207
215
  return i;
208
- }, fe = (e, t) => {
216
+ }, be = (e, t) => {
209
217
  let n = e.path.split("/"), r = n[n.length - 1] === "*", i = r ? n.slice(0, -1) : n, a = t.split("/");
210
218
  if (a.length < i.length) return !1;
211
219
  for (let e = 0; e < i.length; e++) {
@@ -215,225 +223,317 @@ var ae = () => (e) => {
215
223
  } else if (t !== n) return !1;
216
224
  }
217
225
  return a.length === i.length ? !0 : e.match === "exact" && !r ? !1 : a.slice(i.length).some((e) => e.length > 0);
218
- }, pe = (e, t, n) => ({
219
- query: de(e.query),
226
+ }, xe = (e, t, n) => ({
227
+ query: ve(e.query),
220
228
  params: t,
221
- body: n ? Y(e.rawBody, J(e)) : void 0,
222
- form: J(e) === "application/x-www-form-urlencoded"
229
+ body: n ? _e(e.rawBody, X(e)) : void 0,
230
+ form: X(e) === "application/x-www-form-urlencoded"
223
231
  }), Q = /* @__PURE__ */ new Set([
224
232
  "POST",
225
233
  "PUT",
226
234
  "PATCH",
227
235
  "DELETE"
228
236
  ]), $ = (t, n, r, i, a) => {
229
- if (t instanceof z) return K(t.status, t.body, {
237
+ if (r.mapFailure !== void 0) try {
238
+ let e = r.mapFailure(t, {
239
+ method: a.method,
240
+ path: a.path,
241
+ query: a.query
242
+ });
243
+ if (e instanceof Promise) throw e.catch(() => void 0), Error("REST failure mapping must complete synchronously");
244
+ if (L.isEffect(e) && !(e instanceof Error)) throw Error("REST failure mapping must be pure");
245
+ e !== void 0 && (t = e);
246
+ } catch {
247
+ t = /* @__PURE__ */ Error("REST failure mapping could not be applied");
248
+ }
249
+ if (t instanceof G) return J(t.status, t.body, {
230
250
  ...i,
231
251
  ...t.headers
232
252
  }, t.contentType);
233
253
  if (typeof t == "object" && t) {
234
254
  let o = t;
235
- if (typeof o.status == "number") return q(r, a, o.status, typeof o._tag == "string" ? o._tag : "Error", typeof o.message == "string" ? o.message : "Error", {}, { ...i });
236
- if (o._tag === "Unauthenticated" || t instanceof e) return q(r, a, 401, "Unauthorized", typeof o.reason == "string" ? o.reason : "Authentication required", {}, { ...i });
255
+ if (typeof o.status == "number") return Y(r, a, o.status, typeof o._tag == "string" ? o._tag : "Error", typeof o.message == "string" ? o.message : "Error", {}, { ...i });
256
+ if (o._tag === "Unauthenticated" || t instanceof e) return Y(r, a, 401, "Unauthorized", typeof o.reason == "string" ? o.reason : "Authentication required", {}, { ...i });
237
257
  if (o._tag === "ScopeError") {
238
258
  let e = n.type === "anonymous" ? 401 : 403;
239
- return q(r, a, e, e === 401 ? "Unauthorized" : "Forbidden", typeof o.message == "string" ? o.message : "Forbidden", {}, { ...i });
259
+ return Y(r, a, e, e === 401 ? "Unauthorized" : "Forbidden", typeof o.message == "string" ? o.message : "Forbidden", {}, { ...i });
240
260
  }
241
261
  if (o._tag === "NoSuchResource") {
242
262
  let e = t;
243
- return q(r, a, 404, "NoSuchResource", typeof o.message == "string" ? o.message : "Not Found", {
263
+ return Y(r, a, 404, "NoSuchResource", typeof o.message == "string" ? o.message : "Not Found", {
244
264
  resourceType: typeof e.resourceType == "string" ? e.resourceType : null,
245
265
  resourceId: typeof e.resourceId == "string" ? e.resourceId : null
246
266
  }, { ...i });
247
267
  }
248
268
  }
249
- return s({
269
+ return h({
250
270
  error: t,
251
271
  source: "rest",
252
272
  name: `${r.method} ${r.path}`,
253
273
  fields: { status: 500 }
254
274
  }), {
255
- ...q(r, a, 500, "InternalServerError", "Internal Server Error", {}, { ...i }),
275
+ ...Y(r, a, 500, "InternalServerError", "Internal Server Error", {}, { ...i }),
256
276
  cause: t
257
277
  };
258
- }, me = (s, c, l) => {
259
- let u = s.input ? j.decodeUnknownEffect(s.input) : void 0, d = j.encodeEffect(s.output), f = s.input === void 0 ? void 0 : M.toEncoded(s.input.ast), p = f !== void 0 && (!M.isObjects(f) || f.indexSignatures.length > 0 || f.propertySignatures.some((e) => e.name === "body")), m = {};
260
- s.projection !== void 0 && (m["x-voltro-rest-profile"] = s.projection.format.name);
261
- let h = (e) => e.replace(/\/$/, "").split("/").length, g = h(s.path);
262
- s.deprecated !== void 0 && (m.Deprecation = "true"), s.sunset !== void 0 && (m.Sunset = s.sunset);
263
- let _ = {
264
- method: s.method,
278
+ }, Se = (e, r, i) => {
279
+ let d = e.input ? R.decodeUnknownEffect(e.input) : void 0, f = R.encodeEffect(e.output), m = D(e.projection === void 0 ? e.output : e.publicApiDescriptor?.output ?? e.output, e.projection === void 0 ? "raw" : "projection"), h = (t, n, r) => {
280
+ if (!Number.isInteger(t.status) || t.status < 200 || t.status > 599) throw Error("Invalid final REST response status");
281
+ let i = e.projection;
282
+ if (i === void 0) return {
283
+ ...t,
284
+ body: n
285
+ };
286
+ let a = b(i.format, n, {
287
+ tag: i.tag,
288
+ method: r.method,
289
+ path: r.path,
290
+ query: r.query,
291
+ source: i.source,
292
+ status: t.status
293
+ });
294
+ return U(a.body, {
295
+ status: t.status,
296
+ headers: {
297
+ ...t.headers,
298
+ ...a.headers
299
+ },
300
+ ...(a.contentType ?? t.contentType) === void 0 ? {} : { contentType: a.contentType ?? t.contentType }
301
+ });
302
+ }, g = e.input === void 0 ? void 0 : ae.toEncoded(e.input.ast), _ = g !== void 0 && (!ae.isObjects(g) || g.indexSignatures.length > 0 || g.propertySignatures.some((e) => e.name === "body")), v = {};
303
+ e.projection !== void 0 && (v["x-voltro-rest-profile"] = e.projection.format.name);
304
+ let y = (e) => e.replace(/\/$/, "").split("/").length, x = y(e.path);
305
+ e.deprecated !== void 0 && (v.Deprecation = "true"), e.sunset !== void 0 && (v.Sunset = e.sunset);
306
+ let S = {
307
+ method: e.method,
308
+ ...e.publicApiDescriptor === void 0 ? {} : { restContract: e },
265
309
  answersOtherMethods: !0,
266
- path: s.path,
267
- match: s.path.endsWith("/*") ? "prefix" : "exact",
268
- ...s.maxBodyBytes === void 0 ? {} : { maxBodyBytes: s.maxBodyBytes },
269
- ...s.cors === void 0 ? {} : { cors: s.cors },
270
- ...s.credentials === void 0 ? {} : { credentials: s.credentials },
271
- handle: async (f) => {
272
- if (!s.path.endsWith("/*") && h(f.path) !== g) return q(s, f, 404, "NotFound", "Not Found", {}, { ...m });
273
- let _ = f.method.toUpperCase();
274
- if (!(_ === s.method || _ === "HEAD" && s.method === "GET")) return q(s, f, 405, "MethodNotAllowed", "Method Not Allowed", { allow: l }, {
275
- ...m,
276
- Allow: l
310
+ path: e.path,
311
+ match: e.path.endsWith("/*") ? "prefix" : "exact",
312
+ ...e.maxBodyBytes === void 0 ? {} : { maxBodyBytes: e.maxBodyBytes },
313
+ ...e.cors === void 0 ? {} : { cors: e.cors },
314
+ ...e.credentials === void 0 ? {} : { credentials: e.credentials },
315
+ handle: async (g) => {
316
+ if (!e.path.endsWith("/*") && y(g.path) !== x) return Y(e, g, 404, "NotFound", "Not Found", {}, { ...v });
317
+ let b = g.method.toUpperCase();
318
+ if (!(b === e.method || b === "HEAD" && e.method === "GET")) return Y(e, g, 405, "MethodNotAllowed", "Method Not Allowed", { allow: i }, {
319
+ ...v,
320
+ Allow: i
277
321
  });
278
- if (s.sunset !== void 0) {
279
- let e = Date.parse(s.sunset);
280
- if (!Number.isNaN(e) && Date.now() >= e) return q(s, f, 410, "Gone", "Gone", {
281
- ...s.version === void 0 ? {} : { version: s.version },
282
- ...s.deprecated === void 0 ? {} : { replacement: s.deprecated }
283
- }, { ...m });
322
+ if (e.sunset !== void 0) {
323
+ let t = Date.parse(e.sunset);
324
+ if (!Number.isNaN(t) && Date.now() >= t) return Y(e, g, 410, "Gone", "Gone", {
325
+ ...e.version === void 0 ? {} : { version: e.version },
326
+ ...e.deprecated === void 0 ? {} : { replacement: e.deprecated }
327
+ }, { ...v });
284
328
  }
285
- let v;
286
- if (u) {
287
- let e;
329
+ let S;
330
+ if (d) {
331
+ let t;
288
332
  try {
289
- e = pe(f, Z(s.path, f.path), p);
333
+ t = xe(g, ye(e.path, g.path), _);
290
334
  } catch {
291
- return q(s, f, 400, "InvalidRequest", "Malformed request body", {}, { ...m });
335
+ return Y(e, g, 400, "InvalidRequest", "Malformed request body", {}, { ...v });
292
336
  }
293
- let t = await A.runPromise(u(e).pipe(A.map((e) => ({
337
+ let n = await L.runPromise(d(t).pipe(L.map((e) => ({
294
338
  ok: !0,
295
339
  value: e
296
- })), A.catch((e) => A.succeed({
340
+ })), L.catch((e) => L.succeed({
297
341
  ok: !1,
298
342
  cause: e
299
343
  }))));
300
- if (!t.ok) return q(s, f, 400, "InvalidRequest", "Invalid request", { detail: String(t.cause) }, { ...m });
301
- v = t.value;
344
+ if (!n.ok) return Y(e, g, 400, "InvalidRequest", "Invalid request", { detail: String(n.cause) }, { ...v });
345
+ S = n.value;
302
346
  }
303
- let y;
347
+ let C;
304
348
  try {
305
- y = c.resolveSubject ? await c.resolveSubject(f.headers) : t(f.headers["x-tenant"] ?? null);
306
- } catch (t) {
307
- if (t instanceof e || typeof t == "object" && t && t._tag === "Unauthenticated") {
308
- let e = t.reason;
309
- return q(s, f, 401, "Unauthorized", e ?? "Authentication required", {}, { ...m });
310
- }
311
- throw t;
349
+ C = r.resolveSubject ? await r.resolveSubject(g.headers, {
350
+ path: g.path,
351
+ query: g.query
352
+ }) : t(g.headers["x-tenant"] ?? null);
353
+ } catch (n) {
354
+ return H(e, $(n, t(null), e, v, g));
312
355
  }
313
- if (s.credentials === "bearer" && y.type === "anonymous") return q(s, f, 401, "Unauthorized", y.credentialRejected ?? "Authentication required", {}, { ...m });
314
- let b;
315
- try {
316
- b = c.buildContext ? await c.buildContext(y, f.headers) : void 0;
317
- } catch (e) {
318
- return I(s, $(e, y, s, m, f));
356
+ if (e.credentials === "bearer" && C.type === "anonymous") return Y(e, g, 401, "Unauthorized", C.credentialRejected ?? "Authentication required", {}, { ...v });
357
+ let w = C, T = r.traceId?.() ?? oe(), E = {
358
+ traceId: T,
359
+ ...g.remoteAddr === void 0 ? {} : { remoteAddr: g.remoteAddr }
360
+ }, D = r.idempotency, O = D && Q.has(e.method) ? g.headers[D.header.toLowerCase()] : void 0, k = D && O ? u(C.tenantId, e.method, e.path) : "", A = e.projection === void 0 ? void 0 : e.publicApiDescriptor, j;
361
+ if (D && O) try {
362
+ let t = await p(A?.input ?? e.input ?? R.Unknown, A === void 0 ? S : S.value, C, {
363
+ path: g.path,
364
+ ...A === void 0 && e.input === void 0 ? {
365
+ query: g.query,
366
+ rawBody: g.rawBody
367
+ } : {}
368
+ });
369
+ S = A === void 0 ? t.input : { value: t.input }, j = t.fingerprint;
370
+ } catch {
371
+ return Y(e, g, 503, "IdempotencyUnavailable", "This request input cannot be safely retained for replay.", {}, { ...v });
319
372
  }
320
- let x = typeof b == "object" && b && "store" in b ? b.store : c.store, S = {
321
- subject: y,
322
- headers: f.headers,
323
- store: x,
324
- method: _,
325
- path: f.path,
326
- query: f.query,
327
- rawBody: f.rawBody,
328
- ...b === void 0 ? {} : { app: b },
329
- ...f.remoteAddr === void 0 ? {} : { remoteAddr: f.remoteAddr }
330
- };
331
- try {
332
- if (s.guards) for (let e of s.guards) {
333
- let t = await e(S);
334
- if (t) return q(s, f, t.status, t.status === 401 ? "Unauthorized" : t.status === 403 ? "Forbidden" : "GuardRejected", t.message, {}, { ...m });
373
+ let M, N = async () => {
374
+ let t = r.bindReplayAuthority?.({
375
+ subject: w,
376
+ traceId: T,
377
+ tag: A?.name ?? e.operationId ?? `${e.method} ${e.path}`,
378
+ kind: A?.kind ?? "rest",
379
+ input: A === void 0 ? S : S.value,
380
+ surface: "rest",
381
+ ...A?.publicApi === void 0 ? {} : { publicApi: A.publicApi },
382
+ ...g.remoteAddr === void 0 ? {} : { remoteAddr: g.remoteAddr }
383
+ });
384
+ if (t !== void 0) throw t instanceof Promise && t.catch(() => void 0), Error("Replay authority bindings must complete synchronously");
385
+ let i = await L.runPromise(a(w, void 0, S));
386
+ if (i) throw i;
387
+ C = n(w);
388
+ let o = r.buildContext ? await r.buildContext(C, g.headers, E) : void 0, s = typeof o == "object" && o && "store" in o ? o.store : r.store;
389
+ M = {
390
+ ...E,
391
+ subject: C,
392
+ headers: g.headers,
393
+ store: s,
394
+ method: b,
395
+ path: g.path,
396
+ query: g.query,
397
+ rawBody: g.rawBody,
398
+ ...o === void 0 ? {} : { app: o }
399
+ };
400
+ for (let t of e.guards ?? []) {
401
+ let n = await t(M, {
402
+ input: S,
403
+ defaultDeny: r.defaultDeny === !0
404
+ });
405
+ if (n) return Y(e, g, n.status, n.status === 401 ? "Unauthorized" : n.status === 403 ? "Forbidden" : "GuardRejected", n.message, {}, { ...v });
335
406
  }
336
- if (s.rateLimit !== void 0 && c.rateLimit !== void 0) {
337
- let e = await A.runPromise(c.rateLimit(s.rateLimit, S, s).pipe(A.as({ allowed: !0 }), A.catch((e) => A.succeed({
407
+ }, P, F, I = !1;
408
+ try {
409
+ let t = await N();
410
+ if (t) return t;
411
+ if (e.rateLimit !== void 0 && r.rateLimit !== void 0) {
412
+ let t = await L.runPromise(r.rateLimit(e.rateLimit, M, e).pipe(L.as({ allowed: !0 }), L.catch((e) => L.succeed({
338
413
  allowed: !1,
339
414
  error: e
340
415
  }))));
341
- if (!e.allowed) return $(e.error, y, s, m, f);
416
+ if (!t.allowed) return $(t.error, C, e, v, g);
417
+ let n = await N();
418
+ if (n) return n;
342
419
  }
343
- } catch (e) {
344
- return $(e, y, s, m, f);
345
- }
346
- let C = c.idempotency, w = C && Q.has(s.method) ? f.headers[C.header.toLowerCase()] : void 0, T = C && w ? o(y.tenantId, s.method, s.path) : "", E;
347
- if (C && w) {
348
- let e = await n(C.store, T, w, C.ttlMs, Date.now());
349
- if (e.kind === "replay") return K(e.response.status, e.response.body, {
350
- ...m,
351
- "Idempotency-Replayed": "true"
352
- });
353
- if (e.kind === "conflict") return q(s, f, 409, "Conflict", "A request with this Idempotency-Key is already being processed", {}, { ...m });
354
- E = a(C.store, T, w);
355
- }
356
- try {
357
- let e = await s.handler(v, S);
358
- if (W(e) || G(e)) return C && w && await r(C.store, T, w), G(e) ? {
359
- status: e.status ?? 200,
420
+ if (D && O) {
421
+ if (j === void 0) throw Error("Missing captured REST input identity");
422
+ let t = await o(D.store, k, O, j, D.ttlMs, Date.now());
423
+ t.kind === "fresh" && (F = t.claim, P = l(D.store, F));
424
+ let n = await N();
425
+ if (n) return n;
426
+ if (t.kind === "input-conflict" || t.kind === "input-unbound") return Y(e, g, 409, "IdempotencyInputRefused", "Check the original operation before starting another action; this request cannot be matched safely.", {}, { ...v });
427
+ if (t.kind === "replay") try {
428
+ let n = t.response.status;
429
+ if (!Number.isInteger(n) || n < 200 || n > 599 || e.projection !== void 0 && n !== 200) throw Error("Invalid retained REST response status");
430
+ let r = await m.read(t.response), i = await L.runPromise(f(r.body)), a = h(U(r.body, {
431
+ status: n,
432
+ ...r.headers === void 0 ? {} : { headers: r.headers },
433
+ ...r.contentType === void 0 ? {} : { contentType: r.contentType }
434
+ }), i, g), o = {
435
+ ...v,
436
+ ...a.headers,
437
+ "Idempotency-Replayed": "true"
438
+ };
439
+ return H(e, n === 204 || n === 304 ? {
440
+ status: n,
441
+ headers: o
442
+ } : J(n, a.body, o, a.contentType));
443
+ } catch {
444
+ throw Error("Stored REST response is incompatible with the current output contract");
445
+ }
446
+ if (t.kind === "conflict") return Y(e, g, 409, "Conflict", "A request with this Idempotency-Key is already being processed", {}, { ...v });
447
+ }
448
+ let n = await e.handler(S, M);
449
+ if (I = !0, K(n) || q(n)) return D && F && await s(D.store, F), q(n) ? {
450
+ status: n.status ?? 200,
360
451
  headers: {
361
- ...m,
362
- ...e.headers
452
+ ...v,
453
+ ...n.headers
363
454
  },
364
- byteStream: e.byteStream,
365
- ...e.contentType === void 0 ? {} : { contentType: e.contentType }
455
+ byteStream: n.byteStream,
456
+ ...n.contentType === void 0 ? {} : { contentType: n.contentType }
366
457
  } : {
367
458
  status: 200,
368
- headers: m,
369
- stream: e.stream
459
+ headers: v,
460
+ stream: n.stream
370
461
  };
371
- let t = R(e) ? e : L(e), n = await A.runPromise(d(t.body)), a = s.method === "GET" && t.status === 200 ? ce(s.cache, f, n, v, y) : {}, o = {
372
- ...m,
373
- ...t.headers,
374
- ...a
462
+ let i = W(n) ? n : U(n), a = await L.runPromise(f(i.body)), u = h(i, a, g), d = u.body, p = e.method === "GET" && u.status === 200 ? ue(e.cache, g, d, S, C) : {}, _ = {
463
+ ...v,
464
+ ...u.headers,
465
+ ...p
375
466
  };
376
- if (C && w && await i(C.store, T, w, {
377
- status: t.status,
378
- body: n
379
- }, Date.now()), s.etag === !0 && s.method === "GET") {
380
- let e = `W/"${await ue(JSON.stringify(n))}"`, r = f.headers["if-none-match"];
381
- return r !== void 0 && r.split(",").some((t) => t.trim() === e) ? {
467
+ if (D && F && !await c(D.store, F, {
468
+ status: u.status,
469
+ ...await m.capture(i.body, i)
470
+ }, Date.now())) throw Error("Original idempotent response claim is no longer owned");
471
+ if (e.etag === !0 && e.method === "GET") {
472
+ let t = `W/"${await ge(JSON.stringify(d))}"`, n = g.headers["if-none-match"];
473
+ return n !== void 0 && n.split(",").some((e) => e.trim() === t) ? {
382
474
  status: 304,
383
475
  headers: {
384
- ...m,
385
- ...a,
386
- ETag: e
476
+ ...v,
477
+ ...p,
478
+ ETag: t
387
479
  }
388
- } : I(s, K(t.status, n, {
389
- ...o,
390
- ETag: e
391
- }, t.contentType));
480
+ } : H(e, J(u.status, d, {
481
+ ..._,
482
+ ETag: t
483
+ }, u.contentType));
392
484
  }
393
- return t.status === 204 || t.status === 304 ? I(s, {
394
- status: t.status,
395
- headers: o
396
- }) : I(s, K(t.status, n, o, t.contentType));
397
- } catch (e) {
398
- return C && w && await r(C.store, T, w), I(s, $(e, y, s, m, f));
485
+ return u.status === 204 || u.status === 304 ? H(e, {
486
+ status: u.status,
487
+ headers: _
488
+ }) : H(e, J(u.status, d, _, u.contentType));
489
+ } catch (t) {
490
+ if (D && F && I) try {
491
+ await c(D.store, F, {
492
+ status: 500,
493
+ body: null
494
+ }, Date.now());
495
+ } catch {}
496
+ return H(e, $(I && F ? /* @__PURE__ */ Error("Idempotent response could not be retained") : t, C, e, v, g));
399
497
  } finally {
400
- E?.();
498
+ if (P?.(), D && F && !I) try {
499
+ await s(D.store, F);
500
+ } catch {}
401
501
  }
402
502
  }
403
503
  };
404
504
  return {
405
- ..._,
406
- handle: async (e) => {
407
- let n = P(s.cors, e.headers.origin), r;
408
- if (s.cors !== void 0 && e.method === "OPTIONS" && e.headers["access-control-request-method"] !== void 0 && e.headers["access-control-request-method"] === s.method) return F(s.cors, s.method, e.headers);
409
- let i = e;
410
- if (s.credentials === "bearer" && (e.method === s.method || e.method === "HEAD" && s.method === "GET")) {
411
- let t = Object.fromEntries(Object.entries(e.headers).filter(([e]) => e.toLowerCase() !== "cookie"));
412
- if (i = {
413
- ...e,
505
+ ...S,
506
+ handle: async (n) => {
507
+ let r = B(e.cors, n.headers.origin), i;
508
+ if (e.cors !== void 0 && n.method === "OPTIONS" && n.headers["access-control-request-method"] !== void 0 && n.headers["access-control-request-method"] === e.method) return V(e.cors, e.method, n.headers);
509
+ let a = n;
510
+ if (e.credentials === "bearer" && (n.method === e.method || n.method === "HEAD" && e.method === "GET")) {
511
+ let t = Object.fromEntries(Object.entries(n.headers).filter(([e]) => e.toLowerCase() !== "cookie"));
512
+ if (a = {
513
+ ...n,
414
514
  headers: t
415
- }, !/^Bearer\s+\S+$/i.test(t.authorization ?? "")) return q(s, i, 401, "Unauthorized", "Bearer authentication required", {}, n);
515
+ }, !/^Bearer\s+\S+$/i.test(t.authorization ?? "")) return Y(e, a, 401, "Unauthorized", "Bearer authentication required", {}, r);
416
516
  }
417
517
  try {
418
- r = await _.handle(i);
419
- } catch (e) {
420
- r = $(e, t(null), s, m, i);
518
+ i = await S.handle(a);
519
+ } catch (n) {
520
+ i = $(n, t(null), e, v, a);
421
521
  }
422
- let a = {
423
- ...r.headers,
424
- ...n
425
- }, o = Object.entries(r.headers ?? {}).find(([e]) => e.toLowerCase() === "vary")?.[1];
426
- if (o !== void 0 && s.cors !== void 0) {
427
- for (let e of Object.keys(a)) e.toLowerCase() === "vary" && delete a[e];
428
- a.vary = [...new Set(`${Array.isArray(o) ? o.join(", ") : o}, Origin`.split(",").map((e) => e.trim()))].join(", ");
522
+ let o = {
523
+ ...i.headers,
524
+ ...r
525
+ }, s = Object.entries(i.headers ?? {}).find(([e]) => e.toLowerCase() === "vary")?.[1];
526
+ if (s !== void 0 && e.cors !== void 0) {
527
+ for (let e of Object.keys(o)) e.toLowerCase() === "vary" && delete o[e];
528
+ o.vary = [...new Set(`${Array.isArray(s) ? s.join(", ") : s}, Origin`.split(",").map((e) => e.trim()))].join(", ");
429
529
  }
430
- return I(s, {
431
- ...r,
432
- headers: a
530
+ return H(e, {
531
+ ...i,
532
+ headers: o
433
533
  });
434
534
  }
435
535
  };
436
- }, he = (e, t = {}) => {
536
+ }, Ce = (e, t = {}) => {
437
537
  for (let n of e) {
438
538
  if (n.rateLimit !== void 0 && t.rateLimit === void 0) throw Error(`REST route ${n.method} ${n.path} declares rateLimit but no rate-limit plugin is mounted`);
439
539
  if (n.rateLimit !== void 0 && (!Number.isInteger(n.rateLimit.limit) || n.rateLimit.limit <= 0)) throw Error(`REST route ${n.method} ${n.path} rateLimit.limit must be a positive integer`);
@@ -446,11 +546,13 @@ var ae = () => (e) => {
446
546
  let e = r.get(n(t.path)) ?? [];
447
547
  e.includes(t.method) || e.push(t.method), r.set(n(t.path), e);
448
548
  }
449
- return e.map((e) => me(e, t, r.get(n(e.path)).join(", ")));
450
- }, ge = async (e, t) => {
549
+ return e.map((e) => ({
550
+ ...Se(e, t, r.get(n(e.path)).join(", ")),
551
+ workload: "rest"
552
+ }));
553
+ }, we = async (e, t) => {
451
554
  let n = await e[0].handle(t);
452
555
  for (let r = 1; r < e.length && n.status === 405; r++) n = await e[r].handle(t);
453
556
  return n;
454
557
  };
455
- //#endregion
456
- export { c as JSONAPI_MEDIA_TYPE, l as PROBLEM_JSON, u as REST_PROFILE_NAMES, z as RestRouteError, le as bytes, y as coerceQueryObject, b as coerceQueryValue, x as collectPublicApiRoutes, S as declaredErrorTags, V as defineRestRoute, C as derivePublicMethod, w as derivePublicPath, T as deriveResource, ge as dispatchSharedPath, d as encodeRestError, f as encodeRestSuccess, E as errorMemberSchema, G as isRestByteResponse, R as isRestResponse, W as isRestStreamResponse, Z as matchPathParams, p as nextLink, D as normalizePathParams, O as operationIdOf, k as pathParamNames, m as problemDetails, h as problemTypeOf, ee as projectedFailure, te as publicApiRoute, ne as publicSurfaceDigest, se as requireAnyScope, ae as requireAuthenticated, oe as requireScope, g as resolveRestFormat, re as resourceIdField, L as response, P as restCorsHeaders, F as restCorsPreflight, B as restError, he as restRoutesToHttpRoutes, _ as restViewSchema, fe as routeAcceptsPath, H as sse, U as sseFrame, v as toSnakeCase, ie as wireExample };
558
+ export { g as JSONAPI_MEDIA_TYPE, _ as PROBLEM_JSON, v as REST_PROFILE_NAMES, G as RestRouteError, he as bytes, O as coerceQueryObject, k as coerceQueryValue, A as collectPublicApiRoutes, d as declaredErrorTags, fe as defineRestRoute, j as derivePublicMethod, M as derivePublicPath, N as deriveResource, we as dispatchSharedPath, y as encodeRestError, b as encodeRestSuccess, f as errorMemberSchema, q as isRestByteResponse, W as isRestResponse, K as isRestStreamResponse, ye as matchPathParams, x as nextLink, P as normalizePathParams, F as operationIdOf, I as pathParamNames, S as problemDetails, C as problemTypeOf, ee as projectedFailure, te as publicApiRoute, ne as publicSurfaceDigest, le as requireAnyScope, se as requireAuthenticated, ce as requireScope, w as resolveRestFormat, re as resourceIdField, U as response, B as restCorsHeaders, V as restCorsPreflight, de as restError, Ce as restRoutesToHttpRoutes, T as restViewSchema, be as routeAcceptsPath, pe as sse, me as sseFrame, E as toSnakeCase, ie as wireExample };