@voltro/plugin-economy 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 (177) hide show
  1. package/CHANGELOG.md +24329 -0
  2. package/LICENSE +61 -0
  3. package/README.md +2719 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9189 -0
  6. package/dist/amount.js +21 -0
  7. package/dist/appleIap.server.js +263 -0
  8. package/dist/appleIapNotifications.server.js +163 -0
  9. package/dist/appleIapTrust.server.js +31 -0
  10. package/dist/bundleValue.server.js +113 -0
  11. package/dist/canonicalDataJson.js +11 -0
  12. package/dist/capture.js +54 -0
  13. package/dist/codePort.fixture.js +124 -0
  14. package/dist/codeStore.server.js +440 -0
  15. package/dist/codeTables.entity.js +44 -0
  16. package/dist/codes.d.ts +150 -0
  17. package/dist/codes.js +83 -0
  18. package/dist/components.d.ts +397 -0
  19. package/dist/components.js +284 -0
  20. package/dist/consistency.server.js +116 -0
  21. package/dist/containerStore.server.js +688 -0
  22. package/dist/containerStore.testFixtures.js +76 -0
  23. package/dist/containerTables.entity.js +46 -0
  24. package/dist/containers.d.ts +311 -0
  25. package/dist/containers.fixture.js +129 -0
  26. package/dist/containers.js +215 -0
  27. package/dist/containers.server.js +40 -0
  28. package/dist/containersPort.fixture.js +75 -0
  29. package/dist/currency.js +33 -0
  30. package/dist/declarationFixtures.js +62 -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 +125 -0
  34. package/dist/errors.d.ts +14 -0
  35. package/dist/errors.js +22 -0
  36. package/dist/events.d.ts +46 -0
  37. package/dist/events.js +1 -0
  38. package/dist/googleIap.server.js +392 -0
  39. package/dist/googleIapNotifications.server.js +131 -0
  40. package/dist/googleIapSubscription.server.js +184 -0
  41. package/dist/iap.d.ts +309 -0
  42. package/dist/iap.js +304 -0
  43. package/dist/iap.testFixtures.js +145 -0
  44. package/dist/iapAccountTables.entity.js +40 -0
  45. package/dist/iapAccounts.server.js +201 -0
  46. package/dist/iapBinding.server.js +524 -0
  47. package/dist/iapCheckout.server.js +98 -0
  48. package/dist/iapCompletion.server.js +56 -0
  49. package/dist/iapCurrentState.server.js +108 -0
  50. package/dist/iapCurrentState.testFixtures.js +23 -0
  51. package/dist/iapCurrentStatePort.fixture.js +64 -0
  52. package/dist/iapEntitlements.d.ts +79 -0
  53. package/dist/iapEntitlements.js +58 -0
  54. package/dist/iapEntitlements.server.js +49 -0
  55. package/dist/iapEntitlementsBinding.server.js +106 -0
  56. package/dist/iapEntitlementsPort.fixture.js +81 -0
  57. package/dist/iapInstalledEntitlements.testFixtures.js +76 -0
  58. package/dist/iapInstalledNotifications.testFixtures.js +94 -0
  59. package/dist/iapInventoryRefunds.server.js +262 -0
  60. package/dist/iapNotificationCustodyPort.fixture.js +68 -0
  61. package/dist/iapNotificationPort.fixture.js +74 -0
  62. package/dist/iapNotificationProcessor.server.js +135 -0
  63. package/dist/iapNotificationProcessor.testFixtures.js +64 -0
  64. package/dist/iapNotificationProcessorPort.fixture.js +56 -0
  65. package/dist/iapNotificationSchedule.server.js +70 -0
  66. package/dist/iapNotificationStore.server.js +353 -0
  67. package/dist/iapNotificationStore.testFixtures.js +32 -0
  68. package/dist/iapNotificationTables.entity.js +49 -0
  69. package/dist/iapNotificationTarget.server.js +37 -0
  70. package/dist/iapNotificationTarget.testFixtures.js +30 -0
  71. package/dist/iapNotifications.d.ts +644 -0
  72. package/dist/iapNotifications.js +6 -0
  73. package/dist/iapNotifications.server.js +96 -0
  74. package/dist/iapNotificationsBinding.server.js +233 -0
  75. package/dist/iapNotificationsSystemPort.fixture.js +51 -0
  76. package/dist/iapPlugin.testFixtures.js +60 -0
  77. package/dist/iapPort.fixture.js +75 -0
  78. package/dist/iapProviderCapture.server.js +18 -0
  79. package/dist/iapRecovery.d.ts +146 -0
  80. package/dist/iapRecovery.js +90 -0
  81. package/dist/iapRefundEventDelivery.server.js +83 -0
  82. package/dist/iapRefundEvents.js +45 -0
  83. package/dist/iapRefundEventsPort.fixture.js +60 -0
  84. package/dist/iapRefundPort.fixture.js +55 -0
  85. package/dist/iapRefundTables.entity.js +56 -0
  86. package/dist/iapRefunds.d.ts +755 -0
  87. package/dist/iapRefunds.js +6 -0
  88. package/dist/iapRefunds.server.js +554 -0
  89. package/dist/iapRefunds.testFixtures.js +65 -0
  90. package/dist/iapSpendAdmission.server.js +99 -0
  91. package/dist/iapStore.server.js +741 -0
  92. package/dist/iapStore.testFixtures.js +128 -0
  93. package/dist/iapTables.entity.js +81 -0
  94. package/dist/iapVerification.server.js +121 -0
  95. package/dist/index.d.ts +2984 -0
  96. package/dist/index.js +15 -0
  97. package/dist/intentionRecovery.js +134 -0
  98. package/dist/ledger.js +78 -0
  99. package/dist/loyalty.d.ts +274 -0
  100. package/dist/loyalty.fixture.js +93 -0
  101. package/dist/loyalty.js +312 -0
  102. package/dist/loyaltyBinding.server.js +204 -0
  103. package/dist/loyaltyPort.fixture.js +87 -0
  104. package/dist/loyaltyShopSource.server.js +91 -0
  105. package/dist/loyaltyStore.server.js +553 -0
  106. package/dist/loyaltyStore.testFixtures.js +83 -0
  107. package/dist/loyaltyTables.entity.js +50 -0
  108. package/dist/offerMerchandising.fixture.js +115 -0
  109. package/dist/offerMerchandising.js +283 -0
  110. package/dist/offerPolicies.d.ts +441 -0
  111. package/dist/offerPolicies.fixture.js +54 -0
  112. package/dist/offerPolicies.js +268 -0
  113. package/dist/piggyBanks.d.ts +272 -0
  114. package/dist/piggyBanks.fixture.js +71 -0
  115. package/dist/piggyBanks.js +201 -0
  116. package/dist/piggyBinding.server.js +205 -0
  117. package/dist/piggyPort.fixture.js +73 -0
  118. package/dist/piggyStore.server.js +611 -0
  119. package/dist/piggyStore.testFixtures.js +98 -0
  120. package/dist/piggyTables.entity.js +41 -0
  121. package/dist/plugin.js +1048 -0
  122. package/dist/port.js +13 -0
  123. package/dist/price.d.ts +99 -0
  124. package/dist/price.js +144 -0
  125. package/dist/purchaseRecovery.js +56 -0
  126. package/dist/reports.server.js +115 -0
  127. package/dist/rpc.d.ts +3201 -0
  128. package/dist/rpc.js +1201 -0
  129. package/dist/sanctionsTradeAuthority.server.js +80 -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 +196 -0
  134. package/dist/shop.testFixtures.js +114 -0
  135. package/dist/shopPort.fixture.js +72 -0
  136. package/dist/shopPresentation.js +68 -0
  137. package/dist/shopStore.server.js +624 -0
  138. package/dist/shopTables.entity.js +63 -0
  139. package/dist/shopUiCopy.js +57 -0
  140. package/dist/spendLimits.d.ts +140 -0
  141. package/dist/spendLimits.fixture.js +53 -0
  142. package/dist/spendLimits.js +155 -0
  143. package/dist/spendLimitsPort.fixture.js +120 -0
  144. package/dist/subscriptionBinding.server.js +211 -0
  145. package/dist/subscriptionStore.server.js +643 -0
  146. package/dist/subscriptionStore.testFixtures.js +72 -0
  147. package/dist/subscriptionTables.entity.js +37 -0
  148. package/dist/subscriptions.d.ts +394 -0
  149. package/dist/subscriptions.fixture.js +97 -0
  150. package/dist/subscriptions.js +213 -0
  151. package/dist/subscriptionsPort.fixture.js +76 -0
  152. package/dist/systemFixtures.js +89 -0
  153. package/dist/tables.entity.js +83 -0
  154. package/dist/testing.d.ts +4615 -0
  155. package/dist/testing.js +29 -0
  156. package/dist/tradeAuthority.server.js +172 -0
  157. package/dist/tradeBinding.server.js +201 -0
  158. package/dist/tradeComponents.js +342 -0
  159. package/dist/tradeEscrow.server.js +232 -0
  160. package/dist/tradeEscrow.testFixtures.js +133 -0
  161. package/dist/tradeExpiry.server.js +43 -0
  162. package/dist/tradeRecovery.js +48 -0
  163. package/dist/tradeStore.server.js +750 -0
  164. package/dist/tradeStore.testFixtures.js +73 -0
  165. package/dist/tradeTables.entity.js +66 -0
  166. package/dist/tradeUiCopy.js +79 -0
  167. package/dist/trades.d.ts +246 -0
  168. package/dist/trades.fixture.js +103 -0
  169. package/dist/trades.js +289 -0
  170. package/dist/tradesPort.fixture.js +94 -0
  171. package/dist/walletEscrow.js +106 -0
  172. package/dist/walletEscrow.server.js +376 -0
  173. package/dist/walletKeys.server.js +5 -0
  174. package/dist/walletStore.js +571 -0
  175. package/dist/web.d.ts +2257 -0
  176. package/dist/web.js +9 -0
  177. package/package.json +161 -4
@@ -0,0 +1,215 @@
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 { positiveAmount as a } from "./amount.js";
4
+ import { captureCurrencies as o } from "./currency.js";
5
+ import { definePrice as s } from "./price.js";
6
+ import { shopInteger as c } from "./shop.js";
7
+ import { Context as l } from "effect";
8
+ //#region src/containers.ts
9
+ var u = (t, l, u = !1) => {
10
+ let d = r(t, [
11
+ "id",
12
+ "version",
13
+ "group",
14
+ "price",
15
+ "drops",
16
+ "pity",
17
+ "countries"
18
+ ]), f = o(l), p = Object.freeze(n(d.drops, 256).map((t) => {
19
+ let o = r(t, [
20
+ "id",
21
+ "rarity",
22
+ "weight",
23
+ "items",
24
+ "currencies"
25
+ ]), s = Object.freeze(n(o.items ?? [], 16).map((e) => {
26
+ let t = r(e, ["itemId", "qty"]);
27
+ return Object.freeze({
28
+ itemId: i(t.itemId),
29
+ qty: c(t.qty, 1, 1e6)
30
+ });
31
+ })), l = Object.freeze(n(o.currencies ?? [], 16).map((t) => {
32
+ let n = r(t, ["currency", "amount"]), o = i(n.currency), s = f.find((e) => e.id === o), c = a(n.amount);
33
+ if (!s || c > BigInt(s.cap)) throw e("invalid_currency");
34
+ return Object.freeze({
35
+ currency: o,
36
+ amount: c.toString()
37
+ });
38
+ }));
39
+ if (!s.length && !l.length || new Set(s.map((e) => e.itemId)).size !== s.length || new Set(l.map((e) => e.currency)).size !== l.length) throw e("invalid_input");
40
+ return Object.freeze({
41
+ id: i(o.id),
42
+ rarity: i(o.rarity),
43
+ weight: a(o.weight).toString(),
44
+ items: s,
45
+ currencies: l
46
+ });
47
+ }));
48
+ if (!p.length || new Set(p.map((e) => e.id)).size !== p.length) throw e("invalid_input");
49
+ let m = null;
50
+ if (d.pity != null) {
51
+ let t = r(d.pity, [
52
+ "guaranteed",
53
+ "after",
54
+ "softFrom",
55
+ "softRampBps"
56
+ ]), n = i(t.guaranteed), a = c(t.after, 1, 1e6), o = t.softFrom == null ? null : c(t.softFrom, 1, a), s = c(t.softRampBps ?? 0, 0, 1e4);
57
+ if (!p.some((e) => e.rarity === n) || o === null && s !== 0 || o !== null && s === 0) throw e("invalid_input");
58
+ m = Object.freeze({
59
+ guaranteed: n,
60
+ after: a,
61
+ softFrom: o,
62
+ softRampBps: s
63
+ });
64
+ }
65
+ let h = i(d.id), g = Object.freeze(n(d.countries ?? [], 256).map((t) => {
66
+ if (typeof t != "string" || !/^[A-Z]{2}$/.test(t)) throw e("invalid_input");
67
+ return t;
68
+ }).sort());
69
+ if (new Set(g).size !== g.length) throw e("invalid_input");
70
+ return Object.freeze({
71
+ id: h,
72
+ version: i(d.version ?? "1"),
73
+ group: i(d.group ?? h),
74
+ price: s(d.price, f, u),
75
+ drops: p,
76
+ pity: m,
77
+ countries: g
78
+ });
79
+ }, d = (t, n = !0) => {
80
+ if (typeof t != "string" || !/^(0|[1-9][0-9]{0,255})$/.test(t) || !n && t === "0") throw e("invalid_input");
81
+ return BigInt(t);
82
+ }, f = (t) => {
83
+ let n = r(t, [
84
+ "container",
85
+ "misses",
86
+ "currencies",
87
+ "realMoney"
88
+ ]), i = o(n.currencies), a = n.realMoney ?? !1;
89
+ if (typeof a != "boolean") throw e("invalid_input");
90
+ let s = u(n.container, i, a), l = c(n.misses, 0, s.pity ? s.pity.after - 1 : 0);
91
+ return Object.freeze({
92
+ container: s,
93
+ misses: l,
94
+ currencies: i,
95
+ realMoney: a
96
+ });
97
+ }, p = ({ container: e, misses: t }) => {
98
+ let n = e.pity, r = e.drops.map((e) => BigInt(e.weight)), i = r.reduce((e, t) => e + t, 0n);
99
+ if (!n) return Object.freeze(e.drops.map((e, t) => Object.freeze({
100
+ dropId: e.id,
101
+ weight: r[t].toString()
102
+ })));
103
+ let a = e.drops.reduce((e, t, i) => e + (t.rarity === n.guaranteed ? r[i] : 0n), 0n), o = i - a;
104
+ if (t + 1 >= n.after || o === 0n) return Object.freeze(e.drops.map((e, t) => Object.freeze({
105
+ dropId: e.id,
106
+ weight: e.rarity === n.guaranteed ? r[t].toString() : "0"
107
+ })));
108
+ if (n.softFrom === null || t + 1 < n.softFrom) return Object.freeze(e.drops.map((e, t) => Object.freeze({
109
+ dropId: e.id,
110
+ weight: r[t].toString()
111
+ })));
112
+ let s = a * 10000n + BigInt(t + 2 - n.softFrom) * BigInt(n.softRampBps) * i, c = i * 10000n, l = s > c ? c : s;
113
+ return Object.freeze(e.drops.map((e, t) => Object.freeze({
114
+ dropId: e.id,
115
+ weight: (e.rarity === n.guaranteed ? r[t] * l * o : r[t] * (c - l) * a).toString()
116
+ })));
117
+ }, m = (t, a = p) => {
118
+ if (typeof a != "function") throw e("invalid_input");
119
+ let o = f(t), s = n(a(o), 256), c = /* @__PURE__ */ new Set(), l = Object.freeze(s.map((t) => {
120
+ let n = r(t, ["dropId", "weight"]), a = i(n.dropId), s = d(n.weight);
121
+ if (c.has(a) || !o.container.drops.some((e) => e.id === a)) throw e("invalid_input");
122
+ return c.add(a), Object.freeze({
123
+ dropId: a,
124
+ weight: s.toString()
125
+ });
126
+ }));
127
+ if (l.length !== o.container.drops.length) throw e("invalid_input");
128
+ let u = l.reduce((e, t) => e + d(t.weight), 0n);
129
+ if (u === 0n || u.toString().length > 256) throw e("invalid_input");
130
+ let m = o.container.pity !== null && o.misses + 1 >= o.container.pity.after;
131
+ if (m && l.some((e) => d(e.weight) > 0n && o.container.drops.find((t) => t.id === e.dropId).rarity !== o.container.pity.guaranteed)) throw e("invalid_input");
132
+ return Object.freeze({
133
+ entries: l,
134
+ total: u.toString(),
135
+ guaranteed: m
136
+ });
137
+ }, h = (e, t = p) => {
138
+ let n = m(e, t);
139
+ return Object.freeze({
140
+ guaranteed: n.guaranteed,
141
+ probabilities: Object.freeze(n.entries.map((e) => Object.freeze({
142
+ dropId: e.dropId,
143
+ numerator: e.weight,
144
+ denominator: n.total
145
+ })))
146
+ });
147
+ }, g = ({ distribution: t, draw: n }) => {
148
+ let r = d(n);
149
+ if (r >= d(t.total, !1)) throw e("invalid_input");
150
+ for (let e of t.entries) {
151
+ let t = d(e.weight);
152
+ if (r < t) return e.dropId;
153
+ r -= t;
154
+ }
155
+ throw e("invalid_input");
156
+ }, _ = (t, n, r = p, a = g) => {
157
+ if (typeof a != "function") throw e("invalid_input");
158
+ let o = f(t), s = m(o, r), c = d(n);
159
+ if (c >= d(s.total, !1)) throw e("invalid_input");
160
+ let l = i(a(Object.freeze({
161
+ distribution: s,
162
+ draw: c.toString()
163
+ }))), u = s.entries.find((e) => e.dropId === l);
164
+ if (!u || d(u.weight) === 0n) throw e("invalid_input");
165
+ let h = o.container.drops.find((e) => e.id === l), _ = o.container.pity !== null && h.rarity === o.container.pity.guaranteed;
166
+ return Object.freeze({
167
+ drop: h,
168
+ misses: o.container.pity === null || _ ? 0 : o.misses + 1,
169
+ distribution: s
170
+ });
171
+ }, v = class extends l.Service()("@voltro/ContainerRandomPort") {}, y = (t) => {
172
+ let n = r(t, [
173
+ "containerId",
174
+ "containerVersion",
175
+ "containerDigest",
176
+ "disclosureDigest",
177
+ "requestId",
178
+ "currency"
179
+ ]);
180
+ if (typeof n.containerDigest != "string" || !/^[a-f0-9]{64}$/.test(n.containerDigest) || typeof n.disclosureDigest != "string" || !/^[a-f0-9]{64}$/.test(n.disclosureDigest)) throw e("invalid_input");
181
+ return Object.freeze({
182
+ containerId: i(n.containerId),
183
+ containerVersion: i(n.containerVersion),
184
+ containerDigest: n.containerDigest,
185
+ disclosureDigest: n.disclosureDigest,
186
+ requestId: i(n.requestId),
187
+ currency: n.currency === void 0 ? null : i(n.currency)
188
+ });
189
+ }, b = (e) => !e.isMinor && e.eligible && (e.container.countries.length === 0 || e.container.countries.includes(e.country)), x = (t, n, i = !1, a = b) => {
190
+ let o = r(t, [
191
+ "container",
192
+ "at",
193
+ "isMinor",
194
+ "country",
195
+ "eligible"
196
+ ]);
197
+ if (typeof a != "function" || typeof o.isMinor != "boolean" || typeof o.eligible != "boolean" || typeof o.country != "string" || !/^[A-Z]{2}$/.test(o.country)) throw e("invalid_input");
198
+ let s = Object.freeze({
199
+ container: u(o.container, n, i),
200
+ at: c(o.at, 0, 864e13),
201
+ isMinor: o.isMinor,
202
+ country: o.country,
203
+ eligible: o.eligible
204
+ }), l = a(s);
205
+ if (typeof l != "boolean") throw e("invalid_input");
206
+ return l && b(s);
207
+ }, S = class extends l.Service()("@voltro/ContainersPort") {}, C = (e) => t(e, [
208
+ "list",
209
+ "open",
210
+ "receipt",
211
+ "exportSubject",
212
+ "eraseSubject"
213
+ ]);
214
+ //#endregion
215
+ export { v as ContainerRandomPort, S as ContainersPort, y as captureContainerIntent, C as captureContainersService, f as containerProbabilityContext, b as defaultContainerEligibility, p as defaultContainerProbability, g as defaultContainerRoll, u as defineContainer, h as discloseContainer, m as resolveContainerDistribution, x as resolveContainerEligibility, _ as resolveContainerRoll };
@@ -0,0 +1,40 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { ContainerRandomPort as n, containerProbabilityContext as r, defaultContainerProbability as i, defaultContainerRoll as a, resolveContainerDistribution as o, resolveContainerRoll as s } from "./containers.js";
3
+ import { Effect as c, Layer as l } from "effect";
4
+ import { randomBytes as u } from "node:crypto";
5
+ //#region src/containers.server.ts
6
+ var d = Object.freeze({ draw: (n) => {
7
+ let r;
8
+ try {
9
+ if (typeof n != "string" || !/^[1-9][0-9]{0,255}$/.test(n)) throw t("invalid_input");
10
+ r = BigInt(n);
11
+ } catch {
12
+ return c.fail(t("invalid_input"));
13
+ }
14
+ return c.try({
15
+ try: () => {
16
+ if (r === 1n) return "0";
17
+ let e = (r - 1n).toString(2).length, n = Math.ceil(e / 8), i = 255 >>> n * 8 - e;
18
+ for (let e = 0; e < 128; e++) {
19
+ let e = u(n);
20
+ e[0] &= i;
21
+ let t = BigInt("0x" + e.toString("hex"));
22
+ if (t < r) return t.toString();
23
+ }
24
+ throw t("conflict");
25
+ },
26
+ catch: (n) => n instanceof e ? n : t("unavailable")
27
+ });
28
+ } }), f = l.succeed(n, d), p = (e, l = i, u = a) => {
29
+ let d = r(e), f = o(d, l), p = () => f.entries;
30
+ if (typeof u != "function") throw t("invalid_input");
31
+ return c.gen(function* () {
32
+ let e = yield* (yield* n).draw(f.total);
33
+ return yield* c.try({
34
+ try: () => s(d, e, p, u),
35
+ catch: () => t("invalid_input")
36
+ });
37
+ });
38
+ };
39
+ //#endregion
40
+ export { d as cryptoContainerRandom, f as cryptoContainerRandomLayer, p as sampleContainer };
@@ -0,0 +1,75 @@
1
+ import { ContainersPort as e } from "./containers.js";
2
+ import { EconomyPort as t } from "./port.js";
3
+ import { economyPlugin as n } from "./plugin.js";
4
+ import { containerOpenIntent as r, containerStoreFixture as i } from "./containerStore.testFixtures.js";
5
+ import { Effect as a, Layer as o } from "effect";
6
+ import { InMemoryDataStore as s } from "@voltro/runtime";
7
+ //#region src/containersPort.fixture.ts
8
+ var c = {
9
+ app: {
10
+ name: "containers-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
+ }, l = a.gen(function* () {
23
+ let e = new s(), t = yield* a.promise(() => i(e, "fixture")), r = t.options, o = n({
24
+ currencies: r.currencies,
25
+ now: r.now,
26
+ containers: {
27
+ containers: r.containers,
28
+ inventory: r.inventory,
29
+ accessSource: r.accessSource,
30
+ version: r.version,
31
+ probability: r.probability,
32
+ roll: r.roll,
33
+ random: r.random,
34
+ eligibility: r.eligibility,
35
+ priceResolver: r.priceResolver,
36
+ systemAccount: r.systemAccount,
37
+ maxHistoryRows: r.maxHistoryRows,
38
+ now: r.now
39
+ }
40
+ });
41
+ return yield* a.promise(async () => {
42
+ await o.bindDataStore?.(e);
43
+ }), Object.freeze({
44
+ store: e,
45
+ plugin: o,
46
+ base: t,
47
+ close: a.suspend(() => o.onDeactivate?.(c))
48
+ });
49
+ }), u = o.effectContext(a.acquireRelease(l, (e) => e.close).pipe(a.flatMap((e) => o.build(e.plugin.services)))), d = Object.freeze({
50
+ kind: "port",
51
+ tag: e,
52
+ fakeLayer: u,
53
+ probe: {
54
+ run: () => a.scoped(a.gen(function* () {
55
+ let n = yield* e, i = yield* t, a = {
56
+ type: "user",
57
+ id: "a",
58
+ tenantId: "fixture",
59
+ kind: "guest"
60
+ }, o = (yield* n.list(a))[0], s = r(o), c = yield* n.open(a, s), l = yield* n.open(a, s), u = yield* i.mine(a);
61
+ return {
62
+ same: c.operationId === l.operationId,
63
+ misses: c.misses,
64
+ balance: u[0]?.balance
65
+ };
66
+ }).pipe(a.provide(u))),
67
+ expected: {
68
+ same: !0,
69
+ misses: 1,
70
+ balance: "95"
71
+ }
72
+ }
73
+ });
74
+ //#endregion
75
+ export { u as containersFakeLayer, l as containersPortFixture, d as containersPortSystemFixture };
@@ -0,0 +1,33 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { dataList as t, dataObject as n, identifier as r } from "./capture.js";
3
+ import { economyAmountString as i, positiveAmount as a } from "./amount.js";
4
+ //#region src/currency.ts
5
+ var o = (t) => {
6
+ let o = n(t, [
7
+ "id",
8
+ "kind",
9
+ "cap",
10
+ "premium",
11
+ "display"
12
+ ], "invalid_currency"), s = r(o.id, "invalid_currency");
13
+ if (o.kind !== "soft" && o.kind !== "hard" || o.premium !== void 0 && typeof o.premium != "boolean") throw e("invalid_currency");
14
+ let c = null;
15
+ if (o.display !== void 0 && o.display !== null) {
16
+ let e = n(o.display, ["nameKey"], "invalid_currency");
17
+ c = Object.freeze({ nameKey: r(e.nameKey, "invalid_currency") });
18
+ }
19
+ let l = o.cap === void 0 ? "9223372036854775807" : i(a(o.cap));
20
+ return Object.freeze({
21
+ id: s,
22
+ kind: o.kind,
23
+ cap: l,
24
+ premium: o.premium ?? !1,
25
+ display: c
26
+ });
27
+ }, s = (n) => {
28
+ let r = t(n, 128, "invalid_currency").map((e) => o(e));
29
+ if (new Set(r.map((e) => e.id)).size !== r.length) throw e("invalid_currency");
30
+ return Object.freeze(r);
31
+ };
32
+ //#endregion
33
+ export { s as captureCurrencies, o as defineCurrency };
@@ -0,0 +1,62 @@
1
+ import { defaultPriceResolver as e, priceResolverContext as t } from "./price.js";
2
+ import { defineShopOffer as n } from "./shop.js";
3
+ import { planLedgerTransfer as r } from "./ledger.js";
4
+ //#region src/declarationFixtures.ts
5
+ var i = () => Object.freeze({
6
+ resolver: e,
7
+ context: t({
8
+ kind: "virtual",
9
+ options: [{
10
+ currency: "test.gold",
11
+ amount: "11"
12
+ }]
13
+ }, [{
14
+ id: "test.gold",
15
+ kind: "soft",
16
+ cap: "1000"
17
+ }], !1, [{
18
+ currency: "test.gold",
19
+ discountBps: 5e3,
20
+ minimum: "2"
21
+ }])
22
+ }), a = () => r({
23
+ tenantId: "test.tenant",
24
+ requestId: "test.reward.1",
25
+ currency: "test.gold",
26
+ amount: "11",
27
+ from: {
28
+ kind: "system",
29
+ id: "match-rewards"
30
+ },
31
+ to: {
32
+ kind: "wallet",
33
+ ownerKind: "player",
34
+ ownerId: "test.player"
35
+ },
36
+ reason: "match.reward",
37
+ ref: {
38
+ kind: "match",
39
+ id: "test.match"
40
+ }
41
+ }), o = () => n({
42
+ id: "test.potion",
43
+ version: "1",
44
+ titleKey: "test.potion.offer",
45
+ price: {
46
+ kind: "virtual",
47
+ options: [{
48
+ currency: "test.gold",
49
+ amount: "7"
50
+ }]
51
+ },
52
+ items: [{
53
+ itemId: "test.potion",
54
+ qty: 2
55
+ }],
56
+ oneTime: !0
57
+ }, [{
58
+ id: "test.gold",
59
+ kind: "soft"
60
+ }]);
61
+ //#endregion
62
+ export { a as ledgerTransferFixture, i as priceResolverFixture, o as shopOfferFixture };
@@ -0,0 +1 @@
1
+ export { economyRefundReversed as default } from '@voltro/plugin-economy/events'
@@ -0,0 +1 @@
1
+ export { economyRefunded as default } from '@voltro/plugin-economy/events'
@@ -0,0 +1,125 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { dataList as n, dataObject as r, identifier as i } from "./capture.js";
3
+ import { captureCurrencies as a } from "./currency.js";
4
+ import { applyWalletPosting as o, captureAccount as s, economyAccountKey as c, planLedgerTransfer as l } from "./ledger.js";
5
+ import { EconomyPort as u } from "./port.js";
6
+ import { Effect as d, Layer as f } from "effect";
7
+ //#region src/economyPort.fixture.ts
8
+ var p = (p) => {
9
+ let m = r(p, [
10
+ "currencies",
11
+ "allowedServices",
12
+ "now"
13
+ ]), h = a(m.currencies), g = new Set(n(m.allowedServices ?? [], 256).map((e) => i(e))), _ = m.now ?? (() => 0);
14
+ if (typeof _ != "function") throw t("invalid_input");
15
+ let v = _, y = !1, b = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), S = (e) => {
16
+ if (e.type !== "system" && !(e.type === "service" && g.has(e.service))) throw t("forbidden");
17
+ }, C = (e, t, n) => JSON.stringify([
18
+ i(e),
19
+ c(t),
20
+ i(n)
21
+ ]), w = (e) => {
22
+ let n = h.find((t) => t.id === i(e));
23
+ if (!n) throw t("invalid_currency");
24
+ return n;
25
+ }, T = (n) => n instanceof e ? n : t("invalid_input"), E = (e) => {
26
+ try {
27
+ return e();
28
+ } catch (e) {
29
+ return d.fail(T(e));
30
+ }
31
+ }, D = (e) => d.try({
32
+ try: () => {
33
+ if (y) throw t("unavailable");
34
+ return e();
35
+ },
36
+ catch: T
37
+ }), O = (e, t, n) => {
38
+ let r = 0n, i = 0;
39
+ for (let { plan: a } of x.values()) if (a.tenantId === e && a.currency === n) for (let e of a.postings) c(e.account) === c(t) && (r += BigInt(e.credit) - BigInt(e.debit), i++);
40
+ return {
41
+ ledgerBalance: r.toString(),
42
+ ledgerRows: i
43
+ };
44
+ }, k = (e) => (n, r, a, o) => E(() => {
45
+ let c = structuredClone(n), l = s(a), u = i(o), d = i(r);
46
+ return D(() => {
47
+ if (S(c), w(u), l.kind !== "wallet") throw t("invalid_input");
48
+ let n = C(d, l, u), r = b.get(n), i = r?.balance ?? "0", a = O(d, l, u), o = i === a.ledgerBalance;
49
+ return e && !o && b.set(n, {
50
+ balance: a.ledgerBalance,
51
+ updatedAt: r?.updatedAt ?? 0
52
+ }), Object.freeze({
53
+ currency: u,
54
+ balance: e ? a.ledgerBalance : i,
55
+ ...a,
56
+ matches: e || o
57
+ });
58
+ });
59
+ }), A = Object.freeze({
60
+ transfer: (e, n) => E(() => {
61
+ let r = structuredClone(e), i = l(n);
62
+ return D(() => {
63
+ S(r);
64
+ let e = w(i.currency), n = JSON.stringify([i.tenantId, i.requestId]), a = x.get(n);
65
+ if (a) {
66
+ if (JSON.stringify(a.plan) !== JSON.stringify(i)) throw t("conflict");
67
+ return a.receipt;
68
+ }
69
+ let s = i.postings.filter((e) => e.account.kind === "wallet").map((t) => {
70
+ let n = C(i.tenantId, t.account, i.currency);
71
+ return {
72
+ identity: n,
73
+ balance: o(b.get(n)?.balance ?? "0", t, e)
74
+ };
75
+ }), c = v();
76
+ if (!Number.isSafeInteger(c) || c < 0 || c > 864e13) throw t("unavailable");
77
+ if (s.some((e) => (b.get(e.identity)?.updatedAt ?? 0) > c)) throw t("invalid_record");
78
+ let l = Object.freeze({
79
+ txId: `fixture.tx.${x.size + 1}`,
80
+ currency: i.currency,
81
+ amount: i.amount,
82
+ at: c
83
+ });
84
+ for (let e of s) b.set(e.identity, {
85
+ balance: e.balance,
86
+ updatedAt: c
87
+ });
88
+ return x.set(n, {
89
+ plan: i,
90
+ receipt: l
91
+ }), l;
92
+ });
93
+ }),
94
+ mine: (e) => E(() => {
95
+ let n = structuredClone(e);
96
+ return D(() => {
97
+ if (n.type !== "user") throw t("forbidden");
98
+ let e = {
99
+ kind: "wallet",
100
+ ownerKind: "player",
101
+ ownerId: i(n.id)
102
+ }, r = i(n.tenantId);
103
+ return Object.freeze(h.map((t) => {
104
+ let n = b.get(C(r, e, t.id));
105
+ return Object.freeze({
106
+ currency: t.id,
107
+ balance: n?.balance ?? "0",
108
+ updatedAt: n?.updatedAt ?? null
109
+ });
110
+ }));
111
+ });
112
+ }),
113
+ auditWallet: k(!1),
114
+ rebuildWallet: k(!0)
115
+ }), j = d.sync(() => {
116
+ y = !0, b.clear(), x.clear();
117
+ });
118
+ return Object.freeze({
119
+ service: A,
120
+ layer: f.succeed(u, A),
121
+ close: j
122
+ });
123
+ };
124
+ //#endregion
125
+ export { p as economyPortFixture };
@@ -0,0 +1,14 @@
1
+ import { Schema } from 'effect';
2
+ import { YieldableError } from 'effect/Cause';
3
+
4
+ /** Redacted codes; never carries owners, amounts or provider payloads. */
5
+ export declare class EconomyError extends EconomyError_base {
6
+ }
7
+
8
+ export declare const economyError: (code: EconomyError["code"]) => EconomyError;
9
+
10
+ declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
11
+ readonly code: Schema.Literals<readonly ["invalid_currency", "invalid_amount", "overflow", "invalid_price", "real_money_disabled", "invalid_input", "invalid_record", "currency_cap_reached", "insufficient_funds", "conflict", "forbidden", "unavailable", "not_found", "erased", "limit_exceeded", "already_redeemed"]>;
12
+ }>, YieldableError>;
13
+
14
+ export { }
package/dist/errors.js ADDED
@@ -0,0 +1,22 @@
1
+ import { Schema as e } from "effect";
2
+ //#region src/errors.ts
3
+ var t = class extends e.TaggedError()("EconomyError", { code: e.Literals([
4
+ "invalid_currency",
5
+ "invalid_amount",
6
+ "overflow",
7
+ "invalid_price",
8
+ "real_money_disabled",
9
+ "invalid_input",
10
+ "invalid_record",
11
+ "currency_cap_reached",
12
+ "insufficient_funds",
13
+ "conflict",
14
+ "forbidden",
15
+ "unavailable",
16
+ "not_found",
17
+ "erased",
18
+ "limit_exceeded",
19
+ "already_redeemed"
20
+ ]) }) {}, n = (e) => new t({ code: e });
21
+ //#endregion
22
+ export { t as EconomyError, n as economyError };
@@ -0,0 +1,46 @@
1
+ import { DeclaredAccess } from '@voltro/protocol';
2
+ import { EventDescriptor } from '@voltro/protocol';
3
+ import { Schema } from 'effect';
4
+
5
+ /** Guarded server-produced metadata. Ephemeral listeners are not the durable SQL audience. */
6
+ export declare const economyRefunded: EventDescriptor<"economy.refunded", Schema.Struct<{
7
+ readonly subjectId: Schema.String;
8
+ }>, Schema.Struct<{
9
+ readonly eventId: Schema.String;
10
+ readonly orderId: Schema.String;
11
+ readonly sequence: Schema.Number;
12
+ readonly state: Schema.Literals<readonly ["active", "partially-refunded", "revoked"]>;
13
+ readonly refundNumerator: Schema.Number;
14
+ readonly refundDenominator: Schema.Number;
15
+ readonly observedAt: Schema.Number;
16
+ }>, DeclaredAccess<{
17
+ readonly subjectId: string;
18
+ }>>;
19
+
20
+ export declare const economyRefundReversed: EventDescriptor<"economy.refundReversed", Schema.Struct<{
21
+ readonly subjectId: Schema.String;
22
+ }>, Schema.Struct<{
23
+ readonly eventId: Schema.String;
24
+ readonly orderId: Schema.String;
25
+ readonly sequence: Schema.Number;
26
+ readonly state: Schema.Literals<readonly ["active", "partially-refunded", "revoked"]>;
27
+ readonly refundNumerator: Schema.Number;
28
+ readonly refundDenominator: Schema.Number;
29
+ readonly observedAt: Schema.Number;
30
+ }>, DeclaredAccess<{
31
+ readonly subjectId: string;
32
+ }>>;
33
+
34
+ export declare type IapRefundEventPayload = typeof IapRefundEventPayloadSchema.Type;
35
+
36
+ export declare const IapRefundEventPayloadSchema: Schema.Struct<{
37
+ readonly eventId: Schema.String;
38
+ readonly orderId: Schema.String;
39
+ readonly sequence: Schema.Number;
40
+ readonly state: Schema.Literals<readonly ["active", "partially-refunded", "revoked"]>;
41
+ readonly refundNumerator: Schema.Number;
42
+ readonly refundDenominator: Schema.Number;
43
+ readonly observedAt: Schema.Number;
44
+ }>;
45
+
46
+ export { }
package/dist/events.js ADDED
@@ -0,0 +1 @@
1
+ export { IapRefundEventPayloadSchema, economyRefundReversed, economyRefunded } from "./iapRefundEvents.js";