@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,2984 @@
1
+ import { Context } from 'effect';
2
+ import { DataStore } from '@voltro/database';
3
+ import { Effect } from 'effect';
4
+ import { FieldCipher } from '@voltro/database';
5
+ import { InventorySqlService } from '@voltro/plugin-inventory/server';
6
+ import { PluginPrivacyTarget } from '@voltro/protocol';
7
+ import { PreparedSqlMutation } from '@voltro/database/sql';
8
+ import { Schema } from 'effect';
9
+ import { Subject } from '@voltro/protocol';
10
+ import { VoltroPlugin } from '@voltro/protocol';
11
+ import { YieldableError } from 'effect/Cause';
12
+
13
+ declare const acceptedCompletion: unique symbol;
14
+
15
+ /** SQL-issued capability. A player reference or serialized object cannot authorize provider completion. */
16
+ declare interface AcceptedIapCompletion {
17
+ readonly [acceptedCompletion]: true;
18
+ readonly orderId: string;
19
+ }
20
+
21
+ /** Read-only SQL custody capability, never current provider state or refund authority. */
22
+ declare interface AcceptedIapNotificationTarget {
23
+ readonly [acceptedNotificationTarget]: true;
24
+ readonly orderId: string;
25
+ readonly noticeId: string;
26
+ }
27
+
28
+ declare const acceptedNotificationTarget: unique symbol;
29
+
30
+ /** Exact ordinary wallet policy; hard-currency credits may repay existing refund debt. */
31
+ export declare const applyWalletPosting: (balance: EconomyAmountInput, posting: LedgerPosting, definition: CurrencyDefinition) => string;
32
+
33
+ export declare const assertSpendBudget: (projection: ReturnType<typeof projectSpend>, input: EconomyAmountInput, budget: SpendBudget) => void;
34
+
35
+ export declare const captureCodeIntent: (input: RedeemCodeInput) => RedeemCodeInput;
36
+
37
+ export declare const captureCodeService: (input: CodeService) => CodeService;
38
+
39
+ /** Case-sensitive code intention, never normalization that expands authority. */
40
+ export declare const captureCodeValue: (input: unknown) => string;
41
+
42
+ export declare const captureEconomyService: (input: EconomySystemService) => EconomySystemService;
43
+
44
+ export declare const captureLoyaltyService: (input: LoyaltyService) => LoyaltyService;
45
+
46
+ export declare const capturePiggyBanksService: (input: PiggyBanksService) => PiggyBanksService;
47
+
48
+ /** The same detached receipt admission serves SQL history and browser recovery. */
49
+ export declare const captureShopOrderReceipt: (input: unknown) => ShopOrderReceipt;
50
+
51
+ /** Capture required methods without invoking accessors; retain the original receiver, including class instances. */
52
+ export declare const captureShopService: (input: ShopService) => ShopService;
53
+
54
+ export declare const captureSpendLimitsOptions: (input: SpendLimitsOptions, currencies: readonly CurrencyDefinition[]) => Readonly<{
55
+ limits: readonly SpendLimit[];
56
+ source: SpendFactsSource;
57
+ version: string;
58
+ policy: SpendLimitPolicy;
59
+ }>;
60
+
61
+ export declare const captureSubscriptionReceiptIntent: (input: SubscriptionReceiptInput) => SubscriptionReceiptInput;
62
+
63
+ export declare const captureSubscriptionsService: (input: SubscriptionsService) => SubscriptionsService;
64
+
65
+ export declare const captureTradeLeg: (input: TradeLegDefinition | TradeLeg, declarations: readonly CurrencyDefinition[]) => TradeLeg;
66
+
67
+ export declare const captureTradeObservation: (input: unknown) => TradeObservation;
68
+
69
+ export declare const captureTradeParticipantAuthority: (value: unknown, tenantId: string, expectedOwner: string) => TradeParticipantAuthority;
70
+
71
+ /** Pure detached wire shape only. New admission must still validate actual
72
+ * currencies and rules; originals compare before current declarations. */
73
+ export declare const captureTradeProposeIntention: (input: TradeProposeInput) => Readonly<{
74
+ toId: string | null;
75
+ offered: TradeLeg;
76
+ requested: TradeLeg;
77
+ durationMs: number;
78
+ requestId: string;
79
+ }>;
80
+
81
+ export declare const captureTradeReceipt: (input: unknown) => TradeReceipt;
82
+
83
+ export declare const captureTradesService: (input: TradesService) => TradesService;
84
+
85
+ /** Browser-safe detached receipt shape, never a substitute for server custody/permission proof. */
86
+ export declare const captureTradeView: (input: unknown) => TradeView;
87
+
88
+ export declare interface CodeDefinition {
89
+ readonly id: string;
90
+ readonly version?: string | undefined;
91
+ readonly campaign: string;
92
+ readonly items?: readonly {
93
+ readonly itemId: string | undefined;
94
+ readonly qty: number;
95
+ }[];
96
+ readonly currencies?: readonly {
97
+ readonly currency: string | undefined;
98
+ readonly amount: EconomyAmountInput;
99
+ }[];
100
+ readonly from?: number | null;
101
+ readonly until?: number | null;
102
+ readonly limits: {
103
+ readonly global: number;
104
+ readonly perPlayer: number;
105
+ };
106
+ }
107
+
108
+ export declare type CodeEligibility = (input: CodeEligibilityContext) => boolean;
109
+
110
+ export declare interface CodeEligibilityContext {
111
+ readonly definition: PromoCode;
112
+ readonly at: number;
113
+ readonly claims: number;
114
+ readonly playerClaims: number;
115
+ }
116
+
117
+ export declare type CodeObservation = {
118
+ readonly requestId: string;
119
+ readonly state: 'not-observed' | 'pending';
120
+ } | {
121
+ readonly requestId: string;
122
+ readonly state: 'fulfilled';
123
+ readonly receipt: CodeReceipt;
124
+ };
125
+
126
+ export declare interface CodePluginOptions extends Omit<CodeStoreOptions, 'currencies' | 'economy'> {
127
+ /** Complete replacement owns SQL authority, receipts and subject privacy. */
128
+ readonly service?: CodeService;
129
+ readonly querySources?: {
130
+ readonly receipt: readonly string[];
131
+ } | undefined;
132
+ }
133
+
134
+ export declare class CodePort extends CodePort_base {
135
+ }
136
+
137
+ declare const CodePort_base: Context.ServiceClass<CodePort, "@voltro/CodePort", CodeService>;
138
+
139
+ export declare interface CodeReceipt {
140
+ readonly operationId: string;
141
+ readonly codeId: string;
142
+ readonly version: string;
143
+ readonly campaign: string;
144
+ readonly at: number;
145
+ readonly transfers: readonly {
146
+ readonly txId: string;
147
+ readonly currency: string;
148
+ readonly amount: string;
149
+ readonly at: number;
150
+ }[];
151
+ readonly grants: readonly {
152
+ readonly operationId: string;
153
+ readonly kind: 'grant';
154
+ readonly changes: readonly {
155
+ readonly instanceId: string;
156
+ readonly delta: number;
157
+ }[];
158
+ readonly at: number;
159
+ }[];
160
+ }
161
+
162
+ export declare interface CodeService {
163
+ readonly create: (subject: Subject, input: CreateCodeInput) => Effect.Effect<void, EconomyError>;
164
+ readonly redeem: (subject: Subject, input: RedeemCodeInput) => Effect.Effect<CodeReceipt, EconomyError>;
165
+ readonly receipt: (subject: Subject, input: RedeemCodeInput) => Effect.Effect<CodeObservation, EconomyError>;
166
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
167
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
168
+ }
169
+
170
+ declare interface CodeStoreOptions {
171
+ readonly currencies: readonly CurrencyDefinition[];
172
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
173
+ readonly inventory?: Pick<InventorySqlService, 'prepareGrant'> | undefined;
174
+ readonly systemAccount?: string | undefined;
175
+ readonly allowedServices?: readonly string[] | undefined;
176
+ readonly maxHistoryRows?: number | undefined;
177
+ readonly now?: (() => number) | undefined;
178
+ readonly eligibility?: CodeEligibility | undefined;
179
+ readonly version?: string | undefined;
180
+ }
181
+
182
+ declare interface Container {
183
+ readonly id: string;
184
+ readonly version: string;
185
+ readonly group: string;
186
+ readonly price: Price;
187
+ readonly drops: readonly ContainerDrop[];
188
+ readonly pity: Readonly<{
189
+ guaranteed: string;
190
+ after: number;
191
+ softFrom: number | null;
192
+ softRampBps: number;
193
+ }> | null;
194
+ readonly countries: readonly string[];
195
+ }
196
+
197
+ declare interface ContainerAccessContext {
198
+ readonly container: Container;
199
+ readonly at: number;
200
+ readonly isMinor: boolean;
201
+ readonly country: string;
202
+ readonly eligible: boolean;
203
+ }
204
+
205
+ declare interface ContainerAccessSource {
206
+ readonly read: (input: {
207
+ readonly tenantId: string;
208
+ readonly ownerId: string;
209
+ readonly container: Container;
210
+ readonly at: number;
211
+ }) => Effect.Effect<{
212
+ readonly isMinor: boolean;
213
+ readonly country: string;
214
+ readonly eligible: boolean;
215
+ readonly adjustments: readonly VirtualPriceAdjustment[];
216
+ }, EconomyError>;
217
+ }
218
+
219
+ declare interface ContainerDefinition {
220
+ readonly id: string;
221
+ readonly version?: string | undefined;
222
+ readonly group?: string;
223
+ readonly price: PriceDefinition;
224
+ readonly drops: readonly ContainerDropDefinition[];
225
+ readonly pity?: {
226
+ readonly guaranteed: string;
227
+ readonly after: number;
228
+ readonly softFrom?: number;
229
+ readonly softRampBps?: number;
230
+ };
231
+ readonly countries?: readonly string[];
232
+ }
233
+
234
+ declare interface ContainerDistribution {
235
+ readonly entries: readonly ContainerProbabilityWeight[];
236
+ readonly total: string;
237
+ readonly guaranteed: boolean;
238
+ }
239
+
240
+ declare interface ContainerDrop {
241
+ readonly id: string;
242
+ readonly rarity: string;
243
+ readonly weight: string;
244
+ readonly items: readonly {
245
+ readonly itemId: string;
246
+ readonly qty: number;
247
+ }[];
248
+ readonly currencies: readonly {
249
+ readonly currency: string;
250
+ readonly amount: string;
251
+ }[];
252
+ }
253
+
254
+ declare interface ContainerDropDefinition {
255
+ readonly id: string;
256
+ readonly rarity: string;
257
+ readonly weight: EconomyAmountInput;
258
+ readonly items?: readonly {
259
+ readonly itemId: string | undefined;
260
+ readonly qty: number;
261
+ }[];
262
+ readonly currencies?: readonly {
263
+ readonly currency: string | undefined;
264
+ readonly amount: EconomyAmountInput;
265
+ }[];
266
+ }
267
+
268
+ declare type ContainerEligibility = (input: ContainerAccessContext) => boolean;
269
+
270
+ declare type ContainerObservation = {
271
+ readonly requestId: string;
272
+ readonly state: 'not-observed' | 'pending';
273
+ } | {
274
+ readonly requestId: string;
275
+ readonly state: 'fulfilled';
276
+ readonly receipt: ContainerReceipt;
277
+ };
278
+
279
+ declare interface ContainerOpenInput {
280
+ readonly containerId: string;
281
+ readonly containerVersion: string;
282
+ readonly containerDigest: string;
283
+ readonly disclosureDigest: string;
284
+ readonly requestId: string;
285
+ readonly currency?: string | undefined;
286
+ }
287
+
288
+ declare interface ContainerProbabilityContext {
289
+ readonly container: Container;
290
+ readonly misses: number;
291
+ readonly currencies: readonly CurrencyDefinition[];
292
+ readonly realMoney?: boolean;
293
+ }
294
+
295
+ declare type ContainerProbabilityResolver = (input: ContainerProbabilityContext) => readonly ContainerProbabilityWeight[];
296
+
297
+ declare interface ContainerProbabilityWeight {
298
+ readonly dropId: string;
299
+ readonly weight: string;
300
+ }
301
+
302
+ declare interface ContainerRandomService {
303
+ readonly draw: (exclusiveMaximum: string) => Effect.Effect<string, EconomyError>;
304
+ }
305
+
306
+ declare interface ContainerReceipt {
307
+ readonly operationId: string;
308
+ readonly containerId: string;
309
+ readonly containerVersion: string;
310
+ readonly containerDigest: string;
311
+ readonly dropId: string;
312
+ readonly rarity: string;
313
+ readonly previousMisses: number;
314
+ readonly misses: number;
315
+ readonly sequence: number;
316
+ readonly at: number;
317
+ readonly distribution: ContainerDistribution;
318
+ readonly pricePaid: ShopOrderReceipt['pricePaid'];
319
+ readonly transfers: ShopOrderReceipt['transfers'];
320
+ readonly grants: ShopOrderReceipt['grants'];
321
+ }
322
+
323
+ declare interface ContainerRollContext {
324
+ readonly distribution: ContainerDistribution;
325
+ readonly draw: string;
326
+ }
327
+
328
+ declare type ContainerRollResolver = (input: ContainerRollContext) => string;
329
+
330
+ export declare interface ContainersPluginOptions extends Omit<ContainersStoreOptions, 'currencies' | 'economy' | 'accessSource' | 'realMoney'> {
331
+ readonly accessSource?: ContainersStoreOptions['accessSource'];
332
+ readonly service?: ContainersService;
333
+ /** Full replacement requires actual sources; default may add app source tables. */
334
+ readonly querySources?: {
335
+ readonly list: readonly string[] | undefined;
336
+ readonly receipt: readonly string[];
337
+ };
338
+ }
339
+
340
+ declare interface ContainersService {
341
+ readonly list: (subject: Subject) => Effect.Effect<readonly ContainerView[], EconomyError>;
342
+ readonly open: (subject: Subject, input: ContainerOpenInput) => Effect.Effect<ContainerReceipt, EconomyError>;
343
+ readonly receipt: (subject: Subject, input: ContainerOpenInput) => Effect.Effect<ContainerObservation, EconomyError>;
344
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
345
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
346
+ }
347
+
348
+ declare interface ContainersStoreOptions {
349
+ readonly containers: readonly (ContainerDefinition | Container)[];
350
+ readonly currencies: readonly CurrencyDefinition[];
351
+ readonly realMoney?: boolean;
352
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
353
+ readonly inventory?: Pick<InventorySqlService, 'prepareGrant'> | undefined;
354
+ /** App-owned trusted age/country authority. No adult/allowed fallback. */
355
+ readonly accessSource: ContainerAccessSource;
356
+ readonly version: string;
357
+ readonly probability?: ContainerProbabilityResolver | undefined;
358
+ readonly roll?: ContainerRollResolver | undefined;
359
+ readonly random?: ContainerRandomService | undefined;
360
+ readonly eligibility?: ContainerEligibility | undefined;
361
+ readonly priceResolver?: PriceResolver | undefined;
362
+ readonly systemAccount?: string | undefined;
363
+ readonly maxHistoryRows?: number | undefined;
364
+ readonly now?: (() => number) | undefined;
365
+ }
366
+
367
+ declare interface ContainerView {
368
+ readonly container: Container;
369
+ readonly containerDigest: string;
370
+ readonly disclosureDigest: string;
371
+ readonly misses: number;
372
+ readonly price: Price;
373
+ readonly disclosure: ReturnType<typeof discloseContainer>;
374
+ }
375
+
376
+ export declare interface CreateCodeInput {
377
+ readonly tenantId: string;
378
+ readonly code: string;
379
+ readonly definition: CodeDefinition | PromoCode;
380
+ }
381
+
382
+ export declare interface CurrencyDefinition {
383
+ readonly id: string;
384
+ readonly kind: 'soft' | 'hard';
385
+ readonly cap?: EconomyAmountInput;
386
+ readonly premium?: boolean;
387
+ readonly display?: {
388
+ readonly nameKey: string;
389
+ } | null;
390
+ }
391
+
392
+ /** One default, independently preserved as the hard safety envelope for custom
393
+ * rules. A custom rule can narrow admission; never raise captured code limits. */
394
+ export declare const defaultCodeEligibility: CodeEligibility;
395
+
396
+ export declare const defaultLoyaltyPerks: LoyaltyPerksResolver;
397
+
398
+ export declare const defaultLoyaltyTier: LoyaltyTierResolver;
399
+
400
+ export declare const defaultPiggyFill: PiggyFillPolicy;
401
+
402
+ export declare const defaultPiggyReset: PiggyResetPolicy;
403
+
404
+ /** The one actual default. A real-money reference never constitutes a receipt. */
405
+ export declare const defaultPriceResolver: PriceResolver;
406
+
407
+ /** Currency-specific virtual limits, not an exchange rate, legal age source,
408
+ * provider payment limit or consent/withdrawal implementation. */
409
+ export declare const defaultSpendLimitPolicy: SpendLimitPolicy;
410
+
411
+ /** Pure decision only. claimedDays must come from complete authoritative SQL
412
+ * grant receipts; a player cannot submit this context to a value-write route. */
413
+ export declare const defaultSubscriptionDailyGrant: SubscriptionDailyGrantPolicy;
414
+
415
+ /** UTC calendar windows anchored to original purchase, never the previously
416
+ * clamped renewal date. Thus Jan31 -> Feb28/29 -> Mar31 without monthly drift. */
417
+ export declare const defaultSubscriptionPeriod: SubscriptionPeriodResolver;
418
+
419
+ export declare const defaultTradeEligibilityPolicy: TradeEligibilityPolicy;
420
+
421
+ /** Seller deduction, rounded upward; gross = net + tax exactly. No real-money
422
+ * channel or minted treasury value is part of a tax projection. */
423
+ export declare const defaultTradeTaxPolicy: TradeTaxPolicy;
424
+
425
+ /** Code values are supplied privately at runtime; declarations contain no code,
426
+ * provider credential, amount chosen by a player or alternative grant writer. */
427
+ export declare const defineCode: (input: CodeDefinition | PromoCode, declarations: readonly CurrencyDefinition[]) => PromoCode;
428
+
429
+ /** The framework invents no deployment currencies or prices. */
430
+ export declare const defineCurrency: (definition: CurrencyDefinition) => ResolvedCurrency;
431
+
432
+ export declare const defineLoyalty: (input: LoyaltyDefinition | Loyalty, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => Loyalty;
433
+
434
+ export declare const definePiggyBank: (input: PiggyBankDefinition | PiggyBank, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => PiggyBank;
435
+
436
+ /** Captures declarations and enforces the global real-money switch. */
437
+ export declare const definePrice: (input: PriceDefinition, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => Price;
438
+
439
+ /** `grantless`: the offer may grant nothing, for a store subscription whose value is its paid
440
+ * period (an entitlement such as game time). Every other offer grants items or currencies. */
441
+ export declare const defineShopOffer: (input: ShopOfferDefinition | ShopOffer, declarations: readonly CurrencyDefinition[], realMoney?: boolean, options?: {
442
+ readonly grantless?: boolean;
443
+ }) => ShopOffer;
444
+
445
+ export declare const defineSpendLimits: (input: readonly (SpendLimitDefinition | SpendLimit)[], declarations: readonly CurrencyDefinition[]) => readonly SpendLimit[];
446
+
447
+ /** Content only. No entitlement, charge, automatic renewal or consent follows
448
+ * from declaring a price. Required UI copy/path must be rendered by a consumer. */
449
+ export declare const defineSubscription: (input: SubscriptionDefinition | Subscription, declarations: readonly CurrencyDefinition[], realMoney?: boolean) => Subscription;
450
+
451
+ export declare const defineTradeRules: (input: TradeRulesDefinition | TradeRules) => TradeRules;
452
+
453
+ /** Public disclosure uses the exact same captured distribution as the draw. */
454
+ declare const discloseContainer: (input: ContainerProbabilityContext, slot?: ContainerProbabilityResolver) => Readonly<{
455
+ guaranteed: boolean;
456
+ probabilities: readonly Readonly<{
457
+ dropId: string;
458
+ numerator: string;
459
+ denominator: string;
460
+ }>[];
461
+ }>;
462
+
463
+ export declare type EconomyAccount = {
464
+ readonly kind: 'wallet';
465
+ readonly ownerId: string;
466
+ readonly ownerKind: WalletOwnerKind;
467
+ } | {
468
+ readonly kind: 'system';
469
+ readonly id: string;
470
+ };
471
+
472
+ export declare const economyAccountKey: (account: EconomyAccount) => string;
473
+
474
+ /** Exact signed SQL BIGINT; wire values are canonical decimal strings. */
475
+ export declare const economyAmount: (input: EconomyAmountInput) => bigint;
476
+
477
+ export declare type EconomyAmountInput = string | number | bigint;
478
+
479
+ export declare const economyAmountString: (input: EconomyAmountInput) => string;
480
+
481
+ export declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
482
+
483
+ /** System21 manifest of the optional redemption-code subsystem (`codes` option). */
484
+ export declare const economyCodesSystemContract: Readonly<{
485
+ slots: {
486
+ codeEligibility: {
487
+ defaultExport: string;
488
+ fixtureExport: string;
489
+ };
490
+ };
491
+ ports: {
492
+ codes: {
493
+ tagExport: string;
494
+ fakeLayerExport: string;
495
+ fixtureExport: string;
496
+ };
497
+ };
498
+ events: readonly string[];
499
+ }>;
500
+
501
+ declare interface EconomyConsistencyInput {
502
+ readonly tenantId: string;
503
+ readonly maxLedgerRows?: number | undefined;
504
+ readonly maxWallets?: number;
505
+ }
506
+
507
+ declare interface EconomyConsistencyResult {
508
+ readonly checked: number;
509
+ readonly mismatches: number;
510
+ readonly matches: boolean;
511
+ readonly ledgerRows: number;
512
+ }
513
+
514
+ declare interface EconomyConsistencyRunner {
515
+ readonly checkConsistency: (subject: Subject, input: EconomyConsistencyInput) => Effect.Effect<EconomyConsistencyResult, EconomyError>;
516
+ }
517
+
518
+ export declare const economyContainersSystemContract: Readonly<{
519
+ slots: {
520
+ containerProbability: {
521
+ defaultExport: string;
522
+ fixtureExport: string;
523
+ };
524
+ containerRoll: {
525
+ defaultExport: string;
526
+ fixtureExport: string;
527
+ };
528
+ containerEligibility: {
529
+ defaultExport: string;
530
+ fixtureExport: string;
531
+ };
532
+ };
533
+ ports: {
534
+ containers: {
535
+ tagExport: string;
536
+ fakeLayerExport: string;
537
+ fixtureExport: string;
538
+ };
539
+ containerRandom: {
540
+ tagExport: string;
541
+ fakeLayerExport: string;
542
+ fixtureExport: string;
543
+ };
544
+ };
545
+ events: readonly string[];
546
+ }>;
547
+
548
+ /** Redacted codes; never carries owners, amounts or provider payloads. */
549
+ export declare class EconomyError extends EconomyError_base {
550
+ }
551
+
552
+ declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
553
+ 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"]>;
554
+ }>, YieldableError>;
555
+
556
+ export declare const economyIapSystemContract: Readonly<{
557
+ slots: {
558
+ iapEntitlementPolicy: {
559
+ defaultExport: string;
560
+ fixtureExport: string;
561
+ };
562
+ };
563
+ ports: {
564
+ iap: {
565
+ tagExport: string;
566
+ fakeLayerExport: string;
567
+ fixtureExport: string;
568
+ };
569
+ iapSystem: {
570
+ tagExport: string;
571
+ fakeLayerExport: string;
572
+ fixtureExport: string;
573
+ };
574
+ iapNotification: {
575
+ tagExport: string;
576
+ fakeLayerExport: string;
577
+ fixtureExport: string;
578
+ };
579
+ iapCurrentState: {
580
+ tagExport: string;
581
+ fakeLayerExport: string;
582
+ fixtureExport: string;
583
+ };
584
+ iapNotificationCustody: {
585
+ tagExport: string;
586
+ fakeLayerExport: string;
587
+ fixtureExport: string;
588
+ };
589
+ iapRefund: {
590
+ tagExport: string;
591
+ fakeLayerExport: string;
592
+ fixtureExport: string;
593
+ };
594
+ iapNotificationProcessor: {
595
+ tagExport: string;
596
+ fakeLayerExport: string;
597
+ fixtureExport: string;
598
+ };
599
+ iapNotificationsSystem: {
600
+ tagExport: string;
601
+ fakeLayerExport: string;
602
+ fixtureExport: string;
603
+ };
604
+ iapRefundEvents: {
605
+ tagExport: string;
606
+ fakeLayerExport: string;
607
+ fixtureExport: string;
608
+ };
609
+ iapEntitlements: {
610
+ tagExport: string;
611
+ fakeLayerExport: string;
612
+ fixtureExport: string;
613
+ };
614
+ };
615
+ events: readonly string[];
616
+ }>;
617
+
618
+ export declare const economyLoyaltySystemContract: Readonly<{
619
+ slots: {
620
+ loyaltyTier: {
621
+ defaultExport: string;
622
+ fixtureExport: string;
623
+ };
624
+ loyaltyPerks: {
625
+ defaultExport: string;
626
+ fixtureExport: string;
627
+ };
628
+ };
629
+ ports: {
630
+ loyalty: {
631
+ tagExport: string;
632
+ fakeLayerExport: string;
633
+ fixtureExport: string;
634
+ };
635
+ };
636
+ events: readonly string[];
637
+ }>;
638
+
639
+ export declare const economyPiggyBanksSystemContract: Readonly<{
640
+ slots: {
641
+ piggyFill: {
642
+ defaultExport: string;
643
+ fixtureExport: string;
644
+ };
645
+ piggyReset: {
646
+ defaultExport: string;
647
+ fixtureExport: string;
648
+ };
649
+ };
650
+ ports: {
651
+ piggyBanks: {
652
+ tagExport: string;
653
+ fakeLayerExport: string;
654
+ fixtureExport: string;
655
+ };
656
+ };
657
+ events: readonly string[];
658
+ }>;
659
+
660
+ export declare interface EconomyPlugin extends VoltroPlugin {
661
+ readonly economy: {
662
+ readonly service: () => EconomyService;
663
+ readonly prepareEscrowReserve: EconomySqlService['prepareEscrowReserve'];
664
+ readonly prepareEscrowRelease: EconomySqlService['prepareEscrowRelease'];
665
+ readonly prepareEscrowSettle: EconomySqlService['prepareEscrowSettle'];
666
+ readonly prepareEscrowTaxSettle: EconomySqlService['prepareEscrowTaxSettle'];
667
+ readonly prepareEscrowReserveTaxSettle: EconomySqlService['prepareEscrowReserveTaxSettle'];
668
+ readonly escrow: EconomySqlService['escrow'];
669
+ readonly prepareTransfer: EconomySqlService['prepareTransfer'];
670
+ readonly checkConsistency: EconomyConsistencyRunner['checkConsistency'];
671
+ readonly iap: () => IapSystemService;
672
+ readonly iapEntitlements: () => IapEntitlementsService;
673
+ readonly iapNotifications: () => IapNotificationsSystemService;
674
+ readonly iapRefundEvents: () => IapRefundEventsService;
675
+ readonly shop: () => ShopService;
676
+ readonly codes: () => CodeService;
677
+ readonly containers: () => ContainersService;
678
+ readonly subscriptions: () => SubscriptionsService;
679
+ readonly loyalty: () => LoyaltyService;
680
+ readonly trades: () => TradesService;
681
+ readonly expireTrade: TradesSqlService['expire'];
682
+ readonly expireDueTrades: TradesSqlService['expireDue'];
683
+ readonly piggyBanks: () => PiggyBanksService;
684
+ /** Trusted reference-price projection; never grants value. */
685
+ readonly price: (subject: Subject, offerId: string, adjustments?: readonly VirtualPriceAdjustment[]) => Effect.Effect<Price, EconomyError>;
686
+ };
687
+ }
688
+
689
+ export declare const economyPlugin: (input: EconomyPluginOptions) => EconomyPlugin;
690
+
691
+ export declare interface EconomyPluginOptions extends EconomyStoreOptions {
692
+ /** Full wallet replacement owns conservation, SQL authority, receipts and privacy. */
693
+ readonly service?: EconomySystemService;
694
+ /** Actual app-owned wallet query invalidation tables, required only for a replacement. */
695
+ readonly querySources?: readonly string[] | undefined;
696
+ /** Explicit non-default identity is required for a complete replacement. */
697
+ readonly version?: string | undefined;
698
+ readonly realMoney?: boolean;
699
+ /** Captured price declarations only; no shop or payment fulfillment is implied. */
700
+ readonly offers?: readonly {
701
+ readonly id: string;
702
+ readonly price: PriceDefinition;
703
+ }[];
704
+ readonly priceResolver?: PriceResolver | undefined;
705
+ readonly iap?: IapPluginOptions;
706
+ readonly shop?: ShopPluginOptions;
707
+ readonly codes?: CodePluginOptions;
708
+ readonly containers?: ContainersPluginOptions;
709
+ readonly subscriptions?: SubscriptionsPluginOptions;
710
+ readonly loyalty?: LoyaltyPluginOptions;
711
+ readonly trades?: TradesPluginOptions;
712
+ readonly piggyBanks?: PiggyPluginOptions;
713
+ }
714
+
715
+ export declare class EconomyPort extends EconomyPort_base {
716
+ }
717
+
718
+ declare const EconomyPort_base: Context.ServiceClass<EconomyPort, "@voltro/EconomyPort", EconomyService>;
719
+
720
+ export declare interface EconomyReceipt {
721
+ readonly txId: string;
722
+ readonly currency: string;
723
+ readonly amount: string;
724
+ readonly at: number;
725
+ }
726
+
727
+ export declare interface EconomyReference {
728
+ readonly kind: string;
729
+ readonly id: string;
730
+ }
731
+
732
+ export declare interface EconomyService {
733
+ /** Trusted server transfer, never a player-authored value mutation. */
734
+ readonly transfer: (subject: Subject, input: LedgerTransferInput) => Effect.Effect<EconomyReceipt, EconomyError>;
735
+ readonly mine: (subject: Subject) => Effect.Effect<readonly EconomyWallet[], EconomyError>;
736
+ readonly auditWallet: (subject: Subject, tenantId: string, account: EconomyAccount, currency: string) => Effect.Effect<EconomyWalletAudit, EconomyError>;
737
+ readonly rebuildWallet: (subject: Subject, tenantId: string, account: EconomyAccount, currency: string) => Effect.Effect<EconomyWalletAudit, EconomyError>;
738
+ }
739
+
740
+ export declare const economyShopSystemContract: Readonly<{
741
+ slots: {
742
+ experimentBucket: {
743
+ defaultExport: string;
744
+ fixtureExport: string;
745
+ };
746
+ personalizedOfferSelector: {
747
+ defaultExport: string;
748
+ fixtureExport: string;
749
+ };
750
+ flashTrigger: {
751
+ defaultExport: string;
752
+ fixtureExport: string;
753
+ };
754
+ };
755
+ ports: {
756
+ shop: {
757
+ tagExport: string;
758
+ fakeLayerExport: string;
759
+ fixtureExport: string;
760
+ };
761
+ };
762
+ events: readonly string[];
763
+ }>;
764
+
765
+ export declare const economySpendLimitsSystemContract: Readonly<{
766
+ slots: {
767
+ spendLimitPolicy: {
768
+ defaultExport: string;
769
+ fixtureExport: string;
770
+ };
771
+ };
772
+ ports: {
773
+ economy: {
774
+ tagExport: string;
775
+ fakeLayerExport: string;
776
+ fixtureExport: string;
777
+ };
778
+ };
779
+ events: readonly string[];
780
+ }>;
781
+
782
+ declare interface EconomySqlService extends EconomySystemService, WalletEscrowParticipant {
783
+ /** Trusted original purchase evidence required; no player price, owner or state authority. */
784
+ readonly prepareIapRefund: (subject: Subject, proof: VerifiedIapCurrentState, input: IapWalletRefundInput) => Effect.Effect<PreparedSqlMutation<EconomyReceipt>, EconomyError>;
785
+ readonly prepareTransfer: (subject: Subject, input: LedgerTransferInput) => Effect.Effect<PreparedSqlMutation<EconomyReceipt>, EconomyError>;
786
+ }
787
+
788
+ declare interface EconomyStoreOptions {
789
+ readonly currencies: readonly CurrencyDefinition[];
790
+ readonly allowedServices?: readonly string[] | undefined;
791
+ /** Whole-work bounds; excess refuses rather than returning a prefix. */
792
+ readonly maxLedgerRows?: number | undefined;
793
+ readonly maxExportRows?: number | undefined;
794
+ readonly now?: (() => number) | undefined;
795
+ readonly spendLimits?: SpendLimitsOptions | undefined;
796
+ }
797
+
798
+ export declare const economySubscriptionsSystemContract: Readonly<{
799
+ slots: {
800
+ subscriptionPeriod: {
801
+ defaultExport: string;
802
+ fixtureExport: string;
803
+ };
804
+ subscriptionDaily: {
805
+ defaultExport: string;
806
+ fixtureExport: string;
807
+ };
808
+ };
809
+ ports: {
810
+ subscriptions: {
811
+ tagExport: string;
812
+ fakeLayerExport: string;
813
+ fixtureExport: string;
814
+ };
815
+ };
816
+ events: readonly string[];
817
+ }>;
818
+
819
+ /** System21 manifest of the installed core wallet system. Optional subsystems (shop, codes, containers,
820
+ * subscriptions, loyalty, piggy banks, trades, IAP) contribute their own slots, ports and tables. */
821
+ export declare const economySystemContract: Readonly<{
822
+ slots: {
823
+ priceResolver: {
824
+ defaultExport: string;
825
+ fixtureExport: string;
826
+ };
827
+ };
828
+ ports: {
829
+ economy: {
830
+ tagExport: string;
831
+ fakeLayerExport: string;
832
+ fixtureExport: string;
833
+ };
834
+ };
835
+ events: readonly string[];
836
+ }>;
837
+
838
+ /** Full installed replacement adds both privacy hooks; the dependent port stays four methods. */
839
+ export declare interface EconomySystemService extends EconomyService {
840
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
841
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
842
+ }
843
+
844
+ export declare const economyTradesSystemContract: Readonly<{
845
+ slots: {
846
+ tradeTax: {
847
+ defaultExport: string;
848
+ fixtureExport: string;
849
+ };
850
+ tradeEligibility: {
851
+ defaultExport: string;
852
+ fixtureExport: string;
853
+ };
854
+ };
855
+ ports: {
856
+ trades: {
857
+ tagExport: string;
858
+ fakeLayerExport: string;
859
+ fixtureExport: string;
860
+ };
861
+ };
862
+ events: readonly string[];
863
+ }>;
864
+
865
+ export declare interface EconomyWallet {
866
+ readonly currency: string;
867
+ readonly balance: string;
868
+ readonly updatedAt: number | null;
869
+ }
870
+
871
+ export declare interface EconomyWalletAudit {
872
+ readonly currency: string;
873
+ readonly balance: string;
874
+ readonly ledgerBalance: string;
875
+ readonly ledgerRows: number;
876
+ readonly matches: boolean;
877
+ }
878
+
879
+ declare type EscrowWallet = Extract<EconomyAccount, {
880
+ readonly kind: 'wallet';
881
+ }>;
882
+
883
+ declare interface IapAccountBindingService {
884
+ /** Observe existing SQL binding only; no mint, seed, fence update or ownership write. */
885
+ readonly observe: (scope: IapScope, channel: EconomyChannel, environment: IapEnvironment) => Effect.Effect<string, EconomyError>;
886
+ readonly read: (scope: IapScope, channel: EconomyChannel, environment: IapEnvironment) => Effect.Effect<string, EconomyError>;
887
+ readonly prepareBinding: (scope: IapScope, channel: EconomyChannel, environment: IapEnvironment, token: string) => Effect.Effect<PreparedSqlMutation<unknown>, EconomyError>;
888
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
889
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
890
+ }
891
+
892
+ /** A web checkout about to start: nothing is paid or verified yet. */
893
+ declare interface IapCheckoutAdmission {
894
+ readonly scope: IapScope;
895
+ readonly product: IapProduct;
896
+ readonly at: number;
897
+ }
898
+
899
+ /** One purchase a provider is asked to start: the owner, the selected offer and where the
900
+ * player returns afterwards. The account token binds the later receipt to this owner. */
901
+ declare interface IapCheckoutContext {
902
+ readonly scope: IapScope;
903
+ readonly product: IapProduct;
904
+ readonly requestId: string;
905
+ readonly accountToken: string;
906
+ readonly returnUrl: string;
907
+ readonly at: number;
908
+ }
909
+
910
+ /** Provider-owned web checkout (Stripe, Paddle, an app's own PSP, ...). Construction does no
911
+ * I/O; `initialize` checks credentials. Verification of the paid checkout stays with the same
912
+ * provider's `IapVerificationAuthority`, which must check the bound account token. */
913
+ declare interface IapCheckoutService {
914
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
915
+ readonly start: (context: IapCheckoutContext) => Effect.Effect<IapCheckoutSession, EconomyError>;
916
+ }
917
+
918
+ /** A started provider checkout. `checkoutId` is the receipt the player redeems afterwards. */
919
+ declare interface IapCheckoutSession {
920
+ readonly checkoutId: string;
921
+ readonly redirectUrl: string;
922
+ readonly expiresAt: number;
923
+ }
924
+
925
+ declare interface IapCompletionReceipt {
926
+ readonly orderId: string;
927
+ readonly channel: EconomyChannel;
928
+ readonly operation: 'acknowledge' | 'consume' | 'finalize' | 'finish';
929
+ readonly observedAt: number;
930
+ }
931
+
932
+ declare interface IapCompletionService {
933
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
934
+ readonly complete: (evidence: AcceptedIapCompletion) => Effect.Effect<IapCompletionReceipt, EconomyError>;
935
+ }
936
+
937
+ declare interface IapCurrentPurchaseState {
938
+ readonly orderId: string;
939
+ readonly channel: IapRefundChannel;
940
+ readonly state: 'active' | 'partially-refunded' | 'revoked';
941
+ /** Exact cumulative provider refund share; never floating point or money sent by a player. */
942
+ readonly refundNumerator: number;
943
+ readonly refundDenominator: number;
944
+ readonly observedAt: number;
945
+ readonly revokedAt: number | null;
946
+ }
947
+
948
+ declare interface IapCurrentStateService {
949
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
950
+ readonly read: (target: AcceptedIapNotificationTarget) => Effect.Effect<VerifiedIapCurrentState, EconomyError>;
951
+ }
952
+
953
+ declare type IapDebtPolicy = 'allowNegative' | 'blockSpend';
954
+
955
+ /** A purchase or subscription renewal the provider reports on its own (a webhook), for the
956
+ * owner it once received as account token at checkout. Redeemed through the same pipeline as a
957
+ * player's redeem: the same `requestId` + `receipt` converge on one order. */
958
+ declare interface IapDelivery {
959
+ readonly accountToken: string;
960
+ readonly offerId: string;
961
+ readonly offerVersion: string;
962
+ readonly requestId: string;
963
+ readonly receipt: string;
964
+ }
965
+
966
+ /** Provider-owned delivery reader on the channel's notification route. `read` authenticates the
967
+ * request and returns `null` when it carries nothing to deliver; the request then continues to
968
+ * the notification pipeline (refunds, disputes). */
969
+ declare interface IapDeliveryService {
970
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
971
+ readonly read: (input: IapNotificationInput) => Effect.Effect<IapDelivery | null, EconomyError>;
972
+ }
973
+
974
+ declare interface IapEntitlementObservation {
975
+ readonly offerId: string;
976
+ readonly entitled: boolean;
977
+ readonly expiresAt: number | null;
978
+ readonly observedAt: number;
979
+ }
980
+
981
+ declare type IapEntitlementPolicy = (context: IapEntitlementPolicyContext) => boolean;
982
+
983
+ declare interface IapEntitlementPolicyContext {
984
+ readonly period: IapSubscriptionPeriod;
985
+ readonly at: number;
986
+ }
987
+
988
+ declare interface IapEntitlementsPluginOptions {
989
+ readonly version: string;
990
+ readonly policy?: IapEntitlementPolicy;
991
+ readonly service?: IapEntitlementsService;
992
+ readonly querySources?: readonly string[] | undefined;
993
+ }
994
+
995
+ declare interface IapEntitlementsService {
996
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
997
+ readonly entitled: (subject: Subject, offerId: string) => Effect.Effect<IapEntitlementObservation, EconomyError>;
998
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
999
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1000
+ }
1001
+
1002
+ declare type IapEnvironment = 'sandbox' | 'production';
1003
+
1004
+ /** Where an owner manages what they pay for (cancel a subscription, change the card). */
1005
+ declare interface IapManagementContext {
1006
+ readonly accountToken: string;
1007
+ /** The provider's original transaction IDs (subscriptions) of the owner's accepted orders on
1008
+ * this channel, newest first; empty when the owner holds none. */
1009
+ readonly originals: readonly string[];
1010
+ readonly returnUrl: string;
1011
+ readonly at: number;
1012
+ }
1013
+
1014
+ declare interface IapManagementService {
1015
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1016
+ /** A provider page for this owner; `not_found` when the owner has nothing to manage there. */
1017
+ readonly open: (context: IapManagementContext) => Effect.Effect<{
1018
+ readonly url: string;
1019
+ }, EconomyError>;
1020
+ }
1021
+
1022
+ declare interface IapNotificationCipherSource {
1023
+ /** Default is the registered framework FieldCipher. Explicit sources use that same codec/row binding contract. */
1024
+ readonly read: () => FieldCipher | undefined;
1025
+ }
1026
+
1027
+ declare interface IapNotificationCustodyReceipt {
1028
+ readonly id: string;
1029
+ readonly orderId: string;
1030
+ readonly state: 'pending' | 'processed' | 'expired' | 'erased';
1031
+ }
1032
+
1033
+ declare interface IapNotificationInput {
1034
+ readonly body: string;
1035
+ /** Actual HTTP Authorization header for authenticated Pub/Sub push; never query/body authority. */
1036
+ readonly authorization?: string;
1037
+ /** The request's other headers, lowercased and bounded, for providers that sign in a header
1038
+ * (Stripe: `stripe-signature`). Never authority by themselves. */
1039
+ readonly headers?: Readonly<Record<string, string>>;
1040
+ }
1041
+
1042
+ declare interface IapNotificationProcessorService {
1043
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1044
+ /** `null`: an authenticated test notice (a store's TEST message, a provider event with no
1045
+ * purchase in it) is acknowledged and not retained; no retry could ever process it. */
1046
+ readonly ingest: (input: IapNotificationInput) => Effect.Effect<IapNotificationCustodyReceipt | null, EconomyError>;
1047
+ readonly process: (id: string) => Effect.Effect<IapNotificationCustodyReceipt, EconomyError>;
1048
+ readonly pending: () => Effect.Effect<readonly IapNotificationCustodyReceipt[], EconomyError>;
1049
+ readonly prune: () => Effect.Effect<number, EconomyError>;
1050
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
1051
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1052
+ }
1053
+
1054
+ declare interface IapNotificationService {
1055
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1056
+ readonly verify: (input: IapNotificationInput) => Effect.Effect<VerifiedIapNotification, EconomyError>;
1057
+ }
1058
+
1059
+ declare interface IapNotificationsPluginOptions {
1060
+ readonly version: string;
1061
+ readonly pathPrefix?: string;
1062
+ readonly maxBodyBytes?: number;
1063
+ readonly bodyRetentionMs?: number | undefined;
1064
+ readonly debtPolicy?: IapDebtPolicy | undefined;
1065
+ readonly assets?: IapRefundAssetParticipant | undefined;
1066
+ readonly assetsVersion?: string | undefined;
1067
+ readonly maxNoticeRows?: number;
1068
+ readonly maxRefundRows?: number;
1069
+ readonly cipher?: IapNotificationCipherSource | undefined;
1070
+ /** Complete replacement owns authentication/current state/financial authority, queue and privacy. */
1071
+ readonly service?: IapNotificationsSystemService;
1072
+ /** Complete notification replacements may expose their own three-method event queue. */
1073
+ readonly refundEvents?: IapRefundEventsService;
1074
+ /** Custom borrowed-transaction SQL read. Omit when the custom system exposes no own order disposition. */
1075
+ readonly refundDisposition?: IapRefundDispositionSource | undefined;
1076
+ /** Runs after a notice changed a purchase (a refund, a revocation), e.g. to end game time at once:
1077
+ * `rooms.moderation.recheckAccess({ tenantId, subjectId: ownerId })`. Best effort: a failure is
1078
+ * ignored and the notice stays processed. Not with a complete replacement `service`. */
1079
+ readonly onChange?: ((change: IapPurchaseChange) => Effect.Effect<void, unknown>) | undefined;
1080
+ }
1081
+
1082
+ declare interface IapNotificationsSystemService {
1083
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1084
+ readonly processor: (channel: EconomyChannel) => Effect.Effect<IapNotificationProcessorService, EconomyError>;
1085
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
1086
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1087
+ }
1088
+
1089
+ declare type IapOrderObservation = {
1090
+ readonly requestId: string;
1091
+ readonly state: 'not-observed' | 'pending';
1092
+ } | {
1093
+ readonly requestId: string;
1094
+ readonly state: 'fulfilled';
1095
+ readonly receipt: IapOrderReceipt;
1096
+ readonly refund?: IapRefundDisposition;
1097
+ } | {
1098
+ readonly requestId: string;
1099
+ readonly state: 'partially-refunded' | 'refunded';
1100
+ readonly receipt: IapOrderReceipt;
1101
+ readonly refund: IapRefundDisposition;
1102
+ };
1103
+
1104
+ declare interface IapOrderReceipt {
1105
+ readonly orderId: string;
1106
+ readonly offerId: string;
1107
+ readonly offerVersion: string;
1108
+ readonly quantity: number;
1109
+ readonly at: number;
1110
+ readonly pricePaid: IapPaidAmount | null;
1111
+ readonly transfers: readonly {
1112
+ readonly txId: string;
1113
+ readonly currency: string;
1114
+ readonly amount: string;
1115
+ readonly at: number;
1116
+ }[];
1117
+ readonly grants: readonly {
1118
+ readonly operationId: string;
1119
+ readonly kind: 'grant';
1120
+ readonly changes: readonly {
1121
+ readonly instanceId: string;
1122
+ readonly delta: number;
1123
+ }[];
1124
+ readonly at: number;
1125
+ }[];
1126
+ }
1127
+
1128
+ /** Provider units retain their own decimal scale. Reference prices are never substituted. */
1129
+ declare interface IapPaidAmount {
1130
+ readonly currency: string;
1131
+ readonly units: string;
1132
+ readonly scale: number;
1133
+ }
1134
+
1135
+ declare interface IapPluginOptions {
1136
+ readonly version: string;
1137
+ readonly products: readonly IapProductDefinition[];
1138
+ readonly providers?: readonly IapProviderDefinition[];
1139
+ readonly namespace?: string;
1140
+ readonly admission?: IapStoreOptions['admission'] | undefined;
1141
+ readonly inventory?: IapStoreOptions['inventory'] | undefined;
1142
+ readonly systemAccount?: string | undefined;
1143
+ readonly maxHistoryRows?: number | undefined;
1144
+ readonly now?: (() => number) | undefined;
1145
+ readonly notifications?: IapNotificationsPluginOptions | undefined;
1146
+ readonly entitlements?: IapEntitlementsPluginOptions;
1147
+ readonly service?: IapSystemService;
1148
+ readonly querySources?: {
1149
+ readonly receipt: readonly string[];
1150
+ } | undefined;
1151
+ }
1152
+
1153
+ declare interface IapProduct {
1154
+ readonly offer: ShopOffer;
1155
+ readonly channel: EconomyChannel;
1156
+ readonly kind: IapProductKind;
1157
+ readonly storeProductId: string;
1158
+ }
1159
+
1160
+ declare interface IapProductDefinition {
1161
+ readonly offer: ShopOfferDefinition | ShopOffer;
1162
+ readonly channel: EconomyChannel;
1163
+ readonly kind: IapProductKind;
1164
+ }
1165
+
1166
+ declare type IapProductKind = 'consumable' | 'non-consumable' | 'subscription';
1167
+
1168
+ declare interface IapProviderContext {
1169
+ readonly realMoney: true;
1170
+ readonly channel: EconomyChannel;
1171
+ readonly environment: IapEnvironment;
1172
+ readonly applicationId: string;
1173
+ readonly products: readonly IapProductDefinition[];
1174
+ readonly currencies: readonly CurrencyDefinition[];
1175
+ readonly accounts: IapAccountBindingService;
1176
+ readonly now: () => number;
1177
+ }
1178
+
1179
+ declare interface IapProviderDefinition {
1180
+ readonly channel: EconomyChannel;
1181
+ readonly environment: IapEnvironment;
1182
+ readonly applicationId: string;
1183
+ /** Server-owned verifier factory. Construction does no I/O; initialize is awaited at activation. */
1184
+ readonly create: (context: IapProviderContext) => IapVerificationService;
1185
+ /** Optional authenticated notification authority, initialized only when configured. */
1186
+ readonly createNotifications?: ((context: IapProviderContext) => IapNotificationService) | undefined;
1187
+ readonly createCurrentState?: ((context: IapProviderContext) => IapCurrentStateService) | undefined;
1188
+ /** Optional server completion authority, initialized before this IAP system activates. */
1189
+ readonly createCompletion?: ((context: IapProviderContext) => IapCompletionService) | undefined;
1190
+ /** Optional web checkout (`economy.iap.checkout`): the provider starts a hosted payment and
1191
+ * the player redeems its `checkoutId` as the receipt. Any payment provider fits. */
1192
+ readonly createCheckout?: ((context: IapProviderContext) => IapCheckoutService) | undefined;
1193
+ /** Origins a checkout may return to (`https://game.example`); required with `createCheckout`. */
1194
+ readonly checkoutReturnOrigins?: readonly string[] | undefined;
1195
+ /** Optional provider-delivered purchases and subscription renewals, read on the channel's
1196
+ * notification route (needs `notifications`). Each is redeemed for the owner of its account token. */
1197
+ readonly createDeliveries?: ((context: IapProviderContext) => IapDeliveryService) | undefined;
1198
+ /** Optional provider page where the owner manages subscriptions (`economy.iap.manage`). */
1199
+ readonly createManagement?: ((context: IapProviderContext) => IapManagementService) | undefined;
1200
+ }
1201
+
1202
+ declare interface IapPurchaseAdmission {
1203
+ readonly scope: IapScope;
1204
+ readonly product: IapProduct;
1205
+ readonly facts: IapTransactionFacts;
1206
+ readonly at: number;
1207
+ }
1208
+
1209
+ /** Required real SQL age/consent/spend eligibility authority. No permissive default. */
1210
+ declare interface IapPurchaseAdmissionSource {
1211
+ readonly prepare: (input: IapPurchaseAdmission) => Effect.Effect<PreparedSqlMutation<unknown>, EconomyError>;
1212
+ /** Optional check before a web checkout starts. Refuse what `prepare` would certainly
1213
+ * refuse, so the player is never charged for a purchase that cannot be redeemed;
1214
+ * `prepare` stays the authority. */
1215
+ readonly checkout?: (input: IapCheckoutAdmission) => Effect.Effect<void, EconomyError>;
1216
+ }
1217
+
1218
+ /** A store or provider notice changed a purchase: a refund, a revocation. `ownerId` is the player. */
1219
+ declare interface IapPurchaseChange {
1220
+ readonly tenantId: string;
1221
+ readonly ownerId: string;
1222
+ readonly orderId: string;
1223
+ readonly offerId: string;
1224
+ readonly offerVersion: string;
1225
+ readonly state: IapRefundReceipt['state'];
1226
+ }
1227
+
1228
+ declare interface IapReceiptIntent {
1229
+ readonly channel: EconomyChannel;
1230
+ readonly offerId: string;
1231
+ readonly offerVersion: string;
1232
+ readonly requestId: string;
1233
+ /** Opaque store evidence. Never log or persist this in player receipts. */
1234
+ readonly receipt: string;
1235
+ }
1236
+
1237
+ /** Read-only original-intention reference. Never send raw receipts in query parameters. */
1238
+ declare interface IapReceiptReference {
1239
+ readonly channel: EconomyChannel;
1240
+ readonly offerId: string;
1241
+ readonly offerVersion: string;
1242
+ readonly requestId: string;
1243
+ readonly receiptDigest: string;
1244
+ }
1245
+
1246
+ declare interface IapRefundAssetContext {
1247
+ readonly original: IapSqlOriginalPurchase;
1248
+ readonly state: IapCurrentPurchaseState;
1249
+ readonly previous: IapRefundReceipt | null;
1250
+ readonly sequence: number;
1251
+ }
1252
+
1253
+ /** Mandatory for orders with item grants. It must use the same real store and original grant custody. */
1254
+ declare interface IapRefundAssetParticipant {
1255
+ readonly prepare: (input: IapRefundAssetContext) => Effect.Effect<PreparedSqlMutation<unknown>, EconomyError>;
1256
+ readonly validate: (input: IapRefundAssetContext, receipt: unknown) => unknown;
1257
+ /** SQL-only audit of accepted movement receipts; no provider/application callbacks. */
1258
+ readonly audit: (tx: DataStore, input: IapRefundAssetContext, receipt: unknown) => Promise<void>;
1259
+ }
1260
+
1261
+ /** Channels whose providers report refunds and revocations to the economy. */
1262
+ declare type IapRefundChannel = 'ios' | 'android' | 'web';
1263
+
1264
+ declare interface IapRefundCurrency {
1265
+ readonly currency: string;
1266
+ readonly original: string;
1267
+ readonly refunded: string;
1268
+ }
1269
+
1270
+ /** Accepted SQL refund history only. This projection never authorizes a grant or completion. */
1271
+ declare interface IapRefundDisposition {
1272
+ readonly sequence: number;
1273
+ readonly state: 'active' | 'partially-refunded' | 'revoked';
1274
+ readonly refundNumerator: number;
1275
+ readonly refundDenominator: number;
1276
+ readonly observedAt: number;
1277
+ }
1278
+
1279
+ /** Borrowed transaction read only: no provider, nested transaction, seed, clock or mutation. */
1280
+ declare interface IapRefundDispositionSource {
1281
+ readonly read: (tx: DataStore, original: IapSqlOriginalPurchase) => Promise<IapRefundDisposition | null>;
1282
+ }
1283
+
1284
+ declare interface IapRefundEventContext {
1285
+ readonly namespace: string;
1286
+ readonly tenantId: string;
1287
+ readonly subjectId: string;
1288
+ readonly payload: IapRefundEventPayload;
1289
+ /** Complete bounded accepted history; these are observations, never a fraud verdict. */
1290
+ readonly refundedOrders: number;
1291
+ readonly observedOrders: number;
1292
+ readonly refundAdjustments: number;
1293
+ }
1294
+
1295
+ declare type IapRefundEventPayload = typeof IapRefundEventPayloadSchema.Type;
1296
+
1297
+ declare const IapRefundEventPayloadSchema: Schema.Struct<{
1298
+ readonly eventId: Schema.String;
1299
+ readonly orderId: Schema.String;
1300
+ readonly sequence: Schema.Number;
1301
+ readonly state: Schema.Literals<readonly ["active", "partially-refunded", "revoked"]>;
1302
+ readonly refundNumerator: Schema.Number;
1303
+ readonly refundDenominator: Schema.Number;
1304
+ readonly observedAt: Schema.Number;
1305
+ }>;
1306
+
1307
+ declare interface IapRefundEventsService {
1308
+ readonly pending: (subject: Subject) => Effect.Effect<readonly PendingIapRefundEvent[], EconomyError>;
1309
+ readonly read: (subject: Subject, event: PendingIapRefundEvent) => Effect.Effect<IapRefundEventContext, EconomyError>;
1310
+ readonly acknowledge: (subject: Subject, event: PendingIapRefundEvent, deliveryVersion: string) => Effect.Effect<void, EconomyError>;
1311
+ }
1312
+
1313
+ declare interface IapRefundReceipt {
1314
+ readonly orderId: string;
1315
+ readonly sequence: number;
1316
+ readonly state: IapCurrentPurchaseState['state'];
1317
+ readonly refundNumerator: number;
1318
+ readonly refundDenominator: number;
1319
+ readonly observedAt: number;
1320
+ readonly noticeId: string;
1321
+ readonly fingerprint: string;
1322
+ readonly debtPolicy: IapDebtPolicy;
1323
+ readonly currencies: readonly IapRefundCurrency[];
1324
+ readonly transfers: readonly EconomyReceipt[];
1325
+ /** Opaque actual asset participant receipt, validated by its captured participant. */
1326
+ readonly assets: unknown;
1327
+ }
1328
+
1329
+ declare interface IapScope {
1330
+ readonly tenantId: string;
1331
+ readonly ownerId: string;
1332
+ }
1333
+
1334
+ declare interface IapService {
1335
+ readonly redeem: (subject: Subject, input: IapReceiptIntent) => Effect.Effect<IapOrderReceipt, EconomyError>;
1336
+ readonly receipt: (subject: Subject, input: IapReceiptReference) => Effect.Effect<IapOrderObservation, EconomyError>;
1337
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
1338
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1339
+ }
1340
+
1341
+ /** SQL original after the owning adapter has validated its immutable custody and receipt. */
1342
+ declare interface IapSqlOriginalPurchase {
1343
+ readonly orderId: string;
1344
+ readonly scope: IapScope;
1345
+ readonly receipt: IapOrderReceipt;
1346
+ readonly product: IapProduct;
1347
+ readonly facts: IapTransactionFacts;
1348
+ readonly currencies: readonly CurrencyDefinition[];
1349
+ }
1350
+
1351
+ declare interface IapStoreOptions {
1352
+ readonly realMoney: boolean;
1353
+ /** Operator-owned immutable work/privacy namespace, never an RPC input. */
1354
+ readonly namespace: string;
1355
+ readonly currencies: readonly CurrencyDefinition[];
1356
+ readonly verification: Pick<IapVerificationService, 'verify'>;
1357
+ readonly admission: IapPurchaseAdmissionSource;
1358
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
1359
+ readonly inventory?: Pick<InventorySqlService, 'prepareGrant'> | undefined;
1360
+ readonly refundDisposition?: IapRefundDispositionSource | undefined;
1361
+ readonly systemAccount: string;
1362
+ readonly maxHistoryRows?: number | undefined;
1363
+ readonly now?: (() => number) | undefined;
1364
+ }
1365
+
1366
+ /** An accepted store period, not a fresh provider observation or financial capability. */
1367
+ declare interface IapSubscriptionPeriod {
1368
+ readonly orderId: string;
1369
+ readonly offerId: string;
1370
+ readonly offerVersion: string;
1371
+ readonly channel: EconomyChannel;
1372
+ readonly startsAt: number;
1373
+ readonly expiresAt: number;
1374
+ readonly refund: IapRefundDisposition | null;
1375
+ }
1376
+
1377
+ /** Complete system replacement owns provider readiness, accounts, financial authority and privacy. */
1378
+ declare interface IapSystemService extends IapService {
1379
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1380
+ readonly account: (subject: Subject, channel: EconomyChannel) => Effect.Effect<string, EconomyError>;
1381
+ /** Explicit retry of the same accepted original intent. Never redeems or grants. */
1382
+ readonly complete: (subject: Subject, intent: Parameters<IapService['redeem']>[1]) => Effect.Effect<IapCompletionReceipt, EconomyError>;
1383
+ }
1384
+
1385
+ declare interface IapTransactionFacts {
1386
+ readonly channel: EconomyChannel;
1387
+ readonly environment: IapEnvironment;
1388
+ readonly applicationId: string;
1389
+ readonly transactionId: string;
1390
+ readonly originalTransactionId: string | null;
1391
+ readonly storeProductId: string;
1392
+ readonly kind: IapProductKind;
1393
+ readonly quantity: number;
1394
+ readonly purchasedAt: number;
1395
+ readonly expiresAt: number | null;
1396
+ readonly paid: IapPaidAmount | null;
1397
+ readonly acknowledgement: 'none' | 'pending' | 'acknowledged';
1398
+ readonly consumption: 'none' | 'available' | 'consumed';
1399
+ }
1400
+
1401
+ declare interface IapVerificationService {
1402
+ readonly initialize: () => Effect.Effect<void, EconomyError>;
1403
+ readonly verify: (scope: IapScope, input: IapReceiptIntent) => Effect.Effect<VerifiedIapPurchase, EconomyError>;
1404
+ }
1405
+
1406
+ declare interface IapWalletRefundInput {
1407
+ readonly requestId: string;
1408
+ readonly currency: string;
1409
+ readonly amount: string;
1410
+ readonly debtPolicy: IapDebtPolicy;
1411
+ }
1412
+
1413
+ export declare interface LedgerPosting {
1414
+ readonly account: EconomyAccount;
1415
+ readonly debit: string;
1416
+ readonly credit: string;
1417
+ }
1418
+
1419
+ export declare interface LedgerTransfer {
1420
+ readonly tenantId: string;
1421
+ readonly requestId: string;
1422
+ readonly currency: string;
1423
+ readonly amount: string;
1424
+ readonly reason: string;
1425
+ readonly ref: EconomyReference;
1426
+ readonly postings: readonly [LedgerPosting, LedgerPosting];
1427
+ }
1428
+
1429
+ export declare interface LedgerTransferInput {
1430
+ readonly tenantId: string;
1431
+ readonly requestId: string;
1432
+ readonly currency: string;
1433
+ readonly from: EconomyAccount;
1434
+ readonly to: EconomyAccount;
1435
+ readonly amount: EconomyAmountInput;
1436
+ readonly reason: string;
1437
+ readonly ref: EconomyReference;
1438
+ }
1439
+
1440
+ export declare interface Loyalty {
1441
+ readonly id: string;
1442
+ readonly version: string;
1443
+ readonly titleKey: string;
1444
+ readonly pointsFrom: readonly {
1445
+ readonly id: string;
1446
+ readonly kind: 'purchase.real' | 'purchase.virtual';
1447
+ readonly currency: string;
1448
+ readonly numerator: string;
1449
+ readonly denominator: string;
1450
+ }[];
1451
+ readonly tiers: readonly {
1452
+ readonly id: string;
1453
+ readonly at: string;
1454
+ readonly perks: readonly LoyaltyPerk[];
1455
+ }[];
1456
+ readonly decay: 'none' | 'seasonal';
1457
+ }
1458
+
1459
+ /** Only trusted server callers name receipts. Amounts, weights, points, tiers
1460
+ * and seasons are never request fields. No player credit/reverse action. */
1461
+ export declare interface LoyaltyCreditInput {
1462
+ readonly tenantId: string;
1463
+ readonly ownerId: string;
1464
+ readonly loyaltyId: string;
1465
+ readonly sourceId: string;
1466
+ readonly purchaseId: string;
1467
+ readonly requestId: string;
1468
+ }
1469
+
1470
+ export declare const loyaltyCreditIntent: (input: LoyaltyCreditInput) => LoyaltyCreditInput;
1471
+
1472
+ export declare interface LoyaltyDefinition {
1473
+ readonly id: string;
1474
+ readonly version?: string | undefined;
1475
+ readonly titleKey: string;
1476
+ readonly pointsFrom: readonly {
1477
+ readonly id: string;
1478
+ readonly kind: 'purchase.real' | 'purchase.virtual';
1479
+ readonly currency: string;
1480
+ readonly numerator: EconomyAmountInput;
1481
+ readonly denominator: EconomyAmountInput;
1482
+ }[];
1483
+ readonly tiers: readonly {
1484
+ readonly id: string;
1485
+ readonly at: EconomyAmountInput;
1486
+ readonly perks: readonly LoyaltyPerkDefinition[];
1487
+ }[];
1488
+ readonly decay?: 'none' | 'seasonal';
1489
+ }
1490
+
1491
+ export declare interface LoyaltyMineInput {
1492
+ readonly loyaltyId: string;
1493
+ }
1494
+
1495
+ export declare const loyaltyMineIntent: (input: LoyaltyMineInput) => LoyaltyMineInput;
1496
+
1497
+ export declare type LoyaltyObservation = {
1498
+ readonly requestId: string;
1499
+ readonly state: 'not-observed';
1500
+ } | {
1501
+ readonly requestId: string;
1502
+ readonly state: 'fulfilled';
1503
+ readonly receipt: LoyaltyReceipt;
1504
+ };
1505
+
1506
+ export declare type LoyaltyPerk = Exclude<LoyaltyPerkDefinition, {
1507
+ readonly kind: 'inboxGift';
1508
+ }> | {
1509
+ readonly id: string;
1510
+ readonly kind: 'inboxGift';
1511
+ readonly items: readonly ShopItemGrant[];
1512
+ readonly currencies: readonly {
1513
+ readonly currency: string;
1514
+ readonly amount: string;
1515
+ }[];
1516
+ };
1517
+
1518
+ export declare type LoyaltyPerkDefinition = {
1519
+ readonly id: string;
1520
+ readonly kind: 'xpMultiplier';
1521
+ readonly bps: number;
1522
+ } | {
1523
+ readonly id: string;
1524
+ readonly kind: 'discount';
1525
+ readonly bps: number;
1526
+ } | {
1527
+ readonly id: string;
1528
+ readonly kind: 'chatBadge';
1529
+ readonly badgeId: string;
1530
+ } | {
1531
+ readonly id: string;
1532
+ readonly kind: 'inboxGift';
1533
+ readonly items?: readonly ShopItemGrant[] | undefined;
1534
+ readonly currencies?: readonly ShopCurrencyGrant[] | undefined;
1535
+ };
1536
+
1537
+ export declare interface LoyaltyPerksContext extends LoyaltyTierContext {
1538
+ readonly tierId: string;
1539
+ }
1540
+
1541
+ export declare type LoyaltyPerksResolver = (input: LoyaltyPerksContext) => readonly LoyaltyPerk[];
1542
+
1543
+ declare interface LoyaltyPluginOptions extends Omit<LoyaltyStoreOptions, 'currencies' | 'realMoney' | 'receiptSource'> {
1544
+ readonly receiptSource?: LoyaltyStoreOptions['receiptSource'];
1545
+ readonly service?: LoyaltyService;
1546
+ readonly querySources?: {
1547
+ readonly list: readonly string[] | undefined;
1548
+ readonly mine: readonly string[];
1549
+ readonly receipt: readonly string[];
1550
+ };
1551
+ }
1552
+
1553
+ export declare type LoyaltyPointEntry = {
1554
+ readonly id: string;
1555
+ readonly sequence: number;
1556
+ readonly kind: 'credit';
1557
+ readonly at: number;
1558
+ readonly sourceId: string;
1559
+ readonly purchaseId: string;
1560
+ readonly seasonId: string | null;
1561
+ readonly purchaseAmount: string;
1562
+ readonly numerator: string;
1563
+ readonly denominator: string;
1564
+ readonly delta: string;
1565
+ } | {
1566
+ readonly id: string;
1567
+ readonly sequence: number;
1568
+ readonly kind: 'reverse';
1569
+ readonly at: number;
1570
+ readonly originalId: string;
1571
+ readonly refundId: string;
1572
+ readonly seasonId: string | null;
1573
+ readonly totalRefunded: string;
1574
+ readonly delta: string;
1575
+ };
1576
+
1577
+ export declare interface LoyaltyPointProjection {
1578
+ readonly entries: readonly LoyaltyPointEntry[];
1579
+ readonly balances: readonly {
1580
+ readonly seasonId: string | null;
1581
+ readonly points: string;
1582
+ }[];
1583
+ readonly credits: readonly {
1584
+ readonly id: string;
1585
+ readonly refundedAmount: string;
1586
+ readonly remainingPoints: string;
1587
+ }[];
1588
+ }
1589
+
1590
+ /** Trusted verified settlement projection only, not a player input/receipt
1591
+ * validator. Exact floor rounding is defined once per accepted purchase; a full
1592
+ * reversal must reverse its recorded credit, never independently reround it. */
1593
+ export declare const loyaltyPointsForPurchase: (input: LoyaltyDefinition | Loyalty, sourceId: string, amount: EconomyAmountInput, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => string;
1594
+
1595
+ export declare class LoyaltyPort extends LoyaltyPort_base {
1596
+ }
1597
+
1598
+ declare const LoyaltyPort_base: Context.ServiceClass<LoyaltyPort, "@voltro/LoyaltyPort", LoyaltyService>;
1599
+
1600
+ /** Receipt authority must use immutable accepted SQL/provider evidence, verify
1601
+ * ownership and canonical purchase identity independently of source aliases,
1602
+ * and refuse revoked/unsettled/already-refunded purchases. No player evidence. */
1603
+ declare interface LoyaltyPurchaseEvidence {
1604
+ readonly tenantId: string;
1605
+ readonly ownerId: string;
1606
+ readonly authorityId: string;
1607
+ readonly purchaseId: string;
1608
+ readonly kind: 'purchase.real' | 'purchase.virtual';
1609
+ readonly currency: string;
1610
+ readonly amount: string;
1611
+ readonly settledAt: number;
1612
+ readonly refundedAmount: '0';
1613
+ }
1614
+
1615
+ export declare interface LoyaltyRebuildInput extends LoyaltyMineInput {
1616
+ readonly tenantId: string;
1617
+ readonly ownerId: string;
1618
+ }
1619
+
1620
+ export declare const loyaltyRebuildIntent: (input: LoyaltyRebuildInput) => LoyaltyRebuildInput;
1621
+
1622
+ export declare interface LoyaltyReceipt {
1623
+ readonly operationId: string;
1624
+ readonly requestId: string;
1625
+ readonly loyaltyId: string;
1626
+ readonly entry: LoyaltyPointEntry;
1627
+ readonly points: string;
1628
+ }
1629
+
1630
+ export declare interface LoyaltyReceiptInput {
1631
+ readonly requestId: string;
1632
+ }
1633
+
1634
+ export declare const loyaltyReceiptIntent: (input: LoyaltyReceiptInput) => LoyaltyReceiptInput;
1635
+
1636
+ declare interface LoyaltyReceiptSource {
1637
+ readonly purchase: (input: {
1638
+ readonly tenantId: string;
1639
+ readonly ownerId: string;
1640
+ readonly source: Loyalty['pointsFrom'][number];
1641
+ readonly purchaseId: string;
1642
+ }) => Effect.Effect<LoyaltyPurchaseEvidence, EconomyError>;
1643
+ readonly refund: (input: {
1644
+ readonly tenantId: string;
1645
+ readonly ownerId: string;
1646
+ readonly purchase: LoyaltyPurchaseEvidence;
1647
+ readonly refundId: string;
1648
+ }) => Effect.Effect<LoyaltyRefundEvidence, EconomyError>;
1649
+ }
1650
+
1651
+ declare interface LoyaltyRefundEvidence {
1652
+ readonly tenantId: string;
1653
+ readonly ownerId: string;
1654
+ readonly authorityId: string;
1655
+ readonly purchaseId: string;
1656
+ readonly refundId: string;
1657
+ readonly totalRefunded: string;
1658
+ readonly refundedAt: number;
1659
+ }
1660
+
1661
+ export declare interface LoyaltyReverseInput {
1662
+ readonly tenantId: string;
1663
+ readonly ownerId: string;
1664
+ readonly loyaltyId: string;
1665
+ readonly originalId: string;
1666
+ readonly refundId: string;
1667
+ readonly requestId: string;
1668
+ }
1669
+
1670
+ export declare const loyaltyReverseIntent: (input: LoyaltyReverseInput) => LoyaltyReverseInput;
1671
+
1672
+ declare interface LoyaltySeason {
1673
+ readonly id: string;
1674
+ readonly startsAt: number;
1675
+ readonly endsAt: number;
1676
+ }
1677
+
1678
+ declare interface LoyaltySeasonSource {
1679
+ readonly read: (input: {
1680
+ readonly tenantId: string;
1681
+ readonly loyaltyId: string;
1682
+ readonly at: number;
1683
+ }) => Effect.Effect<LoyaltySeason, EconomyError>;
1684
+ }
1685
+
1686
+ export declare interface LoyaltyService {
1687
+ readonly list: (subject: Subject) => Effect.Effect<readonly Loyalty[], EconomyError>;
1688
+ readonly mine: (subject: Subject, input: LoyaltyMineInput) => Effect.Effect<LoyaltyState, EconomyError>;
1689
+ readonly credit: (subject: Subject, input: LoyaltyCreditInput) => Effect.Effect<LoyaltyReceipt, EconomyError>;
1690
+ readonly reverse: (subject: Subject, input: LoyaltyReverseInput) => Effect.Effect<LoyaltyReceipt, EconomyError>;
1691
+ readonly receipt: (subject: Subject, input: LoyaltyReceiptInput) => Effect.Effect<LoyaltyObservation, EconomyError>;
1692
+ readonly rebuild: (subject: Subject, input: LoyaltyRebuildInput) => Effect.Effect<LoyaltyPointProjection, EconomyError>;
1693
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
1694
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1695
+ }
1696
+
1697
+ export declare interface LoyaltyState {
1698
+ readonly loyalty: Loyalty;
1699
+ readonly rulesVersion: string;
1700
+ readonly seasonId: string | null;
1701
+ readonly points: string;
1702
+ readonly tierId: string;
1703
+ readonly perks: readonly LoyaltyPerk[];
1704
+ }
1705
+
1706
+ declare interface LoyaltyStoreOptions {
1707
+ readonly loyalty: readonly (LoyaltyDefinition | Loyalty)[];
1708
+ readonly currencies: readonly CurrencyDefinition[];
1709
+ readonly realMoney?: boolean;
1710
+ readonly receiptSource: LoyaltyReceiptSource;
1711
+ readonly seasonSource?: LoyaltySeasonSource | undefined;
1712
+ readonly version: string;
1713
+ readonly tier?: LoyaltyTierResolver | undefined;
1714
+ readonly perks?: LoyaltyPerksResolver | undefined;
1715
+ readonly allowedServices?: readonly string[] | undefined;
1716
+ readonly maxHistoryRows?: number | undefined;
1717
+ readonly maxDefinitionRows?: number | undefined;
1718
+ readonly maxSeasonRows?: number | undefined;
1719
+ readonly now?: (() => number) | undefined;
1720
+ }
1721
+
1722
+ export declare interface LoyaltyTierContext {
1723
+ readonly loyalty: Loyalty;
1724
+ readonly currencies: readonly CurrencyDefinition[];
1725
+ readonly realMoney?: boolean;
1726
+ readonly points: EconomyAmountInput;
1727
+ readonly rulesVersion?: string;
1728
+ }
1729
+
1730
+ export declare type LoyaltyTierResolver = (context: LoyaltyTierContext) => string;
1731
+
1732
+ /** Actual pending SQL event authority. Copies and serialized payloads cannot authorize delivery acknowledgement. */
1733
+ declare interface PendingIapRefundEvent {
1734
+ readonly [refundEvent]: true;
1735
+ readonly eventId: string;
1736
+ }
1737
+
1738
+ export declare interface PiggyBank {
1739
+ readonly id: string;
1740
+ readonly version: string;
1741
+ readonly titleKey: string;
1742
+ readonly currency: string;
1743
+ readonly cap: string;
1744
+ readonly unlock: Price;
1745
+ readonly fillFrom: readonly string[];
1746
+ readonly reset: 'onUnlock';
1747
+ }
1748
+
1749
+ export declare interface PiggyBankDefinition {
1750
+ readonly id: string;
1751
+ readonly version?: string | undefined;
1752
+ readonly titleKey: string;
1753
+ readonly currency: string;
1754
+ readonly cap: EconomyAmountInput;
1755
+ readonly unlock: PriceDefinition;
1756
+ readonly fillFrom: readonly string[];
1757
+ readonly reset?: 'onUnlock' | undefined;
1758
+ }
1759
+
1760
+ export declare class PiggyBanksPort extends PiggyBanksPort_base {
1761
+ }
1762
+
1763
+ declare const PiggyBanksPort_base: Context.ServiceClass<PiggyBanksPort, "@voltro/PiggyBanksPort", PiggyBanksService>;
1764
+
1765
+ export declare interface PiggyBanksService {
1766
+ readonly list: (subject: Subject) => Effect.Effect<readonly PiggyView[], EconomyError>;
1767
+ readonly fill: (subject: Subject, input: PiggyFillInput) => Effect.Effect<PiggyReceipt, EconomyError>;
1768
+ readonly unlock: (subject: Subject, input: PiggyUnlockInput) => Effect.Effect<PiggyReceipt, EconomyError>;
1769
+ readonly receipt: (subject: Subject, input: {
1770
+ readonly requestId: string;
1771
+ }) => Effect.Effect<PiggyObservation, EconomyError>;
1772
+ readonly rebuild: (subject: Subject, input: {
1773
+ readonly tenantId: string;
1774
+ readonly ownerId: string;
1775
+ readonly bankId: string;
1776
+ }) => Effect.Effect<PiggyProjection, EconomyError>;
1777
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
1778
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
1779
+ }
1780
+
1781
+ export declare type PiggyEvent = {
1782
+ readonly id: string;
1783
+ readonly sequence: number;
1784
+ readonly kind: 'fill';
1785
+ readonly at: number;
1786
+ readonly authorityId: string;
1787
+ readonly eventId: string;
1788
+ readonly sourceId: string;
1789
+ readonly acceptedAmount: string;
1790
+ readonly delta: string;
1791
+ } | {
1792
+ readonly id: string;
1793
+ readonly sequence: number;
1794
+ readonly kind: 'unlock';
1795
+ readonly at: number;
1796
+ readonly amount: string;
1797
+ readonly remaining: string;
1798
+ };
1799
+
1800
+ export declare interface PiggyFillContext extends PiggyRuleContext {
1801
+ readonly acceptedAmount: EconomyAmountInput;
1802
+ }
1803
+
1804
+ declare interface PiggyFillEvidence {
1805
+ readonly tenantId: string;
1806
+ readonly ownerId: string;
1807
+ readonly authorityId: string;
1808
+ readonly eventId: string;
1809
+ readonly sourceId: string;
1810
+ readonly amount: string;
1811
+ readonly acceptedAt: number;
1812
+ }
1813
+
1814
+ export declare interface PiggyFillInput {
1815
+ readonly tenantId: string;
1816
+ readonly ownerId: string;
1817
+ readonly bankId: string;
1818
+ readonly sourceId: string;
1819
+ readonly eventId: string;
1820
+ readonly requestId: string;
1821
+ }
1822
+
1823
+ export declare const piggyFillIntent: (input: PiggyFillInput) => PiggyFillInput;
1824
+
1825
+ export declare type PiggyFillPolicy = (context: PiggyFillContext) => EconomyAmountInput;
1826
+
1827
+ /** Actual accepted server events only. Canonical authority/event identity must
1828
+ * stay independent of aliases and be scoped/verified by the application's
1829
+ * authoritative event source. No player match result or amount is accepted. */
1830
+ declare interface PiggyFillSource {
1831
+ readonly read: (input: {
1832
+ readonly tenantId: string;
1833
+ readonly ownerId: string;
1834
+ readonly bank: PiggyBank;
1835
+ readonly sourceId: string;
1836
+ readonly eventId: string;
1837
+ }) => Effect.Effect<PiggyFillEvidence, EconomyError>;
1838
+ }
1839
+
1840
+ export declare type PiggyObservation = {
1841
+ readonly requestId: string;
1842
+ readonly state: 'not-observed';
1843
+ } | {
1844
+ readonly requestId: string;
1845
+ readonly state: 'fulfilled';
1846
+ readonly receipt: PiggyReceipt;
1847
+ };
1848
+
1849
+ declare interface PiggyPluginOptions extends Omit<PiggyStoreOptions, 'currencies' | 'economy' | 'realMoney' | 'fillSource' | 'unlockSource'> {
1850
+ readonly fillSource?: PiggyStoreOptions['fillSource'];
1851
+ readonly unlockSource?: PiggyStoreOptions['unlockSource'];
1852
+ readonly service?: PiggyBanksService;
1853
+ readonly querySources?: {
1854
+ readonly list: readonly string[] | undefined;
1855
+ readonly receipt: readonly string[];
1856
+ };
1857
+ }
1858
+
1859
+ export declare interface PiggyProjection {
1860
+ readonly events: readonly PiggyEvent[];
1861
+ readonly available: string;
1862
+ readonly cycles: number;
1863
+ }
1864
+
1865
+ export declare type PiggyReceipt = {
1866
+ readonly operationId: string;
1867
+ readonly requestId: string;
1868
+ readonly bankId: string;
1869
+ readonly event: Extract<PiggyEvent, {
1870
+ kind: 'fill';
1871
+ }>;
1872
+ readonly available: string;
1873
+ } | {
1874
+ readonly operationId: string;
1875
+ readonly requestId: string;
1876
+ readonly bankId: string;
1877
+ readonly event: Extract<PiggyEvent, {
1878
+ kind: 'unlock';
1879
+ }>;
1880
+ readonly available: string;
1881
+ readonly value: ShopOrderReceipt;
1882
+ };
1883
+
1884
+ export declare type PiggyResetPolicy = (context: PiggyRuleContext) => EconomyAmountInput;
1885
+
1886
+ export declare interface PiggyRuleContext {
1887
+ readonly bank: PiggyBank;
1888
+ readonly currencies: readonly CurrencyDefinition[];
1889
+ readonly realMoney?: boolean;
1890
+ readonly available: EconomyAmountInput;
1891
+ readonly rulesVersion?: string;
1892
+ }
1893
+
1894
+ declare interface PiggyStoreOptions {
1895
+ readonly banks: readonly (PiggyBankDefinition | PiggyBank)[];
1896
+ readonly currencies: readonly CurrencyDefinition[];
1897
+ readonly realMoney?: boolean;
1898
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
1899
+ readonly fillSource: PiggyFillSource;
1900
+ readonly unlockSource: PiggyUnlockSource;
1901
+ readonly version: string;
1902
+ readonly fill?: PiggyFillPolicy | undefined;
1903
+ readonly reset?: PiggyResetPolicy | undefined;
1904
+ readonly priceResolver?: PriceResolver | undefined;
1905
+ readonly systemAccount?: string | undefined;
1906
+ readonly allowedServices?: readonly string[] | undefined;
1907
+ readonly maxHistoryRows?: number | undefined;
1908
+ readonly now?: (() => number) | undefined;
1909
+ }
1910
+
1911
+ export declare interface PiggyUnlockInput {
1912
+ readonly bankId: string;
1913
+ readonly bankVersion: string;
1914
+ readonly bankDigest: string;
1915
+ readonly requestId: string;
1916
+ readonly currency?: string | undefined;
1917
+ }
1918
+
1919
+ export declare const piggyUnlockIntent: (input: PiggyUnlockInput) => Readonly<{
1920
+ bankId: string;
1921
+ bankVersion: string;
1922
+ bankDigest: string;
1923
+ requestId: string;
1924
+ currency: string | null;
1925
+ }>;
1926
+
1927
+ declare interface PiggyUnlockSource {
1928
+ readonly read: (input: {
1929
+ readonly subject: Subject;
1930
+ readonly bank: PiggyBank;
1931
+ readonly at: number;
1932
+ }) => Effect.Effect<{
1933
+ readonly eligible: boolean;
1934
+ readonly adjustments: readonly VirtualPriceAdjustment[];
1935
+ }, EconomyError>;
1936
+ }
1937
+
1938
+ export declare interface PiggyView {
1939
+ readonly bank: PiggyBank;
1940
+ readonly bankDigest: string;
1941
+ readonly available: string;
1942
+ readonly cycles: number;
1943
+ }
1944
+
1945
+ export declare const planLedgerTransfer: (input: LedgerTransferInput) => LedgerTransfer;
1946
+
1947
+ export declare type Price = {
1948
+ readonly kind: 'virtual';
1949
+ readonly options: readonly ResolvedVirtualPriceOption[];
1950
+ } | ({
1951
+ readonly kind: 'real';
1952
+ } & RealPriceDefinition) | {
1953
+ readonly kind: 'mixed';
1954
+ readonly real: RealPriceDefinition;
1955
+ readonly virtual: readonly ResolvedVirtualPriceOption[];
1956
+ } | {
1957
+ readonly kind: 'free';
1958
+ };
1959
+
1960
+ export declare type PriceDefinition = {
1961
+ readonly kind: 'virtual';
1962
+ readonly options: readonly VirtualPriceOption[];
1963
+ } | ({
1964
+ readonly kind: 'real';
1965
+ } & RealPriceDefinition) | {
1966
+ readonly kind: 'mixed';
1967
+ readonly real: RealPriceDefinition;
1968
+ readonly virtual: readonly VirtualPriceOption[];
1969
+ } | {
1970
+ readonly kind: 'free';
1971
+ };
1972
+
1973
+ export declare type PriceResolver = (context: PriceResolverContext) => Price;
1974
+
1975
+ export declare interface PriceResolverContext {
1976
+ readonly price: Price;
1977
+ readonly currencies: readonly ResolvedCurrency[];
1978
+ readonly realMoney: boolean;
1979
+ readonly adjustments: readonly Readonly<{
1980
+ currency: string;
1981
+ discountBps: number;
1982
+ minimum: string;
1983
+ }>[];
1984
+ }
1985
+
1986
+ export declare const priceResolverContext: (price: PriceDefinition, currencies: readonly CurrencyDefinition[], realMoney?: boolean, adjustments?: readonly VirtualPriceAdjustment[]) => PriceResolverContext;
1987
+
1988
+ /** Whole accepted-history projection shared by the future SQL writer/rebuild.
1989
+ * No purchase/refund authenticity is inferred here. The owner must provide all
1990
+ * rows from one tenant/subject, and archive original source weights as evidence.
1991
+ * Cumulative partial refunds cannot exploit independent floor rounding. */
1992
+ export declare const projectLoyaltyPoints: (input: readonly LoyaltyPointEntry[], decay?: Loyalty["decay"]) => LoyaltyPointProjection;
1993
+
1994
+ /** One complete accepted history owner for writer/rebuild. SQL/source layers
1995
+ * separately establish receipt authenticity, ownership and complete tail. */
1996
+ export declare const projectPiggyBank: (bank: Pick<PiggyBank, "cap" | "fillFrom">, input: readonly PiggyEvent[]) => PiggyProjection;
1997
+
1998
+ /** Complete owner/currency history is supplied and validated by SQL custody.
1999
+ * Credits/refunds never silently replenish an already consumed spend allowance. */
2000
+ export declare const projectSpend: (input: readonly SpendPosting[], at: number) => Readonly<{
2001
+ windows: Readonly<{
2002
+ day: Readonly<{
2003
+ from: number;
2004
+ until: number;
2005
+ }>;
2006
+ month: Readonly<{
2007
+ from: number;
2008
+ until: number;
2009
+ }>;
2010
+ }>;
2011
+ daily: string;
2012
+ monthly: string;
2013
+ balance: string;
2014
+ }>;
2015
+
2016
+ export declare interface PromoCode {
2017
+ readonly id: string;
2018
+ readonly version: string;
2019
+ readonly campaign: string;
2020
+ readonly items: readonly {
2021
+ readonly itemId: string;
2022
+ readonly qty: number;
2023
+ }[];
2024
+ readonly currencies: readonly {
2025
+ readonly currency: string;
2026
+ readonly amount: string;
2027
+ }[];
2028
+ readonly from: number | null;
2029
+ readonly until: number | null;
2030
+ readonly limits: {
2031
+ readonly global: number;
2032
+ readonly perPlayer: number;
2033
+ };
2034
+ }
2035
+
2036
+ export declare interface RealPriceDefinition {
2037
+ /** Integer minor-unit references; verified store receipts remain authoritative. */
2038
+ readonly prices: Readonly<Record<string, number>>;
2039
+ readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
2040
+ }
2041
+
2042
+ export declare interface RedeemCodeInput {
2043
+ readonly code: string;
2044
+ readonly requestId: string;
2045
+ }
2046
+
2047
+ declare const refundEvent: unique symbol;
2048
+
2049
+ export declare const resolveCodeEligibility: (input: CodeEligibilityContext, declarations: readonly CurrencyDefinition[], slot?: CodeEligibility) => boolean;
2050
+
2051
+ export declare interface ResolvedCurrency {
2052
+ readonly id: string;
2053
+ readonly kind: 'soft' | 'hard';
2054
+ readonly cap: string;
2055
+ readonly premium: boolean;
2056
+ readonly display: {
2057
+ readonly nameKey: string;
2058
+ } | null;
2059
+ }
2060
+
2061
+ export declare interface ResolvedVirtualPriceOption {
2062
+ readonly currency: string;
2063
+ readonly amount: string;
2064
+ }
2065
+
2066
+ /** A named override chooses a subset of declared qualifying-tier perks. App
2067
+ * authors change the declaration to change rewards, never return hidden grants. */
2068
+ export declare const resolveLoyaltyPerks: (input: LoyaltyPerksContext, slot?: LoyaltyPerksResolver) => readonly LoyaltyPerk[];
2069
+
2070
+ export declare const resolveLoyaltyTier: (input: LoyaltyTierContext, slot?: LoyaltyTierResolver) => {
2071
+ readonly id: string;
2072
+ readonly at: string;
2073
+ readonly perks: readonly LoyaltyPerk[];
2074
+ };
2075
+
2076
+ /** Custom fill narrows the accepted source amount and remaining cap. No player
2077
+ * event, source validation, SQL grant or wallet mint is implied by this rule. */
2078
+ export declare const resolvePiggyFill: (input: PiggyFillContext, slot?: PiggyFillPolicy) => string;
2079
+
2080
+ /** Custom reset retains a remainder; only available-minus-remainder is granted,
2081
+ * so retaining points cannot recreate already paid currency. */
2082
+ export declare const resolvePiggyReset: (input: PiggyRuleContext, slot?: PiggyResetPolicy) => Readonly<{
2083
+ remaining: string;
2084
+ amount: string;
2085
+ }>;
2086
+
2087
+ /** Detaches custom output and preserves alternatives, floors and real references. */
2088
+ export declare const resolvePrice: (context: PriceResolverContext, resolver?: PriceResolver) => Price;
2089
+
2090
+ export declare const resolveSpendBudget: (input: SpendLimitContext, policy?: SpendLimitPolicy) => SpendBudget;
2091
+
2092
+ export declare const resolveSubscriptionDailyGrant: (input: SubscriptionDailyContext, slot?: SubscriptionDailyGrantPolicy) => Readonly<{
2093
+ eligible: boolean;
2094
+ day: number;
2095
+ }>;
2096
+
2097
+ /** A custom window may narrow the canonical period, never overlap/extend it.
2098
+ * Actual accepted entitlement/renewal identity remains the SQL owner's duty. */
2099
+ export declare const resolveSubscriptionPeriod: (input: SubscriptionPeriodContext, slot?: SubscriptionPeriodResolver) => SubscriptionWindow;
2100
+
2101
+ export declare const resolveTradeEligibility: (input: TradeEligibilityContext, policy?: TradeEligibilityPolicy) => boolean;
2102
+
2103
+ export declare const resolveTradeTax: (input: TradeTaxContext, policy?: TradeTaxPolicy) => Readonly<{
2104
+ currency: string;
2105
+ gross: string;
2106
+ net: string;
2107
+ tax: string;
2108
+ }>;
2109
+
2110
+ export declare interface ShopBuyInput {
2111
+ readonly offerId: string;
2112
+ readonly offerVersion: string;
2113
+ readonly offerDigest: string;
2114
+ readonly requestId: string;
2115
+ readonly currency?: string | undefined;
2116
+ readonly qty?: number | undefined;
2117
+ }
2118
+
2119
+ export declare const shopBuyIntent: (input: ShopBuyInput) => Readonly<{
2120
+ offerId: string;
2121
+ offerVersion: string;
2122
+ offerDigest: string;
2123
+ requestId: string;
2124
+ currency: string | null;
2125
+ qty: number;
2126
+ }>;
2127
+
2128
+ export declare interface ShopContextInput {
2129
+ readonly subject: Subject;
2130
+ readonly offer: ShopOffer;
2131
+ readonly at: number;
2132
+ }
2133
+
2134
+ export declare interface ShopContextSnapshot {
2135
+ readonly eligible: boolean;
2136
+ readonly adjustments: readonly VirtualPriceAdjustment[];
2137
+ }
2138
+
2139
+ /** Trusted external profile/segment/flag facts; never inside a replayable SQL callback. */
2140
+ export declare interface ShopContextSource {
2141
+ readonly read: (input: ShopContextInput) => Effect.Effect<ShopContextSnapshot, EconomyError>;
2142
+ }
2143
+
2144
+ export declare interface ShopCurrencyGrant {
2145
+ readonly currency: string;
2146
+ readonly amount: EconomyAmountInput;
2147
+ }
2148
+
2149
+ export declare const shopInteger: (input: unknown, minimum: number, maximum: number) => number;
2150
+
2151
+ export declare interface ShopItemGrant {
2152
+ readonly itemId: string;
2153
+ readonly qty: number;
2154
+ }
2155
+
2156
+ export declare interface ShopOffer {
2157
+ readonly id: string;
2158
+ readonly version: string;
2159
+ readonly titleKey: string;
2160
+ readonly price: Price;
2161
+ readonly items: readonly ShopItemGrant[];
2162
+ readonly currencies: readonly {
2163
+ readonly currency: string;
2164
+ readonly amount: string;
2165
+ }[];
2166
+ readonly from: number | null;
2167
+ readonly until: number | null;
2168
+ readonly segment: string | null;
2169
+ readonly flag: string | null;
2170
+ readonly countries: readonly string[];
2171
+ readonly limits: {
2172
+ readonly perPlayer: number | null;
2173
+ readonly perDay: number | null;
2174
+ readonly global: number | null;
2175
+ };
2176
+ readonly oneTime: boolean;
2177
+ readonly maxQuantity: number;
2178
+ }
2179
+
2180
+ export declare interface ShopOfferDefinition {
2181
+ readonly id: string;
2182
+ readonly version?: string | undefined;
2183
+ readonly titleKey: string;
2184
+ readonly price: PriceDefinition;
2185
+ readonly items?: readonly ShopItemGrant[] | undefined;
2186
+ readonly currencies?: readonly ShopCurrencyGrant[] | undefined;
2187
+ readonly from?: number | null | undefined;
2188
+ readonly until?: number | null | undefined;
2189
+ readonly segment?: string | null | undefined;
2190
+ readonly flag?: string | null | undefined;
2191
+ readonly countries?: readonly string[] | undefined;
2192
+ readonly limits?: {
2193
+ readonly perPlayer?: number | null | undefined;
2194
+ readonly perDay?: number | null | undefined;
2195
+ readonly global?: number | null | undefined;
2196
+ } | undefined;
2197
+ readonly oneTime?: boolean | undefined;
2198
+ readonly maxQuantity?: number | undefined;
2199
+ }
2200
+
2201
+ export declare interface ShopOfferView {
2202
+ readonly offerDigest: string;
2203
+ readonly offer: ShopOffer;
2204
+ readonly price: Price;
2205
+ }
2206
+
2207
+ export declare interface ShopOrderReceipt {
2208
+ readonly orderId: string;
2209
+ readonly offerId: string;
2210
+ readonly offerVersion: string;
2211
+ readonly offerDigest: string;
2212
+ readonly quantity: number;
2213
+ readonly at: number;
2214
+ readonly pricePaid: {
2215
+ readonly kind: 'free';
2216
+ } | {
2217
+ readonly kind: 'virtual';
2218
+ readonly currency: string;
2219
+ readonly amount: string;
2220
+ };
2221
+ readonly transfers: readonly {
2222
+ readonly txId: string;
2223
+ readonly currency: string;
2224
+ readonly amount: string;
2225
+ readonly at: number;
2226
+ }[];
2227
+ readonly grants: readonly {
2228
+ readonly operationId: string;
2229
+ readonly kind: 'grant';
2230
+ readonly changes: readonly {
2231
+ readonly instanceId: string;
2232
+ readonly delta: number;
2233
+ }[];
2234
+ readonly at: number;
2235
+ }[];
2236
+ }
2237
+
2238
+ export declare const shopPayment: (price: Price, currency: string | null, quantity: number) => ShopOrderReceipt["pricePaid"];
2239
+
2240
+ export declare interface ShopPluginOptions extends ShopRules {
2241
+ readonly inventory?: ShopStoreOptions['inventory'] | undefined;
2242
+ /** Full port replacement owns authority/receipts/privacy; no default SQL roles or fallback. */
2243
+ readonly service?: ShopService;
2244
+ readonly querySources?: {
2245
+ readonly offers: readonly string[] | undefined;
2246
+ readonly receipt: readonly string[];
2247
+ };
2248
+ }
2249
+
2250
+ export declare class ShopPort extends ShopPort_base {
2251
+ }
2252
+
2253
+ declare const ShopPort_base: Context.ServiceClass<ShopPort, "@voltro/ShopPort", ShopService>;
2254
+
2255
+ /** Nonterminal observations never authorize a new request identity or prove that no purchase can commit. */
2256
+ export declare type ShopPurchaseObservation = {
2257
+ readonly requestId: string;
2258
+ readonly state: 'not-observed' | 'pending';
2259
+ } | {
2260
+ readonly requestId: string;
2261
+ readonly state: 'fulfilled';
2262
+ readonly receipt: ShopOrderReceipt;
2263
+ };
2264
+
2265
+ export declare interface ShopRules {
2266
+ readonly offers: readonly (ShopOfferDefinition | ShopOffer)[];
2267
+ readonly priceResolver?: PriceResolver | undefined;
2268
+ readonly contextSource?: ShopContextSource | undefined;
2269
+ readonly version?: string | undefined;
2270
+ readonly systemAccount?: string | undefined;
2271
+ readonly maxOrders?: number | undefined;
2272
+ readonly maxAuditRows?: number | undefined;
2273
+ readonly now?: (() => number) | undefined;
2274
+ }
2275
+
2276
+ export declare interface ShopService {
2277
+ readonly offers: (subject: Subject) => Effect.Effect<readonly ShopOfferView[], EconomyError>;
2278
+ readonly buy: (subject: Subject, input: ShopBuyInput) => Effect.Effect<ShopOrderReceipt, EconomyError>;
2279
+ readonly receipt: (subject: Subject, input: ShopBuyInput) => Effect.Effect<ShopPurchaseObservation, EconomyError>;
2280
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
2281
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
2282
+ }
2283
+
2284
+ declare interface ShopStoreOptions extends ShopRules {
2285
+ readonly currencies: readonly CurrencyDefinition[];
2286
+ readonly realMoney?: boolean;
2287
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
2288
+ readonly inventory?: Pick<InventorySqlService, 'prepareGrant'> | undefined;
2289
+ }
2290
+
2291
+ export declare interface SpendBudget {
2292
+ readonly daily: string | null;
2293
+ readonly monthly: string | null;
2294
+ readonly allowed: boolean;
2295
+ }
2296
+
2297
+ export declare interface SpendFacts extends SpendFactsInput {
2298
+ readonly allowed: boolean;
2299
+ readonly minor: boolean;
2300
+ readonly observedAt: number;
2301
+ readonly daily?: EconomyAmountInput | null | undefined;
2302
+ readonly monthly?: EconomyAmountInput | null;
2303
+ readonly blockedUntil?: number | null;
2304
+ }
2305
+
2306
+ export declare interface SpendFactsInput {
2307
+ readonly tenantId: string;
2308
+ readonly ownerId: string;
2309
+ readonly ownerKind: 'player' | 'guild';
2310
+ readonly currency: string;
2311
+ readonly at: number;
2312
+ }
2313
+
2314
+ export declare interface SpendFactsSource {
2315
+ readonly read: (input: SpendFactsInput) => Effect.Effect<SpendFacts, EconomyError>;
2316
+ }
2317
+
2318
+ export declare interface SpendLimit {
2319
+ readonly currency: string;
2320
+ readonly daily: string | null;
2321
+ readonly monthly: string | null;
2322
+ readonly minors: {
2323
+ readonly daily: string | null;
2324
+ readonly monthly: string | null;
2325
+ } | null;
2326
+ }
2327
+
2328
+ export declare interface SpendLimitContext {
2329
+ readonly limit: SpendLimit;
2330
+ readonly facts: SpendFacts;
2331
+ readonly version: string;
2332
+ }
2333
+
2334
+ export declare interface SpendLimitDefinition {
2335
+ readonly currency: string;
2336
+ readonly daily?: EconomyAmountInput | null | undefined;
2337
+ readonly monthly?: EconomyAmountInput | null;
2338
+ readonly minors?: {
2339
+ readonly daily?: EconomyAmountInput | null | undefined;
2340
+ readonly monthly?: EconomyAmountInput | null;
2341
+ };
2342
+ }
2343
+
2344
+ export declare type SpendLimitPolicy = (input: SpendLimitContext) => SpendBudget;
2345
+
2346
+ export declare interface SpendLimitsOptions {
2347
+ readonly limits: readonly (SpendLimitDefinition | SpendLimit)[];
2348
+ readonly source: SpendFactsSource;
2349
+ readonly version: string;
2350
+ readonly policy?: SpendLimitPolicy;
2351
+ }
2352
+
2353
+ export declare interface SpendPosting {
2354
+ readonly id: string;
2355
+ readonly debit: string;
2356
+ readonly credit: string;
2357
+ readonly at: number;
2358
+ }
2359
+
2360
+ export declare interface Subscription {
2361
+ readonly id: string;
2362
+ readonly version: string;
2363
+ readonly titleKey: string;
2364
+ readonly price: Price;
2365
+ readonly period: Readonly<{
2366
+ unit: 'day' | 'week' | 'month';
2367
+ count: number;
2368
+ }>;
2369
+ readonly grants: Readonly<{
2370
+ onPurchase: SubscriptionGift;
2371
+ daily: SubscriptionGift;
2372
+ }>;
2373
+ readonly graceDays: number;
2374
+ readonly coolingOff: Readonly<{
2375
+ days: number;
2376
+ overrideReason: string | null;
2377
+ }>;
2378
+ readonly disclosure: Readonly<{
2379
+ durationKey: string;
2380
+ renewalKey: string;
2381
+ cancellationPath: string;
2382
+ }>;
2383
+ }
2384
+
2385
+ /** Consent and eligibility are application authority, never inferred from a
2386
+ * price declaration or a player boolean. No automatic provider acquisition. */
2387
+ declare interface SubscriptionAccessSource {
2388
+ readonly read: (input: {
2389
+ readonly tenantId: string;
2390
+ readonly ownerId: string;
2391
+ readonly subscription: Subscription;
2392
+ readonly at: number;
2393
+ readonly kind: 'start' | 'renew';
2394
+ }) => Effect.Effect<{
2395
+ readonly eligible: boolean;
2396
+ readonly renewalConsent: boolean;
2397
+ readonly adjustments: readonly VirtualPriceAdjustment[];
2398
+ }, EconomyError>;
2399
+ }
2400
+
2401
+ export declare interface SubscriptionActiveView {
2402
+ readonly entitlementId: string;
2403
+ readonly subscription: Subscription;
2404
+ readonly subscriptionDigest: string;
2405
+ readonly originAt: number;
2406
+ readonly periodIndex: number;
2407
+ readonly window: SubscriptionEntitlement;
2408
+ readonly currency: string | null;
2409
+ readonly renews: boolean;
2410
+ readonly cancelledAt: number | null;
2411
+ }
2412
+
2413
+ export declare interface SubscriptionCancelInput {
2414
+ readonly entitlementId: string;
2415
+ readonly requestId: string;
2416
+ }
2417
+
2418
+ export declare interface SubscriptionCancellationReceipt {
2419
+ readonly operationId: string;
2420
+ readonly entitlementId: string;
2421
+ readonly at: number;
2422
+ readonly renews: false;
2423
+ }
2424
+
2425
+ export declare interface SubscriptionDailyContext {
2426
+ readonly entitlement: SubscriptionEntitlement;
2427
+ readonly at: number;
2428
+ readonly claimedDays: readonly number[];
2429
+ readonly rulesVersion?: string;
2430
+ }
2431
+
2432
+ export declare type SubscriptionDailyGrantPolicy = (input: SubscriptionDailyContext) => boolean;
2433
+
2434
+ export declare interface SubscriptionDailyInput {
2435
+ readonly entitlementId: string;
2436
+ readonly requestId: string;
2437
+ }
2438
+
2439
+ export declare interface SubscriptionDefinition {
2440
+ readonly id: string;
2441
+ readonly version?: string | undefined;
2442
+ readonly titleKey: string;
2443
+ readonly price: PriceDefinition;
2444
+ readonly period: {
2445
+ readonly unit: 'day' | 'week' | 'month';
2446
+ readonly count: number;
2447
+ };
2448
+ readonly grants: {
2449
+ readonly onPurchase?: SubscriptionGiftDefinition;
2450
+ readonly daily?: SubscriptionGiftDefinition | undefined;
2451
+ };
2452
+ readonly graceDays?: number;
2453
+ readonly coolingOff?: {
2454
+ readonly days: number;
2455
+ readonly overrideReason?: string | null;
2456
+ };
2457
+ readonly disclosure: {
2458
+ readonly durationKey: string;
2459
+ readonly renewalKey: string;
2460
+ readonly cancellationPath: string;
2461
+ };
2462
+ }
2463
+
2464
+ export declare interface SubscriptionEntitlement {
2465
+ readonly startsAt: number;
2466
+ readonly expiresAt: number;
2467
+ readonly graceUntil: number;
2468
+ readonly state: 'active' | 'grace' | 'expired';
2469
+ }
2470
+
2471
+ export declare const subscriptionEntitlementIntent: (input: SubscriptionDailyInput | SubscriptionCancelInput) => Readonly<{
2472
+ entitlementId: string;
2473
+ requestId: string;
2474
+ }>;
2475
+
2476
+ export declare interface SubscriptionGift {
2477
+ readonly items: ShopOffer['items'];
2478
+ readonly currencies: ShopOffer['currencies'];
2479
+ }
2480
+
2481
+ export declare interface SubscriptionGiftDefinition {
2482
+ readonly items?: ShopOfferDefinition['items'] | undefined;
2483
+ readonly currencies?: ShopOfferDefinition['currencies'] | undefined;
2484
+ }
2485
+
2486
+ export declare type SubscriptionObservation = {
2487
+ readonly requestId: string;
2488
+ readonly state: 'not-observed';
2489
+ } | {
2490
+ readonly requestId: string;
2491
+ readonly state: 'fulfilled';
2492
+ readonly receipt: SubscriptionValueReceipt | SubscriptionCancellationReceipt;
2493
+ };
2494
+
2495
+ export declare interface SubscriptionPeriodContext {
2496
+ readonly subscription: Subscription;
2497
+ readonly currencies: readonly CurrencyDefinition[];
2498
+ readonly realMoney?: boolean;
2499
+ readonly originAt: number;
2500
+ readonly index: number;
2501
+ readonly rulesVersion?: string;
2502
+ }
2503
+
2504
+ export declare type SubscriptionPeriodResolver = (input: SubscriptionPeriodContext) => SubscriptionWindow;
2505
+
2506
+ export declare type SubscriptionReceiptInput = {
2507
+ readonly kind: 'start';
2508
+ readonly intent: SubscriptionStartInput;
2509
+ } | {
2510
+ readonly kind: 'renew' | 'daily' | 'cancel';
2511
+ readonly intent: SubscriptionDailyInput;
2512
+ };
2513
+
2514
+ export declare interface SubscriptionRenewInput {
2515
+ readonly tenantId: string;
2516
+ readonly ownerId: string;
2517
+ readonly entitlementId: string;
2518
+ readonly requestId: string;
2519
+ }
2520
+
2521
+ export declare const subscriptionRenewIntent: (input: SubscriptionRenewInput) => Readonly<{
2522
+ tenantId: string;
2523
+ ownerId: string;
2524
+ entitlementId: string;
2525
+ requestId: string;
2526
+ }>;
2527
+
2528
+ export declare interface SubscriptionsPluginOptions extends Omit<SubscriptionsStoreOptions, 'currencies' | 'economy' | 'realMoney' | 'accessSource'> {
2529
+ readonly accessSource?: SubscriptionsStoreOptions['accessSource'];
2530
+ readonly service?: SubscriptionsService;
2531
+ readonly querySources?: {
2532
+ readonly list: readonly string[] | undefined;
2533
+ readonly active: readonly string[];
2534
+ readonly receipt: readonly string[];
2535
+ };
2536
+ }
2537
+
2538
+ export declare class SubscriptionsPort extends SubscriptionsPort_base {
2539
+ }
2540
+
2541
+ declare const SubscriptionsPort_base: Context.ServiceClass<SubscriptionsPort, "@voltro/SubscriptionsPort", SubscriptionsService>;
2542
+
2543
+ /** Renew is a trusted server intention. Implementations must deny players and
2544
+ * enforce one accepted renewal per entitlement/period independently of nonce.
2545
+ * Calendar/daily strategies alone cannot establish durable idempotency. */
2546
+ export declare interface SubscriptionsService {
2547
+ readonly list: (subject: Subject) => Effect.Effect<readonly SubscriptionView[], EconomyError>;
2548
+ readonly active: (subject: Subject) => Effect.Effect<readonly SubscriptionActiveView[], EconomyError>;
2549
+ readonly start: (subject: Subject, input: SubscriptionStartInput) => Effect.Effect<SubscriptionValueReceipt, EconomyError>;
2550
+ readonly renew: (subject: Subject, input: SubscriptionRenewInput) => Effect.Effect<SubscriptionValueReceipt, EconomyError>;
2551
+ readonly claimDaily: (subject: Subject, input: SubscriptionDailyInput) => Effect.Effect<SubscriptionValueReceipt, EconomyError>;
2552
+ readonly cancel: (subject: Subject, input: SubscriptionCancelInput) => Effect.Effect<SubscriptionCancellationReceipt, EconomyError>;
2553
+ readonly receipt: (subject: Subject, input: SubscriptionReceiptInput) => Effect.Effect<SubscriptionObservation, EconomyError>;
2554
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
2555
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
2556
+ }
2557
+
2558
+ declare interface SubscriptionsStoreOptions {
2559
+ readonly subscriptions: readonly (SubscriptionDefinition | Subscription)[];
2560
+ readonly currencies: readonly CurrencyDefinition[];
2561
+ readonly realMoney?: boolean;
2562
+ readonly economy: Pick<EconomySqlService, 'prepareTransfer'>;
2563
+ readonly inventory?: Pick<InventorySqlService, 'prepareGrant'> | undefined;
2564
+ readonly accessSource: SubscriptionAccessSource;
2565
+ readonly version: string;
2566
+ readonly period?: SubscriptionPeriodResolver | undefined;
2567
+ readonly daily?: SubscriptionDailyGrantPolicy | undefined;
2568
+ readonly priceResolver?: PriceResolver | undefined;
2569
+ readonly systemAccount?: string | undefined;
2570
+ readonly maxHistoryRows?: number | undefined;
2571
+ readonly now?: (() => number) | undefined;
2572
+ }
2573
+
2574
+ /** Player intentions contain observed identities, never charge amounts, dates,
2575
+ * provider receipts, claimed days, entitlement state or renewal authority. */
2576
+ export declare interface SubscriptionStartInput {
2577
+ readonly subscriptionId: string;
2578
+ readonly subscriptionVersion: string;
2579
+ readonly subscriptionDigest: string;
2580
+ readonly requestId: string;
2581
+ readonly currency?: string | undefined;
2582
+ }
2583
+
2584
+ export declare const subscriptionStartIntent: (input: SubscriptionStartInput) => Readonly<{
2585
+ subscriptionId: string;
2586
+ subscriptionVersion: string;
2587
+ subscriptionDigest: string;
2588
+ requestId: string;
2589
+ currency: string | null;
2590
+ }>;
2591
+
2592
+ export declare interface SubscriptionValueReceipt {
2593
+ readonly operationId: string;
2594
+ readonly entitlementId: string;
2595
+ readonly kind: 'start' | 'renew' | 'daily';
2596
+ readonly at: number;
2597
+ readonly periodIndex: number;
2598
+ readonly day: number | null;
2599
+ readonly window: SubscriptionEntitlement;
2600
+ readonly value: ShopOrderReceipt;
2601
+ }
2602
+
2603
+ export declare interface SubscriptionView {
2604
+ readonly subscription: Subscription;
2605
+ readonly subscriptionDigest: string;
2606
+ }
2607
+
2608
+ export declare interface SubscriptionWindow {
2609
+ readonly startsAt: number;
2610
+ readonly expiresAt: number;
2611
+ }
2612
+
2613
+ export declare interface TradeAcceptInput {
2614
+ readonly tradeId: string;
2615
+ readonly tradeDigest: string;
2616
+ readonly requestId: string;
2617
+ }
2618
+
2619
+ export declare const tradeAcceptIntent: (input: TradeAcceptInput) => TradeAcceptInput;
2620
+
2621
+ declare interface TradeAuthorityAdmission {
2622
+ readonly tenantId: string;
2623
+ readonly tradeId: string;
2624
+ readonly phase: 'propose' | 'accept';
2625
+ readonly at: number;
2626
+ readonly expiresAt: number;
2627
+ readonly participants: readonly TradeParticipantAuthority[];
2628
+ }
2629
+
2630
+ /** Required real trust/sanctions facts plus an exact-store SQL revalidation unit.
2631
+ * Read/prepare execute outside replayable SQL. The unit owns admission fences;
2632
+ * no default permission, trust score or revoked-consent behavior is fabricated. */
2633
+ declare interface TradeAuthoritySource {
2634
+ readonly read: (input: {
2635
+ readonly tenantId: string;
2636
+ readonly ownerId: string;
2637
+ readonly tradeId: string;
2638
+ readonly at: number;
2639
+ }) => Effect.Effect<TradeParticipantAuthority, EconomyError>;
2640
+ readonly prepare: (input: TradeAuthorityAdmission) => Effect.Effect<PreparedSqlMutation<void>, EconomyError>;
2641
+ }
2642
+
2643
+ export declare const tradeCancelIntent: (input: {
2644
+ readonly tradeId: string;
2645
+ readonly requestId: string;
2646
+ }) => Readonly<{
2647
+ tradeId: string;
2648
+ requestId: string;
2649
+ }>;
2650
+
2651
+ export declare interface TradeCurrencyIntention {
2652
+ readonly currency: string;
2653
+ readonly amount: EconomyAmountInput;
2654
+ }
2655
+
2656
+ export declare interface TradeEligibilityContext {
2657
+ readonly tenantId: string;
2658
+ readonly proposerId: string;
2659
+ readonly accepterId: string;
2660
+ readonly tradeId: string;
2661
+ readonly proposedToId: string | null;
2662
+ readonly createdAt: number;
2663
+ readonly at: number;
2664
+ readonly expiresAt: number;
2665
+ readonly rules: TradeRules;
2666
+ readonly currencies: readonly CurrencyDefinition[];
2667
+ readonly offered: TradeLeg;
2668
+ readonly requested: TradeLeg;
2669
+ readonly proposer: TradeParticipantAuthority;
2670
+ readonly accepter: TradeParticipantAuthority;
2671
+ }
2672
+
2673
+ export declare type TradeEligibilityPolicy = (input: TradeEligibilityContext) => boolean;
2674
+
2675
+ declare interface TradeEscrowOptions {
2676
+ readonly currencies: readonly CurrencyDefinition[];
2677
+ readonly rules: TradeRulesDefinition;
2678
+ readonly taxPolicy?: TradeTaxPolicy | undefined;
2679
+ readonly economy: Pick<WalletEscrowParticipant, 'prepareEscrowReserve' | 'prepareEscrowRelease' | 'prepareEscrowTaxSettle' | 'prepareEscrowReserveTaxSettle' | 'escrow'>;
2680
+ readonly inventory?: Pick<InventorySqlService, 'prepareReserve' | 'prepareRelease' | 'prepareReservationTransfer' | 'prepareReserveTransfer' | 'reservation'> | undefined;
2681
+ readonly allowedServices?: readonly string[] | undefined;
2682
+ }
2683
+
2684
+ declare interface TradeExpiryInput {
2685
+ readonly tenantId: string;
2686
+ readonly maxTrades?: number | undefined;
2687
+ }
2688
+
2689
+ declare interface TradeExpiryResult {
2690
+ readonly capturedAt: number;
2691
+ readonly scannedRows: number;
2692
+ readonly dueTrades: number;
2693
+ /** Matching original expiry receipts observed by this call, not newly committed closes. */
2694
+ readonly expiredTrades: number;
2695
+ readonly alreadyClosedTrades: number;
2696
+ }
2697
+
2698
+ export declare interface TradeItemAuthority {
2699
+ readonly instanceId: string;
2700
+ readonly itemId: string;
2701
+ readonly qty: number;
2702
+ readonly tradable: boolean;
2703
+ readonly locked: boolean;
2704
+ readonly reservationId: string | null;
2705
+ readonly expiresAt: number | null;
2706
+ }
2707
+
2708
+ export declare interface TradeItemIntention {
2709
+ readonly instanceId: string;
2710
+ readonly qty: number;
2711
+ }
2712
+
2713
+ export declare interface TradeLeg {
2714
+ readonly items: readonly TradeItemIntention[];
2715
+ readonly currencies: readonly {
2716
+ readonly currency: string;
2717
+ readonly amount: string;
2718
+ }[];
2719
+ }
2720
+
2721
+ export declare interface TradeLegDefinition {
2722
+ readonly items: readonly TradeItemIntention[];
2723
+ readonly currencies: readonly TradeCurrencyIntention[];
2724
+ }
2725
+
2726
+ export declare type TradeObservation = {
2727
+ readonly requestId: string;
2728
+ readonly state: 'not-observed';
2729
+ } | {
2730
+ readonly requestId: string;
2731
+ readonly state: 'fulfilled';
2732
+ readonly receipt: TradeReceipt;
2733
+ };
2734
+
2735
+ export declare interface TradeParticipantAuthority {
2736
+ readonly tenantId: string;
2737
+ readonly ownerId: string;
2738
+ readonly allowed: boolean;
2739
+ readonly trustScore: number;
2740
+ readonly items: readonly TradeItemAuthority[];
2741
+ }
2742
+
2743
+ export declare interface TradeProposeInput {
2744
+ readonly toId: string | null;
2745
+ readonly offered: TradeLegDefinition;
2746
+ readonly requested: TradeLegDefinition;
2747
+ readonly durationMs: number;
2748
+ readonly requestId: string;
2749
+ }
2750
+
2751
+ export declare const tradeProposeIntent: (input: TradeProposeInput, currencies: readonly CurrencyDefinition[], rulesInput: TradeRulesDefinition) => Readonly<{
2752
+ offered: TradeLeg;
2753
+ requested: TradeLeg;
2754
+ durationMs: number;
2755
+ toId: string | null;
2756
+ requestId: string;
2757
+ }>;
2758
+
2759
+ export declare interface TradeReceipt {
2760
+ readonly operationId: string;
2761
+ readonly requestId: string;
2762
+ readonly trade: TradeView;
2763
+ }
2764
+
2765
+ export declare interface TradeRules {
2766
+ readonly version: string;
2767
+ readonly taxBps: number;
2768
+ readonly maxDurationMs: number;
2769
+ readonly minTrustScore: number;
2770
+ }
2771
+
2772
+ export declare interface TradeRulesDefinition {
2773
+ readonly version: string;
2774
+ readonly taxBps?: number;
2775
+ readonly maxDurationMs?: number;
2776
+ readonly minTrustScore?: number;
2777
+ }
2778
+
2779
+ export declare interface TradesPluginOptions extends Omit<TradeStoreOptions, 'currencies' | 'economy' | 'authority'> {
2780
+ readonly authority?: TradeStoreOptions['authority'];
2781
+ readonly service?: TradesService;
2782
+ /** Complete replacements require actual query invalidation sources. Defaults may add app facts. */
2783
+ readonly querySources?: {
2784
+ readonly mine: readonly string[] | undefined;
2785
+ readonly receipt: readonly string[];
2786
+ };
2787
+ }
2788
+
2789
+ export declare class TradesPort extends TradesPort_base {
2790
+ }
2791
+
2792
+ declare const TradesPort_base: Context.ServiceClass<TradesPort, "@voltro/TradesPort", TradesService>;
2793
+
2794
+ /** Full owning service; no default implementation or escrow installation is
2795
+ * inferred from a Tag. SQL reservation/transfer/expiry/privacy own acceptance. */
2796
+ export declare interface TradesService {
2797
+ readonly propose: (subject: Subject, input: TradeProposeInput) => Effect.Effect<TradeReceipt, EconomyError>;
2798
+ readonly accept: (subject: Subject, input: TradeAcceptInput) => Effect.Effect<TradeReceipt, EconomyError>;
2799
+ readonly cancel: (subject: Subject, input: {
2800
+ readonly tradeId: string;
2801
+ readonly requestId: string;
2802
+ }) => Effect.Effect<TradeReceipt, EconomyError>;
2803
+ readonly mine: (subject: Subject) => Effect.Effect<readonly TradeView[], EconomyError>;
2804
+ readonly receipt: (subject: Subject, input: {
2805
+ readonly requestId: string;
2806
+ }) => Effect.Effect<TradeObservation, EconomyError>;
2807
+ readonly rebuild: (subject: Subject, input: {
2808
+ readonly tenantId: string;
2809
+ readonly tradeId: string;
2810
+ }) => Effect.Effect<TradeView, EconomyError>;
2811
+ readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
2812
+ readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
2813
+ }
2814
+
2815
+ declare interface TradesSqlService extends TradesService {
2816
+ readonly expireDue: (subject: Subject, input: TradeExpiryInput) => Effect.Effect<TradeExpiryResult, EconomyError>;
2817
+ readonly expire: (subject: Subject, input: {
2818
+ readonly tenantId: string;
2819
+ readonly tradeId: string;
2820
+ }) => Effect.Effect<TradeReceipt, EconomyError>;
2821
+ }
2822
+
2823
+ declare interface TradeStoreOptions extends TradeEscrowOptions {
2824
+ readonly authority: TradeAuthoritySource;
2825
+ readonly inventory?: NonNullable<TradeEscrowOptions['inventory']> & Pick<InventorySqlService, 'reservationEvidence'> | undefined;
2826
+ readonly eligibility?: TradeEligibilityPolicy | undefined;
2827
+ readonly maxHistoryRows?: number | undefined;
2828
+ readonly now?: (() => number) | undefined;
2829
+ }
2830
+
2831
+ export declare interface TradeTaxContext {
2832
+ readonly currency: string;
2833
+ readonly amount: EconomyAmountInput;
2834
+ readonly rules: TradeRules;
2835
+ }
2836
+
2837
+ export declare type TradeTaxPolicy = (input: TradeTaxContext) => EconomyAmountInput;
2838
+
2839
+ export declare interface TradeTaxView {
2840
+ readonly leg: 'offered' | 'requested';
2841
+ readonly currency: string;
2842
+ readonly gross: string;
2843
+ readonly net: string;
2844
+ readonly tax: string;
2845
+ }
2846
+
2847
+ export declare interface TradeView {
2848
+ readonly tradeId: string;
2849
+ readonly tradeDigest: string;
2850
+ readonly proposerId: string;
2851
+ readonly toId: string | null;
2852
+ readonly offered: TradeLeg;
2853
+ readonly requested: TradeLeg;
2854
+ readonly createdAt: number;
2855
+ readonly expiresAt: number;
2856
+ readonly state: 'proposed' | 'accepted' | 'cancelled' | 'expired';
2857
+ readonly accepterId: string | null;
2858
+ readonly rulesVersion: string;
2859
+ readonly taxes: readonly TradeTaxView[];
2860
+ }
2861
+
2862
+ export declare const utcSpendWindows: (at: number) => Readonly<{
2863
+ day: Readonly<{
2864
+ from: number;
2865
+ until: number;
2866
+ }>;
2867
+ month: Readonly<{
2868
+ from: number;
2869
+ until: number;
2870
+ }>;
2871
+ }>;
2872
+
2873
+ declare const verifiedCurrentState: unique symbol;
2874
+
2875
+ /** Fresh provider observation bound to revalidated original SQL. Never copied player refund authority. */
2876
+ declare interface VerifiedIapCurrentState {
2877
+ readonly [verifiedCurrentState]: true;
2878
+ readonly orderId: string;
2879
+ }
2880
+
2881
+ /** Authenticated notice, never current purchase state or grant/refund authority. */
2882
+ declare interface VerifiedIapNotification {
2883
+ readonly [verifiedNotification]: true;
2884
+ readonly noticeId: string;
2885
+ readonly channel: IapRefundChannel;
2886
+ }
2887
+
2888
+ /** Process-local opaque evidence. A serialized object is never a verification capability. */
2889
+ declare interface VerifiedIapPurchase {
2890
+ readonly [verifiedPurchase]: true;
2891
+ readonly scope: IapScope;
2892
+ readonly offerId: string;
2893
+ readonly offerVersion: string;
2894
+ readonly requestId: string;
2895
+ readonly verifiedAt: number;
2896
+ readonly identity: string;
2897
+ readonly facts: IapTransactionFacts;
2898
+ }
2899
+
2900
+ declare const verifiedNotification: unique symbol;
2901
+
2902
+ declare const verifiedPurchase: unique symbol;
2903
+
2904
+ export declare interface VirtualPriceAdjustment {
2905
+ readonly currency: string;
2906
+ /** Inclusive integer 0..10000. */
2907
+ readonly discountBps: number;
2908
+ /** A trusted floor, enforced independently of a custom resolver. */
2909
+ readonly minimum: EconomyAmountInput;
2910
+ }
2911
+
2912
+ export declare interface VirtualPriceOption {
2913
+ readonly currency: string;
2914
+ readonly amount: EconomyAmountInput;
2915
+ }
2916
+
2917
+ declare interface WalletEscrowFundedSettlementReceipt {
2918
+ readonly reserve: EconomyReceipt;
2919
+ readonly settlement: WalletEscrowSettlementReceipt;
2920
+ }
2921
+
2922
+ declare interface WalletEscrowInput {
2923
+ readonly tenantId: string;
2924
+ readonly owner: EscrowWallet;
2925
+ readonly reservationId: string;
2926
+ readonly currency: string;
2927
+ }
2928
+
2929
+ declare type WalletEscrowObservation = {
2930
+ readonly reservationId: string;
2931
+ readonly currency: string;
2932
+ readonly state: 'not-observed';
2933
+ } | {
2934
+ readonly reservationId: string;
2935
+ readonly currency: string;
2936
+ readonly amount: string;
2937
+ readonly state: 'held' | 'released' | 'settled';
2938
+ readonly receipt: EconomyReceipt;
2939
+ readonly closingReceipt: EconomyReceipt | null;
2940
+ readonly taxReceipt: EconomyReceipt | null;
2941
+ };
2942
+
2943
+ declare interface WalletEscrowParticipant {
2944
+ readonly prepareEscrowReserve: (subject: Subject, input: WalletEscrowReserveInput) => Effect.Effect<PreparedSqlMutation<EconomyReceipt>, EconomyError>;
2945
+ readonly prepareEscrowRelease: (subject: Subject, input: WalletEscrowInput) => Effect.Effect<PreparedSqlMutation<EconomyReceipt>, EconomyError>;
2946
+ /** Whole gross payout; use prepareEscrowTaxSettle for an exact net/sink split. */
2947
+ readonly prepareEscrowSettle: (subject: Subject, input: WalletEscrowSettleInput) => Effect.Effect<PreparedSqlMutation<EconomyReceipt>, EconomyError>;
2948
+ readonly prepareEscrowTaxSettle: (subject: Subject, input: WalletEscrowTaxSettleInput) => Effect.Effect<PreparedSqlMutation<WalletEscrowSettlementReceipt>, EconomyError>;
2949
+ readonly prepareEscrowReserveTaxSettle: (subject: Subject, input: WalletEscrowReserveTaxSettleInput) => Effect.Effect<PreparedSqlMutation<WalletEscrowFundedSettlementReceipt>, EconomyError>;
2950
+ readonly escrow: (subject: Subject, input: WalletEscrowInput) => Effect.Effect<WalletEscrowObservation, EconomyError>;
2951
+ }
2952
+
2953
+ declare interface WalletEscrowReserveInput extends WalletEscrowInput {
2954
+ readonly amount: EconomyAmountInput;
2955
+ }
2956
+
2957
+ declare interface WalletEscrowReserveTaxSettleInput extends WalletEscrowReserveInput {
2958
+ readonly to: EscrowWallet;
2959
+ readonly taxAmount: EconomyAmountInput;
2960
+ readonly taxAccountId?: string | undefined;
2961
+ }
2962
+
2963
+ declare interface WalletEscrowSettleInput extends WalletEscrowInput {
2964
+ readonly to: EscrowWallet;
2965
+ }
2966
+
2967
+ declare interface WalletEscrowSettlementReceipt {
2968
+ readonly reservationId: string;
2969
+ readonly currency: string;
2970
+ readonly gross: string;
2971
+ readonly net: string;
2972
+ readonly tax: string;
2973
+ readonly payout: EconomyReceipt | null;
2974
+ readonly taxReceipt: EconomyReceipt | null;
2975
+ }
2976
+
2977
+ declare interface WalletEscrowTaxSettleInput extends WalletEscrowSettleInput {
2978
+ readonly taxAmount: EconomyAmountInput;
2979
+ readonly taxAccountId?: string | undefined;
2980
+ }
2981
+
2982
+ export declare type WalletOwnerKind = 'player' | 'guild';
2983
+
2984
+ export { }