@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/session.js CHANGED
@@ -1,100 +1,101 @@
1
1
  import { SubjectIdentity as e, subjectIdentity as t } from "./auth.js";
2
2
  import { subjectScopes as n } from "./scopes.js";
3
3
  import { SESSION_HEADER_NAME as r, sessionValueFromHeaders as i } from "./sessionHeader.js";
4
- import { Schema as a } from "effect";
5
- import { createHmac as o, timingSafeEqual as s } from "node:crypto";
6
- import { createLogger as c } from "@voltro/logger";
7
- //#region src/session.ts
8
- var l = c({ scope: "@voltro/protocol:session" }), u = 2, d = a.Struct({
9
- v: a.Literal(2),
4
+ import { applySecretWindows as a, bearerMatches as o, clearSecretWindows as s, drainSecretActivity as c, noteConfigured as l, noteSigned as u, noteSigningLifetime as d, previousAccepted as f, secretFingerprint as p, setSecretWindow as m } from "./secretWindows.js";
5
+ import { Schema as h } from "effect";
6
+ import { createHmac as g, timingSafeEqual as _ } from "node:crypto";
7
+ import { createLogger as v } from "@voltro/logger";
8
+ // src/session.ts
9
+ var y = v({ scope: "@voltro/protocol:session" }), b = 2, x = h.Struct({
10
+ v: h.Literal(2),
10
11
  subject: e,
11
- exp: a.Number,
12
- iat: a.Number,
13
- kid: a.optional(a.String)
14
- }), f = "k0", p = "k-previous", m = () => {
12
+ exp: h.Number,
13
+ iat: h.Number,
14
+ kid: h.optional(h.String)
15
+ }), S = "k0", C = "k-previous", w = () => {
15
16
  throw Error("VOLTRO_SESSION_SECRET is not set. It signs and verifies session cookies, and the framework refuses to invent one at this point: a fixed fallback would be readable by anyone with the source, making every session forgeable. `voltro dev` mints a project-local value into .env.local on boot; for a deployment, generate one with `voltro secret generate session`.");
16
- }, h = () => process.env.VOLTRO_SESSION_SECRET ?? m(), g = () => v() ?? { current: {
17
- kid: _(),
18
- secret: h()
19
- } }, _ = () => process.env.VOLTRO_SESSION_KID ?? "k0", v = () => {
17
+ }, T = () => process.env.VOLTRO_SESSION_SECRET ?? w(), E = () => O() ?? { current: {
18
+ kid: D(),
19
+ secret: T()
20
+ } }, D = () => process.env.VOLTRO_SESSION_KID ?? "k0", O = () => {
20
21
  let e = process.env.VOLTRO_SESSION_SECRET;
21
22
  if (e === void 0 || e === "") return;
22
23
  let t = {
23
- kid: _(),
24
+ kid: D(),
24
25
  secret: e
25
26
  }, n = process.env.VOLTRO_SESSION_SECRET_PREVIOUS;
26
- return n ? {
27
+ return l("session", e, n), n && f("session", n) ? {
27
28
  current: t,
28
29
  previous: {
29
30
  kid: process.env.VOLTRO_SESSION_KID_PREVIOUS ?? "k-previous",
30
31
  secret: n
31
32
  }
32
33
  } : { current: t };
33
- }, y = 32, b = (e = process.env) => {
34
+ }, k = 32, A = (e = process.env) => {
34
35
  let t = e.VOLTRO_SESSION_SECRET;
35
36
  if (t === void 0 || t === "") throw Error("VOLTRO_SESSION_SECRET is not set — refusing to serve. It signs session cookies, and there is no fallback: a built-in one would be readable by anyone with the source. Generate one with `voltro secret generate session`. (`voltro dev` mints a project-local value automatically; a deployment needs its own.)");
36
37
  if (t.length < 32) throw Error(`VOLTRO_SESSION_SECRET is only ${t.length} chars — too short for a session secret (need >= 32). This looks like a placeholder. Generate a real one with \`voltro secret generate session\`.`);
37
- }, x = a.encodeSync(d), S = a.decodeUnknownSync(d), C = (e) => (typeof e == "string" ? Buffer.from(e, "utf8") : e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), w = (e) => {
38
+ }, j = h.encodeSync(x), M = h.decodeUnknownSync(x), N = (e) => (typeof e == "string" ? Buffer.from(e, "utf8") : e).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""), P = (e) => {
38
39
  let t = e.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - e.length % 4) % 4);
39
40
  return Buffer.from(t, "base64");
40
- }, T = 604800, E = .7, D = (e, t) => C(o("sha256", t).update(e).digest()), O = (e) => typeof e == "string" ? {
41
+ }, F = 604800, I = .7, L = (e, t) => N(g("sha256", t).update(e).digest()), R = (e) => typeof e == "string" ? {
41
42
  kid: "k0",
42
43
  secret: e
43
- } : e, k = (e, r, i = {}) => {
44
- let a = O(r);
44
+ } : e, z = (e, r, i = {}) => {
45
+ let a = R(r);
45
46
  if (!a.secret) throw Error("signSession: secret must be a non-empty string");
46
47
  let o = n(e);
47
48
  if (o.length > 0) throw Error(`signSession: refusing to mint a session cookie for a ${e.type} subject carrying ${o.length} scope(s) (${o.slice(0, 5).join(", ")}). A session cookie carries IDENTITY only — authority is resolved per request, so that removing a role takes effect on the session that already exists instead of in up to 7 days. Mint the session from the identity and move the scopes into the auth.resolveScopes resolver, which runs on every request and can be invalidated the moment a role changes.`);
48
- let s = i.ttlSeconds ?? T, c = Math.floor((i.now ?? Date.now)() / 1e3), l = {
49
+ let s = i.ttlSeconds ?? F, c = Math.floor((i.now ?? Date.now)() / 1e3), l = {
49
50
  v: 2,
50
51
  subject: t(e),
51
52
  exp: c + s,
52
53
  iat: c,
53
54
  ...typeof r == "string" ? {} : { kid: a.kid }
54
- }, u = C(JSON.stringify(x(l)));
55
- return `${u}.${D(u, a.secret)}`;
56
- }, A = (e, t, n, r) => {
57
- let i = o("sha256", n).update(e).digest(), a = w(t);
58
- if (a.length !== i.length || !s(a, i)) return null;
55
+ }, d = N(JSON.stringify(j(l)));
56
+ return u("session", a.secret, l.exp * 1e3, c * 1e3), `${d}.${L(d, a.secret)}`;
57
+ }, B = (e, t, n, r) => {
58
+ let i = g("sha256", n).update(e).digest(), a = P(t);
59
+ if (a.length !== i.length || !_(a, i)) return null;
59
60
  try {
60
- let t = w(e).toString("utf8"), n = S(JSON.parse(t));
61
+ let t = P(e).toString("utf8"), n = M(JSON.parse(t));
61
62
  return n.exp < Math.floor(r() / 1e3) ? null : n;
62
63
  } catch {
63
64
  return null;
64
65
  }
65
- }, j = (e, t) => {
66
+ }, V = (e, t) => {
66
67
  if (!e || !t) return null;
67
68
  let n = e.indexOf(".");
68
69
  if (n <= 0 || n === e.length - 1) return null;
69
- let r = A(e.slice(0, n), e.slice(n + 1), t, Date.now);
70
+ let r = B(e.slice(0, n), e.slice(n + 1), t, Date.now);
70
71
  return r ? r.subject : null;
71
- }, M = (e, t, n = {}) => {
72
+ }, H = (e, t, n = {}) => {
72
73
  if (!e) return null;
73
74
  let r = e.indexOf(".");
74
75
  if (r <= 0 || r === e.length - 1) return null;
75
76
  let i = e.slice(0, r), a = e.slice(r + 1), o = t.previous ? [t.current, t.previous] : [t.current], s = n.now ?? Date.now;
76
77
  for (let e of o) {
77
- if (!e.secret) continue;
78
- let t = A(i, a, e.secret, s);
79
- if (!t) continue;
80
- let r = n.renewFraction ?? E, o = Math.floor(s() / 1e3), c = t.exp - t.iat, l = t.iat + c * r;
78
+ if (!e.secret || e === t.previous && !f("session", e.secret, s())) continue;
79
+ let r = B(i, a, e.secret, s);
80
+ if (!r) continue;
81
+ let o = n.renewFraction ?? I, c = Math.floor(s() / 1e3), l = r.exp - r.iat, u = r.iat + l * o;
81
82
  return {
82
- subject: t.subject,
83
- renew: o >= l,
83
+ subject: r.subject,
84
+ renew: c >= u,
84
85
  kid: e.kid,
85
- exp: t.exp,
86
- iat: t.iat
86
+ exp: r.exp,
87
+ iat: r.iat
87
88
  };
88
89
  }
89
90
  return null;
90
- }, N = (e, t) => {
91
+ }, U = (e, t) => {
91
92
  let n = Buffer.from(e, "utf8"), r = Buffer.from(t, "utf8");
92
- return n.length === r.length && s(n, r);
93
- }, P = (e, t, n) => {
93
+ return n.length === r.length && _(n, r);
94
+ }, W = (e, t, n) => {
94
95
  if (!t || t.length === 0) return n?.openWhenUnset === !0;
95
96
  let r = e.authorization ?? e.Authorization;
96
- return !r || !r.startsWith("Bearer ") ? !1 : N(r.slice(7).trim(), t);
97
- }, F = (e, t) => {
97
+ return !r || !r.startsWith("Bearer ") ? !1 : U(r.slice(7).trim(), t);
98
+ }, G = (e, t) => {
98
99
  if (e) for (let n of e.split(";")) {
99
100
  let e = n.indexOf("=");
100
101
  if (e < 0 || n.slice(0, e).trim() !== t) continue;
@@ -106,23 +107,22 @@ var l = c({ scope: "@voltro/protocol:session" }), u = 2, d = a.Struct({
106
107
  return r;
107
108
  }
108
109
  }
109
- }, I = (e, t, n = {}) => {
110
+ }, K = (e, t, n = {}) => {
110
111
  let r = [`${e}=${encodeURIComponent(t)}`];
111
112
  if (r.push(`Path=${n.path ?? "/"}`), n.maxAgeSeconds !== void 0 && r.push(`Max-Age=${n.maxAgeSeconds}`), r.push("HttpOnly"), n.httpOnly === !1) {
112
113
  let e = r.indexOf("HttpOnly");
113
114
  e >= 0 && r.splice(e, 1);
114
115
  }
115
116
  return r.push(`SameSite=${n.sameSite ?? "Lax"}`), (n.secure ?? !0) && r.push("Secure"), n.domain && r.push(`Domain=${n.domain}`), r.join("; ");
116
- }, L = process.env.VOLTRO_SESSION_COOKIE ?? "voltro:session", R = (e, t = L) => i(e, t, F), z = (e) => {
117
- let t = i(e, L, F);
117
+ }, q = process.env.VOLTRO_SESSION_COOKIE ?? "voltro:session", J = (e, t = q) => i(e, t, G), Y = (e) => {
118
+ let t = i(e, q, G);
118
119
  if (!t) return;
119
- let n = v();
120
- if (!n) V();
121
- else return M(t, n)?.exp;
122
- }, B = !1, V = () => {
123
- B || (B = !0, l.error("a `voltro:session` cookie was presented but VOLTRO_SESSION_SECRET is not set — the session cannot be verified, so no credential-expiry bound is imposed and realtime subscriptions on this connection will not be cut off when the session expires. Set VOLTRO_SESSION_SECRET (`voltro secret generate session`); `voltro dev` mints one, `voltro serve` refuses to boot without one.", { cookieName: L }));
124
- }, H = () => {
125
- B = !1;
120
+ let n = O();
121
+ if (!n) Z();
122
+ else return H(t, n)?.exp;
123
+ }, X = !1, Z = () => {
124
+ X || (X = !0, y.error("a `voltro:session` cookie was presented but VOLTRO_SESSION_SECRET is not set — the session cannot be verified, so no credential-expiry bound is imposed and realtime subscriptions on this connection will not be cut off when the session expires. Set VOLTRO_SESSION_SECRET (`voltro secret generate session`); `voltro dev` mints one, `voltro serve` refuses to boot without one.", { cookieName: q }));
125
+ }, Q = () => {
126
+ X = !1;
126
127
  };
127
- //#endregion
128
- export { p as DEFAULT_PREVIOUS_SESSION_KID, f as DEFAULT_SESSION_KID, y as MIN_SESSION_SECRET_LENGTH, L as SESSION_COOKIE_NAME, r as SESSION_HEADER_NAME, u as SESSION_PAYLOAD_VERSION, b as assertProductionSessionSecret, I as buildSetCookie, P as checkBearer, F as readCookie, R as readSessionValue, H as resetSessionSecretWarningLatch, v as resolveOptionalSessionSecrets, h as resolveSessionSecret, g as resolveSessionSecrets, z as sessionExpiryFromHeaders, k as signSession, N as timingSafeStringEqual, j as verifySession, M as verifySessionKeyed };
128
+ export { C as DEFAULT_PREVIOUS_SESSION_KID, S as DEFAULT_SESSION_KID, k as MIN_SESSION_SECRET_LENGTH, q as SESSION_COOKIE_NAME, r as SESSION_HEADER_NAME, b as SESSION_PAYLOAD_VERSION, a as applySecretWindows, A as assertProductionSessionSecret, o as bearerMatches, K as buildSetCookie, W as checkBearer, s as clearSecretWindows, c as drainSecretActivity, l as noteConfigured, u as noteSigned, d as noteSigningLifetime, f as previousAccepted, G as readCookie, J as readSessionValue, Q as resetSessionSecretWarningLatch, O as resolveOptionalSessionSecrets, T as resolveSessionSecret, E as resolveSessionSecrets, p as secretFingerprint, Y as sessionExpiryFromHeaders, m as setSecretWindow, z as signSession, U as timingSafeStringEqual, V as verifySession, H as verifySessionKeyed };
@@ -1,7 +1,6 @@
1
- //#region src/sessionHeader.ts
1
+ // src/sessionHeader.ts
2
2
  var e = "x-voltro-session", t = (e, t, n) => {
3
3
  let r = e["x-voltro-session"] ?? e["X-Voltro-Session"];
4
4
  return r !== void 0 && r.length > 0 ? r : n(e.cookie ?? e.Cookie, t);
5
5
  };
6
- //#endregion
7
6
  export { e as SESSION_HEADER_NAME, t as sessionValueFromHeaders };
@@ -0,0 +1,29 @@
1
+ // src/ssrfPolicy.ts
2
+ var e = (e, t) => e === 0 || e === 10 || e === 127 || e === 100 && t >= 64 && t <= 127 || e === 169 && t === 254 || e === 172 && t >= 16 && t <= 31 || e === 192 && t === 168 || e === 198 && (t === 18 || t === 19) || e >= 224, t = (e) => e === "::" || e === "::1" || e.startsWith("fc") || e.startsWith("fd") || e.startsWith("fe80") || e.startsWith("::ffff:"), n = (e, t, n) => n.some((n) => {
3
+ let r = n.trim().toLowerCase();
4
+ if (r === "") return !1;
5
+ let i = t === "" ? e : `${e}:${t}`;
6
+ return r === e || r === i ? !0 : r.startsWith("*.") ? e.endsWith(r.slice(1)) : !1;
7
+ }), r = (i, a = {}) => {
8
+ let o;
9
+ try {
10
+ o = new URL(i);
11
+ } catch {
12
+ return "malformed url";
13
+ }
14
+ if (o.protocol !== "http:" && o.protocol !== "https:") return `blocked scheme "${o.protocol}"`;
15
+ let s = o.hostname.replace(/^\[|\]$/g, "").toLowerCase();
16
+ if (n(s, o.port, a.allowHosts ?? [])) return null;
17
+ if (s === "localhost" || s.endsWith(".localhost") || s.endsWith(".internal") || s.endsWith(".local")) return `blocked host "${s}"`;
18
+ let c = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(s);
19
+ if (c) {
20
+ let t = Number(c[1]), n = Number(c[2]);
21
+ return t > 255 || n > 255 || Number(c[3]) > 255 || Number(c[4]) > 255 ? "malformed ipv4 literal" : e(t, n) ? `blocked private/reserved address ${s}` : null;
22
+ }
23
+ if (s.includes(":")) {
24
+ let e = /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.exec(s);
25
+ return e ? r(`${o.protocol}//${e[1]}`, a) : t(s) ? `blocked private/reserved address ${s}` : null;
26
+ }
27
+ return null;
28
+ };
29
+ export { r as ssrfReason };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/storageAccess.ts
2
+ // src/storageAccess.ts
3
3
  var t = e.Array(e.String).pipe(e.check(e.isMaxLength(64))), n = e.Struct({
4
4
  owner: e.optional(e.Boolean),
5
5
  roles: e.optional(t),
@@ -10,5 +10,4 @@ var t = e.Array(e.String).pipe(e.check(e.isMaxLength(64))), n = e.Struct({
10
10
  password: e.optional(e.Boolean),
11
11
  guard: e.optional(e.String)
12
12
  }), r = e.Array(n).pipe(e.check(e.isMaxLength(32)));
13
- //#endregion
14
13
  export { r as StorageAccessPolicySchema, n as StorageAccessRuleSchema };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/storeErrors.ts
2
+ // src/storeErrors.ts
3
3
  var t = class extends e.TaggedError()("TenantScopeViolation", {
4
4
  table: e.String,
5
5
  reason: e.String
@@ -62,5 +62,4 @@ var t = class extends e.TaggedError()("TenantScopeViolation", {
62
62
  }
63
63
  }
64
64
  };
65
- //#endregion
66
65
  export { s as ConstraintViolation, r as NoRowFound, o as ServerOnlyColumnWrite, n as StoreOperationFailed, i as TableValidationFailed, a as TenantRowNotFound, t as TenantScopeViolation };
@@ -1,4 +1,4 @@
1
- //#region src/storeScreenshots.ts
1
+ // src/storeScreenshots.ts
2
2
  var e = [
3
3
  "app-store",
4
4
  "play",
@@ -86,5 +86,4 @@ var e = [
86
86
  width: e.viewport.width * e.deviceScaleFactor,
87
87
  height: e.viewport.height * e.deviceScaleFactor
88
88
  }), a = (e) => t.filter((t) => t.stores.includes(e));
89
- //#endregion
90
89
  export { t as STORE_SCREENSHOT_PRESETS, n as STORE_SCREENSHOT_PRESET_NAMES, e as STORE_SCREENSHOT_STORES, i as storeScreenshotPixels, r as storeScreenshotPreset, a as storeScreenshotPresetsFor };
@@ -1,6 +1,6 @@
1
1
  import { Effect as e, Schema as t, SchemaIssue as n } from "effect";
2
2
  import * as r from "effect/SchemaAST";
3
- //#region src/strictInput.ts
3
+ // src/strictInput.ts
4
4
  var i = (e, t) => {
5
5
  let n = `${e ?? "this procedure"} input`;
6
6
  return t === !0 ? `${n} (guarded — the guard did NOT run: the payload failed to decode first, so this says nothing about access)` : n;
@@ -23,5 +23,4 @@ var i = (e, t) => {
23
23
  let l = i(o, s);
24
24
  return t.make(c(r.ast)).pipe(t.middlewareDecoding((t) => e.catch(t, (t) => e.fail(new n.InvalidValue({ message: `${l}\n${a(t)}` })))));
25
25
  };
26
- //#endregion
27
26
  export { i as inputLabel, u as strictInput };
@@ -1,6 +1,6 @@
1
1
  import { rowPatchSchema as e } from "./rowPatch.js";
2
2
  import { Schema as t, SchemaGetter as n } from "effect";
3
- //#region src/subscriptionEvent.ts
3
+ // src/subscriptionEvent.ts
4
4
  var r = t.Json.pipe(t.decodeTo(t.Unknown, {
5
5
  decode: n.passthrough({ strict: !1 }),
6
6
  encode: n.transform((e) => JSON.parse(JSON.stringify(e)))
@@ -33,5 +33,4 @@ var r = t.Json.pipe(t.decodeTo(t.Unknown, {
33
33
  default: return t;
34
34
  }
35
35
  };
36
- //#endregion
37
36
  export { a as firstEventValue, i as subscriptionEvent };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/tenantSelection.ts
2
+ // src/tenantSelection.ts
3
3
  var t = class extends e.TaggedError()("RequestedTenantRefused", { reason: e.Literals([
4
4
  "target-unavailable",
5
5
  "invalid-target",
@@ -36,5 +36,4 @@ var t = class extends e.TaggedError()("RequestedTenantRefused", { reason: e.Lite
36
36
  }
37
37
  };
38
38
  };
39
- //#endregion
40
39
  export { t as RequestedTenantRefused, r as TenantSelectionRefused, n as isTenantSelectable, i as selectSubjectTenant };
package/dist/time.js CHANGED
@@ -1,7 +1,6 @@
1
- //#region src/time.ts
1
+ // src/time.ts
2
2
  var e = (e) => {
3
3
  let t = e instanceof Date ? e.getTime() : typeof e == "number" ? e : typeof e == "string" ? new Date(e).getTime() : 0;
4
4
  return Number.isNaN(t) ? 0 : t;
5
5
  };
6
- //#endregion
7
6
  export { e as tsMs };
package/dist/undo.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defineMutation as e, defineQuery as t } from "./procedure.js";
2
2
  import { Schema as n } from "effect";
3
- //#region src/undo.ts
3
+ // src/undo.ts
4
4
  var r = "__voltro.undo.log", i = "__voltro.undo.apply", a = "__voltro.undo.redo", o = n.Struct({
5
5
  id: n.String,
6
6
  tag: n.String,
@@ -34,5 +34,4 @@ var r = "__voltro.undo.log", i = "__voltro.undo.apply", a = "__voltro.undo.redo"
34
34
  error: u,
35
35
  openAccess: "subject-scoped by construction: redo is per-actor — another subject's invocation fails typed with UndoForbidden"
36
36
  });
37
- //#endregion
38
37
  export { i as UNDO_APPLY_TAG, r as UNDO_LOG_TAG, a as UNDO_REDO_TAG, l as UndoConflict, c as UndoForbidden, o as UndoLogEntry, s as UndoNotFound, f as undoApplyDescriptor, d as undoLogQueryDescriptor, p as undoRedoDescriptor };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/validation.ts
2
+ // src/validation.ts
3
3
  var t = e.Struct({
4
4
  field: e.String,
5
5
  message: e.String,
@@ -35,5 +35,4 @@ var t = e.Struct({
35
35
  }
36
36
  return [];
37
37
  };
38
- //#endregion
39
38
  export { n as ValidationError, r as ValidationErrors, t as ValidationIssue, i as fieldIssuesOf };
@@ -1,10 +1,15 @@
1
- //#region src/webSocketGateway.ts
1
+ // src/webSocketGateway.ts
2
2
  var e = 4001, t = /* @__PURE__ */ new Set(["/rpc", "/ws"]), n = (e) => {
3
+ if (e.auth === "token") {
4
+ if (typeof e.verify != "function") throw Error("defineWebSocket: auth: 'token' requires verify(firstFrame, context)");
5
+ let t = e.verificationTimeoutMs;
6
+ if (t !== void 0 && (!Number.isSafeInteger(t) || t <= 0 || t > 2147483647)) throw Error("defineWebSocket: verificationTimeoutMs must be a positive safe integer at most 2147483647");
7
+ } else if (e.verify !== void 0 || e.verificationTimeoutMs !== void 0) throw Error("defineWebSocket: verify and verificationTimeoutMs require auth: 'token'");
8
+ if (e.limits?.burst !== void 0 && e.limits.maxInboundMessagesPerSecond === void 0) throw Error("defineWebSocket: limits.burst requires limits.maxInboundMessagesPerSecond");
3
9
  for (let [t, n] of Object.entries(e.limits ?? {})) if (n !== void 0 && (!Number.isSafeInteger(n) || n <= 0)) throw Error(`defineWebSocket: limits.${t} must be a positive safe integer`);
4
10
  if (!e.path.startsWith("/")) throw Error(`defineWebSocket: path must be absolute, got '${e.path}'`);
5
11
  if (t.has(e.path)) throw Error(`defineWebSocket: '${e.path}' is the framework's own socket surface — mount the gateway elsewhere`);
6
- if (e.auth !== "subject" && e.auth !== "public") throw Error(`defineWebSocket: auth must be 'subject' or 'public' (explicitly — an unauthenticated socket has to be a decision somebody wrote down), got '${String(e.auth)}'`);
12
+ if (e.auth !== "subject" && e.auth !== "public" && e.auth !== "token") throw Error(`defineWebSocket: auth must be 'subject', 'public' or 'token' (explicitly — an unauthenticated socket has to be a decision somebody wrote down), got '${String(e.auth)}'`);
7
13
  return e;
8
14
  };
9
- //#endregion
10
15
  export { e as GATEWAY_CREDENTIAL_EXPIRED_CLOSE_CODE, n as defineWebSocket };
package/dist/workflow.js CHANGED
@@ -4,7 +4,7 @@ import { getWorkflowAccess as a } from "./workflowAccess.js";
4
4
  import { WorkflowStartTerminalOutcomeSchema as o } from "./workflowStartOutcome.js";
5
5
  import { Schema as s } from "effect";
6
6
  import { Rpc as c } from "effect/rpc";
7
- //#region src/workflow.ts
7
+ // src/workflow.ts
8
8
  var l = s.Literals([
9
9
  "running",
10
10
  "succeeded",
@@ -293,5 +293,4 @@ var l = s.Literals([
293
293
  output: L,
294
294
  openAccess: "authorization happens in the executor against the target run — the caller must be authenticated and belong to the run's tenant, and a missing run answers exactly like a foreign one"
295
295
  });
296
- //#endregion
297
296
  export { O as WorkflowControlInputSchema, D as WorkflowControlIntentSchema, k as WorkflowControlReadInputSchema, d as WorkflowControlResultSchema, x as WorkflowDomainEventRowSchema, T as WorkflowDomainEventsInputSchema, E as WorkflowEventDeliveriesInputSchema, S as WorkflowEventDeliveryRowSchema, p as WorkflowParentClosePolicySchema, j as WorkflowQueuedCancelInputSchema, f as WorkflowQueuedCancellationResultSchema, A as WorkflowQueuedControlTargetSchema, b as WorkflowRunEventRowSchema, h as WorkflowRunHandleSchema, C as WorkflowRunRefSchema, _ as WorkflowRunRowSchema, u as WorkflowRunSnapshotSchema, l as WorkflowRunStatusSchema, y as WorkflowRunStepRowSchema, w as WorkflowRunTableRefSchema, v as WorkflowRunsInputSchema, F as WorkflowSignalInputSchema, m as WorkflowStartDeferralSchema, I as WorkflowUpdateInputSchema, L as WorkflowUpdateResultSchema, W as workflowCancelDescriptor, P as workflowControlQueryDescriptor, H as workflowDomainEventsQueryDescriptor, U as workflowEventDeliveriesQueryDescriptor, M as workflowQueuedCancelDescriptor, N as workflowQueuedControlQueryDescriptor, G as workflowResumeDescriptor, V as workflowRunEventsQueryDescriptor, R as workflowRunQueryDescriptor, B as workflowRunStepsQueryDescriptor, z as workflowRunsQueryDescriptor, K as workflowSignalDescriptor, g as workflowToRpc, q as workflowUpdateDescriptor };
@@ -1,5 +1,5 @@
1
1
  import { openAccessSpec as e } from "./scopes.js";
2
- //#region src/workflowAccess.ts
2
+ // src/workflowAccess.ts
3
3
  var t = Symbol.for("@voltro/protocol/workflow-access"), n = {
4
4
  guards: void 0,
5
5
  openAccess: void 0,
@@ -57,5 +57,4 @@ var t = Symbol.for("@voltro/protocol/workflow-access"), n = {
57
57
  controls: t.controls
58
58
  };
59
59
  };
60
- //#endregion
61
60
  export { t as WorkflowAccessProperty, i as attachWorkflowAccess, a as getWorkflowAccess, r as resolveWorkflowAccess, o as workflowAccessDescriptor };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/workflowRestart.ts
2
+ // src/workflowRestart.ts
3
3
  var t = e.NonEmptyString.pipe(e.check(e.makeFilter((e) => e.trim().length > 0, { message: "A workflow restart identity must not be blank" }))), n = e.Union([e.Struct({ kind: e.Literal("failed-steps") }), e.Struct({
4
4
  kind: e.Literal("from-step"),
5
5
  stepName: t
@@ -41,5 +41,4 @@ var t = e.NonEmptyString.pipe(e.check(e.makeFilter((e) => e.trim().length > 0, {
41
41
  kind: e.Literal("not-reserved"),
42
42
  reason: e.Literals(["admission", "journal"])
43
43
  })]);
44
- //#endregion
45
44
  export { i as WorkflowRestartCommandSchema, o as WorkflowRestartObservationSchema, s as WorkflowRestartResultSchema, n as WorkflowRestartSelectionSchema, r as WorkflowRestartTargetSchema };
@@ -1,6 +1,6 @@
1
1
  import { WorkflowStartTerminalOutcomeSchema as e } from "./workflowStartOutcome.js";
2
2
  import { Schema as t } from "effect";
3
- //#region src/workflowRetry.ts
3
+ // src/workflowRetry.ts
4
4
  var n = t.NonEmptyString.pipe(t.check(t.makeFilter((e) => e.trim().length > 0, { message: "A workflow retry identity must not be blank" }))), r = t.Struct({
5
5
  runId: n,
6
6
  requestId: n
@@ -40,5 +40,4 @@ var n = t.NonEmptyString.pipe(t.check(t.makeFilter((e) => e.trim().length > 0, {
40
40
  failureId: t.NonEmptyString
41
41
  })
42
42
  ]);
43
- //#endregion
44
43
  export { i as WorkflowRetryCommandSchema, o as WorkflowRetryObservationSchema, r as WorkflowRetryTargetSchema };
@@ -1,5 +1,5 @@
1
1
  import { Schema as e } from "effect";
2
- //#region src/workflowStartOutcome.ts
2
+ // src/workflowStartOutcome.ts
3
3
  var t = e.Union([
4
4
  e.Struct({
5
5
  kind: e.Literal("dropped"),
@@ -26,5 +26,4 @@ var t = e.Union([
26
26
  failureId: e.NonEmptyString
27
27
  })
28
28
  ]);
29
- //#endregion
30
29
  export { t as WorkflowStartTerminalOutcomeSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/protocol",
3
- "version": "0.86.0",
3
+ "version": "0.88.0",
4
4
  "description": "The Voltro wire + plugin contract — defineQuery/Mutation/Action/Stream, definePlugin, sessions / JWT / API-keys, and the RPC protocol.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -63,12 +63,14 @@
63
63
  "node": ">=24.0.0"
64
64
  },
65
65
  "dependencies": {
66
- "@voltro/database": "0.86.0",
67
- "@voltro/logger": "0.86.0",
68
- "jose": "^6.2.12"
66
+ "@voltro/database": "0.88.0",
67
+ "@voltro/kv": "0.88.0",
68
+ "@voltro/logger": "0.88.0",
69
+ "@voltro/shared": "0.88.0",
70
+ "jose": "^6.2.13"
69
71
  },
70
72
  "peerDependencies": {
71
- "effect": "4.0.1"
73
+ "effect": "4.1.0"
72
74
  },
73
75
  "publishConfig": {
74
76
  "access": "public"