@namiml/sdk-core 3.4.0-dev.202604170506 → 3.4.0-dev.202605060437

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -98,7 +98,7 @@ const {
98
98
  // version — stamped by scripts/version.sh
99
99
  NAMI_SDK_VERSION: exports.NAMI_SDK_VERSION = "3.4.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.202604170506",
101
+ NAMI_SDK_PACKAGE_VERSION: exports.NAMI_SDK_PACKAGE_VERSION = "3.4.0-dev.202605060437",
102
102
  // environments
103
103
  PRODUCTION: exports.PRODUCTION = "production", DEVELOPMENT: exports.DEVELOPMENT = "development",
104
104
  // error messages
@@ -7283,7 +7283,9 @@ function uuidFromSplitPosition(namiCommands) {
7283
7283
 
7284
7284
  const isValidUrl = (label) => {
7285
7285
  try {
7286
- return Boolean(new URL(label));
7286
+ const url = new URL(label);
7287
+ const isHttp = url.protocol === 'http:' || url.protocol === 'https:';
7288
+ return isHttp && !!url.hostname;
7287
7289
  }
7288
7290
  catch {
7289
7291
  return false;
@@ -11051,6 +11053,43 @@ class SimpleEventTarget {
11051
11053
  }
11052
11054
 
11053
11055
  let productDetails = [];
11056
+ function createEventWithDetail(name, payload) {
11057
+ if (typeof Event === 'function') {
11058
+ const event = new Event(name);
11059
+ Object.defineProperty(event, 'detail', {
11060
+ configurable: true,
11061
+ enumerable: false,
11062
+ value: payload,
11063
+ writable: false,
11064
+ });
11065
+ return event;
11066
+ }
11067
+ return {
11068
+ type: name,
11069
+ detail: payload,
11070
+ bubbles: false,
11071
+ cancelBubble: false,
11072
+ cancelable: false,
11073
+ composed: false,
11074
+ currentTarget: null,
11075
+ defaultPrevented: false,
11076
+ eventPhase: 0,
11077
+ isTrusted: false,
11078
+ returnValue: true,
11079
+ srcElement: null,
11080
+ target: null,
11081
+ timeStamp: Date.now(),
11082
+ NONE: 0,
11083
+ CAPTURING_PHASE: 1,
11084
+ AT_TARGET: 2,
11085
+ BUBBLING_PHASE: 3,
11086
+ composedPath: () => [],
11087
+ initEvent: () => { },
11088
+ preventDefault: () => { },
11089
+ stopImmediatePropagation: () => { },
11090
+ stopPropagation: () => { },
11091
+ };
11092
+ }
11054
11093
  const initialState = {
11055
11094
  paywallId: '',
11056
11095
  livePaywalls: [],
@@ -11068,6 +11107,7 @@ const initialState = {
11068
11107
  formStates: {},
11069
11108
  timerStates: {},
11070
11109
  currentPage: 'page1',
11110
+ pageHistory: ['page1'],
11071
11111
  currentGroupId: '',
11072
11112
  currentGroupName: '',
11073
11113
  fullScreenPresentation: false,
@@ -11170,7 +11210,7 @@ class PaywallState extends SimpleEventTarget {
11170
11210
  this.subscribers.delete(callback);
11171
11211
  }
11172
11212
  emitEvent(name, payload) {
11173
- this.dispatchEvent(new CustomEvent(name, { detail: payload }));
11213
+ this.dispatchEvent(createEventWithDetail(name, payload));
11174
11214
  }
11175
11215
  onEvent(name, handler) {
11176
11216
  const listener = (e) => handler(e.detail);
@@ -11259,6 +11299,7 @@ class PaywallState extends SimpleEventTarget {
11259
11299
  state.anySkuHasPromoOffer = checkAnySkuHasPromoOffer(this.productDetails, this.filteredSkuMenus);
11260
11300
  state.paywallId = paywall.id;
11261
11301
  state.sku = currentSku(this.productDetails, state, this.filteredSkuMenus, skus);
11302
+ state.pageHistory = [state.currentPage];
11262
11303
  this.setState(state);
11263
11304
  return;
11264
11305
  }
@@ -11296,14 +11337,47 @@ class PaywallState extends SimpleEventTarget {
11296
11337
  return this.state.paywallId;
11297
11338
  }
11298
11339
  setCurrentPage(page) {
11299
- this.setState({ ...this.state, currentPage: page });
11340
+ if (!page || page === this.state.currentPage) {
11341
+ return;
11342
+ }
11343
+ const currentHistory = this.state.pageHistory && this.state.pageHistory.length
11344
+ ? this.state.pageHistory
11345
+ : [this.state.currentPage];
11346
+ this.setState({
11347
+ ...this.state,
11348
+ currentPage: page,
11349
+ pageHistory: [...currentHistory, page],
11350
+ });
11351
+ }
11352
+ canGoBackPage() {
11353
+ return (this.state.pageHistory?.length ?? 0) > 1;
11354
+ }
11355
+ goBackPage() {
11356
+ const currentHistory = this.state.pageHistory && this.state.pageHistory.length
11357
+ ? [...this.state.pageHistory]
11358
+ : [this.state.currentPage];
11359
+ if (currentHistory.length <= 1) {
11360
+ return false;
11361
+ }
11362
+ currentHistory.pop();
11363
+ const previousPage = currentHistory[currentHistory.length - 1];
11364
+ if (!previousPage) {
11365
+ return false;
11366
+ }
11367
+ this.setState({
11368
+ ...this.state,
11369
+ currentPage: previousPage,
11370
+ pageHistory: currentHistory,
11371
+ });
11372
+ return true;
11300
11373
  }
11301
11374
  setCustomerAttribute(attributes) {
11302
11375
  this.setState({ ...this.state, customer: { ...this.state.customer, ...attributes } });
11303
11376
  }
11304
11377
  removeCustomerAttribute(key) {
11305
- delete this.state.customer[key];
11306
- this.setState(this.state);
11378
+ const nextCustomer = { ...this.state.customer };
11379
+ delete nextCustomer[key];
11380
+ this.setState({ ...this.state, customer: nextCustomer });
11307
11381
  }
11308
11382
  setIsLoggedIn(isLoggedIn) {
11309
11383
  this.setState({ ...this.state, isLoggedIn });
@@ -11341,9 +11415,10 @@ class PaywallState extends SimpleEventTarget {
11341
11415
  this.setState({ ...this.state, appSuppliedVideoUrl: url, appSuppliedVideoName: name });
11342
11416
  }
11343
11417
  resetAppSuppliedVideoDetails() {
11344
- delete this.state['appSuppliedVideoUrl'];
11345
- delete this.state['appSuppliedVideoName'];
11346
- this.setState(this.state);
11418
+ const nextState = { ...this.state };
11419
+ delete nextState.appSuppliedVideoUrl;
11420
+ delete nextState.appSuppliedVideoName;
11421
+ this.setState(nextState);
11347
11422
  }
11348
11423
  setLaunchDetails(value, type) {
11349
11424
  this.setState({ ...this.state, launchValue: value, launchType: type });
@@ -11381,7 +11456,7 @@ class PaywallState extends SimpleEventTarget {
11381
11456
  this.setState({ ...this.state, userTags: { ...this.state.userTags, ...tags } });
11382
11457
  }
11383
11458
  setCurrentSlideIndex(index) {
11384
- this.state.currentSlideIndex = index;
11459
+ this.setState({ ...this.state, currentSlideIndex: index });
11385
11460
  }
11386
11461
  }
11387
11462
  PaywallState.providers = [];
@@ -12591,8 +12666,17 @@ class FlowLiquidResolver {
12591
12666
  return screenState?.campaign?.flow?.object_id;
12592
12667
  case "stepName":
12593
12668
  return flow?.currentFlowStep?.name;
12594
- case "buttonText":
12595
- return flow?.currentButton?.firstTextValue();
12669
+ case "buttonText": {
12670
+ const currentButton = flow?.currentButton;
12671
+ if (!currentButton) {
12672
+ return undefined;
12673
+ }
12674
+ const firstTextValue = currentButton.firstTextValue;
12675
+ if (typeof firstTextValue !== "function") {
12676
+ return undefined;
12677
+ }
12678
+ return firstTextValue.call(currentButton);
12679
+ }
12596
12680
  case "slideNumber": {
12597
12681
  const idx = screenState?.getSelectedSlideIndexForCurrentCarousel();
12598
12682
  return idx != null ? `${idx + 1}` : undefined;
package/dist/index.d.ts CHANGED
@@ -1586,6 +1586,7 @@ type TPaywallContext = TInitialState & {
1586
1586
  safeAreaTop: number;
1587
1587
  slides?: TCarouselSlidesState;
1588
1588
  currentPage: string;
1589
+ pageHistory: string[];
1589
1590
  fullScreenPresentation?: boolean;
1590
1591
  isLoggedIn?: boolean;
1591
1592
  darkMode?: boolean;
@@ -2311,6 +2312,8 @@ declare class PaywallState extends SimpleEventTarget {
2311
2312
  getPaywallActionEventData(): Partial<NamiPaywallEvent>;
2312
2313
  paywallId(): string;
2313
2314
  setCurrentPage(page: string): void;
2315
+ canGoBackPage(): boolean;
2316
+ goBackPage(): boolean;
2314
2317
  setCustomerAttribute(attributes: {
2315
2318
  [key: string]: string;
2316
2319
  }): void;
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.202604170506",
99
+ NAMI_SDK_PACKAGE_VERSION = "3.4.0-dev.202605060437",
100
100
  // environments
101
101
  PRODUCTION = "production", DEVELOPMENT = "development",
102
102
  // error messages
@@ -7281,7 +7281,9 @@ function uuidFromSplitPosition(namiCommands) {
7281
7281
 
7282
7282
  const isValidUrl = (label) => {
7283
7283
  try {
7284
- return Boolean(new URL(label));
7284
+ const url = new URL(label);
7285
+ const isHttp = url.protocol === 'http:' || url.protocol === 'https:';
7286
+ return isHttp && !!url.hostname;
7285
7287
  }
7286
7288
  catch {
7287
7289
  return false;
@@ -11049,6 +11051,43 @@ class SimpleEventTarget {
11049
11051
  }
11050
11052
 
11051
11053
  let productDetails = [];
11054
+ function createEventWithDetail(name, payload) {
11055
+ if (typeof Event === 'function') {
11056
+ const event = new Event(name);
11057
+ Object.defineProperty(event, 'detail', {
11058
+ configurable: true,
11059
+ enumerable: false,
11060
+ value: payload,
11061
+ writable: false,
11062
+ });
11063
+ return event;
11064
+ }
11065
+ return {
11066
+ type: name,
11067
+ detail: payload,
11068
+ bubbles: false,
11069
+ cancelBubble: false,
11070
+ cancelable: false,
11071
+ composed: false,
11072
+ currentTarget: null,
11073
+ defaultPrevented: false,
11074
+ eventPhase: 0,
11075
+ isTrusted: false,
11076
+ returnValue: true,
11077
+ srcElement: null,
11078
+ target: null,
11079
+ timeStamp: Date.now(),
11080
+ NONE: 0,
11081
+ CAPTURING_PHASE: 1,
11082
+ AT_TARGET: 2,
11083
+ BUBBLING_PHASE: 3,
11084
+ composedPath: () => [],
11085
+ initEvent: () => { },
11086
+ preventDefault: () => { },
11087
+ stopImmediatePropagation: () => { },
11088
+ stopPropagation: () => { },
11089
+ };
11090
+ }
11052
11091
  const initialState = {
11053
11092
  paywallId: '',
11054
11093
  livePaywalls: [],
@@ -11066,6 +11105,7 @@ const initialState = {
11066
11105
  formStates: {},
11067
11106
  timerStates: {},
11068
11107
  currentPage: 'page1',
11108
+ pageHistory: ['page1'],
11069
11109
  currentGroupId: '',
11070
11110
  currentGroupName: '',
11071
11111
  fullScreenPresentation: false,
@@ -11168,7 +11208,7 @@ class PaywallState extends SimpleEventTarget {
11168
11208
  this.subscribers.delete(callback);
11169
11209
  }
11170
11210
  emitEvent(name, payload) {
11171
- this.dispatchEvent(new CustomEvent(name, { detail: payload }));
11211
+ this.dispatchEvent(createEventWithDetail(name, payload));
11172
11212
  }
11173
11213
  onEvent(name, handler) {
11174
11214
  const listener = (e) => handler(e.detail);
@@ -11257,6 +11297,7 @@ class PaywallState extends SimpleEventTarget {
11257
11297
  state.anySkuHasPromoOffer = checkAnySkuHasPromoOffer(this.productDetails, this.filteredSkuMenus);
11258
11298
  state.paywallId = paywall.id;
11259
11299
  state.sku = currentSku(this.productDetails, state, this.filteredSkuMenus, skus);
11300
+ state.pageHistory = [state.currentPage];
11260
11301
  this.setState(state);
11261
11302
  return;
11262
11303
  }
@@ -11294,14 +11335,47 @@ class PaywallState extends SimpleEventTarget {
11294
11335
  return this.state.paywallId;
11295
11336
  }
11296
11337
  setCurrentPage(page) {
11297
- this.setState({ ...this.state, currentPage: page });
11338
+ if (!page || page === this.state.currentPage) {
11339
+ return;
11340
+ }
11341
+ const currentHistory = this.state.pageHistory && this.state.pageHistory.length
11342
+ ? this.state.pageHistory
11343
+ : [this.state.currentPage];
11344
+ this.setState({
11345
+ ...this.state,
11346
+ currentPage: page,
11347
+ pageHistory: [...currentHistory, page],
11348
+ });
11349
+ }
11350
+ canGoBackPage() {
11351
+ return (this.state.pageHistory?.length ?? 0) > 1;
11352
+ }
11353
+ goBackPage() {
11354
+ const currentHistory = this.state.pageHistory && this.state.pageHistory.length
11355
+ ? [...this.state.pageHistory]
11356
+ : [this.state.currentPage];
11357
+ if (currentHistory.length <= 1) {
11358
+ return false;
11359
+ }
11360
+ currentHistory.pop();
11361
+ const previousPage = currentHistory[currentHistory.length - 1];
11362
+ if (!previousPage) {
11363
+ return false;
11364
+ }
11365
+ this.setState({
11366
+ ...this.state,
11367
+ currentPage: previousPage,
11368
+ pageHistory: currentHistory,
11369
+ });
11370
+ return true;
11298
11371
  }
11299
11372
  setCustomerAttribute(attributes) {
11300
11373
  this.setState({ ...this.state, customer: { ...this.state.customer, ...attributes } });
11301
11374
  }
11302
11375
  removeCustomerAttribute(key) {
11303
- delete this.state.customer[key];
11304
- this.setState(this.state);
11376
+ const nextCustomer = { ...this.state.customer };
11377
+ delete nextCustomer[key];
11378
+ this.setState({ ...this.state, customer: nextCustomer });
11305
11379
  }
11306
11380
  setIsLoggedIn(isLoggedIn) {
11307
11381
  this.setState({ ...this.state, isLoggedIn });
@@ -11339,9 +11413,10 @@ class PaywallState extends SimpleEventTarget {
11339
11413
  this.setState({ ...this.state, appSuppliedVideoUrl: url, appSuppliedVideoName: name });
11340
11414
  }
11341
11415
  resetAppSuppliedVideoDetails() {
11342
- delete this.state['appSuppliedVideoUrl'];
11343
- delete this.state['appSuppliedVideoName'];
11344
- this.setState(this.state);
11416
+ const nextState = { ...this.state };
11417
+ delete nextState.appSuppliedVideoUrl;
11418
+ delete nextState.appSuppliedVideoName;
11419
+ this.setState(nextState);
11345
11420
  }
11346
11421
  setLaunchDetails(value, type) {
11347
11422
  this.setState({ ...this.state, launchValue: value, launchType: type });
@@ -11379,7 +11454,7 @@ class PaywallState extends SimpleEventTarget {
11379
11454
  this.setState({ ...this.state, userTags: { ...this.state.userTags, ...tags } });
11380
11455
  }
11381
11456
  setCurrentSlideIndex(index) {
11382
- this.state.currentSlideIndex = index;
11457
+ this.setState({ ...this.state, currentSlideIndex: index });
11383
11458
  }
11384
11459
  }
11385
11460
  PaywallState.providers = [];
@@ -12589,8 +12664,17 @@ class FlowLiquidResolver {
12589
12664
  return screenState?.campaign?.flow?.object_id;
12590
12665
  case "stepName":
12591
12666
  return flow?.currentFlowStep?.name;
12592
- case "buttonText":
12593
- return flow?.currentButton?.firstTextValue();
12667
+ case "buttonText": {
12668
+ const currentButton = flow?.currentButton;
12669
+ if (!currentButton) {
12670
+ return undefined;
12671
+ }
12672
+ const firstTextValue = currentButton.firstTextValue;
12673
+ if (typeof firstTextValue !== "function") {
12674
+ return undefined;
12675
+ }
12676
+ return firstTextValue.call(currentButton);
12677
+ }
12594
12678
  case "slideNumber": {
12595
12679
  const idx = screenState?.getSelectedSlideIndexForCurrentCarousel();
12596
12680
  return idx != null ? `${idx + 1}` : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@namiml/sdk-core",
3
- "version": "3.4.0-dev.202604170506",
3
+ "version": "3.4.0-dev.202605060437",
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",