@voltro/plugin-sanctions 0.0.0-stage → 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.
@@ -0,0 +1,96 @@
1
+ import { POINTS as e } from "./contract.js";
2
+ import { sanctionsError as t } from "./errors.js";
3
+ // src/admission.server.ts
4
+ var n = (e, n) => {
5
+ if (!e || typeof e != "object" || Array.isArray(e) || ![Object.prototype, null].includes(Object.getPrototypeOf(e))) throw t("invalid_input");
6
+ let r = Object.create(null);
7
+ for (let i of Reflect.ownKeys(e)) {
8
+ let a = Object.getOwnPropertyDescriptor(e, i);
9
+ if (typeof i != "string" || !n.includes(i) || !a || !("value" in a) || !a.enumerable) throw t("invalid_input");
10
+ r[i] = a.value;
11
+ }
12
+ return Object.freeze(r);
13
+ }, r = (r, i) => {
14
+ let a = n(r, i ? [
15
+ "point",
16
+ "at",
17
+ "context",
18
+ "expected"
19
+ ] : [
20
+ "point",
21
+ "at",
22
+ "context"
23
+ ]);
24
+ if (!e.includes(a.point) || typeof a.at != "number" || !Number.isSafeInteger(a.at) || a.at < 0 || a.at > 864e13) throw t("invalid_input");
25
+ let o = a.context === void 0 ? {} : n(a.context, ["channelId", "queueId"]), s = {};
26
+ for (let e of ["channelId", "queueId"]) if (o[e] !== void 0) {
27
+ let n = o[e];
28
+ if (typeof n != "string" || !n.trim() || n.length > 256 || n.includes("\0") || n === "~") throw t("invalid_input");
29
+ s[e] = n;
30
+ }
31
+ let c;
32
+ if (i) {
33
+ let e = n(a.expected, ["allowed", "trustScore"]);
34
+ if (typeof e.allowed != "boolean" || typeof e.trustScore != "number" || !Number.isSafeInteger(e.trustScore) || e.trustScore < 0 || e.trustScore > 100) throw t("invalid_input");
35
+ c = Object.freeze({
36
+ allowed: e.allowed,
37
+ trustScore: e.trustScore
38
+ });
39
+ }
40
+ return Object.freeze({
41
+ point: a.point,
42
+ at: a.at,
43
+ context: Object.freeze(s),
44
+ expected: c
45
+ });
46
+ }, i = (e) => {
47
+ let i = n(e, [
48
+ "tenantId",
49
+ "participants",
50
+ "point",
51
+ "at",
52
+ "context"
53
+ ]), a = i.tenantId;
54
+ if (typeof a != "string" || !a.trim() || a.length > 256 || a.includes("\0") || a === "~" || !Array.isArray(i.participants) || i.participants.length < 1 || i.participants.length > 32) throw t("invalid_input");
55
+ let o = Object.getOwnPropertyDescriptors(i.participants);
56
+ if (Reflect.ownKeys(o).length !== i.participants.length + 1) throw t("invalid_input");
57
+ let s = [];
58
+ for (let e = 0; e < i.participants.length; e++) {
59
+ let a = o[String(e)];
60
+ if (!a || !("value" in a) || !a.enumerable) throw t("invalid_input");
61
+ let c = n(a.value, ["ownerId", "expected"]), l = c.ownerId;
62
+ if (typeof l != "string" || !l.trim() || l.length > 256 || l.includes("\0") || l === "~") throw t("invalid_input");
63
+ let u = r({
64
+ point: i.point,
65
+ at: i.at,
66
+ context: i.context,
67
+ expected: c.expected
68
+ }, !0);
69
+ if (!u.expected) throw t("invalid_input");
70
+ s.push(Object.freeze({
71
+ ownerId: l,
72
+ expected: u.expected
73
+ }));
74
+ }
75
+ if (new Set(s.map((e) => e.ownerId)).size !== s.length) throw t("invalid_input");
76
+ let c = r({
77
+ point: i.point,
78
+ at: i.at,
79
+ context: i.context
80
+ }, !1);
81
+ return Object.freeze({
82
+ tenantId: a,
83
+ point: c.point,
84
+ at: c.at,
85
+ context: c.context,
86
+ participants: Object.freeze(s)
87
+ });
88
+ }, a = (e) => {
89
+ if (e instanceof Date) return JSON.stringify(e.toISOString());
90
+ if (Array.isArray(e)) return "[" + e.map(a).join(",") + "]";
91
+ if (typeof e == "object" && e) return "{" + Object.keys(e).sort().map((t) => JSON.stringify(t) + ":" + a(e[t])).join(",") + "}";
92
+ let n = JSON.stringify(e);
93
+ if (n === void 0) throw t("unavailable");
94
+ return n;
95
+ };
96
+ export { a as canonicalSanctionsRecords, r as captureSanctionsAdmission, i as captureSanctionsAdmissionBatch };
@@ -0,0 +1,282 @@
1
+ import { CATEGORIES as e } from "./contract.js";
2
+ import { useId as t } from "react";
3
+ import { Button as n, Textarea as r } from "@voltro/ui-shadcn";
4
+ import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
5
+ // src/components.tsx
6
+ var s = {
7
+ en: {
8
+ reportTitle: "Report player",
9
+ category: "Category",
10
+ note: "What happened?",
11
+ report: "Submit report",
12
+ cancel: "Cancel",
13
+ pending: "Request pending. Keep this draft for recovery.",
14
+ appealTitle: "Request a review",
15
+ appealText: "Why should this measure be reviewed?",
16
+ appeal: "Submit appeal",
17
+ expires: "Ends",
18
+ permanent: "No end date",
19
+ scopeLoading: "Waiting for this account’s observation.",
20
+ noActions: "No active measures in this observation.",
21
+ noticeTitle: "Account measures",
22
+ categories: {
23
+ cheating: "Cheating",
24
+ abuse: "Abuse",
25
+ name: "Player name",
26
+ spam: "Spam",
27
+ griefing: "Griefing",
28
+ rmt: "Real-money trading"
29
+ },
30
+ kinds: {
31
+ warn: "Warning",
32
+ mute: "Chat mute",
33
+ chatBan: "Chat restriction",
34
+ matchmakingBan: "Matchmaking restriction",
35
+ rankedBan: "Ranked restriction",
36
+ tradeBan: "Trading restriction",
37
+ ban: "Account restriction",
38
+ shadowBan: "Matchmaking measure",
39
+ nameReset: "Name review",
40
+ rollback: "Progress review"
41
+ }
42
+ },
43
+ de: {
44
+ reportTitle: "Spieler melden",
45
+ category: "Kategorie",
46
+ note: "Was ist passiert?",
47
+ report: "Meldung senden",
48
+ cancel: "Abbrechen",
49
+ pending: "Anfrage läuft. Entwurf zur Wiederaufnahme behalten.",
50
+ appealTitle: "Prüfung beantragen",
51
+ appealText: "Warum soll diese Maßnahme geprüft werden?",
52
+ appeal: "Einspruch senden",
53
+ expires: "Endet",
54
+ permanent: "Ohne Enddatum",
55
+ scopeLoading: "Beobachtung dieses Kontos wird geladen.",
56
+ noActions: "Keine aktiven Maßnahmen in dieser Beobachtung.",
57
+ noticeTitle: "Kontomaßnahmen",
58
+ categories: {
59
+ cheating: "Cheating",
60
+ abuse: "Beleidigung",
61
+ name: "Spielername",
62
+ spam: "Spam",
63
+ griefing: "Griefing",
64
+ rmt: "Echtgeldhandel"
65
+ },
66
+ kinds: {
67
+ warn: "Warnung",
68
+ mute: "Chat-Stummschaltung",
69
+ chatBan: "Chat-Einschränkung",
70
+ matchmakingBan: "Matchmaking-Einschränkung",
71
+ rankedBan: "Ranglisten-Einschränkung",
72
+ tradeBan: "Handels-Einschränkung",
73
+ ban: "Konto-Einschränkung",
74
+ shadowBan: "Matchmaking-Maßnahme",
75
+ nameReset: "Namensprüfung",
76
+ rollback: "Fortschrittsprüfung"
77
+ }
78
+ }
79
+ }, c = ({ scopeKey: i, dataScopeKey: c, targetId: l, draft: u, pending: d = !1, error: f, labels: p = s.en, onChange: m, onSubmit: h, onCancel: g, maxNoteLength: _ = 4e3 }) => {
80
+ let v = t(), y = i === c, b = y && !d && l.trim().length > 0 && [...u.note].length <= _;
81
+ return /* @__PURE__ */ o("section", {
82
+ role: "dialog",
83
+ "aria-modal": "false",
84
+ "aria-labelledby": v + "-title",
85
+ className: "space-y-4 rounded-lg border p-4",
86
+ children: [/* @__PURE__ */ a("h2", {
87
+ id: v + "-title",
88
+ className: "text-lg font-semibold",
89
+ children: p.reportTitle
90
+ }), y ? /* @__PURE__ */ o("form", {
91
+ className: "space-y-4",
92
+ onSubmit: (e) => {
93
+ e.preventDefault(), b && h();
94
+ },
95
+ children: [
96
+ /* @__PURE__ */ o("div", {
97
+ className: "space-y-2",
98
+ children: [/* @__PURE__ */ a("label", {
99
+ htmlFor: v + "-category",
100
+ children: p.category
101
+ }), /* @__PURE__ */ a("select", {
102
+ id: v + "-category",
103
+ value: u.category,
104
+ disabled: d,
105
+ className: "w-full rounded-md border bg-background px-3 py-2",
106
+ onChange: (t) => {
107
+ !d && e.includes(t.target.value) && m({
108
+ ...u,
109
+ category: t.target.value
110
+ });
111
+ },
112
+ children: e.map((e) => /* @__PURE__ */ a("option", {
113
+ value: e,
114
+ children: p.categories[e]
115
+ }, e))
116
+ })]
117
+ }),
118
+ /* @__PURE__ */ o("div", {
119
+ className: "space-y-2",
120
+ children: [/* @__PURE__ */ a("label", {
121
+ htmlFor: v + "-note",
122
+ children: p.note
123
+ }), /* @__PURE__ */ a(r, {
124
+ id: v + "-note",
125
+ value: u.note,
126
+ readOnly: d,
127
+ onChange: (e) => {
128
+ d || m({
129
+ ...u,
130
+ note: e.target.value
131
+ });
132
+ },
133
+ "aria-describedby": d ? v + "-pending" : void 0
134
+ })]
135
+ }),
136
+ d ? /* @__PURE__ */ a("p", {
137
+ id: v + "-pending",
138
+ role: "status",
139
+ className: "text-sm text-muted-foreground",
140
+ children: p.pending
141
+ }) : null,
142
+ f ? /* @__PURE__ */ a("p", {
143
+ role: "alert",
144
+ className: "text-sm text-destructive",
145
+ children: f
146
+ }) : null,
147
+ /* @__PURE__ */ o("div", {
148
+ className: "flex flex-wrap gap-2",
149
+ children: [/* @__PURE__ */ a(n, {
150
+ type: "submit",
151
+ "aria-disabled": !b,
152
+ children: p.report
153
+ }), /* @__PURE__ */ a(n, {
154
+ type: "button",
155
+ variant: "outline",
156
+ "aria-disabled": d,
157
+ onClick: () => {
158
+ d || g();
159
+ },
160
+ children: p.cancel
161
+ })]
162
+ })
163
+ ]
164
+ }) : /* @__PURE__ */ a("p", {
165
+ role: "status",
166
+ className: "text-sm text-muted-foreground",
167
+ children: p.scopeLoading
168
+ })]
169
+ });
170
+ }, l = ({ scopeKey: e, dataScopeKey: t, actions: r, appeals: c = [], locale: l = "en", labels: u = s[l], onAppeal: d }) => {
171
+ let f = e === t;
172
+ return /* @__PURE__ */ a("section", {
173
+ className: "space-y-4",
174
+ "aria-label": u.noticeTitle,
175
+ children: f ? r.length === 0 ? /* @__PURE__ */ a("p", {
176
+ className: "text-sm text-muted-foreground",
177
+ children: u.noActions
178
+ }) : /* @__PURE__ */ a("ul", {
179
+ className: "space-y-3",
180
+ children: r.map((e) => /* @__PURE__ */ o("li", {
181
+ className: "space-y-2 rounded-lg border p-4",
182
+ children: [
183
+ /* @__PURE__ */ a("h3", {
184
+ className: "font-medium",
185
+ children: u.kinds[e.kind]
186
+ }),
187
+ /* @__PURE__ */ a("p", {
188
+ className: "whitespace-pre-wrap break-words text-sm",
189
+ children: e.publicReason
190
+ }),
191
+ /* @__PURE__ */ a("p", {
192
+ className: "text-sm text-muted-foreground",
193
+ children: e.until === null ? u.permanent : /* @__PURE__ */ o(i, { children: [
194
+ u.expires,
195
+ " ",
196
+ /* @__PURE__ */ a("time", {
197
+ dateTime: new Date(e.until).toISOString(),
198
+ children: new Date(e.until).toLocaleString(l)
199
+ })
200
+ ] })
201
+ }),
202
+ e.appealable && d && !c.some((t) => t.actionId === e.id) ? /* @__PURE__ */ a(n, {
203
+ type: "button",
204
+ variant: "outline",
205
+ onClick: () => d(e.id),
206
+ children: u.appealTitle
207
+ }) : null
208
+ ]
209
+ }, e.id))
210
+ }) : /* @__PURE__ */ a("p", {
211
+ role: "status",
212
+ children: u.scopeLoading
213
+ })
214
+ });
215
+ }, u = ({ scopeKey: e, dataScopeKey: i, action: c, text: l, pending: u = !1, error: d, labels: f = s.en, onChange: p, onSubmit: m, onCancel: h, maxTextLength: g = 4e3 }) => {
216
+ let _ = t(), v = e === i, y = v && !u && c.appealable && l.trim().length > 0 && [...l].length <= g;
217
+ return /* @__PURE__ */ o("section", {
218
+ role: "dialog",
219
+ "aria-modal": "false",
220
+ "aria-labelledby": _ + "-title",
221
+ className: "space-y-4 rounded-lg border p-4",
222
+ children: [/* @__PURE__ */ a("h2", {
223
+ id: _ + "-title",
224
+ className: "text-lg font-semibold",
225
+ children: f.appealTitle
226
+ }), v ? /* @__PURE__ */ o("form", {
227
+ className: "space-y-4",
228
+ onSubmit: (e) => {
229
+ e.preventDefault(), y && m();
230
+ },
231
+ children: [
232
+ /* @__PURE__ */ a("p", {
233
+ className: "whitespace-pre-wrap break-words text-sm",
234
+ children: c.publicReason
235
+ }),
236
+ /* @__PURE__ */ a("label", {
237
+ htmlFor: _ + "-text",
238
+ className: "block",
239
+ children: f.appealText
240
+ }),
241
+ /* @__PURE__ */ a(r, {
242
+ id: _ + "-text",
243
+ value: l,
244
+ readOnly: u,
245
+ onChange: (e) => {
246
+ u || p(e.target.value);
247
+ }
248
+ }),
249
+ u ? /* @__PURE__ */ a("p", {
250
+ role: "status",
251
+ className: "text-sm text-muted-foreground",
252
+ children: f.pending
253
+ }) : null,
254
+ d ? /* @__PURE__ */ a("p", {
255
+ role: "alert",
256
+ className: "text-sm text-destructive",
257
+ children: d
258
+ }) : null,
259
+ /* @__PURE__ */ o("div", {
260
+ className: "flex flex-wrap gap-2",
261
+ children: [/* @__PURE__ */ a(n, {
262
+ type: "submit",
263
+ "aria-disabled": !y,
264
+ children: f.appeal
265
+ }), /* @__PURE__ */ a(n, {
266
+ type: "button",
267
+ variant: "outline",
268
+ "aria-disabled": u,
269
+ onClick: () => {
270
+ u || h();
271
+ },
272
+ children: f.cancel
273
+ })]
274
+ })
275
+ ]
276
+ }) : /* @__PURE__ */ a("p", {
277
+ role: "status",
278
+ children: f.scopeLoading
279
+ })]
280
+ });
281
+ };
282
+ export { u as AppealDialog, c as ReportDialog, l as SanctionNotice, s as sanctionLabels };
@@ -0,0 +1,88 @@
1
+ import { Schema as e } from "effect";
2
+ // src/contract.ts
3
+ var t = "_voltro_sanc_reports", n = "_voltro_sanc_cases", r = "_voltro_sanc_actions", i = "_voltro_sanc_appeals", a = "_voltro_sanc_strikes", o = "_voltro_sanc_device_hints", s = "_voltro_sanc_admissions", c = [
4
+ "warn",
5
+ "mute",
6
+ "chatBan",
7
+ "matchmakingBan",
8
+ "rankedBan",
9
+ "tradeBan",
10
+ "ban",
11
+ "shadowBan",
12
+ "nameReset",
13
+ "rollback"
14
+ ], l = [
15
+ "cheating",
16
+ "abuse",
17
+ "name",
18
+ "spam",
19
+ "griefing",
20
+ "rmt"
21
+ ], u = [
22
+ "chat",
23
+ "matchmaking",
24
+ "trade",
25
+ "ranked",
26
+ "login"
27
+ ], d = e.Number.pipe(e.check(e.isInt()), e.check(e.isGreaterThanOrEqualTo(0))), f = e.Struct({
28
+ channels: e.Array(e.String),
29
+ queues: e.Array(e.String)
30
+ }), p = e.Struct({
31
+ channelId: e.optional(e.String),
32
+ messageIds: e.optional(e.Array(e.String)),
33
+ roomId: e.optional(e.String),
34
+ matchId: e.optional(e.String),
35
+ replayRef: e.optional(e.String)
36
+ }), m = e.Struct({
37
+ id: e.String,
38
+ kind: e.Literals(c),
39
+ scope: f,
40
+ from: d,
41
+ until: e.NullOr(d),
42
+ publicReason: e.String,
43
+ appealable: e.Boolean
44
+ }), h = e.Struct({
45
+ id: e.String,
46
+ targetId: e.String,
47
+ category: e.Literals(l),
48
+ state: e.Literals([
49
+ "open",
50
+ "reviewing",
51
+ "actioned",
52
+ "dismissed"
53
+ ]),
54
+ createdAt: d,
55
+ caseId: e.String
56
+ }), g = e.Struct({
57
+ id: e.String,
58
+ actionId: e.String,
59
+ text: e.String,
60
+ state: e.Literals(["pending", "reviewed"]),
61
+ outcome: e.NullOr(e.Literals(["upheld", "revoked"])),
62
+ createdAt: d,
63
+ decidedAt: e.NullOr(d)
64
+ }), _ = e.Struct({
65
+ id: e.String,
66
+ targetId: e.NullOr(e.String),
67
+ reports: d,
68
+ evidence: e.Array(e.Record(e.String, e.Unknown)),
69
+ trustScore: e.Number.pipe(e.check(e.isBetween({
70
+ minimum: 0,
71
+ maximum: 100
72
+ }))),
73
+ state: e.Literals([
74
+ "open",
75
+ "reviewing",
76
+ "actioned",
77
+ "dismissed"
78
+ ]),
79
+ decidedBy: e.NullOr(e.String),
80
+ decidedAt: e.NullOr(d),
81
+ version: d
82
+ });
83
+ e.Struct({
84
+ allowed: e.Boolean,
85
+ actionIds: e.Array(e.String),
86
+ shadow: e.Boolean
87
+ });
88
+ export { r as ACTIONS_TABLE, c as ACTION_KINDS, s as ADMISSIONS_TABLE, i as APPEALS_TABLE, g as AppealSchema, n as CASES_TABLE, l as CATEGORIES, _ as CaseSchema, o as DEVICE_HINTS_TABLE, u as POINTS, t as REPORTS_TABLE, p as ReportContextSchema, h as ReportSchema, a as STRIKES_TABLE, m as SanctionSchema, f as SanctionScopeSchema };
@@ -0,0 +1,101 @@
1
+ import { ACTIONS_TABLE as e, ACTION_KINDS as t, ADMISSIONS_TABLE as n, APPEALS_TABLE as r, CASES_TABLE as i, CATEGORIES as a, DEVICE_HINTS_TABLE as o, REPORTS_TABLE as s, STRIKES_TABLE as c } from "./contract.js";
2
+ import { boolean as l, id as u, integer as d, json as f, table as p, text as m, timestamp as h } from "@voltro/database";
3
+ // src/entities.ts
4
+ var g = () => m().maxLength(256).externalId().sensitive("pii"), _ = () => m().maxLength(256).externalId().sensitive("pii"), v = () => m().maxLength(64).safe(), y = p(s, {
5
+ id: u({ prefix: "srep" }),
6
+ tenantId: g(),
7
+ reporterId: _().nullable(),
8
+ targetId: _().nullable(),
9
+ category: m().oneOf(a).safe(),
10
+ context: f().sensitive("pii"),
11
+ note: m().sensitive("pii"),
12
+ state: m().oneOf([
13
+ "open",
14
+ "reviewing",
15
+ "actioned",
16
+ "dismissed"
17
+ ]).safe(),
18
+ assignee: _().nullable(),
19
+ createdAt: h().safe(),
20
+ caseId: v(),
21
+ requestKey: m().maxLength(64).serverOnly(),
22
+ source: m().oneOf(["human", "system"]).serverOnly(),
23
+ metadata: f().sensitive("pii")
24
+ }).index(["tenantId", "targetId"]).index(["tenantId", "reporterId"]), b = p(i, {
25
+ id: u({ prefix: "scase" }),
26
+ tenantId: g(),
27
+ targetId: _().nullable(),
28
+ reports: d().safe(),
29
+ evidence: f().sensitive("pii"),
30
+ trustScore: d().safe(),
31
+ state: m().oneOf([
32
+ "open",
33
+ "reviewing",
34
+ "actioned",
35
+ "dismissed"
36
+ ]).safe(),
37
+ decidedBy: _().nullable(),
38
+ decidedAt: h().nullable().safe(),
39
+ version: d().safe(),
40
+ metadata: f().sensitive("pii")
41
+ }).index(["tenantId", "targetId"]).index(["tenantId", "state"]), x = p(e, {
42
+ id: u({ prefix: "sact" }),
43
+ tenantId: g(),
44
+ targetId: _().nullable(),
45
+ kind: m().oneOf(t).safe(),
46
+ scope: f().safe(),
47
+ from: h().safe(),
48
+ until: h().nullable().safe(),
49
+ reason: m().sensitive("pii").serverOnly(),
50
+ publicReason: m().sensitive("pii"),
51
+ issuedBy: _().nullable(),
52
+ evidenceCaseId: v().nullable(),
53
+ appealable: l().safe(),
54
+ revokedAt: h().nullable().safe(),
55
+ requestKey: m().maxLength(64).serverOnly(),
56
+ metadata: f().sensitive("pii")
57
+ }).index(["tenantId", "targetId"]), S = p(r, {
58
+ id: u({ prefix: "sappeal" }),
59
+ tenantId: g(),
60
+ actionId: v(),
61
+ subjectId: _().nullable(),
62
+ text: m().sensitive("pii"),
63
+ state: m().oneOf(["pending", "reviewed"]).safe(),
64
+ decidedBy: _().nullable(),
65
+ decidedAt: h().nullable().safe(),
66
+ outcome: m().oneOf(["upheld", "revoked"]).nullable().safe(),
67
+ createdAt: h().safe(),
68
+ metadata: f().sensitive("pii")
69
+ }).unique(["actionId"]).index(["tenantId", "subjectId"]), C = p(c, {
70
+ id: u({ prefix: "sstrike" }),
71
+ tenantId: g(),
72
+ targetId: _().nullable(),
73
+ category: m().oneOf(a).safe(),
74
+ count: d().safe(),
75
+ lastAt: h().safe(),
76
+ decayAt: h().safe(),
77
+ metadata: f().sensitive("pii")
78
+ }).index(["tenantId", "targetId"]), w = p(o, {
79
+ id: u({ prefix: "sdhint" }),
80
+ tenantId: g(),
81
+ subjectId: _().nullable(),
82
+ deviceHash: m().maxLength(64).sensitive("pii"),
83
+ firstSeen: h().safe(),
84
+ metadata: f().sensitive("pii")
85
+ }).index(["tenantId", "subjectId"]), T = p(n, {
86
+ id: u({ prefix: "sadmit" }),
87
+ tenantId: g(),
88
+ subjectId: _().nullable(),
89
+ admission: d().serverOnly(),
90
+ erased: l().serverOnly(),
91
+ metadata: f().sensitive("pii")
92
+ }).index(["tenantId", "subjectId"]), E = [
93
+ y,
94
+ b,
95
+ x,
96
+ S,
97
+ C,
98
+ w,
99
+ T
100
+ ];
101
+ export { x as sanctionActionsTable, T as sanctionAdmissionsTable, S as sanctionAppealsTable, b as sanctionCasesTable, w as sanctionDeviceHintsTable, y as sanctionReportsTable, C as sanctionStrikesTable, E as sanctionTables };
@@ -0,0 +1,13 @@
1
+ import { Schema } from 'effect';
2
+ import { YieldableError } from 'effect/Cause';
3
+
4
+ export declare class SanctionsError extends SanctionsError_base {
5
+ }
6
+
7
+ export declare const sanctionsError: (code: SanctionsError["code"]) => SanctionsError;
8
+
9
+ declare const SanctionsError_base: Schema.Class<SanctionsError, Schema.TaggedStruct<"SanctionsError", {
10
+ readonly code: Schema.Literals<readonly ["identity_required", "invalid_input", "forbidden", "not_found", "conflict", "rate_limited", "sanctioned", "unavailable", "export_limit"]>;
11
+ }>, YieldableError>;
12
+
13
+ export { }
package/dist/errors.js ADDED
@@ -0,0 +1,14 @@
1
+ import { Schema as e } from "effect";
2
+ // src/errors.ts
3
+ var t = class extends e.TaggedError()("SanctionsError", { code: e.Literals([
4
+ "identity_required",
5
+ "invalid_input",
6
+ "forbidden",
7
+ "not_found",
8
+ "conflict",
9
+ "rate_limited",
10
+ "sanctioned",
11
+ "unavailable",
12
+ "export_limit"
13
+ ]) }) {}, n = (e) => new t({ code: e });
14
+ export { t as SanctionsError, n as sanctionsError };
@@ -0,0 +1,8 @@
1
+ import { ChangeEvent } from '@voltro/database';
2
+ import { SubscribeContext } from '@voltro/runtime';
3
+
4
+ export declare const publishSanctionChange: (event: ChangeEvent, ctx: SubscribeContext) => Promise<void>;
5
+
6
+ export declare const sanctionEventTenant: (event: ChangeEvent) => string;
7
+
8
+ export { }
@@ -0,0 +1,19 @@
1
+ import "./contract.js";
2
+ import { sanctionsChanged as e } from "./events.js";
3
+ // src/eventProducer.ts
4
+ var t = (e) => {
5
+ if (e.table !== "_voltro_sanc_actions") throw Error("Sanction events require the owned actions table");
6
+ let t = (e.op === "delete" ? e.old : e.new)?.tenantId;
7
+ if (typeof t != "string" || !t.trim() || t.length > 256 || t.includes("\0") || t === "~" || e.op === "update" && e.old?.tenantId !== t) throw Error("Sanction events require stable committed tenant evidence");
8
+ return t;
9
+ }, n = async (n, r) => {
10
+ t(n);
11
+ let i = n.op === "delete" ? n.old : n.new;
12
+ if (i?.targetId !== null) {
13
+ if (!i || typeof i.targetId != "string" || !i.targetId.trim() || i.targetId.length > 256 || typeof i.id != "string" || !i.id || i.id.length > 64) throw Error("Sanction events require committed action identity");
14
+ if (n.op === "update" && n.old?.targetId !== i.targetId) throw Error("Sanction events cannot transfer an action target");
15
+ if (!r.publish) throw Error("Sanction event publisher is unavailable");
16
+ await r.publish(e, { subjectId: i.targetId }, { actionId: i.id });
17
+ }
18
+ };
19
+ export { n as publishSanctionChange, t as sanctionEventTenant };
@@ -0,0 +1,14 @@
1
+ import { DeclaredAccess } from '@voltro/protocol';
2
+ import { EventDescriptor } from '@voltro/protocol';
3
+ import { Schema } from 'effect';
4
+
5
+ /** Operator metadata. Players receive their own public measures via Live Queries. */
6
+ export declare const sanctionsChanged: EventDescriptor<"sanctions.changed", Schema.Struct<{
7
+ readonly subjectId: Schema.String;
8
+ }>, Schema.Struct<{
9
+ readonly actionId: Schema.String;
10
+ }>, DeclaredAccess<{
11
+ readonly subjectId: string;
12
+ }>>;
13
+
14
+ export { }
package/dist/events.js ADDED
@@ -0,0 +1,10 @@
1
+ import { defineEvent as e } from "@voltro/protocol";
2
+ import { Schema as t } from "effect";
3
+ // src/events.ts
4
+ var n = e({
5
+ name: "sanctions.changed",
6
+ key: t.Struct({ subjectId: t.String }),
7
+ payload: t.Struct({ actionId: t.String }),
8
+ guards: [{ scope: "sanctions:events:read" }]
9
+ });
10
+ export { n as sanctionsChanged };