@voltro/plugin-progression 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 (97) hide show
  1. package/CHANGELOG.md +24492 -0
  2. package/LICENSE +61 -0
  3. package/README.md +478 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9841 -0
  6. package/dist/achievementComponents.js +91 -0
  7. package/dist/achievementStore.js +602 -0
  8. package/dist/achievementTables.entity.js +97 -0
  9. package/dist/achievements.d.ts +188 -0
  10. package/dist/achievements.js +204 -0
  11. package/dist/capture.js +63 -0
  12. package/dist/cmsQuests.d.ts +91 -0
  13. package/dist/cmsQuests.js +82 -0
  14. package/dist/components.d.ts +172 -0
  15. package/dist/components.js +4 -0
  16. package/dist/curve.d.ts +27 -0
  17. package/dist/curve.js +37 -0
  18. package/dist/daily.d.ts +152 -0
  19. package/dist/daily.js +125 -0
  20. package/dist/dailyStore.js +420 -0
  21. package/dist/dailySystem.fixture.js +137 -0
  22. package/dist/dailyTables.entity.js +89 -0
  23. package/dist/declarationFixtures.js +142 -0
  24. package/dist/errors.d.ts +13 -0
  25. package/dist/errors.js +19 -0
  26. package/dist/index.d.ts +1833 -0
  27. package/dist/index.js +19 -0
  28. package/dist/pass.d.ts +186 -0
  29. package/dist/pass.js +121 -0
  30. package/dist/passRules.js +95 -0
  31. package/dist/passStore.js +484 -0
  32. package/dist/passTables.entity.js +95 -0
  33. package/dist/plugin.js +1085 -0
  34. package/dist/port.js +4 -0
  35. package/dist/progressionStore.js +705 -0
  36. package/dist/questComponents.js +162 -0
  37. package/dist/questPort.d.ts +126 -0
  38. package/dist/questPort.js +4 -0
  39. package/dist/questRefresh.js +55 -0
  40. package/dist/questRefresh.server.js +125 -0
  41. package/dist/questRerollJournal.js +76 -0
  42. package/dist/questStore.js +591 -0
  43. package/dist/questTables.entity.js +116 -0
  44. package/dist/quests.d.ts +142 -0
  45. package/dist/quests.js +152 -0
  46. package/dist/rank-app/schedules/progression.dispatchRankClosures.cron.tsx +19 -0
  47. package/dist/rank-app/workflows/progression.closeRankSeason.workflow.server.tsx +10 -0
  48. package/dist/rank-app/workflows/progression.closeRankSeason.workflow.tsx +1 -0
  49. package/dist/rankClosure.d.ts +69 -0
  50. package/dist/rankClosure.js +34 -0
  51. package/dist/rankClosure.server.js +138 -0
  52. package/dist/rankClosureWorkflow.d.ts +34 -0
  53. package/dist/rankClosureWorkflow.js +15 -0
  54. package/dist/rankReader.server.js +56 -0
  55. package/dist/rankRewardParent.server.js +64 -0
  56. package/dist/rankSeasons.d.ts +144 -0
  57. package/dist/rankSeasons.js +90 -0
  58. package/dist/rankStore.js +520 -0
  59. package/dist/rankSystem.fixture.js +169 -0
  60. package/dist/rankTables.entity.js +100 -0
  61. package/dist/ranks.d.ts +167 -0
  62. package/dist/ranks.js +218 -0
  63. package/dist/resourceStore.js +463 -0
  64. package/dist/resourceTables.entity.js +88 -0
  65. package/dist/resources.d.ts +105 -0
  66. package/dist/resources.js +59 -0
  67. package/dist/reward-app/schedules/progression.dispatchRewards.cron.tsx +19 -0
  68. package/dist/reward-app/workflows/progression.deliverReward.workflow.server.tsx +10 -0
  69. package/dist/reward-app/workflows/progression.deliverReward.workflow.tsx +1 -0
  70. package/dist/reward.d.ts +27 -0
  71. package/dist/reward.js +38 -0
  72. package/dist/rewardDelivery.d.ts +163 -0
  73. package/dist/rewardDelivery.js +37 -0
  74. package/dist/rewardDelivery.server.js +429 -0
  75. package/dist/rewardDeliveryRecord.js +47 -0
  76. package/dist/rewardDeliveryWorkflow.d.ts +36 -0
  77. package/dist/rewardDeliveryWorkflow.js +15 -0
  78. package/dist/rpc.d.ts +880 -0
  79. package/dist/rpc.js +497 -0
  80. package/dist/server.d.ts +2812 -0
  81. package/dist/server.js +21 -0
  82. package/dist/stats.js +44 -0
  83. package/dist/strategies.d.ts +131 -0
  84. package/dist/strategies.js +4 -0
  85. package/dist/systemFixtures.js +473 -0
  86. package/dist/tables.entity.js +154 -0
  87. package/dist/testing.d.ts +1566 -0
  88. package/dist/testing.js +11 -0
  89. package/dist/track.js +71 -0
  90. package/dist/tutorial.d.ts +157 -0
  91. package/dist/tutorial.js +109 -0
  92. package/dist/tutorialStore.js +495 -0
  93. package/dist/tutorialSystem.fixture.js +99 -0
  94. package/dist/tutorialTables.entity.js +90 -0
  95. package/dist/web.d.ts +363 -0
  96. package/dist/web.js +6 -0
  97. package/package.json +167 -4
@@ -0,0 +1,100 @@
1
+ import { boolean as e, id as t, integer as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
2
+ // src/rankTables.entity.ts
3
+ var s = () => a().maxLength(120).externalId().sensitive("pii"), c = () => a().maxLength(120).externalId().sensitive("pii"), l = () => a().maxLength(64).nullable().serverOnly(), u = i("_voltro_prog_rank_definitions", {
4
+ id: t({ prefix: "prd" }),
5
+ tenantId: s(),
6
+ seasonId: a().maxLength(120).safe(),
7
+ config: r().serverOnly(),
8
+ rulesVersion: a().maxLength(120).safe(),
9
+ admission: n().serverOnly()
10
+ }).index(["tenantId", "seasonId"]), d = i("_voltro_prog_rank_subjects", {
11
+ id: t({ prefix: "prs" }),
12
+ tenantId: s(),
13
+ ownerId: c().nullable(),
14
+ erased: e().serverOnly(),
15
+ sequence: n().serverOnly(),
16
+ admission: n().serverOnly()
17
+ }).index(["tenantId", "ownerId"]), f = i("_voltro_prog_rank", {
18
+ id: t({ prefix: "prv" }),
19
+ tenantId: s(),
20
+ ownerId: c(),
21
+ ownerKey: l(),
22
+ seasonId: a().maxLength(120).safe(),
23
+ state: r().serverOnly(),
24
+ updatedAt: o().safe()
25
+ }).index(["tenantId", "ownerKey"]), p = i("_voltro_prog_rank_ledger", {
26
+ id: t({ prefix: "prl" }),
27
+ tenantId: s(),
28
+ ownerId: c().nullable(),
29
+ ownerKey: l(),
30
+ seasonId: a().maxLength(120).safe(),
31
+ sequence: n().serverOnly(),
32
+ operationId: a().maxLength(64).safe(),
33
+ claimKey: a().maxLength(64).serverOnly(),
34
+ intent: r().nullable().serverOnly(),
35
+ before: r().nullable().serverOnly(),
36
+ after: r().nullable().serverOnly(),
37
+ at: o().safe()
38
+ }).index(["tenantId", "ownerKey"]), m = i("_voltro_prog_rank_operations", {
39
+ id: t({ prefix: "pro" }),
40
+ tenantId: s(),
41
+ ownerKey: l(),
42
+ state: a().maxLength(16).oneOf([
43
+ "committed",
44
+ "replayed",
45
+ "erased"
46
+ ]).serverOnly(),
47
+ claimKey: a().maxLength(64).serverOnly(),
48
+ linkedOperationId: a().maxLength(64).nullable().serverOnly(),
49
+ intent: r().nullable().serverOnly(),
50
+ digest: a().maxLength(64).nullable().serverOnly(),
51
+ receipt: r().nullable().serverOnly(),
52
+ at: o().safe()
53
+ }).index(["tenantId", "ownerKey"]), h = i("_voltro_prog_rank_rewards", {
54
+ id: t({ prefix: "prr" }),
55
+ tenantId: s(),
56
+ ownerId: c().nullable(),
57
+ ownerKey: l(),
58
+ seasonId: a().maxLength(120).safe(),
59
+ operationId: a().maxLength(64).safe(),
60
+ reward: r().nullable().serverOnly(),
61
+ state: a().maxLength(16).oneOf([
62
+ "pending",
63
+ "delivered",
64
+ "erased"
65
+ ]).serverOnly(),
66
+ createdAt: o().safe(),
67
+ deliveredAt: o().nullable().safe(),
68
+ deliveryIntent: r().nullable().serverOnly(),
69
+ deliveryDigest: a().maxLength(64).nullable().serverOnly(),
70
+ deliveryReceipt: r().nullable().serverOnly()
71
+ }).index(["tenantId", "ownerKey"]), g = i("_voltro_prog_rank_closure_units", {
72
+ id: t({ prefix: "prc" }),
73
+ tenantId: s(),
74
+ ownerId: c().nullable(),
75
+ ownerKey: l(),
76
+ seasonId: a().maxLength(120).safe(),
77
+ version: n().safe(),
78
+ stateId: a().maxLength(64).serverOnly(),
79
+ until: o().safe(),
80
+ state: a().maxLength(16).oneOf([
81
+ "open",
82
+ "closed",
83
+ "erased"
84
+ ]).serverOnly(),
85
+ receipt: r().nullable().serverOnly(),
86
+ createdAt: o().safe()
87
+ }).index([
88
+ "state",
89
+ "until",
90
+ "id"
91
+ ]).index(["tenantId", "ownerKey"]), _ = [
92
+ u,
93
+ d,
94
+ f,
95
+ p,
96
+ m,
97
+ h,
98
+ g
99
+ ];
100
+ export { g as rankClosureUnitsTable, u as rankDefinitionsTable, p as rankLedgerTable, m as rankOperationsTable, h as rankRewardsTable, f as rankStatesTable, d as rankSubjectsTable, _ as rankTables };
@@ -0,0 +1,167 @@
1
+ import { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ import { Schema } from 'effect';
4
+ import { Subject } from '@voltro/protocol';
5
+ import { YieldableError } from 'effect/Cause';
6
+
7
+ /** Admit accepted custom-slot output for journal repair without calling historical strategies. */
8
+ export declare const capturePlayerRank: (input: unknown, ladder: RankLadder, rulesVersion: string) => PlayerRank;
9
+
10
+ export declare const captureRankRating: (input: unknown, pool: string) => RankRating;
11
+
12
+ /** A read-only displayed score; it never writes or claims to decay the Ratings SQL pool. */
13
+ export declare const defaultRankDecay: RankDecayResolver;
14
+
15
+ export declare const defaultRankGrade: RankGradeResolver;
16
+
17
+ export declare const defaultRankScore: RankScoreResolver;
18
+
19
+ export declare const defaultRankSeasonReset: RankSeasonReset;
20
+
21
+ export declare const defineRankLadder: (input: RankLadderDefinition | RankLadder) => RankLadder;
22
+
23
+ export declare interface PlayerRank {
24
+ readonly ladderId: string;
25
+ readonly version: number;
26
+ readonly pool: string;
27
+ readonly games: number;
28
+ readonly placementsRemaining: number;
29
+ readonly rawScore: number;
30
+ readonly score: number;
31
+ readonly grade: RankGrade | null;
32
+ readonly ratingUpdatedAt: number | null;
33
+ readonly observedAt: number;
34
+ readonly rulesVersion: string;
35
+ }
36
+
37
+ declare class ProgressionError extends ProgressionError_base {
38
+ }
39
+
40
+ declare const ProgressionError_base: Schema.Class<ProgressionError, Schema.TaggedStruct<"ProgressionError", {
41
+ readonly code: Schema.Literals<readonly ["invalid_input", "invalid_record", "invalid_curve", "invalid_reward", "invalid_track", "invalid_stat", "overflow", "insufficient_resource", "forbidden", "conflict", "erased", "not_found", "limit_exceeded", "unavailable"]>;
42
+ }>, YieldableError>;
43
+
44
+ export declare interface RankContext {
45
+ readonly ladder: RankLadder;
46
+ readonly rating: RankRating;
47
+ readonly at: number;
48
+ }
49
+
50
+ export declare interface RankDecayDefinition {
51
+ readonly afterDays: number;
52
+ readonly perDay: number;
53
+ readonly floor: number;
54
+ }
55
+
56
+ export declare type RankDecayResolver = (input: RankGradeContext) => number;
57
+
58
+ export declare interface RankGrade {
59
+ readonly index: number;
60
+ readonly tier: string;
61
+ readonly tierIndex: number;
62
+ readonly division: number;
63
+ }
64
+
65
+ export declare interface RankGradeContext extends RankContext {
66
+ readonly score: number;
67
+ }
68
+
69
+ export declare type RankGradeResolver = (input: RankGradeContext) => RankGrade | null;
70
+
71
+ export declare interface RankLadder {
72
+ readonly id: string;
73
+ readonly version: number;
74
+ readonly rating: string;
75
+ readonly tiers: readonly string[];
76
+ readonly divisions: number;
77
+ readonly thresholds: readonly number[];
78
+ readonly placements: number;
79
+ readonly confidence: number;
80
+ readonly decay: RankDecayDefinition | null;
81
+ readonly softReset: RankResetDefinition | null;
82
+ }
83
+
84
+ export declare interface RankLadderDefinition {
85
+ readonly id?: string;
86
+ readonly version?: number;
87
+ readonly rating: string;
88
+ readonly tiers: readonly string[];
89
+ readonly divisions?: number;
90
+ /** Ascending cutoffs for each boundary, lowest division to highest. No hidden balancing values. */
91
+ readonly thresholds: readonly number[];
92
+ readonly placements?: number;
93
+ readonly confidence?: number;
94
+ readonly decay?: RankDecayDefinition | null;
95
+ readonly softReset?: RankResetDefinition | null;
96
+ }
97
+
98
+ export declare interface RankRating {
99
+ readonly pool: string;
100
+ readonly state: RankRatingState;
101
+ readonly games: number;
102
+ readonly updatedAt: number | null;
103
+ }
104
+
105
+ export declare class RankRatingSource extends RankRatingSource_base {
106
+ }
107
+
108
+ declare const RankRatingSource_base: Context.ServiceClass<RankRatingSource, "@voltro/RankRatingSource", RankRatingSourceService>;
109
+
110
+ export declare interface RankRatingSourceService {
111
+ readonly read: (subject: Subject, pool: string) => Effect.Effect<RankRating, ProgressionError>;
112
+ }
113
+
114
+ /** SQL Ratings remain the authority; this detached shape matches Ratings.myRating. */
115
+ export declare type RankRatingState = {
116
+ readonly algorithm: 'elo';
117
+ readonly rating: number;
118
+ } | {
119
+ readonly algorithm: 'openskill';
120
+ readonly mu: number;
121
+ readonly sigma: number;
122
+ } | {
123
+ readonly algorithm: 'glicko2';
124
+ readonly rating: number;
125
+ readonly deviation: number;
126
+ readonly volatility: number;
127
+ };
128
+
129
+ export declare interface RankReaderService {
130
+ readonly mine: (subject: Subject) => Effect.Effect<readonly PlayerRank[], ProgressionError>;
131
+ }
132
+
133
+ export declare interface RankResetContext {
134
+ readonly ladder: RankLadder;
135
+ readonly score: number;
136
+ }
137
+
138
+ export declare interface RankResetDefinition {
139
+ readonly target: number;
140
+ readonly retain: number;
141
+ }
142
+
143
+ export declare type RankScoreResolver = (input: RankContext) => number;
144
+
145
+ export declare type RankSeasonReset = (input: RankResetContext) => number;
146
+
147
+ export declare interface RankStrategies {
148
+ readonly version?: string;
149
+ readonly score?: RankScoreResolver;
150
+ readonly decay?: RankDecayResolver;
151
+ readonly grade?: RankGradeResolver;
152
+ readonly seasonReset?: RankSeasonReset;
153
+ }
154
+
155
+ export declare const resolveRank: (input: RankContext, strategies?: RankStrategies) => PlayerRank;
156
+
157
+ export declare const resolveRankSeasonReset: (ladderInput: RankLadder, value: number, strategies?: RankStrategies) => number;
158
+
159
+ export declare const resolveRankStrategies: (input?: RankStrategies) => Readonly<{
160
+ version: string;
161
+ score: RankScoreResolver;
162
+ decay: RankDecayResolver;
163
+ grade: RankGradeResolver;
164
+ seasonReset: RankSeasonReset;
165
+ }>;
166
+
167
+ export { }
package/dist/ranks.js ADDED
@@ -0,0 +1,218 @@
1
+ import { progressionError as e } from "./errors.js";
2
+ import { identifier as t, integer as n, list as r, object as i } from "./capture.js";
3
+ import { Context as a } from "effect";
4
+ // src/ranks.ts
5
+ var o = (t, n = -1e9, r = 1e9) => {
6
+ if (typeof t != "number" || !Number.isFinite(t) || Object.is(t, -0) || t < n || t > r) throw e("invalid_input");
7
+ return t;
8
+ }, s = (r, a) => {
9
+ let s = i(r, [
10
+ "pool",
11
+ "state",
12
+ "games",
13
+ "updatedAt"
14
+ ]), c = i(s.state).algorithm;
15
+ if (s.pool !== a || c !== "elo" && c !== "openskill" && c !== "glicko2") throw e("invalid_record");
16
+ let l;
17
+ if (c === "elo") {
18
+ let e = i(s.state, ["algorithm", "rating"]);
19
+ l = Object.freeze({
20
+ algorithm: c,
21
+ rating: o(e.rating)
22
+ });
23
+ } else if (c === "openskill") {
24
+ let e = i(s.state, [
25
+ "algorithm",
26
+ "mu",
27
+ "sigma"
28
+ ]);
29
+ l = Object.freeze({
30
+ algorithm: c,
31
+ mu: o(e.mu),
32
+ sigma: o(e.sigma, 1e-12)
33
+ });
34
+ } else {
35
+ let e = i(s.state, [
36
+ "algorithm",
37
+ "rating",
38
+ "deviation",
39
+ "volatility"
40
+ ]);
41
+ l = Object.freeze({
42
+ algorithm: "glicko2",
43
+ rating: o(e.rating),
44
+ deviation: o(e.deviation, 1e-12),
45
+ volatility: o(e.volatility, 1e-12)
46
+ });
47
+ }
48
+ let u = n(s.games, 0, 2147483647), d = s.updatedAt === null ? null : n(s.updatedAt, 0, 864e13);
49
+ if (u > 0 && d === null) throw e("invalid_record");
50
+ return Object.freeze({
51
+ pool: t(s.pool),
52
+ state: l,
53
+ games: u,
54
+ updatedAt: d
55
+ });
56
+ }, c = (t) => {
57
+ if (typeof t != "string" || t.length < 1 || t.length > 120 || t.trim() !== t || /[\u0000-\u001f\u007f]/u.test(t)) throw e("invalid_input");
58
+ return t;
59
+ }, l = (a) => {
60
+ let s = i(a, [
61
+ "id",
62
+ "version",
63
+ "rating",
64
+ "tiers",
65
+ "divisions",
66
+ "thresholds",
67
+ "placements",
68
+ "confidence",
69
+ "decay",
70
+ "softReset"
71
+ ]), l = Object.freeze(r(s.tiers, 64).map(c)), u = n(s.divisions ?? 1, 1, 16), d = Object.freeze(r(s.thresholds, 1023).map((e) => o(e)));
72
+ if (!l.length || new Set(l).size !== l.length || d.length !== l.length * u - 1 || d.some((e, t) => t > 0 && e <= d[t - 1])) throw e("invalid_input");
73
+ let f = s.decay == null ? null : i(s.decay, [
74
+ "afterDays",
75
+ "perDay",
76
+ "floor"
77
+ ]), p = s.softReset == null ? null : i(s.softReset, ["target", "retain"]), m = f === null ? null : Object.freeze({
78
+ afterDays: n(f.afterDays, 0, 365e3),
79
+ perDay: o(f.perDay, Number.MIN_VALUE),
80
+ floor: o(f.floor)
81
+ }), h = p === null ? null : Object.freeze({
82
+ target: o(p.target),
83
+ retain: o(p.retain, 0, 1)
84
+ });
85
+ return Object.freeze({
86
+ id: t(s.id ?? "rank"),
87
+ version: n(s.version ?? 1, 1, 1e6),
88
+ rating: t(s.rating),
89
+ tiers: l,
90
+ divisions: u,
91
+ thresholds: d,
92
+ placements: n(s.placements ?? 10, 0, 2147483647),
93
+ confidence: o(s.confidence ?? 3, 0, 10),
94
+ decay: m,
95
+ softReset: h
96
+ });
97
+ }, u = ({ ladder: e, rating: t }) => t.state.algorithm === "openskill" ? Math.max(-1e9, Math.min(1e9, t.state.mu - e.confidence * t.state.sigma)) : t.state.rating, d = ({ ladder: e, rating: t, at: n, score: r }) => {
98
+ if (!e.decay || t.updatedAt === null) return r;
99
+ let i = Math.max(0, Math.floor((n - t.updatedAt) / 864e5) - e.decay.afterDays);
100
+ return Math.min(r, Math.max(e.decay.floor, r - i * e.decay.perDay));
101
+ }, f = (e, t) => Object.freeze({
102
+ index: t,
103
+ tierIndex: Math.floor(t / e.divisions),
104
+ tier: e.tiers[Math.floor(t / e.divisions)],
105
+ division: e.divisions - t % e.divisions
106
+ }), p = ({ ladder: e, rating: t, score: n }) => {
107
+ if (t.games < e.placements) return null;
108
+ let r = 0, i = e.thresholds.length;
109
+ for (; r < i;) {
110
+ let t = Math.floor((r + i) / 2);
111
+ n >= e.thresholds[t] ? r = t + 1 : i = t;
112
+ }
113
+ return f(e, r);
114
+ }, m = ({ ladder: e, score: t }) => e.softReset ? e.softReset.target + (t - e.softReset.target) * e.softReset.retain : t, h = (n = {}) => {
115
+ let r = i(n, [
116
+ "version",
117
+ "score",
118
+ "decay",
119
+ "grade",
120
+ "seasonReset"
121
+ ]), a = r.score ?? u, o = r.decay ?? d, s = r.grade ?? p, c = r.seasonReset ?? m;
122
+ if ([
123
+ a,
124
+ o,
125
+ s,
126
+ c
127
+ ].some((e) => typeof e != "function") || (a !== u || o !== d || s !== p || c !== m) && (r.version === void 0 || r.version === "default.v1")) throw e("invalid_input");
128
+ return Object.freeze({
129
+ version: t(r.version ?? "default.v1"),
130
+ score: a,
131
+ decay: o,
132
+ grade: s,
133
+ seasonReset: c
134
+ });
135
+ }, g = (t, r = {}) => {
136
+ let a = l(t.ladder), c = s(t.rating, a.rating), u = n(t.at, c.updatedAt ?? 0, 864e13), d = h(r), p = Object.freeze({
137
+ ladder: a,
138
+ rating: c,
139
+ at: u
140
+ }), m = o(d.score(p)), g = o(d.decay(Object.freeze({
141
+ ...p,
142
+ score: m
143
+ })));
144
+ if (g > m) throw e("invalid_input");
145
+ let _ = d.grade(Object.freeze({
146
+ ...p,
147
+ score: g
148
+ })), v = Math.max(0, a.placements - c.games), y = null;
149
+ if (_ !== null) {
150
+ let t = i(_, [
151
+ "index",
152
+ "tier",
153
+ "tierIndex",
154
+ "division"
155
+ ]), r = f(a, n(t.index, 0, a.tiers.length * a.divisions - 1));
156
+ if (v > 0 || t.tier !== r.tier || t.tierIndex !== r.tierIndex || t.division !== r.division) throw e("invalid_input");
157
+ y = r;
158
+ } else if (v === 0) throw e("invalid_input");
159
+ return Object.freeze({
160
+ ladderId: a.id,
161
+ version: a.version,
162
+ pool: a.rating,
163
+ games: c.games,
164
+ placementsRemaining: v,
165
+ rawScore: m,
166
+ score: g,
167
+ grade: y,
168
+ ratingUpdatedAt: c.updatedAt,
169
+ observedAt: u,
170
+ rulesVersion: d.version
171
+ });
172
+ }, _ = (e, t, n = {}) => {
173
+ let r = l(e);
174
+ return o(h(n).seasonReset(Object.freeze({
175
+ ladder: r,
176
+ score: o(t)
177
+ })));
178
+ }, v = class extends a.Service()("@voltro/RankRatingSource") {}, y = (t, r, a) => {
179
+ let s = i(t, [
180
+ "ladderId",
181
+ "version",
182
+ "pool",
183
+ "games",
184
+ "placementsRemaining",
185
+ "rawScore",
186
+ "score",
187
+ "grade",
188
+ "ratingUpdatedAt",
189
+ "observedAt",
190
+ "rulesVersion"
191
+ ]), c = n(s.games, 0, 2147483647), l = Math.max(0, r.placements - c), u = o(s.rawScore), d = o(s.score), p = s.ratingUpdatedAt === null ? null : n(s.ratingUpdatedAt, 0, 864e13), m = n(s.observedAt, p ?? 0, 864e13);
192
+ if (s.ladderId !== r.id || s.version !== r.version || s.pool !== r.rating || s.rulesVersion !== a || s.placementsRemaining !== l || d > u || c > 0 && p === null) throw e("invalid_record");
193
+ let h = null;
194
+ if (s.grade !== null) {
195
+ let t = i(s.grade, [
196
+ "index",
197
+ "tier",
198
+ "tierIndex",
199
+ "division"
200
+ ]), a = f(r, n(t.index, 0, r.tiers.length * r.divisions - 1));
201
+ if (l > 0 || t.tier !== a.tier || t.tierIndex !== a.tierIndex || t.division !== a.division) throw e("invalid_record");
202
+ h = a;
203
+ } else if (l === 0) throw e("invalid_record");
204
+ return Object.freeze({
205
+ ladderId: r.id,
206
+ version: r.version,
207
+ pool: r.rating,
208
+ games: c,
209
+ placementsRemaining: l,
210
+ rawScore: u,
211
+ score: d,
212
+ grade: h,
213
+ ratingUpdatedAt: p,
214
+ observedAt: m,
215
+ rulesVersion: a
216
+ });
217
+ };
218
+ export { v as RankRatingSource, y as capturePlayerRank, s as captureRankRating, d as defaultRankDecay, p as defaultRankGrade, u as defaultRankScore, m as defaultRankSeasonReset, l as defineRankLadder, g as resolveRank, _ as resolveRankSeasonReset, h as resolveRankStrategies };