@namiml/sdk-core 3.4.1-dev.202605280043 → 3.4.1-dev.202605300006

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.cjs CHANGED
@@ -98,7 +98,7 @@ const {
98
98
  // version — stamped by scripts/version.sh
99
99
  NAMI_SDK_VERSION: exports.NAMI_SDK_VERSION = "3.4.1",
100
100
  // full package version including dev suffix — stamped by scripts/version.sh
101
- NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.1-dev.202605280043",
101
+ NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.1-dev.202605300006",
102
102
  // environments
103
103
  PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
104
104
  // error messages
@@ -7041,6 +7041,10 @@ exports.NamiCampaignRuleType = void 0;
7041
7041
  NamiCampaignRuleType["UNKNOWN"] = "unknown";
7042
7042
  NamiCampaignRuleType["URL"] = "url";
7043
7043
  })(exports.NamiCampaignRuleType || (exports.NamiCampaignRuleType = {}));
7044
+ // NamiCampaignManagerStatic interface + const proxy live in
7045
+ // `src/managers/campaign.ts`. They must stay out of this file: PaywallState
7046
+ // type-imports from here, and pulling in the manager class triggers a
7047
+ // constructor chain that runs before PaywallState finishes loading. See NAM-1207.
7044
7048
 
7045
7049
  /**
7046
7050
  * Get initial paywalls from storage service.
@@ -8677,12 +8681,12 @@ SessionService.instance = new SessionService();
8677
8681
  * @class NamiPurchaseManager
8678
8682
  * Provides methods for managing all aspects of a purchase in the Nami SDK.
8679
8683
  */
8680
- class NamiPurchaseManager {
8684
+ let NamiPurchaseManager$2 = class NamiPurchaseManager {
8681
8685
  static allPurchases() {
8682
8686
  return [];
8683
8687
  }
8684
- }
8685
- NamiPurchaseManager.instance = new NamiPurchaseManager();
8688
+ };
8689
+ NamiPurchaseManager$2.instance = new NamiPurchaseManager$2();
8686
8690
 
8687
8691
  var en = {
8688
8692
  nami_day: "day",
@@ -11741,7 +11745,7 @@ const createNamiEntitlements = (entitlements) => {
11741
11745
  const namiEntitlements = activeEntitlements();
11742
11746
  if (!entitlements)
11743
11747
  return namiEntitlements;
11744
- NamiPurchaseManager.allPurchases().forEach((namiPurchase) => {
11748
+ NamiPurchaseManager$2.allPurchases().forEach((namiPurchase) => {
11745
11749
  applyEntitlementActivation(namiPurchase);
11746
11750
  });
11747
11751
  const entitlementsToSkus = skuMapFromEntitlements(entitlements);
@@ -12222,7 +12226,7 @@ function isEqual(objA, objB) {
12222
12226
  return isEqual$1(normA, normB);
12223
12227
  }
12224
12228
 
12225
- class NamiProfileManager {
12229
+ let NamiProfileManager$1 = class NamiProfileManager {
12226
12230
  constructor() {
12227
12231
  this.load();
12228
12232
  }
@@ -12295,8 +12299,8 @@ class NamiProfileManager {
12295
12299
  this.logoutLocal();
12296
12300
  await this.logoutRemote();
12297
12301
  }
12298
- }
12299
- NamiProfileManager.instance = new NamiProfileManager();
12302
+ };
12303
+ NamiProfileManager$1.instance = new NamiProfileManager$1();
12300
12304
 
12301
12305
  var _Nami_isInitialized;
12302
12306
  // NamiFlowManager is intentionally NOT imported at top level — it
@@ -12334,13 +12338,13 @@ class Nami {
12334
12338
  __classPrivateFieldSet(Nami.instance, _Nami_isInitialized, false, "f");
12335
12339
  // In-memory singleton state that previously survived reset and
12336
12340
  // bled into the next configure() cycle.
12337
- NamiProfileManager.instance.setExternalId(undefined);
12341
+ NamiProfileManager$1.instance.setExternalId(undefined);
12338
12342
  PaywallState.reset();
12339
12343
  NamiAPI.reset();
12340
12344
  CampaignRuleRepository.instance.reset();
12341
12345
  // Lazy import to avoid a load-order cycle (NamiFlowManager imports
12342
12346
  // back to this module for `Nami.instance.maxLogging`).
12343
- const { NamiFlowManager } = await Promise.resolve().then(function () { return NamiFlowManager$1; });
12347
+ const { NamiFlowManager } = await Promise.resolve().then(function () { return NamiFlowManager$3; });
12344
12348
  NamiFlowManager.reset();
12345
12349
  // Give platform adapters a chance to drop their own state
12346
12350
  // (e.g. Expo's UI adapter holds listener refs from PaywallView).
@@ -12447,20 +12451,6 @@ class Nami {
12447
12451
  _Nami_isInitialized = new WeakMap();
12448
12452
  Nami.instance = new Nami();
12449
12453
 
12450
- exports.LaunchCampaignError = void 0;
12451
- (function (LaunchCampaignError) {
12452
- LaunchCampaignError["DEFAULT_CAMPAIGN_NOT_FOUND"] = "Default campaign not found";
12453
- LaunchCampaignError["LABELED_CAMPAIGN_NOT_FOUND"] = "Labeled campaign not found";
12454
- LaunchCampaignError["CAMPAIGN_DATA_NOT_FOUND"] = "Campaign data not found";
12455
- LaunchCampaignError["PAYWALL_ALREADY_DISPLAYED"] = "Paywall is already being displayed";
12456
- LaunchCampaignError["SDK_NOT_INITIALIZED"] = "SDK has not been initialized";
12457
- LaunchCampaignError["PAYWALL_COULD_NOT_DISPLAY"] = "Failed to display paywall";
12458
- LaunchCampaignError["URL_CAMPAIGN_NOT_FOUND"] = "URL campaign not found";
12459
- LaunchCampaignError["PRODUCT_DATA_NOT_FOUND"] = "Product data not found";
12460
- LaunchCampaignError["PRODUCT_GROUPS_NOT_FOUND"] = "Product groups not found";
12461
- LaunchCampaignError["FLOW_SCREEN_DATA_UNAVILABLE"] = "Flow unavailable due to missing screen data";
12462
- })(exports.LaunchCampaignError || (exports.LaunchCampaignError = {}));
12463
-
12464
12454
  const VALID_STYLES = new Set(['fullscreen', 'sheet', 'compact_sheet', 'modal']);
12465
12455
  function getEffectiveWebStyle(style) {
12466
12456
  if (!style || !VALID_STYLES.has(style))
@@ -12512,6 +12502,20 @@ exports.NamiPaywallAction = void 0;
12512
12502
  NamiPaywallAction["UNKNOWN"] = "UNKNOWN";
12513
12503
  })(exports.NamiPaywallAction || (exports.NamiPaywallAction = {}));
12514
12504
 
12505
+ exports.LaunchCampaignError = void 0;
12506
+ (function (LaunchCampaignError) {
12507
+ LaunchCampaignError["DEFAULT_CAMPAIGN_NOT_FOUND"] = "Default campaign not found";
12508
+ LaunchCampaignError["LABELED_CAMPAIGN_NOT_FOUND"] = "Labeled campaign not found";
12509
+ LaunchCampaignError["CAMPAIGN_DATA_NOT_FOUND"] = "Campaign data not found";
12510
+ LaunchCampaignError["PAYWALL_ALREADY_DISPLAYED"] = "Paywall is already being displayed";
12511
+ LaunchCampaignError["SDK_NOT_INITIALIZED"] = "SDK has not been initialized";
12512
+ LaunchCampaignError["PAYWALL_COULD_NOT_DISPLAY"] = "Failed to display paywall";
12513
+ LaunchCampaignError["URL_CAMPAIGN_NOT_FOUND"] = "URL campaign not found";
12514
+ LaunchCampaignError["PRODUCT_DATA_NOT_FOUND"] = "Product data not found";
12515
+ LaunchCampaignError["PRODUCT_GROUPS_NOT_FOUND"] = "Product groups not found";
12516
+ LaunchCampaignError["FLOW_SCREEN_DATA_UNAVILABLE"] = "Flow unavailable due to missing screen data";
12517
+ })(exports.LaunchCampaignError || (exports.LaunchCampaignError = {}));
12518
+
12515
12519
  const NamiFlowStepType = {
12516
12520
  ENTRY: 'entry',
12517
12521
  SCREEN: 'screen',
@@ -13255,7 +13259,7 @@ exports.AccountStateAction = void 0;
13255
13259
  AccountStateAction["NAMI_DEVICE_ID_CLEARED"] = "nami_device_id_cleared";
13256
13260
  })(exports.AccountStateAction || (exports.AccountStateAction = {}));
13257
13261
 
13258
- class NamiFlowManager {
13262
+ let NamiFlowManager$2 = class NamiFlowManager {
13259
13263
  static get instance() {
13260
13264
  if (!NamiFlowManager._instance) {
13261
13265
  NamiFlowManager._instance = new NamiFlowManager();
@@ -13284,11 +13288,50 @@ class NamiFlowManager {
13284
13288
  i.lastAnimatedFlowProgress = new Map();
13285
13289
  i.navGraphCache = new WeakMap();
13286
13290
  }
13291
+ /**
13292
+ * Registers a handoff step handler and returns an unsubscribe callback.
13293
+ *
13294
+ * The returned callback clears the registered handler only if it is still
13295
+ * the active one (identity-check guard). This protects against React 18
13296
+ * StrictMode dev-mode double-mount where a stale unsubscribe from the
13297
+ * first effect could fire after a second effect has already registered.
13298
+ *
13299
+ * Passing `undefined` clears the current handler immediately (preserved
13300
+ * for backward compatibility with the 3.3.x escape hatch). The returned
13301
+ * callback in that case is a no-op identity-check that will never fire.
13302
+ *
13303
+ * Aligns with the rest of the SDK's register*Handler family: all
13304
+ * NamiPaywallManager / NamiCampaignManager / NamiCustomerManager handler
13305
+ * registration methods return `Callback`. See NAM-1219.
13306
+ */
13287
13307
  static registerStepHandoff(handoffStepHandler) {
13288
13308
  this.instance.handoffStepHandler = handoffStepHandler;
13309
+ const captured = handoffStepHandler;
13310
+ return () => {
13311
+ if (this.instance.handoffStepHandler === captured) {
13312
+ this.instance.handoffStepHandler = undefined;
13313
+ }
13314
+ };
13289
13315
  }
13316
+ /**
13317
+ * Registers an event handler and returns an unsubscribe callback.
13318
+ *
13319
+ * The returned callback clears the registered handler only if it is still
13320
+ * the active one (identity-check guard). See `registerStepHandoff` for the
13321
+ * full rationale.
13322
+ *
13323
+ * Passing `undefined` clears the current handler immediately.
13324
+ *
13325
+ * See NAM-1219.
13326
+ */
13290
13327
  static registerEventHandler(eventHandler) {
13291
13328
  this.instance.eventHandler = eventHandler;
13329
+ const captured = eventHandler;
13330
+ return () => {
13331
+ if (this.instance.eventHandler === captured) {
13332
+ this.instance.eventHandler = undefined;
13333
+ }
13334
+ };
13292
13335
  }
13293
13336
  static resume() {
13294
13337
  const { flowOpen, currentFlow } = NamiFlowManager.instance;
@@ -13565,11 +13608,11 @@ class NamiFlowManager {
13565
13608
  static getCurrentFlowStepAutoAdvanceDelay() {
13566
13609
  return this.instance.getCurrentFlowStepAutoAdvanceDelay();
13567
13610
  }
13568
- }
13611
+ };
13569
13612
 
13570
- var NamiFlowManager$1 = /*#__PURE__*/Object.freeze({
13613
+ var NamiFlowManager$3 = /*#__PURE__*/Object.freeze({
13571
13614
  __proto__: null,
13572
- NamiFlowManager: NamiFlowManager
13615
+ NamiFlowManager: NamiFlowManager$2
13573
13616
  });
13574
13617
 
13575
13618
  const SHOULD_SHOW_LOADING_INDICATOR = false;
@@ -13591,7 +13634,7 @@ const isAsyncLoginLogoutDisabled = () => {
13591
13634
  * @class NamiCustomerManager
13592
13635
  * Provides methods for managing customer-related functionality.
13593
13636
  */
13594
- class NamiCustomerManager {
13637
+ let NamiCustomerManager$2 = class NamiCustomerManager {
13595
13638
  constructor() {
13596
13639
  this.emitter = NamiEventEmitter.getInstance();
13597
13640
  NamiConditionEvaluator.shared.registerNamespaceResolver("UserTags", (identifier) => {
@@ -13618,7 +13661,7 @@ class NamiCustomerManager {
13618
13661
  * @returns {boolean} Returns true if the customer is logged in, false otherwise.
13619
13662
  */
13620
13663
  static isLoggedIn() {
13621
- return NamiProfileManager.instance.isLoggedIn();
13664
+ return NamiProfileManager$1.instance.isLoggedIn();
13622
13665
  }
13623
13666
  /**
13624
13667
  * Returns the external ID of the currently logged in user.
@@ -13629,7 +13672,7 @@ class NamiCustomerManager {
13629
13672
  if (!this.instance.isSDKInitialized) {
13630
13673
  logger.debug(exports.SDK_NOT_INITIALIZED);
13631
13674
  }
13632
- return NamiProfileManager.instance.getExternalId();
13675
+ return NamiProfileManager$1.instance.getExternalId();
13633
13676
  }
13634
13677
  /**
13635
13678
  * Logs in a customer with the specified ID.
@@ -13652,10 +13695,10 @@ class NamiCustomerManager {
13652
13695
  // Default sync/fast path: update local state, notify handlers, and fire
13653
13696
  // lifecycle immediately. Dispatch the underlying API call and entitlement
13654
13697
  // refresh fire-and-forget — failures are logged but do not surface.
13655
- NamiProfileManager.instance.loginLocal(externalId);
13698
+ NamiProfileManager$1.instance.loginLocal(externalId);
13656
13699
  this.invokeStateHandler(exports.AccountStateAction.LOGIN, true);
13657
- if (NamiFlowManager.instance.flowOpen) {
13658
- const currentFlow = NamiFlowManager.instance.currentFlow;
13700
+ if (NamiFlowManager$2.instance.flowOpen) {
13701
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13659
13702
  const currentStep = currentFlow?.currentFlowStep;
13660
13703
  if (currentStep) {
13661
13704
  if (Nami.instance.maxLogging) {
@@ -13664,7 +13707,7 @@ class NamiCustomerManager {
13664
13707
  currentFlow.executeLifecycle(currentStep, NamiReservedActions.LOGIN_SUCCESS);
13665
13708
  }
13666
13709
  }
13667
- void NamiProfileManager.instance.loginRemote(externalId).catch((err) => {
13710
+ void NamiProfileManager$1.instance.loginRemote(externalId).catch((err) => {
13668
13711
  logger.error('[NamiCustomerManager] async login API failed', err);
13669
13712
  });
13670
13713
  void EntitlementRepository.instance.fetchActiveEntitlements().catch((err) => {
@@ -13673,11 +13716,11 @@ class NamiCustomerManager {
13673
13716
  return;
13674
13717
  }
13675
13718
  try {
13676
- await NamiProfileManager.instance.login(externalId);
13719
+ await NamiProfileManager$1.instance.login(externalId);
13677
13720
  await EntitlementRepository.instance.fetchActiveEntitlements();
13678
13721
  this.invokeStateHandler(exports.AccountStateAction.LOGIN, true);
13679
- if (NamiFlowManager.instance.flowOpen) {
13680
- const currentFlow = NamiFlowManager.instance.currentFlow;
13722
+ if (NamiFlowManager$2.instance.flowOpen) {
13723
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13681
13724
  const currentStep = currentFlow?.currentFlowStep;
13682
13725
  if (currentStep) {
13683
13726
  if (Nami.instance.maxLogging) {
@@ -13689,8 +13732,8 @@ class NamiCustomerManager {
13689
13732
  }
13690
13733
  catch (error) {
13691
13734
  this.invokeStateHandler(exports.AccountStateAction.LOGIN, false, error);
13692
- if (NamiFlowManager.instance.flowOpen) {
13693
- const currentFlow = NamiFlowManager.instance.currentFlow;
13735
+ if (NamiFlowManager$2.instance.flowOpen) {
13736
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13694
13737
  const currentStep = currentFlow?.currentFlowStep;
13695
13738
  if (currentStep) {
13696
13739
  if (Nami.instance.maxLogging) {
@@ -13721,10 +13764,10 @@ class NamiCustomerManager {
13721
13764
  // Default sync/fast path: clear local state, notify handlers, and fire
13722
13765
  // lifecycle immediately. Dispatch the underlying API call and entitlement
13723
13766
  // refresh fire-and-forget — failures are logged but do not surface.
13724
- NamiProfileManager.instance.logoutLocal();
13767
+ NamiProfileManager$1.instance.logoutLocal();
13725
13768
  this.invokeStateHandler(exports.AccountStateAction.LOGOUT, true);
13726
- if (NamiFlowManager.instance.flowOpen) {
13727
- const currentFlow = NamiFlowManager.instance.currentFlow;
13769
+ if (NamiFlowManager$2.instance.flowOpen) {
13770
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13728
13771
  const currentStep = currentFlow?.currentFlowStep;
13729
13772
  if (currentStep) {
13730
13773
  if (Nami.instance.maxLogging) {
@@ -13733,7 +13776,7 @@ class NamiCustomerManager {
13733
13776
  currentFlow.executeLifecycle(currentStep, NamiReservedActions.LOGOUT_SUCCESS);
13734
13777
  }
13735
13778
  }
13736
- void NamiProfileManager.instance.logoutRemote().catch((err) => {
13779
+ void NamiProfileManager$1.instance.logoutRemote().catch((err) => {
13737
13780
  logger.error('[NamiCustomerManager] async logout API failed', err);
13738
13781
  });
13739
13782
  void EntitlementRepository.instance.fetchActiveEntitlements().catch((err) => {
@@ -13742,11 +13785,11 @@ class NamiCustomerManager {
13742
13785
  return;
13743
13786
  }
13744
13787
  try {
13745
- await NamiProfileManager.instance.logout();
13788
+ await NamiProfileManager$1.instance.logout();
13746
13789
  await EntitlementRepository.instance.fetchActiveEntitlements();
13747
13790
  this.invokeStateHandler(exports.AccountStateAction.LOGOUT, true);
13748
- if (NamiFlowManager.instance.flowOpen) {
13749
- const currentFlow = NamiFlowManager.instance.currentFlow;
13791
+ if (NamiFlowManager$2.instance.flowOpen) {
13792
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13750
13793
  const currentStep = currentFlow?.currentFlowStep;
13751
13794
  if (currentStep) {
13752
13795
  currentFlow.executeLifecycle(currentStep, NamiReservedActions.LOGOUT_SUCCESS);
@@ -13755,8 +13798,8 @@ class NamiCustomerManager {
13755
13798
  }
13756
13799
  catch (error) {
13757
13800
  this.invokeStateHandler(exports.AccountStateAction.LOGOUT, false, error);
13758
- if (NamiFlowManager.instance.flowOpen) {
13759
- const currentFlow = NamiFlowManager.instance.currentFlow;
13801
+ if (NamiFlowManager$2.instance.flowOpen) {
13802
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13760
13803
  const currentStep = currentFlow?.currentFlowStep;
13761
13804
  if (currentStep) {
13762
13805
  currentFlow.executeLifecycle(currentStep, NamiReservedActions.LOGOUT_FAILURE);
@@ -13865,8 +13908,8 @@ class NamiCustomerManager {
13865
13908
  PaywallState.setCustomerAttribute({ [key]: value });
13866
13909
  logger.debug(`This customer attribute you set is now available for paywall personalization using the smart text variable: ${key}`);
13867
13910
  }
13868
- if (NamiFlowManager.instance.flowOpen) {
13869
- const currentFlow = NamiFlowManager.instance.currentFlow;
13911
+ if (NamiFlowManager$2.instance.flowOpen) {
13912
+ const currentFlow = NamiFlowManager$2.instance.currentFlow;
13870
13913
  if (currentFlow) {
13871
13914
  const currentStep = currentFlow.currentFlowStep;
13872
13915
  if (currentStep) {
@@ -14040,8 +14083,8 @@ class NamiCustomerManager {
14040
14083
  ]);
14041
14084
  }
14042
14085
  }
14043
- }
14044
- NamiCustomerManager.instance = new NamiCustomerManager();
14086
+ };
14087
+ NamiCustomerManager$2.instance = new NamiCustomerManager$2();
14045
14088
 
14046
14089
  class BasicNamiFlow {
14047
14090
  constructor(flowObject = {}) {
@@ -14478,7 +14521,7 @@ class NamiFlow extends BasicNamiFlow {
14478
14521
  if (action.parameters) {
14479
14522
  PaywallState.setUserTags(action.parameters);
14480
14523
  Object.entries(action.parameters).forEach(([key, value]) => {
14481
- NamiCustomerManager.setCustomerAttribute(key, value);
14524
+ NamiCustomerManager$2.setCustomerAttribute(key, value);
14482
14525
  });
14483
14526
  }
14484
14527
  break;
@@ -14625,7 +14668,7 @@ class NamiFlow extends BasicNamiFlow {
14625
14668
  * @class NamiCampaignManager
14626
14669
  * Provides methods for managing all aspects of a campaign.
14627
14670
  */
14628
- class NamiCampaignManager {
14671
+ let NamiCampaignManager$2 = class NamiCampaignManager {
14629
14672
  constructor() {
14630
14673
  this.emitter = NamiEventEmitter.getInstance();
14631
14674
  }
@@ -14855,8 +14898,115 @@ class NamiCampaignManager {
14855
14898
  }
14856
14899
  return { type, value };
14857
14900
  }
14858
- }
14859
- NamiCampaignManager.instance = new NamiCampaignManager();
14901
+ };
14902
+ NamiCampaignManager$2.instance = new NamiCampaignManager$2();
14903
+
14904
+ // Re-export the class itself, typed as the narrow public interface. The
14905
+ // runtime value IS the class (same object identity), so `jest.spyOn(...)`
14906
+ // in tests intercepts the same method that internal callers reach via
14907
+ // direct class import — no method-call indirection. The public `.d.ts`
14908
+ // however only sees the `NamiCampaignManagerStatic` surface: no
14909
+ // `.instance`, no `register()`-internal helpers, no private statics.
14910
+ // Renderer/test code that needs the unrestricted class imports from
14911
+ // `_internal` namespace on `@namiml/sdk-core` (NAM-1217). See NAM-1207.
14912
+ const NamiCampaignManager$1 = NamiCampaignManager$2;
14913
+
14914
+ // Re-export the class itself, typed as the narrow public interface. Same
14915
+ // object identity as the underlying class so jest.spyOn works. See
14916
+ // `src/managers/campaign.ts` and NAM-1207 for the full rationale.
14917
+ const NamiCustomerManager$1 = NamiCustomerManager$2;
14918
+
14919
+ /**
14920
+ * @class NamiEntitlementManager
14921
+ * Contains all methods and objects to work with entitlements in the SDK.
14922
+ */
14923
+ let NamiEntitlementManager$2 = class NamiEntitlementManager {
14924
+ constructor() {
14925
+ this.emitter = NamiEventEmitter.getInstance();
14926
+ }
14927
+ /**
14928
+ * @returns {NamiEntitlement[]} A list of currently active entitlements
14929
+ */
14930
+ static active() {
14931
+ if (!hasPurchaseManagement()) {
14932
+ return createNamiEntitlements();
14933
+ }
14934
+ return activeEntitlements();
14935
+ }
14936
+ /**
14937
+ * Checks if a Nami Control Center defined Entitlement has at least one backing purchase
14938
+ * and it's not expired.
14939
+ *
14940
+ * @param referenceId - entitlement referenceId
14941
+ * @returns {boolean} True if the entitlement is active for given referenceId, false otherwise.
14942
+ */
14943
+ static isEntitlementActive(referenceId) {
14944
+ if (!hasPurchaseManagement("NamiEntitlementManager.isEntitlementActive")) {
14945
+ return false;
14946
+ }
14947
+ return this.active().some((entitlement) => entitlement.referenceId == referenceId);
14948
+ }
14949
+ /**
14950
+ * Asks Nami to fetch the latest active entitlements
14951
+ *
14952
+ * @returns {Promise<NamiEntitlement[]>} A promise that resolves to a list of NamiEntitlement
14953
+ */
14954
+ static async refresh() {
14955
+ if (!this.instance.sdkInitialized) {
14956
+ throw new SDKNotInitializedError();
14957
+ }
14958
+ if (!hasPurchaseManagement("NamiEntitlementManager.refresh")) {
14959
+ return [];
14960
+ }
14961
+ await EntitlementRepository.instance.fetchActiveEntitlements();
14962
+ return activeEntitlements();
14963
+ }
14964
+ /**
14965
+ * When there has been an update received to the active entitlements,
14966
+ * the Nami SDK will provide notification of that event through
14967
+ * this callback with list of active [NamiEntitlement]
14968
+ *
14969
+ * @param {NamiActiveEntitlementsHandler} handler - The callback function that will be invoked when the campaign list is updated.
14970
+ * @returns {Callback} A function that can be called to unregister the handler.
14971
+ */
14972
+ static registerActiveEntitlementsHandler(handler) {
14973
+ if (hasPurchaseManagement("NamiEntitlementManager.registerActiveEntitlementsHandler")) {
14974
+ this.instance.emitter.addListener(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, handler);
14975
+ return () => {
14976
+ this.instance.emitter.removeListener(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, handler);
14977
+ };
14978
+ }
14979
+ }
14980
+ /**
14981
+ * Clear any provisional entitlement grants, which are entitlements issued on-device only.
14982
+ * Useful for development and purchase testing. Not recommended to be called in production.
14983
+ */
14984
+ static clearProvisionalEntitlementGrants() {
14985
+ let entitlements = activeEntitlements();
14986
+ entitlements = entitlements.filter((entitlement) => {
14987
+ return entitlement.expires && entitlement.expires > new Date().valueOf();
14988
+ });
14989
+ storageService.setNamiEntitlements(exports.LOCAL_NAMI_ENTITLEMENTS, entitlements);
14990
+ this.instance.emitter.emit(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED);
14991
+ }
14992
+ /**
14993
+ * Private Instance Methods
14994
+ */
14995
+ get sdkInitialized() {
14996
+ return Nami.instance.isInitialized;
14997
+ }
14998
+ };
14999
+ NamiEntitlementManager$2.instance = new NamiEntitlementManager$2();
15000
+
15001
+ // Re-export the class itself, typed as the narrow public interface. Same
15002
+ // object identity as the underlying class so jest.spyOn works. See
15003
+ // `src/managers/campaign.ts` and NAM-1207.
15004
+ const NamiEntitlementManager$1 = NamiEntitlementManager$2;
15005
+
15006
+ // Re-export the class itself, typed as the narrow public interface. Same
15007
+ // object identity as the underlying class so jest.spyOn works. See
15008
+ // `src/managers/campaign.ts` and NAM-1207.
15009
+ const NamiFlowManager$1 = NamiFlowManager$2;
14860
15010
 
14861
15011
  const postConversion = async (transactionInfo) => {
14862
15012
  if (isAnonymousMode()) {
@@ -14875,7 +15025,7 @@ const postConversion = async (transactionInfo) => {
14875
15025
  * @class NamiPaywallManager
14876
15026
  * Provides methods for managing all aspects of a paywall in the Nami SDK.
14877
15027
  */
14878
- class NamiPaywallManager {
15028
+ let NamiPaywallManager$2 = class NamiPaywallManager {
14879
15029
  constructor() {
14880
15030
  this.emitter = NamiEventEmitter.getInstance();
14881
15031
  }
@@ -14958,14 +15108,14 @@ class NamiPaywallManager {
14958
15108
  static async buySkuComplete(purchase) {
14959
15109
  // clear loading indicator
14960
15110
  PaywallState.setPurchaseInProgress(false);
14961
- if (NamiFlowManager.instance.flowOpen) {
14962
- const flow = NamiFlowManager.instance.currentFlow;
15111
+ if (NamiFlowManager$2.instance.flowOpen) {
15112
+ const flow = NamiFlowManager$2.instance.currentFlow;
14963
15113
  const currentStep = flow?.currentFlowStep;
14964
15114
  if (flow && currentStep) {
14965
15115
  flow.executeLifecycle(currentStep, NamiReservedActions.PURCHASE_SUCCESS);
14966
15116
  }
14967
15117
  }
14968
- if (NamiCustomerManager.inAnonymousMode()) {
15118
+ if (NamiCustomerManager$2.inAnonymousMode()) {
14969
15119
  logger.debug("Skipping purchase validation - anonymous mode");
14970
15120
  return;
14971
15121
  }
@@ -15046,142 +15196,19 @@ class NamiPaywallManager {
15046
15196
  get sdkInitialized() {
15047
15197
  return Nami.instance.isInitialized;
15048
15198
  }
15049
- }
15050
- NamiPaywallManager.instance = new NamiPaywallManager();
15051
- NamiPaywallManager.emitter = NamiEventEmitter.getInstance();
15199
+ };
15200
+ NamiPaywallManager$2.instance = new NamiPaywallManager$2();
15201
+ NamiPaywallManager$2.emitter = NamiEventEmitter.getInstance();
15052
15202
 
15053
- /**
15054
- * @class NamiEntitlementManager
15055
- * Contains all methods and objects to work with entitlements in the SDK.
15056
- */
15057
- class NamiEntitlementManager {
15058
- constructor() {
15059
- this.emitter = NamiEventEmitter.getInstance();
15060
- }
15061
- /**
15062
- * @returns {NamiEntitlement[]} A list of currently active entitlements
15063
- */
15064
- static active() {
15065
- if (!hasPurchaseManagement()) {
15066
- return createNamiEntitlements();
15067
- }
15068
- return activeEntitlements();
15069
- }
15070
- /**
15071
- * Checks if a Nami Control Center defined Entitlement has at least one backing purchase
15072
- * and it's not expired.
15073
- *
15074
- * @param referenceId - entitlement referenceId
15075
- * @returns {boolean} True if the entitlement is active for given referenceId, false otherwise.
15076
- */
15077
- static isEntitlementActive(referenceId) {
15078
- if (!hasPurchaseManagement("NamiEntitlementManager.isEntitlementActive")) {
15079
- return false;
15080
- }
15081
- return this.active().some((entitlement) => entitlement.referenceId == referenceId);
15082
- }
15083
- /**
15084
- * Asks Nami to fetch the latest active entitlements
15085
- *
15086
- * @returns {Promise<NamiEntitlement[]>} A promise that resolves to a list of NamiEntitlement
15087
- */
15088
- static async refresh() {
15089
- if (!this.instance.sdkInitialized) {
15090
- throw new SDKNotInitializedError();
15091
- }
15092
- if (!hasPurchaseManagement("NamiEntitlementManager.refresh")) {
15093
- return [];
15094
- }
15095
- await EntitlementRepository.instance.fetchActiveEntitlements();
15096
- return activeEntitlements();
15097
- }
15098
- /**
15099
- * When there has been an update received to the active entitlements,
15100
- * the Nami SDK will provide notification of that event through
15101
- * this callback with list of active [NamiEntitlement]
15102
- *
15103
- * @param {NamiActiveEntitlementsHandler} handler - The callback function that will be invoked when the campaign list is updated.
15104
- * @returns {Callback} A function that can be called to unregister the handler.
15105
- */
15106
- static registerActiveEntitlementsHandler(handler) {
15107
- if (hasPurchaseManagement("NamiEntitlementManager.registerActiveEntitlementsHandler")) {
15108
- this.instance.emitter.addListener(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, handler);
15109
- return () => {
15110
- this.instance.emitter.removeListener(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, handler);
15111
- };
15112
- }
15113
- }
15114
- /**
15115
- * Clear any provisional entitlement grants, which are entitlements issued on-device only.
15116
- * Useful for development and purchase testing. Not recommended to be called in production.
15117
- */
15118
- static clearProvisionalEntitlementGrants() {
15119
- let entitlements = activeEntitlements();
15120
- entitlements = entitlements.filter((entitlement) => {
15121
- return entitlement.expires && entitlement.expires > new Date().valueOf();
15122
- });
15123
- storageService.setNamiEntitlements(exports.LOCAL_NAMI_ENTITLEMENTS, entitlements);
15124
- this.instance.emitter.emit(exports.AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED);
15125
- }
15126
- /**
15127
- * Private Instance Methods
15128
- */
15129
- get sdkInitialized() {
15130
- return Nami.instance.isInitialized;
15131
- }
15132
- }
15133
- NamiEntitlementManager.instance = new NamiEntitlementManager();
15203
+ // Re-export the class itself, typed as the narrow public interface. Same
15204
+ // object identity as the underlying class so jest.spyOn works. See
15205
+ // `src/managers/campaign.ts` and NAM-1207.
15206
+ const NamiPaywallManager$1 = NamiPaywallManager$2;
15134
15207
 
15135
- ({
15136
- /**
15137
- * Registers a handler to be invoked when a flow step triggers a handoff event.
15138
- *
15139
- * This allows you to intercept a handoff step in a Nami Flow and execute custom logic
15140
- *
15141
- * @param handoffStepHandler - A callback function that will be called when a handoff occurs.
15142
- * It receives the `handoffTag` string (identifying the step) and an optional `handoffData`
15143
- * object with additional context. If `undefined`, the current handler is cleared.
15144
- *
15145
- */
15146
- registerStepHandoff: NamiFlowManager.registerStepHandoff.bind(NamiFlowManager),
15147
- /**
15148
- * Registers a handler to be invoked when events are emitted.
15149
- *
15150
- * This enables you to use your own custom event tracking.
15151
- *
15152
- * @param eventHandler - A callback function that will be called when an event occurs.
15153
- * The argument is a key-value object containing event data.
15154
- * If `undefined`, the current handler is cleared
15155
- *
15156
- */
15157
- registerEventHandler: NamiFlowManager.registerEventHandler.bind(NamiFlowManager),
15158
- /**
15159
- * Resumes the Nami Flow after a handoff has been completed.
15160
- *
15161
- * This should be called by once any custom logic associated with
15162
- * a handoff has completed.
15163
- * It signals to continue to the next step in the flow sequence.
15164
- */
15165
- resume: NamiFlowManager.resume.bind(NamiFlowManager),
15166
- /**
15167
- * Finishes the current flow programmatically.
15168
- *
15169
- * This can be used to end the flow at any point, typically after a handoff or custom logic.
15170
- */
15171
- finish: NamiFlowManager.finish.bind(NamiFlowManager),
15172
- /**
15173
- * Pauses the current flow.
15174
- *
15175
- * This can be used to temporarily halt the flow, typically in response to user input or other events.
15176
- */
15177
- pause: NamiFlowManager.pause.bind(NamiFlowManager),
15178
- /**
15179
- * Checks if a flow is currently open.
15180
- *
15181
- * @returns {boolean} - True if a flow is open, false otherwise.
15182
- */
15183
- isFlowOpen: NamiFlowManager.isFlowOpen.bind(NamiFlowManager),
15184
- });
15208
+ // Re-export the class itself, typed as the narrow public interface. Same
15209
+ // object identity as the underlying class so jest.spyOn works. See
15210
+ // `src/managers/campaign.ts` and NAM-1207.
15211
+ const NamiPurchaseManager$1 = NamiPurchaseManager$2;
15185
15212
 
15186
15213
  const BorderMap = {
15187
15214
  upperLeft: 'border-top-left-radius',
@@ -64696,6 +64723,53 @@ function namiBuySKU(skuRefId) {
64696
64723
  return result;
64697
64724
  }
64698
64725
 
64726
+ /**
64727
+ * Source of the `_internal` namespace re-exported from `index.ts` — typed
64728
+ * escape hatch for the underlying manager classes.
64729
+ *
64730
+ * The public surface at `@namiml/sdk-core` (and `@namiml/web-sdk`) exposes each
64731
+ * manager as a narrow const proxy of documented methods only. Renderer code and
64732
+ * tests that need the singleton (`Foo.instance`), private event emitters, or
64733
+ * internal helper statics that aren't part of the documented public API import
64734
+ * the classes via the `_internal` namespace on `@namiml/sdk-core` — which
64735
+ * re-exports the values declared here with their wider class types.
64736
+ *
64737
+ * **Critical bundle behavior.** Every runtime value here is imported from
64738
+ * `'./index'` (the package's root entry). When index.ts re-exports this module
64739
+ * as `export * as _internal from './internal'`, the values flow through the
64740
+ * same module identity as the root entry — no duplication. Adapters registered
64741
+ * via the documented public surface remain visible to code reached through the
64742
+ * `_internal` namespace, because both paths reference the same module-scoped
64743
+ * `_adapters` map in `adapters/index.ts`. See NAM-1207 (PR #340 + PR #342) for
64744
+ * the singleton-split regression history that motivated this indirection, and
64745
+ * NAM-1217 for the move from the `/internal` subpath to a root namespace.
64746
+ *
64747
+ * Not part of the public contract. Method signatures here can change between
64748
+ * minor releases. If you depend on something here as a third-party integrator,
64749
+ * file a ticket asking for a documented public equivalent — that's a signal we
64750
+ * should widen the public surface, not a license to track this entry point.
64751
+ */
64752
+ // Runtime values are the same class identities the root entry holds — cast
64753
+ // widens the type from the narrow public proxy back to the class.
64754
+ const NamiCampaignManager = NamiCampaignManager$1;
64755
+ const NamiCustomerManager = NamiCustomerManager$1;
64756
+ const NamiPaywallManager = NamiPaywallManager$1;
64757
+ const NamiEntitlementManager = NamiEntitlementManager$1;
64758
+ const NamiFlowManager = NamiFlowManager$1;
64759
+ const NamiPurchaseManager = NamiPurchaseManager$1;
64760
+ const NamiProfileManager = NamiProfileManager$1;
64761
+
64762
+ var internal = /*#__PURE__*/Object.freeze({
64763
+ __proto__: null,
64764
+ NamiCampaignManager: NamiCampaignManager,
64765
+ NamiCustomerManager: NamiCustomerManager,
64766
+ NamiEntitlementManager: NamiEntitlementManager,
64767
+ NamiFlowManager: NamiFlowManager,
64768
+ NamiPaywallManager: NamiPaywallManager,
64769
+ NamiProfileManager: NamiProfileManager,
64770
+ NamiPurchaseManager: NamiPurchaseManager
64771
+ });
64772
+
64699
64773
  exports.APIError = APIError;
64700
64774
  exports.AnonymousCDPError = AnonymousCDPError;
64701
64775
  exports.AnonymousLoginError = AnonymousLoginError;
@@ -64724,18 +64798,17 @@ exports.NAMI_STORAGE_KEYS = NAMI_STORAGE_KEYS;
64724
64798
  exports.Nami = Nami;
64725
64799
  exports.NamiAPI = NamiAPI;
64726
64800
  exports.NamiAnimationType = NamiAnimationType;
64727
- exports.NamiCampaignManager = NamiCampaignManager;
64801
+ exports.NamiCampaignManager = NamiCampaignManager$1;
64728
64802
  exports.NamiConditionEvaluator = NamiConditionEvaluator;
64729
- exports.NamiCustomerManager = NamiCustomerManager;
64730
- exports.NamiEntitlementManager = NamiEntitlementManager;
64803
+ exports.NamiCustomerManager = NamiCustomerManager$1;
64804
+ exports.NamiEntitlementManager = NamiEntitlementManager$1;
64731
64805
  exports.NamiEventEmitter = NamiEventEmitter;
64732
64806
  exports.NamiFlow = NamiFlow;
64733
- exports.NamiFlowManager = NamiFlowManager;
64807
+ exports.NamiFlowManager = NamiFlowManager$1;
64734
64808
  exports.NamiFlowStepType = NamiFlowStepType;
64735
- exports.NamiPaywallManager = NamiPaywallManager;
64809
+ exports.NamiPaywallManager = NamiPaywallManager$1;
64736
64810
  exports.NamiPaywallManagerEvents = exports.PaywallManagerEvents;
64737
- exports.NamiProfileManager = NamiProfileManager;
64738
- exports.NamiPurchaseManager = NamiPurchaseManager;
64811
+ exports.NamiPurchaseManager = NamiPurchaseManager$1;
64739
64812
  exports.NamiRefs = NamiRefs;
64740
64813
  exports.NamiReservedActions = NamiReservedActions;
64741
64814
  exports.NotFoundError = NotFoundError;
@@ -64750,6 +64823,8 @@ exports.SHOULD_SHOW_LOADING_INDICATOR = SHOULD_SHOW_LOADING_INDICATOR;
64750
64823
  exports.SessionService = SessionService;
64751
64824
  exports.SimpleEventTarget = SimpleEventTarget;
64752
64825
  exports.StorageService = StorageService;
64826
+ exports._NamiProfileManager = NamiProfileManager$1;
64827
+ exports._internal = internal;
64753
64828
  exports.activateEntitlementByPurchase = activateEntitlementByPurchase;
64754
64829
  exports.activeEntitlements = activeEntitlements;
64755
64830
  exports.aggregateScreenreaderText = aggregateScreenreaderText;