@entitlehub/react-native 0.1.7 → 0.1.8
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 +33 -15
- package/README.md +11 -8
- package/dist/index.cjs +24 -4
- package/dist/index.d.cts +10 -11
- package/dist/index.d.ts +10 -11
- package/dist/index.js +14 -11
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,38 +1,56 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 0.1.
|
|
3
|
+
## 0.1.8 (2026-09-19)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Black screen on launch: "Requiring unknown module expo-iap".** The SDK loaded `expo-iap` with
|
|
7
|
+
`require()`. Metro decides what to bundle by reading literal `require("…")` / `import("…")` calls,
|
|
8
|
+
and the ESM build rewrote that call into esbuild's `__require` shim, which Metro cannot see. So
|
|
9
|
+
`expo-iap` was never put in the bundle, the first call threw, and React Native tore the UI down
|
|
10
|
+
with it, before the store sheet ever opened. It is now loaded with `import("expo-iap")`, which
|
|
11
|
+
survives the build as a literal. Verified by bundling a real Expo app: with 0.1.7 the store
|
|
12
|
+
library is absent from the bundle, with 0.1.8 it is there.
|
|
13
|
+
- The module now loads while `configureEntitleHub()` runs, so a missing or broken `expo-iap` raises
|
|
14
|
+
a clear error there instead of being swallowed by the store-connection catch, and handles CJS
|
|
15
|
+
interop (module namespace or `.default`).
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- `configureEntitleHub({ iap })` is no longer a workaround for the bug above, just the way to pin an
|
|
19
|
+
exact module instance or use another OpenIAP-compatible library.
|
|
20
|
+
|
|
21
|
+
## 0.1.7 (2026-07-22)
|
|
4
22
|
|
|
5
23
|
### Fixed
|
|
6
24
|
- **A completed purchase could still be reported as failed.** After a timeout, `purchaseProduct()`
|
|
7
25
|
checked for confirmation exactly once. Store notifications are asynchronous, so that single
|
|
8
|
-
reading races the grant and sometimes loses
|
|
26
|
+
reading races the grant and sometimes loses, observed live: the entitlement was written seconds
|
|
9
27
|
after the check ran, and the user saw a purchase-failed error for a purchase that worked. It now
|
|
10
28
|
polls the store and the server with backoff (`reconcileMs`, default 30s) before giving up.
|
|
11
29
|
- **The timeout counted the user's own time.** The timer was armed when `purchaseProduct()` was
|
|
12
|
-
called
|
|
30
|
+
called: before the store's password / Face ID sheet appears, so a user who paused mid-purchase
|
|
13
31
|
tripped it. It now starts once the request is actually in flight, with a separate generous
|
|
14
32
|
backstop (`sheetTimeoutMs`, default 10m) so a stuck bridge still can't hang forever.
|
|
15
33
|
|
|
16
34
|
### Changed
|
|
17
|
-
- **Rejections are now typed `PurchaseError`s
|
|
35
|
+
- **Rejections are now typed `PurchaseError`s: branch on `.code`, not the message.**
|
|
18
36
|
`purchase-cancelled`, `purchase-failed`, and the new `purchase-pending`. **`purchase-pending` is
|
|
19
|
-
not a failure**: the store took the money but hasn't confirmed yet. Show "still confirming"
|
|
37
|
+
not a failure**: the store took the money but hasn't confirmed yet. Show "still confirming", the
|
|
20
38
|
entitlement lands on its own and `addCustomerInfoUpdateListener` fires when it does. `.pending`
|
|
21
39
|
and `.customerInfo` are on the error. The old untyped `"purchase-timeout"` message is gone.
|
|
22
40
|
|
|
23
|
-
## 0.1.6
|
|
41
|
+
## 0.1.6 (2026-07-21)
|
|
24
42
|
|
|
25
43
|
### Added
|
|
26
44
|
- Reports `react-native/<version>` to EntitleHub on each call, so the dashboard can tell you when
|
|
27
|
-
your SDK is behind a release with fixes in it
|
|
45
|
+
your SDK is behind a release with fixes in it, rather than you finding out by hitting the bug.
|
|
28
46
|
Version only; no device or user data.
|
|
29
47
|
|
|
30
|
-
## 0.1.5
|
|
48
|
+
## 0.1.5 (2026-07-21)
|
|
31
49
|
|
|
32
50
|
### Fixed
|
|
33
51
|
- **`purchaseProduct()` could hang forever after a successful purchase.** It waited only on
|
|
34
52
|
`purchaseUpdatedListener`; on the react-native-iap 15+ / Nitro bridge that callback never fires,
|
|
35
|
-
so the promise never settled
|
|
53
|
+
so the promise never settled: the paywall stayed open and features stayed locked even though the
|
|
36
54
|
user had been charged and EntitleHub had already granted the entitlement server-side.
|
|
37
55
|
`requestPurchase`'s resolved value was being discarded entirely; it is now honoured, so bridges
|
|
38
56
|
that resolve instead of emitting an event work.
|
|
@@ -40,14 +58,14 @@
|
|
|
40
58
|
### Added
|
|
41
59
|
- Reconciliation safety net: if no result arrives within `timeoutMs` (default 120s),
|
|
42
60
|
`purchaseProduct()` re-reads `getAvailablePurchases()` and, failing that, re-checks entitlements
|
|
43
|
-
from the server
|
|
61
|
+
from the server: resolving successfully if the entitlement appeared while the client was waiting.
|
|
44
62
|
Only rejects (`"purchase-timeout"`) when nothing was actually granted.
|
|
45
63
|
- `purchaseProduct(id, { timeoutMs })` to tune that window.
|
|
46
64
|
|
|
47
|
-
## 0.1.2
|
|
65
|
+
## 0.1.2 (2026-07-18)
|
|
48
66
|
|
|
49
67
|
### Added
|
|
50
|
-
- `configureEntitleHub({ iap })
|
|
68
|
+
- `configureEntitleHub({ iap })`: inject the OpenIAP-compatible store module (pinned expo-iap
|
|
51
69
|
version, or react-native-iap) instead of the hard-coded `expo-iap`. Decouples this SDK from a
|
|
52
70
|
single store-library version so you can work around a native issue without changing the SDK.
|
|
53
71
|
|
|
@@ -56,17 +74,17 @@
|
|
|
56
74
|
thread) are a store-library-version concern; how to pin a version, inject a module, or fall back
|
|
57
75
|
to the fully-decoupled `@entitlehub/sdk` + your own billing library.
|
|
58
76
|
|
|
59
|
-
## 0.1.1
|
|
77
|
+
## 0.1.1 (2026-07-18)
|
|
60
78
|
|
|
61
79
|
### Fixed
|
|
62
|
-
- **`purchaseProduct` crashed
|
|
80
|
+
- **`purchaseProduct` crashed**: 0.1.0 was written against expo-iap's old flat `requestPurchase`
|
|
63
81
|
API and read the purchase from the return value. `expo-iap@4.x` is **event-based** with a
|
|
64
82
|
discriminated request. Now: `requestPurchase({ request: { apple: { sku }, google: { skus } },
|
|
65
83
|
type })` with the result bridged from `purchaseUpdatedListener` / `purchaseErrorListener`.
|
|
66
84
|
- Android subscriptions now pass the required `offerToken` (fetched from the product).
|
|
67
85
|
- `getProducts` uses expo-iap's `fetchProducts` (the old `getProducts` no longer exists).
|
|
68
86
|
|
|
69
|
-
## 0.1.0
|
|
87
|
+
## 0.1.0 (2026-07-18)
|
|
70
88
|
|
|
71
89
|
Initial release.
|
|
72
90
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@entitlehub/react-native)
|
|
4
4
|
[](./LICENSE)
|
|
5
5
|
|
|
6
|
-
EntitleHub for **React Native & Expo
|
|
6
|
+
EntitleHub for **React Native & Expo**: one call to purchase and unlock entitlements. It opens the
|
|
7
7
|
native store sheet (via [`expo-iap`](https://github.com/hyochan/expo-iap)), validates the receipt
|
|
8
8
|
with EntitleHub server-side, and hands you the updated entitlements. The RevenueCat developer
|
|
9
9
|
experience, on EntitleHub.
|
|
@@ -26,7 +26,7 @@ await configureEntitleHub({ apiKey: "pk_live_…", appUserId: user.id });
|
|
|
26
26
|
// gate a feature:
|
|
27
27
|
if (await isEntitled("pro")) unlockPro();
|
|
28
28
|
|
|
29
|
-
// buy
|
|
29
|
+
// buy: opens the native sheet, validates, returns entitlements:
|
|
30
30
|
const info = await purchaseProduct("app_pro_monthly", { isSubscription: true });
|
|
31
31
|
if (info.isActive("pro")) unlockPro();
|
|
32
32
|
|
|
@@ -45,7 +45,7 @@ const restored = await restorePurchases();
|
|
|
45
45
|
| `addCustomerInfoUpdateListener(fn)` | React to entitlement changes. |
|
|
46
46
|
|
|
47
47
|
Only your **publishable** key (`pk_`) ships in the app. EntitleHub validates the Apple/Google
|
|
48
|
-
receipt server-side, so a forged one is rejected
|
|
48
|
+
receipt server-side, so a forged one is rejected, no secret key on the device.
|
|
49
49
|
|
|
50
50
|
## How it works
|
|
51
51
|
|
|
@@ -60,22 +60,25 @@ Full guide: **[entitlehub.com/docs/purchases](https://entitlehub.com/docs/purcha
|
|
|
60
60
|
## Choosing / pinning the store library
|
|
61
61
|
|
|
62
62
|
The on-device purchase runs through **expo-iap** (OpenIAP). That native layer is the store
|
|
63
|
-
library's responsibility, not EntitleHub's
|
|
63
|
+
library's responsibility, not EntitleHub's, and a given version can have platform-specific native
|
|
64
64
|
bugs. If you hit a **native IAP crash** (e.g. an `EXC_BAD_ACCESS` in the store module), it's the
|
|
65
65
|
store library, not this SDK or your app code, and no JS change can catch a native exception thrown
|
|
66
66
|
off the JS thread.
|
|
67
67
|
|
|
68
68
|
Two levers, both without changing this SDK:
|
|
69
69
|
|
|
70
|
-
- **Pin a working version:** `npm install expo-iap@<version
|
|
70
|
+
- **Pin a working version:** `npm install expo-iap@<version>`, this package uses whatever `expo-iap`
|
|
71
71
|
is installed (peer dependency).
|
|
72
|
-
- **Supply your own module:** pass any OpenIAP-compatible library to `configureEntitleHub
|
|
72
|
+
- **Supply your own module:** pass any OpenIAP-compatible library to `configureEntitleHub`. You do
|
|
73
|
+
not need this to use `expo-iap`, which is loaded for you; it is for pinning an exact instance or
|
|
74
|
+
using a different library:
|
|
73
75
|
```ts
|
|
74
|
-
|
|
76
|
+
import * as iap from "expo-iap"; // or react-native-iap
|
|
77
|
+
await configureEntitleHub({ apiKey, appUserId, iap });
|
|
75
78
|
```
|
|
76
79
|
|
|
77
80
|
Fully decoupled fallback: skip this package and use **[`@entitlehub/sdk`](https://www.npmjs.com/package/@entitlehub/sdk)**
|
|
78
|
-
directly
|
|
81
|
+
directly: open the purchase with *any* billing library you've verified on your target OS, then call
|
|
79
82
|
`eh.reportPurchase({ signedTransaction | purchaseToken })`. See
|
|
80
83
|
[Purchases → manual](https://entitlehub.com/docs/purchases).
|
|
81
84
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -34,16 +44,25 @@ __export(index_exports, {
|
|
|
34
44
|
module.exports = __toCommonJS(index_exports);
|
|
35
45
|
var import_sdk = require("@entitlehub/sdk");
|
|
36
46
|
var _iap;
|
|
37
|
-
function
|
|
47
|
+
async function loadIap() {
|
|
38
48
|
if (_iap) return _iap;
|
|
49
|
+
let mod;
|
|
39
50
|
try {
|
|
40
|
-
|
|
51
|
+
mod = await import("expo-iap");
|
|
41
52
|
} catch {
|
|
42
53
|
throw new Error("@entitlehub/react-native needs 'expo-iap'. Install it with: npx expo install expo-iap");
|
|
43
54
|
}
|
|
55
|
+
_iap = typeof mod?.initConnection === "function" ? mod : mod?.default ?? mod;
|
|
56
|
+
if (typeof _iap?.initConnection !== "function") {
|
|
57
|
+
throw new Error("@entitlehub/react-native: the 'expo-iap' module did not load correctly (no initConnection). Check that expo-iap is installed and its version supports the OpenIAP API.");
|
|
58
|
+
}
|
|
59
|
+
return _iap;
|
|
60
|
+
}
|
|
61
|
+
function iap() {
|
|
62
|
+
if (!_iap) throw new Error("Call configureEntitleHub({ apiKey, appUserId }) before using EntitleHub purchases.");
|
|
44
63
|
return _iap;
|
|
45
64
|
}
|
|
46
|
-
var RN_SDK_VERSION = "0.1.
|
|
65
|
+
var RN_SDK_VERSION = "0.1.8";
|
|
47
66
|
var client;
|
|
48
67
|
function eh() {
|
|
49
68
|
if (!client) throw new Error("Call configureEntitleHub({ apiKey, appUserId }) before using EntitleHub.");
|
|
@@ -51,6 +70,7 @@ function eh() {
|
|
|
51
70
|
}
|
|
52
71
|
async function configureEntitleHub(opts) {
|
|
53
72
|
if (opts.iap) _iap = opts.iap;
|
|
73
|
+
else await loadIap();
|
|
54
74
|
client = new import_sdk.EntitleHub({
|
|
55
75
|
apiKey: opts.apiKey,
|
|
56
76
|
appUserId: opts.appUserId,
|
|
@@ -179,7 +199,7 @@ async function purchaseProduct(productId, opts = {}) {
|
|
|
179
199
|
}
|
|
180
200
|
fail(new PurchaseError(
|
|
181
201
|
"purchase-pending",
|
|
182
|
-
"The store hasn't confirmed this purchase yet. It may still complete
|
|
202
|
+
"The store hasn't confirmed this purchase yet. It may still complete, show a pending state, not a failure.",
|
|
183
203
|
lastInfo
|
|
184
204
|
));
|
|
185
205
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -13,9 +13,8 @@ interface ConfigureOptions {
|
|
|
13
13
|
* `fetchProducts`, `requestPurchase`, `purchaseUpdatedListener`, `purchaseErrorListener`,
|
|
14
14
|
* `finishTransaction`, `getAvailablePurchases`). Defaults to `expo-iap`.
|
|
15
15
|
*
|
|
16
|
-
* Pass your own
|
|
17
|
-
*
|
|
18
|
-
* a native issue in a particular store-library version without changing this SDK.
|
|
16
|
+
* Optional. Pass your own only to pin a specific version or to use a different OpenIAP-compatible
|
|
17
|
+
* library (e.g. `react-native-iap`); expo-iap is loaded for you otherwise.
|
|
19
18
|
*/
|
|
20
19
|
iap?: unknown;
|
|
21
20
|
}
|
|
@@ -31,13 +30,13 @@ declare function isEntitled(entitlementId: string): Promise<boolean>;
|
|
|
31
30
|
declare function getOfferings(): Promise<Offerings>;
|
|
32
31
|
/** Live store products (prices, localized titles) from the native store (expo-iap `fetchProducts`). */
|
|
33
32
|
declare function getProducts(productIds: string[], type?: "in-app" | "subs" | "all"): Promise<any[]>;
|
|
34
|
-
/** Why a purchase didn't complete. Check `code
|
|
33
|
+
/** Why a purchase didn't complete. Check `code`, never match on the message. */
|
|
35
34
|
type PurchaseErrorCode = "purchase-cancelled" | "purchase-pending" | "purchase-failed";
|
|
36
35
|
/**
|
|
37
36
|
* A purchase that didn't return entitlements.
|
|
38
37
|
*
|
|
39
38
|
* `code === "purchase-pending"` is NOT a failure: the store took the money but confirmation hasn't
|
|
40
|
-
* reached us yet (store notifications are asynchronous). Show "still confirming", not an error
|
|
39
|
+
* reached us yet (store notifications are asynchronous). Show "still confirming", not an error,
|
|
41
40
|
* the entitlement will arrive on its own, and `addCustomerInfoUpdateListener` will fire when it does.
|
|
42
41
|
*/
|
|
43
42
|
declare class PurchaseError extends Error {
|
|
@@ -54,18 +53,18 @@ declare class PurchaseError extends Error {
|
|
|
54
53
|
*
|
|
55
54
|
* Store bridges disagree about how the result comes back, so we accept it from any source and never
|
|
56
55
|
* hang waiting for one of them:
|
|
57
|
-
* 1. `purchaseUpdatedListener
|
|
58
|
-
* 2. `requestPurchase`'s resolved value
|
|
56
|
+
* 1. `purchaseUpdatedListener`: expo-iap's event-based flow.
|
|
57
|
+
* 2. `requestPurchase`'s resolved value: react-native-iap 15+ / Nitro resolves with the purchase
|
|
59
58
|
* and may never emit the event.
|
|
60
|
-
* 3. Reconciliation after `timeoutMs
|
|
59
|
+
* 3. Reconciliation after `timeoutMs`: re-read `getAvailablePurchases()`, and failing that check
|
|
61
60
|
* whether the entitlement appeared server-side anyway (EntitleHub's store-notification webhook
|
|
62
61
|
* grants it independently of the client).
|
|
63
62
|
*
|
|
64
63
|
* Rejects with a `PurchaseError`; branch on `.code`, never the message:
|
|
65
|
-
* - `purchase-cancelled
|
|
66
|
-
* - `purchase-pending`
|
|
64
|
+
* - `purchase-cancelled`: the user backed out.
|
|
65
|
+
* - `purchase-pending` : the store took the money but hasn't confirmed. NOT a failure; show a
|
|
67
66
|
* pending state. `.pending` is true and the entitlement will land on its own.
|
|
68
|
-
* - `purchase-failed`
|
|
67
|
+
* - `purchase-failed` : a real failure.
|
|
69
68
|
*/
|
|
70
69
|
declare function purchaseProduct(productId: string, opts?: {
|
|
71
70
|
isSubscription?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,9 +13,8 @@ interface ConfigureOptions {
|
|
|
13
13
|
* `fetchProducts`, `requestPurchase`, `purchaseUpdatedListener`, `purchaseErrorListener`,
|
|
14
14
|
* `finishTransaction`, `getAvailablePurchases`). Defaults to `expo-iap`.
|
|
15
15
|
*
|
|
16
|
-
* Pass your own
|
|
17
|
-
*
|
|
18
|
-
* a native issue in a particular store-library version without changing this SDK.
|
|
16
|
+
* Optional. Pass your own only to pin a specific version or to use a different OpenIAP-compatible
|
|
17
|
+
* library (e.g. `react-native-iap`); expo-iap is loaded for you otherwise.
|
|
19
18
|
*/
|
|
20
19
|
iap?: unknown;
|
|
21
20
|
}
|
|
@@ -31,13 +30,13 @@ declare function isEntitled(entitlementId: string): Promise<boolean>;
|
|
|
31
30
|
declare function getOfferings(): Promise<Offerings>;
|
|
32
31
|
/** Live store products (prices, localized titles) from the native store (expo-iap `fetchProducts`). */
|
|
33
32
|
declare function getProducts(productIds: string[], type?: "in-app" | "subs" | "all"): Promise<any[]>;
|
|
34
|
-
/** Why a purchase didn't complete. Check `code
|
|
33
|
+
/** Why a purchase didn't complete. Check `code`, never match on the message. */
|
|
35
34
|
type PurchaseErrorCode = "purchase-cancelled" | "purchase-pending" | "purchase-failed";
|
|
36
35
|
/**
|
|
37
36
|
* A purchase that didn't return entitlements.
|
|
38
37
|
*
|
|
39
38
|
* `code === "purchase-pending"` is NOT a failure: the store took the money but confirmation hasn't
|
|
40
|
-
* reached us yet (store notifications are asynchronous). Show "still confirming", not an error
|
|
39
|
+
* reached us yet (store notifications are asynchronous). Show "still confirming", not an error,
|
|
41
40
|
* the entitlement will arrive on its own, and `addCustomerInfoUpdateListener` will fire when it does.
|
|
42
41
|
*/
|
|
43
42
|
declare class PurchaseError extends Error {
|
|
@@ -54,18 +53,18 @@ declare class PurchaseError extends Error {
|
|
|
54
53
|
*
|
|
55
54
|
* Store bridges disagree about how the result comes back, so we accept it from any source and never
|
|
56
55
|
* hang waiting for one of them:
|
|
57
|
-
* 1. `purchaseUpdatedListener
|
|
58
|
-
* 2. `requestPurchase`'s resolved value
|
|
56
|
+
* 1. `purchaseUpdatedListener`: expo-iap's event-based flow.
|
|
57
|
+
* 2. `requestPurchase`'s resolved value: react-native-iap 15+ / Nitro resolves with the purchase
|
|
59
58
|
* and may never emit the event.
|
|
60
|
-
* 3. Reconciliation after `timeoutMs
|
|
59
|
+
* 3. Reconciliation after `timeoutMs`: re-read `getAvailablePurchases()`, and failing that check
|
|
61
60
|
* whether the entitlement appeared server-side anyway (EntitleHub's store-notification webhook
|
|
62
61
|
* grants it independently of the client).
|
|
63
62
|
*
|
|
64
63
|
* Rejects with a `PurchaseError`; branch on `.code`, never the message:
|
|
65
|
-
* - `purchase-cancelled
|
|
66
|
-
* - `purchase-pending`
|
|
64
|
+
* - `purchase-cancelled`: the user backed out.
|
|
65
|
+
* - `purchase-pending` : the store took the money but hasn't confirmed. NOT a failure; show a
|
|
67
66
|
* pending state. `.pending` is true and the entitlement will land on its own.
|
|
68
|
-
* - `purchase-failed`
|
|
67
|
+
* - `purchase-failed` : a real failure.
|
|
69
68
|
*/
|
|
70
69
|
declare function purchaseProduct(productId: string, opts?: {
|
|
71
70
|
isSubscription?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
1
|
// src/index.ts
|
|
9
2
|
import { EntitleHub } from "@entitlehub/sdk";
|
|
10
3
|
var _iap;
|
|
11
|
-
function
|
|
4
|
+
async function loadIap() {
|
|
12
5
|
if (_iap) return _iap;
|
|
6
|
+
let mod;
|
|
13
7
|
try {
|
|
14
|
-
|
|
8
|
+
mod = await import("expo-iap");
|
|
15
9
|
} catch {
|
|
16
10
|
throw new Error("@entitlehub/react-native needs 'expo-iap'. Install it with: npx expo install expo-iap");
|
|
17
11
|
}
|
|
12
|
+
_iap = typeof mod?.initConnection === "function" ? mod : mod?.default ?? mod;
|
|
13
|
+
if (typeof _iap?.initConnection !== "function") {
|
|
14
|
+
throw new Error("@entitlehub/react-native: the 'expo-iap' module did not load correctly (no initConnection). Check that expo-iap is installed and its version supports the OpenIAP API.");
|
|
15
|
+
}
|
|
16
|
+
return _iap;
|
|
17
|
+
}
|
|
18
|
+
function iap() {
|
|
19
|
+
if (!_iap) throw new Error("Call configureEntitleHub({ apiKey, appUserId }) before using EntitleHub purchases.");
|
|
18
20
|
return _iap;
|
|
19
21
|
}
|
|
20
|
-
var RN_SDK_VERSION = "0.1.
|
|
22
|
+
var RN_SDK_VERSION = "0.1.8";
|
|
21
23
|
var client;
|
|
22
24
|
function eh() {
|
|
23
25
|
if (!client) throw new Error("Call configureEntitleHub({ apiKey, appUserId }) before using EntitleHub.");
|
|
@@ -25,6 +27,7 @@ function eh() {
|
|
|
25
27
|
}
|
|
26
28
|
async function configureEntitleHub(opts) {
|
|
27
29
|
if (opts.iap) _iap = opts.iap;
|
|
30
|
+
else await loadIap();
|
|
28
31
|
client = new EntitleHub({
|
|
29
32
|
apiKey: opts.apiKey,
|
|
30
33
|
appUserId: opts.appUserId,
|
|
@@ -153,7 +156,7 @@ async function purchaseProduct(productId, opts = {}) {
|
|
|
153
156
|
}
|
|
154
157
|
fail(new PurchaseError(
|
|
155
158
|
"purchase-pending",
|
|
156
|
-
"The store hasn't confirmed this purchase yet. It may still complete
|
|
159
|
+
"The store hasn't confirmed this purchase yet. It may still complete, show a pending state, not a failure.",
|
|
157
160
|
lastInfo
|
|
158
161
|
));
|
|
159
162
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entitlehub/react-native",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "EntitleHub for React Native & Expo
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "EntitleHub for React Native & Expo, one call to purchase and unlock entitlements. Wraps expo-iap for the native store sheet and validates receipts via EntitleHub.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entitlehub",
|
|
7
7
|
"react-native",
|