@voltro/plugin-gm 0.0.0-stage → 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.
- package/CHANGELOG.md +24329 -0
- package/LICENSE +61 -0
- package/README.md +46 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +5007 -0
- package/dist/action.js +4 -0
- package/dist/builtins.js +349 -0
- package/dist/contract.js +29 -0
- package/dist/entities.js +22 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +19 -0
- package/dist/index.d.ts +498 -0
- package/dist/index.js +108 -0
- package/dist/inspect.js +22 -0
- package/dist/rpc.d.ts +103 -0
- package/dist/rpc.js +63 -0
- package/dist/service.js +258 -0
- package/dist/testing.d.ts +206 -0
- package/dist/testing.js +69 -0
- package/dist/web.d.ts +123 -0
- package/dist/web.js +7 -0
- package/package.json +81 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { ColumnBuilder } from '@voltro/database';
|
|
2
|
+
import { DataStore } from '@voltro/database';
|
|
3
|
+
import { EconomyService } from '@voltro/plugin-economy';
|
|
4
|
+
import { Effect } from 'effect';
|
|
5
|
+
import { FieldDefinitions } from '@voltro/database';
|
|
6
|
+
import { PluginPrivacyTarget } from '@voltro/protocol';
|
|
7
|
+
import { RoomModerationService } from '@voltro/plugin-rooms';
|
|
8
|
+
import { SanctionsOperatorService } from '@voltro/plugin-sanctions';
|
|
9
|
+
import { Schema } from 'effect';
|
|
10
|
+
import { Subject } from '@voltro/protocol';
|
|
11
|
+
import { systemSubject } from '@voltro/protocol';
|
|
12
|
+
import { Table } from '@voltro/database';
|
|
13
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
14
|
+
import { YieldableError } from 'effect/Cause';
|
|
15
|
+
|
|
16
|
+
export declare const ACTION_RISKS: readonly ["routine", "sensitive"];
|
|
17
|
+
|
|
18
|
+
declare namespace C {
|
|
19
|
+
export {
|
|
20
|
+
REQUESTS_TABLE,
|
|
21
|
+
REQUEST_STATES,
|
|
22
|
+
GmRequestState,
|
|
23
|
+
ACTION_RISKS,
|
|
24
|
+
GmActionRisk,
|
|
25
|
+
GmRequestSchema,
|
|
26
|
+
GmRequest,
|
|
27
|
+
GmActionInfoSchema,
|
|
28
|
+
GmActionInfo,
|
|
29
|
+
GmExecuteInput
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Sets a Remote Config value for everyone. The value is JSON text (a form field), checked
|
|
34
|
+
* against the key's schema and bounds; durable and audited with the requester. Sensitive by default. */
|
|
35
|
+
export declare const configSet: (source: GmConfigSource, options?: GmConfigActionOptions) => GmAction;
|
|
36
|
+
|
|
37
|
+
/** Borrowed SQL owner. The request row is the idempotency and approval record; the action itself
|
|
38
|
+
* stays idempotent on its request id, so a crash between action and bookkeeping is retried safely. */
|
|
39
|
+
export declare const dataStoreGm: (store: DataStore, options: ResolvedGmOptions) => {
|
|
40
|
+
api: GmApi;
|
|
41
|
+
exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<{
|
|
42
|
+
readonly id: string;
|
|
43
|
+
readonly actionId: string;
|
|
44
|
+
readonly state: "rejected" | "pending" | "approved" | "executed";
|
|
45
|
+
readonly targetId: string | null;
|
|
46
|
+
readonly input: unknown;
|
|
47
|
+
readonly output: unknown;
|
|
48
|
+
readonly reason: string;
|
|
49
|
+
readonly ticket: string | null;
|
|
50
|
+
readonly requesterId: string | null;
|
|
51
|
+
readonly approverId: string | null;
|
|
52
|
+
readonly createdAt: number;
|
|
53
|
+
readonly decidedAt: number | null;
|
|
54
|
+
readonly executedAt: number | null;
|
|
55
|
+
}[], GmError, never>;
|
|
56
|
+
/** Redacts what the request said about the player, unlinks staff ids and withdraws open requests that lost their subject. */
|
|
57
|
+
eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, GmError, never>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** Default approval rule: actions marked `sensitive` wait for a second person. */
|
|
61
|
+
export declare const defaultGmApprovalWhen: ({ action }: {
|
|
62
|
+
readonly action: GmActionSummary;
|
|
63
|
+
}) => boolean;
|
|
64
|
+
|
|
65
|
+
export declare const defaultGmAuthorize: (actor: GmActor, action: GmActionSummary) => boolean;
|
|
66
|
+
|
|
67
|
+
export declare const defineGmAction: <I, IE, O, OE>(definition: GmActionDefinition<I, IE, O, OE>) => GmAction;
|
|
68
|
+
|
|
69
|
+
/** Pays currency from a system account into a player's wallet. */
|
|
70
|
+
export declare const economyGrant: (source: GmEconomySource, options: GmEconomyActionOptions) => GmAction;
|
|
71
|
+
|
|
72
|
+
/** A compensating transfer back to the system account; ledger history is never deleted. */
|
|
73
|
+
export declare const economyRevoke: (source: GmEconomySource, options: GmEconomyActionOptions) => GmAction;
|
|
74
|
+
|
|
75
|
+
/** Flips a feature's kill switch (a flag's `enabled`): live at once, durable and audited with the
|
|
76
|
+
* requesting staff member on the postgres tier. Sensitive: needs a second person by default. */
|
|
77
|
+
export declare const flagsToggle: (source: GmFlagsSource, options?: GmFlagsActionOptions) => GmAction;
|
|
78
|
+
|
|
79
|
+
/** Chunk reset: undoes every player's geometry edits in one chunk of a live Room, back to its
|
|
80
|
+
* built-in (static) version. Same path and policy as `geometryRollback`, with no target player;
|
|
81
|
+
* the history stays in the journal. Sensitive by default. */
|
|
82
|
+
export declare const geometryReset: (source: GmGeometrySource, overrides?: GmActionOverrides) => GmAction;
|
|
83
|
+
|
|
84
|
+
/** Griefing rollback: undoes one player's geometry edits in one chunk of a live Room. Runs as the
|
|
85
|
+
* requesting staff member; the Room's Host asks the app's rollback policy. The GM request is the
|
|
86
|
+
* rollback request ID, so a retried approval rolls back once. Sensitive by default. */
|
|
87
|
+
export declare const geometryRollback: (source: GmGeometrySource, overrides?: GmActionOverrides) => GmAction;
|
|
88
|
+
|
|
89
|
+
/** The erased shape the plugin stores; build one with `defineGmAction`. */
|
|
90
|
+
export declare interface GmAction {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly title: string;
|
|
93
|
+
readonly input: Schema.Codec<unknown, unknown>;
|
|
94
|
+
readonly output: Schema.Codec<unknown, unknown>;
|
|
95
|
+
readonly risk: GmActionRisk;
|
|
96
|
+
readonly target?: ((input: never) => string | null) | undefined;
|
|
97
|
+
readonly execute: (input: never, ctx: GmActionContext) => Effect.Effect<unknown, unknown>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** What an action receives besides its decoded input. `requestId` is stable for the request
|
|
101
|
+
* (`[A-Za-z0-9-]`, at most 64 characters): pass it to the owning plugin as its idempotency key. */
|
|
102
|
+
export declare interface GmActionContext {
|
|
103
|
+
readonly tenantId: string;
|
|
104
|
+
readonly requestId: string;
|
|
105
|
+
readonly requesterId: string;
|
|
106
|
+
readonly approverId: string | null;
|
|
107
|
+
readonly reason: string;
|
|
108
|
+
readonly ticket: string | null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export declare interface GmActionDefinition<I, IE, O, OE> {
|
|
112
|
+
/** Stable, namespaced id (`economy.grant`); the default scope is `gm:<id>`. */
|
|
113
|
+
readonly id: string;
|
|
114
|
+
readonly title: string;
|
|
115
|
+
/** Decoded server-side; its encoded form must be a JSON object and is stored with the request. */
|
|
116
|
+
readonly input: Schema.Codec<I, IE>;
|
|
117
|
+
readonly output: Schema.Codec<O, OE>;
|
|
118
|
+
/** `sensitive` requests need a second person when the plugin's `approval` is configured. */
|
|
119
|
+
readonly risk: GmActionRisk;
|
|
120
|
+
/** The player the request acts on: indexed for history and redacted with that player. */
|
|
121
|
+
readonly target?: (input: I) => string | null;
|
|
122
|
+
/** Must be idempotent on `requestId`: a retried request or a second approval runs it again. */
|
|
123
|
+
readonly execute: (input: I, ctx: GmActionContext) => Effect.Effect<O, unknown>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export declare type GmActionInfo = typeof GmActionInfoSchema.Type;
|
|
127
|
+
|
|
128
|
+
/** One action the caller may run; `input` is the JSON Schema of the encoded input a console renders its form from. */
|
|
129
|
+
declare const GmActionInfoSchema: Schema.Struct<{
|
|
130
|
+
readonly id: Schema.String;
|
|
131
|
+
readonly title: Schema.String;
|
|
132
|
+
readonly risk: Schema.Literals<readonly ["routine", "sensitive"]>;
|
|
133
|
+
readonly input: Schema.Unknown;
|
|
134
|
+
}>;
|
|
135
|
+
|
|
136
|
+
export declare interface GmActionOverrides {
|
|
137
|
+
readonly id?: string;
|
|
138
|
+
readonly title?: string;
|
|
139
|
+
readonly risk?: GmActionRisk;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export declare type GmActionRisk = typeof ACTION_RISKS[number];
|
|
143
|
+
|
|
144
|
+
export declare interface GmActionSummary {
|
|
145
|
+
readonly id: string;
|
|
146
|
+
readonly title: string;
|
|
147
|
+
readonly risk: C.GmActionRisk;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** The staff caller as the policies see it: resolved scopes, never a credential claim. */
|
|
151
|
+
export declare interface GmActor {
|
|
152
|
+
readonly type: 'user' | 'serviceAccount';
|
|
153
|
+
readonly id: string;
|
|
154
|
+
readonly tenantId: string;
|
|
155
|
+
readonly scopes: ReadonlyArray<string>;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export declare interface GmApi {
|
|
159
|
+
readonly actions: (subject: Subject) => Effect.Effect<ReadonlyArray<C.GmActionInfo>, GmError>;
|
|
160
|
+
readonly requests: (subject: Subject, input: {
|
|
161
|
+
readonly state?: C.GmRequestState | undefined;
|
|
162
|
+
}) => Effect.Effect<ReadonlyArray<C.GmRequest>, GmError>;
|
|
163
|
+
readonly execute: (subject: Subject, input: C.GmExecuteInput) => Effect.Effect<C.GmRequest, GmError>;
|
|
164
|
+
readonly approve: (subject: Subject, id: string) => Effect.Effect<C.GmRequest, GmError>;
|
|
165
|
+
readonly reject: (subject: Subject, id: string) => Effect.Effect<C.GmRequest, GmError>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export declare interface GmApprovalPolicy {
|
|
169
|
+
/** Which requests wait for a second person. Default: actions whose risk is `sensitive`. */
|
|
170
|
+
readonly when?: (request: {
|
|
171
|
+
readonly action: GmActionSummary;
|
|
172
|
+
readonly input: unknown;
|
|
173
|
+
readonly actor: GmActor;
|
|
174
|
+
}) => boolean;
|
|
175
|
+
/** Scope an approver holds (`admin:full` also approves). Default `gm:approve`. */
|
|
176
|
+
readonly approverScope?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export declare interface GmConfigActionOptions extends GmActionOverrides {
|
|
180
|
+
/** Config keys the console offers; omitted, any declared key. */
|
|
181
|
+
readonly keys?: readonly [string, ...string[]];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** The installed flags plugin with a Config catalogue (`flagsPlugin({ config })`). */
|
|
185
|
+
export declare interface GmConfigSource {
|
|
186
|
+
readonly setConfig?: (input: {
|
|
187
|
+
readonly key: string;
|
|
188
|
+
readonly value: unknown;
|
|
189
|
+
readonly actor?: string | null;
|
|
190
|
+
}) => Effect.Effect<{
|
|
191
|
+
readonly key: string;
|
|
192
|
+
readonly value: unknown;
|
|
193
|
+
}, unknown>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export declare interface GmEconomyActionOptions extends GmActionOverrides {
|
|
197
|
+
/** The system account a grant is paid from and a revoke is paid into. */
|
|
198
|
+
readonly systemAccount: string;
|
|
199
|
+
/** Currencies the console offers; omitted, any declared economy currency. */
|
|
200
|
+
readonly currencies?: readonly [string, ...string[]];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** The installed economy plugin (`economyPlugin(...)`) or anything with its trusted transfer service. */
|
|
204
|
+
export declare interface GmEconomySource {
|
|
205
|
+
readonly economy: {
|
|
206
|
+
readonly service: () => Pick<EconomyService, 'transfer'>;
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** `action_failed` carries the owning plugin's own error code (`insufficient_funds`, `conflict`, …) in `actionCode`. */
|
|
211
|
+
export declare class GmError extends GmError_base {
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
declare const GmError_base: Schema.Class<GmError, Schema.TaggedStruct<"GmError", {
|
|
215
|
+
readonly code: Schema.Literals<readonly ["identity_required", "invalid_input", "forbidden", "not_found", "conflict", "unavailable", "action_failed"]>;
|
|
216
|
+
readonly actionCode: Schema.optional<Schema.String>;
|
|
217
|
+
}>, YieldableError>;
|
|
218
|
+
|
|
219
|
+
export declare interface GmExecuteInput {
|
|
220
|
+
readonly requestId: string;
|
|
221
|
+
readonly actionId: string;
|
|
222
|
+
readonly input: unknown;
|
|
223
|
+
readonly reason: string;
|
|
224
|
+
readonly ticket?: string | undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export declare interface GmFlagsActionOptions extends GmActionOverrides {
|
|
228
|
+
/** Kill switches the console offers (flag keys); omitted, any non-Config flag. */
|
|
229
|
+
readonly keys?: readonly [string, ...string[]];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** The installed flags plugin (`flagsPlugin(...)`) or anything with its audited kill-switch flip. */
|
|
233
|
+
export declare interface GmFlagsSource {
|
|
234
|
+
readonly toggle: (input: {
|
|
235
|
+
readonly key: string;
|
|
236
|
+
readonly enabled: boolean;
|
|
237
|
+
readonly actor?: string | null;
|
|
238
|
+
}) => Effect.Effect<{
|
|
239
|
+
readonly key: string;
|
|
240
|
+
readonly enabled: boolean;
|
|
241
|
+
readonly previous: boolean;
|
|
242
|
+
}, unknown>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export declare interface GmGeometrySource {
|
|
246
|
+
readonly moderation: Pick<RoomModerationService, 'rollbackGeometry'>;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export declare interface GmLeaguesSource {
|
|
250
|
+
readonly leaderboards: {
|
|
251
|
+
readonly service: () => {
|
|
252
|
+
readonly assignLeague: (subject: ReturnType<typeof systemSubject>, input: {
|
|
253
|
+
readonly tenantId: string;
|
|
254
|
+
readonly league: string;
|
|
255
|
+
readonly ownerId: string;
|
|
256
|
+
readonly division: string;
|
|
257
|
+
}) => Effect.Effect<{
|
|
258
|
+
readonly league: string;
|
|
259
|
+
readonly division: string;
|
|
260
|
+
}, unknown>;
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** The installed liveops plugin with maintenance (`liveOpsPlugin({ maintenance })`). */
|
|
266
|
+
export declare interface GmMaintenanceSource {
|
|
267
|
+
readonly maintenance?: () => {
|
|
268
|
+
readonly schedule: (subject: ReturnType<typeof systemSubject>, tenantId: string, intent: {
|
|
269
|
+
readonly requestId: string;
|
|
270
|
+
readonly from: number;
|
|
271
|
+
readonly until: number;
|
|
272
|
+
readonly drainBy: number;
|
|
273
|
+
readonly messageKey: string;
|
|
274
|
+
}) => Effect.Effect<{
|
|
275
|
+
readonly id: string;
|
|
276
|
+
readonly from: number;
|
|
277
|
+
readonly until: number;
|
|
278
|
+
readonly drainBy: number;
|
|
279
|
+
readonly state: string;
|
|
280
|
+
}, unknown>;
|
|
281
|
+
readonly cancel: (subject: ReturnType<typeof systemSubject>, tenantId: string, intent: {
|
|
282
|
+
readonly requestId: string;
|
|
283
|
+
readonly windowId: string;
|
|
284
|
+
}) => Effect.Effect<{
|
|
285
|
+
readonly id: string;
|
|
286
|
+
readonly state: string;
|
|
287
|
+
}, unknown>;
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export declare interface GmOptions {
|
|
292
|
+
readonly actions: ReadonlyArray<GmAction>;
|
|
293
|
+
/** Replaces the default rule: `gm:<id>`, `gm:<namespace>.*`, `gm:*` or `admin:full`. */
|
|
294
|
+
readonly authorize?: (actor: GmActor, action: GmActionSummary) => boolean;
|
|
295
|
+
/** Omitted: every authorized request runs at once. */
|
|
296
|
+
readonly approval?: GmApprovalPolicy;
|
|
297
|
+
readonly now?: () => number;
|
|
298
|
+
readonly pageSize?: number;
|
|
299
|
+
readonly maxExportRows?: number;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export declare interface GmPlugin extends VoltroPlugin {
|
|
303
|
+
readonly gm: {
|
|
304
|
+
readonly api: () => GmApi;
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Game-master actions: each request names its action, input and reason, runs once per
|
|
309
|
+
* request id, and optionally waits for a second person. RPC calls are audited by plugin-audit. */
|
|
310
|
+
export declare const gmPlugin: (input: GmOptions) => GmPlugin;
|
|
311
|
+
|
|
312
|
+
export declare type GmRequest = typeof GmRequestSchema.Type;
|
|
313
|
+
|
|
314
|
+
declare const GmRequestSchema: Schema.Struct<{
|
|
315
|
+
readonly id: Schema.String;
|
|
316
|
+
readonly actionId: Schema.String;
|
|
317
|
+
readonly state: Schema.Literals<readonly ["pending", "approved", "executed", "rejected"]>;
|
|
318
|
+
readonly targetId: Schema.NullOr<Schema.String>;
|
|
319
|
+
readonly input: Schema.Unknown;
|
|
320
|
+
readonly output: Schema.NullOr<Schema.Unknown>;
|
|
321
|
+
readonly reason: Schema.String;
|
|
322
|
+
readonly ticket: Schema.NullOr<Schema.String>;
|
|
323
|
+
readonly requesterId: Schema.NullOr<Schema.String>;
|
|
324
|
+
readonly approverId: Schema.NullOr<Schema.String>;
|
|
325
|
+
readonly createdAt: Schema.Number;
|
|
326
|
+
readonly decidedAt: Schema.NullOr<Schema.Number>;
|
|
327
|
+
readonly executedAt: Schema.NullOr<Schema.Number>;
|
|
328
|
+
}>;
|
|
329
|
+
|
|
330
|
+
export declare const gmRequestsTable: Table<"_voltro_gm_requests", FieldDefinitions<{
|
|
331
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
332
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
333
|
+
readonly actionId: ColumnBuilder<string, "text", boolean>;
|
|
334
|
+
readonly state: ColumnBuilder<"rejected" | "pending" | "approved" | "executed", "text", boolean>;
|
|
335
|
+
readonly targetId: ColumnBuilder<string | null, "text", boolean>;
|
|
336
|
+
readonly input: ColumnBuilder<unknown, "json", boolean>;
|
|
337
|
+
readonly output: ColumnBuilder<unknown, "json", boolean>;
|
|
338
|
+
readonly reason: ColumnBuilder<string, "text", boolean>;
|
|
339
|
+
readonly ticket: ColumnBuilder<string | null, "text", boolean>;
|
|
340
|
+
readonly requesterId: ColumnBuilder<string | null, "text", boolean>;
|
|
341
|
+
readonly approverId: ColumnBuilder<string | null, "text", boolean>;
|
|
342
|
+
readonly digest: ColumnBuilder<string, "text", boolean>;
|
|
343
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
344
|
+
readonly decidedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
345
|
+
readonly executedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
346
|
+
}>, true, never>;
|
|
347
|
+
|
|
348
|
+
export declare type GmRequestState = typeof REQUEST_STATES[number];
|
|
349
|
+
|
|
350
|
+
/** The installed rooms plugin (`roomsPlugin(...)`) or anything that can drain a tenant's Rooms. */
|
|
351
|
+
export declare interface GmRoomsDrainSource {
|
|
352
|
+
readonly moderation: Pick<RoomModerationService, 'closeAll'>;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** The installed rooms plugin (`roomsPlugin(...)`) or anything with its operator moderation. */
|
|
356
|
+
export declare interface GmRoomsSource {
|
|
357
|
+
readonly moderation: Pick<RoomModerationService, 'kick'>;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** The installed sanctions plugin (`sanctionsPlugin(...)`) or anything with its operator service. */
|
|
361
|
+
export declare interface GmSanctionsSource {
|
|
362
|
+
readonly sanctions: {
|
|
363
|
+
readonly operator: () => Pick<SanctionsOperatorService, 'issue'>;
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Declared GM configuration for operators: actions, rule slots and budgets. No request, reason or staff enumeration. */
|
|
368
|
+
export declare const gmStatus: (options: ResolvedGmOptions, bound: boolean) => {
|
|
369
|
+
observedAt: number;
|
|
370
|
+
bound: boolean;
|
|
371
|
+
actions: {
|
|
372
|
+
id: string;
|
|
373
|
+
title: string;
|
|
374
|
+
risk: "sensitive" | "routine";
|
|
375
|
+
}[];
|
|
376
|
+
authorize: "custom" | "default";
|
|
377
|
+
approval: {
|
|
378
|
+
when: "custom" | "default";
|
|
379
|
+
approverScope: string;
|
|
380
|
+
} | null;
|
|
381
|
+
pageSize: number;
|
|
382
|
+
maxExportRows: number;
|
|
383
|
+
tables: "_voltro_gm_requests"[];
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
/** System21 inventory: the two policy slots; GM owns no port or event. */
|
|
387
|
+
export declare const gmSystemContract: {
|
|
388
|
+
readonly slots: {
|
|
389
|
+
readonly authorize: {
|
|
390
|
+
readonly defaultExport: "defaultGmAuthorize";
|
|
391
|
+
readonly fixtureExport: "gmAuthorizeSlotFixture";
|
|
392
|
+
};
|
|
393
|
+
readonly 'approval.when': {
|
|
394
|
+
readonly defaultExport: "defaultGmApprovalWhen";
|
|
395
|
+
readonly fixtureExport: "gmApprovalSlotFixture";
|
|
396
|
+
};
|
|
397
|
+
};
|
|
398
|
+
readonly ports: {};
|
|
399
|
+
readonly events: readonly [];
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
export declare const gmTables: Table<"_voltro_gm_requests", FieldDefinitions<{
|
|
403
|
+
readonly id: ColumnBuilder<string, "id", boolean>;
|
|
404
|
+
readonly tenantId: ColumnBuilder<string, "text", boolean>;
|
|
405
|
+
readonly actionId: ColumnBuilder<string, "text", boolean>;
|
|
406
|
+
readonly state: ColumnBuilder<"rejected" | "pending" | "approved" | "executed", "text", boolean>;
|
|
407
|
+
readonly targetId: ColumnBuilder<string | null, "text", boolean>;
|
|
408
|
+
readonly input: ColumnBuilder<unknown, "json", boolean>;
|
|
409
|
+
readonly output: ColumnBuilder<unknown, "json", boolean>;
|
|
410
|
+
readonly reason: ColumnBuilder<string, "text", boolean>;
|
|
411
|
+
readonly ticket: ColumnBuilder<string | null, "text", boolean>;
|
|
412
|
+
readonly requesterId: ColumnBuilder<string | null, "text", boolean>;
|
|
413
|
+
readonly approverId: ColumnBuilder<string | null, "text", boolean>;
|
|
414
|
+
readonly digest: ColumnBuilder<string, "text", boolean>;
|
|
415
|
+
readonly createdAt: ColumnBuilder<Date, "timestamp", boolean>;
|
|
416
|
+
readonly decidedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
417
|
+
readonly executedAt: ColumnBuilder<Date | null, "timestamp", boolean>;
|
|
418
|
+
}>, true, never>[];
|
|
419
|
+
|
|
420
|
+
/** The installed leaderboards plugin with tournament coordination (`leaderboardsPlugin({ tournamentCoordination })`). */
|
|
421
|
+
export declare interface GmTournamentsSource {
|
|
422
|
+
readonly leaderboards: {
|
|
423
|
+
readonly tournaments: () => {
|
|
424
|
+
readonly resolve: (subject: ReturnType<typeof systemSubject>, scope: {
|
|
425
|
+
readonly tenantId: string;
|
|
426
|
+
readonly tournamentId: string;
|
|
427
|
+
}, intent: {
|
|
428
|
+
readonly disputeId: string;
|
|
429
|
+
readonly resolutionId: string;
|
|
430
|
+
readonly winnerId: string;
|
|
431
|
+
}) => Effect.Effect<{
|
|
432
|
+
readonly phase: string;
|
|
433
|
+
readonly champion: string | null;
|
|
434
|
+
readonly unresolvedDisputes: number;
|
|
435
|
+
}, unknown>;
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/** Places a player in a league division (a correction or a placement). Takes effect at once;
|
|
441
|
+
* the next league close moves the player from there. Sensitive by default. */
|
|
442
|
+
export declare const leaguesAssign: (source: GmLeaguesSource, overrides?: GmActionOverrides) => GmAction;
|
|
443
|
+
|
|
444
|
+
/** Cancels a planned or running maintenance window of the staff member's tenant. */
|
|
445
|
+
export declare const maintenanceCancel: (source: GmMaintenanceSource, overrides?: GmActionOverrides) => GmAction;
|
|
446
|
+
|
|
447
|
+
/** Plans a maintenance window for the staff member's tenant (epoch ms). New Room reservations
|
|
448
|
+
* close and running Rooms drain where the app wires that up. Sensitive by default. */
|
|
449
|
+
export declare const maintenanceSchedule: (source: GmMaintenanceSource, overrides?: GmActionOverrides) => GmAction;
|
|
450
|
+
|
|
451
|
+
/** pending: waits for a second person. approved: may run (retries re-run the idempotent action). executed and rejected are terminal. */
|
|
452
|
+
export declare const REQUEST_STATES: readonly ["pending", "approved", "executed", "rejected"];
|
|
453
|
+
|
|
454
|
+
export declare const REQUESTS_TABLE = "_voltro_gm_requests";
|
|
455
|
+
|
|
456
|
+
declare interface ResolvedAction {
|
|
457
|
+
readonly action: GmAction;
|
|
458
|
+
readonly summary: GmActionSummary;
|
|
459
|
+
readonly schema: unknown;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
export declare interface ResolvedGmOptions {
|
|
463
|
+
readonly actions: ReadonlyMap<string, ResolvedAction>;
|
|
464
|
+
readonly authorize: (actor: GmActor, action: GmActionSummary) => boolean;
|
|
465
|
+
readonly approval: {
|
|
466
|
+
readonly when: NonNullable<GmApprovalPolicy['when']>;
|
|
467
|
+
readonly approverScope: string;
|
|
468
|
+
} | null;
|
|
469
|
+
readonly now: () => number;
|
|
470
|
+
readonly pageSize: number;
|
|
471
|
+
readonly maxExportRows: number;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/** Validates the configured actions once at construction; a bad definition refuses the plugin, not a request. */
|
|
475
|
+
export declare const resolveGmOptions: (input: GmOptions) => ResolvedGmOptions;
|
|
476
|
+
|
|
477
|
+
/** Maintenance drain: kicks every session in every live Room of the tenant (seats released, no
|
|
478
|
+
* reconnect). Close new reservations first (Rooms `admission`), or players join again. Sensitive:
|
|
479
|
+
* needs a second person by default. */
|
|
480
|
+
export declare const roomsCloseAll: (source: GmRoomsDrainSource, overrides?: GmActionOverrides) => GmAction;
|
|
481
|
+
|
|
482
|
+
/** Closes the player's sessions in one Room with a Kick frame and releases their seats; the
|
|
483
|
+
* owning Host is found through the Rooms directory. Pair with a ban to keep them out. */
|
|
484
|
+
export declare const roomsKick: (source: GmRoomsSource, overrides?: GmActionOverrides) => GmAction;
|
|
485
|
+
|
|
486
|
+
/** Account ban through the sanctions plugin; permanent when `durationMs` is omitted. */
|
|
487
|
+
export declare const sanctionsBan: (source: GmSanctionsSource, overrides?: GmActionOverrides) => GmAction;
|
|
488
|
+
|
|
489
|
+
/** Chat mute through the sanctions plugin. */
|
|
490
|
+
export declare const sanctionsMute: (source: GmSanctionsSource, overrides?: GmActionOverrides) => GmAction;
|
|
491
|
+
|
|
492
|
+
export declare const staffActor: (subject: Subject) => GmActor;
|
|
493
|
+
|
|
494
|
+
/** Decides a disputed tournament match for the named winner; the bracket resumes when no dispute
|
|
495
|
+
* is left. The GM request is the resolution ID, so a retried approval resolves once. Sensitive by default. */
|
|
496
|
+
export declare const tournamentsResolve: (source: GmTournamentsSource, overrides?: GmActionOverrides) => GmAction;
|
|
497
|
+
|
|
498
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { GmError as e, gmError as t } from "./errors.js";
|
|
2
|
+
import { ACTION_RISKS as n, REQUESTS_TABLE as r, REQUEST_STATES as i } from "./contract.js";
|
|
3
|
+
import { gmRequestsTable as a, gmTables as o } from "./entities.js";
|
|
4
|
+
import { dataStoreGm as s, defaultGmApprovalWhen as c, defaultGmAuthorize as l, resolveGmOptions as u, staffActor as d } from "./service.js";
|
|
5
|
+
import { gmStatus as f } from "./inspect.js";
|
|
6
|
+
import { BASE_NAME as p, actionsDescriptor as m, approveDescriptor as h, executeDescriptor as g, gmRpcClientImports as _, rejectDescriptor as v, requestsDescriptor as y } from "./rpc.js";
|
|
7
|
+
import { defineGmAction as b } from "./action.js";
|
|
8
|
+
import { configSet as x, economyGrant as S, economyRevoke as C, flagsToggle as w, geometryReset as T, geometryRollback as E, leaguesAssign as D, maintenanceCancel as O, maintenanceSchedule as k, roomsCloseAll as A, roomsKick as j, sanctionsBan as M, sanctionsMute as N, tournamentsResolve as P } from "./builtins.js";
|
|
9
|
+
import { defineLicensedGamePlugin as F } from "@voltro/plugin-licensing/gate";
|
|
10
|
+
import { Effect as I } from "effect";
|
|
11
|
+
//#region src/index.ts
|
|
12
|
+
var L = {
|
|
13
|
+
slots: {
|
|
14
|
+
authorize: {
|
|
15
|
+
defaultExport: "defaultGmAuthorize",
|
|
16
|
+
fixtureExport: "gmAuthorizeSlotFixture"
|
|
17
|
+
},
|
|
18
|
+
"approval.when": {
|
|
19
|
+
defaultExport: "defaultGmApprovalWhen",
|
|
20
|
+
fixtureExport: "gmApprovalSlotFixture"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
ports: {},
|
|
24
|
+
events: []
|
|
25
|
+
}, R = (n) => {
|
|
26
|
+
let r = u(n), i, a, c = (e) => I.suspend(() => a === void 0 ? I.fail(t("unavailable")) : e(a)), l = {
|
|
27
|
+
actions: (e) => c((t) => t.api.actions(e)),
|
|
28
|
+
requests: (e, t) => c((n) => n.api.requests(e, t)),
|
|
29
|
+
execute: (e, t) => c((n) => n.api.execute(e, t)),
|
|
30
|
+
approve: (e, t) => c((n) => n.api.approve(e, t)),
|
|
31
|
+
reject: (e, t) => c((n) => n.api.reject(e, t))
|
|
32
|
+
}, d = [
|
|
33
|
+
{
|
|
34
|
+
...m,
|
|
35
|
+
execute: (e, t) => l.actions(t.request.subject)
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
...y,
|
|
39
|
+
execute: (e, t) => l.requests(t.request.subject, e)
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
...g,
|
|
43
|
+
execute: (e, t) => l.execute(t.request.subject, e)
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
...h,
|
|
47
|
+
execute: (e, t) => l.approve(t.request.subject, e.id)
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
...v,
|
|
51
|
+
execute: (e, t) => l.reject(t.request.subject, e.id)
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
return {
|
|
55
|
+
gm: { api: () => l },
|
|
56
|
+
...F({
|
|
57
|
+
name: p,
|
|
58
|
+
description: "Configurable game-master actions with reasons, idempotent requests and optional second-person approval.",
|
|
59
|
+
permissions: ["store:write", "inspect:read"],
|
|
60
|
+
routes: d,
|
|
61
|
+
inspectEndpoints: [{
|
|
62
|
+
method: "GET",
|
|
63
|
+
path: "/status",
|
|
64
|
+
scope: "process",
|
|
65
|
+
description: "Declared GM actions, rule slots and budgets; no request, reason or staff enumeration.",
|
|
66
|
+
handler: () => I.try({
|
|
67
|
+
try: () => ({
|
|
68
|
+
kind: "json",
|
|
69
|
+
data: f(r, a !== void 0)
|
|
70
|
+
}),
|
|
71
|
+
catch: () => t("unavailable")
|
|
72
|
+
})
|
|
73
|
+
}],
|
|
74
|
+
rpcClientDescriptors: _,
|
|
75
|
+
errorSchemas: [{
|
|
76
|
+
schema: e,
|
|
77
|
+
import: {
|
|
78
|
+
module: "@voltro/plugin-gm/errors",
|
|
79
|
+
name: "GmError"
|
|
80
|
+
}
|
|
81
|
+
}],
|
|
82
|
+
extendSchema: { tables: o },
|
|
83
|
+
subjectPrivacy: {
|
|
84
|
+
tables: o.map((e) => e.tableName),
|
|
85
|
+
kinds: ["user", "guest"]
|
|
86
|
+
},
|
|
87
|
+
bindDataStore: (e) => {
|
|
88
|
+
if (i !== void 0 && i !== e) throw Error("GM plugin instance cannot cross app stores");
|
|
89
|
+
i = e, a = s(e, r);
|
|
90
|
+
},
|
|
91
|
+
onExport: (e, t) => c((n) => n.exportSubject({
|
|
92
|
+
subjectId: e,
|
|
93
|
+
tenantId: t.tenantId,
|
|
94
|
+
kind: t.kind
|
|
95
|
+
})),
|
|
96
|
+
onErase: (e, t) => c((n) => n.eraseSubject({
|
|
97
|
+
subjectId: e,
|
|
98
|
+
tenantId: t.tenantId,
|
|
99
|
+
kind: t.kind
|
|
100
|
+
})),
|
|
101
|
+
onDeactivate: () => I.sync(() => {
|
|
102
|
+
a = void 0, i = void 0;
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
//#endregion
|
|
108
|
+
export { n as ACTION_RISKS, e as GmError, r as REQUESTS_TABLE, i as REQUEST_STATES, x as configSet, s as dataStoreGm, c as defaultGmApprovalWhen, l as defaultGmAuthorize, b as defineGmAction, S as economyGrant, C as economyRevoke, w as flagsToggle, T as geometryReset, E as geometryRollback, R as gmPlugin, a as gmRequestsTable, f as gmStatus, L as gmSystemContract, o as gmTables, D as leaguesAssign, O as maintenanceCancel, k as maintenanceSchedule, u as resolveGmOptions, A as roomsCloseAll, j as roomsKick, M as sanctionsBan, N as sanctionsMute, d as staffActor, P as tournamentsResolve };
|
package/dist/inspect.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { gmTables as e } from "./entities.js";
|
|
2
|
+
import { defaultGmApprovalWhen as t, defaultGmAuthorize as n } from "./service.js";
|
|
3
|
+
//#region src/inspect.ts
|
|
4
|
+
var r = (r, i) => ({
|
|
5
|
+
observedAt: r.now(),
|
|
6
|
+
bound: i,
|
|
7
|
+
actions: [...r.actions.values()].map(({ summary: e }) => ({
|
|
8
|
+
id: e.id,
|
|
9
|
+
title: e.title,
|
|
10
|
+
risk: e.risk
|
|
11
|
+
})),
|
|
12
|
+
authorize: r.authorize === n ? "default" : "custom",
|
|
13
|
+
approval: r.approval === null ? null : {
|
|
14
|
+
when: r.approval.when === t ? "default" : "custom",
|
|
15
|
+
approverScope: r.approval.approverScope
|
|
16
|
+
},
|
|
17
|
+
pageSize: r.pageSize,
|
|
18
|
+
maxExportRows: r.maxExportRows,
|
|
19
|
+
tables: e.map((e) => e.tableName)
|
|
20
|
+
});
|
|
21
|
+
//#endregion
|
|
22
|
+
export { r as gmStatus };
|