@namiml/sdk-core 3.4.0-dev.202605141714 → 3.4.0-dev.202605182046
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 +259 -6
- package/dist/index.d.ts +91 -5
- package/dist/index.mjs +259 -7
- package/package.json +1 -1
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.0",
|
|
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.0-dev.
|
|
101
|
+
NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.0-dev.202605182046",
|
|
102
102
|
// environments
|
|
103
103
|
PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
|
|
104
104
|
// error messages
|
|
@@ -7404,19 +7404,34 @@ const mapAnonymousCampaigns = (campaigns, splitPosition, formFactor) => {
|
|
|
7404
7404
|
});
|
|
7405
7405
|
};
|
|
7406
7406
|
/**
|
|
7407
|
+
* Returns the combined list of API + initial-config campaigns for the current device's
|
|
7408
|
+
* form factor, deduplicated by (type, value) with API entries winning on collision.
|
|
7407
7409
|
*
|
|
7408
|
-
*
|
|
7409
|
-
*
|
|
7410
|
+
* Mirrors NamiCampaignManager.allCampaigns() on Apple (Set keyed on hash(value, type))
|
|
7411
|
+
* and Android (.distinct() with server-first ordering). Keying on (type, value) — rather
|
|
7412
|
+
* than rule UUID — ensures the same logical placement does not surface twice when the
|
|
7413
|
+
* server has republished a campaign under a new rule id.
|
|
7410
7414
|
*
|
|
7411
|
-
* Note:
|
|
7412
|
-
*
|
|
7415
|
+
* Note: this list reflects which placements are available, not whether they are launchable.
|
|
7416
|
+
* An API entry surfaced here may reference a paywall that has not yet been published in the
|
|
7417
|
+
* API response. NamiCampaignManager.launch() handles that case independently via
|
|
7418
|
+
* getPaywallDataFromLabel(), which falls back to the initial-config (campaign, paywall) pair
|
|
7419
|
+
* when the API pair is incomplete — matching the merged-paywall-lookup behavior on
|
|
7420
|
+
* Apple and Android.
|
|
7413
7421
|
*/
|
|
7414
7422
|
const allCampaigns = () => {
|
|
7415
7423
|
const apiCampaigns = storageService.getCampaignRules(exports.API_CAMPAIGN_RULES) ?? [];
|
|
7416
7424
|
const initialCampaigns = storageService.getCampaignRules(exports.INITIAL_CAMPAIGN_RULES) ?? [];
|
|
7417
7425
|
const formFactor = getDeviceFormFactor();
|
|
7418
7426
|
const campaigns = compact([...apiCampaigns, ...initialCampaigns]).filter((cRule) => cRule.form_factors?.some((f) => f.form_factor === formFactor));
|
|
7419
|
-
|
|
7427
|
+
const seen = new Set();
|
|
7428
|
+
return campaigns.filter((c) => {
|
|
7429
|
+
const key = `${c.type ?? ''}::${c.value ?? ''}`;
|
|
7430
|
+
if (seen.has(key))
|
|
7431
|
+
return false;
|
|
7432
|
+
seen.add(key);
|
|
7433
|
+
return true;
|
|
7434
|
+
});
|
|
7420
7435
|
};
|
|
7421
7436
|
/**
|
|
7422
7437
|
* Get campaigns by rule key, filtered by form factor.
|
|
@@ -13670,6 +13685,19 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
13670
13685
|
this.forward(nextStep.id);
|
|
13671
13686
|
}
|
|
13672
13687
|
}
|
|
13688
|
+
handleRemoteBack() {
|
|
13689
|
+
const step = this.currentFlowStep;
|
|
13690
|
+
if (step?.actions[NamiReservedActions.REMOTE_BACK]) {
|
|
13691
|
+
this.triggerActions(NamiReservedActions.REMOTE_BACK);
|
|
13692
|
+
return 'handler';
|
|
13693
|
+
}
|
|
13694
|
+
if (this.previousStepAvailable) {
|
|
13695
|
+
this.back();
|
|
13696
|
+
return 'back';
|
|
13697
|
+
}
|
|
13698
|
+
this.finished();
|
|
13699
|
+
return 'dismissed';
|
|
13700
|
+
}
|
|
13673
13701
|
backToPreviousScreenStep() {
|
|
13674
13702
|
if (this.previousFlowStep?.allow_back_to === false) {
|
|
13675
13703
|
logger.warn(`Not allowed to go back to ${this.previousFlowStep.id}`);
|
|
@@ -63913,6 +63941,230 @@ const convertLocale = (locale) => {
|
|
|
63913
63941
|
return intlLocale.language + (intlLocale.region ?? intlLocale.script ?? '');
|
|
63914
63942
|
};
|
|
63915
63943
|
|
|
63944
|
+
/**
|
|
63945
|
+
* Components that are skipped entirely (they and their subtree do not
|
|
63946
|
+
* contribute text to the page-level announcement).
|
|
63947
|
+
*
|
|
63948
|
+
* - Buttons / interactive controls: their label is appended as the
|
|
63949
|
+
* focused-button suffix, not collected mid-tree. Recursing into them
|
|
63950
|
+
* would double-count the label and pull in non-spoken decorative text.
|
|
63951
|
+
* - Image-like leaves: explicitly skipped per spec.
|
|
63952
|
+
* - Form pickers + QR codes + raw video: not informational text.
|
|
63953
|
+
*/
|
|
63954
|
+
const SKIP_COMPONENTS = new Set([
|
|
63955
|
+
'button',
|
|
63956
|
+
'playPauseButton',
|
|
63957
|
+
'volumeButton',
|
|
63958
|
+
'toggleButton',
|
|
63959
|
+
'toggleSwitch',
|
|
63960
|
+
'radio',
|
|
63961
|
+
'image',
|
|
63962
|
+
'svgImage',
|
|
63963
|
+
'symbol',
|
|
63964
|
+
'qrCode',
|
|
63965
|
+
'videoUrl',
|
|
63966
|
+
'segmentPicker',
|
|
63967
|
+
'segmentPickerItem',
|
|
63968
|
+
]);
|
|
63969
|
+
/** Component values in {@link SKIP_COMPONENTS} that are interactive controls
|
|
63970
|
+
* (as opposed to images / media / non-text leaves). When a text component
|
|
63971
|
+
* shares a container with one of these, the text is treated as that
|
|
63972
|
+
* button's accessible label and excluded from the page composite. */
|
|
63973
|
+
const BUTTON_COMPONENTS = new Set([
|
|
63974
|
+
'button',
|
|
63975
|
+
'playPauseButton',
|
|
63976
|
+
'volumeButton',
|
|
63977
|
+
'toggleButton',
|
|
63978
|
+
'toggleSwitch',
|
|
63979
|
+
'radio',
|
|
63980
|
+
]);
|
|
63981
|
+
/** `namiComponentType` values that are always included in the page
|
|
63982
|
+
* composite — even when their structural position (e.g. a sibling of a
|
|
63983
|
+
* utility button) would otherwise mark them for exclusion. Driven by the
|
|
63984
|
+
* spec's schema table:
|
|
63985
|
+
*
|
|
63986
|
+
* | `namiComponentType: "legalText"` | Legal/T&C content (included in tree-walk) |
|
|
63987
|
+
*/
|
|
63988
|
+
const ALWAYS_INCLUDE_NAMI_TYPES = new Set(['legalText']);
|
|
63989
|
+
/**
|
|
63990
|
+
* Whether a text leaf inside `parent` should be skipped because it acts as
|
|
63991
|
+
* the accessible label for a sibling button.
|
|
63992
|
+
*
|
|
63993
|
+
* Schema pattern this catches: a container whose direct children include
|
|
63994
|
+
* BOTH a text/text-list AND an interactive button (e.g. Page 3's "Login
|
|
63995
|
+
* Group" — `[ text "Already an NFL+ subscriber?", loginButton "Sign In" ]`).
|
|
63996
|
+
* The text describes the button and is announced when the button is
|
|
63997
|
+
* focused, NOT as page-level content. Without this rule, the composite
|
|
63998
|
+
* leaks "Already an NFL+ subscriber? Subscribe to NFL plus button" instead
|
|
63999
|
+
* of "Subscribe to NFL plus button".
|
|
64000
|
+
*
|
|
64001
|
+
* Texts marked `namiComponentType: "legalText"` are exempt — the spec
|
|
64002
|
+
* explicitly opts legal copy in regardless of its container's other
|
|
64003
|
+
* children (e.g. Page 5's "Bottom Wrapper" mixes a body text, a restore
|
|
64004
|
+
* button, and the legal text — the legal text must still be spoken).
|
|
64005
|
+
*/
|
|
64006
|
+
function isButtonSiblingLabel(node, parent) {
|
|
64007
|
+
if (!parent || !Array.isArray(parent.components))
|
|
64008
|
+
return false;
|
|
64009
|
+
if (typeof node.namiComponentType === 'string' &&
|
|
64010
|
+
ALWAYS_INCLUDE_NAMI_TYPES.has(node.namiComponentType)) {
|
|
64011
|
+
return false;
|
|
64012
|
+
}
|
|
64013
|
+
for (const sibling of parent.components) {
|
|
64014
|
+
if (sibling && typeof sibling === 'object') {
|
|
64015
|
+
const s = sibling;
|
|
64016
|
+
if (typeof s.component === 'string' && BUTTON_COMPONENTS.has(s.component)) {
|
|
64017
|
+
return true;
|
|
64018
|
+
}
|
|
64019
|
+
}
|
|
64020
|
+
}
|
|
64021
|
+
return false;
|
|
64022
|
+
}
|
|
64023
|
+
/**
|
|
64024
|
+
* Recursively collect spoken text from a component subtree following the
|
|
64025
|
+
* TV Full-Page Announcement contract.
|
|
64026
|
+
*
|
|
64027
|
+
* Rules (in order):
|
|
64028
|
+
* 1. `null` / `undefined` → contribute nothing.
|
|
64029
|
+
* 2. `hidden: true` → skip the node AND its subtree.
|
|
64030
|
+
* 3. `component` in {@link SKIP_COMPONENTS} → skip the node AND its subtree.
|
|
64031
|
+
* 4. `screenreaderText` set on this container → take that string verbatim
|
|
64032
|
+
* and do NOT recurse (server-supplied override).
|
|
64033
|
+
* 5. `component: "text"` or `"text-list"` → collect, UNLESS the text is a
|
|
64034
|
+
* sibling label for an adjacent button (see
|
|
64035
|
+
* {@link isButtonSiblingLabel}). `namiComponentType: "legalText"` is
|
|
64036
|
+
* exempted from the sibling-label exclusion.
|
|
64037
|
+
* 6. Otherwise → recurse into `components`.
|
|
64038
|
+
*/
|
|
64039
|
+
function collectText(node, parent = null) {
|
|
64040
|
+
if (!node || typeof node !== 'object')
|
|
64041
|
+
return [];
|
|
64042
|
+
const n = node;
|
|
64043
|
+
if (n.hidden === true)
|
|
64044
|
+
return [];
|
|
64045
|
+
if (typeof n.component === 'string' && SKIP_COMPONENTS.has(n.component))
|
|
64046
|
+
return [];
|
|
64047
|
+
// Container-level override: when an enclosing container pre-supplies its own
|
|
64048
|
+
// screenreader text, take it verbatim and stop descending — the customer
|
|
64049
|
+
// has authored a polished announcement for this subtree.
|
|
64050
|
+
if (typeof n.screenreaderText === 'string' && n.screenreaderText.trim().length > 0) {
|
|
64051
|
+
return [n.screenreaderText.trim()];
|
|
64052
|
+
}
|
|
64053
|
+
if (n.component === 'text') {
|
|
64054
|
+
if (isButtonSiblingLabel(n, parent))
|
|
64055
|
+
return [];
|
|
64056
|
+
return typeof n.text === 'string' && n.text.length > 0 ? [n.text] : [];
|
|
64057
|
+
}
|
|
64058
|
+
if (n.component === 'text-list') {
|
|
64059
|
+
if (isButtonSiblingLabel(n, parent))
|
|
64060
|
+
return [];
|
|
64061
|
+
if (!Array.isArray(n.texts))
|
|
64062
|
+
return [];
|
|
64063
|
+
return n.texts.filter((t) => typeof t === 'string' && t.length > 0);
|
|
64064
|
+
}
|
|
64065
|
+
if (Array.isArray(n.components)) {
|
|
64066
|
+
const out = [];
|
|
64067
|
+
for (const child of n.components) {
|
|
64068
|
+
out.push(...collectText(child, n));
|
|
64069
|
+
}
|
|
64070
|
+
return out;
|
|
64071
|
+
}
|
|
64072
|
+
return [];
|
|
64073
|
+
}
|
|
64074
|
+
function collectHeaderFooter(slot) {
|
|
64075
|
+
if (!Array.isArray(slot))
|
|
64076
|
+
return [];
|
|
64077
|
+
// The slot itself acts as the synthetic parent so a top-level text inside
|
|
64078
|
+
// a header/footer that sits alongside a top-level button is treated as a
|
|
64079
|
+
// button label and excluded.
|
|
64080
|
+
const syntheticParent = { components: slot };
|
|
64081
|
+
const out = [];
|
|
64082
|
+
for (const node of slot) {
|
|
64083
|
+
out.push(...collectText(node, syntheticParent));
|
|
64084
|
+
}
|
|
64085
|
+
return out;
|
|
64086
|
+
}
|
|
64087
|
+
/**
|
|
64088
|
+
* Join an ordered list of collected text fragments into a single speakable
|
|
64089
|
+
* string. Each fragment is trimmed; empty fragments are dropped. Author
|
|
64090
|
+
* terminators (`.`, `!`, `?`) are preserved so emphasis carries through to
|
|
64091
|
+
* the screenreader; only fragments that lack a terminator get `". "`
|
|
64092
|
+
* inserted before the next fragment. The result is a string that reads
|
|
64093
|
+
* naturally without double-punctuation like `"...REACH!. Watch..."`.
|
|
64094
|
+
*/
|
|
64095
|
+
function joinFragments(fragments) {
|
|
64096
|
+
let out = '';
|
|
64097
|
+
for (const raw of fragments) {
|
|
64098
|
+
const trimmed = raw.trim();
|
|
64099
|
+
if (!trimmed)
|
|
64100
|
+
continue;
|
|
64101
|
+
if (!out) {
|
|
64102
|
+
out = trimmed;
|
|
64103
|
+
continue;
|
|
64104
|
+
}
|
|
64105
|
+
const last = out[out.length - 1];
|
|
64106
|
+
const endsWithTerminator = last === '.' || last === '!' || last === '?';
|
|
64107
|
+
out += (endsWithTerminator ? ' ' : '. ') + trimmed;
|
|
64108
|
+
}
|
|
64109
|
+
return out;
|
|
64110
|
+
}
|
|
64111
|
+
/**
|
|
64112
|
+
* Build the full-screen announcement string for a paywall page per the
|
|
64113
|
+
* TV Full-Page Announcement contract
|
|
64114
|
+
* (https://linear.app/nami-product-development/document/tv-full-page-announcement-980f61b96e7c).
|
|
64115
|
+
*
|
|
64116
|
+
* Behaviour:
|
|
64117
|
+
* 1. **Override path.** If `page.screenreaderText` is set, that string is
|
|
64118
|
+
* returned verbatim (followed by `focusedButtonLabel` if provided and
|
|
64119
|
+
* not already present at the tail). Server-authored polished
|
|
64120
|
+
* announcements win over client-side aggregation.
|
|
64121
|
+
*
|
|
64122
|
+
* 2. **Tree-walk fallback.** Otherwise, walk the page's containers in
|
|
64123
|
+
* reading order — `header` → `backgroundContainer` → `contentContainer`
|
|
64124
|
+
* → `footer` — collecting visible `text` / `text-list` descendants in
|
|
64125
|
+
* source order. `image`, `hidden: true` subtrees, interactive controls
|
|
64126
|
+
* (buttons / toggles), and non-text leaves are skipped. The
|
|
64127
|
+
* `focusedButtonLabel` is appended as the final sentence.
|
|
64128
|
+
*
|
|
64129
|
+
* SDKs invoke this once per page on the first focus of the default CTA, and
|
|
64130
|
+
* speak the result via their platform TTS API. On subsequent focuses within
|
|
64131
|
+
* the same page, the SDK announces only the focused element's own label —
|
|
64132
|
+
* this helper is NOT re-called.
|
|
64133
|
+
*
|
|
64134
|
+
* @param page The paywall page to announce.
|
|
64135
|
+
* @param focusedButtonLabel The resolved label of the button that
|
|
64136
|
+
* triggered the announcement (typically the
|
|
64137
|
+
* page's default-focused CTA). For
|
|
64138
|
+
* subscription-plan CTAs this is the dynamic
|
|
64139
|
+
* `"{price} {period} subscription plan button"`
|
|
64140
|
+
* string the backend already resolved.
|
|
64141
|
+
* @returns A single string ready to pass to a platform TTS API. Empty when
|
|
64142
|
+
* the page has no spoken content and no focused button label.
|
|
64143
|
+
*/
|
|
64144
|
+
function aggregateScreenreaderText(page, focusedButtonLabel = '') {
|
|
64145
|
+
const trimmedLabel = focusedButtonLabel.trim();
|
|
64146
|
+
// Override path
|
|
64147
|
+
if (typeof page.screenreaderText === 'string' && page.screenreaderText.trim().length > 0) {
|
|
64148
|
+
const override = page.screenreaderText.trim();
|
|
64149
|
+
if (!trimmedLabel)
|
|
64150
|
+
return override;
|
|
64151
|
+
// If the server-authored override already ends with the focused button
|
|
64152
|
+
// label, don't append it again.
|
|
64153
|
+
if (override.toLowerCase().endsWith(trimmedLabel.toLowerCase()))
|
|
64154
|
+
return override;
|
|
64155
|
+
return joinFragments([override, trimmedLabel]);
|
|
64156
|
+
}
|
|
64157
|
+
// Tree-walk path
|
|
64158
|
+
const fragments = [];
|
|
64159
|
+
fragments.push(...collectHeaderFooter(page.header));
|
|
64160
|
+
fragments.push(...collectText(page.backgroundContainer));
|
|
64161
|
+
fragments.push(...collectText(page.contentContainer));
|
|
64162
|
+
fragments.push(...collectHeaderFooter(page.footer));
|
|
64163
|
+
if (trimmedLabel)
|
|
64164
|
+
fragments.push(trimmedLabel);
|
|
64165
|
+
return joinFragments(fragments);
|
|
64166
|
+
}
|
|
64167
|
+
|
|
63916
64168
|
function namiBuySKU(skuRefId) {
|
|
63917
64169
|
if (!hasPurchaseManagement("NamiPurchaseManager.buySKU")) {
|
|
63918
64170
|
return;
|
|
@@ -63982,6 +64234,7 @@ exports.SimpleEventTarget = SimpleEventTarget;
|
|
|
63982
64234
|
exports.StorageService = StorageService;
|
|
63983
64235
|
exports.activateEntitlementByPurchase = activateEntitlementByPurchase;
|
|
63984
64236
|
exports.activeEntitlements = activeEntitlements;
|
|
64237
|
+
exports.aggregateScreenreaderText = aggregateScreenreaderText;
|
|
63985
64238
|
exports.allCampaigns = allCampaigns;
|
|
63986
64239
|
exports.allPaywalls = allPaywalls;
|
|
63987
64240
|
exports.applyEntitlementActivation = applyEntitlementActivation;
|
package/dist/index.d.ts
CHANGED
|
@@ -113,6 +113,7 @@ declare const NamiFlowStepType: {
|
|
|
113
113
|
readonly UNKNOWN: "unknown";
|
|
114
114
|
};
|
|
115
115
|
type NamiFlowStepType = (typeof NamiFlowStepType)[keyof typeof NamiFlowStepType];
|
|
116
|
+
type RemoteBackOutcome = 'handler' | 'back' | 'dismissed';
|
|
116
117
|
declare enum NamiFlowActionFunction {
|
|
117
118
|
NAVIGATE = "flowNav",
|
|
118
119
|
BACK = "flowPrev",
|
|
@@ -772,6 +773,31 @@ interface TBaseComponent {
|
|
|
772
773
|
context?: {
|
|
773
774
|
[key: string]: any;
|
|
774
775
|
};
|
|
776
|
+
/**
|
|
777
|
+
* Text spoken by the platform screenreader. Plays two roles depending on
|
|
778
|
+
* where it is set, per the TV Full-Page Announcement contract
|
|
779
|
+
* (https://linear.app/nami-product-development/document/tv-full-page-announcement-980f61b96e7c):
|
|
780
|
+
*
|
|
781
|
+
* - **On focusable elements** (buttons, toggles, etc.): the element's own
|
|
782
|
+
* label, spoken when the element receives focus. For subscription-plan
|
|
783
|
+
* CTAs the backend resolves this dynamically to
|
|
784
|
+
* `"{price} {period} [{tier}] subscription plan button"`.
|
|
785
|
+
*
|
|
786
|
+
* - **On containers** (any TBaseComponent-derived container, and TPages):
|
|
787
|
+
* an optional *server-supplied composite override*. When set, SDKs
|
|
788
|
+
* announce this verbatim on first focus of the page's default CTA
|
|
789
|
+
* instead of tree-walking the page's text. When omitted, SDKs derive
|
|
790
|
+
* the composite by walking visible `text` / `text-list` descendants in
|
|
791
|
+
* source order (skipping `image`, `hidden: true`, and non-text leaves)
|
|
792
|
+
* and appending the focused button's label.
|
|
793
|
+
*/
|
|
794
|
+
screenreaderText?: string;
|
|
795
|
+
/**
|
|
796
|
+
* Supplementary hint announced after `screenreaderText` on the element it
|
|
797
|
+
* is set on (e.g. "Double-tap to subscribe"). Optional; SDKs that lack a
|
|
798
|
+
* hint affordance may omit it.
|
|
799
|
+
*/
|
|
800
|
+
screenreaderHint?: string;
|
|
775
801
|
moveX?: number | string;
|
|
776
802
|
moveY?: string | number;
|
|
777
803
|
direction?: DirectionType;
|
|
@@ -1404,6 +1430,7 @@ declare class NamiFlow extends BasicNamiFlow {
|
|
|
1404
1430
|
finished(): void;
|
|
1405
1431
|
back(): void;
|
|
1406
1432
|
next(): void;
|
|
1433
|
+
handleRemoteBack(): RemoteBackOutcome;
|
|
1407
1434
|
private backToPreviousScreenStep;
|
|
1408
1435
|
forward(stepId: string): void;
|
|
1409
1436
|
pause(): void;
|
|
@@ -1701,6 +1728,22 @@ type TPages = {
|
|
|
1701
1728
|
contentContainer: TContainer | null;
|
|
1702
1729
|
footer: THeaderFooter;
|
|
1703
1730
|
backgroundContainer: TContainer | null;
|
|
1731
|
+
/**
|
|
1732
|
+
* Optional server-supplied composite announcement for the page. When set,
|
|
1733
|
+
* TV SDKs speak this verbatim on first focus of the default CTA instead of
|
|
1734
|
+
* tree-walking the page's text content. When omitted, SDKs derive the
|
|
1735
|
+
* composite client-side from visible `text` / `text-list` descendants (in
|
|
1736
|
+
* source order, skipping `image`, `hidden: true`, and non-text leaves) and
|
|
1737
|
+
* append the focused button's label.
|
|
1738
|
+
*
|
|
1739
|
+
* Video pages are detected by the presence of `component: "videoUrl"` in
|
|
1740
|
+
* `backgroundContainer` with `autoplayVideo: true` and `loopVideo: false`
|
|
1741
|
+
* — TTS is deferred until playback completes. No additional schema flag is
|
|
1742
|
+
* required for that suppression.
|
|
1743
|
+
*
|
|
1744
|
+
* Contract: https://linear.app/nami-product-development/document/tv-full-page-announcement-980f61b96e7c
|
|
1745
|
+
*/
|
|
1746
|
+
screenreaderText?: string;
|
|
1704
1747
|
};
|
|
1705
1748
|
type TInitialState = {
|
|
1706
1749
|
slides?: TCarouselSlidesState;
|
|
@@ -2623,6 +2666,41 @@ interface INamiRefsInstance {
|
|
|
2623
2666
|
*/
|
|
2624
2667
|
declare function isAnonymousMode(): boolean;
|
|
2625
2668
|
|
|
2669
|
+
/**
|
|
2670
|
+
* Build the full-screen announcement string for a paywall page per the
|
|
2671
|
+
* TV Full-Page Announcement contract
|
|
2672
|
+
* (https://linear.app/nami-product-development/document/tv-full-page-announcement-980f61b96e7c).
|
|
2673
|
+
*
|
|
2674
|
+
* Behaviour:
|
|
2675
|
+
* 1. **Override path.** If `page.screenreaderText` is set, that string is
|
|
2676
|
+
* returned verbatim (followed by `focusedButtonLabel` if provided and
|
|
2677
|
+
* not already present at the tail). Server-authored polished
|
|
2678
|
+
* announcements win over client-side aggregation.
|
|
2679
|
+
*
|
|
2680
|
+
* 2. **Tree-walk fallback.** Otherwise, walk the page's containers in
|
|
2681
|
+
* reading order — `header` → `backgroundContainer` → `contentContainer`
|
|
2682
|
+
* → `footer` — collecting visible `text` / `text-list` descendants in
|
|
2683
|
+
* source order. `image`, `hidden: true` subtrees, interactive controls
|
|
2684
|
+
* (buttons / toggles), and non-text leaves are skipped. The
|
|
2685
|
+
* `focusedButtonLabel` is appended as the final sentence.
|
|
2686
|
+
*
|
|
2687
|
+
* SDKs invoke this once per page on the first focus of the default CTA, and
|
|
2688
|
+
* speak the result via their platform TTS API. On subsequent focuses within
|
|
2689
|
+
* the same page, the SDK announces only the focused element's own label —
|
|
2690
|
+
* this helper is NOT re-called.
|
|
2691
|
+
*
|
|
2692
|
+
* @param page The paywall page to announce.
|
|
2693
|
+
* @param focusedButtonLabel The resolved label of the button that
|
|
2694
|
+
* triggered the announcement (typically the
|
|
2695
|
+
* page's default-focused CTA). For
|
|
2696
|
+
* subscription-plan CTAs this is the dynamic
|
|
2697
|
+
* `"{price} {period} subscription plan button"`
|
|
2698
|
+
* string the backend already resolved.
|
|
2699
|
+
* @returns A single string ready to pass to a platform TTS API. Empty when
|
|
2700
|
+
* the page has no spoken content and no focused button label.
|
|
2701
|
+
*/
|
|
2702
|
+
declare function aggregateScreenreaderText(page: TPages, focusedButtonLabel?: string): string;
|
|
2703
|
+
|
|
2626
2704
|
/**
|
|
2627
2705
|
* Returns the translated string for the given key in the current SDK language.
|
|
2628
2706
|
* Uses Nami language code from storage (set via Nami.configure({ namiLanguageCode })).
|
|
@@ -2675,12 +2753,20 @@ declare const bestUrlCampaignMatch: (incomingUrl: string, campaigns: NamiCampaig
|
|
|
2675
2753
|
declare const selectSegment: (segments: NamiCampaignSegment[], splitPosition: number) => NamiCampaignSegment;
|
|
2676
2754
|
declare const mapAnonymousCampaigns: (campaigns: NamiAnonymousCampaign[], splitPosition: number, formFactor?: TDevice) => NamiCampaign[];
|
|
2677
2755
|
/**
|
|
2756
|
+
* Returns the combined list of API + initial-config campaigns for the current device's
|
|
2757
|
+
* form factor, deduplicated by (type, value) with API entries winning on collision.
|
|
2678
2758
|
*
|
|
2679
|
-
*
|
|
2680
|
-
*
|
|
2759
|
+
* Mirrors NamiCampaignManager.allCampaigns() on Apple (Set keyed on hash(value, type))
|
|
2760
|
+
* and Android (.distinct() with server-first ordering). Keying on (type, value) — rather
|
|
2761
|
+
* than rule UUID — ensures the same logical placement does not surface twice when the
|
|
2762
|
+
* server has republished a campaign under a new rule id.
|
|
2681
2763
|
*
|
|
2682
|
-
* Note:
|
|
2683
|
-
*
|
|
2764
|
+
* Note: this list reflects which placements are available, not whether they are launchable.
|
|
2765
|
+
* An API entry surfaced here may reference a paywall that has not yet been published in the
|
|
2766
|
+
* API response. NamiCampaignManager.launch() handles that case independently via
|
|
2767
|
+
* getPaywallDataFromLabel(), which falls back to the initial-config (campaign, paywall) pair
|
|
2768
|
+
* when the API pair is incomplete — matching the merged-paywall-lookup behavior on
|
|
2769
|
+
* Apple and Android.
|
|
2684
2770
|
*/
|
|
2685
2771
|
declare const allCampaigns: () => NamiCampaign[];
|
|
2686
2772
|
declare const getInitialCampaigns: () => NamiCampaign[];
|
|
@@ -2985,5 +3071,5 @@ declare const getBillingPeriodNumber: (billingPeriod: string) => number;
|
|
|
2985
3071
|
declare const formattedPrice: (price: number) => number;
|
|
2986
3072
|
declare function toDouble(num: number): number;
|
|
2987
3073
|
|
|
2988
|
-
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, 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, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager, NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager, NamiFlowStepType, NamiPaywallAction, NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiProfileManager, 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, 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, activateEntitlementByPurchase, activeEntitlements, 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, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateMinSDKVersion };
|
|
3074
|
+
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, 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, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager, NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager, NamiFlowStepType, NamiPaywallAction, NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiProfileManager, 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, 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, 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, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateMinSDKVersion };
|
|
2989
3075
|
export type { AlignmentType, AmazonProduct, ApiResponse, AppleProduct, AvailableCampaignsResponseHandler, BorderLocationType, BorderSideType, Callback$1 as Callback, CloseHandler, CustomerJourneyState, DeepLinkUrlHandler, Device, DevicePayload, DeviceProfile, DirectionType, ExtendedPlatformInfo, FlexDirectionObject, FlowNavigationOptions, FontCollection, FontDetails, FormFactor, GoogleProduct, IConfig, IDeviceAdapter, IEntitlements$1 as IEntitlements, IPaywall, IPlatformAdapters, IProductsWithComponents, IPurchaseAdapter, ISkuMenu, IStorageAdapter, IUIAdapter, Impression, InitialConfig, InitialConfigCompressed, InitiateStateGroup, LoginResponse, NamiAnimation, NamiAnimationObjectSpec, NamiAnimationSpec, NamiAnonymousCampaign, NamiAppSuppliedVideoDetails, NamiCampaign, NamiCampaignSegment, NamiConfiguration, NamiConfigurationState, NamiEntitlement$1 as NamiEntitlement, NamiFlowAction, NamiFlowAnimation, NamiFlowCampaign, NamiFlowDTO, NamiFlowEventHandler, NamiFlowHandoffStepHandler, NamiFlowObjectDTO, NamiFlowOn, NamiFlowStep, NamiFlowTransition, NamiFlowTransitionDirection, NamiFlowWithObject, NamiInitialConfig, NamiLanguageCodes, NamiLogLevel, NamiPaywallActionHandler, NamiPaywallComponentChange, NamiPaywallEvent, NamiPaywallEventVideoMetadata, NamiPaywallLaunchContext, NamiPresentationStyle, NamiProductDetails, NamiProductOffer, NamiProfile, NamiPurchase, NamiPurchaseCompleteResult, NamiPurchaseDetails, NamiPurchasesState, NamiSKU, NamiSKUType, NamiSubscriptionInterval, NamiSubscriptionPeriod, None, NoneSpec, PaywallActionEvent, PaywallHandle, PaywallResultHandler, PaywallSKU, PricingPhase, ProductGroup, Pulse, PulseSpec, PurchaseContext, PurchaseResult, PurchaseValidationRequest, SKU, SKUActionHandler, ScreenInfo, Session, TBaseComponent, TButtonContainer, TCarouselContainer, TCarouselSlide, TCarouselSlidesState, TCollapseContainer, TComponent, TConditionalAttributes, TConditionalComponent, TContainer, TContainerPosition, TCountdownTimerTextComponent, TDevice, TDisabledButton, TField, TFieldSettings, TFlexProductContainer, THeaderFooter, TImageComponent, TInitialState, TMediaTypes, TOffer, TPages, TPaywallContext, TPaywallLaunchContext, TPaywallMedia, TPaywallTemplate, TPlayPauseButton, TProductContainer, TProductGroup, TProgressBarComponent, TProgressIndicatorComponent, TQRCodeComponent, TRadioButton, TRepeatingGrid, TResponsiveGrid, TSegmentPicker, TSegmentPickerItem, TSemverObj, TSpacerComponent, TStack, TSvgImageComponent, TSymbolComponent, TTestObject, TTextComponent, TTextLikeComponent, TTextListComponent, TToggleButtonComponent, TToggleSwitch, TVariablePattern, TVideoComponent, TVolumeButton, TimerState, TransactionRequest, UserAction, UserActionParameters, Wave, WaveSpec };
|
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.0",
|
|
98
98
|
// full package version including dev suffix — stamped by scripts/version.sh
|
|
99
|
-
NAMI_SDK_PACKAGE_VERSION = "3.4.0-dev.
|
|
99
|
+
NAMI_SDK_PACKAGE_VERSION = "3.4.0-dev.202605182046",
|
|
100
100
|
// environments
|
|
101
101
|
PRODUCTION = "production", DEVELOPMENT = "development",
|
|
102
102
|
// error messages
|
|
@@ -7402,19 +7402,34 @@ const mapAnonymousCampaigns = (campaigns, splitPosition, formFactor) => {
|
|
|
7402
7402
|
});
|
|
7403
7403
|
};
|
|
7404
7404
|
/**
|
|
7405
|
+
* Returns the combined list of API + initial-config campaigns for the current device's
|
|
7406
|
+
* form factor, deduplicated by (type, value) with API entries winning on collision.
|
|
7405
7407
|
*
|
|
7406
|
-
*
|
|
7407
|
-
*
|
|
7408
|
+
* Mirrors NamiCampaignManager.allCampaigns() on Apple (Set keyed on hash(value, type))
|
|
7409
|
+
* and Android (.distinct() with server-first ordering). Keying on (type, value) — rather
|
|
7410
|
+
* than rule UUID — ensures the same logical placement does not surface twice when the
|
|
7411
|
+
* server has republished a campaign under a new rule id.
|
|
7408
7412
|
*
|
|
7409
|
-
* Note:
|
|
7410
|
-
*
|
|
7413
|
+
* Note: this list reflects which placements are available, not whether they are launchable.
|
|
7414
|
+
* An API entry surfaced here may reference a paywall that has not yet been published in the
|
|
7415
|
+
* API response. NamiCampaignManager.launch() handles that case independently via
|
|
7416
|
+
* getPaywallDataFromLabel(), which falls back to the initial-config (campaign, paywall) pair
|
|
7417
|
+
* when the API pair is incomplete — matching the merged-paywall-lookup behavior on
|
|
7418
|
+
* Apple and Android.
|
|
7411
7419
|
*/
|
|
7412
7420
|
const allCampaigns = () => {
|
|
7413
7421
|
const apiCampaigns = storageService.getCampaignRules(API_CAMPAIGN_RULES) ?? [];
|
|
7414
7422
|
const initialCampaigns = storageService.getCampaignRules(INITIAL_CAMPAIGN_RULES) ?? [];
|
|
7415
7423
|
const formFactor = getDeviceFormFactor();
|
|
7416
7424
|
const campaigns = compact([...apiCampaigns, ...initialCampaigns]).filter((cRule) => cRule.form_factors?.some((f) => f.form_factor === formFactor));
|
|
7417
|
-
|
|
7425
|
+
const seen = new Set();
|
|
7426
|
+
return campaigns.filter((c) => {
|
|
7427
|
+
const key = `${c.type ?? ''}::${c.value ?? ''}`;
|
|
7428
|
+
if (seen.has(key))
|
|
7429
|
+
return false;
|
|
7430
|
+
seen.add(key);
|
|
7431
|
+
return true;
|
|
7432
|
+
});
|
|
7418
7433
|
};
|
|
7419
7434
|
/**
|
|
7420
7435
|
* Get campaigns by rule key, filtered by form factor.
|
|
@@ -13668,6 +13683,19 @@ class NamiFlow extends BasicNamiFlow {
|
|
|
13668
13683
|
this.forward(nextStep.id);
|
|
13669
13684
|
}
|
|
13670
13685
|
}
|
|
13686
|
+
handleRemoteBack() {
|
|
13687
|
+
const step = this.currentFlowStep;
|
|
13688
|
+
if (step?.actions[NamiReservedActions.REMOTE_BACK]) {
|
|
13689
|
+
this.triggerActions(NamiReservedActions.REMOTE_BACK);
|
|
13690
|
+
return 'handler';
|
|
13691
|
+
}
|
|
13692
|
+
if (this.previousStepAvailable) {
|
|
13693
|
+
this.back();
|
|
13694
|
+
return 'back';
|
|
13695
|
+
}
|
|
13696
|
+
this.finished();
|
|
13697
|
+
return 'dismissed';
|
|
13698
|
+
}
|
|
13671
13699
|
backToPreviousScreenStep() {
|
|
13672
13700
|
if (this.previousFlowStep?.allow_back_to === false) {
|
|
13673
13701
|
logger.warn(`Not allowed to go back to ${this.previousFlowStep.id}`);
|
|
@@ -63911,6 +63939,230 @@ const convertLocale = (locale) => {
|
|
|
63911
63939
|
return intlLocale.language + (intlLocale.region ?? intlLocale.script ?? '');
|
|
63912
63940
|
};
|
|
63913
63941
|
|
|
63942
|
+
/**
|
|
63943
|
+
* Components that are skipped entirely (they and their subtree do not
|
|
63944
|
+
* contribute text to the page-level announcement).
|
|
63945
|
+
*
|
|
63946
|
+
* - Buttons / interactive controls: their label is appended as the
|
|
63947
|
+
* focused-button suffix, not collected mid-tree. Recursing into them
|
|
63948
|
+
* would double-count the label and pull in non-spoken decorative text.
|
|
63949
|
+
* - Image-like leaves: explicitly skipped per spec.
|
|
63950
|
+
* - Form pickers + QR codes + raw video: not informational text.
|
|
63951
|
+
*/
|
|
63952
|
+
const SKIP_COMPONENTS = new Set([
|
|
63953
|
+
'button',
|
|
63954
|
+
'playPauseButton',
|
|
63955
|
+
'volumeButton',
|
|
63956
|
+
'toggleButton',
|
|
63957
|
+
'toggleSwitch',
|
|
63958
|
+
'radio',
|
|
63959
|
+
'image',
|
|
63960
|
+
'svgImage',
|
|
63961
|
+
'symbol',
|
|
63962
|
+
'qrCode',
|
|
63963
|
+
'videoUrl',
|
|
63964
|
+
'segmentPicker',
|
|
63965
|
+
'segmentPickerItem',
|
|
63966
|
+
]);
|
|
63967
|
+
/** Component values in {@link SKIP_COMPONENTS} that are interactive controls
|
|
63968
|
+
* (as opposed to images / media / non-text leaves). When a text component
|
|
63969
|
+
* shares a container with one of these, the text is treated as that
|
|
63970
|
+
* button's accessible label and excluded from the page composite. */
|
|
63971
|
+
const BUTTON_COMPONENTS = new Set([
|
|
63972
|
+
'button',
|
|
63973
|
+
'playPauseButton',
|
|
63974
|
+
'volumeButton',
|
|
63975
|
+
'toggleButton',
|
|
63976
|
+
'toggleSwitch',
|
|
63977
|
+
'radio',
|
|
63978
|
+
]);
|
|
63979
|
+
/** `namiComponentType` values that are always included in the page
|
|
63980
|
+
* composite — even when their structural position (e.g. a sibling of a
|
|
63981
|
+
* utility button) would otherwise mark them for exclusion. Driven by the
|
|
63982
|
+
* spec's schema table:
|
|
63983
|
+
*
|
|
63984
|
+
* | `namiComponentType: "legalText"` | Legal/T&C content (included in tree-walk) |
|
|
63985
|
+
*/
|
|
63986
|
+
const ALWAYS_INCLUDE_NAMI_TYPES = new Set(['legalText']);
|
|
63987
|
+
/**
|
|
63988
|
+
* Whether a text leaf inside `parent` should be skipped because it acts as
|
|
63989
|
+
* the accessible label for a sibling button.
|
|
63990
|
+
*
|
|
63991
|
+
* Schema pattern this catches: a container whose direct children include
|
|
63992
|
+
* BOTH a text/text-list AND an interactive button (e.g. Page 3's "Login
|
|
63993
|
+
* Group" — `[ text "Already an NFL+ subscriber?", loginButton "Sign In" ]`).
|
|
63994
|
+
* The text describes the button and is announced when the button is
|
|
63995
|
+
* focused, NOT as page-level content. Without this rule, the composite
|
|
63996
|
+
* leaks "Already an NFL+ subscriber? Subscribe to NFL plus button" instead
|
|
63997
|
+
* of "Subscribe to NFL plus button".
|
|
63998
|
+
*
|
|
63999
|
+
* Texts marked `namiComponentType: "legalText"` are exempt — the spec
|
|
64000
|
+
* explicitly opts legal copy in regardless of its container's other
|
|
64001
|
+
* children (e.g. Page 5's "Bottom Wrapper" mixes a body text, a restore
|
|
64002
|
+
* button, and the legal text — the legal text must still be spoken).
|
|
64003
|
+
*/
|
|
64004
|
+
function isButtonSiblingLabel(node, parent) {
|
|
64005
|
+
if (!parent || !Array.isArray(parent.components))
|
|
64006
|
+
return false;
|
|
64007
|
+
if (typeof node.namiComponentType === 'string' &&
|
|
64008
|
+
ALWAYS_INCLUDE_NAMI_TYPES.has(node.namiComponentType)) {
|
|
64009
|
+
return false;
|
|
64010
|
+
}
|
|
64011
|
+
for (const sibling of parent.components) {
|
|
64012
|
+
if (sibling && typeof sibling === 'object') {
|
|
64013
|
+
const s = sibling;
|
|
64014
|
+
if (typeof s.component === 'string' && BUTTON_COMPONENTS.has(s.component)) {
|
|
64015
|
+
return true;
|
|
64016
|
+
}
|
|
64017
|
+
}
|
|
64018
|
+
}
|
|
64019
|
+
return false;
|
|
64020
|
+
}
|
|
64021
|
+
/**
|
|
64022
|
+
* Recursively collect spoken text from a component subtree following the
|
|
64023
|
+
* TV Full-Page Announcement contract.
|
|
64024
|
+
*
|
|
64025
|
+
* Rules (in order):
|
|
64026
|
+
* 1. `null` / `undefined` → contribute nothing.
|
|
64027
|
+
* 2. `hidden: true` → skip the node AND its subtree.
|
|
64028
|
+
* 3. `component` in {@link SKIP_COMPONENTS} → skip the node AND its subtree.
|
|
64029
|
+
* 4. `screenreaderText` set on this container → take that string verbatim
|
|
64030
|
+
* and do NOT recurse (server-supplied override).
|
|
64031
|
+
* 5. `component: "text"` or `"text-list"` → collect, UNLESS the text is a
|
|
64032
|
+
* sibling label for an adjacent button (see
|
|
64033
|
+
* {@link isButtonSiblingLabel}). `namiComponentType: "legalText"` is
|
|
64034
|
+
* exempted from the sibling-label exclusion.
|
|
64035
|
+
* 6. Otherwise → recurse into `components`.
|
|
64036
|
+
*/
|
|
64037
|
+
function collectText(node, parent = null) {
|
|
64038
|
+
if (!node || typeof node !== 'object')
|
|
64039
|
+
return [];
|
|
64040
|
+
const n = node;
|
|
64041
|
+
if (n.hidden === true)
|
|
64042
|
+
return [];
|
|
64043
|
+
if (typeof n.component === 'string' && SKIP_COMPONENTS.has(n.component))
|
|
64044
|
+
return [];
|
|
64045
|
+
// Container-level override: when an enclosing container pre-supplies its own
|
|
64046
|
+
// screenreader text, take it verbatim and stop descending — the customer
|
|
64047
|
+
// has authored a polished announcement for this subtree.
|
|
64048
|
+
if (typeof n.screenreaderText === 'string' && n.screenreaderText.trim().length > 0) {
|
|
64049
|
+
return [n.screenreaderText.trim()];
|
|
64050
|
+
}
|
|
64051
|
+
if (n.component === 'text') {
|
|
64052
|
+
if (isButtonSiblingLabel(n, parent))
|
|
64053
|
+
return [];
|
|
64054
|
+
return typeof n.text === 'string' && n.text.length > 0 ? [n.text] : [];
|
|
64055
|
+
}
|
|
64056
|
+
if (n.component === 'text-list') {
|
|
64057
|
+
if (isButtonSiblingLabel(n, parent))
|
|
64058
|
+
return [];
|
|
64059
|
+
if (!Array.isArray(n.texts))
|
|
64060
|
+
return [];
|
|
64061
|
+
return n.texts.filter((t) => typeof t === 'string' && t.length > 0);
|
|
64062
|
+
}
|
|
64063
|
+
if (Array.isArray(n.components)) {
|
|
64064
|
+
const out = [];
|
|
64065
|
+
for (const child of n.components) {
|
|
64066
|
+
out.push(...collectText(child, n));
|
|
64067
|
+
}
|
|
64068
|
+
return out;
|
|
64069
|
+
}
|
|
64070
|
+
return [];
|
|
64071
|
+
}
|
|
64072
|
+
function collectHeaderFooter(slot) {
|
|
64073
|
+
if (!Array.isArray(slot))
|
|
64074
|
+
return [];
|
|
64075
|
+
// The slot itself acts as the synthetic parent so a top-level text inside
|
|
64076
|
+
// a header/footer that sits alongside a top-level button is treated as a
|
|
64077
|
+
// button label and excluded.
|
|
64078
|
+
const syntheticParent = { components: slot };
|
|
64079
|
+
const out = [];
|
|
64080
|
+
for (const node of slot) {
|
|
64081
|
+
out.push(...collectText(node, syntheticParent));
|
|
64082
|
+
}
|
|
64083
|
+
return out;
|
|
64084
|
+
}
|
|
64085
|
+
/**
|
|
64086
|
+
* Join an ordered list of collected text fragments into a single speakable
|
|
64087
|
+
* string. Each fragment is trimmed; empty fragments are dropped. Author
|
|
64088
|
+
* terminators (`.`, `!`, `?`) are preserved so emphasis carries through to
|
|
64089
|
+
* the screenreader; only fragments that lack a terminator get `". "`
|
|
64090
|
+
* inserted before the next fragment. The result is a string that reads
|
|
64091
|
+
* naturally without double-punctuation like `"...REACH!. Watch..."`.
|
|
64092
|
+
*/
|
|
64093
|
+
function joinFragments(fragments) {
|
|
64094
|
+
let out = '';
|
|
64095
|
+
for (const raw of fragments) {
|
|
64096
|
+
const trimmed = raw.trim();
|
|
64097
|
+
if (!trimmed)
|
|
64098
|
+
continue;
|
|
64099
|
+
if (!out) {
|
|
64100
|
+
out = trimmed;
|
|
64101
|
+
continue;
|
|
64102
|
+
}
|
|
64103
|
+
const last = out[out.length - 1];
|
|
64104
|
+
const endsWithTerminator = last === '.' || last === '!' || last === '?';
|
|
64105
|
+
out += (endsWithTerminator ? ' ' : '. ') + trimmed;
|
|
64106
|
+
}
|
|
64107
|
+
return out;
|
|
64108
|
+
}
|
|
64109
|
+
/**
|
|
64110
|
+
* Build the full-screen announcement string for a paywall page per the
|
|
64111
|
+
* TV Full-Page Announcement contract
|
|
64112
|
+
* (https://linear.app/nami-product-development/document/tv-full-page-announcement-980f61b96e7c).
|
|
64113
|
+
*
|
|
64114
|
+
* Behaviour:
|
|
64115
|
+
* 1. **Override path.** If `page.screenreaderText` is set, that string is
|
|
64116
|
+
* returned verbatim (followed by `focusedButtonLabel` if provided and
|
|
64117
|
+
* not already present at the tail). Server-authored polished
|
|
64118
|
+
* announcements win over client-side aggregation.
|
|
64119
|
+
*
|
|
64120
|
+
* 2. **Tree-walk fallback.** Otherwise, walk the page's containers in
|
|
64121
|
+
* reading order — `header` → `backgroundContainer` → `contentContainer`
|
|
64122
|
+
* → `footer` — collecting visible `text` / `text-list` descendants in
|
|
64123
|
+
* source order. `image`, `hidden: true` subtrees, interactive controls
|
|
64124
|
+
* (buttons / toggles), and non-text leaves are skipped. The
|
|
64125
|
+
* `focusedButtonLabel` is appended as the final sentence.
|
|
64126
|
+
*
|
|
64127
|
+
* SDKs invoke this once per page on the first focus of the default CTA, and
|
|
64128
|
+
* speak the result via their platform TTS API. On subsequent focuses within
|
|
64129
|
+
* the same page, the SDK announces only the focused element's own label —
|
|
64130
|
+
* this helper is NOT re-called.
|
|
64131
|
+
*
|
|
64132
|
+
* @param page The paywall page to announce.
|
|
64133
|
+
* @param focusedButtonLabel The resolved label of the button that
|
|
64134
|
+
* triggered the announcement (typically the
|
|
64135
|
+
* page's default-focused CTA). For
|
|
64136
|
+
* subscription-plan CTAs this is the dynamic
|
|
64137
|
+
* `"{price} {period} subscription plan button"`
|
|
64138
|
+
* string the backend already resolved.
|
|
64139
|
+
* @returns A single string ready to pass to a platform TTS API. Empty when
|
|
64140
|
+
* the page has no spoken content and no focused button label.
|
|
64141
|
+
*/
|
|
64142
|
+
function aggregateScreenreaderText(page, focusedButtonLabel = '') {
|
|
64143
|
+
const trimmedLabel = focusedButtonLabel.trim();
|
|
64144
|
+
// Override path
|
|
64145
|
+
if (typeof page.screenreaderText === 'string' && page.screenreaderText.trim().length > 0) {
|
|
64146
|
+
const override = page.screenreaderText.trim();
|
|
64147
|
+
if (!trimmedLabel)
|
|
64148
|
+
return override;
|
|
64149
|
+
// If the server-authored override already ends with the focused button
|
|
64150
|
+
// label, don't append it again.
|
|
64151
|
+
if (override.toLowerCase().endsWith(trimmedLabel.toLowerCase()))
|
|
64152
|
+
return override;
|
|
64153
|
+
return joinFragments([override, trimmedLabel]);
|
|
64154
|
+
}
|
|
64155
|
+
// Tree-walk path
|
|
64156
|
+
const fragments = [];
|
|
64157
|
+
fragments.push(...collectHeaderFooter(page.header));
|
|
64158
|
+
fragments.push(...collectText(page.backgroundContainer));
|
|
64159
|
+
fragments.push(...collectText(page.contentContainer));
|
|
64160
|
+
fragments.push(...collectHeaderFooter(page.footer));
|
|
64161
|
+
if (trimmedLabel)
|
|
64162
|
+
fragments.push(trimmedLabel);
|
|
64163
|
+
return joinFragments(fragments);
|
|
64164
|
+
}
|
|
64165
|
+
|
|
63914
64166
|
function namiBuySKU(skuRefId) {
|
|
63915
64167
|
if (!hasPurchaseManagement("NamiPurchaseManager.buySKU")) {
|
|
63916
64168
|
return;
|
|
@@ -63925,4 +64177,4 @@ function namiBuySKU(skuRefId) {
|
|
|
63925
64177
|
return result;
|
|
63926
64178
|
}
|
|
63927
64179
|
|
|
63928
|
-
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, 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, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager, NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager, NamiFlowStepType, NamiPaywallAction, NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiProfileManager, 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, 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, activateEntitlementByPurchase, activeEntitlements, 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, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateMinSDKVersion };
|
|
64180
|
+
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, 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, NamiCampaignRuleType, NamiConditionEvaluator, NamiCustomerManager, NamiEntitlementManager, NamiEventEmitter, NamiFlow, NamiFlowActionFunction, NamiFlowManager, NamiFlowStepType, NamiPaywallAction, NamiPaywallManager, PaywallManagerEvents as NamiPaywallManagerEvents, NamiProfileManager, 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, 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, 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, selectSegment, setActiveNamiEntitlements, shouldValidateProductGroups, skuItems, skuMapFromEntitlements, storageService, toDouble, toNamiEntitlements, toNamiSKU, tryParseB64Gzip, tryParseJson, updateRelatedSKUsForNamiEntitlement, uuidFromSplitPosition, validateMinSDKVersion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namiml/sdk-core",
|
|
3
|
-
"version": "3.4.0-dev.
|
|
3
|
+
"version": "3.4.0-dev.202605182046",
|
|
4
4
|
"description": "Platform-agnostic core for the Nami SDK — business logic, API, types, and state management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|