@chipmobilesdk/rn-payment 0.4.0 → 0.5.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 +482 -334
- package/README.md +925 -897
- package/package.json +52 -54
- package/skills/sdk-rn-payment/SKILL.md +175 -174
- package/src/adapter/createStoreProvider.ts +116 -118
- package/src/adapter/iap-adapter.ts +627 -660
- package/src/adapter/port.ts +209 -215
- package/src/config/types.ts +298 -310
- package/src/config/validate.ts +224 -232
- package/src/core/mutex.ts +25 -128
- package/src/core/retry.ts +95 -133
- package/src/core/timers.ts +272 -267
- package/src/diagnostics/errors.ts +124 -117
- package/src/diagnostics/events.ts +282 -266
- package/src/diagnostics/messageKeys.ts +93 -95
- package/src/engine/engine.ts +921 -999
- package/src/engine/finalize.ts +343 -346
- package/src/engine/foreground.ts +29 -0
- package/src/engine/products.ts +259 -259
- package/src/engine/purchase.ts +589 -614
- package/src/engine/subscriptions.ts +146 -157
- package/src/entitlements/aggregate.ts +261 -242
- package/src/entitlements/mapping.ts +67 -67
- package/src/entitlements/policy.ts +121 -129
- package/src/index.ts +5 -9
- package/src/persistence/mmkv-store.ts +158 -158
- package/src/persistence/snapshot.ts +220 -247
- package/src/react/PaymentProvider.tsx +90 -79
- package/src/react/hooks.ts +236 -274
- package/src/testing/conformance.ts +169 -0
- package/src/testing/fakeStore.ts +360 -393
- package/src/testing/index.ts +19 -10
|
@@ -1,118 +1,116 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Platform selection for the store adapter.
|
|
3
|
-
*
|
|
4
|
-
* This exists so the public surface never names a store. An app writes
|
|
5
|
-
* `createStoreProvider()`, not `createIapAdapter()` — the same call will pick the
|
|
6
|
-
* StoreKit adapter once iOS exists, and no consumer line changes (FR-002, FR-004,
|
|
7
|
-
* FR-007).
|
|
8
|
-
*
|
|
9
|
-
* On a platform with no adapter the result is a stub that reports
|
|
10
|
-
* `platform_unsupported` rather than throwing. That is what lets a host app start
|
|
11
|
-
* and run normally where selling is impossible, losing only the ability to sell
|
|
12
|
-
* (FR-021, FR-023).
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { Platform } from 'react-native';
|
|
16
|
-
import type { ProductType, Unsubscribe } from '../config/types';
|
|
17
|
-
import { createIapAdapter } from './iap-adapter';
|
|
18
|
-
import type {
|
|
19
|
-
ProviderCapabilities,
|
|
20
|
-
ProviderConnectOutcome,
|
|
21
|
-
ProviderPort,
|
|
22
|
-
ProviderPriceChangeOutcome,
|
|
23
|
-
ProviderProduct,
|
|
24
|
-
ProviderPurchase,
|
|
25
|
-
ProviderPurchaseOutcome,
|
|
26
|
-
} from './port';
|
|
27
|
-
|
|
28
|
-
const UNSUPPORTED_CAPABILITIES: ProviderCapabilities = {
|
|
29
|
-
supportsSubscriptions: false,
|
|
30
|
-
supportsPlanChange: false,
|
|
31
|
-
supportsPriceChangeConfirmation: false,
|
|
32
|
-
reportsGraceAndHoldDistinctly: false,
|
|
33
|
-
supportsExternalTransactions: false,
|
|
34
|
-
/** Nothing here can charge anyone, so the environment guard has nothing to block. */
|
|
35
|
-
createsRealTransactions: false,
|
|
36
|
-
purchaseOutcomeIncludesStoreTime: false,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* The no-adapter stub.
|
|
41
|
-
*
|
|
42
|
-
* Every operation fails safely and predictably. Notably `queryOwned` returns an
|
|
43
|
-
* empty list rather than throwing: the engine then computes `not_entitled` after a
|
|
44
|
-
* successful-but-empty sync, which is honest — on a platform with no store, the
|
|
45
|
-
* user genuinely holds nothing this package can verify.
|
|
46
|
-
*/
|
|
47
|
-
function createUnsupportedProvider(): ProviderPort {
|
|
48
|
-
return {
|
|
49
|
-
async connect(): Promise<ProviderConnectOutcome> {
|
|
50
|
-
return { ok: false, reason: 'platform_unsupported', retryable: false };
|
|
51
|
-
},
|
|
52
|
-
async disconnect(): Promise<void> {
|
|
53
|
-
// Nothing was ever connected.
|
|
54
|
-
},
|
|
55
|
-
observeConnection(): Unsubscribe {
|
|
56
|
-
return () => undefined;
|
|
57
|
-
},
|
|
58
|
-
async queryProducts(): Promise<ProviderProduct[]> {
|
|
59
|
-
return [];
|
|
60
|
-
},
|
|
61
|
-
async queryOwned(): Promise<ProviderPurchase[]> {
|
|
62
|
-
return [];
|
|
63
|
-
},
|
|
64
|
-
async launchPurchase(): Promise<ProviderPurchaseOutcome> {
|
|
65
|
-
return { ok: false, reason: 'not_ready', detail: 'platform_unsupported' };
|
|
66
|
-
},
|
|
67
|
-
observePurchases(): Unsubscribe {
|
|
68
|
-
return () => undefined;
|
|
69
|
-
},
|
|
70
|
-
async acknowledge(): Promise<void> {
|
|
71
|
-
// No transaction can exist to acknowledge.
|
|
72
|
-
},
|
|
73
|
-
async consume(): Promise<void> {
|
|
74
|
-
// As above.
|
|
75
|
-
},
|
|
76
|
-
async openSubscriptionManagement(): Promise<void> {
|
|
77
|
-
// No store screen to open.
|
|
78
|
-
},
|
|
79
|
-
async confirmPriceChange(): Promise<ProviderPriceChangeOutcome> {
|
|
80
|
-
return { ok: false, reason: 'not_ready' };
|
|
81
|
-
},
|
|
82
|
-
capabilities: () => UNSUPPORTED_CAPABILITIES,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface StoreProviderOptions {
|
|
87
|
-
/**
|
|
88
|
-
* Force the unsupported stub regardless of platform.
|
|
89
|
-
*
|
|
90
|
-
* Useful for an app that wants to ship one build with selling switched off at
|
|
91
|
-
* the provider level rather than through the `enabled` flag.
|
|
92
|
-
*/
|
|
93
|
-
forceUnsupported?: boolean;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* The platform's store adapter.
|
|
98
|
-
*
|
|
99
|
-
* iOS deliberately returns the stub today rather than throwing: the contract is
|
|
100
|
-
* prepared for StoreKit, the implementation is not, and an app running on iOS
|
|
101
|
-
* should degrade to "cannot sell here" instead of crashing.
|
|
102
|
-
*/
|
|
103
|
-
export function createStoreProvider(
|
|
104
|
-
options
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
export {
|
|
117
|
-
|
|
118
|
-
export type { ProductType };
|
|
1
|
+
/**
|
|
2
|
+
* Platform selection for the store adapter.
|
|
3
|
+
*
|
|
4
|
+
* This exists so the public surface never names a store. An app writes
|
|
5
|
+
* `createStoreProvider()`, not `createIapAdapter()` — the same call will pick the
|
|
6
|
+
* StoreKit adapter once iOS exists, and no consumer line changes (FR-002, FR-004,
|
|
7
|
+
* FR-007).
|
|
8
|
+
*
|
|
9
|
+
* On a platform with no adapter the result is a stub that reports
|
|
10
|
+
* `platform_unsupported` rather than throwing. That is what lets a host app start
|
|
11
|
+
* and run normally where selling is impossible, losing only the ability to sell
|
|
12
|
+
* (FR-021, FR-023).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { Platform } from 'react-native';
|
|
16
|
+
import type { ProductType, Unsubscribe } from '../config/types';
|
|
17
|
+
import { createIapAdapter } from './iap-adapter';
|
|
18
|
+
import type {
|
|
19
|
+
ProviderCapabilities,
|
|
20
|
+
ProviderConnectOutcome,
|
|
21
|
+
ProviderPort,
|
|
22
|
+
ProviderPriceChangeOutcome,
|
|
23
|
+
ProviderProduct,
|
|
24
|
+
ProviderPurchase,
|
|
25
|
+
ProviderPurchaseOutcome,
|
|
26
|
+
} from './port';
|
|
27
|
+
|
|
28
|
+
const UNSUPPORTED_CAPABILITIES: ProviderCapabilities = {
|
|
29
|
+
supportsSubscriptions: false,
|
|
30
|
+
supportsPlanChange: false,
|
|
31
|
+
supportsPriceChangeConfirmation: false,
|
|
32
|
+
reportsGraceAndHoldDistinctly: false,
|
|
33
|
+
supportsExternalTransactions: false,
|
|
34
|
+
/** Nothing here can charge anyone, so the environment guard has nothing to block. */
|
|
35
|
+
createsRealTransactions: false,
|
|
36
|
+
purchaseOutcomeIncludesStoreTime: false,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The no-adapter stub.
|
|
41
|
+
*
|
|
42
|
+
* Every operation fails safely and predictably. Notably `queryOwned` returns an
|
|
43
|
+
* empty list rather than throwing: the engine then computes `not_entitled` after a
|
|
44
|
+
* successful-but-empty sync, which is honest — on a platform with no store, the
|
|
45
|
+
* user genuinely holds nothing this package can verify.
|
|
46
|
+
*/
|
|
47
|
+
function createUnsupportedProvider(): ProviderPort {
|
|
48
|
+
return {
|
|
49
|
+
async connect(): Promise<ProviderConnectOutcome> {
|
|
50
|
+
return { ok: false, reason: 'platform_unsupported', retryable: false };
|
|
51
|
+
},
|
|
52
|
+
async disconnect(): Promise<void> {
|
|
53
|
+
// Nothing was ever connected.
|
|
54
|
+
},
|
|
55
|
+
observeConnection(): Unsubscribe {
|
|
56
|
+
return () => undefined;
|
|
57
|
+
},
|
|
58
|
+
async queryProducts(): Promise<ProviderProduct[]> {
|
|
59
|
+
return [];
|
|
60
|
+
},
|
|
61
|
+
async queryOwned(): Promise<ProviderPurchase[]> {
|
|
62
|
+
return [];
|
|
63
|
+
},
|
|
64
|
+
async launchPurchase(): Promise<ProviderPurchaseOutcome> {
|
|
65
|
+
return { ok: false, reason: 'not_ready', detail: 'platform_unsupported' };
|
|
66
|
+
},
|
|
67
|
+
observePurchases(): Unsubscribe {
|
|
68
|
+
return () => undefined;
|
|
69
|
+
},
|
|
70
|
+
async acknowledge(): Promise<void> {
|
|
71
|
+
// No transaction can exist to acknowledge.
|
|
72
|
+
},
|
|
73
|
+
async consume(): Promise<void> {
|
|
74
|
+
// As above.
|
|
75
|
+
},
|
|
76
|
+
async openSubscriptionManagement(): Promise<void> {
|
|
77
|
+
// No store screen to open.
|
|
78
|
+
},
|
|
79
|
+
async confirmPriceChange(): Promise<ProviderPriceChangeOutcome> {
|
|
80
|
+
return { ok: false, reason: 'not_ready' };
|
|
81
|
+
},
|
|
82
|
+
capabilities: () => UNSUPPORTED_CAPABILITIES,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface StoreProviderOptions {
|
|
87
|
+
/**
|
|
88
|
+
* Force the unsupported stub regardless of platform.
|
|
89
|
+
*
|
|
90
|
+
* Useful for an app that wants to ship one build with selling switched off at
|
|
91
|
+
* the provider level rather than through the `enabled` flag.
|
|
92
|
+
*/
|
|
93
|
+
forceUnsupported?: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The platform's store adapter.
|
|
98
|
+
*
|
|
99
|
+
* iOS deliberately returns the stub today rather than throwing: the contract is
|
|
100
|
+
* prepared for StoreKit, the implementation is not, and an app running on iOS
|
|
101
|
+
* should degrade to "cannot sell here" instead of crashing.
|
|
102
|
+
*/
|
|
103
|
+
export function createStoreProvider(options: StoreProviderOptions = {}): ProviderPort {
|
|
104
|
+
if (options.forceUnsupported) {
|
|
105
|
+
return createUnsupportedProvider();
|
|
106
|
+
}
|
|
107
|
+
if (Platform.OS === 'android') {
|
|
108
|
+
return createIapAdapter();
|
|
109
|
+
}
|
|
110
|
+
return createUnsupportedProvider();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Exported for a test or a screen that needs the stub explicitly. */
|
|
114
|
+
export { createUnsupportedProvider };
|
|
115
|
+
|
|
116
|
+
export type { ProductType };
|