@magicfeedback/popup-sdk 1.1.4 → 1.1.6
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/assets/assets/style.css +10 -1
- package/dist/{chunk-IOAZQPZE.mjs → chunk-4UXOEIAB.mjs} +54 -2
- package/dist/chunk-4UXOEIAB.mjs.map +1 -0
- package/dist/{chunk-6WTOQGET.mjs → chunk-XOTM5CHX.mjs} +54 -2
- package/dist/chunk-XOTM5CHX.mjs.map +1 -0
- package/dist/index.d.mts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +118 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +27 -15
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +25 -1
- package/dist/react-native.d.ts +25 -1
- package/dist/react-native.js +118 -16
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +27 -15
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-YLFRGPQN.mjs → renderPopup-EZKDMLVZ.mjs} +42 -8
- package/dist/renderPopup-EZKDMLVZ.mjs.map +1 -0
- package/dist/{renderPopup-KBDWWSUU.mjs → renderPopup-PS3NJDUR.mjs} +42 -8
- package/dist/renderPopup-PS3NJDUR.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6WTOQGET.mjs.map +0 -1
- package/dist/chunk-IOAZQPZE.mjs.map +0 -1
- package/dist/renderPopup-KBDWWSUU.mjs.map +0 -1
- package/dist/renderPopup-YLFRGPQN.mjs.map +0 -1
|
@@ -138,13 +138,22 @@
|
|
|
138
138
|
padding: 0;
|
|
139
139
|
font-weight: 900;
|
|
140
140
|
color: #222;
|
|
141
|
-
font-family: 'Montserrat';
|
|
141
|
+
font-family: var(--deepdots-font, 'Montserrat');
|
|
142
142
|
font-size: 18px;
|
|
143
143
|
text-transform: uppercase;
|
|
144
144
|
text-align: center;
|
|
145
145
|
margin-bottom: 40px;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
/* Los controles de formulario no heredan font-family por defecto: cuando hay
|
|
149
|
+
fuente custom (clase deepdots-has-font), los forzamos a usar la del contenedor. */
|
|
150
|
+
.deepdots-popup.deepdots-has-font button,
|
|
151
|
+
.deepdots-popup.deepdots-has-font input,
|
|
152
|
+
.deepdots-popup.deepdots-has-font textarea,
|
|
153
|
+
.deepdots-popup.deepdots-has-font select {
|
|
154
|
+
font-family: var(--deepdots-font, inherit);
|
|
155
|
+
}
|
|
156
|
+
|
|
148
157
|
.deepdots-popup h6 {
|
|
149
158
|
margin-bottom: 1rem;
|
|
150
159
|
}
|
|
@@ -110,11 +110,63 @@ var TrackingManager = class {
|
|
|
110
110
|
}
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
// src/ui/font.ts
|
|
114
|
+
var FORMAT_BY_EXT = {
|
|
115
|
+
woff2: "woff2",
|
|
116
|
+
woff: "woff",
|
|
117
|
+
ttf: "truetype",
|
|
118
|
+
otf: "opentype"
|
|
119
|
+
};
|
|
120
|
+
function fontFormatFromUrl(url) {
|
|
121
|
+
const clean = url.split("?")[0].split("#")[0];
|
|
122
|
+
const ext = clean.slice(clean.lastIndexOf(".") + 1).toLowerCase();
|
|
123
|
+
return FORMAT_BY_EXT[ext];
|
|
124
|
+
}
|
|
125
|
+
function sanitizeFamily(family) {
|
|
126
|
+
return family.replace(/[^A-Za-z0-9 ._-]/g, "").trim();
|
|
127
|
+
}
|
|
128
|
+
function isSafeFontUrl(url) {
|
|
129
|
+
if (!/^(https?:|data:)/i.test(url)) return false;
|
|
130
|
+
return !/[\x00-\x20"<>\\]/.test(url);
|
|
131
|
+
}
|
|
132
|
+
function buildFontFamilyValue(family) {
|
|
133
|
+
const safe = sanitizeFamily(family);
|
|
134
|
+
return `"${safe}", -apple-system, system-ui, sans-serif`;
|
|
135
|
+
}
|
|
136
|
+
function buildFontFaceCss(family, url) {
|
|
137
|
+
if (!url || !isSafeFontUrl(url)) return "";
|
|
138
|
+
const safe = sanitizeFamily(family);
|
|
139
|
+
const fmt = fontFormatFromUrl(url);
|
|
140
|
+
const src = fmt ? `url("${url}") format("${fmt}")` : `url("${url}")`;
|
|
141
|
+
return `@font-face{font-family:"${safe}";src:${src};font-display:swap;}`;
|
|
142
|
+
}
|
|
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
|
+
|
|
113
159
|
export {
|
|
114
160
|
__require,
|
|
115
161
|
createDefaultStorage,
|
|
116
162
|
STORAGE_KEYS,
|
|
117
163
|
buildSurveyIdentity,
|
|
118
|
-
TrackingManager
|
|
164
|
+
TrackingManager,
|
|
165
|
+
buildFontFamilyValue,
|
|
166
|
+
buildFontFaceCss,
|
|
167
|
+
setLogger,
|
|
168
|
+
sdkLog,
|
|
169
|
+
sdkWarn,
|
|
170
|
+
sdkError
|
|
119
171
|
};
|
|
120
|
-
//# 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":[]}
|
|
@@ -129,6 +129,52 @@ var TrackingManager = class {
|
|
|
129
129
|
}
|
|
130
130
|
};
|
|
131
131
|
|
|
132
|
+
// src/ui/font.ts
|
|
133
|
+
var FORMAT_BY_EXT = {
|
|
134
|
+
woff2: "woff2",
|
|
135
|
+
woff: "woff",
|
|
136
|
+
ttf: "truetype",
|
|
137
|
+
otf: "opentype"
|
|
138
|
+
};
|
|
139
|
+
function fontFormatFromUrl(url) {
|
|
140
|
+
const clean = url.split("?")[0].split("#")[0];
|
|
141
|
+
const ext = clean.slice(clean.lastIndexOf(".") + 1).toLowerCase();
|
|
142
|
+
return FORMAT_BY_EXT[ext];
|
|
143
|
+
}
|
|
144
|
+
function sanitizeFamily(family) {
|
|
145
|
+
return family.replace(/[^A-Za-z0-9 ._-]/g, "").trim();
|
|
146
|
+
}
|
|
147
|
+
function isSafeFontUrl(url) {
|
|
148
|
+
if (!/^(https?:|data:)/i.test(url)) return false;
|
|
149
|
+
return !/[\x00-\x20"<>\\]/.test(url);
|
|
150
|
+
}
|
|
151
|
+
function buildFontFamilyValue(family) {
|
|
152
|
+
const safe = sanitizeFamily(family);
|
|
153
|
+
return `"${safe}", -apple-system, system-ui, sans-serif`;
|
|
154
|
+
}
|
|
155
|
+
function buildFontFaceCss(family, url) {
|
|
156
|
+
if (!url || !isSafeFontUrl(url)) return "";
|
|
157
|
+
const safe = sanitizeFamily(family);
|
|
158
|
+
const fmt = fontFormatFromUrl(url);
|
|
159
|
+
const src = fmt ? `url("${url}") format("${fmt}")` : `url("${url}")`;
|
|
160
|
+
return `@font-face{font-family:"${safe}";src:${src};font-display:swap;}`;
|
|
161
|
+
}
|
|
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
|
+
|
|
132
178
|
export {
|
|
133
179
|
__commonJS,
|
|
134
180
|
__toESM,
|
|
@@ -136,6 +182,12 @@ export {
|
|
|
136
182
|
createDefaultStorage,
|
|
137
183
|
STORAGE_KEYS,
|
|
138
184
|
buildSurveyIdentity,
|
|
139
|
-
TrackingManager
|
|
185
|
+
TrackingManager,
|
|
186
|
+
buildFontFamilyValue,
|
|
187
|
+
buildFontFaceCss,
|
|
188
|
+
setLogger,
|
|
189
|
+
sdkLog,
|
|
190
|
+
sdkWarn,
|
|
191
|
+
sdkError
|
|
140
192
|
};
|
|
141
|
-
//# 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":"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","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -155,6 +155,17 @@ declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink
|
|
|
155
155
|
* Configuration options for initializing the DeepdotsPopups SDK
|
|
156
156
|
*/
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Custom logger to receive the SDK's debug output instead of the console.
|
|
160
|
+
* Only `log` is required; `warn`/`error`/`info` fall back to `log` when omitted.
|
|
161
|
+
* Lets the host pipe debug output to a file, Firebase, etc. `console` satisfies this shape.
|
|
162
|
+
*/
|
|
163
|
+
interface DeepdotsLogger {
|
|
164
|
+
log: (...args: unknown[]) => void;
|
|
165
|
+
warn?: (...args: unknown[]) => void;
|
|
166
|
+
error?: (...args: unknown[]) => void;
|
|
167
|
+
info?: (...args: unknown[]) => void;
|
|
168
|
+
}
|
|
158
169
|
interface DeepdotsInitParams {
|
|
159
170
|
/** API key for authentication */
|
|
160
171
|
apiKey?: string;
|
|
@@ -162,6 +173,8 @@ interface DeepdotsInitParams {
|
|
|
162
173
|
nodeEnv?: 'development' | 'production';
|
|
163
174
|
/** Enable debug logging */
|
|
164
175
|
debug?: boolean;
|
|
176
|
+
/** Custom logger for debug output. When set (and `debug` is true), the SDK routes its logs here instead of `console`. Default: `console`. */
|
|
177
|
+
logger?: DeepdotsLogger;
|
|
165
178
|
/** Optional user id to send with popup events */
|
|
166
179
|
userId?: string;
|
|
167
180
|
/** Starts tracking enabled (default) or disabled (e.g. until consent is granted). Equivalent to calling `setTrackingEnabled` after init. */
|
|
@@ -267,12 +280,21 @@ interface PopupActions {
|
|
|
267
280
|
start?: PopupActionStart;
|
|
268
281
|
back?: PopupActionDecline;
|
|
269
282
|
}
|
|
283
|
+
/** Fuente personalizable del popup + survey (viene de la API por popup) */
|
|
284
|
+
interface PopupFont {
|
|
285
|
+
/** Nombre de la familia. Ej: "Inter" (nombre limpio, NO un stack). */
|
|
286
|
+
family: string;
|
|
287
|
+
/** Opcional: URL a un archivo de fuente (woff2/ttf/otf) para armar un @font-face. */
|
|
288
|
+
url?: string;
|
|
289
|
+
}
|
|
270
290
|
/** Configurable popup styles */
|
|
271
291
|
interface PopupStyle {
|
|
272
292
|
theme: 'light' | 'dark';
|
|
273
293
|
position: 'bottom' | 'bottom-right' | 'bottom-left' | 'top' | 'top-right' | 'top-left' | 'center';
|
|
274
294
|
/** @deprecated Not used by the SDK; kept only for API compatibility */
|
|
275
295
|
imageUrl?: string | null;
|
|
296
|
+
/** Fuente personalizada. Si falta, se mantiene el comportamiento actual. */
|
|
297
|
+
font?: PopupFont;
|
|
276
298
|
}
|
|
277
299
|
/** Segments/targeting rules for showing the popup */
|
|
278
300
|
interface PopupSegments {
|
|
@@ -464,6 +486,8 @@ declare class DeepdotsPopups {
|
|
|
464
486
|
private triggers;
|
|
465
487
|
private initialized;
|
|
466
488
|
private renderer;
|
|
489
|
+
/** Logger para el output de debug. Default `console`; el host puede inyectar el suyo en init(). */
|
|
490
|
+
private logger;
|
|
467
491
|
private popupContainer;
|
|
468
492
|
private popupDefinitions;
|
|
469
493
|
private popupsLoaded;
|
|
@@ -658,7 +682,7 @@ declare class ReactNativePopupRenderer implements PopupRenderer {
|
|
|
658
682
|
private partialEmitted;
|
|
659
683
|
constructor(options?: ReactNativeRendererOptions);
|
|
660
684
|
init(): void;
|
|
661
|
-
show(surveyId: string, productId: string, _actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string,
|
|
685
|
+
show(surveyId: string, productId: string, _actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
662
686
|
hide(): void;
|
|
663
687
|
/**
|
|
664
688
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
@@ -684,6 +708,7 @@ interface BuildSurveyHtmlOptions {
|
|
|
684
708
|
profile?: IdentityAnswer[];
|
|
685
709
|
metadata?: IdentityAnswer[];
|
|
686
710
|
version?: string;
|
|
711
|
+
font?: PopupFont;
|
|
687
712
|
}
|
|
688
713
|
declare function buildSurveyHtml(opts: BuildSurveyHtmlOptions): string;
|
|
689
714
|
|
|
@@ -735,4 +760,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
735
760
|
*/
|
|
736
761
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
737
762
|
|
|
738
|
-
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 };
|
|
763
|
+
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
|
@@ -155,6 +155,17 @@ declare function createFeedbackSink(options: FeedbackSinkOptions): AnalyticsSink
|
|
|
155
155
|
* Configuration options for initializing the DeepdotsPopups SDK
|
|
156
156
|
*/
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Custom logger to receive the SDK's debug output instead of the console.
|
|
160
|
+
* Only `log` is required; `warn`/`error`/`info` fall back to `log` when omitted.
|
|
161
|
+
* Lets the host pipe debug output to a file, Firebase, etc. `console` satisfies this shape.
|
|
162
|
+
*/
|
|
163
|
+
interface DeepdotsLogger {
|
|
164
|
+
log: (...args: unknown[]) => void;
|
|
165
|
+
warn?: (...args: unknown[]) => void;
|
|
166
|
+
error?: (...args: unknown[]) => void;
|
|
167
|
+
info?: (...args: unknown[]) => void;
|
|
168
|
+
}
|
|
158
169
|
interface DeepdotsInitParams {
|
|
159
170
|
/** API key for authentication */
|
|
160
171
|
apiKey?: string;
|
|
@@ -162,6 +173,8 @@ interface DeepdotsInitParams {
|
|
|
162
173
|
nodeEnv?: 'development' | 'production';
|
|
163
174
|
/** Enable debug logging */
|
|
164
175
|
debug?: boolean;
|
|
176
|
+
/** Custom logger for debug output. When set (and `debug` is true), the SDK routes its logs here instead of `console`. Default: `console`. */
|
|
177
|
+
logger?: DeepdotsLogger;
|
|
165
178
|
/** Optional user id to send with popup events */
|
|
166
179
|
userId?: string;
|
|
167
180
|
/** Starts tracking enabled (default) or disabled (e.g. until consent is granted). Equivalent to calling `setTrackingEnabled` after init. */
|
|
@@ -267,12 +280,21 @@ interface PopupActions {
|
|
|
267
280
|
start?: PopupActionStart;
|
|
268
281
|
back?: PopupActionDecline;
|
|
269
282
|
}
|
|
283
|
+
/** Fuente personalizable del popup + survey (viene de la API por popup) */
|
|
284
|
+
interface PopupFont {
|
|
285
|
+
/** Nombre de la familia. Ej: "Inter" (nombre limpio, NO un stack). */
|
|
286
|
+
family: string;
|
|
287
|
+
/** Opcional: URL a un archivo de fuente (woff2/ttf/otf) para armar un @font-face. */
|
|
288
|
+
url?: string;
|
|
289
|
+
}
|
|
270
290
|
/** Configurable popup styles */
|
|
271
291
|
interface PopupStyle {
|
|
272
292
|
theme: 'light' | 'dark';
|
|
273
293
|
position: 'bottom' | 'bottom-right' | 'bottom-left' | 'top' | 'top-right' | 'top-left' | 'center';
|
|
274
294
|
/** @deprecated Not used by the SDK; kept only for API compatibility */
|
|
275
295
|
imageUrl?: string | null;
|
|
296
|
+
/** Fuente personalizada. Si falta, se mantiene el comportamiento actual. */
|
|
297
|
+
font?: PopupFont;
|
|
276
298
|
}
|
|
277
299
|
/** Segments/targeting rules for showing the popup */
|
|
278
300
|
interface PopupSegments {
|
|
@@ -464,6 +486,8 @@ declare class DeepdotsPopups {
|
|
|
464
486
|
private triggers;
|
|
465
487
|
private initialized;
|
|
466
488
|
private renderer;
|
|
489
|
+
/** Logger para el output de debug. Default `console`; el host puede inyectar el suyo en init(). */
|
|
490
|
+
private logger;
|
|
467
491
|
private popupContainer;
|
|
468
492
|
private popupDefinitions;
|
|
469
493
|
private popupsLoaded;
|
|
@@ -658,7 +682,7 @@ declare class ReactNativePopupRenderer implements PopupRenderer {
|
|
|
658
682
|
private partialEmitted;
|
|
659
683
|
constructor(options?: ReactNativeRendererOptions);
|
|
660
684
|
init(): void;
|
|
661
|
-
show(surveyId: string, productId: string, _actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string,
|
|
685
|
+
show(surveyId: string, productId: string, _actions: PopupActions | undefined, emit: EmitFn, onClose: () => void, env?: string, userId?: string, style?: PopupStyle, sessionId?: string, miniService?: string, analyticsFeedbackSessionId?: string): void;
|
|
662
686
|
hide(): void;
|
|
663
687
|
/**
|
|
664
688
|
* El host la conecta al `onMessage` del WebView. Traduce los mensajes del survey a
|
|
@@ -684,6 +708,7 @@ interface BuildSurveyHtmlOptions {
|
|
|
684
708
|
profile?: IdentityAnswer[];
|
|
685
709
|
metadata?: IdentityAnswer[];
|
|
686
710
|
version?: string;
|
|
711
|
+
font?: PopupFont;
|
|
687
712
|
}
|
|
688
713
|
declare function buildSurveyHtml(opts: BuildSurveyHtmlOptions): string;
|
|
689
714
|
|
|
@@ -735,4 +760,4 @@ declare function collectRnDevice(d: DeviceInfoLike): DeviceInfo;
|
|
|
735
760
|
*/
|
|
736
761
|
declare function setupReactNative(sdk: DeepdotsPopups, config: DeepdotsInitParams, deps?: ReactNativeSetupDeps): () => void;
|
|
737
762
|
|
|
738
|
-
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 };
|
|
763
|
+
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 };
|