@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.
- package/CHANGELOG.md +24492 -0
- package/LICENSE +61 -0
- package/README.md +198 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +8333 -0
- package/dist/admission.server.js +96 -0
- package/dist/components.js +282 -0
- package/dist/contract.js +88 -0
- package/dist/entities.js +101 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +14 -0
- package/dist/eventProducer.d.ts +8 -0
- package/dist/eventProducer.js +19 -0
- package/dist/events.d.ts +14 -0
- package/dist/events.js +10 -0
- package/dist/guard.d.ts +83 -0
- package/dist/guard.js +16 -0
- package/dist/index.d.ts +585 -0
- package/dist/index.js +179 -0
- package/dist/inspect.js +23 -0
- package/dist/port.d.ts +82 -0
- package/dist/port.js +4 -0
- package/dist/rpc.d.ts +165 -0
- package/dist/rpc.js +146 -0
- package/dist/rpcRoutes.js +49 -0
- package/dist/sanctions-app/events/sanctions.changed.event.ts +1 -0
- package/dist/sanctions-app/subscribers/sanctions.actions.subscribe.ts +3 -0
- package/dist/server.d.ts +363 -0
- package/dist/server.js +1 -0
- package/dist/service.js +708 -0
- package/dist/strategies.d.ts +154 -0
- package/dist/strategies.js +72 -0
- package/dist/testing.d.ts +211 -0
- package/dist/testing.js +120 -0
- package/dist/web.d.ts +239 -0
- package/dist/web.js +7 -0
- package/package.json +99 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { sanctionActionsTable as e, sanctionAdmissionsTable as t, sanctionAppealsTable as n, sanctionCasesTable as r, sanctionDeviceHintsTable as i, sanctionReportsTable as a, sanctionStrikesTable as o, sanctionTables as s } from "./entities.js";
|
|
2
|
+
import { SanctionsError as c, sanctionsError as l } from "./errors.js";
|
|
3
|
+
import { captureSanctionsAdmission as u, captureSanctionsAdmissionBatch as d } from "./admission.server.js";
|
|
4
|
+
import { dataStoreSanctions as f } from "./service.js";
|
|
5
|
+
import { SanctionsPort as p } from "./port.js";
|
|
6
|
+
import { defaultSanctionsStrategies as m, resolveSanctionsOptions as h } from "./strategies.js";
|
|
7
|
+
import { BASE_NAME as g, sanctionsRpcClientImports as _ } from "./rpc.js";
|
|
8
|
+
import { sanctionsRpcRoutes as v } from "./rpcRoutes.js";
|
|
9
|
+
import { sanctionsStatus as y } from "./inspect.js";
|
|
10
|
+
import { sanctionsChanged as b } from "./events.js";
|
|
11
|
+
import { Effect as x, Layer as S } from "effect";
|
|
12
|
+
import { prepareSqlMutation as C, prepareSqlMutationGroup as w } from "@voltro/database/sql";
|
|
13
|
+
import { defineLicensedGamePlugin as T } from "@voltro/plugin-licensing/gate";
|
|
14
|
+
import { fileURLToPath as E } from "node:url";
|
|
15
|
+
import { replicaEvidence as D } from "@voltro/protocol/identity";
|
|
16
|
+
import { redisStore as O } from "@voltro/plugin-ratelimit";
|
|
17
|
+
// src/index.ts
|
|
18
|
+
var k = {
|
|
19
|
+
slots: {
|
|
20
|
+
escalationLadder: {
|
|
21
|
+
defaultExport: "abuseEscalationLadder",
|
|
22
|
+
fixtureExport: "sanctionsEscalationFixture"
|
|
23
|
+
},
|
|
24
|
+
trustScore: {
|
|
25
|
+
defaultExport: "conservativeTrustScore",
|
|
26
|
+
fixtureExport: "sanctionsTrustFixture"
|
|
27
|
+
},
|
|
28
|
+
evidenceCollector: {
|
|
29
|
+
defaultExport: "noCollectedSanctionEvidence",
|
|
30
|
+
fixtureExport: "sanctionsEvidenceFixture"
|
|
31
|
+
},
|
|
32
|
+
enforcementPoints: {
|
|
33
|
+
defaultExport: "defaultSanctionEnforcement",
|
|
34
|
+
fixtureExport: "sanctionsEnforcementFixture"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
ports: { sanctions: {
|
|
38
|
+
tagExport: "SanctionsPort",
|
|
39
|
+
fakeLayerExport: "sanctionsFakeLayer",
|
|
40
|
+
fixtureExport: "sanctionsPortFixture"
|
|
41
|
+
} },
|
|
42
|
+
events: [b.name]
|
|
43
|
+
}, A = (e = {}) => {
|
|
44
|
+
let t = h(e), n = O(t.rateLimit), r, i, a = !1, o = (e) => x.suspend(() => i === void 0 ? x.fail(l("unavailable")) : e(i)), m = {
|
|
45
|
+
report: (e, t) => o((n) => n.api.report(e, t)),
|
|
46
|
+
reportsMine: (e) => o((t) => t.api.reportsMine(e)),
|
|
47
|
+
mine: (e) => o((t) => t.api.mine(e)),
|
|
48
|
+
appeal: (e, t) => o((n) => n.api.appeal(e, t)),
|
|
49
|
+
appealsMine: (e) => o((t) => t.api.appealsMine(e)),
|
|
50
|
+
cases: (e) => o((t) => t.api.cases(e)),
|
|
51
|
+
reviewCase: (e, t) => o((n) => n.api.reviewCase(e, t)),
|
|
52
|
+
issue: (e, t) => o((n) => n.api.issue(e, t)),
|
|
53
|
+
revoke: (e, t) => o((n) => n.api.revoke(e, t)),
|
|
54
|
+
appealsQueue: (e) => o((t) => t.api.appealsQueue(e)),
|
|
55
|
+
reviewAppeal: (e, t) => o((n) => n.api.reviewAppeal(e, t))
|
|
56
|
+
}, b = {
|
|
57
|
+
issue: (e, t) => o((n) => n.operator.issue(e, t)),
|
|
58
|
+
revoke: (e, t) => o((n) => n.operator.revoke(e, t))
|
|
59
|
+
}, k = {
|
|
60
|
+
check: (e, t, n) => o((r) => r.port.check(e, t, n)),
|
|
61
|
+
active: (e) => o((t) => t.port.active(e)),
|
|
62
|
+
trust: (e) => o((t) => t.port.trust(e)),
|
|
63
|
+
recordSignal: (e, t) => o((n) => n.port.recordSignal(e, t))
|
|
64
|
+
}, A = (e, t) => x.try({
|
|
65
|
+
try: () => {
|
|
66
|
+
let n = r;
|
|
67
|
+
if (!n) throw l("unavailable");
|
|
68
|
+
let a = C(n, async () => {
|
|
69
|
+
if (i !== e || r !== n) throw l("unavailable");
|
|
70
|
+
});
|
|
71
|
+
return w(n, [a, t], async () => {});
|
|
72
|
+
},
|
|
73
|
+
catch: () => l("unavailable")
|
|
74
|
+
}), j = {
|
|
75
|
+
read: (e, t) => {
|
|
76
|
+
try {
|
|
77
|
+
let n = structuredClone(e), r = u(t, !1), i = {
|
|
78
|
+
point: r.point,
|
|
79
|
+
at: r.at,
|
|
80
|
+
context: r.context
|
|
81
|
+
};
|
|
82
|
+
return o((e) => e.admission.read(n, i));
|
|
83
|
+
} catch (e) {
|
|
84
|
+
return x.fail(e instanceof c ? e : l("invalid_input"));
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
prepare: (e, t) => {
|
|
88
|
+
try {
|
|
89
|
+
let n = structuredClone(e), r = u(t, !0);
|
|
90
|
+
if (!r.expected) throw l("invalid_input");
|
|
91
|
+
let i = {
|
|
92
|
+
point: r.point,
|
|
93
|
+
at: r.at,
|
|
94
|
+
context: r.context,
|
|
95
|
+
expected: r.expected
|
|
96
|
+
};
|
|
97
|
+
return o((e) => e.admission.prepare(n, i).pipe(x.flatMap((t) => A(e, t))));
|
|
98
|
+
} catch (e) {
|
|
99
|
+
return x.fail(e instanceof c ? e : l("invalid_input"));
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
prepareMany: (e) => {
|
|
103
|
+
try {
|
|
104
|
+
let t = d(e);
|
|
105
|
+
return o((e) => e.admission.prepareMany(t).pipe(x.flatMap((t) => A(e, t))));
|
|
106
|
+
} catch (e) {
|
|
107
|
+
return x.fail(e instanceof c ? e : l("invalid_input"));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
return {
|
|
112
|
+
sanctions: {
|
|
113
|
+
admission: () => j,
|
|
114
|
+
operator: () => b
|
|
115
|
+
},
|
|
116
|
+
...T({
|
|
117
|
+
name: g,
|
|
118
|
+
description: "SQL-authoritative sanctions, human review and replaceable enforcement.",
|
|
119
|
+
permissions: ["store:write", "inspect:read"],
|
|
120
|
+
services: S.succeed(p, k),
|
|
121
|
+
routes: v(m),
|
|
122
|
+
rpcClientDescriptors: _,
|
|
123
|
+
errorSchemas: [{
|
|
124
|
+
schema: c,
|
|
125
|
+
import: {
|
|
126
|
+
module: "@voltro/plugin-sanctions/errors",
|
|
127
|
+
name: "SanctionsError"
|
|
128
|
+
}
|
|
129
|
+
}],
|
|
130
|
+
sources: E(new URL("./sanctions-app", "" + import.meta.url)),
|
|
131
|
+
extendSchema: { tables: s },
|
|
132
|
+
subjectPrivacy: {
|
|
133
|
+
tables: s.map((e) => e.tableName),
|
|
134
|
+
kinds: ["user", "guest"]
|
|
135
|
+
},
|
|
136
|
+
inspectEndpoints: [{
|
|
137
|
+
method: "GET",
|
|
138
|
+
path: "/status",
|
|
139
|
+
scope: "process",
|
|
140
|
+
description: "Declared sanctions configuration and binding; no case or evidence enumeration.",
|
|
141
|
+
handler: () => x.try({
|
|
142
|
+
try: () => ({
|
|
143
|
+
kind: "json",
|
|
144
|
+
data: y(t, i !== void 0, a)
|
|
145
|
+
}),
|
|
146
|
+
catch: () => l("unavailable")
|
|
147
|
+
})
|
|
148
|
+
}],
|
|
149
|
+
bindDataStore: (e) => {
|
|
150
|
+
if (r !== void 0 && r !== e) throw Error("Sanctions plugin instance cannot cross app stores");
|
|
151
|
+
r = e, i = f(e, t, n);
|
|
152
|
+
},
|
|
153
|
+
onActivate: (e) => x.tryPromise({
|
|
154
|
+
try: async () => {
|
|
155
|
+
if (t.rateLimit?.hotStore !== void 0 && D(e.env) !== null) throw l("unavailable");
|
|
156
|
+
await n.activate(e.env, e.connectionRegistry), a = !0;
|
|
157
|
+
},
|
|
158
|
+
catch: () => l("unavailable")
|
|
159
|
+
}),
|
|
160
|
+
onExport: (e, t) => o((n) => n.exportSubject({
|
|
161
|
+
subjectId: e,
|
|
162
|
+
tenantId: t.tenantId,
|
|
163
|
+
kind: t.kind
|
|
164
|
+
})),
|
|
165
|
+
onErase: (e, t) => o((n) => n.eraseSubject({
|
|
166
|
+
subjectId: e,
|
|
167
|
+
tenantId: t.tenantId,
|
|
168
|
+
kind: t.kind
|
|
169
|
+
})),
|
|
170
|
+
onDeactivate: () => x.tryPromise({
|
|
171
|
+
try: async () => {
|
|
172
|
+
i = void 0, r = void 0, a = !1, await n.deactivate();
|
|
173
|
+
},
|
|
174
|
+
catch: () => l("unavailable")
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
export { c as SanctionsError, p as SanctionsPort, f as dataStoreSanctions, m as defaultSanctionsStrategies, h as resolveSanctionsOptions, e as sanctionActionsTable, t as sanctionAdmissionsTable, n as sanctionAppealsTable, r as sanctionCasesTable, i as sanctionDeviceHintsTable, a as sanctionReportsTable, o as sanctionStrikesTable, s as sanctionTables, A as sanctionsPlugin, k as sanctionsSystemContract };
|
package/dist/inspect.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sanctionTables as e } from "./entities.js";
|
|
2
|
+
import { defaultSanctionsStrategies as t } from "./strategies.js";
|
|
3
|
+
// src/inspect.ts
|
|
4
|
+
var n = (n, r, i) => ({
|
|
5
|
+
observedAt: n.now(),
|
|
6
|
+
bound: r,
|
|
7
|
+
rateActive: i,
|
|
8
|
+
atomicAdmissionInstalled: !0,
|
|
9
|
+
maxActiveActions: n.maxActiveActions,
|
|
10
|
+
maxReportsPerCase: n.maxReportsPerCase,
|
|
11
|
+
maxEvidenceRefs: n.maxEvidenceRefs,
|
|
12
|
+
maxContextMessageIds: n.maxContextMessageIds,
|
|
13
|
+
maxTextLength: n.maxTextLength,
|
|
14
|
+
pageSize: n.pageSize,
|
|
15
|
+
maxExportRows: n.maxExportRows,
|
|
16
|
+
reportLimit: n.reportLimit,
|
|
17
|
+
reportWindowMs: n.reportWindowMs,
|
|
18
|
+
strikeDecayMs: n.strikeDecayMs,
|
|
19
|
+
minimumSignalConfidence: n.minimumSignalConfidence,
|
|
20
|
+
slots: Object.fromEntries(Object.keys(t).map((e) => [e, n.strategies[e] === t[e] ? "default" : "custom"])),
|
|
21
|
+
tables: e.map((e) => e.tableName)
|
|
22
|
+
});
|
|
23
|
+
export { n as sanctionsStatus };
|
package/dist/port.d.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { Schema } from 'effect';
|
|
4
|
+
import { Subject } from '@voltro/protocol';
|
|
5
|
+
import { YieldableError } from 'effect/Cause';
|
|
6
|
+
|
|
7
|
+
declare const CATEGORIES: readonly ["cheating", "abuse", "name", "spam", "griefing", "rmt"];
|
|
8
|
+
|
|
9
|
+
declare const DecisionSchema: Schema.Struct<{
|
|
10
|
+
readonly allowed: Schema.Boolean;
|
|
11
|
+
readonly actionIds: Schema.$Array<Schema.String>;
|
|
12
|
+
readonly shadow: Schema.Boolean;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
declare const POINTS: readonly ["chat", "matchmaking", "trade", "ranked", "login"];
|
|
16
|
+
|
|
17
|
+
declare type ReportContext = typeof ReportContextSchema.Type;
|
|
18
|
+
|
|
19
|
+
declare const ReportContextSchema: Schema.Struct<{
|
|
20
|
+
readonly channelId: Schema.optional<Schema.String>;
|
|
21
|
+
readonly messageIds: Schema.optional<Schema.$Array<Schema.String>>;
|
|
22
|
+
readonly roomId: Schema.optional<Schema.String>;
|
|
23
|
+
readonly matchId: Schema.optional<Schema.String>;
|
|
24
|
+
readonly replayRef: Schema.optional<Schema.String>;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
declare type Sanction = typeof SanctionSchema.Type;
|
|
28
|
+
|
|
29
|
+
declare type SanctionCategory = typeof CATEGORIES[number];
|
|
30
|
+
|
|
31
|
+
declare interface SanctionCheckContext {
|
|
32
|
+
readonly channelId?: string;
|
|
33
|
+
readonly queueId?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
declare type SanctionDecision = typeof DecisionSchema.Type;
|
|
37
|
+
|
|
38
|
+
declare type SanctionPoint = typeof POINTS[number];
|
|
39
|
+
|
|
40
|
+
declare const SanctionSchema: Schema.Struct<{
|
|
41
|
+
readonly id: Schema.String;
|
|
42
|
+
readonly kind: Schema.Literals<readonly ["warn", "mute", "chatBan", "matchmakingBan", "rankedBan", "tradeBan", "ban", "shadowBan", "nameReset", "rollback"]>;
|
|
43
|
+
readonly scope: Schema.Struct<{
|
|
44
|
+
readonly channels: Schema.$Array<Schema.String>;
|
|
45
|
+
readonly queues: Schema.$Array<Schema.String>;
|
|
46
|
+
}>;
|
|
47
|
+
readonly from: Schema.Number;
|
|
48
|
+
readonly until: Schema.NullOr<Schema.Number>;
|
|
49
|
+
readonly publicReason: Schema.String;
|
|
50
|
+
readonly appealable: Schema.Boolean;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
declare class SanctionsError extends SanctionsError_base {
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
declare const SanctionsError_base: Schema.Class<SanctionsError, Schema.TaggedStruct<"SanctionsError", {
|
|
57
|
+
readonly code: Schema.Literals<readonly ["identity_required", "invalid_input", "forbidden", "not_found", "conflict", "rate_limited", "sanctioned", "unavailable", "export_limit"]>;
|
|
58
|
+
}>, YieldableError>;
|
|
59
|
+
|
|
60
|
+
/** Other systems consult this small port rather than sanction SQL or an app-local enforcement map. */
|
|
61
|
+
export declare class SanctionsPort extends SanctionsPort_base {
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
declare const SanctionsPort_base: Context.ServiceClass<SanctionsPort, "@voltro/SanctionsPort", SanctionsService>;
|
|
65
|
+
|
|
66
|
+
export declare interface SanctionsService {
|
|
67
|
+
readonly check: (subject: Subject, point: SanctionPoint, context?: SanctionCheckContext) => Effect.Effect<SanctionDecision, SanctionsError>;
|
|
68
|
+
readonly active: (subject: Subject) => Effect.Effect<ReadonlyArray<Sanction>, SanctionsError>;
|
|
69
|
+
readonly trust: (subject: Subject) => Effect.Effect<number, SanctionsError>;
|
|
70
|
+
readonly recordSignal: (subject: Subject, input: TrustedSanctionSignal) => Effect.Effect<void, SanctionsError>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
declare interface TrustedSanctionSignal {
|
|
74
|
+
readonly tenantId: string;
|
|
75
|
+
readonly targetId: string;
|
|
76
|
+
readonly requestId: string;
|
|
77
|
+
readonly category: SanctionCategory;
|
|
78
|
+
readonly confidence: number;
|
|
79
|
+
readonly context?: ReportContext;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { }
|
package/dist/port.js
ADDED
package/dist/rpc.d.ts
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { ActionProcedureDescriptor } from '@voltro/protocol';
|
|
2
|
+
import { PluginRpcClientDescriptor } from '@voltro/protocol';
|
|
3
|
+
import { QueryProcedureDescriptor } from '@voltro/protocol';
|
|
4
|
+
import { Schema } from 'effect';
|
|
5
|
+
import { YieldableError } from 'effect/Cause';
|
|
6
|
+
|
|
7
|
+
export declare const appealDescriptor: ActionProcedureDescriptor<"sanctions.appeal", Schema.Struct<{
|
|
8
|
+
readonly actionId: Schema.NonEmptyString;
|
|
9
|
+
readonly text: Schema.NonEmptyString;
|
|
10
|
+
}>, Schema.Struct<{
|
|
11
|
+
readonly id: Schema.String;
|
|
12
|
+
readonly actionId: Schema.String;
|
|
13
|
+
readonly text: Schema.String;
|
|
14
|
+
readonly state: Schema.Literals<readonly ["pending", "reviewed"]>;
|
|
15
|
+
readonly outcome: Schema.NullOr<Schema.Literals<readonly ["upheld", "revoked"]>>;
|
|
16
|
+
readonly createdAt: Schema.Number;
|
|
17
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
18
|
+
}>, typeof SanctionsError>;
|
|
19
|
+
|
|
20
|
+
export declare const appealsMineDescriptor: QueryProcedureDescriptor<"sanctions.appealsMine", Schema.Struct<{}>, Schema.$Array<Schema.Struct<{
|
|
21
|
+
readonly id: Schema.String;
|
|
22
|
+
readonly actionId: Schema.String;
|
|
23
|
+
readonly text: Schema.String;
|
|
24
|
+
readonly state: Schema.Literals<readonly ["pending", "reviewed"]>;
|
|
25
|
+
readonly outcome: Schema.NullOr<Schema.Literals<readonly ["upheld", "revoked"]>>;
|
|
26
|
+
readonly createdAt: Schema.Number;
|
|
27
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
28
|
+
}>>, typeof SanctionsError>;
|
|
29
|
+
|
|
30
|
+
export declare const appealsQueueDescriptor: QueryProcedureDescriptor<"sanctions.appealsQueue", Schema.Struct<{}>, Schema.$Array<Schema.Struct<{
|
|
31
|
+
readonly id: Schema.String;
|
|
32
|
+
readonly actionId: Schema.String;
|
|
33
|
+
readonly text: Schema.String;
|
|
34
|
+
readonly state: Schema.Literals<readonly ["pending", "reviewed"]>;
|
|
35
|
+
readonly outcome: Schema.NullOr<Schema.Literals<readonly ["upheld", "revoked"]>>;
|
|
36
|
+
readonly createdAt: Schema.Number;
|
|
37
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
38
|
+
}>>, typeof SanctionsError>;
|
|
39
|
+
|
|
40
|
+
export declare const BASE_NAME = "@voltro/plugin-sanctions";
|
|
41
|
+
|
|
42
|
+
export declare const casesDescriptor: QueryProcedureDescriptor<"sanctions.cases", Schema.Struct<{}>, Schema.$Array<Schema.Struct<{
|
|
43
|
+
readonly id: Schema.String;
|
|
44
|
+
readonly targetId: Schema.NullOr<Schema.String>;
|
|
45
|
+
readonly reports: Schema.Number;
|
|
46
|
+
readonly evidence: Schema.$Array<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
47
|
+
readonly trustScore: Schema.Number;
|
|
48
|
+
readonly state: Schema.Literals<readonly ["open", "reviewing", "actioned", "dismissed"]>;
|
|
49
|
+
readonly decidedBy: Schema.NullOr<Schema.String>;
|
|
50
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
51
|
+
readonly version: Schema.Number;
|
|
52
|
+
}>>, typeof SanctionsError>;
|
|
53
|
+
|
|
54
|
+
export declare const issueDescriptor: ActionProcedureDescriptor<"sanctions.issue", Schema.Struct<{
|
|
55
|
+
readonly requestId: Schema.NonEmptyString;
|
|
56
|
+
readonly targetId: Schema.NonEmptyString;
|
|
57
|
+
readonly kind: Schema.Literals<readonly ["warn", "mute", "chatBan", "matchmakingBan", "rankedBan", "tradeBan", "ban", "shadowBan", "nameReset", "rollback"]>;
|
|
58
|
+
readonly scope: Schema.optional<Schema.Struct<{
|
|
59
|
+
readonly channels: Schema.$Array<Schema.String>;
|
|
60
|
+
readonly queues: Schema.$Array<Schema.String>;
|
|
61
|
+
}>>;
|
|
62
|
+
readonly durationMs: Schema.optional<Schema.NullOr<Schema.Number>>;
|
|
63
|
+
readonly reason: Schema.NonEmptyString;
|
|
64
|
+
readonly publicReason: Schema.NonEmptyString;
|
|
65
|
+
readonly evidenceCaseId: Schema.optional<Schema.NonEmptyString>;
|
|
66
|
+
readonly appealable: Schema.optional<Schema.Boolean>;
|
|
67
|
+
}>, Schema.Struct<{
|
|
68
|
+
readonly id: Schema.String;
|
|
69
|
+
readonly kind: Schema.Literals<readonly ["warn", "mute", "chatBan", "matchmakingBan", "rankedBan", "tradeBan", "ban", "shadowBan", "nameReset", "rollback"]>;
|
|
70
|
+
readonly scope: Schema.Struct<{
|
|
71
|
+
readonly channels: Schema.$Array<Schema.String>;
|
|
72
|
+
readonly queues: Schema.$Array<Schema.String>;
|
|
73
|
+
}>;
|
|
74
|
+
readonly from: Schema.Number;
|
|
75
|
+
readonly until: Schema.NullOr<Schema.Number>;
|
|
76
|
+
readonly publicReason: Schema.String;
|
|
77
|
+
readonly appealable: Schema.Boolean;
|
|
78
|
+
}>, typeof SanctionsError>;
|
|
79
|
+
|
|
80
|
+
export declare const mineDescriptor: QueryProcedureDescriptor<"sanctions.mine", Schema.Struct<{}>, Schema.$Array<Schema.Struct<{
|
|
81
|
+
readonly id: Schema.String;
|
|
82
|
+
readonly kind: Schema.Literals<readonly ["warn", "mute", "chatBan", "matchmakingBan", "rankedBan", "tradeBan", "ban", "shadowBan", "nameReset", "rollback"]>;
|
|
83
|
+
readonly scope: Schema.Struct<{
|
|
84
|
+
readonly channels: Schema.$Array<Schema.String>;
|
|
85
|
+
readonly queues: Schema.$Array<Schema.String>;
|
|
86
|
+
}>;
|
|
87
|
+
readonly from: Schema.Number;
|
|
88
|
+
readonly until: Schema.NullOr<Schema.Number>;
|
|
89
|
+
readonly publicReason: Schema.String;
|
|
90
|
+
readonly appealable: Schema.Boolean;
|
|
91
|
+
}>>, typeof SanctionsError>;
|
|
92
|
+
|
|
93
|
+
export declare const reportDescriptor: ActionProcedureDescriptor<"sanctions.report", Schema.Struct<{
|
|
94
|
+
readonly requestId: Schema.NonEmptyString;
|
|
95
|
+
readonly targetId: Schema.NonEmptyString;
|
|
96
|
+
readonly category: Schema.Literals<readonly ["cheating", "abuse", "name", "spam", "griefing", "rmt"]>;
|
|
97
|
+
readonly context: Schema.optional<Schema.Struct<{
|
|
98
|
+
readonly channelId: Schema.optional<Schema.String>;
|
|
99
|
+
readonly messageIds: Schema.optional<Schema.$Array<Schema.String>>;
|
|
100
|
+
readonly roomId: Schema.optional<Schema.String>;
|
|
101
|
+
readonly matchId: Schema.optional<Schema.String>;
|
|
102
|
+
readonly replayRef: Schema.optional<Schema.String>;
|
|
103
|
+
}>>;
|
|
104
|
+
readonly note: Schema.optional<Schema.String>;
|
|
105
|
+
}>, Schema.Struct<{
|
|
106
|
+
readonly id: Schema.String;
|
|
107
|
+
readonly targetId: Schema.String;
|
|
108
|
+
readonly category: Schema.Literals<readonly ["cheating", "abuse", "name", "spam", "griefing", "rmt"]>;
|
|
109
|
+
readonly state: Schema.Literals<readonly ["open", "reviewing", "actioned", "dismissed"]>;
|
|
110
|
+
readonly createdAt: Schema.Number;
|
|
111
|
+
readonly caseId: Schema.String;
|
|
112
|
+
}>, typeof SanctionsError>;
|
|
113
|
+
|
|
114
|
+
export declare const reportsMineDescriptor: QueryProcedureDescriptor<"sanctions.reportsMine", Schema.Struct<{}>, Schema.$Array<Schema.Struct<{
|
|
115
|
+
readonly id: Schema.String;
|
|
116
|
+
readonly targetId: Schema.String;
|
|
117
|
+
readonly category: Schema.Literals<readonly ["cheating", "abuse", "name", "spam", "griefing", "rmt"]>;
|
|
118
|
+
readonly state: Schema.Literals<readonly ["open", "reviewing", "actioned", "dismissed"]>;
|
|
119
|
+
readonly createdAt: Schema.Number;
|
|
120
|
+
readonly caseId: Schema.String;
|
|
121
|
+
}>>, typeof SanctionsError>;
|
|
122
|
+
|
|
123
|
+
export declare const reviewAppealDescriptor: ActionProcedureDescriptor<"sanctions.reviewAppeal", Schema.Struct<{
|
|
124
|
+
readonly appealId: Schema.NonEmptyString;
|
|
125
|
+
readonly outcome: Schema.Literals<readonly ["upheld", "revoked"]>;
|
|
126
|
+
}>, Schema.Struct<{
|
|
127
|
+
readonly id: Schema.String;
|
|
128
|
+
readonly actionId: Schema.String;
|
|
129
|
+
readonly text: Schema.String;
|
|
130
|
+
readonly state: Schema.Literals<readonly ["pending", "reviewed"]>;
|
|
131
|
+
readonly outcome: Schema.NullOr<Schema.Literals<readonly ["upheld", "revoked"]>>;
|
|
132
|
+
readonly createdAt: Schema.Number;
|
|
133
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
134
|
+
}>, typeof SanctionsError>;
|
|
135
|
+
|
|
136
|
+
export declare const reviewCaseDescriptor: ActionProcedureDescriptor<"sanctions.reviewCase", Schema.Struct<{
|
|
137
|
+
readonly caseId: Schema.NonEmptyString;
|
|
138
|
+
readonly baseVersion: Schema.Number;
|
|
139
|
+
readonly state: Schema.Literals<readonly ["open", "reviewing", "actioned", "dismissed"]>;
|
|
140
|
+
}>, Schema.Struct<{
|
|
141
|
+
readonly id: Schema.String;
|
|
142
|
+
readonly targetId: Schema.NullOr<Schema.String>;
|
|
143
|
+
readonly reports: Schema.Number;
|
|
144
|
+
readonly evidence: Schema.$Array<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
145
|
+
readonly trustScore: Schema.Number;
|
|
146
|
+
readonly state: Schema.Literals<readonly ["open", "reviewing", "actioned", "dismissed"]>;
|
|
147
|
+
readonly decidedBy: Schema.NullOr<Schema.String>;
|
|
148
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
149
|
+
readonly version: Schema.Number;
|
|
150
|
+
}>, typeof SanctionsError>;
|
|
151
|
+
|
|
152
|
+
export declare const revokeDescriptor: ActionProcedureDescriptor<"sanctions.revoke", Schema.Struct<{
|
|
153
|
+
readonly actionId: Schema.NonEmptyString;
|
|
154
|
+
}>, Schema.Void, typeof SanctionsError>;
|
|
155
|
+
|
|
156
|
+
declare class SanctionsError extends SanctionsError_base {
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
declare const SanctionsError_base: Schema.Class<SanctionsError, Schema.TaggedStruct<"SanctionsError", {
|
|
160
|
+
readonly code: Schema.Literals<readonly ["identity_required", "invalid_input", "forbidden", "not_found", "conflict", "rate_limited", "sanctioned", "unavailable", "export_limit"]>;
|
|
161
|
+
}>, YieldableError>;
|
|
162
|
+
|
|
163
|
+
export declare const sanctionsRpcClientImports: ReadonlyArray<PluginRpcClientDescriptor>;
|
|
164
|
+
|
|
165
|
+
export { }
|
package/dist/rpc.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { ACTIONS_TABLE as e, ACTION_KINDS as t, ADMISSIONS_TABLE as n, APPEALS_TABLE as r, AppealSchema as i, CASES_TABLE as a, CATEGORIES as o, CaseSchema as s, REPORTS_TABLE as c, ReportContextSchema as l, ReportSchema as u, SanctionSchema as d, SanctionScopeSchema as f } from "./contract.js";
|
|
2
|
+
import { SanctionsError as p } from "./errors.js";
|
|
3
|
+
import { defineAction as m, defineQuery as h } from "@voltro/protocol";
|
|
4
|
+
import { Schema as g } from "effect";
|
|
5
|
+
// src/rpc.ts
|
|
6
|
+
var _ = "@voltro/plugin-sanctions", v = g.NonEmptyString, y = g.Number.pipe(g.check(g.isInt()), g.check(g.isGreaterThanOrEqualTo(0))), b = "Trusted human or guest identity and exact tenant are required. Operator actions require sanctions:manage or admin:full; the server owns all sanction decisions.", x = g.Struct({}), S = [
|
|
7
|
+
c,
|
|
8
|
+
a,
|
|
9
|
+
e,
|
|
10
|
+
r,
|
|
11
|
+
n
|
|
12
|
+
], C = m({
|
|
13
|
+
name: "sanctions.report",
|
|
14
|
+
input: g.Struct({
|
|
15
|
+
requestId: v,
|
|
16
|
+
targetId: v,
|
|
17
|
+
category: g.Literals(o),
|
|
18
|
+
context: g.optional(l),
|
|
19
|
+
note: g.optional(g.String)
|
|
20
|
+
}),
|
|
21
|
+
output: u,
|
|
22
|
+
error: p,
|
|
23
|
+
openAccess: b
|
|
24
|
+
}), w = h({
|
|
25
|
+
name: "sanctions.reportsMine",
|
|
26
|
+
input: x,
|
|
27
|
+
output: g.Array(u),
|
|
28
|
+
source: S,
|
|
29
|
+
error: p,
|
|
30
|
+
openAccess: b
|
|
31
|
+
}), T = h({
|
|
32
|
+
name: "sanctions.mine",
|
|
33
|
+
input: x,
|
|
34
|
+
output: g.Array(d),
|
|
35
|
+
source: [e, n],
|
|
36
|
+
error: p,
|
|
37
|
+
openAccess: b
|
|
38
|
+
}), E = m({
|
|
39
|
+
name: "sanctions.appeal",
|
|
40
|
+
input: g.Struct({
|
|
41
|
+
actionId: v,
|
|
42
|
+
text: v
|
|
43
|
+
}),
|
|
44
|
+
output: i,
|
|
45
|
+
error: p,
|
|
46
|
+
openAccess: b
|
|
47
|
+
}), D = h({
|
|
48
|
+
name: "sanctions.appealsMine",
|
|
49
|
+
input: x,
|
|
50
|
+
output: g.Array(i),
|
|
51
|
+
source: [
|
|
52
|
+
r,
|
|
53
|
+
e,
|
|
54
|
+
n
|
|
55
|
+
],
|
|
56
|
+
error: p,
|
|
57
|
+
openAccess: b
|
|
58
|
+
}), O = h({
|
|
59
|
+
name: "sanctions.cases",
|
|
60
|
+
input: x,
|
|
61
|
+
output: g.Array(s),
|
|
62
|
+
source: S,
|
|
63
|
+
error: p,
|
|
64
|
+
openAccess: b
|
|
65
|
+
}), k = m({
|
|
66
|
+
name: "sanctions.reviewCase",
|
|
67
|
+
input: g.Struct({
|
|
68
|
+
caseId: v,
|
|
69
|
+
baseVersion: y,
|
|
70
|
+
state: g.Literals([
|
|
71
|
+
"open",
|
|
72
|
+
"reviewing",
|
|
73
|
+
"actioned",
|
|
74
|
+
"dismissed"
|
|
75
|
+
])
|
|
76
|
+
}),
|
|
77
|
+
output: s,
|
|
78
|
+
error: p,
|
|
79
|
+
openAccess: b
|
|
80
|
+
}), A = m({
|
|
81
|
+
name: "sanctions.issue",
|
|
82
|
+
input: g.Struct({
|
|
83
|
+
requestId: v,
|
|
84
|
+
targetId: v,
|
|
85
|
+
kind: g.Literals(t),
|
|
86
|
+
scope: g.optional(f),
|
|
87
|
+
durationMs: g.optional(g.NullOr(y)),
|
|
88
|
+
reason: v,
|
|
89
|
+
publicReason: v,
|
|
90
|
+
evidenceCaseId: g.optional(v),
|
|
91
|
+
appealable: g.optional(g.Boolean)
|
|
92
|
+
}),
|
|
93
|
+
output: d,
|
|
94
|
+
error: p,
|
|
95
|
+
openAccess: b
|
|
96
|
+
}), j = m({
|
|
97
|
+
name: "sanctions.revoke",
|
|
98
|
+
input: g.Struct({ actionId: v }),
|
|
99
|
+
output: g.Void,
|
|
100
|
+
error: p,
|
|
101
|
+
openAccess: b
|
|
102
|
+
}), M = h({
|
|
103
|
+
name: "sanctions.appealsQueue",
|
|
104
|
+
input: x,
|
|
105
|
+
output: g.Array(i),
|
|
106
|
+
source: [r, e],
|
|
107
|
+
error: p,
|
|
108
|
+
openAccess: b
|
|
109
|
+
}), N = m({
|
|
110
|
+
name: "sanctions.reviewAppeal",
|
|
111
|
+
input: g.Struct({
|
|
112
|
+
appealId: v,
|
|
113
|
+
outcome: g.Literals(["upheld", "revoked"])
|
|
114
|
+
}),
|
|
115
|
+
output: i,
|
|
116
|
+
error: p,
|
|
117
|
+
openAccess: b
|
|
118
|
+
}), P = [...[
|
|
119
|
+
"report",
|
|
120
|
+
"appeal",
|
|
121
|
+
"reviewCase",
|
|
122
|
+
"issue",
|
|
123
|
+
"revoke",
|
|
124
|
+
"reviewAppeal"
|
|
125
|
+
].map((e) => ({
|
|
126
|
+
tag: "sanctions." + e,
|
|
127
|
+
kind: "action",
|
|
128
|
+
import: {
|
|
129
|
+
module: "@voltro/plugin-sanctions/rpc",
|
|
130
|
+
name: e + "Descriptor"
|
|
131
|
+
}
|
|
132
|
+
})), ...[
|
|
133
|
+
"reportsMine",
|
|
134
|
+
"mine",
|
|
135
|
+
"appealsMine",
|
|
136
|
+
"cases",
|
|
137
|
+
"appealsQueue"
|
|
138
|
+
].map((e) => ({
|
|
139
|
+
tag: "sanctions." + e,
|
|
140
|
+
kind: "query",
|
|
141
|
+
import: {
|
|
142
|
+
module: "@voltro/plugin-sanctions/rpc",
|
|
143
|
+
name: e + "Descriptor"
|
|
144
|
+
}
|
|
145
|
+
}))];
|
|
146
|
+
export { _ as BASE_NAME, E as appealDescriptor, D as appealsMineDescriptor, M as appealsQueueDescriptor, O as casesDescriptor, A as issueDescriptor, T as mineDescriptor, C as reportDescriptor, w as reportsMineDescriptor, N as reviewAppealDescriptor, k as reviewCaseDescriptor, j as revokeDescriptor, P as sanctionsRpcClientImports };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { appealDescriptor as e, appealsMineDescriptor as t, appealsQueueDescriptor as n, casesDescriptor as r, issueDescriptor as i, mineDescriptor as a, reportDescriptor as o, reportsMineDescriptor as s, reviewAppealDescriptor as c, reviewCaseDescriptor as l, revokeDescriptor as u } from "./rpc.js";
|
|
2
|
+
// src/rpcRoutes.ts
|
|
3
|
+
var d = (d) => [
|
|
4
|
+
{
|
|
5
|
+
...o,
|
|
6
|
+
execute: (e, t) => d.report(t.request.subject, e)
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
...s,
|
|
10
|
+
execute: (e, t) => d.reportsMine(t.request.subject)
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
...a,
|
|
14
|
+
execute: (e, t) => d.mine(t.request.subject)
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
...e,
|
|
18
|
+
execute: (e, t) => d.appeal(t.request.subject, e)
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
...t,
|
|
22
|
+
execute: (e, t) => d.appealsMine(t.request.subject)
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
...r,
|
|
26
|
+
execute: (e, t) => d.cases(t.request.subject)
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
...l,
|
|
30
|
+
execute: (e, t) => d.reviewCase(t.request.subject, e)
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
...i,
|
|
34
|
+
execute: (e, t) => d.issue(t.request.subject, e)
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
...u,
|
|
38
|
+
execute: (e, t) => d.revoke(t.request.subject, e.actionId)
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
...n,
|
|
42
|
+
execute: (e, t) => d.appealsQueue(t.request.subject)
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
...c,
|
|
46
|
+
execute: (e, t) => d.reviewAppeal(t.request.subject, e)
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
export { d as sanctionsRpcRoutes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { sanctionsChanged as default } from '@voltro/plugin-sanctions/events'
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { defineSubscriber } from '@voltro/runtime'
|
|
2
|
+
import { sanctionEventTenant,publishSanctionChange } from '@voltro/plugin-sanctions/events/server'
|
|
3
|
+
export default defineSubscriber({table:'_voltro_sanc_actions',on:['insert','update','delete'],once:true,eventTenant:sanctionEventTenant,handler:publishSanctionChange})
|