@magicfeedback/popup-sdk 1.8.4 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/dist/assets/assets/style.css +113 -60
- package/dist/{chunk-EBJZDVC6.mjs → chunk-AKVMUQXO.mjs} +114 -61
- package/dist/chunk-AKVMUQXO.mjs.map +1 -0
- package/dist/{chunk-AV2TTQXB.mjs → chunk-MTV7T4OW.mjs} +114 -61
- package/dist/chunk-MTV7T4OW.mjs.map +1 -0
- package/dist/index.d.mts +42 -1
- package/dist/index.d.ts +42 -1
- package/dist/index.js +173 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -11
- package/dist/index.mjs.map +1 -1
- package/dist/react-native.d.mts +35 -0
- package/dist/react-native.d.ts +35 -0
- package/dist/react-native.js +173 -67
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +64 -11
- package/dist/react-native.mjs.map +1 -1
- package/dist/{renderPopup-3CZ6WTXF.mjs → renderPopup-LEGTSBLD.mjs} +2 -2
- package/dist/{renderPopup-E2OLIXIQ.mjs → renderPopup-LEM2MLWT.mjs} +2 -2
- package/package.json +1 -1
- package/dist/chunk-AV2TTQXB.mjs.map +0 -1
- package/dist/chunk-EBJZDVC6.mjs.map +0 -1
- /package/dist/{renderPopup-3CZ6WTXF.mjs.map → renderPopup-LEGTSBLD.mjs.map} +0 -0
- /package/dist/{renderPopup-E2OLIXIQ.mjs.map → renderPopup-LEM2MLWT.mjs.map} +0 -0
package/dist/react-native.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
sdkWarn,
|
|
19
19
|
setLogger,
|
|
20
20
|
style_default
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-AKVMUQXO.mjs";
|
|
22
22
|
|
|
23
23
|
// src/react-native/index.tsx
|
|
24
24
|
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
@@ -870,7 +870,7 @@ function createReactNativeRenderer() {
|
|
|
870
870
|
}
|
|
871
871
|
|
|
872
872
|
// src/ui/preload.ts
|
|
873
|
-
var defaultLoader = () => import("./renderPopup-
|
|
873
|
+
var defaultLoader = () => import("./renderPopup-LEM2MLWT.mjs");
|
|
874
874
|
var pending = null;
|
|
875
875
|
function preloadRenderPopup(loader = defaultLoader) {
|
|
876
876
|
if (pending) return pending;
|
|
@@ -943,7 +943,7 @@ var BrowserPopupRenderer = class {
|
|
|
943
943
|
if (!this.container) return;
|
|
944
944
|
this.visible = true;
|
|
945
945
|
const container = this.container;
|
|
946
|
-
void import("./renderPopup-
|
|
946
|
+
void import("./renderPopup-LEM2MLWT.mjs").then(({ renderPopup }) => {
|
|
947
947
|
renderPopup(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
|
|
948
948
|
});
|
|
949
949
|
}
|
|
@@ -1220,8 +1220,10 @@ async function safeBodyText(res) {
|
|
|
1220
1220
|
function createFeedbackSink(options) {
|
|
1221
1221
|
let feedbackSessionId;
|
|
1222
1222
|
let firstPostInFlight = null;
|
|
1223
|
+
let generation = 0;
|
|
1223
1224
|
const url = `${options.baseUrl}/sdk/feedback`;
|
|
1224
1225
|
const post = async (body, final, sessionEnd = false) => {
|
|
1226
|
+
const postGeneration = generation;
|
|
1225
1227
|
const json = JSON.stringify(body);
|
|
1226
1228
|
const small = json.length <= KEEPALIVE_MAX_BYTES;
|
|
1227
1229
|
if (final) options.log?.("[DeepdotsAnalytics] final flush via fetch keepalive");
|
|
@@ -1251,9 +1253,25 @@ function createFeedbackSink(options) {
|
|
|
1251
1253
|
);
|
|
1252
1254
|
return;
|
|
1253
1255
|
}
|
|
1254
|
-
if (sessionEnd)
|
|
1256
|
+
if (sessionEnd) {
|
|
1257
|
+
let closedId = body.sessionId;
|
|
1258
|
+
try {
|
|
1259
|
+
const data = await res.json();
|
|
1260
|
+
closedId = data?.sessionId ?? closedId;
|
|
1261
|
+
} catch {
|
|
1262
|
+
}
|
|
1263
|
+
try {
|
|
1264
|
+
if (closedId) options.onSessionClosed?.(closedId);
|
|
1265
|
+
} catch {
|
|
1266
|
+
}
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1255
1269
|
try {
|
|
1256
1270
|
const data = await res.json();
|
|
1271
|
+
if (postGeneration !== generation) {
|
|
1272
|
+
options.log?.("[DeepdotsAnalytics] sessionId of a closed session ignored:", data?.sessionId);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1257
1275
|
if (data?.sessionId && data.sessionId !== feedbackSessionId) {
|
|
1258
1276
|
feedbackSessionId = data.sessionId;
|
|
1259
1277
|
options.log?.("[DeepdotsAnalytics] feedbackSessionId cached:", feedbackSessionId);
|
|
@@ -1266,6 +1284,7 @@ function createFeedbackSink(options) {
|
|
|
1266
1284
|
if (meta?.resetSession) {
|
|
1267
1285
|
feedbackSessionId = void 0;
|
|
1268
1286
|
firstPostInFlight = null;
|
|
1287
|
+
generation++;
|
|
1269
1288
|
options.onSessionReset?.();
|
|
1270
1289
|
return;
|
|
1271
1290
|
}
|
|
@@ -1280,6 +1299,7 @@ function createFeedbackSink(options) {
|
|
|
1280
1299
|
if (sessionEnd) {
|
|
1281
1300
|
feedbackSessionId = void 0;
|
|
1282
1301
|
firstPostInFlight = null;
|
|
1302
|
+
generation++;
|
|
1283
1303
|
options.onSessionReset?.();
|
|
1284
1304
|
} else if (!feedbackSessionId) {
|
|
1285
1305
|
firstPostInFlight = sent.then(
|
|
@@ -1293,7 +1313,7 @@ function createFeedbackSink(options) {
|
|
|
1293
1313
|
|
|
1294
1314
|
// src/tracking/navigation-observer.ts
|
|
1295
1315
|
var UUID_PREFIX = /^[0-9a-f]{8}-[0-9a-f]{4}-/i;
|
|
1296
|
-
function
|
|
1316
|
+
function screenPath(href) {
|
|
1297
1317
|
let pathAndHash;
|
|
1298
1318
|
try {
|
|
1299
1319
|
const u = new URL(href, "http://deepdots.local");
|
|
@@ -1301,7 +1321,10 @@ function normalizeScreen(href) {
|
|
|
1301
1321
|
} catch {
|
|
1302
1322
|
pathAndHash = href;
|
|
1303
1323
|
}
|
|
1304
|
-
|
|
1324
|
+
return pathAndHash.replace(/\?[^#]*/g, "") || "/";
|
|
1325
|
+
}
|
|
1326
|
+
function normalizeScreen(href) {
|
|
1327
|
+
const pathAndHash = screenPath(href);
|
|
1305
1328
|
const collapsed = pathAndHash.split("/").map((seg) => /^[0-9]+$/.test(seg) || UUID_PREFIX.test(seg) ? ":id" : seg).join("/");
|
|
1306
1329
|
return collapsed || "/";
|
|
1307
1330
|
}
|
|
@@ -1309,6 +1332,7 @@ var NavigationObserver = class {
|
|
|
1309
1332
|
constructor(options = {}) {
|
|
1310
1333
|
this.listeners = /* @__PURE__ */ new Set();
|
|
1311
1334
|
this.currentScreen = null;
|
|
1335
|
+
this.currentPath = null;
|
|
1312
1336
|
this.entryAt = 0;
|
|
1313
1337
|
this.installed = false;
|
|
1314
1338
|
this.domHandlers = [];
|
|
@@ -1320,20 +1344,23 @@ var NavigationObserver = class {
|
|
|
1320
1344
|
/** Fija la pantalla inicial (sin emitir visita; su duración se cierra al salir). */
|
|
1321
1345
|
begin(href) {
|
|
1322
1346
|
this.currentScreen = normalizeScreen(href);
|
|
1347
|
+
this.currentPath = screenPath(href);
|
|
1323
1348
|
this.entryAt = this.now();
|
|
1324
1349
|
}
|
|
1325
1350
|
/** Navega a una pantalla nueva: cierra la anterior (emite visita) y abre la nueva. */
|
|
1326
1351
|
visit(href) {
|
|
1327
|
-
const
|
|
1328
|
-
if (
|
|
1352
|
+
const nextPath = screenPath(href);
|
|
1353
|
+
if (this.currentScreen != null && nextPath === this.currentPath) return;
|
|
1329
1354
|
this.closeCurrent();
|
|
1330
|
-
this.currentScreen =
|
|
1355
|
+
this.currentScreen = normalizeScreen(href);
|
|
1356
|
+
this.currentPath = nextPath;
|
|
1331
1357
|
this.entryAt = this.now();
|
|
1332
1358
|
}
|
|
1333
1359
|
/** Cierra la pantalla actual emitiendo su visita (p. ej. al cerrar la app/pestaña). */
|
|
1334
1360
|
stop() {
|
|
1335
1361
|
this.closeCurrent();
|
|
1336
1362
|
this.currentScreen = null;
|
|
1363
|
+
this.currentPath = null;
|
|
1337
1364
|
}
|
|
1338
1365
|
/**
|
|
1339
1366
|
* Olvida la pantalla actual SIN emitir su visita. Para una sesión que el backend ya dio
|
|
@@ -1342,6 +1369,7 @@ var NavigationObserver = class {
|
|
|
1342
1369
|
*/
|
|
1343
1370
|
discard() {
|
|
1344
1371
|
this.currentScreen = null;
|
|
1372
|
+
this.currentPath = null;
|
|
1345
1373
|
}
|
|
1346
1374
|
/**
|
|
1347
1375
|
* Retoma el seguimiento en la pantalla actual tras un `stop()`, cuando se abre una sesión
|
|
@@ -1357,6 +1385,7 @@ var NavigationObserver = class {
|
|
|
1357
1385
|
const exit = this.now();
|
|
1358
1386
|
const visit = {
|
|
1359
1387
|
screen: this.currentScreen,
|
|
1388
|
+
path: this.currentPath ?? this.currentScreen,
|
|
1360
1389
|
entry: this.entryAt,
|
|
1361
1390
|
exit,
|
|
1362
1391
|
durationSeconds: Math.max(0, Math.round((exit - this.entryAt) / 1e3))
|
|
@@ -1917,6 +1946,8 @@ var DeepdotsPopups = class {
|
|
|
1917
1946
|
this.analytics = null;
|
|
1918
1947
|
/** feedbackSessionId cacheado del canal de analytics (devuelto por POST /sdk/feedback). */
|
|
1919
1948
|
this.analyticsFeedbackSessionId = void 0;
|
|
1949
|
+
/** `init({ onFeedbackSession })`: avisa al host al abrir y cerrar cada registro. */
|
|
1950
|
+
this.onFeedbackSession = void 0;
|
|
1920
1951
|
/** Timer del flush periódico de analytics (cada ANALYTICS_FLUSH_INTERVAL_MS). */
|
|
1921
1952
|
this.analyticsFlushTimer = void 0;
|
|
1922
1953
|
/** Crash & error reporting (#14–17). Null hasta init(). */
|
|
@@ -1974,6 +2005,7 @@ var DeepdotsPopups = class {
|
|
|
1974
2005
|
this.renderChrome = config.renderChrome ?? true;
|
|
1975
2006
|
this.showProgressBar = config.showProgressBar;
|
|
1976
2007
|
this.surveyCss = config.surveyCss;
|
|
2008
|
+
this.onFeedbackSession = config.onFeedbackSession;
|
|
1977
2009
|
this.config = {
|
|
1978
2010
|
apiKey: config.apiKey || void 0,
|
|
1979
2011
|
debug: config.debug || false,
|
|
@@ -2007,7 +2039,9 @@ var DeepdotsPopups = class {
|
|
|
2007
2039
|
log: (...a) => this.log(...a),
|
|
2008
2040
|
onSessionId: (id) => {
|
|
2009
2041
|
this.analyticsFeedbackSessionId = id;
|
|
2042
|
+
this.notifyFeedbackSession(id, "open");
|
|
2010
2043
|
},
|
|
2044
|
+
onSessionClosed: (id) => this.notifyFeedbackSession(id, "closed"),
|
|
2011
2045
|
onSessionReset: () => {
|
|
2012
2046
|
this.analyticsFeedbackSessionId = void 0;
|
|
2013
2047
|
}
|
|
@@ -2045,7 +2079,9 @@ var DeepdotsPopups = class {
|
|
|
2045
2079
|
this.geoWanted = this.geoEnabled && !!config.analytics;
|
|
2046
2080
|
this.resolveGeo();
|
|
2047
2081
|
this.navObserver = new NavigationObserver();
|
|
2048
|
-
this.navObserver.onVisit(
|
|
2082
|
+
this.navObserver.onVisit(
|
|
2083
|
+
(v) => this.track("deepdots_page_view", { screen: v.screen, path: v.path, duration_seconds: v.durationSeconds })
|
|
2084
|
+
);
|
|
2049
2085
|
this.navObserver.install();
|
|
2050
2086
|
this.engagement = new EngagementTracker();
|
|
2051
2087
|
this.setupAnalyticsFlush();
|
|
@@ -2080,6 +2116,23 @@ var DeepdotsPopups = class {
|
|
|
2080
2116
|
getSessionId() {
|
|
2081
2117
|
return this.tracking?.getSessionId() ?? null;
|
|
2082
2118
|
}
|
|
2119
|
+
/**
|
|
2120
|
+
* Id del registro de analytics abierto: el `sessionId` que devolvió `POST /sdk/feedback`,
|
|
2121
|
+
* que la API guarda como `sdkSessionId` en el Feedback en que se convierte la sesión. No es
|
|
2122
|
+
* `getSessionId()`. Null hasta que el backend acepta el primer lote y de nuevo al cerrar la
|
|
2123
|
+
* sesión: para saber también qué registro se cerró, usa `init({ onFeedbackSession })`.
|
|
2124
|
+
*/
|
|
2125
|
+
getFeedbackSessionId() {
|
|
2126
|
+
return this.analyticsFeedbackSessionId ?? null;
|
|
2127
|
+
}
|
|
2128
|
+
/** Avisa al host del registro abierto o cerrado; un fallo del host no corta el envío. */
|
|
2129
|
+
notifyFeedbackSession(sessionId, status) {
|
|
2130
|
+
try {
|
|
2131
|
+
this.onFeedbackSession?.({ sessionId, status });
|
|
2132
|
+
} catch (error) {
|
|
2133
|
+
this.log("analytics \xB7 onFeedbackSession threw:", error);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2083
2136
|
/** Activa/desactiva el tracking (identidad + sesión + analytics). Kill-switch del contrato §7bis. */
|
|
2084
2137
|
setTrackingEnabled(enabled) {
|
|
2085
2138
|
if (!enabled) this.closeSession("tracking_disabled");
|
|
@@ -2920,7 +2973,7 @@ var DeepdotsPopups = class {
|
|
|
2920
2973
|
}
|
|
2921
2974
|
if (!this.popupContainer) return;
|
|
2922
2975
|
const container = this.popupContainer;
|
|
2923
|
-
void import("./renderPopup-
|
|
2976
|
+
void import("./renderPopup-LEM2MLWT.mjs").then(({ renderPopup }) => {
|
|
2924
2977
|
renderPopup(
|
|
2925
2978
|
container,
|
|
2926
2979
|
surveyId,
|