@magicfeedback/popup-sdk 1.1.2 → 1.1.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/dist/index.d.mts +116 -3
- package/dist/index.d.ts +116 -3
- package/dist/index.js +232 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +232 -31
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +58 -2
- package/dist/react-native.d.ts +58 -2
- package/dist/react-native.js +229 -31
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +229 -31
- package/dist/react-native.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -387,8 +387,8 @@ var AnalyticsManager = class {
|
|
|
387
387
|
constructor(options = {}) {
|
|
388
388
|
this.events = [];
|
|
389
389
|
this.attributes = {};
|
|
390
|
-
|
|
391
|
-
this.
|
|
390
|
+
/** Mini-services activos: nombre → timestamp de entrada. El orden de inserción marca el "más reciente". */
|
|
391
|
+
this.activeMiniServices = /* @__PURE__ */ new Map();
|
|
392
392
|
this.sink = options.sink ?? dryRunSink;
|
|
393
393
|
this.now = options.now ?? (() => Date.now());
|
|
394
394
|
this.publicKey = options.publicKey;
|
|
@@ -409,24 +409,38 @@ var AnalyticsManager = class {
|
|
|
409
409
|
this.attributes[k] = String(v);
|
|
410
410
|
}
|
|
411
411
|
}
|
|
412
|
-
/**
|
|
412
|
+
/**
|
|
413
|
+
* Marca el inicio de un mini-service; etiqueta los eventos siguientes con `mini_service`.
|
|
414
|
+
* Admite varios activos a la vez (concurrencia); el "actual" para etiquetar es el más reciente.
|
|
415
|
+
* Reentrar con un nombre ya activo refresca su orden y su tiempo de entrada.
|
|
416
|
+
*/
|
|
413
417
|
enterMiniService(name, entryPointType) {
|
|
414
|
-
this.
|
|
415
|
-
this.
|
|
416
|
-
this.track("
|
|
417
|
-
}
|
|
418
|
-
/**
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
418
|
+
this.activeMiniServices.delete(name);
|
|
419
|
+
this.activeMiniServices.set(name, this.now());
|
|
420
|
+
this.track("deepdots_mini_service_enter", { entry_point_type: entryPointType ?? null });
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Cierra el mini-service `name` emitiendo `mini_service_exit` con su duración (#27).
|
|
424
|
+
* No-op si ese nombre no está activo. Cierre coherente con concurrencia.
|
|
425
|
+
*/
|
|
426
|
+
exitMiniService(name) {
|
|
427
|
+
const enteredAt = this.activeMiniServices.get(name);
|
|
428
|
+
if (enteredAt === void 0) return;
|
|
429
|
+
const durationSeconds = Math.max(0, Math.round((this.now() - enteredAt) / 1e3));
|
|
430
|
+
this.activeMiniServices.delete(name);
|
|
431
|
+
this.track("deepdots_mini_service_exit", { mini_service: name, duration_seconds: durationSeconds });
|
|
432
|
+
}
|
|
433
|
+
/** Cierra TODOS los mini-services activos (orden LIFO). Para el cierre por lifecycle (background/cierre). */
|
|
434
|
+
exitAllMiniServices() {
|
|
435
|
+
for (const name of Array.from(this.activeMiniServices.keys()).reverse()) {
|
|
436
|
+
this.exitMiniService(name);
|
|
437
|
+
}
|
|
425
438
|
}
|
|
426
439
|
/** Registra un evento de analítica (modelo GA: nombre + params). */
|
|
427
440
|
track(name, params) {
|
|
441
|
+
const current = this.getMiniService();
|
|
428
442
|
const merged = {
|
|
429
|
-
...
|
|
443
|
+
...current ? { mini_service: current } : {},
|
|
430
444
|
...params ?? {}
|
|
431
445
|
};
|
|
432
446
|
this.events.push({
|
|
@@ -438,9 +452,11 @@ var AnalyticsManager = class {
|
|
|
438
452
|
this.onFlushNeeded?.();
|
|
439
453
|
}
|
|
440
454
|
}
|
|
441
|
-
/** Mini-service activo
|
|
455
|
+
/** Mini-service actual (el más reciente aún activo) para etiquetar eventos + metadata del survey (#33). */
|
|
442
456
|
getMiniService() {
|
|
443
|
-
|
|
457
|
+
let last = null;
|
|
458
|
+
for (const name of this.activeMiniServices.keys()) last = name;
|
|
459
|
+
return last;
|
|
444
460
|
}
|
|
445
461
|
/** Nº de eventos pendientes de flush. */
|
|
446
462
|
pending() {
|
|
@@ -779,11 +795,153 @@ var ContactManager = class {
|
|
|
779
795
|
}
|
|
780
796
|
};
|
|
781
797
|
|
|
798
|
+
// src/analytics/crash-reporter.ts
|
|
799
|
+
var STACK_MAX = 8e3;
|
|
800
|
+
var QUEUE_KEY = "deepdots.crash.queue";
|
|
801
|
+
var MAX_QUEUED = 20;
|
|
802
|
+
function crashRecordToParams(r) {
|
|
803
|
+
const params = {
|
|
804
|
+
crashed_at: r.crashedAt,
|
|
805
|
+
crash_type: r.crashType,
|
|
806
|
+
message: r.message,
|
|
807
|
+
stack: r.stack,
|
|
808
|
+
fatal: r.fatal,
|
|
809
|
+
handled: r.handled,
|
|
810
|
+
severity: r.severity
|
|
811
|
+
};
|
|
812
|
+
if (r.sessionId) params.crashed_session_id = r.sessionId;
|
|
813
|
+
if (r.appVersion) params.crashed_app_version = r.appVersion;
|
|
814
|
+
if (r.osVersion) params.crashed_os_version = r.osVersion;
|
|
815
|
+
if (r.deviceModel) params.crashed_device_model = r.deviceModel;
|
|
816
|
+
if (r.context) {
|
|
817
|
+
for (const [k, v] of Object.entries(r.context)) params[`ctx_${k}`] = v;
|
|
818
|
+
}
|
|
819
|
+
return params;
|
|
820
|
+
}
|
|
821
|
+
var CrashReporter = class {
|
|
822
|
+
constructor(options) {
|
|
823
|
+
this.options = options;
|
|
824
|
+
this.now = options.now ?? (() => Date.now());
|
|
825
|
+
}
|
|
826
|
+
isEnabled() {
|
|
827
|
+
return this.options.enabled ? this.options.enabled() : true;
|
|
828
|
+
}
|
|
829
|
+
/** Construye un CrashRecord capturando contexto en el momento del crash. */
|
|
830
|
+
buildRecord(error, severity, handled, fatal, context) {
|
|
831
|
+
const err = error;
|
|
832
|
+
const isErr = error instanceof Error;
|
|
833
|
+
const dev = this.options.device();
|
|
834
|
+
const ctx = context ? Object.fromEntries(Object.entries(context).map(([k, v]) => [k, String(v)])) : void 0;
|
|
835
|
+
return {
|
|
836
|
+
crashedAt: this.now(),
|
|
837
|
+
crashType: isErr && err.name || "Error",
|
|
838
|
+
message: isErr ? String(err.message ?? "") : String(error),
|
|
839
|
+
stack: (isErr && typeof err.stack === "string" ? err.stack : "").slice(0, STACK_MAX),
|
|
840
|
+
fatal,
|
|
841
|
+
handled,
|
|
842
|
+
severity,
|
|
843
|
+
sessionId: this.options.sessionId(),
|
|
844
|
+
appVersion: dev.appVersion,
|
|
845
|
+
osVersion: dev.osVersion,
|
|
846
|
+
deviceModel: dev.deviceModel,
|
|
847
|
+
context: ctx
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
/** API pública del host: reporta un error (app viva) → emite el evento ya. */
|
|
851
|
+
reportError(error, options = {}) {
|
|
852
|
+
if (!this.isEnabled()) return;
|
|
853
|
+
const severity = options.severity ?? "error";
|
|
854
|
+
const handled = options.handled ?? true;
|
|
855
|
+
const fatal = severity === "fatal";
|
|
856
|
+
const record = this.buildRecord(error, severity, handled, fatal, options.context);
|
|
857
|
+
this.options.emit(crashRecordToParams(record));
|
|
858
|
+
}
|
|
859
|
+
/** Captura un error no manejado (fatal) → persiste a disco para replay en el siguiente arranque. */
|
|
860
|
+
captureUnhandled(error) {
|
|
861
|
+
this.persist(this.buildRecord(error, "fatal", false, true));
|
|
862
|
+
}
|
|
863
|
+
/** Persiste un crash no capturado a disco para reenviarlo en el siguiente arranque. */
|
|
864
|
+
persist(record) {
|
|
865
|
+
let queue = [];
|
|
866
|
+
try {
|
|
867
|
+
const raw = this.options.storage.getItem(QUEUE_KEY);
|
|
868
|
+
if (raw) queue = JSON.parse(raw);
|
|
869
|
+
if (!Array.isArray(queue)) queue = [];
|
|
870
|
+
} catch {
|
|
871
|
+
queue = [];
|
|
872
|
+
}
|
|
873
|
+
queue.push(record);
|
|
874
|
+
if (queue.length > MAX_QUEUED) queue = queue.slice(queue.length - MAX_QUEUED);
|
|
875
|
+
try {
|
|
876
|
+
this.options.storage.setItem(QUEUE_KEY, JSON.stringify(queue));
|
|
877
|
+
} catch {
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
/** Lee y vacía la cola de crashes pendientes (llamado en init para el replay). */
|
|
881
|
+
drainPendingCrashes() {
|
|
882
|
+
let queue = [];
|
|
883
|
+
try {
|
|
884
|
+
const raw = this.options.storage.getItem(QUEUE_KEY);
|
|
885
|
+
if (raw) queue = JSON.parse(raw);
|
|
886
|
+
if (!Array.isArray(queue)) queue = [];
|
|
887
|
+
} catch {
|
|
888
|
+
queue = [];
|
|
889
|
+
}
|
|
890
|
+
if (queue.length) {
|
|
891
|
+
try {
|
|
892
|
+
this.options.storage.removeItem(QUEUE_KEY);
|
|
893
|
+
} catch {
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return queue;
|
|
897
|
+
}
|
|
898
|
+
/** Instala los handlers globales de errores no capturados (no-op sin `window`). */
|
|
899
|
+
install() {
|
|
900
|
+
if (typeof window === "undefined") return;
|
|
901
|
+
window.addEventListener("error", (e) => {
|
|
902
|
+
if (!this.isEnabled()) return;
|
|
903
|
+
this.captureUnhandled(e.error ?? e.message ?? "error");
|
|
904
|
+
});
|
|
905
|
+
window.addEventListener("unhandledrejection", (e) => {
|
|
906
|
+
if (!this.isEnabled()) return;
|
|
907
|
+
this.captureUnhandled(e.reason ?? "unhandledrejection");
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
/** Engancha `global.ErrorUtils` de RN (no hay `window`): persiste y encadena al handler previo. */
|
|
911
|
+
installReactNative(errorUtils) {
|
|
912
|
+
const previous = errorUtils.getGlobalHandler?.();
|
|
913
|
+
errorUtils.setGlobalHandler((error, isFatal) => {
|
|
914
|
+
if (this.isEnabled()) this.captureUnhandled(error);
|
|
915
|
+
previous?.(error, isFatal);
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
/** @internal Test seam: ejercita el camino de persistencia (window handlers no son testeables en vitest). */
|
|
919
|
+
_persistForTest(error) {
|
|
920
|
+
this.captureUnhandled(error);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
|
|
924
|
+
// src/analytics/messaging.ts
|
|
925
|
+
function buildMessageParams(stage, o) {
|
|
926
|
+
const p = {
|
|
927
|
+
stage,
|
|
928
|
+
message_id: o.id,
|
|
929
|
+
message_title: o.title,
|
|
930
|
+
channel: o.channel
|
|
931
|
+
};
|
|
932
|
+
if (o.campaign) p.campaign = o.campaign;
|
|
933
|
+
if (o.value !== void 0) p.value = o.value;
|
|
934
|
+
if (o.currency) p.currency = o.currency;
|
|
935
|
+
return { ...p, ...o.params ?? {} };
|
|
936
|
+
}
|
|
937
|
+
|
|
782
938
|
// src/core/deepdots-popups.ts
|
|
783
939
|
var EXIT_QUEUE_STORAGE_KEY = "__deepdots_exit_popup_queue__";
|
|
784
940
|
var DAY_IN_MS = 24 * 60 * 60 * 1e3;
|
|
785
941
|
var ANALYTICS_MAX_BATCH_SIZE = 20;
|
|
786
942
|
var ANALYTICS_FLUSH_INTERVAL_MS = 3e4;
|
|
943
|
+
var RESERVED_EVENT_PREFIX = "deepdots_";
|
|
944
|
+
var CUSTOM_EVENT_PREFIX = "deepdots_event_";
|
|
787
945
|
var DeepdotsPopups = class {
|
|
788
946
|
constructor() {
|
|
789
947
|
this.config = null;
|
|
@@ -813,6 +971,8 @@ var DeepdotsPopups = class {
|
|
|
813
971
|
this.analyticsFeedbackSessionId = void 0;
|
|
814
972
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
815
973
|
this.analyticsFlushTimer = void 0;
|
|
974
|
+
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
975
|
+
this.crashReporter = null;
|
|
816
976
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
817
977
|
this.navObserver = null;
|
|
818
978
|
/** Tiempo activo (engagement time, #8). */
|
|
@@ -864,25 +1024,44 @@ var DeepdotsPopups = class {
|
|
|
864
1024
|
this.analyticsFeedbackSessionId = id;
|
|
865
1025
|
}
|
|
866
1026
|
}) : void 0;
|
|
1027
|
+
const device = config.device ?? collectDeviceInfo(config.appVersion);
|
|
867
1028
|
this.analytics = new AnalyticsManager({
|
|
868
1029
|
sink: analyticsSink,
|
|
869
1030
|
publicKey: config.analytics?.publicKey ?? this.config.apiKey,
|
|
870
1031
|
language: typeof navigator !== "undefined" ? navigator.language : void 0,
|
|
871
1032
|
platform: config.platform ?? "web",
|
|
872
|
-
device
|
|
1033
|
+
device,
|
|
873
1034
|
maxBatchSize: ANALYTICS_MAX_BATCH_SIZE,
|
|
874
1035
|
onFlushNeeded: () => this.flushAnalytics()
|
|
875
1036
|
});
|
|
1037
|
+
this.crashReporter = new CrashReporter({
|
|
1038
|
+
storage,
|
|
1039
|
+
emit: (params) => this.track("deepdots_app_crash", params),
|
|
1040
|
+
device: () => ({ appVersion: device.app_version, osVersion: device.os_version, deviceModel: device.device_model }),
|
|
1041
|
+
sessionId: () => this.tracking?.getSessionId() ?? null,
|
|
1042
|
+
now: () => Date.now(),
|
|
1043
|
+
enabled: () => this.tracking?.isTrackingEnabled() ?? false
|
|
1044
|
+
});
|
|
1045
|
+
if (this.tracking?.isTrackingEnabled()) {
|
|
1046
|
+
this.crashReporter.install();
|
|
1047
|
+
}
|
|
876
1048
|
collectGeoInfo().then((geo) => {
|
|
877
1049
|
if (geo) this.analytics?.updateDevice(geo);
|
|
878
1050
|
}).catch(() => {
|
|
879
1051
|
});
|
|
880
1052
|
this.navObserver = new NavigationObserver();
|
|
881
|
-
this.navObserver.onVisit((v) => this.track("
|
|
1053
|
+
this.navObserver.onVisit((v) => this.track("deepdots_page_view", { screen: v.screen, duration_seconds: v.durationSeconds }));
|
|
882
1054
|
this.navObserver.install();
|
|
883
1055
|
this.engagement = new EngagementTracker();
|
|
884
1056
|
this.engagement.resume();
|
|
885
1057
|
this.setupAnalyticsFlush();
|
|
1058
|
+
this.track("deepdots_session_start", {});
|
|
1059
|
+
const pendingCrashes = this.crashReporter.drainPendingCrashes();
|
|
1060
|
+
if (this.tracking?.isTrackingEnabled()) {
|
|
1061
|
+
for (const rec of pendingCrashes) {
|
|
1062
|
+
this.track("deepdots_app_crash", crashRecordToParams(rec));
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
886
1065
|
this.initialized = true;
|
|
887
1066
|
this.log("SDK initialized", this.config);
|
|
888
1067
|
if (this.renderer.init) this.renderer.init();
|
|
@@ -915,14 +1094,25 @@ var DeepdotsPopups = class {
|
|
|
915
1094
|
/** Registra un evento de analítica (modelo GA: nombre + params). No-op si tracking off. */
|
|
916
1095
|
track(name, params) {
|
|
917
1096
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
918
|
-
|
|
919
|
-
this.
|
|
1097
|
+
const eventName = name.startsWith(RESERVED_EVENT_PREFIX) ? name : `${CUSTOM_EVENT_PREFIX}${name}`;
|
|
1098
|
+
this.analytics?.track(eventName, params);
|
|
1099
|
+
this.log("analytics \xB7 track:", eventName, params ?? {});
|
|
920
1100
|
}
|
|
921
1101
|
/** User attributes para breakdowns (registration_status, pass_type, sector, pass_status…). */
|
|
922
1102
|
setUserAttributes(attributes) {
|
|
923
1103
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
924
1104
|
this.analytics?.setUserAttributes(attributes);
|
|
925
1105
|
}
|
|
1106
|
+
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
1107
|
+
reportError(error, options) {
|
|
1108
|
+
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1109
|
+
this.crashReporter?.reportError(error, options);
|
|
1110
|
+
}
|
|
1111
|
+
/** Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. No-op si tracking off. */
|
|
1112
|
+
installReactNativeCrashHandler(errorUtils) {
|
|
1113
|
+
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1114
|
+
this.crashReporter?.installReactNative(errorUtils);
|
|
1115
|
+
}
|
|
926
1116
|
/**
|
|
927
1117
|
* Info interna del usuario que solo conoce el host (idioma, edad, plan…), persistida en el
|
|
928
1118
|
* Contact del backend para segmentación/targeting de popups. Identificada por el `userId` del
|
|
@@ -940,23 +1130,27 @@ var DeepdotsPopups = class {
|
|
|
940
1130
|
this.analytics?.enterMiniService(name, entryPointType);
|
|
941
1131
|
this.log("analytics \xB7 enterMiniService:", name, entryPointType ?? "");
|
|
942
1132
|
}
|
|
943
|
-
/** Cierra el mini-service
|
|
944
|
-
exitMiniService() {
|
|
1133
|
+
/** Cierra el mini-service `name` (emite `mini_service_exit` con duración, #27). No-op si tracking off o si ese no está activo. */
|
|
1134
|
+
exitMiniService(name) {
|
|
945
1135
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
946
|
-
this.analytics?.exitMiniService();
|
|
947
|
-
this.log("analytics \xB7 exitMiniService");
|
|
1136
|
+
this.analytics?.exitMiniService(name);
|
|
1137
|
+
this.log("analytics \xB7 exitMiniService:", name);
|
|
948
1138
|
}
|
|
949
1139
|
/** Findability (#31/#35): registra una búsqueda. `has_results` se deriva de `resultsCount`. */
|
|
950
1140
|
trackSearch(query, resultsCount, params) {
|
|
951
|
-
this.track("
|
|
1141
|
+
this.track("deepdots_search", { query, results_count: resultsCount, has_results: resultsCount > 0, ...params ?? {} });
|
|
952
1142
|
}
|
|
953
1143
|
/** Findability friction (#34/#35): señal de fricción con su `friction_topic`. */
|
|
954
1144
|
trackFindabilityFriction(frictionTopic, params) {
|
|
955
|
-
this.track("
|
|
1145
|
+
this.track("deepdots_findability_friction", { friction_topic: frictionTopic, ...params ?? {} });
|
|
956
1146
|
}
|
|
957
1147
|
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
958
1148
|
trackFunnelStep(funnel, step, taskId, params) {
|
|
959
|
-
this.track("
|
|
1149
|
+
this.track("deepdots_funnel_step", { funnel, step, task_id: taskId, ...params ?? {} });
|
|
1150
|
+
}
|
|
1151
|
+
/** Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app). No-op si tracking off. */
|
|
1152
|
+
trackMessage(stage, options) {
|
|
1153
|
+
this.track("deepdots_message", buildMessageParams(stage, options));
|
|
960
1154
|
}
|
|
961
1155
|
/**
|
|
962
1156
|
* Navegación MANUAL (entornos sin History API, p. ej. React Native con React Navigation).
|
|
@@ -982,7 +1176,7 @@ var DeepdotsPopups = class {
|
|
|
982
1176
|
onBackground() {
|
|
983
1177
|
this.navObserver?.stop();
|
|
984
1178
|
this.navStarted = false;
|
|
985
|
-
this.
|
|
1179
|
+
if (this.tracking?.isTrackingEnabled()) this.analytics?.exitAllMiniServices();
|
|
986
1180
|
this.flushEngagement();
|
|
987
1181
|
this.engagement?.pause();
|
|
988
1182
|
this.flushAnalytics();
|
|
@@ -1005,7 +1199,7 @@ var DeepdotsPopups = class {
|
|
|
1005
1199
|
flushEngagement() {
|
|
1006
1200
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1007
1201
|
const ms = this.engagement?.consume() ?? 0;
|
|
1008
|
-
if (ms > 0) this.track("
|
|
1202
|
+
if (ms > 0) this.track("deepdots_user_engagement", { engagement_time_msec: ms });
|
|
1009
1203
|
}
|
|
1010
1204
|
analyticsIdentity() {
|
|
1011
1205
|
return {
|
|
@@ -1020,7 +1214,7 @@ var DeepdotsPopups = class {
|
|
|
1020
1214
|
window.addEventListener("pagehide", () => {
|
|
1021
1215
|
clearInterval(this.analyticsFlushTimer);
|
|
1022
1216
|
this.navObserver?.stop();
|
|
1023
|
-
this.
|
|
1217
|
+
if (this.tracking?.isTrackingEnabled()) this.analytics?.exitAllMiniServices();
|
|
1024
1218
|
this.flushEngagement();
|
|
1025
1219
|
this.flushAnalytics();
|
|
1026
1220
|
});
|
|
@@ -1686,6 +1880,10 @@ function setupReactNative(sdk, config, deps = {}) {
|
|
|
1686
1880
|
const device = deps.deviceInfo ? collectRnDevice(deps.deviceInfo) : config.device;
|
|
1687
1881
|
const platform = deps.platform ?? config.platform;
|
|
1688
1882
|
sdk.init({ ...config, storage, device, platform });
|
|
1883
|
+
const errorUtils = deps.errorUtils ?? globalThis.ErrorUtils;
|
|
1884
|
+
if (errorUtils && typeof errorUtils.setGlobalHandler === "function") {
|
|
1885
|
+
sdk.installReactNativeCrashHandler(errorUtils);
|
|
1886
|
+
}
|
|
1689
1887
|
let subscription;
|
|
1690
1888
|
if (deps.appState?.addEventListener) {
|
|
1691
1889
|
subscription = deps.appState.addEventListener("change", (state) => {
|
|
@@ -1700,14 +1898,17 @@ function setupReactNative(sdk, config, deps = {}) {
|
|
|
1700
1898
|
export {
|
|
1701
1899
|
BrowserPopupRenderer,
|
|
1702
1900
|
ContactManager,
|
|
1901
|
+
CrashReporter,
|
|
1703
1902
|
DeepdotsPopups,
|
|
1704
1903
|
InMemoryStorage,
|
|
1705
1904
|
NoopPopupRenderer,
|
|
1706
1905
|
POPUP_TRIGGER_CONDITION_STATUSES,
|
|
1707
1906
|
ReactNativePopupRenderer,
|
|
1708
1907
|
buildAnalyticsFeedbackBody,
|
|
1908
|
+
buildMessageParams,
|
|
1709
1909
|
buildSurveyHtml,
|
|
1710
1910
|
collectRnDevice,
|
|
1911
|
+
crashRecordToParams,
|
|
1711
1912
|
createDefaultRenderer,
|
|
1712
1913
|
createFeedbackSink,
|
|
1713
1914
|
mmkvStorage,
|