@voltro/plugin-economy 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 (177) hide show
  1. package/CHANGELOG.md +24492 -0
  2. package/LICENSE +61 -0
  3. package/README.md +2719 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9841 -0
  6. package/dist/amount.js +20 -0
  7. package/dist/appleIap.server.js +262 -0
  8. package/dist/appleIapNotifications.server.js +162 -0
  9. package/dist/appleIapTrust.server.js +30 -0
  10. package/dist/bundleValue.server.js +112 -0
  11. package/dist/canonicalDataJson.js +10 -0
  12. package/dist/capture.js +53 -0
  13. package/dist/codePort.fixture.js +123 -0
  14. package/dist/codeStore.server.js +439 -0
  15. package/dist/codeTables.entity.js +43 -0
  16. package/dist/codes.d.ts +150 -0
  17. package/dist/codes.js +82 -0
  18. package/dist/components.d.ts +397 -0
  19. package/dist/components.js +283 -0
  20. package/dist/consistency.server.js +115 -0
  21. package/dist/containerStore.server.js +687 -0
  22. package/dist/containerStore.testFixtures.js +75 -0
  23. package/dist/containerTables.entity.js +45 -0
  24. package/dist/containers.d.ts +311 -0
  25. package/dist/containers.fixture.js +128 -0
  26. package/dist/containers.js +214 -0
  27. package/dist/containers.server.js +39 -0
  28. package/dist/containersPort.fixture.js +74 -0
  29. package/dist/currency.js +32 -0
  30. package/dist/declarationFixtures.js +61 -0
  31. package/dist/economy-app/events/economy.refundReversed.event.ts +1 -0
  32. package/dist/economy-app/events/economy.refunded.event.ts +1 -0
  33. package/dist/economyPort.fixture.js +124 -0
  34. package/dist/errors.d.ts +14 -0
  35. package/dist/errors.js +21 -0
  36. package/dist/events.d.ts +46 -0
  37. package/dist/events.js +1 -0
  38. package/dist/googleIap.server.js +391 -0
  39. package/dist/googleIapNotifications.server.js +130 -0
  40. package/dist/googleIapSubscription.server.js +183 -0
  41. package/dist/iap.d.ts +309 -0
  42. package/dist/iap.js +303 -0
  43. package/dist/iap.testFixtures.js +144 -0
  44. package/dist/iapAccountTables.entity.js +39 -0
  45. package/dist/iapAccounts.server.js +200 -0
  46. package/dist/iapBinding.server.js +523 -0
  47. package/dist/iapCheckout.server.js +97 -0
  48. package/dist/iapCompletion.server.js +55 -0
  49. package/dist/iapCurrentState.server.js +107 -0
  50. package/dist/iapCurrentState.testFixtures.js +22 -0
  51. package/dist/iapCurrentStatePort.fixture.js +63 -0
  52. package/dist/iapEntitlements.d.ts +79 -0
  53. package/dist/iapEntitlements.js +57 -0
  54. package/dist/iapEntitlements.server.js +48 -0
  55. package/dist/iapEntitlementsBinding.server.js +105 -0
  56. package/dist/iapEntitlementsPort.fixture.js +80 -0
  57. package/dist/iapInstalledEntitlements.testFixtures.js +75 -0
  58. package/dist/iapInstalledNotifications.testFixtures.js +93 -0
  59. package/dist/iapInventoryRefunds.server.js +261 -0
  60. package/dist/iapNotificationCustodyPort.fixture.js +67 -0
  61. package/dist/iapNotificationPort.fixture.js +73 -0
  62. package/dist/iapNotificationProcessor.server.js +134 -0
  63. package/dist/iapNotificationProcessor.testFixtures.js +63 -0
  64. package/dist/iapNotificationProcessorPort.fixture.js +55 -0
  65. package/dist/iapNotificationSchedule.server.js +69 -0
  66. package/dist/iapNotificationStore.server.js +352 -0
  67. package/dist/iapNotificationStore.testFixtures.js +31 -0
  68. package/dist/iapNotificationTables.entity.js +48 -0
  69. package/dist/iapNotificationTarget.server.js +36 -0
  70. package/dist/iapNotificationTarget.testFixtures.js +29 -0
  71. package/dist/iapNotifications.d.ts +644 -0
  72. package/dist/iapNotifications.js +6 -0
  73. package/dist/iapNotifications.server.js +95 -0
  74. package/dist/iapNotificationsBinding.server.js +232 -0
  75. package/dist/iapNotificationsSystemPort.fixture.js +50 -0
  76. package/dist/iapPlugin.testFixtures.js +59 -0
  77. package/dist/iapPort.fixture.js +74 -0
  78. package/dist/iapProviderCapture.server.js +17 -0
  79. package/dist/iapRecovery.d.ts +146 -0
  80. package/dist/iapRecovery.js +89 -0
  81. package/dist/iapRefundEventDelivery.server.js +82 -0
  82. package/dist/iapRefundEvents.js +44 -0
  83. package/dist/iapRefundEventsPort.fixture.js +59 -0
  84. package/dist/iapRefundPort.fixture.js +54 -0
  85. package/dist/iapRefundTables.entity.js +55 -0
  86. package/dist/iapRefunds.d.ts +755 -0
  87. package/dist/iapRefunds.js +6 -0
  88. package/dist/iapRefunds.server.js +553 -0
  89. package/dist/iapRefunds.testFixtures.js +64 -0
  90. package/dist/iapSpendAdmission.server.js +98 -0
  91. package/dist/iapStore.server.js +740 -0
  92. package/dist/iapStore.testFixtures.js +127 -0
  93. package/dist/iapTables.entity.js +80 -0
  94. package/dist/iapVerification.server.js +120 -0
  95. package/dist/index.d.ts +2984 -0
  96. package/dist/index.js +15 -0
  97. package/dist/intentionRecovery.js +133 -0
  98. package/dist/ledger.js +77 -0
  99. package/dist/loyalty.d.ts +274 -0
  100. package/dist/loyalty.fixture.js +92 -0
  101. package/dist/loyalty.js +311 -0
  102. package/dist/loyaltyBinding.server.js +203 -0
  103. package/dist/loyaltyPort.fixture.js +86 -0
  104. package/dist/loyaltyShopSource.server.js +90 -0
  105. package/dist/loyaltyStore.server.js +552 -0
  106. package/dist/loyaltyStore.testFixtures.js +82 -0
  107. package/dist/loyaltyTables.entity.js +49 -0
  108. package/dist/offerMerchandising.fixture.js +114 -0
  109. package/dist/offerMerchandising.js +282 -0
  110. package/dist/offerPolicies.d.ts +441 -0
  111. package/dist/offerPolicies.fixture.js +53 -0
  112. package/dist/offerPolicies.js +267 -0
  113. package/dist/piggyBanks.d.ts +272 -0
  114. package/dist/piggyBanks.fixture.js +70 -0
  115. package/dist/piggyBanks.js +200 -0
  116. package/dist/piggyBinding.server.js +204 -0
  117. package/dist/piggyPort.fixture.js +72 -0
  118. package/dist/piggyStore.server.js +610 -0
  119. package/dist/piggyStore.testFixtures.js +97 -0
  120. package/dist/piggyTables.entity.js +40 -0
  121. package/dist/plugin.js +1047 -0
  122. package/dist/port.js +12 -0
  123. package/dist/price.d.ts +99 -0
  124. package/dist/price.js +143 -0
  125. package/dist/purchaseRecovery.js +55 -0
  126. package/dist/reports.server.js +114 -0
  127. package/dist/rpc.d.ts +3201 -0
  128. package/dist/rpc.js +1200 -0
  129. package/dist/sanctionsTradeAuthority.server.js +79 -0
  130. package/dist/server.d.ts +3856 -0
  131. package/dist/server.js +43 -0
  132. package/dist/shop.d.ts +279 -0
  133. package/dist/shop.js +195 -0
  134. package/dist/shop.testFixtures.js +113 -0
  135. package/dist/shopPort.fixture.js +71 -0
  136. package/dist/shopPresentation.js +67 -0
  137. package/dist/shopStore.server.js +623 -0
  138. package/dist/shopTables.entity.js +62 -0
  139. package/dist/shopUiCopy.js +56 -0
  140. package/dist/spendLimits.d.ts +140 -0
  141. package/dist/spendLimits.fixture.js +52 -0
  142. package/dist/spendLimits.js +154 -0
  143. package/dist/spendLimitsPort.fixture.js +119 -0
  144. package/dist/subscriptionBinding.server.js +210 -0
  145. package/dist/subscriptionStore.server.js +642 -0
  146. package/dist/subscriptionStore.testFixtures.js +71 -0
  147. package/dist/subscriptionTables.entity.js +36 -0
  148. package/dist/subscriptions.d.ts +394 -0
  149. package/dist/subscriptions.fixture.js +96 -0
  150. package/dist/subscriptions.js +212 -0
  151. package/dist/subscriptionsPort.fixture.js +75 -0
  152. package/dist/systemFixtures.js +88 -0
  153. package/dist/tables.entity.js +82 -0
  154. package/dist/testing.d.ts +4615 -0
  155. package/dist/testing.js +29 -0
  156. package/dist/tradeAuthority.server.js +171 -0
  157. package/dist/tradeBinding.server.js +200 -0
  158. package/dist/tradeComponents.js +341 -0
  159. package/dist/tradeEscrow.server.js +231 -0
  160. package/dist/tradeEscrow.testFixtures.js +132 -0
  161. package/dist/tradeExpiry.server.js +42 -0
  162. package/dist/tradeRecovery.js +47 -0
  163. package/dist/tradeStore.server.js +749 -0
  164. package/dist/tradeStore.testFixtures.js +72 -0
  165. package/dist/tradeTables.entity.js +65 -0
  166. package/dist/tradeUiCopy.js +78 -0
  167. package/dist/trades.d.ts +246 -0
  168. package/dist/trades.fixture.js +102 -0
  169. package/dist/trades.js +288 -0
  170. package/dist/tradesPort.fixture.js +93 -0
  171. package/dist/walletEscrow.js +105 -0
  172. package/dist/walletEscrow.server.js +375 -0
  173. package/dist/walletKeys.server.js +4 -0
  174. package/dist/walletStore.js +570 -0
  175. package/dist/web.d.ts +2257 -0
  176. package/dist/web.js +8 -0
  177. package/package.json +161 -4
@@ -0,0 +1,311 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { captureBoundMethods as t, dataList as n, dataObject as r, identifier as i } from "./capture.js";
3
+ import { economyAmount as a, nonNegativeAmount as o, positiveAmount as s } from "./amount.js";
4
+ import { captureCurrencies as c } from "./currency.js";
5
+ import { defineShopOffer as l, shopInteger as u } from "./shop.js";
6
+ import { Context as d } from "effect";
7
+ // src/loyalty.ts
8
+ var f = (t, n) => {
9
+ let a = r(t, [
10
+ "id",
11
+ "kind",
12
+ "bps",
13
+ "badgeId",
14
+ "items",
15
+ "currencies"
16
+ ]), o = i(a.id);
17
+ if (a.kind === "xpMultiplier" || a.kind === "discount") return r(t, [
18
+ "id",
19
+ "kind",
20
+ "bps"
21
+ ]), Object.freeze({
22
+ id: o,
23
+ kind: a.kind,
24
+ bps: u(a.bps, +(a.kind === "xpMultiplier"), a.kind === "xpMultiplier" ? 1e5 : 1e4)
25
+ });
26
+ if (a.kind === "chatBadge") return r(t, [
27
+ "id",
28
+ "kind",
29
+ "badgeId"
30
+ ]), Object.freeze({
31
+ id: o,
32
+ kind: "chatBadge",
33
+ badgeId: i(a.badgeId)
34
+ });
35
+ if (a.kind !== "inboxGift") throw e("invalid_input");
36
+ r(t, [
37
+ "id",
38
+ "kind",
39
+ "items",
40
+ "currencies"
41
+ ]);
42
+ let s = l({
43
+ id: o,
44
+ titleKey: o,
45
+ price: { kind: "free" },
46
+ items: a.items,
47
+ currencies: a.currencies
48
+ }, n);
49
+ return Object.freeze({
50
+ id: o,
51
+ kind: "inboxGift",
52
+ items: s.items,
53
+ currencies: s.currencies
54
+ });
55
+ }, p = (t, a, l = !1) => {
56
+ let u = r(t, [
57
+ "id",
58
+ "version",
59
+ "titleKey",
60
+ "pointsFrom",
61
+ "tiers",
62
+ "decay"
63
+ ]), d = c(a);
64
+ if (typeof l != "boolean") throw e("invalid_input");
65
+ let p = n(u.pointsFrom, 32).map((t) => {
66
+ let n = r(t, [
67
+ "id",
68
+ "kind",
69
+ "currency",
70
+ "numerator",
71
+ "denominator"
72
+ ]), a = i(n.id), o = i(n.currency);
73
+ if (n.kind !== "purchase.real" && n.kind !== "purchase.virtual") throw e("invalid_input");
74
+ if (n.kind === "purchase.real") {
75
+ if (!l) throw e("real_money_disabled");
76
+ if (!/^[A-Z]{3}$/.test(o)) throw e("invalid_currency");
77
+ } else if (!d.some((e) => e.id === o)) throw e("invalid_currency");
78
+ return Object.freeze({
79
+ id: a,
80
+ kind: n.kind,
81
+ currency: o,
82
+ numerator: s(n.numerator).toString(),
83
+ denominator: s(n.denominator).toString()
84
+ });
85
+ }), m = n(u.tiers, 128).map((t) => {
86
+ let a = r(t, [
87
+ "id",
88
+ "at",
89
+ "perks"
90
+ ]), s = Object.freeze(n(a.perks, 32).map((e) => f(e, d)));
91
+ if (new Set(s.map((e) => e.id)).size !== s.length) throw e("invalid_input");
92
+ return Object.freeze({
93
+ id: i(a.id),
94
+ at: o(a.at).toString(),
95
+ perks: s
96
+ });
97
+ }), h = u.decay ?? "none";
98
+ if (!p.length || new Set(p.map((e) => e.id)).size !== p.length || !m.length || m[0].at !== "0" || new Set(m.map((e) => e.id)).size !== m.length || m.some((e, t) => t > 0 && BigInt(e.at) <= BigInt(m[t - 1].at)) || h !== "none" && h !== "seasonal") throw e("invalid_input");
99
+ return Object.freeze({
100
+ id: i(u.id),
101
+ version: i(u.version ?? "1"),
102
+ titleKey: i(u.titleKey),
103
+ pointsFrom: Object.freeze(p),
104
+ tiers: Object.freeze(m),
105
+ decay: h
106
+ });
107
+ }, m = (t, n, r, a, s = !1) => {
108
+ let c = p(t, a, s).pointsFrom.find((e) => e.id === i(n));
109
+ if (!c) throw e("not_found");
110
+ return o(o(r) * BigInt(c.numerator) / BigInt(c.denominator)).toString();
111
+ }, h = ({ loyalty: e, points: t }) => e.tiers.filter((e) => BigInt(e.at) <= o(t)).at(-1).id, g = (t) => {
112
+ let n = r(t, [
113
+ "loyalty",
114
+ "currencies",
115
+ "realMoney",
116
+ "points",
117
+ "rulesVersion"
118
+ ]), a = c(n.currencies), s = n.realMoney ?? !1;
119
+ if (typeof s != "boolean") throw e("invalid_input");
120
+ return Object.freeze({
121
+ loyalty: p(n.loyalty, a, s),
122
+ currencies: a,
123
+ realMoney: s,
124
+ points: o(n.points).toString(),
125
+ rulesVersion: i(n.rulesVersion ?? "default.v1")
126
+ });
127
+ }, _ = (t, n = h) => {
128
+ let r = g(t);
129
+ if (typeof n != "function" || n !== h && r.rulesVersion === "default.v1") throw e("invalid_input");
130
+ let a = i(n(r)), o = r.loyalty.tiers.find((e) => e.id === a);
131
+ if (!o || BigInt(o.at) > BigInt(r.points)) throw e("invalid_input");
132
+ return o;
133
+ }, v = (e) => e.loyalty.tiers.find((t) => t.id === e.tierId).perks, y = (t, a = v) => {
134
+ let { tierId: o, ...s } = r(t, [
135
+ "loyalty",
136
+ "currencies",
137
+ "realMoney",
138
+ "points",
139
+ "rulesVersion",
140
+ "tierId"
141
+ ]), c = g(s), l = i(o), u = c.loyalty.tiers.find((e) => e.id === l);
142
+ if (!u || BigInt(u.at) > BigInt(c.points) || typeof a != "function" || a !== v && c.rulesVersion === "default.v1") throw e("invalid_input");
143
+ let d = Object.freeze(n(a(Object.freeze({
144
+ ...c,
145
+ tierId: l
146
+ })), 32).map((e) => f(e, c.currencies)));
147
+ if (new Set(d.map((e) => e.id)).size !== d.length || d.some((e) => !u.perks.some((t) => JSON.stringify(t) === JSON.stringify(e)))) throw e("invalid_input");
148
+ return d;
149
+ }, b = (t, c = "none") => {
150
+ if (c !== "none" && c !== "seasonal") throw e("invalid_input");
151
+ let l = /* @__PURE__ */ new Set(), d = /* @__PURE__ */ new Set(), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map(), h = (t, n = !1) => {
152
+ if (typeof t != "string" || (n ? s(t) : o(t)).toString() !== t) throw e("invalid_record");
153
+ return BigInt(t);
154
+ }, g = 0, _ = Object.freeze(n(t, 1e5, "invalid_record").map((t, n) => {
155
+ let s = r(t, [
156
+ "id",
157
+ "sequence",
158
+ "kind",
159
+ "at",
160
+ "sourceId",
161
+ "purchaseId",
162
+ "seasonId",
163
+ "purchaseAmount",
164
+ "numerator",
165
+ "denominator",
166
+ "delta",
167
+ "originalId",
168
+ "refundId",
169
+ "totalRefunded"
170
+ ], "invalid_record"), _ = i(s.id, "invalid_record"), v = u(s.at, 0, 864e13), y = u(s.sequence, 1, 1e5), b = s.seasonId === null ? null : i(s.seasonId, "invalid_record");
171
+ if (l.has(_) || y !== n + 1 || v < g || c === "none" && b !== null || c === "seasonal" && b === null || typeof s.delta != "string" || a(s.delta).toString() !== s.delta) throw e("invalid_record");
172
+ l.add(_), g = v;
173
+ let x, S = a(s.delta);
174
+ if (s.kind === "credit") {
175
+ r(t, [
176
+ "id",
177
+ "sequence",
178
+ "kind",
179
+ "at",
180
+ "sourceId",
181
+ "purchaseId",
182
+ "seasonId",
183
+ "purchaseAmount",
184
+ "numerator",
185
+ "denominator",
186
+ "delta"
187
+ ], "invalid_record");
188
+ let n = i(s.sourceId, "invalid_record"), a = i(s.purchaseId, "invalid_record"), o = h(s.purchaseAmount), c = h(s.numerator, !0), l = h(s.denominator, !0), u = JSON.stringify([n, a]);
189
+ if (d.has(u) || S !== o * c / l || S < 0n) throw e("invalid_record");
190
+ d.add(u), x = Object.freeze({
191
+ id: _,
192
+ sequence: y,
193
+ kind: "credit",
194
+ at: v,
195
+ sourceId: n,
196
+ purchaseId: a,
197
+ seasonId: b,
198
+ purchaseAmount: o.toString(),
199
+ numerator: c.toString(),
200
+ denominator: l.toString(),
201
+ delta: S.toString()
202
+ }), m.set(_, {
203
+ entry: x,
204
+ refunded: 0n,
205
+ remaining: S
206
+ });
207
+ } else if (s.kind === "reverse") {
208
+ r(t, [
209
+ "id",
210
+ "sequence",
211
+ "kind",
212
+ "at",
213
+ "originalId",
214
+ "refundId",
215
+ "seasonId",
216
+ "totalRefunded",
217
+ "delta"
218
+ ], "invalid_record");
219
+ let n = i(s.originalId, "invalid_record"), a = i(s.refundId, "invalid_record"), o = m.get(n), c = h(s.totalRefunded);
220
+ if (!o || o.entry.seasonId !== b || c <= o.refunded || c > BigInt(o.entry.purchaseAmount) || f.has(JSON.stringify([o.entry.sourceId, a]))) throw e("invalid_record");
221
+ let l = (BigInt(o.entry.purchaseAmount) - c) * BigInt(o.entry.numerator) / BigInt(o.entry.denominator);
222
+ if (S !== l - o.remaining || S > 0n) throw e("invalid_record");
223
+ f.add(JSON.stringify([o.entry.sourceId, a])), o.refunded = c, o.remaining = l, x = Object.freeze({
224
+ id: _,
225
+ sequence: y,
226
+ kind: "reverse",
227
+ at: v,
228
+ originalId: n,
229
+ refundId: a,
230
+ seasonId: b,
231
+ totalRefunded: c.toString(),
232
+ delta: S.toString()
233
+ });
234
+ } else throw e("invalid_record");
235
+ let C = (p.get(b) ?? 0n) + S;
236
+ return p.set(b, o(C)), x;
237
+ }));
238
+ return Object.freeze({
239
+ entries: _,
240
+ balances: Object.freeze([...p].sort(([e], [t]) => (e ?? "") < (t ?? "") ? -1 : +((e ?? "") > (t ?? ""))).map(([e, t]) => Object.freeze({
241
+ seasonId: e,
242
+ points: t.toString()
243
+ }))),
244
+ credits: Object.freeze([...m.values()].map((e) => Object.freeze({
245
+ id: e.entry.id,
246
+ refundedAmount: e.refunded.toString(),
247
+ remainingPoints: e.remaining.toString()
248
+ })))
249
+ });
250
+ }, x = class extends d.Service()("@voltro/LoyaltyPort") {}, S = (e) => t(e, [
251
+ "list",
252
+ "mine",
253
+ "credit",
254
+ "reverse",
255
+ "receipt",
256
+ "rebuild",
257
+ "exportSubject",
258
+ "eraseSubject"
259
+ ]), C = (e) => {
260
+ let t = r(e, [
261
+ "tenantId",
262
+ "ownerId",
263
+ "loyaltyId",
264
+ "sourceId",
265
+ "purchaseId",
266
+ "requestId"
267
+ ]);
268
+ return Object.freeze({
269
+ tenantId: i(t.tenantId),
270
+ ownerId: i(t.ownerId),
271
+ loyaltyId: i(t.loyaltyId),
272
+ sourceId: i(t.sourceId),
273
+ purchaseId: i(t.purchaseId),
274
+ requestId: i(t.requestId)
275
+ });
276
+ }, w = (e) => {
277
+ let t = r(e, [
278
+ "tenantId",
279
+ "ownerId",
280
+ "loyaltyId",
281
+ "originalId",
282
+ "refundId",
283
+ "requestId"
284
+ ]);
285
+ return Object.freeze({
286
+ tenantId: i(t.tenantId),
287
+ ownerId: i(t.ownerId),
288
+ loyaltyId: i(t.loyaltyId),
289
+ originalId: i(t.originalId),
290
+ refundId: i(t.refundId),
291
+ requestId: i(t.requestId)
292
+ });
293
+ }, T = (e) => {
294
+ let t = r(e, ["loyaltyId"]);
295
+ return Object.freeze({ loyaltyId: i(t.loyaltyId) });
296
+ }, E = (e) => {
297
+ let t = r(e, ["requestId"]);
298
+ return Object.freeze({ requestId: i(t.requestId) });
299
+ }, D = (e) => {
300
+ let t = r(e, [
301
+ "tenantId",
302
+ "ownerId",
303
+ "loyaltyId"
304
+ ]);
305
+ return Object.freeze({
306
+ tenantId: i(t.tenantId),
307
+ ownerId: i(t.ownerId),
308
+ loyaltyId: i(t.loyaltyId)
309
+ });
310
+ };
311
+ export { x as LoyaltyPort, S as captureLoyaltyService, v as defaultLoyaltyPerks, h as defaultLoyaltyTier, p as defineLoyalty, C as loyaltyCreditIntent, T as loyaltyMineIntent, m as loyaltyPointsForPurchase, D as loyaltyRebuildIntent, E as loyaltyReceiptIntent, w as loyaltyReverseIntent, b as projectLoyaltyPoints, y as resolveLoyaltyPerks, _ as resolveLoyaltyTier };
@@ -0,0 +1,203 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { captureQueryTables as n, dataList as r, dataObject as i, declaredSources as a, identifier as o } from "./capture.js";
3
+ import { loyaltyListDescriptor as s, loyaltyMineDescriptor as c, loyaltyReceiptDescriptor as l, loyaltyRpcClientImports as u } from "./rpc.js";
4
+ import { LoyaltyPort as d, captureLoyaltyService as f, defaultLoyaltyPerks as p, defaultLoyaltyTier as m, defineLoyalty as h, loyaltyCreditIntent as g, loyaltyMineIntent as _, loyaltyRebuildIntent as v, loyaltyReceiptIntent as y, loyaltyReverseIntent as b } from "./loyalty.js";
5
+ import { loyaltyTables as x } from "./loyaltyTables.entity.js";
6
+ import { dataStoreLoyalty as S, resolveLoyaltyStoreOptions as C } from "./loyaltyStore.server.js";
7
+ import { Effect as w, Layer as T } from "effect";
8
+ // src/loyaltyBinding.server.ts
9
+ var E = () => w.fail(t("unavailable")), D = Object.freeze({
10
+ list: E,
11
+ mine: E,
12
+ credit: E,
13
+ reverse: E,
14
+ receipt: E,
15
+ rebuild: E,
16
+ exportSubject: E,
17
+ eraseSubject: E
18
+ }), O = (E, D) => {
19
+ if (E === void 0) return;
20
+ let O = i(E, [
21
+ "loyalty",
22
+ "receiptSource",
23
+ "seasonSource",
24
+ "version",
25
+ "tier",
26
+ "perks",
27
+ "allowedServices",
28
+ "maxHistoryRows",
29
+ "maxDefinitionRows",
30
+ "maxSeasonRows",
31
+ "now",
32
+ "service",
33
+ "querySources"
34
+ ]), k = O.service === void 0 ? void 0 : f(O.service);
35
+ if (k && [
36
+ "receiptSource",
37
+ "seasonSource",
38
+ "tier",
39
+ "perks",
40
+ "allowedServices",
41
+ "maxHistoryRows",
42
+ "maxDefinitionRows",
43
+ "maxSeasonRows",
44
+ "now"
45
+ ].some((e) => O[e] !== void 0)) throw t("invalid_input");
46
+ let A = O.querySources === void 0 ? void 0 : i(O.querySources, [
47
+ "list",
48
+ "mine",
49
+ "receipt"
50
+ ]);
51
+ if (k && !A) throw t("invalid_input");
52
+ let j = A ? Object.freeze({
53
+ list: n(A.list),
54
+ mine: n(A.mine),
55
+ receipt: n(A.receipt)
56
+ }) : void 0, M = k ? void 0 : C({
57
+ currencies: D.currencies,
58
+ realMoney: D.realMoney,
59
+ loyalty: O.loyalty,
60
+ receiptSource: O.receiptSource,
61
+ seasonSource: O.seasonSource,
62
+ version: O.version,
63
+ tier: O.tier,
64
+ perks: O.perks,
65
+ allowedServices: O.allowedServices ?? D.allowedServices,
66
+ maxHistoryRows: O.maxHistoryRows,
67
+ maxDefinitionRows: O.maxDefinitionRows,
68
+ maxSeasonRows: O.maxSeasonRows,
69
+ now: O.now ?? D.now
70
+ }), N = M?.loyalty ?? Object.freeze(r(O.loyalty, 32).map((e) => h(e, D.currencies, D.realMoney)));
71
+ if (!N.length || new Set(N.map((e) => e.id)).size !== N.length) throw t("invalid_input");
72
+ let P = M?.version ?? o(O.version);
73
+ if (P === "default.v1") throw t("invalid_input");
74
+ let F = new Set(M?.allowedServices ?? D.allowedServices), I, L = !1, R, z = (e) => w.suspend(() => {
75
+ let n = k ?? I;
76
+ return L && n ? e(n) : w.fail(t("unavailable"));
77
+ }), B = (n) => {
78
+ try {
79
+ return n();
80
+ } catch (n) {
81
+ return w.fail(n instanceof e ? n : t("invalid_input"));
82
+ }
83
+ }, V = (e) => {
84
+ let n = structuredClone(e);
85
+ if (n.type !== "user") throw t("forbidden");
86
+ return o(n.id), o(n.tenantId), n;
87
+ }, H = (e) => {
88
+ let n = structuredClone(e);
89
+ if (n.type !== "system" && (n.type !== "service" || !F.has(n.service))) throw t("forbidden");
90
+ return n;
91
+ }, U = (e) => {
92
+ let n = i(e, [
93
+ "tenantId",
94
+ "subjectId",
95
+ "kind"
96
+ ]);
97
+ if (n.kind !== "user" && n.kind !== "guest") throw t("invalid_input");
98
+ return Object.freeze({
99
+ tenantId: o(n.tenantId),
100
+ subjectId: o(n.subjectId),
101
+ kind: n.kind
102
+ });
103
+ }, W = Object.freeze({
104
+ list: (e) => B(() => {
105
+ let t = V(e);
106
+ return z((e) => e.list(t));
107
+ }),
108
+ mine: (e, t) => B(() => {
109
+ let n = V(e), r = _(t);
110
+ return z((e) => e.mine(n, r));
111
+ }),
112
+ credit: (e, t) => B(() => {
113
+ let n = H(e), r = g(t);
114
+ return z((e) => e.credit(n, r));
115
+ }),
116
+ reverse: (e, t) => B(() => {
117
+ let n = H(e), r = b(t);
118
+ return z((e) => e.reverse(n, r));
119
+ }),
120
+ receipt: (e, t) => B(() => {
121
+ let n = V(e), r = y(t);
122
+ return z((e) => e.receipt(n, r));
123
+ }),
124
+ rebuild: (e, t) => B(() => {
125
+ let n = H(e), r = v(t);
126
+ return z((e) => e.rebuild(n, r));
127
+ }),
128
+ exportSubject: (e) => B(() => {
129
+ let t = U(e);
130
+ return z((e) => e.exportSubject(t));
131
+ }),
132
+ eraseSubject: (e) => B(() => {
133
+ let t = U(e);
134
+ return z((e) => e.eraseSubject(t));
135
+ })
136
+ }), G = (e, t) => k ? j[e] : [.../* @__PURE__ */ new Set([...t, ...j?.[e] ?? []])], K = [
137
+ {
138
+ ...s,
139
+ source: G("list", a(s.source)),
140
+ execute: (e, t) => W.list(t.request.subject)
141
+ },
142
+ {
143
+ ...c,
144
+ source: G("mine", a(c.source)),
145
+ execute: (e, t) => W.mine(t.request.subject, e)
146
+ },
147
+ {
148
+ ...l,
149
+ source: G("receipt", a(l.source)),
150
+ execute: (e, t) => W.receipt(t.request.subject, e)
151
+ }
152
+ ], q = M ? x : [], J = Object.freeze({
153
+ backend: k ? "custom" : "sql",
154
+ version: P,
155
+ slots: Object.freeze({
156
+ tier: k || M?.tier !== m ? "custom" : "default",
157
+ perks: k || M?.perks !== p ? "custom" : "default"
158
+ }),
159
+ receiptSource: k ? "app-owned" : "custom",
160
+ seasonSource: k ? "app-owned" : M?.seasonSource ? "custom" : "none",
161
+ loyalty: Object.freeze(N.map((e) => Object.freeze({
162
+ id: e.id,
163
+ version: e.version,
164
+ decay: e.decay,
165
+ sourceKinds: e.pointsFrom.length,
166
+ realSourceKinds: e.pointsFrom.filter((e) => e.kind === "purchase.real").length,
167
+ tierKinds: e.tiers.length
168
+ }))),
169
+ budgets: k ? null : Object.freeze({
170
+ historyRows: M.maxHistoryRows,
171
+ definitionRows: M.maxDefinitionRows,
172
+ seasonRows: M.maxSeasonRows
173
+ }),
174
+ virtualPointsInstalled: !0,
175
+ realReceiptVerificationInstalled: !1,
176
+ perkEffectsInstalled: !1,
177
+ automaticConsumptionInstalled: !1,
178
+ gmActionsInstalled: !1
179
+ });
180
+ return Object.freeze({
181
+ service: W,
182
+ layer: T.succeed(d, W),
183
+ tables: q,
184
+ routes: K,
185
+ status: J,
186
+ rpcClientDescriptors: u,
187
+ roles: M ? [
188
+ "loyaltyTenants",
189
+ "loyaltyDefinitions",
190
+ "loyaltySubjects",
191
+ "loyaltyEntries",
192
+ "loyaltySeasons"
193
+ ] : [],
194
+ bind: (e) => {
195
+ if (R !== void 0 && R !== e) throw Error("Loyalty system cannot cross app stores");
196
+ R = e, M && (I = S(e, M)), L = !0;
197
+ },
198
+ deactivate: () => {
199
+ L = !1, I = void 0;
200
+ }
201
+ });
202
+ };
203
+ export { O as bindLoyaltySystem, D as unavailableLoyalty };
@@ -0,0 +1,86 @@
1
+ import { LoyaltyPort as e } from "./loyalty.js";
2
+ import { economyPlugin as t } from "./plugin.js";
3
+ import { shopMachine as n } from "./shop.testFixtures.js";
4
+ import { loyaltyStoreFixture as r } from "./loyaltyStore.testFixtures.js";
5
+ import { Effect as i, Layer as a } from "effect";
6
+ import { InMemoryDataStore as o } from "@voltro/runtime";
7
+ // src/loyaltyPort.fixture.ts
8
+ var s = {
9
+ app: {
10
+ name: "loyalty-fixture",
11
+ type: "api",
12
+ voltroVersion: "0.83.1"
13
+ },
14
+ config: {},
15
+ env: {},
16
+ logger: {
17
+ info() {},
18
+ warn() {},
19
+ error() {},
20
+ debug() {}
21
+ }
22
+ }, c = i.gen(function* () {
23
+ let e = new o(), a = yield* i.promise(() => r(e, "fixture")), c = a.options, l = yield* a.base.shop.buy(a.base.user, a.base.buy), u = t({
24
+ currencies: c.currencies,
25
+ now: c.now,
26
+ loyalty: {
27
+ loyalty: c.loyalty,
28
+ receiptSource: c.receiptSource,
29
+ seasonSource: c.seasonSource,
30
+ version: c.version,
31
+ tier: c.tier,
32
+ perks: c.perks,
33
+ allowedServices: c.allowedServices,
34
+ maxHistoryRows: c.maxHistoryRows,
35
+ maxDefinitionRows: c.maxDefinitionRows,
36
+ maxSeasonRows: c.maxSeasonRows,
37
+ now: c.now
38
+ }
39
+ });
40
+ yield* i.promise(async () => {
41
+ await u.bindDataStore?.(e);
42
+ });
43
+ let d = yield* u.economy.loyalty().credit(n, a.credit(l.orderId));
44
+ return Object.freeze({
45
+ store: e,
46
+ plugin: u,
47
+ base: a,
48
+ purchase: l,
49
+ accepted: d,
50
+ close: i.suspend(() => u.onDeactivate?.(s))
51
+ });
52
+ }), l = a.effectContext(i.acquireRelease(c, (e) => e.close).pipe(i.flatMap((e) => a.build(e.plugin.services)))), u = Object.freeze({
53
+ kind: "port",
54
+ tag: e,
55
+ fakeLayer: l,
56
+ probe: {
57
+ run: () => i.scoped(i.gen(function* () {
58
+ let t = yield* e, r = {
59
+ type: "user",
60
+ id: "a",
61
+ tenantId: "fixture",
62
+ kind: "guest"
63
+ }, i = yield* t.receipt(r, { requestId: "credit" });
64
+ if (i.state !== "fulfilled" || i.receipt.entry.kind !== "credit") throw Error("Actual fixture purchase evidence was not admitted");
65
+ let a = i.receipt.entry, o = yield* t.credit(n, {
66
+ tenantId: "fixture",
67
+ ownerId: "a",
68
+ loyaltyId: "vip",
69
+ sourceId: a.sourceId,
70
+ purchaseId: a.purchaseId,
71
+ requestId: "credit"
72
+ }), s = yield* t.mine(r, { loyaltyId: "vip" });
73
+ return {
74
+ same: i.receipt.operationId === o.operationId,
75
+ points: s.points,
76
+ tier: s.tierId
77
+ };
78
+ }).pipe(i.provide(l))),
79
+ expected: {
80
+ same: !0,
81
+ points: "10",
82
+ tier: "silver"
83
+ }
84
+ }
85
+ });
86
+ export { l as loyaltyFakeLayer, c as loyaltyPortFixture, u as loyaltyPortSystemFixture };
@@ -0,0 +1,90 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { captureBoundMethods as n, dataObject as r, identifier as i } from "./capture.js";
3
+ import { shopBuyIntent as a } from "./shop.js";
4
+ import { shopOrdersTable as o } from "./shopTables.entity.js";
5
+ import { Effect as s, Result as c } from "effect";
6
+ import { eq as l, queryFor as u } from "@voltro/database";
7
+ // src/loyaltyShopSource.server.ts
8
+ var d = (d, f) => {
9
+ let p = r(f, ["shop", "refunds"]), m = n(p.shop, ["receipt"]), h = p.refunds === void 0 ? void 0 : n(p.refunds, ["read"]);
10
+ return Object.freeze({
11
+ purchase: (n) => {
12
+ try {
13
+ let f = r(n, [
14
+ "tenantId",
15
+ "ownerId",
16
+ "source",
17
+ "purchaseId"
18
+ ]), p = r(f.source, [
19
+ "id",
20
+ "kind",
21
+ "currency",
22
+ "numerator",
23
+ "denominator"
24
+ ]), h = i(f.tenantId), g = i(f.ownerId), _ = i(f.purchaseId), v = i(p.currency);
25
+ if (p.kind !== "purchase.virtual") throw t("forbidden");
26
+ return s.tryPromise({
27
+ try: async () => {
28
+ let e = (await d.query(u(o).where(l("id", _)).limit(1).descriptor))[0];
29
+ if (!e) throw t("not_found");
30
+ if (e.tenantId !== h || e.ownerId !== g) throw t("forbidden");
31
+ if (e.state !== "fulfilled") throw t(e.state === "erased" ? "erased" : "not_found");
32
+ let n = r(e.intent, [
33
+ "request",
34
+ "offer",
35
+ "currencies",
36
+ "realMoney",
37
+ "rulesVersion",
38
+ "price",
39
+ "adjustments",
40
+ "quotedAt",
41
+ "at",
42
+ "counters"
43
+ ], "invalid_record"), i = r(n.request, [
44
+ "tenantId",
45
+ "ownerId",
46
+ "offerId",
47
+ "offerVersion",
48
+ "offerDigest",
49
+ "requestId",
50
+ "currency",
51
+ "qty"
52
+ ], "invalid_record");
53
+ if (i.tenantId !== h || i.ownerId !== g) throw t("invalid_record");
54
+ let { tenantId: f, ownerId: p, ...y } = i, b = a({
55
+ ...y,
56
+ currency: y.currency ?? void 0
57
+ }), x = Object.freeze({
58
+ type: "user",
59
+ tenantId: h,
60
+ id: g
61
+ }), S = await s.runPromise(s.result(m.receipt(x, {
62
+ ...b,
63
+ currency: b.currency ?? void 0
64
+ })));
65
+ if (c.isFailure(S)) throw S.failure;
66
+ if (S.success.state !== "fulfilled") throw t("not_found");
67
+ let C = S.success.receipt;
68
+ if (C.orderId !== _ || C.pricePaid.kind !== "virtual" || C.pricePaid.currency !== v) throw t("forbidden");
69
+ return Object.freeze({
70
+ tenantId: h,
71
+ ownerId: g,
72
+ authorityId: "economy.shop.sql.v1",
73
+ purchaseId: _,
74
+ kind: "purchase.virtual",
75
+ currency: C.pricePaid.currency,
76
+ amount: C.pricePaid.amount,
77
+ settledAt: C.at,
78
+ refundedAmount: "0"
79
+ });
80
+ },
81
+ catch: (n) => n instanceof e ? n : t("unavailable")
82
+ });
83
+ } catch (n) {
84
+ return s.fail(n instanceof e ? n : t("invalid_input"));
85
+ }
86
+ },
87
+ refund: (e) => h ? h.read(e) : s.fail(t("not_found"))
88
+ });
89
+ };
90
+ export { d as shopLoyaltyReceiptSource };