@interfere/next 0.0.13 → 0.0.15-alpha.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 +1 -6
- package/dist/build/env-config.d.mts +7 -0
- package/dist/build/env-config.d.mts.map +1 -0
- package/dist/build/env-config.mjs +17 -0
- package/dist/build/env-config.mjs.map +1 -0
- package/dist/build/logger.d.mts +11 -0
- package/dist/build/logger.d.mts.map +1 -0
- package/dist/build/logger.mjs +155 -0
- package/dist/build/logger.mjs.map +1 -0
- package/dist/build/release-program.d.mts +19 -0
- package/dist/build/release-program.d.mts.map +1 -0
- package/dist/build/release-program.mjs +92 -0
- package/dist/build/release-program.mjs.map +1 -0
- package/dist/build/secret-key.d.mts +10 -0
- package/dist/build/secret-key.d.mts.map +1 -0
- package/dist/build/secret-key.mjs +16 -0
- package/dist/build/secret-key.mjs.map +1 -0
- package/dist/build/services/config.service.d.mts +9 -0
- package/dist/build/services/config.service.d.mts.map +1 -0
- package/dist/build/services/config.service.mjs +8 -0
- package/dist/build/services/config.service.mjs.map +1 -0
- package/dist/build/services/preflight.service.d.mts +19 -0
- package/dist/build/services/preflight.service.d.mts.map +1 -0
- package/dist/build/services/preflight.service.mjs +76 -0
- package/dist/build/services/preflight.service.mjs.map +1 -0
- package/dist/build/services/release-identity.service.d.mts +22 -0
- package/dist/build/services/release-identity.service.d.mts.map +1 -0
- package/dist/build/services/release-identity.service.mjs +48 -0
- package/dist/build/services/release-identity.service.mjs.map +1 -0
- package/dist/build/services/source-map.service.d.mts +24 -0
- package/dist/build/services/source-map.service.d.mts.map +1 -0
- package/dist/build/services/source-map.service.mjs +58 -0
- package/dist/build/services/source-map.service.mjs.map +1 -0
- package/dist/build/source-maps/api.d.mts +35 -0
- package/dist/build/source-maps/api.d.mts.map +1 -0
- package/dist/build/source-maps/api.mjs +61 -0
- package/dist/build/source-maps/api.mjs.map +1 -0
- package/dist/build/source-maps/client.d.mts +73 -0
- package/dist/build/source-maps/client.d.mts.map +1 -0
- package/dist/build/source-maps/client.mjs +228 -0
- package/dist/build/source-maps/client.mjs.map +1 -0
- package/dist/build/source-maps/errors.d.mts +109 -0
- package/dist/build/source-maps/errors.d.mts.map +1 -0
- package/dist/build/source-maps/errors.mjs +22 -0
- package/dist/build/source-maps/errors.mjs.map +1 -0
- package/dist/build/source-maps/files.d.mts +35 -0
- package/dist/build/source-maps/files.d.mts.map +1 -0
- package/dist/build/source-maps/files.mjs +222 -0
- package/dist/build/source-maps/files.mjs.map +1 -0
- package/dist/build/source-maps/providers/deployment/detector.d.mts +26 -0
- package/dist/build/source-maps/providers/deployment/detector.d.mts.map +1 -0
- package/dist/build/source-maps/providers/deployment/detector.mjs +22 -0
- package/dist/build/source-maps/providers/deployment/detector.mjs.map +1 -0
- package/dist/build/source-maps/providers/deployment/types.d.mts +12 -0
- package/dist/build/source-maps/providers/deployment/types.d.mts.map +1 -0
- package/dist/build/source-maps/providers/deployment/types.mjs +3 -0
- package/dist/build/source-maps/providers/deployment/vercel.d.mts +6 -0
- package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +1 -0
- package/dist/build/source-maps/providers/deployment/vercel.mjs +44 -0
- package/dist/build/source-maps/providers/deployment/vercel.mjs.map +1 -0
- package/dist/build/source-maps/providers/source-control/detector.d.mts +15 -0
- package/dist/build/source-maps/providers/source-control/detector.d.mts.map +1 -0
- package/dist/build/source-maps/providers/source-control/detector.mjs +22 -0
- package/dist/build/source-maps/providers/source-control/detector.mjs.map +1 -0
- package/dist/build/source-maps/providers/source-control/git.d.mts +6 -0
- package/dist/build/source-maps/providers/source-control/git.d.mts.map +1 -0
- package/dist/build/source-maps/providers/source-control/git.mjs +50 -0
- package/dist/build/source-maps/providers/source-control/git.mjs.map +1 -0
- package/dist/build/source-maps/providers/source-control/types.d.mts +12 -0
- package/dist/build/source-maps/providers/source-control/types.d.mts.map +1 -0
- package/dist/build/source-maps/providers/source-control/types.mjs +3 -0
- package/dist/build/with-interfere.d.mts +49 -0
- package/dist/build/with-interfere.d.mts.map +1 -0
- package/dist/build/with-interfere.mjs +75 -0
- package/dist/build/with-interfere.mjs.map +1 -0
- package/dist/client/client.d.mts +3 -0
- package/dist/client/client.mjs +5 -0
- package/dist/client/provider.d.mts +22 -0
- package/dist/client/provider.d.mts.map +1 -0
- package/dist/client/provider.mjs +33 -0
- package/dist/client/provider.mjs.map +1 -0
- package/dist/lib/env.d.mts +12 -0
- package/dist/lib/env.d.mts.map +1 -0
- package/dist/lib/env.mjs +17 -0
- package/dist/lib/env.mjs.map +1 -0
- package/dist/lib/test-utils/make-next-request.d.mts +6 -0
- package/dist/lib/test-utils/make-next-request.d.mts.map +1 -0
- package/dist/lib/test-utils/make-next-request.mjs +12 -0
- package/dist/lib/test-utils/make-next-request.mjs.map +1 -0
- package/dist/lib/types.d.mts +22 -0
- package/dist/lib/types.d.mts.map +1 -0
- package/dist/lib/types.mjs +7 -0
- package/dist/lib/types.mjs.map +1 -0
- package/dist/server/middleware.d.mts +11 -0
- package/dist/server/middleware.d.mts.map +1 -0
- package/dist/server/middleware.mjs +84 -0
- package/dist/server/middleware.mjs.map +1 -0
- package/dist/server/proxy.d.mts +6 -0
- package/dist/server/proxy.d.mts.map +1 -0
- package/dist/server/proxy.mjs +29 -0
- package/dist/server/proxy.mjs.map +1 -0
- package/dist/server/route-handler.d.mts +9 -0
- package/dist/server/route-handler.d.mts.map +1 -0
- package/dist/server/route-handler.mjs +172 -0
- package/dist/server/route-handler.mjs.map +1 -0
- package/dist/server/services/config.service.d.mts +21 -0
- package/dist/server/services/config.service.d.mts.map +1 -0
- package/dist/server/services/config.service.mjs +43 -0
- package/dist/server/services/config.service.mjs.map +1 -0
- package/dist/server/services/error-tracking.service.d.mts +19 -0
- package/dist/server/services/error-tracking.service.d.mts.map +1 -0
- package/dist/server/services/error-tracking.service.mjs +31 -0
- package/dist/server/services/error-tracking.service.mjs.map +1 -0
- package/package.json +67 -36
- package/dist/__tests__/build/with-interfere-coverage.test.d.ts +0 -2
- package/dist/__tests__/build/with-interfere-coverage.test.d.ts.map +0 -1
- package/dist/__tests__/build/with-interfere-coverage.test.js +0 -325
- package/dist/__tests__/build/with-interfere-coverage.test.js.map +0 -1
- package/dist/__tests__/build/with-interfere.test.d.ts +0 -2
- package/dist/__tests__/build/with-interfere.test.d.ts.map +0 -1
- package/dist/__tests__/build/with-interfere.test.js +0 -424
- package/dist/__tests__/build/with-interfere.test.js.map +0 -1
- package/dist/__tests__/core/client.test.d.ts +0 -2
- package/dist/__tests__/core/client.test.d.ts.map +0 -1
- package/dist/__tests__/core/client.test.js +0 -373
- package/dist/__tests__/core/client.test.js.map +0 -1
- package/dist/__tests__/core/encoders.test.d.ts +0 -2
- package/dist/__tests__/core/encoders.test.d.ts.map +0 -1
- package/dist/__tests__/core/encoders.test.js +0 -56
- package/dist/__tests__/core/encoders.test.js.map +0 -1
- package/dist/__tests__/core/rage-click.test.d.ts +0 -2
- package/dist/__tests__/core/rage-click.test.d.ts.map +0 -1
- package/dist/__tests__/core/rage-click.test.js +0 -121
- package/dist/__tests__/core/rage-click.test.js.map +0 -1
- package/dist/__tests__/core/session-manager.test.d.ts +0 -2
- package/dist/__tests__/core/session-manager.test.d.ts.map +0 -1
- package/dist/__tests__/core/session-manager.test.js +0 -1168
- package/dist/__tests__/core/session-manager.test.js.map +0 -1
- package/dist/__tests__/integration/release-upload.test.d.ts +0 -2
- package/dist/__tests__/integration/release-upload.test.d.ts.map +0 -1
- package/dist/__tests__/integration/release-upload.test.js +0 -167
- package/dist/__tests__/integration/release-upload.test.js.map +0 -1
- package/dist/__tests__/session/persistence.test.d.ts +0 -2
- package/dist/__tests__/session/persistence.test.d.ts.map +0 -1
- package/dist/__tests__/session/persistence.test.js +0 -129
- package/dist/__tests__/session/persistence.test.js.map +0 -1
- package/dist/__tests__/session/session-summary.test.d.ts +0 -2
- package/dist/__tests__/session/session-summary.test.d.ts.map +0 -1
- package/dist/__tests__/session/session-summary.test.js +0 -763
- package/dist/__tests__/session/session-summary.test.js.map +0 -1
- package/dist/client.d.ts +0 -75
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -123
- package/dist/client.js.map +0 -1
- package/dist/config.d.ts +0 -61
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -315
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/index.jsx +0 -50
- package/dist/index.jsx.map +0 -1
- package/dist/lib/core/client-core.d.ts +0 -27
- package/dist/lib/core/client-core.d.ts.map +0 -1
- package/dist/lib/core/client-core.js +0 -152
- package/dist/lib/core/client-core.js.map +0 -1
- package/dist/lib/core/constants.d.ts +0 -12
- package/dist/lib/core/constants.d.ts.map +0 -1
- package/dist/lib/core/constants.js +0 -17
- package/dist/lib/core/constants.js.map +0 -1
- package/dist/lib/core/debug.d.ts +0 -47
- package/dist/lib/core/debug.d.ts.map +0 -1
- package/dist/lib/core/debug.js +0 -79
- package/dist/lib/core/debug.js.map +0 -1
- package/dist/lib/core/encoders.d.ts +0 -3
- package/dist/lib/core/encoders.d.ts.map +0 -1
- package/dist/lib/core/encoders.js +0 -5
- package/dist/lib/core/encoders.js.map +0 -1
- package/dist/lib/core/error-handlers.d.ts +0 -14
- package/dist/lib/core/error-handlers.d.ts.map +0 -1
- package/dist/lib/core/error-handlers.js +0 -191
- package/dist/lib/core/error-handlers.js.map +0 -1
- package/dist/lib/core/runtime.d.ts +0 -7
- package/dist/lib/core/runtime.d.ts.map +0 -1
- package/dist/lib/core/runtime.js +0 -16
- package/dist/lib/core/runtime.js.map +0 -1
- package/dist/lib/persistence/storage.d.ts +0 -5
- package/dist/lib/persistence/storage.d.ts.map +0 -1
- package/dist/lib/persistence/storage.js +0 -67
- package/dist/lib/persistence/storage.js.map +0 -1
- package/dist/lib/session/constants.d.ts +0 -19
- package/dist/lib/session/constants.d.ts.map +0 -1
- package/dist/lib/session/constants.js +0 -34
- package/dist/lib/session/constants.js.map +0 -1
- package/dist/lib/session/persistence.d.ts +0 -58
- package/dist/lib/session/persistence.d.ts.map +0 -1
- package/dist/lib/session/persistence.js +0 -179
- package/dist/lib/session/persistence.js.map +0 -1
- package/dist/lib/session/rage-click.d.ts +0 -17
- package/dist/lib/session/rage-click.d.ts.map +0 -1
- package/dist/lib/session/rage-click.js +0 -104
- package/dist/lib/session/rage-click.js.map +0 -1
- package/dist/lib/session/replay.d.ts +0 -3
- package/dist/lib/session/replay.d.ts.map +0 -1
- package/dist/lib/session/replay.js +0 -109
- package/dist/lib/session/replay.js.map +0 -1
- package/dist/lib/session/session-manager.d.ts +0 -126
- package/dist/lib/session/session-manager.d.ts.map +0 -1
- package/dist/lib/session/session-manager.js +0 -635
- package/dist/lib/session/session-manager.js.map +0 -1
- package/dist/lib/session/session-summary.d.ts +0 -3
- package/dist/lib/session/session-summary.d.ts.map +0 -1
- package/dist/lib/session/session-summary.js +0 -214
- package/dist/lib/session/session-summary.js.map +0 -1
- package/dist/middleware.d.ts +0 -8
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js +0 -139
- package/dist/middleware.js.map +0 -1
- package/dist/types/storage.d.ts +0 -7
- package/dist/types/storage.d.ts.map +0 -1
- package/dist/types/storage.js +0 -2
- package/dist/types/storage.js.map +0 -1
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -4
- package/dist/types.js.map +0 -1
|
@@ -1,635 +0,0 @@
|
|
|
1
|
-
import { v7 as uuidv7 } from "uuid";
|
|
2
|
-
import { sessionStore } from "../persistence/storage.js";
|
|
3
|
-
import { DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS, MAX_SESSION_IDLE_TIMEOUT_SECONDS, MIN_SESSION_IDLE_TIMEOUT_SECONDS, SESSION_ID, SESSION_LENGTH_LIMIT_MILLISECONDS, toMs, } from "./constants.js";
|
|
4
|
-
/**
|
|
5
|
-
* Default clock implementation using native browser APIs
|
|
6
|
-
*/
|
|
7
|
-
const defaultClock = {
|
|
8
|
-
now: () => Date.now(),
|
|
9
|
-
setTimeout: (callback, delay) => setTimeout(callback, delay),
|
|
10
|
-
clearTimeout: (timeoutId) => clearTimeout(timeoutId),
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Reasons why a session ID might change
|
|
14
|
-
*/
|
|
15
|
-
export const SessionChangeReason = {
|
|
16
|
-
NO_SESSION_ID: "noSessionId",
|
|
17
|
-
ACTIVITY_TIMEOUT: "activityTimeout",
|
|
18
|
-
SESSION_PAST_MAXIMUM_LENGTH: "sessionPastMaximumLength",
|
|
19
|
-
};
|
|
20
|
-
const clampToRange = (value, min, max, defaultValue) => {
|
|
21
|
-
if (value < min || value > max) {
|
|
22
|
-
return defaultValue;
|
|
23
|
-
}
|
|
24
|
-
return value;
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Manages session and window IDs with automatic timeout and persistence
|
|
28
|
-
*/
|
|
29
|
-
export class SessionIdManager {
|
|
30
|
-
_sessionIdGenerator;
|
|
31
|
-
_windowIdGenerator;
|
|
32
|
-
_config;
|
|
33
|
-
_persistence;
|
|
34
|
-
_clock;
|
|
35
|
-
_windowId;
|
|
36
|
-
_sessionId;
|
|
37
|
-
_windowIdStorageKey;
|
|
38
|
-
_primaryWindowExistsStorageKey;
|
|
39
|
-
_sessionStartTimestamp;
|
|
40
|
-
_sessionActivityTimestamp;
|
|
41
|
-
_sessionIdChangedHandlers = [];
|
|
42
|
-
_sessionTimeoutMs;
|
|
43
|
-
_enforceIdleTimeout;
|
|
44
|
-
_canUseSessionStorageCache = null;
|
|
45
|
-
_lastStorageCheck = null;
|
|
46
|
-
_beforeUnloadHandler = null;
|
|
47
|
-
_pageHideHandler = null;
|
|
48
|
-
_visibilityChangeHandler = null;
|
|
49
|
-
_heartbeatInterval = null;
|
|
50
|
-
heartbeatPaused = false;
|
|
51
|
-
_debugLogger;
|
|
52
|
-
/**
|
|
53
|
-
* Creates a new SessionIdManager
|
|
54
|
-
* @param surface - The surface ID for storage key namespacing
|
|
55
|
-
* @param config - Configuration options
|
|
56
|
-
* @param persistence - Persistence layer for storing session data
|
|
57
|
-
* @param options - Optional generators and clock for testing
|
|
58
|
-
*/
|
|
59
|
-
constructor(surface, config, persistence, options) {
|
|
60
|
-
this._config = config;
|
|
61
|
-
this._persistence = persistence;
|
|
62
|
-
this._clock = options?.clock || defaultClock;
|
|
63
|
-
this._debugLogger = options?.debugLogger;
|
|
64
|
-
this._windowId = undefined;
|
|
65
|
-
this._sessionId = undefined;
|
|
66
|
-
this._sessionStartTimestamp = null;
|
|
67
|
-
this._sessionActivityTimestamp = null;
|
|
68
|
-
this._sessionIdGenerator = options?.sessionId || uuidv7;
|
|
69
|
-
this._windowIdGenerator = options?.windowId || uuidv7;
|
|
70
|
-
const persistenceName = surface;
|
|
71
|
-
// Session idle timeout is now static - may be server-configurable in the future
|
|
72
|
-
const desiredTimeout = DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS;
|
|
73
|
-
// Normalize timeout to milliseconds using utility function
|
|
74
|
-
this._sessionTimeoutMs = toMs(clampToRange(desiredTimeout, MIN_SESSION_IDLE_TIMEOUT_SECONDS, MAX_SESSION_IDLE_TIMEOUT_SECONDS, DEFAULT_SESSION_IDLE_TIMEOUT_SECONDS));
|
|
75
|
-
this._windowIdStorageKey = `interfere_${persistenceName}_window_id`;
|
|
76
|
-
this._primaryWindowExistsStorageKey = `interfere_${persistenceName}_primary_window_exists`;
|
|
77
|
-
// Handle window ID persistence
|
|
78
|
-
if (this._canUseSessionStorage()) {
|
|
79
|
-
// Clean up stale window flags first
|
|
80
|
-
this._cleanupStaleWindowFlags();
|
|
81
|
-
const lastWindowId = sessionStore._parse(this._windowIdStorageKey);
|
|
82
|
-
const primaryWindowExists = sessionStore._parse(this._primaryWindowExistsStorageKey);
|
|
83
|
-
if (lastWindowId &&
|
|
84
|
-
!primaryWindowExists &&
|
|
85
|
-
typeof lastWindowId === "string") {
|
|
86
|
-
this._windowId = lastWindowId;
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
sessionStore._remove(this._windowIdStorageKey);
|
|
90
|
-
}
|
|
91
|
-
try {
|
|
92
|
-
sessionStore._set(this._primaryWindowExistsStorageKey, true);
|
|
93
|
-
// Set heartbeat timestamp for this window
|
|
94
|
-
sessionStore._set(`${this._windowIdStorageKey}_heartbeat`, this._clock.now());
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
// Gracefully handle session storage errors
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
// Handle bootstrap sessionID
|
|
101
|
-
if (config.sessionId) {
|
|
102
|
-
try {
|
|
103
|
-
const now = this._clock.now();
|
|
104
|
-
this._setSessionId(config.sessionId, now, now);
|
|
105
|
-
}
|
|
106
|
-
catch {
|
|
107
|
-
// Invalid sessionID in config, will generate a new one
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
this._resetIdleTimer();
|
|
111
|
-
this._listenToReloadWindow();
|
|
112
|
-
this._startWindowHeartbeat();
|
|
113
|
-
}
|
|
114
|
-
get sessionTimeoutMs() {
|
|
115
|
-
return this._sessionTimeoutMs;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Register a callback to be called when the session ID changes
|
|
119
|
-
* @param callback - Function to call when session changes
|
|
120
|
-
* @returns Unsubscribe function
|
|
121
|
-
*/
|
|
122
|
-
onSessionId(callback) {
|
|
123
|
-
this._sessionIdChangedHandlers.push(callback);
|
|
124
|
-
// Always call callback with current state, even if sessionId is null
|
|
125
|
-
// Include appropriate change reason for initial call
|
|
126
|
-
const initialChangeReason = this._sessionId
|
|
127
|
-
? undefined // Existing session, no change reason needed
|
|
128
|
-
: { [SessionChangeReason.NO_SESSION_ID]: true }; // No session yet
|
|
129
|
-
callback(this._sessionId || null, this._windowId || null, initialChangeReason);
|
|
130
|
-
return () => {
|
|
131
|
-
this._sessionIdChangedHandlers = this._sessionIdChangedHandlers.filter((h) => h !== callback);
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
_debugLog(message, error) {
|
|
135
|
-
if (this._debugLogger) {
|
|
136
|
-
this._debugLogger(message, error);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
_canUseSessionStorage() {
|
|
140
|
-
// Re-evaluate periodically in case storage availability changes
|
|
141
|
-
// (e.g., Safari Private Mode toggles, quota exhausted)
|
|
142
|
-
const now = this._clock.now();
|
|
143
|
-
const CACHE_DURATION = 30_000; // Re-check every 30 seconds
|
|
144
|
-
if (this._canUseSessionStorageCache === null ||
|
|
145
|
-
!this._lastStorageCheck ||
|
|
146
|
-
now - this._lastStorageCheck > CACHE_DURATION) {
|
|
147
|
-
this._canUseSessionStorageCache =
|
|
148
|
-
this._config.persistence !== "memory" &&
|
|
149
|
-
!this._persistence.isDisabled() &&
|
|
150
|
-
sessionStore._is_supported();
|
|
151
|
-
this._lastStorageCheck = now;
|
|
152
|
-
}
|
|
153
|
-
return this._canUseSessionStorageCache ?? false;
|
|
154
|
-
}
|
|
155
|
-
_cleanupStaleWindowFlags() {
|
|
156
|
-
if (!this._canUseSessionStorage()) {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
try {
|
|
160
|
-
const STALE_WINDOW_TIMEOUT = 60_000; // Increased from 30s to 60s for mobile browser compatibility
|
|
161
|
-
const heartbeatKey = `${this._windowIdStorageKey}_heartbeat`;
|
|
162
|
-
const lastHeartbeat = sessionStore._parse(heartbeatKey);
|
|
163
|
-
if (typeof lastHeartbeat === "number") {
|
|
164
|
-
const timeSinceHeartbeat = this._clock.now() - lastHeartbeat;
|
|
165
|
-
if (timeSinceHeartbeat > STALE_WINDOW_TIMEOUT) {
|
|
166
|
-
// Clean up stale window flags
|
|
167
|
-
sessionStore._remove(this._primaryWindowExistsStorageKey);
|
|
168
|
-
sessionStore._remove(heartbeatKey);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
// No heartbeat found - check if primary window flag exists without heartbeat
|
|
173
|
-
// This handles cases where all tabs crashed and left phantom flags
|
|
174
|
-
const primaryWindowExists = sessionStore._parse(this._primaryWindowExistsStorageKey);
|
|
175
|
-
if (primaryWindowExists) {
|
|
176
|
-
this._debugLog("Found phantom primary window flag without heartbeat, cleaning up");
|
|
177
|
-
sessionStore._remove(this._primaryWindowExistsStorageKey);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
// Gracefully handle storage errors
|
|
183
|
-
this._debugLog("Heartbeat cleanup failed", error instanceof Error ? error : undefined);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
_startWindowHeartbeat() {
|
|
187
|
-
if (typeof window === "undefined") {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const HEARTBEAT_INTERVAL_MS = 5000; // 5 seconds
|
|
191
|
-
const writeHeartbeat = () => {
|
|
192
|
-
// Only write heartbeat when tab is visible and not paused to reduce storage pressure
|
|
193
|
-
if (!this.heartbeatPaused &&
|
|
194
|
-
typeof document !== "undefined" &&
|
|
195
|
-
document.visibilityState === "visible" &&
|
|
196
|
-
this._canUseSessionStorage()) {
|
|
197
|
-
try {
|
|
198
|
-
const heartbeatKey = `${this._windowIdStorageKey}_heartbeat`;
|
|
199
|
-
sessionStore._set(heartbeatKey, this._clock.now());
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
// Storage failed - invalidate cache to re-check availability
|
|
203
|
-
this._debugLog("Heartbeat storage failed", error instanceof Error ? error : undefined);
|
|
204
|
-
this._canUseSessionStorageCache = null;
|
|
205
|
-
this._lastStorageCheck = null;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
// Write initial heartbeat
|
|
210
|
-
writeHeartbeat();
|
|
211
|
-
// Continue periodic heartbeats
|
|
212
|
-
this._heartbeatInterval = setInterval(writeHeartbeat, HEARTBEAT_INTERVAL_MS);
|
|
213
|
-
}
|
|
214
|
-
_setWindowId(windowId) {
|
|
215
|
-
if (windowId !== this._windowId) {
|
|
216
|
-
this._windowId = windowId;
|
|
217
|
-
if (this._canUseSessionStorage() && windowId) {
|
|
218
|
-
try {
|
|
219
|
-
sessionStore._set(this._windowIdStorageKey, windowId);
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// Gracefully handle session storage errors
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
_getWindowId() {
|
|
228
|
-
if (this._windowId) {
|
|
229
|
-
return this._windowId;
|
|
230
|
-
}
|
|
231
|
-
if (this._canUseSessionStorage()) {
|
|
232
|
-
const stored = sessionStore._parse(this._windowIdStorageKey);
|
|
233
|
-
return typeof stored === "string" ? stored : null;
|
|
234
|
-
}
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
_setSessionId(sessionId, sessionActivityTimestamp, sessionStartTimestamp) {
|
|
238
|
-
if (sessionId !== this._sessionId ||
|
|
239
|
-
sessionActivityTimestamp !== this._sessionActivityTimestamp ||
|
|
240
|
-
sessionStartTimestamp !== this._sessionStartTimestamp) {
|
|
241
|
-
this._sessionStartTimestamp = sessionStartTimestamp;
|
|
242
|
-
this._sessionActivityTimestamp = sessionActivityTimestamp;
|
|
243
|
-
this._sessionId = sessionId;
|
|
244
|
-
this._persistSessionWithOptimisticLocking(sessionId, sessionActivityTimestamp, sessionStartTimestamp);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
_persistSessionWithOptimisticLocking(sessionId, sessionActivityTimestamp, sessionStartTimestamp) {
|
|
248
|
-
// Use optimistic locking to prevent race conditions between tabs
|
|
249
|
-
try {
|
|
250
|
-
const currentData = this._persistence.getProperty(SESSION_ID);
|
|
251
|
-
// If another tab updated more recently, don't overwrite
|
|
252
|
-
if (Array.isArray(currentData) &&
|
|
253
|
-
typeof currentData[0] === "number" &&
|
|
254
|
-
typeof sessionActivityTimestamp === "number" &&
|
|
255
|
-
currentData[0] > sessionActivityTimestamp) {
|
|
256
|
-
// Another tab has more recent activity, sync our state
|
|
257
|
-
this._sessionActivityTimestamp = currentData[0];
|
|
258
|
-
this._sessionId =
|
|
259
|
-
typeof currentData[1] === "string" ? currentData[1] : null;
|
|
260
|
-
this._sessionStartTimestamp =
|
|
261
|
-
typeof currentData[2] === "number"
|
|
262
|
-
? currentData[2]
|
|
263
|
-
: sessionActivityTimestamp;
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
// Add microsecond jitter to reduce same-timestamp collisions in production
|
|
267
|
-
// Skip jitter in test environments to maintain predictable behavior
|
|
268
|
-
const isTestEnvironment = typeof process !== "undefined" && process.env?.NODE_ENV === "test";
|
|
269
|
-
const finalTimestamp = sessionActivityTimestamp !== null && !isTestEnvironment
|
|
270
|
-
? sessionActivityTimestamp + Math.random()
|
|
271
|
-
: sessionActivityTimestamp;
|
|
272
|
-
this._persistence.register({
|
|
273
|
-
[SESSION_ID]: [finalTimestamp, sessionId, sessionStartTimestamp],
|
|
274
|
-
});
|
|
275
|
-
// Only update our internal state after successful persistence
|
|
276
|
-
this._sessionActivityTimestamp = finalTimestamp;
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
// Gracefully handle persistence errors (e.g., storage quota exceeded)
|
|
280
|
-
this._debugLog("Session persistence failed", error instanceof Error ? error : undefined);
|
|
281
|
-
// Don't update internal state if persistence failed to keep them in sync
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
_getSessionId() {
|
|
285
|
-
if (this._sessionId !== null &&
|
|
286
|
-
this._sessionId !== undefined &&
|
|
287
|
-
this._sessionActivityTimestamp !== null &&
|
|
288
|
-
this._sessionStartTimestamp !== null) {
|
|
289
|
-
return [
|
|
290
|
-
this._sessionActivityTimestamp,
|
|
291
|
-
this._sessionId,
|
|
292
|
-
this._sessionStartTimestamp,
|
|
293
|
-
];
|
|
294
|
-
}
|
|
295
|
-
const sessionIdInfo = this._persistence.getProperty(SESSION_ID);
|
|
296
|
-
return this._parseSessionIdInfo(sessionIdInfo);
|
|
297
|
-
}
|
|
298
|
-
_parseSessionIdInfo(sessionIdInfo) {
|
|
299
|
-
if (!Array.isArray(sessionIdInfo)) {
|
|
300
|
-
this._debugLog(`Malformed session data: expected array, got ${typeof sessionIdInfo}`);
|
|
301
|
-
return [0, null, 0];
|
|
302
|
-
}
|
|
303
|
-
// Handle backwards compatibility for 2-element arrays
|
|
304
|
-
let normalizedInfo = sessionIdInfo;
|
|
305
|
-
if (sessionIdInfo.length === 2) {
|
|
306
|
-
const activityTs = sessionIdInfo[0];
|
|
307
|
-
const startTs = typeof activityTs === "number" ? activityTs : 0;
|
|
308
|
-
normalizedInfo = [...sessionIdInfo, startTs];
|
|
309
|
-
}
|
|
310
|
-
// Type guard for proper 3-element array
|
|
311
|
-
const EXPECTED_ARRAY_LENGTH = 3;
|
|
312
|
-
if (normalizedInfo.length < EXPECTED_ARRAY_LENGTH) {
|
|
313
|
-
this._debugLog(`Malformed session data: array too short (${normalizedInfo.length} < ${EXPECTED_ARRAY_LENGTH})`);
|
|
314
|
-
return [0, null, 0];
|
|
315
|
-
}
|
|
316
|
-
const rawActivityTs = normalizedInfo[0];
|
|
317
|
-
const rawSessionId = normalizedInfo[1];
|
|
318
|
-
const rawStartTs = normalizedInfo[2];
|
|
319
|
-
const parsedActivityTs = typeof rawActivityTs === "number" ? rawActivityTs : 0;
|
|
320
|
-
const parsedStartTs = typeof rawStartTs === "number" ? rawStartTs : 0;
|
|
321
|
-
// Log type mismatches for debugging
|
|
322
|
-
if (typeof rawActivityTs !== "number") {
|
|
323
|
-
this._debugLog(`Invalid activity timestamp type: ${typeof rawActivityTs}`);
|
|
324
|
-
}
|
|
325
|
-
if (typeof rawSessionId !== "string" && rawSessionId !== null) {
|
|
326
|
-
this._debugLog(`Invalid session ID type: ${typeof rawSessionId}`);
|
|
327
|
-
}
|
|
328
|
-
if (typeof rawStartTs !== "number") {
|
|
329
|
-
this._debugLog(`Invalid start timestamp type: ${typeof rawStartTs}`);
|
|
330
|
-
}
|
|
331
|
-
// Ensure start timestamp is not later than activity timestamp
|
|
332
|
-
const validStartTs = parsedStartTs > parsedActivityTs ? parsedActivityTs : parsedStartTs;
|
|
333
|
-
return [
|
|
334
|
-
parsedActivityTs,
|
|
335
|
-
typeof rawSessionId === "string" ? rawSessionId : null,
|
|
336
|
-
validStartTs,
|
|
337
|
-
];
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Reset the current session, forcing a new session to be created on next access
|
|
341
|
-
* @param reason - Optional reason for the reset
|
|
342
|
-
*/
|
|
343
|
-
resetSessionId(reason) {
|
|
344
|
-
this._setSessionId(null, null, null);
|
|
345
|
-
// Notify handlers that session has been reset with appropriate reason
|
|
346
|
-
const changeReason = reason ?? {
|
|
347
|
-
[SessionChangeReason.NO_SESSION_ID]: true,
|
|
348
|
-
};
|
|
349
|
-
for (const handler of this._sessionIdChangedHandlers) {
|
|
350
|
-
handler(null, null, changeReason);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
_performWindowCleanup() {
|
|
354
|
-
if (this._canUseSessionStorage()) {
|
|
355
|
-
// Check if we're the primary window before removing anything
|
|
356
|
-
const storedWindowId = sessionStore._parse(this._windowIdStorageKey);
|
|
357
|
-
const isPrimaryWindow = storedWindowId === this._windowId;
|
|
358
|
-
// Check for orphaned primary flag BEFORE removing our heartbeat
|
|
359
|
-
let shouldCleanupOrphanedFlag = false;
|
|
360
|
-
if (!isPrimaryWindow) {
|
|
361
|
-
try {
|
|
362
|
-
const heartbeatKey = `${this._windowIdStorageKey}_heartbeat`;
|
|
363
|
-
const lastHeartbeat = sessionStore._parse(heartbeatKey);
|
|
364
|
-
const ORPHAN_THRESHOLD = 30_000; // Increased from 10s to 30s
|
|
365
|
-
shouldCleanupOrphanedFlag =
|
|
366
|
-
typeof lastHeartbeat === "number" &&
|
|
367
|
-
this._clock.now() - lastHeartbeat > ORPHAN_THRESHOLD;
|
|
368
|
-
}
|
|
369
|
-
catch {
|
|
370
|
-
// If we can't check, err on the side of cleaning up
|
|
371
|
-
shouldCleanupOrphanedFlag = true;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
// Now remove our own window ID and heartbeat
|
|
375
|
-
sessionStore._remove(this._windowIdStorageKey);
|
|
376
|
-
sessionStore._remove(`${this._windowIdStorageKey}_heartbeat`);
|
|
377
|
-
// Remove primary window flag if appropriate
|
|
378
|
-
if (isPrimaryWindow || shouldCleanupOrphanedFlag) {
|
|
379
|
-
sessionStore._remove(this._primaryWindowExistsStorageKey);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
_listenToReloadWindow() {
|
|
384
|
-
if (typeof window === "undefined") {
|
|
385
|
-
return;
|
|
386
|
-
}
|
|
387
|
-
// Create shared cleanup handler
|
|
388
|
-
const cleanupHandler = () => this._performWindowCleanup();
|
|
389
|
-
// Set up multiple event listeners for better cross-browser compatibility
|
|
390
|
-
this._beforeUnloadHandler = cleanupHandler;
|
|
391
|
-
this._pageHideHandler = cleanupHandler;
|
|
392
|
-
this._visibilityChangeHandler = () => {
|
|
393
|
-
if (document.visibilityState === "hidden") {
|
|
394
|
-
// Pause heartbeat when document is hidden to save resources
|
|
395
|
-
this.heartbeatPaused = true;
|
|
396
|
-
// Use a small delay to distinguish between temporary hiding and permanent navigation
|
|
397
|
-
const VISIBILITY_CLEANUP_DELAY_MS = 100;
|
|
398
|
-
setTimeout(() => {
|
|
399
|
-
if (document.visibilityState === "hidden") {
|
|
400
|
-
this._performWindowCleanup();
|
|
401
|
-
}
|
|
402
|
-
}, VISIBILITY_CLEANUP_DELAY_MS);
|
|
403
|
-
}
|
|
404
|
-
else if (document.visibilityState === "visible") {
|
|
405
|
-
// Resume heartbeat when document becomes visible again
|
|
406
|
-
this.heartbeatPaused = false;
|
|
407
|
-
}
|
|
408
|
-
};
|
|
409
|
-
// Add all event listeners
|
|
410
|
-
window.addEventListener("beforeunload", this._beforeUnloadHandler, {
|
|
411
|
-
capture: false,
|
|
412
|
-
});
|
|
413
|
-
window.addEventListener("pagehide", this._pageHideHandler, {
|
|
414
|
-
capture: false,
|
|
415
|
-
});
|
|
416
|
-
if (typeof document !== "undefined") {
|
|
417
|
-
document.addEventListener("visibilitychange", this._visibilityChangeHandler, {
|
|
418
|
-
capture: false,
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
_sessionHasBeenIdleTooLong(timestamp, lastActivityTimestamp) {
|
|
423
|
-
// Don't use Math.abs - clock skew backwards should not revive old sessions
|
|
424
|
-
// Only consider session idle if current time is actually later than last activity
|
|
425
|
-
const timeSinceActivity = timestamp - lastActivityTimestamp;
|
|
426
|
-
// If clock went backwards, consider session still active (conservative approach)
|
|
427
|
-
if (timeSinceActivity < 0) {
|
|
428
|
-
return false;
|
|
429
|
-
}
|
|
430
|
-
return timeSinceActivity > this.sessionTimeoutMs;
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Check and get the current session and window IDs, updating them if necessary
|
|
434
|
-
* @param readOnly - If true, won't update activity timestamp or reset idle timer
|
|
435
|
-
* @param _timestamp - Optional timestamp override (primarily for testing)
|
|
436
|
-
* @returns Session data with optional change reason
|
|
437
|
-
*/
|
|
438
|
-
checkAndGetSessionAndWindowId(readOnly = false, _timestamp = null) {
|
|
439
|
-
const timestamp = _timestamp || this._clock.now();
|
|
440
|
-
const [lastActivityTimestamp, sessionId, startTimestamp] = this._getSessionId();
|
|
441
|
-
const windowId = this._getWindowId();
|
|
442
|
-
const changeReasons = this._evaluateSessionChangeReasons({
|
|
443
|
-
timestamp,
|
|
444
|
-
sessionId,
|
|
445
|
-
startTimestamp,
|
|
446
|
-
lastActivityTimestamp,
|
|
447
|
-
});
|
|
448
|
-
const { updatedSessionId, updatedWindowId, updatedStartTimestamp, valuesChanged, } = this._updateSessionIfNeeded({
|
|
449
|
-
sessionId,
|
|
450
|
-
windowId,
|
|
451
|
-
startTimestamp,
|
|
452
|
-
timestamp,
|
|
453
|
-
changeReasons,
|
|
454
|
-
});
|
|
455
|
-
const sessionData = this._finalizeSessionUpdate({
|
|
456
|
-
sessionId: updatedSessionId,
|
|
457
|
-
windowId: updatedWindowId,
|
|
458
|
-
startTimestamp: updatedStartTimestamp,
|
|
459
|
-
lastActivityTimestamp,
|
|
460
|
-
timestamp,
|
|
461
|
-
readOnly,
|
|
462
|
-
sessionPastMaximumLength: changeReasons.sessionPastMaximumLength,
|
|
463
|
-
valuesChanged,
|
|
464
|
-
changeReasons,
|
|
465
|
-
});
|
|
466
|
-
return sessionData;
|
|
467
|
-
}
|
|
468
|
-
_evaluateSessionChangeReasons(params) {
|
|
469
|
-
const { timestamp, sessionId, startTimestamp, lastActivityTimestamp } = params;
|
|
470
|
-
return {
|
|
471
|
-
[SessionChangeReason.NO_SESSION_ID]: !sessionId,
|
|
472
|
-
[SessionChangeReason.ACTIVITY_TIMEOUT]: this._sessionHasBeenIdleTooLong(timestamp, lastActivityTimestamp),
|
|
473
|
-
[SessionChangeReason.SESSION_PAST_MAXIMUM_LENGTH]: typeof startTimestamp === "number" &&
|
|
474
|
-
startTimestamp > 0 &&
|
|
475
|
-
timestamp - startTimestamp > SESSION_LENGTH_LIMIT_MILLISECONDS,
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
_updateSessionIfNeeded(params) {
|
|
479
|
-
const { sessionId, windowId, startTimestamp, timestamp, changeReasons } = params;
|
|
480
|
-
const { [SessionChangeReason.NO_SESSION_ID]: noSessionId, [SessionChangeReason.ACTIVITY_TIMEOUT]: activityTimeout, [SessionChangeReason.SESSION_PAST_MAXIMUM_LENGTH]: sessionPastMaximumLength, } = changeReasons;
|
|
481
|
-
if (noSessionId || activityTimeout || sessionPastMaximumLength) {
|
|
482
|
-
return {
|
|
483
|
-
updatedSessionId: this._sessionIdGenerator(),
|
|
484
|
-
// Keep existing window ID for continuity, only generate new one if none exists
|
|
485
|
-
updatedWindowId: windowId || this._windowIdGenerator(),
|
|
486
|
-
updatedStartTimestamp: timestamp,
|
|
487
|
-
valuesChanged: true,
|
|
488
|
-
};
|
|
489
|
-
}
|
|
490
|
-
if (!windowId) {
|
|
491
|
-
return {
|
|
492
|
-
updatedSessionId: sessionId,
|
|
493
|
-
updatedWindowId: this._windowIdGenerator(),
|
|
494
|
-
updatedStartTimestamp: startTimestamp,
|
|
495
|
-
valuesChanged: true,
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
return {
|
|
499
|
-
updatedSessionId: sessionId,
|
|
500
|
-
updatedWindowId: windowId,
|
|
501
|
-
updatedStartTimestamp: startTimestamp,
|
|
502
|
-
valuesChanged: false,
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
_calculateActivityTimestamp(params) {
|
|
506
|
-
const { lastActivityTimestamp, timestamp, readOnly, sessionPastMaximumLength, valuesChanged, changeReasons, } = params;
|
|
507
|
-
// Check if session was regenerated due to specific conditions
|
|
508
|
-
const noSessionId = changeReasons[SessionChangeReason.NO_SESSION_ID];
|
|
509
|
-
const activityTimeout = changeReasons[SessionChangeReason.ACTIVITY_TIMEOUT];
|
|
510
|
-
const sessionPastMaxLength = changeReasons[SessionChangeReason.SESSION_PAST_MAXIMUM_LENGTH];
|
|
511
|
-
const sessionWasRegenerated = valuesChanged && (noSessionId || activityTimeout || sessionPastMaxLength);
|
|
512
|
-
// Fixed logic: Update activity timestamp for all session regenerations to prevent infinite loops
|
|
513
|
-
const shouldUpdateActivity = !readOnly ||
|
|
514
|
-
sessionPastMaximumLength ||
|
|
515
|
-
lastActivityTimestamp === 0 ||
|
|
516
|
-
(sessionWasRegenerated &&
|
|
517
|
-
(noSessionId || sessionPastMaxLength || activityTimeout)); // Include activityTimeout to prevent infinite regeneration
|
|
518
|
-
// For all regenerations, use current timestamp to mark new activity and prevent immediate timeout
|
|
519
|
-
return shouldUpdateActivity ? timestamp : lastActivityTimestamp;
|
|
520
|
-
}
|
|
521
|
-
_finalizeSessionUpdate(params) {
|
|
522
|
-
const { sessionId, windowId, startTimestamp, lastActivityTimestamp, timestamp, readOnly, sessionPastMaximumLength, valuesChanged, changeReasons, } = params;
|
|
523
|
-
// Calculate the appropriate activity timestamp
|
|
524
|
-
const newActivityTimestamp = this._calculateActivityTimestamp({
|
|
525
|
-
lastActivityTimestamp,
|
|
526
|
-
timestamp,
|
|
527
|
-
readOnly,
|
|
528
|
-
sessionPastMaximumLength,
|
|
529
|
-
valuesChanged,
|
|
530
|
-
changeReasons,
|
|
531
|
-
});
|
|
532
|
-
// Handle session start timestamp consistently
|
|
533
|
-
const noSessionId = changeReasons[SessionChangeReason.NO_SESSION_ID];
|
|
534
|
-
const activityTimeout = changeReasons[SessionChangeReason.ACTIVITY_TIMEOUT];
|
|
535
|
-
const sessionPastMaxLength = changeReasons[SessionChangeReason.SESSION_PAST_MAXIMUM_LENGTH];
|
|
536
|
-
const sessionWasRegenerated = valuesChanged && (noSessionId || activityTimeout || sessionPastMaxLength);
|
|
537
|
-
// Use current timestamp if no start timestamp or if session was reset/regenerated
|
|
538
|
-
const sessionStartTimestamp = startTimestamp === 0 || sessionWasRegenerated
|
|
539
|
-
? timestamp
|
|
540
|
-
: startTimestamp;
|
|
541
|
-
this._setWindowId(windowId);
|
|
542
|
-
this._setSessionId(sessionId, // Keep null internally
|
|
543
|
-
newActivityTimestamp, sessionStartTimestamp);
|
|
544
|
-
if (!readOnly) {
|
|
545
|
-
this._resetIdleTimer();
|
|
546
|
-
}
|
|
547
|
-
if (valuesChanged) {
|
|
548
|
-
for (const handler of this._sessionIdChangedHandlers) {
|
|
549
|
-
handler(sessionId, windowId, changeReasons); // Pass null values to handlers
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
// Ensure we always have a sessionId - generate one if null
|
|
553
|
-
const finalSessionId = sessionId || this._sessionIdGenerator();
|
|
554
|
-
// If we had to generate a sessionId, persist it
|
|
555
|
-
if (!sessionId && finalSessionId) {
|
|
556
|
-
this._setSessionId(finalSessionId, newActivityTimestamp, sessionStartTimestamp);
|
|
557
|
-
}
|
|
558
|
-
return {
|
|
559
|
-
sessionId: finalSessionId,
|
|
560
|
-
windowId, // Keep null for consistency with callbacks
|
|
561
|
-
sessionStartTimestamp,
|
|
562
|
-
lastActivityTimestamp: newActivityTimestamp,
|
|
563
|
-
...(valuesChanged && { changeReason: changeReasons }),
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
_resetIdleTimer() {
|
|
567
|
-
// Always reset the timer - throttling was causing sessions to end prematurely
|
|
568
|
-
if (this._enforceIdleTimeout) {
|
|
569
|
-
this._clock.clearTimeout(this._enforceIdleTimeout);
|
|
570
|
-
}
|
|
571
|
-
this._enforceIdleTimeout = this._clock.setTimeout(() => {
|
|
572
|
-
try {
|
|
573
|
-
// Get fresh activity timestamp directly from persistence, not cached value
|
|
574
|
-
const sessionIdInfo = this._persistence.getProperty(SESSION_ID);
|
|
575
|
-
let lastActivityTimestamp = null;
|
|
576
|
-
if (Array.isArray(sessionIdInfo) &&
|
|
577
|
-
typeof sessionIdInfo[0] === "number") {
|
|
578
|
-
lastActivityTimestamp = sessionIdInfo[0];
|
|
579
|
-
}
|
|
580
|
-
const currentTime = this._clock.now();
|
|
581
|
-
// If we can't get a valid timestamp, reset the session to be safe
|
|
582
|
-
if (typeof lastActivityTimestamp === "number") {
|
|
583
|
-
if (this._sessionHasBeenIdleTooLong(currentTime, lastActivityTimestamp)) {
|
|
584
|
-
this.resetSessionId({
|
|
585
|
-
[SessionChangeReason.ACTIVITY_TIMEOUT]: true,
|
|
586
|
-
});
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
// Persistence failure or corrupt data - reset session
|
|
591
|
-
this.resetSessionId({ [SessionChangeReason.ACTIVITY_TIMEOUT]: true });
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
catch (error) {
|
|
595
|
-
// Persistence error - reset session to be safe
|
|
596
|
-
this._debugLog("Idle timeout check failed", error instanceof Error ? error : undefined);
|
|
597
|
-
this.resetSessionId({ [SessionChangeReason.ACTIVITY_TIMEOUT]: true });
|
|
598
|
-
}
|
|
599
|
-
}, this._sessionTimeoutMs); // Use exact configured timeout
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Clean up resources and event listeners
|
|
603
|
-
* Call this when the SessionIdManager is no longer needed
|
|
604
|
-
*/
|
|
605
|
-
dispose() {
|
|
606
|
-
// Clear idle timeout
|
|
607
|
-
if (this._enforceIdleTimeout) {
|
|
608
|
-
this._clock.clearTimeout(this._enforceIdleTimeout);
|
|
609
|
-
this._enforceIdleTimeout = undefined;
|
|
610
|
-
}
|
|
611
|
-
// Clear heartbeat interval
|
|
612
|
-
if (this._heartbeatInterval) {
|
|
613
|
-
clearInterval(this._heartbeatInterval);
|
|
614
|
-
this._heartbeatInterval = null;
|
|
615
|
-
}
|
|
616
|
-
// Remove event listeners
|
|
617
|
-
if (typeof window !== "undefined") {
|
|
618
|
-
if (this._beforeUnloadHandler) {
|
|
619
|
-
window.removeEventListener("beforeunload", this._beforeUnloadHandler);
|
|
620
|
-
this._beforeUnloadHandler = null;
|
|
621
|
-
}
|
|
622
|
-
if (this._pageHideHandler) {
|
|
623
|
-
window.removeEventListener("pagehide", this._pageHideHandler);
|
|
624
|
-
this._pageHideHandler = null;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (typeof document !== "undefined" && this._visibilityChangeHandler) {
|
|
628
|
-
document.removeEventListener("visibilitychange", this._visibilityChangeHandler);
|
|
629
|
-
this._visibilityChangeHandler = null;
|
|
630
|
-
}
|
|
631
|
-
// Clear handlers
|
|
632
|
-
this._sessionIdChangedHandlers = [];
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
//# sourceMappingURL=session-manager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/lib/session/session-manager.ts"],"names":[],"mappings":"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"}
|