@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,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The purchase flow.
|
|
3
|
+
*
|
|
4
|
+
* Ordering here is deliberate and load-bearing:
|
|
5
|
+
*
|
|
6
|
+
* 1. Refuse early and cheaply — disabled, not ready, already busy, environment
|
|
7
|
+
* blocked, unknown product — so nothing reaches the store that should not.
|
|
8
|
+
* 2. Launch, and map every store outcome onto a typed result (FR-005).
|
|
9
|
+
* 3. Pending stops here: it is persisted and signalled, but **never granted**
|
|
10
|
+
* (FR-037).
|
|
11
|
+
* 4. Validate with the app's backend, if one is configured, and only for a
|
|
12
|
+
* **newly completed** purchase (FR-069a).
|
|
13
|
+
* 5. Grant the entitlement, then finalize. In that order — the user gets what
|
|
14
|
+
* they paid for before the bookkeeping completes, so a finalize failure never
|
|
15
|
+
* withholds a paid entitlement. Finalization is still guaranteed, by the
|
|
16
|
+
* persisted queue.
|
|
17
|
+
*/
|
|
18
|
+
import type { PaymentConfig, PaymentStatusKind, ProductKey, PurchaseOptions, PurchaseResult } from '../config/types.js';
|
|
19
|
+
import type { ResolvedConfig, TargetPlatform } from '../config/validate.js';
|
|
20
|
+
import type { ProviderPort, ProviderPurchase } from '../adapter/port.js';
|
|
21
|
+
import type { ExclusiveOutcome } from '../core/mutex.js';
|
|
22
|
+
import type { PaymentEventInput } from '../diagnostics/events.js';
|
|
23
|
+
import type { PersistedSnapshot } from '../persistence/snapshot.js';
|
|
24
|
+
import type { Finalizer } from './finalize.js';
|
|
25
|
+
export interface PurchaseFlowDeps {
|
|
26
|
+
config: PaymentConfig;
|
|
27
|
+
resolved: ResolvedConfig;
|
|
28
|
+
provider: ProviderPort;
|
|
29
|
+
platform: TargetPlatform;
|
|
30
|
+
finalizer: Finalizer;
|
|
31
|
+
snapshot: () => PersistedSnapshot;
|
|
32
|
+
commit: (next: PersistedSnapshot) => void;
|
|
33
|
+
emit: (event: PaymentEventInput) => void;
|
|
34
|
+
now: () => number;
|
|
35
|
+
nextCorrelationId: () => string;
|
|
36
|
+
statusKind: () => PaymentStatusKind;
|
|
37
|
+
mayCreateRealTransaction: () => boolean;
|
|
38
|
+
recordBlockedOperation: (productKey: ProductKey) => void;
|
|
39
|
+
requestSync: (trigger: 'already_owned') => void;
|
|
40
|
+
runExclusive: <T>(operation: () => Promise<T>) => Promise<ExclusiveOutcome<T>>;
|
|
41
|
+
}
|
|
42
|
+
export interface InternalPurchaseOptions extends PurchaseOptions {
|
|
43
|
+
replaceProductKey?: ProductKey;
|
|
44
|
+
prorationMode?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface PurchaseFlow {
|
|
47
|
+
purchase(productKey: ProductKey, options?: InternalPurchaseOptions): Promise<PurchaseResult>;
|
|
48
|
+
/** Handles a store-pushed update, e.g. a pending purchase settling (FR-039). */
|
|
49
|
+
ingest(purchase: ProviderPurchase): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Re-runs the backend check for transactions granted under the
|
|
52
|
+
* failure-fallback (FR-072a).
|
|
53
|
+
*
|
|
54
|
+
* Called on sync, so recovery happens on the app's own rhythm rather than on a
|
|
55
|
+
* timer of ours. A rejection here revokes, which is what bounds the exposure
|
|
56
|
+
* that `grant_and_queue` accepts.
|
|
57
|
+
*/
|
|
58
|
+
revalidate(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
export declare function createPurchaseFlow(deps: PurchaseFlowDeps): PurchaseFlow;
|
|
61
|
+
//# sourceMappingURL=purchase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purchase.d.ts","sourceRoot":"","sources":["../../../../src/engine/purchase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,cAAc,EAEd,MAAM,oBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzE,OAAO,KAAK,EACX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,oBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAe,CAAC;AAItD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAAuB,CAAC;AAC/D,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAY,CAAC;AAG5C,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,cAAc,CAAC;IACzB,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC1C,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACzC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,UAAU,EAAE,MAAM,iBAAiB,CAAC;IACpC,wBAAwB,EAAE,MAAM,OAAO,CAAC;IACxC,sBAAsB,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IACzD,WAAW,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAChD,YAAY,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/E;AAMD,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC/D,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7F,gFAAgF;IAChF,MAAM,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD;;;;;;;OAOG;IACH,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY,CA0YvE"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a refused purchase means to the app (PAY-19).
|
|
3
|
+
*
|
|
4
|
+
* The store answers with a reason of its own; this turns it into the result the
|
|
5
|
+
* app sees, under the code it can branch on, so no store vocabulary leaks out.
|
|
6
|
+
* Split from the flow next door, which is about the sequence of calls.
|
|
7
|
+
*/
|
|
8
|
+
import type { ProviderFailureReason } from '../adapter/port.js';
|
|
9
|
+
import type { PaymentStatusKind, ProductKey, PurchaseResult } from '../config/types.js';
|
|
10
|
+
import type { PaymentErrorCode } from '../diagnostics/errors.js';
|
|
11
|
+
export declare const FAILURE_CODES: Partial<Record<PurchaseResult['kind'], PaymentErrorCode>>;
|
|
12
|
+
/** Maps a provider failure onto the public vocabulary, so no store code leaks out. */
|
|
13
|
+
export declare function mapFailure(reason: ProviderFailureReason, productKey: ProductKey, status: PaymentStatusKind): PurchaseResult;
|
|
14
|
+
/** Plan-change parameters, which only `subscriptions.ts` supplies. */
|
|
15
|
+
//# sourceMappingURL=purchaseFailure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purchaseFailure.d.ts","sourceRoot":"","sources":["../../../../src/engine/purchaseFailure.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,oBAAiB,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAAuB,CAAC;AAE9D,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAKnF,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,UAAU,CACzB,MAAM,EAAE,qBAAqB,EAC7B,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,iBAAiB,GACvB,cAAc,CAsBhB;AAED,sEAAsE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asking the app's backend whether a purchase is real (FR-069a, FR-072b).
|
|
3
|
+
*
|
|
4
|
+
* The hook is optional and bounded by a timeout, and its answer decides whether
|
|
5
|
+
* an entitlement is granted — so what happens when it throws, times out, or is
|
|
6
|
+
* absent is the whole point of this module. Split from the flow next door,
|
|
7
|
+
* which is about the sequence of store calls.
|
|
8
|
+
*
|
|
9
|
+
* A hook that could not answer is never an implicit approval: the configured
|
|
10
|
+
* `onValidationUnavailable` decides, and the default refuses.
|
|
11
|
+
*/
|
|
12
|
+
import type { ProviderPurchase } from '../adapter/port.js';
|
|
13
|
+
import type { PaymentConfig, ProductKey } from '../config/types.js';
|
|
14
|
+
import type { ResolvedConfig, TargetPlatform } from '../config/validate.js';
|
|
15
|
+
import type { PaymentEventInput } from '../diagnostics/events.js';
|
|
16
|
+
export interface ReceiptValidationDeps {
|
|
17
|
+
config: PaymentConfig;
|
|
18
|
+
platform: TargetPlatform;
|
|
19
|
+
resolved: ResolvedConfig;
|
|
20
|
+
emit: (event: PaymentEventInput) => void;
|
|
21
|
+
}
|
|
22
|
+
/** What the backend decided about one purchase. */
|
|
23
|
+
export type ValidationOutcome = {
|
|
24
|
+
outcome: 'approved';
|
|
25
|
+
} | {
|
|
26
|
+
outcome: 'rejected';
|
|
27
|
+
reason?: string;
|
|
28
|
+
} | {
|
|
29
|
+
outcome: 'granted_pending_revalidation';
|
|
30
|
+
};
|
|
31
|
+
export declare function createReceiptValidation(deps: ReceiptValidationDeps): {
|
|
32
|
+
askHook: (hook: NonNullable<PaymentConfig["validateTransaction"]>, candidate: Parameters<NonNullable<PaymentConfig["validateTransaction"]>>[0]) => Promise<import("../index.js").ValidationDecision>;
|
|
33
|
+
validate: (purchase: ProviderPurchase, productKey: ProductKey, correlationId: string) => Promise<{
|
|
34
|
+
outcome: "approved";
|
|
35
|
+
} | {
|
|
36
|
+
outcome: "rejected";
|
|
37
|
+
reason?: string;
|
|
38
|
+
} | {
|
|
39
|
+
outcome: "granted_pending_revalidation";
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=receiptValidation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"receiptValidation.d.ts","sourceRoot":"","sources":["../../../../src/engine/receiptValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAAuB,CAAC;AAI/D,MAAM,WAAW,qBAAqB;IACrC,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACzC;AAED,mDAAmD;AACnD,MAAM,MAAM,iBAAiB,GAC1B;IAAE,OAAO,EAAE,UAAU,CAAA;CAAE,GACvB;IAAE,OAAO,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,OAAO,EAAE,8BAA8B,CAAA;CAAE,CAAC;AAE/C,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB;oBAI3D,WAAW,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,aAC5C,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;yBAsBjE,gBAAgB,cACd,UAAU,iBACP,MAAM,KACnB,OAAO,CACP;QAAE,OAAO,EAAE,UAAU,CAAA;KAAE,GACvB;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GACxC;QAAE,OAAO,EAAE,8BAA8B,CAAA;KAAE,CAC7C;EAmCD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine's state and the one way it changes (PAY-10).
|
|
3
|
+
*
|
|
4
|
+
* Status, the persisted snapshot, entitlements and pending purchases live here
|
|
5
|
+
* with the listeners that hear about them. Every change goes through `commit`
|
|
6
|
+
* (the snapshot) or `setStatus`, so diffing and emission are written once:
|
|
7
|
+
* an entitlement is granted or revoked exactly once however many sources it has
|
|
8
|
+
* (FR-079), a renewal that changes nothing emits nothing (FR-068), and an
|
|
9
|
+
* unchanged map is the same object (PERF-03).
|
|
10
|
+
*/
|
|
11
|
+
import { type ListenerSet } from '@chipmobilesdk/rn-core';
|
|
12
|
+
import type { ProviderPort } from '../adapter/port.js';
|
|
13
|
+
import type { ResolvedConfig } from '../config/validate.js';
|
|
14
|
+
import type { PaymentConfig, PaymentStatus, PendingPurchasesState } from '../config/types.js';
|
|
15
|
+
import { type PaymentEmitter, type PaymentEventInput } from '../diagnostics/events.js';
|
|
16
|
+
import { type EntitlementMap } from '../entitlements/aggregate.js';
|
|
17
|
+
import type { SnapshotStore } from '../persistence/mmkv-store.js';
|
|
18
|
+
import { type PersistedSnapshot } from '../persistence/snapshot.js';
|
|
19
|
+
export interface EngineState {
|
|
20
|
+
readonly config: PaymentConfig;
|
|
21
|
+
readonly resolved: ResolvedConfig;
|
|
22
|
+
readonly provider: ProviderPort;
|
|
23
|
+
readonly store: SnapshotStore;
|
|
24
|
+
readonly now: () => number;
|
|
25
|
+
readonly emitter: PaymentEmitter;
|
|
26
|
+
readonly statusListeners: ListenerSet<[PaymentStatus]>;
|
|
27
|
+
readonly entitlementListeners: ListenerSet<[EntitlementMap]>;
|
|
28
|
+
readonly pendingListeners: ListenerSet<[PendingPurchasesState]>;
|
|
29
|
+
disposed: boolean;
|
|
30
|
+
/** Whether the snapshot comes from a sync that succeeded; until then entitlements are `unknown`. */
|
|
31
|
+
hasSynced: boolean;
|
|
32
|
+
snapshot: PersistedSnapshot;
|
|
33
|
+
entitlements: EntitlementMap;
|
|
34
|
+
status: PaymentStatus;
|
|
35
|
+
pending: PendingPurchasesState;
|
|
36
|
+
emit(event: PaymentEventInput): void;
|
|
37
|
+
setStatus(next: Partial<PaymentStatus>): void;
|
|
38
|
+
/** Writes the snapshot, reports pending purchases that ended, and recomputes. */
|
|
39
|
+
commit(next: PersistedSnapshot): void;
|
|
40
|
+
/** Loads the persisted snapshot at startup (FR-053). */
|
|
41
|
+
hydrate(): void;
|
|
42
|
+
/** Forgets everything local, back to `unknown` (FR-057). */
|
|
43
|
+
forget(): void;
|
|
44
|
+
}
|
|
45
|
+
export declare function createEngineState(config: PaymentConfig, resolved: ResolvedConfig, provider: ProviderPort, store: SnapshotStore, now: () => number): EngineState;
|
|
46
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/engine/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,oBAAiB,CAAC;AAE3F,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EACtB,MAAM,0BAAuB,CAAC;AAC/B,OAAO,EAKN,KAAK,cAAc,EACnB,MAAM,8BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA2B,CAAC;AAC/D,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AAKhF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,oBAAoB,EAAE,WAAW,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAEhE,QAAQ,EAAE,OAAO,CAAC;IAClB,oGAAoG;IACpG,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,YAAY,EAAE,cAAc,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,qBAAqB,CAAC;IAE/B,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;IAC9C,iFAAiF;IACjF,MAAM,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,wDAAwD;IACxD,OAAO,IAAI,IAAI,CAAC;IAChB,4DAA4D;IAC5D,MAAM,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,MAAM,MAAM,GACf,WAAW,CAsLb"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subscription plan changes and the route to the store's management screen (US12).
|
|
3
|
+
*
|
|
4
|
+
* Two platform rules drive this module:
|
|
5
|
+
*
|
|
6
|
+
* - **Proration is the app's decision, inside what the store permits** (FR-065).
|
|
7
|
+
* Whether a user who upgrades gets charged immediately, keeps their remaining
|
|
8
|
+
* time, or starts a fresh period is a product and pricing choice, so the
|
|
9
|
+
* package forwards it rather than picking.
|
|
10
|
+
* - **Cancellation belongs to the store.** Platforms forbid an app presenting its
|
|
11
|
+
* own cancellation screen, so this module offers only a route to the store's
|
|
12
|
+
* (FR-066) — there is deliberately no self-built alternative anywhere in the
|
|
13
|
+
* package.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProductKey, PurchaseOptions, PurchaseResult } from '../config/types.js';
|
|
16
|
+
import type { ResolvedConfig } from '../config/validate.js';
|
|
17
|
+
import type { ProviderPort } from '../adapter/port.js';
|
|
18
|
+
import type { PersistedSnapshot } from '../persistence/snapshot.js';
|
|
19
|
+
/**
|
|
20
|
+
* How already-paid time is handled when a plan changes.
|
|
21
|
+
*
|
|
22
|
+
* Named for the user-visible effect rather than mirroring a store's enum, so the
|
|
23
|
+
* same vocabulary will map onto StoreKit later (FR-004).
|
|
24
|
+
*/
|
|
25
|
+
export type ProrationMode =
|
|
26
|
+
/** Switch now; credit unused time against the new plan. The usual upgrade. */
|
|
27
|
+
'immediate_with_time_proration'
|
|
28
|
+
/** Switch now; charge the full new price immediately and restart the period. */
|
|
29
|
+
| 'immediate_and_charge_full_price'
|
|
30
|
+
/** Switch now; charge the prorated difference for the current period. */
|
|
31
|
+
| 'immediate_and_charge_prorated_price'
|
|
32
|
+
/** Keep the current plan until it expires, then start the new one. Usual downgrade. */
|
|
33
|
+
| 'deferred';
|
|
34
|
+
export type PriceChangeResult = {
|
|
35
|
+
kind: 'confirmed';
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'dismissed';
|
|
38
|
+
}
|
|
39
|
+
/** The platform has no client-side flow; it notifies the user itself (FR-067). */
|
|
40
|
+
| {
|
|
41
|
+
kind: 'unsupported';
|
|
42
|
+
} | {
|
|
43
|
+
kind: 'failed';
|
|
44
|
+
code: string;
|
|
45
|
+
};
|
|
46
|
+
export interface SubscriptionsDeps {
|
|
47
|
+
resolved: ResolvedConfig;
|
|
48
|
+
provider: ProviderPort;
|
|
49
|
+
snapshot: () => PersistedSnapshot;
|
|
50
|
+
purchase: (productKey: ProductKey, options?: PurchaseOptions & {
|
|
51
|
+
replaceProductKey?: ProductKey;
|
|
52
|
+
prorationMode?: string;
|
|
53
|
+
}) => Promise<PurchaseResult>;
|
|
54
|
+
}
|
|
55
|
+
export interface Subscriptions {
|
|
56
|
+
changePlan(fromProductKey: ProductKey, toProductKey: ProductKey, mode: ProrationMode, options?: PurchaseOptions): Promise<PurchaseResult>;
|
|
57
|
+
openManagement(productKey?: ProductKey): Promise<void>;
|
|
58
|
+
confirmPriceChange(productKey: ProductKey): Promise<PriceChangeResult>;
|
|
59
|
+
}
|
|
60
|
+
export declare function createSubscriptions(deps: SubscriptionsDeps): Subscriptions;
|
|
61
|
+
//# sourceMappingURL=subscriptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../../../src/engine/subscriptions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAiB,CAAC;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAiB,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,aAAa;AACxB,8EAA8E;AAC5E,+BAA+B;AACjC,gFAAgF;GAC9E,iCAAiC;AACnC,yEAAyE;GACvE,qCAAqC;AACvC,uFAAuF;GACrF,UAAU,CAAC;AAUd,MAAM,MAAM,iBAAiB,GAC1B;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE;AACvB,kFAAkF;GAChF;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;IAClC,QAAQ,EAAE,CACT,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,eAAe,GAAG;QAAE,iBAAiB,CAAC,EAAE,UAAU,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,KAClF,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC7B,UAAU,CACT,cAAc,EAAE,UAAU,EAC1B,YAAY,EAAE,UAAU,EACxB,IAAI,EAAE,aAAa,EACnB,OAAO,CAAC,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3B,cAAc,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAwE1E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Syncing with the store, and the one translation from a store purchase to a
|
|
3
|
+
* persisted record (PAY-10).
|
|
4
|
+
*
|
|
5
|
+
* The purchase flow and sync both build records here, so they cannot disagree
|
|
6
|
+
* about what a transaction still owes: a disagreement is how a paid purchase
|
|
7
|
+
* goes unacknowledged and is refunded three days later.
|
|
8
|
+
*/
|
|
9
|
+
import type { ProviderPurchase } from '../adapter/port.js';
|
|
10
|
+
import type { ProductKey } from '../config/types.js';
|
|
11
|
+
import type { ResolvedConfig } from '../config/validate.js';
|
|
12
|
+
import { PaymentError } from '../diagnostics/errors.js';
|
|
13
|
+
import type { SyncTrigger } from '../diagnostics/events.js';
|
|
14
|
+
import { type PersistedPurchase } from '../persistence/snapshot.js';
|
|
15
|
+
import type { EngineState } from './state.js';
|
|
16
|
+
export type SyncOutcome = {
|
|
17
|
+
ok: true;
|
|
18
|
+
restoredCount: number;
|
|
19
|
+
revokedCount: number;
|
|
20
|
+
} | {
|
|
21
|
+
ok: false;
|
|
22
|
+
error: PaymentError;
|
|
23
|
+
};
|
|
24
|
+
/** The persisted record for one store purchase, keeping what we already knew about it. */
|
|
25
|
+
export declare function toPersistedRecord(resolved: ResolvedConfig, purchase: ProviderPurchase, productKey: ProductKey, existing: PersistedPurchase | undefined): PersistedPurchase;
|
|
26
|
+
export interface Sync {
|
|
27
|
+
sync(trigger?: SyncTrigger): Promise<SyncOutcome>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `settle` runs after every successful sync, outside the sync flight: the finalize
|
|
31
|
+
* drain and backend revalidation (FR-039, FR-042, FR-072a). Inside the flight, one
|
|
32
|
+
* store call or hook that never answered held it, and every later sync joined
|
|
33
|
+
* that stuck promise for the rest of the session.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createSync(state: EngineState, settle: () => Promise<void>): Sync;
|
|
36
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/engine/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAAuB,CAAC;AAGzD,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAS,CAAC;AAE3C,MAAM,MAAM,WAAW,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEhG,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GACrC,iBAAiB,CAgBnB;AAkCD,MAAM,WAAW,IAAI;IACpB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAClD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAyEhF"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entitlement aggregation — the package's primary output.
|
|
3
|
+
*
|
|
4
|
+
* Everything else exists to make this one answer correct. The most damaging
|
|
5
|
+
* defect class in a payment SDK lives here: collapsing "not yet synced" into "not
|
|
6
|
+
* entitled" makes a paying user watch ads flash on cold start or see a purchased
|
|
7
|
+
* feature sit locked.
|
|
8
|
+
*
|
|
9
|
+
* Two rules do most of the work:
|
|
10
|
+
*
|
|
11
|
+
* - **A pending purchase is never a source** (FR-037). Enforced here, in
|
|
12
|
+
* aggregation, rather than at each call site, so no future code path can grant
|
|
13
|
+
* on money that has not arrived.
|
|
14
|
+
* - **Uncertainty resolves to `unknown`, never `not_entitled`** (FR-047,
|
|
15
|
+
* FR-055a). Never synced, stale, or scope-changed all mean "we do not know",
|
|
16
|
+
* and the package says so rather than asserting the user did not pay.
|
|
17
|
+
*/
|
|
18
|
+
import type { ResolvedConfig } from '../config/validate.js';
|
|
19
|
+
import type { EntitlementKey, ProductKey } from '../config/types.js';
|
|
20
|
+
import type { PersistedSnapshot } from '../persistence/snapshot.js';
|
|
21
|
+
import { type RenewalState } from './policy.js';
|
|
22
|
+
export type EntitlementStatus = 'unknown' | 'entitled' | 'not_entitled';
|
|
23
|
+
export interface SubscriptionDetail {
|
|
24
|
+
expiresAt?: number;
|
|
25
|
+
willAutoRenew: boolean;
|
|
26
|
+
isCancelledButValid: boolean;
|
|
27
|
+
renewalState: RenewalState;
|
|
28
|
+
}
|
|
29
|
+
export interface EntitlementState {
|
|
30
|
+
key: EntitlementKey;
|
|
31
|
+
status: EntitlementStatus;
|
|
32
|
+
/** The app's own product keys currently granting this. Never raw transactions (FR-051). */
|
|
33
|
+
sources: ProductKey[];
|
|
34
|
+
subscription?: SubscriptionDetail;
|
|
35
|
+
lastSyncedAt?: number;
|
|
36
|
+
/** True once the snapshot is older than `staleAfterMs`; status is then `unknown`. */
|
|
37
|
+
isStale: boolean;
|
|
38
|
+
}
|
|
39
|
+
export type EntitlementMap = Record<EntitlementKey, EntitlementState>;
|
|
40
|
+
export interface AggregateInput {
|
|
41
|
+
config: ResolvedConfig;
|
|
42
|
+
snapshot: PersistedSnapshot;
|
|
43
|
+
/** False until the first successful sync of this session or a hydrated one. */
|
|
44
|
+
hasSynced: boolean;
|
|
45
|
+
reportsGraceAndHoldDistinctly: boolean;
|
|
46
|
+
now: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Computes the full entitlement map.
|
|
50
|
+
*
|
|
51
|
+
* Pure and synchronous by design: it runs on render paths, so it must never
|
|
52
|
+
* touch I/O (PERF-001). The engine calls it after any state change and caches the
|
|
53
|
+
* result.
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* How far the snapshot can be trusted right now.
|
|
57
|
+
*
|
|
58
|
+
* Shared by entitlements and the pending set (FR-103) so the two can never
|
|
59
|
+
* disagree about whether the package knows anything — a paywall that showed
|
|
60
|
+
* "not entitled" next to "nothing pending" from one stale snapshot would offer
|
|
61
|
+
* Buy to a user whose payment is in flight.
|
|
62
|
+
*/
|
|
63
|
+
export declare function snapshotCertainty(input: {
|
|
64
|
+
config: Pick<ResolvedConfig, 'staleAfterMs'>;
|
|
65
|
+
snapshot: Pick<PersistedSnapshot, 'lastSyncedAt'>;
|
|
66
|
+
hasSynced: boolean;
|
|
67
|
+
now: number;
|
|
68
|
+
}): {
|
|
69
|
+
isStale: boolean;
|
|
70
|
+
undetermined: boolean;
|
|
71
|
+
};
|
|
72
|
+
export declare function aggregate(input: AggregateInput): EntitlementMap;
|
|
73
|
+
/** The initial map, before anything is known. Every key starts at `unknown` (FR-047). */
|
|
74
|
+
export declare function initialEntitlements(config: ResolvedConfig): EntitlementMap;
|
|
75
|
+
export interface EntitlementChange {
|
|
76
|
+
key: EntitlementKey;
|
|
77
|
+
previous: EntitlementStatus;
|
|
78
|
+
next: EntitlementStatus;
|
|
79
|
+
sources: ProductKey[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Diffs two maps to produce change signals.
|
|
83
|
+
*
|
|
84
|
+
* Emitting from a diff rather than from grant call sites is what makes the
|
|
85
|
+
* exactly-once guarantees structural (FR-079): a successful subscription renewal
|
|
86
|
+
* changes no status, so it produces no event and cannot double-signal (FR-068);
|
|
87
|
+
* and an entitlement with three sources fires once on transition, not once per
|
|
88
|
+
* source.
|
|
89
|
+
*/
|
|
90
|
+
export declare function diffEntitlements(previous: EntitlementMap, next: EntitlementMap): EntitlementChange[];
|
|
91
|
+
/**
|
|
92
|
+
* `next`, with every entitlement that did not change replaced by the object it
|
|
93
|
+
* replaces, and `previous` itself when nothing changed (PERF-03, PAY-08). A hook
|
|
94
|
+
* selecting one entitlement then sees the same object and does not re-render.
|
|
95
|
+
*/
|
|
96
|
+
export declare function shareUnchanged(previous: EntitlementMap, next: EntitlementMap): EntitlementMap;
|
|
97
|
+
//# sourceMappingURL=aggregate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../../../src/entitlements/aggregate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAiB,CAAC;AAClE,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,4BAAyB,CAAC;AAEpF,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,aAAU,CAAC;AAEhG,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,GAAG,cAAc,CAAC;AAExE,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAChC,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,2FAA2F;IAC3F,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,+EAA+E;IAC/E,SAAS,EAAE,OAAO,CAAC;IACnB,6BAA6B,EAAE,OAAO,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;CACZ;AAkED;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACxC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;IAC7C,QAAQ,EAAE,IAAI,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAAC;IAClD,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACZ,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAS9C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc,CAuB/D;AAED,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CAY1E;AAED,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,cAAc,CAAC;IACpB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,IAAI,EAAE,iBAAiB,CAAC;IACxB,OAAO,EAAE,UAAU,EAAE,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,cAAc,EACxB,IAAI,EAAE,cAAc,GAClB,iBAAiB,EAAE,CAerB;AAaD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,GAAG,cAAc,CAe7F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product ↔ entitlement indexing.
|
|
3
|
+
*
|
|
4
|
+
* The relation is many-to-many (FR-010): monthly, yearly, and lifetime products
|
|
5
|
+
* may all grant `no_ads`, and one bundle product may grant several entitlements.
|
|
6
|
+
*
|
|
7
|
+
* Both directions are indexed once at configure time. The reverse direction is
|
|
8
|
+
* what makes two requirements cheap on hot paths: naming which product currently
|
|
9
|
+
* grants an entitlement (FR-051), and keeping an entitlement valid while *any*
|
|
10
|
+
* source remains (FR-052).
|
|
11
|
+
*/
|
|
12
|
+
import type { ResolvedConfig } from '../config/validate.js';
|
|
13
|
+
import type { EntitlementKey, ProductKey } from '../config/types.js';
|
|
14
|
+
/** Entitlements a product confers. Empty for an unknown key rather than throwing. */
|
|
15
|
+
export declare function entitlementsFor(config: ResolvedConfig, productKey: ProductKey): readonly EntitlementKey[];
|
|
16
|
+
/**
|
|
17
|
+
* Translates a store product id back to the app's own product key.
|
|
18
|
+
*
|
|
19
|
+
* Needed because store callbacks and `queryOwned` speak in store ids, while
|
|
20
|
+
* everything above the adapter speaks in product keys (FR-003). Returns
|
|
21
|
+
* `undefined` for an id absent from the catalog — which happens legitimately when
|
|
22
|
+
* a user owns something from a build whose catalog has since changed, so it must
|
|
23
|
+
* be handled rather than treated as impossible.
|
|
24
|
+
*/
|
|
25
|
+
export declare function productKeyForStoreId(config: ResolvedConfig, storeProductId: string): ProductKey | undefined;
|
|
26
|
+
export declare function storeIdForProductKey(config: ResolvedConfig, productKey: ProductKey): string | undefined;
|
|
27
|
+
//# sourceMappingURL=mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../../../../src/entitlements/mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAiB,CAAC;AAElE,qFAAqF;AACrF,wBAAgB,eAAe,CAC9B,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,UAAU,GACpB,SAAS,cAAc,EAAE,CAE3B;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,cAAc,EACtB,cAAc,EAAE,MAAM,GACpB,UAAU,GAAG,SAAS,CAExB;AAED,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,cAAc,EACtB,UAAU,EAAE,UAAU,GACpB,MAAM,GAAG,SAAS,CAEpB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grace and hold entitlement policy.
|
|
3
|
+
*
|
|
4
|
+
* This is a **business decision, not a technical constant** (FR-049), so it is
|
|
5
|
+
* configurable with documented defaults.
|
|
6
|
+
*
|
|
7
|
+
* ## The defaults, and why
|
|
8
|
+
*
|
|
9
|
+
* `gracePolicy: 'grant'` — a grace period means the store is still retrying a
|
|
10
|
+
* payment method that failed for reasons usually outside the user's control: an
|
|
11
|
+
* expired card, a bank decline, a temporary hold. Revoking immediately punishes a
|
|
12
|
+
* paying customer for a billing hiccup they may not know about yet.
|
|
13
|
+
*
|
|
14
|
+
* `holdPolicy: 'withhold'` — account hold means the store has given up retrying.
|
|
15
|
+
* The subscription is effectively unpaid, and continuing to serve paid features
|
|
16
|
+
* indefinitely is giving away the product.
|
|
17
|
+
*
|
|
18
|
+
* ## What Android can actually tell us
|
|
19
|
+
*
|
|
20
|
+
* Client-side Play Billing **cannot** separate grace from hold: a grace-period
|
|
21
|
+
* subscription is still returned as active, and one in account hold stops being
|
|
22
|
+
* returned at all — indistinguishable from expired, cancelled, or refunded.
|
|
23
|
+
*
|
|
24
|
+
* Fortunately the platform's own behavior matches the defaults above. Play keeps
|
|
25
|
+
* returning a grace-period purchase, so the entitlement holds. Play stops
|
|
26
|
+
* returning a held one, so it lapses at the next sync. **The default policy is
|
|
27
|
+
* therefore correct with no backend at all.**
|
|
28
|
+
*
|
|
29
|
+
* What is *not* achievable client-side is a non-default policy — withholding
|
|
30
|
+
* during grace, or granting during hold — because that needs the state the client
|
|
31
|
+
* cannot see. Such an app supplies it through the validation hook (FR-069). This
|
|
32
|
+
* limitation is documented rather than papered over (FR-058).
|
|
33
|
+
*/
|
|
34
|
+
import type { LapsePolicy } from '../config/types.js';
|
|
35
|
+
/**
|
|
36
|
+
* A subscription's renewal state as far as the package can honestly tell.
|
|
37
|
+
*
|
|
38
|
+
* `indeterminate` is not a failure — it is the truthful answer when the platform
|
|
39
|
+
* reports a subscription as active but cannot say whether that is a healthy
|
|
40
|
+
* renewal, a cancelled-but-still-paid period, or a grace period.
|
|
41
|
+
*/
|
|
42
|
+
export type RenewalState = 'active' | 'cancelled_valid' | 'grace' | 'hold' | 'indeterminate';
|
|
43
|
+
export interface LapsePolicyConfig {
|
|
44
|
+
gracePolicy: LapsePolicy;
|
|
45
|
+
holdPolicy: LapsePolicy;
|
|
46
|
+
}
|
|
47
|
+
export interface SubscriptionFacts {
|
|
48
|
+
expiresAt?: number;
|
|
49
|
+
willAutoRenew?: boolean;
|
|
50
|
+
/** True only where the provider genuinely distinguishes grace/hold. */
|
|
51
|
+
reportsGraceAndHoldDistinctly: boolean;
|
|
52
|
+
/** Provider-reported, only meaningful when the flag above is true. */
|
|
53
|
+
providerRenewalState?: 'active' | 'grace' | 'hold';
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Derives the renewal state without inventing information.
|
|
57
|
+
*
|
|
58
|
+
* The temptation is to read `willAutoRenew === false` as "grace period", but that
|
|
59
|
+
* same value is what a deliberate cancellation looks like. Guessing would mean
|
|
60
|
+
* showing "there's a problem with your payment method" to someone who simply
|
|
61
|
+
* chose not to renew — so when the provider cannot distinguish, neither do we.
|
|
62
|
+
*/
|
|
63
|
+
export declare function deriveRenewalState(facts: SubscriptionFacts): RenewalState;
|
|
64
|
+
/**
|
|
65
|
+
* Whether a subscription in this state should confer its entitlement.
|
|
66
|
+
*
|
|
67
|
+
* `hold` reaching this function at all requires a provider that reports it,
|
|
68
|
+
* which Android does not. On Android a held subscription simply stops being
|
|
69
|
+
* returned, so it never becomes a source and the entitlement lapses — the same
|
|
70
|
+
* result the `withhold` default expresses.
|
|
71
|
+
*/
|
|
72
|
+
export declare function grantsUnderPolicy(state: RenewalState, policy: LapsePolicyConfig): boolean;
|
|
73
|
+
/** True once a subscription's paid period has genuinely elapsed (FR-048). */
|
|
74
|
+
export declare function hasExpired(expiresAt: number | undefined, now: number): boolean;
|
|
75
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../../src/entitlements/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAiB,CAAC;AAEnD;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,eAAe,CAAC;AAE7F,MAAM,WAAW,iBAAiB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,uEAAuE;IACvE,6BAA6B,EAAE,OAAO,CAAC;IACvC,sEAAsE;IACtE,oBAAoB,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAwBzE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAczF;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE9E"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@chipmobilesdk/rn-payment` — reusable in-app payment and entitlement
|
|
3
|
+
* capability for ChipMobileSdk-family React Native apps.
|
|
4
|
+
*
|
|
5
|
+
* This is the public entrypoint (LIB-003). Modules under `config/`, `core/`,
|
|
6
|
+
* `engine/`, `entitlements/`, `persistence/`, `adapter/`, `diagnostics/`, and
|
|
7
|
+
* `react/` are private; import them only through this file. The fake store lives
|
|
8
|
+
* behind `@chipmobilesdk/rn-payment/testing` so test doubles cannot reach a
|
|
9
|
+
* production bundle.
|
|
10
|
+
*
|
|
11
|
+
* Nothing exported here names Google, Play Billing, or `react-native-iap`
|
|
12
|
+
* (FR-002). `src/__tests__/public-api.test.ts` asserts that mechanically.
|
|
13
|
+
*
|
|
14
|
+
* The package owns **capability**: a safe, consistent way to sell, finalize,
|
|
15
|
+
* restore, and report entitlements. The consuming app owns **policy** — what is
|
|
16
|
+
* sold, at what price, on which screen, at which moment, what each entitlement
|
|
17
|
+
* unlocks, and how generous the grace policy is. There is no product identifier,
|
|
18
|
+
* no screen name, and no business rule in this package (FR-016).
|
|
19
|
+
*
|
|
20
|
+
* The one output that matters most is the **entitlement key**: an app-chosen key
|
|
21
|
+
* such as `no_ads`. Business logic asks about entitlement keys and never about
|
|
22
|
+
* store product identifiers, product types, or which store sold the thing.
|
|
23
|
+
*/
|
|
24
|
+
export type { BackoffConfig, BlockedOperation, CatalogEntry, EntitlementKey, Environment, FinalizeResult, LapsePolicy, LoggerAdapter, PaymentConfig, PaymentStatus, PaymentStatusKind, PendingPurchase, PendingPurchasesState, PendingResolution, ProductKey, ProductType, PurchaseOptions, PurchaseResult, RetryConfig, StoreProductIds, TimeoutConfig, TransactionRef, UnavailableReason, UnfinalizedSummary, Unsubscribe, ValidationCandidate, ValidationDecision, ValidationHook, ValidationUnavailablePolicy, } from './config/types.js';
|
|
25
|
+
export { BACKOFF_ATTEMPT_BOUNDS, BACKOFF_MAX_DELAY_BOUNDS, CONNECT_TIMEOUT_BOUNDS, DEFAULT_CONNECT_TIMEOUT_MS, DEFAULT_FINALIZE_ATTEMPT_TIMEOUT_MS, DEFAULT_FINALIZE_BACKOFF, DEFAULT_FOREGROUND_SYNC_MIN_INTERVAL_MS, DEFAULT_PRODUCT_CACHE_TTL_MS, DEFAULT_PRODUCT_QUERY_TIMEOUT_MS, DEFAULT_PURCHASE_LAUNCH_TIMEOUT_MS, DEFAULT_RECONNECT_BACKOFF, DEFAULT_STALE_AFTER_MS, DEFAULT_SYNC_TIMEOUT_MS, FINALIZE_ATTEMPT_TIMEOUT_BOUNDS, FOREGROUND_SYNC_MIN_INTERVAL_BOUNDS, PRODUCT_CACHE_TTL_BOUNDS, PRODUCT_QUERY_TIMEOUT_BOUNDS, PURCHASE_LAUNCH_TIMEOUT_BOUNDS, STALE_AFTER_BOUNDS, SYNC_TIMEOUT_BOUNDS, } from './core/timers.js';
|
|
26
|
+
export type { MissingProduct, MissingProductReason, Offer, ProductInfo, ProductQueryResult, } from './engine/products.js';
|
|
27
|
+
export type { PriceChangeResult, ProrationMode } from './engine/subscriptions.js';
|
|
28
|
+
export type { EntitlementMap, EntitlementState, EntitlementStatus, SubscriptionDetail, } from './entitlements/aggregate.js';
|
|
29
|
+
export type { RenewalState } from './entitlements/policy.js';
|
|
30
|
+
export { createStoreProvider } from './adapter/createStoreProvider.js';
|
|
31
|
+
export type { StoreProviderOptions } from './adapter/createStoreProvider.js';
|
|
32
|
+
export { createEngine } from './engine/engine.js';
|
|
33
|
+
export type { EngineDeps, InitOutcome, PaymentEngine, RestoreOutcome, SyncOutcome, } from './engine/engine.js';
|
|
34
|
+
export { syncOnForeground } from './engine/foreground.js';
|
|
35
|
+
export { PaymentProvider, usePaymentEngine } from './react/PaymentProvider.js';
|
|
36
|
+
export type { PaymentProviderProps } from './react/PaymentProvider.js';
|
|
37
|
+
export { useEntitlement, useEntitlements, usePaymentStatus, usePendingPurchases, useProducts, usePurchase, useSync, } from './react/hooks.js';
|
|
38
|
+
export type { UseProductsResult, UsePurchaseResult, UseSyncResult } from './react/hooks.js';
|
|
39
|
+
export { PaymentConfigError, PaymentError, PAYMENT_ERROR_CODES } from './diagnostics/errors.js';
|
|
40
|
+
export type { PaymentErrorCode, PaymentOperation } from './diagnostics/errors.js';
|
|
41
|
+
export type { PaymentEvent, PaymentEventListener, PaymentEventType, SyncTrigger, } from './diagnostics/events.js';
|
|
42
|
+
export { DEFAULT_DEVELOPER_MESSAGES, DEFAULT_MESSAGES, paymentMessages, DEFAULT_USER_MESSAGES, DEVELOPER_MESSAGE_KEYS, USER_MESSAGE_KEYS, isUserMessageKey, } from './diagnostics/messageKeys.js';
|
|
43
|
+
export type { PaymentDeveloperMessageKey, PaymentDeveloperMessageMap, PaymentMessageKey, PaymentMessageMap, PaymentUserMessageKey, PaymentUserMessageMap, } from './diagnostics/messageKeys.js';
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,YAAY,EACX,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,WAAW,EACX,cAAc,EACd,WAAW,EACX,aAAa,EACb,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,WAAW,EACX,eAAe,EACf,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,2BAA2B,GAC3B,MAAM,mBAAgB,CAAC;AAKxB,OAAO,EACN,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,EAC1B,mCAAmC,EACnC,wBAAwB,EACxB,uCAAuC,EACvC,4BAA4B,EAC5B,gCAAgC,EAChC,kCAAkC,EAClC,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,+BAA+B,EAC/B,mCAAmC,EACnC,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,EAC9B,kBAAkB,EAClB,mBAAmB,GACnB,MAAM,kBAAe,CAAC;AAGvB,YAAY,EACX,cAAc,EACd,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,kBAAkB,GAClB,MAAM,sBAAmB,CAAC;AAG3B,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,2BAAwB,CAAC;AAG/E,YAAY,EACX,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GAClB,MAAM,6BAA0B,CAAC;AAClC,YAAY,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AAO1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAA+B,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,kCAA+B,CAAC;AAG1E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAiB,CAAC;AAC/C,YAAY,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,cAAc,EACd,WAAW,GACX,MAAM,oBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAqB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,4BAAyB,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,MAAM,4BAAyB,CAAC;AACpE,OAAO,EACN,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,OAAO,GACP,MAAM,kBAAe,CAAC;AACvB,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,kBAAe,CAAC;AAGzF,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,yBAAsB,CAAC;AAC7F,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,yBAAsB,CAAC;AAC/E,YAAY,EACX,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,GACX,MAAM,yBAAsB,CAAC;AAK9B,OAAO,EACN,0BAA0B,EAC1B,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,8BAA2B,CAAC;AACnC,YAAY,EACX,0BAA0B,EAC1B,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,GACrB,MAAM,8BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMKV-backed snapshot store.
|
|
3
|
+
*
|
|
4
|
+
* Every MMKV import is confined to this file, so the rest of the package stays
|
|
5
|
+
* testable without a native module.
|
|
6
|
+
*
|
|
7
|
+
* MMKV is chosen because it is **synchronous**, which is what lets
|
|
8
|
+
* `getEntitlement` be an in-memory read with no I/O on render paths (PERF-001).
|
|
9
|
+
* An async store would force either an async entitlement read or a hidden
|
|
10
|
+
* hydration race on every call.
|
|
11
|
+
*
|
|
12
|
+
* Records are partitioned by cache-scope token (FR-057a). The token is a
|
|
13
|
+
* partition key and nothing more: never interpreted, never transmitted, never
|
|
14
|
+
* attached to a transaction.
|
|
15
|
+
*/
|
|
16
|
+
import { type MmkvLike } from '@chipmobilesdk/rn-core';
|
|
17
|
+
import { type PersistedSnapshot } from './snapshot.js';
|
|
18
|
+
export interface SnapshotStore {
|
|
19
|
+
load(scopeToken?: string): PersistedSnapshot;
|
|
20
|
+
/**
|
|
21
|
+
* Writes the snapshot. Returns false when the write failed, so the engine can
|
|
22
|
+
* say so; a store returning nothing is taken to have succeeded.
|
|
23
|
+
*/
|
|
24
|
+
save(snapshot: PersistedSnapshot): boolean | void;
|
|
25
|
+
/** Clears every scope — for logout and data-deletion requests (FR-057). */
|
|
26
|
+
clearAll(): void;
|
|
27
|
+
/** Whether writes actually persist. False means the memory fallback is active. */
|
|
28
|
+
isDurable(): boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates the store.
|
|
32
|
+
*
|
|
33
|
+
* The memory fallback is a **documented degradation**, not a silent one: without
|
|
34
|
+
* MMKV the snapshot does not survive a cold start, so entitlements read `unknown`
|
|
35
|
+
* until the first sync. That is safe by construction — `unknown`, never
|
|
36
|
+
* `not_entitled` (FR-047) — and FR-059's startup sync repairs it. `isDurable()`
|
|
37
|
+
* lets the engine warn, so the condition is visible rather than mysterious.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createSnapshotStore(injected?: {
|
|
40
|
+
backing: MmkvLike;
|
|
41
|
+
durable: boolean;
|
|
42
|
+
}): SnapshotStore;
|
|
43
|
+
/** Test seam for driving the store without the native module. */
|
|
44
|
+
export declare function createMemorySnapshotStore(): SnapshotStore;
|
|
45
|
+
//# sourceMappingURL=mmkv-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mmkv-store.d.ts","sourceRoot":"","sources":["../../../../src/persistence/mmkv-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAA+C,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEpG,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,eAAY,CAAC;AAcpF,MAAM,WAAW,aAAa;IAC7B,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAC7C;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,GAAG,IAAI,CAAC;IAClD,2EAA2E;IAC3E,QAAQ,IAAI,IAAI,CAAC;IACjB,kFAAkF;IAClF,SAAS,IAAI,OAAO,CAAC;CACrB;AAkCD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE;IAC9C,OAAO,EAAE,QAAQ,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CACjB,GAAG,aAAa,CA4DhB;AAED,iEAAiE;AACjE,wBAAgB,yBAAyB,IAAI,aAAa,CAYzD"}
|