@nosslabs/iap 0.4.0 → 7.0.0-next.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 CHANGED
@@ -5,6 +5,53 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [7.0.0-next.0] — 2026-05-14
9
+
10
+ First release of the **Capacitor 7+** line, published on the `@next`
11
+ npm dist-tag. The Capacitor 5 line continues as `5.x` on `@latest`
12
+ (from the `5.x` branch) — see [Migration](https://iap.nossdev.com/migration/).
13
+
14
+ Numbering: the library's major version tracks the Capacitor major it
15
+ targets (the convention `@capgo/native-purchases` and Ionic plugins
16
+ use). What was framed as `1.0.0-next.0` during development is published
17
+ as `7.0.0-next.0` for the same reason `5.0.0` superseded `0.4.0` on
18
+ the maintenance line — same code, version aligned with the platform.
19
+
20
+ ### Changed
21
+
22
+ - **BREAKING: dropped Capacitor 5 support.** The `7.x` line targets
23
+ **Capacitor 7+** (also runs on Capacitor 8) via
24
+ [`@capgo/native-purchases`](https://github.com/Cap-go/native-purchases),
25
+ replacing `cordova-plugin-purchase`. The native adapter now lives at
26
+ `src/adapters/native/capgo/native-adapter.ts` (`CapgoNativeAdapter`),
27
+ selected behind the same `NativeAdapter` interface as before.
28
+ - **Peer dependencies** are now `@capacitor/core`, `@capacitor/preferences`,
29
+ and (optional) `@capacitor/app` at `^7.0.0 || ^8.0.0`, plus
30
+ `@capgo/native-purchases` at `7.16.x || ^8.0.0`. `cordova-plugin-purchase`
31
+ is no longer a peer dependency. Migration is a peer-dep swap + `npx cap sync`
32
+ — no changes to your `createIAP({ ... })` config or any consumer code.
33
+ - **Acknowledgement defers on both platforms.** `@capgo/native-purchases`
34
+ supports `autoAcknowledgePurchases: false` on iOS and Android, so the
35
+ "never grant entitlement before the backend confirms" guarantee holds
36
+ with no iOS-specific finish-before-verify race.
37
+ - **Android user-cancellation surfaces as `status: 'failed'`** (not
38
+ `'cancelled'`). Google Play Billing — at the level `@capgo/native-purchases`
39
+ exposes — doesn't distinguish a user-cancelled flow from other purchase
40
+ failures; iOS still reports `'cancelled'` reliably. Treat `failed` on
41
+ Android the same as `cancelled` for UX. (The Capacitor 5 line via
42
+ `cordova-plugin-purchase` could distinguish this.)
43
+
44
+ ### Unchanged
45
+
46
+ - Public API surface: `createIAP`, the `IAP` interface, all events, all
47
+ `IAPErrorCode` values, and every public type are identical to `5.0.0`
48
+ (= `0.4.0` code).
49
+ - The full `0.2`–`0.4` feature set carries forward: the options-object
50
+ `purchase()` signature, optional `appUserId` pre-attachment, the
51
+ `INVALID_APP_USER_ID` / `APP_USER_ID_FETCH_FAILED` error codes, the
52
+ `permanentErrorCodes` config, the `recovery-dropped-permanent` event,
53
+ and `RecoveryResult.droppedPermanent`.
54
+
8
55
  ## [0.4.0] — 2026-05-08
9
56
 
10
57
  ### Added
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  > Thin Capacitor IAP orchestrator. Server-side validation via [Attesto](https://attesto.nossdev.com).
4
4
 
5
- **Status: 0.2.0 — published.** API may have breaking changes through the 0.x line as it's exercised in production apps. Pin the minor version (`^0.2.0`) and watch the [CHANGELOG](./CHANGELOG.md).
5
+ **Status: `7.0.0-next.0`prerelease on the `@next` dist-tag** (the Capacitor 7+ line, built on `@capgo/native-purchases`). The Capacitor 5 line (`cordova-plugin-purchase`) continues as `5.x` on `@latest` (from the `5.x` branch). API may have breaking changes through the 7.x prerelease line; watch the [CHANGELOG](./CHANGELOG.md).
6
6
 
7
7
  ```bash
8
- npm install @nosslabs/iap cordova-plugin-purchase
8
+ npm install @nosslabs/iap@next @capgo/native-purchases
9
9
  npx cap sync
10
10
  ```
11
11
 
@@ -65,9 +65,9 @@ await iap.purchase({
65
65
 
66
66
  `@nosslabs/iap` does **one thing**: orchestrate the purchase flow on the client. It
67
67
 
68
- - wraps `cordova-plugin-purchase` for native purchase + restore,
68
+ - wraps [`@capgo/native-purchases`](https://github.com/Cap-go/native-purchases) for native purchase + restore,
69
69
  - POSTs to **your** backend (which calls Attesto) for receipt validation,
70
- - acknowledges native transactions only **after** the backend confirms (no phantom grants),
70
+ - acknowledges native transactions only **after** the backend confirms — `autoAcknowledgePurchases: false` defers finishing on **both** iOS and Android, so there's no phantom grant and no iOS finish-before-verify race,
71
71
  - caches entitlements locally for instant, reactive UI reads,
72
72
  - recovers unfinished transactions across app launches.
73
73
 
@@ -75,10 +75,10 @@ It does **not**: talk to Attesto directly, define entitlement business logic, ma
75
75
 
76
76
  ## Capacitor support matrix
77
77
 
78
- | `@nosslabs/iap` | Capacitor | Plugin | Status |
79
- |---|---|---|---|
80
- | 0.x | 5.x | `cordova-plugin-purchase ^13.x` | **Current** |
81
- | 1.x | 7.x | TBD (Capacitor-native plugin) | Roadmap |
78
+ | `@nosslabs/iap` | Capacitor | Native plugin | dist-tag | Status |
79
+ |---|---|---|---|---|
80
+ | 7.x | 7.x (also runs on 8.x) | `@capgo/native-purchases 7.16.x` (or `^8` on Cap 8) | `@next` | **Current (prerelease)** |
81
+ | 5.x | 5.x | `cordova-plugin-purchase ^13.x` | `@latest` | Maintenance |
82
82
 
83
83
  ## Optional peer dependency
84
84
 
@@ -94,7 +94,7 @@ Or disable the listener with `options.refreshOnResume: false`. See [installation
94
94
  ## Development
95
95
 
96
96
  ```bash
97
- mise install # Node 22 + npm 10
97
+ mise install # Node 22 + npm 11 (pinned in mise.toml)
98
98
  npm install
99
99
  npm run typecheck # tsc --noEmit
100
100
  npm run lint # biome check
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var core = require('@capacitor/core');
4
- require('cordova-plugin-purchase');
4
+ var nativePurchases = require('@capgo/native-purchases');
5
5
  var zod = require('zod');
6
6
  var preferences = require('@capacitor/preferences');
7
7
 
@@ -85,7 +85,7 @@ var init_errors = __esm({
85
85
  NOT_INITIALIZED: "Call iap.initialize() before this method, or recreate the instance after destroy().",
86
86
  // Native plugin
87
87
  PLATFORM_NOT_SUPPORTED: "In-app purchases run on iOS/Android only. Web is no-op by design \u2014 guard your purchase UI behind Capacitor.isNativePlatform().",
88
- BILLING_NOT_AVAILABLE: "cordova-plugin-purchase failed to initialize. Confirm the plugin is installed and `npx cap sync` has run; check device sandbox/test account is signed in.",
88
+ BILLING_NOT_AVAILABLE: "The store billing service is unavailable. Confirm @capgo/native-purchases is installed and `npx cap sync` has run; check the device sandbox/test account is signed in.",
89
89
  PRODUCT_NOT_FOUND: "Ensure the productId is registered in App Store Connect / Play Console AND in your createIAP({ products }) config.",
90
90
  USER_CANCELLED: "No action needed \u2014 the user dismissed the native purchase sheet.",
91
91
  PURCHASE_PENDING: "Android only: payment is awaiting external clearance (e.g. cash payment, bank verification). The backend will receive a Google RTDN webhook when it clears; call iap.refresh() afterward.",
@@ -139,295 +139,170 @@ var init_platform = __esm({
139
139
  }
140
140
  });
141
141
 
142
- // src/adapters/native/cdv/native-adapter.ts
142
+ // src/adapters/native/capgo/native-adapter.ts
143
143
  var native_adapter_exports = {};
144
144
  __export(native_adapter_exports, {
145
- CdvNativeAdapter: () => CdvNativeAdapter
145
+ CapgoNativeAdapter: () => CapgoNativeAdapter
146
146
  });
147
- function getCdv() {
148
- const candidate = globalThis.CdvPurchase;
149
- if (!candidate || !candidate.store) {
150
- throw new exports.IAPError({
151
- code: exports.IAPErrorCode.BILLING_NOT_AVAILABLE,
152
- message: "cordova-plugin-purchase is not available. Ensure the plugin is installed and `npx cap sync` has run."
153
- });
154
- }
155
- return candidate;
156
- }
157
- function currentCdvPlatform() {
158
- const cdv = getCdv();
159
- const platform = getPlatform();
160
- if (platform === "android") return cdv.Platform.GOOGLE_PLAY;
161
- return cdv.Platform.APPLE_APPSTORE;
162
- }
163
- function mapProductType(type) {
164
- const cdv = getCdv();
165
- switch (type) {
166
- case "subscription":
167
- return cdv.ProductType.PAID_SUBSCRIPTION;
168
- case "consumable":
169
- return cdv.ProductType.CONSUMABLE;
170
- default:
171
- return cdv.ProductType.NON_CONSUMABLE;
172
- }
173
- }
174
- function inferProductType(tx, configured) {
175
- const id = tx.products[0]?.id;
176
- if (!id) return "product";
177
- const match = configured.find((p) => p.id === id);
178
- return match?.type ?? "product";
179
- }
180
147
  function normalizeProduct(p, type) {
181
- const offer = p.getOffer();
182
- const phase = offer?.pricingPhases?.[0];
183
- const priceMicros = phase?.priceMicros?.toString() ?? "0";
184
- const priceString = phase?.price ?? "";
185
- const currency = phase?.currency ?? "";
148
+ const priceMicros = Math.round(p.price * 1e6).toString();
186
149
  return {
187
- id: p.id,
150
+ id: p.identifier,
188
151
  type,
189
- title: p.title ?? p.id,
190
- description: p.description ?? "",
191
- priceString,
152
+ title: p.title,
153
+ description: p.description,
154
+ priceString: p.priceString,
192
155
  priceMicros,
193
- currency
156
+ currency: p.currencyCode
194
157
  };
195
158
  }
196
- function normalizeTransaction(tx, productType, token) {
197
- const platform = tx.platform === "ios-appstore" ? "apple" : "google";
198
- const productId = tx.products[0]?.id ?? "";
199
- const result = {
159
+ function normalizeTransaction(tx, productType) {
160
+ const platform = inferPlatform(tx);
161
+ const token = platform === "google" ? tx.purchaseToken ?? tx.transactionId : tx.transactionId;
162
+ const native = {
200
163
  platform,
201
- productId,
164
+ productId: tx.productIdentifier,
202
165
  token,
203
166
  productType,
204
167
  raw: tx
205
168
  };
206
- if (platform === "google") {
207
- const packageName = googlePackageName(tx);
208
- if (packageName) result.packageName = packageName;
169
+ return native;
170
+ }
171
+ function inferPlatform(tx) {
172
+ if (tx.purchaseToken !== void 0 || tx.purchaseState !== void 0 || tx.orderId !== void 0) {
173
+ return "google";
174
+ }
175
+ if (tx.receipt !== void 0 || tx.jwsRepresentation !== void 0) {
176
+ return "apple";
209
177
  }
210
- return result;
178
+ return getPlatform() === "android" ? "google" : "apple";
211
179
  }
212
- function googlePackageName(tx) {
213
- const googleTx = tx;
214
- return googleTx.nativePurchase?.packageName;
180
+ function inferProductType(tx) {
181
+ if (tx.productType === "subs") return "subscription";
182
+ return "product";
215
183
  }
216
- function transactionToken(tx) {
217
- if (tx.platform === "ios-appstore") {
218
- return tx.transactionId || null;
219
- }
220
- const googleTx = tx;
221
- return googleTx.nativePurchase?.purchaseToken ?? googleTx.parentReceipt?.purchaseToken ?? tx.transactionId ?? null;
184
+ function mapToPluginPurchaseType(type) {
185
+ return type === "subscription" ? nativePurchases.PURCHASE_TYPE.SUBS : nativePurchases.PURCHASE_TYPE.INAPP;
222
186
  }
223
- function mapOrderError(err, productId) {
224
- const cdv = getCdv();
225
- const cancelled = cdv.ErrorCode?.PAYMENT_CANCELLED;
226
- if (cancelled !== void 0 && err.code === cancelled) {
187
+ function mapPurchaseError(error, productId) {
188
+ if (error instanceof exports.IAPError) return error;
189
+ const message = error instanceof Error ? error.message : String(error);
190
+ const lower = message.toLowerCase();
191
+ if (lower.includes("cancel")) {
227
192
  return new exports.IAPError({
228
193
  code: exports.IAPErrorCode.USER_CANCELLED,
229
- message: "User cancelled the native purchase sheet.",
230
- cause: err
194
+ message: `Purchase of "${productId}" was cancelled.`,
195
+ cause: error
196
+ });
197
+ }
198
+ if (lower.includes("pending")) {
199
+ return new exports.IAPError({
200
+ code: exports.IAPErrorCode.PURCHASE_PENDING,
201
+ message: `Purchase of "${productId}" is pending external clearance.`,
202
+ cause: error
203
+ });
204
+ }
205
+ if (lower.includes("product not found")) {
206
+ return new exports.IAPError({
207
+ code: exports.IAPErrorCode.PRODUCT_NOT_FOUND,
208
+ message: `Product "${productId}" was not found in the store catalog.`,
209
+ cause: error
231
210
  });
232
211
  }
233
212
  return new exports.IAPError({
234
213
  code: exports.IAPErrorCode.STORE_ERROR,
235
- message: err.message ?? `order() failed for ${productId}.`,
236
- cause: err
214
+ message: `Native purchase of "${productId}" failed.`,
215
+ cause: error
237
216
  });
238
217
  }
239
- var CdvNativeAdapter;
218
+ var CapgoNativeAdapter;
240
219
  var init_native_adapter = __esm({
241
- "src/adapters/native/cdv/native-adapter.ts"() {
220
+ "src/adapters/native/capgo/native-adapter.ts"() {
242
221
  init_errors();
243
222
  init_platform();
244
- CdvNativeAdapter = class {
245
- products;
246
- bootstrapped = false;
247
- bootstrapping = null;
248
- pendingFinish = /* @__PURE__ */ new Map();
249
- /** Long-lived bootstrap-time .approved() listener — kept for dispose(). */
250
- bootstrapApprovedHandler = null;
251
- constructor(opts) {
252
- this.products = opts.products;
253
- }
223
+ CapgoNativeAdapter = class {
254
224
  async isAvailable() {
255
225
  try {
256
- await this.bootstrap();
257
- return true;
226
+ const result = await nativePurchases.NativePurchases.isBillingSupported();
227
+ return result.isBillingSupported;
258
228
  } catch {
259
229
  return false;
260
230
  }
261
231
  }
262
232
  async getProducts(requests) {
263
233
  if (requests.length === 0) return [];
264
- const store = await this.ensureStore();
265
- await store.update();
266
- const out = [];
234
+ const inappIds = [];
235
+ const subsIds = [];
236
+ const requestById = /* @__PURE__ */ new Map();
267
237
  for (const req of requests) {
268
- const native = store.get(req.id);
269
- if (!native) continue;
270
- out.push(normalizeProduct(native, req.type));
238
+ requestById.set(req.id, req.type);
239
+ if (req.type === "subscription") {
240
+ subsIds.push(req.id);
241
+ } else {
242
+ inappIds.push(req.id);
243
+ }
271
244
  }
272
- return out;
245
+ const [inapp, subs] = await Promise.all([
246
+ inappIds.length > 0 ? nativePurchases.NativePurchases.getProducts({
247
+ productIdentifiers: inappIds,
248
+ productType: nativePurchases.PURCHASE_TYPE.INAPP
249
+ }) : Promise.resolve({ products: [] }),
250
+ subsIds.length > 0 ? nativePurchases.NativePurchases.getProducts({
251
+ productIdentifiers: subsIds,
252
+ productType: nativePurchases.PURCHASE_TYPE.SUBS
253
+ }) : Promise.resolve({ products: [] })
254
+ ]);
255
+ const all = [...inapp.products, ...subs.products];
256
+ return all.map((p) => normalizeProduct(p, requestById.get(p.identifier) ?? "product"));
273
257
  }
274
258
  async purchaseProduct(opts) {
275
- const store = await this.ensureStore();
276
- const native = store.get(opts.productId);
277
- if (!native) {
278
- throw new exports.IAPError({
279
- code: exports.IAPErrorCode.PRODUCT_NOT_FOUND,
280
- message: `Product "${opts.productId}" not registered or not available from the store.`
281
- });
282
- }
283
- const offer = opts.androidPlanId ? native.getOffer(opts.androidPlanId) ?? native.getOffer() : native.getOffer();
284
- if (!offer) {
285
- throw new exports.IAPError({
286
- code: exports.IAPErrorCode.PRODUCT_NOT_FOUND,
287
- message: `Product "${opts.productId}" has no purchasable offer${opts.androidPlanId ? ` (planId="${opts.androidPlanId}")` : ""}.`
259
+ const purchaseType = mapToPluginPurchaseType(opts.productType);
260
+ const isConsumable = opts.productType === "consumable";
261
+ let tx;
262
+ try {
263
+ tx = await nativePurchases.NativePurchases.purchaseProduct({
264
+ productIdentifier: opts.productId,
265
+ productType: purchaseType,
266
+ planIdentifier: opts.androidPlanId,
267
+ appAccountToken: opts.appAccountToken,
268
+ isConsumable,
269
+ autoAcknowledgePurchases: false
288
270
  });
271
+ } catch (error) {
272
+ throw mapPurchaseError(error, opts.productId);
289
273
  }
290
- return new Promise((resolve, reject) => {
291
- let settled = false;
292
- const cleanup = () => {
293
- store.off(handleApproved);
294
- };
295
- const handleApproved = (tx) => {
296
- if (settled) return;
297
- if (!tx.products.some((p) => p.id === opts.productId)) return;
298
- const token = transactionToken(tx);
299
- if (!token) {
300
- settled = true;
301
- cleanup();
302
- reject(
303
- new exports.IAPError({
304
- code: exports.IAPErrorCode.STORE_ERROR,
305
- message: `Approved transaction for "${opts.productId}" has no token; cannot verify.`
306
- })
307
- );
308
- return;
309
- }
310
- settled = true;
311
- cleanup();
312
- const normalized = normalizeTransaction(tx, opts.productType, token);
313
- this.pendingFinish.set(token, tx);
314
- resolve(normalized);
315
- };
316
- store.when().approved(handleApproved);
317
- const additionalData = opts.appAccountToken ? { applicationUsername: opts.appAccountToken } : void 0;
318
- void Promise.resolve(offer.order(additionalData)).then((err) => {
319
- if (settled) return;
320
- if (!err) return;
321
- settled = true;
322
- cleanup();
323
- reject(mapOrderError(err, opts.productId));
324
- }).catch((cause) => {
325
- if (settled) return;
326
- settled = true;
327
- cleanup();
328
- reject(
329
- new exports.IAPError({
330
- code: exports.IAPErrorCode.STORE_ERROR,
331
- message: `order() rejected for ${opts.productId}.`,
332
- cause
333
- })
334
- );
335
- });
336
- });
274
+ return normalizeTransaction(tx, opts.productType);
337
275
  }
338
276
  async getOwnedTransactions() {
339
- const store = await this.ensureStore();
340
- await store.restorePurchases();
341
- const out = [];
342
- for (const tx of store.localTransactions) {
343
- if (tx.state !== getCdv().TransactionState.APPROVED) continue;
344
- const token = transactionToken(tx);
345
- if (!token) continue;
346
- const normalized = normalizeTransaction(tx, inferProductType(tx, this.products), token);
347
- this.pendingFinish.set(token, tx);
348
- out.push(normalized);
349
- }
350
- return out;
277
+ const result = await nativePurchases.NativePurchases.getPurchases();
278
+ return result.purchases.filter((tx) => tx.purchaseState === void 0 || tx.purchaseState === "1").map((tx) => normalizeTransaction(tx, inferProductType(tx)));
351
279
  }
352
280
  async acknowledge(transaction) {
353
- const cdvTx = this.pendingFinish.get(transaction.token);
354
- if (!cdvTx) {
355
- return;
356
- }
357
281
  try {
358
- await cdvTx.finish();
359
- } catch (cause) {
282
+ await nativePurchases.NativePurchases.acknowledgePurchase({
283
+ purchaseToken: transaction.token
284
+ });
285
+ } catch (error) {
360
286
  throw new exports.IAPError({
361
287
  code: exports.IAPErrorCode.STORE_ERROR,
362
- message: `Failed to finish transaction for ${transaction.productId}.`,
363
- cause,
288
+ message: `Failed to acknowledge transaction for ${transaction.productId}.`,
289
+ cause: error,
364
290
  recoverable: true
365
291
  });
366
292
  }
367
- this.pendingFinish.delete(transaction.token);
368
293
  }
369
294
  async manageSubscriptions() {
370
- const store = await this.ensureStore();
371
- const err = await store.manageSubscriptions();
372
- if (err) {
295
+ try {
296
+ await nativePurchases.NativePurchases.manageSubscriptions();
297
+ } catch (error) {
373
298
  throw new exports.IAPError({
374
299
  code: exports.IAPErrorCode.STORE_ERROR,
375
- message: err.message ?? "Failed to open subscription management."
300
+ message: "Failed to open the native subscription management UI.",
301
+ cause: error
376
302
  });
377
303
  }
378
304
  }
379
305
  async dispose() {
380
- if (this.bootstrapApprovedHandler) {
381
- try {
382
- const cdv = globalThis.CdvPurchase;
383
- cdv?.store?.off(this.bootstrapApprovedHandler);
384
- } catch {
385
- }
386
- this.bootstrapApprovedHandler = null;
387
- }
388
- this.pendingFinish.clear();
389
- this.bootstrapped = false;
390
- this.bootstrapping = null;
391
- }
392
- // ----- internals -----
393
- async ensureStore() {
394
- await this.bootstrap();
395
- return getCdv().store;
396
- }
397
- bootstrap() {
398
- if (this.bootstrapped) return Promise.resolve();
399
- if (this.bootstrapping) return this.bootstrapping;
400
- this.bootstrapping = (async () => {
401
- const cdv = getCdv();
402
- const platform = currentCdvPlatform();
403
- cdv.store.register(
404
- this.products.map((p) => ({
405
- id: p.id,
406
- type: mapProductType(p.type),
407
- platform
408
- }))
409
- );
410
- const errors = await cdv.store.initialize([platform]);
411
- if (errors && errors.length > 0) {
412
- const first = errors[0];
413
- throw new exports.IAPError({
414
- code: exports.IAPErrorCode.BILLING_NOT_AVAILABLE,
415
- message: first?.message ?? "cordova-plugin-purchase initialize() reported errors."
416
- });
417
- }
418
- const handler = (tx) => {
419
- const token = transactionToken(tx);
420
- if (!token) return;
421
- if (!this.pendingFinish.has(token)) {
422
- this.pendingFinish.set(token, tx);
423
- }
424
- };
425
- this.bootstrapApprovedHandler = handler;
426
- cdv.store.when().approved(handler);
427
- await cdv.store.update();
428
- this.bootstrapped = true;
429
- })();
430
- return this.bootstrapping;
431
306
  }
432
307
  };
433
308
  }
@@ -960,11 +835,11 @@ var WebStubAdapter = class {
960
835
  };
961
836
 
962
837
  // src/adapters/native/index.ts
963
- async function selectNativeAdapter(options) {
838
+ async function selectNativeAdapter() {
964
839
  const platform = getPlatform();
965
840
  if (platform === "ios" || platform === "android") {
966
841
  const mod = await Promise.resolve().then(() => (init_native_adapter(), native_adapter_exports));
967
- return new mod.CdvNativeAdapter({ products: options.products });
842
+ return new mod.CapgoNativeAdapter();
968
843
  }
969
844
  return new WebStubAdapter();
970
845
  }
@@ -1902,7 +1777,7 @@ function createIAP(input) {
1902
1777
  state.products = Object.freeze([...validated.data]);
1903
1778
  state.logger.debug(`Resolved ${validated.data.length} product(s) from backend manifest.`);
1904
1779
  }
1905
- state.adapter = await selectNativeAdapter({ products: state.products });
1780
+ state.adapter = await selectNativeAdapter();
1906
1781
  const configGetAuthHeaders = state.config.backend.getAuthHeaders;
1907
1782
  const getAuthHeaders = configGetAuthHeaders ? async () => configGetAuthHeaders() : async () => ({});
1908
1783
  const sharedDeps = {