@magicfeedback/popup-sdk 1.1.7 → 1.2.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/README.md +5 -0
- package/dist/index.d.mts +169 -19
- package/dist/index.d.ts +169 -19
- package/dist/index.js +312 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +308 -50
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +77 -12
- package/dist/react-native.d.ts +77 -12
- package/dist/react-native.js +309 -48
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +305 -50
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-PS3NJDUR.mjs → renderPopup-NHWJ7YSI.mjs} +7 -1
- package/dist/renderPopup-NHWJ7YSI.mjs.map +1 -0
- package/dist/{renderPopup-EZKDMLVZ.mjs → renderPopup-R53C7DB3.mjs} +7 -1
- package/dist/renderPopup-R53C7DB3.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/renderPopup-EZKDMLVZ.mjs.map +0 -1
- package/dist/renderPopup-PS3NJDUR.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -177,6 +177,11 @@ Config fields:
|
|
|
177
177
|
- `mode?: 'server' | 'client'`
|
|
178
178
|
- `debug?: boolean`
|
|
179
179
|
- `popups?: PopupDefinition[]`
|
|
180
|
+
- `language?: string` — BCP-47 tag (`'en'`, `'en-US'`, …) used for popup language
|
|
181
|
+
segmentation (`segments.lang`) and for the analytics context. If omitted it is
|
|
182
|
+
auto-detected from `navigator.language`, falling back to the `Intl` locale (which is
|
|
183
|
+
what makes it work in React Native, where `navigator.language` does not exist). If no
|
|
184
|
+
source resolves a language, popups with `segments.lang` cannot be filtered and are shown.
|
|
180
185
|
|
|
181
186
|
### `autoLaunch()`
|
|
182
187
|
|
package/dist/index.d.mts
CHANGED
|
@@ -91,14 +91,36 @@ interface AnalyticsEnvelope {
|
|
|
91
91
|
};
|
|
92
92
|
events: AnalyticsEvent[];
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
/** Contexto del flush, para que el sink pueda adaptar el transporte. */
|
|
95
|
+
interface AnalyticsFlushMeta {
|
|
96
|
+
/**
|
|
97
|
+
* `true` cuando el flush ocurre porque la página/app se está cerrando. El sink debe usar
|
|
98
|
+
* un transporte que sobreviva al unload (sendBeacon) y no puede esperar respuestas.
|
|
99
|
+
*/
|
|
100
|
+
final?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* `true` cuando este es el ÚLTIMO lote de la sesión (cierre de página, app a background,
|
|
103
|
+
* cambio de usuario, tracking desactivado). El sink lo envía con `completed:true` y olvida
|
|
104
|
+
* el `sessionId`, para que el lote siguiente abra un registro nuevo.
|
|
105
|
+
*/
|
|
106
|
+
sessionEnd?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Envío del lote. Si devuelve una promesa que **rechaza**, el manager re-encola los
|
|
110
|
+
* eventos para reintentarlos en el siguiente flush (fallo transitorio: red o 5xx).
|
|
111
|
+
* Resolver = lote entregado o descartado definitivamente (no se reintenta).
|
|
112
|
+
*/
|
|
113
|
+
type AnalyticsSink = (payload: AnalyticsEnvelope, meta?: AnalyticsFlushMeta) => void | Promise<void>;
|
|
95
114
|
|
|
96
115
|
/**
|
|
97
116
|
* Mapeo del envelope de analytics → body de `POST /sdk/feedback`.
|
|
98
117
|
*
|
|
99
118
|
* La analítica se envía como un Feedback del modelo del Surveys SDK, agrupado por una
|
|
100
|
-
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false
|
|
101
|
-
*
|
|
119
|
+
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false`; el
|
|
120
|
+
* backend cose por `sessionId` + `user_id`. El ÚLTIMO lote de una sesión (cierre de página,
|
|
121
|
+
* app a background, cambio de usuario) va con `completed:true`: cierra el registro y el
|
|
122
|
+
* siguiente lote omite el `sessionId` viejo para que el backend abra uno nuevo.
|
|
123
|
+
* `feedback.finished` se queda siempre en `false` (no es la señal de cierre acordada).
|
|
102
124
|
*
|
|
103
125
|
* Encoding:
|
|
104
126
|
* - todo va en `feedback.metadata`: contexto (user_id, session_id, platform…) + eventos
|
|
@@ -134,7 +156,15 @@ interface AnalyticsFeedbackBody {
|
|
|
134
156
|
/** sessionId devuelto por el primer POST; permite que el backend agrupe todos los eventos en un solo registro. */
|
|
135
157
|
sessionId?: string;
|
|
136
158
|
}
|
|
137
|
-
|
|
159
|
+
interface BuildBodyOptions {
|
|
160
|
+
/**
|
|
161
|
+
* `true` en el último lote de la sesión → `completed:true` (cierra el registro en backend).
|
|
162
|
+
* El body SÍ lleva el `sessionId` actual (es el registro que se cierra); es el lote
|
|
163
|
+
* SIGUIENTE el que lo omite.
|
|
164
|
+
*/
|
|
165
|
+
sessionEnd?: boolean;
|
|
166
|
+
}
|
|
167
|
+
declare function buildAnalyticsFeedbackBody(envelope: AnalyticsEnvelope, keys: AnalyticsKeys, feedbackSessionId?: string, options?: BuildBodyOptions): AnalyticsFeedbackBody;
|
|
138
168
|
interface FeedbackSinkOptions {
|
|
139
169
|
/** Base URL del backend (api(.|-dev.)deepdots.com) ya resuelta por el entorno. */
|
|
140
170
|
baseUrl: string;
|
|
@@ -143,15 +173,31 @@ interface FeedbackSinkOptions {
|
|
|
143
173
|
log?: (...args: unknown[]) => void;
|
|
144
174
|
/** fetch inyectable (tests / RN). */
|
|
145
175
|
fetchImpl?: typeof fetch;
|
|
176
|
+
/**
|
|
177
|
+
* `navigator.sendBeacon` inyectable. Solo se usa en el flush final (cierre de página):
|
|
178
|
+
* sobrevive al unload, a cambio de no poder leer la respuesta. Si no se pasa, el flush
|
|
179
|
+
* final usa `fetch` con `keepalive`.
|
|
180
|
+
*/
|
|
181
|
+
sendBeaconImpl?: (url: string, body: Blob | string) => boolean;
|
|
146
182
|
/** Callback invocado cuando el backend devuelve un nuevo sessionId (primer POST). */
|
|
147
183
|
onSessionId?: (id: string) => void;
|
|
184
|
+
/** Callback invocado al cerrar la sesión (`completed:true`): el sessionId cacheado se olvida. */
|
|
185
|
+
onSessionReset?: () => void;
|
|
148
186
|
}
|
|
149
187
|
/**
|
|
150
188
|
* Sink real: transforma el envelope y hace `POST {baseUrl}/sdk/feedback`.
|
|
151
|
-
*
|
|
152
|
-
* Stateful: cachea el `sessionId` que devuelve el backend en la primera respuesta
|
|
153
|
-
*
|
|
154
|
-
*
|
|
189
|
+
*
|
|
190
|
+
* Stateful: cachea el `sessionId` que devuelve el backend en la primera respuesta y lo
|
|
191
|
+
* envía en los siguientes POSTs para que el backend agrupe todos los eventos en un único
|
|
192
|
+
* registro de feedback.
|
|
193
|
+
*
|
|
194
|
+
* Garantías de entrega:
|
|
195
|
+
* - mientras no se conozca el `sessionId`, los lotes se **serializan** (esperan la primera
|
|
196
|
+
* respuesta): dos POSTs a la vez sin `sessionId` crearían dos registros y partirían los datos;
|
|
197
|
+
* - `keepalive` para que el navegador no cancele el POST al navegar fuera, y `sendBeacon`
|
|
198
|
+
* en el flush final (cierre de página), donde `fetch` puede morir con el documento;
|
|
199
|
+
* - la promesa **rechaza** en fallo transitorio (red, 5xx, 408, 429) para que el
|
|
200
|
+
* `AnalyticsManager` re-encole el lote; un 4xx se loguea y se descarta.
|
|
155
201
|
*/
|
|
156
202
|
declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink;
|
|
157
203
|
|
|
@@ -190,9 +236,11 @@ interface DeepdotsInitParams {
|
|
|
190
236
|
/** Platform used in the analytics envelope. Default is 'web'; in RN pass 'android'/'ios'. */
|
|
191
237
|
platform?: 'web' | 'android' | 'ios';
|
|
192
238
|
/**
|
|
193
|
-
* BCP-47 language tag
|
|
194
|
-
*
|
|
195
|
-
*
|
|
239
|
+
* BCP-47 language tag (e.g. 'es-ES') used for the analytics context AND for popup
|
|
240
|
+
* language segmentation (`segments.lang`). If omitted, the SDK auto-detects:
|
|
241
|
+
* `navigator.language` on web, or the `Intl` locale as a fallback (works in
|
|
242
|
+
* React Native with Hermes, where `navigator.language` is absent). If no source
|
|
243
|
+
* resolves a language, popups with `segments.lang` cannot be filtered and are shown.
|
|
196
244
|
*/
|
|
197
245
|
language?: string;
|
|
198
246
|
/** Injectable device info (RN: from react-native-device-info). If missing, it is derived from the browser. */
|
|
@@ -247,6 +295,16 @@ interface DeepdotsEvent {
|
|
|
247
295
|
* Event listener callback
|
|
248
296
|
*/
|
|
249
297
|
type EventListener = (event: DeepdotsEvent) => void;
|
|
298
|
+
/**
|
|
299
|
+
* Motivo del `deepdots_session_end` (último lote de la sesión, enviado con `completed:true`):
|
|
300
|
+
* - `page_hide`: la página web se cierra o se navega fuera (`pagehide`).
|
|
301
|
+
* - `background`: la app pasa a background (RN/nativo). Única señal disponible en móvil:
|
|
302
|
+
* el kill de la app por el usuario o el SO NO produce ningún callback.
|
|
303
|
+
* - `user_change`: `setUserId()` o un `init()` con otro `userId` (login/logout del host).
|
|
304
|
+
* - `tracking_disabled`: `setTrackingEnabled(false)` (consentimiento revocado).
|
|
305
|
+
* - `manual`: `endSession()` llamado por el host.
|
|
306
|
+
*/
|
|
307
|
+
type SessionEndReason = 'page_hide' | 'background' | 'user_change' | 'tracking_disabled' | 'manual';
|
|
250
308
|
/** Trigger type used by remote popup definitions */
|
|
251
309
|
type PopupTriggerType = 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
|
|
252
310
|
type PopupTriggerConditionStatus = 'SHOWED' | 'PARTIAL' | 'COMPLETED';
|
|
@@ -469,13 +527,16 @@ declare class CrashReporter {
|
|
|
469
527
|
* el funnel se correlaciona por `message_id` y se agrupa por `message_title`.
|
|
470
528
|
*/
|
|
471
529
|
type MessageStage = 'delivered' | 'clicked' | 'converted';
|
|
530
|
+
/** Canales válidos. Un mensaje tiene UN canal: se valida en runtime porque el host puede no ser TS. */
|
|
531
|
+
declare const MESSAGE_CHANNELS: readonly ["push", "in_app"];
|
|
532
|
+
type MessageChannel = (typeof MESSAGE_CHANNELS)[number];
|
|
472
533
|
interface TrackMessageOptions {
|
|
473
534
|
/** Identificador del mensaje/notificación — correlaciona el funnel delivered→clicked→converted. */
|
|
474
535
|
id: string;
|
|
475
536
|
/** Título del mensaje — dimensión de agrupación de #18–22. */
|
|
476
537
|
title: string;
|
|
477
538
|
/** Canal de entrega. */
|
|
478
|
-
channel:
|
|
539
|
+
channel: MessageChannel;
|
|
479
540
|
/** Nombre de la campaña (opcional). */
|
|
480
541
|
campaign?: string;
|
|
481
542
|
/** Valor de conversión (opcional, típico en `stage: 'converted'`). */
|
|
@@ -486,6 +547,38 @@ interface TrackMessageOptions {
|
|
|
486
547
|
}
|
|
487
548
|
/** Construye los params del evento `deepdots_message` (omite opcionales ausentes). */
|
|
488
549
|
declare function buildMessageParams(stage: MessageStage, o: TrackMessageOptions): Record<string, unknown>;
|
|
550
|
+
/** Techo de `message_id` vigilados por sesión; los más antiguos se evictan (memoria acotada). */
|
|
551
|
+
declare const MAX_TRACKED_MESSAGES = 500;
|
|
552
|
+
type MessageRejectionReason = 'invalid_channel' | 'duplicate_stage' | 'channel_conflict';
|
|
553
|
+
type MessageGuardVerdict = {
|
|
554
|
+
emit: true;
|
|
555
|
+
} | {
|
|
556
|
+
emit: false;
|
|
557
|
+
reason: MessageRejectionReason;
|
|
558
|
+
detail: string;
|
|
559
|
+
};
|
|
560
|
+
/**
|
|
561
|
+
* Protege el funnel de Messaging de las formas imposibles que el host puede producir por error
|
|
562
|
+
* (visto en producción: CTR > 100% por falta de `delivered` + el mismo `message_id` reportado en
|
|
563
|
+
* dos canales). Tres reglas, todas dentro de la sesión (se reinicia en cada `init()`):
|
|
564
|
+
*
|
|
565
|
+
* 1. `channel` fuera de `MESSAGE_CHANNELS` → se descarta el evento.
|
|
566
|
+
* 2. Un `(message_id, stage)` ya emitido → se emite una sola vez.
|
|
567
|
+
* 3. Un `message_id` ya visto en un canal → se descartan los eventos de otro canal.
|
|
568
|
+
*
|
|
569
|
+
* Los eventos rechazados NO mutan el estado: un rechazo nunca "consume" el stage bueno.
|
|
570
|
+
* Lo que el SDK no puede arreglar es la ausencia de `delivered`: eso lo instrumenta el host.
|
|
571
|
+
*/
|
|
572
|
+
declare class MessageGuard {
|
|
573
|
+
private maxTrackedMessages;
|
|
574
|
+
/** message_id → canal fijado + stages ya emitidos. El orden de inserción marca la eviction. */
|
|
575
|
+
private seen;
|
|
576
|
+
constructor(maxTrackedMessages?: number);
|
|
577
|
+
evaluate(stage: MessageStage, options: TrackMessageOptions): MessageGuardVerdict;
|
|
578
|
+
/** Olvida todo lo vigilado (nueva sesión). */
|
|
579
|
+
reset(): void;
|
|
580
|
+
private remember;
|
|
581
|
+
}
|
|
489
582
|
|
|
490
583
|
/**
|
|
491
584
|
* Main class for managing survey popups
|
|
@@ -519,14 +612,29 @@ declare class DeepdotsPopups {
|
|
|
519
612
|
private analyticsFlushTimer;
|
|
520
613
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
521
614
|
private crashReporter;
|
|
615
|
+
/** Protecciones del funnel de Messaging (#18–22). Vigencia de sesión: se reinicia en init(). */
|
|
616
|
+
private messageGuard;
|
|
522
617
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
523
618
|
private navObserver;
|
|
524
619
|
/** Tiempo activo (engagement time, #8). */
|
|
525
620
|
private engagement;
|
|
526
621
|
/** Atributos internos del usuario identificado → POST /sdk/popups/contact. Null si no hay userId. */
|
|
527
622
|
private contact;
|
|
623
|
+
/** Storage resuelto en init() (inyectado por el host o localStorage). Reusado al cambiar de usuario. */
|
|
624
|
+
private storage;
|
|
528
625
|
/** Marca si ya se inició la navegación manual (setScreen) — para RN sin History API. */
|
|
529
626
|
private navStarted;
|
|
627
|
+
/**
|
|
628
|
+
* `true` entre `session_start` y `session_end`. Hace idempotente tanto la apertura como
|
|
629
|
+
* el cierre (p. ej. `visibilitychange` + `pagehide` seguidos) y permite abrir una sesión
|
|
630
|
+
* nueva al volver a foreground o al conceder el consentimiento más tarde.
|
|
631
|
+
*/
|
|
632
|
+
private sessionOpen;
|
|
633
|
+
/**
|
|
634
|
+
* Idioma resuelto en init() (explícito > navigator.language > Intl). Única fuente de
|
|
635
|
+
* verdad para el context de analytics Y para la segmentación por idioma de los popups.
|
|
636
|
+
*/
|
|
637
|
+
private language;
|
|
530
638
|
/** Initialize the SDK with configuration */
|
|
531
639
|
init(config: DeepdotsInitParams): void;
|
|
532
640
|
/** User id actual (generado por el SDK o provisto por el cliente). Null si tracking off. */
|
|
@@ -565,24 +673,66 @@ declare class DeepdotsPopups {
|
|
|
565
673
|
trackFindabilityFriction(frictionTopic: string, params?: Record<string, unknown>): void;
|
|
566
674
|
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
567
675
|
trackFunnelStep(funnel: string, step: string, taskId: string, params?: Record<string, unknown>): void;
|
|
568
|
-
/**
|
|
676
|
+
/**
|
|
677
|
+
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
678
|
+
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
679
|
+
* si ese `(message_id, stage)` ya se emitió en la sesión, o si el `message_id` ya se reportó
|
|
680
|
+
* en otro canal — ver `MessageGuard`.
|
|
681
|
+
*/
|
|
569
682
|
trackMessage(stage: MessageStage, options: TrackMessageOptions): void;
|
|
570
683
|
/**
|
|
571
684
|
* Navegación MANUAL (entornos sin History API, p. ej. React Native con React Navigation).
|
|
572
685
|
* El host la llama en cada cambio de pantalla; emite `page_view` al salir de la anterior.
|
|
573
686
|
*/
|
|
574
687
|
setScreen(name: string): void;
|
|
575
|
-
/** App a foreground (RN: AppState 'active'): reanuda el engagement time. */
|
|
688
|
+
/** App a foreground (RN: AppState 'active'): reanuda el engagement time y abre sesión nueva. */
|
|
576
689
|
onForeground(): void;
|
|
577
690
|
/**
|
|
578
|
-
* App a background (RN: AppState 'background'):
|
|
579
|
-
* mini-
|
|
691
|
+
* App a background (RN: AppState 'background'): FIN DE SESIÓN. Cierra pantalla actual
|
|
692
|
+
* (page_view), mini-services (mini_service_exit), emite engagement + `session_end` y
|
|
693
|
+
* envía el último lote con `completed:true`.
|
|
694
|
+
*
|
|
695
|
+
* Es la única señal disponible en móvil: el kill de la app (swipe) NO da callback.
|
|
580
696
|
*/
|
|
581
697
|
onBackground(): void;
|
|
698
|
+
/**
|
|
699
|
+
* Cierre EXPLÍCITO de la sesión por parte del host (logout, fin de flujo…): emite
|
|
700
|
+
* `session_end` y envía el último lote con `completed:true`.
|
|
701
|
+
*/
|
|
702
|
+
endSession(): void;
|
|
703
|
+
/**
|
|
704
|
+
* Cambio de usuario (login / logout / cambio de cuenta). Cierra la sesión del usuario
|
|
705
|
+
* anterior (`session_end` con `reason: 'user_change'` + `completed:true`), cambia la
|
|
706
|
+
* identidad y abre una sesión nueva. Sin `userId` vuelve al id anónimo del SDK.
|
|
707
|
+
*
|
|
708
|
+
* Equivale a llamar a `init()` otra vez con otro `userId`.
|
|
709
|
+
*/
|
|
710
|
+
setUserId(userId?: string): void;
|
|
711
|
+
/**
|
|
712
|
+
* Cierra la sesión actual: vuelca todo lo que quedaba abierto y envía el último lote
|
|
713
|
+
* marcado con `completed:true`, para que el backend cierre el registro. El `sessionId`
|
|
714
|
+
* cacheado se olvida → el lote siguiente abre un registro nuevo.
|
|
715
|
+
*
|
|
716
|
+
* Idempotente: dos cierres seguidos (p. ej. `visibilitychange` + `pagehide`) no duplican
|
|
717
|
+
* el `session_end`.
|
|
718
|
+
*/
|
|
719
|
+
private closeSession;
|
|
720
|
+
/**
|
|
721
|
+
* Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente:
|
|
722
|
+
* se llama en init(), al volver a foreground y al conceder el consentimiento.
|
|
723
|
+
*/
|
|
724
|
+
private openSession;
|
|
582
725
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
583
726
|
previewAnalytics(): AnalyticsEnvelope;
|
|
584
|
-
/**
|
|
585
|
-
|
|
727
|
+
/**
|
|
728
|
+
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
729
|
+
* `final: true` (cierre de página/app) cambia el transporte a `sendBeacon`, que sobrevive
|
|
730
|
+
* al unload; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
731
|
+
*/
|
|
732
|
+
flushAnalytics(options?: {
|
|
733
|
+
final?: boolean;
|
|
734
|
+
sessionEnd?: boolean;
|
|
735
|
+
}): void;
|
|
586
736
|
/** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
|
|
587
737
|
private flushEngagement;
|
|
588
738
|
private analyticsIdentity;
|
|
@@ -775,4 +925,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
775
925
|
*/
|
|
776
926
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
777
927
|
|
|
778
|
-
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, type MessageStage, type MmkvLike, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, mmkvStorage, setupReactNative };
|
|
928
|
+
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, mmkvStorage, setupReactNative };
|
package/dist/index.d.ts
CHANGED
|
@@ -91,14 +91,36 @@ interface AnalyticsEnvelope {
|
|
|
91
91
|
};
|
|
92
92
|
events: AnalyticsEvent[];
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
/** Contexto del flush, para que el sink pueda adaptar el transporte. */
|
|
95
|
+
interface AnalyticsFlushMeta {
|
|
96
|
+
/**
|
|
97
|
+
* `true` cuando el flush ocurre porque la página/app se está cerrando. El sink debe usar
|
|
98
|
+
* un transporte que sobreviva al unload (sendBeacon) y no puede esperar respuestas.
|
|
99
|
+
*/
|
|
100
|
+
final?: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* `true` cuando este es el ÚLTIMO lote de la sesión (cierre de página, app a background,
|
|
103
|
+
* cambio de usuario, tracking desactivado). El sink lo envía con `completed:true` y olvida
|
|
104
|
+
* el `sessionId`, para que el lote siguiente abra un registro nuevo.
|
|
105
|
+
*/
|
|
106
|
+
sessionEnd?: boolean;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Envío del lote. Si devuelve una promesa que **rechaza**, el manager re-encola los
|
|
110
|
+
* eventos para reintentarlos en el siguiente flush (fallo transitorio: red o 5xx).
|
|
111
|
+
* Resolver = lote entregado o descartado definitivamente (no se reintenta).
|
|
112
|
+
*/
|
|
113
|
+
type AnalyticsSink = (payload: AnalyticsEnvelope, meta?: AnalyticsFlushMeta) => void | Promise<void>;
|
|
95
114
|
|
|
96
115
|
/**
|
|
97
116
|
* Mapeo del envelope de analytics → body de `POST /sdk/feedback`.
|
|
98
117
|
*
|
|
99
118
|
* La analítica se envía como un Feedback del modelo del Surveys SDK, agrupado por una
|
|
100
|
-
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false
|
|
101
|
-
*
|
|
119
|
+
* INTEGRACIÓN creada en la plataforma. Se manda en streaming con `completed:false`; el
|
|
120
|
+
* backend cose por `sessionId` + `user_id`. El ÚLTIMO lote de una sesión (cierre de página,
|
|
121
|
+
* app a background, cambio de usuario) va con `completed:true`: cierra el registro y el
|
|
122
|
+
* siguiente lote omite el `sessionId` viejo para que el backend abra uno nuevo.
|
|
123
|
+
* `feedback.finished` se queda siempre en `false` (no es la señal de cierre acordada).
|
|
102
124
|
*
|
|
103
125
|
* Encoding:
|
|
104
126
|
* - todo va en `feedback.metadata`: contexto (user_id, session_id, platform…) + eventos
|
|
@@ -134,7 +156,15 @@ interface AnalyticsFeedbackBody {
|
|
|
134
156
|
/** sessionId devuelto por el primer POST; permite que el backend agrupe todos los eventos en un solo registro. */
|
|
135
157
|
sessionId?: string;
|
|
136
158
|
}
|
|
137
|
-
|
|
159
|
+
interface BuildBodyOptions {
|
|
160
|
+
/**
|
|
161
|
+
* `true` en el último lote de la sesión → `completed:true` (cierra el registro en backend).
|
|
162
|
+
* El body SÍ lleva el `sessionId` actual (es el registro que se cierra); es el lote
|
|
163
|
+
* SIGUIENTE el que lo omite.
|
|
164
|
+
*/
|
|
165
|
+
sessionEnd?: boolean;
|
|
166
|
+
}
|
|
167
|
+
declare function buildAnalyticsFeedbackBody(envelope: AnalyticsEnvelope, keys: AnalyticsKeys, feedbackSessionId?: string, options?: BuildBodyOptions): AnalyticsFeedbackBody;
|
|
138
168
|
interface FeedbackSinkOptions {
|
|
139
169
|
/** Base URL del backend (api(.|-dev.)deepdots.com) ya resuelta por el entorno. */
|
|
140
170
|
baseUrl: string;
|
|
@@ -143,15 +173,31 @@ interface FeedbackSinkOptions {
|
|
|
143
173
|
log?: (...args: unknown[]) => void;
|
|
144
174
|
/** fetch inyectable (tests / RN). */
|
|
145
175
|
fetchImpl?: typeof fetch;
|
|
176
|
+
/**
|
|
177
|
+
* `navigator.sendBeacon` inyectable. Solo se usa en el flush final (cierre de página):
|
|
178
|
+
* sobrevive al unload, a cambio de no poder leer la respuesta. Si no se pasa, el flush
|
|
179
|
+
* final usa `fetch` con `keepalive`.
|
|
180
|
+
*/
|
|
181
|
+
sendBeaconImpl?: (url: string, body: Blob | string) => boolean;
|
|
146
182
|
/** Callback invocado cuando el backend devuelve un nuevo sessionId (primer POST). */
|
|
147
183
|
onSessionId?: (id: string) => void;
|
|
184
|
+
/** Callback invocado al cerrar la sesión (`completed:true`): el sessionId cacheado se olvida. */
|
|
185
|
+
onSessionReset?: () => void;
|
|
148
186
|
}
|
|
149
187
|
/**
|
|
150
188
|
* Sink real: transforma el envelope y hace `POST {baseUrl}/sdk/feedback`.
|
|
151
|
-
*
|
|
152
|
-
* Stateful: cachea el `sessionId` que devuelve el backend en la primera respuesta
|
|
153
|
-
*
|
|
154
|
-
*
|
|
189
|
+
*
|
|
190
|
+
* Stateful: cachea el `sessionId` que devuelve el backend en la primera respuesta y lo
|
|
191
|
+
* envía en los siguientes POSTs para que el backend agrupe todos los eventos en un único
|
|
192
|
+
* registro de feedback.
|
|
193
|
+
*
|
|
194
|
+
* Garantías de entrega:
|
|
195
|
+
* - mientras no se conozca el `sessionId`, los lotes se **serializan** (esperan la primera
|
|
196
|
+
* respuesta): dos POSTs a la vez sin `sessionId` crearían dos registros y partirían los datos;
|
|
197
|
+
* - `keepalive` para que el navegador no cancele el POST al navegar fuera, y `sendBeacon`
|
|
198
|
+
* en el flush final (cierre de página), donde `fetch` puede morir con el documento;
|
|
199
|
+
* - la promesa **rechaza** en fallo transitorio (red, 5xx, 408, 429) para que el
|
|
200
|
+
* `AnalyticsManager` re-encole el lote; un 4xx se loguea y se descarta.
|
|
155
201
|
*/
|
|
156
202
|
declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink;
|
|
157
203
|
|
|
@@ -190,9 +236,11 @@ interface DeepdotsInitParams {
|
|
|
190
236
|
/** Platform used in the analytics envelope. Default is 'web'; in RN pass 'android'/'ios'. */
|
|
191
237
|
platform?: 'web' | 'android' | 'ios';
|
|
192
238
|
/**
|
|
193
|
-
* BCP-47 language tag
|
|
194
|
-
*
|
|
195
|
-
*
|
|
239
|
+
* BCP-47 language tag (e.g. 'es-ES') used for the analytics context AND for popup
|
|
240
|
+
* language segmentation (`segments.lang`). If omitted, the SDK auto-detects:
|
|
241
|
+
* `navigator.language` on web, or the `Intl` locale as a fallback (works in
|
|
242
|
+
* React Native with Hermes, where `navigator.language` is absent). If no source
|
|
243
|
+
* resolves a language, popups with `segments.lang` cannot be filtered and are shown.
|
|
196
244
|
*/
|
|
197
245
|
language?: string;
|
|
198
246
|
/** Injectable device info (RN: from react-native-device-info). If missing, it is derived from the browser. */
|
|
@@ -247,6 +295,16 @@ interface DeepdotsEvent {
|
|
|
247
295
|
* Event listener callback
|
|
248
296
|
*/
|
|
249
297
|
type EventListener = (event: DeepdotsEvent) => void;
|
|
298
|
+
/**
|
|
299
|
+
* Motivo del `deepdots_session_end` (último lote de la sesión, enviado con `completed:true`):
|
|
300
|
+
* - `page_hide`: la página web se cierra o se navega fuera (`pagehide`).
|
|
301
|
+
* - `background`: la app pasa a background (RN/nativo). Única señal disponible en móvil:
|
|
302
|
+
* el kill de la app por el usuario o el SO NO produce ningún callback.
|
|
303
|
+
* - `user_change`: `setUserId()` o un `init()` con otro `userId` (login/logout del host).
|
|
304
|
+
* - `tracking_disabled`: `setTrackingEnabled(false)` (consentimiento revocado).
|
|
305
|
+
* - `manual`: `endSession()` llamado por el host.
|
|
306
|
+
*/
|
|
307
|
+
type SessionEndReason = 'page_hide' | 'background' | 'user_change' | 'tracking_disabled' | 'manual';
|
|
250
308
|
/** Trigger type used by remote popup definitions */
|
|
251
309
|
type PopupTriggerType = 'time_on_page' | 'scroll' | 'exit' | 'click' | 'event';
|
|
252
310
|
type PopupTriggerConditionStatus = 'SHOWED' | 'PARTIAL' | 'COMPLETED';
|
|
@@ -469,13 +527,16 @@ declare class CrashReporter {
|
|
|
469
527
|
* el funnel se correlaciona por `message_id` y se agrupa por `message_title`.
|
|
470
528
|
*/
|
|
471
529
|
type MessageStage = 'delivered' | 'clicked' | 'converted';
|
|
530
|
+
/** Canales válidos. Un mensaje tiene UN canal: se valida en runtime porque el host puede no ser TS. */
|
|
531
|
+
declare const MESSAGE_CHANNELS: readonly ["push", "in_app"];
|
|
532
|
+
type MessageChannel = (typeof MESSAGE_CHANNELS)[number];
|
|
472
533
|
interface TrackMessageOptions {
|
|
473
534
|
/** Identificador del mensaje/notificación — correlaciona el funnel delivered→clicked→converted. */
|
|
474
535
|
id: string;
|
|
475
536
|
/** Título del mensaje — dimensión de agrupación de #18–22. */
|
|
476
537
|
title: string;
|
|
477
538
|
/** Canal de entrega. */
|
|
478
|
-
channel:
|
|
539
|
+
channel: MessageChannel;
|
|
479
540
|
/** Nombre de la campaña (opcional). */
|
|
480
541
|
campaign?: string;
|
|
481
542
|
/** Valor de conversión (opcional, típico en `stage: 'converted'`). */
|
|
@@ -486,6 +547,38 @@ interface TrackMessageOptions {
|
|
|
486
547
|
}
|
|
487
548
|
/** Construye los params del evento `deepdots_message` (omite opcionales ausentes). */
|
|
488
549
|
declare function buildMessageParams(stage: MessageStage, o: TrackMessageOptions): Record<string, unknown>;
|
|
550
|
+
/** Techo de `message_id` vigilados por sesión; los más antiguos se evictan (memoria acotada). */
|
|
551
|
+
declare const MAX_TRACKED_MESSAGES = 500;
|
|
552
|
+
type MessageRejectionReason = 'invalid_channel' | 'duplicate_stage' | 'channel_conflict';
|
|
553
|
+
type MessageGuardVerdict = {
|
|
554
|
+
emit: true;
|
|
555
|
+
} | {
|
|
556
|
+
emit: false;
|
|
557
|
+
reason: MessageRejectionReason;
|
|
558
|
+
detail: string;
|
|
559
|
+
};
|
|
560
|
+
/**
|
|
561
|
+
* Protege el funnel de Messaging de las formas imposibles que el host puede producir por error
|
|
562
|
+
* (visto en producción: CTR > 100% por falta de `delivered` + el mismo `message_id` reportado en
|
|
563
|
+
* dos canales). Tres reglas, todas dentro de la sesión (se reinicia en cada `init()`):
|
|
564
|
+
*
|
|
565
|
+
* 1. `channel` fuera de `MESSAGE_CHANNELS` → se descarta el evento.
|
|
566
|
+
* 2. Un `(message_id, stage)` ya emitido → se emite una sola vez.
|
|
567
|
+
* 3. Un `message_id` ya visto en un canal → se descartan los eventos de otro canal.
|
|
568
|
+
*
|
|
569
|
+
* Los eventos rechazados NO mutan el estado: un rechazo nunca "consume" el stage bueno.
|
|
570
|
+
* Lo que el SDK no puede arreglar es la ausencia de `delivered`: eso lo instrumenta el host.
|
|
571
|
+
*/
|
|
572
|
+
declare class MessageGuard {
|
|
573
|
+
private maxTrackedMessages;
|
|
574
|
+
/** message_id → canal fijado + stages ya emitidos. El orden de inserción marca la eviction. */
|
|
575
|
+
private seen;
|
|
576
|
+
constructor(maxTrackedMessages?: number);
|
|
577
|
+
evaluate(stage: MessageStage, options: TrackMessageOptions): MessageGuardVerdict;
|
|
578
|
+
/** Olvida todo lo vigilado (nueva sesión). */
|
|
579
|
+
reset(): void;
|
|
580
|
+
private remember;
|
|
581
|
+
}
|
|
489
582
|
|
|
490
583
|
/**
|
|
491
584
|
* Main class for managing survey popups
|
|
@@ -519,14 +612,29 @@ declare class DeepdotsPopups {
|
|
|
519
612
|
private analyticsFlushTimer;
|
|
520
613
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
521
614
|
private crashReporter;
|
|
615
|
+
/** Protecciones del funnel de Messaging (#18–22). Vigencia de sesión: se reinicia en init(). */
|
|
616
|
+
private messageGuard;
|
|
522
617
|
/** Observador de navegación (Fase 2): emite page_view por el canal de analytics. */
|
|
523
618
|
private navObserver;
|
|
524
619
|
/** Tiempo activo (engagement time, #8). */
|
|
525
620
|
private engagement;
|
|
526
621
|
/** Atributos internos del usuario identificado → POST /sdk/popups/contact. Null si no hay userId. */
|
|
527
622
|
private contact;
|
|
623
|
+
/** Storage resuelto en init() (inyectado por el host o localStorage). Reusado al cambiar de usuario. */
|
|
624
|
+
private storage;
|
|
528
625
|
/** Marca si ya se inició la navegación manual (setScreen) — para RN sin History API. */
|
|
529
626
|
private navStarted;
|
|
627
|
+
/**
|
|
628
|
+
* `true` entre `session_start` y `session_end`. Hace idempotente tanto la apertura como
|
|
629
|
+
* el cierre (p. ej. `visibilitychange` + `pagehide` seguidos) y permite abrir una sesión
|
|
630
|
+
* nueva al volver a foreground o al conceder el consentimiento más tarde.
|
|
631
|
+
*/
|
|
632
|
+
private sessionOpen;
|
|
633
|
+
/**
|
|
634
|
+
* Idioma resuelto en init() (explícito > navigator.language > Intl). Única fuente de
|
|
635
|
+
* verdad para el context de analytics Y para la segmentación por idioma de los popups.
|
|
636
|
+
*/
|
|
637
|
+
private language;
|
|
530
638
|
/** Initialize the SDK with configuration */
|
|
531
639
|
init(config: DeepdotsInitParams): void;
|
|
532
640
|
/** User id actual (generado por el SDK o provisto por el cliente). Null si tracking off. */
|
|
@@ -565,24 +673,66 @@ declare class DeepdotsPopups {
|
|
|
565
673
|
trackFindabilityFriction(frictionTopic: string, params?: Record<string, unknown>): void;
|
|
566
674
|
/** Funnel: un paso del embudo, correlacionado por `taskId`. El backend reconstruye conversión/drop-off/tiempo. */
|
|
567
675
|
trackFunnelStep(funnel: string, step: string, taskId: string, params?: Record<string, unknown>): void;
|
|
568
|
-
/**
|
|
676
|
+
/**
|
|
677
|
+
* Messaging (#18–22): registra una etapa del funnel de una notificación (push/in-app).
|
|
678
|
+
* No-op si tracking off. El evento se descarta (con warning) si el `channel` no es válido,
|
|
679
|
+
* si ese `(message_id, stage)` ya se emitió en la sesión, o si el `message_id` ya se reportó
|
|
680
|
+
* en otro canal — ver `MessageGuard`.
|
|
681
|
+
*/
|
|
569
682
|
trackMessage(stage: MessageStage, options: TrackMessageOptions): void;
|
|
570
683
|
/**
|
|
571
684
|
* Navegación MANUAL (entornos sin History API, p. ej. React Native con React Navigation).
|
|
572
685
|
* El host la llama en cada cambio de pantalla; emite `page_view` al salir de la anterior.
|
|
573
686
|
*/
|
|
574
687
|
setScreen(name: string): void;
|
|
575
|
-
/** App a foreground (RN: AppState 'active'): reanuda el engagement time. */
|
|
688
|
+
/** App a foreground (RN: AppState 'active'): reanuda el engagement time y abre sesión nueva. */
|
|
576
689
|
onForeground(): void;
|
|
577
690
|
/**
|
|
578
|
-
* App a background (RN: AppState 'background'):
|
|
579
|
-
* mini-
|
|
691
|
+
* App a background (RN: AppState 'background'): FIN DE SESIÓN. Cierra pantalla actual
|
|
692
|
+
* (page_view), mini-services (mini_service_exit), emite engagement + `session_end` y
|
|
693
|
+
* envía el último lote con `completed:true`.
|
|
694
|
+
*
|
|
695
|
+
* Es la única señal disponible en móvil: el kill de la app (swipe) NO da callback.
|
|
580
696
|
*/
|
|
581
697
|
onBackground(): void;
|
|
698
|
+
/**
|
|
699
|
+
* Cierre EXPLÍCITO de la sesión por parte del host (logout, fin de flujo…): emite
|
|
700
|
+
* `session_end` y envía el último lote con `completed:true`.
|
|
701
|
+
*/
|
|
702
|
+
endSession(): void;
|
|
703
|
+
/**
|
|
704
|
+
* Cambio de usuario (login / logout / cambio de cuenta). Cierra la sesión del usuario
|
|
705
|
+
* anterior (`session_end` con `reason: 'user_change'` + `completed:true`), cambia la
|
|
706
|
+
* identidad y abre una sesión nueva. Sin `userId` vuelve al id anónimo del SDK.
|
|
707
|
+
*
|
|
708
|
+
* Equivale a llamar a `init()` otra vez con otro `userId`.
|
|
709
|
+
*/
|
|
710
|
+
setUserId(userId?: string): void;
|
|
711
|
+
/**
|
|
712
|
+
* Cierra la sesión actual: vuelca todo lo que quedaba abierto y envía el último lote
|
|
713
|
+
* marcado con `completed:true`, para que el backend cierre el registro. El `sessionId`
|
|
714
|
+
* cacheado se olvida → el lote siguiente abre un registro nuevo.
|
|
715
|
+
*
|
|
716
|
+
* Idempotente: dos cierres seguidos (p. ej. `visibilitychange` + `pagehide`) no duplican
|
|
717
|
+
* el `session_end`.
|
|
718
|
+
*/
|
|
719
|
+
private closeSession;
|
|
720
|
+
/**
|
|
721
|
+
* Abre sesión (`session_start`) si no hay una abierta y el tracking está activo. Idempotente:
|
|
722
|
+
* se llama en init(), al volver a foreground y al conceder el consentimiento.
|
|
723
|
+
*/
|
|
724
|
+
private openSession;
|
|
582
725
|
/** Payload que se ENVIARÍA al endpoint de analytics (no envía ni vacía el buffer). */
|
|
583
726
|
previewAnalytics(): AnalyticsEnvelope;
|
|
584
|
-
/**
|
|
585
|
-
|
|
727
|
+
/**
|
|
728
|
+
* Envía el lote acumulado de analytics y vacía el buffer.
|
|
729
|
+
* `final: true` (cierre de página/app) cambia el transporte a `sendBeacon`, que sobrevive
|
|
730
|
+
* al unload; un lote que falle por red o 5xx se re-encola para el siguiente flush.
|
|
731
|
+
*/
|
|
732
|
+
flushAnalytics(options?: {
|
|
733
|
+
final?: boolean;
|
|
734
|
+
sessionEnd?: boolean;
|
|
735
|
+
}): void;
|
|
586
736
|
/** Emite un evento `user_engagement` con el tiempo activo acumulado (#8). */
|
|
587
737
|
private flushEngagement;
|
|
588
738
|
private analyticsIdentity;
|
|
@@ -775,4 +925,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
775
925
|
*/
|
|
776
926
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
777
927
|
|
|
778
|
-
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, type MessageStage, type MmkvLike, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, mmkvStorage, setupReactNative };
|
|
928
|
+
export { type AnalyticsFeedbackBody, type AnalyticsKeys, type AppStateLike, BrowserPopupRenderer, type BuildBodyOptions, type ContactAttributeValue, type ContactAttributes, type ContactBody, ContactManager, type CrashRecord, CrashReporter, type CrashSeverity, type DeepdotsConfig, type DeepdotsEvent, type DeepdotsEventType, type DeepdotsInitParams, type DeepdotsLogger, DeepdotsPopups, type DeviceInfo, type DeviceInfoLike, type DeviceSnapshot, type EventListener, type FeedbackKV, InMemoryStorage, type KeyValueStorage, MAX_TRACKED_MESSAGES, MESSAGE_CHANNELS, type MessageChannel, MessageGuard, type MessageGuardVerdict, type MessageRejectionReason, type MessageStage, type MmkvLike, NoopPopupRenderer, POPUP_TRIGGER_CONDITION_STATUSES, type PopupDefinition, type PopupRenderer, type PopupTrigger, type PopupTriggerCondition, type PopupTriggerConditionStatus, type ReactNativeErrorUtils, ReactNativePopupRenderer, type ReactNativeRendererOptions, type ReactNativeSetupDeps, type ReactNativeSurveyPayload, type ReportErrorOptions, type SessionEndReason, type TrackMessageOptions, type TriggerConfig, buildAnalyticsFeedbackBody, buildMessageParams, buildSurveyHtml, collectRnDevice, crashRecordToParams, createDefaultRenderer, createFeedbackSink, mmkvStorage, setupReactNative };
|