@magicfeedback/popup-sdk 1.16.1 → 1.17.0
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 +53 -20
- package/dist/index.d.ts +53 -20
- package/dist/index.js +163 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +163 -64
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +16 -4
- package/dist/react-native.d.ts +16 -4
- package/dist/react-native.js +163 -64
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +163 -64
- package/dist/react-native.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react-native.d.mts
CHANGED
|
@@ -87,9 +87,9 @@ interface AnalyticsEnvelope {
|
|
|
87
87
|
*
|
|
88
88
|
* La analítica se envía como un Feedback del modelo del Surveys SDK, agrupado por una
|
|
89
89
|
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false`; el
|
|
90
|
-
* backend
|
|
91
|
-
* app a background, cambio de usuario) va con
|
|
92
|
-
*
|
|
90
|
+
* backend agrupa los lotes por `sessionId`, que genera el SDK al abrir cada sesión. El
|
|
91
|
+
* ÚLTIMO lote de una sesión (cierre de página, app a background, cambio de usuario) va con
|
|
92
|
+
* `completed:true`: cierra el registro y el lote siguiente abre otro con un sessionId nuevo.
|
|
93
93
|
* `feedback.finished` se queda siempre en `false` (no es la señal de cierre acordada).
|
|
94
94
|
*
|
|
95
95
|
* Encoding:
|
|
@@ -445,6 +445,8 @@ declare class DeepdotsPopups {
|
|
|
445
445
|
private analyticsFlushTimer;
|
|
446
446
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
447
447
|
private crashReporter;
|
|
448
|
+
/** ErrorUtils de RN recibido del host (o del Provider); se engancha en cuanto haya consentimiento. */
|
|
449
|
+
private rnErrorUtils;
|
|
448
450
|
/** Protecciones del funnel de Messaging (#18–22). Vigencia de sesión: se reinicia en init(). */
|
|
449
451
|
private messageGuard;
|
|
450
452
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
@@ -513,8 +515,18 @@ declare class DeepdotsPopups {
|
|
|
513
515
|
setMetric(key: string, value: string | number | boolean): void;
|
|
514
516
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
515
517
|
reportError(error: unknown, options?: ReportErrorOptions): void;
|
|
516
|
-
/**
|
|
518
|
+
/**
|
|
519
|
+
* Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. Con tracking off
|
|
520
|
+
* se recuerda y se engancha cuando se conceda el consentimiento (`setTrackingEnabled(true)`).
|
|
521
|
+
*/
|
|
517
522
|
installReactNativeCrashHandler(errorUtils: ReactNativeErrorUtils): void;
|
|
523
|
+
/**
|
|
524
|
+
* Pone los handlers de errores no capturados: `window` en web y `ErrorUtils` en RN (el que
|
|
525
|
+
* pasó el host o, si no pasó ninguno, `globalThis.ErrorUtils`, para que un `init()` sin
|
|
526
|
+
* `setupReactNative` también capture). Solo con consentimiento; idempotente, así que se
|
|
527
|
+
* llama en `init()` y cada vez que se activa el tracking.
|
|
528
|
+
*/
|
|
529
|
+
private installCrashHandlers;
|
|
518
530
|
/**
|
|
519
531
|
* Info interna del usuario que solo conoce el host (idioma, edad, plan…), persistida en el
|
|
520
532
|
* Contact del backend para segmentación/targeting de popups. Identificada por el `userId` del
|
package/dist/react-native.d.ts
CHANGED
|
@@ -87,9 +87,9 @@ interface AnalyticsEnvelope {
|
|
|
87
87
|
*
|
|
88
88
|
* La analítica se envía como un Feedback del modelo del Surveys SDK, agrupado por una
|
|
89
89
|
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false`; el
|
|
90
|
-
* backend
|
|
91
|
-
* app a background, cambio de usuario) va con
|
|
92
|
-
*
|
|
90
|
+
* backend agrupa los lotes por `sessionId`, que genera el SDK al abrir cada sesión. El
|
|
91
|
+
* ÚLTIMO lote de una sesión (cierre de página, app a background, cambio de usuario) va con
|
|
92
|
+
* `completed:true`: cierra el registro y el lote siguiente abre otro con un sessionId nuevo.
|
|
93
93
|
* `feedback.finished` se queda siempre en `false` (no es la señal de cierre acordada).
|
|
94
94
|
*
|
|
95
95
|
* Encoding:
|
|
@@ -445,6 +445,8 @@ declare class DeepdotsPopups {
|
|
|
445
445
|
private analyticsFlushTimer;
|
|
446
446
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
447
447
|
private crashReporter;
|
|
448
|
+
/** ErrorUtils de RN recibido del host (o del Provider); se engancha en cuanto haya consentimiento. */
|
|
449
|
+
private rnErrorUtils;
|
|
448
450
|
/** Protecciones del funnel de Messaging (#18–22). Vigencia de sesión: se reinicia en init(). */
|
|
449
451
|
private messageGuard;
|
|
450
452
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
@@ -513,8 +515,18 @@ declare class DeepdotsPopups {
|
|
|
513
515
|
setMetric(key: string, value: string | number | boolean): void;
|
|
514
516
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
515
517
|
reportError(error: unknown, options?: ReportErrorOptions): void;
|
|
516
|
-
/**
|
|
518
|
+
/**
|
|
519
|
+
* Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. Con tracking off
|
|
520
|
+
* se recuerda y se engancha cuando se conceda el consentimiento (`setTrackingEnabled(true)`).
|
|
521
|
+
*/
|
|
517
522
|
installReactNativeCrashHandler(errorUtils: ReactNativeErrorUtils): void;
|
|
523
|
+
/**
|
|
524
|
+
* Pone los handlers de errores no capturados: `window` en web y `ErrorUtils` en RN (el que
|
|
525
|
+
* pasó el host o, si no pasó ninguno, `globalThis.ErrorUtils`, para que un `init()` sin
|
|
526
|
+
* `setupReactNative` también capture). Solo con consentimiento; idempotente, así que se
|
|
527
|
+
* llama en `init()` y cada vez que se activa el tracking.
|
|
528
|
+
*/
|
|
529
|
+
private installCrashHandlers;
|
|
518
530
|
/**
|
|
519
531
|
* Info interna del usuario que solo conoce el host (idioma, edad, plan…), persistida en el
|
|
520
532
|
* Contact del backend para segmentación/targeting de popups. Identificada por el `userId` del
|
package/dist/react-native.js
CHANGED
|
@@ -4851,97 +4851,166 @@ async function safeBodyText(res) {
|
|
|
4851
4851
|
return "";
|
|
4852
4852
|
}
|
|
4853
4853
|
}
|
|
4854
|
+
var PENDING_MAX = 50;
|
|
4855
|
+
var PENDING_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
4856
|
+
var POST_TIMEOUT_MS = 2e4;
|
|
4857
|
+
function pendingKey(integration) {
|
|
4858
|
+
return `__deepdots_analytics_pending__:${integration}`;
|
|
4859
|
+
}
|
|
4860
|
+
function generateSessionId() {
|
|
4861
|
+
const c = globalThis.crypto;
|
|
4862
|
+
if (typeof c?.randomUUID === "function") return c.randomUUID();
|
|
4863
|
+
const b = new Uint8Array(16);
|
|
4864
|
+
if (typeof c?.getRandomValues === "function") c.getRandomValues(b);
|
|
4865
|
+
else for (let i = 0; i < 16; i++) b[i] = Math.floor(Math.random() * 256);
|
|
4866
|
+
b[6] = b[6] & 15 | 64;
|
|
4867
|
+
b[8] = b[8] & 63 | 128;
|
|
4868
|
+
const h = Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
|
|
4869
|
+
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20)}`;
|
|
4870
|
+
}
|
|
4854
4871
|
function createFeedbackSink(options) {
|
|
4855
|
-
let feedbackSessionId = options.initialSessionId || void 0;
|
|
4856
|
-
let firstPostInFlight = null;
|
|
4857
|
-
let generation = 0;
|
|
4858
4872
|
const url = `${options.baseUrl}/sdk/feedback`;
|
|
4859
|
-
const
|
|
4860
|
-
|
|
4873
|
+
const newSessionId = options.newSessionId ?? generateSessionId;
|
|
4874
|
+
const now = options.now ?? (() => Date.now());
|
|
4875
|
+
const storageKey = pendingKey(options.keys.integration);
|
|
4876
|
+
let feedbackSessionId = options.initialSessionId || void 0;
|
|
4877
|
+
let announcedId = feedbackSessionId;
|
|
4878
|
+
const pending2 = loadPending();
|
|
4879
|
+
let draining = null;
|
|
4880
|
+
function loadPending() {
|
|
4881
|
+
if (!options.storage) return [];
|
|
4882
|
+
try {
|
|
4883
|
+
const raw = options.storage.getItem(storageKey);
|
|
4884
|
+
const list = raw ? JSON.parse(raw) : [];
|
|
4885
|
+
return Array.isArray(list) ? list.filter((p) => p?.body && now() - p.at <= PENDING_MAX_AGE_MS) : [];
|
|
4886
|
+
} catch {
|
|
4887
|
+
return [];
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4890
|
+
function savePending() {
|
|
4891
|
+
if (!options.storage) return;
|
|
4892
|
+
try {
|
|
4893
|
+
if (pending2.length) options.storage.setItem(storageKey, JSON.stringify(pending2));
|
|
4894
|
+
else options.storage.removeItem(storageKey);
|
|
4895
|
+
} catch {
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
function addPending(batch) {
|
|
4899
|
+
pending2.push(batch);
|
|
4900
|
+
if (pending2.length > PENDING_MAX) pending2.splice(0, pending2.length - PENDING_MAX);
|
|
4901
|
+
savePending();
|
|
4902
|
+
}
|
|
4903
|
+
function removePending(batch) {
|
|
4904
|
+
const i = pending2.indexOf(batch);
|
|
4905
|
+
if (i >= 0) pending2.splice(i, 1);
|
|
4906
|
+
savePending();
|
|
4907
|
+
}
|
|
4908
|
+
async function post(body, final) {
|
|
4861
4909
|
const json = JSON.stringify(body);
|
|
4862
4910
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
4863
4911
|
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
4864
4912
|
const f = options.fetchImpl ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
4865
4913
|
if (!f) {
|
|
4866
4914
|
options.log?.("[DeepdotsAnalytics] no fetch available; payload not sent", body);
|
|
4867
|
-
return;
|
|
4915
|
+
return "drop";
|
|
4868
4916
|
}
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4917
|
+
let timer;
|
|
4918
|
+
try {
|
|
4919
|
+
const request = f(url, {
|
|
4920
|
+
method: "POST",
|
|
4921
|
+
headers: { "Content-Type": "application/json" },
|
|
4922
|
+
body: json,
|
|
4923
|
+
// La API autentica por `publicKey` en el body y responde `Allow-Origin: *`: una
|
|
4924
|
+
// petición con credenciales fallaría el CORS. Explícito para no depender del default.
|
|
4925
|
+
credentials: "omit",
|
|
4926
|
+
// keepalive: el POST sobrevive a la navegación mientras el body sea pequeño.
|
|
4927
|
+
...small ? { keepalive: true } : {}
|
|
4928
|
+
});
|
|
4929
|
+
const timeout = new Promise((_, reject) => {
|
|
4930
|
+
timer = setTimeout(() => reject(new Error("timeout")), POST_TIMEOUT_MS);
|
|
4931
|
+
});
|
|
4932
|
+
const res = await Promise.race([request, timeout]);
|
|
4933
|
+
if (res.ok) return "ok";
|
|
4880
4934
|
const detail = await safeBodyText(res);
|
|
4881
4935
|
if (isRetryableStatus(res.status)) {
|
|
4882
|
-
|
|
4936
|
+
options.log?.(`[DeepdotsAnalytics] POST /sdk/feedback ${res.status} (retryable): ${detail}`);
|
|
4937
|
+
return "retry";
|
|
4883
4938
|
}
|
|
4884
4939
|
options.log?.(
|
|
4885
4940
|
`[DeepdotsAnalytics] POST /sdk/feedback rejected with ${res.status}; batch DISCARDED:`,
|
|
4886
4941
|
detail
|
|
4887
4942
|
);
|
|
4888
|
-
return;
|
|
4889
|
-
}
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
closedId = data?.sessionId ?? closedId;
|
|
4895
|
-
} catch {
|
|
4896
|
-
}
|
|
4897
|
-
try {
|
|
4898
|
-
if (closedId) options.onSessionClosed?.(closedId);
|
|
4899
|
-
} catch {
|
|
4900
|
-
}
|
|
4901
|
-
return;
|
|
4943
|
+
return "drop";
|
|
4944
|
+
} catch (error) {
|
|
4945
|
+
options.log?.("[DeepdotsAnalytics] POST /sdk/feedback failed (will retry):", error);
|
|
4946
|
+
return "retry";
|
|
4947
|
+
} finally {
|
|
4948
|
+
clearTimeout(timer);
|
|
4902
4949
|
}
|
|
4950
|
+
}
|
|
4951
|
+
function delivered(body) {
|
|
4952
|
+
const id = body.sessionId;
|
|
4953
|
+
if (!id) return;
|
|
4903
4954
|
try {
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
feedbackSessionId = data.sessionId;
|
|
4911
|
-
options.log?.("[DeepdotsAnalytics] feedbackSessionId cached:", feedbackSessionId);
|
|
4912
|
-
options.onSessionId?.(feedbackSessionId);
|
|
4955
|
+
if (body.completed) {
|
|
4956
|
+
options.onSessionClosed?.(id);
|
|
4957
|
+
} else if (id === feedbackSessionId && id !== announcedId) {
|
|
4958
|
+
announcedId = id;
|
|
4959
|
+
options.log?.("[DeepdotsAnalytics] feedback session open:", id);
|
|
4960
|
+
options.onSessionId?.(id);
|
|
4913
4961
|
}
|
|
4914
4962
|
} catch {
|
|
4915
4963
|
}
|
|
4916
|
-
}
|
|
4964
|
+
}
|
|
4965
|
+
async function send(batch, final, alreadyPending) {
|
|
4966
|
+
const result = await post(batch.body, final);
|
|
4967
|
+
if (result === "retry") {
|
|
4968
|
+
if (!alreadyPending) addPending(batch);
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
if (alreadyPending) removePending(batch);
|
|
4972
|
+
if (result === "ok") delivered(batch.body);
|
|
4973
|
+
}
|
|
4974
|
+
function drain() {
|
|
4975
|
+
const run = async () => {
|
|
4976
|
+
for (let i = 0; i < pending2.length; ) {
|
|
4977
|
+
const batch = pending2[i];
|
|
4978
|
+
await send(batch, false, true);
|
|
4979
|
+
if (pending2[i] === batch) return;
|
|
4980
|
+
}
|
|
4981
|
+
};
|
|
4982
|
+
const next = draining ? draining.then(run) : run();
|
|
4983
|
+
draining = next;
|
|
4984
|
+
void next.finally(() => {
|
|
4985
|
+
if (draining === next) draining = null;
|
|
4986
|
+
});
|
|
4987
|
+
return next;
|
|
4988
|
+
}
|
|
4989
|
+
if (pending2.length) {
|
|
4990
|
+
savePending();
|
|
4991
|
+
setTimeout(() => void drain(), 0);
|
|
4992
|
+
}
|
|
4917
4993
|
return async (envelope, meta) => {
|
|
4918
4994
|
if (meta?.resetSession) {
|
|
4919
4995
|
feedbackSessionId = void 0;
|
|
4920
|
-
firstPostInFlight = null;
|
|
4921
|
-
generation++;
|
|
4922
4996
|
options.onSessionReset?.();
|
|
4923
4997
|
return;
|
|
4924
4998
|
}
|
|
4925
4999
|
const final = meta?.final === true;
|
|
4926
5000
|
const sessionEnd = meta?.sessionEnd === true;
|
|
4927
|
-
if (!feedbackSessionId
|
|
4928
|
-
await firstPostInFlight;
|
|
4929
|
-
}
|
|
5001
|
+
if (!feedbackSessionId) feedbackSessionId = newSessionId();
|
|
4930
5002
|
const body = buildAnalyticsFeedbackBody(envelope, options.keys, feedbackSessionId, { sessionEnd });
|
|
4931
5003
|
options.log?.("[DeepdotsAnalytics] POST /sdk/feedback \u2192", body);
|
|
4932
|
-
const
|
|
5004
|
+
const batch = { body, at: now() };
|
|
4933
5005
|
if (sessionEnd) {
|
|
4934
5006
|
feedbackSessionId = void 0;
|
|
4935
|
-
firstPostInFlight = null;
|
|
4936
|
-
generation++;
|
|
4937
5007
|
options.onSessionReset?.();
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
() => void 0
|
|
4942
|
-
);
|
|
5008
|
+
addPending(batch);
|
|
5009
|
+
await drain();
|
|
5010
|
+
return;
|
|
4943
5011
|
}
|
|
4944
|
-
|
|
5012
|
+
const retries = pending2.length ? drain() : null;
|
|
5013
|
+
await Promise.all([retries, send(batch, final, false)]);
|
|
4945
5014
|
};
|
|
4946
5015
|
}
|
|
4947
5016
|
|
|
@@ -5361,6 +5430,10 @@ function crashRecordToParams(r) {
|
|
|
5361
5430
|
}
|
|
5362
5431
|
var CrashReporter = class {
|
|
5363
5432
|
constructor(options) {
|
|
5433
|
+
/** Los handlers de `window` ya están puestos: `install()` es idempotente. */
|
|
5434
|
+
this.windowInstalled = false;
|
|
5435
|
+
/** ErrorUtils ya enganchados: engancharlos dos veces capturaría cada error dos veces. */
|
|
5436
|
+
this.hookedErrorUtils = /* @__PURE__ */ new Set();
|
|
5364
5437
|
this.options = options;
|
|
5365
5438
|
this.now = options.now ?? (() => Date.now());
|
|
5366
5439
|
}
|
|
@@ -5436,9 +5509,11 @@ var CrashReporter = class {
|
|
|
5436
5509
|
}
|
|
5437
5510
|
return queue;
|
|
5438
5511
|
}
|
|
5439
|
-
/** Instala los handlers globales de errores no capturados (no-op sin `window`). */
|
|
5512
|
+
/** Instala los handlers globales de errores no capturados (no-op sin `window`). Idempotente. */
|
|
5440
5513
|
install() {
|
|
5514
|
+
if (this.windowInstalled) return;
|
|
5441
5515
|
if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
|
|
5516
|
+
this.windowInstalled = true;
|
|
5442
5517
|
window.addEventListener("error", (e) => {
|
|
5443
5518
|
if (!this.isEnabled()) return;
|
|
5444
5519
|
this.captureUnhandled(e.error ?? e.message ?? "error");
|
|
@@ -5448,8 +5523,10 @@ var CrashReporter = class {
|
|
|
5448
5523
|
this.captureUnhandled(e.reason ?? "unhandledrejection");
|
|
5449
5524
|
});
|
|
5450
5525
|
}
|
|
5451
|
-
/** Engancha `global.ErrorUtils` de RN (no hay `window`): persiste y encadena al handler previo. */
|
|
5526
|
+
/** Engancha `global.ErrorUtils` de RN (no hay `window`): persiste y encadena al handler previo. Idempotente por instancia de ErrorUtils. */
|
|
5452
5527
|
installReactNative(errorUtils) {
|
|
5528
|
+
if (this.hookedErrorUtils.has(errorUtils)) return;
|
|
5529
|
+
this.hookedErrorUtils.add(errorUtils);
|
|
5453
5530
|
const previous = errorUtils.getGlobalHandler?.();
|
|
5454
5531
|
errorUtils.setGlobalHandler((error, isFatal) => {
|
|
5455
5532
|
if (this.isEnabled()) this.captureUnhandled(error);
|
|
@@ -5665,6 +5742,8 @@ var DeepdotsPopups = class {
|
|
|
5665
5742
|
this.analyticsFlushTimer = void 0;
|
|
5666
5743
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
5667
5744
|
this.crashReporter = null;
|
|
5745
|
+
/** ErrorUtils de RN recibido del host (o del Provider); se engancha en cuanto haya consentimiento. */
|
|
5746
|
+
this.rnErrorUtils = null;
|
|
5668
5747
|
/** Protecciones del funnel de Messaging (#18–22). Vigencia de sesión: se reinicia en init(). */
|
|
5669
5748
|
this.messageGuard = new MessageGuard();
|
|
5670
5749
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
@@ -5765,6 +5844,10 @@ var DeepdotsPopups = class {
|
|
|
5765
5844
|
keys: config.analytics,
|
|
5766
5845
|
log: (...a) => this.log(...a),
|
|
5767
5846
|
initialSessionId: resumable?.sessionId,
|
|
5847
|
+
// En móvil (RN) la app puede morir con el lote de cierre sin entregar: se
|
|
5848
|
+
// persiste y se reenvía en el arranque siguiente. En web el cierre sale con
|
|
5849
|
+
// `keepalive` y varias pestañas compartirían el mismo storage.
|
|
5850
|
+
storage: (config.platform ?? "web") !== "web" ? storage : void 0,
|
|
5768
5851
|
onSessionId: (id) => {
|
|
5769
5852
|
this.analyticsFeedbackSessionId = id;
|
|
5770
5853
|
this.notifyFeedbackSession(id, "open");
|
|
@@ -5800,9 +5883,7 @@ var DeepdotsPopups = class {
|
|
|
5800
5883
|
now: () => Date.now(),
|
|
5801
5884
|
enabled: () => this.tracking?.isTrackingEnabled() ?? false
|
|
5802
5885
|
});
|
|
5803
|
-
|
|
5804
|
-
this.crashReporter.install();
|
|
5805
|
-
}
|
|
5886
|
+
this.installCrashHandlers();
|
|
5806
5887
|
this.geoEnabled = config.geolocation ?? true;
|
|
5807
5888
|
this.geoWanted = this.geoEnabled && !!config.analytics;
|
|
5808
5889
|
this.resolveGeo();
|
|
@@ -5871,6 +5952,7 @@ var DeepdotsPopups = class {
|
|
|
5871
5952
|
if (!enabled) this.closeSession("tracking_disabled");
|
|
5872
5953
|
this.tracking?.setTrackingEnabled(enabled);
|
|
5873
5954
|
if (enabled) this.openSession("tracking_enabled");
|
|
5955
|
+
if (enabled) this.installCrashHandlers();
|
|
5874
5956
|
if (enabled) this.resolveGeo();
|
|
5875
5957
|
this.log("tracking \xB7 setTrackingEnabled:", enabled, "\xB7 session_id:", this.tracking?.getSessionId() ?? null);
|
|
5876
5958
|
}
|
|
@@ -5901,10 +5983,27 @@ var DeepdotsPopups = class {
|
|
|
5901
5983
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
5902
5984
|
this.crashReporter?.reportError(error, options);
|
|
5903
5985
|
}
|
|
5904
|
-
/**
|
|
5986
|
+
/**
|
|
5987
|
+
* Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. Con tracking off
|
|
5988
|
+
* se recuerda y se engancha cuando se conceda el consentimiento (`setTrackingEnabled(true)`).
|
|
5989
|
+
*/
|
|
5905
5990
|
installReactNativeCrashHandler(errorUtils) {
|
|
5906
|
-
|
|
5907
|
-
this.
|
|
5991
|
+
this.rnErrorUtils = errorUtils;
|
|
5992
|
+
this.installCrashHandlers();
|
|
5993
|
+
}
|
|
5994
|
+
/**
|
|
5995
|
+
* Pone los handlers de errores no capturados: `window` en web y `ErrorUtils` en RN (el que
|
|
5996
|
+
* pasó el host o, si no pasó ninguno, `globalThis.ErrorUtils`, para que un `init()` sin
|
|
5997
|
+
* `setupReactNative` también capture). Solo con consentimiento; idempotente, así que se
|
|
5998
|
+
* llama en `init()` y cada vez que se activa el tracking.
|
|
5999
|
+
*/
|
|
6000
|
+
installCrashHandlers() {
|
|
6001
|
+
if (!this.crashReporter || !this.tracking?.isTrackingEnabled()) return;
|
|
6002
|
+
this.crashReporter.install();
|
|
6003
|
+
const errorUtils = this.rnErrorUtils ?? globalThis.ErrorUtils;
|
|
6004
|
+
if (errorUtils && typeof errorUtils.setGlobalHandler === "function") {
|
|
6005
|
+
this.crashReporter.installReactNative(errorUtils);
|
|
6006
|
+
}
|
|
5908
6007
|
}
|
|
5909
6008
|
/**
|
|
5910
6009
|
* Info interna del usuario que solo conoce el host (idioma, edad, plan…), persistida en el
|