@chipmobilesdk/rn-payment 0.5.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 +172 -0
- package/README.md +47 -16
- 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
- package/skills/sdk-rn-payment/SKILL.md +4 -4
- package/src/adapter/iap-adapter.ts +12 -216
- package/src/adapter/iapShapes.ts +232 -0
- package/src/config/types.ts +8 -0
- package/src/config/validate.ts +19 -4
- package/src/core/retry.ts +1 -58
- package/src/diagnostics/events.ts +1 -1
- package/src/engine/connection.ts +194 -0
- package/src/engine/engine.ts +140 -700
- package/src/engine/internals.ts +40 -0
- package/src/engine/products.ts +39 -17
- package/src/engine/purchase.ts +22 -130
- package/src/engine/purchaseFailure.ts +48 -0
- package/src/engine/receiptValidation.ts +101 -0
- package/src/engine/state.ts +253 -0
- package/src/engine/sync.ts +161 -0
- package/src/entitlements/aggregate.ts +3 -5
- package/src/entitlements/mapping.ts +0 -22
- package/src/persistence/mmkv-store.ts +10 -3
- package/src/persistence/snapshot.ts +102 -27
- package/src/react/PaymentProvider.tsx +73 -24
- package/src/react/hooks.ts +13 -3
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What tests and diagnostics need from an engine, off its public type (PAY-11).
|
|
3
|
+
*
|
|
4
|
+
* Until 0.6.0 these were methods of `PaymentEngine`, so any consumer could commit
|
|
5
|
+
* a snapshot of its own and grant itself an entitlement the store never sold,
|
|
6
|
+
* and a hand-written engine double had to implement all of them. They live in a
|
|
7
|
+
* WeakMap keyed by the engine now, and this module is not exported from the
|
|
8
|
+
* package entrypoint.
|
|
9
|
+
*/
|
|
10
|
+
import type { ProductKey } from '../config/types';
|
|
11
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
12
|
+
import type { PaymentEmitter } from '../diagnostics/events';
|
|
13
|
+
import type { PersistedSnapshot } from '../persistence/snapshot';
|
|
14
|
+
import type { PaymentEngine } from './engine';
|
|
15
|
+
export interface EngineInternals {
|
|
16
|
+
resolvedConfig(): ResolvedConfig;
|
|
17
|
+
nextCorrelationId(): string;
|
|
18
|
+
emitter(): PaymentEmitter;
|
|
19
|
+
snapshot(): PersistedSnapshot;
|
|
20
|
+
commitSnapshot(next: PersistedSnapshot): void;
|
|
21
|
+
mayCreateRealTransaction(): boolean;
|
|
22
|
+
/** Records a purchase refused because this environment may not move real money (FR-014). */
|
|
23
|
+
recordBlockedOperation(productKey: ProductKey): void;
|
|
24
|
+
}
|
|
25
|
+
export declare function attachEngineInternals(engine: PaymentEngine, internals: EngineInternals): void;
|
|
26
|
+
/** The internals of an engine `createEngine` made. Throws for any other object. */
|
|
27
|
+
export declare function engineInternals(engine: PaymentEngine): EngineInternals;
|
|
28
|
+
//# sourceMappingURL=internals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internals.d.ts","sourceRoot":"","sources":["../../../../src/engine/internals.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC/B,cAAc,IAAI,cAAc,CAAC;IACjC,iBAAiB,IAAI,MAAM,CAAC;IAC5B,OAAO,IAAI,cAAc,CAAC;IAC1B,QAAQ,IAAI,iBAAiB,CAAC;IAC9B,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC9C,wBAAwB,IAAI,OAAO,CAAC;IACpC,4FAA4F;IAC5F,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;CACrD;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,GAAG,IAAI,CAE7F;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,CAMtE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pending set, and how a pending purchase ends (FR-101 – FR-104), added in
|
|
3
|
+
* 0.2.0.
|
|
4
|
+
*
|
|
5
|
+
* 0.1.0 handled pending purchases correctly on the grant side — pending never
|
|
6
|
+
* grants, a settled one is granted at the next sync, an abandoned one is removed
|
|
7
|
+
* — but an app could only *see* one in the session it started in. The record
|
|
8
|
+
* was already persisted with a `pending` state; this module is the read side of
|
|
9
|
+
* it, and nothing more. It decides nothing about granting: that stays in
|
|
10
|
+
* `entitlements/aggregate.ts`, where pending is refused unconditionally.
|
|
11
|
+
*
|
|
12
|
+
* Pure: no provider, no I/O, no React. The engine calls it from `commit`.
|
|
13
|
+
*/
|
|
14
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
15
|
+
import type { PendingPurchasesState, PendingResolution, ProductKey } from '../config/types';
|
|
16
|
+
import type { PersistedSnapshot } from '../persistence/snapshot';
|
|
17
|
+
export declare const UNKNOWN_PENDING: PendingPurchasesState;
|
|
18
|
+
/**
|
|
19
|
+
* Derives the pending set from the snapshot.
|
|
20
|
+
*
|
|
21
|
+
* Read from the persisted record, so it survives an app kill and an offline
|
|
22
|
+
* restart, and judged by the very staleness rule entitlements use (FR-103).
|
|
23
|
+
* Products no longer in the catalog are left out: an app cannot render a row,
|
|
24
|
+
* or withhold a Buy button, for a product key it no longer has.
|
|
25
|
+
*/
|
|
26
|
+
export declare function derivePending(input: {
|
|
27
|
+
config: ResolvedConfig;
|
|
28
|
+
snapshot: PersistedSnapshot;
|
|
29
|
+
hasSynced: boolean;
|
|
30
|
+
now: number;
|
|
31
|
+
}): PendingPurchasesState;
|
|
32
|
+
export interface PendingTransition {
|
|
33
|
+
readonly productKey: ProductKey;
|
|
34
|
+
readonly outcome: PendingResolution;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every pending transaction that stopped being pending between two snapshots.
|
|
38
|
+
*
|
|
39
|
+
* Computed from the commit itself rather than at each call site that might end
|
|
40
|
+
* a pending purchase — sync, a store push, a purchase — which is what makes
|
|
41
|
+
* "exactly once" structural (FR-104, FR-079). A store push and a sync racing on
|
|
42
|
+
* one settling purchase both commit, but only the first commit sees it leave
|
|
43
|
+
* the pending set.
|
|
44
|
+
*
|
|
45
|
+
* A record that disappeared ended without payment. Why is the store's to say;
|
|
46
|
+
* when it says nothing, `cancelled` (see `PendingResolution`).
|
|
47
|
+
*/
|
|
48
|
+
export declare function pendingTransitions(previous: PersistedSnapshot, next: PersistedSnapshot, config: ResolvedConfig, endReason: (transactionId: string) => 'cancelled' | 'expired' | undefined): PendingTransition[];
|
|
49
|
+
/** Whether a listener has anything new to hear. */
|
|
50
|
+
export declare function samePending(a: PendingPurchasesState, b: PendingPurchasesState): boolean;
|
|
51
|
+
//# sourceMappingURL=pending.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../src/engine/pending.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAEX,qBAAqB,EACrB,iBAAiB,EACjB,UAAU,EACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,eAAO,MAAM,eAAe,EAAE,qBAI7B,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACpC,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACZ,GAAG,qBAAqB,CAoBxB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;CACpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,GAAG,SAAS,GACvE,iBAAiB,EAAE,CAgBrB;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAWvF"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product query, normalization, and the in-memory price cache (US11).
|
|
3
|
+
*
|
|
4
|
+
* Two rules shape this module:
|
|
5
|
+
*
|
|
6
|
+
* - **Prices come from the store, formatted.** An app must never build a price
|
|
7
|
+
* string (FR-028): only the store knows the right currency symbol, its
|
|
8
|
+
* placement, the decimal separator, and the grouping for the user's locale. A
|
|
9
|
+
* hand-built "$9.99" is wrong in most of the world.
|
|
10
|
+
* - **Offer eligibility is reported, never computed.** The store decides who
|
|
11
|
+
* qualifies for a trial or an introductory price (FR-026). Guessing locally
|
|
12
|
+
* would promise a trial the store then refuses at checkout.
|
|
13
|
+
*
|
|
14
|
+
* The cache is in **memory only** and short-lived. Persisting prices would risk
|
|
15
|
+
* showing a stale one as current in a later session, and a paywall is exactly
|
|
16
|
+
* where that matters.
|
|
17
|
+
*/
|
|
18
|
+
import type { ProductKey, ProductType } from '../config/types';
|
|
19
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
20
|
+
import type { ProviderPort } from '../adapter/port';
|
|
21
|
+
import { PaymentError } from '../diagnostics/errors';
|
|
22
|
+
import type { PaymentEventInput } from '../diagnostics/events';
|
|
23
|
+
export interface Offer {
|
|
24
|
+
offerKey: string;
|
|
25
|
+
billingPeriod: string;
|
|
26
|
+
formattedPrice: string;
|
|
27
|
+
priceAmountMicros: number;
|
|
28
|
+
currencyCode: string;
|
|
29
|
+
trialPeriod?: string;
|
|
30
|
+
introductoryPrice?: {
|
|
31
|
+
formattedPrice: string;
|
|
32
|
+
period: string;
|
|
33
|
+
cycles: number;
|
|
34
|
+
};
|
|
35
|
+
/** As the store determined it. Never computed here (FR-026). */
|
|
36
|
+
isEligible: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ProductInfo {
|
|
39
|
+
productKey: ProductKey;
|
|
40
|
+
productType: ProductType;
|
|
41
|
+
title: string;
|
|
42
|
+
description: string;
|
|
43
|
+
/** Store-formatted and locale-correct. For display (FR-024). */
|
|
44
|
+
formattedPrice: string;
|
|
45
|
+
currencyCode: string;
|
|
46
|
+
/** For comparison and sorting only — never for display (FR-028). */
|
|
47
|
+
priceAmountMicros: number;
|
|
48
|
+
offers: Offer[];
|
|
49
|
+
}
|
|
50
|
+
/** Why a requested product produced nothing, kept distinct from a network error. */
|
|
51
|
+
export type MissingProductReason = 'not_in_catalog'
|
|
52
|
+
/** Does not exist, is unapproved, or is not sold in this country (FR-027). */
|
|
53
|
+
| 'not_available_from_store';
|
|
54
|
+
export interface MissingProduct {
|
|
55
|
+
productKey: ProductKey;
|
|
56
|
+
reason: MissingProductReason;
|
|
57
|
+
}
|
|
58
|
+
export type ProductQueryResult = {
|
|
59
|
+
ok: true;
|
|
60
|
+
products: ProductInfo[];
|
|
61
|
+
/** Reported separately so an app shows an explanation, not an empty row. */
|
|
62
|
+
missing: MissingProduct[];
|
|
63
|
+
fromCache: boolean;
|
|
64
|
+
} | {
|
|
65
|
+
ok: false;
|
|
66
|
+
error: PaymentError;
|
|
67
|
+
};
|
|
68
|
+
export interface ProductsDeps {
|
|
69
|
+
resolved: ResolvedConfig;
|
|
70
|
+
provider: ProviderPort;
|
|
71
|
+
emit: (event: PaymentEventInput) => void;
|
|
72
|
+
now: () => number;
|
|
73
|
+
}
|
|
74
|
+
export interface Products {
|
|
75
|
+
get(productKeys: ProductKey[]): Promise<ProductQueryResult>;
|
|
76
|
+
/** Bypasses the cache; for a pull-to-refresh on a paywall (FR-029). */
|
|
77
|
+
refresh(productKeys: ProductKey[]): Promise<ProductQueryResult>;
|
|
78
|
+
/** Drops the cache, e.g. after a locale or account change. */
|
|
79
|
+
invalidate(): void;
|
|
80
|
+
}
|
|
81
|
+
export declare function createProducts(deps: ProductsDeps): Products;
|
|
82
|
+
//# sourceMappingURL=products.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../../../../src/engine/products.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAmB,MAAM,iBAAiB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,MAAM,WAAW,KAAK;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE;QACnB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KACf,CAAC;IACF,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED,oFAAoF;AACpF,MAAM,MAAM,oBAAoB,GAC7B,gBAAgB;AAClB,8EAA8E;GAC5E,0BAA0B,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,oBAAoB,CAAC;CAC7B;AAED,MAAM,MAAM,kBAAkB,GAC3B;IACA,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,4EAA4E;IAC5E,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;CAClB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACzC,GAAG,EAAE,MAAM,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACxB,GAAG,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC5D,uEAAuE;IACvE,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChE,8DAA8D;IAC9D,UAAU,IAAI,IAAI,CAAC;CACnB;AAiCD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,QAAQ,CA8J3D"}
|
|
@@ -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';
|
|
19
|
+
import type { ResolvedConfig, TargetPlatform } from '../config/validate';
|
|
20
|
+
import type { ProviderPort, ProviderPurchase } from '../adapter/port';
|
|
21
|
+
import type { ExclusiveOutcome } from '../core/mutex';
|
|
22
|
+
import type { PaymentEventInput } from '../diagnostics/events';
|
|
23
|
+
import type { PersistedSnapshot } from '../persistence/snapshot';
|
|
24
|
+
import type { Finalizer } from './finalize';
|
|
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,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EACX,YAAY,EACZ,gBAAgB,EAIhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,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';
|
|
9
|
+
import type { PaymentStatusKind, ProductKey, PurchaseResult } from '../config/types';
|
|
10
|
+
import type { PaymentErrorCode } from '../diagnostics/errors';
|
|
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,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,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';
|
|
13
|
+
import type { PaymentConfig, ProductKey } from '../config/types';
|
|
14
|
+
import type { ResolvedConfig, TargetPlatform } from '../config/validate';
|
|
15
|
+
import type { PaymentEventInput } from '../diagnostics/events';
|
|
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("..").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,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,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';
|
|
13
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
14
|
+
import type { PaymentConfig, PaymentStatus, PendingPurchasesState } from '../config/types';
|
|
15
|
+
import { type PaymentEmitter, type PaymentEventInput } from '../diagnostics/events';
|
|
16
|
+
import { type EntitlementMap } from '../entitlements/aggregate';
|
|
17
|
+
import type { SnapshotStore } from '../persistence/mmkv-store';
|
|
18
|
+
import { type PersistedSnapshot } from '../persistence/snapshot';
|
|
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,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAE3F,OAAO,EAEN,KAAK,cAAc,EAEnB,KAAK,iBAAiB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAKN,KAAK,cAAc,EACnB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,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';
|
|
16
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
17
|
+
import type { ProviderPort } from '../adapter/port';
|
|
18
|
+
import type { PersistedSnapshot } from '../persistence/snapshot';
|
|
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,iBAAiB,CAAC;AACnF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,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';
|
|
10
|
+
import type { ProductKey } from '../config/types';
|
|
11
|
+
import type { ResolvedConfig } from '../config/validate';
|
|
12
|
+
import { PaymentError } from '../diagnostics/errors';
|
|
13
|
+
import type { SyncTrigger } from '../diagnostics/events';
|
|
14
|
+
import { type PersistedPurchase } from '../persistence/snapshot';
|
|
15
|
+
import type { EngineState } from './state';
|
|
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,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,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';
|
|
19
|
+
import type { EntitlementKey, ProductKey } from '../config/types';
|
|
20
|
+
import type { PersistedSnapshot } from '../persistence/snapshot';
|
|
21
|
+
import { type RenewalState } from './policy';
|
|
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,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,EAAqD,KAAK,YAAY,EAAE,MAAM,UAAU,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';
|
|
13
|
+
import type { EntitlementKey, ProductKey } from '../config/types';
|
|
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,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,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"}
|