@magicfeedback/popup-sdk 1.8.1 → 1.8.2
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.d.mts +25 -11
- package/dist/index.d.ts +25 -11
- package/dist/index.js +50 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -22
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +15 -5
- package/dist/react-native.d.ts +15 -5
- package/dist/react-native.js +48 -19
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +48 -19
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-3CZ6WTXF.mjs → renderPopup-ERUKQE4U.mjs} +3 -3
- package/dist/renderPopup-ERUKQE4U.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/renderPopup-3CZ6WTXF.mjs.map +0 -1
package/dist/react-native.mjs
CHANGED
|
@@ -1208,14 +1208,7 @@ function createFeedbackSink(options) {
|
|
|
1208
1208
|
const post = async (body, final, sessionEnd = false) => {
|
|
1209
1209
|
const json = JSON.stringify(body);
|
|
1210
1210
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
1211
|
-
if (final
|
|
1212
|
-
const payload = typeof Blob !== "undefined" ? new Blob([json], { type: "application/json" }) : json;
|
|
1213
|
-
if (options.sendBeaconImpl(url, payload)) {
|
|
1214
|
-
options.log?.("[DeepdotsAnalytics] final flush via sendBeacon");
|
|
1215
|
-
return;
|
|
1216
|
-
}
|
|
1217
|
-
options.log?.("[DeepdotsAnalytics] sendBeacon rejected the batch; falling back to fetch");
|
|
1218
|
-
}
|
|
1211
|
+
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
1219
1212
|
const f = options.fetchImpl ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
1220
1213
|
if (!f) {
|
|
1221
1214
|
options.log?.("[DeepdotsAnalytics] no fetch available; payload not sent", body);
|
|
@@ -1225,6 +1218,9 @@ function createFeedbackSink(options) {
|
|
|
1225
1218
|
method: "POST",
|
|
1226
1219
|
headers: { "Content-Type": "application/json" },
|
|
1227
1220
|
body: json,
|
|
1221
|
+
// La API autentica por `publicKey` en el body y responde `Allow-Origin: *`: una
|
|
1222
|
+
// petición con credenciales fallaría el CORS. Explícito para no depender del default.
|
|
1223
|
+
credentials: "omit",
|
|
1228
1224
|
// keepalive: el POST sobrevive a la navegación mientras el body sea pequeño.
|
|
1229
1225
|
...small ? { keepalive: true } : {}
|
|
1230
1226
|
});
|
|
@@ -1317,6 +1313,15 @@ var NavigationObserver = class {
|
|
|
1317
1313
|
this.closeCurrent();
|
|
1318
1314
|
this.currentScreen = null;
|
|
1319
1315
|
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Retoma el seguimiento en la pantalla actual tras un `stop()`, cuando se abre una sesión
|
|
1318
|
+
* nueva sin navegar (cambio de usuario, vuelta de la bfcache). No-op si nunca se instaló
|
|
1319
|
+
* (navegación manual por `setScreen`, RN) o si ya hay pantalla en curso.
|
|
1320
|
+
*/
|
|
1321
|
+
restart() {
|
|
1322
|
+
if (!this.installed || this.currentScreen != null || typeof window === "undefined") return;
|
|
1323
|
+
this.begin(window.location.href);
|
|
1324
|
+
}
|
|
1320
1325
|
closeCurrent() {
|
|
1321
1326
|
if (this.currentScreen == null) return;
|
|
1322
1327
|
const exit = this.now();
|
|
@@ -1956,8 +1961,6 @@ var DeepdotsPopups = class {
|
|
|
1956
1961
|
baseUrl: this.baseUrl,
|
|
1957
1962
|
keys: config.analytics,
|
|
1958
1963
|
log: (...a) => this.log(...a),
|
|
1959
|
-
// sendBeacon: único transporte que sobrevive al cierre de la página.
|
|
1960
|
-
sendBeaconImpl: typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" ? (url, body) => navigator.sendBeacon(url, body) : void 0,
|
|
1961
1964
|
onSessionId: (id) => {
|
|
1962
1965
|
this.analyticsFeedbackSessionId = id;
|
|
1963
1966
|
},
|
|
@@ -2005,7 +2008,6 @@ var DeepdotsPopups = class {
|
|
|
2005
2008
|
this.navObserver.onVisit((v) => this.track("deepdots_page_view", { screen: v.screen, duration_seconds: v.durationSeconds }));
|
|
2006
2009
|
this.navObserver.install();
|
|
2007
2010
|
this.engagement = new EngagementTracker();
|
|
2008
|
-
this.engagement.resume();
|
|
2009
2011
|
this.setupAnalyticsFlush();
|
|
2010
2012
|
this.openSession();
|
|
2011
2013
|
const pendingCrashes = this.crashReporter.drainPendingCrashes();
|
|
@@ -2224,6 +2226,7 @@ var DeepdotsPopups = class {
|
|
|
2224
2226
|
this.navStarted = false;
|
|
2225
2227
|
this.analytics?.exitAllMiniServices();
|
|
2226
2228
|
this.flushEngagement();
|
|
2229
|
+
this.engagement?.pause();
|
|
2227
2230
|
this.track("deepdots_session_end", { reason });
|
|
2228
2231
|
this.flushAnalytics({ final: reason === "page_hide", sessionEnd: true });
|
|
2229
2232
|
this.analyticsFeedbackSessionId = void 0;
|
|
@@ -2239,6 +2242,12 @@ var DeepdotsPopups = class {
|
|
|
2239
2242
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
2240
2243
|
this.sessionOpen = true;
|
|
2241
2244
|
this.track("deepdots_session_start", {});
|
|
2245
|
+
this.navObserver?.restart();
|
|
2246
|
+
if (this.isDocumentVisible()) this.engagement?.resume();
|
|
2247
|
+
}
|
|
2248
|
+
/** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
|
|
2249
|
+
isDocumentVisible() {
|
|
2250
|
+
return typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
2242
2251
|
}
|
|
2243
2252
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
2244
2253
|
previewAnalytics() {
|
|
@@ -2251,8 +2260,8 @@ var DeepdotsPopups = class {
|
|
|
2251
2260
|
}
|
|
2252
2261
|
/**
|
|
2253
2262
|
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
2254
|
-
* `final: true` (cierre de página/app)
|
|
2255
|
-
*
|
|
2263
|
+
* `final: true` (cierre de página/app): el lote no espera al primer POST en vuelo, porque
|
|
2264
|
+
* el documento se muere; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
2256
2265
|
*/
|
|
2257
2266
|
flushAnalytics(options) {
|
|
2258
2267
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
@@ -2273,21 +2282,30 @@ var DeepdotsPopups = class {
|
|
|
2273
2282
|
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
2274
2283
|
setupAnalyticsFlush() {
|
|
2275
2284
|
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
2276
|
-
this.
|
|
2285
|
+
this.startAnalyticsFlushTimer();
|
|
2277
2286
|
window.addEventListener("pagehide", () => {
|
|
2278
2287
|
clearInterval(this.analyticsFlushTimer);
|
|
2279
2288
|
this.closeSession("page_hide");
|
|
2280
2289
|
});
|
|
2290
|
+
window.addEventListener("pageshow", (event) => {
|
|
2291
|
+
if (!event.persisted) return;
|
|
2292
|
+
this.startAnalyticsFlushTimer();
|
|
2293
|
+
this.openSession();
|
|
2294
|
+
});
|
|
2281
2295
|
document.addEventListener("visibilitychange", () => {
|
|
2282
2296
|
if (document.visibilityState === "hidden") {
|
|
2283
2297
|
this.flushEngagement();
|
|
2284
2298
|
this.engagement?.pause();
|
|
2285
2299
|
this.flushAnalytics();
|
|
2286
2300
|
} else if (document.visibilityState === "visible") {
|
|
2287
|
-
this.engagement?.resume();
|
|
2301
|
+
if (this.sessionOpen) this.engagement?.resume();
|
|
2288
2302
|
}
|
|
2289
2303
|
});
|
|
2290
2304
|
}
|
|
2305
|
+
startAnalyticsFlushTimer() {
|
|
2306
|
+
clearInterval(this.analyticsFlushTimer);
|
|
2307
|
+
this.analyticsFlushTimer = setInterval(() => this.flushAnalytics(), ANALYTICS_FLUSH_INTERVAL_MS);
|
|
2308
|
+
}
|
|
2291
2309
|
/** Enable auto-launch functionality with configured triggers */
|
|
2292
2310
|
autoLaunch() {
|
|
2293
2311
|
if (!this.initialized) {
|
|
@@ -2381,6 +2399,7 @@ var DeepdotsPopups = class {
|
|
|
2381
2399
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
2382
2400
|
}
|
|
2383
2401
|
shouldShow(def, pathUrl, skipPathCheck = false) {
|
|
2402
|
+
if (this.storage) this.loadPopupState(this.storage);
|
|
2384
2403
|
if (this.isPathExcluded(def, pathUrl)) {
|
|
2385
2404
|
return false;
|
|
2386
2405
|
}
|
|
@@ -2907,22 +2926,32 @@ var DeepdotsPopups = class {
|
|
|
2907
2926
|
this.persistPopupState();
|
|
2908
2927
|
}
|
|
2909
2928
|
/**
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
2929
|
+
* Fusiona el estado de redisplay del storage con el de memoria: por cada popup/survey gana
|
|
2930
|
+
* la entrada MÁS RECIENTE. Fusionar y no sustituir es lo que hace convivir a varias
|
|
2931
|
+
* pestañas sobre el mismo `localStorage`: se llama en el `init()`, antes de cada decisión
|
|
2932
|
+
* de mostrar y antes de cada escritura. `answeredSurveys` se reconstruye desde las
|
|
2933
|
+
* entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
2912
2934
|
*/
|
|
2913
2935
|
loadPopupState(storage) {
|
|
2914
2936
|
const state = readPopupState(storage);
|
|
2915
2937
|
Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
|
|
2916
|
-
this.lastShown.set(popupId, timestamp);
|
|
2938
|
+
if (timestamp > (this.lastShown.get(popupId) ?? -Infinity)) this.lastShown.set(popupId, timestamp);
|
|
2917
2939
|
});
|
|
2918
2940
|
Object.entries(state.progress).forEach(([surveyId, entry]) => {
|
|
2941
|
+
const current = this.surveyProgress.get(surveyId);
|
|
2942
|
+
if (current && current.timestamp >= entry.timestamp) return;
|
|
2919
2943
|
this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
|
|
2920
2944
|
if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
|
|
2921
2945
|
});
|
|
2922
2946
|
}
|
|
2923
|
-
/**
|
|
2947
|
+
/**
|
|
2948
|
+
* Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria.
|
|
2949
|
+
* Fusiona antes de escribir: escribir solo la foto en memoria borraba lo que otra pestaña
|
|
2950
|
+
* hubiese guardado desde nuestro `init()`.
|
|
2951
|
+
*/
|
|
2924
2952
|
persistPopupState() {
|
|
2925
2953
|
if (!this.storage) return;
|
|
2954
|
+
this.loadPopupState(this.storage);
|
|
2926
2955
|
writePopupState(this.storage, {
|
|
2927
2956
|
lastShown: Object.fromEntries(this.lastShown),
|
|
2928
2957
|
progress: Object.fromEntries(this.surveyProgress)
|