@voltro/plugin-economy 0.0.0-stage → 0.88.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/CHANGELOG.md +24492 -0
  2. package/LICENSE +61 -0
  3. package/README.md +2719 -2
  4. package/SECURITY.md +56 -0
  5. package/THIRD-PARTY-NOTICES.md +9841 -0
  6. package/dist/amount.js +20 -0
  7. package/dist/appleIap.server.js +262 -0
  8. package/dist/appleIapNotifications.server.js +162 -0
  9. package/dist/appleIapTrust.server.js +30 -0
  10. package/dist/bundleValue.server.js +112 -0
  11. package/dist/canonicalDataJson.js +10 -0
  12. package/dist/capture.js +53 -0
  13. package/dist/codePort.fixture.js +123 -0
  14. package/dist/codeStore.server.js +439 -0
  15. package/dist/codeTables.entity.js +43 -0
  16. package/dist/codes.d.ts +150 -0
  17. package/dist/codes.js +82 -0
  18. package/dist/components.d.ts +397 -0
  19. package/dist/components.js +283 -0
  20. package/dist/consistency.server.js +115 -0
  21. package/dist/containerStore.server.js +687 -0
  22. package/dist/containerStore.testFixtures.js +75 -0
  23. package/dist/containerTables.entity.js +45 -0
  24. package/dist/containers.d.ts +311 -0
  25. package/dist/containers.fixture.js +128 -0
  26. package/dist/containers.js +214 -0
  27. package/dist/containers.server.js +39 -0
  28. package/dist/containersPort.fixture.js +74 -0
  29. package/dist/currency.js +32 -0
  30. package/dist/declarationFixtures.js +61 -0
  31. package/dist/economy-app/events/economy.refundReversed.event.ts +1 -0
  32. package/dist/economy-app/events/economy.refunded.event.ts +1 -0
  33. package/dist/economyPort.fixture.js +124 -0
  34. package/dist/errors.d.ts +14 -0
  35. package/dist/errors.js +21 -0
  36. package/dist/events.d.ts +46 -0
  37. package/dist/events.js +1 -0
  38. package/dist/googleIap.server.js +391 -0
  39. package/dist/googleIapNotifications.server.js +130 -0
  40. package/dist/googleIapSubscription.server.js +183 -0
  41. package/dist/iap.d.ts +309 -0
  42. package/dist/iap.js +303 -0
  43. package/dist/iap.testFixtures.js +144 -0
  44. package/dist/iapAccountTables.entity.js +39 -0
  45. package/dist/iapAccounts.server.js +200 -0
  46. package/dist/iapBinding.server.js +523 -0
  47. package/dist/iapCheckout.server.js +97 -0
  48. package/dist/iapCompletion.server.js +55 -0
  49. package/dist/iapCurrentState.server.js +107 -0
  50. package/dist/iapCurrentState.testFixtures.js +22 -0
  51. package/dist/iapCurrentStatePort.fixture.js +63 -0
  52. package/dist/iapEntitlements.d.ts +79 -0
  53. package/dist/iapEntitlements.js +57 -0
  54. package/dist/iapEntitlements.server.js +48 -0
  55. package/dist/iapEntitlementsBinding.server.js +105 -0
  56. package/dist/iapEntitlementsPort.fixture.js +80 -0
  57. package/dist/iapInstalledEntitlements.testFixtures.js +75 -0
  58. package/dist/iapInstalledNotifications.testFixtures.js +93 -0
  59. package/dist/iapInventoryRefunds.server.js +261 -0
  60. package/dist/iapNotificationCustodyPort.fixture.js +67 -0
  61. package/dist/iapNotificationPort.fixture.js +73 -0
  62. package/dist/iapNotificationProcessor.server.js +134 -0
  63. package/dist/iapNotificationProcessor.testFixtures.js +63 -0
  64. package/dist/iapNotificationProcessorPort.fixture.js +55 -0
  65. package/dist/iapNotificationSchedule.server.js +69 -0
  66. package/dist/iapNotificationStore.server.js +352 -0
  67. package/dist/iapNotificationStore.testFixtures.js +31 -0
  68. package/dist/iapNotificationTables.entity.js +48 -0
  69. package/dist/iapNotificationTarget.server.js +36 -0
  70. package/dist/iapNotificationTarget.testFixtures.js +29 -0
  71. package/dist/iapNotifications.d.ts +644 -0
  72. package/dist/iapNotifications.js +6 -0
  73. package/dist/iapNotifications.server.js +95 -0
  74. package/dist/iapNotificationsBinding.server.js +232 -0
  75. package/dist/iapNotificationsSystemPort.fixture.js +50 -0
  76. package/dist/iapPlugin.testFixtures.js +59 -0
  77. package/dist/iapPort.fixture.js +74 -0
  78. package/dist/iapProviderCapture.server.js +17 -0
  79. package/dist/iapRecovery.d.ts +146 -0
  80. package/dist/iapRecovery.js +89 -0
  81. package/dist/iapRefundEventDelivery.server.js +82 -0
  82. package/dist/iapRefundEvents.js +44 -0
  83. package/dist/iapRefundEventsPort.fixture.js +59 -0
  84. package/dist/iapRefundPort.fixture.js +54 -0
  85. package/dist/iapRefundTables.entity.js +55 -0
  86. package/dist/iapRefunds.d.ts +755 -0
  87. package/dist/iapRefunds.js +6 -0
  88. package/dist/iapRefunds.server.js +553 -0
  89. package/dist/iapRefunds.testFixtures.js +64 -0
  90. package/dist/iapSpendAdmission.server.js +98 -0
  91. package/dist/iapStore.server.js +740 -0
  92. package/dist/iapStore.testFixtures.js +127 -0
  93. package/dist/iapTables.entity.js +80 -0
  94. package/dist/iapVerification.server.js +120 -0
  95. package/dist/index.d.ts +2984 -0
  96. package/dist/index.js +15 -0
  97. package/dist/intentionRecovery.js +133 -0
  98. package/dist/ledger.js +77 -0
  99. package/dist/loyalty.d.ts +274 -0
  100. package/dist/loyalty.fixture.js +92 -0
  101. package/dist/loyalty.js +311 -0
  102. package/dist/loyaltyBinding.server.js +203 -0
  103. package/dist/loyaltyPort.fixture.js +86 -0
  104. package/dist/loyaltyShopSource.server.js +90 -0
  105. package/dist/loyaltyStore.server.js +552 -0
  106. package/dist/loyaltyStore.testFixtures.js +82 -0
  107. package/dist/loyaltyTables.entity.js +49 -0
  108. package/dist/offerMerchandising.fixture.js +114 -0
  109. package/dist/offerMerchandising.js +282 -0
  110. package/dist/offerPolicies.d.ts +441 -0
  111. package/dist/offerPolicies.fixture.js +53 -0
  112. package/dist/offerPolicies.js +267 -0
  113. package/dist/piggyBanks.d.ts +272 -0
  114. package/dist/piggyBanks.fixture.js +70 -0
  115. package/dist/piggyBanks.js +200 -0
  116. package/dist/piggyBinding.server.js +204 -0
  117. package/dist/piggyPort.fixture.js +72 -0
  118. package/dist/piggyStore.server.js +610 -0
  119. package/dist/piggyStore.testFixtures.js +97 -0
  120. package/dist/piggyTables.entity.js +40 -0
  121. package/dist/plugin.js +1047 -0
  122. package/dist/port.js +12 -0
  123. package/dist/price.d.ts +99 -0
  124. package/dist/price.js +143 -0
  125. package/dist/purchaseRecovery.js +55 -0
  126. package/dist/reports.server.js +114 -0
  127. package/dist/rpc.d.ts +3201 -0
  128. package/dist/rpc.js +1200 -0
  129. package/dist/sanctionsTradeAuthority.server.js +79 -0
  130. package/dist/server.d.ts +3856 -0
  131. package/dist/server.js +43 -0
  132. package/dist/shop.d.ts +279 -0
  133. package/dist/shop.js +195 -0
  134. package/dist/shop.testFixtures.js +113 -0
  135. package/dist/shopPort.fixture.js +71 -0
  136. package/dist/shopPresentation.js +67 -0
  137. package/dist/shopStore.server.js +623 -0
  138. package/dist/shopTables.entity.js +62 -0
  139. package/dist/shopUiCopy.js +56 -0
  140. package/dist/spendLimits.d.ts +140 -0
  141. package/dist/spendLimits.fixture.js +52 -0
  142. package/dist/spendLimits.js +154 -0
  143. package/dist/spendLimitsPort.fixture.js +119 -0
  144. package/dist/subscriptionBinding.server.js +210 -0
  145. package/dist/subscriptionStore.server.js +642 -0
  146. package/dist/subscriptionStore.testFixtures.js +71 -0
  147. package/dist/subscriptionTables.entity.js +36 -0
  148. package/dist/subscriptions.d.ts +394 -0
  149. package/dist/subscriptions.fixture.js +96 -0
  150. package/dist/subscriptions.js +212 -0
  151. package/dist/subscriptionsPort.fixture.js +75 -0
  152. package/dist/systemFixtures.js +88 -0
  153. package/dist/tables.entity.js +82 -0
  154. package/dist/testing.d.ts +4615 -0
  155. package/dist/testing.js +29 -0
  156. package/dist/tradeAuthority.server.js +171 -0
  157. package/dist/tradeBinding.server.js +200 -0
  158. package/dist/tradeComponents.js +341 -0
  159. package/dist/tradeEscrow.server.js +231 -0
  160. package/dist/tradeEscrow.testFixtures.js +132 -0
  161. package/dist/tradeExpiry.server.js +42 -0
  162. package/dist/tradeRecovery.js +47 -0
  163. package/dist/tradeStore.server.js +749 -0
  164. package/dist/tradeStore.testFixtures.js +72 -0
  165. package/dist/tradeTables.entity.js +65 -0
  166. package/dist/tradeUiCopy.js +78 -0
  167. package/dist/trades.d.ts +246 -0
  168. package/dist/trades.fixture.js +102 -0
  169. package/dist/trades.js +288 -0
  170. package/dist/tradesPort.fixture.js +93 -0
  171. package/dist/walletEscrow.js +105 -0
  172. package/dist/walletEscrow.server.js +375 -0
  173. package/dist/walletKeys.server.js +4 -0
  174. package/dist/walletStore.js +570 -0
  175. package/dist/web.d.ts +2257 -0
  176. package/dist/web.js +8 -0
  177. package/package.json +161 -4
@@ -0,0 +1,75 @@
1
+ import { defineContainer as e } from "./containers.js";
2
+ import { containerTables as t } from "./containerTables.entity.js";
3
+ import { dataStoreContainers as n } from "./containerStore.server.js";
4
+ import { shopAt as r, shopFixture as i } from "./shop.testFixtures.js";
5
+ import { Effect as a } from "effect";
6
+ import { ensureTableRegistered as o } from "@voltro/database";
7
+ // src/containerStore.testFixtures.ts
8
+ var s = async (s, c = "tenant", l = {}, u = 4096) => {
9
+ t.forEach(o);
10
+ let d = await i(s, c, {}, u), f = d.options.currencies, p = {
11
+ id: "fixture.chest",
12
+ price: {
13
+ kind: "virtual",
14
+ options: [{
15
+ currency: "test.gold",
16
+ amount: "7"
17
+ }]
18
+ },
19
+ countries: ["DE"],
20
+ drops: [{
21
+ id: "common",
22
+ rarity: "common",
23
+ weight: "9",
24
+ currencies: [{
25
+ currency: "test.gold",
26
+ amount: "2"
27
+ }]
28
+ }, {
29
+ id: "rare",
30
+ rarity: "legendary",
31
+ weight: "1",
32
+ items: [{
33
+ itemId: "test.potion",
34
+ qty: 2
35
+ }],
36
+ currencies: [{
37
+ currency: "test.gold",
38
+ amount: "5"
39
+ }]
40
+ }],
41
+ pity: {
42
+ guaranteed: "legendary",
43
+ after: 2
44
+ }
45
+ }, m = 0, h = {
46
+ currencies: f,
47
+ containers: [e(p, f)],
48
+ economy: d.economy,
49
+ inventory: d.inventory,
50
+ accessSource: { read: () => a.succeed({
51
+ isMinor: !1,
52
+ country: "DE",
53
+ eligible: !0,
54
+ adjustments: []
55
+ }) },
56
+ version: "fixture.v1",
57
+ random: { draw: () => a.sync(() => (m++, "0")) },
58
+ now: () => r,
59
+ ...l
60
+ };
61
+ return {
62
+ base: d,
63
+ options: h,
64
+ service: n(s, h),
65
+ draws: () => m
66
+ };
67
+ }, c = (e, t = "fixture.open") => Object.freeze({
68
+ containerId: e.container.id,
69
+ containerVersion: e.container.version,
70
+ containerDigest: e.containerDigest,
71
+ disclosureDigest: e.disclosureDigest,
72
+ requestId: t,
73
+ ...e.container.price.kind === "virtual" ? { currency: e.container.price.options[0].currency } : e.container.price.kind === "mixed" ? { currency: e.container.price.virtual[0].currency } : {}
74
+ });
75
+ export { c as containerOpenIntent, s as containerStoreFixture };
@@ -0,0 +1,45 @@
1
+ import { boolean as e, id as t, integer as n, json as r, table as i, text as a, timestamp as o } from "@voltro/database";
2
+ // src/containerTables.entity.ts
3
+ var s = () => a().maxLength(120).externalId().sensitive("pii"), c = i("_voltro_eco_container_tenants", {
4
+ id: t({ prefix: "eut" }),
5
+ tenantId: s(),
6
+ admission: n().serverOnly()
7
+ }).index(["tenantId"]), l = i("_voltro_eco_containers", {
8
+ id: t({ prefix: "eud" }),
9
+ tenantId: s(),
10
+ definition: r().serverOnly(),
11
+ currencies: r().serverOnly(),
12
+ realMoney: e().serverOnly(),
13
+ rulesVersion: a().maxLength(120).serverOnly(),
14
+ createdAt: o().serverOnly()
15
+ }).index(["tenantId"]), u = i("_voltro_eco_container_subjects", {
16
+ id: t({ prefix: "eus" }),
17
+ tenantId: s(),
18
+ ownerId: a().maxLength(120).nullable().externalId().sensitive("pii"),
19
+ erased: e().serverOnly(),
20
+ admission: n().serverOnly(),
21
+ pendingId: a().maxLength(64).nullable().serverOnly()
22
+ }).index(["tenantId", "ownerId"]), d = i("_voltro_eco_container_openings", {
23
+ id: t({ prefix: "euo" }),
24
+ tenantId: s(),
25
+ ownerId: a().maxLength(120).nullable().externalId().sensitive("pii"),
26
+ ownerKey: a().maxLength(64).serverOnly(),
27
+ state: a().maxLength(16).oneOf([
28
+ "pending",
29
+ "fulfilled",
30
+ "erased"
31
+ ]).serverOnly(),
32
+ digest: a().maxLength(64).nullable().serverOnly(),
33
+ intent: r().nullable().serverOnly(),
34
+ selection: r().nullable().serverOnly(),
35
+ receipt: r().nullable().serverOnly(),
36
+ sequence: n().nullable().serverOnly(),
37
+ createdAt: o().serverOnly(),
38
+ fulfilledAt: o().nullable().serverOnly()
39
+ }).index(["tenantId", "ownerKey"]), f = [
40
+ c,
41
+ l,
42
+ u,
43
+ d
44
+ ];
45
+ export { l as containerDefinitionsTable, d as containerOpeningsTable, u as containerSubjectsTable, f as containerTables, c as containerTenantsTable };
@@ -0,0 +1,311 @@
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 captureContainerIntent: (input: ContainerOpenInput) => Readonly<{
9
+ containerId: string;
10
+ containerVersion: string;
11
+ containerDigest: string;
12
+ disclosureDigest: string;
13
+ requestId: string;
14
+ currency: string | null;
15
+ }>;
16
+
17
+ export declare const captureContainersService: (input: ContainersService) => ContainersService;
18
+
19
+ export declare interface Container {
20
+ readonly id: string;
21
+ readonly version: string;
22
+ readonly group: string;
23
+ readonly price: Price;
24
+ readonly drops: readonly ContainerDrop[];
25
+ readonly pity: Readonly<{
26
+ guaranteed: string;
27
+ after: number;
28
+ softFrom: number | null;
29
+ softRampBps: number;
30
+ }> | null;
31
+ readonly countries: readonly string[];
32
+ }
33
+
34
+ export declare interface ContainerAccessContext {
35
+ readonly container: Container;
36
+ readonly at: number;
37
+ readonly isMinor: boolean;
38
+ readonly country: string;
39
+ readonly eligible: boolean;
40
+ }
41
+
42
+ export declare interface ContainerDefinition {
43
+ readonly id: string;
44
+ readonly version?: string | undefined;
45
+ readonly group?: string;
46
+ readonly price: PriceDefinition;
47
+ readonly drops: readonly ContainerDropDefinition[];
48
+ readonly pity?: {
49
+ readonly guaranteed: string;
50
+ readonly after: number;
51
+ readonly softFrom?: number;
52
+ readonly softRampBps?: number;
53
+ };
54
+ readonly countries?: readonly string[];
55
+ }
56
+
57
+ export declare interface ContainerDistribution {
58
+ readonly entries: readonly ContainerProbabilityWeight[];
59
+ readonly total: string;
60
+ readonly guaranteed: boolean;
61
+ }
62
+
63
+ export declare interface ContainerDrop {
64
+ readonly id: string;
65
+ readonly rarity: string;
66
+ readonly weight: string;
67
+ readonly items: readonly {
68
+ readonly itemId: string;
69
+ readonly qty: number;
70
+ }[];
71
+ readonly currencies: readonly {
72
+ readonly currency: string;
73
+ readonly amount: string;
74
+ }[];
75
+ }
76
+
77
+ export declare interface ContainerDropDefinition {
78
+ readonly id: string;
79
+ readonly rarity: string;
80
+ readonly weight: EconomyAmountInput;
81
+ readonly items?: readonly {
82
+ readonly itemId: string | undefined;
83
+ readonly qty: number;
84
+ }[];
85
+ readonly currencies?: readonly {
86
+ readonly currency: string | undefined;
87
+ readonly amount: EconomyAmountInput;
88
+ }[];
89
+ }
90
+
91
+ export declare type ContainerEligibility = (input: ContainerAccessContext) => boolean;
92
+
93
+ export declare type ContainerObservation = {
94
+ readonly requestId: string;
95
+ readonly state: 'not-observed' | 'pending';
96
+ } | {
97
+ readonly requestId: string;
98
+ readonly state: 'fulfilled';
99
+ readonly receipt: ContainerReceipt;
100
+ };
101
+
102
+ export declare interface ContainerOpenInput {
103
+ readonly containerId: string;
104
+ readonly containerVersion: string;
105
+ readonly containerDigest: string;
106
+ readonly disclosureDigest: string;
107
+ readonly requestId: string;
108
+ readonly currency?: string | undefined;
109
+ }
110
+
111
+ export declare interface ContainerProbabilityContext {
112
+ readonly container: Container;
113
+ readonly misses: number;
114
+ readonly currencies: readonly CurrencyDefinition[];
115
+ readonly realMoney?: boolean;
116
+ }
117
+
118
+ export declare const containerProbabilityContext: (input: ContainerProbabilityContext) => ContainerProbabilityContext;
119
+
120
+ export declare type ContainerProbabilityResolver = (input: ContainerProbabilityContext) => readonly ContainerProbabilityWeight[];
121
+
122
+ export declare interface ContainerProbabilityWeight {
123
+ readonly dropId: string;
124
+ readonly weight: string;
125
+ }
126
+
127
+ /** Server authority only: no player draw/seed/state is accepted by any route. */
128
+ export declare class ContainerRandomPort extends ContainerRandomPort_base {
129
+ }
130
+
131
+ declare const ContainerRandomPort_base: Context.ServiceClass<ContainerRandomPort, "@voltro/ContainerRandomPort", ContainerRandomService>;
132
+
133
+ export declare interface ContainerRandomService {
134
+ readonly draw: (exclusiveMaximum: string) => Effect.Effect<string, EconomyError>;
135
+ }
136
+
137
+ export declare interface ContainerReceipt {
138
+ readonly operationId: string;
139
+ readonly containerId: string;
140
+ readonly containerVersion: string;
141
+ readonly containerDigest: string;
142
+ readonly dropId: string;
143
+ readonly rarity: string;
144
+ readonly previousMisses: number;
145
+ readonly misses: number;
146
+ readonly sequence: number;
147
+ readonly at: number;
148
+ readonly distribution: ContainerDistribution;
149
+ readonly pricePaid: ShopOrderReceipt['pricePaid'];
150
+ readonly transfers: ShopOrderReceipt['transfers'];
151
+ readonly grants: ShopOrderReceipt['grants'];
152
+ }
153
+
154
+ export declare interface ContainerRollContext {
155
+ readonly distribution: ContainerDistribution;
156
+ readonly draw: string;
157
+ }
158
+
159
+ export declare type ContainerRollResolver = (input: ContainerRollContext) => string;
160
+
161
+ export declare class ContainersPort extends ContainersPort_base {
162
+ }
163
+
164
+ declare const ContainersPort_base: Context.ServiceClass<ContainersPort, "@voltro/ContainersPort", ContainersService>;
165
+
166
+ export declare interface ContainersService {
167
+ readonly list: (subject: Subject) => Effect.Effect<readonly ContainerView[], EconomyError>;
168
+ readonly open: (subject: Subject, input: ContainerOpenInput) => Effect.Effect<ContainerReceipt, EconomyError>;
169
+ readonly receipt: (subject: Subject, input: ContainerOpenInput) => Effect.Effect<ContainerObservation, EconomyError>;
170
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
171
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
172
+ }
173
+
174
+ export declare interface ContainerView {
175
+ readonly container: Container;
176
+ readonly containerDigest: string;
177
+ readonly disclosureDigest: string;
178
+ readonly misses: number;
179
+ readonly price: Price;
180
+ readonly disclosure: ReturnType<typeof discloseContainer>;
181
+ }
182
+
183
+ declare interface CurrencyDefinition {
184
+ readonly id: string;
185
+ readonly kind: 'soft' | 'hard';
186
+ readonly cap?: EconomyAmountInput;
187
+ readonly premium?: boolean;
188
+ readonly display?: {
189
+ readonly nameKey: string;
190
+ } | null;
191
+ }
192
+
193
+ /** Required trusted facts; absent age/country never means adult or eligible. */
194
+ export declare const defaultContainerEligibility: ContainerEligibility;
195
+
196
+ /** Exact integer distribution. Soft pity redistributes probability mass while
197
+ * preserving relative weights inside each rarity group; hard pity has no miss. */
198
+ export declare const defaultContainerProbability: ContainerProbabilityResolver;
199
+
200
+ export declare const defaultContainerRoll: ContainerRollResolver;
201
+
202
+ /** Captured content only. Opening/payment/history must be owned by an ordinary
203
+ * authoritative service; this declaration creates no value or mutable counter. */
204
+ export declare const defineContainer: (input: ContainerDefinition | Container, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => Container;
205
+
206
+ /** Public disclosure uses the exact same captured distribution as the draw. */
207
+ export declare const discloseContainer: (input: ContainerProbabilityContext, slot?: ContainerProbabilityResolver) => Readonly<{
208
+ guaranteed: boolean;
209
+ probabilities: readonly Readonly<{
210
+ dropId: string;
211
+ numerator: string;
212
+ denominator: string;
213
+ }>[];
214
+ }>;
215
+
216
+ declare type EconomyAmountInput = string | number | bigint;
217
+
218
+ declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
219
+
220
+ /** Redacted codes; never carries owners, amounts or provider payloads. */
221
+ declare class EconomyError extends EconomyError_base {
222
+ }
223
+
224
+ declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
225
+ 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"]>;
226
+ }>, YieldableError>;
227
+
228
+ declare type Price = {
229
+ readonly kind: 'virtual';
230
+ readonly options: readonly ResolvedVirtualPriceOption[];
231
+ } | ({
232
+ readonly kind: 'real';
233
+ } & RealPriceDefinition) | {
234
+ readonly kind: 'mixed';
235
+ readonly real: RealPriceDefinition;
236
+ readonly virtual: readonly ResolvedVirtualPriceOption[];
237
+ } | {
238
+ readonly kind: 'free';
239
+ };
240
+
241
+ declare type PriceDefinition = {
242
+ readonly kind: 'virtual';
243
+ readonly options: readonly VirtualPriceOption[];
244
+ } | ({
245
+ readonly kind: 'real';
246
+ } & RealPriceDefinition) | {
247
+ readonly kind: 'mixed';
248
+ readonly real: RealPriceDefinition;
249
+ readonly virtual: readonly VirtualPriceOption[];
250
+ } | {
251
+ readonly kind: 'free';
252
+ };
253
+
254
+ declare interface RealPriceDefinition {
255
+ /** Integer minor-unit references; verified store receipts remain authoritative. */
256
+ readonly prices: Readonly<Record<string, number>>;
257
+ readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
258
+ }
259
+
260
+ export declare const resolveContainerDistribution: (input: ContainerProbabilityContext, slot?: ContainerProbabilityResolver) => ContainerDistribution;
261
+
262
+ export declare const resolveContainerEligibility: (input: ContainerAccessContext, declarations: readonly CurrencyDefinition[], realMoney?: boolean, slot?: ContainerEligibility) => boolean;
263
+
264
+ export declare const resolveContainerRoll: (input: ContainerProbabilityContext, draw: string, probability?: ContainerProbabilityResolver, roll?: ContainerRollResolver) => Readonly<{
265
+ drop: ContainerDrop;
266
+ misses: number;
267
+ distribution: ContainerDistribution;
268
+ }>;
269
+
270
+ declare interface ResolvedVirtualPriceOption {
271
+ readonly currency: string;
272
+ readonly amount: string;
273
+ }
274
+
275
+ declare interface ShopOrderReceipt {
276
+ readonly orderId: string;
277
+ readonly offerId: string;
278
+ readonly offerVersion: string;
279
+ readonly offerDigest: string;
280
+ readonly quantity: number;
281
+ readonly at: number;
282
+ readonly pricePaid: {
283
+ readonly kind: 'free';
284
+ } | {
285
+ readonly kind: 'virtual';
286
+ readonly currency: string;
287
+ readonly amount: string;
288
+ };
289
+ readonly transfers: readonly {
290
+ readonly txId: string;
291
+ readonly currency: string;
292
+ readonly amount: string;
293
+ readonly at: number;
294
+ }[];
295
+ readonly grants: readonly {
296
+ readonly operationId: string;
297
+ readonly kind: 'grant';
298
+ readonly changes: readonly {
299
+ readonly instanceId: string;
300
+ readonly delta: number;
301
+ }[];
302
+ readonly at: number;
303
+ }[];
304
+ }
305
+
306
+ declare interface VirtualPriceOption {
307
+ readonly currency: string;
308
+ readonly amount: EconomyAmountInput;
309
+ }
310
+
311
+ export { }
@@ -0,0 +1,128 @@
1
+ import { economyError as e } from "./errors.js";
2
+ import { ContainerRandomPort as t, defaultContainerEligibility as n, defaultContainerProbability as r, defaultContainerRoll as i, defineContainer as a, resolveContainerDistribution as o, resolveContainerEligibility as s, resolveContainerRoll as c } from "./containers.js";
3
+ import { Effect as l, Layer as u } from "effect";
4
+ // src/containers.fixture.ts
5
+ var d = () => {
6
+ let e = [{
7
+ id: "test.gold",
8
+ kind: "soft",
9
+ cap: "1000000"
10
+ }], t = a({
11
+ id: "test.container",
12
+ price: {
13
+ kind: "virtual",
14
+ options: [{
15
+ currency: "test.gold",
16
+ amount: "5"
17
+ }]
18
+ },
19
+ drops: [{
20
+ id: "common",
21
+ rarity: "common",
22
+ weight: "99",
23
+ currencies: [{
24
+ currency: "test.gold",
25
+ amount: "1"
26
+ }]
27
+ }, {
28
+ id: "legendary",
29
+ rarity: "legendary",
30
+ weight: "1",
31
+ items: [{
32
+ itemId: "test.skin",
33
+ qty: 1
34
+ }]
35
+ }],
36
+ pity: {
37
+ guaranteed: "legendary",
38
+ after: 90,
39
+ softFrom: 75,
40
+ softRampBps: 600
41
+ }
42
+ }, e);
43
+ return Object.freeze({
44
+ container: t,
45
+ currencies: e,
46
+ misses: 0,
47
+ realMoney: !1
48
+ });
49
+ }, f = u.succeed(t, Object.freeze({ draw: (t) => typeof t == "string" && /^[1-9][0-9]{0,255}$/.test(t) ? l.succeed("0") : l.fail(e("invalid_input")) })), p = d(), m = {
50
+ ...p,
51
+ misses: 89
52
+ }, h = Object.freeze({
53
+ kind: "slot",
54
+ defaultImplementation: r,
55
+ defaultProbe: {
56
+ run: () => l.sync(() => o(p)),
57
+ expected: {
58
+ entries: [{
59
+ dropId: "common",
60
+ weight: "99"
61
+ }, {
62
+ dropId: "legendary",
63
+ weight: "1"
64
+ }],
65
+ total: "100",
66
+ guaranteed: !1
67
+ }
68
+ },
69
+ overrideProbe: {
70
+ run: () => l.sync(() => o(p, () => [{
71
+ dropId: "common",
72
+ weight: "1"
73
+ }, {
74
+ dropId: "legendary",
75
+ weight: "1"
76
+ }])),
77
+ expected: {
78
+ entries: [{
79
+ dropId: "common",
80
+ weight: "1"
81
+ }, {
82
+ dropId: "legendary",
83
+ weight: "1"
84
+ }],
85
+ total: "2",
86
+ guaranteed: !1
87
+ }
88
+ }
89
+ }), g = Object.freeze({
90
+ kind: "slot",
91
+ defaultImplementation: i,
92
+ defaultProbe: {
93
+ run: () => l.sync(() => c(p, "0").drop.id),
94
+ expected: "common"
95
+ },
96
+ overrideProbe: {
97
+ run: () => l.sync(() => c(p, "0", r, () => "legendary").drop.id),
98
+ expected: "legendary"
99
+ }
100
+ }), _ = Object.freeze({
101
+ kind: "port",
102
+ tag: t,
103
+ fakeLayer: f,
104
+ probe: {
105
+ run: () => l.scoped(l.gen(function* () {
106
+ return yield* (yield* t).draw(o(m).total);
107
+ }).pipe(l.provide(f))),
108
+ expected: "0"
109
+ }
110
+ }), v = Object.freeze({
111
+ container: p.container,
112
+ at: 0,
113
+ isMinor: !1,
114
+ country: "DE",
115
+ eligible: !0
116
+ }), y = Object.freeze({
117
+ kind: "slot",
118
+ defaultImplementation: n,
119
+ defaultProbe: {
120
+ run: () => l.sync(() => s(v, p.currencies)),
121
+ expected: !0
122
+ },
123
+ overrideProbe: {
124
+ run: () => l.sync(() => s(v, p.currencies, !1, (e) => n(e) && e.at > 0)),
125
+ expected: !1
126
+ }
127
+ });
128
+ export { y as containerEligibilitySystemFixture, d as containerFixture, h as containerProbabilitySystemFixture, f as containerRandomFakeLayer, _ as containerRandomPortSystemFixture, g as containerRollSystemFixture };