@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/index.js ADDED
@@ -0,0 +1,15 @@
1
+ import { EconomyError as e } from "./errors.js";
2
+ import { economyAmount as t, economyAmountString as n } from "./amount.js";
3
+ import { defineCurrency as r } from "./currency.js";
4
+ import { defaultPriceResolver as i, definePrice as a, priceResolverContext as o, resolvePrice as s } from "./price.js";
5
+ import { ShopPort as c, captureShopOrderReceipt as l, captureShopService as u, defineShopOffer as d, shopBuyIntent as f, shopInteger as p, shopPayment as m } from "./shop.js";
6
+ import { applyWalletPosting as h, economyAccountKey as g, planLedgerTransfer as _ } from "./ledger.js";
7
+ import { assertSpendBudget as v, captureSpendLimitsOptions as y, defaultSpendLimitPolicy as b, defineSpendLimits as x, projectSpend as S, resolveSpendBudget as C, utcSpendWindows as w } from "./spendLimits.js";
8
+ import { TradesPort as T, captureTradeLeg as E, captureTradeObservation as D, captureTradeParticipantAuthority as O, captureTradeProposeIntention as k, captureTradeReceipt as A, captureTradeView as j, captureTradesService as M, defaultTradeEligibilityPolicy as N, defaultTradeTaxPolicy as P, defineTradeRules as F, resolveTradeEligibility as I, resolveTradeTax as L, tradeAcceptIntent as R, tradeCancelIntent as z, tradeProposeIntent as B } from "./trades.js";
9
+ import { CodePort as V, captureCodeIntent as H, captureCodeService as U, captureCodeValue as W, defaultCodeEligibility as G, defineCode as K, resolveCodeEligibility as q } from "./codes.js";
10
+ import { SubscriptionsPort as J, captureSubscriptionReceiptIntent as Y, captureSubscriptionsService as X, defaultSubscriptionDailyGrant as Z, defaultSubscriptionPeriod as Q, defineSubscription as $, resolveSubscriptionDailyGrant as ee, resolveSubscriptionPeriod as te, subscriptionEntitlementIntent as ne, subscriptionRenewIntent as re, subscriptionStartIntent as ie } from "./subscriptions.js";
11
+ import { LoyaltyPort as ae, captureLoyaltyService as oe, defaultLoyaltyPerks as se, defaultLoyaltyTier as ce, defineLoyalty as le, loyaltyCreditIntent as ue, loyaltyMineIntent as de, loyaltyPointsForPurchase as fe, loyaltyRebuildIntent as pe, loyaltyReceiptIntent as me, loyaltyReverseIntent as he, projectLoyaltyPoints as ge, resolveLoyaltyPerks as _e, resolveLoyaltyTier as ve } from "./loyalty.js";
12
+ import { PiggyBanksPort as ye, capturePiggyBanksService as be, defaultPiggyFill as xe, defaultPiggyReset as Se, definePiggyBank as Ce, piggyFillIntent as we, piggyUnlockIntent as Te, projectPiggyBank as Ee, resolvePiggyFill as De, resolvePiggyReset as Oe } from "./piggyBanks.js";
13
+ import { EconomyPort as ke, captureEconomyService as Ae } from "./port.js";
14
+ import { economyCodesSystemContract as je, economyContainersSystemContract as Me, economyIapSystemContract as Ne, economyLoyaltySystemContract as Pe, economyPiggyBanksSystemContract as Fe, economyPlugin as Ie, economyShopSystemContract as Le, economySpendLimitsSystemContract as Re, economySubscriptionsSystemContract as ze, economySystemContract as Be, economyTradesSystemContract as Ve } from "./plugin.js";
15
+ export { V as CodePort, e as EconomyError, ke as EconomyPort, ae as LoyaltyPort, ye as PiggyBanksPort, c as ShopPort, J as SubscriptionsPort, T as TradesPort, h as applyWalletPosting, v as assertSpendBudget, H as captureCodeIntent, U as captureCodeService, W as captureCodeValue, Ae as captureEconomyService, oe as captureLoyaltyService, be as capturePiggyBanksService, l as captureShopOrderReceipt, u as captureShopService, y as captureSpendLimitsOptions, Y as captureSubscriptionReceiptIntent, X as captureSubscriptionsService, E as captureTradeLeg, D as captureTradeObservation, O as captureTradeParticipantAuthority, k as captureTradeProposeIntention, A as captureTradeReceipt, j as captureTradeView, M as captureTradesService, G as defaultCodeEligibility, se as defaultLoyaltyPerks, ce as defaultLoyaltyTier, xe as defaultPiggyFill, Se as defaultPiggyReset, i as defaultPriceResolver, b as defaultSpendLimitPolicy, Z as defaultSubscriptionDailyGrant, Q as defaultSubscriptionPeriod, N as defaultTradeEligibilityPolicy, P as defaultTradeTaxPolicy, K as defineCode, r as defineCurrency, le as defineLoyalty, Ce as definePiggyBank, a as definePrice, d as defineShopOffer, x as defineSpendLimits, $ as defineSubscription, F as defineTradeRules, g as economyAccountKey, t as economyAmount, n as economyAmountString, je as economyCodesSystemContract, Me as economyContainersSystemContract, Ne as economyIapSystemContract, Pe as economyLoyaltySystemContract, Fe as economyPiggyBanksSystemContract, Ie as economyPlugin, Le as economyShopSystemContract, Re as economySpendLimitsSystemContract, ze as economySubscriptionsSystemContract, Be as economySystemContract, Ve as economyTradesSystemContract, ue as loyaltyCreditIntent, de as loyaltyMineIntent, fe as loyaltyPointsForPurchase, pe as loyaltyRebuildIntent, me as loyaltyReceiptIntent, he as loyaltyReverseIntent, we as piggyFillIntent, Te as piggyUnlockIntent, _ as planLedgerTransfer, o as priceResolverContext, ge as projectLoyaltyPoints, Ee as projectPiggyBank, S as projectSpend, q as resolveCodeEligibility, _e as resolveLoyaltyPerks, ve as resolveLoyaltyTier, De as resolvePiggyFill, Oe as resolvePiggyReset, s as resolvePrice, C as resolveSpendBudget, ee as resolveSubscriptionDailyGrant, te as resolveSubscriptionPeriod, I as resolveTradeEligibility, L as resolveTradeTax, f as shopBuyIntent, p as shopInteger, m as shopPayment, ne as subscriptionEntitlementIntent, re as subscriptionRenewIntent, ie as subscriptionStartIntent, R as tradeAcceptIntent, z as tradeCancelIntent, B as tradeProposeIntent, w as utcSpendWindows };
@@ -0,0 +1,133 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { captureBoundMethods as t, dataObject as n, identifier as r } from "./capture.js";
3
+ // src/intentionRecovery.ts
4
+ var i = (t, i, a) => {
5
+ let o = n(t, [
6
+ "version",
7
+ "scope",
8
+ "request"
9
+ ], "invalid_record");
10
+ if (o.version !== 1 || o.scope !== i) throw e("invalid_record");
11
+ return Object.freeze({
12
+ version: 1,
13
+ scope: r(i),
14
+ request: a(o.request)
15
+ });
16
+ }, a = (e, t) => e.scope === t.scope && JSON.stringify(e.request) === JSON.stringify(t.request), o = (n, o, s) => {
17
+ let c = t(n, ["withLocked"]);
18
+ if (typeof o != "function") throw e("invalid_input");
19
+ let l, u = 0, d = () => {
20
+ if (l === void 0) throw e("forbidden");
21
+ return {
22
+ scope: l,
23
+ generation: u
24
+ };
25
+ }, f = (t) => {
26
+ if (t.scope !== l || t.generation !== u) throw e("conflict");
27
+ }, p = (e) => {
28
+ let t = d();
29
+ return c.withLocked(t.scope, async (n) => (f(t), e(n, t.scope, () => f(t))));
30
+ };
31
+ return Object.freeze({
32
+ selectScope: (e) => {
33
+ let t = e === void 0 ? void 0 : r(e);
34
+ u++, l = t;
35
+ },
36
+ pending: () => p(async (e, t) => {
37
+ let n = e.read();
38
+ return n === void 0 ? void 0 : i(n, t, s.request);
39
+ }),
40
+ begin: (t) => {
41
+ let n = s.request(t);
42
+ return p(async (t, r) => {
43
+ let o = Object.freeze({
44
+ version: 1,
45
+ scope: r,
46
+ request: n
47
+ }), c = t.read();
48
+ if (c !== void 0) {
49
+ let t = i(c, r, s.request);
50
+ if (!a(t, o)) throw e("conflict");
51
+ return t;
52
+ }
53
+ t.write(o);
54
+ let l = t.read();
55
+ if (!l || !a(i(l, r, s.request), o)) throw e("unavailable");
56
+ return o;
57
+ });
58
+ },
59
+ retry: (t) => {
60
+ let n = s.request(t);
61
+ return p(async (t, r, c) => {
62
+ let l = t.read();
63
+ if (l === void 0) throw e("not_found");
64
+ let u = i(l, r, s.request);
65
+ if (!a(u, {
66
+ version: 1,
67
+ scope: r,
68
+ request: n
69
+ })) throw e("conflict");
70
+ c();
71
+ let d = await o(u.request, c);
72
+ c();
73
+ let f = s.resolve(u.request, s.observation(s.fulfilled(u.request, d)));
74
+ if (f === void 0) throw e("invalid_record");
75
+ let p = t.read();
76
+ if (!p || !a(i(p, r, s.request), u)) throw e("conflict");
77
+ return t.clear(u), f;
78
+ });
79
+ },
80
+ observe: (e) => {
81
+ let t = s.observation(e);
82
+ return p(async (e, n) => {
83
+ let r = e.read();
84
+ if (r === void 0) return;
85
+ let a = i(r, n, s.request);
86
+ if (s.resolve(a.request, t) === void 0) return a;
87
+ e.clear(a);
88
+ });
89
+ }
90
+ });
91
+ }, s = (n, o, s, c, l) => {
92
+ if (!n || !o) throw e("unavailable");
93
+ let u = t(n, [
94
+ "getItem",
95
+ "setItem",
96
+ "removeItem"
97
+ ]), d = t(o, ["request"]);
98
+ return Object.freeze({ withLocked: (t, n) => {
99
+ let o = r(t), f = s + o;
100
+ return d.request(f, async () => {
101
+ let t = () => {
102
+ let t = u.getItem(f);
103
+ if (t === null) return;
104
+ if (t.length > c) throw e("invalid_record");
105
+ let n;
106
+ try {
107
+ n = JSON.parse(t);
108
+ } catch {
109
+ throw e("invalid_record");
110
+ }
111
+ return i(n, o, l);
112
+ };
113
+ return n(Object.freeze({
114
+ read: t,
115
+ write: (n) => {
116
+ let r = i(n, o, l), s = t();
117
+ if (s && !a(s, r)) throw e("conflict");
118
+ let d = JSON.stringify(r);
119
+ if (d.length > c) throw e("invalid_input");
120
+ u.setItem(f, d);
121
+ let p = t();
122
+ if (!p || !a(p, r)) throw e("unavailable");
123
+ },
124
+ clear: (n) => {
125
+ let r = t();
126
+ if (!r || !a(r, i(n, o, l))) throw e("conflict");
127
+ if (u.removeItem(f), u.getItem(f) !== null) throw e("unavailable");
128
+ }
129
+ }));
130
+ });
131
+ } });
132
+ };
133
+ export { s as browserIntentionJournal, o as createIntentionRecovery };
package/dist/ledger.js ADDED
@@ -0,0 +1,77 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { dataObject as t, identifier as n } from "./capture.js";
3
+ import { economyAmount as r, positiveAmount as i } from "./amount.js";
4
+ import { defineCurrency as a } from "./currency.js";
5
+ // src/ledger.ts
6
+ var o = (r) => {
7
+ let i = t(r, [
8
+ "kind",
9
+ "ownerId",
10
+ "ownerKind",
11
+ "id"
12
+ ]);
13
+ if (i.kind === "system") return t(r, ["kind", "id"]), Object.freeze({
14
+ kind: "system",
15
+ id: n(i.id)
16
+ });
17
+ if (i.kind !== "wallet" || i.ownerKind !== "player" && i.ownerKind !== "guild") throw e("invalid_input");
18
+ return t(r, [
19
+ "kind",
20
+ "ownerId",
21
+ "ownerKind"
22
+ ]), Object.freeze({
23
+ kind: "wallet",
24
+ ownerId: n(i.ownerId),
25
+ ownerKind: i.ownerKind
26
+ });
27
+ }, s = (e) => {
28
+ let t = o(e);
29
+ return t.kind === "system" ? JSON.stringify(["system", t.id]) : JSON.stringify([
30
+ "wallet",
31
+ t.ownerKind,
32
+ t.ownerId
33
+ ]);
34
+ }, c = (r, a) => {
35
+ let c = t(r, [
36
+ "tenantId",
37
+ "requestId",
38
+ "currency",
39
+ "from",
40
+ "to",
41
+ "amount",
42
+ "reason",
43
+ "ref"
44
+ ]), l = o(c.from), u = o(c.to);
45
+ if (s(l) === s(u) || l.kind === "system" && u.kind === "system" && (!a || !l.id.startsWith("escrow.") || l.id.startsWith("escrow.tax.") || !u.id.startsWith("escrow.tax.") || c.reason !== "escrow.tax")) throw e("invalid_input");
46
+ let d = i(c.amount).toString(), f = t(c.ref, ["kind", "id"]), p = Object.freeze({
47
+ kind: n(f.kind),
48
+ id: n(f.id)
49
+ }), m = Object.freeze([Object.freeze({
50
+ account: l,
51
+ debit: d,
52
+ credit: "0"
53
+ }), Object.freeze({
54
+ account: u,
55
+ debit: "0",
56
+ credit: d
57
+ })]);
58
+ return Object.freeze({
59
+ tenantId: n(c.tenantId),
60
+ requestId: n(c.requestId),
61
+ currency: n(c.currency),
62
+ amount: d,
63
+ reason: n(c.reason),
64
+ ref: p,
65
+ postings: m
66
+ });
67
+ }, l = (e) => c(e, !1), u = (e) => c(e, !0), d = (t, n, i, o) => {
68
+ let s = a(i), c = r(t);
69
+ if (c < 0n && s.kind !== "hard" || c > BigInt(s.cap)) throw e("invalid_record");
70
+ let l = r(n.debit), u = r(n.credit);
71
+ if (l < 0n || u < 0n || l === 0n == (u === 0n)) throw e("invalid_record");
72
+ let d = c + u - l;
73
+ if (l > 0n && d < 0n && (!o || s.kind !== "hard")) throw e("insufficient_funds");
74
+ if (d > BigInt(s.cap)) throw e("currency_cap_reached");
75
+ return r(d).toString();
76
+ }, f = (e, t, n) => d(e, t, n, !1), p = (e, t, n) => d(e, t, n, !0);
77
+ export { f as applyWalletPosting, p as applyWalletRefundPosting, o as captureAccount, s as economyAccountKey, u as planEscrowLedgerTransfer, l as planLedgerTransfer };
@@ -0,0 +1,274 @@
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 captureLoyaltyService: (input: LoyaltyService) => LoyaltyService;
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 defaultLoyaltyPerks: LoyaltyPerksResolver;
21
+
22
+ export declare const defaultLoyaltyTier: LoyaltyTierResolver;
23
+
24
+ export declare const defineLoyalty: (input: LoyaltyDefinition | Loyalty, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => Loyalty;
25
+
26
+ declare type EconomyAmountInput = string | number | bigint;
27
+
28
+ /** Redacted codes; never carries owners, amounts or provider payloads. */
29
+ declare class EconomyError extends EconomyError_base {
30
+ }
31
+
32
+ declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
33
+ 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"]>;
34
+ }>, YieldableError>;
35
+
36
+ export declare interface Loyalty {
37
+ readonly id: string;
38
+ readonly version: string;
39
+ readonly titleKey: string;
40
+ readonly pointsFrom: readonly {
41
+ readonly id: string;
42
+ readonly kind: 'purchase.real' | 'purchase.virtual';
43
+ readonly currency: string;
44
+ readonly numerator: string;
45
+ readonly denominator: string;
46
+ }[];
47
+ readonly tiers: readonly {
48
+ readonly id: string;
49
+ readonly at: string;
50
+ readonly perks: readonly LoyaltyPerk[];
51
+ }[];
52
+ readonly decay: 'none' | 'seasonal';
53
+ }
54
+
55
+ /** Only trusted server callers name receipts. Amounts, weights, points, tiers
56
+ * and seasons are never request fields. No player credit/reverse action. */
57
+ export declare interface LoyaltyCreditInput {
58
+ readonly tenantId: string;
59
+ readonly ownerId: string;
60
+ readonly loyaltyId: string;
61
+ readonly sourceId: string;
62
+ readonly purchaseId: string;
63
+ readonly requestId: string;
64
+ }
65
+
66
+ export declare const loyaltyCreditIntent: (input: LoyaltyCreditInput) => LoyaltyCreditInput;
67
+
68
+ export declare interface LoyaltyDefinition {
69
+ readonly id: string;
70
+ readonly version?: string | undefined;
71
+ readonly titleKey: string;
72
+ readonly pointsFrom: readonly {
73
+ readonly id: string;
74
+ readonly kind: 'purchase.real' | 'purchase.virtual';
75
+ readonly currency: string;
76
+ readonly numerator: EconomyAmountInput;
77
+ readonly denominator: EconomyAmountInput;
78
+ }[];
79
+ readonly tiers: readonly {
80
+ readonly id: string;
81
+ readonly at: EconomyAmountInput;
82
+ readonly perks: readonly LoyaltyPerkDefinition[];
83
+ }[];
84
+ readonly decay?: 'none' | 'seasonal';
85
+ }
86
+
87
+ export declare interface LoyaltyMineInput {
88
+ readonly loyaltyId: string;
89
+ }
90
+
91
+ export declare const loyaltyMineIntent: (input: LoyaltyMineInput) => LoyaltyMineInput;
92
+
93
+ export declare type LoyaltyObservation = {
94
+ readonly requestId: string;
95
+ readonly state: 'not-observed';
96
+ } | {
97
+ readonly requestId: string;
98
+ readonly state: 'fulfilled';
99
+ readonly receipt: LoyaltyReceipt;
100
+ };
101
+
102
+ export declare type LoyaltyPerk = Exclude<LoyaltyPerkDefinition, {
103
+ readonly kind: 'inboxGift';
104
+ }> | {
105
+ readonly id: string;
106
+ readonly kind: 'inboxGift';
107
+ readonly items: readonly ShopItemGrant[];
108
+ readonly currencies: readonly {
109
+ readonly currency: string;
110
+ readonly amount: string;
111
+ }[];
112
+ };
113
+
114
+ export declare type LoyaltyPerkDefinition = {
115
+ readonly id: string;
116
+ readonly kind: 'xpMultiplier';
117
+ readonly bps: number;
118
+ } | {
119
+ readonly id: string;
120
+ readonly kind: 'discount';
121
+ readonly bps: number;
122
+ } | {
123
+ readonly id: string;
124
+ readonly kind: 'chatBadge';
125
+ readonly badgeId: string;
126
+ } | {
127
+ readonly id: string;
128
+ readonly kind: 'inboxGift';
129
+ readonly items?: readonly ShopItemGrant[] | undefined;
130
+ readonly currencies?: readonly ShopCurrencyGrant[] | undefined;
131
+ };
132
+
133
+ export declare interface LoyaltyPerksContext extends LoyaltyTierContext {
134
+ readonly tierId: string;
135
+ }
136
+
137
+ export declare type LoyaltyPerksResolver = (input: LoyaltyPerksContext) => readonly LoyaltyPerk[];
138
+
139
+ export declare type LoyaltyPointEntry = {
140
+ readonly id: string;
141
+ readonly sequence: number;
142
+ readonly kind: 'credit';
143
+ readonly at: number;
144
+ readonly sourceId: string;
145
+ readonly purchaseId: string;
146
+ readonly seasonId: string | null;
147
+ readonly purchaseAmount: string;
148
+ readonly numerator: string;
149
+ readonly denominator: string;
150
+ readonly delta: string;
151
+ } | {
152
+ readonly id: string;
153
+ readonly sequence: number;
154
+ readonly kind: 'reverse';
155
+ readonly at: number;
156
+ readonly originalId: string;
157
+ readonly refundId: string;
158
+ readonly seasonId: string | null;
159
+ readonly totalRefunded: string;
160
+ readonly delta: string;
161
+ };
162
+
163
+ export declare interface LoyaltyPointProjection {
164
+ readonly entries: readonly LoyaltyPointEntry[];
165
+ readonly balances: readonly {
166
+ readonly seasonId: string | null;
167
+ readonly points: string;
168
+ }[];
169
+ readonly credits: readonly {
170
+ readonly id: string;
171
+ readonly refundedAmount: string;
172
+ readonly remainingPoints: string;
173
+ }[];
174
+ }
175
+
176
+ /** Trusted verified settlement projection only, not a player input/receipt
177
+ * validator. Exact floor rounding is defined once per accepted purchase; a full
178
+ * reversal must reverse its recorded credit, never independently reround it. */
179
+ export declare const loyaltyPointsForPurchase: (input: LoyaltyDefinition | Loyalty, sourceId: string, amount: EconomyAmountInput, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => string;
180
+
181
+ export declare class LoyaltyPort extends LoyaltyPort_base {
182
+ }
183
+
184
+ declare const LoyaltyPort_base: Context.ServiceClass<LoyaltyPort, "@voltro/LoyaltyPort", LoyaltyService>;
185
+
186
+ export declare interface LoyaltyRebuildInput extends LoyaltyMineInput {
187
+ readonly tenantId: string;
188
+ readonly ownerId: string;
189
+ }
190
+
191
+ export declare const loyaltyRebuildIntent: (input: LoyaltyRebuildInput) => LoyaltyRebuildInput;
192
+
193
+ export declare interface LoyaltyReceipt {
194
+ readonly operationId: string;
195
+ readonly requestId: string;
196
+ readonly loyaltyId: string;
197
+ readonly entry: LoyaltyPointEntry;
198
+ readonly points: string;
199
+ }
200
+
201
+ export declare interface LoyaltyReceiptInput {
202
+ readonly requestId: string;
203
+ }
204
+
205
+ export declare const loyaltyReceiptIntent: (input: LoyaltyReceiptInput) => LoyaltyReceiptInput;
206
+
207
+ export declare interface LoyaltyReverseInput {
208
+ readonly tenantId: string;
209
+ readonly ownerId: string;
210
+ readonly loyaltyId: string;
211
+ readonly originalId: string;
212
+ readonly refundId: string;
213
+ readonly requestId: string;
214
+ }
215
+
216
+ export declare const loyaltyReverseIntent: (input: LoyaltyReverseInput) => LoyaltyReverseInput;
217
+
218
+ export declare interface LoyaltyService {
219
+ readonly list: (subject: Subject) => Effect.Effect<readonly Loyalty[], EconomyError>;
220
+ readonly mine: (subject: Subject, input: LoyaltyMineInput) => Effect.Effect<LoyaltyState, EconomyError>;
221
+ readonly credit: (subject: Subject, input: LoyaltyCreditInput) => Effect.Effect<LoyaltyReceipt, EconomyError>;
222
+ readonly reverse: (subject: Subject, input: LoyaltyReverseInput) => Effect.Effect<LoyaltyReceipt, EconomyError>;
223
+ readonly receipt: (subject: Subject, input: LoyaltyReceiptInput) => Effect.Effect<LoyaltyObservation, EconomyError>;
224
+ readonly rebuild: (subject: Subject, input: LoyaltyRebuildInput) => Effect.Effect<LoyaltyPointProjection, EconomyError>;
225
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
226
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
227
+ }
228
+
229
+ export declare interface LoyaltyState {
230
+ readonly loyalty: Loyalty;
231
+ readonly rulesVersion: string;
232
+ readonly seasonId: string | null;
233
+ readonly points: string;
234
+ readonly tierId: string;
235
+ readonly perks: readonly LoyaltyPerk[];
236
+ }
237
+
238
+ export declare interface LoyaltyTierContext {
239
+ readonly loyalty: Loyalty;
240
+ readonly currencies: readonly CurrencyDefinition[];
241
+ readonly realMoney?: boolean;
242
+ readonly points: EconomyAmountInput;
243
+ readonly rulesVersion?: string;
244
+ }
245
+
246
+ export declare type LoyaltyTierResolver = (context: LoyaltyTierContext) => string;
247
+
248
+ /** Whole accepted-history projection shared by the future SQL writer/rebuild.
249
+ * No purchase/refund authenticity is inferred here. The owner must provide all
250
+ * rows from one tenant/subject, and archive original source weights as evidence.
251
+ * Cumulative partial refunds cannot exploit independent floor rounding. */
252
+ export declare const projectLoyaltyPoints: (input: readonly LoyaltyPointEntry[], decay?: Loyalty["decay"]) => LoyaltyPointProjection;
253
+
254
+ /** A named override chooses a subset of declared qualifying-tier perks. App
255
+ * authors change the declaration to change rewards, never return hidden grants. */
256
+ export declare const resolveLoyaltyPerks: (input: LoyaltyPerksContext, slot?: LoyaltyPerksResolver) => readonly LoyaltyPerk[];
257
+
258
+ export declare const resolveLoyaltyTier: (input: LoyaltyTierContext, slot?: LoyaltyTierResolver) => {
259
+ readonly id: string;
260
+ readonly at: string;
261
+ readonly perks: readonly LoyaltyPerk[];
262
+ };
263
+
264
+ declare interface ShopCurrencyGrant {
265
+ readonly currency: string;
266
+ readonly amount: EconomyAmountInput;
267
+ }
268
+
269
+ declare interface ShopItemGrant {
270
+ readonly itemId: string;
271
+ readonly qty: number;
272
+ }
273
+
274
+ export { }
@@ -0,0 +1,92 @@
1
+ import { defaultLoyaltyPerks as e, defaultLoyaltyTier as t, defineLoyalty as n, resolveLoyaltyPerks as r, resolveLoyaltyTier as i } from "./loyalty.js";
2
+ import { Effect as a } from "effect";
3
+ // src/loyalty.fixture.ts
4
+ var o = () => {
5
+ let e = [{
6
+ id: "test.gold",
7
+ kind: "soft"
8
+ }], t = n({
9
+ id: "test.vip",
10
+ titleKey: "test.vip",
11
+ pointsFrom: [{
12
+ id: "virtual.gold",
13
+ kind: "purchase.virtual",
14
+ currency: "test.gold",
15
+ numerator: "1",
16
+ denominator: "1"
17
+ }],
18
+ tiers: [
19
+ {
20
+ id: "base",
21
+ at: "0",
22
+ perks: []
23
+ },
24
+ {
25
+ id: "silver",
26
+ at: "1000",
27
+ perks: [{
28
+ id: "silver.discount",
29
+ kind: "discount",
30
+ bps: 500
31
+ }]
32
+ },
33
+ {
34
+ id: "gold",
35
+ at: "10000",
36
+ perks: [{
37
+ id: "gold.xp",
38
+ kind: "xpMultiplier",
39
+ bps: 12e3
40
+ }, {
41
+ id: "gold.badge",
42
+ kind: "chatBadge",
43
+ badgeId: "test.gold"
44
+ }]
45
+ }
46
+ ],
47
+ decay: "none"
48
+ }, e);
49
+ return Object.freeze({
50
+ loyalty: t,
51
+ currencies: e,
52
+ points: "1000",
53
+ realMoney: !1
54
+ });
55
+ }, s = o(), c = Object.freeze({
56
+ kind: "slot",
57
+ defaultImplementation: t,
58
+ defaultProbe: {
59
+ run: () => a.sync(() => i(s).id),
60
+ expected: "silver"
61
+ },
62
+ overrideProbe: {
63
+ run: () => a.sync(() => i({
64
+ ...s,
65
+ rulesVersion: "test.lower.v1"
66
+ }, () => "base").id),
67
+ expected: "base"
68
+ }
69
+ }), l = Object.freeze({
70
+ kind: "slot",
71
+ defaultImplementation: e,
72
+ defaultProbe: {
73
+ run: () => a.sync(() => r({
74
+ ...s,
75
+ tierId: "silver"
76
+ })),
77
+ expected: [{
78
+ id: "silver.discount",
79
+ kind: "discount",
80
+ bps: 500
81
+ }]
82
+ },
83
+ overrideProbe: {
84
+ run: () => a.sync(() => r({
85
+ ...s,
86
+ tierId: "silver",
87
+ rulesVersion: "test.no-perks.v1"
88
+ }, () => [])),
89
+ expected: []
90
+ }
91
+ });
92
+ export { o as loyaltyFixture, l as loyaltyPerksSystemFixture, c as loyaltyTierSystemFixture };