@chipmobilesdk/rn-payment 0.6.0 → 0.7.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 +111 -0
- package/README.md +1 -1
- package/lib/commonjs/adapter/createStoreProvider.js +110 -0
- package/lib/commonjs/adapter/createStoreProvider.js.map +1 -0
- package/lib/commonjs/adapter/iap-adapter.js +393 -0
- package/lib/commonjs/adapter/iap-adapter.js.map +1 -0
- package/lib/commonjs/adapter/iapShapes.js +169 -0
- package/lib/commonjs/adapter/iapShapes.js.map +1 -0
- package/lib/commonjs/adapter/port.js +6 -0
- package/lib/commonjs/adapter/port.js.map +1 -0
- package/lib/commonjs/config/types.js +2 -0
- package/lib/commonjs/config/types.js.map +1 -0
- package/lib/commonjs/config/validate.js +181 -0
- package/lib/commonjs/config/validate.js.map +1 -0
- package/lib/commonjs/core/mutex.js +31 -0
- package/lib/commonjs/core/mutex.js.map +1 -0
- package/lib/commonjs/core/retry.js +37 -0
- package/lib/commonjs/core/retry.js.map +1 -0
- package/lib/commonjs/core/timers.js +207 -0
- package/lib/commonjs/core/timers.js.map +1 -0
- package/lib/commonjs/diagnostics/errors.js +83 -0
- package/lib/commonjs/diagnostics/errors.js.map +1 -0
- package/lib/commonjs/diagnostics/events.js +126 -0
- package/lib/commonjs/diagnostics/events.js.map +1 -0
- package/lib/commonjs/diagnostics/messageKeys.js +70 -0
- package/lib/commonjs/diagnostics/messageKeys.js.map +1 -0
- package/lib/commonjs/engine/connection.js +189 -0
- package/lib/commonjs/engine/connection.js.map +1 -0
- package/lib/commonjs/engine/engine.js +279 -0
- package/lib/commonjs/engine/engine.js.map +1 -0
- package/lib/commonjs/engine/finalize.js +325 -0
- package/lib/commonjs/engine/finalize.js.map +1 -0
- package/lib/commonjs/engine/foreground.js +26 -0
- package/lib/commonjs/engine/foreground.js.map +1 -0
- package/lib/commonjs/engine/internals.js +31 -0
- package/lib/commonjs/engine/internals.js.map +1 -0
- package/lib/commonjs/engine/pending.js +102 -0
- package/lib/commonjs/engine/pending.js.map +1 -0
- package/lib/commonjs/engine/products.js +198 -0
- package/lib/commonjs/engine/products.js.map +1 -0
- package/lib/commonjs/engine/purchase.js +395 -0
- package/lib/commonjs/engine/purchase.js.map +1 -0
- package/lib/commonjs/engine/purchaseFailure.js +77 -0
- package/lib/commonjs/engine/purchaseFailure.js.map +1 -0
- package/lib/commonjs/engine/receiptValidation.js +90 -0
- package/lib/commonjs/engine/receiptValidation.js.map +1 -0
- package/lib/commonjs/engine/state.js +201 -0
- package/lib/commonjs/engine/state.js.map +1 -0
- package/lib/commonjs/engine/subscriptions.js +122 -0
- package/lib/commonjs/engine/subscriptions.js.map +1 -0
- package/lib/commonjs/engine/sync.js +163 -0
- package/lib/commonjs/engine/sync.js.map +1 -0
- package/lib/commonjs/entitlements/aggregate.js +212 -0
- package/lib/commonjs/entitlements/aggregate.js.map +1 -0
- package/lib/commonjs/entitlements/mapping.js +41 -0
- package/lib/commonjs/entitlements/mapping.js.map +1 -0
- package/lib/commonjs/entitlements/policy.js +110 -0
- package/lib/commonjs/entitlements/policy.js.map +1 -0
- package/lib/commonjs/index.js +266 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/persistence/mmkv-store.js +149 -0
- package/lib/commonjs/persistence/mmkv-store.js.map +1 -0
- package/lib/commonjs/persistence/snapshot.js +229 -0
- package/lib/commonjs/persistence/snapshot.js.map +1 -0
- package/lib/commonjs/react/PaymentProvider.js +96 -0
- package/lib/commonjs/react/PaymentProvider.js.map +1 -0
- package/lib/commonjs/react/hooks.js +202 -0
- package/lib/commonjs/react/hooks.js.map +1 -0
- package/lib/commonjs/testing/conformance.js +136 -0
- package/lib/commonjs/testing/conformance.js.map +1 -0
- package/lib/commonjs/testing/fakeStore.js +281 -0
- package/lib/commonjs/testing/fakeStore.js.map +1 -0
- package/lib/commonjs/testing/index.js +45 -0
- package/lib/commonjs/testing/index.js.map +1 -0
- package/lib/module/adapter/createStoreProvider.js +106 -0
- package/lib/module/adapter/createStoreProvider.js.map +1 -0
- package/lib/module/adapter/iap-adapter.js +383 -0
- package/lib/module/adapter/iap-adapter.js.map +1 -0
- package/lib/module/adapter/iapShapes.js +160 -0
- package/lib/module/adapter/iapShapes.js.map +1 -0
- package/lib/module/adapter/port.js +4 -0
- package/lib/module/adapter/port.js.map +1 -0
- package/lib/module/config/types.js +2 -0
- package/lib/module/config/types.js.map +1 -0
- package/lib/module/config/validate.js +175 -0
- package/lib/module/config/validate.js.map +1 -0
- package/lib/module/core/mutex.js +22 -0
- package/lib/module/core/mutex.js.map +1 -0
- package/lib/module/core/retry.js +33 -0
- package/lib/module/core/retry.js.map +1 -0
- package/lib/module/core/timers.js +198 -0
- package/lib/module/core/timers.js.map +1 -0
- package/lib/module/diagnostics/errors.js +76 -0
- package/lib/module/diagnostics/errors.js.map +1 -0
- package/lib/module/diagnostics/events.js +117 -0
- package/lib/module/diagnostics/events.js.map +1 -0
- package/lib/module/diagnostics/messageKeys.js +64 -0
- package/lib/module/diagnostics/messageKeys.js.map +1 -0
- package/lib/module/engine/connection.js +185 -0
- package/lib/module/engine/connection.js.map +1 -0
- package/lib/module/engine/engine.js +274 -0
- package/lib/module/engine/engine.js.map +1 -0
- package/lib/module/engine/finalize.js +322 -0
- package/lib/module/engine/finalize.js.map +1 -0
- package/lib/module/engine/foreground.js +21 -0
- package/lib/module/engine/foreground.js.map +1 -0
- package/lib/module/engine/internals.js +26 -0
- package/lib/module/engine/internals.js.map +1 -0
- package/lib/module/engine/pending.js +95 -0
- package/lib/module/engine/pending.js.map +1 -0
- package/lib/module/engine/products.js +195 -0
- package/lib/module/engine/products.js.map +1 -0
- package/lib/module/engine/purchase.js +390 -0
- package/lib/module/engine/purchase.js.map +1 -0
- package/lib/module/engine/purchaseFailure.js +72 -0
- package/lib/module/engine/purchaseFailure.js.map +1 -0
- package/lib/module/engine/receiptValidation.js +87 -0
- package/lib/module/engine/receiptValidation.js.map +1 -0
- package/lib/module/engine/state.js +196 -0
- package/lib/module/engine/state.js.map +1 -0
- package/lib/module/engine/subscriptions.js +119 -0
- package/lib/module/engine/subscriptions.js.map +1 -0
- package/lib/module/engine/sync.js +158 -0
- package/lib/module/engine/sync.js.map +1 -0
- package/lib/module/entitlements/aggregate.js +204 -0
- package/lib/module/entitlements/aggregate.js.map +1 -0
- package/lib/module/entitlements/mapping.js +35 -0
- package/lib/module/entitlements/mapping.js.map +1 -0
- package/lib/module/entitlements/policy.js +104 -0
- package/lib/module/entitlements/policy.js.map +1 -0
- package/lib/module/index.js +59 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/persistence/mmkv-store.js +144 -0
- package/lib/module/persistence/mmkv-store.js.map +1 -0
- package/lib/module/persistence/snapshot.js +221 -0
- package/lib/module/persistence/snapshot.js.map +1 -0
- package/lib/module/react/PaymentProvider.js +90 -0
- package/lib/module/react/PaymentProvider.js.map +1 -0
- package/lib/module/react/hooks.js +192 -0
- package/lib/module/react/hooks.js.map +1 -0
- package/lib/module/testing/conformance.js +130 -0
- package/lib/module/testing/conformance.js.map +1 -0
- package/lib/module/testing/fakeStore.js +276 -0
- package/lib/module/testing/fakeStore.js.map +1 -0
- package/lib/module/testing/index.js +13 -0
- package/lib/module/testing/index.js.map +1 -0
- package/lib/typescript/commonjs/adapter/createStoreProvider.d.ts +45 -0
- package/lib/typescript/commonjs/adapter/createStoreProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapter/iap-adapter.d.ts +80 -0
- package/lib/typescript/commonjs/adapter/iap-adapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapter/iapShapes.d.ts +94 -0
- package/lib/typescript/commonjs/adapter/iapShapes.d.ts.map +1 -0
- package/lib/typescript/commonjs/adapter/port.d.ts +184 -0
- package/lib/typescript/commonjs/adapter/port.d.ts.map +1 -0
- package/lib/typescript/commonjs/config/types.d.ts +326 -0
- package/lib/typescript/commonjs/config/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/config/validate.d.ts +63 -0
- package/lib/typescript/commonjs/config/validate.d.ts.map +1 -0
- package/lib/typescript/commonjs/core/mutex.d.ts +17 -0
- package/lib/typescript/commonjs/core/mutex.d.ts.map +1 -0
- package/lib/typescript/commonjs/core/retry.d.ts +19 -0
- package/lib/typescript/commonjs/core/retry.d.ts.map +1 -0
- package/lib/typescript/commonjs/core/timers.d.ts +142 -0
- package/lib/typescript/commonjs/core/timers.d.ts.map +1 -0
- package/lib/typescript/commonjs/diagnostics/errors.d.ts +55 -0
- package/lib/typescript/commonjs/diagnostics/errors.d.ts.map +1 -0
- package/lib/typescript/commonjs/diagnostics/events.d.ts +158 -0
- package/lib/typescript/commonjs/diagnostics/events.d.ts.map +1 -0
- package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts +54 -0
- package/lib/typescript/commonjs/diagnostics/messageKeys.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/connection.d.ts +30 -0
- package/lib/typescript/commonjs/engine/connection.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/engine.d.ts +93 -0
- package/lib/typescript/commonjs/engine/engine.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/finalize.d.ts +53 -0
- package/lib/typescript/commonjs/engine/finalize.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/foreground.d.ts +15 -0
- package/lib/typescript/commonjs/engine/foreground.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/internals.d.ts +28 -0
- package/lib/typescript/commonjs/engine/internals.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/pending.d.ts +51 -0
- package/lib/typescript/commonjs/engine/pending.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/products.d.ts +82 -0
- package/lib/typescript/commonjs/engine/products.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/purchase.d.ts +61 -0
- package/lib/typescript/commonjs/engine/purchase.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/purchaseFailure.d.ts +15 -0
- package/lib/typescript/commonjs/engine/purchaseFailure.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/receiptValidation.d.ts +42 -0
- package/lib/typescript/commonjs/engine/receiptValidation.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/state.d.ts +46 -0
- package/lib/typescript/commonjs/engine/state.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/subscriptions.d.ts +61 -0
- package/lib/typescript/commonjs/engine/subscriptions.d.ts.map +1 -0
- package/lib/typescript/commonjs/engine/sync.d.ts +36 -0
- package/lib/typescript/commonjs/engine/sync.d.ts.map +1 -0
- package/lib/typescript/commonjs/entitlements/aggregate.d.ts +97 -0
- package/lib/typescript/commonjs/entitlements/aggregate.d.ts.map +1 -0
- package/lib/typescript/commonjs/entitlements/mapping.d.ts +27 -0
- package/lib/typescript/commonjs/entitlements/mapping.d.ts.map +1 -0
- package/lib/typescript/commonjs/entitlements/policy.d.ts +75 -0
- package/lib/typescript/commonjs/entitlements/policy.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +44 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/persistence/mmkv-store.d.ts +45 -0
- package/lib/typescript/commonjs/persistence/mmkv-store.d.ts.map +1 -0
- package/lib/typescript/commonjs/persistence/snapshot.d.ts +106 -0
- package/lib/typescript/commonjs/persistence/snapshot.d.ts.map +1 -0
- package/lib/typescript/commonjs/react/PaymentProvider.d.ts +57 -0
- package/lib/typescript/commonjs/react/PaymentProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/react/hooks.d.ts +80 -0
- package/lib/typescript/commonjs/react/hooks.d.ts.map +1 -0
- package/lib/typescript/commonjs/testing/conformance.d.ts +41 -0
- package/lib/typescript/commonjs/testing/conformance.d.ts.map +1 -0
- package/lib/typescript/commonjs/testing/fakeStore.d.ts +69 -0
- package/lib/typescript/commonjs/testing/fakeStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/testing/index.d.ts +12 -0
- package/lib/typescript/commonjs/testing/index.d.ts.map +1 -0
- package/lib/typescript/module/adapter/createStoreProvider.d.ts +45 -0
- package/lib/typescript/module/adapter/createStoreProvider.d.ts.map +1 -0
- package/lib/typescript/module/adapter/iap-adapter.d.ts +80 -0
- package/lib/typescript/module/adapter/iap-adapter.d.ts.map +1 -0
- package/lib/typescript/module/adapter/iapShapes.d.ts +94 -0
- package/lib/typescript/module/adapter/iapShapes.d.ts.map +1 -0
- package/lib/typescript/module/adapter/port.d.ts +184 -0
- package/lib/typescript/module/adapter/port.d.ts.map +1 -0
- package/lib/typescript/module/config/types.d.ts +326 -0
- package/lib/typescript/module/config/types.d.ts.map +1 -0
- package/lib/typescript/module/config/validate.d.ts +63 -0
- package/lib/typescript/module/config/validate.d.ts.map +1 -0
- package/lib/typescript/module/core/mutex.d.ts +17 -0
- package/lib/typescript/module/core/mutex.d.ts.map +1 -0
- package/lib/typescript/module/core/retry.d.ts +19 -0
- package/lib/typescript/module/core/retry.d.ts.map +1 -0
- package/lib/typescript/module/core/timers.d.ts +142 -0
- package/lib/typescript/module/core/timers.d.ts.map +1 -0
- package/lib/typescript/module/diagnostics/errors.d.ts +55 -0
- package/lib/typescript/module/diagnostics/errors.d.ts.map +1 -0
- package/lib/typescript/module/diagnostics/events.d.ts +158 -0
- package/lib/typescript/module/diagnostics/events.d.ts.map +1 -0
- package/lib/typescript/module/diagnostics/messageKeys.d.ts +54 -0
- package/lib/typescript/module/diagnostics/messageKeys.d.ts.map +1 -0
- package/lib/typescript/module/engine/connection.d.ts +30 -0
- package/lib/typescript/module/engine/connection.d.ts.map +1 -0
- package/lib/typescript/module/engine/engine.d.ts +93 -0
- package/lib/typescript/module/engine/engine.d.ts.map +1 -0
- package/lib/typescript/module/engine/finalize.d.ts +53 -0
- package/lib/typescript/module/engine/finalize.d.ts.map +1 -0
- package/lib/typescript/module/engine/foreground.d.ts +15 -0
- package/lib/typescript/module/engine/foreground.d.ts.map +1 -0
- package/lib/typescript/module/engine/internals.d.ts +28 -0
- package/lib/typescript/module/engine/internals.d.ts.map +1 -0
- package/lib/typescript/module/engine/pending.d.ts +51 -0
- package/lib/typescript/module/engine/pending.d.ts.map +1 -0
- package/lib/typescript/module/engine/products.d.ts +82 -0
- package/lib/typescript/module/engine/products.d.ts.map +1 -0
- package/lib/typescript/module/engine/purchase.d.ts +61 -0
- package/lib/typescript/module/engine/purchase.d.ts.map +1 -0
- package/lib/typescript/module/engine/purchaseFailure.d.ts +15 -0
- package/lib/typescript/module/engine/purchaseFailure.d.ts.map +1 -0
- package/lib/typescript/module/engine/receiptValidation.d.ts +42 -0
- package/lib/typescript/module/engine/receiptValidation.d.ts.map +1 -0
- package/lib/typescript/module/engine/state.d.ts +46 -0
- package/lib/typescript/module/engine/state.d.ts.map +1 -0
- package/lib/typescript/module/engine/subscriptions.d.ts +61 -0
- package/lib/typescript/module/engine/subscriptions.d.ts.map +1 -0
- package/lib/typescript/module/engine/sync.d.ts +36 -0
- package/lib/typescript/module/engine/sync.d.ts.map +1 -0
- package/lib/typescript/module/entitlements/aggregate.d.ts +97 -0
- package/lib/typescript/module/entitlements/aggregate.d.ts.map +1 -0
- package/lib/typescript/module/entitlements/mapping.d.ts +27 -0
- package/lib/typescript/module/entitlements/mapping.d.ts.map +1 -0
- package/lib/typescript/module/entitlements/policy.d.ts +75 -0
- package/lib/typescript/module/entitlements/policy.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +44 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/persistence/mmkv-store.d.ts +45 -0
- package/lib/typescript/module/persistence/mmkv-store.d.ts.map +1 -0
- package/lib/typescript/module/persistence/snapshot.d.ts +106 -0
- package/lib/typescript/module/persistence/snapshot.d.ts.map +1 -0
- package/lib/typescript/module/react/PaymentProvider.d.ts +57 -0
- package/lib/typescript/module/react/PaymentProvider.d.ts.map +1 -0
- package/lib/typescript/module/react/hooks.d.ts +80 -0
- package/lib/typescript/module/react/hooks.d.ts.map +1 -0
- package/lib/typescript/module/testing/conformance.d.ts +41 -0
- package/lib/typescript/module/testing/conformance.d.ts.map +1 -0
- package/lib/typescript/module/testing/fakeStore.d.ts +69 -0
- package/lib/typescript/module/testing/fakeStore.d.ts.map +1 -0
- package/lib/typescript/module/testing/index.d.ts +12 -0
- package/lib/typescript/module/testing/index.d.ts.map +1 -0
- package/package.json +49 -13
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createProducts = createProducts;
|
|
7
|
+
var _errors = require("../diagnostics/errors.js");
|
|
8
|
+
var _mutex = require("../core/mutex.js");
|
|
9
|
+
var _mapping = require("../entitlements/mapping.js");
|
|
10
|
+
/**
|
|
11
|
+
* Product query, normalization, and the in-memory price cache (US11).
|
|
12
|
+
*
|
|
13
|
+
* Two rules shape this module:
|
|
14
|
+
*
|
|
15
|
+
* - **Prices come from the store, formatted.** An app must never build a price
|
|
16
|
+
* string (FR-028): only the store knows the right currency symbol, its
|
|
17
|
+
* placement, the decimal separator, and the grouping for the user's locale. A
|
|
18
|
+
* hand-built "$9.99" is wrong in most of the world.
|
|
19
|
+
* - **Offer eligibility is reported, never computed.** The store decides who
|
|
20
|
+
* qualifies for a trial or an introductory price (FR-026). Guessing locally
|
|
21
|
+
* would promise a trial the store then refuses at checkout.
|
|
22
|
+
*
|
|
23
|
+
* The cache is in **memory only** and short-lived. Persisting prices would risk
|
|
24
|
+
* showing a stale one as current in a later session, and a paywall is exactly
|
|
25
|
+
* where that matters.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/** Why a requested product produced nothing, kept distinct from a network error. */
|
|
29
|
+
|
|
30
|
+
function normalize(raw, productKey, productType) {
|
|
31
|
+
return {
|
|
32
|
+
productKey,
|
|
33
|
+
productType,
|
|
34
|
+
title: raw.title,
|
|
35
|
+
description: raw.description,
|
|
36
|
+
formattedPrice: raw.formattedPrice,
|
|
37
|
+
currencyCode: raw.currencyCode,
|
|
38
|
+
priceAmountMicros: raw.priceAmountMicros,
|
|
39
|
+
offers: raw.offers.map(offer => ({
|
|
40
|
+
offerKey: offer.offerKey,
|
|
41
|
+
billingPeriod: offer.billingPeriod,
|
|
42
|
+
formattedPrice: offer.formattedPrice,
|
|
43
|
+
priceAmountMicros: offer.priceAmountMicros,
|
|
44
|
+
currencyCode: offer.currencyCode,
|
|
45
|
+
trialPeriod: offer.trialPeriod,
|
|
46
|
+
introductoryPrice: offer.introductoryPrice,
|
|
47
|
+
isEligible: offer.isEligible
|
|
48
|
+
}))
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function createProducts(deps) {
|
|
52
|
+
const {
|
|
53
|
+
resolved
|
|
54
|
+
} = deps;
|
|
55
|
+
const cache = new Map();
|
|
56
|
+
const isFresh = entry => deps.now() - entry.cachedAt < resolved.productCacheTtlMs;
|
|
57
|
+
const query = async (productKeys, useCache) => {
|
|
58
|
+
const missing = [];
|
|
59
|
+
const resolvedProducts = [];
|
|
60
|
+
const toFetch = [];
|
|
61
|
+
for (const productKey of productKeys) {
|
|
62
|
+
const entry = resolved.entries.get(productKey);
|
|
63
|
+
const storeProductId = (0, _mapping.storeIdForProductKey)(resolved, productKey);
|
|
64
|
+
if (!entry || !storeProductId) {
|
|
65
|
+
// A configuration problem, not a store one. Distinguishing them tells a
|
|
66
|
+
// developer whether to fix the catalog or check Play Console.
|
|
67
|
+
missing.push({
|
|
68
|
+
productKey,
|
|
69
|
+
reason: 'not_in_catalog'
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const cached = useCache ? cache.get(productKey) : undefined;
|
|
74
|
+
if (cached && isFresh(cached)) {
|
|
75
|
+
resolvedProducts.push(cached.product);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
toFetch.push({
|
|
79
|
+
productKey,
|
|
80
|
+
storeProductId,
|
|
81
|
+
productType: entry.productType
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (toFetch.length === 0) {
|
|
85
|
+
deps.emit({
|
|
86
|
+
type: 'products_queried',
|
|
87
|
+
productKeys,
|
|
88
|
+
found: resolvedProducts.length,
|
|
89
|
+
missing: missing.map(m => m.productKey),
|
|
90
|
+
fromCache: true
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
ok: true,
|
|
94
|
+
products: resolvedProducts,
|
|
95
|
+
missing,
|
|
96
|
+
fromCache: true
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Grouped by product type because the store queries in-app products and
|
|
101
|
+
// subscriptions through separate calls.
|
|
102
|
+
const byType = new Map();
|
|
103
|
+
for (const item of toFetch) {
|
|
104
|
+
const list = byType.get(item.productType) ?? [];
|
|
105
|
+
list.push(item);
|
|
106
|
+
byType.set(item.productType, list);
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
// In parallel: a paywall offering a subscription and a one-time purchase
|
|
110
|
+
// used to wait for one store round-trip after the other (PAY-20).
|
|
111
|
+
const groups = await Promise.all([...byType].map(async ([productType, items]) => ({
|
|
112
|
+
items,
|
|
113
|
+
raw: await (0, _mutex.withTimeout)(deps.provider.queryProducts(items.map(i => i.storeProductId), productType), resolved.timeouts.productQueryMs, () => new _errors.PaymentError({
|
|
114
|
+
code: 'PAYMENT_TIMEOUT',
|
|
115
|
+
message: 'Querying products timed out',
|
|
116
|
+
operation: 'getProducts',
|
|
117
|
+
retryable: true
|
|
118
|
+
}))
|
|
119
|
+
})));
|
|
120
|
+
for (const {
|
|
121
|
+
items,
|
|
122
|
+
raw
|
|
123
|
+
} of groups) {
|
|
124
|
+
const returned = new Map(raw.map(p => [p.storeProductId, p]));
|
|
125
|
+
for (const item of items) {
|
|
126
|
+
const found = returned.get(item.storeProductId);
|
|
127
|
+
if (!found) {
|
|
128
|
+
// The store knows the id but will not sell it here: unapproved, or
|
|
129
|
+
// not available in this country. Never conflated with a network
|
|
130
|
+
// failure (FR-027).
|
|
131
|
+
missing.push({
|
|
132
|
+
productKey: item.productKey,
|
|
133
|
+
reason: 'not_available_from_store'
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const product = normalize(found, item.productKey, item.productType);
|
|
138
|
+
cache.set(item.productKey, {
|
|
139
|
+
product,
|
|
140
|
+
cachedAt: deps.now()
|
|
141
|
+
});
|
|
142
|
+
resolvedProducts.push(product);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const paymentError = error instanceof _errors.PaymentError ? error : new _errors.PaymentError({
|
|
147
|
+
code: 'PAYMENT_NETWORK_ERROR',
|
|
148
|
+
message: 'Could not reach the store to query products',
|
|
149
|
+
operation: 'getProducts',
|
|
150
|
+
retryable: true
|
|
151
|
+
});
|
|
152
|
+
deps.emit({
|
|
153
|
+
type: 'internal_error',
|
|
154
|
+
code: paymentError.code,
|
|
155
|
+
operation: 'getProducts'
|
|
156
|
+
});
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: paymentError
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
deps.emit({
|
|
163
|
+
type: 'products_queried',
|
|
164
|
+
productKeys,
|
|
165
|
+
found: resolvedProducts.length,
|
|
166
|
+
missing: missing.map(m => m.productKey),
|
|
167
|
+
fromCache: false
|
|
168
|
+
});
|
|
169
|
+
return {
|
|
170
|
+
ok: true,
|
|
171
|
+
products: resolvedProducts,
|
|
172
|
+
missing,
|
|
173
|
+
fromCache: false
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Identical requests in flight share one store call (PAY-20): several screens
|
|
179
|
+
* mounting `useProducts` for the same paywall ask once.
|
|
180
|
+
*/
|
|
181
|
+
const flights = new Map();
|
|
182
|
+
const joined = (productKeys, useCache) => {
|
|
183
|
+
const key = `${useCache ? 'get' : 'refresh'}:${productKeys.join('|')}`;
|
|
184
|
+
const running = flights.get(key);
|
|
185
|
+
if (running) {
|
|
186
|
+
return running;
|
|
187
|
+
}
|
|
188
|
+
const promise = query(productKeys, useCache).finally(() => flights.delete(key));
|
|
189
|
+
flights.set(key, promise);
|
|
190
|
+
return promise;
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
get: productKeys => joined(productKeys, true),
|
|
194
|
+
refresh: productKeys => joined(productKeys, false),
|
|
195
|
+
invalidate: () => cache.clear()
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=products.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_errors","require","_mutex","_mapping","normalize","raw","productKey","productType","title","description","formattedPrice","currencyCode","priceAmountMicros","offers","map","offer","offerKey","billingPeriod","trialPeriod","introductoryPrice","isEligible","createProducts","deps","resolved","cache","Map","isFresh","entry","now","cachedAt","productCacheTtlMs","query","productKeys","useCache","missing","resolvedProducts","toFetch","entries","get","storeProductId","storeIdForProductKey","push","reason","cached","undefined","product","length","emit","type","found","m","fromCache","ok","products","byType","item","list","set","groups","Promise","all","items","withTimeout","provider","queryProducts","i","timeouts","productQueryMs","PaymentError","code","message","operation","retryable","returned","p","error","paymentError","flights","joined","key","join","running","promise","finally","delete","refresh","invalidate","clear"],"sourceRoot":"../../../src","sources":["engine/products.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createPurchaseFlow = createPurchaseFlow;
|
|
7
|
+
var _mutex = require("../core/mutex.js");
|
|
8
|
+
var _timers = require("../core/timers.js");
|
|
9
|
+
var _errors = require("../diagnostics/errors.js");
|
|
10
|
+
var _mapping = require("../entitlements/mapping.js");
|
|
11
|
+
var _sync = require("./sync.js");
|
|
12
|
+
var _receiptValidation = require("./receiptValidation.js");
|
|
13
|
+
var _purchaseFailure = require("./purchaseFailure.js");
|
|
14
|
+
/**
|
|
15
|
+
* The purchase flow.
|
|
16
|
+
*
|
|
17
|
+
* Ordering here is deliberate and load-bearing:
|
|
18
|
+
*
|
|
19
|
+
* 1. Refuse early and cheaply — disabled, not ready, already busy, environment
|
|
20
|
+
* blocked, unknown product — so nothing reaches the store that should not.
|
|
21
|
+
* 2. Launch, and map every store outcome onto a typed result (FR-005).
|
|
22
|
+
* 3. Pending stops here: it is persisted and signalled, but **never granted**
|
|
23
|
+
* (FR-037).
|
|
24
|
+
* 4. Validate with the app's backend, if one is configured, and only for a
|
|
25
|
+
* **newly completed** purchase (FR-069a).
|
|
26
|
+
* 5. Grant the entitlement, then finalize. In that order — the user gets what
|
|
27
|
+
* they paid for before the bookkeeping completes, so a finalize failure never
|
|
28
|
+
* withholds a paid entitlement. Finalization is still guaranteed, by the
|
|
29
|
+
* persisted queue.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/** The error code each failed purchase kind is reported under (PAY-19). */
|
|
33
|
+
|
|
34
|
+
function createPurchaseFlow(deps) {
|
|
35
|
+
const {
|
|
36
|
+
resolved
|
|
37
|
+
} = deps;
|
|
38
|
+
// The backend check and what to do when it cannot answer (receiptValidation).
|
|
39
|
+
const {
|
|
40
|
+
askHook,
|
|
41
|
+
validate
|
|
42
|
+
} = (0, _receiptValidation.createReceiptValidation)({
|
|
43
|
+
config: deps.config,
|
|
44
|
+
platform: deps.platform,
|
|
45
|
+
resolved,
|
|
46
|
+
emit: deps.emit
|
|
47
|
+
});
|
|
48
|
+
const toRef = record => ({
|
|
49
|
+
transactionId: record.transactionId,
|
|
50
|
+
productKey: record.productKey
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/** Writes or replaces the record for one transaction. */
|
|
54
|
+
const upsert = record => {
|
|
55
|
+
const snapshot = deps.snapshot();
|
|
56
|
+
const others = snapshot.purchases.filter(p => p.transactionId !== record.transactionId);
|
|
57
|
+
deps.commit({
|
|
58
|
+
...snapshot,
|
|
59
|
+
purchases: [...others, record]
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const recordFor = (purchase, productKey) => (0, _sync.toPersistedRecord)(resolved, purchase, productKey, deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId));
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Calls the app's hook under `timeouts.validateMs`.
|
|
66
|
+
*
|
|
67
|
+
* Unbounded, a hook that never answers held the purchase lock and, through
|
|
68
|
+
* revalidation, the sync flight for the rest of the session. A timeout rejects,
|
|
69
|
+
* so callers treat it exactly like a hook that throws: unavailable (FR-072b).
|
|
70
|
+
*/
|
|
71
|
+
/**
|
|
72
|
+
* Settlements in progress, by transaction.
|
|
73
|
+
*
|
|
74
|
+
* The Play binding delivers a launched purchase twice: to the launch and, at
|
|
75
|
+
* the same moment, to the session-long update listener. Both paths reach
|
|
76
|
+
* `settle`, and without this the hook ran twice and the purchase was settled
|
|
77
|
+
* twice. The second caller joins the first and gets the same result.
|
|
78
|
+
*/
|
|
79
|
+
const inFlightSettle = new Map();
|
|
80
|
+
const settleOnce = (purchase, productKey, correlationId) => {
|
|
81
|
+
const running = inFlightSettle.get(purchase.transactionId);
|
|
82
|
+
if (running) {
|
|
83
|
+
return running;
|
|
84
|
+
}
|
|
85
|
+
const flight = settle(purchase, productKey, correlationId).finally(() => {
|
|
86
|
+
inFlightSettle.delete(purchase.transactionId);
|
|
87
|
+
});
|
|
88
|
+
inFlightSettle.set(purchase.transactionId, flight);
|
|
89
|
+
return flight;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** Persists a completed purchase, grants it, then finalizes. */
|
|
93
|
+
const settle = async (purchase, productKey, correlationId) => {
|
|
94
|
+
const decision = await validate(purchase, productKey, correlationId);
|
|
95
|
+
if (decision.outcome === 'rejected') {
|
|
96
|
+
upsert({
|
|
97
|
+
...recordFor(purchase, productKey),
|
|
98
|
+
validationState: 'rejected',
|
|
99
|
+
finalizeState: 'queued'
|
|
100
|
+
});
|
|
101
|
+
// Still finalized with the store: the money moved, so leaving it
|
|
102
|
+
// unacknowledged would have Google refund it while our backend has
|
|
103
|
+
// already decided the user is not entitled. Refunding is the app owner's
|
|
104
|
+
// call, not a side effect of a bookkeeping omission.
|
|
105
|
+
await deps.finalizer.enqueue(purchase.transactionId);
|
|
106
|
+
return {
|
|
107
|
+
kind: 'validation_rejected',
|
|
108
|
+
productKey,
|
|
109
|
+
reason: decision.reason
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
upsert({
|
|
113
|
+
...recordFor(purchase, productKey),
|
|
114
|
+
validationState: decision.outcome === 'granted_pending_revalidation' ? 'queued_for_revalidation' : 'approved',
|
|
115
|
+
finalizeState: 'queued'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Grant is already live at this point: `commit` recomputed entitlements.
|
|
119
|
+
// Finalize second, so a store hiccup cannot withhold what was paid for.
|
|
120
|
+
await deps.finalizer.enqueue(purchase.transactionId);
|
|
121
|
+
const record = deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId);
|
|
122
|
+
return {
|
|
123
|
+
kind: 'success',
|
|
124
|
+
productKey,
|
|
125
|
+
transaction: record ? toRef(record) : {
|
|
126
|
+
transactionId: purchase.transactionId,
|
|
127
|
+
productKey
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
const handlePending = (purchase, productKey) => {
|
|
132
|
+
// The same pending transaction arrives from the launch and from the update
|
|
133
|
+
// listener (see `inFlightSettle`). The signal is about a purchase becoming
|
|
134
|
+
// pending, so it fires once per transaction, not once per delivery.
|
|
135
|
+
const alreadyPending = deps.snapshot().purchases.some(p => p.transactionId === purchase.transactionId && p.state === 'pending');
|
|
136
|
+
upsert(recordFor(purchase, productKey));
|
|
137
|
+
if (!alreadyPending) {
|
|
138
|
+
deps.emit({
|
|
139
|
+
type: 'purchase_pending',
|
|
140
|
+
productKey
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
kind: 'pending',
|
|
145
|
+
productKey,
|
|
146
|
+
transaction: {
|
|
147
|
+
transactionId: purchase.transactionId,
|
|
148
|
+
productKey
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The store returned a purchase in a state it could not name — neither paid
|
|
155
|
+
* nor pending. Nothing is granted, persisted or acknowledged on it.
|
|
156
|
+
*
|
|
157
|
+
* Retrying is the repair path: if the money did move, the store answers
|
|
158
|
+
* `already_owned`, which re-syncs and grants (FR-033).
|
|
159
|
+
*/
|
|
160
|
+
const handleUnspecified = (productKey, correlationId) => {
|
|
161
|
+
deps.emit({
|
|
162
|
+
type: 'purchase_failed',
|
|
163
|
+
productKey,
|
|
164
|
+
code: 'PAYMENT_STORE_ERROR',
|
|
165
|
+
retryable: true,
|
|
166
|
+
correlationId
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
kind: 'store_error',
|
|
170
|
+
productKey,
|
|
171
|
+
code: 'PAYMENT_STORE_ERROR'
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/** What the store is asked for: the product and, for a plan change, what it replaces. */
|
|
176
|
+
const launchRequest = (productKey, storeProductId, options) => {
|
|
177
|
+
const replaceKey = options?.replaceProductKey;
|
|
178
|
+
return {
|
|
179
|
+
storeProductId,
|
|
180
|
+
productType: resolved.entries.get(productKey)?.productType ?? 'one_time_permanent',
|
|
181
|
+
offerKey: options?.offerKey,
|
|
182
|
+
obfuscatedAccountId: options?.obfuscatedAccountId,
|
|
183
|
+
// Present only for a plan change. The store needs the token of the
|
|
184
|
+
// subscription being replaced so it migrates the existing purchase instead
|
|
185
|
+
// of creating a second one (FR-065), and its product id to apply the
|
|
186
|
+
// replacement mode.
|
|
187
|
+
replacePurchaseToken: replaceKey ? deps.snapshot().purchases.find(p => p.productKey === replaceKey && p.state === 'purchased')?.token : undefined,
|
|
188
|
+
replaceStoreProductId: replaceKey ? (0, _mapping.storeIdForProductKey)(resolved, replaceKey) : undefined,
|
|
189
|
+
prorationMode: options?.prorationMode
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* The launch timeout covers opening the store surface only; time the user
|
|
195
|
+
* spends inside it is the store's, not ours (FR-035). A provider that reports
|
|
196
|
+
* nothing until the flow ends gives no "opened" moment to time, so it gets only
|
|
197
|
+
* `PURCHASE_FLOW_CEILING_MS`: far beyond any real purchase, there so a binding
|
|
198
|
+
* that never answers cannot hold the purchase lock for the whole session.
|
|
199
|
+
*/
|
|
200
|
+
const launch = request => {
|
|
201
|
+
const launched = deps.provider.launchPurchase(request);
|
|
202
|
+
const includesStoreTime = deps.provider.capabilities().purchaseOutcomeIncludesStoreTime;
|
|
203
|
+
return (0, _mutex.withTimeout)(launched, includesStoreTime ? _timers.PURCHASE_FLOW_CEILING_MS : resolved.timeouts.purchaseLaunchMs, () => new _errors.PaymentError({
|
|
204
|
+
code: 'PAYMENT_TIMEOUT',
|
|
205
|
+
message: 'Opening the purchase surface timed out',
|
|
206
|
+
operation: 'purchase',
|
|
207
|
+
retryable: true
|
|
208
|
+
}));
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
async purchase(productKey, options) {
|
|
212
|
+
if (!resolved.enabled) {
|
|
213
|
+
return {
|
|
214
|
+
kind: 'disabled'
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const status = deps.statusKind();
|
|
218
|
+
if (status !== 'ready') {
|
|
219
|
+
return {
|
|
220
|
+
kind: 'not_ready',
|
|
221
|
+
status
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const storeProductId = (0, _mapping.storeIdForProductKey)(resolved, productKey);
|
|
225
|
+
if (!storeProductId) {
|
|
226
|
+
return {
|
|
227
|
+
kind: 'unknown_product',
|
|
228
|
+
productKey
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// The block that makes a developer mistake unable to move real money.
|
|
233
|
+
// Gated on the provider actually being one that would: the fake store
|
|
234
|
+
// must still be able to complete a purchase in a test (FR-014).
|
|
235
|
+
if (deps.provider.capabilities().createsRealTransactions && !deps.mayCreateRealTransaction()) {
|
|
236
|
+
deps.recordBlockedOperation(productKey);
|
|
237
|
+
return {
|
|
238
|
+
kind: 'environment_blocked',
|
|
239
|
+
productKey,
|
|
240
|
+
environment: deps.config.environment
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const correlationId = deps.nextCorrelationId();
|
|
244
|
+
|
|
245
|
+
// Exclusive, not single-flight: a second purchase is refused rather than
|
|
246
|
+
// joined or queued, so no second store surface opens (FR-031).
|
|
247
|
+
const attempt = await deps.runExclusive(async () => {
|
|
248
|
+
deps.emit({
|
|
249
|
+
type: 'purchase_started',
|
|
250
|
+
productKey,
|
|
251
|
+
correlationId
|
|
252
|
+
});
|
|
253
|
+
let outcome;
|
|
254
|
+
try {
|
|
255
|
+
outcome = await launch(launchRequest(productKey, storeProductId, options));
|
|
256
|
+
} catch {
|
|
257
|
+
deps.emit({
|
|
258
|
+
type: 'purchase_failed',
|
|
259
|
+
productKey,
|
|
260
|
+
code: 'PAYMENT_TIMEOUT',
|
|
261
|
+
retryable: true,
|
|
262
|
+
correlationId
|
|
263
|
+
});
|
|
264
|
+
return {
|
|
265
|
+
kind: 'timeout',
|
|
266
|
+
productKey
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (!outcome.ok) {
|
|
270
|
+
const mapped = (0, _purchaseFailure.mapFailure)(outcome.reason, productKey, deps.statusKind());
|
|
271
|
+
if (mapped.kind === 'user_cancelled') {
|
|
272
|
+
// A normal outcome. Reported on its own channel so it is never
|
|
273
|
+
// counted as a technical failure (FR-032).
|
|
274
|
+
deps.emit({
|
|
275
|
+
type: 'purchase_cancelled',
|
|
276
|
+
productKey,
|
|
277
|
+
correlationId
|
|
278
|
+
});
|
|
279
|
+
return mapped;
|
|
280
|
+
}
|
|
281
|
+
if (mapped.kind === 'already_owned') {
|
|
282
|
+
// How a reinstall or a new device repairs itself (FR-033).
|
|
283
|
+
deps.requestSync('already_owned');
|
|
284
|
+
return mapped;
|
|
285
|
+
}
|
|
286
|
+
deps.emit({
|
|
287
|
+
type: 'purchase_failed',
|
|
288
|
+
productKey,
|
|
289
|
+
code: _purchaseFailure.FAILURE_CODES[mapped.kind] ?? 'PAYMENT_STORE_ERROR',
|
|
290
|
+
retryable: mapped.kind === 'network_error',
|
|
291
|
+
correlationId
|
|
292
|
+
});
|
|
293
|
+
return mapped;
|
|
294
|
+
}
|
|
295
|
+
if (outcome.purchase.state === 'pending') {
|
|
296
|
+
return handlePending(outcome.purchase, productKey);
|
|
297
|
+
}
|
|
298
|
+
if (outcome.purchase.state === 'unspecified') {
|
|
299
|
+
return handleUnspecified(productKey, correlationId);
|
|
300
|
+
}
|
|
301
|
+
deps.emit({
|
|
302
|
+
type: 'purchase_succeeded',
|
|
303
|
+
productKey,
|
|
304
|
+
correlationId
|
|
305
|
+
});
|
|
306
|
+
return settleOnce(outcome.purchase, productKey, correlationId);
|
|
307
|
+
});
|
|
308
|
+
if (!attempt.acquired) {
|
|
309
|
+
return {
|
|
310
|
+
kind: 'purchase_in_progress'
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
return attempt.value;
|
|
314
|
+
},
|
|
315
|
+
/**
|
|
316
|
+
* A store-pushed update.
|
|
317
|
+
*
|
|
318
|
+
* This is how a pending purchase that settled between sessions is granted
|
|
319
|
+
* without the user buying again (FR-039). It runs outside the exclusive lock
|
|
320
|
+
* because it is not a user-initiated purchase and must not be refused just
|
|
321
|
+
* because one is open.
|
|
322
|
+
*/
|
|
323
|
+
async ingest(purchase) {
|
|
324
|
+
const productKey = resolved.byStoreId.get(purchase.storeProductId);
|
|
325
|
+
if (!productKey) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (purchase.state === 'pending') {
|
|
329
|
+
handlePending(purchase, productKey);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (purchase.state === 'unspecified') {
|
|
333
|
+
// No basis to grant or to end anything. The next sync reports what
|
|
334
|
+
// the store actually holds.
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const existing = deps.snapshot().purchases.find(p => p.transactionId === purchase.transactionId);
|
|
338
|
+
|
|
339
|
+
// Already settled and validated: nothing to redo, and re-running the hook
|
|
340
|
+
// here would break FR-069a's "new purchases only" rule.
|
|
341
|
+
if (existing && existing.state === 'purchased' && existing.validationState !== 'not_required') {
|
|
342
|
+
await deps.finalizer.enqueue(purchase.transactionId);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
await settleOnce(purchase, productKey, deps.nextCorrelationId());
|
|
346
|
+
},
|
|
347
|
+
async revalidate() {
|
|
348
|
+
const hook = deps.config.validateTransaction;
|
|
349
|
+
if (!hook) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const queued = deps.snapshot().purchases.filter(p => p.validationState === 'queued_for_revalidation');
|
|
353
|
+
for (const record of queued) {
|
|
354
|
+
const entry = resolved.entries.get(record.productKey);
|
|
355
|
+
let approved;
|
|
356
|
+
try {
|
|
357
|
+
const decision = await askHook(hook, {
|
|
358
|
+
productKey: record.productKey,
|
|
359
|
+
productType: entry?.productType ?? 'one_time_permanent',
|
|
360
|
+
// Re-validation deliberately carries no payload: the original
|
|
361
|
+
// verification material is not persisted (FR-056), so the backend
|
|
362
|
+
// re-checks by transaction against its own record of the purchase —
|
|
363
|
+
// which is why the transaction id has to travel with it.
|
|
364
|
+
verificationPayload: '',
|
|
365
|
+
correlationId: deps.nextCorrelationId(),
|
|
366
|
+
transactionId: record.transactionId,
|
|
367
|
+
platform: deps.platform
|
|
368
|
+
});
|
|
369
|
+
approved = decision.approved;
|
|
370
|
+
} catch {
|
|
371
|
+
// Still unreachable. Leave it queued and try again next sync rather
|
|
372
|
+
// than revoking from a paying user because our backend is down.
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
const snapshot = deps.snapshot();
|
|
376
|
+
deps.commit({
|
|
377
|
+
...snapshot,
|
|
378
|
+
purchases: snapshot.purchases.map(p => p.transactionId === record.transactionId ? {
|
|
379
|
+
...p,
|
|
380
|
+
validationState: approved ? 'approved' : 'rejected',
|
|
381
|
+
// A rejection on recovery revokes, which is the bound on the
|
|
382
|
+
// exposure `grant_and_queue` accepts (FR-072a).
|
|
383
|
+
state: approved ? p.state : 'revoked'
|
|
384
|
+
} : p)
|
|
385
|
+
});
|
|
386
|
+
deps.emit({
|
|
387
|
+
type: 'validation_decided',
|
|
388
|
+
productKey: record.productKey,
|
|
389
|
+
decision: approved ? 'approved' : 'rejected'
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=purchase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_mutex","require","_timers","_errors","_mapping","_sync","_receiptValidation","_purchaseFailure","createPurchaseFlow","deps","resolved","askHook","validate","createReceiptValidation","config","platform","emit","toRef","record","transactionId","productKey","upsert","snapshot","others","purchases","filter","p","commit","recordFor","purchase","toPersistedRecord","find","inFlightSettle","Map","settleOnce","correlationId","running","get","flight","settle","finally","delete","set","decision","outcome","validationState","finalizeState","finalizer","enqueue","kind","reason","transaction","handlePending","alreadyPending","some","state","type","handleUnspecified","code","retryable","launchRequest","storeProductId","options","replaceKey","replaceProductKey","productType","entries","offerKey","obfuscatedAccountId","replacePurchaseToken","token","undefined","replaceStoreProductId","storeIdForProductKey","prorationMode","launch","request","launched","provider","launchPurchase","includesStoreTime","capabilities","purchaseOutcomeIncludesStoreTime","withTimeout","PURCHASE_FLOW_CEILING_MS","timeouts","purchaseLaunchMs","PaymentError","message","operation","enabled","status","statusKind","createsRealTransactions","mayCreateRealTransaction","recordBlockedOperation","environment","nextCorrelationId","attempt","runExclusive","ok","mapped","mapFailure","requestSync","FAILURE_CODES","acquired","value","ingest","byStoreId","existing","revalidate","hook","validateTransaction","queued","entry","approved","verificationPayload","map"],"sourceRoot":"../../../src","sources":["engine/purchase.ts"],"mappings":"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","ignoreList":[]}
|