@sailfish-ai/recorder 1.8.7 → 1.8.9
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 +2 -0
- package/dist/index.js +15 -1
- package/dist/recorder.cjs +808 -770
- package/dist/recorder.js +810 -772
- package/dist/recorder.js.br +0 -0
- package/dist/recorder.js.gz +0 -0
- package/dist/recorder.umd.cjs +808 -770
- package/dist/websocket.js +131 -15
- package/package.json +1 -1
package/dist/websocket.js
CHANGED
|
@@ -14,15 +14,102 @@ const FUNCSPAN_HEADER_VALUE = "1-0-5-5-0-1.0";
|
|
|
14
14
|
// Tracking configuration type constants (must match backend TrackingConfigurationType enum)
|
|
15
15
|
const TRACKING_CONFIG_GLOBAL = "global";
|
|
16
16
|
const TRACKING_CONFIG_PER_SESSION = "per_session";
|
|
17
|
+
// localStorage key for persisting global function span tracking state
|
|
18
|
+
const FUNCSPAN_GLOBAL_STATE_KEY = "sailfish_funcspan_global_state";
|
|
17
19
|
let webSocket = null;
|
|
18
20
|
let isDraining = false;
|
|
19
21
|
let inFlightFlush = null;
|
|
20
22
|
let flushIntervalId = null;
|
|
23
|
+
function saveGlobalFuncSpanState(enabled, expirationTimestampMs) {
|
|
24
|
+
try {
|
|
25
|
+
if (typeof localStorage === "undefined")
|
|
26
|
+
return;
|
|
27
|
+
const state = {
|
|
28
|
+
enabled,
|
|
29
|
+
expirationTimestampMs,
|
|
30
|
+
};
|
|
31
|
+
localStorage.setItem(FUNCSPAN_GLOBAL_STATE_KEY, JSON.stringify(state));
|
|
32
|
+
if (DEBUG) {
|
|
33
|
+
console.log(`[Sailfish] Saved global function span state to localStorage:`, state);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
if (DEBUG) {
|
|
38
|
+
console.warn(`[Sailfish] Failed to save global function span state to localStorage:`, e);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function loadGlobalFuncSpanState() {
|
|
43
|
+
try {
|
|
44
|
+
if (typeof localStorage === "undefined")
|
|
45
|
+
return null;
|
|
46
|
+
const stored = localStorage.getItem(FUNCSPAN_GLOBAL_STATE_KEY);
|
|
47
|
+
if (!stored)
|
|
48
|
+
return null;
|
|
49
|
+
const state = JSON.parse(stored);
|
|
50
|
+
// Check if the stored state has expired
|
|
51
|
+
if (state.enabled && state.expirationTimestampMs) {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
if (now >= state.expirationTimestampMs) {
|
|
54
|
+
// Expired - clear localStorage and return null
|
|
55
|
+
if (DEBUG) {
|
|
56
|
+
console.log(`[Sailfish] Stored global function span state has expired, clearing`);
|
|
57
|
+
}
|
|
58
|
+
localStorage.removeItem(FUNCSPAN_GLOBAL_STATE_KEY);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (DEBUG) {
|
|
63
|
+
console.log(`[Sailfish] Loaded global function span state from localStorage:`, state);
|
|
64
|
+
}
|
|
65
|
+
return state;
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
if (DEBUG) {
|
|
69
|
+
console.warn(`[Sailfish] Failed to load global function span state from localStorage:`, e);
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function clearGlobalFuncSpanState() {
|
|
75
|
+
try {
|
|
76
|
+
if (typeof localStorage === "undefined")
|
|
77
|
+
return;
|
|
78
|
+
localStorage.removeItem(FUNCSPAN_GLOBAL_STATE_KEY);
|
|
79
|
+
if (DEBUG) {
|
|
80
|
+
console.log(`[Sailfish] Cleared global function span state from localStorage`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
if (DEBUG) {
|
|
85
|
+
console.warn(`[Sailfish] Failed to clear global function span state from localStorage:`, e);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
21
89
|
// Function span tracking state (only manages enabled/disabled)
|
|
22
90
|
let funcSpanTrackingEnabled = false;
|
|
23
91
|
let funcSpanTimeoutId = null;
|
|
24
92
|
let funcSpanExpirationTime = null; // Timestamp when tracking should expire (milliseconds)
|
|
25
93
|
let isLocalTrackingMode = false; // True when tracking is enabled locally (Report Issue), not globally
|
|
94
|
+
// Saved global state when switching to local mode
|
|
95
|
+
let savedGlobalTimeoutId = null;
|
|
96
|
+
let savedGlobalExpirationTime = null;
|
|
97
|
+
// Load persisted global state immediately on module initialization
|
|
98
|
+
// This ensures headers are added from the very first HTTP request, even before WebSocket connects
|
|
99
|
+
(() => {
|
|
100
|
+
const persistedState = loadGlobalFuncSpanState();
|
|
101
|
+
if (persistedState && persistedState.enabled) {
|
|
102
|
+
funcSpanTrackingEnabled = true;
|
|
103
|
+
funcSpanExpirationTime = persistedState.expirationTimestampMs;
|
|
104
|
+
isLocalTrackingMode = false;
|
|
105
|
+
if (DEBUG) {
|
|
106
|
+
console.log(`[Sailfish] Module init: Restored global function span tracking from localStorage:`, {
|
|
107
|
+
enabled: true,
|
|
108
|
+
expirationTimestampMs: funcSpanExpirationTime,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
})();
|
|
26
113
|
function isWebSocketOpen(ws) {
|
|
27
114
|
return ws?.readyState === WebSocket.OPEN;
|
|
28
115
|
}
|
|
@@ -117,6 +204,9 @@ export function sendEvent(event) {
|
|
|
117
204
|
}
|
|
118
205
|
}
|
|
119
206
|
export function initializeWebSocket(backendApi, apiKey, sessionId) {
|
|
207
|
+
// Note: Global function span tracking state is now loaded at module initialization time
|
|
208
|
+
// (see IIFE above) so headers work immediately, even before WebSocket connects.
|
|
209
|
+
// The WebSocket "funcSpanTrackingControl" message will update the state if needed.
|
|
120
210
|
const wsHost = getWebSocketHost(backendApi);
|
|
121
211
|
const apiProtocol = new URL(backendApi).protocol;
|
|
122
212
|
const wsScheme = apiProtocol === "https:" ? "wss" : "ws";
|
|
@@ -187,11 +277,15 @@ export function initializeWebSocket(backendApi, apiKey, sessionId) {
|
|
|
187
277
|
console.log(`[Sailfish] Server expiration timestamp: ${funcSpanExpirationTime}, ms until expiration: ${msUntilExpiration}`);
|
|
188
278
|
}
|
|
189
279
|
if (msUntilExpiration > 0) {
|
|
280
|
+
// Save to localStorage for persistence across page refreshes
|
|
281
|
+
saveGlobalFuncSpanState(true, funcSpanExpirationTime);
|
|
190
282
|
funcSpanTimeoutId = window.setTimeout(() => {
|
|
191
283
|
// Only auto-disable if still in global mode
|
|
192
284
|
if (!isLocalTrackingMode) {
|
|
193
285
|
funcSpanTrackingEnabled = false;
|
|
194
286
|
funcSpanExpirationTime = null;
|
|
287
|
+
// Clear localStorage when tracking expires
|
|
288
|
+
clearGlobalFuncSpanState();
|
|
195
289
|
if (DEBUG) {
|
|
196
290
|
console.log(`[Sailfish] GLOBAL function span tracking auto-disabled at server expiration time`);
|
|
197
291
|
}
|
|
@@ -202,6 +296,8 @@ export function initializeWebSocket(backendApi, apiKey, sessionId) {
|
|
|
202
296
|
// Already expired
|
|
203
297
|
funcSpanTrackingEnabled = false;
|
|
204
298
|
funcSpanExpirationTime = null;
|
|
299
|
+
// Clear localStorage if tracking already expired
|
|
300
|
+
clearGlobalFuncSpanState();
|
|
205
301
|
if (DEBUG) {
|
|
206
302
|
console.log(`[Sailfish] Tracking already expired, not enabling`);
|
|
207
303
|
}
|
|
@@ -212,10 +308,14 @@ export function initializeWebSocket(backendApi, apiKey, sessionId) {
|
|
|
212
308
|
const timeoutSeconds = data.timeoutSeconds || 3600; // Default 1 hour
|
|
213
309
|
if (timeoutSeconds > 0) {
|
|
214
310
|
funcSpanExpirationTime = Date.now() + (timeoutSeconds * 1000);
|
|
311
|
+
// Save to localStorage for persistence across page refreshes
|
|
312
|
+
saveGlobalFuncSpanState(true, funcSpanExpirationTime);
|
|
215
313
|
funcSpanTimeoutId = window.setTimeout(() => {
|
|
216
314
|
if (!isLocalTrackingMode) {
|
|
217
315
|
funcSpanTrackingEnabled = false;
|
|
218
316
|
funcSpanExpirationTime = null;
|
|
317
|
+
// Clear localStorage when tracking expires
|
|
318
|
+
clearGlobalFuncSpanState();
|
|
219
319
|
if (DEBUG) {
|
|
220
320
|
console.log(`[Sailfish] GLOBAL function span tracking auto-disabled after ${timeoutSeconds}s (legacy)`);
|
|
221
321
|
}
|
|
@@ -244,8 +344,9 @@ export function initializeWebSocket(backendApi, apiKey, sessionId) {
|
|
|
244
344
|
}
|
|
245
345
|
}
|
|
246
346
|
else {
|
|
247
|
-
// When disabled, clear expiration time
|
|
347
|
+
// When disabled, clear expiration time and localStorage
|
|
248
348
|
funcSpanExpirationTime = null;
|
|
349
|
+
clearGlobalFuncSpanState();
|
|
249
350
|
}
|
|
250
351
|
}
|
|
251
352
|
}
|
|
@@ -288,14 +389,18 @@ export function enableFunctionSpanTracking() {
|
|
|
288
389
|
if (DEBUG) {
|
|
289
390
|
console.log("[Sailfish] enableFunctionSpanTracking() called - Report Issue recording started (LOCAL MODE)");
|
|
290
391
|
}
|
|
392
|
+
// If global tracking was already active, save its state so we can restore it later
|
|
393
|
+
if (funcSpanTrackingEnabled && !isLocalTrackingMode) {
|
|
394
|
+
savedGlobalTimeoutId = funcSpanTimeoutId;
|
|
395
|
+
savedGlobalExpirationTime = funcSpanExpirationTime;
|
|
396
|
+
if (DEBUG) {
|
|
397
|
+
console.log("[Sailfish] Saved global tracking state while switching to local mode");
|
|
398
|
+
}
|
|
399
|
+
}
|
|
291
400
|
funcSpanTrackingEnabled = true;
|
|
292
401
|
isLocalTrackingMode = true; // Mark as local tracking
|
|
293
402
|
funcSpanExpirationTime = null; // Local mode has no expiration
|
|
294
|
-
// Clear
|
|
295
|
-
if (funcSpanTimeoutId !== null) {
|
|
296
|
-
window.clearTimeout(funcSpanTimeoutId);
|
|
297
|
-
funcSpanTimeoutId = null;
|
|
298
|
-
}
|
|
403
|
+
funcSpanTimeoutId = null; // Clear timeout (saved above if it was global)
|
|
299
404
|
// Report this session to backend for tracking with per_session configuration type
|
|
300
405
|
if (isWebSocketOpen(webSocket)) {
|
|
301
406
|
try {
|
|
@@ -348,17 +453,28 @@ export function disableFunctionSpanTracking() {
|
|
|
348
453
|
console.warn(`[FUNCSPAN STOP] ✗ WebSocket not open, cannot notify tracking end`);
|
|
349
454
|
}
|
|
350
455
|
if (isLocalTrackingMode) {
|
|
351
|
-
funcSpanTrackingEnabled = false;
|
|
352
456
|
isLocalTrackingMode = false;
|
|
353
|
-
|
|
354
|
-
if (
|
|
355
|
-
|
|
457
|
+
// Restore global tracking state if it was active before local mode
|
|
458
|
+
if (savedGlobalTimeoutId !== null || savedGlobalExpirationTime !== null) {
|
|
459
|
+
funcSpanTrackingEnabled = true; // Keep tracking enabled (global was active)
|
|
460
|
+
funcSpanExpirationTime = savedGlobalExpirationTime;
|
|
461
|
+
funcSpanTimeoutId = savedGlobalTimeoutId;
|
|
462
|
+
if (DEBUG) {
|
|
463
|
+
console.log("[Sailfish] LOCAL tracking mode disabled, restored GLOBAL tracking state");
|
|
464
|
+
}
|
|
465
|
+
// Clear saved state
|
|
466
|
+
savedGlobalTimeoutId = null;
|
|
467
|
+
savedGlobalExpirationTime = null;
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
// No global tracking was active, fully disable
|
|
471
|
+
funcSpanTrackingEnabled = false;
|
|
472
|
+
funcSpanExpirationTime = null;
|
|
473
|
+
funcSpanTimeoutId = null;
|
|
474
|
+
if (DEBUG) {
|
|
475
|
+
console.log("[Sailfish] LOCAL tracking mode disabled, no global tracking to restore");
|
|
476
|
+
}
|
|
356
477
|
}
|
|
357
|
-
}
|
|
358
|
-
// Clear any existing timeout
|
|
359
|
-
if (funcSpanTimeoutId !== null) {
|
|
360
|
-
window.clearTimeout(funcSpanTimeoutId);
|
|
361
|
-
funcSpanTimeoutId = null;
|
|
362
478
|
}
|
|
363
479
|
}
|
|
364
480
|
/**
|