@namiml/expo-sdk 3.4.5-dev.202607100416 → 3.4.5-dev.202607101515

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _namiml_sdk_core from '@namiml/sdk-core';
2
- import { IUIAdapter, IPaywall, NamiPaywallLaunchContext, FlowNavigationOptions, PaywallHandle, IStorageAdapter, IDeviceAdapter, DevicePayload, TDevice, ScreenInfo, IPurchaseAdapter, NamiProductDetails, PurchaseContext, PurchaseResult, Nami as Nami$1, NamiPaywallEvent, NamiCampaign, NamiFlow, TPaywallContext, ISkuMenu, FormFieldValidator, TimerState, NamiSKU, NamiAppSuppliedVideoDetails, TPaywallMedia, TComponent } from '@namiml/sdk-core';
2
+ import { IUIAdapter, IPaywall, NamiPaywallLaunchContext, FlowNavigationOptions, PaywallHandle, IPurchaseAdapter, NamiProductDetails, PurchaseContext, PurchaseResult, IStorageAdapter, IDeviceAdapter, DevicePayload, TDevice, ScreenInfo, Nami as Nami$1, NamiPaywallEvent, NamiCampaign, NamiFlow, TPaywallContext, ISkuMenu, FormFieldValidator, TimerState, NamiSKU, NamiAppSuppliedVideoDetails, TPaywallMedia, TComponent } from '@namiml/sdk-core';
3
3
  export { CustomerJourneyState, FormFieldValidator, IPurchaseAdapter, NamiCampaign, NamiCampaignManager, NamiConfiguration, NamiCustomerManager, NamiEntitlement, NamiEntitlementManager, NamiFlow, NamiFlowEventHandler, NamiFlowHandoffStepHandler, NamiFlowManager, NamiHandoffAttributeValue, NamiHandoffComplete, NamiHandoffOutcome, NamiHandoffTag, NamiLanguageCodes, NamiLogLevel, NamiLoginSuccess, NamiPaywallAction, NamiPaywallEvent, NamiPaywallLaunchContext, NamiPaywallManager, NamiPermissionOutcome, NamiProductDetails, NamiPurchase, NamiPurchaseManager, NamiPurchaseSuccess, NamiSKU, NamiSKUType, NamiUserDataEnvelope, PurchaseContext, PurchaseResult, TTextInputComponent, TTextInputType } from '@namiml/sdk-core';
4
4
  import React from 'react';
5
5
 
@@ -31,6 +31,12 @@ declare class ExpoUIAdapter implements IUIAdapter {
31
31
  onReset(): void;
32
32
  }
33
33
 
34
+ declare class ExpoPurchaseAdapter implements IPurchaseAdapter {
35
+ getProducts(skuIds: string[]): Promise<NamiProductDetails[]>;
36
+ purchase(skuId: string, context?: PurchaseContext): Promise<PurchaseResult>;
37
+ restorePurchases(): Promise<PurchaseResult[]>;
38
+ }
39
+
34
40
  declare class ExpoStorageAdapter implements IStorageAdapter {
35
41
  private db;
36
42
  private memoryFallback;
@@ -52,12 +58,6 @@ declare class ExpoDeviceAdapter implements IDeviceAdapter {
52
58
  getLanguage(): string;
53
59
  }
54
60
 
55
- declare class ExpoPurchaseAdapter implements IPurchaseAdapter {
56
- getProducts(skuIds: string[]): Promise<NamiProductDetails[]>;
57
- purchase(skuId: string, context?: PurchaseContext): Promise<PurchaseResult>;
58
- restorePurchases(): Promise<PurchaseResult[]>;
59
- }
60
-
61
61
  declare class Nami {
62
62
  static get sdkVersion(): string;
63
63
  static sdkPackageVersion(): string;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { NAMI_SDK_PACKAGE_VERSION, registerPlatformAdapters, registerPurchaseAdapter, logger, Nami as Nami$1, PaywallState, initialState, getUrlParams, SMART_TEXT_PATTERN, VAR_REGEX, LIQUID_VARIABLE_REGEX, isAnonymousMode, NamiAPI, storageService, getDeviceScaleFactor, NamiEventEmitter, PAYWALL_ACTION_EVENT, NamiPaywallAction, NamiReservedActions, _internal, isValidUrl, isNamiFlowCampaign, hasAllPaywalls, getPaywallDataFromLabel, getPaywall } from '@namiml/sdk-core';
1
+ import { NAMI_SDK_PACKAGE_VERSION, registerPlatformAdapters, registerPurchaseAdapter, logger, NamiPaywallManager, Nami as Nami$1, PaywallState, initialState, getUrlParams, SMART_TEXT_PATTERN, VAR_REGEX, LIQUID_VARIABLE_REGEX, isAnonymousMode, NamiAPI, storageService, getDeviceScaleFactor, NamiEventEmitter, PAYWALL_ACTION_EVENT, NamiPaywallAction, NamiReservedActions, _internal, isValidUrl, isNamiFlowCampaign, hasAllPaywalls, getPaywallDataFromLabel, getPaywall } from '@namiml/sdk-core';
2
2
  export { NamiCampaignManager, NamiCustomerManager, NamiEntitlementManager, NamiFlowManager, NamiHandoffTag, NamiPaywallManager, NamiPermissionOutcome, NamiPurchaseManager } from '@namiml/sdk-core';
3
3
  import { Platform, Dimensions, StyleSheet, View, ScrollView, ImageBackground, BackHandler, ActivityIndicator, StatusBar, Animated } from 'react-native';
4
4
  import require$$0, { createContext, useRef, useState, useEffect, useMemo, useContext, useCallback, useLayoutEffect } from 'react';
@@ -291,6 +291,7 @@ class ExpoPurchaseAdapter {
291
291
  }
292
292
 
293
293
  const expoUIAdapter = new ExpoUIAdapter();
294
+ const expoPurchaseAdapter = new ExpoPurchaseAdapter();
294
295
  let adaptersRegistered = false;
295
296
  function registerExpoAdapters() {
296
297
  if (adaptersRegistered) {
@@ -302,7 +303,7 @@ function registerExpoAdapters() {
302
303
  device: new ExpoDeviceAdapter(),
303
304
  ui: expoUIAdapter,
304
305
  });
305
- registerPurchaseAdapter(new ExpoPurchaseAdapter());
306
+ registerPurchaseAdapter(expoPurchaseAdapter);
306
307
  adaptersRegistered = true;
307
308
  }
308
309
  catch (error) {
@@ -311,6 +312,79 @@ function registerExpoAdapters() {
311
312
  }
312
313
  registerExpoAdapters();
313
314
 
315
+ // Accumulated store product details, keyed by product_ref_id (== sku_ref_id).
316
+ const productsById = new Map();
317
+ // Serializes backfill runs so concurrent launches/prefetches don't double-fetch
318
+ // or race the map (parity with the Apple SDK's backfillTaskLock).
319
+ let pending = Promise.resolve(false);
320
+ /** Collect unique store product ids (sku_ref_id) from the given paywalls' sku menus. */
321
+ function collectSkuRefIds(paywalls) {
322
+ const ids = new Set();
323
+ for (const paywall of paywalls ?? []) {
324
+ for (const menu of paywall?.sku_menus ?? []) {
325
+ for (const sku of menu?.products ?? []) {
326
+ if (sku?.sku_ref_id)
327
+ ids.add(sku.sku_ref_id);
328
+ }
329
+ }
330
+ }
331
+ return [...ids];
332
+ }
333
+ /**
334
+ * Fetch store product details for any of `skuRefIds` not already loaded, merge them into
335
+ * the accumulated set, and push the union to core via NamiPaywallManager.setProductDetails.
336
+ * Serialized; returns whether new products were added. Never throws.
337
+ */
338
+ function backfill(skuRefIds) {
339
+ pending = pending.then(() => backfillOnce(skuRefIds));
340
+ return pending;
341
+ }
342
+ async function backfillOnce(skuRefIds) {
343
+ const missing = [...new Set(skuRefIds)].filter((id) => id && !productsById.has(id));
344
+ if (!missing.length)
345
+ return false;
346
+ try {
347
+ const products = await expoPurchaseAdapter.getProducts(missing);
348
+ let added = false;
349
+ for (const product of products ?? []) {
350
+ if (product?.product_ref_id) {
351
+ productsById.set(product.product_ref_id, product);
352
+ added = true;
353
+ }
354
+ }
355
+ if (added) {
356
+ NamiPaywallManager.setProductDetails([...productsById.values()]);
357
+ }
358
+ return added;
359
+ }
360
+ catch (error) {
361
+ logger.warn('[NamiExpo] Failed to load store products.', error);
362
+ return false;
363
+ }
364
+ }
365
+ /** Clear accumulated products. Called on Nami.reset so reconfigure doesn't serve stale data. */
366
+ function reset() {
367
+ pending = pending.then(() => {
368
+ productsById.clear();
369
+ return false;
370
+ });
371
+ }
372
+
373
+ /**
374
+ * Prefetch StoreKit/Play product details for every configured paywall's SKUs so that
375
+ * prices are available before any paywall mounts (mirrors the Apple SDK startup load).
376
+ * Fire-and-forget and error-safe: a failure here never blocks configure.
377
+ */
378
+ async function prefetchProducts() {
379
+ try {
380
+ const ids = collectSkuRefIds(NamiPaywallManager.allPaywalls());
381
+ if (ids.length)
382
+ await backfill(ids);
383
+ }
384
+ catch (error) {
385
+ logger.warn('[NamiExpo] Product prefetch skipped.', error);
386
+ }
387
+ }
314
388
  class Nami {
315
389
  static get sdkVersion() {
316
390
  return Nami$1.sdkVersion();
@@ -319,9 +393,12 @@ class Nami {
319
393
  return Nami$1.sdkPackageVersion();
320
394
  }
321
395
  static async configure(config) {
322
- return Nami$1.configure(config);
396
+ const result = await Nami$1.configure(config);
397
+ void prefetchProducts();
398
+ return result;
323
399
  }
324
400
  static async reset() {
401
+ reset();
325
402
  await Nami$1.reset?.();
326
403
  }
327
404
  }
@@ -3705,6 +3782,9 @@ const NamiView = ({ placement, url, onClose, onSignIn, onDeepLink, onPurchase, o
3705
3782
  launchCacheRef.current.set(cacheKey, nextLaunch);
3706
3783
  }
3707
3784
  prewarmPaywallFonts([paywall, ...flowPaywalls]);
3785
+ const launchSkuRefIds = collectSkuRefIds([paywall, ...flowPaywalls].filter((item) => item != null));
3786
+ if (launchSkuRefIds.length)
3787
+ void backfill(launchSkuRefIds);
3708
3788
  if (initialPaywall?.fonts) {
3709
3789
  void prepareAndLoadFontsWithTimeout(initialPaywall.fonts);
3710
3790
  }