@magicfeedback/popup-sdk 1.7.0 → 1.7.1

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.mjs CHANGED
@@ -811,7 +811,7 @@ var BrowserPopupRenderer = class {
811
811
  if (!this.container) return;
812
812
  this.visible = true;
813
813
  const container = this.container;
814
- void import("./renderPopup-IHGYFMXO.mjs").then(({ renderPopup }) => {
814
+ void import("./renderPopup-HHQMAW3G.mjs").then(({ renderPopup }) => {
815
815
  renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
816
816
  });
817
817
  }
@@ -1563,6 +1563,75 @@ var CrashReporter = class {
1563
1563
  }
1564
1564
  };
1565
1565
 
1566
+ // src/core/popup-state-store.ts
1567
+ var POPUP_STATE_STORAGE_KEY = "deepdots.popups.state";
1568
+ var MAX_TRACKED_POPUP_ENTRIES = 200;
1569
+ function emptyState() {
1570
+ return { lastShown: {}, progress: {} };
1571
+ }
1572
+ function isValidTimestamp(value) {
1573
+ return typeof value === "number" && Number.isFinite(value);
1574
+ }
1575
+ function capEntries(entries, timestampOf) {
1576
+ if (entries.length <= MAX_TRACKED_POPUP_ENTRIES) return entries;
1577
+ return [...entries].sort((a, b) => timestampOf(b[1]) - timestampOf(a[1])).slice(0, MAX_TRACKED_POPUP_ENTRIES);
1578
+ }
1579
+ function readPopupState(storage) {
1580
+ let raw = null;
1581
+ try {
1582
+ raw = storage.getItem(POPUP_STATE_STORAGE_KEY);
1583
+ } catch {
1584
+ return emptyState();
1585
+ }
1586
+ if (!raw) return emptyState();
1587
+ let parsed;
1588
+ try {
1589
+ parsed = JSON.parse(raw);
1590
+ } catch {
1591
+ return emptyState();
1592
+ }
1593
+ if (typeof parsed !== "object" || parsed === null) return emptyState();
1594
+ const source = parsed;
1595
+ const state = emptyState();
1596
+ if (typeof source.lastShown === "object" && source.lastShown !== null) {
1597
+ const valid = Object.entries(source.lastShown).filter((entry) => isValidTimestamp(entry[1]));
1598
+ capEntries(valid, (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
1599
+ state.lastShown[popupId] = timestamp;
1600
+ });
1601
+ }
1602
+ if (typeof source.progress === "object" && source.progress !== null) {
1603
+ const valid = Object.entries(source.progress).filter((entry) => {
1604
+ const value = entry[1];
1605
+ if (typeof value !== "object" || value === null) return false;
1606
+ const candidate = value;
1607
+ return POPUP_TRIGGER_CONDITION_STATUSES.includes(candidate.status) && isValidTimestamp(candidate.timestamp);
1608
+ });
1609
+ capEntries(valid, (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
1610
+ state.progress[surveyId] = { status: entry.status, timestamp: entry.timestamp };
1611
+ });
1612
+ }
1613
+ return state;
1614
+ }
1615
+ function writePopupState(storage, state) {
1616
+ const capped = emptyState();
1617
+ capEntries(Object.entries(state.lastShown), (timestamp) => timestamp).forEach(([popupId, timestamp]) => {
1618
+ capped.lastShown[popupId] = timestamp;
1619
+ });
1620
+ capEntries(Object.entries(state.progress), (entry) => entry.timestamp).forEach(([surveyId, entry]) => {
1621
+ capped.progress[surveyId] = entry;
1622
+ });
1623
+ try {
1624
+ storage.setItem(POPUP_STATE_STORAGE_KEY, JSON.stringify(capped));
1625
+ } catch {
1626
+ }
1627
+ }
1628
+ function clearPopupState(storage) {
1629
+ try {
1630
+ storage.removeItem(POPUP_STATE_STORAGE_KEY);
1631
+ } catch {
1632
+ }
1633
+ }
1634
+
1566
1635
  // src/analytics/messaging.ts
1567
1636
  var MESSAGE_CHANNELS = ["push", "in_app"];
1568
1637
  function buildMessageParams(stage, o) {
@@ -1650,6 +1719,10 @@ var DeepdotsPopups = class {
1650
1719
  this.popupDefinitions = [];
1651
1720
  this.popupsLoaded = false;
1652
1721
  this.pendingAutoLaunch = false;
1722
+ // Estado que alimenta las reglas de redisplay. Copia de trabajo en memoria; la fuente
1723
+ // duradera es el storage (`popup-state-store`), rehidratada en `init()` — sin eso, una
1724
+ // recarga reiniciaba el cooldown y el popup volvía a salir. `answeredSurveys` se deriva
1725
+ // de las entradas COMPLETED de `surveyProgress` (los dos los escribe `markSurveyAnswered`).
1653
1726
  this.answeredSurveys = /* @__PURE__ */ new Set();
1654
1727
  this.surveyProgress = /* @__PURE__ */ new Map();
1655
1728
  this.lastShown = /* @__PURE__ */ new Map();
@@ -1725,6 +1798,7 @@ var DeepdotsPopups = class {
1725
1798
  };
1726
1799
  const storage = config.storage ?? createDefaultStorage();
1727
1800
  this.storage = storage;
1801
+ this.loadPopupState(storage);
1728
1802
  this.tracking = new TrackingManager({
1729
1803
  storage,
1730
1804
  clientUserId: this.config.userId,
@@ -1992,6 +2066,10 @@ var DeepdotsPopups = class {
1992
2066
  }) : null;
1993
2067
  this.analytics?.resetUserScope();
1994
2068
  this.messageGuard.reset();
2069
+ this.lastShown.clear();
2070
+ this.surveyProgress.clear();
2071
+ this.answeredSurveys.clear();
2072
+ clearPopupState(storage);
1995
2073
  this.log("tracking \xB7 user_change \xB7 user_id:", this.tracking.getUserId());
1996
2074
  this.openSession();
1997
2075
  }
@@ -2163,6 +2241,7 @@ var DeepdotsPopups = class {
2163
2241
  this.log("Showing popup (definition)", def);
2164
2242
  this.surveyToPopupId.set(def.surveyId, def.id);
2165
2243
  this.lastShown.set(def.id, Date.now());
2244
+ this.persistPopupState();
2166
2245
  this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
2167
2246
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2168
2247
  }
@@ -2527,7 +2606,7 @@ var DeepdotsPopups = class {
2527
2606
  }
2528
2607
  if (!this.popupContainer) return;
2529
2608
  const container = this.popupContainer;
2530
- void import("./renderPopup-IHGYFMXO.mjs").then(({ renderPopup }) => {
2609
+ void import("./renderPopup-HHQMAW3G.mjs").then(({ renderPopup }) => {
2531
2610
  renderPopup(
2532
2611
  container,
2533
2612
  surveyId,
@@ -2642,6 +2721,29 @@ var DeepdotsPopups = class {
2642
2721
  return;
2643
2722
  }
2644
2723
  this.surveyProgress.set(surveyId, { status, timestamp: Date.now() });
2724
+ this.persistPopupState();
2725
+ }
2726
+ /**
2727
+ * Rehidrata el estado de redisplay desde el storage. `answeredSurveys` se reconstruye
2728
+ * desde las entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
2729
+ */
2730
+ loadPopupState(storage) {
2731
+ const state = readPopupState(storage);
2732
+ Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
2733
+ this.lastShown.set(popupId, timestamp);
2734
+ });
2735
+ Object.entries(state.progress).forEach(([surveyId, entry]) => {
2736
+ this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
2737
+ if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
2738
+ });
2739
+ }
2740
+ /** Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria. */
2741
+ persistPopupState() {
2742
+ if (!this.storage) return;
2743
+ writePopupState(this.storage, {
2744
+ lastShown: Object.fromEntries(this.lastShown),
2745
+ progress: Object.fromEntries(this.surveyProgress)
2746
+ });
2645
2747
  }
2646
2748
  isPopupDefinition(value) {
2647
2749
  if (typeof value !== "object" || value === null) return false;