♻️ Rewrite SessionManager with reactive strategy interface#4348
Draft
thomas-lebeau wants to merge 31 commits intov7from
Draft
♻️ Rewrite SessionManager with reactive strategy interface#4348thomas-lebeau wants to merge 31 commits intov7from
thomas-lebeau wants to merge 31 commits intov7from
Conversation
Bundles Sizes Evolution
🚀 CPU PerformancePending... 🧠 Memory PerformancePending... |
|
✨ Fix all issues with BitsAI or with Cursor
|
918db7f to
741db9f
Compare
New interface: setSessionState(fn) + sessionObservable. Removes isLockEnabled, persistSession, retrieveSession, expireSession.
- setSessionState(fn) reads global, applies fn, writes back, notifies - Shared observable across SDK instances via global object - Updated fake strategy for new interface
- setSessionState(fn) reads localStorage, applies fn, writes back - Cross-tab detection via native storage event - Observable with onFirstSubscribe for lazy event listener setup
- setSessionState(fn) uses Web Locks API for atomic read-modify-write - Falls back to no-lock (last-write-wins) when Web Locks unavailable - BroadcastChannel for cross-tab notification, polling as fallback - Handles c=xxx cookie options encoding internally - Cookie expiration respects trackAnonymousUser setting
Merge sessionStore and sessionManager into a single cohesive unit that reacts to strategy emissions instead of polling. The new SessionManager subscribes to strategy.sessionObservable for all state changes and uses setSessionState(fn) for all writes, eliminating the old sessionStore layer, sessionStoreOperations, and polling loop.
- configuration.ts imports selectSessionStoreStrategyType from sessionManager - Remove STORAGE_POLL_DELAY export (now internal to cookie strategy)
These are replaced by the merged SessionManager and per-strategy queuing (Web Locks for cookies).
Replace old cookie-based tests with comprehensive tests using the fake session store strategy. Make getSessionStoreStrategy mockable so tests can inject the fake strategy.
STORAGE_POLL_DELAY was removed from core exports as polling is now internal to the cookie strategy.
- Fix import order in sessionInMemory.spec.ts - Add void to navigator.locks.request promise in sessionInCookie.ts - Disable Zone.js lint rule for localStorage storage event listener - Fix type imports in sessionManager.spec.ts - Remove unnecessary type assertion
The init call now also expands the session (creates ID + expire timestamp) so it's immediately usable. Previously, initializeSession only created an expired state, requiring user activity before the session became active — breaking the async Web Locks flow where onReady fired with an expired, ID-less session.
Move cookieObservable from rum-core to core and use it for cross-tab session change detection instead of BroadcastChannel + polling fallback.
- Extract CookieAccess interface that unifies CookieStore API and document.cookie behind async get/getAll/set/delete methods - Move CookieStoreWindow type to browser.types.ts alongside CookieStore - Refactor sessionInCookie to use CookieAccess instead of raw cookie helpers - Simplify queue processing: use Web Locks directly per call with promise chain fallback - Update session cookie tests to be async (flush via Web Locks)
- Change SessionStoreStrategy interface to return Promise<void> from setSessionState - Update cookie strategy to await navigator.locks and pendingChain instead of fire-and-forget - Update localStorage and memory strategies to return Promise.resolve() for consistency - Add void annotations at all fire-and-forget call sites in sessionManager - Simplify cookie tests by awaiting setSessionState directly instead of using flushAsyncQueue
Replace the synchronous first-emission pattern (isFirstEmission flag + sessionObservable subscription) with an async initialization flow that awaits the initial setSessionState promise before subscribing to subsequent changes. This ensures consent revocation during async cookie lock acquisition is handled correctly. - Remove `stop` property from SessionManager interface (already handled by stopSessionManager) - Update collectAsyncCalls to preserve spy behavior when chaining - Align all session manager tests and mocks with async initialization
- Apply expired state to in-memory tracking before async storage persist so events stop being collected immediately - Prevents race where events could still be collected between expire() call and async setSessionState completion
- Consolidate get/getAll/set/delete into a single getAllAndSet(cb) method that reads all cookie values and writes atomically via a callback - Adapt sessionInCookie to use the callback pattern, moving session string building and expire delay computation into the callback - Remove now-unnecessary writeSessionState function and CookieAccessItem type usage
…til session is ready
…nd cleanup - Rename motifyCookieValieIfChanged → notifyCookieValueIfChanged (typo fix) - Rewrite cookieAccess.spec.ts to cover getAllAndSet and observable behavior - Add telemetrySessionContext.spec.ts for new extracted context function - Move pendingChain to module scope with eslint-disable for side-effects rule - Remove @only tag and stale TODO comment from microfrontend scenario
- Remove AssembleTelemetry hook tests from userContext, sessionContext (logs/rum-core), and defaultContext specs - Remove unused DefaultTelemetryEventAttributes type imports and SKIPPED import from context source files
e523edd to
bfefbe6
Compare
…d fix async test assertions - Simplify normalizePersistenceList to default to cookie-only, removing the legacy allowFallbackToLocalStorage fallback and the unused initConfiguration parameter - Add async/await with collectAsyncCalls in preStartRum and rumPublicApi specs where spy assertions now require awaiting async session initialization
- Replace inline mockSessionManager helper with shared createSessionManagerMock utility - Use MOCK_SESSION_ID and setNotTracked() for consistent test patterns
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The existing
SessionManagerandSessionStorearchitecture has accumulated complexity through layered abstractions (sessionStore.ts,sessionStoreOperations.ts, product-specific wrappers). This makes it difficult to adopt modern browser APIs like the CookieStore API and Web Locks, and the synchronous mutex-based approach creates contention issues.This PR rewrites the session management layer with a reactive strategy interface, preparing the foundation for async-first storage (CookieStore API) in v7.
Changes
SessionStoreStrategyinterface — strategies now own their state and expose it reactively via an observable, replacing the synchronous read/write/mutex patterncookieObservablefor change detection, replacing the polling-based mutexCookieAccessabstraction to decouple cookie read/write from thedocument.cookieAPI, preparing for CookieStore API adoptionSessionStoreintoSessionManager— removesessionStore.tsandsessionStoreOperations.ts, consolidating session lifecycle logic into a single moduleSessionManagerinitialization fully async —startSessionManagernow returnsPromise<SessionManager>, withsetSessionStatealso async across all strategiesrumSessionManager.ts,logsSessionManager.ts) — the genericSessionManagernow handles all productsTrackingTypegeneric parameter fromSessionManager— session tracking decisions are no longer encoded in the session manager typeTest instructions
Checklist