@tracelane/wdio 0.1.0-alpha.2 → 0.1.0-alpha.21

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 CHANGED
@@ -1,6 +1,53 @@
1
+ <img src="https://raw.githubusercontent.com/Cubenest/rrweb-stack/main/assets/brand/sub-tracelane.svg" height="40" alt="tracelane">
2
+
1
3
  # @tracelane/wdio
2
4
 
3
- A [WebdriverIO](https://webdriver.io) **Service** that records an [rrweb](https://www.rrweb.io)-grade session of your test run and, on a failed test, writes a **single self-contained `.html` report** to `./tracelane-reports/` — replay, console panel, and failed-network panel, all offline in one file.
5
+ > The reporter for your WebdriverIO tests Playwright and Cypress on the roadmap. Self-contained HTML for every run — replay failures, audit successes, attach to any bug tracker. No SaaS, no dashboard, no signup.
6
+
7
+ [![npm](https://img.shields.io/npm/v/@tracelane/wdio.svg)](https://www.npmjs.com/package/@tracelane/wdio)
8
+ [![downloads](https://img.shields.io/npm/dw/@tracelane/wdio.svg)](https://www.npmjs.com/package/@tracelane/wdio)
9
+ [![license](https://img.shields.io/npm/l/@tracelane/wdio.svg)](https://github.com/Cubenest/rrweb-stack/blob/main/LICENSE)
10
+ [![CI](https://github.com/Cubenest/rrweb-stack/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Cubenest/rrweb-stack/actions/workflows/ci.yml)
11
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Cubenest/rrweb-stack/badge)](https://scorecard.dev/viewer/?uri=github.com/Cubenest/rrweb-stack)
12
+
13
+ ![tracelane install — one command](https://raw.githubusercontent.com/Cubenest/rrweb-stack/main/assets/tracelane-hero.gif)
14
+
15
+ Docs: <https://tracelane.cubenest.in>
16
+
17
+ ```sh
18
+ cd your-wdio-project
19
+ npx @tracelane/cli init
20
+ ```
21
+
22
+ That's it. [`npx @tracelane/cli init`](https://www.npmjs.com/package/@tracelane/cli) detects your runner, installs `@tracelane/wdio`, edits `wdio.conf.ts` in place, and gitignores the reports directory. Idempotent (re-run is a no-op) and dry-runnable (`--dry-run`).
23
+
24
+ Run your suite. On a failing test you get a single `.html` file at `./tracelane-reports/<spec>--<title>--<cid>-<ts>.html` — open it in any browser, fully offline. Replay the run with [rrweb-player](https://www.rrweb.io), inspect the console + failed-network panels, attach to your bug tracker, archive it forever. No upload, no signup, no cloud.
25
+
26
+ ### Or wire it manually
27
+
28
+ ```sh
29
+ npm install --save-dev @tracelane/wdio
30
+ ```
31
+
32
+ ```ts
33
+ // wdio.conf.ts
34
+ import TraceLaneService from '@tracelane/wdio';
35
+
36
+ export const config = {
37
+ // ...your existing config
38
+ services: [[TraceLaneService, { mode: 'failed' }]],
39
+ };
40
+ ```
41
+
42
+ Same result — `npx @tracelane/cli init` is just the orchestration that does the lines above for you.
43
+
44
+ ## What this is NOT
45
+
46
+ - Not Cypress Cloud, Replay.io, or Sentry Session Replay. There is no SaaS to host. There is no signup. There is no dashboard. There is no telemetry. The artifact is a single HTML file on your filesystem.
47
+ - Not a reporter (in the `@wdio/reporter` sense). `tracelane` is a WDIO **Service** because only a Service can attach to the live browser, inject the rrweb recorder + in-page network plugin, drain the in-page buffer, and (where available) use CDP to enrich network capture. A paired Allure **Reporter** shim is planned for v1.1.
48
+ - Not just for failures. `mode: 'all'` writes a report for every test — useful as a CI artifact, evidence in a PR, or a "what changed between green and red" diff.
49
+
50
+ ## Full example
4
51
 
5
52
  ```ts
6
53
  // wdio.conf.ts
@@ -18,7 +65,10 @@ export const config: Options.Testrunner = {
18
65
  },
19
66
  ],
20
67
  services: [
21
- ['devtools', {}], // enables browser.cdp(...) for network capture see "Network capture" below
68
+ // Optional: network is captured in-page by default (all browsers, no CDP).
69
+ // Add devtools only to enrich it with authoritative status + no-response
70
+ // failures on Chromium — see "Network capture" below.
71
+ ['devtools', {}],
22
72
  [
23
73
  TraceLaneService,
24
74
  {
@@ -32,21 +82,13 @@ export const config: Options.Testrunner = {
32
82
  };
33
83
  ```
34
84
 
35
- Run your suite. On a failing Chrome+Mocha test you get `./tracelane-reports/<spec>--<title>--<cid>-<ts>.html` — open it in any browser, fully offline.
36
-
37
- ## Install
38
-
39
- ```sh
40
- pnpm add -D @tracelane/wdio webdriverio @wdio/cli @wdio/local-runner @wdio/mocha-framework
41
- ```
42
-
43
85
  `webdriverio` and `@wdio/types` are **peer dependencies** (`^9.0.0`); you already have them in a WDIO project.
44
86
 
45
87
  ## How it works
46
88
 
47
89
  - On the first test, the Service injects an rrweb recorder bundle into the page and installs an in-page event buffer (`window.__tracelane__events`).
48
- - The Node side drains that buffer on a poll (default every 5 s) and on every `afterTest`, re-injecting on navigation ([ADR-0006](https://github.com/Cubenest/rrweb-stack/blob/main/prds/adrs/0006-p1-in-page-buffer-node-polled.md)).
49
- - In `failed` mode (default) a passing test discards its buffer; a failing test's buffer is handed to [`@tracelane/report`](https://github.com/Cubenest/rrweb-stack/tree/main/packages/tracelane-report), which builds the single offline HTML (≤ 25 MB, [ADR-0005](https://github.com/Cubenest/rrweb-stack/blob/main/prds/adrs/0005-p1-failed-only-self-contained-html.md)).
90
+ - The Node side drains that buffer on a poll (default every 500 ms) and on every `afterTest`, re-injecting after each navigation.
91
+ - In `failed` mode (default) a passing test discards its buffer; a failing test's buffer is handed to [`@tracelane/report`](https://github.com/Cubenest/rrweb-stack/tree/main/packages/tracelane-report), which builds the single offline HTML (≤ 25 MB).
50
92
 
51
93
  ## Options
52
94
 
@@ -55,9 +97,10 @@ pnpm add -D @tracelane/wdio webdriverio @wdio/cli @wdio/local-runner @wdio/mocha
55
97
  | `mode` | `'failed' \| 'all'` | `'failed'` | `failed` writes a report only on failure; `all` on every test. `TRACELANE_MODE` env var overrides this. |
56
98
  | `outDir` | `string` | `'./tracelane-reports'` | Report output directory (created if missing). |
57
99
  | `capture.rrweb` | `boolean` | `true` | Record the rrweb session. |
58
- | `capture.network` | `boolean` | `true` | Route failed responses (`status >= 400`) into the console timeline via CDP. |
59
- | `capture.console` | `boolean` | `true` | Capture `console.*` via the rrweb console plugin. Setting this `false` also drops the `[tracelane.net]` network-error lines, since `capture.network` surfaces them through `console.error`. |
60
- | `drainIntervalMs` | `number` | `5000` | Node-side drain poll interval. |
100
+ | `capture.network` | `boolean` | `true` | Capture network requests via the in-page `rrweb/network@1` plugin — all browsers, no CDP. Privacy-first: only URL/method/status/timing by default (headers + bodies off; opt in via `capture.networkOptions`). CDP is an optional fallback that adds authoritative status + true no-response failures where it's available. |
101
+ | `capture.networkOptions` | `NetworkRecordOptions` | plugin defaults | Forwarded to the in-page network plugin (`recordHeaders`, `recordBody`, `maskRequestFn`, `payloadHostDenyList`, …). Defaults are privacy-first (headers + bodies off). Ignored when `capture.network` is `false`. |
102
+ | `capture.console` | `boolean` | `true` | Capture `console.*` via the rrweb console plugin. Setting this `false` also drops any `[tracelane.net]` network-error lines from the CDP fallback path, since those surface through `console.error`. |
103
+ | `drainIntervalMs` | `number` | `500` | Node-side drain poll interval. |
61
104
  | `cooldownMs` | `number` | `250` | Re-injection cooldown guard (suppresses double-init on hash/HMR navigation). |
62
105
  | `allure` | `boolean` | `false` | Reserved for the v1.1 Allure shim. No-op in v1. |
63
106
  | `visualDiff` | `boolean` | `false` | Reserved for the post-MVP visual-diff add-on. No-op in v1. |
@@ -66,7 +109,7 @@ The options type is published — `import type { TraceLaneOptions } from '@trace
66
109
 
67
110
  ## Hook-factory alternative (no Service)
68
111
 
69
- For setups that can't register a Service, the **same logic** is available as plain `wdio.conf.ts` hook functions ([ADR-0004](https://github.com/Cubenest/rrweb-stack/blob/main/prds/adrs/0004-p1-wdio-service-not-reporter.md)):
112
+ For setups that can't register a Service, the **same logic** is available as plain `wdio.conf.ts` hook functions:
70
113
 
71
114
  ```ts
72
115
  import { traceLaneHooks } from '@tracelane/wdio/hooks';
@@ -79,7 +122,7 @@ export const config: Options.Testrunner = {
79
122
  before: tracelane.before,
80
123
  beforeSuite: tracelane.beforeSuite,
81
124
  beforeTest: tracelane.beforeTest,
82
- beforeCommand: tracelane.beforeCommand, // re-injection on navigation
125
+ afterCommand: tracelane.afterCommand, // re-injection after navigation
83
126
  afterTest: tracelane.afterTest,
84
127
  afterSuite: tracelane.afterSuite,
85
128
  after: tracelane.after,
@@ -87,26 +130,23 @@ export const config: Options.Testrunner = {
87
130
  };
88
131
  ```
89
132
 
90
- ## FAQ — Why is this a Service and not a Reporter?
133
+ ## Network capture
91
134
 
92
- Because only a **Service** can do what `tracelane` needs ([ADR-0004](https://github.com/Cubenest/rrweb-stack/blob/main/prds/adrs/0004-p1-wdio-service-not-reporter.md)):
135
+ By default network is captured **in-page** by the framework-agnostic `rrweb/network@1` plugin (shipped in `@cubenest/rrweb-core`). It works on **every browser** — Chrome, Edge, Firefox, Safari, and cloud Selenium — with **no CDP and no extra service**, because the plugin wraps `fetch`/`XHR` and reads `PerformanceObserver` entries from inside the page.
93
136
 
94
- | | Service (`Services.ServiceInstance`) | Reporter (`@wdio/reporter`) |
95
- |---|---|---|
96
- | Access to live `browser` in worker hooks | **Yes** | No — reporters run in the launcher process |
97
- | `browser.execute(...)` to inject rrweb / drain the buffer | **Yes** | No |
98
- | `browser.cdp(...)` for network capture | **Yes** | No |
137
+ Privacy-first by default: only **URL, method, status, and timing** are captured. Request/response **headers and bodies are OFF** unless you opt in via `capture.networkOptions` (`recordHeaders` / `recordBody`, plus masking hooks like `maskRequestFn` and `payloadHostDenyList`). A couple of accuracy caveats of the default timing surface:
99
138
 
100
- A Reporter receives only serialized lifecycle events (`testFail`, `testEnd`, …) in the launcher process — it has no page handle, so it can't inject rrweb, drain the in-page buffer, or attach CDP. (`wdio-allure-reporter` hit exactly this wall and had to add a runtime-side `addAttachment` helper to bridge browser access.) A paired Allure **Reporter** shim is planned for v1.1 to push `tracelane` artifacts into Allure's `addAttachment` API that's a Reporter-shaped problem; capture is not.
139
+ - For cross-origin **sub-resources** (images, scripts, fonts loaded from another origin), the Resource Timing spec reports `status: 0` and no methodthese are not surfaced as failures.
140
+ - Accurate per-request **status** for `fetch`/`XHR` requires those wrappers, which are part of the default capture; the plugin only omits header/body payloads unless opted in.
101
141
 
102
- ## Network capture
142
+ ### CDP fallback (optional enhancement)
103
143
 
104
- Failed responses (`status >= 400`) are routed into the report's console timeline (prefixed `[tracelane.net]`, [P1 PRD §E.2](https://github.com/Cubenest/rrweb-stack/blob/main/prds/compass_artifact_wf-d53d32da-17e9-41b5-bb70-21dd1bf648c6_text_markdown.md)). This needs `browser.cdp(...)`, which a separate WDIO service provides:
144
+ When a CDP-capable session is present, `tracelane` *additionally* uses `browser.cdp(...)` to capture **authoritative HTTP status** for failed responses (`status >= 400`) and **true no-response failures** (CORS/DNS/offline/abort) that the page wrappers can't always see. These are routed into the report's console timeline (prefixed `[tracelane.net]`) and the report merges them over the in-page rows for the same request (real status wins). To enable it:
105
145
 
106
146
  - **WDIO 8:** add `['devtools', {}]` via `@wdio/devtools-service@8`.
107
- - **WDIO 9:** `@wdio/devtools-service` has no stable v9 line (it stabilized at v10); use the v10 service or a CDP-capable session. **If `browser.cdp` is unavailable, `tracelane` degrades gracefully to rrweb + console capture** — the report is still produced, just without the network panel.
147
+ - **WDIO 9:** `@wdio/devtools-service` has no stable v9 line (it stabilized at v10); use the v10 service or a CDP-capable session.
108
148
 
109
- Cloud Selenium vendors typically don't expose CDP; rrweb + console capture still work there.
149
+ If CDP is unavailable (cloud Selenium, Firefox, Safari), nothing is lost beyond the CDP-only authoritative-status enhancement the in-page plugin still populates the network panel and the report is still produced.
110
150
 
111
151
  ## Supported runners / browsers
112
152
 
@@ -116,23 +156,30 @@ Cloud Selenium vendors typically don't expose CDP; rrweb + console capture still
116
156
  | Jasmine | Supported (same `afterTest` result shape) |
117
157
  | Cucumber | Supported via `beforeScenario`/`afterScenario` |
118
158
 
119
- | Browser | rrweb + console | Network (CDP) |
120
- |---|---|---|
121
- | Chrome / Chromium ≥ 116 | **Yes** | Yes (with a CDP-capable session) |
122
- | Edge (Chromium) | Yes | Yes |
123
- | Firefox | Yes | No (CDP is Chromium-only) |
124
- | Safari | Yes | No |
159
+ | Browser | rrweb + console | Network (in-page plugin) | Authoritative status / no-response failures (CDP) |
160
+ |---|---|---|---|
161
+ | Chrome / Chromium ≥ 116 | **Yes** | Yes | Yes (with a CDP-capable session) |
162
+ | Edge (Chromium) | Yes | Yes | Yes |
163
+ | Firefox | Yes | Yes (in-page plugin) | No (CDP is Chromium-only) |
164
+ | Safari | Yes | Yes (in-page plugin) | No |
165
+
166
+ ## Playwright + Cypress
167
+
168
+ The tagline says Playwright and Cypress because the design is portable across runners — same `@tracelane/core` engine, different glue. Tracking issues:
169
+
170
+ - **`@tracelane/playwright`** — Playwright Reporter implementing `onTestEnd` + `onAttachment` for shareable HTML. Targeted for week 2-3 of the public launch.
171
+ - **`@tracelane/cypress`** — JSON-output adapter only (no Cypress Test Replay overlap). Targeted for week 11.
125
172
 
126
- ## Versioning
173
+ Watch the [release notes](https://github.com/Cubenest/rrweb-stack/releases) on `Cubenest/rrweb-stack` or follow `@cubenest_in` on X (when announced).
127
174
 
128
- Semantic Versioning. Currently `0.1.0-alpha.0` (pre-release; the API may shift before `1.0.0`).
175
+ ## Versioning & telemetry
129
176
 
130
- ## Telemetry
177
+ Semantic Versioning. Currently `0.1.0-alpha.x` (pre-release; the API may shift before `1.0.0`). See [SUPPORTED.md](https://github.com/Cubenest/rrweb-stack/blob/main/SUPPORTED.md) for the compatibility matrix.
131
178
 
132
- None. `tracelane` collects and sends nothing; reports are written to your local `outDir` only.
179
+ **No telemetry.** `tracelane` collects and sends nothing; reports are written to your local `outDir` only. The generated HTML report includes a footer crediting the tool; you can suppress it with `report: { footer: false }`.
133
180
 
134
181
  ## License
135
182
 
136
183
  Apache 2.0. The bundled rrweb engine + console plugin remain MIT-licensed; see `NOTICE`.
137
184
 
138
- Contributions are accepted under the [Developer Certificate of Origin (DCO)](https://developercertificate.org/) — sign your commits with `git commit -s`.
185
+ Contributions are accepted under the [Developer Certificate of Origin (DCO)](https://developercertificate.org/) — sign your commits with `git commit -s`. See [CONTRIBUTING.md](https://github.com/Cubenest/rrweb-stack/blob/main/CONTRIBUTING.md) + [SECURITY.md](https://github.com/Cubenest/rrweb-stack/blob/main/SECURITY.md).
package/dist/hooks.d.ts CHANGED
@@ -15,7 +15,14 @@ export interface TraceLaneHooks {
15
15
  before(capabilities: unknown, specs: string[], browser: WebdriverIO.Browser): Promise<void>;
16
16
  beforeSuite(suite: Frameworks.Suite): void;
17
17
  beforeTest(test: Frameworks.Test, context?: unknown): Promise<void>;
18
- beforeCommand(commandName: string, args: unknown[]): Promise<void>;
18
+ /**
19
+ * Post-command hook. Re-injects the recorder AFTER a `url(...)` returns
20
+ * (T-9 fix, 2026-05-28 QA walk) — re-injecting before the navigation lands
21
+ * on a doomed page that's about to be torn down, leaving no recorder on
22
+ * the new page. The full Service / hooks pair was previously wired to
23
+ * `beforeCommand`; that was the bug.
24
+ */
25
+ afterCommand(commandName: string, args: unknown[], result: unknown, error?: Error): Promise<void>;
19
26
  afterTest(test: Frameworks.Test, context: unknown, result: Frameworks.TestResult): Promise<void>;
20
27
  afterSuite(suite: Frameworks.Suite): void;
21
28
  after(result: number, capabilities: unknown, specs: string[]): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKrD,6EAA6E;AAC7E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3F,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC;IAC3C,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjG,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1C,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7F,yDAAyD;IACzD,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,uDAAuD;IACvD,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAoCjF"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKrD,6EAA6E;AAC7E,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC5D;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,mEAAmE;AACnE,MAAM,WAAW,cAAc;IAC7B,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3F,MAAM,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5F,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC;IAC3C,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;;;;OAMG;IACH,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClG,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjG,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC;IAC1C,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7F,yDAAyD;IACzD,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,uDAAuD;IACvD,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,GAAE,oBAAyB,GAAG,cAAc,CAuCjF"}
package/dist/hooks.js CHANGED
@@ -31,10 +31,15 @@ export function traceLaneHooks(options = {}) {
31
31
  const { title, spec } = testIdentity(test);
32
32
  await session.onBeforeTest(title, spec);
33
33
  },
34
- async beforeCommand(commandName, args) {
35
- if (commandName === 'url' && typeof args[0] === 'string') {
36
- await session.onUrl(args[0]);
37
- }
34
+ async afterCommand(commandName, args, _result, error) {
35
+ // T-9 fix (2026-05-28): re-inject only after a successful url() returns.
36
+ // `beforeCommand` fires before the navigation, so injecting there
37
+ // lands rrweb on a page that's about to be torn down.
38
+ if (commandName !== 'url' || typeof args[0] !== 'string')
39
+ return;
40
+ if (error !== undefined)
41
+ return;
42
+ await session.onUrl(args[0]);
38
43
  },
39
44
  async afterTest(_test, _context, result) {
40
45
  await session.onAfterTest(result);
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,2BAA2B;AAC3B,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,oBAAoB;AACpB,EAAE;AACF,wFAAwF;AACxF,4FAA4F;AAC5F,EAAE;AACF,kFAAkF;AAClF,iCAAiC;AAIjC,OAAO,EAAiB,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AA8B1D;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAgC,EAAE;IAC/D,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC;IAE5E,OAAO;QACL,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG;YAC/C,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO;YACzC,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAiC,CAAC,CAAC;QAC5D,CAAC;QACD,WAAW,CAAC,MAAM,IAAG,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ;YAC7B,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,IAAgB,CAAC,CAAC;YACvD,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI;YACnC,IAAI,WAAW,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACzD,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM;YACrC,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,UAAU,CAAC,MAAM,IAAG,CAAC;QACrB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM;YACxC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;QACD,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,IAAG,CAAC;QAC1D,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ;YAClC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM;YAC/B,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,2BAA2B;AAC3B,EAAE;AACF,8EAA8E;AAC9E,gFAAgF;AAChF,oBAAoB;AACpB,EAAE;AACF,wFAAwF;AACxF,4FAA4F;AAC5F,EAAE;AACF,kFAAkF;AAClF,iCAAiC;AAIjC,OAAO,EAAiB,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAqC1D;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAgC,EAAE;IAC/D,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC;IAE5E,OAAO;QACL,aAAa,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG;YAC/C,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO;YACzC,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAiC,CAAC,CAAC;QAC5D,CAAC;QACD,WAAW,CAAC,MAAM,IAAG,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,QAAQ;YAC7B,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,IAAgB,CAAC,CAAC;YACvD,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK;YAClD,yEAAyE;YACzE,kEAAkE;YAClE,sDAAsD;YACtD,IAAI,WAAW,KAAK,KAAK,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;gBAAE,OAAO;YACjE,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO;YAChC,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM;YACrC,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACpC,CAAC;QACD,UAAU,CAAC,MAAM,IAAG,CAAC;QACrB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM;YACxC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1B,CAAC;QACD,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,IAAG,CAAC;QAC1D,KAAK,CAAC,cAAc,CAAC,KAAK,EAAE,QAAQ;YAClC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1C,CAAC;QACD,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM;YAC/B,MAAM,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC;AACJ,CAAC"}
package/dist/options.d.ts CHANGED
@@ -1,12 +1,49 @@
1
+ import type { NetworkRecordOptions } from '@cubenest/rrweb-core';
1
2
  import type { ConsolePluginOptions, Mode } from '@tracelane/core';
2
3
  /** Which capture channels are enabled (P1 PRD §M.1). */
3
4
  export interface CaptureOptions {
4
5
  /** Record the rrweb session. Default true. */
5
6
  rrweb?: boolean;
6
- /** Attach CDP and route failed responses into the console timeline. Default true. */
7
+ /**
8
+ * Capture network requests. Default `true`.
9
+ *
10
+ * When enabled (default), the in-page rrweb network plugin
11
+ * (`rrweb/network@1`) is registered alongside the recorder —
12
+ * framework-agnostic, no CDP required, works on all browsers. The
13
+ * legacy CDP-based path is preserved as a fallback but no longer the
14
+ * primary capture mechanism.
15
+ *
16
+ * Privacy defaults (inherited from `@cubenest/rrweb-core`): headers and
17
+ * bodies are NOT captured unless opted in via {@link networkOptions}.
18
+ * Because the fetch/XHR wrappers are gated behind `recordHeaders` /
19
+ * `recordBody` (both off by default), the DEFAULT capture surface is
20
+ * PerformanceObserver timing only. That has two consequences worth
21
+ * knowing:
22
+ * - method and an accurate per-request status may be unavailable
23
+ * (PerformanceObserver entries don't carry the request method, and
24
+ * report `status` only on same-origin / Timing-Allow-Origin
25
+ * responses);
26
+ * - cross-origin sub-resources report `status: 0` per the Resource
27
+ * Timing spec even though they loaded fine — these are NOT treated
28
+ * as failures by the report.
29
+ * Enable the wrappers (and thus accurate per-request method + status,
30
+ * plus optional headers/bodies) via {@link networkOptions}. The CDP
31
+ * fallback, when present, separately supplies authoritative status and
32
+ * true no-response failures.
33
+ */
7
34
  network?: boolean;
8
35
  /** Capture `console.*` via the rrweb console plugin. Default true. */
9
36
  console?: boolean;
37
+ /**
38
+ * Options forwarded to the in-page rrweb network plugin
39
+ * (`getRecordNetworkPlugin`). The full surface from
40
+ * `@cubenest/rrweb-core` is exposed: `recordHeaders`, `recordBody`,
41
+ * `maskRequestFn`, `payloadHostDenyList`, etc. Defaults are the
42
+ * plugin's defaults (privacy-first — headers + bodies off).
43
+ *
44
+ * Ignored when {@link network} is `false`.
45
+ */
46
+ networkOptions?: NetworkRecordOptions;
10
47
  }
11
48
  /** Options for {@link TraceLaneService} and {@link traceLaneHooks} (P1 PRD §M.1). */
12
49
  export interface TraceLaneOptions {
@@ -24,12 +61,25 @@ export interface TraceLaneOptions {
24
61
  capture?: CaptureOptions;
25
62
  /** Reserved for the post-MVP visual-diff add-on (P1 PRD §H). No-op in v1. */
26
63
  visualDiff?: boolean;
27
- /** Node-side drain poll interval in ms (ADR-0006). Default 5000. */
64
+ /** Node-side drain poll interval in ms (ADR-0006). Default 500 (from @tracelane/core when unset). */
28
65
  drainIntervalMs?: number;
29
66
  /** Re-injection cooldown guard in ms (ADR-0006). Default 250. */
30
67
  cooldownMs?: number;
31
68
  /** Options forwarded to the in-page rrweb console plugin. */
32
69
  consolePluginOptions?: ConsolePluginOptions;
70
+ /** Advisory security-hygiene signals in the report (default true). Set false to disable capture + analysis. */
71
+ security?: boolean;
72
+ /**
73
+ * Report-output tweaks.
74
+ *
75
+ * - `footer` — render the self-contained report's "Generated by tracelane"
76
+ * footer. Default `true`. Set `false` to suppress it (e.g. when embedding
77
+ * reports in an internal tool where the attribution isn't wanted).
78
+ */
79
+ report?: {
80
+ /** Render the report footer. Default `true`. */
81
+ footer?: boolean;
82
+ };
33
83
  }
34
84
  /** The default output directory for reports. */
35
85
  export declare const DEFAULT_OUT_DIR = "./tracelane-reports";
@@ -1 +1 @@
1
- {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElE,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED,gDAAgD;AAChD,eAAO,MAAM,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAElE,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;OAQG;IACH,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED,qFAAqF;AACrF,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mCAAmC;IACnC,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qGAAqG;IACrG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,+GAA+G;IAC/G,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE;QACP,gDAAgD;QAChD,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,gDAAgD;AAChD,eAAO,MAAM,eAAe,wBAAwB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAsCzE,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,qBAAqB,CAAC"}
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAwFzE,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,qBAAqB,CAAC"}