@voltro/plugin-leaderboards 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 +1087 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +5603 -0
- package/dist/administration.js +4 -0
- package/dist/bracketAdmission.js +293 -0
- package/dist/bracketAdmissionPolicy.js +21 -0
- package/dist/bracketInstallation.js +132 -0
- package/dist/bracketMatchPorts.js +4 -0
- package/dist/bracketMatches.js +545 -0
- package/dist/brackets.d.ts +149 -0
- package/dist/brackets.js +378 -0
- package/dist/bucketStore.js +92 -0
- package/dist/buckets.js +8 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +16 -0
- package/dist/glicko2.js +71 -0
- package/dist/index.d.ts +1208 -0
- package/dist/index.js +15 -0
- package/dist/inspect.js +83 -0
- package/dist/json.js +38 -0
- package/dist/leaderboard.d.ts +49 -0
- package/dist/leaderboard.js +56 -0
- package/dist/leagueSchedule.js +39 -0
- package/dist/leagues.js +30 -0
- package/dist/openskill.js +73 -0
- package/dist/plugin.js +337 -0
- package/dist/portLifetime.js +66 -0
- package/dist/ports.d.ts +294 -0
- package/dist/ports.js +6 -0
- package/dist/rankQuery.js +23 -0
- package/dist/ranking.d.ts +42 -0
- package/dist/ranking.js +70 -0
- package/dist/rating.d.ts +103 -0
- package/dist/rating.js +49 -0
- package/dist/ratingPools.js +133 -0
- package/dist/ratingStore.js +333 -0
- package/dist/ratingStrategies.js +107 -0
- package/dist/records.d.ts +116 -0
- package/dist/records.js +87 -0
- package/dist/rpc.d.ts +321 -0
- package/dist/rpc.js +305 -0
- package/dist/score.d.ts +13 -0
- package/dist/score.js +26 -0
- package/dist/server.d.ts +1477 -0
- package/dist/server.js +17 -0
- package/dist/service.js +948 -0
- package/dist/subjectFences.js +43 -0
- package/dist/tables.entity.js +187 -0
- package/dist/testing.d.ts +872 -0
- package/dist/testing.js +367 -0
- package/dist/tournament-app/tournament.advance.workflow.server.tsx +3 -0
- package/dist/tournament-app/tournament.advance.workflow.tsx +12 -0
- package/dist/tournament-app/tournament.stage.workflow.server.tsx +3 -0
- package/dist/tournament-app/tournament.stage.workflow.tsx +10 -0
- package/dist/tournamentInstallation.js +167 -0
- package/dist/tournamentPrizes.js +33 -0
- package/dist/tournamentStage.js +150 -0
- package/dist/tournamentStagePorts.js +4 -0
- package/dist/tournamentWorkflow.js +100 -0
- package/dist/tournamentWorkflowSchemas.js +53 -0
- package/dist/tournaments.d.ts +32 -0
- package/dist/tournaments.js +20 -0
- package/dist/web.d.ts +175 -0
- package/dist/web.js +16 -0
- package/package.json +113 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1208 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import { DataStore } from '@voltro/database';
|
|
3
|
+
import { Effect } from 'effect';
|
|
4
|
+
import { PluginPrivacyRequest } from '@voltro/protocol';
|
|
5
|
+
import { PluginPrivacyTarget } from '@voltro/protocol';
|
|
6
|
+
import { Schema } from 'effect';
|
|
7
|
+
import { Subject } from '@voltro/protocol';
|
|
8
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
9
|
+
import { YieldableError } from 'effect/Cause';
|
|
10
|
+
|
|
11
|
+
declare interface AdmissionState {
|
|
12
|
+
readonly version: 1;
|
|
13
|
+
readonly definition: BracketAdmissionDefinition;
|
|
14
|
+
readonly phase: 'open' | 'sealed' | 'erasing' | 'cancelled';
|
|
15
|
+
readonly entries: ReadonlyArray<BracketAdmissionEntry>;
|
|
16
|
+
readonly eraseRequest: string | null;
|
|
17
|
+
readonly eraseTarget: string | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare interface ApplyRatingMatchInput {
|
|
21
|
+
readonly tenantId: string;
|
|
22
|
+
readonly pool: string;
|
|
23
|
+
readonly matchId: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Submission idempotency belongs to SQL, not this pure arithmetic function. */
|
|
27
|
+
export declare const applyScore: (previous: string | bigint | number | null, submitted: string | bigint | number, operator: ScoreOperator, sort?: LeaderboardSort) => string;
|
|
28
|
+
|
|
29
|
+
declare type BracketAdmissionBinding = {
|
|
30
|
+
readonly backend: 'sql';
|
|
31
|
+
readonly options: BracketAdmissionOptions;
|
|
32
|
+
} | {
|
|
33
|
+
readonly backend: 'custom';
|
|
34
|
+
readonly version: string;
|
|
35
|
+
readonly service: BracketAdmissionService;
|
|
36
|
+
readonly sources: ReadonlyArray<string>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
declare interface BracketAdmissionDefinition {
|
|
40
|
+
readonly registrationOpensAt: number;
|
|
41
|
+
readonly registrationClosesAt: number;
|
|
42
|
+
readonly checkInOpensAt: number;
|
|
43
|
+
readonly checkInClosesAt: number;
|
|
44
|
+
readonly maxEntries: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
declare interface BracketAdmissionEntrants {
|
|
48
|
+
readonly phase: AdmissionState['phase'];
|
|
49
|
+
readonly entries: ReadonlyArray<BracketAdmissionEntry>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
declare interface BracketAdmissionEntry {
|
|
53
|
+
readonly ownerId: string;
|
|
54
|
+
readonly joinedAt: number;
|
|
55
|
+
readonly checkedInAt: number | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare interface BracketAdmissionExport extends BracketAdmissionEntry {
|
|
59
|
+
readonly tournamentId: string;
|
|
60
|
+
readonly phase: BracketAdmissionStatus['phase'];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare interface BracketAdmissionOptions {
|
|
64
|
+
readonly epochNow: () => number;
|
|
65
|
+
readonly maxTenantTournaments?: number;
|
|
66
|
+
/** Normal current application guards; no successful policy is provided. */
|
|
67
|
+
authorize(subject: Subject, scope: BracketAdmissionScope, operation: 'create' | 'register' | 'checkIn' | 'status' | 'seal' | 'entrants'): Effect.Effect<void, LeaderboardError>;
|
|
68
|
+
/** Permanent Subject admission fence + await every accepted app association. */
|
|
69
|
+
withdrawSubject(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
70
|
+
/** Cancel and await actual Rooms/timers/rewards that use this sealed roster. */
|
|
71
|
+
withdrawTournament(scope: BracketAdmissionScope, request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
72
|
+
authorizeExport(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Browser-safe Tag; consumers depend on admission, never a SQL adapter. */
|
|
76
|
+
export declare class BracketAdmissionPort extends BracketAdmissionPort_base {
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
declare const BracketAdmissionPort_base: Context.ServiceClass<BracketAdmissionPort, "@voltro/BracketAdmissionPort", {
|
|
80
|
+
create(subject: Subject, scope: BracketAdmissionScope, definition: BracketAdmissionDefinition): Effect.Effect<void, LeaderboardError>;
|
|
81
|
+
register(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<BracketAdmissionStatus, LeaderboardError>;
|
|
82
|
+
checkIn(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<BracketAdmissionStatus, LeaderboardError>;
|
|
83
|
+
status(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<BracketAdmissionStatus, LeaderboardError>;
|
|
84
|
+
seal(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<BracketAdmissionRoster, LeaderboardError>;
|
|
85
|
+
/** Trusted read of every registration with its check-in, for notifications. */
|
|
86
|
+
entrants(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<BracketAdmissionEntrants, LeaderboardError>;
|
|
87
|
+
exportSubject(request: PluginPrivacyRequest): Effect.Effect<ReadonlyArray<BracketAdmissionExport>, LeaderboardError>;
|
|
88
|
+
eraseSubject(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
89
|
+
}>;
|
|
90
|
+
|
|
91
|
+
declare interface BracketAdmissionRoster {
|
|
92
|
+
readonly checkedIn: ReadonlyArray<string>;
|
|
93
|
+
readonly noShows: ReadonlyArray<string>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
declare interface BracketAdmissionScope {
|
|
97
|
+
readonly tenantId: string;
|
|
98
|
+
readonly tournamentId: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export declare type BracketAdmissionService = Context.Service.Shape<typeof BracketAdmissionPort>;
|
|
102
|
+
|
|
103
|
+
declare interface BracketAdmissionStatus {
|
|
104
|
+
readonly phase: AdmissionState['phase'];
|
|
105
|
+
readonly entries: number;
|
|
106
|
+
readonly checkedIn: number;
|
|
107
|
+
readonly own: BracketAdmissionEntry | null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare interface BracketMatchObservation {
|
|
111
|
+
readonly id: string;
|
|
112
|
+
readonly round: number;
|
|
113
|
+
readonly left: string | null;
|
|
114
|
+
readonly right: string | null;
|
|
115
|
+
readonly status: 'pending' | 'ready' | 'walkover' | 'complete';
|
|
116
|
+
readonly winnerId: string | null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
declare interface BracketProgress {
|
|
120
|
+
readonly matches: ReadonlyArray<BracketMatchObservation>;
|
|
121
|
+
readonly champion: string | null;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
declare type BracketSlot = {
|
|
125
|
+
readonly kind: 'entrant';
|
|
126
|
+
readonly entrantId: string;
|
|
127
|
+
} | {
|
|
128
|
+
readonly kind: 'winner';
|
|
129
|
+
readonly matchId: string;
|
|
130
|
+
} | {
|
|
131
|
+
readonly kind: 'bye';
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
declare interface BracketState extends TournamentBracketDefinition {
|
|
135
|
+
readonly version: 1;
|
|
136
|
+
readonly phase: 'active' | 'paused' | 'complete' | 'erasing' | 'cancelled';
|
|
137
|
+
readonly withdrawn: boolean;
|
|
138
|
+
readonly provisions: ReadonlyArray<Provision>;
|
|
139
|
+
readonly results: ReadonlyArray<Result>;
|
|
140
|
+
readonly disputes: ReadonlyArray<Dispute>;
|
|
141
|
+
readonly settlement: {
|
|
142
|
+
readonly requestId: string;
|
|
143
|
+
readonly winnerId: string;
|
|
144
|
+
readonly complete: boolean;
|
|
145
|
+
} | null;
|
|
146
|
+
readonly erase: {
|
|
147
|
+
readonly requestId: string;
|
|
148
|
+
readonly targetDigest: string;
|
|
149
|
+
} | null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
declare interface CloseLeaderboardTournamentInput {
|
|
153
|
+
readonly tenantId: string;
|
|
154
|
+
readonly tournament: string;
|
|
155
|
+
readonly requestId: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Bounded SQL snapshot foundation: no hot board, reset scheduler or client writes. */
|
|
159
|
+
declare const dataStoreLeaderboards: (store: DataStore, input: LeaderboardStoreOptions) => {
|
|
160
|
+
assignLeague: (subject: Subject, original: {
|
|
161
|
+
readonly tenantId: string;
|
|
162
|
+
readonly league: string;
|
|
163
|
+
readonly ownerId: string;
|
|
164
|
+
readonly division: string;
|
|
165
|
+
}) => Effect.Effect<{
|
|
166
|
+
readonly league: string;
|
|
167
|
+
readonly division: string;
|
|
168
|
+
}, LeaderboardError>;
|
|
169
|
+
myLeague: (subject: Subject, league: string) => Effect.Effect<{
|
|
170
|
+
readonly league: string;
|
|
171
|
+
readonly division: string;
|
|
172
|
+
readonly assigned: boolean;
|
|
173
|
+
}, LeaderboardError>;
|
|
174
|
+
rollLeague: (subject: Subject, original: {
|
|
175
|
+
readonly tenantId: string;
|
|
176
|
+
readonly league: string;
|
|
177
|
+
readonly requestId: string;
|
|
178
|
+
readonly closedAt: number;
|
|
179
|
+
}) => Effect.Effect<{
|
|
180
|
+
readonly divisions: ReadonlyArray<{
|
|
181
|
+
readonly division: string;
|
|
182
|
+
readonly closedPeriodId: string;
|
|
183
|
+
readonly activePeriodId: string;
|
|
184
|
+
}>;
|
|
185
|
+
readonly movements: ReadonlyArray<LeagueMovement>;
|
|
186
|
+
}, LeaderboardError>;
|
|
187
|
+
leagueTenants: (subject: Subject, original: {
|
|
188
|
+
readonly league: string;
|
|
189
|
+
readonly after?: string | null;
|
|
190
|
+
readonly limit: number;
|
|
191
|
+
}) => Effect.Effect<{
|
|
192
|
+
readonly tenants: ReadonlyArray<string>;
|
|
193
|
+
readonly next: string | null;
|
|
194
|
+
}, LeaderboardError>;
|
|
195
|
+
prepareRatingMatch: (subject: Subject, original: PrepareRatingMatchInput) => Effect.Effect< RatingMatchReceipt, LeaderboardError, never>;
|
|
196
|
+
applyRatingMatch: (subject: Subject, original: ApplyRatingMatchInput) => Effect.Effect< RatingMatchReceipt, LeaderboardError, never>;
|
|
197
|
+
myRating: (subject: Subject, poolName: string) => Effect.Effect<{
|
|
198
|
+
pool: string;
|
|
199
|
+
state: {
|
|
200
|
+
readonly algorithm: "elo";
|
|
201
|
+
readonly rating: number;
|
|
202
|
+
} | {
|
|
203
|
+
readonly algorithm: "openskill";
|
|
204
|
+
readonly mu: number;
|
|
205
|
+
readonly sigma: number;
|
|
206
|
+
} | {
|
|
207
|
+
readonly algorithm: "glicko2";
|
|
208
|
+
readonly rating: number;
|
|
209
|
+
readonly deviation: number;
|
|
210
|
+
readonly volatility: number;
|
|
211
|
+
};
|
|
212
|
+
games: number;
|
|
213
|
+
updatedAt: number | null;
|
|
214
|
+
}, LeaderboardError, never>;
|
|
215
|
+
pendingRatingMatches: (subject: Subject, tenantId: string, poolName: string, limit?: number) => Effect.Effect<{
|
|
216
|
+
tenantId: string;
|
|
217
|
+
pool: string;
|
|
218
|
+
matchId: string;
|
|
219
|
+
}[], LeaderboardError, never>;
|
|
220
|
+
closeTournament: (subject: Subject, original: CloseLeaderboardTournamentInput) => Effect.Effect<RollLeaderboardPeriodResult, LeaderboardError>;
|
|
221
|
+
joinTournament: (subject: Subject, tournamentName: string) => Effect.Effect<{
|
|
222
|
+
readonly tournament: string;
|
|
223
|
+
readonly joinedAt: number;
|
|
224
|
+
readonly attemptsLeft: number;
|
|
225
|
+
}, LeaderboardError, never>;
|
|
226
|
+
tournamentStatus: (subject: Subject, tournamentName: string) => Effect.Effect<{
|
|
227
|
+
readonly tournament: string;
|
|
228
|
+
readonly board: string;
|
|
229
|
+
readonly startsAt: number;
|
|
230
|
+
readonly endsAt: number;
|
|
231
|
+
readonly observedAt: number;
|
|
232
|
+
readonly joinRequired: boolean;
|
|
233
|
+
readonly state: "open" | "upcoming" | "ended";
|
|
234
|
+
readonly entry: {
|
|
235
|
+
readonly tournament: string;
|
|
236
|
+
readonly joinedAt: number;
|
|
237
|
+
readonly attemptsLeft: number;
|
|
238
|
+
} | null;
|
|
239
|
+
}, LeaderboardError, never>;
|
|
240
|
+
rollPeriod: (subject: Subject, original: RollLeaderboardPeriodInput) => Effect.Effect<RollLeaderboardPeriodResult, LeaderboardError>;
|
|
241
|
+
history: (subject: Subject, boardName: string, limit?: number) => Effect.Effect<{
|
|
242
|
+
readonly id: string;
|
|
243
|
+
readonly board: string;
|
|
244
|
+
readonly startsAt: number;
|
|
245
|
+
readonly endsAt: number | null;
|
|
246
|
+
readonly state: "closed" | "active" | "archived";
|
|
247
|
+
readonly summary: {
|
|
248
|
+
readonly participants: number;
|
|
249
|
+
readonly top: readonly {
|
|
250
|
+
readonly id: string;
|
|
251
|
+
readonly tenantId: string;
|
|
252
|
+
readonly board: string;
|
|
253
|
+
readonly periodId: string;
|
|
254
|
+
readonly ownerId: string;
|
|
255
|
+
readonly score: string;
|
|
256
|
+
readonly subscore: string;
|
|
257
|
+
readonly updatedAt: number;
|
|
258
|
+
readonly rank: number;
|
|
259
|
+
}[];
|
|
260
|
+
} | null;
|
|
261
|
+
}[], LeaderboardError, never>;
|
|
262
|
+
submit: (subject: Subject, original: SubmitLeaderboardInput) => Effect.Effect<LeaderboardRecord, LeaderboardError>;
|
|
263
|
+
top: (subject: Subject, boardName: string, limit?: number, scope?: "global" | "bucket") => Effect.Effect<{
|
|
264
|
+
rank: number;
|
|
265
|
+
id: string;
|
|
266
|
+
board: string;
|
|
267
|
+
periodId: string;
|
|
268
|
+
ownerId: string;
|
|
269
|
+
score: string;
|
|
270
|
+
subscore: string;
|
|
271
|
+
numSubmits: number;
|
|
272
|
+
metadata: {
|
|
273
|
+
readonly [x: string]: unknown;
|
|
274
|
+
};
|
|
275
|
+
updatedAt: number;
|
|
276
|
+
bucket: string | null;
|
|
277
|
+
}[], LeaderboardError, never>;
|
|
278
|
+
me: (subject: Subject, boardName: string) => Effect.Effect<{
|
|
279
|
+
rank: number;
|
|
280
|
+
id: string;
|
|
281
|
+
board: string;
|
|
282
|
+
periodId: string;
|
|
283
|
+
ownerId: string;
|
|
284
|
+
score: string;
|
|
285
|
+
subscore: string;
|
|
286
|
+
numSubmits: number;
|
|
287
|
+
metadata: {
|
|
288
|
+
readonly [x: string]: unknown;
|
|
289
|
+
};
|
|
290
|
+
updatedAt: number;
|
|
291
|
+
bucket: string | null;
|
|
292
|
+
} | null, LeaderboardError, never>;
|
|
293
|
+
around: (subject: Subject, boardName: string, radius?: number) => Effect.Effect<{
|
|
294
|
+
rank: number;
|
|
295
|
+
id: string;
|
|
296
|
+
board: string;
|
|
297
|
+
periodId: string;
|
|
298
|
+
ownerId: string;
|
|
299
|
+
score: string;
|
|
300
|
+
subscore: string;
|
|
301
|
+
numSubmits: number;
|
|
302
|
+
metadata: {
|
|
303
|
+
readonly [x: string]: unknown;
|
|
304
|
+
};
|
|
305
|
+
updatedAt: number;
|
|
306
|
+
bucket: string | null;
|
|
307
|
+
}[], LeaderboardError, never>;
|
|
308
|
+
exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<{
|
|
309
|
+
records: {
|
|
310
|
+
readonly id: string;
|
|
311
|
+
readonly board: string;
|
|
312
|
+
readonly periodId: string;
|
|
313
|
+
readonly ownerId: string;
|
|
314
|
+
readonly score: string;
|
|
315
|
+
readonly subscore: string;
|
|
316
|
+
readonly numSubmits: number;
|
|
317
|
+
readonly metadata: {
|
|
318
|
+
readonly [x: string]: unknown;
|
|
319
|
+
};
|
|
320
|
+
readonly updatedAt: number;
|
|
321
|
+
readonly bucket: string | null;
|
|
322
|
+
}[];
|
|
323
|
+
submissions: {
|
|
324
|
+
id: unknown;
|
|
325
|
+
board: unknown;
|
|
326
|
+
periodId: unknown;
|
|
327
|
+
record: {
|
|
328
|
+
readonly id: string;
|
|
329
|
+
readonly board: string;
|
|
330
|
+
readonly periodId: string;
|
|
331
|
+
readonly ownerId: string;
|
|
332
|
+
readonly score: string;
|
|
333
|
+
readonly subscore: string;
|
|
334
|
+
readonly numSubmits: number;
|
|
335
|
+
readonly metadata: {
|
|
336
|
+
readonly [x: string]: unknown;
|
|
337
|
+
};
|
|
338
|
+
readonly updatedAt: number;
|
|
339
|
+
readonly bucket: string | null;
|
|
340
|
+
};
|
|
341
|
+
roomId: unknown;
|
|
342
|
+
matchId: unknown;
|
|
343
|
+
tournamentId: unknown;
|
|
344
|
+
at: number;
|
|
345
|
+
}[];
|
|
346
|
+
bucketAssignments: {
|
|
347
|
+
board: unknown;
|
|
348
|
+
periodId: unknown;
|
|
349
|
+
bucket: unknown;
|
|
350
|
+
group: unknown;
|
|
351
|
+
assignedAt: number;
|
|
352
|
+
}[];
|
|
353
|
+
leagues: {
|
|
354
|
+
league: unknown;
|
|
355
|
+
division: unknown;
|
|
356
|
+
updatedAt: number;
|
|
357
|
+
}[];
|
|
358
|
+
leagueMoves: {
|
|
359
|
+
league: unknown;
|
|
360
|
+
from: string;
|
|
361
|
+
to: string;
|
|
362
|
+
at: number;
|
|
363
|
+
}[];
|
|
364
|
+
periodSummaries: {
|
|
365
|
+
periodId: string;
|
|
366
|
+
board: string;
|
|
367
|
+
startsAt: number;
|
|
368
|
+
endsAt: number;
|
|
369
|
+
record: RankedLeaderboardRecord;
|
|
370
|
+
}[];
|
|
371
|
+
tournamentEntries: {
|
|
372
|
+
readonly tournament: string;
|
|
373
|
+
readonly joinedAt: number;
|
|
374
|
+
readonly attemptsLeft: number;
|
|
375
|
+
}[];
|
|
376
|
+
ratings: {
|
|
377
|
+
pool: unknown;
|
|
378
|
+
state: unknown;
|
|
379
|
+
games: unknown;
|
|
380
|
+
updatedAt: number;
|
|
381
|
+
}[];
|
|
382
|
+
ratingResults: {
|
|
383
|
+
pool: unknown;
|
|
384
|
+
matchId: {} | null;
|
|
385
|
+
previous: unknown;
|
|
386
|
+
current: unknown;
|
|
387
|
+
at: number;
|
|
388
|
+
}[];
|
|
389
|
+
pendingRatingMatches: {
|
|
390
|
+
pool: unknown;
|
|
391
|
+
matchId: unknown;
|
|
392
|
+
weight: number;
|
|
393
|
+
rank: number | undefined;
|
|
394
|
+
preparedAt: number;
|
|
395
|
+
}[];
|
|
396
|
+
}, LeaderboardError, never>;
|
|
397
|
+
eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, LeaderboardError, never>;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
export declare const defaultLeaderboardBucketAssign: LeaderboardBucketAssign;
|
|
401
|
+
|
|
402
|
+
export declare const defaultLeaderboardRankQuery: LeaderboardRankQuery;
|
|
403
|
+
|
|
404
|
+
/** Equal primary score: higher subscore, then earlier submission, then binary owner/record ID. */
|
|
405
|
+
export declare const defaultLeaderboardTiebreak: LeaderboardTiebreak;
|
|
406
|
+
|
|
407
|
+
export declare const defaultPeriodSummary: (records: ReadonlyArray<RankedLeaderboardRecord>, top?: number) => Readonly<{
|
|
408
|
+
participants: number;
|
|
409
|
+
top: readonly RankedLeaderboardRecord[];
|
|
410
|
+
}>;
|
|
411
|
+
|
|
412
|
+
/** Decay is applied on fresh participated match application, never on a read or
|
|
413
|
+
* retry. The default preserves the exact prior; no periodic decay job exists. */
|
|
414
|
+
export declare const defaultRatingDecay: RatingDecayPolicy;
|
|
415
|
+
|
|
416
|
+
export declare const defaultRatingPlacement: RatingPlacementPolicy;
|
|
417
|
+
|
|
418
|
+
export declare const defaultRatingRate: RatingRateStrategy;
|
|
419
|
+
|
|
420
|
+
export declare const defineLeaderboard: <S extends Schema.Codec<unknown, unknown>>(input: LeaderboardDefinition<S>) => LeaderboardDescriptor<S>;
|
|
421
|
+
|
|
422
|
+
export declare const defineLeague: (input: LeagueDefinition) => LeagueDefinition;
|
|
423
|
+
|
|
424
|
+
/** Declarative entry/attempt budgets only. No price, prize or reward is invented. */
|
|
425
|
+
export declare const defineTournament: (input: TournamentDefinition) => TournamentDescriptor;
|
|
426
|
+
|
|
427
|
+
declare interface Dispute extends TournamentDisputeIntent {
|
|
428
|
+
readonly ownerId: string;
|
|
429
|
+
readonly resolutionId: string | null;
|
|
430
|
+
readonly winnerId: string | null;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
declare interface DoubleEliminationMatch {
|
|
434
|
+
readonly id: string;
|
|
435
|
+
readonly stage: 'winners' | 'losers' | 'final' | 'reset';
|
|
436
|
+
readonly round: number;
|
|
437
|
+
readonly left: DoubleEliminationSlot;
|
|
438
|
+
readonly right: DoubleEliminationSlot;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
declare interface DoubleEliminationObservation extends Omit<BracketMatchObservation, 'status'> {
|
|
442
|
+
readonly stage: DoubleEliminationMatch['stage'];
|
|
443
|
+
readonly status: BracketMatchObservation['status'] | 'empty' | 'inactive';
|
|
444
|
+
readonly loserId: string | null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
declare interface DoubleEliminationProgress {
|
|
448
|
+
readonly matches: ReadonlyArray<DoubleEliminationObservation>;
|
|
449
|
+
readonly champion: string | null;
|
|
450
|
+
readonly losses: ReadonlyArray<{
|
|
451
|
+
readonly entrantId: string;
|
|
452
|
+
readonly losses: number;
|
|
453
|
+
}>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
declare type DoubleEliminationSlot = BracketSlot | {
|
|
457
|
+
readonly kind: 'loser';
|
|
458
|
+
readonly matchId: string;
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/** Pairwise mean Elo; each team's delta is split by participation weight. */
|
|
462
|
+
export declare const elo: (options?: EloOptions) => EloRate;
|
|
463
|
+
|
|
464
|
+
export declare interface EloInput {
|
|
465
|
+
readonly teams: ReadonlyArray<ReadonlyArray<EloPlayer>>;
|
|
466
|
+
readonly ranks: ReadonlyArray<number>;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export declare interface EloOptions {
|
|
470
|
+
readonly k?: number;
|
|
471
|
+
readonly scale?: number;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export declare interface EloPlayer {
|
|
475
|
+
readonly id: string;
|
|
476
|
+
readonly rating: number;
|
|
477
|
+
readonly weight?: number;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export declare type EloRate = (input: EloInput) => ReadonlyArray<ReadonlyArray<EloResult>>;
|
|
481
|
+
|
|
482
|
+
export declare interface EloResult {
|
|
483
|
+
readonly id: string;
|
|
484
|
+
readonly previous: number;
|
|
485
|
+
readonly rating: number;
|
|
486
|
+
readonly delta: number;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Glickman's revised Illinois procedure; one complete simultaneous rating period.
|
|
490
|
+
* https://glicko.net/glicko/glicko2.pdf — independently implemented equations. */
|
|
491
|
+
export declare const glicko2: (options?: Glicko2Options) => Glicko2Rate;
|
|
492
|
+
|
|
493
|
+
export declare interface Glicko2Input {
|
|
494
|
+
readonly player: Glicko2Rating;
|
|
495
|
+
/** All opponents carry their pre-period ratings, not sequentially updated ones. */
|
|
496
|
+
readonly opponents: ReadonlyArray<Glicko2Opponent>;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export declare interface Glicko2Opponent {
|
|
500
|
+
readonly rating: number;
|
|
501
|
+
readonly deviation: number;
|
|
502
|
+
readonly score: 0 | 0.5 | 1;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export declare interface Glicko2Options {
|
|
506
|
+
readonly tau?: number;
|
|
507
|
+
readonly epsilon?: number;
|
|
508
|
+
readonly maxIterations?: number;
|
|
509
|
+
readonly maxOpponents?: number;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export declare type Glicko2Rate = (input: Glicko2Input) => Glicko2Result;
|
|
513
|
+
|
|
514
|
+
export declare interface Glicko2Rating {
|
|
515
|
+
readonly rating: number;
|
|
516
|
+
readonly deviation: number;
|
|
517
|
+
readonly volatility: number;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export declare interface Glicko2Result extends Glicko2Rating {
|
|
521
|
+
readonly previous: Glicko2Rating;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/** Stable FNV-1a UTF-8 partition helper. Does not enforce fixed-size cohort admission. */
|
|
525
|
+
export declare const hashBucket: (tenantId: string, periodId: string, ownerId: string, bucketCount: number) => number;
|
|
526
|
+
|
|
527
|
+
/** Internal server service for this leaf plugin's handlers, not a game-stack Port. */
|
|
528
|
+
declare type LeaderboardAdministrationService = Omit<ReturnType<typeof dataStoreLeaderboards>, 'exportSubject' | 'eraseSubject'>;
|
|
529
|
+
|
|
530
|
+
export declare const leaderboardAround: (records: ReadonlyArray<RankedLeaderboardRecord>, ownerId: string, radius?: number) => ReadonlyArray<RankedLeaderboardRecord>;
|
|
531
|
+
|
|
532
|
+
/** Choose one actual capacity-admitted candidate. Grouping/SQL writer admission,
|
|
533
|
+
* membership and capacity stay inside the adapter. */
|
|
534
|
+
export declare type LeaderboardBucketAssign = (context: LeaderboardBucketContext) => string;
|
|
535
|
+
|
|
536
|
+
export declare interface LeaderboardBucketCandidate {
|
|
537
|
+
readonly id: string;
|
|
538
|
+
readonly ordinal: number;
|
|
539
|
+
readonly entries: number;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
export declare interface LeaderboardBucketContext {
|
|
543
|
+
readonly tenantId: string;
|
|
544
|
+
readonly board: string;
|
|
545
|
+
readonly periodId: string;
|
|
546
|
+
readonly ownerId: string;
|
|
547
|
+
readonly assign: 'hash' | 'skill' | 'cohort';
|
|
548
|
+
readonly size: number;
|
|
549
|
+
readonly group: string | null;
|
|
550
|
+
readonly candidates: ReadonlyArray<LeaderboardBucketCandidate>;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export declare interface LeaderboardDefinition<S extends Schema.Codec<unknown, unknown>> {
|
|
554
|
+
readonly name: string;
|
|
555
|
+
readonly sort?: LeaderboardSort;
|
|
556
|
+
readonly operator?: ScoreOperator;
|
|
557
|
+
readonly metadata: S;
|
|
558
|
+
/** Only service-owned writes exist in this foundation; no client score route. */
|
|
559
|
+
readonly submit?: {
|
|
560
|
+
readonly via: 'service-only';
|
|
561
|
+
};
|
|
562
|
+
readonly reset?: {
|
|
563
|
+
readonly cron: string;
|
|
564
|
+
readonly timezone: string;
|
|
565
|
+
readonly keepHistory: number;
|
|
566
|
+
} | undefined;
|
|
567
|
+
readonly maxRankRecords?: number;
|
|
568
|
+
readonly maxPageSize?: number;
|
|
569
|
+
readonly buckets?: {
|
|
570
|
+
readonly size: number;
|
|
571
|
+
readonly assign: 'hash' | 'skill' | 'cohort';
|
|
572
|
+
readonly skillWidth?: number;
|
|
573
|
+
} | undefined;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export declare interface LeaderboardDescriptor<S extends Schema.Codec<unknown, unknown>> {
|
|
577
|
+
readonly kind: 'leaderboard';
|
|
578
|
+
readonly name: string;
|
|
579
|
+
readonly sort: LeaderboardSort;
|
|
580
|
+
readonly operator: ScoreOperator;
|
|
581
|
+
readonly metadata: S;
|
|
582
|
+
readonly submit: {
|
|
583
|
+
readonly via: 'service-only';
|
|
584
|
+
};
|
|
585
|
+
readonly reset: LeaderboardDefinition<S>['reset'];
|
|
586
|
+
readonly maxRankRecords: number;
|
|
587
|
+
readonly maxPageSize: number;
|
|
588
|
+
readonly buckets: LeaderboardDefinition<S>['buckets'];
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
export declare class LeaderboardError extends LeaderboardError_base {
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
declare const LeaderboardError_base: Schema.Class<LeaderboardError, Schema.TaggedStruct<"LeaderboardError", {
|
|
595
|
+
readonly code: Schema.Literals<readonly ["invalid_board", "invalid_score", "invalid_record", "invalid_input", "overflow", "unavailable", "forbidden", "not_found", "conflict", "erased", "limit_exceeded"]>;
|
|
596
|
+
}>, YieldableError>;
|
|
597
|
+
|
|
598
|
+
declare interface LeaderboardPeriodSummary {
|
|
599
|
+
readonly participants: number;
|
|
600
|
+
readonly top: ReadonlyArray<RankedLeaderboardRecord>;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** A summary selector may only retain exact records from the captured snapshot. */
|
|
604
|
+
declare type LeaderboardPeriodSummarySlot = (records: ReadonlyArray<RankedLeaderboardRecord>) => LeaderboardPeriodSummary;
|
|
605
|
+
|
|
606
|
+
/** Complete ordered record identities. The adapter supplies consecutive ordinal
|
|
607
|
+
* ranks and all values from its SQL snapshot, never from strategy output. */
|
|
608
|
+
export declare type LeaderboardRankQuery = (context: LeaderboardRankQueryContext) => Effect.Effect<ReadonlyArray<string>, LeaderboardError>;
|
|
609
|
+
|
|
610
|
+
/** The admitted complete SQL snapshot is detached from the storage rows. A
|
|
611
|
+
* dialect implementation may use the declared read capability; writes are not
|
|
612
|
+
* part of this strategy's contract. Every returned ID must belong to records. */
|
|
613
|
+
export declare interface LeaderboardRankQueryContext {
|
|
614
|
+
readonly tenantId: string;
|
|
615
|
+
readonly board: string;
|
|
616
|
+
readonly periodId: string;
|
|
617
|
+
/** null is the global view; a value is the admitted owner's current cohort. */
|
|
618
|
+
readonly bucketId: string | null;
|
|
619
|
+
readonly sort: LeaderboardSort;
|
|
620
|
+
readonly maxRecords: number;
|
|
621
|
+
readonly records: ReadonlyArray<LeaderboardRankRecord>;
|
|
622
|
+
readonly tiebreak: LeaderboardTiebreak;
|
|
623
|
+
readonly query: DataStore['query'];
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
export declare interface LeaderboardRankRecord {
|
|
627
|
+
readonly id: string;
|
|
628
|
+
readonly tenantId: string;
|
|
629
|
+
readonly board: string;
|
|
630
|
+
readonly periodId: string;
|
|
631
|
+
readonly ownerId: string;
|
|
632
|
+
readonly score: string;
|
|
633
|
+
readonly subscore: string;
|
|
634
|
+
readonly updatedAt: number;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
declare type LeaderboardRecord = typeof LeaderboardRecordSchema.Type;
|
|
638
|
+
|
|
639
|
+
declare const LeaderboardRecordSchema: Schema.Struct<{
|
|
640
|
+
readonly id: Schema.String;
|
|
641
|
+
readonly board: Schema.String;
|
|
642
|
+
readonly periodId: Schema.String;
|
|
643
|
+
readonly ownerId: Schema.String;
|
|
644
|
+
readonly score: Schema.String;
|
|
645
|
+
readonly subscore: Schema.String;
|
|
646
|
+
readonly numSubmits: Schema.Number;
|
|
647
|
+
readonly metadata: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
648
|
+
readonly updatedAt: Schema.Number;
|
|
649
|
+
readonly bucket: Schema.NullOr<Schema.String>;
|
|
650
|
+
}>;
|
|
651
|
+
|
|
652
|
+
export declare type LeaderboardSort = 'asc' | 'desc';
|
|
653
|
+
|
|
654
|
+
export declare interface LeaderboardsPlugin extends VoltroPlugin {
|
|
655
|
+
/** Trusted server facade of the same installed internal service; no browser authority. */
|
|
656
|
+
readonly leaderboards: {
|
|
657
|
+
readonly service: () => LeaderboardAdministrationService;
|
|
658
|
+
readonly brackets: () => BracketAdmissionService;
|
|
659
|
+
readonly tournaments: () => TournamentBracketService;
|
|
660
|
+
readonly tournamentStages: () => TournamentStageService;
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
export declare const leaderboardsPlugin: (input: LeaderboardsPluginOptions) => LeaderboardsPlugin;
|
|
665
|
+
|
|
666
|
+
export declare interface LeaderboardsPluginOptions extends LeaderboardStoreOptions {
|
|
667
|
+
readonly brackets?: BracketAdmissionBinding;
|
|
668
|
+
readonly tournamentCoordination?: TournamentBinding;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/** System21 manifest: strategy slots, ports and events this system declares. */
|
|
672
|
+
export declare const leaderboardsSystemContract: Readonly<{
|
|
673
|
+
slots: {
|
|
674
|
+
tiebreak: {
|
|
675
|
+
defaultExport: string;
|
|
676
|
+
fixtureExport: string;
|
|
677
|
+
};
|
|
678
|
+
rankQuery: {
|
|
679
|
+
defaultExport: string;
|
|
680
|
+
fixtureExport: string;
|
|
681
|
+
};
|
|
682
|
+
bucketAssign: {
|
|
683
|
+
defaultExport: string;
|
|
684
|
+
fixtureExport: string;
|
|
685
|
+
};
|
|
686
|
+
periodSummary: {
|
|
687
|
+
defaultExport: string;
|
|
688
|
+
fixtureExport: string;
|
|
689
|
+
};
|
|
690
|
+
validate: {
|
|
691
|
+
defaultExport: string;
|
|
692
|
+
fixtureExport: string;
|
|
693
|
+
};
|
|
694
|
+
ratingRate: {
|
|
695
|
+
defaultExport: string;
|
|
696
|
+
fixtureExport: string;
|
|
697
|
+
};
|
|
698
|
+
ratingPlacement: {
|
|
699
|
+
defaultExport: string;
|
|
700
|
+
fixtureExport: string;
|
|
701
|
+
};
|
|
702
|
+
ratingDecay: {
|
|
703
|
+
defaultExport: string;
|
|
704
|
+
fixtureExport: string;
|
|
705
|
+
};
|
|
706
|
+
};
|
|
707
|
+
ports: {
|
|
708
|
+
bracketAdmission: {
|
|
709
|
+
tagExport: string;
|
|
710
|
+
fakeLayerExport: string;
|
|
711
|
+
fixtureExport: string;
|
|
712
|
+
};
|
|
713
|
+
tournamentBracket: {
|
|
714
|
+
tagExport: string;
|
|
715
|
+
fakeLayerExport: string;
|
|
716
|
+
fixtureExport: string;
|
|
717
|
+
};
|
|
718
|
+
tournamentStage: {
|
|
719
|
+
tagExport: string;
|
|
720
|
+
fakeLayerExport: string;
|
|
721
|
+
fixtureExport: string;
|
|
722
|
+
};
|
|
723
|
+
};
|
|
724
|
+
events: readonly string[];
|
|
725
|
+
}>;
|
|
726
|
+
|
|
727
|
+
export declare interface LeaderboardStoreOptions {
|
|
728
|
+
readonly boards: ReadonlyArray<LeaderboardDescriptor<Schema.Codec<unknown, unknown>>>;
|
|
729
|
+
readonly tournaments?: ReadonlyArray<TournamentDescriptor>;
|
|
730
|
+
/** Leagues over declared, non-bucketed boards (`defineLeague`); a board belongs to at most one league. */
|
|
731
|
+
readonly leagues?: ReadonlyArray<LeagueDefinition>;
|
|
732
|
+
readonly ratingPools?: ReadonlyArray<RatingPoolDefinition>;
|
|
733
|
+
readonly ratingStrategies?: RatingStrategies;
|
|
734
|
+
/** Explicit verified service callers; none are authorized by default. System tasks are trusted. */
|
|
735
|
+
readonly allowedServices?: ReadonlyArray<string>;
|
|
736
|
+
readonly validate?: (input: SubmitLeaderboardInput, previous: LeaderboardRecord | null, tx: DataStore) => Effect.Effect<void, LeaderboardError>;
|
|
737
|
+
readonly tiebreak?: LeaderboardTiebreak;
|
|
738
|
+
readonly rankQuery?: LeaderboardRankQuery;
|
|
739
|
+
readonly bucketAssign?: LeaderboardBucketAssign;
|
|
740
|
+
readonly bucketStrategyVersion?: string;
|
|
741
|
+
readonly periodSummary?: LeaderboardPeriodSummarySlot;
|
|
742
|
+
readonly maxPeriodRows?: number;
|
|
743
|
+
readonly maxSummaryBytes?: number;
|
|
744
|
+
readonly maxMetadataBytes?: number;
|
|
745
|
+
readonly maxExportRows?: number;
|
|
746
|
+
readonly maxSubmissionsPerOwner?: number;
|
|
747
|
+
readonly now?: () => number;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
export declare type LeaderboardTiebreak = (left: LeaderboardRankRecord, right: LeaderboardRankRecord) => number;
|
|
751
|
+
|
|
752
|
+
/** A league: ordered division boards (best first) whose periods close together; at each
|
|
753
|
+
* close the best `promote` of a division move up and the worst `relegate` move down. */
|
|
754
|
+
export declare interface LeagueDefinition {
|
|
755
|
+
readonly name: string;
|
|
756
|
+
/** Board names, top division first; each a declared, non-bucketed board of this plugin. */
|
|
757
|
+
readonly divisions: readonly [string, string, ...string[]];
|
|
758
|
+
readonly promote: number;
|
|
759
|
+
readonly relegate: number;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
export declare interface LeagueMovement {
|
|
763
|
+
readonly ownerId: string;
|
|
764
|
+
readonly from: string;
|
|
765
|
+
readonly to: string;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** Moves for one close, from each division's standings (best first). The top division
|
|
769
|
+
* promotes nobody, the bottom one relegates nobody; a player is never moved twice. */
|
|
770
|
+
export declare const leagueMovements: (league: LeagueDefinition, standings: ReadonlyArray<{
|
|
771
|
+
readonly division: string;
|
|
772
|
+
readonly owners: ReadonlyArray<string>;
|
|
773
|
+
}>) => ReadonlyArray<LeagueMovement>;
|
|
774
|
+
|
|
775
|
+
/** Weng–Lin Plackett–Luce, Algorithm4 (2011), with linear Gaussian partial play.
|
|
776
|
+
* https://jmlr.org/papers/volume12/weng11a/weng11a.pdf
|
|
777
|
+
* Fractional weights enter the team mean linearly and variance quadratically;
|
|
778
|
+
* they are not the OpenSkill library's contribution/weight-normalization API. */
|
|
779
|
+
export declare const openskill: (options?: OpenSkillOptions) => OpenSkillRate;
|
|
780
|
+
|
|
781
|
+
export declare interface OpenSkillInput {
|
|
782
|
+
readonly teams: ReadonlyArray<ReadonlyArray<OpenSkillPlayer>>;
|
|
783
|
+
readonly ranks: ReadonlyArray<number>;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
export declare interface OpenSkillOptions {
|
|
787
|
+
readonly beta?: number;
|
|
788
|
+
readonly tau?: number;
|
|
789
|
+
readonly kappa?: number;
|
|
790
|
+
readonly ordinalZ?: number;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
export declare interface OpenSkillPlayer {
|
|
794
|
+
readonly id: string;
|
|
795
|
+
readonly mu: number;
|
|
796
|
+
readonly sigma: number;
|
|
797
|
+
/** Fraction of participation. Zero retains the exact prior. */
|
|
798
|
+
readonly weight?: number;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
export declare type OpenSkillRate = (input: OpenSkillInput) => ReadonlyArray<ReadonlyArray<OpenSkillResult>>;
|
|
802
|
+
|
|
803
|
+
export declare interface OpenSkillResult {
|
|
804
|
+
readonly id: string;
|
|
805
|
+
readonly previous: {
|
|
806
|
+
readonly mu: number;
|
|
807
|
+
readonly sigma: number;
|
|
808
|
+
};
|
|
809
|
+
readonly mu: number;
|
|
810
|
+
readonly sigma: number;
|
|
811
|
+
readonly ordinal: number;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
export declare type PrepareRatingMatchInput = typeof PrepareRatingMatchSchema.Type;
|
|
815
|
+
|
|
816
|
+
declare const PrepareRatingMatchSchema: Schema.Struct<{
|
|
817
|
+
readonly tenantId: Schema.NonEmptyString;
|
|
818
|
+
readonly pool: Schema.NonEmptyString;
|
|
819
|
+
readonly matchId: Schema.NonEmptyString;
|
|
820
|
+
readonly teams: Schema.$Array<Schema.$Array<Schema.Struct<{
|
|
821
|
+
readonly ownerId: Schema.NonEmptyString;
|
|
822
|
+
readonly weight: Schema.optional<Schema.Number>;
|
|
823
|
+
}>>>;
|
|
824
|
+
readonly ranks: Schema.$Array<Schema.Number>;
|
|
825
|
+
}>;
|
|
826
|
+
|
|
827
|
+
declare interface Provision extends TournamentRoomWork {
|
|
828
|
+
readonly roomId: string | null;
|
|
829
|
+
readonly epoch: number | null;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
export declare interface RankedLeaderboardRecord extends LeaderboardRankRecord {
|
|
833
|
+
readonly rank: number;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
/** Whole supplied board/period snapshot. No SQL/window-query or million-row capacity claim. */
|
|
837
|
+
export declare const rankLeaderboardRecords: (input: ReadonlyArray<LeaderboardRankRecord>, options?: RankOptions) => ReadonlyArray<RankedLeaderboardRecord>;
|
|
838
|
+
|
|
839
|
+
export declare interface RankOptions {
|
|
840
|
+
readonly sort?: LeaderboardSort;
|
|
841
|
+
readonly tiebreak?: LeaderboardTiebreak;
|
|
842
|
+
readonly maxRecords?: number;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
export declare interface RatingDecayContext extends RatingPlacementContext {
|
|
846
|
+
readonly state: RatingState;
|
|
847
|
+
readonly games: number;
|
|
848
|
+
readonly updatedAt: number;
|
|
849
|
+
readonly elapsedMs: number;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
export declare type RatingDecayPolicy = (context: RatingDecayContext) => RatingState;
|
|
853
|
+
|
|
854
|
+
export declare interface RatingMatchReceipt {
|
|
855
|
+
readonly pool: string;
|
|
856
|
+
readonly matchId: string;
|
|
857
|
+
readonly participants: number;
|
|
858
|
+
readonly state: 'prepared' | 'applied';
|
|
859
|
+
readonly preparedAt: number;
|
|
860
|
+
readonly appliedAt: number | null;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
export declare interface RatingPlacementContext {
|
|
864
|
+
readonly tenantId: string;
|
|
865
|
+
readonly ownerId: string;
|
|
866
|
+
readonly pool: ResolvedRatingPool;
|
|
867
|
+
readonly at: number;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export declare type RatingPlacementPolicy = (context: RatingPlacementContext) => RatingState;
|
|
871
|
+
|
|
872
|
+
export declare type RatingPoolDefinition = {
|
|
873
|
+
readonly name: string;
|
|
874
|
+
readonly algorithm: 'elo';
|
|
875
|
+
readonly initial?: {
|
|
876
|
+
readonly rating: number;
|
|
877
|
+
};
|
|
878
|
+
readonly options?: EloOptions;
|
|
879
|
+
} | {
|
|
880
|
+
readonly name: string;
|
|
881
|
+
readonly algorithm: 'openskill';
|
|
882
|
+
readonly initial?: {
|
|
883
|
+
readonly mu: number;
|
|
884
|
+
readonly sigma: number;
|
|
885
|
+
};
|
|
886
|
+
readonly options?: OpenSkillOptions;
|
|
887
|
+
} | {
|
|
888
|
+
readonly name: string;
|
|
889
|
+
readonly algorithm: 'glicko2';
|
|
890
|
+
readonly initial?: {
|
|
891
|
+
readonly rating: number;
|
|
892
|
+
readonly deviation: number;
|
|
893
|
+
readonly volatility: number;
|
|
894
|
+
};
|
|
895
|
+
readonly options?: Glicko2Options;
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
export declare interface RatingRateContext {
|
|
899
|
+
readonly tenantId: string;
|
|
900
|
+
readonly matchId: string;
|
|
901
|
+
readonly pool: ResolvedRatingPool;
|
|
902
|
+
readonly at: number;
|
|
903
|
+
readonly teams: ReadonlyArray<ReadonlyArray<RatingStrategyPlayer>>;
|
|
904
|
+
readonly ranks: ReadonlyArray<number>;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
export declare type RatingRateStrategy = (context: RatingRateContext) => ReadonlyArray<RatingStrategyResult>;
|
|
908
|
+
|
|
909
|
+
export declare type RatingState = typeof RatingStateSchema.Type;
|
|
910
|
+
|
|
911
|
+
declare const RatingStateSchema: Schema.Union<readonly [Schema.Struct<{
|
|
912
|
+
readonly algorithm: Schema.Literal<"elo">;
|
|
913
|
+
readonly rating: Schema.Number;
|
|
914
|
+
}>, Schema.Struct<{
|
|
915
|
+
readonly algorithm: Schema.Literal<"openskill">;
|
|
916
|
+
readonly mu: Schema.Number;
|
|
917
|
+
readonly sigma: Schema.Number;
|
|
918
|
+
}>, Schema.Struct<{
|
|
919
|
+
readonly algorithm: Schema.Literal<"glicko2">;
|
|
920
|
+
readonly rating: Schema.Number;
|
|
921
|
+
readonly deviation: Schema.Number;
|
|
922
|
+
readonly volatility: Schema.Number;
|
|
923
|
+
}>]>;
|
|
924
|
+
|
|
925
|
+
export declare interface RatingStrategies {
|
|
926
|
+
/** Required for any custom callback. Change it whenever rule meaning changes;
|
|
927
|
+
* the SQL pool configuration refuses conflicting versions across writers. */
|
|
928
|
+
readonly version?: string;
|
|
929
|
+
readonly rate?: RatingRateStrategy;
|
|
930
|
+
readonly placementPolicy?: RatingPlacementPolicy;
|
|
931
|
+
readonly decay?: RatingDecayPolicy;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
export declare interface RatingStrategyPlayer {
|
|
935
|
+
readonly ownerId: string;
|
|
936
|
+
readonly state: RatingState;
|
|
937
|
+
readonly games: number;
|
|
938
|
+
readonly updatedAt: number | null;
|
|
939
|
+
readonly weight: number;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
export declare interface RatingStrategyResult {
|
|
943
|
+
readonly ownerId: string;
|
|
944
|
+
readonly state: RatingState;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
export declare interface ResolvedRatingPool {
|
|
948
|
+
readonly name: string;
|
|
949
|
+
readonly algorithm: RatingState['algorithm'];
|
|
950
|
+
readonly initial: RatingState;
|
|
951
|
+
readonly options: EloOptions | OpenSkillOptions | Glicko2Options;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
declare interface Result extends TournamentResultReport {
|
|
955
|
+
readonly reportedWinnerId: string;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
declare interface RollLeaderboardPeriodInput {
|
|
959
|
+
readonly tenantId: string;
|
|
960
|
+
readonly board: string;
|
|
961
|
+
readonly requestId: string;
|
|
962
|
+
readonly expectedPeriodId: string;
|
|
963
|
+
/** Stable intended boundary, retained on retry; never supplied by a player. */
|
|
964
|
+
readonly closedAt: number;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
declare interface RollLeaderboardPeriodResult {
|
|
968
|
+
readonly closedPeriodId: string;
|
|
969
|
+
readonly activePeriodId: string;
|
|
970
|
+
readonly closedAt: number;
|
|
971
|
+
readonly summary: LeaderboardPeriodSummary;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
export declare type ScoreOperator = 'best' | 'set' | 'increment' | 'decrement';
|
|
975
|
+
|
|
976
|
+
export declare const scoreString: (input: string | bigint | number) => string;
|
|
977
|
+
|
|
978
|
+
/** SQL signed BIGINT range; wire values use canonical decimal strings. */
|
|
979
|
+
export declare const scoreValue: (input: string | bigint | number) => bigint;
|
|
980
|
+
|
|
981
|
+
/** Trusted service submission, never a player score-intent payload. */
|
|
982
|
+
declare interface SubmitLeaderboardInput {
|
|
983
|
+
readonly tenantId: string;
|
|
984
|
+
readonly board: string;
|
|
985
|
+
readonly ownerId: string;
|
|
986
|
+
readonly submissionId: string;
|
|
987
|
+
readonly score: string;
|
|
988
|
+
readonly subscore?: string;
|
|
989
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
990
|
+
readonly roomId?: string;
|
|
991
|
+
readonly matchId?: string;
|
|
992
|
+
readonly tournamentId?: string;
|
|
993
|
+
readonly bucketSkill?: number;
|
|
994
|
+
readonly bucketCohort?: string;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
declare type TournamentBinding = ({
|
|
998
|
+
readonly backend: 'sql';
|
|
999
|
+
readonly options: TournamentBracketOptions;
|
|
1000
|
+
} | {
|
|
1001
|
+
readonly backend: 'custom';
|
|
1002
|
+
readonly version: string;
|
|
1003
|
+
readonly service: TournamentBracketService;
|
|
1004
|
+
readonly sources: ReadonlyArray<string>;
|
|
1005
|
+
}) & {
|
|
1006
|
+
readonly stage?: TournamentStageBinding;
|
|
1007
|
+
readonly workflowSources?: string;
|
|
1008
|
+
};
|
|
1009
|
+
|
|
1010
|
+
declare interface TournamentBracketDefinition {
|
|
1011
|
+
readonly format: TournamentBracketFormat;
|
|
1012
|
+
readonly entrants: ReadonlyArray<TournamentEntrant>;
|
|
1013
|
+
/** Swiss only: rounds to play (default: enough to separate a winner, ceil(log2 entrants)). */
|
|
1014
|
+
readonly rounds?: number | undefined;
|
|
1015
|
+
/** Immutable application prize/Room/no-show policy identity, not a price. */
|
|
1016
|
+
readonly ruleVersion: string;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
declare interface TournamentBracketExport {
|
|
1020
|
+
readonly tournamentId: string;
|
|
1021
|
+
readonly phase: BracketState['phase'];
|
|
1022
|
+
readonly seed: number;
|
|
1023
|
+
readonly matches: ReadonlyArray<{
|
|
1024
|
+
readonly matchId: string;
|
|
1025
|
+
readonly roomId: string;
|
|
1026
|
+
readonly won: boolean;
|
|
1027
|
+
}>;
|
|
1028
|
+
readonly disputes: ReadonlyArray<TournamentDisputeIntent & {
|
|
1029
|
+
readonly resolutionId: string | null;
|
|
1030
|
+
}>;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
declare type TournamentBracketFormat = 'single-elimination' | 'double-elimination' | 'round-robin' | 'swiss';
|
|
1034
|
+
|
|
1035
|
+
/** A bracket match with the Room it plays in, once one was provisioned. */
|
|
1036
|
+
declare type TournamentBracketMatch = (BracketProgress['matches'][number] | DoubleEliminationProgress['matches'][number]) & {
|
|
1037
|
+
readonly roomId: string | null;
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
declare interface TournamentBracketOptions {
|
|
1041
|
+
readonly epochNow: () => number;
|
|
1042
|
+
readonly maxTenantTournaments?: number;
|
|
1043
|
+
authorize(subject: Subject, scope: BracketAdmissionScope, operation: 'create' | 'report' | 'dispute' | 'resolve' | 'advance' | 'status'): Effect.Effect<void, LeaderboardError>;
|
|
1044
|
+
/** Actual durable Room creation/reservations: same request returns same Room,
|
|
1045
|
+
* enforces private roster/options/current grants, and awaits accepted work. */
|
|
1046
|
+
provisionRoom(work: TournamentRoomWork): Effect.Effect<TournamentRoomReceipt, LeaderboardError>;
|
|
1047
|
+
verifyResult(subject: Subject, scope: BracketAdmissionScope, report: TournamentResultReport): Effect.Effect<void, LeaderboardError>;
|
|
1048
|
+
/** The real economy/inventory/Inbox participant owns atomic idempotency. */
|
|
1049
|
+
settleChampion(work: BracketAdmissionScope & {
|
|
1050
|
+
readonly requestId: string;
|
|
1051
|
+
readonly winnerId: string;
|
|
1052
|
+
readonly ruleVersion: string;
|
|
1053
|
+
}): Effect.Effect<void, LeaderboardError>;
|
|
1054
|
+
withdrawSubject(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
1055
|
+
/** Must withdraw pending request identities too, even with lost Room replies. */
|
|
1056
|
+
withdrawTournament(scope: BracketAdmissionScope, request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
1057
|
+
authorizeExport(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/** Trusted server coordinator contract; SQL types are erased imports only. */
|
|
1061
|
+
declare class TournamentBracketPort extends TournamentBracketPort_base {
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
declare const TournamentBracketPort_base: Context.ServiceClass<TournamentBracketPort, "@voltro/TournamentBracketPort", {
|
|
1065
|
+
create(subject: Subject, scope: BracketAdmissionScope, definition: TournamentBracketDefinition): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1066
|
+
report(subject: Subject, scope: BracketAdmissionScope, report: TournamentResultReport): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1067
|
+
dispute(subject: Subject, scope: BracketAdmissionScope, intent: TournamentDisputeIntent): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1068
|
+
resolve(subject: Subject, scope: BracketAdmissionScope, intent: TournamentDisputeResolution): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1069
|
+
advance(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1070
|
+
status(subject: Subject, scope: BracketAdmissionScope): Effect.Effect<TournamentBracketStatus, LeaderboardError>;
|
|
1071
|
+
exportSubject(request: PluginPrivacyRequest): Effect.Effect<ReadonlyArray<TournamentBracketExport>, LeaderboardError>;
|
|
1072
|
+
eraseSubject(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
1073
|
+
}>;
|
|
1074
|
+
|
|
1075
|
+
declare type TournamentBracketService = Context.Service.Shape<typeof TournamentBracketPort>;
|
|
1076
|
+
|
|
1077
|
+
declare interface TournamentBracketStatus {
|
|
1078
|
+
readonly phase: BracketState['phase'];
|
|
1079
|
+
readonly format: TournamentBracketFormat;
|
|
1080
|
+
readonly champion: string | null;
|
|
1081
|
+
readonly matches: ReadonlyArray<TournamentBracketMatch>;
|
|
1082
|
+
readonly unresolvedDisputes: number;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
export declare interface TournamentDefinition {
|
|
1086
|
+
readonly name: string;
|
|
1087
|
+
readonly board: string;
|
|
1088
|
+
readonly startsAt: number;
|
|
1089
|
+
readonly endsAt: number;
|
|
1090
|
+
readonly maxEntries: number;
|
|
1091
|
+
readonly joinRequired?: boolean;
|
|
1092
|
+
readonly attemptsPerEntry?: number;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
export declare interface TournamentDescriptor extends Omit<TournamentDefinition, 'joinRequired' | 'attemptsPerEntry'> {
|
|
1096
|
+
readonly kind: 'tournament';
|
|
1097
|
+
readonly format: 'time-window';
|
|
1098
|
+
readonly joinRequired: boolean;
|
|
1099
|
+
readonly attemptsPerEntry: number;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
declare interface TournamentDisputeIntent {
|
|
1103
|
+
readonly disputeId: string;
|
|
1104
|
+
readonly matchId: string;
|
|
1105
|
+
readonly reason: 'result_mismatch' | 'no_show' | 'connection';
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
declare interface TournamentDisputeResolution {
|
|
1109
|
+
readonly disputeId: string;
|
|
1110
|
+
readonly resolutionId: string;
|
|
1111
|
+
readonly winnerId: string;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
declare interface TournamentEntrant {
|
|
1115
|
+
readonly entrantId: string;
|
|
1116
|
+
readonly seed: number;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
declare interface TournamentResultReport extends TournamentRoomReceipt {
|
|
1120
|
+
readonly matchId: string;
|
|
1121
|
+
readonly reportId: string;
|
|
1122
|
+
readonly winnerId: string;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
declare interface TournamentRoomReceipt {
|
|
1126
|
+
readonly roomId: string;
|
|
1127
|
+
readonly epoch: number;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
declare interface TournamentRoomWork extends BracketAdmissionScope {
|
|
1131
|
+
readonly matchId: string;
|
|
1132
|
+
readonly requestId: string;
|
|
1133
|
+
readonly left: string;
|
|
1134
|
+
readonly right: string;
|
|
1135
|
+
readonly ruleVersion: string;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
declare type TournamentStageBinding = ({
|
|
1139
|
+
readonly backend: 'sql';
|
|
1140
|
+
readonly options: Omit<TournamentStageOptions, 'admissions' | 'brackets'>;
|
|
1141
|
+
} | {
|
|
1142
|
+
readonly backend: 'custom';
|
|
1143
|
+
readonly version: string;
|
|
1144
|
+
readonly service: TournamentStageService;
|
|
1145
|
+
}) & {
|
|
1146
|
+
readonly privacy: TournamentStagePrivacy;
|
|
1147
|
+
};
|
|
1148
|
+
|
|
1149
|
+
declare interface TournamentStageOptions {
|
|
1150
|
+
readonly epochNow: () => number;
|
|
1151
|
+
readonly admissions: Pick<BracketAdmissionService, 'seal'>;
|
|
1152
|
+
readonly brackets: Pick<TournamentBracketService, 'create'>;
|
|
1153
|
+
authorize(subject: Subject, scope: BracketAdmissionScope, operation: 'window' | 'notify' | 'seed'): Effect.Effect<void, LeaderboardError>;
|
|
1154
|
+
/** Current SQL/rating/no-show preparation participant. Same request must
|
|
1155
|
+
* recover the same durable seed decision, never reread a changed prior. */
|
|
1156
|
+
seedRoster(work: TournamentStagePayload & BracketAdmissionRoster & {
|
|
1157
|
+
readonly requestId: string;
|
|
1158
|
+
}): Effect.Effect<ReadonlyArray<TournamentEntrant>, LeaderboardError>;
|
|
1159
|
+
/** Actual Inbox/Push idempotency and external withdrawal remain required. */
|
|
1160
|
+
notifyEntrants(work: TournamentStagePayload & {
|
|
1161
|
+
readonly phase: 'registration' | 'check-in';
|
|
1162
|
+
readonly requestId: string;
|
|
1163
|
+
}): Effect.Effect<void, LeaderboardError>;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
declare const TournamentStagePayload: Schema.Struct<{
|
|
1167
|
+
readonly format: Schema.Literals<readonly ["single-elimination", "double-elimination", "round-robin", "swiss"]>;
|
|
1168
|
+
readonly ruleVersion: Schema.String;
|
|
1169
|
+
readonly tenantId: Schema.String;
|
|
1170
|
+
readonly tournamentId: Schema.String;
|
|
1171
|
+
readonly runKey: Schema.String;
|
|
1172
|
+
}>;
|
|
1173
|
+
|
|
1174
|
+
declare type TournamentStagePayload = typeof TournamentStagePayload.Type;
|
|
1175
|
+
|
|
1176
|
+
declare class TournamentStagePort extends TournamentStagePort_base {
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
declare const TournamentStagePort_base: Context.ServiceClass<TournamentStagePort, "@voltro/TournamentStagePort", {
|
|
1180
|
+
window(subject: Subject, payload: TournamentStagePayload): Effect.Effect<BracketAdmissionDefinition, LeaderboardError>;
|
|
1181
|
+
notify(subject: Subject, payload: TournamentStagePayload, phase: "registration" | "check-in"): Effect.Effect<{
|
|
1182
|
+
readonly notified: boolean;
|
|
1183
|
+
}, LeaderboardError>;
|
|
1184
|
+
seed(subject: Subject, payload: TournamentStagePayload): Effect.Effect<TournamentWorkflowSummary, LeaderboardError>;
|
|
1185
|
+
}>;
|
|
1186
|
+
|
|
1187
|
+
declare interface TournamentStagePrivacy {
|
|
1188
|
+
/** Own subject data from actual seed/notification participants, no peer export. */
|
|
1189
|
+
exportSubject(request: PluginPrivacyRequest): Effect.Effect<unknown, LeaderboardError>;
|
|
1190
|
+
/** Permanently withdraw accepted seed/reminder work before subject cleanup. */
|
|
1191
|
+
eraseSubject(request: PluginPrivacyRequest): Effect.Effect<void, LeaderboardError>;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
declare type TournamentStageService = Context.Service.Shape<typeof TournamentStagePort>;
|
|
1195
|
+
|
|
1196
|
+
/** Counts only: no roster/winner/ratings/Room credentials in workflow journals. */
|
|
1197
|
+
declare const TournamentWorkflowSummary: Schema.Struct<{
|
|
1198
|
+
readonly phase: Schema.Literals<readonly ["active", "paused", "complete", "erasing", "cancelled"]>;
|
|
1199
|
+
readonly ready: Schema.Int;
|
|
1200
|
+
readonly completed: Schema.Int;
|
|
1201
|
+
/** Advance work still open: ready matches without a Room, plus the champion's settlement. */
|
|
1202
|
+
readonly waiting: Schema.Int;
|
|
1203
|
+
readonly unresolvedDisputes: Schema.Int;
|
|
1204
|
+
}>;
|
|
1205
|
+
|
|
1206
|
+
declare type TournamentWorkflowSummary = typeof TournamentWorkflowSummary.Type;
|
|
1207
|
+
|
|
1208
|
+
export { }
|