@magicfeedback/popup-sdk 1.8.2 → 1.8.4
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/README.md +34 -2
- package/dist/index.d.mts +48 -2
- package/dist/index.d.ts +48 -2
- package/dist/index.js +132 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +133 -21
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +39 -1
- package/dist/react-native.d.ts +39 -1
- package/dist/react-native.js +130 -18
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +130 -18
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-ERUKQE4U.mjs → renderPopup-3CZ6WTXF.mjs} +3 -3
- package/dist/renderPopup-3CZ6WTXF.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/renderPopup-ERUKQE4U.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -868,7 +868,7 @@ function createReactNativeRenderer() {
|
|
|
868
868
|
}
|
|
869
869
|
|
|
870
870
|
// src/ui/preload.ts
|
|
871
|
-
var defaultLoader = () => import("./renderPopup-
|
|
871
|
+
var defaultLoader = () => import("./renderPopup-3CZ6WTXF.mjs");
|
|
872
872
|
var pending = null;
|
|
873
873
|
function preloadRenderPopup(loader = defaultLoader) {
|
|
874
874
|
if (pending) return pending;
|
|
@@ -941,7 +941,7 @@ var BrowserPopupRenderer = class {
|
|
|
941
941
|
if (!this.container) return;
|
|
942
942
|
this.visible = true;
|
|
943
943
|
const container = this.container;
|
|
944
|
-
void import("./renderPopup-
|
|
944
|
+
void import("./renderPopup-3CZ6WTXF.mjs").then(({ renderPopup }) => {
|
|
945
945
|
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
|
|
946
946
|
});
|
|
947
947
|
}
|
|
@@ -966,10 +966,13 @@ function createDefaultRenderer() {
|
|
|
966
966
|
|
|
967
967
|
// src/analytics/analytics-manager.ts
|
|
968
968
|
function createDryRunSink(log = console.log) {
|
|
969
|
-
return (payload) =>
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
969
|
+
return (payload, meta) => {
|
|
970
|
+
if (meta?.resetSession) return;
|
|
971
|
+
log(
|
|
972
|
+
"[DeepdotsAnalytics] (dry-run \xB7 NOT sent \xB7 no init.analytics) POST /sdk/feedback \u2192",
|
|
973
|
+
JSON.stringify(payload, null, 2)
|
|
974
|
+
);
|
|
975
|
+
};
|
|
973
976
|
}
|
|
974
977
|
var dryRunSink = createDryRunSink();
|
|
975
978
|
var AnalyticsManager = class {
|
|
@@ -1036,6 +1039,19 @@ var AnalyticsManager = class {
|
|
|
1036
1039
|
this.exitMiniService(name);
|
|
1037
1040
|
}
|
|
1038
1041
|
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Olvida la sesión en curso SIN emitir nada: vacía el buffer y los mini-services activos
|
|
1044
|
+
* (sin `mini_service_exit`). Para una sesión que el backend ya cerró por inactividad: lo
|
|
1045
|
+
* que quedara pendiente pertenecía a ella y no debe llegar con la sesión nueva.
|
|
1046
|
+
*/
|
|
1047
|
+
discardSession(identity) {
|
|
1048
|
+
this.events = [];
|
|
1049
|
+
this.activeMiniServices.clear();
|
|
1050
|
+
try {
|
|
1051
|
+
void this.sink({ ...this.buildPayload(identity), events: [] }, { resetSession: true });
|
|
1052
|
+
} catch {
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1039
1055
|
/**
|
|
1040
1056
|
* Olvida lo que pertenecía al usuario anterior (user attributes + métricas) al cambiar de
|
|
1041
1057
|
* usuario. NO toca el buffer de eventos: el cierre de sesión ya lo vació con la identidad
|
|
@@ -1245,6 +1261,12 @@ function createFeedbackSink(options) {
|
|
|
1245
1261
|
}
|
|
1246
1262
|
};
|
|
1247
1263
|
return async (envelope, meta) => {
|
|
1264
|
+
if (meta?.resetSession) {
|
|
1265
|
+
feedbackSessionId = void 0;
|
|
1266
|
+
firstPostInFlight = null;
|
|
1267
|
+
options.onSessionReset?.();
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1248
1270
|
const final = meta?.final === true;
|
|
1249
1271
|
const sessionEnd = meta?.sessionEnd === true;
|
|
1250
1272
|
if (!feedbackSessionId && firstPostInFlight && !final) {
|
|
@@ -1311,6 +1333,14 @@ var NavigationObserver = class {
|
|
|
1311
1333
|
this.closeCurrent();
|
|
1312
1334
|
this.currentScreen = null;
|
|
1313
1335
|
}
|
|
1336
|
+
/**
|
|
1337
|
+
* Olvida la pantalla actual SIN emitir su visita. Para una sesión que el backend ya dio
|
|
1338
|
+
* por cerrada: su visita no tiene dónde ir, y mandarla con la sesión nueva la contaría
|
|
1339
|
+
* donde no ocurrió. Después, `restart()` vuelve a empezar en la pantalla actual.
|
|
1340
|
+
*/
|
|
1341
|
+
discard() {
|
|
1342
|
+
this.currentScreen = null;
|
|
1343
|
+
}
|
|
1314
1344
|
/**
|
|
1315
1345
|
* Retoma el seguimiento en la pantalla actual tras un `stop()`, cuando se abre una sesión
|
|
1316
1346
|
* nueva sin navegar (cambio de usuario, vuelta de la bfcache). No-op si nunca se instaló
|
|
@@ -1840,6 +1870,10 @@ var EXIT_QUEUE_STORAGE_KEY = "__deepdots_exit_popup_queue__";
|
|
|
1840
1870
|
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
1841
1871
|
var ANALYTICS_MAX_BATCH_SIZE = 20;
|
|
1842
1872
|
var ANALYTICS_FLUSH_INTERVAL_MS = 3e4;
|
|
1873
|
+
var ANALYTICS_HEARTBEAT_MS = 5 * 6e4;
|
|
1874
|
+
var ANALYTICS_SESSION_TIMEOUT_MS = 30 * 6e4;
|
|
1875
|
+
var ANALYTICS_SERVER_IDLE_MS = 60 * 6e4;
|
|
1876
|
+
var ANALYTICS_SESSION_DISCARD_MS = ANALYTICS_SERVER_IDLE_MS - 10 * 6e4;
|
|
1843
1877
|
var RESERVED_EVENT_PREFIX = "deepdots_";
|
|
1844
1878
|
var CUSTOM_EVENT_PREFIX = "deepdots_event_";
|
|
1845
1879
|
var DeepdotsPopups = class {
|
|
@@ -1903,11 +1937,21 @@ var DeepdotsPopups = class {
|
|
|
1903
1937
|
* nueva al volver a foreground o al conceder el consentimiento más tarde.
|
|
1904
1938
|
*/
|
|
1905
1939
|
this.sessionOpen = false;
|
|
1940
|
+
/** Último `user_engagement` emitido (ms epoch): marca el latido. */
|
|
1941
|
+
this.lastEngagementAt = 0;
|
|
1942
|
+
/** Cuándo se ocultó la pestaña por última vez (ms epoch); null si está visible. */
|
|
1943
|
+
this.hiddenAt = null;
|
|
1906
1944
|
/**
|
|
1907
1945
|
* Idioma resuelto en init() (explícito > navigator.language > Intl). Única fuente de
|
|
1908
1946
|
* verdad para el context de analytics Y para la segmentación por idioma de los popups.
|
|
1909
1947
|
*/
|
|
1910
1948
|
this.language = void 0;
|
|
1949
|
+
/** `geolocation` del init: si es false no se usa ni la caché ni el lookup. */
|
|
1950
|
+
this.geoEnabled = true;
|
|
1951
|
+
/** Solo se consulta a terceros si el país/ciudad se va a enviar (analytics configurado). */
|
|
1952
|
+
this.geoWanted = false;
|
|
1953
|
+
/** Evita más de un lookup por instancia (el consentimiento puede ir y venir). */
|
|
1954
|
+
this.geoLookupStarted = false;
|
|
1911
1955
|
}
|
|
1912
1956
|
/** Initialize the SDK with configuration */
|
|
1913
1957
|
init(config) {
|
|
@@ -1965,7 +2009,9 @@ var DeepdotsPopups = class {
|
|
|
1965
2009
|
onSessionReset: () => {
|
|
1966
2010
|
this.analyticsFeedbackSessionId = void 0;
|
|
1967
2011
|
}
|
|
1968
|
-
}) : createDryRunSink((...a) =>
|
|
2012
|
+
}) : createDryRunSink((...a) => {
|
|
2013
|
+
if (this.config?.debug) this.logger.log(...a);
|
|
2014
|
+
});
|
|
1969
2015
|
const device = config.device ?? collectDeviceInfo(config.appVersion);
|
|
1970
2016
|
this.language = resolveLanguage({
|
|
1971
2017
|
explicit: config.language,
|
|
@@ -1993,15 +2039,9 @@ var DeepdotsPopups = class {
|
|
|
1993
2039
|
if (this.tracking?.isTrackingEnabled()) {
|
|
1994
2040
|
this.crashReporter.install();
|
|
1995
2041
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
if (geo) {
|
|
2000
|
-
this.analytics?.updateDevice(geo);
|
|
2001
|
-
writeCachedGeo(storage, geo, Date.now());
|
|
2002
|
-
}
|
|
2003
|
-
}).catch(() => {
|
|
2004
|
-
});
|
|
2042
|
+
this.geoEnabled = config.geolocation ?? true;
|
|
2043
|
+
this.geoWanted = this.geoEnabled && !!config.analytics;
|
|
2044
|
+
this.resolveGeo();
|
|
2005
2045
|
this.navObserver = new NavigationObserver();
|
|
2006
2046
|
this.navObserver.onVisit((v) => this.track("deepdots_page_view", { screen: v.screen, duration_seconds: v.durationSeconds }));
|
|
2007
2047
|
this.navObserver.install();
|
|
@@ -2043,6 +2083,7 @@ var DeepdotsPopups = class {
|
|
|
2043
2083
|
if (!enabled) this.closeSession("tracking_disabled");
|
|
2044
2084
|
this.tracking?.setTrackingEnabled(enabled);
|
|
2045
2085
|
if (enabled) this.openSession();
|
|
2086
|
+
if (enabled) this.resolveGeo();
|
|
2046
2087
|
this.log("tracking \xB7 setTrackingEnabled:", enabled, "\xB7 session_id:", this.tracking?.getSessionId() ?? null);
|
|
2047
2088
|
}
|
|
2048
2089
|
// ───────── Analytics (canal separado del feedback, vinculado por user_id) ─────────
|
|
@@ -2239,6 +2280,7 @@ var DeepdotsPopups = class {
|
|
|
2239
2280
|
if (this.sessionOpen) return;
|
|
2240
2281
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
2241
2282
|
this.sessionOpen = true;
|
|
2283
|
+
this.lastEngagementAt = Date.now();
|
|
2242
2284
|
this.track("deepdots_session_start", {});
|
|
2243
2285
|
this.navObserver?.restart();
|
|
2244
2286
|
if (this.isDocumentVisible()) this.engagement?.resume();
|
|
@@ -2269,7 +2311,76 @@ var DeepdotsPopups = class {
|
|
|
2269
2311
|
flushEngagement() {
|
|
2270
2312
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
2271
2313
|
const ms = this.engagement?.consume() ?? 0;
|
|
2272
|
-
if (ms > 0)
|
|
2314
|
+
if (ms > 0) {
|
|
2315
|
+
this.track("deepdots_user_engagement", { engagement_time_msec: ms });
|
|
2316
|
+
this.lastEngagementAt = Date.now();
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
/** Tick del flush periódico: latido de engagement si toca, y envío de lo acumulado. */
|
|
2320
|
+
onAnalyticsFlushTick() {
|
|
2321
|
+
if (this.sessionOpen && this.isDocumentVisible() && Date.now() - this.lastEngagementAt >= ANALYTICS_HEARTBEAT_MS) {
|
|
2322
|
+
this.flushEngagement();
|
|
2323
|
+
}
|
|
2324
|
+
this.flushAnalytics();
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* La pestaña vuelve a verse. Tras más de ANALYTICS_SESSION_TIMEOUT_MS oculta, la sesión
|
|
2328
|
+
* anterior termina y empieza otra: seguir con el mismo sessionId mezclaba dos visitas y,
|
|
2329
|
+
* si el backend ya la había cerrado por inactividad, la partía en dos feedbacks.
|
|
2330
|
+
* - Oculta menos de ANALYTICS_SESSION_DISCARD_MS: el backend aún la tiene abierta → se
|
|
2331
|
+
* cierra con normalidad (page_view de la pantalla, session_end `idle_timeout`, completed).
|
|
2332
|
+
* - Más: ya la cerró el backend → se descarta sin enviar nada.
|
|
2333
|
+
*/
|
|
2334
|
+
onDocumentVisible() {
|
|
2335
|
+
const hiddenFor = this.hiddenAt === null ? 0 : Date.now() - this.hiddenAt;
|
|
2336
|
+
this.hiddenAt = null;
|
|
2337
|
+
if (!this.sessionOpen) return;
|
|
2338
|
+
if (hiddenFor < ANALYTICS_SESSION_TIMEOUT_MS) {
|
|
2339
|
+
this.engagement?.resume();
|
|
2340
|
+
return;
|
|
2341
|
+
}
|
|
2342
|
+
if (hiddenFor < ANALYTICS_SESSION_DISCARD_MS) {
|
|
2343
|
+
this.closeSession("idle_timeout");
|
|
2344
|
+
} else {
|
|
2345
|
+
this.discardSession();
|
|
2346
|
+
}
|
|
2347
|
+
this.openSession();
|
|
2348
|
+
}
|
|
2349
|
+
/** Olvida la sesión abierta sin enviar nada (ver onDocumentVisible). */
|
|
2350
|
+
discardSession() {
|
|
2351
|
+
this.sessionOpen = false;
|
|
2352
|
+
this.navObserver?.discard();
|
|
2353
|
+
this.analytics?.discardSession(this.analyticsIdentity());
|
|
2354
|
+
this.engagement?.consume();
|
|
2355
|
+
this.engagement?.pause();
|
|
2356
|
+
this.analyticsFeedbackSessionId = void 0;
|
|
2357
|
+
this.tracking?.setSessionId(null);
|
|
2358
|
+
this.log("tracking \xB7 session discarded after", ANALYTICS_SESSION_DISCARD_MS / 6e4, "min hidden");
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Geolocalización por IP (país/ciudad para analytics). La caché persistente es local y se
|
|
2362
|
+
* aplica siempre que `geolocation` no esté desactivado. El lookup a terceros (ipapi.co →
|
|
2363
|
+
* ipwho.is → ipinfo.io, fallback con timeout) solo se hace si el dato se va a ENVIAR:
|
|
2364
|
+
* analytics configurado + tracking activo + caché ausente o caducada. Una vez por instancia.
|
|
2365
|
+
*/
|
|
2366
|
+
resolveGeo() {
|
|
2367
|
+
const storage = this.storage;
|
|
2368
|
+
if (!this.geoEnabled || !storage || !this.analytics) return;
|
|
2369
|
+
const cachedGeo = readCachedGeo(storage, Date.now());
|
|
2370
|
+
if (cachedGeo) {
|
|
2371
|
+
this.analytics.updateDevice(cachedGeo);
|
|
2372
|
+
return;
|
|
2373
|
+
}
|
|
2374
|
+
if (!this.geoWanted || this.geoLookupStarted) return;
|
|
2375
|
+
if (!this.tracking?.isTrackingEnabled()) return;
|
|
2376
|
+
this.geoLookupStarted = true;
|
|
2377
|
+
fetchGeo().then((geo) => {
|
|
2378
|
+
if (geo) {
|
|
2379
|
+
this.analytics?.updateDevice(geo);
|
|
2380
|
+
writeCachedGeo(storage, geo, Date.now());
|
|
2381
|
+
}
|
|
2382
|
+
}).catch(() => {
|
|
2383
|
+
});
|
|
2273
2384
|
}
|
|
2274
2385
|
analyticsIdentity() {
|
|
2275
2386
|
return {
|
|
@@ -2279,8 +2390,8 @@ var DeepdotsPopups = class {
|
|
|
2279
2390
|
}
|
|
2280
2391
|
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
2281
2392
|
setupAnalyticsFlush() {
|
|
2282
|
-
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
2283
2393
|
this.startAnalyticsFlushTimer();
|
|
2394
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
2284
2395
|
window.addEventListener("pagehide", () => {
|
|
2285
2396
|
clearInterval(this.analyticsFlushTimer);
|
|
2286
2397
|
this.closeSession("page_hide");
|
|
@@ -2295,14 +2406,15 @@ var DeepdotsPopups = class {
|
|
|
2295
2406
|
this.flushEngagement();
|
|
2296
2407
|
this.engagement?.pause();
|
|
2297
2408
|
this.flushAnalytics();
|
|
2409
|
+
this.hiddenAt = Date.now();
|
|
2298
2410
|
} else if (document.visibilityState === "visible") {
|
|
2299
|
-
|
|
2411
|
+
this.onDocumentVisible();
|
|
2300
2412
|
}
|
|
2301
2413
|
});
|
|
2302
2414
|
}
|
|
2303
2415
|
startAnalyticsFlushTimer() {
|
|
2304
2416
|
clearInterval(this.analyticsFlushTimer);
|
|
2305
|
-
this.analyticsFlushTimer = setInterval(() => this.
|
|
2417
|
+
this.analyticsFlushTimer = setInterval(() => this.onAnalyticsFlushTick(), ANALYTICS_FLUSH_INTERVAL_MS);
|
|
2306
2418
|
}
|
|
2307
2419
|
/** Enable auto-launch functionality with configured triggers */
|
|
2308
2420
|
autoLaunch() {
|
|
@@ -2806,7 +2918,7 @@ var DeepdotsPopups = class {
|
|
|
2806
2918
|
}
|
|
2807
2919
|
if (!this.popupContainer) return;
|
|
2808
2920
|
const container = this.popupContainer;
|
|
2809
|
-
void import("./renderPopup-
|
|
2921
|
+
void import("./renderPopup-3CZ6WTXF.mjs").then(({ renderPopup }) => {
|
|
2810
2922
|
renderPopup(
|
|
2811
2923
|
container,
|
|
2812
2924
|
surveyId,
|