@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.
Files changed (67) hide show
  1. package/CHANGELOG.md +24492 -0
  2. package/LICENSE +61 -0
  3. package/README.md +1087 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +5603 -0
  6. package/dist/administration.js +4 -0
  7. package/dist/bracketAdmission.js +293 -0
  8. package/dist/bracketAdmissionPolicy.js +21 -0
  9. package/dist/bracketInstallation.js +132 -0
  10. package/dist/bracketMatchPorts.js +4 -0
  11. package/dist/bracketMatches.js +545 -0
  12. package/dist/brackets.d.ts +149 -0
  13. package/dist/brackets.js +378 -0
  14. package/dist/bucketStore.js +92 -0
  15. package/dist/buckets.js +8 -0
  16. package/dist/errors.d.ts +13 -0
  17. package/dist/errors.js +16 -0
  18. package/dist/glicko2.js +71 -0
  19. package/dist/index.d.ts +1208 -0
  20. package/dist/index.js +15 -0
  21. package/dist/inspect.js +83 -0
  22. package/dist/json.js +38 -0
  23. package/dist/leaderboard.d.ts +49 -0
  24. package/dist/leaderboard.js +56 -0
  25. package/dist/leagueSchedule.js +39 -0
  26. package/dist/leagues.js +30 -0
  27. package/dist/openskill.js +73 -0
  28. package/dist/plugin.js +337 -0
  29. package/dist/portLifetime.js +66 -0
  30. package/dist/ports.d.ts +294 -0
  31. package/dist/ports.js +6 -0
  32. package/dist/rankQuery.js +23 -0
  33. package/dist/ranking.d.ts +42 -0
  34. package/dist/ranking.js +70 -0
  35. package/dist/rating.d.ts +103 -0
  36. package/dist/rating.js +49 -0
  37. package/dist/ratingPools.js +133 -0
  38. package/dist/ratingStore.js +333 -0
  39. package/dist/ratingStrategies.js +107 -0
  40. package/dist/records.d.ts +116 -0
  41. package/dist/records.js +87 -0
  42. package/dist/rpc.d.ts +321 -0
  43. package/dist/rpc.js +305 -0
  44. package/dist/score.d.ts +13 -0
  45. package/dist/score.js +26 -0
  46. package/dist/server.d.ts +1477 -0
  47. package/dist/server.js +17 -0
  48. package/dist/service.js +948 -0
  49. package/dist/subjectFences.js +43 -0
  50. package/dist/tables.entity.js +187 -0
  51. package/dist/testing.d.ts +872 -0
  52. package/dist/testing.js +367 -0
  53. package/dist/tournament-app/tournament.advance.workflow.server.tsx +3 -0
  54. package/dist/tournament-app/tournament.advance.workflow.tsx +12 -0
  55. package/dist/tournament-app/tournament.stage.workflow.server.tsx +3 -0
  56. package/dist/tournament-app/tournament.stage.workflow.tsx +10 -0
  57. package/dist/tournamentInstallation.js +167 -0
  58. package/dist/tournamentPrizes.js +33 -0
  59. package/dist/tournamentStage.js +150 -0
  60. package/dist/tournamentStagePorts.js +4 -0
  61. package/dist/tournamentWorkflow.js +100 -0
  62. package/dist/tournamentWorkflowSchemas.js +53 -0
  63. package/dist/tournaments.d.ts +32 -0
  64. package/dist/tournaments.js +20 -0
  65. package/dist/web.d.ts +175 -0
  66. package/dist/web.js +16 -0
  67. package/package.json +113 -4
@@ -0,0 +1,378 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { canonicalLeaderboardJson as t, captureLeaderboardJson as n } from "./json.js";
3
+ import { Schema as r } from "effect";
4
+ // src/brackets.ts
5
+ var i = Object.freeze({
6
+ maxEntrants: 256,
7
+ maxMatches: 65536,
8
+ maxSearchNodes: 1e5,
9
+ maxInputBytes: 65536
10
+ });
11
+ function a() {
12
+ throw e("invalid_input");
13
+ }
14
+ var o = (e, t) => Number.isSafeInteger(e) && e > 0 && e <= t ? e : a(), s = (e) => typeof e == "string" && e.length > 0 && e.length <= 120 && e.trim() === e && e.isWellFormed() && !/[\u0000-\u001f\u007f]/.test(e) ? e : a(), c = (e, t) => {
15
+ try {
16
+ return r.decodeUnknownSync(e)(t, { onExcessProperty: "error" });
17
+ } catch {
18
+ return a();
19
+ }
20
+ }, l = r.Struct({
21
+ entrantId: r.String,
22
+ seed: r.Int
23
+ }), u = (e) => {
24
+ let t = n(e, 1024);
25
+ (typeof t != "object" || !t || Array.isArray(t)) && a();
26
+ for (let e of Object.keys(t)) Object.hasOwn(i, e) || a();
27
+ let r = {
28
+ ...i,
29
+ ...t
30
+ };
31
+ return o(r.maxEntrants, 256), o(r.maxMatches, 65536), o(r.maxSearchNodes, 1e6), o(r.maxInputBytes, 65536), Object.freeze(r);
32
+ }, d = (e, t) => {
33
+ let i = c(r.Array(l), n(e, t.maxInputBytes));
34
+ (i.length < 2 || i.length > t.maxEntrants) && a();
35
+ let u = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set();
36
+ for (let e of i) s(e.entrantId), o(e.seed, i.length), (u.has(e.seed) || d.has(e.entrantId)) && a(), u.add(e.seed), d.add(e.entrantId);
37
+ return Object.freeze(i.map((e) => Object.freeze({ ...e })).sort((e, t) => e.seed - t.seed));
38
+ }, f = (e, t) => Object.freeze({
39
+ left: e,
40
+ right: t
41
+ }), p = (t, i = {}) => {
42
+ let o = c(r.Struct({
43
+ doubleRound: r.optional(r.Boolean),
44
+ limits: r.optional(r.Unknown)
45
+ }), n(i, 2048)), s = u(o.limits ?? {}), l = d(t, s);
46
+ if (l.length * (l.length - 1) / 2 * (o.doubleRound ? 2 : 1) > s.maxMatches) throw e("limit_exceeded");
47
+ let p = l.map((e) => e.entrantId);
48
+ p.length % 2 == 1 && p.push(null);
49
+ let m = [];
50
+ for (let e = 0; e < p.length - 1; e++) {
51
+ let t = [], n = null;
52
+ for (let r = 0; r < p.length / 2; r++) {
53
+ let i = p[r], o = p[p.length - r - 1];
54
+ (i === void 0 || o === void 0 || i === null && o === null) && a(), i === null ? n = o : o === null ? n = i : t.push(e % 2 == 0 ? f(i, o) : f(o, i));
55
+ }
56
+ m.push(Object.freeze({
57
+ round: e + 1,
58
+ pairs: Object.freeze(t),
59
+ bye: n
60
+ }));
61
+ let r = p.pop();
62
+ r === void 0 && a(), p.splice(1, 0, r);
63
+ }
64
+ if (o.doubleRound) {
65
+ let e = m.length;
66
+ for (let t of m.slice()) m.push(Object.freeze({
67
+ round: t.round + e,
68
+ bye: t.bye,
69
+ pairs: Object.freeze(t.pairs.map((e) => f(e.right, e.left)))
70
+ }));
71
+ }
72
+ return Object.freeze(m);
73
+ }, m = r.Struct({
74
+ entrantId: r.String,
75
+ seed: r.Int,
76
+ points: r.Int,
77
+ byes: r.Int,
78
+ opponents: r.Array(r.String)
79
+ }), h = (t, i = {}) => {
80
+ let o = u(i), s = c(r.Array(m), n(t, o.maxInputBytes)), l = d(s.map((e) => ({
81
+ entrantId: e.entrantId,
82
+ seed: e.seed
83
+ })), o);
84
+ if (s.length > 128) throw e("limit_exceeded");
85
+ let p = new Set(l.map((e) => e.entrantId)), h = /* @__PURE__ */ new Map();
86
+ for (let e of s) {
87
+ (!Number.isSafeInteger(e.points) || e.points < 0 || !Number.isSafeInteger(e.byes) || e.byes < 0 || e.byes > 1e6 || e.opponents.length >= s.length) && a();
88
+ let t = /* @__PURE__ */ new Set();
89
+ for (let n of e.opponents) (!p.has(n) || n === e.entrantId || t.has(n)) && a(), t.add(n);
90
+ h.set(e.entrantId, t);
91
+ }
92
+ for (let [e, t] of h) for (let n of t) h.get(n)?.has(e) || a();
93
+ let g = s.map((e) => Object.freeze({
94
+ ...e,
95
+ opponents: Object.freeze([...e.opponents])
96
+ })).sort((e, t) => e.points === t.points ? e.seed - t.seed : e.points > t.points ? -1 : 1), _ = 0, v = (t, n) => {
97
+ if (_ >= o.maxSearchNodes) throw e("limit_exceeded");
98
+ _++;
99
+ let r = t[0];
100
+ if (!r) return n;
101
+ let i = t.slice(1).filter((e) => !h.get(r.entrantId)?.has(e.entrantId)).sort((e, t) => {
102
+ let n = r.points > e.points ? BigInt(r.points) - BigInt(e.points) : BigInt(e.points) - BigInt(r.points), i = r.points > t.points ? BigInt(r.points) - BigInt(t.points) : BigInt(t.points) - BigInt(r.points);
103
+ return n === i ? Math.abs(e.seed - r.seed) - Math.abs(t.seed - r.seed) || e.seed - t.seed : n < i ? -1 : 1;
104
+ });
105
+ for (let e of i) {
106
+ let i = v(t.filter((t) => t.entrantId !== r.entrantId && t.entrantId !== e.entrantId), [...n, f(r.entrantId, e.entrantId)]);
107
+ if (i) return i;
108
+ }
109
+ return null;
110
+ };
111
+ if (Math.floor(s.length / 2) > o.maxMatches) throw e("limit_exceeded");
112
+ let y = Math.min(...g.map((e) => e.byes)), b = g.length % 2 == 0 ? [null] : g.filter((e) => e.byes === y).sort((e, t) => e.points === t.points ? t.seed - e.seed : e.points < t.points ? -1 : 1);
113
+ for (let e of b) {
114
+ let t = v(g.filter((t) => t.entrantId !== e?.entrantId), []);
115
+ if (t) return Object.freeze({
116
+ pairs: Object.freeze(t),
117
+ bye: e?.entrantId ?? null,
118
+ searchNodes: _
119
+ });
120
+ }
121
+ throw e("conflict");
122
+ }, g = (e, t, i) => {
123
+ let o = c(r.Array(r.Struct({
124
+ matchId: r.String,
125
+ winnerId: r.String
126
+ })), n(e, i.maxInputBytes)), l = /* @__PURE__ */ new Map();
127
+ for (let e of o) s(e.winnerId), (!t.has(e.matchId) || l.has(e.matchId)) && a(), l.set(e.matchId, e.winnerId);
128
+ return l;
129
+ }, _ = (t, n, r, i, a) => {
130
+ if (a !== void 0 && a !== r && a !== i) throw e("conflict");
131
+ return Object.freeze({
132
+ id: t,
133
+ round: n,
134
+ left: r,
135
+ right: i,
136
+ status: a === void 0 ? "ready" : "complete",
137
+ winnerId: a ?? null
138
+ });
139
+ }, v = (e, t, n) => {
140
+ let r = Math.max(...e.map((e) => t.get(e.entrantId) ?? 0)), i = new Set(e.filter((e) => (t.get(e.entrantId) ?? 0) === r).map((e) => e.entrantId)), a = (e) => n.filter((t) => t.winnerId === e && i.has(t.left) && i.has(t.right)).length, o = (e) => n.filter((t) => t.left === e || t.right === e).reduce((n, r) => n + (t.get(r.left === e ? r.right : r.left) ?? 0), 0);
141
+ return [...e].filter((e) => i.has(e.entrantId)).sort((e, t) => a(t.entrantId) - a(e.entrantId) || o(t.entrantId) - o(e.entrantId) || e.seed - t.seed)[0].entrantId;
142
+ }, y = (e, t, n = {}) => {
143
+ let r = u(n), i = d(e, r), a = p(i, { limits: r }).flatMap((e) => e.pairs.map((t, n) => ({
144
+ id: "rr-" + e.round + "-" + (n + 1),
145
+ round: e.round,
146
+ pairing: t
147
+ }))), o = g(t, new Set(a.map((e) => e.id)), r), s = a.map((e) => _(e.id, e.round, e.pairing.left, e.pairing.right, o.get(e.id))), c = /* @__PURE__ */ new Map();
148
+ for (let e of s) e.winnerId && c.set(e.winnerId, (c.get(e.winnerId) ?? 0) + 1);
149
+ let l = s.every((e) => e.status === "complete");
150
+ return Object.freeze({
151
+ matches: Object.freeze(s),
152
+ champion: l ? v(i, c, s) : null
153
+ });
154
+ }, b = (t, i, o, l = {}) => {
155
+ let f = u(l), p = d(t, f);
156
+ (!Number.isSafeInteger(o) || o < 1 || o >= p.length) && a();
157
+ let m = c(r.Array(r.Struct({
158
+ matchId: r.String,
159
+ winnerId: r.String
160
+ })), n(i, f.maxInputBytes)), g = /* @__PURE__ */ new Map();
161
+ for (let e of m) s(e.winnerId), (!/^sw-[0-9]+-[0-9]+$/.test(e.matchId) || g.has(e.matchId)) && a(), g.set(e.matchId, e.winnerId);
162
+ let y = /* @__PURE__ */ new Map(), b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = [];
163
+ for (let e = 1; e <= o; e++) {
164
+ let t = h(p.map((e) => ({
165
+ ...e,
166
+ points: y.get(e.entrantId) ?? 0,
167
+ byes: b.get(e.entrantId) ?? 0,
168
+ opponents: x.get(e.entrantId) ?? []
169
+ })), f), n = t.pairs.map((t, n) => {
170
+ let r = "sw-" + e + "-" + (n + 1), i = g.get(r);
171
+ return g.delete(r), _(r, e, t.left, t.right, i);
172
+ });
173
+ if (t.bye !== null && S.push(Object.freeze({
174
+ id: "sw-" + e + "-bye",
175
+ round: e,
176
+ left: t.bye,
177
+ right: null,
178
+ status: "walkover",
179
+ winnerId: t.bye
180
+ })), S.push(...n), n.some((e) => e.status !== "complete")) break;
181
+ for (let e of n) y.set(e.winnerId, (y.get(e.winnerId) ?? 0) + 1), x.set(e.left, [...x.get(e.left) ?? [], e.right]), x.set(e.right, [...x.get(e.right) ?? [], e.left]);
182
+ t.bye !== null && (y.set(t.bye, (y.get(t.bye) ?? 0) + 1), b.set(t.bye, (b.get(t.bye) ?? 0) + 1));
183
+ }
184
+ if (g.size > 0) throw e("conflict");
185
+ let C = S.filter((e) => e.right !== null), w = S.filter((e) => e.right !== null && e.round === o).length > 0 && C.every((e) => e.status === "complete");
186
+ return Object.freeze({
187
+ matches: Object.freeze(S),
188
+ champion: w ? v(p, y, C) : null
189
+ });
190
+ }, x = (t, n = {}) => {
191
+ let r = u(n), i = d(t, r), o = 2, s = [1, 2];
192
+ for (; o < i.length;) o *= 2, s = s.flatMap((e) => [e, o + 1 - e]);
193
+ if (o - 1 > r.maxMatches) throw e("limit_exceeded");
194
+ let c = [], l = (e) => {
195
+ let t = i[e - 1];
196
+ return Object.freeze(t ? {
197
+ kind: "entrant",
198
+ entrantId: t.entrantId
199
+ } : { kind: "bye" });
200
+ }, f = [];
201
+ for (let e = o / 2, t = 1; e >= 1; e /= 2, t++) {
202
+ let n = [];
203
+ for (let r = 0; r < e; r++) {
204
+ let e = `w${t}.${r + 1}`, i = (e) => t === 1 ? l(s[e] ?? a()) : Object.freeze({
205
+ kind: "winner",
206
+ matchId: f[e] ?? a()
207
+ });
208
+ c.push(Object.freeze({
209
+ id: e,
210
+ round: t,
211
+ left: i(r * 2),
212
+ right: i(r * 2 + 1)
213
+ })), n.push(e);
214
+ }
215
+ f = n;
216
+ }
217
+ return Object.freeze({
218
+ format: "single-elimination",
219
+ version: 1,
220
+ entrants: i,
221
+ matches: Object.freeze(c)
222
+ });
223
+ }, S = (i, o, l = {}) => {
224
+ let d = u(l), f = n(i, d.maxInputBytes);
225
+ (typeof f != "object" || !f || Array.isArray(f)) && a();
226
+ let p = x(f.entrants, d);
227
+ t(f) !== t(p) && a();
228
+ let m = c(r.Array(r.Struct({
229
+ matchId: r.String,
230
+ winnerId: r.String
231
+ })), n(o, d.maxInputBytes)), h = /* @__PURE__ */ new Map(), g = new Set(p.matches.map((e) => e.id));
232
+ for (let e of m) s(e.winnerId), (!g.has(e.matchId) || h.has(e.matchId)) && a(), h.set(e.matchId, e.winnerId);
233
+ let _ = /* @__PURE__ */ new Map(), v = [], y = (e) => {
234
+ if (e.kind === "entrant") return {
235
+ kind: "present",
236
+ id: e.entrantId
237
+ };
238
+ if (e.kind === "bye") return e;
239
+ let t = _.get(e.matchId)?.winnerId;
240
+ return t ? {
241
+ kind: "present",
242
+ id: t
243
+ } : { kind: "waiting" };
244
+ };
245
+ for (let t of p.matches) {
246
+ let n = y(t.left), r = y(t.right), i = h.get(t.id), a = "pending", o = null;
247
+ if (n.kind === "present" && r.kind === "present") {
248
+ if (a = i === void 0 ? "ready" : "complete", i !== void 0 && i !== n.id && i !== r.id) throw e("conflict");
249
+ o = i ?? null;
250
+ } else n.kind === "present" && r.kind === "bye" ? (a = "walkover", o = n.id) : r.kind === "present" && n.kind === "bye" && (a = "walkover", o = r.id);
251
+ if (i !== void 0 && a !== "complete") throw e("conflict");
252
+ let s = Object.freeze({
253
+ id: t.id,
254
+ round: t.round,
255
+ left: n.kind === "present" ? n.id : null,
256
+ right: r.kind === "present" ? r.id : null,
257
+ status: a,
258
+ winnerId: o
259
+ });
260
+ _.set(t.id, s), v.push(s);
261
+ }
262
+ return Object.freeze({
263
+ matches: Object.freeze(v),
264
+ champion: v.at(-1)?.winnerId ?? null
265
+ });
266
+ }, C = (t, n = {}) => {
267
+ let r = u(n), i = x(t, r), o = i.matches.at(-1)?.round ?? a(), s = 2 ** o;
268
+ if (2 * s - 1 > r.maxMatches) throw e("limit_exceeded");
269
+ let c = i.matches.map((e) => Object.freeze({
270
+ ...e,
271
+ stage: "winners"
272
+ })), l = (e, t) => Object.freeze({
273
+ kind: e,
274
+ matchId: t
275
+ }), d = (e, t, n, r) => {
276
+ let i = `l${e}.${t + 1}`;
277
+ return c.push(Object.freeze({
278
+ id: i,
279
+ stage: "losers",
280
+ round: e,
281
+ left: n,
282
+ right: r
283
+ })), i;
284
+ }, f = [], p = 1;
285
+ for (let e = 0; e < Math.floor(s / 4); e++) f.push(d(p, e, l("loser", `w1.${e * 2 + 1}`), l("loser", `w1.${e * 2 + 2}`)));
286
+ for (let e = 2; e <= o; e++) {
287
+ let t = s / 2 ** e, n = [];
288
+ p++;
289
+ for (let r = 0; r < t; r++) {
290
+ let i = t > 1 ? r ^ 1 : r;
291
+ n.push(d(p, r, l("winner", f[r] ?? a()), l("loser", `w${e}.${i + 1}`)));
292
+ }
293
+ if (e === o) {
294
+ f = n;
295
+ break;
296
+ }
297
+ let r = [];
298
+ p++;
299
+ for (let e = 0; e < n.length / 2; e++) r.push(d(p, e, l("winner", n[e * 2] ?? a()), l("winner", n[e * 2 + 1] ?? a())));
300
+ f = r;
301
+ }
302
+ let m = o === 1 ? l("loser", "w1.1") : l("winner", f[0] ?? a());
303
+ return c.push(Object.freeze({
304
+ id: "g1.1",
305
+ stage: "final",
306
+ round: 1,
307
+ left: l("winner", `w${o}.1`),
308
+ right: m
309
+ })), c.push(Object.freeze({
310
+ id: "g2.1",
311
+ stage: "reset",
312
+ round: 2,
313
+ left: l("loser", "g1.1"),
314
+ right: l("winner", "g1.1")
315
+ })), Object.freeze({
316
+ format: "double-elimination",
317
+ version: 1,
318
+ entrants: i.entrants,
319
+ matches: Object.freeze(c)
320
+ });
321
+ }, w = (i, o, l = {}) => {
322
+ let d = u(l), f = n(i, d.maxInputBytes);
323
+ (typeof f != "object" || !f || Array.isArray(f)) && a();
324
+ let p = C(f.entrants, d);
325
+ t(f) !== t(p) && a();
326
+ let m = c(r.Array(r.Struct({
327
+ matchId: r.String,
328
+ winnerId: r.String
329
+ })), n(o, d.maxInputBytes)), h = /* @__PURE__ */ new Map(), g = new Set(p.matches.map((e) => e.id));
330
+ for (let e of m) s(e.winnerId), (!g.has(e.matchId) || h.has(e.matchId)) && a(), h.set(e.matchId, e.winnerId);
331
+ let _ = [], v = /* @__PURE__ */ new Map(), y = new Map(p.entrants.map((e) => [e.entrantId, 0])), b = (e) => {
332
+ if (e.kind === "entrant") return {
333
+ kind: "present",
334
+ id: e.entrantId
335
+ };
336
+ if (e.kind === "bye") return e;
337
+ let t = v.get(e.matchId);
338
+ if (!t || t.status === "pending" || t.status === "ready") return { kind: "waiting" };
339
+ let n = e.kind === "winner" ? t.winnerId : t.loserId;
340
+ return n ? {
341
+ kind: "present",
342
+ id: n
343
+ } : { kind: "bye" };
344
+ };
345
+ for (let t of p.matches) {
346
+ let n = b(t.left), r = b(t.right), i = h.get(t.id), a = v.get("g1.1"), o = "pending", s = null, c = null;
347
+ if (t.stage === "reset" && a?.status === "complete" && a.winnerId === a.left) o = "inactive";
348
+ else if (n.kind === "present" && r.kind === "present") {
349
+ if (n.id === r.id || (y.get(n.id) ?? 2) >= 2 || (y.get(r.id) ?? 2) >= 2) throw e("conflict");
350
+ if (o = i === void 0 ? "ready" : "complete", i !== void 0) {
351
+ if (i !== n.id && i !== r.id) throw e("conflict");
352
+ s = i, c = i === n.id ? r.id : n.id, y.set(c, (y.get(c) ?? 0) + 1);
353
+ }
354
+ } else n.kind === "present" && r.kind === "bye" ? (o = "walkover", s = n.id) : r.kind === "present" && n.kind === "bye" ? (o = "walkover", s = r.id) : n.kind === "bye" && r.kind === "bye" && (o = "empty");
355
+ if (i !== void 0 && o !== "complete") throw e("conflict");
356
+ let l = Object.freeze({
357
+ id: t.id,
358
+ round: t.round,
359
+ stage: t.stage,
360
+ left: n.kind === "present" ? n.id : null,
361
+ right: r.kind === "present" ? r.id : null,
362
+ status: o,
363
+ winnerId: s,
364
+ loserId: c
365
+ });
366
+ _.push(l), v.set(t.id, l);
367
+ }
368
+ let x = v.get("g1.1"), S = v.get("g2.1"), w = x?.status === "complete" ? x.winnerId === x.left ? x.winnerId : S?.status === "complete" ? S.winnerId : null : null;
369
+ return Object.freeze({
370
+ matches: Object.freeze(_),
371
+ champion: w,
372
+ losses: Object.freeze(p.entrants.map((e) => Object.freeze({
373
+ entrantId: e.entrantId,
374
+ losses: y.get(e.entrantId) ?? 0
375
+ })))
376
+ });
377
+ };
378
+ export { w as advanceDoubleElimination, y as advanceRoundRobin, S as advanceSingleElimination, b as advanceSwiss, p as roundRobin, C as seedDoubleElimination, x as seedSingleElimination, h as swissPairings };
@@ -0,0 +1,92 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { leaderboardBucketAssignmentsTable as t } from "./tables.entity.js";
3
+ import { and as n, eq as r, queryFor as i } from "@voltro/database";
4
+ // src/bucketStore.ts
5
+ var a = (a) => {
6
+ let o = (e, t, n, r) => a.key("lbba_", [
7
+ e,
8
+ t,
9
+ n,
10
+ r
11
+ ]), s = async (n, a, s, c, l) => {
12
+ let u = o(a, s, c, l), d = (await n.query(i(t).where(r("id", u)).limit(1).descriptor))[0];
13
+ if (d && (d.tenantId !== a || d.board !== s || d.periodId !== c || d.ownerId !== l || typeof d.bucket != "string" || d.bucket.length > 64)) throw e("unavailable");
14
+ return d;
15
+ };
16
+ return {
17
+ readOwn: s,
18
+ admit: async (c, l, u, d, f) => {
19
+ if (l.buckets === void 0) return null;
20
+ let p = await s(c, u.tenantId, l.name, d, u.ownerId);
21
+ if (p) return String(p.bucket);
22
+ let m = l.buckets, h = m.assign === "hash" ? null : m.assign === "cohort" ? u.bucketCohort : "skill:" + Math.floor(u.bucketSkill / m.skillWidth), g = a.hash([
23
+ u.tenantId,
24
+ l.name,
25
+ d,
26
+ m.assign,
27
+ h
28
+ ]), _ = await c.query(i(t).where(n(r("tenantId", u.tenantId), r("board", l.name), r("periodId", d))).orderBy("id", "asc").limit(l.maxRankRecords + 1).descriptor);
29
+ if (_.length >= l.maxRankRecords) throw e("limit_exceeded");
30
+ let v = /* @__PURE__ */ new Map(), y = -1;
31
+ for (let t of _) {
32
+ if (t.tenantId !== u.tenantId || t.board !== l.name || t.periodId !== d || !Number.isSafeInteger(t.ordinal) || Number(t.ordinal) < 0 || Number(t.ordinal) >= l.maxRankRecords || typeof t.groupKey != "string" || typeof t.bucket != "string") throw e("unavailable");
33
+ let n = a.key("lbbk_", [
34
+ u.tenantId,
35
+ l.name,
36
+ d,
37
+ t.groupKey,
38
+ String(t.ordinal)
39
+ ]);
40
+ if (t.bucket !== n) throw e("unavailable");
41
+ if (t.groupKey !== g) continue;
42
+ if (t.group !== h) throw e("unavailable");
43
+ let r = Number(t.ordinal), i = v.get(t.bucket);
44
+ i ? i.entries++ : v.set(t.bucket, {
45
+ id: t.bucket,
46
+ ordinal: r,
47
+ entries: 1
48
+ }), y = Math.max(y, r);
49
+ }
50
+ if ([...v.values()].some((e) => e.entries > m.size)) throw e("unavailable");
51
+ let b = [...v.values()].filter((e) => e.entries < m.size).sort((e, t) => e.ordinal - t.ordinal);
52
+ if (b.length === 0) {
53
+ let e = y + 1;
54
+ b = [{
55
+ id: a.key("lbbk_", [
56
+ u.tenantId,
57
+ l.name,
58
+ d,
59
+ g,
60
+ String(e)
61
+ ]),
62
+ ordinal: e,
63
+ entries: 0
64
+ }];
65
+ }
66
+ let x = Object.freeze(b.map((e) => Object.freeze({ ...e }))), S = a.assign(Object.freeze({
67
+ tenantId: u.tenantId,
68
+ board: l.name,
69
+ periodId: d,
70
+ ownerId: u.ownerId,
71
+ assign: m.assign,
72
+ size: m.size,
73
+ group: h,
74
+ candidates: x
75
+ })), C = x.find((e) => e.id === S);
76
+ if (!C) throw e("invalid_record");
77
+ return await c.insert(t.tableName, {
78
+ id: o(u.tenantId, l.name, d, u.ownerId),
79
+ tenantId: u.tenantId,
80
+ board: l.name,
81
+ periodId: d,
82
+ ownerId: u.ownerId,
83
+ bucket: S,
84
+ ordinal: C.ordinal,
85
+ groupKey: g,
86
+ group: h,
87
+ assignedAt: new Date(f)
88
+ }), S;
89
+ }
90
+ };
91
+ };
92
+ export { a as makeBucketStore };
@@ -0,0 +1,8 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { hashBucket as t } from "./ranking.js";
3
+ // src/buckets.ts
4
+ var n = (n) => {
5
+ if (n.candidates.length === 0) throw e("limit_exceeded");
6
+ return n.candidates[t(n.tenantId, n.periodId, n.ownerId, n.candidates.length)].id;
7
+ };
8
+ export { n as defaultLeaderboardBucketAssign };
@@ -0,0 +1,13 @@
1
+ import { Schema } from 'effect';
2
+ import { YieldableError } from 'effect/Cause';
3
+
4
+ export declare class LeaderboardError extends LeaderboardError_base {
5
+ }
6
+
7
+ export declare const leaderboardError: (code: LeaderboardError["code"]) => LeaderboardError;
8
+
9
+ declare const LeaderboardError_base: Schema.Class<LeaderboardError, Schema.TaggedStruct<"LeaderboardError", {
10
+ readonly code: Schema.Literals<readonly ["invalid_board", "invalid_score", "invalid_record", "invalid_input", "overflow", "unavailable", "forbidden", "not_found", "conflict", "erased", "limit_exceeded"]>;
11
+ }>, YieldableError>;
12
+
13
+ export { }
package/dist/errors.js ADDED
@@ -0,0 +1,16 @@
1
+ import { Schema as e } from "effect";
2
+ // src/errors.ts
3
+ var t = class extends e.TaggedError()("LeaderboardError", { code: e.Literals([
4
+ "invalid_board",
5
+ "invalid_score",
6
+ "invalid_record",
7
+ "invalid_input",
8
+ "overflow",
9
+ "unavailable",
10
+ "forbidden",
11
+ "not_found",
12
+ "conflict",
13
+ "erased",
14
+ "limit_exceeded"
15
+ ]) }) {}, n = (e) => new t({ code: e });
16
+ export { t as LeaderboardError, n as leaderboardError };
@@ -0,0 +1,71 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ // src/glicko2.ts
3
+ var t = 173.7178, n = (e, t, n) => Number.isFinite(e) && e >= t && e <= n, r = (e, t) => Number.isSafeInteger(e) && e >= 1 && e <= t, i = (e) => n(e, -1e9, 1e9), a = (e) => n(e, 1e-6, 1e6), o = (e) => n(e, 1e-12, 10), s = (t) => {
4
+ if (!Number.isFinite(t)) throw e("overflow");
5
+ return t;
6
+ }, c = (e) => e >= 0 ? 1 / (1 + Math.exp(-e)) : Math.exp(e) / (1 + Math.exp(e)), l = (l = {}) => {
7
+ let u = l.tau ?? .5, d = l.epsilon ?? 1e-6, f = l.maxIterations ?? 100, p = l.maxOpponents ?? 4096;
8
+ if (!n(u, 1e-6, 10) || !n(d, 1e-12, .01) || !r(f, 1e4) || !r(p, 1e5)) throw e("invalid_input");
9
+ return (n) => {
10
+ let r = n?.player, l = n?.opponents;
11
+ if (!r || !i(r.rating) || !a(r.deviation) || !o(r.volatility) || !Array.isArray(l)) throw e("invalid_input");
12
+ if (l.length > p) throw e("limit_exceeded");
13
+ let m = Object.freeze({
14
+ rating: r.rating,
15
+ deviation: r.deviation,
16
+ volatility: r.volatility
17
+ }), h = l.map((t) => {
18
+ if (!t || !i(t.rating) || !a(t.deviation) || ![
19
+ 0,
20
+ .5,
21
+ 1
22
+ ].includes(t.score)) throw e("invalid_input");
23
+ return {
24
+ rating: t.rating,
25
+ deviation: t.deviation,
26
+ score: t.score
27
+ };
28
+ });
29
+ for (let t = 0; t < l.length; t++) if (!Object.hasOwn(l, t)) throw e("invalid_input");
30
+ let g = (m.rating - 1500) / t, _ = m.deviation / t, v = (n, r, c) => {
31
+ let l = s(n * t + 1500), u = s(r * t);
32
+ if (!i(l) || !a(u) || !o(c)) throw e("overflow");
33
+ return Object.freeze({
34
+ previous: m,
35
+ rating: l,
36
+ deviation: u,
37
+ volatility: c
38
+ });
39
+ };
40
+ if (h.length === 0) return v(g, Math.hypot(_, m.volatility), m.volatility);
41
+ let y = 0, b = 0;
42
+ for (let e of h) {
43
+ let n = e.deviation / t, r = 1 / Math.sqrt(1 + 3 * n ** 2 / Math.PI ** 2), i = c(r * (g - (e.rating - 1500) / t));
44
+ y += r ** 2 * i * (1 - i), b += r * (e.score - i);
45
+ }
46
+ if (!Number.isFinite(y) || y <= 0) throw e("overflow");
47
+ let x = s(1 / y), S = s(s(x * b) ** 2), C = Math.log(m.volatility ** 2), w = _ ** 2, T = (e) => {
48
+ let t = s(Math.exp(e)), n = w + x + t;
49
+ return s(t * (S - n) / (2 * n ** 2) - (e - C) / u ** 2);
50
+ }, E = 0, D = () => {
51
+ if (++E > f) throw e("limit_exceeded");
52
+ }, O = C, k;
53
+ if (S > w + x) k = Math.log(S - w - x);
54
+ else {
55
+ let e = 1;
56
+ for (k = C - e * u; T(k) < 0;) D(), k = C - ++e * u;
57
+ }
58
+ let A = T(O), j = T(k);
59
+ if (A * j > 0) throw e("overflow");
60
+ for (; Math.abs(k - O) > d && A !== 0 && j !== 0;) {
61
+ D();
62
+ let t = j - A;
63
+ if (t === 0) throw e("overflow");
64
+ let n = s(O + (O - k) * A / t), r = T(n);
65
+ r * j <= 0 ? (O = k, A = j) : A /= 2, k = n, j = r;
66
+ }
67
+ let M = s(Math.exp((j === 0 ? k : O) / 2)), N = 1 / Math.sqrt(1 / Math.hypot(_, M) ** 2 + y);
68
+ return v(g + N ** 2 * b, N, M);
69
+ };
70
+ };
71
+ export { l as glicko2 };