@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,268 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { captureBoundMethods as n, dataList as r, dataObject as i, identifier as a } from "./capture.js";
3
+ import { positiveAmount as o } from "./amount.js";
4
+ import { captureCurrencies as s } from "./currency.js";
5
+ import { priceResolverContext as c } from "./price.js";
6
+ import { defineShopOffer as l, shopInteger as u } from "./shop.js";
7
+ import { captureFlashTriggerReceipt as d, defaultFlashTriggerPolicy as f, defaultPersonalizedOfferSelector as p, defineBundle as m, defineFlashOffer as h, definePersonalizedOffers as g, projectBundleValue as _, resolveFlashOffer as v, resolvePersonalizedOffers as y } from "./offerMerchandising.js";
8
+ import { Effect as b } from "effect";
9
+ //#region src/offerPolicies.ts
10
+ var x = (e, n, r = !1) => {
11
+ let s = i(e, [
12
+ "offer",
13
+ "expiresAfterMs",
14
+ "bonus"
15
+ ]), c = l(s.offer, n, r);
16
+ if (c.maxQuantity !== 1 || c.limits.perPlayer !== null && c.limits.perPlayer !== 1) throw t("invalid_input");
17
+ let d = c.currencies;
18
+ if (s.bonus !== void 0) {
19
+ let e = i(s.bonus, ["currency", "multiplier"]), n = a(e.currency), r = u(e.multiplier, 1, 1e3);
20
+ if (!d.some((e) => e.currency === n)) throw t("invalid_input");
21
+ d = Object.freeze(d.map((e) => e.currency === n ? Object.freeze({
22
+ currency: n,
23
+ amount: o(BigInt(e.amount) * BigInt(r)).toString()
24
+ }) : e));
25
+ }
26
+ let f = l({
27
+ ...c,
28
+ currencies: d,
29
+ oneTime: !0,
30
+ limits: {
31
+ ...c.limits,
32
+ perPlayer: 1
33
+ }
34
+ }, n, r);
35
+ return Object.freeze({
36
+ offer: f,
37
+ expiresAfterMs: u(s.expiresAfterMs, 1, 316224e5)
38
+ });
39
+ }, S = (e, t, n) => {
40
+ let r = u(t, 0, 864e13), i = u(n, r, 864e13), a = u(e.expiresAfterMs, 1, 316224e5);
41
+ return i - r < a;
42
+ }, C = (e, n, o = !1) => {
43
+ let s = i(e, [
44
+ "id",
45
+ "version",
46
+ "from",
47
+ "until",
48
+ "variants",
49
+ "metrics"
50
+ ]), c = u(s.from, 0, 864e13), d = u(s.until, 1, 864e13);
51
+ if (c >= d) throw t("invalid_input");
52
+ let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set(), m = Object.freeze(r(s.variants, 32).map((e) => {
53
+ let s = i(e, [
54
+ "id",
55
+ "weight",
56
+ "offers"
57
+ ]), c = Object.freeze(r(s.offers, 32).map((e) => l(e, n, o)));
58
+ if (!c.length) throw t("invalid_input");
59
+ let d = /* @__PURE__ */ new Set();
60
+ for (let e of c) {
61
+ if (f.has(e.id)) throw t("invalid_input");
62
+ f.add(e.id);
63
+ let n = e.price.kind === "real" ? e.price : e.price.kind === "mixed" ? e.price.real : null;
64
+ if (n) for (let [e, r] of Object.entries(n.storeProductIds)) {
65
+ let n = JSON.stringify([e, r]);
66
+ if (p.has(n)) throw t("invalid_price");
67
+ d.add(n);
68
+ }
69
+ }
70
+ for (let e of d) p.add(e);
71
+ return Object.freeze({
72
+ id: a(s.id),
73
+ weight: u(s.weight, 1, 1e6),
74
+ offers: c
75
+ });
76
+ }).sort((e, t) => e.id < t.id ? -1 : +(e.id > t.id))), h = Object.freeze(r(s.metrics, 32).map((e) => a(e)));
77
+ if (m.length < 2 || new Set(m.map((e) => e.id)).size !== m.length || !h.length || new Set(h).size !== h.length) throw t("invalid_input");
78
+ return Object.freeze({
79
+ id: a(s.id),
80
+ version: a(s.version ?? "1"),
81
+ from: c,
82
+ until: d,
83
+ variants: m,
84
+ metrics: h
85
+ });
86
+ }, w = ({ experiment: e, tenantId: n, key: r }) => {
87
+ let i = 2166136261;
88
+ for (let t of new TextEncoder().encode(JSON.stringify([
89
+ n,
90
+ e.id,
91
+ e.version,
92
+ r
93
+ ]))) i = Math.imul(i ^ t, 16777619) >>> 0;
94
+ let a = i % e.variants.reduce((e, t) => e + t.weight, 0);
95
+ for (let t of e.variants) {
96
+ if (a < t.weight) return t.id;
97
+ a -= t.weight;
98
+ }
99
+ throw t("invalid_input");
100
+ }, T = (e, n = w) => {
101
+ if (typeof n != "function") throw t("invalid_input");
102
+ let r = i(e, [
103
+ "experiment",
104
+ "tenantId",
105
+ "key",
106
+ "at",
107
+ "currencies",
108
+ "realMoney"
109
+ ]), o = s(r.currencies), c = r.realMoney ?? !1;
110
+ if (typeof c != "boolean") throw t("invalid_input");
111
+ let l = C(r.experiment, o, c), d = u(r.at, 0, 864e13), f = Object.freeze({
112
+ experiment: l,
113
+ at: d,
114
+ tenantId: a(r.tenantId),
115
+ key: a(r.key),
116
+ currencies: o,
117
+ realMoney: c
118
+ });
119
+ if (d < l.from || d >= l.until) return null;
120
+ let p = a(n(f)), m = l.variants.find((e) => e.id === p);
121
+ if (!m) throw t("invalid_input");
122
+ return Object.freeze({
123
+ experimentId: l.id,
124
+ version: l.version,
125
+ variantId: p,
126
+ offers: m.offers
127
+ });
128
+ }, E = (o) => {
129
+ let m = i(o, [
130
+ "currencies",
131
+ "realMoney",
132
+ "source",
133
+ "starterPacks",
134
+ "experiments",
135
+ "experimentBucket",
136
+ "personalized",
137
+ "flashOffers",
138
+ "personalizedSelector",
139
+ "flashTrigger",
140
+ "policyVersion"
141
+ ]), _ = s(m.currencies), E = m.realMoney ?? !1;
142
+ if (typeof E != "boolean") throw t("invalid_input");
143
+ let D = n(m.source, ["read"]), O = Object.freeze(r(m.starterPacks ?? [], 128).map((e) => x(e, _, E))), k = Object.freeze(r(m.experiments ?? [], 128).map((e) => C(e, _, E))), A = Object.freeze(r(m.personalized ?? [], 128).map((e) => g(e, _, E))), j = Object.freeze(r(m.flashOffers ?? [], 128).map((e) => h(e, _, E))), M = m.personalizedSelector ?? p, N = m.flashTrigger ?? f, P = a(m.policyVersion ?? "default.v1");
144
+ if ([M, N].some((e) => typeof e != "function") || (A.length || j.length || M !== p || N !== f) && P === "default.v1" || new Set(A.map((e) => e.id)).size !== A.length || new Set(j.map((e) => e.id)).size !== j.length || new Set(j.map((e) => e.offer.id)).size !== j.length) throw t("invalid_input");
145
+ let F = A.flatMap((e) => e.pool.map((e) => e.offer.id));
146
+ if (new Set(F).size !== F.length) throw t("invalid_input");
147
+ let I = m.experimentBucket ?? w;
148
+ if (typeof I != "function" || new Set(O.map((e) => e.offer.id)).size !== O.length || new Set(k.map((e) => e.id)).size !== k.length) throw t("invalid_input");
149
+ let L = k.flatMap((e) => e.variants.flatMap((e) => e.offers.map((e) => e.id)));
150
+ if (new Set(L).size !== L.length) throw t("invalid_input");
151
+ return Object.freeze({ read: (n) => {
152
+ let o;
153
+ try {
154
+ let e = i(n, [
155
+ "subject",
156
+ "offer",
157
+ "at"
158
+ ]), r = i(e.subject, [
159
+ "type",
160
+ "id",
161
+ "tenantId",
162
+ "kind",
163
+ "scopes",
164
+ "metadata"
165
+ ]);
166
+ if (r.type !== "user" || r.kind !== void 0 && r.kind !== "guest") throw t("forbidden");
167
+ o = Object.freeze({
168
+ subject: Object.freeze({
169
+ type: "user",
170
+ id: a(r.id),
171
+ tenantId: a(r.tenantId),
172
+ ...r.kind === "guest" ? { kind: "guest" } : {}
173
+ }),
174
+ offer: l(e.offer, _, E),
175
+ at: u(e.at, 0, 864e13)
176
+ });
177
+ } catch {
178
+ return b.fail(t("invalid_input"));
179
+ }
180
+ let s = o.subject;
181
+ return s.type === "user" ? b.try({
182
+ try: () => D.read(Object.freeze({
183
+ tenantId: s.tenantId,
184
+ ownerId: s.id,
185
+ offer: o.offer,
186
+ at: o.at
187
+ })),
188
+ catch: (n) => n instanceof e ? n : t("unavailable")
189
+ }).pipe(b.flatMap((e) => b.isEffect(e) ? e : b.fail(t("invalid_input"))), b.flatMap((n) => b.try({
190
+ try: () => {
191
+ let e = i(n, [
192
+ "eligible",
193
+ "adjustments",
194
+ "firstSessionAt",
195
+ "experimentKey",
196
+ "personalization",
197
+ "flashTriggers"
198
+ ]);
199
+ if (typeof e.eligible != "boolean") throw t("invalid_input");
200
+ let l = u(e.firstSessionAt, 0, o.at), f = a(e.experimentKey), p = c(o.offer.price, _, E, e.adjustments).adjustments, m = e.eligible, h = O.find((e) => e.offer.id === o.offer.id);
201
+ if (h) {
202
+ if (JSON.stringify(h.offer) !== JSON.stringify(o.offer)) throw t("conflict");
203
+ m &&= S(h, l, o.at);
204
+ }
205
+ for (let e of k) if (e.variants.some((e) => e.offers.some((e) => e.id === o.offer.id))) {
206
+ let n = T({
207
+ experiment: e,
208
+ tenantId: s.tenantId,
209
+ key: f,
210
+ at: o.at,
211
+ currencies: _,
212
+ realMoney: E
213
+ }, I)?.offers.find((e) => e.id === o.offer.id);
214
+ if (n && JSON.stringify(n) !== JSON.stringify(o.offer)) throw t("conflict");
215
+ m &&= n !== void 0;
216
+ }
217
+ for (let n of A) if (n.pool.some((e) => e.offer.id === o.offer.id)) {
218
+ let r = n.pool.find((e) => e.offer.id === o.offer.id).offer;
219
+ if (JSON.stringify(r) !== JSON.stringify(o.offer)) throw t("conflict");
220
+ let a = i(e.personalization, ["ownedItemIds", "playStyles"]), c = y({
221
+ personalized: n,
222
+ currencies: _,
223
+ realMoney: E,
224
+ tenantId: s.tenantId,
225
+ key: f,
226
+ at: o.at,
227
+ ownedItemIds: a.ownedItemIds,
228
+ playStyles: a.playStyles,
229
+ rulesVersion: P
230
+ }, M);
231
+ m &&= c?.offers.some((e) => e.id === o.offer.id) === !0;
232
+ }
233
+ let g = j.find((e) => e.offer.id === o.offer.id);
234
+ if (g) {
235
+ if (JSON.stringify(g.offer) !== JSON.stringify(o.offer)) throw t("conflict");
236
+ let n = r(e.flashTriggers, 128).map((e) => {
237
+ let t = i(e, ["flashId", "trigger"]);
238
+ return Object.freeze({
239
+ flashId: a(t.flashId),
240
+ trigger: t.trigger === null ? null : d(t.trigger)
241
+ });
242
+ });
243
+ if (new Set(n.map((e) => e.flashId)).size !== n.length) throw t("invalid_input");
244
+ let c = n.find((e) => e.flashId === g.id);
245
+ if (!c) throw t("invalid_input");
246
+ let l = v({
247
+ flash: g,
248
+ currencies: _,
249
+ realMoney: E,
250
+ tenantId: s.tenantId,
251
+ ownerId: s.id,
252
+ at: o.at,
253
+ trigger: c.trigger,
254
+ rulesVersion: P
255
+ }, N);
256
+ m &&= l !== null;
257
+ }
258
+ return Object.freeze({
259
+ eligible: m,
260
+ adjustments: p
261
+ });
262
+ },
263
+ catch: (n) => n instanceof e ? n : t("invalid_input")
264
+ }))) : b.fail(t("forbidden"));
265
+ } });
266
+ };
267
+ //#endregion
268
+ export { d as captureFlashTriggerReceipt, w as defaultExperimentBucket, f as defaultFlashTriggerPolicy, p as defaultPersonalizedOfferSelector, m as defineBundle, h as defineFlashOffer, C as defineOfferExperiment, g as definePersonalizedOffers, x as defineStarterPack, E as offerPolicyContextSource, _ as projectBundleValue, v as resolveFlashOffer, T as resolveOfferExperiment, y as resolvePersonalizedOffers, S as starterPackAvailable };
@@ -0,0 +1,272 @@
1
+ import { Context } from 'effect';
2
+ import { Effect } from 'effect';
3
+ import { PluginPrivacyTarget } from '@voltro/protocol';
4
+ import { Schema } from 'effect';
5
+ import { Subject } from '@voltro/protocol';
6
+ import { YieldableError } from 'effect/Cause';
7
+
8
+ export declare const capturePiggyBanksService: (input: PiggyBanksService) => PiggyBanksService;
9
+
10
+ declare interface CurrencyDefinition {
11
+ readonly id: string;
12
+ readonly kind: 'soft' | 'hard';
13
+ readonly cap?: EconomyAmountInput;
14
+ readonly premium?: boolean;
15
+ readonly display?: {
16
+ readonly nameKey: string;
17
+ } | null;
18
+ }
19
+
20
+ export declare const defaultPiggyFill: PiggyFillPolicy;
21
+
22
+ export declare const defaultPiggyReset: PiggyResetPolicy;
23
+
24
+ export declare const definePiggyBank: (input: PiggyBankDefinition | PiggyBank, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => PiggyBank;
25
+
26
+ declare type EconomyAmountInput = string | number | bigint;
27
+
28
+ declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
29
+
30
+ /** Redacted codes; never carries owners, amounts or provider payloads. */
31
+ declare class EconomyError extends EconomyError_base {
32
+ }
33
+
34
+ declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
35
+ 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"]>;
36
+ }>, YieldableError>;
37
+
38
+ export declare interface PiggyBank {
39
+ readonly id: string;
40
+ readonly version: string;
41
+ readonly titleKey: string;
42
+ readonly currency: string;
43
+ readonly cap: string;
44
+ readonly unlock: Price;
45
+ readonly fillFrom: readonly string[];
46
+ readonly reset: 'onUnlock';
47
+ }
48
+
49
+ export declare interface PiggyBankDefinition {
50
+ readonly id: string;
51
+ readonly version?: string | undefined;
52
+ readonly titleKey: string;
53
+ readonly currency: string;
54
+ readonly cap: EconomyAmountInput;
55
+ readonly unlock: PriceDefinition;
56
+ readonly fillFrom: readonly string[];
57
+ readonly reset?: 'onUnlock' | undefined;
58
+ }
59
+
60
+ export declare class PiggyBanksPort extends PiggyBanksPort_base {
61
+ }
62
+
63
+ declare const PiggyBanksPort_base: Context.ServiceClass<PiggyBanksPort, "@voltro/PiggyBanksPort", PiggyBanksService>;
64
+
65
+ export declare interface PiggyBanksService {
66
+ readonly list: (subject: Subject) => Effect.Effect<readonly PiggyView[], EconomyError>;
67
+ readonly fill: (subject: Subject, input: PiggyFillInput) => Effect.Effect<PiggyReceipt, EconomyError>;
68
+ readonly unlock: (subject: Subject, input: PiggyUnlockInput) => Effect.Effect<PiggyReceipt, EconomyError>;
69
+ readonly receipt: (subject: Subject, input: {
70
+ readonly requestId: string;
71
+ }) => Effect.Effect<PiggyObservation, EconomyError>;
72
+ readonly rebuild: (subject: Subject, input: {
73
+ readonly tenantId: string;
74
+ readonly ownerId: string;
75
+ readonly bankId: string;
76
+ }) => Effect.Effect<PiggyProjection, EconomyError>;
77
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
78
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
79
+ }
80
+
81
+ export declare type PiggyEvent = {
82
+ readonly id: string;
83
+ readonly sequence: number;
84
+ readonly kind: 'fill';
85
+ readonly at: number;
86
+ readonly authorityId: string;
87
+ readonly eventId: string;
88
+ readonly sourceId: string;
89
+ readonly acceptedAmount: string;
90
+ readonly delta: string;
91
+ } | {
92
+ readonly id: string;
93
+ readonly sequence: number;
94
+ readonly kind: 'unlock';
95
+ readonly at: number;
96
+ readonly amount: string;
97
+ readonly remaining: string;
98
+ };
99
+
100
+ export declare interface PiggyFillContext extends PiggyRuleContext {
101
+ readonly acceptedAmount: EconomyAmountInput;
102
+ }
103
+
104
+ export declare interface PiggyFillInput {
105
+ readonly tenantId: string;
106
+ readonly ownerId: string;
107
+ readonly bankId: string;
108
+ readonly sourceId: string;
109
+ readonly eventId: string;
110
+ readonly requestId: string;
111
+ }
112
+
113
+ export declare const piggyFillIntent: (input: PiggyFillInput) => PiggyFillInput;
114
+
115
+ export declare type PiggyFillPolicy = (context: PiggyFillContext) => EconomyAmountInput;
116
+
117
+ export declare type PiggyObservation = {
118
+ readonly requestId: string;
119
+ readonly state: 'not-observed';
120
+ } | {
121
+ readonly requestId: string;
122
+ readonly state: 'fulfilled';
123
+ readonly receipt: PiggyReceipt;
124
+ };
125
+
126
+ export declare interface PiggyProjection {
127
+ readonly events: readonly PiggyEvent[];
128
+ readonly available: string;
129
+ readonly cycles: number;
130
+ }
131
+
132
+ export declare type PiggyReceipt = {
133
+ readonly operationId: string;
134
+ readonly requestId: string;
135
+ readonly bankId: string;
136
+ readonly event: Extract<PiggyEvent, {
137
+ kind: 'fill';
138
+ }>;
139
+ readonly available: string;
140
+ } | {
141
+ readonly operationId: string;
142
+ readonly requestId: string;
143
+ readonly bankId: string;
144
+ readonly event: Extract<PiggyEvent, {
145
+ kind: 'unlock';
146
+ }>;
147
+ readonly available: string;
148
+ readonly value: ShopOrderReceipt;
149
+ };
150
+
151
+ export declare type PiggyResetPolicy = (context: PiggyRuleContext) => EconomyAmountInput;
152
+
153
+ export declare interface PiggyRuleContext {
154
+ readonly bank: PiggyBank;
155
+ readonly currencies: readonly CurrencyDefinition[];
156
+ readonly realMoney?: boolean;
157
+ readonly available: EconomyAmountInput;
158
+ readonly rulesVersion?: string;
159
+ }
160
+
161
+ export declare interface PiggyUnlockInput {
162
+ readonly bankId: string;
163
+ readonly bankVersion: string;
164
+ readonly bankDigest: string;
165
+ readonly requestId: string;
166
+ readonly currency?: string | undefined;
167
+ }
168
+
169
+ export declare const piggyUnlockIntent: (input: PiggyUnlockInput) => Readonly<{
170
+ bankId: string;
171
+ bankVersion: string;
172
+ bankDigest: string;
173
+ requestId: string;
174
+ currency: string | null;
175
+ }>;
176
+
177
+ export declare interface PiggyView {
178
+ readonly bank: PiggyBank;
179
+ readonly bankDigest: string;
180
+ readonly available: string;
181
+ readonly cycles: number;
182
+ }
183
+
184
+ declare type Price = {
185
+ readonly kind: 'virtual';
186
+ readonly options: readonly ResolvedVirtualPriceOption[];
187
+ } | ({
188
+ readonly kind: 'real';
189
+ } & RealPriceDefinition) | {
190
+ readonly kind: 'mixed';
191
+ readonly real: RealPriceDefinition;
192
+ readonly virtual: readonly ResolvedVirtualPriceOption[];
193
+ } | {
194
+ readonly kind: 'free';
195
+ };
196
+
197
+ declare type PriceDefinition = {
198
+ readonly kind: 'virtual';
199
+ readonly options: readonly VirtualPriceOption[];
200
+ } | ({
201
+ readonly kind: 'real';
202
+ } & RealPriceDefinition) | {
203
+ readonly kind: 'mixed';
204
+ readonly real: RealPriceDefinition;
205
+ readonly virtual: readonly VirtualPriceOption[];
206
+ } | {
207
+ readonly kind: 'free';
208
+ };
209
+
210
+ /** One complete accepted history owner for writer/rebuild. SQL/source layers
211
+ * separately establish receipt authenticity, ownership and complete tail. */
212
+ export declare const projectPiggyBank: (bank: Pick<PiggyBank, "cap" | "fillFrom">, input: readonly PiggyEvent[]) => PiggyProjection;
213
+
214
+ declare interface RealPriceDefinition {
215
+ /** Integer minor-unit references; verified store receipts remain authoritative. */
216
+ readonly prices: Readonly<Record<string, number>>;
217
+ readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
218
+ }
219
+
220
+ declare interface ResolvedVirtualPriceOption {
221
+ readonly currency: string;
222
+ readonly amount: string;
223
+ }
224
+
225
+ /** Custom fill narrows the accepted source amount and remaining cap. No player
226
+ * event, source validation, SQL grant or wallet mint is implied by this rule. */
227
+ export declare const resolvePiggyFill: (input: PiggyFillContext, slot?: PiggyFillPolicy) => string;
228
+
229
+ /** Custom reset retains a remainder; only available-minus-remainder is granted,
230
+ * so retaining points cannot recreate already paid currency. */
231
+ export declare const resolvePiggyReset: (input: PiggyRuleContext, slot?: PiggyResetPolicy) => Readonly<{
232
+ remaining: string;
233
+ amount: string;
234
+ }>;
235
+
236
+ declare interface ShopOrderReceipt {
237
+ readonly orderId: string;
238
+ readonly offerId: string;
239
+ readonly offerVersion: string;
240
+ readonly offerDigest: string;
241
+ readonly quantity: number;
242
+ readonly at: number;
243
+ readonly pricePaid: {
244
+ readonly kind: 'free';
245
+ } | {
246
+ readonly kind: 'virtual';
247
+ readonly currency: string;
248
+ readonly amount: string;
249
+ };
250
+ readonly transfers: readonly {
251
+ readonly txId: string;
252
+ readonly currency: string;
253
+ readonly amount: string;
254
+ readonly at: number;
255
+ }[];
256
+ readonly grants: readonly {
257
+ readonly operationId: string;
258
+ readonly kind: 'grant';
259
+ readonly changes: readonly {
260
+ readonly instanceId: string;
261
+ readonly delta: number;
262
+ }[];
263
+ readonly at: number;
264
+ }[];
265
+ }
266
+
267
+ declare interface VirtualPriceOption {
268
+ readonly currency: string;
269
+ readonly amount: EconomyAmountInput;
270
+ }
271
+
272
+ export { }
@@ -0,0 +1,71 @@
1
+ import { defaultPiggyFill as e, defaultPiggyReset as t, definePiggyBank as n, resolvePiggyFill as r, resolvePiggyReset as i } from "./piggyBanks.js";
2
+ import { Effect as a } from "effect";
3
+ //#region src/piggyBanks.fixture.ts
4
+ var o = () => {
5
+ let e = [{
6
+ id: "test.gold",
7
+ kind: "soft",
8
+ cap: "1000"
9
+ }], t = n({
10
+ id: "test.piggy",
11
+ titleKey: "test.piggy",
12
+ currency: "test.gold",
13
+ cap: "20",
14
+ unlock: {
15
+ kind: "virtual",
16
+ options: [{
17
+ currency: "test.gold",
18
+ amount: "5"
19
+ }]
20
+ },
21
+ fillFrom: ["match.reward"]
22
+ }, e);
23
+ return Object.freeze({
24
+ bank: t,
25
+ currencies: e,
26
+ available: "13",
27
+ acceptedAmount: "13",
28
+ realMoney: !1
29
+ });
30
+ }, s = o(), c = Object.freeze({
31
+ bank: s.bank,
32
+ currencies: s.currencies,
33
+ available: s.available,
34
+ realMoney: s.realMoney
35
+ }), l = Object.freeze({
36
+ kind: "slot",
37
+ defaultImplementation: e,
38
+ defaultProbe: {
39
+ run: () => a.sync(() => r(s)),
40
+ expected: "7"
41
+ },
42
+ overrideProbe: {
43
+ run: () => a.sync(() => r({
44
+ ...s,
45
+ rulesVersion: "test.narrow.v1"
46
+ }, () => "3")),
47
+ expected: "3"
48
+ }
49
+ }), u = Object.freeze({
50
+ kind: "slot",
51
+ defaultImplementation: t,
52
+ defaultProbe: {
53
+ run: () => a.sync(() => i(c)),
54
+ expected: {
55
+ remaining: "0",
56
+ amount: "13"
57
+ }
58
+ },
59
+ overrideProbe: {
60
+ run: () => a.sync(() => i({
61
+ ...c,
62
+ rulesVersion: "test.retain.v1"
63
+ }, () => "3")),
64
+ expected: {
65
+ remaining: "3",
66
+ amount: "10"
67
+ }
68
+ }
69
+ });
70
+ //#endregion
71
+ export { o as piggyBankFixture, l as piggyFillSystemFixture, u as piggyResetSystemFixture };