@magicfeedback/popup-sdk 1.1.5 → 1.1.7
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/{chunk-LSTKGFU7.mjs → chunk-4UXOEIAB.mjs} +21 -2
- package/dist/chunk-4UXOEIAB.mjs.map +1 -0
- package/dist/{chunk-7TOLYAFL.mjs → chunk-XOTM5CHX.mjs} +21 -2
- package/dist/chunk-XOTM5CHX.mjs.map +1 -0
- package/dist/index.d.mts +32 -2
- package/dist/index.d.ts +32 -2
- package/dist/index.js +167 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +141 -24
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +30 -1
- package/dist/react-native.d.ts +30 -1
- package/dist/react-native.js +167 -26
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +141 -24
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-MES7IINW.mjs → renderPopup-EZKDMLVZ.mjs} +10 -7
- package/dist/renderPopup-EZKDMLVZ.mjs.map +1 -0
- package/dist/{renderPopup-YNH2TD3B.mjs → renderPopup-PS3NJDUR.mjs} +10 -7
- package/dist/renderPopup-PS3NJDUR.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-7TOLYAFL.mjs.map +0 -1
- package/dist/chunk-LSTKGFU7.mjs.map +0 -1
- package/dist/renderPopup-MES7IINW.mjs.map +0 -1
- package/dist/renderPopup-YNH2TD3B.mjs.map +0 -1
|
@@ -141,6 +141,21 @@ function buildFontFaceCss(family, url) {
|
|
|
141
141
|
return `@font-face{font-family:"${safe}";src:${src};font-display:swap;}`;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
// src/util/logger.ts
|
|
145
|
+
var active = console;
|
|
146
|
+
function setLogger(logger) {
|
|
147
|
+
active = logger ?? console;
|
|
148
|
+
}
|
|
149
|
+
function sdkLog(...args) {
|
|
150
|
+
active.log(...args);
|
|
151
|
+
}
|
|
152
|
+
function sdkWarn(...args) {
|
|
153
|
+
(active.warn ?? active.log)(...args);
|
|
154
|
+
}
|
|
155
|
+
function sdkError(...args) {
|
|
156
|
+
(active.error ?? active.log)(...args);
|
|
157
|
+
}
|
|
158
|
+
|
|
144
159
|
export {
|
|
145
160
|
__require,
|
|
146
161
|
createDefaultStorage,
|
|
@@ -148,6 +163,10 @@ export {
|
|
|
148
163
|
buildSurveyIdentity,
|
|
149
164
|
TrackingManager,
|
|
150
165
|
buildFontFamilyValue,
|
|
151
|
-
buildFontFaceCss
|
|
166
|
+
buildFontFaceCss,
|
|
167
|
+
setLogger,
|
|
168
|
+
sdkLog,
|
|
169
|
+
sdkWarn,
|
|
170
|
+
sdkError
|
|
152
171
|
};
|
|
153
|
-
//# sourceMappingURL=chunk-
|
|
172
|
+
//# sourceMappingURL=chunk-4UXOEIAB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracking/tracking-manager.ts","../src/ui/font.ts","../src/util/logger.ts"],"sourcesContent":["/**\n * Identidad + sesión para el tracking de navegación (Fase 1).\n * Implementa el \"Contrato común Web+KMP\".\n *\n * Modelo: el SDK gestiona el `user_id` (persistente). El `session_id` es propiedad\n * del BACKEND: llega en la respuesta de `POST /sdk/popups` y se cachea; el backend\n * cose sesiones por `user_id` + ventana. El SDK NO genera ni expira sesiones.\n *\n * Sin dependencias de DOM: recibe el storage y (opcionalmente) el reloj y el\n * generador de uuid por inyección. El binding a `localStorage` vive en `createDefaultStorage`.\n */\n\n/** Store clave/valor mínimo (espejo conceptual del `KeyValueStorage` de KMP). */\nexport interface KeyValueStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/** Impl en memoria — usada en tests y como fallback sin `localStorage`. */\nexport class InMemoryStorage implements KeyValueStorage {\n private map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** Storage por defecto en Web: `localStorage` si está disponible, si no in-memory. */\nexport function createDefaultStorage(): KeyValueStorage {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const ls = window.localStorage;\n const probe = '__deepdots_probe__';\n ls.setItem(probe, '1');\n ls.removeItem(probe);\n return {\n getItem: (k) => ls.getItem(k),\n setItem: (k, v) => ls.setItem(k, v),\n removeItem: (k) => ls.removeItem(k),\n };\n }\n } catch {\n // cae a in-memory\n }\n return new InMemoryStorage();\n}\n\n/** Claves de storage — namespace `deepdots.*`. Solo identidad (la sesión no se persiste). */\nexport const STORAGE_KEYS = {\n userId: 'deepdots.user_id',\n firstSeen: 'deepdots.user.first_seen',\n contactAttributes: 'deepdots.contact.attributes',\n} as const;\n\n/** Par clave/valor con el formato `NativeAnswer` que espera `@magicfeedback/native`. */\nexport interface IdentityAnswer {\n key: string;\n value: string[];\n}\n\n/**\n * Construye el `profile` y el `metadata` de identidad para inyectar en el survey\n * (`magicfeedback.form(appId, publicKey, profile, metadata)`), según el contrato §5.\n * `session_id` solo se incluye si el backend ya lo proveyó.\n */\nexport function buildSurveyIdentity(\n userId: string | null,\n sessionId: string | null,\n miniService: string | null = null,\n analyticsFeedbackSessionId: string | null = null,\n): { profile: IdentityAnswer[]; metadata: IdentityAnswer[] } {\n const profile: IdentityAnswer[] = userId ? [{ key: 'external-user-id', value: [userId] }] : [];\n const metadata: IdentityAnswer[] = [];\n if (sessionId) metadata.push({ key: 'session_id', value: [sessionId] });\n if (userId) metadata.push({ key: 'user_id', value: [userId] });\n if (miniService) metadata.push({ key: 'mini_service', value: [miniService] });\n if (analyticsFeedbackSessionId) metadata.push({ key: 'deepdots_analytics_feedback_session_id', value: [analyticsFeedbackSessionId] });\n return { profile, metadata };\n}\n\nexport interface TrackingManagerOptions {\n storage: KeyValueStorage;\n /** Id provisto por el cliente; si existe se usa y NO se persiste. */\n clientUserId?: string;\n /** Reloj inyectable (default `Date.now`). */\n now?: () => number;\n /** Generador de uuid inyectable (default uuid v4). */\n uuid?: () => string;\n /** Estado inicial del tracking (default `true`). */\n enabled?: boolean;\n}\n\nfunction defaultUuid(): string {\n const g = (typeof globalThis !== 'undefined' ? globalThis : {}) as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n const bytes = new Uint8Array(16);\n if (g.crypto?.getRandomValues) {\n g.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex\n .slice(6, 8)\n .join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`;\n}\n\nexport class TrackingManager {\n private storage: KeyValueStorage;\n private clientUserId?: string;\n private now: () => number;\n private uuid: () => string;\n private enabled: boolean;\n\n /** session_id cacheado, provisto por el backend (no se genera ni se persiste). */\n private sessionId: string | null = null;\n private userWasJustCreated = false;\n\n constructor(options: TrackingManagerOptions) {\n this.storage = options.storage;\n this.clientUserId = options.clientUserId;\n this.now = options.now ?? (() => Date.now());\n this.uuid = options.uuid ?? defaultUuid;\n this.enabled = options.enabled ?? true;\n }\n\n isTrackingEnabled(): boolean {\n return this.enabled;\n }\n\n setTrackingEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /** Resuelve el user_id según la regla: cliente > persistido > generar+persistir. */\n getUserId(): string | null {\n if (!this.enabled) return null;\n if (this.clientUserId) return this.clientUserId;\n\n const persisted = this.storage.getItem(STORAGE_KEYS.userId);\n if (persisted) return persisted;\n\n const id = this.uuid();\n this.storage.setItem(STORAGE_KEYS.userId, id);\n this.storage.setItem(STORAGE_KEYS.firstSeen, String(this.now()));\n this.userWasJustCreated = true;\n return id;\n }\n\n /** `true` solo en la primera sesión tras crear el user_id propio del SDK. */\n isNewUser(): boolean {\n return this.userWasJustCreated;\n }\n\n /** session_id actual provisto por el backend, o null si aún no llegó. */\n getSessionId(): string | null {\n if (!this.enabled) return null;\n return this.sessionId;\n }\n\n /** Cachea el session_id devuelto por el backend (respuesta de POST /sdk/popups). */\n setSessionId(sessionId: string | null): void {\n if (!this.enabled) return;\n this.sessionId = sessionId;\n }\n}\n","/**\n * Helpers puros (sin DOM) para la fuente personalizable del popup/survey.\n * Espejo exacto en KMP: `ui/Font.kt`. Cualquier cambio aquí se replica allí.\n */\n\nconst FORMAT_BY_EXT: Record<string, string> = {\n woff2: 'woff2',\n woff: 'woff',\n ttf: 'truetype',\n otf: 'opentype',\n};\n\n/** Deriva el `format()` del `@font-face` a partir de la extensión de la URL. */\nexport function fontFormatFromUrl(url: string): string | undefined {\n const clean = url.split('?')[0].split('#')[0];\n const ext = clean.slice(clean.lastIndexOf('.') + 1).toLowerCase();\n return FORMAT_BY_EXT[ext];\n}\n\n// family/url provienen de la API y se interpolan en CSS y en el <style> del HTML del WebView.\n// Saneamos para evitar romper el string/rule (CSS injection) o cerrar </style> (script injection).\nfunction sanitizeFamily(family: string): string {\n return family.replace(/[^A-Za-z0-9 ._-]/g, '').trim();\n}\n\nfunction isSafeFontUrl(url: string): boolean {\n // Solo http(s)/data y sin caracteres que rompan url(\"...\") o el <style>:\n // comillas, <>, backslash, y cualquier whitespace o carácter de control.\n if (!/^(https?:|data:)/i.test(url)) return false;\n // eslint-disable-next-line no-control-regex\n return !/[\\x00-\\x20\"<>\\\\]/.test(url);\n}\n\n/** Valor a aplicar en `font-family`: nombre custom + fallback de sistema. */\nexport function buildFontFamilyValue(family: string): string {\n const safe = sanitizeFamily(family);\n return `\"${safe}\", -apple-system, system-ui, sans-serif`;\n}\n\n/** CSS del `@font-face`. Devuelve \"\" si no hay url (o no es segura). */\nexport function buildFontFaceCss(family: string, url?: string): string {\n if (!url || !isSafeFontUrl(url)) return '';\n const safe = sanitizeFamily(family);\n const fmt = fontFormatFromUrl(url);\n const src = fmt ? `url(\"${url}\") format(\"${fmt}\")` : `url(\"${url}\")`;\n return `@font-face{font-family:\"${safe}\";src:${src};font-display:swap;}`;\n}\n","import type { DeepdotsLogger } from '../types';\n\n/**\n * Logger de módulo compartido: el core lo fija en init() con el logger inyectado\n * por el host (o `console` por defecto), y los módulos que no reciben `this`\n * (renderPopup, renderers) enrutan por aquí. `warn`/`error` caen a `log` si el\n * logger del host no los provee (solo `log` es obligatorio en DeepdotsLogger).\n */\nlet active: DeepdotsLogger = console;\n\nexport function setLogger(logger: DeepdotsLogger | undefined): void {\n active = logger ?? console;\n}\n\nexport function sdkLog(...args: unknown[]): void {\n active.log(...args);\n}\n\nexport function sdkWarn(...args: unknown[]): void {\n (active.warn ?? active.log)(...args);\n}\n\nexport function sdkError(...args: unknown[]): void {\n (active.error ?? active.log)(...args);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -160,6 +160,21 @@ function buildFontFaceCss(family, url) {
|
|
|
160
160
|
return `@font-face{font-family:"${safe}";src:${src};font-display:swap;}`;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
// src/util/logger.ts
|
|
164
|
+
var active = console;
|
|
165
|
+
function setLogger(logger) {
|
|
166
|
+
active = logger ?? console;
|
|
167
|
+
}
|
|
168
|
+
function sdkLog(...args) {
|
|
169
|
+
active.log(...args);
|
|
170
|
+
}
|
|
171
|
+
function sdkWarn(...args) {
|
|
172
|
+
(active.warn ?? active.log)(...args);
|
|
173
|
+
}
|
|
174
|
+
function sdkError(...args) {
|
|
175
|
+
(active.error ?? active.log)(...args);
|
|
176
|
+
}
|
|
177
|
+
|
|
163
178
|
export {
|
|
164
179
|
__commonJS,
|
|
165
180
|
__toESM,
|
|
@@ -169,6 +184,10 @@ export {
|
|
|
169
184
|
buildSurveyIdentity,
|
|
170
185
|
TrackingManager,
|
|
171
186
|
buildFontFamilyValue,
|
|
172
|
-
buildFontFaceCss
|
|
187
|
+
buildFontFaceCss,
|
|
188
|
+
setLogger,
|
|
189
|
+
sdkLog,
|
|
190
|
+
sdkWarn,
|
|
191
|
+
sdkError
|
|
173
192
|
};
|
|
174
|
-
//# sourceMappingURL=chunk-
|
|
193
|
+
//# sourceMappingURL=chunk-XOTM5CHX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tracking/tracking-manager.ts","../src/ui/font.ts","../src/util/logger.ts"],"sourcesContent":["/**\n * Identidad + sesión para el tracking de navegación (Fase 1).\n * Implementa el \"Contrato común Web+KMP\".\n *\n * Modelo: el SDK gestiona el `user_id` (persistente). El `session_id` es propiedad\n * del BACKEND: llega en la respuesta de `POST /sdk/popups` y se cachea; el backend\n * cose sesiones por `user_id` + ventana. El SDK NO genera ni expira sesiones.\n *\n * Sin dependencias de DOM: recibe el storage y (opcionalmente) el reloj y el\n * generador de uuid por inyección. El binding a `localStorage` vive en `createDefaultStorage`.\n */\n\n/** Store clave/valor mínimo (espejo conceptual del `KeyValueStorage` de KMP). */\nexport interface KeyValueStorage {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n}\n\n/** Impl en memoria — usada en tests y como fallback sin `localStorage`. */\nexport class InMemoryStorage implements KeyValueStorage {\n private map = new Map<string, string>();\n getItem(key: string): string | null {\n return this.map.has(key) ? (this.map.get(key) as string) : null;\n }\n setItem(key: string, value: string): void {\n this.map.set(key, value);\n }\n removeItem(key: string): void {\n this.map.delete(key);\n }\n}\n\n/** Storage por defecto en Web: `localStorage` si está disponible, si no in-memory. */\nexport function createDefaultStorage(): KeyValueStorage {\n try {\n if (typeof window !== 'undefined' && window.localStorage) {\n const ls = window.localStorage;\n const probe = '__deepdots_probe__';\n ls.setItem(probe, '1');\n ls.removeItem(probe);\n return {\n getItem: (k) => ls.getItem(k),\n setItem: (k, v) => ls.setItem(k, v),\n removeItem: (k) => ls.removeItem(k),\n };\n }\n } catch {\n // cae a in-memory\n }\n return new InMemoryStorage();\n}\n\n/** Claves de storage — namespace `deepdots.*`. Solo identidad (la sesión no se persiste). */\nexport const STORAGE_KEYS = {\n userId: 'deepdots.user_id',\n firstSeen: 'deepdots.user.first_seen',\n contactAttributes: 'deepdots.contact.attributes',\n} as const;\n\n/** Par clave/valor con el formato `NativeAnswer` que espera `@magicfeedback/native`. */\nexport interface IdentityAnswer {\n key: string;\n value: string[];\n}\n\n/**\n * Construye el `profile` y el `metadata` de identidad para inyectar en el survey\n * (`magicfeedback.form(appId, publicKey, profile, metadata)`), según el contrato §5.\n * `session_id` solo se incluye si el backend ya lo proveyó.\n */\nexport function buildSurveyIdentity(\n userId: string | null,\n sessionId: string | null,\n miniService: string | null = null,\n analyticsFeedbackSessionId: string | null = null,\n): { profile: IdentityAnswer[]; metadata: IdentityAnswer[] } {\n const profile: IdentityAnswer[] = userId ? [{ key: 'external-user-id', value: [userId] }] : [];\n const metadata: IdentityAnswer[] = [];\n if (sessionId) metadata.push({ key: 'session_id', value: [sessionId] });\n if (userId) metadata.push({ key: 'user_id', value: [userId] });\n if (miniService) metadata.push({ key: 'mini_service', value: [miniService] });\n if (analyticsFeedbackSessionId) metadata.push({ key: 'deepdots_analytics_feedback_session_id', value: [analyticsFeedbackSessionId] });\n return { profile, metadata };\n}\n\nexport interface TrackingManagerOptions {\n storage: KeyValueStorage;\n /** Id provisto por el cliente; si existe se usa y NO se persiste. */\n clientUserId?: string;\n /** Reloj inyectable (default `Date.now`). */\n now?: () => number;\n /** Generador de uuid inyectable (default uuid v4). */\n uuid?: () => string;\n /** Estado inicial del tracking (default `true`). */\n enabled?: boolean;\n}\n\nfunction defaultUuid(): string {\n const g = (typeof globalThis !== 'undefined' ? globalThis : {}) as {\n crypto?: { randomUUID?: () => string; getRandomValues?: (a: Uint8Array) => Uint8Array };\n };\n if (g.crypto?.randomUUID) return g.crypto.randomUUID();\n const bytes = new Uint8Array(16);\n if (g.crypto?.getRandomValues) {\n g.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\n }\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex\n .slice(6, 8)\n .join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`;\n}\n\nexport class TrackingManager {\n private storage: KeyValueStorage;\n private clientUserId?: string;\n private now: () => number;\n private uuid: () => string;\n private enabled: boolean;\n\n /** session_id cacheado, provisto por el backend (no se genera ni se persiste). */\n private sessionId: string | null = null;\n private userWasJustCreated = false;\n\n constructor(options: TrackingManagerOptions) {\n this.storage = options.storage;\n this.clientUserId = options.clientUserId;\n this.now = options.now ?? (() => Date.now());\n this.uuid = options.uuid ?? defaultUuid;\n this.enabled = options.enabled ?? true;\n }\n\n isTrackingEnabled(): boolean {\n return this.enabled;\n }\n\n setTrackingEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /** Resuelve el user_id según la regla: cliente > persistido > generar+persistir. */\n getUserId(): string | null {\n if (!this.enabled) return null;\n if (this.clientUserId) return this.clientUserId;\n\n const persisted = this.storage.getItem(STORAGE_KEYS.userId);\n if (persisted) return persisted;\n\n const id = this.uuid();\n this.storage.setItem(STORAGE_KEYS.userId, id);\n this.storage.setItem(STORAGE_KEYS.firstSeen, String(this.now()));\n this.userWasJustCreated = true;\n return id;\n }\n\n /** `true` solo en la primera sesión tras crear el user_id propio del SDK. */\n isNewUser(): boolean {\n return this.userWasJustCreated;\n }\n\n /** session_id actual provisto por el backend, o null si aún no llegó. */\n getSessionId(): string | null {\n if (!this.enabled) return null;\n return this.sessionId;\n }\n\n /** Cachea el session_id devuelto por el backend (respuesta de POST /sdk/popups). */\n setSessionId(sessionId: string | null): void {\n if (!this.enabled) return;\n this.sessionId = sessionId;\n }\n}\n","/**\n * Helpers puros (sin DOM) para la fuente personalizable del popup/survey.\n * Espejo exacto en KMP: `ui/Font.kt`. Cualquier cambio aquí se replica allí.\n */\n\nconst FORMAT_BY_EXT: Record<string, string> = {\n woff2: 'woff2',\n woff: 'woff',\n ttf: 'truetype',\n otf: 'opentype',\n};\n\n/** Deriva el `format()` del `@font-face` a partir de la extensión de la URL. */\nexport function fontFormatFromUrl(url: string): string | undefined {\n const clean = url.split('?')[0].split('#')[0];\n const ext = clean.slice(clean.lastIndexOf('.') + 1).toLowerCase();\n return FORMAT_BY_EXT[ext];\n}\n\n// family/url provienen de la API y se interpolan en CSS y en el <style> del HTML del WebView.\n// Saneamos para evitar romper el string/rule (CSS injection) o cerrar </style> (script injection).\nfunction sanitizeFamily(family: string): string {\n return family.replace(/[^A-Za-z0-9 ._-]/g, '').trim();\n}\n\nfunction isSafeFontUrl(url: string): boolean {\n // Solo http(s)/data y sin caracteres que rompan url(\"...\") o el <style>:\n // comillas, <>, backslash, y cualquier whitespace o carácter de control.\n if (!/^(https?:|data:)/i.test(url)) return false;\n // eslint-disable-next-line no-control-regex\n return !/[\\x00-\\x20\"<>\\\\]/.test(url);\n}\n\n/** Valor a aplicar en `font-family`: nombre custom + fallback de sistema. */\nexport function buildFontFamilyValue(family: string): string {\n const safe = sanitizeFamily(family);\n return `\"${safe}\", -apple-system, system-ui, sans-serif`;\n}\n\n/** CSS del `@font-face`. Devuelve \"\" si no hay url (o no es segura). */\nexport function buildFontFaceCss(family: string, url?: string): string {\n if (!url || !isSafeFontUrl(url)) return '';\n const safe = sanitizeFamily(family);\n const fmt = fontFormatFromUrl(url);\n const src = fmt ? `url(\"${url}\") format(\"${fmt}\")` : `url(\"${url}\")`;\n return `@font-face{font-family:\"${safe}\";src:${src};font-display:swap;}`;\n}\n","import type { DeepdotsLogger } from '../types';\n\n/**\n * Logger de módulo compartido: el core lo fija en init() con el logger inyectado\n * por el host (o `console` por defecto), y los módulos que no reciben `this`\n * (renderPopup, renderers) enrutan por aquí. `warn`/`error` caen a `log` si el\n * logger del host no los provee (solo `log` es obligatorio en DeepdotsLogger).\n */\nlet active: DeepdotsLogger = console;\n\nexport function setLogger(logger: DeepdotsLogger | undefined): void {\n active = logger ?? console;\n}\n\nexport function sdkLog(...args: unknown[]): void {\n active.log(...args);\n}\n\nexport function sdkWarn(...args: unknown[]): void {\n (active.warn ?? active.log)(...args);\n}\n\nexport function sdkError(...args: unknown[]): void {\n (active.error ?? active.log)(...args);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAoBO,IAAM,kBAAN,MAAiD;AAAA,EAAjD;AACL,SAAQ,MAAM,oBAAI,IAAoB;AAAA;AAAA,EACtC,QAAQ,KAA4B;AAClC,WAAO,KAAK,IAAI,IAAI,GAAG,IAAK,KAAK,IAAI,IAAI,GAAG,IAAe;AAAA,EAC7D;AAAA,EACA,QAAQ,KAAa,OAAqB;AACxC,SAAK,IAAI,IAAI,KAAK,KAAK;AAAA,EACzB;AAAA,EACA,WAAW,KAAmB;AAC5B,SAAK,IAAI,OAAO,GAAG;AAAA,EACrB;AACF;AAGO,SAAS,uBAAwC;AACtD,MAAI;AACF,QAAI,OAAO,WAAW,eAAe,OAAO,cAAc;AACxD,YAAM,KAAK,OAAO;AAClB,YAAM,QAAQ;AACd,SAAG,QAAQ,OAAO,GAAG;AACrB,SAAG,WAAW,KAAK;AACnB,aAAO;AAAA,QACL,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC;AAAA,QAC5B,SAAS,CAAC,GAAG,MAAM,GAAG,QAAQ,GAAG,CAAC;AAAA,QAClC,YAAY,CAAC,MAAM,GAAG,WAAW,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,IAAI,gBAAgB;AAC7B;AAGO,IAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,mBAAmB;AACrB;AAaO,SAAS,oBACd,QACA,WACA,cAA6B,MAC7B,6BAA4C,MACe;AAC3D,QAAM,UAA4B,SAAS,CAAC,EAAE,KAAK,oBAAoB,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;AAC7F,QAAM,WAA6B,CAAC;AACpC,MAAI,UAAW,UAAS,KAAK,EAAE,KAAK,cAAc,OAAO,CAAC,SAAS,EAAE,CAAC;AACtE,MAAI,OAAQ,UAAS,KAAK,EAAE,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,CAAC;AAC7D,MAAI,YAAa,UAAS,KAAK,EAAE,KAAK,gBAAgB,OAAO,CAAC,WAAW,EAAE,CAAC;AAC5E,MAAI,2BAA4B,UAAS,KAAK,EAAE,KAAK,0CAA0C,OAAO,CAAC,0BAA0B,EAAE,CAAC;AACpI,SAAO,EAAE,SAAS,SAAS;AAC7B;AAcA,SAAS,cAAsB;AAC7B,QAAM,IAAK,OAAO,eAAe,cAAc,aAAa,CAAC;AAG7D,MAAI,EAAE,QAAQ,WAAY,QAAO,EAAE,OAAO,WAAW;AACrD,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,MAAI,EAAE,QAAQ,iBAAiB;AAC7B,MAAE,OAAO,gBAAgB,KAAK;AAAA,EAChC,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,IAAI,IAAK,OAAM,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EACxE;AACA,QAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAC/B,QAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAC/B,QAAM,MAAM,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACpE,SAAO,GAAG,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAC/D,MAAM,GAAG,CAAC,EACV,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,MAAM,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC;AACxE;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAW3B,YAAY,SAAiC;AAH7C;AAAA,SAAQ,YAA2B;AACnC,SAAQ,qBAAqB;AAG3B,SAAK,UAAU,QAAQ;AACvB,SAAK,eAAe,QAAQ;AAC5B,SAAK,MAAM,QAAQ,QAAQ,MAAM,KAAK,IAAI;AAC1C,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,UAAU,QAAQ,WAAW;AAAA,EACpC;AAAA,EAEA,oBAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,mBAAmB,SAAwB;AACzC,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,YAA2B;AACzB,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,QAAI,KAAK,aAAc,QAAO,KAAK;AAEnC,UAAM,YAAY,KAAK,QAAQ,QAAQ,aAAa,MAAM;AAC1D,QAAI,UAAW,QAAO;AAEtB,UAAM,KAAK,KAAK,KAAK;AACrB,SAAK,QAAQ,QAAQ,aAAa,QAAQ,EAAE;AAC5C,SAAK,QAAQ,QAAQ,aAAa,WAAW,OAAO,KAAK,IAAI,CAAC,CAAC;AAC/D,SAAK,qBAAqB;AAC1B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,YAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,eAA8B;AAC5B,QAAI,CAAC,KAAK,QAAS,QAAO;AAC1B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,aAAa,WAAgC;AAC3C,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,YAAY;AAAA,EACnB;AACF;;;AC1KA,IAAM,gBAAwC;AAAA,EAC5C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AACP;AAGO,SAAS,kBAAkB,KAAiC;AACjE,QAAM,QAAQ,IAAI,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;AAC5C,QAAM,MAAM,MAAM,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,YAAY;AAChE,SAAO,cAAc,GAAG;AAC1B;AAIA,SAAS,eAAe,QAAwB;AAC9C,SAAO,OAAO,QAAQ,qBAAqB,EAAE,EAAE,KAAK;AACtD;AAEA,SAAS,cAAc,KAAsB;AAG3C,MAAI,CAAC,oBAAoB,KAAK,GAAG,EAAG,QAAO;AAE3C,SAAO,CAAC,mBAAmB,KAAK,GAAG;AACrC;AAGO,SAAS,qBAAqB,QAAwB;AAC3D,QAAM,OAAO,eAAe,MAAM;AAClC,SAAO,IAAI,IAAI;AACjB;AAGO,SAAS,iBAAiB,QAAgB,KAAsB;AACrE,MAAI,CAAC,OAAO,CAAC,cAAc,GAAG,EAAG,QAAO;AACxC,QAAM,OAAO,eAAe,MAAM;AAClC,QAAM,MAAM,kBAAkB,GAAG;AACjC,QAAM,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,OAAO,QAAQ,GAAG;AAChE,SAAO,2BAA2B,IAAI,SAAS,GAAG;AACpD;;;ACtCA,IAAI,SAAyB;AAEtB,SAAS,UAAU,QAA0C;AAClE,WAAS,UAAU;AACrB;AAEO,SAAS,UAAU,MAAuB;AAC/C,SAAO,IAAI,GAAG,IAAI;AACpB;AAEO,SAAS,WAAW,MAAuB;AAChD,GAAC,OAAO,QAAQ,OAAO,KAAK,GAAG,IAAI;AACrC;AAEO,SAAS,YAAY,MAAuB;AACjD,GAAC,OAAO,SAAS,OAAO,KAAK,GAAG,IAAI;AACtC;","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -86,6 +86,8 @@ interface AnalyticsEnvelope {
|
|
|
86
86
|
device?: DeviceInfo;
|
|
87
87
|
/** User attributes del cliente, usados para breakdowns (registration_status, pass_type, …). */
|
|
88
88
|
attributes: Record<string, string>;
|
|
89
|
+
/** Métricas del host: valores medibles persistentes → van en `feedback.metrics` del body. */
|
|
90
|
+
metrics?: Record<string, string>;
|
|
89
91
|
};
|
|
90
92
|
events: AnalyticsEvent[];
|
|
91
93
|
}
|
|
@@ -103,7 +105,8 @@ type AnalyticsSink = (payload: AnalyticsEnvelope) => void;
|
|
|
103
105
|
* - cada entrada usa `value: string[]` (array de un elemento)
|
|
104
106
|
* - eventos: {key: nombre_evento, value: [JSON(timestamp + params)]}
|
|
105
107
|
* - identidad (user_id) → `profile` como `external-user-id`
|
|
106
|
-
* -
|
|
108
|
+
* - métricas del host (setMetric) → `feedback.metrics` (mismo shape que metadata, sin prefijo)
|
|
109
|
+
* - `answers` vacío
|
|
107
110
|
* - `text` vacío
|
|
108
111
|
*/
|
|
109
112
|
|
|
@@ -119,6 +122,7 @@ interface AnalyticsFeedbackBody {
|
|
|
119
122
|
feedback: {
|
|
120
123
|
text: string;
|
|
121
124
|
answers: FeedbackKV[];
|
|
125
|
+
metrics: FeedbackKV[];
|
|
122
126
|
metadata: FeedbackKV[];
|
|
123
127
|
profile: FeedbackKV[];
|
|
124
128
|
finished: boolean;
|
|
@@ -155,6 +159,17 @@ declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink
|
|
|
155
159
|
* Configuration options for initializing the DeepdotsPopups SDK
|
|
156
160
|
*/
|
|
157
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Custom logger to receive the SDK's debug output instead of the console.
|
|
164
|
+
* Only `log` is required; `warn`/`error`/`info` fall back to `log` when omitted.
|
|
165
|
+
* Lets the host pipe debug output to a file, Firebase, etc. `console` satisfies this shape.
|
|
166
|
+
*/
|
|
167
|
+
interface DeepdotsLogger {
|
|
168
|
+
log: (...args: unknown[]) => void;
|
|
169
|
+
warn?: (...args: unknown[]) => void;
|
|
170
|
+
error?: (...args: unknown[]) => void;
|
|
171
|
+
info?: (...args: unknown[]) => void;
|
|
172
|
+
}
|
|
158
173
|
interface DeepdotsInitParams {
|
|
159
174
|
/** API key for authentication */
|
|
160
175
|
apiKey?: string;
|
|
@@ -162,6 +177,8 @@ interface DeepdotsInitParams {
|
|
|
162
177
|
nodeEnv?: 'development' | 'production';
|
|
163
178
|
/** Enable debug logging */
|
|
164
179
|
debug?: boolean;
|
|
180
|
+
/** Custom logger for debug output. When set (and `debug` is true), the SDK routes its logs here instead of `console`. Default: `console`. */
|
|
181
|
+
logger?: DeepdotsLogger;
|
|
165
182
|
/** Optional user id to send with popup events */
|
|
166
183
|
userId?: string;
|
|
167
184
|
/** Starts tracking enabled (default) or disabled (e.g. until consent is granted). Equivalent to calling `setTrackingEnabled` after init. */
|
|
@@ -172,6 +189,12 @@ interface DeepdotsInitParams {
|
|
|
172
189
|
storage?: KeyValueStorage;
|
|
173
190
|
/** Platform used in the analytics envelope. Default is 'web'; in RN pass 'android'/'ios'. */
|
|
174
191
|
platform?: 'web' | 'android' | 'ios';
|
|
192
|
+
/**
|
|
193
|
+
* BCP-47 language tag for the analytics context (e.g. 'es-ES'). If omitted, the SDK
|
|
194
|
+
* auto-detects: `navigator.language` on web, or the `Intl` locale as a fallback (works in
|
|
195
|
+
* React Native with Hermes, where `navigator.language` is absent).
|
|
196
|
+
*/
|
|
197
|
+
language?: string;
|
|
175
198
|
/** Injectable device info (RN: from react-native-device-info). If missing, it is derived from the browser. */
|
|
176
199
|
device?: DeviceInfo;
|
|
177
200
|
/**
|
|
@@ -473,6 +496,8 @@ declare class DeepdotsPopups {
|
|
|
473
496
|
private triggers;
|
|
474
497
|
private initialized;
|
|
475
498
|
private renderer;
|
|
499
|
+
/** Logger para el output de debug. Default `console`; el host puede inyectar el suyo en init(). */
|
|
500
|
+
private logger;
|
|
476
501
|
private popupContainer;
|
|
477
502
|
private popupDefinitions;
|
|
478
503
|
private popupsLoaded;
|
|
@@ -514,6 +539,11 @@ declare class DeepdotsPopups {
|
|
|
514
539
|
track(name: string, params?: Record<string, unknown>): void;
|
|
515
540
|
/** User attributes para breakdowns (registration_status, pass_type, sector, pass_status…). */
|
|
516
541
|
setUserAttributes(attributes: Record<string, string | number | boolean>): void;
|
|
542
|
+
/**
|
|
543
|
+
* Registra/actualiza una métrica (valor medible) → `feedback.metrics` del body.
|
|
544
|
+
* Persistente y sobrescribe por key. No-op si tracking off.
|
|
545
|
+
*/
|
|
546
|
+
setMetric(key: string, value: string | number | boolean): void;
|
|
517
547
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
518
548
|
reportError(error: unknown, options?: ReportErrorOptions): void;
|
|
519
549
|
/** Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. No-op si tracking off. */
|
|
@@ -745,4 +775,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
745
775
|
*/
|
|
746
776
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
747
777
|
|
|
748
|
-
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, 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 };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,8 @@ interface AnalyticsEnvelope {
|
|
|
86
86
|
device?: DeviceInfo;
|
|
87
87
|
/** User attributes del cliente, usados para breakdowns (registration_status, pass_type, …). */
|
|
88
88
|
attributes: Record<string, string>;
|
|
89
|
+
/** Métricas del host: valores medibles persistentes → van en `feedback.metrics` del body. */
|
|
90
|
+
metrics?: Record<string, string>;
|
|
89
91
|
};
|
|
90
92
|
events: AnalyticsEvent[];
|
|
91
93
|
}
|
|
@@ -103,7 +105,8 @@ type AnalyticsSink = (payload: AnalyticsEnvelope) => void;
|
|
|
103
105
|
* - cada entrada usa `value: string[]` (array de un elemento)
|
|
104
106
|
* - eventos: {key: nombre_evento, value: [JSON(timestamp + params)]}
|
|
105
107
|
* - identidad (user_id) → `profile` como `external-user-id`
|
|
106
|
-
* -
|
|
108
|
+
* - métricas del host (setMetric) → `feedback.metrics` (mismo shape que metadata, sin prefijo)
|
|
109
|
+
* - `answers` vacío
|
|
107
110
|
* - `text` vacío
|
|
108
111
|
*/
|
|
109
112
|
|
|
@@ -119,6 +122,7 @@ interface AnalyticsFeedbackBody {
|
|
|
119
122
|
feedback: {
|
|
120
123
|
text: string;
|
|
121
124
|
answers: FeedbackKV[];
|
|
125
|
+
metrics: FeedbackKV[];
|
|
122
126
|
metadata: FeedbackKV[];
|
|
123
127
|
profile: FeedbackKV[];
|
|
124
128
|
finished: boolean;
|
|
@@ -155,6 +159,17 @@ declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink
|
|
|
155
159
|
* Configuration options for initializing the DeepdotsPopups SDK
|
|
156
160
|
*/
|
|
157
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Custom logger to receive the SDK's debug output instead of the console.
|
|
164
|
+
* Only `log` is required; `warn`/`error`/`info` fall back to `log` when omitted.
|
|
165
|
+
* Lets the host pipe debug output to a file, Firebase, etc. `console` satisfies this shape.
|
|
166
|
+
*/
|
|
167
|
+
interface DeepdotsLogger {
|
|
168
|
+
log: (...args: unknown[]) => void;
|
|
169
|
+
warn?: (...args: unknown[]) => void;
|
|
170
|
+
error?: (...args: unknown[]) => void;
|
|
171
|
+
info?: (...args: unknown[]) => void;
|
|
172
|
+
}
|
|
158
173
|
interface DeepdotsInitParams {
|
|
159
174
|
/** API key for authentication */
|
|
160
175
|
apiKey?: string;
|
|
@@ -162,6 +177,8 @@ interface DeepdotsInitParams {
|
|
|
162
177
|
nodeEnv?: 'development' | 'production';
|
|
163
178
|
/** Enable debug logging */
|
|
164
179
|
debug?: boolean;
|
|
180
|
+
/** Custom logger for debug output. When set (and `debug` is true), the SDK routes its logs here instead of `console`. Default: `console`. */
|
|
181
|
+
logger?: DeepdotsLogger;
|
|
165
182
|
/** Optional user id to send with popup events */
|
|
166
183
|
userId?: string;
|
|
167
184
|
/** Starts tracking enabled (default) or disabled (e.g. until consent is granted). Equivalent to calling `setTrackingEnabled` after init. */
|
|
@@ -172,6 +189,12 @@ interface DeepdotsInitParams {
|
|
|
172
189
|
storage?: KeyValueStorage;
|
|
173
190
|
/** Platform used in the analytics envelope. Default is 'web'; in RN pass 'android'/'ios'. */
|
|
174
191
|
platform?: 'web' | 'android' | 'ios';
|
|
192
|
+
/**
|
|
193
|
+
* BCP-47 language tag for the analytics context (e.g. 'es-ES'). If omitted, the SDK
|
|
194
|
+
* auto-detects: `navigator.language` on web, or the `Intl` locale as a fallback (works in
|
|
195
|
+
* React Native with Hermes, where `navigator.language` is absent).
|
|
196
|
+
*/
|
|
197
|
+
language?: string;
|
|
175
198
|
/** Injectable device info (RN: from react-native-device-info). If missing, it is derived from the browser. */
|
|
176
199
|
device?: DeviceInfo;
|
|
177
200
|
/**
|
|
@@ -473,6 +496,8 @@ declare class DeepdotsPopups {
|
|
|
473
496
|
private triggers;
|
|
474
497
|
private initialized;
|
|
475
498
|
private renderer;
|
|
499
|
+
/** Logger para el output de debug. Default `console`; el host puede inyectar el suyo en init(). */
|
|
500
|
+
private logger;
|
|
476
501
|
private popupContainer;
|
|
477
502
|
private popupDefinitions;
|
|
478
503
|
private popupsLoaded;
|
|
@@ -514,6 +539,11 @@ declare class DeepdotsPopups {
|
|
|
514
539
|
track(name: string, params?: Record<string, unknown>): void;
|
|
515
540
|
/** User attributes para breakdowns (registration_status, pass_type, sector, pass_status…). */
|
|
516
541
|
setUserAttributes(attributes: Record<string, string | number | boolean>): void;
|
|
542
|
+
/**
|
|
543
|
+
* Registra/actualiza una métrica (valor medible) → `feedback.metrics` del body.
|
|
544
|
+
* Persistente y sobrescribe por key. No-op si tracking off.
|
|
545
|
+
*/
|
|
546
|
+
setMetric(key: string, value: string | number | boolean): void;
|
|
517
547
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
518
548
|
reportError(error: unknown, options?: ReportErrorOptions): void;
|
|
519
549
|
/** Engancha `global.ErrorUtils` de RN para capturar errores JS no manejados. No-op si tracking off. */
|
|
@@ -745,4 +775,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
745
775
|
*/
|
|
746
776
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
747
777
|
|
|
748
|
-
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, 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 };
|
|
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 };
|