Three surgical edits in src/content/index.ts flip the 7 RED tests from commit3dbc51cto GREEN (full vitest 180/180; tsc-clean preserved). * P1 #11 — fetch URL extraction (TWO sites, identical narrow): - line ~190 (ok-branch of setupNetworkLogging) - line ~210 (catch-branch of setupNetworkLogging) Both replace the implicit-coercion `target: args[0]?.toString() || 'unknown'` with the explicit type-narrow `target: (args[0] instanceof Request ? args[0].url : String(args[0])) || 'unknown'`. This unmasks the failing URL when the page calls `fetch(new Request(url))` — the original code captured the literal '[object Request]' (Request has no custom toString and falls back to Object.prototype.toString). * P1 #14 — navigation URL tracking via module-level previousUrl: - ADD `let previousUrl = window.location.href;` at module scope (line 29; typeof window guard keeps node-env unit tests importable). - REWRITE handleNavigation to swap-then-emit: const fromUrl = previousUrl; const toUrl = window.location.href; previousUrl = toUrl; addUserEvent({ ..., meta: { previousUrl: fromUrl } }); This replaces `meta: { previousUrl: history.state?.url || 'unknown' }` which always emitted 'unknown' in apps that don't populate history.state (almost all of them) — making meta.previousUrl useless for support reproducing where the operator was before a failing navigation. * P1 #15 — rrweb emit timestamp normalization: - Prepend `event.timestamp = Date.now();` inside the rrweb record() emit callback at ~line 312. rrweb-internal timestamps are page-load-relative small ints; without normalization the cleanupOldEvents arithmetic at ~line 33 `(now - event.timestamp) < RRWEB_RETENTION_MS` is a category error (Date.now() - 42 ≫ 10 min retention). Plan: 04-01 Wave 1 (closes Wave 0 RED gate from3dbc51c) Files: - src/content/index.ts (~30 lines added; 3 surgical edits + Plan-citing comments) Verification (GREEN gate): - npm test -- tests/content/ --run → 9 passed (9) - npm test -- --run → 180 passed (180); was 171/171 pre-Plan-04-01 - npx tsc --noEmit → exit 0 - grep -c "instanceof Request" src/content/index.ts → 3 (≥2 expected) - grep -cE "args\[0\]\?\.toString" src/content/index.ts → 0 (old pattern purged) - grep -cE "^let previousUrl" src/content/index.ts → 1 - grep -cE "meta: \{ previousUrl: fromUrl \}" src/content/index.ts → 1 - grep -cE "event\.timestamp = Date\.now\(\)" src/content/index.ts → 2 (1 in addUserEvent normalization at line 54 + 1 new in rrweb emit at line 315) Pre-checkpoint bundle gates: - npm run build → 4.66s; dist/ ships cleanly - Tier-1 FORBIDDEN_HOOK_STRINGS test (no-test-hooks-in-prod-bundle.test.ts) → 13/13 GREEN; inventory at 12 strings (unchanged — Plan 04-01 added no harness hooks). - SW CSP-safety: 1 `new Function("...")` in SW chunk — pre-existing setimmediate polyfill from vite-plugin-node-polyfills, NOT a Plan 04-01 regression; documented at .planning/phases/01-stabilize-video-pipeline/ deferred-items.md as Plan 04-02 fix scope. - Node-globals / DOM-globals in SW chunk: 1 Buffer + 4 window/document references — all from JSZip internals (pre-existing across all Phase 1+2+3 builds; lower-case `Buffer` field names + DOM shimming inside zip assembly). - manifest.json: present, name uses chrome.i18n __MSG_extName__ message resolution (no en↔ru parity surface touched by Plan 04-01). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,13 @@ let rrwebEvents: EventWithTime[] = [];
|
||||
// Буфер пользовательских событий
|
||||
let userEvents: UserEvent[] = [];
|
||||
|
||||
// Plan 04-01 P1 #14 — module-level previousUrl tracker. Initialized at module
|
||||
// load (content-script-realm `window` is always present in production; the
|
||||
// typeof guard keeps node-env unit tests importable). Mutated in
|
||||
// `handleNavigation` so meta.previousUrl carries the prior URL instead of
|
||||
// the stale `history.state?.url || 'unknown'` shape the original code used.
|
||||
let previousUrl: string = (typeof window !== 'undefined') ? window.location.href : '';
|
||||
|
||||
// Очистка старых событий
|
||||
function cleanupOldEvents() {
|
||||
const now = Date.now();
|
||||
@@ -97,14 +104,23 @@ function setupInputLogging() {
|
||||
|
||||
// Логирование навигации
|
||||
function setupNavigationLogging() {
|
||||
// Plan 04-01 P1 #14 — read module-level `previousUrl` (initialized at module
|
||||
// load) into `fromUrl`, then mutate before the addUserEvent emit so the
|
||||
// next navigation captures THIS URL as its previousUrl. The original code
|
||||
// read history.state?.url which is `null` in apps that don't populate it,
|
||||
// leaking the literal string 'unknown' into every meta.previousUrl field
|
||||
// of saved archives.
|
||||
const handleNavigation = () => {
|
||||
const fromUrl = previousUrl;
|
||||
const toUrl = window.location.href;
|
||||
previousUrl = toUrl;
|
||||
addUserEvent({
|
||||
timestamp: Date.now(),
|
||||
type: 'navigation',
|
||||
target: 'window',
|
||||
value: window.location.href,
|
||||
url: window.location.href,
|
||||
meta: { previousUrl: history.state?.url || 'unknown' }
|
||||
value: toUrl,
|
||||
url: toUrl,
|
||||
meta: { previousUrl: fromUrl },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -171,7 +187,11 @@ function setupNetworkLogging() {
|
||||
addUserEvent({
|
||||
timestamp: Date.now(),
|
||||
type: 'network_error',
|
||||
target: args[0]?.toString() || 'unknown',
|
||||
// Plan 04-01 P1 #11 — the original implicit-coercion call
|
||||
// resolved to '[object Request]' when the page invoked
|
||||
// fetch(new Request(url)). Type-narrowing on Request lets us
|
||||
// pull the canonical .url instead.
|
||||
target: (args[0] instanceof Request ? args[0].url : String(args[0])) || 'unknown',
|
||||
value: `HTTP ${response.status} ${response.statusText}`,
|
||||
url: window.location.href,
|
||||
meta: {
|
||||
@@ -187,7 +207,11 @@ function setupNetworkLogging() {
|
||||
addUserEvent({
|
||||
timestamp: Date.now(),
|
||||
type: 'network_error',
|
||||
target: args[0]?.toString() || 'unknown',
|
||||
// Plan 04-01 P1 #11 — twin of the ok-branch narrow above. Both
|
||||
// sites carry the same `instanceof Request` discipline so the
|
||||
// failing URL surfaces verbatim in events.json regardless of
|
||||
// whether the failure was an HTTP non-2xx OR a network throw.
|
||||
target: (args[0] instanceof Request ? args[0].url : String(args[0])) || 'unknown',
|
||||
value: error.message,
|
||||
url: window.location.href,
|
||||
meta: {
|
||||
@@ -285,6 +309,13 @@ function getSelector(element: HTMLElement): string {
|
||||
function initRrweb() {
|
||||
record({
|
||||
emit(event) {
|
||||
// Plan 04-01 P1 #15 — normalize to Unix epoch for events.json
|
||||
// downstream + cleanupOldEvents arithmetic correctness. rrweb's
|
||||
// emit-side timestamps are page-load-relative small ints; without
|
||||
// this normalization `(now - event.timestamp) < RRWEB_RETENTION_MS`
|
||||
// at line ~33 becomes a category error (Date.now() - 42 is always
|
||||
// >> 10 min).
|
||||
event.timestamp = Date.now();
|
||||
rrwebEvents.push(event);
|
||||
},
|
||||
maskInputOptions: {
|
||||
|
||||
Reference in New Issue
Block a user