@voltro/plugin-progression 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 (97) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +478 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9189 -0
  6. package/dist/achievementComponents.js +92 -0
  7. package/dist/achievementStore.js +603 -0
  8. package/dist/achievementTables.entity.js +98 -0
  9. package/dist/achievements.d.ts +188 -0
  10. package/dist/achievements.js +205 -0
  11. package/dist/capture.js +64 -0
  12. package/dist/cmsQuests.d.ts +91 -0
  13. package/dist/cmsQuests.js +83 -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 +38 -0
  18. package/dist/daily.d.ts +152 -0
  19. package/dist/daily.js +126 -0
  20. package/dist/dailyStore.js +421 -0
  21. package/dist/dailySystem.fixture.js +138 -0
  22. package/dist/dailyTables.entity.js +90 -0
  23. package/dist/declarationFixtures.js +143 -0
  24. package/dist/errors.d.ts +13 -0
  25. package/dist/errors.js +20 -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 +122 -0
  30. package/dist/passRules.js +96 -0
  31. package/dist/passStore.js +485 -0
  32. package/dist/passTables.entity.js +96 -0
  33. package/dist/plugin.js +1086 -0
  34. package/dist/port.js +5 -0
  35. package/dist/progressionStore.js +706 -0
  36. package/dist/questComponents.js +163 -0
  37. package/dist/questPort.d.ts +126 -0
  38. package/dist/questPort.js +5 -0
  39. package/dist/questRefresh.js +56 -0
  40. package/dist/questRefresh.server.js +126 -0
  41. package/dist/questRerollJournal.js +77 -0
  42. package/dist/questStore.js +592 -0
  43. package/dist/questTables.entity.js +117 -0
  44. package/dist/quests.d.ts +142 -0
  45. package/dist/quests.js +153 -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 +35 -0
  51. package/dist/rankClosure.server.js +139 -0
  52. package/dist/rankClosureWorkflow.d.ts +34 -0
  53. package/dist/rankClosureWorkflow.js +16 -0
  54. package/dist/rankReader.server.js +57 -0
  55. package/dist/rankRewardParent.server.js +65 -0
  56. package/dist/rankSeasons.d.ts +144 -0
  57. package/dist/rankSeasons.js +91 -0
  58. package/dist/rankStore.js +521 -0
  59. package/dist/rankSystem.fixture.js +170 -0
  60. package/dist/rankTables.entity.js +101 -0
  61. package/dist/ranks.d.ts +167 -0
  62. package/dist/ranks.js +219 -0
  63. package/dist/resourceStore.js +464 -0
  64. package/dist/resourceTables.entity.js +89 -0
  65. package/dist/resources.d.ts +105 -0
  66. package/dist/resources.js +60 -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 +39 -0
  72. package/dist/rewardDelivery.d.ts +163 -0
  73. package/dist/rewardDelivery.js +38 -0
  74. package/dist/rewardDelivery.server.js +430 -0
  75. package/dist/rewardDeliveryRecord.js +48 -0
  76. package/dist/rewardDeliveryWorkflow.d.ts +36 -0
  77. package/dist/rewardDeliveryWorkflow.js +16 -0
  78. package/dist/rpc.d.ts +880 -0
  79. package/dist/rpc.js +498 -0
  80. package/dist/server.d.ts +2812 -0
  81. package/dist/server.js +21 -0
  82. package/dist/stats.js +45 -0
  83. package/dist/strategies.d.ts +131 -0
  84. package/dist/strategies.js +4 -0
  85. package/dist/systemFixtures.js +474 -0
  86. package/dist/tables.entity.js +155 -0
  87. package/dist/testing.d.ts +1566 -0
  88. package/dist/testing.js +11 -0
  89. package/dist/track.js +72 -0
  90. package/dist/tutorial.d.ts +157 -0
  91. package/dist/tutorial.js +110 -0
  92. package/dist/tutorialStore.js +496 -0
  93. package/dist/tutorialSystem.fixture.js +100 -0
  94. package/dist/tutorialTables.entity.js +91 -0
  95. package/dist/web.d.ts +363 -0
  96. package/dist/web.js +7 -0
  97. package/package.json +167 -4
@@ -0,0 +1,430 @@
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 } from "./capture.js";
3
+ import { captureReward as s } from "./reward.js";
4
+ import { captureTutorialEvidence as c, captureTutorialState as l, defineTutorial as u, resolveTutorialSkip as d, resolveTutorialStep as f } from "./tutorial.js";
5
+ import { capturePassState as p, defineSeasonPass as m } from "./pass.js";
6
+ import { defineQuest as h } from "./quests.js";
7
+ import { captureDailyState as g, defineLoginCalendar as _ } from "./daily.js";
8
+ import { admitRewardDeliveryRecord as v } from "./rewardDeliveryRecord.js";
9
+ import { progressionOperationsTable as y, progressionRewardsTable as b, progressionSubjectsTable as x } from "./tables.entity.js";
10
+ import { questOperationsTable as S, questRewardsTable as C, questSubjectsTable as w, questsTable as T } from "./questTables.entity.js";
11
+ import { questHash as E } from "./questStore.js";
12
+ import { defineAchievement as D } from "./achievements.js";
13
+ import { achievementDefinitionsTable as O, achievementOperationsTable as k, achievementRewardsTable as ee, achievementSubjectsTable as te, achievementUnlockLedgerTable as ne } from "./achievementTables.entity.js";
14
+ import { dailyClaimsTable as re, dailyDefinitionsTable as ie, dailyOperationsTable as ae, dailyRewardsTable as oe, dailySubjectsTable as se } from "./dailyTables.entity.js";
15
+ import { applyPassIntent as ce, capturePassIntent as le } from "./passRules.js";
16
+ import { passDefinitionsTable as ue, passLedgerTable as de, passOperationsTable as fe, passRewardsTable as pe, passSubjectsTable as me } from "./passTables.entity.js";
17
+ import { tutorialDefinitionsTable as he, tutorialLedgerTable as ge, tutorialOperationsTable as _e, tutorialRewardsTable as ve, tutorialSubjectsTable as ye } from "./tutorialTables.entity.js";
18
+ import { rankOperationsTable as A, rankRewardsTable as j, rankSubjectsTable as M } from "./rankTables.entity.js";
19
+ import { admitRankRewardParent as N } from "./rankRewardParent.server.js";
20
+ import { Effect as P, Result as be, Schema as xe } from "effect";
21
+ import { WorkflowRunHandleSchema as Se, systemSubject as Ce } from "@voltro/protocol";
22
+ import { and as we, eq as F, gt as Te, queryFor as I } from "@voltro/database";
23
+ //#region src/rewardDelivery.server.ts
24
+ var L = [
25
+ "level",
26
+ "quest",
27
+ "achievement",
28
+ "daily",
29
+ "pass",
30
+ "tutorial",
31
+ "rank"
32
+ ], R = (e) => {
33
+ let i = o(e, [
34
+ "systemAccount",
35
+ "economy",
36
+ "inventory",
37
+ "progression",
38
+ "allowedServices",
39
+ "now",
40
+ "version",
41
+ "service"
42
+ ]), a = (e, n) => {
43
+ if (e === void 0) return;
44
+ let r = o(e);
45
+ if (n.some((e) => typeof r[e] != "function")) throw t("invalid_input");
46
+ return Object.freeze(Object.fromEntries(n.map((e) => [e, r[e]])));
47
+ }, s = a(i.economy, [
48
+ "transfer",
49
+ "mine",
50
+ "auditWallet",
51
+ "rebuildWallet"
52
+ ]), c = a(i.inventory, [
53
+ "grant",
54
+ "consume",
55
+ "mine",
56
+ "loadout",
57
+ "equip",
58
+ "expire",
59
+ "exportSubject",
60
+ "eraseSubject"
61
+ ]), l = a(i.progression, [
62
+ "applyXp",
63
+ "applyStat",
64
+ "mine",
65
+ "stats",
66
+ "exportSubject",
67
+ "eraseSubject"
68
+ ]), u = a(i.service, ["execute", "dispatch"]), d = i.now ?? Date.now, f = n(i.allowedServices ?? []);
69
+ if (!Array.isArray(f) || f.length > 256 || new Set(f).size !== f.length || typeof d != "function" || !u && !s && !c && !l) throw t("invalid_input");
70
+ return Object.freeze({
71
+ systemAccount: r(i.systemAccount),
72
+ version: r(i.version ?? "default.v1"),
73
+ economy: s,
74
+ inventory: c,
75
+ progression: l,
76
+ service: u,
77
+ allowedServices: Object.freeze(f.map(r)),
78
+ now: d
79
+ });
80
+ }, z = (e, ...t) => e + E(t).slice(0, 56), B = (e) => {
81
+ let n = e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : NaN;
82
+ if (!Number.isSafeInteger(n) || n < 0 || n > 864e13) throw t("invalid_record");
83
+ return n;
84
+ }, V = (n) => P.tryPromise({
85
+ try: n,
86
+ catch: (n) => n instanceof e ? n : t("unavailable")
87
+ }), H = (e) => {
88
+ let n = o(e, ["kind", "rewardId"]);
89
+ if (!L.some((e) => e === n.kind)) throw t("invalid_input");
90
+ return Object.freeze({
91
+ kind: n.kind,
92
+ rewardId: r(n.rewardId)
93
+ });
94
+ }, U = (U, Ee, De) => {
95
+ let W = R(Ee), G = Object.freeze(De.map((e) => {
96
+ if (!L.includes(e)) throw t("invalid_input");
97
+ return e;
98
+ })), K = new Set(W.allowedServices);
99
+ if (new Set(G).size !== G.length || G.length === 0) throw t("invalid_input");
100
+ let q = () => i(W.now(), 0, 864e13), J = Ce("progression.reward.delivery"), Y = (e) => {
101
+ if (e.type !== "system" && !(e.type === "service" && K.has(e.service))) throw t("forbidden");
102
+ }, X = (e) => {
103
+ if (!G.includes(e)) throw t("invalid_input");
104
+ return e === "level" ? {
105
+ rewards: b,
106
+ subjects: x,
107
+ operations: y,
108
+ prefix: "pgs_"
109
+ } : e === "quest" ? {
110
+ rewards: C,
111
+ subjects: w,
112
+ operations: S,
113
+ prefix: "qps_"
114
+ } : e === "achievement" ? {
115
+ rewards: ee,
116
+ subjects: te,
117
+ operations: k,
118
+ prefix: "pas_"
119
+ } : e === "daily" ? {
120
+ rewards: oe,
121
+ subjects: se,
122
+ operations: ae,
123
+ prefix: "pds_"
124
+ } : e === "pass" ? {
125
+ rewards: pe,
126
+ subjects: me,
127
+ operations: fe,
128
+ prefix: "pps_"
129
+ } : e === "tutorial" ? {
130
+ rewards: ve,
131
+ subjects: ye,
132
+ operations: _e,
133
+ prefix: "pts_"
134
+ } : {
135
+ rewards: j,
136
+ subjects: M,
137
+ operations: A,
138
+ prefix: "prs_"
139
+ };
140
+ }, Z = async (e, t) => (await e.query(I(X(t.kind).rewards).where(F("id", t.rewardId)).limit(1).descriptor))[0], Oe = (e, n) => {
141
+ let i = r(n.tenantId), a = r(n.ownerId), o = z(X(e).prefix, i, a);
142
+ if (n.ownerKey !== o) throw t("invalid_record");
143
+ return {
144
+ tenantId: i,
145
+ ownerId: a,
146
+ ownerKey: o
147
+ };
148
+ }, Q = async (e, n, v) => {
149
+ let y = Oe(n.kind, v), b = X(n.kind);
150
+ if (await e.updateMany(b.subjects.tableName, { admission: 0 }, { where: F("id", y.ownerKey) }) !== 1) throw t("invalid_record");
151
+ let x = (await e.query(I(b.subjects).where(F("id", y.ownerKey)).limit(1).descriptor))[0];
152
+ if (!x || x.tenantId !== y.tenantId || x.ownerId !== y.ownerId || x.erased !== !1) throw t(x?.erased === !0 ? "erased" : "invalid_record");
153
+ let S = (await e.query(I(b.operations).where(F("id", r(v.operationId))).limit(1).descriptor))[0];
154
+ if (!S || S.tenantId !== y.tenantId || S.ownerKey !== y.ownerKey || S.state !== "committed" || S.receipt === null) throw t("invalid_record");
155
+ let C = o(S.receipt), w = B(v.createdAt);
156
+ if (C.operationId !== S.id || C.at !== w) throw t("invalid_record");
157
+ if (n.kind === "level") {
158
+ let e = o(C.change), n = i(C.rewardsQueued, 1, 256);
159
+ if (e.kind !== "xp" || v.id === void 0 || !Array.from({ length: n }, (e, t) => z("pgr_", r(v.operationId), String(t))).includes(String(v.id))) throw t("invalid_record");
160
+ i(v.level, i(e.fromLevel, 1, 1e4) + 1, i(e.toLevel, 1, 1e4));
161
+ } else if (n.kind === "quest") {
162
+ let n = r(v.assignmentId), i = (await e.query(I(T).where(F("id", n)).limit(1).descriptor))[0];
163
+ if (C.kind !== "record" || !a(C.completedIds, 8).includes(n) || !i || i.tenantId !== y.tenantId || i.ownerId !== y.ownerId || i.state !== "completed" || B(i.completedAt) !== w) throw t("invalid_record");
164
+ let o = h(i.definition), c = o.reward.findIndex((e, t) => z("qpr_", n, String(t)) === v.id);
165
+ if (c < 0 || E(s(v.reward)) !== E(o.reward[c])) throw t("invalid_record");
166
+ } else if (n.kind === "achievement") {
167
+ let n = r(v.unlockId), o = (await e.query(I(ne).where(F("unlockId", n)).limit(1).descriptor))[0];
168
+ if (!a(C.unlockedIds, 256).includes(n) || !o || o.tenantId !== y.tenantId || o.ownerId !== y.ownerId || o.ownerKey !== y.ownerKey || o.operationId !== v.operationId) throw t("invalid_record");
169
+ let c = (await e.query(I(O).where(F("id", z("pad_", y.tenantId, r(o.achievementId), String(i(o.version, 1, 1e6))))).limit(1).descriptor))[0];
170
+ if (!c || c.tenantId !== y.tenantId || c.achievementId !== o.achievementId || c.version !== o.version) throw t("invalid_record");
171
+ let l = D(c.config).tiers.find((e) => e.id === o.tierId), u = l?.reward.findIndex((e, t) => z("par_", n, String(t)) === v.id) ?? -1;
172
+ if (!l || u < 0 || E(s(v.reward)) !== E(l.reward[u])) throw t("invalid_record");
173
+ } else if (n.kind === "daily") {
174
+ let n = r(v.claimId), a = (await e.query(I(re).where(F("id", n)).limit(1).descriptor))[0];
175
+ if (C.claimId !== n || !a || a.tenantId !== y.tenantId || a.ownerId !== y.ownerId || a.ownerKey !== y.ownerKey || a.operationId !== v.operationId || B(a.at) !== w) throw t("invalid_record");
176
+ let o = r(a.calendarId), c = i(a.version, 1, 1e6), l = (await e.query(I(ie).where(F("id", z("pdd_", y.tenantId, o, String(c)))).limit(1).descriptor))[0];
177
+ if (!l || l.tenantId !== y.tenantId || l.calendarId !== o || l.version !== c) throw t("invalid_record");
178
+ let u = _(l.config), d = g(a.after, u), f = u.days[d.dayIndex].findIndex((e, t) => z("pdr_", n, String(t)) === v.id);
179
+ if (n !== z("pdl_", y.tenantId, y.ownerId, o, String(c), String(d.dayOrdinal)) || a.dayOrdinal !== d.dayOrdinal || a.dayKey !== d.dayKey || C.dayKey !== d.dayKey || C.calendarId !== o || E(C.after) !== E(d) || f < 0 || E(s(v.reward)) !== E(u.days[d.dayIndex][f])) throw t("invalid_record");
180
+ } else if (n.kind === "pass") {
181
+ let n = r(v.passId), a = i(v.version, 1, 1e6), o = i(v.tier, 1, 256);
182
+ if (v.track !== "free" && v.track !== "premium") throw t("invalid_record");
183
+ let c = (await e.query(I(ue).where(F("id", z("ppd_", y.tenantId, n, String(a)))).limit(1).descriptor))[0], l = (await e.query(I(de).where(F("id", z("ppl_", r(v.operationId)))).limit(1).descriptor))[0];
184
+ if (!c || c.tenantId !== y.tenantId || c.passId !== n || c.version !== a || !l || l.tenantId !== y.tenantId || l.ownerId !== y.ownerId || l.ownerKey !== y.ownerKey || l.passId !== n || l.version !== a || l.operationId !== v.operationId || B(l.at) !== w) throw t("invalid_record");
185
+ let u = m(c.config), d = le(l.intent, u), f = ce(u, p(l.before, u), d, w);
186
+ if (C.kind !== d.kind || E(f.after) !== E(l.after) || E(f.after) !== E(C.after) || E(f.claims) !== E(C.claims)) throw t("invalid_record");
187
+ let h = f.claims.find((e) => e.track === v.track && e.tier === o), g = h?.rewards.findIndex((e, t) => z("ppr_", y.tenantId, y.ownerId, n, String(a), String(v.track), String(o), String(t)) === v.id) ?? -1;
188
+ if (!h || g < 0 || E(s(v.reward)) !== E(h.rewards[g])) throw t("invalid_record");
189
+ } else if (n.kind === "tutorial") {
190
+ let n = r(v.tutorialId), a = i(v.version, 1, 1e6), p = (await e.query(I(ge).where(F("id", z("ptl_", r(v.operationId)))).limit(1).descriptor))[0], m = (await e.query(I(he).where(F("id", z("ptd_", y.tenantId, n, String(a)))).limit(1).descriptor))[0];
191
+ if (!p || p.tenantId !== y.tenantId || p.ownerId !== y.ownerId || p.ownerKey !== y.ownerKey || p.operationId !== v.operationId || p.tutorialId !== n || p.version !== a || B(p.at) !== w || !m || m.tenantId !== y.tenantId || m.tutorialId !== n || m.version !== a) throw t("invalid_record");
192
+ let h = u(m.config), g = l(p.before, h), _ = o(p.intent, [
193
+ "tutorialId",
194
+ "version",
195
+ "kind",
196
+ "step",
197
+ "mode",
198
+ "source",
199
+ "originId",
200
+ "evidence"
201
+ ]), b = o(S.intent, [
202
+ "tutorialId",
203
+ "version",
204
+ "kind",
205
+ "step",
206
+ "mode",
207
+ "source",
208
+ "originId"
209
+ ]), { evidence: x, ...T } = _;
210
+ if (_.tutorialId !== n || _.version !== a || E(T) !== E(b) || C.kind !== _.kind || C.step !== _.step || _.mode !== "player" && _.mode !== "event" || _.mode === "player" && (_.source !== null || _.originId !== null) || _.kind === "skip" && (_.mode !== "player" || _.step !== null)) throw t("invalid_record");
211
+ if (_.kind === "step" && _.mode === "event") {
212
+ let e = c(x, w);
213
+ if (e.source !== _.source || e.originId !== _.originId || e.version !== "trusted.event.v1") throw t("invalid_record");
214
+ }
215
+ let D = _.kind === "step" ? f({
216
+ tutorial: h,
217
+ before: g,
218
+ step: r(_.step),
219
+ evidence: c(x, w),
220
+ at: w
221
+ }) : _.kind === "skip" && x === null ? d(h, g, w) : void 0, O = h.reward.findIndex((e, t) => z("ptr_", y.tenantId, y.ownerId, n, String(a), String(t)) === v.id);
222
+ if (!D || !D.completed || D.skipped && !h.rewardOnSkip || E(D) !== E(p.after) || E(D) !== E(C.after) || C.rewardsQueued !== h.reward.length || O < 0 || E(s(v.reward)) !== E(h.reward[O])) throw t("invalid_record");
223
+ } else await N(e, v, y, S, i(x.sequence, 1, 2147483647));
224
+ return y;
225
+ }, ke = (e, n) => {
226
+ let a = o(n.deliveryReceipt, [
227
+ "kind",
228
+ "rewardId",
229
+ "status",
230
+ "outputKind",
231
+ "externalOperationId",
232
+ "at"
233
+ ]);
234
+ if (a.kind !== e.kind || a.rewardId !== e.rewardId || a.status !== "delivered" || a.outputKind !== "currency" && a.outputKind !== "item" && a.outputKind !== "xp" || a.at !== B(n.deliveredAt)) throw t("invalid_record");
235
+ return Object.freeze({
236
+ ...e,
237
+ status: "delivered",
238
+ outputKind: a.outputKind,
239
+ externalOperationId: r(a.externalOperationId),
240
+ at: i(a.at, 0, 864e13)
241
+ });
242
+ }, Ae = (e) => Object.freeze({
243
+ ...e,
244
+ status: "erased",
245
+ outputKind: null,
246
+ externalOperationId: null,
247
+ at: q()
248
+ }), $ = (e, n) => {
249
+ if (!n || n.id !== e.rewardId) throw t("invalid_input");
250
+ if (v(n, e.kind, E), n.state === "erased") {
251
+ if (n.ownerId !== null || n.ownerKey !== null || n.reward !== null || n.deliveryIntent != null || n.deliveryDigest != null || n.deliveryReceipt != null) throw t("invalid_record");
252
+ return Ae(e);
253
+ }
254
+ if (n.state === "delivered") return ke(e, n);
255
+ if (n.state !== "pending" || n.deliveredAt !== null || n.deliveryReceipt != null) throw t("invalid_record");
256
+ };
257
+ return Object.freeze({
258
+ execute: (c, l) => {
259
+ try {
260
+ let e = n(c);
261
+ Y(e);
262
+ let u = H(l);
263
+ return X(u.kind), V(async () => {
264
+ let e = await U.transactional(async (e) => {
265
+ let n = await Z(e, u), r = $(u, n);
266
+ if (r) return { receipt: r };
267
+ let i = await Q(e, u, n), a = await Z(e, u), o = $(u, a);
268
+ if (o) return { receipt: o };
269
+ if (!a || a.ownerId !== i.ownerId || a.tenantId !== i.tenantId || a.ownerKey !== i.ownerKey) throw t("invalid_record");
270
+ let c = s(a.reward);
271
+ if (c.kind === "currency" && !W.economy || c.kind === "item" && !W.inventory || c.kind === "xp" && !W.progression) throw t("unavailable");
272
+ let l = Object.freeze({
273
+ ...i,
274
+ reward: c,
275
+ kind: u.kind,
276
+ rewardId: u.rewardId,
277
+ requestId: z("reward_", u.kind, u.rewardId),
278
+ sourceVersion: W.version,
279
+ systemAccount: W.systemAccount
280
+ }), d = E(l);
281
+ if (a.deliveryIntent != null || a.deliveryDigest != null) {
282
+ if (a.deliveryDigest !== d || E(a.deliveryIntent) !== d) throw t("conflict");
283
+ } else await e.update(X(u.kind).rewards.tableName, u.rewardId, {
284
+ deliveryIntent: l,
285
+ deliveryDigest: d
286
+ });
287
+ return {
288
+ intent: l,
289
+ digest: d
290
+ };
291
+ });
292
+ if ("receipt" in e) return e.receipt;
293
+ let { intent: n, digest: c } = e;
294
+ if (!n || !c) throw t("invalid_record");
295
+ let l = n.reward, d = async (e) => {
296
+ let n = await P.runPromise(P.result(e));
297
+ if (be.isFailure(n)) throw t("unavailable");
298
+ return o(n.success);
299
+ }, f;
300
+ if (l.kind === "currency") {
301
+ let e = await d(W.economy.transfer(J, {
302
+ tenantId: n.tenantId,
303
+ requestId: n.requestId,
304
+ currency: l.currency,
305
+ from: {
306
+ kind: "system",
307
+ id: n.systemAccount
308
+ },
309
+ to: {
310
+ kind: "wallet",
311
+ ownerId: n.ownerId,
312
+ ownerKind: "player"
313
+ },
314
+ amount: l.amount,
315
+ reason: "progression.reward",
316
+ ref: {
317
+ kind: "progression.reward",
318
+ id: n.rewardId
319
+ }
320
+ }));
321
+ if (e.currency !== l.currency || e.amount !== l.amount) throw t("invalid_record");
322
+ f = r(e.txId), i(e.at, 0, 864e13);
323
+ } else if (l.kind === "item") {
324
+ let e = await d(W.inventory.grant(J, {
325
+ tenantId: n.tenantId,
326
+ owner: {
327
+ ownerKind: "player",
328
+ ownerId: n.ownerId
329
+ },
330
+ requestId: n.requestId,
331
+ itemId: l.itemId,
332
+ qty: l.qty,
333
+ reason: "progression.reward",
334
+ ref: {
335
+ kind: "progression.reward",
336
+ id: n.rewardId
337
+ }
338
+ })), s = a(e.changes, 1e5);
339
+ if (e.kind !== "grant" || !Array.isArray(s) || s.length > 1e5 || s.reduce((e, t) => {
340
+ let n = o(t, ["instanceId", "delta"]);
341
+ return r(n.instanceId), e + i(n.delta, 1, 1e6);
342
+ }, 0) !== l.qty) throw t("invalid_record");
343
+ f = r(e.operationId), i(e.at, 0, 864e13);
344
+ } else {
345
+ let e = await d(W.progression.applyXp(J, {
346
+ tenantId: n.tenantId,
347
+ ownerId: n.ownerId,
348
+ trackId: l.trackId,
349
+ amount: l.amount,
350
+ requestId: n.requestId,
351
+ source: "progression.reward",
352
+ origin: n.rewardId
353
+ })), a = o(e.change, [
354
+ "kind",
355
+ "trackId",
356
+ "xp",
357
+ "delta",
358
+ "fromLevel",
359
+ "toLevel"
360
+ ]);
361
+ if (a.kind !== "xp" || a.trackId !== l.trackId || a.delta !== l.amount) throw t("invalid_record");
362
+ f = r(e.operationId), i(e.at, 0, 864e13);
363
+ }
364
+ return U.transactional(async (e) => {
365
+ let n = await Z(e, u), r = $(u, n);
366
+ if (r) return r;
367
+ let i = await Q(e, u, n), a = await Z(e, u), o = $(u, a);
368
+ if (o) return o;
369
+ if (!a || a.tenantId !== i.tenantId || a.ownerId !== i.ownerId || a.deliveryDigest !== c || E(a.deliveryIntent) !== c) throw t("conflict");
370
+ let s = q(), d = Object.freeze({
371
+ ...u,
372
+ status: "delivered",
373
+ outputKind: l.kind,
374
+ externalOperationId: f,
375
+ at: s
376
+ });
377
+ if (s < B(a.createdAt)) throw t("conflict");
378
+ return await e.update(X(u.kind).rewards.tableName, u.rewardId, {
379
+ state: "delivered",
380
+ deliveredAt: new Date(s),
381
+ deliveryReceipt: d
382
+ }), d;
383
+ });
384
+ });
385
+ } catch (n) {
386
+ return P.fail(n instanceof e ? n : t("invalid_input"));
387
+ }
388
+ },
389
+ dispatch: (r, a, s) => {
390
+ try {
391
+ let e = n(r);
392
+ Y(e);
393
+ let c = o(a, ["limit", "after"]), l = i(c.limit, 1, 1e3), u = c.after === void 0 ? void 0 : H(c.after);
394
+ if (typeof s != "function") throw t("invalid_input");
395
+ return V(async () => {
396
+ let e = [];
397
+ for (let t of G) {
398
+ if (u && L.indexOf(t) < L.indexOf(u.kind)) continue;
399
+ let n = u?.kind === t ? we(F("state", "pending"), Te("id", u.rewardId)) : F("state", "pending"), r = await U.query(I(X(t).rewards).where(n).orderBy("id", "asc").select("id").limit(l + 1).descriptor);
400
+ for (let n of r) e.push(H({
401
+ kind: t,
402
+ rewardId: n.id
403
+ }));
404
+ if (e.length > l) break;
405
+ }
406
+ let r = e.slice(0, l), i = [], a = [];
407
+ for (let e of r) try {
408
+ let r = xe.decodeUnknownSync(Se, { onExcessProperty: "error" })(n(await s(e)));
409
+ if (r.workflowName !== "progression.deliverReward") throw t("invalid_record");
410
+ i.push(Object.freeze({
411
+ request: e,
412
+ status: r.status
413
+ }));
414
+ } catch {
415
+ a.push(e);
416
+ }
417
+ return Object.freeze({
418
+ submitted: Object.freeze(i),
419
+ failed: Object.freeze(a),
420
+ next: e.length > l ? r.at(-1) : null
421
+ });
422
+ });
423
+ } catch (n) {
424
+ return P.fail(n instanceof e ? n : t("invalid_input"));
425
+ }
426
+ }
427
+ });
428
+ };
429
+ //#endregion
430
+ export { U as dataStoreRewardDelivery, R as resolveRewardDeliveryOptions };
@@ -0,0 +1,48 @@
1
+ import { progressionError as e } from "./errors.js";
2
+ import { identifier as t, integer as n, object as r } from "./capture.js";
3
+ import { captureReward as i } from "./reward.js";
4
+ //#region src/rewardDeliveryRecord.ts
5
+ var a = (a, o, s) => {
6
+ let c = (e) => {
7
+ let t = e instanceof Date ? e.getTime() : typeof e == "string" ? Date.parse(e) : NaN;
8
+ return n(t, 0, 864e13);
9
+ };
10
+ if (a.state === "erased") {
11
+ if (a.ownerId !== null || a.ownerKey !== null || a.reward !== null || a.deliveryIntent != null || a.deliveryDigest != null || a.deliveryReceipt != null || a.deliveredAt !== null) throw e("invalid_record");
12
+ return;
13
+ }
14
+ if (a.state !== "pending" && a.state !== "delivered") throw e("invalid_record");
15
+ let l = c(a.createdAt), u = i(a.reward);
16
+ if (a.deliveryIntent == null) {
17
+ if (a.deliveryDigest != null || a.deliveryReceipt != null || a.deliveredAt !== null || a.state !== "pending") throw e("invalid_record");
18
+ return;
19
+ }
20
+ let d = r(a.deliveryIntent, [
21
+ "tenantId",
22
+ "ownerId",
23
+ "ownerKey",
24
+ "reward",
25
+ "kind",
26
+ "rewardId",
27
+ "requestId",
28
+ "sourceVersion",
29
+ "systemAccount"
30
+ ]), f = o === "level" ? "pgs_" : o === "quest" ? "qps_" : o === "achievement" ? "pas_" : o === "daily" ? "pds_" : o === "pass" ? "pps_" : o === "rank" ? "prs_" : "pts_";
31
+ if (d.tenantId !== t(a.tenantId) || d.ownerId !== t(a.ownerId) || d.ownerKey !== a.ownerKey || d.ownerKey !== f + s([d.tenantId, d.ownerId]).slice(0, 56) || d.kind !== o || d.rewardId !== t(a.id) || d.requestId !== "reward_" + s([o, a.id]).slice(0, 56) || s(i(d.reward)) !== s(u) || s(d) !== a.deliveryDigest) throw e("invalid_record");
32
+ if (t(d.sourceVersion), t(d.systemAccount), a.state === "pending") {
33
+ if (a.deliveryReceipt != null || a.deliveredAt !== null) throw e("invalid_record");
34
+ return;
35
+ }
36
+ let p = r(a.deliveryReceipt, [
37
+ "kind",
38
+ "rewardId",
39
+ "status",
40
+ "outputKind",
41
+ "externalOperationId",
42
+ "at"
43
+ ]);
44
+ if (p.kind !== o || p.rewardId !== a.id || p.status !== "delivered" || p.outputKind !== u.kind || p.at !== c(a.deliveredAt) || Number(p.at) < l) throw e("invalid_record");
45
+ t(p.externalOperationId);
46
+ };
47
+ //#endregion
48
+ export { a as admitRewardDeliveryRecord };
@@ -0,0 +1,36 @@
1
+ import { Literals } from 'effect/Schema';
2
+ import { NullOr } from 'effect/Schema';
3
+ import { Number as Number_2 } from 'effect/Schema';
4
+ import { Schema } from 'effect';
5
+ import { String as String_2 } from 'effect/Schema';
6
+ import { Struct } from 'effect/Schema';
7
+ import { Workflow } from 'effect/workflow/Workflow';
8
+ import { WorkflowMessagesCarrier } from '@voltro/workflow';
9
+ import { YieldableError } from 'effect/Cause';
10
+
11
+ declare class ProgressionError extends ProgressionError_base {
12
+ }
13
+
14
+ declare const ProgressionError_base: Schema.Class<ProgressionError, Schema.TaggedStruct<"ProgressionError", {
15
+ 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"]>;
16
+ }>, YieldableError>;
17
+
18
+ /** The durable journal carries opaque reward identity and redacted receipt, never owner/intent bodies. */
19
+ export declare const ProgressionRewardDelivery: Workflow<"progression.deliverReward", Struct<{
20
+ readonly kind: Literals<readonly ["level", "quest", "achievement", "daily", "pass", "tutorial", "rank"]>;
21
+ readonly rewardId: String_2;
22
+ }>, Struct<{
23
+ readonly kind: Literals<readonly ["level", "quest", "achievement", "daily", "pass", "tutorial", "rank"]>;
24
+ readonly rewardId: String_2;
25
+ readonly status: Literals<readonly ["delivered", "erased"]>;
26
+ readonly outputKind: NullOr<Literals<readonly ["currency", "item", "xp"]>>;
27
+ readonly externalOperationId: NullOr<String_2>;
28
+ readonly at: Number_2;
29
+ }>, typeof ProgressionError> & {
30
+ readonly name: "progression.deliverReward";
31
+ } & WorkflowMessagesCarrier<{
32
+ readonly signals: {};
33
+ readonly updates: {};
34
+ }>;
35
+
36
+ export { }
@@ -0,0 +1,16 @@
1
+ import { ProgressionError as e } from "./errors.js";
2
+ import { RewardDeliveryReceiptSchema as t, RewardDeliveryRequestSchema as n } from "./rewardDelivery.js";
3
+ import { workflow as r } from "@voltro/workflow/define";
4
+ //#region src/rewardDeliveryWorkflow.ts
5
+ var i = r({
6
+ name: "progression.deliverReward",
7
+ payload: n,
8
+ success: t,
9
+ error: e,
10
+ idempotencyKey: ({ kind: e, rewardId: t }) => `progression.reward:${e}:${t}`,
11
+ concurrency: { limit: 4 },
12
+ suspendOnFailure: !0,
13
+ internal: !0
14
+ });
15
+ //#endregion
16
+ export { i as ProgressionRewardDelivery };