@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.d.mts
CHANGED
|
@@ -507,12 +507,14 @@ declare class DeepdotsPopups {
|
|
|
507
507
|
* se llama en init(), al volver a foreground y al conceder el consentimiento.
|
|
508
508
|
*/
|
|
509
509
|
private openSession;
|
|
510
|
+
/** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
|
|
511
|
+
private isDocumentVisible;
|
|
510
512
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
511
513
|
previewAnalytics(): AnalyticsEnvelope;
|
|
512
514
|
/**
|
|
513
515
|
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
514
|
-
* `final: true` (cierre de página/app)
|
|
515
|
-
*
|
|
516
|
+
* `final: true` (cierre de página/app): el lote no espera al primer POST en vuelo, porque
|
|
517
|
+
* el documento se muere; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
516
518
|
*/
|
|
517
519
|
flushAnalytics(options?: {
|
|
518
520
|
final?: boolean;
|
|
@@ -523,6 +525,7 @@ declare class DeepdotsPopups {
|
|
|
523
525
|
private analyticsIdentity;
|
|
524
526
|
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
525
527
|
private setupAnalyticsFlush;
|
|
528
|
+
private startAnalyticsFlushTimer;
|
|
526
529
|
/** Enable auto-launch functionality with configured triggers */
|
|
527
530
|
autoLaunch(): void;
|
|
528
531
|
/** Inicia los triggers configurados */
|
|
@@ -602,11 +605,18 @@ declare class DeepdotsPopups {
|
|
|
602
605
|
private mapPopupTriggerType;
|
|
603
606
|
private markSurveyProgress;
|
|
604
607
|
/**
|
|
605
|
-
*
|
|
606
|
-
*
|
|
608
|
+
* Fusiona el estado de redisplay del storage con el de memoria: por cada popup/survey gana
|
|
609
|
+
* la entrada MÁS RECIENTE. Fusionar y no sustituir es lo que hace convivir a varias
|
|
610
|
+
* pestañas sobre el mismo `localStorage`: se llama en el `init()`, antes de cada decisión
|
|
611
|
+
* de mostrar y antes de cada escritura. `answeredSurveys` se reconstruye desde las
|
|
612
|
+
* entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
607
613
|
*/
|
|
608
614
|
private loadPopupState;
|
|
609
|
-
/**
|
|
615
|
+
/**
|
|
616
|
+
* Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria.
|
|
617
|
+
* Fusiona antes de escribir: escribir solo la foto en memoria borraba lo que otra pestaña
|
|
618
|
+
* hubiese guardado desde nuestro `init()`.
|
|
619
|
+
*/
|
|
610
620
|
private persistPopupState;
|
|
611
621
|
private isPopupDefinition;
|
|
612
622
|
private isPopupTrigger;
|
package/dist/react-native.d.ts
CHANGED
|
@@ -507,12 +507,14 @@ declare class DeepdotsPopups {
|
|
|
507
507
|
* se llama en init(), al volver a foreground y al conceder el consentimiento.
|
|
508
508
|
*/
|
|
509
509
|
private openSession;
|
|
510
|
+
/** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
|
|
511
|
+
private isDocumentVisible;
|
|
510
512
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
511
513
|
previewAnalytics(): AnalyticsEnvelope;
|
|
512
514
|
/**
|
|
513
515
|
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
514
|
-
* `final: true` (cierre de página/app)
|
|
515
|
-
*
|
|
516
|
+
* `final: true` (cierre de página/app): el lote no espera al primer POST en vuelo, porque
|
|
517
|
+
* el documento se muere; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
516
518
|
*/
|
|
517
519
|
flushAnalytics(options?: {
|
|
518
520
|
final?: boolean;
|
|
@@ -523,6 +525,7 @@ declare class DeepdotsPopups {
|
|
|
523
525
|
private analyticsIdentity;
|
|
524
526
|
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
525
527
|
private setupAnalyticsFlush;
|
|
528
|
+
private startAnalyticsFlushTimer;
|
|
526
529
|
/** Enable auto-launch functionality with configured triggers */
|
|
527
530
|
autoLaunch(): void;
|
|
528
531
|
/** Inicia los triggers configurados */
|
|
@@ -602,11 +605,18 @@ declare class DeepdotsPopups {
|
|
|
602
605
|
private mapPopupTriggerType;
|
|
603
606
|
private markSurveyProgress;
|
|
604
607
|
/**
|
|
605
|
-
*
|
|
606
|
-
*
|
|
608
|
+
* Fusiona el estado de redisplay del storage con el de memoria: por cada popup/survey gana
|
|
609
|
+
* la entrada MÁS RECIENTE. Fusionar y no sustituir es lo que hace convivir a varias
|
|
610
|
+
* pestañas sobre el mismo `localStorage`: se llama en el `init()`, antes de cada decisión
|
|
611
|
+
* de mostrar y antes de cada escritura. `answeredSurveys` se reconstruye desde las
|
|
612
|
+
* entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
607
613
|
*/
|
|
608
614
|
private loadPopupState;
|
|
609
|
-
/**
|
|
615
|
+
/**
|
|
616
|
+
* Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria.
|
|
617
|
+
* Fusiona antes de escribir: escribir solo la foto en memoria borraba lo que otra pestaña
|
|
618
|
+
* hubiese guardado desde nuestro `init()`.
|
|
619
|
+
*/
|
|
610
620
|
private persistPopupState;
|
|
611
621
|
private isPopupDefinition;
|
|
612
622
|
private isPopupTrigger;
|
package/dist/react-native.js
CHANGED
|
@@ -4364,14 +4364,7 @@ function createFeedbackSink(options) {
|
|
|
4364
4364
|
const post = async (body, final, sessionEnd = false) => {
|
|
4365
4365
|
const json = JSON.stringify(body);
|
|
4366
4366
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
4367
|
-
if (final
|
|
4368
|
-
const payload = typeof Blob !== "undefined" ? new Blob([json], { type: "application/json" }) : json;
|
|
4369
|
-
if (options.sendBeaconImpl(url, payload)) {
|
|
4370
|
-
options.log?.("[DeepdotsAnalytics] final flush via sendBeacon");
|
|
4371
|
-
return;
|
|
4372
|
-
}
|
|
4373
|
-
options.log?.("[DeepdotsAnalytics] sendBeacon rejected the batch; falling back to fetch");
|
|
4374
|
-
}
|
|
4367
|
+
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
4375
4368
|
const f = options.fetchImpl ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
4376
4369
|
if (!f) {
|
|
4377
4370
|
options.log?.("[DeepdotsAnalytics] no fetch available; payload not sent", body);
|
|
@@ -4381,6 +4374,9 @@ function createFeedbackSink(options) {
|
|
|
4381
4374
|
method: "POST",
|
|
4382
4375
|
headers: { "Content-Type": "application/json" },
|
|
4383
4376
|
body: json,
|
|
4377
|
+
// La API autentica por `publicKey` en el body y responde `Allow-Origin: *`: una
|
|
4378
|
+
// petición con credenciales fallaría el CORS. Explícito para no depender del default.
|
|
4379
|
+
credentials: "omit",
|
|
4384
4380
|
// keepalive: el POST sobrevive a la navegación mientras el body sea pequeño.
|
|
4385
4381
|
...small ? { keepalive: true } : {}
|
|
4386
4382
|
});
|
|
@@ -4473,6 +4469,15 @@ var NavigationObserver = class {
|
|
|
4473
4469
|
this.closeCurrent();
|
|
4474
4470
|
this.currentScreen = null;
|
|
4475
4471
|
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Retoma el seguimiento en la pantalla actual tras un `stop()`, cuando se abre una sesión
|
|
4474
|
+
* nueva sin navegar (cambio de usuario, vuelta de la bfcache). No-op si nunca se instaló
|
|
4475
|
+
* (navegación manual por `setScreen`, RN) o si ya hay pantalla en curso.
|
|
4476
|
+
*/
|
|
4477
|
+
restart() {
|
|
4478
|
+
if (!this.installed || this.currentScreen != null || typeof window === "undefined") return;
|
|
4479
|
+
this.begin(window.location.href);
|
|
4480
|
+
}
|
|
4476
4481
|
closeCurrent() {
|
|
4477
4482
|
if (this.currentScreen == null) return;
|
|
4478
4483
|
const exit = this.now();
|
|
@@ -5116,8 +5121,6 @@ var DeepdotsPopups = class {
|
|
|
5116
5121
|
baseUrl: this.baseUrl,
|
|
5117
5122
|
keys: config.analytics,
|
|
5118
5123
|
log: (...a) => this.log(...a),
|
|
5119
|
-
// sendBeacon: único transporte que sobrevive al cierre de la página.
|
|
5120
|
-
sendBeaconImpl: typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function" ? (url, body) => navigator.sendBeacon(url, body) : void 0,
|
|
5121
5124
|
onSessionId: (id) => {
|
|
5122
5125
|
this.analyticsFeedbackSessionId = id;
|
|
5123
5126
|
},
|
|
@@ -5165,7 +5168,6 @@ var DeepdotsPopups = class {
|
|
|
5165
5168
|
this.navObserver.onVisit((v) => this.track("deepdots_page_view", { screen: v.screen, duration_seconds: v.durationSeconds }));
|
|
5166
5169
|
this.navObserver.install();
|
|
5167
5170
|
this.engagement = new EngagementTracker();
|
|
5168
|
-
this.engagement.resume();
|
|
5169
5171
|
this.setupAnalyticsFlush();
|
|
5170
5172
|
this.openSession();
|
|
5171
5173
|
const pendingCrashes = this.crashReporter.drainPendingCrashes();
|
|
@@ -5384,6 +5386,7 @@ var DeepdotsPopups = class {
|
|
|
5384
5386
|
this.navStarted = false;
|
|
5385
5387
|
this.analytics?.exitAllMiniServices();
|
|
5386
5388
|
this.flushEngagement();
|
|
5389
|
+
this.engagement?.pause();
|
|
5387
5390
|
this.track("deepdots_session_end", { reason });
|
|
5388
5391
|
this.flushAnalytics({ final: reason === "page_hide", sessionEnd: true });
|
|
5389
5392
|
this.analyticsFeedbackSessionId = void 0;
|
|
@@ -5399,6 +5402,12 @@ var DeepdotsPopups = class {
|
|
|
5399
5402
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
5400
5403
|
this.sessionOpen = true;
|
|
5401
5404
|
this.track("deepdots_session_start", {});
|
|
5405
|
+
this.navObserver?.restart();
|
|
5406
|
+
if (this.isDocumentVisible()) this.engagement?.resume();
|
|
5407
|
+
}
|
|
5408
|
+
/** Web: si la pestaña se ve. Sin `document` (RN) manda AppState vía onForeground/onBackground. */
|
|
5409
|
+
isDocumentVisible() {
|
|
5410
|
+
return typeof document === "undefined" || document.visibilityState !== "hidden";
|
|
5402
5411
|
}
|
|
5403
5412
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
5404
5413
|
previewAnalytics() {
|
|
@@ -5411,8 +5420,8 @@ var DeepdotsPopups = class {
|
|
|
5411
5420
|
}
|
|
5412
5421
|
/**
|
|
5413
5422
|
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
5414
|
-
* `final: true` (cierre de página/app)
|
|
5415
|
-
*
|
|
5423
|
+
* `final: true` (cierre de página/app): el lote no espera al primer POST en vuelo, porque
|
|
5424
|
+
* el documento se muere; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
5416
5425
|
*/
|
|
5417
5426
|
flushAnalytics(options) {
|
|
5418
5427
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
@@ -5433,21 +5442,30 @@ var DeepdotsPopups = class {
|
|
|
5433
5442
|
/** Flush automático al ocultar/cerrar la página (no perder el lote pendiente). */
|
|
5434
5443
|
setupAnalyticsFlush() {
|
|
5435
5444
|
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
5436
|
-
this.
|
|
5445
|
+
this.startAnalyticsFlushTimer();
|
|
5437
5446
|
window.addEventListener("pagehide", () => {
|
|
5438
5447
|
clearInterval(this.analyticsFlushTimer);
|
|
5439
5448
|
this.closeSession("page_hide");
|
|
5440
5449
|
});
|
|
5450
|
+
window.addEventListener("pageshow", (event) => {
|
|
5451
|
+
if (!event.persisted) return;
|
|
5452
|
+
this.startAnalyticsFlushTimer();
|
|
5453
|
+
this.openSession();
|
|
5454
|
+
});
|
|
5441
5455
|
document.addEventListener("visibilitychange", () => {
|
|
5442
5456
|
if (document.visibilityState === "hidden") {
|
|
5443
5457
|
this.flushEngagement();
|
|
5444
5458
|
this.engagement?.pause();
|
|
5445
5459
|
this.flushAnalytics();
|
|
5446
5460
|
} else if (document.visibilityState === "visible") {
|
|
5447
|
-
this.engagement?.resume();
|
|
5461
|
+
if (this.sessionOpen) this.engagement?.resume();
|
|
5448
5462
|
}
|
|
5449
5463
|
});
|
|
5450
5464
|
}
|
|
5465
|
+
startAnalyticsFlushTimer() {
|
|
5466
|
+
clearInterval(this.analyticsFlushTimer);
|
|
5467
|
+
this.analyticsFlushTimer = setInterval(() => this.flushAnalytics(), ANALYTICS_FLUSH_INTERVAL_MS);
|
|
5468
|
+
}
|
|
5451
5469
|
/** Enable auto-launch functionality with configured triggers */
|
|
5452
5470
|
autoLaunch() {
|
|
5453
5471
|
if (!this.initialized) {
|
|
@@ -5541,6 +5559,7 @@ var DeepdotsPopups = class {
|
|
|
5541
5559
|
this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
|
|
5542
5560
|
}
|
|
5543
5561
|
shouldShow(def, pathUrl, skipPathCheck = false) {
|
|
5562
|
+
if (this.storage) this.loadPopupState(this.storage);
|
|
5544
5563
|
if (this.isPathExcluded(def, pathUrl)) {
|
|
5545
5564
|
return false;
|
|
5546
5565
|
}
|
|
@@ -6067,22 +6086,32 @@ var DeepdotsPopups = class {
|
|
|
6067
6086
|
this.persistPopupState();
|
|
6068
6087
|
}
|
|
6069
6088
|
/**
|
|
6070
|
-
*
|
|
6071
|
-
*
|
|
6089
|
+
* Fusiona el estado de redisplay del storage con el de memoria: por cada popup/survey gana
|
|
6090
|
+
* la entrada MÁS RECIENTE. Fusionar y no sustituir es lo que hace convivir a varias
|
|
6091
|
+
* pestañas sobre el mismo `localStorage`: se llama en el `init()`, antes de cada decisión
|
|
6092
|
+
* de mostrar y antes de cada escritura. `answeredSurveys` se reconstruye desde las
|
|
6093
|
+
* entradas COMPLETED: es exactamente lo que persiste `markSurveyAnswered`.
|
|
6072
6094
|
*/
|
|
6073
6095
|
loadPopupState(storage) {
|
|
6074
6096
|
const state = readPopupState(storage);
|
|
6075
6097
|
Object.entries(state.lastShown).forEach(([popupId, timestamp]) => {
|
|
6076
|
-
this.lastShown.set(popupId, timestamp);
|
|
6098
|
+
if (timestamp > (this.lastShown.get(popupId) ?? -Infinity)) this.lastShown.set(popupId, timestamp);
|
|
6077
6099
|
});
|
|
6078
6100
|
Object.entries(state.progress).forEach(([surveyId, entry]) => {
|
|
6101
|
+
const current = this.surveyProgress.get(surveyId);
|
|
6102
|
+
if (current && current.timestamp >= entry.timestamp) return;
|
|
6079
6103
|
this.surveyProgress.set(surveyId, { status: entry.status, timestamp: entry.timestamp });
|
|
6080
6104
|
if (entry.status === "COMPLETED") this.answeredSurveys.add(surveyId);
|
|
6081
6105
|
});
|
|
6082
6106
|
}
|
|
6083
|
-
/**
|
|
6107
|
+
/**
|
|
6108
|
+
* Vuelca el estado de redisplay al storage. Sin storage (o bloqueado) degrada a memoria.
|
|
6109
|
+
* Fusiona antes de escribir: escribir solo la foto en memoria borraba lo que otra pestaña
|
|
6110
|
+
* hubiese guardado desde nuestro `init()`.
|
|
6111
|
+
*/
|
|
6084
6112
|
persistPopupState() {
|
|
6085
6113
|
if (!this.storage) return;
|
|
6114
|
+
this.loadPopupState(this.storage);
|
|
6086
6115
|
writePopupState(this.storage, {
|
|
6087
6116
|
lastShown: Object.fromEntries(this.lastShown),
|
|
6088
6117
|
progress: Object.fromEntries(this.surveyProgress)
|