@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
package/dist/react-native.mjs
CHANGED
|
@@ -5,8 +5,10 @@ import {
|
|
|
5
5
|
buildFontFaceCss,
|
|
6
6
|
buildFontFamilyValue,
|
|
7
7
|
buildSurveyIdentity,
|
|
8
|
-
createDefaultStorage
|
|
9
|
-
|
|
8
|
+
createDefaultStorage,
|
|
9
|
+
sdkWarn,
|
|
10
|
+
setLogger
|
|
11
|
+
} from "./chunk-4UXOEIAB.mjs";
|
|
10
12
|
|
|
11
13
|
// src/react-native/index.tsx
|
|
12
14
|
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
@@ -272,7 +274,7 @@ var ReactNativePopupRenderer = class {
|
|
|
272
274
|
if (this.options.onShow) {
|
|
273
275
|
this.options.onShow({ surveyId, productId, html });
|
|
274
276
|
} else {
|
|
275
|
-
|
|
277
|
+
sdkWarn(
|
|
276
278
|
"[Deepdots] ReactNativePopupRenderer sin onShow: pasa { onShow } a new ReactNativePopupRenderer({...}) para montar el WebView del survey."
|
|
277
279
|
);
|
|
278
280
|
}
|
|
@@ -364,7 +366,7 @@ var BrowserPopupRenderer = class {
|
|
|
364
366
|
if (!this.container) return;
|
|
365
367
|
this.visible = true;
|
|
366
368
|
const container = this.container;
|
|
367
|
-
void import("./renderPopup-
|
|
369
|
+
void import("./renderPopup-PS3NJDUR.mjs").then(({ renderPopup }) => {
|
|
368
370
|
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId);
|
|
369
371
|
});
|
|
370
372
|
}
|
|
@@ -386,16 +388,19 @@ function createDefaultRenderer() {
|
|
|
386
388
|
}
|
|
387
389
|
|
|
388
390
|
// src/analytics/analytics-manager.ts
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
function createDryRunSink(log = console.log) {
|
|
392
|
+
return (payload) => log(
|
|
391
393
|
"[DeepdotsAnalytics] (dry-run \xB7 NO enviado \xB7 sin init.analytics) POST /sdk/feedback \u2192",
|
|
392
394
|
JSON.stringify(payload, null, 2)
|
|
393
395
|
);
|
|
394
|
-
}
|
|
396
|
+
}
|
|
397
|
+
var dryRunSink = createDryRunSink();
|
|
395
398
|
var AnalyticsManager = class {
|
|
396
399
|
constructor(options = {}) {
|
|
397
400
|
this.events = [];
|
|
398
401
|
this.attributes = {};
|
|
402
|
+
/** Métricas del host (valores medibles persistentes). Sobrescriben por key; se reenvían en cada flush. */
|
|
403
|
+
this.metrics = {};
|
|
399
404
|
/** Mini-services activos: nombre → timestamp de entrada. El orden de inserción marca el "más reciente". */
|
|
400
405
|
this.activeMiniServices = /* @__PURE__ */ new Map();
|
|
401
406
|
this.sink = options.sink ?? dryRunSink;
|
|
@@ -418,6 +423,14 @@ var AnalyticsManager = class {
|
|
|
418
423
|
this.attributes[k] = String(v);
|
|
419
424
|
}
|
|
420
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* Registra/actualiza una métrica (valor medible). Persistente: se reenvía en cada flush.
|
|
428
|
+
* Repetir la misma key SOBRESCRIBE; el valor se coerciona a string; ignora key vacía.
|
|
429
|
+
*/
|
|
430
|
+
setMetric(key, value) {
|
|
431
|
+
if (!key) return;
|
|
432
|
+
this.metrics[key] = String(value);
|
|
433
|
+
}
|
|
421
434
|
/**
|
|
422
435
|
* Marca el inicio de un mini-service; etiqueta los eventos siguientes con `mini_service`.
|
|
423
436
|
* Admite varios activos a la vez (concurrencia); el "actual" para etiquetar es el más reciente.
|
|
@@ -481,7 +494,8 @@ var AnalyticsManager = class {
|
|
|
481
494
|
platform: this.platform,
|
|
482
495
|
language: this.language,
|
|
483
496
|
device: this.device,
|
|
484
|
-
attributes: { ...this.attributes }
|
|
497
|
+
attributes: { ...this.attributes },
|
|
498
|
+
metrics: { ...this.metrics }
|
|
485
499
|
},
|
|
486
500
|
events: [...this.events]
|
|
487
501
|
};
|
|
@@ -537,10 +551,15 @@ function buildAnalyticsFeedbackBody(envelope, keys, feedbackSessionId) {
|
|
|
537
551
|
value: [JSON.stringify({ timestamp: e.timestamp, ...e.params ?? {} })]
|
|
538
552
|
});
|
|
539
553
|
}
|
|
554
|
+
const metrics = [];
|
|
555
|
+
for (const [k, v] of Object.entries(context.metrics ?? {})) {
|
|
556
|
+
pushKV(metrics, k, v);
|
|
557
|
+
}
|
|
540
558
|
return {
|
|
541
559
|
feedback: {
|
|
542
560
|
text: "",
|
|
543
561
|
answers: [],
|
|
562
|
+
metrics,
|
|
544
563
|
metadata,
|
|
545
564
|
profile,
|
|
546
565
|
finished: false
|
|
@@ -721,20 +740,95 @@ function collectDeviceInfo(appVersion) {
|
|
|
721
740
|
}
|
|
722
741
|
|
|
723
742
|
// src/analytics/geo-info.ts
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
743
|
+
var GEO_STORAGE_KEY = "deepdots.geo";
|
|
744
|
+
var GEO_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
745
|
+
var GEO_TIMEOUT_MS = 3e3;
|
|
746
|
+
function readCachedGeo(storage, now) {
|
|
747
|
+
try {
|
|
748
|
+
const raw = storage.getItem(GEO_STORAGE_KEY);
|
|
749
|
+
if (!raw) return null;
|
|
750
|
+
const cached = JSON.parse(raw);
|
|
751
|
+
if (typeof cached.ts !== "number" || now - cached.ts > GEO_TTL_MS) return null;
|
|
752
|
+
const geo = {};
|
|
753
|
+
if (cached.country) geo.country = cached.country;
|
|
754
|
+
if (cached.city) geo.city = cached.city;
|
|
755
|
+
return geo.country || geo.city ? geo : null;
|
|
756
|
+
} catch {
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
function writeCachedGeo(storage, geo, now) {
|
|
761
|
+
try {
|
|
762
|
+
const payload = { ...geo, ts: now };
|
|
763
|
+
storage.setItem(GEO_STORAGE_KEY, JSON.stringify(payload));
|
|
764
|
+
} catch {
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
var DEFAULT_GEO_PROVIDERS = [
|
|
768
|
+
{
|
|
769
|
+
// https://ipapi.co/json/
|
|
770
|
+
url: "https://ipapi.co/json/",
|
|
771
|
+
parse: (d) => geoFrom(d.country_code, d.city)
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
// https://ipwho.is/ (devuelve success:false con 200 en errores)
|
|
775
|
+
url: "https://ipwho.is/",
|
|
776
|
+
parse: (d) => d.success === false ? null : geoFrom(d.country_code, d.city)
|
|
777
|
+
},
|
|
778
|
+
{
|
|
779
|
+
// https://ipinfo.io/json (country = código ISO)
|
|
780
|
+
url: "https://ipinfo.io/json",
|
|
781
|
+
parse: (d) => geoFrom(d.country, d.city)
|
|
782
|
+
}
|
|
783
|
+
];
|
|
784
|
+
function geoFrom(country, city) {
|
|
785
|
+
const c = typeof country === "string" && country ? country : void 0;
|
|
786
|
+
const t = typeof city === "string" && city ? city : void 0;
|
|
787
|
+
if (!c && !t) return null;
|
|
788
|
+
return { country: c, city: t };
|
|
789
|
+
}
|
|
790
|
+
async function fetchOne(provider, f, timeoutMs) {
|
|
791
|
+
const controller = new AbortController();
|
|
792
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
727
793
|
try {
|
|
728
|
-
const res = await f(
|
|
794
|
+
const res = await f(provider.url, { signal: controller.signal });
|
|
729
795
|
if (!res.ok) return null;
|
|
730
796
|
const data = await res.json();
|
|
731
|
-
|
|
732
|
-
const city = data.city || void 0;
|
|
733
|
-
if (!country && !city) return null;
|
|
734
|
-
return { country, city };
|
|
797
|
+
return provider.parse(data);
|
|
735
798
|
} catch {
|
|
736
799
|
return null;
|
|
800
|
+
} finally {
|
|
801
|
+
clearTimeout(timer);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
async function fetchGeo(options = {}) {
|
|
805
|
+
const f = options.fetchImpl ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
806
|
+
if (!f) return null;
|
|
807
|
+
const providers = options.providers ?? DEFAULT_GEO_PROVIDERS;
|
|
808
|
+
const timeoutMs = options.timeoutMs ?? GEO_TIMEOUT_MS;
|
|
809
|
+
for (const provider of providers) {
|
|
810
|
+
const geo = await fetchOne(provider, f, timeoutMs);
|
|
811
|
+
if (geo) return geo;
|
|
812
|
+
}
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/analytics/language.ts
|
|
817
|
+
function clean(value) {
|
|
818
|
+
const trimmed = value?.trim();
|
|
819
|
+
return trimmed ? trimmed : void 0;
|
|
820
|
+
}
|
|
821
|
+
function resolveLanguage(sources) {
|
|
822
|
+
const explicit = clean(sources.explicit);
|
|
823
|
+
if (explicit) return explicit;
|
|
824
|
+
const navLang = clean(sources.navigator?.language);
|
|
825
|
+
if (navLang) return navLang;
|
|
826
|
+
try {
|
|
827
|
+
const locale = clean(sources.intl?.DateTimeFormat().resolvedOptions().locale);
|
|
828
|
+
if (locale) return locale;
|
|
829
|
+
} catch {
|
|
737
830
|
}
|
|
831
|
+
return void 0;
|
|
738
832
|
}
|
|
739
833
|
|
|
740
834
|
// src/analytics/engagement-tracker.ts
|
|
@@ -906,7 +1000,7 @@ var CrashReporter = class {
|
|
|
906
1000
|
}
|
|
907
1001
|
/** Instala los handlers globales de errores no capturados (no-op sin `window`). */
|
|
908
1002
|
install() {
|
|
909
|
-
if (typeof window === "undefined") return;
|
|
1003
|
+
if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
|
|
910
1004
|
window.addEventListener("error", (e) => {
|
|
911
1005
|
if (!this.isEnabled()) return;
|
|
912
1006
|
this.captureUnhandled(e.error ?? e.message ?? "error");
|
|
@@ -958,6 +1052,8 @@ var DeepdotsPopups = class {
|
|
|
958
1052
|
this.triggers = [];
|
|
959
1053
|
this.initialized = false;
|
|
960
1054
|
this.renderer = createDefaultRenderer();
|
|
1055
|
+
/** Logger para el output de debug. Default `console`; el host puede inyectar el suyo en init(). */
|
|
1056
|
+
this.logger = console;
|
|
961
1057
|
this.popupContainer = null;
|
|
962
1058
|
// deprecated: mantenido para compatibilidad interna
|
|
963
1059
|
this.popupDefinitions = [];
|
|
@@ -993,6 +1089,8 @@ var DeepdotsPopups = class {
|
|
|
993
1089
|
}
|
|
994
1090
|
/** Initialize the SDK with configuration */
|
|
995
1091
|
init(config) {
|
|
1092
|
+
this.logger = config.logger ?? console;
|
|
1093
|
+
setLogger(this.logger);
|
|
996
1094
|
if (this.initialized) {
|
|
997
1095
|
this.log("SDK already initialized");
|
|
998
1096
|
return;
|
|
@@ -1032,12 +1130,16 @@ var DeepdotsPopups = class {
|
|
|
1032
1130
|
onSessionId: (id) => {
|
|
1033
1131
|
this.analyticsFeedbackSessionId = id;
|
|
1034
1132
|
}
|
|
1035
|
-
}) :
|
|
1133
|
+
}) : createDryRunSink((...a) => this.logger.log(...a));
|
|
1036
1134
|
const device = config.device ?? collectDeviceInfo(config.appVersion);
|
|
1037
1135
|
this.analytics = new AnalyticsManager({
|
|
1038
1136
|
sink: analyticsSink,
|
|
1039
1137
|
publicKey: config.analytics?.publicKey ?? this.config.apiKey,
|
|
1040
|
-
language:
|
|
1138
|
+
language: resolveLanguage({
|
|
1139
|
+
explicit: config.language,
|
|
1140
|
+
navigator: typeof navigator !== "undefined" ? navigator : void 0,
|
|
1141
|
+
intl: typeof Intl !== "undefined" ? Intl : void 0
|
|
1142
|
+
}),
|
|
1041
1143
|
platform: config.platform ?? "web",
|
|
1042
1144
|
device,
|
|
1043
1145
|
maxBatchSize: ANALYTICS_MAX_BATCH_SIZE,
|
|
@@ -1054,8 +1156,13 @@ var DeepdotsPopups = class {
|
|
|
1054
1156
|
if (this.tracking?.isTrackingEnabled()) {
|
|
1055
1157
|
this.crashReporter.install();
|
|
1056
1158
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1159
|
+
const cachedGeo = readCachedGeo(storage, Date.now());
|
|
1160
|
+
if (cachedGeo) this.analytics.updateDevice(cachedGeo);
|
|
1161
|
+
fetchGeo().then((geo) => {
|
|
1162
|
+
if (geo) {
|
|
1163
|
+
this.analytics?.updateDevice(geo);
|
|
1164
|
+
writeCachedGeo(storage, geo, Date.now());
|
|
1165
|
+
}
|
|
1059
1166
|
}).catch(() => {
|
|
1060
1167
|
});
|
|
1061
1168
|
this.navObserver = new NavigationObserver();
|
|
@@ -1112,6 +1219,15 @@ var DeepdotsPopups = class {
|
|
|
1112
1219
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1113
1220
|
this.analytics?.setUserAttributes(attributes);
|
|
1114
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Registra/actualiza una métrica (valor medible) → `feedback.metrics` del body.
|
|
1224
|
+
* Persistente y sobrescribe por key. No-op si tracking off.
|
|
1225
|
+
*/
|
|
1226
|
+
setMetric(key, value) {
|
|
1227
|
+
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1228
|
+
this.analytics?.setMetric(key, value);
|
|
1229
|
+
this.log("analytics \xB7 setMetric:", key, value);
|
|
1230
|
+
}
|
|
1115
1231
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
1116
1232
|
reportError(error, options) {
|
|
1117
1233
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
@@ -1685,7 +1801,7 @@ var DeepdotsPopups = class {
|
|
|
1685
1801
|
}
|
|
1686
1802
|
if (!this.popupContainer) return;
|
|
1687
1803
|
const container = this.popupContainer;
|
|
1688
|
-
void import("./renderPopup-
|
|
1804
|
+
void import("./renderPopup-PS3NJDUR.mjs").then(({ renderPopup }) => {
|
|
1689
1805
|
renderPopup(
|
|
1690
1806
|
container,
|
|
1691
1807
|
surveyId,
|
|
@@ -1741,7 +1857,8 @@ var DeepdotsPopups = class {
|
|
|
1741
1857
|
try {
|
|
1742
1858
|
listener(event);
|
|
1743
1859
|
} catch (error) {
|
|
1744
|
-
|
|
1860
|
+
if (this.logger.error) this.logger.error("Error in event listener:", error);
|
|
1861
|
+
else this.logger.log("Error in event listener:", error);
|
|
1745
1862
|
}
|
|
1746
1863
|
});
|
|
1747
1864
|
}
|
|
@@ -1749,7 +1866,7 @@ var DeepdotsPopups = class {
|
|
|
1749
1866
|
/** Log debug messages */
|
|
1750
1867
|
log(...args) {
|
|
1751
1868
|
if (this.config?.debug) {
|
|
1752
|
-
|
|
1869
|
+
this.logger.log("[DeepdotsPopups]", ...args);
|
|
1753
1870
|
}
|
|
1754
1871
|
}
|
|
1755
1872
|
/** External debug method for triggers */
|