@voltro/plugin-economy 0.0.0-stage → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24492 -0
- package/LICENSE +61 -0
- package/README.md +2719 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +9841 -0
- package/dist/amount.js +20 -0
- package/dist/appleIap.server.js +262 -0
- package/dist/appleIapNotifications.server.js +162 -0
- package/dist/appleIapTrust.server.js +30 -0
- package/dist/bundleValue.server.js +112 -0
- package/dist/canonicalDataJson.js +10 -0
- package/dist/capture.js +53 -0
- package/dist/codePort.fixture.js +123 -0
- package/dist/codeStore.server.js +439 -0
- package/dist/codeTables.entity.js +43 -0
- package/dist/codes.d.ts +150 -0
- package/dist/codes.js +82 -0
- package/dist/components.d.ts +397 -0
- package/dist/components.js +283 -0
- package/dist/consistency.server.js +115 -0
- package/dist/containerStore.server.js +687 -0
- package/dist/containerStore.testFixtures.js +75 -0
- package/dist/containerTables.entity.js +45 -0
- package/dist/containers.d.ts +311 -0
- package/dist/containers.fixture.js +128 -0
- package/dist/containers.js +214 -0
- package/dist/containers.server.js +39 -0
- package/dist/containersPort.fixture.js +74 -0
- package/dist/currency.js +32 -0
- package/dist/declarationFixtures.js +61 -0
- package/dist/economy-app/events/economy.refundReversed.event.ts +1 -0
- package/dist/economy-app/events/economy.refunded.event.ts +1 -0
- package/dist/economyPort.fixture.js +124 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +21 -0
- package/dist/events.d.ts +46 -0
- package/dist/events.js +1 -0
- package/dist/googleIap.server.js +391 -0
- package/dist/googleIapNotifications.server.js +130 -0
- package/dist/googleIapSubscription.server.js +183 -0
- package/dist/iap.d.ts +309 -0
- package/dist/iap.js +303 -0
- package/dist/iap.testFixtures.js +144 -0
- package/dist/iapAccountTables.entity.js +39 -0
- package/dist/iapAccounts.server.js +200 -0
- package/dist/iapBinding.server.js +523 -0
- package/dist/iapCheckout.server.js +97 -0
- package/dist/iapCompletion.server.js +55 -0
- package/dist/iapCurrentState.server.js +107 -0
- package/dist/iapCurrentState.testFixtures.js +22 -0
- package/dist/iapCurrentStatePort.fixture.js +63 -0
- package/dist/iapEntitlements.d.ts +79 -0
- package/dist/iapEntitlements.js +57 -0
- package/dist/iapEntitlements.server.js +48 -0
- package/dist/iapEntitlementsBinding.server.js +105 -0
- package/dist/iapEntitlementsPort.fixture.js +80 -0
- package/dist/iapInstalledEntitlements.testFixtures.js +75 -0
- package/dist/iapInstalledNotifications.testFixtures.js +93 -0
- package/dist/iapInventoryRefunds.server.js +261 -0
- package/dist/iapNotificationCustodyPort.fixture.js +67 -0
- package/dist/iapNotificationPort.fixture.js +73 -0
- package/dist/iapNotificationProcessor.server.js +134 -0
- package/dist/iapNotificationProcessor.testFixtures.js +63 -0
- package/dist/iapNotificationProcessorPort.fixture.js +55 -0
- package/dist/iapNotificationSchedule.server.js +69 -0
- package/dist/iapNotificationStore.server.js +352 -0
- package/dist/iapNotificationStore.testFixtures.js +31 -0
- package/dist/iapNotificationTables.entity.js +48 -0
- package/dist/iapNotificationTarget.server.js +36 -0
- package/dist/iapNotificationTarget.testFixtures.js +29 -0
- package/dist/iapNotifications.d.ts +644 -0
- package/dist/iapNotifications.js +6 -0
- package/dist/iapNotifications.server.js +95 -0
- package/dist/iapNotificationsBinding.server.js +232 -0
- package/dist/iapNotificationsSystemPort.fixture.js +50 -0
- package/dist/iapPlugin.testFixtures.js +59 -0
- package/dist/iapPort.fixture.js +74 -0
- package/dist/iapProviderCapture.server.js +17 -0
- package/dist/iapRecovery.d.ts +146 -0
- package/dist/iapRecovery.js +89 -0
- package/dist/iapRefundEventDelivery.server.js +82 -0
- package/dist/iapRefundEvents.js +44 -0
- package/dist/iapRefundEventsPort.fixture.js +59 -0
- package/dist/iapRefundPort.fixture.js +54 -0
- package/dist/iapRefundTables.entity.js +55 -0
- package/dist/iapRefunds.d.ts +755 -0
- package/dist/iapRefunds.js +6 -0
- package/dist/iapRefunds.server.js +553 -0
- package/dist/iapRefunds.testFixtures.js +64 -0
- package/dist/iapSpendAdmission.server.js +98 -0
- package/dist/iapStore.server.js +740 -0
- package/dist/iapStore.testFixtures.js +127 -0
- package/dist/iapTables.entity.js +80 -0
- package/dist/iapVerification.server.js +120 -0
- package/dist/index.d.ts +2984 -0
- package/dist/index.js +15 -0
- package/dist/intentionRecovery.js +133 -0
- package/dist/ledger.js +77 -0
- package/dist/loyalty.d.ts +274 -0
- package/dist/loyalty.fixture.js +92 -0
- package/dist/loyalty.js +311 -0
- package/dist/loyaltyBinding.server.js +203 -0
- package/dist/loyaltyPort.fixture.js +86 -0
- package/dist/loyaltyShopSource.server.js +90 -0
- package/dist/loyaltyStore.server.js +552 -0
- package/dist/loyaltyStore.testFixtures.js +82 -0
- package/dist/loyaltyTables.entity.js +49 -0
- package/dist/offerMerchandising.fixture.js +114 -0
- package/dist/offerMerchandising.js +282 -0
- package/dist/offerPolicies.d.ts +441 -0
- package/dist/offerPolicies.fixture.js +53 -0
- package/dist/offerPolicies.js +267 -0
- package/dist/piggyBanks.d.ts +272 -0
- package/dist/piggyBanks.fixture.js +70 -0
- package/dist/piggyBanks.js +200 -0
- package/dist/piggyBinding.server.js +204 -0
- package/dist/piggyPort.fixture.js +72 -0
- package/dist/piggyStore.server.js +610 -0
- package/dist/piggyStore.testFixtures.js +97 -0
- package/dist/piggyTables.entity.js +40 -0
- package/dist/plugin.js +1047 -0
- package/dist/port.js +12 -0
- package/dist/price.d.ts +99 -0
- package/dist/price.js +143 -0
- package/dist/purchaseRecovery.js +55 -0
- package/dist/reports.server.js +114 -0
- package/dist/rpc.d.ts +3201 -0
- package/dist/rpc.js +1200 -0
- package/dist/sanctionsTradeAuthority.server.js +79 -0
- package/dist/server.d.ts +3856 -0
- package/dist/server.js +43 -0
- package/dist/shop.d.ts +279 -0
- package/dist/shop.js +195 -0
- package/dist/shop.testFixtures.js +113 -0
- package/dist/shopPort.fixture.js +71 -0
- package/dist/shopPresentation.js +67 -0
- package/dist/shopStore.server.js +623 -0
- package/dist/shopTables.entity.js +62 -0
- package/dist/shopUiCopy.js +56 -0
- package/dist/spendLimits.d.ts +140 -0
- package/dist/spendLimits.fixture.js +52 -0
- package/dist/spendLimits.js +154 -0
- package/dist/spendLimitsPort.fixture.js +119 -0
- package/dist/subscriptionBinding.server.js +210 -0
- package/dist/subscriptionStore.server.js +642 -0
- package/dist/subscriptionStore.testFixtures.js +71 -0
- package/dist/subscriptionTables.entity.js +36 -0
- package/dist/subscriptions.d.ts +394 -0
- package/dist/subscriptions.fixture.js +96 -0
- package/dist/subscriptions.js +212 -0
- package/dist/subscriptionsPort.fixture.js +75 -0
- package/dist/systemFixtures.js +88 -0
- package/dist/tables.entity.js +82 -0
- package/dist/testing.d.ts +4615 -0
- package/dist/testing.js +29 -0
- package/dist/tradeAuthority.server.js +171 -0
- package/dist/tradeBinding.server.js +200 -0
- package/dist/tradeComponents.js +341 -0
- package/dist/tradeEscrow.server.js +231 -0
- package/dist/tradeEscrow.testFixtures.js +132 -0
- package/dist/tradeExpiry.server.js +42 -0
- package/dist/tradeRecovery.js +47 -0
- package/dist/tradeStore.server.js +749 -0
- package/dist/tradeStore.testFixtures.js +72 -0
- package/dist/tradeTables.entity.js +65 -0
- package/dist/tradeUiCopy.js +78 -0
- package/dist/trades.d.ts +246 -0
- package/dist/trades.fixture.js +102 -0
- package/dist/trades.js +288 -0
- package/dist/tradesPort.fixture.js +93 -0
- package/dist/walletEscrow.js +105 -0
- package/dist/walletEscrow.server.js +375 -0
- package/dist/walletKeys.server.js +4 -0
- package/dist/walletStore.js +570 -0
- package/dist/web.d.ts +2257 -0
- package/dist/web.js +8 -0
- package/package.json +161 -4
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { Schema } from 'effect';
|
|
3
|
+
import { Subject } from '@voltro/protocol';
|
|
4
|
+
import { YieldableError } from 'effect/Cause';
|
|
5
|
+
|
|
6
|
+
export declare interface Bundle {
|
|
7
|
+
readonly offer: ShopOffer;
|
|
8
|
+
readonly parts: readonly {
|
|
9
|
+
readonly offer: ShopOffer;
|
|
10
|
+
readonly qty: number;
|
|
11
|
+
}[];
|
|
12
|
+
readonly showValue: 'sumOfParts';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export declare interface BundleDefinition {
|
|
16
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
17
|
+
readonly parts: readonly {
|
|
18
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
19
|
+
readonly qty: number;
|
|
20
|
+
}[];
|
|
21
|
+
readonly showValue: 'sumOfParts';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export declare interface BundlePriceReceipt {
|
|
25
|
+
readonly offerId: string;
|
|
26
|
+
readonly offerVersion: string;
|
|
27
|
+
readonly referenceId: string;
|
|
28
|
+
readonly observedAt: number;
|
|
29
|
+
readonly price: Price;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export declare interface BundleValueContext {
|
|
33
|
+
readonly bundle: Bundle;
|
|
34
|
+
readonly currencies: readonly CurrencyDefinition[];
|
|
35
|
+
readonly realMoney?: boolean;
|
|
36
|
+
readonly at: number;
|
|
37
|
+
readonly maxPriceAgeMs: number;
|
|
38
|
+
readonly prices: readonly BundlePriceReceipt[];
|
|
39
|
+
readonly bundlePrice: Price;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare const captureFlashTriggerReceipt: (input: unknown) => FlashTriggerReceipt;
|
|
43
|
+
|
|
44
|
+
declare interface CurrencyDefinition {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly kind: 'soft' | 'hard';
|
|
47
|
+
readonly cap?: EconomyAmountInput;
|
|
48
|
+
readonly premium?: boolean;
|
|
49
|
+
readonly display?: {
|
|
50
|
+
readonly nameKey: string;
|
|
51
|
+
} | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Deterministic affinity only, not a security randomizer. The trusted identity
|
|
55
|
+
* source must preserve its canonical key across account upgrades/merges. */
|
|
56
|
+
export declare const defaultExperimentBucket: ExperimentBucket;
|
|
57
|
+
|
|
58
|
+
/** A trusted accepted event fixes the start; refreshing cannot create a fresh
|
|
59
|
+
* window. The source owns original-event persistence and revocation. */
|
|
60
|
+
export declare const defaultFlashTriggerPolicy: FlashTriggerPolicy;
|
|
61
|
+
|
|
62
|
+
/** Simple novelty + declared play-style affinity. Stable rotation tie-breaking
|
|
63
|
+
* is a merchandising rule, never security randomness or account identity. */
|
|
64
|
+
export declare const defaultPersonalizedOfferSelector: PersonalizedOfferSelector;
|
|
65
|
+
|
|
66
|
+
/** A value comparison must describe exactly the bundle's actual grants, without
|
|
67
|
+
* inventing an exchange rate between currencies or a discounted anchor. */
|
|
68
|
+
export declare const defineBundle: (input: BundleDefinition | Bundle, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => Bundle;
|
|
69
|
+
|
|
70
|
+
export declare const defineFlashOffer: (input: FlashOfferDefinition | FlashOffer, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => FlashOffer;
|
|
71
|
+
|
|
72
|
+
/** Variants use real distinct immutable offers, never a forged storefront price.
|
|
73
|
+
* Real/mixed variants must have distinct products for every configured channel. */
|
|
74
|
+
export declare const defineOfferExperiment: (input: OfferExperimentDefinition | OfferExperiment, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => OfferExperiment;
|
|
75
|
+
|
|
76
|
+
export declare const definePersonalizedOffers: (input: PersonalizedOffersDefinition | PersonalizedOffers, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => PersonalizedOffers;
|
|
77
|
+
|
|
78
|
+
/** One actual Shop declaration/writer. The first-purchase multiplier becomes
|
|
79
|
+
* immutable content; one-time counters own acceptance, never a client flag. */
|
|
80
|
+
export declare const defineStarterPack: (input: StarterPackDefinition | StarterPack, currencies: readonly CurrencyDefinition[], realMoney?: boolean) => StarterPack;
|
|
81
|
+
|
|
82
|
+
declare type EconomyAmountInput = string | number | bigint;
|
|
83
|
+
|
|
84
|
+
declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
|
|
85
|
+
|
|
86
|
+
/** Redacted codes; never carries owners, amounts or provider payloads. */
|
|
87
|
+
declare class EconomyError extends EconomyError_base {
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
|
|
91
|
+
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"]>;
|
|
92
|
+
}>, YieldableError>;
|
|
93
|
+
|
|
94
|
+
export declare type ExperimentBucket = (input: OfferExperimentContext) => string;
|
|
95
|
+
|
|
96
|
+
export declare interface FlashOffer {
|
|
97
|
+
readonly id: string;
|
|
98
|
+
readonly version: string;
|
|
99
|
+
readonly offer: ShopOffer;
|
|
100
|
+
readonly triggerId: string;
|
|
101
|
+
readonly durationMs: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export declare interface FlashOfferContext {
|
|
105
|
+
readonly flash: FlashOffer;
|
|
106
|
+
readonly currencies: readonly CurrencyDefinition[];
|
|
107
|
+
readonly realMoney?: boolean;
|
|
108
|
+
readonly tenantId: string;
|
|
109
|
+
readonly ownerId: string;
|
|
110
|
+
readonly at: number;
|
|
111
|
+
readonly trigger: FlashTriggerReceipt | null;
|
|
112
|
+
readonly rulesVersion?: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export declare interface FlashOfferDefinition {
|
|
116
|
+
readonly id: string;
|
|
117
|
+
readonly version?: string | undefined;
|
|
118
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
119
|
+
readonly triggerId: string;
|
|
120
|
+
readonly durationMs: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export declare type FlashTriggerPolicy = (context: FlashOfferContext) => FlashWindow | null;
|
|
124
|
+
|
|
125
|
+
export declare interface FlashTriggerReceipt {
|
|
126
|
+
readonly tenantId: string;
|
|
127
|
+
readonly ownerId: string;
|
|
128
|
+
readonly authorityId: string;
|
|
129
|
+
readonly eventId: string;
|
|
130
|
+
readonly triggerId: string;
|
|
131
|
+
readonly acceptedAt: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export declare interface FlashWindow {
|
|
135
|
+
readonly from: number;
|
|
136
|
+
readonly until: number;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export declare interface OfferExperiment {
|
|
140
|
+
readonly id: string;
|
|
141
|
+
readonly version: string;
|
|
142
|
+
readonly from: number;
|
|
143
|
+
readonly until: number;
|
|
144
|
+
readonly variants: readonly {
|
|
145
|
+
readonly id: string;
|
|
146
|
+
readonly weight: number;
|
|
147
|
+
readonly offers: readonly ShopOffer[];
|
|
148
|
+
}[];
|
|
149
|
+
readonly metrics: readonly string[];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export declare interface OfferExperimentContext {
|
|
153
|
+
readonly experiment: OfferExperiment;
|
|
154
|
+
readonly tenantId: string;
|
|
155
|
+
readonly key: string;
|
|
156
|
+
readonly at: number;
|
|
157
|
+
readonly currencies: readonly CurrencyDefinition[];
|
|
158
|
+
readonly realMoney?: boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export declare interface OfferExperimentDefinition {
|
|
162
|
+
readonly id: string;
|
|
163
|
+
readonly version?: string | undefined;
|
|
164
|
+
readonly from: number;
|
|
165
|
+
readonly until: number;
|
|
166
|
+
readonly variants: readonly {
|
|
167
|
+
readonly id: string;
|
|
168
|
+
readonly weight: number;
|
|
169
|
+
readonly offers: readonly (ShopOfferDefinition | ShopOffer)[];
|
|
170
|
+
}[];
|
|
171
|
+
readonly metrics: readonly string[];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Composes the existing trusted ShopContextSource. No new price, grant, counter,
|
|
175
|
+
* persistence or fallback writer; ordinary Shop still pins accepted intent. */
|
|
176
|
+
export declare const offerPolicyContextSource: (input: OfferPolicyOptions) => ShopContextSource;
|
|
177
|
+
|
|
178
|
+
export declare interface OfferPolicyFacts {
|
|
179
|
+
readonly eligible: boolean;
|
|
180
|
+
readonly adjustments: readonly VirtualPriceAdjustment[];
|
|
181
|
+
readonly firstSessionAt: number;
|
|
182
|
+
readonly experimentKey: string;
|
|
183
|
+
readonly personalization?: {
|
|
184
|
+
readonly ownedItemIds: readonly string[];
|
|
185
|
+
readonly playStyles: readonly string[];
|
|
186
|
+
};
|
|
187
|
+
readonly flashTriggers?: readonly {
|
|
188
|
+
readonly flashId: string;
|
|
189
|
+
readonly trigger: FlashTriggerReceipt | null;
|
|
190
|
+
}[];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export declare interface OfferPolicyOptions {
|
|
194
|
+
readonly currencies: readonly CurrencyDefinition[];
|
|
195
|
+
readonly realMoney?: boolean;
|
|
196
|
+
readonly source: OfferPolicySource;
|
|
197
|
+
readonly starterPacks?: readonly StarterPack[];
|
|
198
|
+
readonly experiments?: readonly OfferExperiment[];
|
|
199
|
+
readonly experimentBucket?: ExperimentBucket;
|
|
200
|
+
readonly personalized?: readonly PersonalizedOffers[];
|
|
201
|
+
readonly flashOffers?: readonly FlashOffer[];
|
|
202
|
+
readonly personalizedSelector?: PersonalizedOfferSelector;
|
|
203
|
+
readonly flashTrigger?: FlashTriggerPolicy;
|
|
204
|
+
readonly policyVersion?: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export declare interface OfferPolicySource {
|
|
208
|
+
readonly read: (input: Readonly<{
|
|
209
|
+
tenantId: string;
|
|
210
|
+
ownerId: string;
|
|
211
|
+
offer: ShopOffer;
|
|
212
|
+
at: number;
|
|
213
|
+
}>) => Effect.Effect<OfferPolicyFacts, EconomyError>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export declare interface PersonalizedOfferContext {
|
|
217
|
+
readonly personalized: PersonalizedOffers;
|
|
218
|
+
readonly currencies: readonly CurrencyDefinition[];
|
|
219
|
+
readonly realMoney?: boolean;
|
|
220
|
+
readonly tenantId: string;
|
|
221
|
+
readonly key: string;
|
|
222
|
+
readonly at: number;
|
|
223
|
+
readonly ownedItemIds: readonly string[];
|
|
224
|
+
readonly playStyles: readonly string[];
|
|
225
|
+
readonly rulesVersion?: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export declare interface PersonalizedOffers {
|
|
229
|
+
readonly id: string;
|
|
230
|
+
readonly version: string;
|
|
231
|
+
readonly slots: number;
|
|
232
|
+
readonly rotationMs: number;
|
|
233
|
+
readonly rotationAnchorAt: number;
|
|
234
|
+
readonly pool: readonly {
|
|
235
|
+
readonly offer: ShopOffer;
|
|
236
|
+
readonly affinities: readonly string[];
|
|
237
|
+
}[];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export declare interface PersonalizedOffersDefinition {
|
|
241
|
+
readonly id: string;
|
|
242
|
+
readonly version?: string | undefined;
|
|
243
|
+
readonly slots: number;
|
|
244
|
+
readonly rotationMs: number;
|
|
245
|
+
readonly rotationAnchorAt: number;
|
|
246
|
+
readonly pool: readonly {
|
|
247
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
248
|
+
readonly affinities?: readonly string[];
|
|
249
|
+
}[];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export declare type PersonalizedOfferSelector = (input: PersonalizedSelectorContext) => readonly string[];
|
|
253
|
+
|
|
254
|
+
export declare interface PersonalizedSelectorContext extends PersonalizedOfferContext {
|
|
255
|
+
readonly rotation: number;
|
|
256
|
+
readonly rulesVersion: string;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
declare type Price = {
|
|
260
|
+
readonly kind: 'virtual';
|
|
261
|
+
readonly options: readonly ResolvedVirtualPriceOption[];
|
|
262
|
+
} | ({
|
|
263
|
+
readonly kind: 'real';
|
|
264
|
+
} & RealPriceDefinition) | {
|
|
265
|
+
readonly kind: 'mixed';
|
|
266
|
+
readonly real: RealPriceDefinition;
|
|
267
|
+
readonly virtual: readonly ResolvedVirtualPriceOption[];
|
|
268
|
+
} | {
|
|
269
|
+
readonly kind: 'free';
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
declare type PriceDefinition = {
|
|
273
|
+
readonly kind: 'virtual';
|
|
274
|
+
readonly options: readonly VirtualPriceOption[];
|
|
275
|
+
} | ({
|
|
276
|
+
readonly kind: 'real';
|
|
277
|
+
} & RealPriceDefinition) | {
|
|
278
|
+
readonly kind: 'mixed';
|
|
279
|
+
readonly real: RealPriceDefinition;
|
|
280
|
+
readonly virtual: readonly VirtualPriceOption[];
|
|
281
|
+
} | {
|
|
282
|
+
readonly kind: 'free';
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export declare const projectBundleValue: (input: BundleValueContext) => Readonly<{
|
|
286
|
+
offerId: string;
|
|
287
|
+
offerVersion: string;
|
|
288
|
+
comparison: "sumOfParts";
|
|
289
|
+
capturedAt: number;
|
|
290
|
+
sources: readonly Readonly<{
|
|
291
|
+
offerId: string;
|
|
292
|
+
offerVersion: string;
|
|
293
|
+
referenceId: string;
|
|
294
|
+
observedAt: number;
|
|
295
|
+
}>[];
|
|
296
|
+
comparisons: readonly {
|
|
297
|
+
readonly kind: "virtual" | "real";
|
|
298
|
+
readonly currency: string;
|
|
299
|
+
readonly partsValue: string;
|
|
300
|
+
readonly bundleAmount: string;
|
|
301
|
+
readonly saving: string;
|
|
302
|
+
}[];
|
|
303
|
+
}>;
|
|
304
|
+
|
|
305
|
+
declare interface RealPriceDefinition {
|
|
306
|
+
/** Integer minor-unit references; verified store receipts remain authoritative. */
|
|
307
|
+
readonly prices: Readonly<Record<string, number>>;
|
|
308
|
+
readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
declare interface ResolvedVirtualPriceOption {
|
|
312
|
+
readonly currency: string;
|
|
313
|
+
readonly amount: string;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export declare const resolveFlashOffer: (input: FlashOfferContext, policy?: FlashTriggerPolicy) => Readonly<{
|
|
317
|
+
id: string;
|
|
318
|
+
version: string;
|
|
319
|
+
offer: ShopOffer;
|
|
320
|
+
trigger: FlashTriggerReceipt;
|
|
321
|
+
from: number;
|
|
322
|
+
until: number;
|
|
323
|
+
}> | null;
|
|
324
|
+
|
|
325
|
+
export declare const resolveOfferExperiment: (input: OfferExperimentContext, slot?: ExperimentBucket) => Readonly<{
|
|
326
|
+
experimentId: string;
|
|
327
|
+
version: string;
|
|
328
|
+
variantId: string;
|
|
329
|
+
offers: readonly ShopOffer[];
|
|
330
|
+
}> | null;
|
|
331
|
+
|
|
332
|
+
export declare const resolvePersonalizedOffers: (input: PersonalizedOfferContext, selector?: PersonalizedOfferSelector) => Readonly<{
|
|
333
|
+
id: string;
|
|
334
|
+
version: string;
|
|
335
|
+
rotation: number;
|
|
336
|
+
from: number;
|
|
337
|
+
until: number;
|
|
338
|
+
offers: readonly ShopOffer[];
|
|
339
|
+
}> | null;
|
|
340
|
+
|
|
341
|
+
declare interface ShopContextInput {
|
|
342
|
+
readonly subject: Subject;
|
|
343
|
+
readonly offer: ShopOffer;
|
|
344
|
+
readonly at: number;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
declare interface ShopContextSnapshot {
|
|
348
|
+
readonly eligible: boolean;
|
|
349
|
+
readonly adjustments: readonly VirtualPriceAdjustment[];
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Trusted external profile/segment/flag facts; never inside a replayable SQL callback. */
|
|
353
|
+
declare interface ShopContextSource {
|
|
354
|
+
readonly read: (input: ShopContextInput) => Effect.Effect<ShopContextSnapshot, EconomyError>;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
declare interface ShopCurrencyGrant {
|
|
358
|
+
readonly currency: string;
|
|
359
|
+
readonly amount: EconomyAmountInput;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
declare interface ShopItemGrant {
|
|
363
|
+
readonly itemId: string;
|
|
364
|
+
readonly qty: number;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
declare interface ShopOffer {
|
|
368
|
+
readonly id: string;
|
|
369
|
+
readonly version: string;
|
|
370
|
+
readonly titleKey: string;
|
|
371
|
+
readonly price: Price;
|
|
372
|
+
readonly items: readonly ShopItemGrant[];
|
|
373
|
+
readonly currencies: readonly {
|
|
374
|
+
readonly currency: string;
|
|
375
|
+
readonly amount: string;
|
|
376
|
+
}[];
|
|
377
|
+
readonly from: number | null;
|
|
378
|
+
readonly until: number | null;
|
|
379
|
+
readonly segment: string | null;
|
|
380
|
+
readonly flag: string | null;
|
|
381
|
+
readonly countries: readonly string[];
|
|
382
|
+
readonly limits: {
|
|
383
|
+
readonly perPlayer: number | null;
|
|
384
|
+
readonly perDay: number | null;
|
|
385
|
+
readonly global: number | null;
|
|
386
|
+
};
|
|
387
|
+
readonly oneTime: boolean;
|
|
388
|
+
readonly maxQuantity: number;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
declare interface ShopOfferDefinition {
|
|
392
|
+
readonly id: string;
|
|
393
|
+
readonly version?: string | undefined;
|
|
394
|
+
readonly titleKey: string;
|
|
395
|
+
readonly price: PriceDefinition;
|
|
396
|
+
readonly items?: readonly ShopItemGrant[] | undefined;
|
|
397
|
+
readonly currencies?: readonly ShopCurrencyGrant[] | undefined;
|
|
398
|
+
readonly from?: number | null | undefined;
|
|
399
|
+
readonly until?: number | null | undefined;
|
|
400
|
+
readonly segment?: string | null | undefined;
|
|
401
|
+
readonly flag?: string | null | undefined;
|
|
402
|
+
readonly countries?: readonly string[] | undefined;
|
|
403
|
+
readonly limits?: {
|
|
404
|
+
readonly perPlayer?: number | null | undefined;
|
|
405
|
+
readonly perDay?: number | null | undefined;
|
|
406
|
+
readonly global?: number | null | undefined;
|
|
407
|
+
} | undefined;
|
|
408
|
+
readonly oneTime?: boolean | undefined;
|
|
409
|
+
readonly maxQuantity?: number | undefined;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
export declare interface StarterPack {
|
|
413
|
+
readonly offer: ShopOffer;
|
|
414
|
+
readonly expiresAfterMs: number;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export declare const starterPackAvailable: (pack: StarterPack, firstSessionAt: number, at: number) => boolean;
|
|
418
|
+
|
|
419
|
+
export declare interface StarterPackDefinition {
|
|
420
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
421
|
+
readonly expiresAfterMs: number;
|
|
422
|
+
readonly bonus?: {
|
|
423
|
+
readonly currency: string;
|
|
424
|
+
readonly multiplier: number;
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
declare interface VirtualPriceAdjustment {
|
|
429
|
+
readonly currency: string;
|
|
430
|
+
/** Inclusive integer 0..10000. */
|
|
431
|
+
readonly discountBps: number;
|
|
432
|
+
/** A trusted floor, enforced independently of a custom resolver. */
|
|
433
|
+
readonly minimum: EconomyAmountInput;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
declare interface VirtualPriceOption {
|
|
437
|
+
readonly currency: string;
|
|
438
|
+
readonly amount: EconomyAmountInput;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export { }
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defaultExperimentBucket as e, defineOfferExperiment as t, resolveOfferExperiment as n } from "./offerPolicies.js";
|
|
2
|
+
import { Effect as r } from "effect";
|
|
3
|
+
// src/offerPolicies.fixture.ts
|
|
4
|
+
var i = () => {
|
|
5
|
+
let e = [{
|
|
6
|
+
id: "test.gold",
|
|
7
|
+
kind: "soft"
|
|
8
|
+
}], n = t({
|
|
9
|
+
id: "test.experiment",
|
|
10
|
+
from: 0,
|
|
11
|
+
until: 864e5,
|
|
12
|
+
metrics: ["purchase.completed"],
|
|
13
|
+
variants: ["a", "b"].map((e, t) => ({
|
|
14
|
+
id: e,
|
|
15
|
+
weight: 1,
|
|
16
|
+
offers: [{
|
|
17
|
+
id: "offer." + e,
|
|
18
|
+
titleKey: "test.offer",
|
|
19
|
+
price: {
|
|
20
|
+
kind: "virtual",
|
|
21
|
+
options: [{
|
|
22
|
+
currency: "test.gold",
|
|
23
|
+
amount: t ? "9" : "7"
|
|
24
|
+
}]
|
|
25
|
+
},
|
|
26
|
+
currencies: [{
|
|
27
|
+
currency: "test.gold",
|
|
28
|
+
amount: "1"
|
|
29
|
+
}]
|
|
30
|
+
}]
|
|
31
|
+
}))
|
|
32
|
+
}, e);
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
experiment: n,
|
|
35
|
+
currencies: e,
|
|
36
|
+
tenantId: "fixture",
|
|
37
|
+
key: "canonical.a",
|
|
38
|
+
at: 1,
|
|
39
|
+
realMoney: !1
|
|
40
|
+
});
|
|
41
|
+
}, a = i(), o = Object.freeze({
|
|
42
|
+
kind: "slot",
|
|
43
|
+
defaultImplementation: e,
|
|
44
|
+
defaultProbe: {
|
|
45
|
+
run: () => r.sync(() => n(a)?.variantId),
|
|
46
|
+
expected: "b"
|
|
47
|
+
},
|
|
48
|
+
overrideProbe: {
|
|
49
|
+
run: () => r.sync(() => n(a, () => "a")?.variantId),
|
|
50
|
+
expected: "a"
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
export { o as experimentBucketSystemFixture, i as offerExperimentFixture };
|