@voltro/protocol 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +5987 -0
  2. package/README.md +14 -0
  3. package/THIRD-PARTY-NOTICES.md +1122 -31
  4. package/dist/apiRoleEndpoints.js +108 -0
  5. package/dist/apiRoleObservation.js +68 -0
  6. package/dist/apikey.d.ts +10 -0
  7. package/dist/approval.js +64 -0
  8. package/dist/approvalDescriptors.js +26 -0
  9. package/dist/auth.js +389 -0
  10. package/dist/boundedRing.js +27 -0
  11. package/dist/businessRule.js +11 -0
  12. package/dist/canonicalJson.js +14 -0
  13. package/dist/connection.js +73 -0
  14. package/dist/devActivity.js +4 -0
  15. package/dist/errorSchema.js +24 -0
  16. package/dist/errorValue.js +21 -0
  17. package/dist/event.js +110 -0
  18. package/dist/formCapture.js +12 -0
  19. package/dist/httpStreamMaxDuration.js +9 -0
  20. package/dist/idempotency.js +121 -0
  21. package/dist/idempotencyInput.js +123 -0
  22. package/dist/identity.js +5 -9
  23. package/dist/index.d.ts +1095 -139
  24. package/dist/index.js +54 -1700
  25. package/dist/inspect.d.ts +1 -1
  26. package/dist/inspect.js +14 -240
  27. package/dist/inspectBackfill.js +52 -0
  28. package/dist/inspectCommandRejection.js +21 -0
  29. package/dist/inspectProjection.js +133 -0
  30. package/dist/inspectStorageProjection.js +86 -0
  31. package/dist/inspectValueIdentity.js +4 -0
  32. package/dist/inspectWorkflowExecution.js +34 -0
  33. package/dist/inspectWorkflowQueuedStart.js +31 -0
  34. package/dist/jsonSchema.js +54 -0
  35. package/dist/jwt.d.ts +10 -0
  36. package/dist/jwt.js +1 -1
  37. package/dist/outbox.js +10 -0
  38. package/dist/pairing.js +75 -0
  39. package/dist/plugin.js +87 -0
  40. package/dist/pluginAccountMerge.js +88 -0
  41. package/dist/pluginNaming.js +32 -0
  42. package/dist/pluginPrivacy.js +166 -0
  43. package/dist/procedure.js +280 -0
  44. package/dist/publicApi.js +325 -0
  45. package/dist/queryOptionalSources.js +14 -0
  46. package/dist/reactivityChannel.js +34 -0
  47. package/dist/rest.d.ts +260 -64
  48. package/dist/rest.js +345 -499
  49. package/dist/restFormat.js +163 -0
  50. package/dist/restReceipt.js +43 -0
  51. package/dist/revalidate.js +13 -0
  52. package/dist/rowEquality.js +31 -0
  53. package/dist/rowPatch.js +182 -0
  54. package/dist/schemaShape.js +67 -0
  55. package/dist/scopes.js +273 -0
  56. package/dist/secretWindows.js +71 -0
  57. package/dist/serverErrorBus.js +15 -0
  58. package/dist/serviceCall.js +14 -0
  59. package/dist/session.d.ts +89 -6
  60. package/dist/session.js +62 -63
  61. package/dist/{sessionHeader-DriTZhmv.js → sessionHeader.js} +1 -1
  62. package/dist/ssrfPolicy.js +30 -0
  63. package/dist/storageAccess.js +14 -0
  64. package/dist/storeErrors.js +66 -0
  65. package/dist/storeScreenshots.js +90 -0
  66. package/dist/strictInput.js +27 -0
  67. package/dist/subscriptionEvent.js +37 -0
  68. package/dist/tenantSelection.js +40 -0
  69. package/dist/time.js +7 -0
  70. package/dist/undo.js +38 -0
  71. package/dist/validation.js +39 -0
  72. package/dist/webSocketGateway.js +16 -0
  73. package/dist/workflow.js +297 -0
  74. package/dist/workflowAccess.js +61 -0
  75. package/dist/workflowRestart.js +45 -0
  76. package/dist/workflowRetry.js +44 -0
  77. package/dist/workflowStartOutcome.js +30 -0
  78. package/package.json +5 -3
  79. package/dist/restFormat-BlgTLxm1.js +0 -298
  80. package/dist/scopes-ClywBij8.js +0 -548
@@ -0,0 +1,54 @@
1
+ import { Schema as e, SchemaAST as t } from "effect";
2
+ //#region src/jsonSchema.ts
3
+ var n = (e) => typeof e == "object" && !!e && !Array.isArray(e), r = (e, t = /* @__PURE__ */ new Map()) => {
4
+ let n = t.get(e);
5
+ if (n !== void 0) return n;
6
+ let r = i(e, t);
7
+ return t.set(e, r), r;
8
+ }, i = (n, i) => n.encoding === void 0 ? t.isNumber(n) ? e.make(n).check(e.isFinite()).ast : t.isObjects(n) ? new t.Objects(n.propertySignatures.map((e) => new t.PropertySignature(e.name, r(e.type, i))), n.indexSignatures.map((e) => new t.IndexSignature(e.parameter, r(e.type, i))), n.annotations, n.checks, void 0, n.context) : t.isArrays(n) ? new t.Arrays(n.isMutable, n.elements.map((e) => r(e, i)), n.rest.map((e) => r(e, i)), n.annotations, n.checks, void 0, n.context) : t.isUnion(n) ? new t.Union(n.types.map((e) => r(e, i)), n.options, n.annotations, n.checks, void 0, n.context) : t.isSuspend(n) ? new t.Suspend(() => r(n.thunk(), i), n.annotations, n.checks, void 0, n.context) : n : n, a = (e) => {
9
+ if (Array.isArray(e)) return e.map(a);
10
+ if (!n(e)) return e;
11
+ let t = e.not;
12
+ if (n(t) && t.type === "null" && Object.keys(e).length === 1) return {
13
+ type: "object",
14
+ properties: {},
15
+ additionalProperties: !1
16
+ };
17
+ let r = e.anyOf;
18
+ if (Array.isArray(r)) {
19
+ if (r.length === 2) {
20
+ let t = r.find((e) => n(e) && e.type === "number"), i = r.find((e) => n(e) && e.type === "string" && Array.isArray(e.enum) && e.enum.includes("Infinity"));
21
+ if (n(t) && i !== void 0) {
22
+ let { anyOf: n, ...r } = e;
23
+ return a({
24
+ ...r,
25
+ ...t
26
+ });
27
+ }
28
+ }
29
+ if (r.length === 1 && n(r[0])) {
30
+ let { anyOf: t, ...n } = e;
31
+ return a({
32
+ ...n,
33
+ ...r[0]
34
+ });
35
+ }
36
+ }
37
+ let i = {};
38
+ for (let [t, n] of Object.entries(e)) i[t] = a(n);
39
+ return i;
40
+ }, o = (t, n = {}) => {
41
+ let i = e.make(r(t.ast)), o = e.toJsonSchemaDocument(i, n.closed === !1 ? {} : { onExcessProperty: "error" });
42
+ return {
43
+ schema: a(o.schema),
44
+ definitions: a(o.definitions)
45
+ };
46
+ }, s = (e, t = {}) => {
47
+ let { schema: n, definitions: r } = o(e, t);
48
+ return Object.keys(r).length === 0 ? n : {
49
+ ...n,
50
+ $defs: r
51
+ };
52
+ };
53
+ //#endregion
54
+ export { r as finiteNumberView, o as jsonSchemaDocumentOf, s as jsonSchemaOf, a as plainJsonSchema };
package/dist/jwt.d.ts CHANGED
@@ -48,6 +48,13 @@ declare interface AuthStrategy {
48
48
  declare interface AuthStrategyInput {
49
49
  readonly headers: Readonly<Record<string, string | undefined>>;
50
50
  readonly clientId: number;
51
+ /** HTTP request target, supplied by REST transports. Request selectors may
52
+ * read an explicit tenant hint here; it is never authentication or authority.
53
+ * Absent for connection transports and non-HTTP callers. */
54
+ readonly http?: {
55
+ readonly path: string;
56
+ readonly query: string;
57
+ };
51
58
  /**
52
59
  * The app's DataStore, for a strategy that must READ to identify the caller.
53
60
  *
@@ -291,6 +298,9 @@ declare type StrategyResolution = {
291
298
 
292
299
  declare const Subject: Schema.Union<readonly [Schema.Struct<{
293
300
  readonly type: Schema.Literal<"user">;
301
+ /** A guest has a stable identity but has not linked a registered account.
302
+ * This identity mark survives session signing; it never grants authority. */
303
+ readonly kind: Schema.optional<Schema.Literal<"guest">>;
294
304
  readonly id: Schema.String;
295
305
  readonly tenantId: Schema.String;
296
306
  readonly scopes: Schema.optional<Schema.$Array<Schema.String>>;
package/dist/jwt.js CHANGED
@@ -77,7 +77,7 @@ var i = 36e5, a = /* @__PURE__ */ new Map(), o = (e, n) => {
77
77
  if (e instanceof n.JWSInvalid || e instanceof n.JWTInvalid) return new c("malformed jwt", "malformed");
78
78
  if (e instanceof n.JOSEAlgNotAllowed) return new c("jwt algorithm not allowed", "unsupported_algorithm");
79
79
  let t = e?.message ?? String(e);
80
- return /fetch|network|enotfound|econnrefused/i.test(t) ? new c(`jwks unreachable: ${t}`, "jwks_unreachable") : new c(`jwt verify failed: ${t}`, "other");
80
+ return e instanceof n.JWKSTimeout || /fetch|network|enotfound|econnrefused|JSON Web Key Set/i.test(t) ? new c(`jwks unreachable: ${t}`, "jwks_unreachable") : new c(`jwt verify failed: ${t}`, "other");
81
81
  }, v = (t, n, r) => {
82
82
  let i = t.authorization ?? t.Authorization;
83
83
  if (i?.startsWith("Bearer ")) {
package/dist/outbox.js ADDED
@@ -0,0 +1,10 @@
1
+ //#region src/outbox.ts
2
+ function e(e, t) {
3
+ if (typeof e != "object" || !e) throw Error(`Outbox handler ${t}: definition must be an object`);
4
+ let n = e;
5
+ if (typeof n.effect != "string" || n.effect.trim() === "") throw Error(`Outbox handler ${t}: effect must be a non-empty string`);
6
+ if (typeof n.handler != "function") throw Error(`Outbox handler ${t}: handler must be a function`);
7
+ if (n.maxAttempts !== void 0 && (typeof n.maxAttempts != "number" || !Number.isSafeInteger(n.maxAttempts) || n.maxAttempts < 1)) throw Error(`Outbox handler ${t}: maxAttempts must be a positive safe integer`);
8
+ }
9
+ //#endregion
10
+ export { e as validateOutboxHandlerDefinition };
@@ -0,0 +1,75 @@
1
+ //#region src/pairing.ts
2
+ var e = "voltro-dev", t = "pair", n = "voltro:pairing", r = (e) => {
3
+ try {
4
+ let t = new URL(e);
5
+ return t.protocol === "http:" || t.protocol === "https:";
6
+ } catch {
7
+ return !1;
8
+ }
9
+ }, i = (e) => {
10
+ try {
11
+ let t = new URL(e).hostname;
12
+ return t === "localhost" || t === "127.0.0.1" || t === "::1" || t === "[::1]";
13
+ } catch {
14
+ return !1;
15
+ }
16
+ }, a = (n) => {
17
+ if (!r(n.api)) throw Error(`pairingLink: api must be an http(s) url, got ${JSON.stringify(n.api)}`);
18
+ if (i(n.api)) throw Error("pairingLink: api must be the LAN address — a device cannot reach localhost on this machine");
19
+ if (!/^[A-Za-z0-9_-]+$/.test(n.name)) throw Error(`pairingLink: name must be a plain identifier, got ${JSON.stringify(n.name)}`);
20
+ let a = new URLSearchParams({
21
+ api: n.api,
22
+ name: n.name
23
+ });
24
+ return n.token !== void 0 && n.token.length > 0 && a.set("token", n.token), `${e}://${t}?${a.toString()}`;
25
+ }, o = (e) => {
26
+ let t;
27
+ try {
28
+ t = new URL(e);
29
+ } catch {
30
+ return null;
31
+ }
32
+ if (t.protocol !== "voltro-dev:" || (t.host || t.pathname.replace(/^\/+/, "")) !== "pair") return null;
33
+ let n = t.searchParams.get("api") ?? "", a = t.searchParams.get("name") ?? "", o = t.searchParams.get("token");
34
+ return !r(n) || i(n) || !/^[A-Za-z0-9_-]+$/.test(a) ? null : {
35
+ api: n,
36
+ name: a,
37
+ ...o !== null && o.length > 0 ? { token: o } : {}
38
+ };
39
+ }, s = (e) => "getItem" in e ? {
40
+ get: async (t) => e.getItem(t),
41
+ set: async (t, n) => {
42
+ await e.setItem(t, n);
43
+ },
44
+ remove: e.removeItem ? async (t) => {
45
+ await e.removeItem(t);
46
+ } : null
47
+ } : {
48
+ get: async (t) => e.get(t),
49
+ set: async (t, n) => {
50
+ await e.set(t, n);
51
+ },
52
+ remove: e.remove ? async (t) => {
53
+ await e.remove(t);
54
+ } : null
55
+ }, c = async (e, t) => {
56
+ await s(e).set(n, JSON.stringify(t));
57
+ }, l = async (e) => {
58
+ let t = await s(e).get(n);
59
+ if (t === null || t === "") return null;
60
+ try {
61
+ let e = JSON.parse(t);
62
+ return typeof e.api != "string" || typeof e.name != "string" || !r(e.api) ? null : {
63
+ api: e.api,
64
+ name: e.name,
65
+ ...typeof e.token == "string" && e.token.length > 0 ? { token: e.token } : {}
66
+ };
67
+ } catch {
68
+ return null;
69
+ }
70
+ }, u = async (e) => {
71
+ let t = s(e);
72
+ t.remove ? await t.remove(n) : await t.set(n, "");
73
+ };
74
+ //#endregion
75
+ export { t as PAIRING_HOST, e as PAIRING_SCHEME, n as PAIRING_STORAGE_KEY, c as applyPairing, u as clearPairing, a as pairingLink, o as parsePairingLink, l as readPairing };
package/dist/plugin.js ADDED
@@ -0,0 +1,87 @@
1
+ import { Context as e, Layer as t } from "effect";
2
+ //#region src/plugin.ts
3
+ var n = Object.freeze([
4
+ "rpc",
5
+ "subscriptions",
6
+ "events",
7
+ "presence",
8
+ "workflows",
9
+ "schedules",
10
+ "directors",
11
+ "drainers",
12
+ "reapers",
13
+ "retention",
14
+ "rest",
15
+ "webhooks",
16
+ "inspect",
17
+ "cdc"
18
+ ]), r = (e) => e, i = (e) => e, a = (e) => {
19
+ let t = e.alias?.trim(), n = e.instance?.trim(), r = t !== void 0 && t !== "" ? t : e.base;
20
+ return n !== void 0 && n !== "" ? `${r}#${n}` : r;
21
+ }, o = (e) => {
22
+ if (e.length !== 0) return (t, n) => e.reduceRight((e, t) => t(e, n), t);
23
+ }, s = (n, r) => {
24
+ let i = e.Service(n);
25
+ return {
26
+ Tag: i,
27
+ Live: t.succeed(i, r)
28
+ };
29
+ }, c = (e, t, n) => {
30
+ if (!t) return { ok: !0 };
31
+ let r = n === void 0 ? null : l(n);
32
+ if (!r) return {
33
+ ok: !0,
34
+ unverified: `plugin "${e}" requires framework ${t}, but the running framework version is ${n === void 0 ? "unknown" : `unreadable ("${n}")`} — not checked.`
35
+ };
36
+ let i = t.trim();
37
+ if (i === "*" || i === "") return { ok: !0 };
38
+ let a = i.split(/\s+/);
39
+ for (let i of a) if (!d(i, r)) return {
40
+ ok: !1,
41
+ reason: `plugin "${e}" requires framework ${t}, running ${n}`
42
+ };
43
+ return { ok: !0 };
44
+ }, l = (e) => {
45
+ let t = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9a-zA-Z.-]+))?$/.exec(e.trim());
46
+ return t ? {
47
+ major: Number(t[1]),
48
+ minor: Number(t[2]),
49
+ patch: Number(t[3]),
50
+ pre: t[4] ?? ""
51
+ } : null;
52
+ }, u = (e, t) => e.major === t.major ? e.minor === t.minor ? e.patch === t.patch ? e.pre && !t.pre ? -1 : !e.pre && t.pre ? 1 : e.pre && t.pre ? e.pre < t.pre ? -1 : +(e.pre > t.pre) : 0 : e.patch - t.patch : e.minor - t.minor : e.major - t.major, d = (e, t) => {
53
+ if (e === "*") return !0;
54
+ if (e.startsWith("^")) {
55
+ let n = l(e.slice(1));
56
+ return !n || t.major !== n.major ? !1 : u(t, n) >= 0;
57
+ }
58
+ if (e.startsWith("~")) {
59
+ let n = l(e.slice(1));
60
+ return !n || t.major !== n.major || t.minor !== n.minor ? !1 : u(t, n) >= 0;
61
+ }
62
+ let n = /^(>=|<=|>|<)(.+)$/.exec(e);
63
+ if (n) {
64
+ let e = n[1], r = l(n[2]);
65
+ if (!r) return !1;
66
+ let i = u(t, r);
67
+ if (e === ">=") return i >= 0;
68
+ if (e === "<=") return i <= 0;
69
+ if (e === ">") return i > 0;
70
+ if (e === "<") return i < 0;
71
+ }
72
+ let r = l(e);
73
+ return r ? u(t, r) === 0 : !1;
74
+ }, f = (e) => {
75
+ let t = e.flatMap((e) => e.bindReplayAuthority === void 0 ? [] : [e.bindReplayAuthority]);
76
+ if (t.length !== 0) {
77
+ if (t.some((e) => typeof e != "function")) throw Error("Invalid replay authority binding");
78
+ return (e) => {
79
+ for (let n of t) {
80
+ let t = n(e);
81
+ if (t !== void 0) throw t instanceof Promise && t.catch(() => void 0), Error("Replay authority bindings must complete synchronously");
82
+ }
83
+ };
84
+ }
85
+ };
86
+ //#endregion
87
+ export { n as API_WORKLOADS, c as checkFrameworkCompat, f as composeReplayAuthorityBindings, o as composeRpcInterceptors, r as definePlugin, i as definePluginRoute, s as definePluginService, a as pluginInstanceName };
@@ -0,0 +1,88 @@
1
+ import { Effect as e, Schema as t } from "effect";
2
+ //#region src/pluginAccountMerge.ts
3
+ var n = class extends t.TaggedError()("PluginAccountMergeFailure", {
4
+ code: t.Literals([
5
+ "invalid_request",
6
+ "coverage_missing",
7
+ "hook_failed"
8
+ ]),
9
+ requestId: t.String,
10
+ plugin: t.NullOr(t.String),
11
+ returned: t.Array(t.String),
12
+ missing: t.Array(t.String)
13
+ }) {}, r = (e) => typeof e == "object" && e && "tableName" in e && typeof e.tableName == "string" ? e.tableName : void 0, i = (t) => {
14
+ let i = /* @__PURE__ */ new Set(), a = t.map((e) => {
15
+ if (i.has(e.name)) throw Error("Duplicate account merge plugin instance: " + e.name);
16
+ i.add(e.name);
17
+ let t = e.subjectMerge;
18
+ if ((t !== void 0 || e.onMergeAccounts !== void 0) && (t === void 0 || e.onMergeAccounts === void 0 || t.kinds.length === 0 || t.kinds.some((e) => e !== "user" && e !== "guest") || new Set(t.kinds).size !== t.kinds.length || t.tables.some((e) => typeof e != "string" || !e.trim()) || new Set(t.tables).size !== t.tables.length)) throw Error("Account merge requires a valid declaration and hook: " + e.name);
19
+ return {
20
+ name: e.name,
21
+ tables: (e.extendSchema?.tables ?? []).map(r),
22
+ declaration: t === void 0 ? void 0 : {
23
+ tables: [...t.tables],
24
+ kinds: [...t.kinds]
25
+ },
26
+ hook: e.onMergeAccounts
27
+ };
28
+ }), o = (e) => {
29
+ let t = [], n = [];
30
+ for (let r of a) if (r.declaration?.kinds.includes(e) && r.hook) {
31
+ t.push({
32
+ name: r.name,
33
+ tables: Object.freeze([...r.declaration.tables])
34
+ });
35
+ for (let e of r.tables) (e === void 0 || !r.declaration.tables.includes(e)) && n.push(r.name);
36
+ } else (r.tables.length > 0 || r.declaration !== void 0) && n.push(r.name);
37
+ return {
38
+ participants: Object.freeze(t),
39
+ missing: Object.freeze([...new Set(n)])
40
+ };
41
+ };
42
+ return {
43
+ coverage: o,
44
+ mergeInTransaction: (t) => e.gen(function* () {
45
+ if (![
46
+ t.requestId,
47
+ t.tenantId,
48
+ t.sourceId,
49
+ t.targetId
50
+ ].every((e) => typeof e == "string" && e.trim().length > 0 && e.length <= 256) || t.sourceKind !== "user" && t.sourceKind !== "guest" || t.sourceId === t.targetId || t.store === void 0) return yield* e.fail(new n({
51
+ code: "invalid_request",
52
+ requestId: typeof t.requestId == "string" ? t.requestId.slice(0, 256) : "",
53
+ plugin: null,
54
+ returned: [],
55
+ missing: []
56
+ }));
57
+ let r = o(t.sourceKind);
58
+ if (r.missing.length > 0) return yield* e.fail(new n({
59
+ code: "coverage_missing",
60
+ requestId: t.requestId,
61
+ plugin: null,
62
+ returned: [],
63
+ missing: [...r.missing]
64
+ }));
65
+ let i = [], s = Object.freeze({
66
+ requestId: t.requestId,
67
+ tenantId: t.tenantId,
68
+ sourceId: t.sourceId,
69
+ sourceKind: t.sourceKind,
70
+ targetId: t.targetId,
71
+ store: t.store
72
+ });
73
+ for (let t of r.participants) {
74
+ let r = a.find((e) => e.name === t.name);
75
+ yield* e.suspend(() => r.hook(s)).pipe(e.catchCause(() => e.fail(new n({
76
+ code: "hook_failed",
77
+ requestId: s.requestId,
78
+ plugin: t.name,
79
+ returned: [...i],
80
+ missing: []
81
+ })))), i.push(t.name);
82
+ }
83
+ return Object.freeze(i);
84
+ })
85
+ };
86
+ };
87
+ //#endregion
88
+ export { n as PluginAccountMergeFailure, i as createPluginAccountMergeRegistry };
@@ -0,0 +1,32 @@
1
+ //#region src/pluginNaming.ts
2
+ var e = (e) => {
3
+ let t = e.startsWith("@") ? e.replace(/^@[^/]+\//, "") : e;
4
+ return (t.startsWith("plugin-") ? t.slice(7) : t).replace(/-([a-zA-Z0-9])/g, (e, t) => t.toUpperCase());
5
+ }, t = (e) => {
6
+ let t = e.startsWith("@") ? e.replace(/^@[^/]+\//, "") : e;
7
+ return (t.startsWith("plugin-") ? t.slice(7) : t).replace(/#/g, "--").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
8
+ }, n = Symbol.for("@voltro/protocol/pluginAliases"), r = () => {
9
+ let e = globalThis, t = e[n];
10
+ if (t instanceof Map) return t;
11
+ let r = /* @__PURE__ */ new Map();
12
+ return e[n] = r, r;
13
+ }, i = (e) => {
14
+ let t = r();
15
+ for (let [n, r] of Object.entries(e)) {
16
+ if (r === "") continue;
17
+ let e = t.get(n);
18
+ e === void 0 ? t.set(n, /* @__PURE__ */ new Set([r])) : e.add(r);
19
+ }
20
+ }, a = () => {
21
+ r().clear();
22
+ }, o = (t, n) => {
23
+ let i = r().get(t);
24
+ if (i === void 0 || i.size === 0) return `${e(t)}.${n}`;
25
+ if (i.size === 1) for (let e of i) return `${e}.${n}`;
26
+ let a, o = 0;
27
+ for (let e of i) e.includes("#") || (a = e, o++);
28
+ if (o === 1) return `${a}.${n}`;
29
+ throw Error(`[voltro] ${t} is installed more than once (${[...i].sort().join(", ")}) and no single install is the primary one, so a plugin hook cannot tell which of them it addresses. Call the route by its full tag instead — e.g. useSubscription(api, '${[...i].sort()[0]}.${n}').`);
30
+ };
31
+ //#endregion
32
+ export { e as pluginAlias, t as pluginSlug, o as pluginTag, i as registerPluginAliases, a as resetPluginAliases };
@@ -0,0 +1,166 @@
1
+ import { Effect as e, Schema as t } from "effect";
2
+ //#region src/pluginPrivacy.ts
3
+ var n = t.Literals([
4
+ "prepare",
5
+ "data",
6
+ "identity",
7
+ "finalize"
8
+ ]), r = class extends t.TaggedError()("PluginPrivacyFailure", {
9
+ code: t.Literals([
10
+ "invalid_request",
11
+ "coverage_missing",
12
+ "hook_failed",
13
+ "unavailable"
14
+ ]),
15
+ operation: t.Literals(["export", "erase"]),
16
+ requestId: t.String,
17
+ plugin: t.NullOr(t.String),
18
+ completed: t.Array(t.String),
19
+ missing: t.Array(t.String)
20
+ }) {}, i = (e) => typeof e == "object" && e && "tableName" in e && typeof e.tableName == "string" ? e.tableName : void 0, a = (e) => {
21
+ let t = /* @__PURE__ */ new Set(), n = (e) => {
22
+ if (e === null || typeof e == "string" || typeof e == "boolean" || typeof e == "number" && Number.isFinite(e)) return;
23
+ if (typeof e != "object" || !e || t.has(e)) throw Error("Invalid privacy JSON");
24
+ let r = Array.isArray(e), i = Object.getPrototypeOf(e);
25
+ if (r && i !== Array.prototype || !r && i !== Object.prototype && i !== null || Object.getOwnPropertySymbols(e).length !== 0) throw Error("Invalid privacy JSON");
26
+ t.add(e);
27
+ let a = Object.getOwnPropertyDescriptors(e);
28
+ if (r) {
29
+ let e = a.length?.value;
30
+ if (typeof e != "number" || Object.keys(a).length !== e + 1) throw Error("Invalid privacy JSON");
31
+ for (let t = 0; t < e; t++) {
32
+ let e = a[t];
33
+ if (!e || !e.enumerable || !("value" in e)) throw Error("Invalid privacy JSON");
34
+ n(e.value);
35
+ }
36
+ } else for (let e of Object.values(a)) {
37
+ if (!e.enumerable || !("value" in e)) throw Error("Invalid privacy JSON");
38
+ n(e.value);
39
+ }
40
+ t.delete(e);
41
+ };
42
+ return n(e), JSON.parse(JSON.stringify(e));
43
+ }, o = (o) => {
44
+ let s = /* @__PURE__ */ new Set(), c = o.map((e) => {
45
+ if (s.has(e.name)) throw Error(`Duplicate privacy plugin instance: ${e.name}`);
46
+ s.add(e.name);
47
+ let r = e.subjectPrivacy, a = [...e.extendSchema?.tables ?? []].map(i);
48
+ if (r !== void 0 || e.onErase !== void 0 || e.onExport !== void 0) {
49
+ if (r === void 0 || e.onErase === void 0 || e.onExport === void 0) throw Error(`Subject privacy requires a declaration and both hooks: ${e.name}`);
50
+ if (r.kinds.length === 0 || r.kinds.some((e) => e !== "user" && e !== "guest") || new Set(r.kinds).size !== r.kinds.length || r.tables.some((e) => typeof e != "string" || !e.trim()) || new Set(r.tables).size !== r.tables.length || r.erasePhase !== void 0 && !t.is(n)(r.erasePhase)) throw Error(`Invalid subject privacy declaration: ${e.name}`);
51
+ }
52
+ return {
53
+ name: e.name,
54
+ tables: a,
55
+ declaration: r === void 0 ? void 0 : {
56
+ tables: [...r.tables],
57
+ kinds: [...r.kinds],
58
+ erasePhase: r.erasePhase ?? "data"
59
+ },
60
+ onErase: e.onErase,
61
+ onExport: e.onExport
62
+ };
63
+ });
64
+ for (let e of ["user", "guest"]) if (c.filter((t) => t.declaration?.erasePhase === "finalize" && t.declaration.kinds.includes(e)).length > 1) throw Error(`Subject privacy allows one completion owner per kind: ${e}`);
65
+ let l = (e) => {
66
+ let t = [], n = [];
67
+ for (let r of c) {
68
+ let i = r.declaration;
69
+ (i === void 0 || i.kinds.includes(e)) && (i !== void 0 && t.push({
70
+ name: r.name,
71
+ tables: [...i.tables],
72
+ erasePhase: i.erasePhase
73
+ }), r.tables.some((e) => e === void 0 || !i?.tables.includes(e)) && n.push(r.name));
74
+ }
75
+ return {
76
+ participants: t,
77
+ missing: n
78
+ };
79
+ }, u = (t, n) => e.gen(function* () {
80
+ let i = typeof t?.requestId == "string" ? t.requestId : "", a = t?.target;
81
+ if (!i.trim() || typeof a?.subjectId != "string" || !a.subjectId.trim() || !(a.tenantId === null || typeof a.tenantId == "string" && a.tenantId.trim()) || a.kind !== "user" && a.kind !== "guest") return yield* e.fail(new r({
82
+ code: "invalid_request",
83
+ operation: n,
84
+ requestId: i,
85
+ plugin: null,
86
+ completed: [],
87
+ missing: []
88
+ }));
89
+ let o = l(a.kind);
90
+ return o.missing.length > 0 || o.participants.length === 0 ? yield* e.fail(new r({
91
+ code: "coverage_missing",
92
+ operation: n,
93
+ requestId: i,
94
+ plugin: null,
95
+ completed: [],
96
+ missing: o.missing
97
+ })) : {
98
+ requestId: i,
99
+ target: Object.freeze({
100
+ subjectId: a.subjectId,
101
+ tenantId: a.tenantId,
102
+ kind: a.kind
103
+ }),
104
+ context: Object.freeze({
105
+ requestId: i,
106
+ tenantId: a.tenantId,
107
+ kind: a.kind
108
+ }),
109
+ participants: o.participants
110
+ };
111
+ });
112
+ return {
113
+ coverage: l,
114
+ exportSubject: (t) => e.gen(function* () {
115
+ let n = yield* u(t, "export"), i = [];
116
+ for (let t of n.participants) {
117
+ let o = c.find((e) => e.name === t.name).onExport, s = yield* e.suspend(() => o(n.target.subjectId, n.context)).pipe(e.map(a), e.catchCause(() => e.fail(new r({
118
+ code: "hook_failed",
119
+ operation: "export",
120
+ requestId: n.requestId,
121
+ plugin: t.name,
122
+ completed: i.map((e) => e.name),
123
+ missing: []
124
+ }))));
125
+ i.push({
126
+ name: t.name,
127
+ data: s
128
+ });
129
+ }
130
+ return {
131
+ requestId: n.requestId,
132
+ target: n.target,
133
+ plugins: i
134
+ };
135
+ }),
136
+ eraseSubject: (t) => e.gen(function* () {
137
+ let n = yield* u(t, "erase"), i = [], a = [
138
+ ...n.participants.filter((e) => e.erasePhase === "prepare"),
139
+ ...n.participants.filter((e) => e.erasePhase === "data"),
140
+ ...n.participants.filter((e) => e.erasePhase === "identity"),
141
+ ...n.participants.filter((e) => e.erasePhase === "finalize")
142
+ ];
143
+ for (let t of a) {
144
+ let a = c.find((e) => e.name === t.name).onErase, o = t.erasePhase === "finalize" ? Object.freeze({
145
+ ...n.context,
146
+ completed: Object.freeze([...i])
147
+ }) : n.context;
148
+ yield* e.suspend(() => a(n.target.subjectId, o)).pipe(e.catchCause(() => e.fail(new r({
149
+ code: "hook_failed",
150
+ operation: "erase",
151
+ requestId: n.requestId,
152
+ plugin: t.name,
153
+ completed: [...i],
154
+ missing: []
155
+ })))), i.push(t.name);
156
+ }
157
+ return {
158
+ requestId: n.requestId,
159
+ target: n.target,
160
+ completed: i
161
+ };
162
+ })
163
+ };
164
+ };
165
+ //#endregion
166
+ export { n as PluginPrivacyErasePhaseSchema, r as PluginPrivacyFailure, o as createPluginPrivacyRegistry };