@magicfeedback/popup-sdk 1.1.6 → 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/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +123 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -12
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +15 -1
- package/dist/react-native.d.ts +15 -1
- package/dist/react-native.js +123 -14
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +121 -12
- package/dist/react-native.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -394,6 +394,8 @@ var AnalyticsManager = class {
|
|
|
394
394
|
constructor(options = {}) {
|
|
395
395
|
this.events = [];
|
|
396
396
|
this.attributes = {};
|
|
397
|
+
/** Métricas del host (valores medibles persistentes). Sobrescriben por key; se reenvían en cada flush. */
|
|
398
|
+
this.metrics = {};
|
|
397
399
|
/** Mini-services activos: nombre → timestamp de entrada. El orden de inserción marca el "más reciente". */
|
|
398
400
|
this.activeMiniServices = /* @__PURE__ */ new Map();
|
|
399
401
|
this.sink = options.sink ?? dryRunSink;
|
|
@@ -416,6 +418,14 @@ var AnalyticsManager = class {
|
|
|
416
418
|
this.attributes[k] = String(v);
|
|
417
419
|
}
|
|
418
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Registra/actualiza una métrica (valor medible). Persistente: se reenvía en cada flush.
|
|
423
|
+
* Repetir la misma key SOBRESCRIBE; el valor se coerciona a string; ignora key vacía.
|
|
424
|
+
*/
|
|
425
|
+
setMetric(key, value) {
|
|
426
|
+
if (!key) return;
|
|
427
|
+
this.metrics[key] = String(value);
|
|
428
|
+
}
|
|
419
429
|
/**
|
|
420
430
|
* Marca el inicio de un mini-service; etiqueta los eventos siguientes con `mini_service`.
|
|
421
431
|
* Admite varios activos a la vez (concurrencia); el "actual" para etiquetar es el más reciente.
|
|
@@ -479,7 +489,8 @@ var AnalyticsManager = class {
|
|
|
479
489
|
platform: this.platform,
|
|
480
490
|
language: this.language,
|
|
481
491
|
device: this.device,
|
|
482
|
-
attributes: { ...this.attributes }
|
|
492
|
+
attributes: { ...this.attributes },
|
|
493
|
+
metrics: { ...this.metrics }
|
|
483
494
|
},
|
|
484
495
|
events: [...this.events]
|
|
485
496
|
};
|
|
@@ -535,10 +546,15 @@ function buildAnalyticsFeedbackBody(envelope, keys, feedbackSessionId) {
|
|
|
535
546
|
value: [JSON.stringify({ timestamp: e.timestamp, ...e.params ?? {} })]
|
|
536
547
|
});
|
|
537
548
|
}
|
|
549
|
+
const metrics = [];
|
|
550
|
+
for (const [k, v] of Object.entries(context.metrics ?? {})) {
|
|
551
|
+
pushKV(metrics, k, v);
|
|
552
|
+
}
|
|
538
553
|
return {
|
|
539
554
|
feedback: {
|
|
540
555
|
text: "",
|
|
541
556
|
answers: [],
|
|
557
|
+
metrics,
|
|
542
558
|
metadata,
|
|
543
559
|
profile,
|
|
544
560
|
finished: false
|
|
@@ -719,20 +735,95 @@ function collectDeviceInfo(appVersion) {
|
|
|
719
735
|
}
|
|
720
736
|
|
|
721
737
|
// src/analytics/geo-info.ts
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
738
|
+
var GEO_STORAGE_KEY = "deepdots.geo";
|
|
739
|
+
var GEO_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
740
|
+
var GEO_TIMEOUT_MS = 3e3;
|
|
741
|
+
function readCachedGeo(storage, now) {
|
|
725
742
|
try {
|
|
726
|
-
const
|
|
743
|
+
const raw = storage.getItem(GEO_STORAGE_KEY);
|
|
744
|
+
if (!raw) return null;
|
|
745
|
+
const cached = JSON.parse(raw);
|
|
746
|
+
if (typeof cached.ts !== "number" || now - cached.ts > GEO_TTL_MS) return null;
|
|
747
|
+
const geo = {};
|
|
748
|
+
if (cached.country) geo.country = cached.country;
|
|
749
|
+
if (cached.city) geo.city = cached.city;
|
|
750
|
+
return geo.country || geo.city ? geo : null;
|
|
751
|
+
} catch {
|
|
752
|
+
return null;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function writeCachedGeo(storage, geo, now) {
|
|
756
|
+
try {
|
|
757
|
+
const payload = { ...geo, ts: now };
|
|
758
|
+
storage.setItem(GEO_STORAGE_KEY, JSON.stringify(payload));
|
|
759
|
+
} catch {
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
var DEFAULT_GEO_PROVIDERS = [
|
|
763
|
+
{
|
|
764
|
+
// https://ipapi.co/json/
|
|
765
|
+
url: "https://ipapi.co/json/",
|
|
766
|
+
parse: (d) => geoFrom(d.country_code, d.city)
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
// https://ipwho.is/ (devuelve success:false con 200 en errores)
|
|
770
|
+
url: "https://ipwho.is/",
|
|
771
|
+
parse: (d) => d.success === false ? null : geoFrom(d.country_code, d.city)
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
// https://ipinfo.io/json (country = código ISO)
|
|
775
|
+
url: "https://ipinfo.io/json",
|
|
776
|
+
parse: (d) => geoFrom(d.country, d.city)
|
|
777
|
+
}
|
|
778
|
+
];
|
|
779
|
+
function geoFrom(country, city) {
|
|
780
|
+
const c = typeof country === "string" && country ? country : void 0;
|
|
781
|
+
const t = typeof city === "string" && city ? city : void 0;
|
|
782
|
+
if (!c && !t) return null;
|
|
783
|
+
return { country: c, city: t };
|
|
784
|
+
}
|
|
785
|
+
async function fetchOne(provider, f, timeoutMs) {
|
|
786
|
+
const controller = new AbortController();
|
|
787
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
788
|
+
try {
|
|
789
|
+
const res = await f(provider.url, { signal: controller.signal });
|
|
727
790
|
if (!res.ok) return null;
|
|
728
791
|
const data = await res.json();
|
|
729
|
-
|
|
730
|
-
const city = data.city || void 0;
|
|
731
|
-
if (!country && !city) return null;
|
|
732
|
-
return { country, city };
|
|
792
|
+
return provider.parse(data);
|
|
733
793
|
} catch {
|
|
734
794
|
return null;
|
|
795
|
+
} finally {
|
|
796
|
+
clearTimeout(timer);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
async function fetchGeo(options = {}) {
|
|
800
|
+
const f = options.fetchImpl ?? (typeof fetch !== "undefined" ? fetch : void 0);
|
|
801
|
+
if (!f) return null;
|
|
802
|
+
const providers = options.providers ?? DEFAULT_GEO_PROVIDERS;
|
|
803
|
+
const timeoutMs = options.timeoutMs ?? GEO_TIMEOUT_MS;
|
|
804
|
+
for (const provider of providers) {
|
|
805
|
+
const geo = await fetchOne(provider, f, timeoutMs);
|
|
806
|
+
if (geo) return geo;
|
|
807
|
+
}
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// src/analytics/language.ts
|
|
812
|
+
function clean(value) {
|
|
813
|
+
const trimmed = value?.trim();
|
|
814
|
+
return trimmed ? trimmed : void 0;
|
|
815
|
+
}
|
|
816
|
+
function resolveLanguage(sources) {
|
|
817
|
+
const explicit = clean(sources.explicit);
|
|
818
|
+
if (explicit) return explicit;
|
|
819
|
+
const navLang = clean(sources.navigator?.language);
|
|
820
|
+
if (navLang) return navLang;
|
|
821
|
+
try {
|
|
822
|
+
const locale = clean(sources.intl?.DateTimeFormat().resolvedOptions().locale);
|
|
823
|
+
if (locale) return locale;
|
|
824
|
+
} catch {
|
|
735
825
|
}
|
|
826
|
+
return void 0;
|
|
736
827
|
}
|
|
737
828
|
|
|
738
829
|
// src/analytics/engagement-tracker.ts
|
|
@@ -1039,7 +1130,11 @@ var DeepdotsPopups = class {
|
|
|
1039
1130
|
this.analytics = new AnalyticsManager({
|
|
1040
1131
|
sink: analyticsSink,
|
|
1041
1132
|
publicKey: config.analytics?.publicKey ?? this.config.apiKey,
|
|
1042
|
-
language:
|
|
1133
|
+
language: resolveLanguage({
|
|
1134
|
+
explicit: config.language,
|
|
1135
|
+
navigator: typeof navigator !== "undefined" ? navigator : void 0,
|
|
1136
|
+
intl: typeof Intl !== "undefined" ? Intl : void 0
|
|
1137
|
+
}),
|
|
1043
1138
|
platform: config.platform ?? "web",
|
|
1044
1139
|
device,
|
|
1045
1140
|
maxBatchSize: ANALYTICS_MAX_BATCH_SIZE,
|
|
@@ -1056,8 +1151,13 @@ var DeepdotsPopups = class {
|
|
|
1056
1151
|
if (this.tracking?.isTrackingEnabled()) {
|
|
1057
1152
|
this.crashReporter.install();
|
|
1058
1153
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1154
|
+
const cachedGeo = readCachedGeo(storage, Date.now());
|
|
1155
|
+
if (cachedGeo) this.analytics.updateDevice(cachedGeo);
|
|
1156
|
+
fetchGeo().then((geo) => {
|
|
1157
|
+
if (geo) {
|
|
1158
|
+
this.analytics?.updateDevice(geo);
|
|
1159
|
+
writeCachedGeo(storage, geo, Date.now());
|
|
1160
|
+
}
|
|
1061
1161
|
}).catch(() => {
|
|
1062
1162
|
});
|
|
1063
1163
|
this.navObserver = new NavigationObserver();
|
|
@@ -1114,6 +1214,15 @@ var DeepdotsPopups = class {
|
|
|
1114
1214
|
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1115
1215
|
this.analytics?.setUserAttributes(attributes);
|
|
1116
1216
|
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Registra/actualiza una métrica (valor medible) → `feedback.metrics` del body.
|
|
1219
|
+
* Persistente y sobrescribe por key. No-op si tracking off.
|
|
1220
|
+
*/
|
|
1221
|
+
setMetric(key, value) {
|
|
1222
|
+
if (!this.tracking?.isTrackingEnabled()) return;
|
|
1223
|
+
this.analytics?.setMetric(key, value);
|
|
1224
|
+
this.log("analytics \xB7 setMetric:", key, value);
|
|
1225
|
+
}
|
|
1117
1226
|
/** Reporta un error del host (manejado o no) → evento `deepdots_app_crash`. No-op si tracking off. */
|
|
1118
1227
|
reportError(error, options) {
|
|
1119
1228
|
if (!this.tracking?.isTrackingEnabled()) return;
|