@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,705 @@
1
+ import { ProgressionError as e, progressionError as t } from "./errors.js";
2
+ import { captureArguments as n, identifier as r, integer as i, list as a, object as o, progressValue as s } from "./capture.js";
3
+ import { captureRewards as c } from "./reward.js";
4
+ import { defaultXpCurve as l, resolveXpCurve as u } from "./curve.js";
5
+ import { ProgressionReceiptSchema as d } from "./rpc.js";
6
+ import { admitRewardDeliveryRecord as f } from "./rewardDeliveryRecord.js";
7
+ import { STAT_OPERATORS as p, applyStatValue as m, defineStat as h } from "./stats.js";
8
+ import { defaultRewardResolver as g, defineProgression as _, resolveRewards as v } from "./track.js";
9
+ import { progressionDefinitionsTable as y, progressionOperationsTable as b, progressionOriginsTable as x, progressionRewardsTable as S, progressionStatLedgerTable as C, progressionStatsTable as w, progressionSubjectsTable as T, progressionTracksTable as E, progressionXpLedgerTable as D } from "./tables.entity.js";
10
+ import { Effect as O, Schema as k } from "effect";
11
+ import { createHash as A } from "node:crypto";
12
+ import { and as j, eq as M, queryFor as N } from "@voltro/database";
13
+ // src/progressionStore.ts
14
+ var P = (e) => {
15
+ let n = o(e, [
16
+ "tracks",
17
+ "stats",
18
+ "statSources",
19
+ "allowedServices",
20
+ "maxHistoryRows",
21
+ "maxPendingRewards",
22
+ "now",
23
+ "strategies"
24
+ ]), s = Object.freeze(a(n.tracks, 128).map((e) => _(e))), c = Object.freeze(a(n.stats ?? [], 256).map((e) => h(e))), u = Object.freeze(a(n.statSources ?? [], 64).map(r)), d = Object.freeze(a(n.allowedServices ?? [], 256).map(r));
25
+ if (new Set(s.map((e) => e.id)).size !== s.length || new Set(c.map((e) => e.id)).size !== c.length || new Set(u).size !== u.length || new Set(d).size !== d.length || c.length > 0 && u.length === 0) throw t("invalid_input");
26
+ let f = o(n.strategies ?? {}, [
27
+ "xpCurve",
28
+ "rewardResolver",
29
+ "version"
30
+ ]), p = f.xpCurve ?? l, m = f.rewardResolver ?? g, v = n.now ?? Date.now;
31
+ if (typeof p != "function" || typeof m != "function" || typeof v != "function" || (p !== l || m !== g) && f.version === void 0) throw t("invalid_input");
32
+ return Object.freeze({
33
+ tracks: s,
34
+ stats: c,
35
+ statSources: u,
36
+ allowedServices: d,
37
+ maxHistoryRows: i(n.maxHistoryRows ?? 1e4, 1, 1e5),
38
+ maxPendingRewards: i(n.maxPendingRewards ?? 4096, 1, 1e4),
39
+ now: v,
40
+ strategies: Object.freeze({
41
+ xpCurve: p,
42
+ rewardResolver: m,
43
+ version: r(f.version ?? "default.v1")
44
+ })
45
+ });
46
+ }, F = (e) => {
47
+ if (e === null || typeof e == "boolean" || typeof e == "string" || typeof e == "number" && Number.isFinite(e)) return e;
48
+ if (Array.isArray(e)) return a(e, 1e5).map(F);
49
+ let t = o(e);
50
+ return Object.fromEntries(Object.keys(t).sort().map((e) => [e, F(t[e])]));
51
+ }, I = (e) => A("sha256").update(JSON.stringify(F(e))).digest("hex"), L = (e, ...t) => e + I(t).slice(0, 56), R = (n) => O.tryPromise({
52
+ try: n,
53
+ catch: (n) => n instanceof e ? n : t("unavailable")
54
+ }), z = (e) => {
55
+ let n = e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : NaN;
56
+ if (!Number.isSafeInteger(n) || n < 0 || n > 864e13) throw t("invalid_record");
57
+ return n;
58
+ }, B = (a, l) => {
59
+ let h = P(l), g = new Set(h.allowedServices), _ = new Map(h.tracks.map((e) => [e.id, e])), A = new Map(h.stats.map((e) => [e.id, e])), F = (e) => e.type === "system" || e.type === "service" && g.has(e.service), B = (e) => {
60
+ if (e.type !== "user") throw t("forbidden");
61
+ return {
62
+ tenantId: r(e.tenantId),
63
+ ownerId: r(e.id)
64
+ };
65
+ }, V = () => i(h.now(), 0, 864e13), H = (e, t) => L("pgs_", e, t), U = (e, n, r, i = !1) => {
66
+ if (e) {
67
+ if (e.tenantId !== n) throw t("invalid_record");
68
+ if (e.erased === !0) {
69
+ if (i && e.ownerId === null) return;
70
+ throw t("erased");
71
+ }
72
+ if (e.erased !== !1 || e.ownerId !== r) throw t("invalid_record");
73
+ }
74
+ }, W = async (e, t) => {
75
+ try {
76
+ await a.insertIgnore(e, t, { conflictColumns: ["id"] });
77
+ } catch (n) {
78
+ if (!(await a.query({
79
+ table: e,
80
+ predicate: M("id", t.id),
81
+ order: [],
82
+ take: 1,
83
+ skip: void 0,
84
+ projection: void 0
85
+ }))[0]) throw n;
86
+ }
87
+ }, G = (e, t) => W(T.tableName, {
88
+ id: H(e, t),
89
+ tenantId: e,
90
+ ownerId: t,
91
+ erased: !1,
92
+ sequence: 0,
93
+ admission: 0
94
+ }), ee = async (e, n, r, i = !1) => {
95
+ let a = H(n, r);
96
+ if (await e.updateMany(T.tableName, { admission: 0 }, { where: M("id", a) }) !== 1) throw t("unavailable");
97
+ let o = (await e.query(N(T).where(M("id", a)).limit(1).descriptor))[0];
98
+ if (!o) throw t("invalid_record");
99
+ return U(o, n, r, i), o;
100
+ }, K = (e, t) => j(M("tenantId", e), M("ownerId", t)), q = async (e, n, r, i, a = h.maxHistoryRows) => {
101
+ let o = await e.query(N(n).where(K(r, i)).orderBy("id", "asc").limit(a + 1).descriptor);
102
+ if (o.length > a) throw t("limit_exceeded");
103
+ if (o.some((e) => e.tenantId !== r || e.ownerId !== i)) throw t("invalid_record");
104
+ return o;
105
+ }, J = (e) => {
106
+ let n = k.decodeUnknownSync(d, { onExcessProperty: "error" })(e.receipt);
107
+ if (n.operationId !== e.id || z(e.createdAt) > n.at || n.at > 864e13 || !Number.isSafeInteger(n.at)) throw t("invalid_record");
108
+ i(n.rewardsQueued, 0, 256);
109
+ let a = n.change;
110
+ if (a.kind === "xp") {
111
+ if (r(a.trackId), s(a.xp), s(a.delta) === 0n) throw t("invalid_record");
112
+ i(a.fromLevel, 1, 1e4), i(a.toLevel, a.fromLevel, 1e4);
113
+ } else if (r(a.stat), s(a.value), a.period === "season") r(a.seasonId);
114
+ else if (a.seasonId !== null) throw t("invalid_record");
115
+ return Object.freeze({
116
+ ...n,
117
+ change: Object.freeze({ ...a })
118
+ });
119
+ }, te = (e, t) => e === "xp" ? {
120
+ track: _.get(t),
121
+ rules: h.strategies.version
122
+ } : {
123
+ stat: A.get(t),
124
+ sources: h.statSources
125
+ }, Y = (e, n) => {
126
+ let { tenantId: o, ownerId: c, requestId: l, kind: d, id: f, source: p, origin: g, payload: O } = n, k = H(o, c), P = L("pgo_", o, c, l), F = I({
127
+ tenantId: o,
128
+ ownerId: c,
129
+ kind: d,
130
+ id: f,
131
+ source: p,
132
+ origin: g,
133
+ payload: O
134
+ }), B = L("pgn_", o, c, d, f, p, g), U = te(d, f), K = L("pgd_", o, d, f);
135
+ return R(async () => {
136
+ let n = V();
137
+ return await G(o, c), await W(y.tableName, {
138
+ id: K,
139
+ tenantId: o,
140
+ kind: d === "xp" ? "track" : "stat",
141
+ definitionId: f,
142
+ config: U,
143
+ admission: 0
144
+ }), a.transactional(async (a) => {
145
+ let l = await ee(a, o, c);
146
+ if (!(await a.query(N(b).where(M("id", P)).limit(1).descriptor))[0]) {
147
+ if ((await a.query(N(b).where(j(M("tenantId", o), M("ownerKey", k))).limit(h.maxHistoryRows + 1).descriptor)).length >= h.maxHistoryRows) throw t("limit_exceeded");
148
+ await a.insert(b.tableName, {
149
+ id: P,
150
+ tenantId: o,
151
+ ownerKey: k,
152
+ state: "pending",
153
+ sequence: null,
154
+ linkedOperationId: null,
155
+ digest: null,
156
+ receipt: null,
157
+ createdAt: new Date(n),
158
+ admission: 0
159
+ });
160
+ }
161
+ if (await a.updateMany(b.tableName, { admission: 0 }, { where: M("id", P) }) !== 1) throw t("unavailable");
162
+ let R = (await a.query(N(b).where(M("id", P)).limit(1).descriptor))[0];
163
+ if (!R || R.tenantId !== o || R.ownerKey !== k) throw t("invalid_record");
164
+ if (R.state === "committed" || R.state === "replayed") {
165
+ if (R.digest !== F) throw t("conflict");
166
+ if (R.state === "committed") return J(R);
167
+ let e = (await a.query(N(b).where(M("id", r(R.linkedOperationId))).limit(1).descriptor))[0];
168
+ if (!e || e.tenantId !== o || e.ownerKey !== k || e.state !== "committed" || e.digest !== F) throw t("invalid_record");
169
+ return J(e);
170
+ }
171
+ if (R.state !== "pending" || R.sequence !== null || R.linkedOperationId !== null || R.digest !== null || R.receipt !== null || z(R.createdAt) > n) throw t("invalid_record");
172
+ if ((await a.query(N(b).where(j(M("tenantId", o), M("ownerKey", k))).limit(h.maxHistoryRows + 1).descriptor)).length > h.maxHistoryRows) throw t("limit_exceeded");
173
+ let V = (await a.query(N(x).where(M("id", B)).limit(1).descriptor))[0];
174
+ if (V) {
175
+ if (V.tenantId !== o || V.ownerKey !== k || V.source !== p || V.origin !== g || V.digest !== F) throw t("conflict");
176
+ let e = (await a.query(N(b).where(M("id", r(V.operationId))).limit(1).descriptor))[0];
177
+ if (!e || e.tenantId !== o || e.ownerKey !== k || e.state !== "committed" || e.digest !== F) throw t("invalid_record");
178
+ let n = J(e);
179
+ return await a.update(b.tableName, P, {
180
+ state: "replayed",
181
+ linkedOperationId: e.id,
182
+ digest: F
183
+ }), n;
184
+ }
185
+ if (await a.updateMany(y.tableName, { admission: 0 }, { where: M("id", K) }) !== 1) throw t("unavailable");
186
+ let H = (await a.query(N(y).where(M("id", K)).limit(1).descriptor))[0];
187
+ if (!H || H.tenantId !== o || H.definitionId !== f || H.kind !== (d === "xp" ? "track" : "stat") || I(H.config) !== I(U)) throw t("conflict");
188
+ let W = i(l.sequence, 0, 2147483646) + 1, G;
189
+ if (d === "xp") {
190
+ let i = _.get(f);
191
+ if (!i) throw t("invalid_track");
192
+ let l = L("pgt_", o, c, f), d = (await a.query(N(E).where(M("id", l)).limit(1).descriptor))[0];
193
+ if (d && (d.tenantId !== o || d.ownerId !== c || d.trackId !== f || d.version !== i.version || z(d.updatedAt) > n || d.prestige !== 0)) throw t("invalid_record");
194
+ let m = String(s(d?.xp ?? "0")), y = u(m, i.xpCurve, h.strategies.xpCurve);
195
+ if (d && d.level !== y) throw t("conflict");
196
+ let b = s(O.amount), x = String(s(BigInt(m) + b)), C = u(x, i.xpCurve, h.strategies.xpCurve);
197
+ if (C < y) throw t("conflict");
198
+ let w = v({
199
+ track: i,
200
+ fromLevel: y,
201
+ toLevel: C
202
+ }, h.strategies.rewardResolver), T = await a.query(N(S).where(j(M("tenantId", o), M("ownerKey", k))).limit(h.maxHistoryRows + 1).descriptor);
203
+ if (T.length + w.length > h.maxHistoryRows || T.filter((e) => e.state === "pending").length + w.length > h.maxPendingRewards || (await q(a, D, o, c)).length >= h.maxHistoryRows) throw t("limit_exceeded");
204
+ d ? await a.update(E.tableName, l, {
205
+ xp: x,
206
+ level: C,
207
+ updatedAt: new Date(n)
208
+ }) : await a.insert(E.tableName, {
209
+ id: l,
210
+ tenantId: o,
211
+ ownerId: c,
212
+ trackId: f,
213
+ version: i.version,
214
+ xp: x,
215
+ level: C,
216
+ prestige: 0,
217
+ updatedAt: new Date(n),
218
+ metadata: {}
219
+ }), await a.insert(D.tableName, {
220
+ id: L("pgx_", P),
221
+ tenantId: o,
222
+ ownerId: c,
223
+ ownerKey: k,
224
+ operationId: P,
225
+ sequence: W,
226
+ trackId: f,
227
+ delta: String(b),
228
+ afterXp: x,
229
+ fromLevel: y,
230
+ toLevel: C,
231
+ source: p,
232
+ origin: g,
233
+ actor: r(e.id),
234
+ at: new Date(n)
235
+ });
236
+ for (let [e, t] of w.entries()) await a.insert(S.tableName, {
237
+ id: L("pgr_", P, String(e)),
238
+ tenantId: o,
239
+ ownerId: c,
240
+ ownerKey: k,
241
+ operationId: P,
242
+ level: t.level,
243
+ reward: t.reward,
244
+ state: "pending",
245
+ createdAt: new Date(n),
246
+ deliveredAt: null,
247
+ deliveryIntent: null,
248
+ deliveryDigest: null,
249
+ deliveryReceipt: null
250
+ });
251
+ G = Object.freeze({
252
+ operationId: P,
253
+ at: n,
254
+ change: Object.freeze({
255
+ kind: "xp",
256
+ trackId: f,
257
+ xp: x,
258
+ delta: String(b),
259
+ fromLevel: y,
260
+ toLevel: C
261
+ }),
262
+ rewardsQueued: w.length
263
+ });
264
+ } else {
265
+ let i = A.get(f);
266
+ if (!i) throw t("invalid_stat");
267
+ let l = O.period, u = O.seasonId, d = O.operator, _ = O.operand, v = L("pgv_", o, c, f, l, u ?? ""), y = (await a.query(N(w).where(M("id", v)).limit(1).descriptor))[0];
268
+ if (y && (y.tenantId !== o || y.ownerId !== c || y.stat !== f || y.period !== l || y.seasonId !== u || z(y.updatedAt) > n)) throw t("invalid_record");
269
+ let b = y ? String(s(y.value)) : null, x = m(b, _, d, i);
270
+ if ((await q(a, C, o, c)).length >= h.maxHistoryRows) throw t("limit_exceeded");
271
+ y ? await a.update(w.tableName, v, {
272
+ value: x,
273
+ updatedAt: new Date(n)
274
+ }) : await a.insert(w.tableName, {
275
+ id: v,
276
+ tenantId: o,
277
+ ownerId: c,
278
+ stat: f,
279
+ period: l,
280
+ seasonId: u,
281
+ value: x,
282
+ updatedAt: new Date(n)
283
+ }), await a.insert(C.tableName, {
284
+ id: L("pgl_", P),
285
+ tenantId: o,
286
+ ownerId: c,
287
+ ownerKey: k,
288
+ operationId: P,
289
+ sequence: W,
290
+ stat: f,
291
+ period: l,
292
+ seasonId: u,
293
+ operator: d,
294
+ operand: _,
295
+ beforeValue: b,
296
+ afterValue: x,
297
+ source: p,
298
+ origin: g,
299
+ actor: r(e.id),
300
+ at: new Date(n)
301
+ }), G = Object.freeze({
302
+ operationId: P,
303
+ at: n,
304
+ change: Object.freeze({
305
+ kind: "stat",
306
+ stat: f,
307
+ period: l,
308
+ seasonId: u,
309
+ value: x,
310
+ operator: d
311
+ }),
312
+ rewardsQueued: 0
313
+ });
314
+ }
315
+ return await a.insert(x.tableName, {
316
+ id: B,
317
+ tenantId: o,
318
+ ownerKey: k,
319
+ operationId: P,
320
+ source: p,
321
+ origin: g,
322
+ digest: F
323
+ }), await a.update(b.tableName, P, {
324
+ state: "committed",
325
+ sequence: W,
326
+ digest: F,
327
+ receipt: G
328
+ }), await a.update(T.tableName, k, { sequence: W }), G;
329
+ });
330
+ });
331
+ }, X = (n) => {
332
+ try {
333
+ return n();
334
+ } catch (n) {
335
+ return O.fail(n instanceof e ? n : t("invalid_input"));
336
+ }
337
+ }, ne = (e, n) => X(() => {
338
+ let i = structuredClone(e), a = o(n, [
339
+ "tenantId",
340
+ "ownerId",
341
+ "trackId",
342
+ "amount",
343
+ "requestId",
344
+ "source",
345
+ "origin"
346
+ ]);
347
+ if (!F(i)) throw t("forbidden");
348
+ let c = r(a.trackId), l = _.get(c), u = r(a.source), d = s(a.amount);
349
+ if (!l || !l.sources.includes(u)) throw t("invalid_track");
350
+ if (d === 0n) throw t("invalid_input");
351
+ return Y(i, {
352
+ tenantId: r(a.tenantId),
353
+ ownerId: r(a.ownerId),
354
+ requestId: r(a.requestId),
355
+ kind: "xp",
356
+ id: c,
357
+ source: u,
358
+ origin: r(a.origin),
359
+ payload: Object.freeze({ amount: String(d) })
360
+ });
361
+ }), re = (e, n) => X(() => {
362
+ let i = structuredClone(e), a = o(n, [
363
+ "tenantId",
364
+ "ownerId",
365
+ "stat",
366
+ "period",
367
+ "seasonId",
368
+ "operator",
369
+ "operand",
370
+ "requestId",
371
+ "source",
372
+ "origin"
373
+ ]);
374
+ if (!F(i)) throw t("forbidden");
375
+ let c = r(a.stat), l = r(a.source);
376
+ if (!A.has(c) || !h.statSources.includes(l) || !p.some((e) => e === a.operator)) throw t("invalid_stat");
377
+ if (a.period !== "lifetime" && a.period !== "season") throw t("invalid_input");
378
+ let u = a.period === "season" ? r(a.seasonId) : null;
379
+ if (a.period === "lifetime" && a.seasonId !== void 0 && a.seasonId !== null) throw t("invalid_input");
380
+ return Y(i, {
381
+ tenantId: r(a.tenantId),
382
+ ownerId: r(a.ownerId),
383
+ requestId: r(a.requestId),
384
+ kind: "stat",
385
+ id: c,
386
+ source: l,
387
+ origin: r(a.origin),
388
+ payload: Object.freeze({
389
+ period: a.period,
390
+ seasonId: u,
391
+ operator: a.operator,
392
+ operand: String(s(a.operand))
393
+ })
394
+ });
395
+ }), ie = (e, n) => {
396
+ if (e.trackId !== n.id || e.version !== n.version || e.prestige !== 0) throw t("conflict");
397
+ let r = String(s(e.xp)), i = u(r, n.xpCurve, h.strategies.xpCurve);
398
+ if (e.level !== i) throw t("invalid_record");
399
+ return Object.freeze({
400
+ trackId: n.id,
401
+ xp: r,
402
+ level: i,
403
+ prestige: 0,
404
+ updatedAt: z(e.updatedAt)
405
+ });
406
+ }, ae = (e, n) => {
407
+ if (e.stat !== n.id || e.period !== "lifetime" && e.period !== "season" || e.period === "lifetime" && e.seasonId !== null) throw t("invalid_record");
408
+ let i = String(s(e.value));
409
+ if (BigInt(i) > BigInt(n.cap)) throw t("conflict");
410
+ return Object.freeze({
411
+ stat: n.id,
412
+ period: e.period,
413
+ seasonId: e.period === "season" ? r(e.seasonId) : null,
414
+ value: i,
415
+ updatedAt: z(e.updatedAt)
416
+ });
417
+ }, Z = (e) => X(() => {
418
+ let n = structuredClone(e), { tenantId: i, ownerId: o } = B(n);
419
+ return R(async () => {
420
+ U((await a.query(N(T).where(M("id", H(i, o))).limit(1).descriptor))[0], i, o);
421
+ let e = await q(a, E, i, o, 128);
422
+ if (new Set(e.map((e) => e.trackId)).size !== e.length || e.some((e) => !_.has(String(e.trackId)) || e.id !== L("pgt_", i, o, r(e.trackId)))) throw t("invalid_track");
423
+ return Object.freeze(h.tracks.map((t) => {
424
+ let n = e.find((e) => e.trackId === t.id);
425
+ return n ? ie(n, t) : Object.freeze({
426
+ trackId: t.id,
427
+ xp: "0",
428
+ level: u("0", t.xpCurve, h.strategies.xpCurve),
429
+ prestige: 0,
430
+ updatedAt: null
431
+ });
432
+ }));
433
+ });
434
+ }), Q = (e) => X(() => {
435
+ let n = structuredClone(e), { tenantId: r, ownerId: i } = B(n);
436
+ return R(async () => {
437
+ U((await a.query(N(T).where(M("id", H(r, i))).limit(1).descriptor))[0], r, i);
438
+ let e = /* @__PURE__ */ new Set();
439
+ return Object.freeze((await q(a, w, r, i)).map((n) => {
440
+ let a = A.get(String(n.stat));
441
+ if (!a) throw t("invalid_stat");
442
+ let o = ae(n, a), s = L("pgv_", r, i, o.stat, o.period, o.seasonId ?? "");
443
+ if (n.id !== s || e.has(s)) throw t("invalid_record");
444
+ return e.add(s), o;
445
+ }));
446
+ });
447
+ }), $ = (e, o, l, d, g) => X(() => {
448
+ let v = n(e), O = r(o), k = r(l), P = H(O, k);
449
+ if (g !== void 0 && i(g, 1, 1e5), !F(v)) throw t("forbidden");
450
+ return R(async () => (g === void 0 && await G(O, k), a.transactional(async (e) => {
451
+ let n = g === void 0 ? await ee(e, O, k) : (await e.query(N(T).where(M("id", P)).forUpdate().limit(1).descriptor))[0];
452
+ U(n, O, k);
453
+ let a = async (n) => {
454
+ let r = await e.query(N(n).where(j(M("tenantId", O), M("ownerKey", P))).limit(h.maxHistoryRows + 1).descriptor);
455
+ if (r.length > h.maxHistoryRows) throw t("limit_exceeded");
456
+ if (r.some((e) => e.tenantId !== O || e.ownerKey !== P)) throw t("invalid_record");
457
+ return r;
458
+ }, o = await a(b), l = await a(x), v = await a(S), F = o.filter((e) => e.state === "committed").sort((e, t) => Number(e.sequence) - Number(t.sequence));
459
+ if (F.length !== i(n?.sequence ?? 0, 0, 2147483647)) throw t("invalid_record");
460
+ let R = new Map(o.map((e) => [e.id, e])), B = new Map(l.map((e) => [e.operationId, e]));
461
+ if (R.size !== o.length || B.size !== l.length || l.length !== F.length) throw t("invalid_record");
462
+ for (let e of o) if (e.state === "pending") {
463
+ if (e.sequence !== null || e.linkedOperationId !== null || e.digest !== null || e.receipt !== null) throw t("invalid_record");
464
+ } else if (e.state === "replayed") {
465
+ let n = R.get(r(e.linkedOperationId));
466
+ if (e.sequence !== null || e.receipt !== null || !n || n.state !== "committed" || e.digest !== n.digest) throw t("invalid_record");
467
+ } else if (e.state !== "committed") throw t("invalid_record");
468
+ let V = await q(e, D, O, k), H = await q(e, C, O, k), W = /* @__PURE__ */ new Map();
469
+ for (let [e, n] of [["xp", V], ["stat", H]]) for (let i of n) {
470
+ let n = r(i.operationId);
471
+ if (W.has(n) || R.get(n)?.state !== "committed") throw t("invalid_record");
472
+ W.set(n, {
473
+ kind: e,
474
+ row: i
475
+ });
476
+ }
477
+ if (W.size !== F.length) throw t("invalid_record");
478
+ let G = /* @__PURE__ */ new Map();
479
+ for (let e of v) {
480
+ let n = r(e.operationId), i = r(e.id), a = G.get(n) ?? /* @__PURE__ */ new Map();
481
+ if (a.has(i) || R.get(n)?.state !== "committed" || e.ownerId !== k) throw t("invalid_record");
482
+ a.set(i, e), G.set(n, a);
483
+ }
484
+ let Y = /* @__PURE__ */ new Map(), X = /* @__PURE__ */ new Map(), ne = /* @__PURE__ */ new Set(), re = [];
485
+ for (let [n, a] of F.entries()) {
486
+ if (a.sequence !== n + 1 || a.linkedOperationId !== null || typeof a.digest != "string" || !/^[0-9a-f]{64}$/.test(a.digest)) throw t("invalid_record");
487
+ let o = J(a), l = W.get(r(a.id)), d = B.get(a.id);
488
+ if (!l || !d) throw t("invalid_record");
489
+ let { kind: g, row: v } = l, b = o.change, x = r(v.source), S = r(v.origin);
490
+ if (r(v.actor), b.kind !== g || v.sequence !== a.sequence || v.ownerKey !== P || z(v.at) !== o.at || v.id !== L(g === "xp" ? "pgx_" : "pgl_", o.operationId) || d.source !== x || d.origin !== S || d.digest !== a.digest) throw t("invalid_record");
491
+ let C = r(g === "xp" ? v.trackId : v.stat), w = L("pgd_", O, g, C);
492
+ if (!ne.has(w)) {
493
+ let n = (await e.query(N(y).where(M("id", w)).limit(1).descriptor))[0];
494
+ if (!n || n.tenantId !== O || n.kind !== (g === "xp" ? "track" : "stat") || n.definitionId !== C || I(n.config) !== I(te(g, C))) throw t("conflict");
495
+ ne.add(w);
496
+ }
497
+ if (d.id !== L("pgn_", O, k, g, C, x, S)) throw t("invalid_record");
498
+ let T;
499
+ if (g === "xp" && b.kind === "xp") {
500
+ let e = _.get(C);
501
+ if (!e || !e.sources.includes(x)) throw t("invalid_track");
502
+ let n = L("pgt_", O, k, C), r = Y.get(n), a = String(r?.xp ?? "0"), l = String(s(v.delta)), d = String(s(BigInt(a) + BigInt(l))), p = u(a, e.xpCurve, h.strategies.xpCurve), m = u(d, e.xpCurve, h.strategies.xpCurve);
503
+ if (l === "0" || m < p || v.afterXp !== d && String(v.afterXp) !== d || v.fromLevel !== p || v.toLevel !== m || b.trackId !== C || b.xp !== d || b.delta !== l || b.fromLevel !== p || b.toLevel !== m) throw t("invalid_record");
504
+ let g = G.get(o.operationId) ?? /* @__PURE__ */ new Map();
505
+ if (g.size !== o.rewardsQueued) throw t("invalid_record");
506
+ for (let e = 0; e < o.rewardsQueued; e++) {
507
+ let n = g.get(L("pgr_", o.operationId, String(e)));
508
+ if (!n || i(n.level, p + 1, m) !== n.level || z(n.createdAt) !== o.at || n.state !== "pending" && n.state !== "delivered" || n.state === "pending" && n.deliveredAt !== null || n.state === "delivered" && z(n.deliveredAt) < o.at) throw t("invalid_record");
509
+ c([n.reward], 1), f(n, "level", I);
510
+ }
511
+ Y.set(n, {
512
+ id: n,
513
+ tenantId: O,
514
+ ownerId: k,
515
+ trackId: C,
516
+ version: e.version,
517
+ xp: d,
518
+ level: m,
519
+ prestige: 0,
520
+ updatedAt: new Date(o.at),
521
+ metadata: {}
522
+ }), T = { amount: l };
523
+ } else if (g === "stat" && b.kind === "stat") {
524
+ let e = A.get(C);
525
+ if (!e || !h.statSources.includes(x)) throw t("invalid_stat");
526
+ if (v.period !== "lifetime" && v.period !== "season" || v.period === "lifetime" && v.seasonId !== null || !p.some((e) => e === v.operator)) throw t("invalid_record");
527
+ let i = v.period === "season" ? r(v.seasonId) : null, a = L("pgv_", O, k, C, v.period, i ?? ""), c = X.get(a), l = c ? String(c.value) : null, u = String(s(v.operand)), d = v.operator, f = m(l, u, d, e);
528
+ if ((v.beforeValue === null ? null : String(s(v.beforeValue))) !== l || String(s(v.afterValue)) !== f || b.stat !== C || b.period !== v.period || b.seasonId !== i || b.operator !== d || b.value !== f || o.rewardsQueued !== 0 || (G.get(o.operationId)?.size ?? 0) !== 0) throw t("invalid_record");
529
+ X.set(a, {
530
+ id: a,
531
+ tenantId: O,
532
+ ownerId: k,
533
+ stat: C,
534
+ period: v.period,
535
+ seasonId: i,
536
+ value: f,
537
+ updatedAt: new Date(o.at)
538
+ }), re.push(Object.freeze({
539
+ stat: C,
540
+ period: v.period,
541
+ seasonId: i,
542
+ value: f,
543
+ operationId: o.operationId,
544
+ sequence: n + 1,
545
+ at: o.at
546
+ })), T = {
547
+ period: v.period,
548
+ seasonId: i,
549
+ operator: d,
550
+ operand: u
551
+ };
552
+ } else throw t("invalid_record");
553
+ if (a.digest !== I({
554
+ tenantId: O,
555
+ ownerId: k,
556
+ kind: g,
557
+ id: C,
558
+ source: x,
559
+ origin: S,
560
+ payload: T
561
+ })) throw t("invalid_record");
562
+ }
563
+ let Z = await q(e, E, O, k, 128), Q = await q(e, w, O, k), $ = !1;
564
+ try {
565
+ $ = Z.length === Y.size && Q.length === X.size && new Set(Z.map((e) => e.id)).size === Z.length && new Set(Q.map((e) => e.id)).size === Q.length && Z.every((e) => {
566
+ let t = Y.get(String(e.id));
567
+ return t ? I(ie(e, _.get(r(e.trackId)))) === I(ie(t, _.get(r(t.trackId)))) && I(e.metadata) === I({}) : !1;
568
+ }) && Q.every((e) => {
569
+ let t = X.get(String(e.id));
570
+ return t ? I(ae(e, A.get(r(e.stat)))) === I(ae(t, A.get(r(t.stat)))) : !1;
571
+ });
572
+ } catch {
573
+ $ = !1;
574
+ }
575
+ if (d && !$) {
576
+ await e.deleteMany(E.tableName, { where: K(O, k) }), await e.deleteMany(w.tableName, { where: K(O, k) });
577
+ for (let t of Y.values()) await e.insert(E.tableName, t);
578
+ for (let t of X.values()) await e.insert(w.tableName, t);
579
+ $ = !0;
580
+ }
581
+ if (g !== void 0 && re.length > g) throw t("limit_exceeded");
582
+ let oe = Object.freeze(h.stats.map((e) => Object.freeze({
583
+ stat: e.id,
584
+ period: "lifetime",
585
+ seasonId: null,
586
+ value: e.initial
587
+ })));
588
+ return Object.freeze({
589
+ audit: Object.freeze({
590
+ tracks: Y.size,
591
+ stats: X.size,
592
+ acceptedOperations: F.length,
593
+ xpLedgerRows: V.length,
594
+ statLedgerRows: H.length,
595
+ rewardRows: v.length,
596
+ matches: $
597
+ }),
598
+ history: Object.freeze({
599
+ version: I({
600
+ stats: h.stats,
601
+ sources: h.statSources
602
+ }),
603
+ throughSequence: F.length,
604
+ initial: oe,
605
+ events: Object.freeze(re)
606
+ })
607
+ });
608
+ })));
609
+ }), oe = (e, n) => X(() => {
610
+ let i = o(e, [
611
+ "subjectId",
612
+ "tenantId",
613
+ "kind"
614
+ ]), c = r(i.tenantId), l = r(i.subjectId), u = H(c, l);
615
+ if (i.kind !== "user" && i.kind !== "guest") throw t("forbidden");
616
+ return R(async () => (await G(c, l), a.transactional(async (e) => {
617
+ await ee(e, c, l, !0);
618
+ let r = await q(e, E, c, l, 128), i = await q(e, w, c, l), a = await q(e, D, c, l), o = await q(e, C, c, l), d = [
619
+ b,
620
+ x,
621
+ S
622
+ ];
623
+ for (let n of d) if ((await e.query(N(n).where(j(M("tenantId", c), M("ownerKey", u))).limit(h.maxHistoryRows + 1).descriptor)).length > h.maxHistoryRows) throw t("limit_exceeded");
624
+ let f = await e.query(N(S).where(j(M("tenantId", c), M("ownerKey", u))).limit(h.maxHistoryRows + 1).descriptor);
625
+ if (f.length > h.maxHistoryRows) throw t("limit_exceeded");
626
+ if (!n) return {
627
+ ...f.length ? { rewards: f.map((e) => ({
628
+ reward: e.reward,
629
+ state: e.state,
630
+ deliveryIntent: e.deliveryIntent ?? null,
631
+ deliveryReceipt: e.deliveryReceipt ?? null
632
+ })) } : {},
633
+ tracks: r.map((e) => ({
634
+ trackId: e.trackId,
635
+ xp: String(s(e.xp)),
636
+ level: e.level,
637
+ prestige: e.prestige,
638
+ updatedAt: z(e.updatedAt)
639
+ })),
640
+ stats: i.map((e) => ({
641
+ stat: e.stat,
642
+ period: e.period,
643
+ seasonId: e.seasonId,
644
+ value: String(s(e.value)),
645
+ updatedAt: z(e.updatedAt)
646
+ })),
647
+ xpLedger: a.map((e) => ({
648
+ trackId: e.trackId,
649
+ delta: String(s(e.delta)),
650
+ source: e.source,
651
+ at: z(e.at)
652
+ })),
653
+ statLedger: o.map((e) => ({
654
+ stat: e.stat,
655
+ operator: e.operator,
656
+ operand: String(s(e.operand)),
657
+ at: z(e.at)
658
+ }))
659
+ };
660
+ await e.deleteMany(E.tableName, { where: K(c, l) }), await e.deleteMany(w.tableName, { where: K(c, l) });
661
+ for (let t of [D, C]) await e.updateMany(t.tableName, {
662
+ ownerId: null,
663
+ ownerKey: null,
664
+ origin: null,
665
+ actor: null
666
+ }, { where: K(c, l) });
667
+ await e.updateMany(b.tableName, {
668
+ ownerKey: null,
669
+ state: "erased",
670
+ digest: null,
671
+ receipt: null,
672
+ linkedOperationId: null
673
+ }, { where: j(M("tenantId", c), M("ownerKey", u)) }), await e.updateMany(x.tableName, {
674
+ ownerKey: null,
675
+ source: null,
676
+ origin: null,
677
+ digest: null
678
+ }, { where: j(M("tenantId", c), M("ownerKey", u)) }), await e.updateMany(S.tableName, {
679
+ ownerId: null,
680
+ ownerKey: null,
681
+ state: "erased",
682
+ reward: null,
683
+ deliveryIntent: null,
684
+ deliveryDigest: null,
685
+ deliveryReceipt: null,
686
+ deliveredAt: null
687
+ }, { where: j(M("tenantId", c), M("ownerKey", u)) }), await e.update(T.tableName, u, {
688
+ ownerId: null,
689
+ erased: !0
690
+ });
691
+ })));
692
+ });
693
+ return Object.freeze({
694
+ applyXp: ne,
695
+ applyStat: re,
696
+ mine: Z,
697
+ stats: Q,
698
+ exportSubject: (e) => oe(e, !1),
699
+ eraseSubject: (e) => O.asVoid(oe(e, !0)),
700
+ auditProgression: (e, t, n) => O.map($(e, t, n, !1), (e) => e.audit),
701
+ rebuildProgression: (e, t, n) => O.map($(e, t, n, !0), (e) => e.audit),
702
+ achievementHistory: (e, t, n, r) => O.map($(e, t, n, !1, r), (e) => e.history)
703
+ });
704
+ };
705
+ export { B as dataStoreProgression, P as resolveProgressionOptions };