Skip to content

fix(forwarders): reset configuredForwarders on each init to prevent kit accumulation - #1332

Draft
alexs-mparticle wants to merge 6 commits into
developmentfrom
fix/forwarder-reinit-accumulation
Draft

fix(forwarders): reset configuredForwarders on each init to prevent kit accumulation#1332
alexs-mparticle wants to merge 6 commits into
developmentfrom
fix/forwarder-reinit-accumulation

Conversation

@alexs-mparticle

Copy link
Copy Markdown
Collaborator

Summary

  • Resets _Store.configuredForwarders to [] at the start of processForwarders so that each mParticle.init() call starts with a clean forwarder list.
  • Without this fix, SPA partners that call mParticle.init() on every navigation accumulate duplicate kit instances — after N inits, activeForwarders contains N Rokt kit instances and the same event fires N times.

Root cause

configuredForwarders is initialised once to [] in the Store constructor and never reset. processForwardersconfigureUIEnabledKit pushes a new kit instance on every call, but the previous instances are never evicted. initForwarders then promotes all of them to activeForwarders.

Why the reset belongs here

processForwarders is the only function that writes to configuredForwarders. Resetting at the top makes the function idempotent and safe to call multiple times — any future call site gets correct behaviour automatically without needing to remember to reset first.

Logging added (remove before merge)

Verbose logging shows cleared N existing forwarder(s) before re-init and the final configured count on every init, making it easy to verify in local testing.

Test plan

  • Confirm no test regressions (npm test)
  • Test on a Next.js SPA partner (Savage X Fenty) — second navigation should log cleared 1 existing forwarder(s) and produce exactly 1 kit event, not 2
  • Remove diagnostic logging before merge

Notes

Draft — pending local verification on SPA partner site. Companion to #1331.

Add PageViewTracker to auto-log a page view on client-side (SPA)
navigations when the AutoLogPageView feature flag is enabled. The tracker
monkey-patches history.pushState/replaceState and listens for
popstate/hashchange, deduping by pathname and firing the deferred
_Events.logPageView() so the document title has settled.

Wired into completeSDKInitialization: constructs and inits the tracker
when the flag is on, and tears it down if the flag is off on re-init.

This is a validation POC: each detection stage emits a
console.warn('Rokt APV:', ...) so the logic can be verified locally via
browser overrides. The debug logging is not intended to ship.
Replace console.warn debug calls in PageViewTracker with
mpInstance.Logger.verbose so SPA page-view tracking respects the
SDK log level. Adds jest coverage and .nvmrc.
Bug 1 (teardown asymmetry): evaluate pushState and replaceState restoration
independently by identity, so a still-ours replaceState wrapper is restored
even when a third party has replaced only pushState. Prevents a leaked wrapper
from being double-wrapped on re-init.

Bug 2 (final-URL capture): snapshot the settled path at accept time and pass it
through to the deferred flush, so each fire reports its own navigation rather
than reading the live location (which a same-tick navigation would overwrite).
Extract the fire logic into a testable firePageView(path) that emits via
_Events.logEvent(PageView) carrying path, title, and hostname.
The init() seed and handleNavigation() comparison derived the dedup key by
hand in two places; a future edit to one could silently desync the other,
mis-firing or suppressing the first navigation after init. Extract a single
private getCurrentKey() used by both.
Including search in the dedup key over-counted page views (transient UI
state written to the query string via replaceState produced a distinct key
per change) and, combined with the per-fire resetSessionTimer() call, could
keep a session alive indefinitely from background query-string churn with no
user present.

Key and report pathname only. Hash-router support is deferred to a follow-up
along with the anchor-link-vs-route-hash question; the hashchange listener is
removed until then.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant