@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
package/dist/port.js ADDED
@@ -0,0 +1,12 @@
1
+ import { captureBoundMethods as e } from "./capture.js";
2
+ import { Context as t } from "effect";
3
+ // src/port.ts
4
+ var n = class extends t.Service()("@voltro/EconomyPort") {}, r = (t) => e(t, [
5
+ "transfer",
6
+ "mine",
7
+ "auditWallet",
8
+ "rebuildWallet",
9
+ "exportSubject",
10
+ "eraseSubject"
11
+ ]);
12
+ export { n as EconomyPort, r as captureEconomyService };
@@ -0,0 +1,99 @@
1
+ declare interface CurrencyDefinition {
2
+ readonly id: string;
3
+ readonly kind: 'soft' | 'hard';
4
+ readonly cap?: EconomyAmountInput;
5
+ readonly premium?: boolean;
6
+ readonly display?: {
7
+ readonly nameKey: string;
8
+ } | null;
9
+ }
10
+
11
+ /** The one actual default. A real-money reference never constitutes a receipt. */
12
+ export declare const defaultPriceResolver: PriceResolver;
13
+
14
+ /** Captures declarations and enforces the global real-money switch. */
15
+ export declare const definePrice: (input: PriceDefinition, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => Price;
16
+
17
+ declare type EconomyAmountInput = string | number | bigint;
18
+
19
+ export declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
20
+
21
+ export declare type Price = {
22
+ readonly kind: 'virtual';
23
+ readonly options: readonly ResolvedVirtualPriceOption[];
24
+ } | ({
25
+ readonly kind: 'real';
26
+ } & RealPriceDefinition) | {
27
+ readonly kind: 'mixed';
28
+ readonly real: RealPriceDefinition;
29
+ readonly virtual: readonly ResolvedVirtualPriceOption[];
30
+ } | {
31
+ readonly kind: 'free';
32
+ };
33
+
34
+ export declare type PriceDefinition = {
35
+ readonly kind: 'virtual';
36
+ readonly options: readonly VirtualPriceOption[];
37
+ } | ({
38
+ readonly kind: 'real';
39
+ } & RealPriceDefinition) | {
40
+ readonly kind: 'mixed';
41
+ readonly real: RealPriceDefinition;
42
+ readonly virtual: readonly VirtualPriceOption[];
43
+ } | {
44
+ readonly kind: 'free';
45
+ };
46
+
47
+ export declare type PriceResolver = (context: PriceResolverContext) => Price;
48
+
49
+ export declare interface PriceResolverContext {
50
+ readonly price: Price;
51
+ readonly currencies: readonly ResolvedCurrency[];
52
+ readonly realMoney: boolean;
53
+ readonly adjustments: readonly Readonly<{
54
+ currency: string;
55
+ discountBps: number;
56
+ minimum: string;
57
+ }>[];
58
+ }
59
+
60
+ export declare const priceResolverContext: (price: PriceDefinition, currencies: readonly CurrencyDefinition[], realMoney?: boolean, adjustments?: readonly VirtualPriceAdjustment[]) => PriceResolverContext;
61
+
62
+ export declare interface RealPriceDefinition {
63
+ /** Integer minor-unit references; verified store receipts remain authoritative. */
64
+ readonly prices: Readonly<Record<string, number>>;
65
+ readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
66
+ }
67
+
68
+ declare interface ResolvedCurrency {
69
+ readonly id: string;
70
+ readonly kind: 'soft' | 'hard';
71
+ readonly cap: string;
72
+ readonly premium: boolean;
73
+ readonly display: {
74
+ readonly nameKey: string;
75
+ } | null;
76
+ }
77
+
78
+ export declare interface ResolvedVirtualPriceOption {
79
+ readonly currency: string;
80
+ readonly amount: string;
81
+ }
82
+
83
+ /** Detaches custom output and preserves alternatives, floors and real references. */
84
+ export declare const resolvePrice: (context: PriceResolverContext, resolver?: PriceResolver) => Price;
85
+
86
+ export declare interface VirtualPriceAdjustment {
87
+ readonly currency: string;
88
+ /** Inclusive integer 0..10000. */
89
+ readonly discountBps: number;
90
+ /** A trusted floor, enforced independently of a custom resolver. */
91
+ readonly minimum: EconomyAmountInput;
92
+ }
93
+
94
+ export declare interface VirtualPriceOption {
95
+ readonly currency: string;
96
+ readonly amount: EconomyAmountInput;
97
+ }
98
+
99
+ export { }
package/dist/price.js ADDED
@@ -0,0 +1,143 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { dataList as t, dataObject as n, identifier as r } from "./capture.js";
3
+ import { nonNegativeAmount as i } from "./amount.js";
4
+ import { captureCurrencies as a } from "./currency.js";
5
+ // src/price.ts
6
+ var o = [
7
+ "web",
8
+ "ios",
9
+ "android",
10
+ "steam"
11
+ ], s = (t) => {
12
+ let i = n(t, ["prices", "storeProductIds"], "invalid_price");
13
+ if (i.prices === null || typeof i.prices != "object" || Array.isArray(i.prices)) throw e("invalid_price");
14
+ let a = Object.keys(i.prices);
15
+ if (a.length === 0 || a.length > 64) throw e("invalid_price");
16
+ let s = n(i.prices, a, "invalid_price"), c = Object.create(null);
17
+ for (let t of a) {
18
+ let n = s[t];
19
+ if (!/^[A-Z]{3}$/.test(t) || typeof n != "number" || !Number.isSafeInteger(n) || n <= 0) throw e("invalid_price");
20
+ c[t] = n;
21
+ }
22
+ let l = n(i.storeProductIds, o, "invalid_price"), u = {};
23
+ for (let e of o) l[e] !== void 0 && (u[e] = r(l[e], "invalid_price"));
24
+ if (Object.keys(u).length === 0) throw e("invalid_price");
25
+ return Object.freeze({
26
+ prices: Object.freeze(c),
27
+ storeProductIds: Object.freeze(u)
28
+ });
29
+ }, c = (a, o) => {
30
+ let s = t(a, 32, "invalid_price");
31
+ if (s.length === 0) throw e("invalid_price");
32
+ let c = /* @__PURE__ */ new Set();
33
+ return Object.freeze(s.map((t) => {
34
+ let a = n(t, ["currency", "amount"], "invalid_price"), s = r(a.currency, "invalid_price"), l = o.find((e) => e.id === s);
35
+ if (!l || c.has(s)) throw e("invalid_price");
36
+ let u = i(a.amount);
37
+ if (u > BigInt(l.cap)) throw e("invalid_price");
38
+ return c.add(s), Object.freeze({
39
+ currency: s,
40
+ amount: u.toString()
41
+ });
42
+ }));
43
+ }, l = (t, r, i = !1) => {
44
+ if (typeof i != "boolean") throw e("invalid_input");
45
+ let o = a(r), l = n(t, [
46
+ "kind",
47
+ "options",
48
+ "prices",
49
+ "storeProductIds",
50
+ "real",
51
+ "virtual"
52
+ ], "invalid_price");
53
+ switch (l.kind) {
54
+ case "free": return n(t, ["kind"], "invalid_price"), Object.freeze({ kind: "free" });
55
+ case "virtual": return n(t, ["kind", "options"], "invalid_price"), Object.freeze({
56
+ kind: "virtual",
57
+ options: c(l.options, o)
58
+ });
59
+ case "real":
60
+ if (!i) throw e("real_money_disabled");
61
+ return n(t, [
62
+ "kind",
63
+ "prices",
64
+ "storeProductIds"
65
+ ], "invalid_price"), Object.freeze({
66
+ kind: "real",
67
+ ...s({
68
+ prices: l.prices,
69
+ storeProductIds: l.storeProductIds
70
+ })
71
+ });
72
+ case "mixed":
73
+ if (!i) throw e("real_money_disabled");
74
+ return n(t, [
75
+ "kind",
76
+ "real",
77
+ "virtual"
78
+ ], "invalid_price"), Object.freeze({
79
+ kind: "mixed",
80
+ real: s(l.real),
81
+ virtual: c(l.virtual, o)
82
+ });
83
+ default: throw e("invalid_price");
84
+ }
85
+ }, u = (e, t) => Object.freeze(e.map((e) => {
86
+ let n = t.adjustments.find((t) => t.currency === e.currency);
87
+ if (!n) return e;
88
+ let r = (BigInt(e.amount) * BigInt(1e4 - n.discountBps) + 9999n) / 10000n, i = BigInt(n.minimum);
89
+ return Object.freeze({
90
+ currency: e.currency,
91
+ amount: (r < i ? i : r).toString()
92
+ });
93
+ })), d = (e) => {
94
+ switch (e.price.kind) {
95
+ case "virtual": return Object.freeze({
96
+ kind: "virtual",
97
+ options: u(e.price.options, e)
98
+ });
99
+ case "mixed": return Object.freeze({
100
+ kind: "mixed",
101
+ real: e.price.real,
102
+ virtual: u(e.price.virtual, e)
103
+ });
104
+ default: return e.price;
105
+ }
106
+ }, f = (o, s, c = !1, u = []) => {
107
+ let d = a(s), f = l(o, d, c), p = f.kind === "virtual" ? f.options : f.kind === "mixed" ? f.virtual : [], m = /* @__PURE__ */ new Set(), h = t(u, 32, "invalid_price").map((t) => {
108
+ let a = n(t, [
109
+ "currency",
110
+ "discountBps",
111
+ "minimum"
112
+ ], "invalid_price"), o = r(a.currency, "invalid_price"), s = p.find((e) => e.currency === o), c = a.discountBps, l = i(a.minimum);
113
+ if (!s || m.has(o) || typeof c != "number" || !Number.isInteger(c) || c < 0 || c > 1e4 || l > BigInt(s.amount)) throw e("invalid_price");
114
+ return m.add(o), Object.freeze({
115
+ currency: o,
116
+ discountBps: c,
117
+ minimum: l.toString()
118
+ });
119
+ });
120
+ return Object.freeze({
121
+ price: f,
122
+ currencies: d,
123
+ realMoney: c,
124
+ adjustments: Object.freeze(h)
125
+ });
126
+ }, p = (t, n = d) => {
127
+ if (typeof n != "function") throw e("invalid_input");
128
+ let r = f(t.price, t.currencies, t.realMoney, t.adjustments), i = l(n(r), r.currencies, r.realMoney);
129
+ if (i.kind !== r.price.kind) throw e("invalid_price");
130
+ let a = r.price.kind === "virtual" ? r.price.options : r.price.kind === "mixed" ? r.price.virtual : [], o = i.kind === "virtual" ? i.options : i.kind === "mixed" ? i.virtual : [];
131
+ if (a.length !== o.length) throw e("invalid_price");
132
+ for (let t of o) {
133
+ let n = a.find((e) => e.currency === t.currency), i = r.adjustments.find((e) => e.currency === t.currency)?.minimum ?? "0";
134
+ if (!n || BigInt(t.amount) < BigInt(i) || BigInt(t.amount) > BigInt(n.amount)) throw e("invalid_price");
135
+ }
136
+ let s = r.price.kind === "real" ? r.price : r.price.kind === "mixed" ? r.price.real : null, c = i.kind === "real" ? i : i.kind === "mixed" ? i.real : null;
137
+ if (s && c) {
138
+ let t = Object.keys(s.prices), n = Object.keys(s.storeProductIds);
139
+ if (Object.keys(c.prices).length !== t.length || Object.keys(c.storeProductIds).length !== n.length || t.some((e) => s.prices[e] !== c.prices[e]) || n.some((e) => s.storeProductIds[e] !== c.storeProductIds[e])) throw e("invalid_price");
140
+ }
141
+ return i;
142
+ };
143
+ export { d as defaultPriceResolver, l as definePrice, f as priceResolverContext, p as resolvePrice };
@@ -0,0 +1,55 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { dataObject as t, identifier as n } from "./capture.js";
3
+ import { captureShopOrderReceipt as r, shopBuyIntent as i } from "./shop.js";
4
+ import { browserIntentionJournal as a, createIntentionRecovery as o } from "./intentionRecovery.js";
5
+ // src/purchaseRecovery.ts
6
+ var s = (e) => {
7
+ let t = i(e);
8
+ return Object.freeze({
9
+ offerId: t.offerId,
10
+ offerVersion: t.offerVersion,
11
+ offerDigest: t.offerDigest,
12
+ requestId: t.requestId,
13
+ qty: t.qty,
14
+ ...t.currency === null ? {} : { currency: t.currency }
15
+ });
16
+ }, c = (i) => {
17
+ let a = t(i, [
18
+ "requestId",
19
+ "state",
20
+ "receipt"
21
+ ], "invalid_record"), o = n(a.requestId, "invalid_record");
22
+ if (a.state === "not-observed" || a.state === "pending") {
23
+ if (Object.hasOwn(a, "receipt")) throw e("invalid_record");
24
+ return Object.freeze({
25
+ requestId: o,
26
+ state: a.state
27
+ });
28
+ }
29
+ if (a.state !== "fulfilled") throw e("invalid_record");
30
+ return Object.freeze({
31
+ requestId: o,
32
+ state: "fulfilled",
33
+ receipt: r(a.receipt)
34
+ });
35
+ }, l = (t, n) => {
36
+ let r = c(n);
37
+ if (r.requestId !== t.requestId) throw e("conflict");
38
+ if (r.state !== "fulfilled") return r;
39
+ let a = r.receipt, o = i(t);
40
+ if (a.offerId !== o.offerId || a.offerVersion !== o.offerVersion || a.offerDigest !== o.offerDigest || a.quantity !== o.qty || (a.pricePaid.kind === "free" ? o.currency !== null : a.pricePaid.currency !== o.currency)) throw e("conflict");
41
+ return r;
42
+ }, u = (e, t) => o(e, t, {
43
+ request: (e) => s(e),
44
+ observation: c,
45
+ fulfilled: (e, t) => ({
46
+ requestId: e.requestId,
47
+ state: "fulfilled",
48
+ receipt: t
49
+ }),
50
+ resolve: (e, t) => {
51
+ let n = l(e, t);
52
+ return n.state === "fulfilled" ? n.receipt : void 0;
53
+ }
54
+ }), d = (e, t) => a(e, t, "voltro:shop-purchase:v1:", 2048, (e) => s(e));
55
+ export { d as browserShopPurchaseJournal, u as createShopPurchaseRecovery };
@@ -0,0 +1,114 @@
1
+ import { EconomyError as e, economyError as t } from "./errors.js";
2
+ import { dataObject as n, identifier as r } from "./capture.js";
3
+ import { nonNegativeAmount as i } from "./amount.js";
4
+ import { economyLedgerTable as a } from "./tables.entity.js";
5
+ import { economyLedgerAt as o, readEconomyTransferEvidence as s } from "./walletStore.js";
6
+ import { Effect as c, Schema as l } from "effect";
7
+ import { eq as u, queryFor as d } from "@voltro/database";
8
+ import { defineAggregate as f } from "@voltro/runtime";
9
+ // src/reports.server.ts
10
+ var p = l.Struct({
11
+ day: l.String,
12
+ currency: l.String,
13
+ reason: l.String,
14
+ sources: l.String,
15
+ sinks: l.String,
16
+ playerTransfers: l.String,
17
+ transactions: l.Number
18
+ }), m = (e) => {
19
+ let i = n(e, [
20
+ "tenantId",
21
+ "maxRows",
22
+ "maxGroups"
23
+ ]), a = i.maxRows ?? 1e4, o = i.maxGroups ?? 1e3;
24
+ if (typeof a != "number" || !Number.isSafeInteger(a) || a < 2 || a > 1e5 || typeof o != "number" || !Number.isSafeInteger(o) || o < 1 || o > 1e4) throw t("invalid_input");
25
+ return Object.freeze({
26
+ tenantId: r(i.tenantId),
27
+ maxRows: a,
28
+ maxGroups: o
29
+ });
30
+ }, h = (e, n) => {
31
+ let a = /* @__PURE__ */ new Map();
32
+ for (let s of e) {
33
+ if (s.length !== 2) throw t("invalid_record");
34
+ let e = s.find((e) => i(e.debit) > 0n), c = s.find((e) => i(e.credit) > 0n);
35
+ if (!e || !c) throw t("invalid_record");
36
+ let l = new Date(o(e.at)).toISOString().split("T")[0], u = r(e.currency), d = r(e.reason), f = JSON.stringify([
37
+ l,
38
+ u,
39
+ d
40
+ ]), p = a.get(f);
41
+ if (!p) {
42
+ if (a.size === n) throw t("limit_exceeded");
43
+ p = {
44
+ day: l,
45
+ currency: u,
46
+ reason: d,
47
+ sources: 0n,
48
+ sinks: 0n,
49
+ playerTransfers: 0n,
50
+ transactions: 0
51
+ }, a.set(f, p);
52
+ }
53
+ let m = i(e.debit);
54
+ e.accountKind === "system" ? p.sources += m : c.accountKind === "system" ? p.sinks += m : p.playerTransfers += m, p.transactions++;
55
+ }
56
+ return Object.freeze([...a.values()].sort((e, t) => e.day.localeCompare(t.day) || e.currency.localeCompare(t.currency) || e.reason.localeCompare(t.reason)).map((e) => Object.freeze({
57
+ ...e,
58
+ sources: e.sources.toString(),
59
+ sinks: e.sinks.toString(),
60
+ playerTransfers: e.playerTransfers.toString()
61
+ })));
62
+ }, g = (n, i) => {
63
+ try {
64
+ let o = m(i);
65
+ return c.tryPromise({
66
+ try: () => n.transactional(async (e) => {
67
+ let n = await e.query(d(a).where(u("tenantId", o.tenantId)).orderBy("id", "asc").limit(o.maxRows + 1).descriptor);
68
+ if (n.length > o.maxRows) throw t("limit_exceeded");
69
+ let i = /* @__PURE__ */ new Map();
70
+ for (let e of n) {
71
+ if (e.tenantId !== o.tenantId) throw t("invalid_record");
72
+ let n = r(e.currency), a = r(e.txId), s = i.get(n);
73
+ s || (s = /* @__PURE__ */ new Set(), i.set(n, s)), s.add(a);
74
+ }
75
+ let c = [];
76
+ for (let [t, n] of i) {
77
+ let r = await s(e, o.tenantId, [...n], t);
78
+ for (let { pair: e } of r.values()) c.push(e);
79
+ }
80
+ return h(c, o.maxGroups);
81
+ }),
82
+ catch: (n) => n instanceof e ? n : t("unavailable")
83
+ });
84
+ } catch (n) {
85
+ return c.fail(n instanceof e ? n : t("invalid_input"));
86
+ }
87
+ }, _ = (e) => {
88
+ let i = n(e, [
89
+ "tenantId",
90
+ "maxRows",
91
+ "maxGroups",
92
+ "name",
93
+ "refresh"
94
+ ]), a = m({
95
+ tenantId: i.tenantId,
96
+ ...i.maxRows === void 0 ? {} : { maxRows: i.maxRows },
97
+ ...i.maxGroups === void 0 ? {} : { maxGroups: i.maxGroups }
98
+ }), o = r(i.name ?? "economy.flows"), s = i.refresh ?? "1h";
99
+ if (typeof s != "string" || !/^[1-9][0-9]{0,6}(ms|s|m|h|d)$/.test(s)) throw t("invalid_input");
100
+ return f({
101
+ name: o,
102
+ refresh: s,
103
+ output: p,
104
+ bootRefresh: "persistent",
105
+ strategy: "replace",
106
+ indexes: [[
107
+ "day",
108
+ "currency",
109
+ "reason"
110
+ ]],
111
+ build: (e) => g(e.store, a)
112
+ });
113
+ };
114
+ export { p as EconomyFlowRowSchema, m as captureEconomyReportOptions, _ as economyFlowsAggregate, g as readEconomyFlows };