@namiml/sdk-core 3.4.4-dev.202606241934 → 3.4.4-dev.202606241952
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 +637 -222
- package/dist/index.d.ts +1588 -1297
- package/dist/index.mjs +636 -223
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -96,7 +96,7 @@ const {
|
|
|
96
96
|
// version — stamped by scripts/version.sh
|
|
97
97
|
NAMI_SDK_VERSION = "3.4.4",
|
|
98
98
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
99
|
-
NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.
|
|
99
|
+
NAMI_SDK_PACKAGE_VERSION = "3.4.4-dev.202606241952",
|
|
100
100
|
// environments
|
|
101
101
|
PRODUCTION = "production", DEVELOPMENT = "development",
|
|
102
102
|
// error messages
|
|
@@ -6984,8 +6984,21 @@ class NamiAPI {
|
|
|
6984
6984
|
const resp = await this.requestBodyAPI(path, options, "POST", true);
|
|
6985
6985
|
if (resp.id) {
|
|
6986
6986
|
storageService.setLastImpressionId(resp.id);
|
|
6987
|
+
// Notify the flow-completion engine (no-op unless a flow is open) so it
|
|
6988
|
+
// can bind this impression to the current screen's completion context.
|
|
6989
|
+
NamiAPI.impressionListener?.(resp.id);
|
|
6987
6990
|
}
|
|
6988
6991
|
}
|
|
6992
|
+
/**
|
|
6993
|
+
* Reports a flow completion result against a prior impression
|
|
6994
|
+
* (NAM-1545 / Flow Completion Step). UPDATE-only on the server; the
|
|
6995
|
+
* impression must already exist. `keepalive` so a dismiss-triggered PATCH
|
|
6996
|
+
* survives page unload on web.
|
|
6997
|
+
*/
|
|
6998
|
+
async patchImpressionCompletion(impressionId, completion_result, completion_result_date) {
|
|
6999
|
+
const path = `device/${this.deviceID}/impression/${impressionId}/`;
|
|
7000
|
+
await this.requestBodyAPI(path, { completion_result, completion_result_date }, "PATCH", true);
|
|
7001
|
+
}
|
|
6989
7002
|
async postConversion(options) {
|
|
6990
7003
|
const path = `device/${this.deviceID}/transaction/`;
|
|
6991
7004
|
await this.requestBodyAPI(path, options, "POST", true);
|
|
@@ -7024,6 +7037,9 @@ __decorate([
|
|
|
7024
7037
|
__decorate([
|
|
7025
7038
|
requireDeviceID
|
|
7026
7039
|
], NamiAPI.prototype, "postImpression", null);
|
|
7040
|
+
__decorate([
|
|
7041
|
+
requireDeviceID
|
|
7042
|
+
], NamiAPI.prototype, "patchImpressionCompletion", null);
|
|
7027
7043
|
__decorate([
|
|
7028
7044
|
requireDeviceID
|
|
7029
7045
|
], NamiAPI.prototype, "postConversion", null);
|
|
@@ -12621,6 +12637,70 @@ var NamiFlowActionFunction;
|
|
|
12621
12637
|
const HandoffTag = {
|
|
12622
12638
|
SEQUENCE: '__handoff_sequence__',
|
|
12623
12639
|
};
|
|
12640
|
+
/**
|
|
12641
|
+
* Prefix marking SDK-reserved handoff tags. Reserved tags are consumed
|
|
12642
|
+
* internally and are NEVER delivered to host-registered handoff handlers.
|
|
12643
|
+
*/
|
|
12644
|
+
const RESERVED_HANDOFF_TAG_PREFIX = '__';
|
|
12645
|
+
/**
|
|
12646
|
+
* Customer-facing handoff tag vocabulary.
|
|
12647
|
+
*
|
|
12648
|
+
* Keep in sync with `FlowHandoffTag` in nami-platform
|
|
12649
|
+
* `services/frontend/src/api/types/flow.types.tsx` (minus the `__*__`
|
|
12650
|
+
* internal tags, which never reach host handlers). The builder constrains
|
|
12651
|
+
* authoring to this set, but the vocabulary evolves — treat unknown tags as
|
|
12652
|
+
* pass-through, never as errors.
|
|
12653
|
+
*
|
|
12654
|
+
* Note `Tracking` is the legacy `att` authoring convention; the permission
|
|
12655
|
+
* enum value is `tracking` and the completion wire value is
|
|
12656
|
+
* `tracking_authorized`. Aliasing is intentional — do not rename.
|
|
12657
|
+
*/
|
|
12658
|
+
const NamiHandoffTag = {
|
|
12659
|
+
Push: 'push',
|
|
12660
|
+
Location: 'location',
|
|
12661
|
+
Tracking: 'att',
|
|
12662
|
+
Deeplink: 'deeplink',
|
|
12663
|
+
Complete: 'complete',
|
|
12664
|
+
SignIn: 'signin',
|
|
12665
|
+
Restore: 'restore',
|
|
12666
|
+
SignInMvpd: 'signin_mvpd',
|
|
12667
|
+
BuySku: 'buysku',
|
|
12668
|
+
UserData: 'userdata',
|
|
12669
|
+
};
|
|
12670
|
+
/**
|
|
12671
|
+
* Permission types reportable through a handoff outcome.
|
|
12672
|
+
*
|
|
12673
|
+
* Tier 1 (`push`, `location`, `tracking`) map to impression
|
|
12674
|
+
* `completion_result` wire values; the remaining tier-2 types are accepted
|
|
12675
|
+
* (flow state + lifecycle only) and gain wire values via backend tickets
|
|
12676
|
+
* without SDK API churn.
|
|
12677
|
+
*/
|
|
12678
|
+
const NamiPermissionOutcome = {
|
|
12679
|
+
Push: 'push',
|
|
12680
|
+
Location: 'location',
|
|
12681
|
+
Tracking: 'tracking',
|
|
12682
|
+
Camera: 'camera',
|
|
12683
|
+
Microphone: 'microphone',
|
|
12684
|
+
Photos: 'photos',
|
|
12685
|
+
Contacts: 'contacts',
|
|
12686
|
+
Bluetooth: 'bluetooth',
|
|
12687
|
+
Calendar: 'calendar',
|
|
12688
|
+
Biometrics: 'biometrics',
|
|
12689
|
+
Health: 'health',
|
|
12690
|
+
Motion: 'motion',
|
|
12691
|
+
Speech: 'speech',
|
|
12692
|
+
LocalNetwork: 'localNetwork',
|
|
12693
|
+
};
|
|
12694
|
+
/**
|
|
12695
|
+
* Tier-1 permission → impression completion_result wire value. Keep in sync
|
|
12696
|
+
* with omaha `Impression.CompletionResult` / breakwater
|
|
12697
|
+
* `ValidCompletionResults`.
|
|
12698
|
+
*/
|
|
12699
|
+
const COMPLETION_MAPPED_PERMISSIONS = {
|
|
12700
|
+
[NamiPermissionOutcome.Push]: 'push_authorized',
|
|
12701
|
+
[NamiPermissionOutcome.Location]: 'location_authorized',
|
|
12702
|
+
[NamiPermissionOutcome.Tracking]: 'tracking_authorized',
|
|
12703
|
+
};
|
|
12624
12704
|
const NamiReservedActions = {
|
|
12625
12705
|
BUY_SKU: '__buy_sku__',
|
|
12626
12706
|
DEFAULT: '__default__',
|
|
@@ -12635,6 +12715,7 @@ const NamiReservedActions = {
|
|
|
12635
12715
|
RESUME: '__resume__',
|
|
12636
12716
|
REMOTE_BACK: '__remoteback__',
|
|
12637
12717
|
TAG_UPDATE: '__tag_update__',
|
|
12718
|
+
PERMISSION_GRANTED: '__permission_granted__',
|
|
12638
12719
|
};
|
|
12639
12720
|
|
|
12640
12721
|
const LogicalOperator = {
|
|
@@ -13383,6 +13464,198 @@ var AccountStateAction;
|
|
|
13383
13464
|
AccountStateAction["NAMI_DEVICE_ID_CLEARED"] = "nami_device_id_cleared";
|
|
13384
13465
|
})(AccountStateAction || (AccountStateAction = {}));
|
|
13385
13466
|
|
|
13467
|
+
const postConversion = async (transactionInfo) => {
|
|
13468
|
+
if (isAnonymousMode()) {
|
|
13469
|
+
logger.info("Skipping transaction post - anonymous mode");
|
|
13470
|
+
return;
|
|
13471
|
+
}
|
|
13472
|
+
try {
|
|
13473
|
+
await NamiAPI.instance.postConversion(transactionInfo);
|
|
13474
|
+
}
|
|
13475
|
+
catch (e) {
|
|
13476
|
+
logger.error("Error posting conversion", e);
|
|
13477
|
+
}
|
|
13478
|
+
};
|
|
13479
|
+
|
|
13480
|
+
/**
|
|
13481
|
+
* @class NamiPaywallManager
|
|
13482
|
+
* Provides methods for managing all aspects of a paywall in the Nami SDK.
|
|
13483
|
+
*/
|
|
13484
|
+
let NamiPaywallManager$2 = class NamiPaywallManager {
|
|
13485
|
+
constructor() {
|
|
13486
|
+
this.emitter = NamiEventEmitter.getInstance();
|
|
13487
|
+
}
|
|
13488
|
+
/**
|
|
13489
|
+
* @returns {IPaywall[]} a list of Paywall
|
|
13490
|
+
*/
|
|
13491
|
+
static allPaywalls() {
|
|
13492
|
+
if (!this.instance.sdkInitialized) {
|
|
13493
|
+
throw new SDKNotInitializedError();
|
|
13494
|
+
}
|
|
13495
|
+
return allPaywalls();
|
|
13496
|
+
}
|
|
13497
|
+
/**
|
|
13498
|
+
* Used to set product details when store products are unavailable. For advanced use cases only.
|
|
13499
|
+
*/
|
|
13500
|
+
static setProductDetails(productDetails) {
|
|
13501
|
+
this.instance.productDetails = productDetails;
|
|
13502
|
+
PaywallState.setProductDetails(productDetails);
|
|
13503
|
+
}
|
|
13504
|
+
/**
|
|
13505
|
+
* Register a callback which would be invoked when user will sign-in
|
|
13506
|
+
*/
|
|
13507
|
+
static registerSignInHandler(handler) {
|
|
13508
|
+
this.instance.emitter.addListener(PaywallManagerEvents.SignIn, handler);
|
|
13509
|
+
return () => {
|
|
13510
|
+
this.instance.emitter.removeListener(PaywallManagerEvents.SignIn, handler);
|
|
13511
|
+
};
|
|
13512
|
+
}
|
|
13513
|
+
/**
|
|
13514
|
+
* Register a callback which would be invoked when user close a paywall raised by Nami system
|
|
13515
|
+
*/
|
|
13516
|
+
static registerCloseHandler(handler) {
|
|
13517
|
+
this.instance.emitter.addListener(PaywallManagerEvents.Close, handler);
|
|
13518
|
+
return () => {
|
|
13519
|
+
this.instance.emitter.removeListener(PaywallManagerEvents.Close, handler);
|
|
13520
|
+
};
|
|
13521
|
+
}
|
|
13522
|
+
/**
|
|
13523
|
+
* Register a callback which would be invoked when user will take action on deeplink
|
|
13524
|
+
*/
|
|
13525
|
+
static registerDeeplinkActionHandler(handler) {
|
|
13526
|
+
this.instance.emitter.addListener(PaywallManagerEvents.DeeplinkAction, handler);
|
|
13527
|
+
return () => {
|
|
13528
|
+
this.instance.emitter.removeListener(PaywallManagerEvents.DeeplinkAction, handler);
|
|
13529
|
+
};
|
|
13530
|
+
}
|
|
13531
|
+
/**
|
|
13532
|
+
* Register a [NamiBuySkuHandler] which would be invoked when a user triggers
|
|
13533
|
+
* a buy sku action on a paywall.
|
|
13534
|
+
*
|
|
13535
|
+
* Only available for plans where Nami is not handling subscription & IAP management.
|
|
13536
|
+
*/
|
|
13537
|
+
static registerBuySkuHandler(handler) {
|
|
13538
|
+
if (hasPurchaseManagement()) {
|
|
13539
|
+
logger.debug("This handler will not be invoked because this account's plan includes " +
|
|
13540
|
+
"built-in purchase management. Contact support@namiml.com for details.");
|
|
13541
|
+
}
|
|
13542
|
+
this.instance.emitter.addListener(PaywallManagerEvents.BuySku, handler);
|
|
13543
|
+
return () => {
|
|
13544
|
+
this.instance.emitter.removeListener(PaywallManagerEvents.BuySku, handler);
|
|
13545
|
+
};
|
|
13546
|
+
}
|
|
13547
|
+
/**
|
|
13548
|
+
* Register a callback which would be invoked when user restore a product
|
|
13549
|
+
*/
|
|
13550
|
+
static registerRestoreHandler(handler) {
|
|
13551
|
+
this.instance.emitter.addListener(PaywallManagerEvents.Restore, handler);
|
|
13552
|
+
return () => {
|
|
13553
|
+
this.instance.emitter.removeListener(PaywallManagerEvents.Restore, handler);
|
|
13554
|
+
};
|
|
13555
|
+
}
|
|
13556
|
+
/**
|
|
13557
|
+
* Notify the NamiPaywallManager that a purchase initiated from the
|
|
13558
|
+
* [NamiBuySkuHandler] is complete.
|
|
13559
|
+
*
|
|
13560
|
+
* Only available for plans where Nami is not handling subscription & IAP management.
|
|
13561
|
+
*
|
|
13562
|
+
* @returns {Promise<void>} A Promise that resolves when buying SKU will be complete.
|
|
13563
|
+
*/
|
|
13564
|
+
static async buySkuComplete(purchase) {
|
|
13565
|
+
// clear loading indicator
|
|
13566
|
+
PaywallState.setPurchaseInProgress(false);
|
|
13567
|
+
if (NamiFlowManager$2.instance.flowOpen) {
|
|
13568
|
+
const flow = NamiFlowManager$2.instance.currentFlow;
|
|
13569
|
+
const currentStep = flow?.currentFlowStep;
|
|
13570
|
+
if (flow && currentStep) {
|
|
13571
|
+
flow.executeLifecycle(currentStep, NamiReservedActions.PURCHASE_SUCCESS);
|
|
13572
|
+
}
|
|
13573
|
+
}
|
|
13574
|
+
if (NamiCustomerManager$2.inAnonymousMode()) {
|
|
13575
|
+
logger.debug("Skipping purchase validation - anonymous mode");
|
|
13576
|
+
return;
|
|
13577
|
+
}
|
|
13578
|
+
const session = storageService.getSessionId();
|
|
13579
|
+
const impression = storageService.getPurchaseImpression();
|
|
13580
|
+
if (!impression) {
|
|
13581
|
+
logger.debug("Not sending paywall conversion call complete due to unknown impression");
|
|
13582
|
+
return;
|
|
13583
|
+
}
|
|
13584
|
+
// send conversion
|
|
13585
|
+
try {
|
|
13586
|
+
await postConversion({
|
|
13587
|
+
purchase_env: "production",
|
|
13588
|
+
app_env: "production",
|
|
13589
|
+
impression,
|
|
13590
|
+
session,
|
|
13591
|
+
amount: purchase.amount,
|
|
13592
|
+
currency: purchase.currency,
|
|
13593
|
+
transaction_id: purchase.transactionId,
|
|
13594
|
+
sku: purchase.skuId,
|
|
13595
|
+
});
|
|
13596
|
+
}
|
|
13597
|
+
catch (e) {
|
|
13598
|
+
logger.error('Error posting conversion', e);
|
|
13599
|
+
}
|
|
13600
|
+
// validate purchase
|
|
13601
|
+
if (!hasCapability(Capabilities.THIRD_PARTY_TRANSACTIONS)) {
|
|
13602
|
+
try {
|
|
13603
|
+
await NamiAPI.instance.purchaseValidation({
|
|
13604
|
+
app_env: "production",
|
|
13605
|
+
payload: '', // token to be added when here a direct integration is done
|
|
13606
|
+
sku: purchase.skuId,
|
|
13607
|
+
});
|
|
13608
|
+
}
|
|
13609
|
+
catch (e) {
|
|
13610
|
+
logger.error("Error validating purchase", e);
|
|
13611
|
+
}
|
|
13612
|
+
}
|
|
13613
|
+
}
|
|
13614
|
+
/**
|
|
13615
|
+
* Notify the NamiPaywallManager that purchase flow handled by you is cancelled.
|
|
13616
|
+
* Used to disable product purchase-in-progress loading indicators
|
|
13617
|
+
*/
|
|
13618
|
+
static buySkuCancel() {
|
|
13619
|
+
if (!hasCapability(Capabilities.THIRD_PARTY_TRANSACTIONS)) {
|
|
13620
|
+
logger.warn("Call this method is not needed for this app because Nami is responsible for purchase management. Contact support@nami.ml for details.");
|
|
13621
|
+
return;
|
|
13622
|
+
}
|
|
13623
|
+
PaywallState.setPurchase(false);
|
|
13624
|
+
}
|
|
13625
|
+
/**
|
|
13626
|
+
* Set the video details for the app supplied video
|
|
13627
|
+
* @param url The URL of the video
|
|
13628
|
+
* @param name The name of the video
|
|
13629
|
+
*/
|
|
13630
|
+
static setAppSuppliedVideoDetails(url, name) {
|
|
13631
|
+
if (isValidUrl(url)) {
|
|
13632
|
+
logger.debug(`NamiPaywallManager: setAppSuppliedVideoDetails received valid url ${url}`);
|
|
13633
|
+
PaywallState.setAppSuppliedVideoDetails({ url, name });
|
|
13634
|
+
}
|
|
13635
|
+
else {
|
|
13636
|
+
logger.debug(`NamiPaywallManager: setAppSuppliedVideoDetails received invalid url ${url}`);
|
|
13637
|
+
}
|
|
13638
|
+
}
|
|
13639
|
+
/**
|
|
13640
|
+
* Enables or disables user interaction on Nami paywalls.
|
|
13641
|
+
*
|
|
13642
|
+
* @param {boolean} allowed - Whether user interaction should be allowed.
|
|
13643
|
+
* @returns {void}
|
|
13644
|
+
*/
|
|
13645
|
+
static allowUserInteraction(allowed) {
|
|
13646
|
+
logger.debug(`NamiPaywallManager: allowUserInteraction called with ${allowed}`);
|
|
13647
|
+
PaywallState.setUserInteractionEnabled(allowed);
|
|
13648
|
+
}
|
|
13649
|
+
/**
|
|
13650
|
+
* Private Instance Methods
|
|
13651
|
+
*/
|
|
13652
|
+
get sdkInitialized() {
|
|
13653
|
+
return Nami.instance.isInitialized;
|
|
13654
|
+
}
|
|
13655
|
+
};
|
|
13656
|
+
NamiPaywallManager$2.instance = new NamiPaywallManager$2();
|
|
13657
|
+
NamiPaywallManager$2.emitter = NamiEventEmitter.getInstance();
|
|
13658
|
+
|
|
13386
13659
|
let NamiFlowManager$2 = class NamiFlowManager {
|
|
13387
13660
|
static get instance() {
|
|
13388
13661
|
if (!NamiFlowManager._instance) {
|
|
@@ -13411,10 +13684,24 @@ let NamiFlowManager$2 = class NamiFlowManager {
|
|
|
13411
13684
|
i.flowOpen = false;
|
|
13412
13685
|
i.lastAnimatedFlowProgress = new Map();
|
|
13413
13686
|
i.navGraphCache = new WeakMap();
|
|
13687
|
+
i.pendingHandoff = undefined;
|
|
13414
13688
|
}
|
|
13415
13689
|
/**
|
|
13416
13690
|
* Registers a handoff step handler and returns an unsubscribe callback.
|
|
13417
13691
|
*
|
|
13692
|
+
* The handler receives `(tag, data, complete)`. Call `complete(outcome)`
|
|
13693
|
+
* exactly once with a typed {@link NamiHandoffOutcome}: completing
|
|
13694
|
+
* reports the outcome AND resumes the flow in one call. A bare
|
|
13695
|
+
* `complete()` is equivalent to `complete({ kind: 'done' })`. The
|
|
13696
|
+
* outcome's routing (lifecycles, purchase/login machinery) runs before
|
|
13697
|
+
* the resume, matching the pre-outcome `buySkuComplete(); resume()`
|
|
13698
|
+
* call order.
|
|
13699
|
+
*
|
|
13700
|
+
* Handlers written against the old `(tag, data)` signature still run —
|
|
13701
|
+
* the extra argument is ignored at runtime, and their existing
|
|
13702
|
+
* `resume()` call degrades to `complete({kind:'done'})` with a
|
|
13703
|
+
* migration warning.
|
|
13704
|
+
*
|
|
13418
13705
|
* The returned callback clears the registered handler only if it is still
|
|
13419
13706
|
* the active one (identity-check guard). This protects against React 18
|
|
13420
13707
|
* StrictMode dev-mode double-mount where a stale unsubscribe from the
|
|
@@ -13437,6 +13724,131 @@ let NamiFlowManager$2 = class NamiFlowManager {
|
|
|
13437
13724
|
}
|
|
13438
13725
|
};
|
|
13439
13726
|
}
|
|
13727
|
+
/** Whether a handoff handler is registered. */
|
|
13728
|
+
get hasHandoffHandler() {
|
|
13729
|
+
return !!this.handoffStepHandler;
|
|
13730
|
+
}
|
|
13731
|
+
/**
|
|
13732
|
+
* Single delivery point for handoffs reaching the host app. Flow code must
|
|
13733
|
+
* route through here (never invoke the handler field directly) so every
|
|
13734
|
+
* handler receives a working `complete` and reserved-tag guarding stays
|
|
13735
|
+
* upstream in the dispatcher.
|
|
13736
|
+
*/
|
|
13737
|
+
deliverHandoff(tag, data) {
|
|
13738
|
+
const handler = this.handoffStepHandler;
|
|
13739
|
+
if (!handler)
|
|
13740
|
+
return;
|
|
13741
|
+
const pending = { tag, completed: false };
|
|
13742
|
+
this.pendingHandoff = pending;
|
|
13743
|
+
const complete = (outcome) => {
|
|
13744
|
+
if (pending.completed) {
|
|
13745
|
+
logger.warn(`[NamiFlowManager] complete() called more than once for handoff '${tag}' — ignored`);
|
|
13746
|
+
return;
|
|
13747
|
+
}
|
|
13748
|
+
const current = NamiFlowManager.instance.pendingHandoff;
|
|
13749
|
+
if (current && current !== pending) {
|
|
13750
|
+
logger.warn(`[NamiFlowManager] stale complete() for handoff '${tag}' — a newer handoff ('${current.tag}') is pending; ignored`);
|
|
13751
|
+
return;
|
|
13752
|
+
}
|
|
13753
|
+
pending.completed = true;
|
|
13754
|
+
if (this.pendingHandoff === pending) {
|
|
13755
|
+
this.pendingHandoff = undefined;
|
|
13756
|
+
}
|
|
13757
|
+
// No argument means "nothing to report" — the done outcome.
|
|
13758
|
+
NamiFlowManager.routeHandoffOutcome(outcome ?? { kind: 'done' });
|
|
13759
|
+
NamiFlowManager.resume();
|
|
13760
|
+
};
|
|
13761
|
+
handler(tag, data, complete);
|
|
13762
|
+
}
|
|
13763
|
+
/**
|
|
13764
|
+
* Applies a typed handoff outcome to the SDK before the flow resumes.
|
|
13765
|
+
* Ordering contract: outcome routing first (its lifecycles may navigate),
|
|
13766
|
+
* `resume()` last — identical to the legacy integrator call order.
|
|
13767
|
+
*/
|
|
13768
|
+
static routeHandoffOutcome(outcome) {
|
|
13769
|
+
const flow = NamiFlowManager.instance.currentFlow;
|
|
13770
|
+
const step = flow?.currentFlowStep;
|
|
13771
|
+
switch (outcome.kind) {
|
|
13772
|
+
case 'done':
|
|
13773
|
+
return;
|
|
13774
|
+
case 'permission': {
|
|
13775
|
+
if (!flow)
|
|
13776
|
+
return;
|
|
13777
|
+
flow.handoffState.permissions[outcome.permission] = outcome.granted;
|
|
13778
|
+
if (!outcome.granted)
|
|
13779
|
+
return;
|
|
13780
|
+
if (step)
|
|
13781
|
+
flow.executeLifecycle(step, NamiReservedActions.PERMISSION_GRANTED);
|
|
13782
|
+
const wireValue = COMPLETION_MAPPED_PERMISSIONS[outcome.permission];
|
|
13783
|
+
if (wireValue) {
|
|
13784
|
+
// Permissions have no flow lifecycle to ride, so the completion
|
|
13785
|
+
// signal is fired directly here (purchase/login ride
|
|
13786
|
+
// executeLifecycle instead — see below).
|
|
13787
|
+
flow.completionSignal(wireValue);
|
|
13788
|
+
}
|
|
13789
|
+
else {
|
|
13790
|
+
logger.debug(`[NamiFlowManager] permission '${outcome.permission}' granted — no completion_result mapping yet (state/lifecycle only)`);
|
|
13791
|
+
}
|
|
13792
|
+
return;
|
|
13793
|
+
}
|
|
13794
|
+
case 'purchase': {
|
|
13795
|
+
if (outcome.result === 'success') {
|
|
13796
|
+
// buySkuComplete fires __purchase_success__ (and the conversion)
|
|
13797
|
+
// itself; executeLifecycle raises the completion signal. Don't
|
|
13798
|
+
// double-dispatch here.
|
|
13799
|
+
void NamiPaywallManager$2.buySkuComplete(outcome.details);
|
|
13800
|
+
}
|
|
13801
|
+
else {
|
|
13802
|
+
PaywallState.setPurchase(false);
|
|
13803
|
+
if (flow && step)
|
|
13804
|
+
flow.executeLifecycle(step, NamiReservedActions.PURCHASE_FAILURE);
|
|
13805
|
+
}
|
|
13806
|
+
return;
|
|
13807
|
+
}
|
|
13808
|
+
case 'login': {
|
|
13809
|
+
if (outcome.result === 'success') {
|
|
13810
|
+
const { details } = outcome;
|
|
13811
|
+
if (flow) {
|
|
13812
|
+
// Open-ended host-asserted experience data — exposed to branch
|
|
13813
|
+
// conditions and smart text via the `login.*` namespace using
|
|
13814
|
+
// the host's own key names (e.g. login.subscriberStatus).
|
|
13815
|
+
flow.handoffState.login = { ...(details.attributes ?? {}) };
|
|
13816
|
+
}
|
|
13817
|
+
// Identity writes are idempotent: skip when the asserted ids
|
|
13818
|
+
// already match what the SDK holds, so re-asserting an existing
|
|
13819
|
+
// login doesn't re-run profile sync or device updates.
|
|
13820
|
+
if (NamiCustomerManager$2.loggedInId() === details.loginId) {
|
|
13821
|
+
// Already this user — login() would be a no-op network-wise,
|
|
13822
|
+
// but the flow still needs its __login_success__ actions
|
|
13823
|
+
// (login() owns that dispatch on the fresh-login path).
|
|
13824
|
+
if (flow && step)
|
|
13825
|
+
flow.executeLifecycle(step, NamiReservedActions.LOGIN_SUCCESS);
|
|
13826
|
+
}
|
|
13827
|
+
else {
|
|
13828
|
+
// login() fires __login_success__/__login_failure__ itself — do
|
|
13829
|
+
// not double-dispatch lifecycles here.
|
|
13830
|
+
void Promise.resolve(NamiCustomerManager$2.login(details.loginId)).catch((err) => {
|
|
13831
|
+
logger.error('[NamiFlowManager] login from handoff outcome failed', err);
|
|
13832
|
+
});
|
|
13833
|
+
}
|
|
13834
|
+
const currentCdpId = storageService.getDevice()?.customer_data_platform_id;
|
|
13835
|
+
if (details.cdpId && details.cdpId !== currentCdpId) {
|
|
13836
|
+
void Promise.resolve(NamiCustomerManager$2.setCustomerDataPlatformId(details.cdpId)).catch((err) => {
|
|
13837
|
+
logger.error('[NamiFlowManager] CDP id write-through from handoff outcome failed', err);
|
|
13838
|
+
});
|
|
13839
|
+
}
|
|
13840
|
+
// Both the fresh-login and idempotent-skip paths above dispatch
|
|
13841
|
+
// __login_success__ via executeLifecycle, which raises the
|
|
13842
|
+
// completion signal — no direct call needed here.
|
|
13843
|
+
}
|
|
13844
|
+
else {
|
|
13845
|
+
if (flow && step)
|
|
13846
|
+
flow.executeLifecycle(step, NamiReservedActions.LOGIN_FAILURE);
|
|
13847
|
+
}
|
|
13848
|
+
return;
|
|
13849
|
+
}
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13440
13852
|
/**
|
|
13441
13853
|
* Registers an event handler and returns an unsubscribe callback.
|
|
13442
13854
|
*
|
|
@@ -13462,6 +13874,14 @@ let NamiFlowManager$2 = class NamiFlowManager {
|
|
|
13462
13874
|
if (Nami.instance.maxLogging) {
|
|
13463
13875
|
logger.debug(`[NamiFlowManager] resume() — flowOpen=${flowOpen}, hasFlow=${!!currentFlow}, currentStep=${currentFlow?.currentFlowStep?.id ?? 'none'}, isPaused=${currentFlow?.isPaused ?? 'N/A'}`);
|
|
13464
13876
|
}
|
|
13877
|
+
// A v2 handler calling bare resume() instead of complete() is treated as
|
|
13878
|
+
// complete({kind:'done'}) — flow continues, but nudge toward migration.
|
|
13879
|
+
const pending = NamiFlowManager.instance.pendingHandoff;
|
|
13880
|
+
if (pending && !pending.completed) {
|
|
13881
|
+
pending.completed = true;
|
|
13882
|
+
NamiFlowManager.instance.pendingHandoff = undefined;
|
|
13883
|
+
logger.warn(`[NamiFlowManager] resume() called during handoff '${pending.tag}' with a v2 handler registered — treated as complete({kind:'done'}); prefer complete(outcome)`);
|
|
13884
|
+
}
|
|
13465
13885
|
if (!flowOpen || !currentFlow || !currentFlow.currentFlowStep) {
|
|
13466
13886
|
logger.warn('Cannot resume: no active flow or current step');
|
|
13467
13887
|
return;
|
|
@@ -13483,8 +13903,11 @@ let NamiFlowManager$2 = class NamiFlowManager {
|
|
|
13483
13903
|
logger.debug('Cannot finish: no active flow or current step');
|
|
13484
13904
|
return;
|
|
13485
13905
|
}
|
|
13906
|
+
// Host-initiated close is a dismissal — records dismiss_page against the
|
|
13907
|
+
// current screen's impression (R5) before teardown (no-op if a positive
|
|
13908
|
+
// completion was already recorded).
|
|
13486
13909
|
logger.debug(`Finishing flow programmatically at step ${currentFlow.currentFlowStep.id}`);
|
|
13487
|
-
currentFlow.
|
|
13910
|
+
currentFlow.dismiss();
|
|
13488
13911
|
}
|
|
13489
13912
|
static pause() {
|
|
13490
13913
|
const { flowOpen, currentFlow } = NamiFlowManager.instance;
|
|
@@ -13506,6 +13929,13 @@ let NamiFlowManager$2 = class NamiFlowManager {
|
|
|
13506
13929
|
const flow = new NamiFlow(campaign, paywall, this, context);
|
|
13507
13930
|
this.flowOpen = true;
|
|
13508
13931
|
this.currentFlow = flow;
|
|
13932
|
+
// Bind each impression posted for this flow's screens to the active
|
|
13933
|
+
// flow's per-raise completion context (NAM-1545, R1). Registered here so
|
|
13934
|
+
// the listener is in place before the first screen's impression posts;
|
|
13935
|
+
// it no-ops for non-flow impressions because currentFlow clears on finish.
|
|
13936
|
+
NamiAPI.impressionListener = (impressionId) => {
|
|
13937
|
+
NamiFlowManager.instance.currentFlow?.bindImpression(impressionId);
|
|
13938
|
+
};
|
|
13509
13939
|
return flow;
|
|
13510
13940
|
}
|
|
13511
13941
|
finishFlow() {
|
|
@@ -14294,6 +14724,14 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14294
14724
|
this.isPaused = false;
|
|
14295
14725
|
this.flowPath = "";
|
|
14296
14726
|
this.timerStates = {};
|
|
14727
|
+
/**
|
|
14728
|
+
* Flow-scoped state written by typed handoff outcomes (Variant D).
|
|
14729
|
+
* Exposed to branch conditions and smart text via the `login.*` and
|
|
14730
|
+
* `permissions.*` namespaces registered in {@link registerResolvers}.
|
|
14731
|
+
* `login` holds the host's open-ended attributes verbatim, keyed by the
|
|
14732
|
+
* host's own names (e.g. `login.subscriberStatus`, `login.tier`).
|
|
14733
|
+
*/
|
|
14734
|
+
this.handoffState = { permissions: {} };
|
|
14297
14735
|
this.campaign = campaign;
|
|
14298
14736
|
this.component = paywall;
|
|
14299
14737
|
this.context = context;
|
|
@@ -14335,6 +14773,17 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14335
14773
|
return undefined;
|
|
14336
14774
|
}
|
|
14337
14775
|
});
|
|
14776
|
+
// Variant D handoff-outcome state: `login.<attributeKey>` (host-named,
|
|
14777
|
+
// open-ended) and `permissions.<type>` for branch conditions and smart
|
|
14778
|
+
// text.
|
|
14779
|
+
NamiConditionEvaluator.shared.registerNamespaceResolver('login', (identifier) => {
|
|
14780
|
+
const key = identifier.replace(/^login\./, '');
|
|
14781
|
+
return this.handoffState.login?.[key];
|
|
14782
|
+
});
|
|
14783
|
+
NamiConditionEvaluator.shared.registerNamespaceResolver('permissions', (identifier) => {
|
|
14784
|
+
const key = identifier.replace(/^permissions\./, '');
|
|
14785
|
+
return this.handoffState.permissions[key];
|
|
14786
|
+
});
|
|
14338
14787
|
NamiConditionEvaluator.shared.registerNamespaceResolver('__first_session__', () => {
|
|
14339
14788
|
return NamiRefs.instance.getIsFirstSession();
|
|
14340
14789
|
});
|
|
@@ -14385,6 +14834,18 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14385
14834
|
this.manager.finishFlow();
|
|
14386
14835
|
// UI is responsible for closing paywall when flow ends
|
|
14387
14836
|
}
|
|
14837
|
+
/**
|
|
14838
|
+
* Dismiss the flow (hard close): records `dismiss_page` against the current
|
|
14839
|
+
* screen's impression (R5) before tearing down. The single choke point for
|
|
14840
|
+
* host-initiated dismissal, the `flowDismiss` action, back-button exits,
|
|
14841
|
+
* and platform swipe-down dismissals — anything that ends the flow without
|
|
14842
|
+
* a user "skip" or a programmatic `flowDone`. Never overwrites a positive
|
|
14843
|
+
* completion (R4 guard inside `signalNonCompletion`).
|
|
14844
|
+
*/
|
|
14845
|
+
dismiss() {
|
|
14846
|
+
this.signalNonCompletion('dismiss_page');
|
|
14847
|
+
this.finished();
|
|
14848
|
+
}
|
|
14388
14849
|
back() {
|
|
14389
14850
|
if (this.previousFlowStep?.allow_back_to === false) {
|
|
14390
14851
|
logger.debug(`Not allowed to go back to ${this.previousFlowStep.id}`);
|
|
@@ -14395,12 +14856,89 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14395
14856
|
.slice(0, -1)
|
|
14396
14857
|
.some(step => step.type === 'screen');
|
|
14397
14858
|
if (!hasPreviousScreen) {
|
|
14398
|
-
this.flowLog(`back() — no previous screen step,
|
|
14399
|
-
this.
|
|
14859
|
+
this.flowLog(`back() — no previous screen step, dismissing flow`);
|
|
14860
|
+
this.dismiss();
|
|
14400
14861
|
return;
|
|
14401
14862
|
}
|
|
14402
14863
|
this.backToPreviousScreenStep();
|
|
14403
14864
|
}
|
|
14865
|
+
// ─── Flow completion (NAM-1545) ──────────────────────────────────────────
|
|
14866
|
+
/**
|
|
14867
|
+
* Binds a freshly-posted impression id to the current screen's raise.
|
|
14868
|
+
* Called via `NamiAPI.impressionListener` whenever an impression posts
|
|
14869
|
+
* while this flow is open. Starts a fresh completion context for the raise
|
|
14870
|
+
* (a re-render — e.g. back-navigation — rebinds with a clean result),
|
|
14871
|
+
* fires `page_view` completion immediately if applicable (R2), and flushes
|
|
14872
|
+
* any condition signals that arrived before the id (R1).
|
|
14873
|
+
*/
|
|
14874
|
+
bindImpression(impressionId) {
|
|
14875
|
+
const step = this.currentFlowStep;
|
|
14876
|
+
if (!step)
|
|
14877
|
+
return;
|
|
14878
|
+
const ctx = this.completionContext;
|
|
14879
|
+
if (ctx && ctx.stepId === step.id && !ctx.impressionId) {
|
|
14880
|
+
// A signal already created the context for this raise — fill the id.
|
|
14881
|
+
ctx.impressionId = impressionId;
|
|
14882
|
+
}
|
|
14883
|
+
else {
|
|
14884
|
+
this.completionContext = { stepId: step.id, impressionId, resultSent: false, pending: [] };
|
|
14885
|
+
}
|
|
14886
|
+
const cs = step.completion_step;
|
|
14887
|
+
if (cs?.enabled && cs.condition === 'page_view') {
|
|
14888
|
+
this.completionSignal('page_view');
|
|
14889
|
+
}
|
|
14890
|
+
const queued = this.completionContext.pending;
|
|
14891
|
+
this.completionContext.pending = [];
|
|
14892
|
+
queued.forEach((condition) => this.completionSignal(condition));
|
|
14893
|
+
}
|
|
14894
|
+
/**
|
|
14895
|
+
* Reports that `condition` was satisfied on the current page. PATCHes the
|
|
14896
|
+
* completion result only when the current step is a matching, enabled
|
|
14897
|
+
* completion step and no result has been sent for this impression yet.
|
|
14898
|
+
* Signals arriving before the impression id is bound are queued (R1).
|
|
14899
|
+
*/
|
|
14900
|
+
completionSignal(condition) {
|
|
14901
|
+
const step = this.currentFlowStep;
|
|
14902
|
+
const cs = step?.completion_step;
|
|
14903
|
+
if (!step || !cs?.enabled || cs.condition !== condition)
|
|
14904
|
+
return;
|
|
14905
|
+
let ctx = this.completionContext;
|
|
14906
|
+
if (!ctx || ctx.stepId !== step.id) {
|
|
14907
|
+
ctx = this.completionContext = { stepId: step.id, resultSent: false, pending: [] };
|
|
14908
|
+
}
|
|
14909
|
+
if (ctx.resultSent)
|
|
14910
|
+
return; // R4: one completion per impression
|
|
14911
|
+
if (!ctx.impressionId) {
|
|
14912
|
+
if (!ctx.pending.includes(condition))
|
|
14913
|
+
ctx.pending.push(condition);
|
|
14914
|
+
return; // R1: flushed once the impression id binds
|
|
14915
|
+
}
|
|
14916
|
+
ctx.resultSent = true;
|
|
14917
|
+
void this.patchCompletion(ctx.impressionId, condition);
|
|
14918
|
+
}
|
|
14919
|
+
/**
|
|
14920
|
+
* Records a non-completion outcome (`skip_page` / `dismiss_page`) against
|
|
14921
|
+
* the current page's impression when the flow terminates without
|
|
14922
|
+
* completing (R5 — feeds the flow-conversion cube). Applies to any page,
|
|
14923
|
+
* completion-step or not, but never overwrites a positive result (R4) and
|
|
14924
|
+
* no-ops when no impression is bound (e.g. anonymous mode).
|
|
14925
|
+
*/
|
|
14926
|
+
signalNonCompletion(result) {
|
|
14927
|
+
const ctx = this.completionContext;
|
|
14928
|
+
if (!ctx || !ctx.impressionId || ctx.resultSent)
|
|
14929
|
+
return;
|
|
14930
|
+
ctx.resultSent = true;
|
|
14931
|
+
void this.patchCompletion(ctx.impressionId, result);
|
|
14932
|
+
}
|
|
14933
|
+
async patchCompletion(impressionId, result) {
|
|
14934
|
+
this.flowLog(`patchCompletion(${result}) — impression=${impressionId}, step=${this.currentFlowStep?.id}`);
|
|
14935
|
+
try {
|
|
14936
|
+
await NamiAPI.instance.patchImpressionCompletion(impressionId, result, new Date().toISOString());
|
|
14937
|
+
}
|
|
14938
|
+
catch (err) {
|
|
14939
|
+
logger.error(`[NamiFlow] completion PATCH failed for '${result}'`, err);
|
|
14940
|
+
}
|
|
14941
|
+
}
|
|
14404
14942
|
next() {
|
|
14405
14943
|
const nextStep = this.nextFlowStep;
|
|
14406
14944
|
if (nextStep) {
|
|
@@ -14485,6 +15023,17 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14485
15023
|
this.forward(resumeId);
|
|
14486
15024
|
}
|
|
14487
15025
|
executeLifecycle(step, key, data) {
|
|
15026
|
+
// Completion signals ride the lifecycle dispatch so every path that
|
|
15027
|
+
// raises these events — SDK-managed purchase, host-managed purchase,
|
|
15028
|
+
// login (fresh + idempotent-skip), buffered replay — funnels through one
|
|
15029
|
+
// site (NAM-1545). Fired before the no-actions early-return: completion
|
|
15030
|
+
// is about the event happening, not about the step defining flow actions.
|
|
15031
|
+
if (key === NamiReservedActions.PURCHASE_SUCCESS) {
|
|
15032
|
+
this.completionSignal('purchase_success');
|
|
15033
|
+
}
|
|
15034
|
+
else if (key === NamiReservedActions.LOGIN_SUCCESS) {
|
|
15035
|
+
this.completionSignal('login_success');
|
|
15036
|
+
}
|
|
14488
15037
|
const lifecycles = step.actions[key];
|
|
14489
15038
|
if (!lifecycles) {
|
|
14490
15039
|
this.flowLog(`executeLifecycle(${key}) — no actions on step ${step.id}`);
|
|
@@ -14631,10 +15180,18 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14631
15180
|
}
|
|
14632
15181
|
break;
|
|
14633
15182
|
case NamiFlowActionFunction.FINISHED:
|
|
14634
|
-
|
|
15183
|
+
// "Navigate to end of flow" — not a dismissal, not a completion;
|
|
15184
|
+
// no completion result is recorded (R5).
|
|
14635
15185
|
this.finished();
|
|
14636
15186
|
break;
|
|
15187
|
+
case NamiFlowActionFunction.DISMISS:
|
|
15188
|
+
this.dismiss();
|
|
15189
|
+
break;
|
|
14637
15190
|
case NamiFlowActionFunction.EXIT: {
|
|
15191
|
+
// User skip / exit-to-end-of-flow → skip_page (R5). Signalled here,
|
|
15192
|
+
// not at the exit step, because routing through the exit step's own
|
|
15193
|
+
// flowDone would otherwise overwrite the skip intent.
|
|
15194
|
+
this.signalNonCompletion('skip_page');
|
|
14638
15195
|
const exit = this.steps.find((step) => step.type === NamiFlowStepType.EXIT);
|
|
14639
15196
|
if (exit)
|
|
14640
15197
|
this.forward(exit.id);
|
|
@@ -14646,34 +15203,58 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14646
15203
|
case NamiFlowActionFunction.RESUME:
|
|
14647
15204
|
this.resumeFromPause();
|
|
14648
15205
|
break;
|
|
14649
|
-
case NamiFlowActionFunction.HANDOFF:
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
|
|
14654
|
-
|
|
14655
|
-
|
|
14656
|
-
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
|
|
14667
|
-
|
|
14668
|
-
this.manager.handoffStepHandler(action.parameters.handoffTag, formData);
|
|
14669
|
-
}
|
|
15206
|
+
case NamiFlowActionFunction.HANDOFF: {
|
|
15207
|
+
const tag = action.parameters?.handoffTag;
|
|
15208
|
+
if (!tag)
|
|
15209
|
+
break;
|
|
15210
|
+
// Form-commit choke point: a flowHandoff carrying a form id IS the
|
|
15211
|
+
// form submit (R3). Fired before the reserved-tag early-out so the
|
|
15212
|
+
// `__handoff_sequence__` form path signals too; the condition guard
|
|
15213
|
+
// means it only completes on a `form_submitted` page (the push POC
|
|
15214
|
+
// also carries a form id — harmless, its condition is push_authorized).
|
|
15215
|
+
if (action.parameters?.handoffFormId) {
|
|
15216
|
+
this.completionSignal('form_submitted');
|
|
15217
|
+
}
|
|
15218
|
+
// Reserved tags are SDK-internal and must NEVER reach the host
|
|
15219
|
+
// handler — checked FIRST, before any payload branching, so a
|
|
15220
|
+
// sequence action that also carries handoffData cannot leak
|
|
15221
|
+
// (NAM-1556).
|
|
15222
|
+
if (tag.startsWith(RESERVED_HANDOFF_TAG_PREFIX)) {
|
|
15223
|
+
if (tag === HandoffTag.SEQUENCE && action.parameters?.handoffFormId) {
|
|
15224
|
+
this.flowHandoffFormSequence();
|
|
14670
15225
|
}
|
|
14671
15226
|
else {
|
|
14672
|
-
logger.
|
|
14673
|
-
this.manager.
|
|
15227
|
+
logger.warn(`Ignoring reserved handoff tag '${tag}' — resuming flow`);
|
|
15228
|
+
this.manager.resume();
|
|
14674
15229
|
}
|
|
15230
|
+
break;
|
|
14675
15231
|
}
|
|
15232
|
+
if (!this.manager.hasHandoffHandler) {
|
|
15233
|
+
logger.debug('No handoffStepHandler found', action);
|
|
15234
|
+
break;
|
|
15235
|
+
}
|
|
15236
|
+
// userdata is an outbound data delivery: always a structured
|
|
15237
|
+
// envelope, never the bare form dict.
|
|
15238
|
+
if (tag === NamiHandoffTag.UserData && action.parameters?.handoffFormId) {
|
|
15239
|
+
this.manager.deliverHandoff(tag, this.buildUserDataEnvelope(action.parameters.handoffFormId));
|
|
15240
|
+
break;
|
|
15241
|
+
}
|
|
15242
|
+
// Legacy payload precedence, unchanged: embedded handoffData →
|
|
15243
|
+
// trigger data → form data (when a form id is present) → none.
|
|
15244
|
+
let payload;
|
|
15245
|
+
if (action.parameters?.handoffData) {
|
|
15246
|
+
payload = action.parameters.handoffData;
|
|
15247
|
+
}
|
|
15248
|
+
else if (data) {
|
|
15249
|
+
payload = data;
|
|
15250
|
+
}
|
|
15251
|
+
else if (action.parameters?.handoffFormId) {
|
|
15252
|
+
payload = this.getFormData();
|
|
15253
|
+
}
|
|
15254
|
+
logger.debug(`Invoking handoff handler with ${tag}${payload ? ` ${JSON.stringify(payload)}` : ' and no data'}`);
|
|
15255
|
+
this.manager.deliverHandoff(tag, payload);
|
|
14676
15256
|
break;
|
|
15257
|
+
}
|
|
14677
15258
|
case NamiFlowActionFunction.LOG:
|
|
14678
15259
|
if (action.parameters?.eventName) {
|
|
14679
15260
|
logger.info(`logEvent → ${action.parameters.eventName}`);
|
|
@@ -14744,9 +15325,19 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14744
15325
|
}
|
|
14745
15326
|
break;
|
|
14746
15327
|
case NamiFlowActionFunction.SET_TAGS_FROM_FORM: {
|
|
15328
|
+
// Writes captured form values to customer attributes (Apple
|
|
15329
|
+
// parity: skip null / empty-string, KEEP false / 0 — enforced by
|
|
15330
|
+
// formTagValue). Optional `include` lists the only field keys
|
|
15331
|
+
// retained — the orthogonal half of userdata delivery: everything is
|
|
15332
|
+
// delivered to the host, only explicitly routed fields are retained
|
|
15333
|
+
// by Nami.
|
|
15334
|
+
const include = action.parameters?.include;
|
|
15335
|
+
const includeSet = Array.isArray(include) ? new Set(include) : undefined;
|
|
14747
15336
|
const formData = this.getFormData();
|
|
14748
15337
|
const tags = {};
|
|
14749
15338
|
Object.entries(formData).forEach(([key, raw]) => {
|
|
15339
|
+
if (includeSet && !includeSet.has(key))
|
|
15340
|
+
return;
|
|
14750
15341
|
const value = formTagValue(raw);
|
|
14751
15342
|
if (value === undefined) {
|
|
14752
15343
|
return; // skip null / "" (false and 0 are kept by formTagValue)
|
|
@@ -14858,6 +15449,19 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14858
15449
|
getFormData() {
|
|
14859
15450
|
return { ...PaywallState.currentProvider?.state?.formStates ?? {} };
|
|
14860
15451
|
}
|
|
15452
|
+
/**
|
|
15453
|
+
* Structured payload for `userdata` handoffs: Nami delivering the host
|
|
15454
|
+
* app the data the user provided in a Nami-rendered form. Fields ride
|
|
15455
|
+
* verbatim; the customer owns interpretation.
|
|
15456
|
+
*/
|
|
15457
|
+
buildUserDataEnvelope(formId) {
|
|
15458
|
+
return {
|
|
15459
|
+
form_id: formId,
|
|
15460
|
+
step_id: this.currentFlowStep?.id ?? '',
|
|
15461
|
+
collected_at: new Date().toISOString(),
|
|
15462
|
+
fields: this.getFormData(),
|
|
15463
|
+
};
|
|
15464
|
+
}
|
|
14861
15465
|
flowHandoffFormSequence() {
|
|
14862
15466
|
const formStates = this.currentScreenState?.formStates;
|
|
14863
15467
|
if (!formStates) {
|
|
@@ -14900,8 +15504,9 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
14900
15504
|
logger.debug(`Starting handoff for ${nextKey} → ${String(value)}`);
|
|
14901
15505
|
// persist updated sequence (remainingKeys mutated)
|
|
14902
15506
|
this.activeHandoffSequence = sequence;
|
|
14903
|
-
|
|
14904
|
-
|
|
15507
|
+
// Route through the manager's single delivery point so v2 handlers get
|
|
15508
|
+
// a working complete() for sequence-key handoffs too.
|
|
15509
|
+
this.manager.deliverHandoff(`${nextKey}`, undefined);
|
|
14905
15510
|
}
|
|
14906
15511
|
}
|
|
14907
15512
|
|
|
@@ -15249,198 +15854,6 @@ const NamiEntitlementManager$1 = NamiEntitlementManager$2;
|
|
|
15249
15854
|
// `src/managers/campaign.ts` and NAM-1207.
|
|
15250
15855
|
const NamiFlowManager$1 = NamiFlowManager$2;
|
|
15251
15856
|
|
|
15252
|
-
const postConversion = async (transactionInfo) => {
|
|
15253
|
-
if (isAnonymousMode()) {
|
|
15254
|
-
logger.info("Skipping transaction post - anonymous mode");
|
|
15255
|
-
return;
|
|
15256
|
-
}
|
|
15257
|
-
try {
|
|
15258
|
-
await NamiAPI.instance.postConversion(transactionInfo);
|
|
15259
|
-
}
|
|
15260
|
-
catch (e) {
|
|
15261
|
-
logger.error("Error posting conversion", e);
|
|
15262
|
-
}
|
|
15263
|
-
};
|
|
15264
|
-
|
|
15265
|
-
/**
|
|
15266
|
-
* @class NamiPaywallManager
|
|
15267
|
-
* Provides methods for managing all aspects of a paywall in the Nami SDK.
|
|
15268
|
-
*/
|
|
15269
|
-
let NamiPaywallManager$2 = class NamiPaywallManager {
|
|
15270
|
-
constructor() {
|
|
15271
|
-
this.emitter = NamiEventEmitter.getInstance();
|
|
15272
|
-
}
|
|
15273
|
-
/**
|
|
15274
|
-
* @returns {IPaywall[]} a list of Paywall
|
|
15275
|
-
*/
|
|
15276
|
-
static allPaywalls() {
|
|
15277
|
-
if (!this.instance.sdkInitialized) {
|
|
15278
|
-
throw new SDKNotInitializedError();
|
|
15279
|
-
}
|
|
15280
|
-
return allPaywalls();
|
|
15281
|
-
}
|
|
15282
|
-
/**
|
|
15283
|
-
* Used to set product details when store products are unavailable. For advanced use cases only.
|
|
15284
|
-
*/
|
|
15285
|
-
static setProductDetails(productDetails) {
|
|
15286
|
-
this.instance.productDetails = productDetails;
|
|
15287
|
-
PaywallState.setProductDetails(productDetails);
|
|
15288
|
-
}
|
|
15289
|
-
/**
|
|
15290
|
-
* Register a callback which would be invoked when user will sign-in
|
|
15291
|
-
*/
|
|
15292
|
-
static registerSignInHandler(handler) {
|
|
15293
|
-
this.instance.emitter.addListener(PaywallManagerEvents.SignIn, handler);
|
|
15294
|
-
return () => {
|
|
15295
|
-
this.instance.emitter.removeListener(PaywallManagerEvents.SignIn, handler);
|
|
15296
|
-
};
|
|
15297
|
-
}
|
|
15298
|
-
/**
|
|
15299
|
-
* Register a callback which would be invoked when user close a paywall raised by Nami system
|
|
15300
|
-
*/
|
|
15301
|
-
static registerCloseHandler(handler) {
|
|
15302
|
-
this.instance.emitter.addListener(PaywallManagerEvents.Close, handler);
|
|
15303
|
-
return () => {
|
|
15304
|
-
this.instance.emitter.removeListener(PaywallManagerEvents.Close, handler);
|
|
15305
|
-
};
|
|
15306
|
-
}
|
|
15307
|
-
/**
|
|
15308
|
-
* Register a callback which would be invoked when user will take action on deeplink
|
|
15309
|
-
*/
|
|
15310
|
-
static registerDeeplinkActionHandler(handler) {
|
|
15311
|
-
this.instance.emitter.addListener(PaywallManagerEvents.DeeplinkAction, handler);
|
|
15312
|
-
return () => {
|
|
15313
|
-
this.instance.emitter.removeListener(PaywallManagerEvents.DeeplinkAction, handler);
|
|
15314
|
-
};
|
|
15315
|
-
}
|
|
15316
|
-
/**
|
|
15317
|
-
* Register a [NamiBuySkuHandler] which would be invoked when a user triggers
|
|
15318
|
-
* a buy sku action on a paywall.
|
|
15319
|
-
*
|
|
15320
|
-
* Only available for plans where Nami is not handling subscription & IAP management.
|
|
15321
|
-
*/
|
|
15322
|
-
static registerBuySkuHandler(handler) {
|
|
15323
|
-
if (hasPurchaseManagement()) {
|
|
15324
|
-
logger.debug("This handler will not be invoked because this account's plan includes " +
|
|
15325
|
-
"built-in purchase management. Contact support@namiml.com for details.");
|
|
15326
|
-
}
|
|
15327
|
-
this.instance.emitter.addListener(PaywallManagerEvents.BuySku, handler);
|
|
15328
|
-
return () => {
|
|
15329
|
-
this.instance.emitter.removeListener(PaywallManagerEvents.BuySku, handler);
|
|
15330
|
-
};
|
|
15331
|
-
}
|
|
15332
|
-
/**
|
|
15333
|
-
* Register a callback which would be invoked when user restore a product
|
|
15334
|
-
*/
|
|
15335
|
-
static registerRestoreHandler(handler) {
|
|
15336
|
-
this.instance.emitter.addListener(PaywallManagerEvents.Restore, handler);
|
|
15337
|
-
return () => {
|
|
15338
|
-
this.instance.emitter.removeListener(PaywallManagerEvents.Restore, handler);
|
|
15339
|
-
};
|
|
15340
|
-
}
|
|
15341
|
-
/**
|
|
15342
|
-
* Notify the NamiPaywallManager that a purchase initiated from the
|
|
15343
|
-
* [NamiBuySkuHandler] is complete.
|
|
15344
|
-
*
|
|
15345
|
-
* Only available for plans where Nami is not handling subscription & IAP management.
|
|
15346
|
-
*
|
|
15347
|
-
* @returns {Promise<void>} A Promise that resolves when buying SKU will be complete.
|
|
15348
|
-
*/
|
|
15349
|
-
static async buySkuComplete(purchase) {
|
|
15350
|
-
// clear loading indicator
|
|
15351
|
-
PaywallState.setPurchaseInProgress(false);
|
|
15352
|
-
if (NamiFlowManager$2.instance.flowOpen) {
|
|
15353
|
-
const flow = NamiFlowManager$2.instance.currentFlow;
|
|
15354
|
-
const currentStep = flow?.currentFlowStep;
|
|
15355
|
-
if (flow && currentStep) {
|
|
15356
|
-
flow.executeLifecycle(currentStep, NamiReservedActions.PURCHASE_SUCCESS);
|
|
15357
|
-
}
|
|
15358
|
-
}
|
|
15359
|
-
if (NamiCustomerManager$2.inAnonymousMode()) {
|
|
15360
|
-
logger.debug("Skipping purchase validation - anonymous mode");
|
|
15361
|
-
return;
|
|
15362
|
-
}
|
|
15363
|
-
const session = storageService.getSessionId();
|
|
15364
|
-
const impression = storageService.getPurchaseImpression();
|
|
15365
|
-
if (!impression) {
|
|
15366
|
-
logger.debug("Not sending paywall conversion call complete due to unknown impression");
|
|
15367
|
-
return;
|
|
15368
|
-
}
|
|
15369
|
-
// send conversion
|
|
15370
|
-
try {
|
|
15371
|
-
await postConversion({
|
|
15372
|
-
purchase_env: "production",
|
|
15373
|
-
app_env: "production",
|
|
15374
|
-
impression,
|
|
15375
|
-
session,
|
|
15376
|
-
amount: purchase.amount,
|
|
15377
|
-
currency: purchase.currency,
|
|
15378
|
-
transaction_id: purchase.transactionId,
|
|
15379
|
-
sku: purchase.skuId,
|
|
15380
|
-
});
|
|
15381
|
-
}
|
|
15382
|
-
catch (e) {
|
|
15383
|
-
logger.error('Error posting conversion', e);
|
|
15384
|
-
}
|
|
15385
|
-
// validate purchase
|
|
15386
|
-
if (!hasCapability(Capabilities.THIRD_PARTY_TRANSACTIONS)) {
|
|
15387
|
-
try {
|
|
15388
|
-
await NamiAPI.instance.purchaseValidation({
|
|
15389
|
-
app_env: "production",
|
|
15390
|
-
payload: '', // token to be added when here a direct integration is done
|
|
15391
|
-
sku: purchase.skuId,
|
|
15392
|
-
});
|
|
15393
|
-
}
|
|
15394
|
-
catch (e) {
|
|
15395
|
-
logger.error("Error validating purchase", e);
|
|
15396
|
-
}
|
|
15397
|
-
}
|
|
15398
|
-
}
|
|
15399
|
-
/**
|
|
15400
|
-
* Notify the NamiPaywallManager that purchase flow handled by you is cancelled.
|
|
15401
|
-
* Used to disable product purchase-in-progress loading indicators
|
|
15402
|
-
*/
|
|
15403
|
-
static buySkuCancel() {
|
|
15404
|
-
if (!hasCapability(Capabilities.THIRD_PARTY_TRANSACTIONS)) {
|
|
15405
|
-
logger.warn("Call this method is not needed for this app because Nami is responsible for purchase management. Contact support@nami.ml for details.");
|
|
15406
|
-
return;
|
|
15407
|
-
}
|
|
15408
|
-
PaywallState.setPurchase(false);
|
|
15409
|
-
}
|
|
15410
|
-
/**
|
|
15411
|
-
* Set the video details for the app supplied video
|
|
15412
|
-
* @param url The URL of the video
|
|
15413
|
-
* @param name The name of the video
|
|
15414
|
-
*/
|
|
15415
|
-
static setAppSuppliedVideoDetails(url, name) {
|
|
15416
|
-
if (isValidUrl(url)) {
|
|
15417
|
-
logger.debug(`NamiPaywallManager: setAppSuppliedVideoDetails received valid url ${url}`);
|
|
15418
|
-
PaywallState.setAppSuppliedVideoDetails({ url, name });
|
|
15419
|
-
}
|
|
15420
|
-
else {
|
|
15421
|
-
logger.debug(`NamiPaywallManager: setAppSuppliedVideoDetails received invalid url ${url}`);
|
|
15422
|
-
}
|
|
15423
|
-
}
|
|
15424
|
-
/**
|
|
15425
|
-
* Enables or disables user interaction on Nami paywalls.
|
|
15426
|
-
*
|
|
15427
|
-
* @param {boolean} allowed - Whether user interaction should be allowed.
|
|
15428
|
-
* @returns {void}
|
|
15429
|
-
*/
|
|
15430
|
-
static allowUserInteraction(allowed) {
|
|
15431
|
-
logger.debug(`NamiPaywallManager: allowUserInteraction called with ${allowed}`);
|
|
15432
|
-
PaywallState.setUserInteractionEnabled(allowed);
|
|
15433
|
-
}
|
|
15434
|
-
/**
|
|
15435
|
-
* Private Instance Methods
|
|
15436
|
-
*/
|
|
15437
|
-
get sdkInitialized() {
|
|
15438
|
-
return Nami.instance.isInitialized;
|
|
15439
|
-
}
|
|
15440
|
-
};
|
|
15441
|
-
NamiPaywallManager$2.instance = new NamiPaywallManager$2();
|
|
15442
|
-
NamiPaywallManager$2.emitter = NamiEventEmitter.getInstance();
|
|
15443
|
-
|
|
15444
15857
|
// Re-export the class itself, typed as the narrow public interface. Same
|
|
15445
15858
|
// object identity as the underlying class so jest.spyOn works. See
|
|
15446
15859
|
// `src/managers/campaign.ts` and NAM-1207.
|
|
@@ -65012,4 +65425,4 @@ var internal = /*#__PURE__*/Object.freeze({
|
|
|
65012
65425
|
NamiPurchaseManager: NamiPurchaseManager
|
|
65013
65426
|
});
|
|
65014
65427
|
|
|
65015
|
-
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$1 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$1 as NamiCustomerManager, NamiEntitlementManager$1 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiPaywallAction, NamiPaywallManager$1 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPurchaseManager$1 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|
|
65428
|
+
export { ALREADY_CONFIGURED, ANONYMOUS_MODE, ANONYMOUS_MODE_ALREADY_OFF, ANONYMOUS_MODE_ALREADY_ON, ANONYMOUS_MODE_LOGIN_NOT_ALLOWED, ANONYMOUS_UUID, APIError, API_ACTIVE_ENTITLEMENTS, API_CAMPAIGN_RULES, API_CAMPAIGN_SESSION_TIMESTAMP, API_CONFIG, API_MAX_CALLS_LIMIT, API_PAYWALLS, API_PRODUCTS, API_RETRY_DELAY_SEC, API_TIMEOUT_LIMIT, API_VERSION, AUTH_DEVICE, AVAILABLE_ACTIVE_ENTITLEMENTS_CHANGED, AVAILABLE_CAMPAIGNS_CHANGED, AccountStateAction, AnonymousCDPError, AnonymousLoginError, AnonymousModeAlreadyOffError, AnonymousModeAlreadyOnError, BASE_STAGING_URL, BASE_URL, BASE_URL_PATH, BadRequestError, BasicNamiFlow, BorderMap, BorderSideMap, CAMPAIGN_NOT_AVAILABLE, CUSTOMER_ATTRIBUTES_KEY_PREFIX, CUSTOMER_JOURNEY_STATE_CHANGED, CUSTOM_HOST_PREFIX, CampaignNotAvailableError, CampaignRuleConversionEventType, CampaignRuleRepository, Capabilities, ClientError, ConfigRepository, ConflictError, CustomerJourneyRepository, DEVELOPMENT, DEVICE_API_TIMEOUT_LIMIT, DEVICE_ID_NOT_SET, DEVICE_ID_REQUIRED, DISABLE_ASYNC_LOGIN_LOGOUT, DeviceIDRequiredError, DeviceRepository, EXTENDED_CLIENT_INFO_DELIMITER, EXTENDED_CLIENT_INFO_PREFIX, EXTENDED_PLATFORM, EXTENDED_PLATFORM_VERSION, EXTERNAL_ID_REQUIRED, EntitlementRepository, EntitlementUtils, ExternalIDRequiredError, FLOW_SCREENS_NOT_AVAILABLE, FlowScreensNotAvailableError, HTML_REGEX, INITIAL_APP_CONFIG, INITIAL_CAMPAIGN_RULES, INITIAL_PAYWALLS, INITIAL_PRODUCTS, INITIAL_SESSION_COUNTER_VALUE, INITIAL_SUCCESS, InternalServerError, KEY_SESSION_COUNTER, LIQUID_VARIABLE_REGEX, LOCAL_NAMI_ENTITLEMENTS, LOG_HTTP_REQUESTS, LOG_HTTP_TRAFFIC, LaunchCampaignError, LaunchContextResolver, LogLevel, NAMI_CONFIGURATION, NAMI_CUSTOMER_JOURNEY_STATE, NAMI_LANGUAGE_CODE, NAMI_LAST_IMPRESSION_ID, NAMI_LAUNCH_ID, NAMI_PROFILE, NAMI_PURCHASE_CHANNEL, NAMI_PURCHASE_IMPRESSION_ID, NAMI_SDK_PACKAGE_VERSION, NAMI_SDK_VERSION, NAMI_SESSION_ID, NAMI_STORAGE_KEYS, Nami, NamiAPI, NamiAnimationType, NamiCampaignManager$1 as NamiCampaignManager, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager$1 as NamiCustomerManager, NamiEntitlementManager$1 as NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager$1 as NamiFlowManager, NamiFlowStepType, NamiHandoffTag, NamiPaywallAction, NamiPaywallManager$1 as NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiPermissionOutcome, NamiPurchaseManager$1 as NamiPurchaseManager, NamiRefs, NamiReservedActions, NotFoundError, PAYWALL_ACTION_EVENT, PLATFORM_ID_REQUIRED, PRODUCTION, PaywallManagerEvents, PaywallRepository, PaywallState, PlacementLabelResolver, PlatformIDRequiredError, ProductRepository, RECONFIG_SUCCESS, RetryLimitExceededError, SDKNotInitializedError, SDK_NOT_INITIALIZED, SERVER_NAMI_ENTITLEMENTS, SESSION_REQUIRED, SHOULD_SHOW_LOADING_INDICATOR, SKU_TEXT_REGEX, SMART_TEXT_PATTERN, STARTUP_TELEMETRY, STATUS_BAD_REQUEST, STATUS_CONFLICT, STATUS_INTERNAL_SERVER_ERROR, STATUS_NOT_FOUND, STATUS_SUCCESS, SessionService, SimpleEventTarget, StorageService, UNABLE_TO_UPDATE_CDP_ID, USE_STAGING_API, VALIDATE_PRODUCT_GROUPS, VAR_REGEX, NamiProfileManager$1 as _NamiProfileManager, internal as _internal, activateEntitlementByPurchase, activeEntitlements, aggregateScreenreaderText, allCampaigns, allPaywalls, applyEntitlementActivation, audienceSplitPosition, bestUrlCampaignMatch, bigintToUuid, checkAnySkuHasPromoOffer, checkAnySkuHasTrialOffer, convertISO8601PeriodToText, convertLocale, convertOfferToPricingPhase, createNamiEntitlements, currentSku, empty, extractStandardPricingPhases, formatDate, formattedPrice, generateUUID, getApiCampaigns, getApiPaywalls, getBaseUrl, getBillingPeriodNumber, getCurrencyFormat, getDeviceData, getDeviceFormFactor, getDeviceScaleFactor, getEffectiveWebStyle, getEntitlementRefIdsForSku, getExtendedClientInfo, getFreeTrialPeriod, getInitialCampaigns, getInitialPaywalls, getPaywall, getPaywallDataFromLabel, getPercentagePriceDifference, getPeriodNumberInDays, getPeriodNumberInWeeks, getPlatformAdapters, getPriceDifference, getPricePerMonth, getProductDetail, getPurchaseAdapter, getReferenceSku, getSkuProductDetailKeys, getSkuSmartTextValue, getSlideSmartTextValue, getStandardBillingPeriod, getTranslate, getUrlParams, handleErrors, hasAllPaywalls, hasCapability, hasPurchaseManagement, initialState, invokeHandler, isAnonymousMode, isInitialConfigCompressed, isNamiFlowCampaign, isSubscription, isValidISODate, isValidUrl, logger, mapAnonymousCampaigns, namiBuySKU, normalizeLaunchContext, parseToSemver, postConversion, productDetail, registerPlatformAdapters, registerPurchaseAdapter, resolveLoopSource, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateForm, validateMinSDKVersion, validateTextInput };
|