@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,183 @@
|
|
|
1
|
+
import { economyError as e } from "./errors.js";
|
|
2
|
+
import { dataList as t, dataObject as n, identifier as r } from "./capture.js";
|
|
3
|
+
import { captureIapPaidAmount as i, iapTimestamp as a } from "./iap.js";
|
|
4
|
+
import { canonicalDataJson as o } from "./canonicalDataJson.js";
|
|
5
|
+
import { captureIapTransactionFacts as s } from "./iapVerification.server.js";
|
|
6
|
+
import { iapProviderRecord as c, iapProviderText as l, iapProviderTimestamp as u } from "./iapProviderCapture.server.js";
|
|
7
|
+
import { createHash as d } from "node:crypto";
|
|
8
|
+
// src/googleIapSubscription.server.ts
|
|
9
|
+
var f = (i) => {
|
|
10
|
+
let a = t(i === void 0 ? [] : i, 4096).map((e) => {
|
|
11
|
+
let t = n(e, [
|
|
12
|
+
"offerId",
|
|
13
|
+
"offerVersion",
|
|
14
|
+
"basePlanId",
|
|
15
|
+
"storeOfferId"
|
|
16
|
+
]);
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
offerId: r(t.offerId),
|
|
19
|
+
offerVersion: r(t.offerVersion),
|
|
20
|
+
basePlanId: r(t.basePlanId),
|
|
21
|
+
storeOfferId: t.storeOfferId === null ? null : r(t.storeOfferId)
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
if (new Set(a.map((e) => e.offerId + ":" + e.offerVersion)).size !== a.length) throw e("invalid_input");
|
|
25
|
+
return Object.freeze(a);
|
|
26
|
+
}, p = (t, n, r) => {
|
|
27
|
+
let i = c(t), a = r.find((e) => e.offerId === n.product.offer.id && e.offerVersion === n.product.offer.version);
|
|
28
|
+
if (!a || i.basePlanId !== a.basePlanId || (i.offerId ?? null) !== a.storeOfferId) throw e("forbidden");
|
|
29
|
+
}, m = (t) => {
|
|
30
|
+
let n = c(t), r = n.units ?? "0", a = n.nanos ?? 0;
|
|
31
|
+
if (typeof r != "string" || !/^(0|[1-9][0-9]{0,18})$/.test(r) || typeof a != "number" || !Number.isInteger(a) || a < 0 || a > 999999999) throw e("invalid_record");
|
|
32
|
+
let o = i({
|
|
33
|
+
currency: n.currencyCode,
|
|
34
|
+
units: (BigInt(r) * 1000000000n + BigInt(a)).toString(),
|
|
35
|
+
scale: 9
|
|
36
|
+
});
|
|
37
|
+
if (!o) throw e("invalid_record");
|
|
38
|
+
return o;
|
|
39
|
+
}, h = (e) => d("sha256").update(e).digest("hex"), g = (t) => {
|
|
40
|
+
if (t === "ACKNOWLEDGEMENT_STATE_PENDING") return "pending";
|
|
41
|
+
if (t === "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED") return "acknowledged";
|
|
42
|
+
throw e("invalid_record");
|
|
43
|
+
}, _ = (n, r, i, a) => {
|
|
44
|
+
let o = c(n), s = c(o.externalAccountIdentifiers);
|
|
45
|
+
if (r.product.kind !== "subscription" || s.obfuscatedExternalAccountId !== r.accountToken || o.linkedPurchaseToken !== void 0 || o.outOfAppPurchaseContext !== void 0 || (i === "sandbox" ? o.testPurchase === void 0 : o.testPurchase !== void 0)) throw e("forbidden");
|
|
46
|
+
if (o.testPurchase !== void 0 && c(o.testPurchase), typeof o.subscriptionState != "string" || ![
|
|
47
|
+
"SUBSCRIPTION_STATE_PENDING",
|
|
48
|
+
"SUBSCRIPTION_STATE_ACTIVE",
|
|
49
|
+
"SUBSCRIPTION_STATE_PAUSED",
|
|
50
|
+
"SUBSCRIPTION_STATE_IN_GRACE_PERIOD",
|
|
51
|
+
"SUBSCRIPTION_STATE_ON_HOLD",
|
|
52
|
+
"SUBSCRIPTION_STATE_CANCELED",
|
|
53
|
+
"SUBSCRIPTION_STATE_EXPIRED",
|
|
54
|
+
"SUBSCRIPTION_STATE_PENDING_PURCHASE_CANCELED"
|
|
55
|
+
].includes(o.subscriptionState)) throw e("invalid_record");
|
|
56
|
+
let d = t(o.lineItems, 32, "invalid_record");
|
|
57
|
+
if (d.length !== 1) throw e("forbidden");
|
|
58
|
+
let f = c(d[0]);
|
|
59
|
+
if (f.productId !== r.product.storeProductId || f.itemReplacement !== void 0 || f.deferredItemReplacement !== void 0 || f.deferredItemRemoval !== void 0 || f.autoRenewingPlan === void 0 == (f.prepaidPlan === void 0)) throw e("forbidden");
|
|
60
|
+
return c(f.autoRenewingPlan ?? f.prepaidPlan), p(f.offerDetails, r, a), Object.freeze({
|
|
61
|
+
orderId: l(f.latestSuccessfulOrderId, 512),
|
|
62
|
+
expiresAt: u(f.expiryTime),
|
|
63
|
+
startedAt: u(o.startTime),
|
|
64
|
+
acknowledgement: g(o.acknowledgementState),
|
|
65
|
+
state: o.subscriptionState
|
|
66
|
+
});
|
|
67
|
+
}, v = (n, r, i, a, l, d, f = i.orderId) => {
|
|
68
|
+
let g = c(n);
|
|
69
|
+
if (g.orderId !== f || g.purchaseToken !== r.intent.receipt || ![
|
|
70
|
+
"PROCESSED",
|
|
71
|
+
"PARTIALLY_REFUNDED",
|
|
72
|
+
"REFUNDED"
|
|
73
|
+
].includes(String(g.state))) throw e("forbidden");
|
|
74
|
+
let _ = t(g.lineItems, 32, "invalid_record");
|
|
75
|
+
if (_.length !== 1) throw e("forbidden");
|
|
76
|
+
let v = c(_[0]), y = c(v.subscriptionDetails), b = c(g.orderHistory);
|
|
77
|
+
if (v.productId !== r.product.storeProductId || v.oneTimePurchaseDetails !== void 0 || v.paidAppDetails !== void 0) throw e("forbidden");
|
|
78
|
+
p(y, r, d);
|
|
79
|
+
let x = c(y.offerPhaseDetails), S = [
|
|
80
|
+
"baseDetails",
|
|
81
|
+
"introductoryPriceDetails",
|
|
82
|
+
"freeTrialDetails"
|
|
83
|
+
].filter((e) => x[e] !== void 0);
|
|
84
|
+
if (S.length !== 1 || x.prorationPeriodDetails !== void 0) throw e("forbidden");
|
|
85
|
+
c(x[S[0]]);
|
|
86
|
+
let C = m(g.total), w = m(v.total);
|
|
87
|
+
if (o(C) !== o(w)) throw e("invalid_record");
|
|
88
|
+
let T = u(c(b.processedEvent).eventTime), E = u(y.servicePeriodStartTime), D = u(y.servicePeriodEndTime), O = u(g.lastEventTime);
|
|
89
|
+
if (E > T || T >= D || i.startedAt > E || O < T || O > r.at || b.cancellationEvent !== void 0) throw e("invalid_record");
|
|
90
|
+
let k = s({
|
|
91
|
+
channel: "android",
|
|
92
|
+
environment: l,
|
|
93
|
+
applicationId: a,
|
|
94
|
+
transactionId: f,
|
|
95
|
+
originalTransactionId: h(r.intent.receipt),
|
|
96
|
+
storeProductId: r.product.storeProductId,
|
|
97
|
+
kind: "subscription",
|
|
98
|
+
quantity: 1,
|
|
99
|
+
purchasedAt: T,
|
|
100
|
+
expiresAt: D,
|
|
101
|
+
paid: C,
|
|
102
|
+
acknowledgement: i.acknowledgement,
|
|
103
|
+
consumption: "none"
|
|
104
|
+
});
|
|
105
|
+
return Object.freeze({
|
|
106
|
+
facts: k,
|
|
107
|
+
startsAt: E,
|
|
108
|
+
orderState: g.state,
|
|
109
|
+
history: b,
|
|
110
|
+
lastEventAt: O,
|
|
111
|
+
currentExpiresAt: i.expiresAt
|
|
112
|
+
});
|
|
113
|
+
}, y = (n, r, i, a, o, s) => {
|
|
114
|
+
let c = _(n, i, o, s), l = v(r, i, c, a, o, s);
|
|
115
|
+
if (c.state !== "SUBSCRIPTION_STATE_ACTIVE" && c.state !== "SUBSCRIPTION_STATE_CANCELED" || l.orderState !== "PROCESSED" || l.history.refundEvent !== void 0 || t(l.history.partialRefundEvents ?? [], 1e3, "invalid_record").length !== 0 || l.facts.expiresAt === null || c.expiresAt < l.facts.expiresAt || l.facts.expiresAt <= i.at || l.startsAt > i.at) throw e("forbidden");
|
|
116
|
+
return l.facts;
|
|
117
|
+
}, b = (t, n) => {
|
|
118
|
+
if (n <= 0n || t <= 0n || t >= n) throw e("invalid_record");
|
|
119
|
+
let r = t, i = n;
|
|
120
|
+
for (; i;) {
|
|
121
|
+
let e = r % i;
|
|
122
|
+
r = i, i = e;
|
|
123
|
+
}
|
|
124
|
+
let a = t / r, o = n / r;
|
|
125
|
+
if (o > 100000n) throw e("limit_exceeded");
|
|
126
|
+
return {
|
|
127
|
+
numerator: Number(a),
|
|
128
|
+
denominator: Number(o)
|
|
129
|
+
};
|
|
130
|
+
}, x = (n, r, i, s, d, f, p) => {
|
|
131
|
+
let g = a(f);
|
|
132
|
+
if (g < i.at) throw e("invalid_record");
|
|
133
|
+
let y = l(c(i.material.detail).purchaseToken, 4096);
|
|
134
|
+
if (h(y) !== i.facts.originalTransactionId) throw e("forbidden");
|
|
135
|
+
let x = {
|
|
136
|
+
scope: i.scope,
|
|
137
|
+
product: i.product,
|
|
138
|
+
accountToken: i.accountToken,
|
|
139
|
+
at: g,
|
|
140
|
+
intent: {
|
|
141
|
+
channel: "android",
|
|
142
|
+
offerId: i.product.offer.id,
|
|
143
|
+
offerVersion: i.product.offer.version,
|
|
144
|
+
requestId: i.orderId,
|
|
145
|
+
receipt: y
|
|
146
|
+
}
|
|
147
|
+
}, S = v(r, x, _(n, x, d, p), s, d, p, i.facts.transactionId), C = (e) => o({
|
|
148
|
+
...e,
|
|
149
|
+
acknowledgement: "none",
|
|
150
|
+
consumption: "none"
|
|
151
|
+
});
|
|
152
|
+
if (C(S.facts) !== C(i.facts)) throw e("conflict");
|
|
153
|
+
let w = 0, T = 1, E = null;
|
|
154
|
+
if (S.orderState === "REFUNDED") {
|
|
155
|
+
if (E = u(c(S.history.refundEvent).eventTime), E < i.facts.purchasedAt || E > S.lastEventAt || E > g) throw e("invalid_record");
|
|
156
|
+
w = 1;
|
|
157
|
+
} else {
|
|
158
|
+
if (S.history.refundEvent !== void 0) throw e("invalid_record");
|
|
159
|
+
let n = 0n;
|
|
160
|
+
for (let r of t(S.history.partialRefundEvents ?? [], 1e3, "invalid_record")) {
|
|
161
|
+
let t = c(r);
|
|
162
|
+
if (t.state === "PENDING") continue;
|
|
163
|
+
if (t.state !== "PROCESSED_SUCCESSFULLY") throw e("invalid_record");
|
|
164
|
+
let a = u(t.processTime), o = m(c(t.refundDetails).total);
|
|
165
|
+
if (a < i.facts.purchasedAt || a > S.lastEventAt || a > g || o.currency !== S.facts.paid?.currency || BigInt(o.units) <= 0n) throw e("invalid_record");
|
|
166
|
+
n += BigInt(o.units);
|
|
167
|
+
}
|
|
168
|
+
if (S.orderState === "PARTIALLY_REFUNDED") {
|
|
169
|
+
let e = b(n, BigInt(S.facts.paid.units));
|
|
170
|
+
w = e.numerator, T = e.denominator;
|
|
171
|
+
} else if (n !== 0n) throw e("invalid_record");
|
|
172
|
+
}
|
|
173
|
+
return Object.freeze({
|
|
174
|
+
orderId: i.orderId,
|
|
175
|
+
channel: "android",
|
|
176
|
+
state: w === 0 ? "active" : w === T ? "revoked" : "partially-refunded",
|
|
177
|
+
refundNumerator: w,
|
|
178
|
+
refundDenominator: T,
|
|
179
|
+
observedAt: g,
|
|
180
|
+
revokedAt: E
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
export { _ as captureGoogleSubscription, v as captureGoogleSubscriptionOrder, f as captureGoogleSubscriptionPlans, y as projectGoogleIapSubscription, x as projectGoogleIapSubscriptionCurrentState };
|
package/dist/iap.d.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { Context } from 'effect';
|
|
2
|
+
import { Effect } from 'effect';
|
|
3
|
+
import { PluginPrivacyTarget } from '@voltro/protocol';
|
|
4
|
+
import { Schema } from 'effect';
|
|
5
|
+
import { Subject } from '@voltro/protocol';
|
|
6
|
+
import { YieldableError } from 'effect/Cause';
|
|
7
|
+
|
|
8
|
+
/** A decoded observation, not purchase/completion authority. */
|
|
9
|
+
export declare const captureIapCompletionReceipt: (input: unknown) => IapCompletionReceipt;
|
|
10
|
+
|
|
11
|
+
/** Shared strict wire/recovery admission; private notices and financial movements are absent. */
|
|
12
|
+
export declare const captureIapObservation: (input: unknown) => IapOrderObservation;
|
|
13
|
+
|
|
14
|
+
/** Wire admission only. Actual own financial authority is the SQL receipt service. */
|
|
15
|
+
export declare const captureIapOrderReceipt: (input: unknown) => IapOrderReceipt;
|
|
16
|
+
|
|
17
|
+
export declare const captureIapPaidAmount: (input: unknown) => IapPaidAmount | null;
|
|
18
|
+
|
|
19
|
+
export declare const captureIapRefundDisposition: (input: unknown) => IapRefundDisposition;
|
|
20
|
+
|
|
21
|
+
export declare const captureIapScope: (input: IapScope) => IapScope;
|
|
22
|
+
|
|
23
|
+
export declare const captureIapService: (input: IapService) => IapService;
|
|
24
|
+
|
|
25
|
+
export declare const captureIapSubscriptionPeriod: (input: unknown) => IapSubscriptionPeriod;
|
|
26
|
+
|
|
27
|
+
/** Hash the canonical string representation used by SQL; no raw receipt is retained in the result. */
|
|
28
|
+
export declare const createIapReceiptReference: (input: IapReceiptIntent) => Promise<IapReceiptReference>;
|
|
29
|
+
|
|
30
|
+
declare interface CurrencyDefinition {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly kind: 'soft' | 'hard';
|
|
33
|
+
readonly cap?: EconomyAmountInput;
|
|
34
|
+
readonly premium?: boolean;
|
|
35
|
+
readonly display?: {
|
|
36
|
+
readonly nameKey: string;
|
|
37
|
+
} | null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Declarations, not store prices, purchase evidence or grant authority. */
|
|
41
|
+
export declare const defineIapCatalog: (definitions: readonly IapProductDefinition[], currencies: readonly CurrencyDefinition[], realMoney?: boolean) => readonly IapProduct[];
|
|
42
|
+
|
|
43
|
+
declare type EconomyAmountInput = string | number | bigint;
|
|
44
|
+
|
|
45
|
+
declare type EconomyChannel = 'web' | 'ios' | 'android' | 'steam';
|
|
46
|
+
|
|
47
|
+
/** Redacted codes; never carries owners, amounts or provider payloads. */
|
|
48
|
+
declare class EconomyError extends EconomyError_base {
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
declare const EconomyError_base: Schema.Class<EconomyError, Schema.TaggedStruct<"EconomyError", {
|
|
52
|
+
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"]>;
|
|
53
|
+
}>, YieldableError>;
|
|
54
|
+
|
|
55
|
+
export declare const iapChannel: (value: unknown) => EconomyChannel;
|
|
56
|
+
|
|
57
|
+
export declare interface IapCompletionReceipt {
|
|
58
|
+
readonly orderId: string;
|
|
59
|
+
readonly channel: EconomyChannel;
|
|
60
|
+
readonly operation: 'acknowledge' | 'consume' | 'finalize' | 'finish';
|
|
61
|
+
readonly observedAt: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export declare type IapEnvironment = 'sandbox' | 'production';
|
|
65
|
+
|
|
66
|
+
export declare const iapEnvironment: (value: unknown) => IapEnvironment;
|
|
67
|
+
|
|
68
|
+
export declare type IapOrderObservation = {
|
|
69
|
+
readonly requestId: string;
|
|
70
|
+
readonly state: 'not-observed' | 'pending';
|
|
71
|
+
} | {
|
|
72
|
+
readonly requestId: string;
|
|
73
|
+
readonly state: 'fulfilled';
|
|
74
|
+
readonly receipt: IapOrderReceipt;
|
|
75
|
+
readonly refund?: IapRefundDisposition;
|
|
76
|
+
} | {
|
|
77
|
+
readonly requestId: string;
|
|
78
|
+
readonly state: 'partially-refunded' | 'refunded';
|
|
79
|
+
readonly receipt: IapOrderReceipt;
|
|
80
|
+
readonly refund: IapRefundDisposition;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export declare interface IapOrderReceipt {
|
|
84
|
+
readonly orderId: string;
|
|
85
|
+
readonly offerId: string;
|
|
86
|
+
readonly offerVersion: string;
|
|
87
|
+
readonly quantity: number;
|
|
88
|
+
readonly at: number;
|
|
89
|
+
readonly pricePaid: IapPaidAmount | null;
|
|
90
|
+
readonly transfers: readonly {
|
|
91
|
+
readonly txId: string;
|
|
92
|
+
readonly currency: string;
|
|
93
|
+
readonly amount: string;
|
|
94
|
+
readonly at: number;
|
|
95
|
+
}[];
|
|
96
|
+
readonly grants: readonly {
|
|
97
|
+
readonly operationId: string;
|
|
98
|
+
readonly kind: 'grant';
|
|
99
|
+
readonly changes: readonly {
|
|
100
|
+
readonly instanceId: string;
|
|
101
|
+
readonly delta: number;
|
|
102
|
+
}[];
|
|
103
|
+
readonly at: number;
|
|
104
|
+
}[];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Provider units retain their own decimal scale. Reference prices are never substituted. */
|
|
108
|
+
export declare interface IapPaidAmount {
|
|
109
|
+
readonly currency: string;
|
|
110
|
+
readonly units: string;
|
|
111
|
+
readonly scale: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export declare class IapPort extends IapPort_base {
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
declare const IapPort_base: Context.ServiceClass<IapPort, "@voltro/IapPort", IapService>;
|
|
118
|
+
|
|
119
|
+
export declare interface IapProduct {
|
|
120
|
+
readonly offer: ShopOffer;
|
|
121
|
+
readonly channel: EconomyChannel;
|
|
122
|
+
readonly kind: IapProductKind;
|
|
123
|
+
readonly storeProductId: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export declare interface IapProductDefinition {
|
|
127
|
+
readonly offer: ShopOfferDefinition | ShopOffer;
|
|
128
|
+
readonly channel: EconomyChannel;
|
|
129
|
+
readonly kind: IapProductKind;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export declare type IapProductKind = 'consumable' | 'non-consumable' | 'subscription';
|
|
133
|
+
|
|
134
|
+
export declare const iapProductKind: (value: unknown) => IapProductKind;
|
|
135
|
+
|
|
136
|
+
/** Console preparation only. Does not provision products or assert actual prices. */
|
|
137
|
+
export declare const iapProductsCsv: (catalog: readonly IapProduct[]) => string;
|
|
138
|
+
|
|
139
|
+
export declare interface IapReceiptIntent {
|
|
140
|
+
readonly channel: EconomyChannel;
|
|
141
|
+
readonly offerId: string;
|
|
142
|
+
readonly offerVersion: string;
|
|
143
|
+
readonly requestId: string;
|
|
144
|
+
/** Opaque store evidence. Never log or persist this in player receipts. */
|
|
145
|
+
readonly receipt: string;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Players select an offer and submit evidence; no owner, price or state. */
|
|
149
|
+
export declare const iapReceiptIntent: (input: IapReceiptIntent) => IapReceiptIntent;
|
|
150
|
+
|
|
151
|
+
/** Read-only original-intention reference. Never send raw receipts in query parameters. */
|
|
152
|
+
export declare interface IapReceiptReference {
|
|
153
|
+
readonly channel: EconomyChannel;
|
|
154
|
+
readonly offerId: string;
|
|
155
|
+
readonly offerVersion: string;
|
|
156
|
+
readonly requestId: string;
|
|
157
|
+
readonly receiptDigest: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export declare const iapReceiptReference: (input: IapReceiptReference) => IapReceiptReference;
|
|
161
|
+
|
|
162
|
+
/** Accepted SQL refund history only. This projection never authorizes a grant or completion. */
|
|
163
|
+
export declare interface IapRefundDisposition {
|
|
164
|
+
readonly sequence: number;
|
|
165
|
+
readonly state: 'active' | 'partially-refunded' | 'revoked';
|
|
166
|
+
readonly refundNumerator: number;
|
|
167
|
+
readonly refundDenominator: number;
|
|
168
|
+
readonly observedAt: number;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export declare interface IapScope {
|
|
172
|
+
readonly tenantId: string;
|
|
173
|
+
readonly ownerId: string;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export declare interface IapService {
|
|
177
|
+
readonly redeem: (subject: Subject, input: IapReceiptIntent) => Effect.Effect<IapOrderReceipt, EconomyError>;
|
|
178
|
+
readonly receipt: (subject: Subject, input: IapReceiptReference) => Effect.Effect<IapOrderObservation, EconomyError>;
|
|
179
|
+
readonly exportSubject: (target: PluginPrivacyTarget) => Effect.Effect<unknown, EconomyError>;
|
|
180
|
+
readonly eraseSubject: (target: PluginPrivacyTarget) => Effect.Effect<void, EconomyError>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** An accepted store period, not a fresh provider observation or financial capability. */
|
|
184
|
+
export declare interface IapSubscriptionPeriod {
|
|
185
|
+
readonly orderId: string;
|
|
186
|
+
readonly offerId: string;
|
|
187
|
+
readonly offerVersion: string;
|
|
188
|
+
readonly channel: EconomyChannel;
|
|
189
|
+
readonly startsAt: number;
|
|
190
|
+
readonly expiresAt: number;
|
|
191
|
+
readonly refund: IapRefundDisposition | null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export declare const iapTimestamp: (value: unknown) => number;
|
|
195
|
+
|
|
196
|
+
export declare interface IapTransactionFacts {
|
|
197
|
+
readonly channel: EconomyChannel;
|
|
198
|
+
readonly environment: IapEnvironment;
|
|
199
|
+
readonly applicationId: string;
|
|
200
|
+
readonly transactionId: string;
|
|
201
|
+
readonly originalTransactionId: string | null;
|
|
202
|
+
readonly storeProductId: string;
|
|
203
|
+
readonly kind: IapProductKind;
|
|
204
|
+
readonly quantity: number;
|
|
205
|
+
readonly purchasedAt: number;
|
|
206
|
+
readonly expiresAt: number | null;
|
|
207
|
+
readonly paid: IapPaidAmount | null;
|
|
208
|
+
readonly acknowledgement: 'none' | 'pending' | 'acknowledged';
|
|
209
|
+
readonly consumption: 'none' | 'available' | 'consumed';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare type Price = {
|
|
213
|
+
readonly kind: 'virtual';
|
|
214
|
+
readonly options: readonly ResolvedVirtualPriceOption[];
|
|
215
|
+
} | ({
|
|
216
|
+
readonly kind: 'real';
|
|
217
|
+
} & RealPriceDefinition) | {
|
|
218
|
+
readonly kind: 'mixed';
|
|
219
|
+
readonly real: RealPriceDefinition;
|
|
220
|
+
readonly virtual: readonly ResolvedVirtualPriceOption[];
|
|
221
|
+
} | {
|
|
222
|
+
readonly kind: 'free';
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
declare type PriceDefinition = {
|
|
226
|
+
readonly kind: 'virtual';
|
|
227
|
+
readonly options: readonly VirtualPriceOption[];
|
|
228
|
+
} | ({
|
|
229
|
+
readonly kind: 'real';
|
|
230
|
+
} & RealPriceDefinition) | {
|
|
231
|
+
readonly kind: 'mixed';
|
|
232
|
+
readonly real: RealPriceDefinition;
|
|
233
|
+
readonly virtual: readonly VirtualPriceOption[];
|
|
234
|
+
} | {
|
|
235
|
+
readonly kind: 'free';
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
declare interface RealPriceDefinition {
|
|
239
|
+
/** Integer minor-unit references; verified store receipts remain authoritative. */
|
|
240
|
+
readonly prices: Readonly<Record<string, number>>;
|
|
241
|
+
readonly storeProductIds: Partial<Readonly<Record<EconomyChannel, string>>>;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
declare interface ResolvedVirtualPriceOption {
|
|
245
|
+
readonly currency: string;
|
|
246
|
+
readonly amount: string;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
declare interface ShopCurrencyGrant {
|
|
250
|
+
readonly currency: string;
|
|
251
|
+
readonly amount: EconomyAmountInput;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
declare interface ShopItemGrant {
|
|
255
|
+
readonly itemId: string;
|
|
256
|
+
readonly qty: number;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
declare interface ShopOffer {
|
|
260
|
+
readonly id: string;
|
|
261
|
+
readonly version: string;
|
|
262
|
+
readonly titleKey: string;
|
|
263
|
+
readonly price: Price;
|
|
264
|
+
readonly items: readonly ShopItemGrant[];
|
|
265
|
+
readonly currencies: readonly {
|
|
266
|
+
readonly currency: string;
|
|
267
|
+
readonly amount: string;
|
|
268
|
+
}[];
|
|
269
|
+
readonly from: number | null;
|
|
270
|
+
readonly until: number | null;
|
|
271
|
+
readonly segment: string | null;
|
|
272
|
+
readonly flag: string | null;
|
|
273
|
+
readonly countries: readonly string[];
|
|
274
|
+
readonly limits: {
|
|
275
|
+
readonly perPlayer: number | null;
|
|
276
|
+
readonly perDay: number | null;
|
|
277
|
+
readonly global: number | null;
|
|
278
|
+
};
|
|
279
|
+
readonly oneTime: boolean;
|
|
280
|
+
readonly maxQuantity: number;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
declare interface ShopOfferDefinition {
|
|
284
|
+
readonly id: string;
|
|
285
|
+
readonly version?: string | undefined;
|
|
286
|
+
readonly titleKey: string;
|
|
287
|
+
readonly price: PriceDefinition;
|
|
288
|
+
readonly items?: readonly ShopItemGrant[] | undefined;
|
|
289
|
+
readonly currencies?: readonly ShopCurrencyGrant[] | undefined;
|
|
290
|
+
readonly from?: number | null | undefined;
|
|
291
|
+
readonly until?: number | null | undefined;
|
|
292
|
+
readonly segment?: string | null | undefined;
|
|
293
|
+
readonly flag?: string | null | undefined;
|
|
294
|
+
readonly countries?: readonly string[] | undefined;
|
|
295
|
+
readonly limits?: {
|
|
296
|
+
readonly perPlayer?: number | null | undefined;
|
|
297
|
+
readonly perDay?: number | null | undefined;
|
|
298
|
+
readonly global?: number | null | undefined;
|
|
299
|
+
} | undefined;
|
|
300
|
+
readonly oneTime?: boolean | undefined;
|
|
301
|
+
readonly maxQuantity?: number | undefined;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
declare interface VirtualPriceOption {
|
|
305
|
+
readonly currency: string;
|
|
306
|
+
readonly amount: EconomyAmountInput;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export { }
|