@voltro/plugin-leaderboards 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.
Files changed (67) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +1087 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +5007 -0
  6. package/dist/administration.js +5 -0
  7. package/dist/bracketAdmission.js +294 -0
  8. package/dist/bracketAdmissionPolicy.js +22 -0
  9. package/dist/bracketInstallation.js +133 -0
  10. package/dist/bracketMatchPorts.js +5 -0
  11. package/dist/bracketMatches.js +546 -0
  12. package/dist/brackets.d.ts +149 -0
  13. package/dist/brackets.js +379 -0
  14. package/dist/bucketStore.js +93 -0
  15. package/dist/buckets.js +9 -0
  16. package/dist/errors.d.ts +13 -0
  17. package/dist/errors.js +17 -0
  18. package/dist/glicko2.js +72 -0
  19. package/dist/index.d.ts +1208 -0
  20. package/dist/index.js +15 -0
  21. package/dist/inspect.js +84 -0
  22. package/dist/json.js +39 -0
  23. package/dist/leaderboard.d.ts +49 -0
  24. package/dist/leaderboard.js +57 -0
  25. package/dist/leagueSchedule.js +40 -0
  26. package/dist/leagues.js +31 -0
  27. package/dist/openskill.js +74 -0
  28. package/dist/plugin.js +338 -0
  29. package/dist/portLifetime.js +67 -0
  30. package/dist/ports.d.ts +294 -0
  31. package/dist/ports.js +7 -0
  32. package/dist/rankQuery.js +24 -0
  33. package/dist/ranking.d.ts +42 -0
  34. package/dist/ranking.js +71 -0
  35. package/dist/rating.d.ts +103 -0
  36. package/dist/rating.js +50 -0
  37. package/dist/ratingPools.js +134 -0
  38. package/dist/ratingStore.js +334 -0
  39. package/dist/ratingStrategies.js +108 -0
  40. package/dist/records.d.ts +116 -0
  41. package/dist/records.js +88 -0
  42. package/dist/rpc.d.ts +321 -0
  43. package/dist/rpc.js +306 -0
  44. package/dist/score.d.ts +13 -0
  45. package/dist/score.js +27 -0
  46. package/dist/server.d.ts +1477 -0
  47. package/dist/server.js +17 -0
  48. package/dist/service.js +949 -0
  49. package/dist/subjectFences.js +44 -0
  50. package/dist/tables.entity.js +188 -0
  51. package/dist/testing.d.ts +872 -0
  52. package/dist/testing.js +368 -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 +168 -0
  58. package/dist/tournamentPrizes.js +34 -0
  59. package/dist/tournamentStage.js +151 -0
  60. package/dist/tournamentStagePorts.js +5 -0
  61. package/dist/tournamentWorkflow.js +101 -0
  62. package/dist/tournamentWorkflowSchemas.js +54 -0
  63. package/dist/tournaments.d.ts +32 -0
  64. package/dist/tournaments.js +21 -0
  65. package/dist/web.d.ts +175 -0
  66. package/dist/web.js +17 -0
  67. package/package.json +113 -4
@@ -0,0 +1,368 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { applyScore as t } from "./score.js";
3
+ import { elo as ee } from "./rating.js";
4
+ import { resolveRatingPools as n } from "./ratingPools.js";
5
+ import { defaultRatingDecay as r, defaultRatingPlacement as i, defaultRatingRate as a } from "./ratingStrategies.js";
6
+ import { defaultLeaderboardTiebreak as o, defaultPeriodSummary as s, hashBucket as c, rankLeaderboardRecords as l } from "./ranking.js";
7
+ import { defaultLeaderboardBucketAssign as u } from "./buckets.js";
8
+ import { defaultLeaderboardRankQuery as d } from "./rankQuery.js";
9
+ import { acceptLeaderboardSubmission as f } from "./service.js";
10
+ import { TournamentBracketPort as p } from "./bracketMatchPorts.js";
11
+ import { TournamentStagePort as m } from "./tournamentStagePorts.js";
12
+ import { BracketAdmissionPort as h } from "./ports.js";
13
+ import { advanceDoubleElimination as g, advanceSingleElimination as _, roundRobin as v, seedDoubleElimination as y, seedSingleElimination as te, swissPairings as ne } from "./brackets.js";
14
+ import { Effect as b, Layer as x, Result as S } from "effect";
15
+ import { systemSubject as C } from "@voltro/protocol";
16
+ //#region src/testing.ts
17
+ var w = (e = "player") => ({
18
+ id: "record-" + e,
19
+ tenantId: "tenant",
20
+ board: "weekly",
21
+ periodId: "period",
22
+ ownerId: e,
23
+ score: "100",
24
+ subscore: "0",
25
+ updatedAt: 1e3
26
+ }), T = {
27
+ record: w,
28
+ applyScore: t,
29
+ tiebreak: o,
30
+ periodSummary: s,
31
+ hashBucket: c
32
+ }, E = () => ({
33
+ rate: ee(),
34
+ input: {
35
+ teams: [[{
36
+ id: "a",
37
+ rating: 1e3
38
+ }], [{
39
+ id: "b",
40
+ rating: 1e3
41
+ }]],
42
+ ranks: [1, 2]
43
+ }
44
+ }), D = (e) => ({
45
+ rankQuery: d,
46
+ context: Object.freeze({
47
+ tenantId: "tenant",
48
+ board: "weekly",
49
+ periodId: "period",
50
+ bucketId: null,
51
+ sort: "desc",
52
+ maxRecords: 10,
53
+ records: Object.freeze([Object.freeze({
54
+ ...w("a"),
55
+ score: "9007199254740993"
56
+ }), Object.freeze({
57
+ ...w("b"),
58
+ score: "9007199254740994"
59
+ })]),
60
+ tiebreak: o,
61
+ query: e
62
+ })
63
+ }), O = () => {
64
+ let e = n([{
65
+ name: "duels",
66
+ algorithm: "elo"
67
+ }])[0];
68
+ return {
69
+ rate: a,
70
+ placementPolicy: i,
71
+ decay: r,
72
+ context: Object.freeze({
73
+ tenantId: "tenant",
74
+ matchId: "match",
75
+ pool: e,
76
+ at: 1e3,
77
+ teams: Object.freeze(["a", "b"].map((t) => Object.freeze([Object.freeze({
78
+ ownerId: t,
79
+ state: e.initial,
80
+ games: 0,
81
+ updatedAt: null,
82
+ weight: 1
83
+ })]))),
84
+ ranks: Object.freeze([1, 2])
85
+ })
86
+ };
87
+ }, k = () => ({
88
+ bucketAssign: u,
89
+ context: Object.freeze({
90
+ tenantId: "tenant",
91
+ board: "weekly",
92
+ periodId: "period",
93
+ ownerId: "a",
94
+ assign: "hash",
95
+ size: 2,
96
+ group: null,
97
+ candidates: Object.freeze([Object.freeze({
98
+ id: "bucket-one",
99
+ ordinal: 0,
100
+ entries: 1
101
+ }), Object.freeze({
102
+ id: "bucket-two",
103
+ ordinal: 1,
104
+ entries: 1
105
+ })])
106
+ })
107
+ }), re = () => {
108
+ let e = Object.freeze(Array.from({ length: 4 }, (e, t) => Object.freeze({
109
+ entrantId: `p${t + 1}`,
110
+ seed: t + 1
111
+ })));
112
+ return Object.freeze({
113
+ entrants: e,
114
+ standings: Object.freeze(e.map((e) => Object.freeze({
115
+ ...e,
116
+ points: 0,
117
+ byes: 0,
118
+ opponents: Object.freeze([])
119
+ }))),
120
+ roundRobin: v,
121
+ swissPairings: ne,
122
+ seedSingleElimination: te,
123
+ advanceSingleElimination: _,
124
+ seedDoubleElimination: y,
125
+ advanceDoubleElimination: g
126
+ });
127
+ }, A = (t = {}) => ({
128
+ create: () => b.fail(e("unavailable")),
129
+ register: () => b.fail(e("unavailable")),
130
+ checkIn: () => b.fail(e("unavailable")),
131
+ status: () => b.fail(e("unavailable")),
132
+ seal: () => b.fail(e("unavailable")),
133
+ entrants: () => b.fail(e("unavailable")),
134
+ exportSubject: () => b.fail(e("unavailable")),
135
+ eraseSubject: () => b.fail(e("unavailable")),
136
+ ...t
137
+ }), j = (e = {}) => x.succeed(h, A(e)), M = () => {
138
+ let e = j();
139
+ return {
140
+ kind: "port",
141
+ tag: h,
142
+ fakeLayer: e,
143
+ probe: {
144
+ run: () => b.runPromise(b.flatMap(h, (e) => e.seal(C("fixture"), {
145
+ tenantId: "tenant",
146
+ tournamentId: "tournament"
147
+ })).pipe(b.result, b.map((e) => S.isFailure(e) ? e.failure.code : "unexpected-success"), b.provide(e))),
148
+ expected: "unavailable"
149
+ }
150
+ };
151
+ }, N = (t = {}) => ({
152
+ create: () => b.fail(e("unavailable")),
153
+ report: () => b.fail(e("unavailable")),
154
+ dispute: () => b.fail(e("unavailable")),
155
+ resolve: () => b.fail(e("unavailable")),
156
+ advance: () => b.fail(e("unavailable")),
157
+ status: () => b.fail(e("unavailable")),
158
+ exportSubject: () => b.fail(e("unavailable")),
159
+ eraseSubject: () => b.fail(e("unavailable")),
160
+ ...t
161
+ }), P = (e = {}) => x.succeed(p, N(e)), F = () => {
162
+ let e = P();
163
+ return {
164
+ kind: "port",
165
+ tag: p,
166
+ fakeLayer: e,
167
+ probe: {
168
+ run: () => b.runPromise(b.flatMap(p, (e) => e.status(C("fixture"), {
169
+ tenantId: "tenant",
170
+ tournamentId: "tournament"
171
+ })).pipe(b.result, b.map((e) => S.isFailure(e) ? e.failure.code : "unexpected-success"), b.provide(e))),
172
+ expected: "unavailable"
173
+ }
174
+ };
175
+ }, I = (t = {}) => ({
176
+ window: () => b.fail(e("unavailable")),
177
+ notify: () => b.fail(e("unavailable")),
178
+ seed: () => b.fail(e("unavailable")),
179
+ ...t
180
+ }), L = (e = {}) => x.succeed(m, I(e)), R = () => {
181
+ let e = L();
182
+ return {
183
+ kind: "port",
184
+ tag: m,
185
+ fakeLayer: e,
186
+ probe: {
187
+ run: () => b.runPromise(b.flatMap(m, (e) => e.window(C("fixture"), {
188
+ tenantId: "tenant",
189
+ tournamentId: "tournament",
190
+ runKey: "run",
191
+ format: "single-elimination",
192
+ ruleVersion: "studio:rules:1"
193
+ })).pipe(b.result, b.map((e) => S.isFailure(e) ? e.failure.code : "unexpected-success"), b.provide(e))),
194
+ expected: "unavailable"
195
+ }
196
+ };
197
+ }, z = [{
198
+ ...w("a"),
199
+ subscore: "1"
200
+ }, {
201
+ ...w("b"),
202
+ subscore: "2"
203
+ }], B = [
204
+ w("a"),
205
+ null,
206
+ void 0
207
+ ], V = (e) => e.map((e) => e.ownerId), H = (e) => b.map(b.result(e), (e) => S.isFailure(e) ? e.failure.code : "unexpected-success"), U = Object.freeze({
208
+ kind: "slot",
209
+ defaultImplementation: o,
210
+ defaultProbe: {
211
+ run: () => b.sync(() => V(l(z))),
212
+ expected: ["b", "a"]
213
+ },
214
+ overrideProbe: {
215
+ run: () => b.sync(() => V(l(z, { tiebreak: (e, t) => e.ownerId < t.ownerId ? -1 : 1 }))),
216
+ expected: ["a", "b"]
217
+ }
218
+ }), W = Object.freeze({
219
+ kind: "slot",
220
+ defaultImplementation: s,
221
+ defaultProbe: {
222
+ run: () => b.sync(() => s(l(z)).participants),
223
+ expected: 2
224
+ },
225
+ overrideProbe: {
226
+ run: () => b.sync(() => ((e) => ({
227
+ participants: e.length * 10,
228
+ top: []
229
+ }))(l(z)).participants),
230
+ expected: 20
231
+ }
232
+ }), G = Object.freeze({
233
+ kind: "slot",
234
+ defaultImplementation: d,
235
+ defaultProbe: {
236
+ run: () => {
237
+ let e = D(() => Promise.resolve([]));
238
+ return e.rankQuery(e.context);
239
+ },
240
+ expected: ["record-b", "record-a"]
241
+ },
242
+ overrideProbe: {
243
+ run: () => {
244
+ let e = D(() => Promise.resolve([]));
245
+ return b.succeed(e.context.records.map((e) => e.id));
246
+ },
247
+ expected: ["record-a", "record-b"]
248
+ }
249
+ }), K = Object.freeze({
250
+ kind: "slot",
251
+ defaultImplementation: u,
252
+ defaultProbe: {
253
+ run: () => b.sync(() => {
254
+ let e = k();
255
+ return e.bucketAssign(e.context);
256
+ }),
257
+ expected: "bucket-two"
258
+ },
259
+ overrideProbe: {
260
+ run: () => b.sync(() => k().context.candidates[0].id),
261
+ expected: "bucket-one"
262
+ }
263
+ }), q = Object.freeze({
264
+ kind: "slot",
265
+ defaultImplementation: f,
266
+ defaultProbe: {
267
+ run: () => b.as(f(...B), "accepted"),
268
+ expected: "accepted"
269
+ },
270
+ overrideProbe: {
271
+ run: () => H(b.fail(e("invalid_input"))),
272
+ expected: "invalid_input"
273
+ }
274
+ }), J = Object.freeze({
275
+ kind: "slot",
276
+ defaultImplementation: a,
277
+ defaultProbe: {
278
+ run: () => b.sync(() => {
279
+ let e = O();
280
+ return e.rate(e.context).map((e) => e.ownerId);
281
+ }),
282
+ expected: ["a", "b"]
283
+ },
284
+ overrideProbe: {
285
+ run: () => b.sync(() => [...O().context.teams].reverse().flatMap((e) => e.map((e) => e.ownerId))),
286
+ expected: ["b", "a"]
287
+ }
288
+ }), Y = Object.freeze({
289
+ kind: "slot",
290
+ defaultImplementation: i,
291
+ defaultProbe: {
292
+ run: () => b.sync(() => {
293
+ let { context: e } = O();
294
+ return i({
295
+ tenantId: e.tenantId,
296
+ ownerId: "a",
297
+ pool: e.pool,
298
+ at: e.at
299
+ });
300
+ }),
301
+ expected: O().context.pool.initial
302
+ },
303
+ overrideProbe: {
304
+ run: () => b.sync(() => ({ placed: !0 })),
305
+ expected: { placed: !0 }
306
+ }
307
+ }), ie = Object.freeze({
308
+ kind: "slot",
309
+ defaultImplementation: r,
310
+ defaultProbe: {
311
+ run: () => b.sync(() => {
312
+ let { context: e } = O();
313
+ return r({
314
+ tenantId: e.tenantId,
315
+ ownerId: "a",
316
+ pool: e.pool,
317
+ at: e.at,
318
+ state: e.pool.initial,
319
+ games: 3,
320
+ updatedAt: 0,
321
+ elapsedMs: 1e3
322
+ });
323
+ }),
324
+ expected: O().context.pool.initial
325
+ },
326
+ overrideProbe: {
327
+ run: () => b.sync(() => ({ decayed: !0 })),
328
+ expected: { decayed: !0 }
329
+ }
330
+ }), X = j(), Z = P(), Q = L(), $ = C("leaderboards.system.fixture"), ae = Object.freeze({
331
+ kind: "port",
332
+ tag: h,
333
+ fakeLayer: X,
334
+ probe: {
335
+ run: () => H(b.flatMap(h, (e) => e.seal($, {
336
+ tenantId: "tenant",
337
+ tournamentId: "tournament"
338
+ }))).pipe(b.provide(X)),
339
+ expected: "unavailable"
340
+ }
341
+ }), oe = Object.freeze({
342
+ kind: "port",
343
+ tag: p,
344
+ fakeLayer: Z,
345
+ probe: {
346
+ run: () => H(b.flatMap(p, (e) => e.status($, {
347
+ tenantId: "tenant",
348
+ tournamentId: "tournament"
349
+ }))).pipe(b.provide(Z)),
350
+ expected: "unavailable"
351
+ }
352
+ }), se = Object.freeze({
353
+ kind: "port",
354
+ tag: m,
355
+ fakeLayer: Q,
356
+ probe: {
357
+ run: () => H(b.flatMap(m, (e) => e.window($, {
358
+ tenantId: "tenant",
359
+ tournamentId: "tournament",
360
+ runKey: "run",
361
+ format: "single-elimination",
362
+ ruleVersion: "studio:rules:1"
363
+ }))).pipe(b.provide(Q)),
364
+ expected: "unavailable"
365
+ }
366
+ });
367
+ //#endregion
368
+ export { j as bracketAdmissionFakeLayer, M as bracketAdmissionPortFixture, ae as bracketAdmissionPortSystemFixture, X as bracketAdmissionSystemFakeLayer, K as bucketAssignSystemFixture, E as eloFixture, A as fakeBracketAdmissionService, N as fakeTournamentBracketService, I as fakeTournamentStageService, k as leaderboardBucketAssignFixture, T as leaderboardPureFixture, D as leaderboardRankQueryFixture, w as leaderboardRecordFixture, W as periodSummarySystemFixture, G as rankQuerySystemFixture, ie as ratingDecaySystemFixture, Y as ratingPlacementSystemFixture, J as ratingRateSystemFixture, O as ratingStrategiesFixture, U as tiebreakSystemFixture, P as tournamentBracketFakeLayer, F as tournamentBracketPortFixture, oe as tournamentBracketPortSystemFixture, Z as tournamentBracketSystemFakeLayer, re as tournamentPairingFixture, L as tournamentStageFakeLayer, R as tournamentStagePortFixture, se as tournamentStagePortSystemFixture, Q as tournamentStageSystemFakeLayer, q as validateSystemFixture };
@@ -0,0 +1,3 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+ import { tournamentAdvanceExecutor } from '@voltro/plugin-leaderboards/server'
3
+ export default (context: AppContext): ReturnType<typeof tournamentAdvanceExecutor> => tournamentAdvanceExecutor(context)
@@ -0,0 +1,12 @@
1
+ import { workflow } from '@voltro/workflow/define'
2
+ import { TournamentAdvancePayload, TournamentWorkflowSummary } from '@voltro/plugin-leaderboards/rpc'
3
+ import { LeaderboardError } from '@voltro/plugin-leaderboards/errors'
4
+
5
+ export const TournamentAdvance = workflow({ name: 'tournament.advance', payload: TournamentAdvancePayload,
6
+ success: TournamentWorkflowSummary, error: LeaderboardError, internal: true,
7
+ controls: { guards: [{ scope: 'tournaments:operate' }] },
8
+ idempotencyKey: payload => 'tournament.advance:' + JSON.stringify([payload.tenantId, payload.tournamentId, payload.runKey]),
9
+ // One run per tournament at a time; a start during a run waits and then drains what that run
10
+ // could not see, so no result is left without its next Room.
11
+ concurrency: { limit: 1, key: payload => JSON.stringify([payload.tenantId, payload.tournamentId]) },
12
+ })
@@ -0,0 +1,3 @@
1
+ import type { AppContext } from '@voltro/runtime'
2
+ import { tournamentStageExecutor } from '@voltro/plugin-leaderboards/server'
3
+ export default (context: AppContext): ReturnType<typeof tournamentStageExecutor> => tournamentStageExecutor(context)
@@ -0,0 +1,10 @@
1
+ import { workflow } from '@voltro/workflow/define'
2
+ import { TournamentStagePayload, TournamentWorkflowSummary } from '@voltro/plugin-leaderboards/rpc'
3
+ import { LeaderboardError } from '@voltro/plugin-leaderboards/errors'
4
+
5
+ export const TournamentStage = workflow({ name: 'tournament.stage', payload: TournamentStagePayload,
6
+ success: TournamentWorkflowSummary, error: LeaderboardError, internal: true,
7
+ controls: { guards: [{ scope: 'tournaments:operate' }] },
8
+ idempotencyKey: payload => 'tournament.stage:' + JSON.stringify([payload.tenantId, payload.tournamentId, payload.runKey, payload.format, payload.ruleVersion]),
9
+ singleton: { key: payload => JSON.stringify([payload.tenantId, payload.tournamentId]), mode: 'skip' },
10
+ })
@@ -0,0 +1,168 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { captureLeaderboardJson as t } from "./json.js";
3
+ import { dataStoreTournamentBrackets as n, resolveTournamentBracketOptions as r } from "./bracketMatches.js";
4
+ import { dataStoreTournamentStages as i, resolveTournamentStageOptions as a } from "./tournamentStage.js";
5
+ import { assertPortBindingKeys as o, capturePortMethods as s, capturePortPrivacyRequest as c, capturePortSources as l, capturePortSubject as u, capturePortVersion as d, invalidPortBinding as f, makeLeaderboardPortLifetime as p } from "./portLifetime.js";
6
+ import { Effect as m } from "effect";
7
+ import { fileURLToPath as h } from "node:url";
8
+ import { isAbsolute as g } from "node:path";
9
+ //#region src/tournamentInstallation.ts
10
+ var _ = [
11
+ "create",
12
+ "report",
13
+ "dispute",
14
+ "resolve",
15
+ "advance",
16
+ "status",
17
+ "exportSubject",
18
+ "eraseSubject"
19
+ ], v = [
20
+ "window",
21
+ "notify",
22
+ "seed"
23
+ ], y = (y, b, x) => {
24
+ let S = p(), C = p(), w = S.call, T = C.call, E = Object.freeze({
25
+ create: (e, n, r) => w(() => {
26
+ let i = u(e), a = t(n, 1024), o = t(r, 16384);
27
+ return (e) => e.create(i, a, o);
28
+ }),
29
+ report: (e, n, r) => w(() => {
30
+ let i = u(e), a = t(n, 1024), o = t(r, 2048);
31
+ return (e) => e.report(i, a, o);
32
+ }),
33
+ dispute: (e, n, r) => w(() => {
34
+ let i = u(e), a = t(n, 1024), o = t(r, 2048);
35
+ return (e) => e.dispute(i, a, o);
36
+ }),
37
+ resolve: (e, n, r) => w(() => {
38
+ let i = u(e), a = t(n, 1024), o = t(r, 2048);
39
+ return (e) => e.resolve(i, a, o);
40
+ }),
41
+ advance: (e, n) => w(() => {
42
+ let r = u(e), i = t(n, 1024);
43
+ return (e) => e.advance(r, i);
44
+ }),
45
+ status: (e, n) => w(() => {
46
+ let r = u(e), i = t(n, 1024);
47
+ return (e) => e.status(r, i);
48
+ }),
49
+ exportSubject: (e) => w(() => {
50
+ let t = c(e);
51
+ return (e) => e.exportSubject(t);
52
+ }),
53
+ eraseSubject: (e) => w(() => {
54
+ let t = c(e);
55
+ return (e) => e.eraseSubject(t);
56
+ })
57
+ }), D = Object.freeze({
58
+ window: (e, n) => T(() => {
59
+ let r = u(e), i = t(n, 2048);
60
+ return (e) => e.window(r, i);
61
+ }),
62
+ notify: (e, n, r) => T(() => {
63
+ let i = u(e), a = t(n, 2048);
64
+ return (e) => e.notify(i, a, r);
65
+ }),
66
+ seed: (e, n) => T(() => {
67
+ let r = u(e), i = t(n, 2048);
68
+ return (e) => e.seed(r, i);
69
+ })
70
+ }), O, k, A, j, M, N = null, P = Object.freeze([]), F;
71
+ if (y !== void 0) {
72
+ o(y, ["backend"], [
73
+ "options",
74
+ "version",
75
+ "service",
76
+ "sources",
77
+ "stage",
78
+ "workflowSources"
79
+ ]);
80
+ let e, t;
81
+ y.backend === "sql" ? (o(y, ["backend", "options"], ["stage", "workflowSources"]), O = r(y.options), e = "voltro:tournament-brackets:1", t = O.maxTenantTournaments, P = Object.freeze(["_voltro_brackets"])) : y.backend === "custom" ? (o(y, [
82
+ "backend",
83
+ "version",
84
+ "service",
85
+ "sources"
86
+ ], ["stage", "workflowSources"]), e = d(y.version), t = null, k = s(y.service, _), P = l(y.sources)) : f();
87
+ let n = null;
88
+ if (y.stage !== void 0) {
89
+ let e = y.stage;
90
+ o(e, ["backend", "privacy"], [
91
+ "options",
92
+ "version",
93
+ "service"
94
+ ]), M = s(e.privacy, ["exportSubject", "eraseSubject"]), e.backend === "sql" ? (o(e, [
95
+ "backend",
96
+ "options",
97
+ "privacy"
98
+ ]), x !== "sql" && f(), o(e.options, [
99
+ "epochNow",
100
+ "authorize",
101
+ "seedRoster",
102
+ "notifyEntrants"
103
+ ]), A = a({
104
+ ...e.options,
105
+ admissions: b,
106
+ brackets: E
107
+ }), n = Object.freeze({
108
+ backend: "sql",
109
+ version: "voltro:tournament-stage:1"
110
+ })) : e.backend === "custom" ? (o(e, [
111
+ "backend",
112
+ "version",
113
+ "service",
114
+ "privacy"
115
+ ]), j = s(e.service, v), n = Object.freeze({
116
+ backend: "custom",
117
+ version: d(e.version)
118
+ })) : f();
119
+ }
120
+ n === null && y.workflowSources !== void 0 && f(), y.workflowSources !== void 0 && (typeof y.workflowSources != "string" || !g(y.workflowSources) || y.workflowSources.includes("\0")) && f(), F = n === null ? void 0 : y.workflowSources ?? h(new URL("./tournament-app", "" + import.meta.url)), N = Object.freeze({
121
+ backend: y.backend,
122
+ version: e,
123
+ maxTenantTournaments: t,
124
+ stage: n,
125
+ workflowSource: n === null ? null : y.workflowSources === void 0 ? "default" : "custom"
126
+ });
127
+ }
128
+ let I = M;
129
+ return Object.freeze({
130
+ configuration: N,
131
+ sources: P,
132
+ sourceRoot: F,
133
+ service: E,
134
+ stageService: D,
135
+ isBound: S.isBound,
136
+ isStageBound: C.isBound,
137
+ bind: (e, t) => {
138
+ let r = O === void 0 ? k : n(e, O);
139
+ A !== void 0 && (r === void 0 || t === void 0) && f();
140
+ let a = A === void 0 ? j : i(e, {
141
+ ...A,
142
+ admissions: t,
143
+ brackets: r
144
+ });
145
+ r !== void 0 && S.bind(r), a !== void 0 && C.bind(a);
146
+ },
147
+ exportStageSubject: (n) => T(() => {
148
+ let r = c(n);
149
+ return () => I.exportSubject(r).pipe(m.flatMap((n) => m.try({
150
+ try: () => t(n, 65536),
151
+ catch: () => e("unavailable")
152
+ })));
153
+ }),
154
+ eraseStageSubject: (e) => T(() => {
155
+ let t = c(e);
156
+ return () => I.eraseSubject(t);
157
+ }),
158
+ close: () => {
159
+ C.close(), S.close();
160
+ },
161
+ awaitIdle: () => m.all([C.awaitIdle(), S.awaitIdle()], {
162
+ concurrency: "unbounded",
163
+ discard: !0
164
+ })
165
+ });
166
+ };
167
+ //#endregion
168
+ export { y as makeTournamentInstallation };
@@ -0,0 +1,34 @@
1
+ import { leaderboardError as e } from "./errors.js";
2
+ import { Effect as t } from "effect";
3
+ import { systemSubject as n } from "@voltro/protocol";
4
+ import { createHash as r } from "node:crypto";
5
+ //#region src/tournamentPrizes.ts
6
+ var i = (r, i) => {
7
+ if (!r || typeof r.inbox != "function" || !i || typeof i.templateId != "string" || !i.templateId || i.expiresInMs !== void 0 && (!Number.isSafeInteger(i.expiresInMs) || i.expiresInMs < 1)) throw e("invalid_input");
8
+ let a = Object.freeze([...i.attachments ?? []].map((e) => Object.freeze({ ...e }))), o = i.now ?? Date.now, s = n("tournament-prizes");
9
+ return (n) => t.suspend(() => r.inbox().send(s, n.tenantId, n.winnerId, {
10
+ requestId: n.requestId,
11
+ templateId: i.templateId,
12
+ params: { tournamentId: n.tournamentId },
13
+ attachments: a,
14
+ expiresAt: i.expiresInMs === void 0 ? null : o() + i.expiresInMs
15
+ })).pipe(t.asVoid, t.mapError(() => e("unavailable")));
16
+ }, a = (i, a, o) => {
17
+ if (!i || typeof i.inbox != "function" || typeof a != "function" || !o?.templates || !["registration", "check-in"].every((e) => typeof o.templates[e] == "string" && o.templates[e])) throw e("invalid_input");
18
+ let s = Object.freeze({ ...o.templates }), c = n("tournament-notices"), l = (e, t) => "tn:" + r("sha256").update(JSON.stringify([e, t])).digest("hex").slice(0, 48);
19
+ return (n) => t.suspend(() => a().entrants(c, {
20
+ tenantId: n.tenantId,
21
+ tournamentId: n.tournamentId
22
+ })).pipe(t.flatMap((e) => t.forEach(e.entries.filter((e) => n.phase === "registration" || e.checkedInAt === null), (e) => i.inbox().send(c, n.tenantId, e.ownerId, {
23
+ requestId: l(n.requestId, e.ownerId),
24
+ templateId: s[n.phase],
25
+ params: {
26
+ tournamentId: n.tournamentId,
27
+ phase: n.phase
28
+ },
29
+ attachments: [],
30
+ expiresAt: null
31
+ }), { discard: !0 })), t.mapError(() => e("unavailable")));
32
+ };
33
+ //#endregion
34
+ export { a as tournamentInboxNotice, i as tournamentInboxPrize };