pw-sanitizer 0.1.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.
Files changed (86) hide show
  1. package/README.md +415 -0
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +113 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/config/loader.d.ts +30 -0
  7. package/dist/config/loader.d.ts.map +1 -0
  8. package/dist/config/loader.js +173 -0
  9. package/dist/config/loader.js.map +1 -0
  10. package/dist/config/types.d.ts +432 -0
  11. package/dist/config/types.d.ts.map +1 -0
  12. package/dist/config/types.js +6 -0
  13. package/dist/config/types.js.map +1 -0
  14. package/dist/config/validator.d.ts +34 -0
  15. package/dist/config/validator.d.ts.map +1 -0
  16. package/dist/config/validator.js +95 -0
  17. package/dist/config/validator.js.map +1 -0
  18. package/dist/index.d.ts +74 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +190 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/logger.d.ts +82 -0
  23. package/dist/logger.d.ts.map +1 -0
  24. package/dist/logger.js +122 -0
  25. package/dist/logger.js.map +1 -0
  26. package/dist/processors/html-report.d.ts +27 -0
  27. package/dist/processors/html-report.d.ts.map +1 -0
  28. package/dist/processors/html-report.js +220 -0
  29. package/dist/processors/html-report.js.map +1 -0
  30. package/dist/processors/screenshot.d.ts +37 -0
  31. package/dist/processors/screenshot.d.ts.map +1 -0
  32. package/dist/processors/screenshot.js +52 -0
  33. package/dist/processors/screenshot.js.map +1 -0
  34. package/dist/processors/trace-file.d.ts +29 -0
  35. package/dist/processors/trace-file.d.ts.map +1 -0
  36. package/dist/processors/trace-file.js +250 -0
  37. package/dist/processors/trace-file.js.map +1 -0
  38. package/dist/redact/json-walker.d.ts +28 -0
  39. package/dist/redact/json-walker.d.ts.map +1 -0
  40. package/dist/redact/json-walker.js +164 -0
  41. package/dist/redact/json-walker.js.map +1 -0
  42. package/dist/redact/matcher.d.ts +25 -0
  43. package/dist/redact/matcher.d.ts.map +1 -0
  44. package/dist/redact/matcher.js +130 -0
  45. package/dist/redact/matcher.js.map +1 -0
  46. package/dist/redact/pattern-loader.d.ts +25 -0
  47. package/dist/redact/pattern-loader.d.ts.map +1 -0
  48. package/dist/redact/pattern-loader.js +111 -0
  49. package/dist/redact/pattern-loader.js.map +1 -0
  50. package/dist/redact/pattern-registry.d.ts +17 -0
  51. package/dist/redact/pattern-registry.d.ts.map +1 -0
  52. package/dist/redact/pattern-registry.js +58 -0
  53. package/dist/redact/pattern-registry.js.map +1 -0
  54. package/dist/remove/detector.d.ts +22 -0
  55. package/dist/remove/detector.d.ts.map +1 -0
  56. package/dist/remove/detector.js +152 -0
  57. package/dist/remove/detector.js.map +1 -0
  58. package/dist/remove/remover.d.ts +18 -0
  59. package/dist/remove/remover.d.ts.map +1 -0
  60. package/dist/remove/remover.js +72 -0
  61. package/dist/remove/remover.js.map +1 -0
  62. package/dist/remove/rule-loader.d.ts +25 -0
  63. package/dist/remove/rule-loader.d.ts.map +1 -0
  64. package/dist/remove/rule-loader.js +110 -0
  65. package/dist/remove/rule-loader.js.map +1 -0
  66. package/dist/remove/rule-registry.d.ts +17 -0
  67. package/dist/remove/rule-registry.d.ts.map +1 -0
  68. package/dist/remove/rule-registry.js +58 -0
  69. package/dist/remove/rule-registry.js.map +1 -0
  70. package/dist/remove/timestamp-repair.d.ts +28 -0
  71. package/dist/remove/timestamp-repair.d.ts.map +1 -0
  72. package/dist/remove/timestamp-repair.js +157 -0
  73. package/dist/remove/timestamp-repair.js.map +1 -0
  74. package/dist/reporter.d.ts +44 -0
  75. package/dist/reporter.d.ts.map +1 -0
  76. package/dist/reporter.js +180 -0
  77. package/dist/reporter.js.map +1 -0
  78. package/dist/teardown.d.ts +27 -0
  79. package/dist/teardown.d.ts.map +1 -0
  80. package/dist/teardown.js +42 -0
  81. package/dist/teardown.js.map +1 -0
  82. package/dist/utils.d.ts +36 -0
  83. package/dist/utils.d.ts.map +1 -0
  84. package/dist/utils.js +112 -0
  85. package/dist/utils.js.map +1 -0
  86. package/package.json +71 -0
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.processHtmlReport = processHtmlReport;
37
+ const fs = __importStar(require("node:fs"));
38
+ const json_walker_js_1 = require("../redact/json-walker.js");
39
+ const detector_js_1 = require("../remove/detector.js");
40
+ const remover_js_1 = require("../remove/remover.js");
41
+ const timestamp_repair_js_1 = require("../remove/timestamp-repair.js");
42
+ const logger_js_1 = require("../logger.js");
43
+ const utils_js_1 = require("../utils.js");
44
+ /**
45
+ * Regex that locates the embedded JSON blob inside a Playwright HTML report.
46
+ *
47
+ * Playwright injects report data as:
48
+ * `window.__pw_report_data__ = { ... };</script>`
49
+ *
50
+ * The first capture group (`[1]`) contains the raw JSON object literal.
51
+ * The `s` flag allows `.` to match newlines (the blob can be multi-line).
52
+ */
53
+ const REPORT_DATA_REGEX = /window\.__pw_report_data__\s*=\s*(\{.+?\});\s*<\/script>/s;
54
+ /**
55
+ * Sanitizes a single Playwright HTML report file.
56
+ *
57
+ * Processing pipeline:
58
+ * 1. Read the HTML file from disk.
59
+ * 2. Extract the embedded `window.__pw_report_data__` JSON blob via regex.
60
+ * 3. **Redact phase** (if `config.redact` is set and patterns are loaded):
61
+ * walk the JSON tree with {@link walkAndRedact} and replace matched values.
62
+ * 4. **Remove phase** (if `config.remove` is set and rules are loaded):
63
+ * extract step events, run {@link findStepsToRemove}, then
64
+ * {@link removeSteps} and {@link repairTimestamps}.
65
+ * 5. Re-serialise the JSON and splice it back into the original HTML.
66
+ * 6. Write the output according to `config.output.mode`.
67
+ *
68
+ * On any unrecoverable parse error, the function logs a warning and returns
69
+ * an empty {@link ProcessResult} rather than throwing.
70
+ *
71
+ * @param inputPath - Absolute path to the source HTML report file.
72
+ * @param outputPath - Destination path for the sanitized output.
73
+ * @param config - The full sanitizer configuration.
74
+ * @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
75
+ * @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
76
+ * @returns A {@link ProcessResult} with counts and match details for this file.
77
+ */
78
+ async function processHtmlReport(inputPath, outputPath, config, patterns, rules) {
79
+ const result = {
80
+ file: inputPath,
81
+ redactionsApplied: 0,
82
+ stepsRemoved: 0,
83
+ timestampRepairs: 0,
84
+ redactionMatches: [],
85
+ removalMatches: [],
86
+ };
87
+ const html = fs.readFileSync(inputPath, 'utf-8');
88
+ const match = REPORT_DATA_REGEX.exec(html);
89
+ if (!match?.[1]) {
90
+ logger_js_1.logger.warn(`Could not find embedded report data in ${inputPath}. ` +
91
+ `Expected pattern: window.__pw_report_data__ = {...};`);
92
+ return result;
93
+ }
94
+ let reportData;
95
+ try {
96
+ reportData = JSON.parse(match[1]);
97
+ }
98
+ catch (err) {
99
+ logger_js_1.logger.warn(`Failed to parse embedded JSON in ${inputPath}: ` +
100
+ `${err instanceof Error ? err.message : String(err)}`);
101
+ return result;
102
+ }
103
+ let modified = false;
104
+ // Redact phase
105
+ if (config.redact && patterns.length > 0) {
106
+ const walkResult = (0, json_walker_js_1.walkAndRedact)(reportData, patterns, config.redact);
107
+ if (walkResult.count > 0) {
108
+ reportData = walkResult.result;
109
+ result.redactionsApplied = walkResult.count;
110
+ result.redactionMatches = walkResult.matches;
111
+ modified = true;
112
+ }
113
+ }
114
+ // Remove phase
115
+ if (config.remove && rules.length > 0) {
116
+ // The report data typically has a structure with tests/suites containing steps
117
+ const events = extractEventsFromReport(reportData);
118
+ if (events.length > 0) {
119
+ const removalSet = (0, detector_js_1.findStepsToRemove)(events, rules);
120
+ if (removalSet.indices.size > 0) {
121
+ if (config.remove.dryRun) {
122
+ logger_js_1.logger.info(`[DRY RUN] Would remove ${removalSet.indices.size} steps from ${inputPath}`);
123
+ for (const m of removalSet.matches) {
124
+ logger_js_1.logger.info(` - Rule "${m.ruleLabel}": step at index ${m.index} ` +
125
+ `("${m.event.title ?? m.event.action ?? 'unknown'}")`);
126
+ }
127
+ result.removalMatches = removalSet.matches;
128
+ result.stepsRemoved = removalSet.indices.size;
129
+ }
130
+ else {
131
+ const removedEvents = Array.from(removalSet.indices).map((i) => events[i]);
132
+ const cleaned = (0, remover_js_1.removeSteps)(events, removalSet);
133
+ const strategy = config.remove.timestampStrategy ?? 'absorb-into-prev';
134
+ const repaired = (0, timestamp_repair_js_1.repairTimestamps)(cleaned, removedEvents, strategy);
135
+ replaceEventsInReport(reportData, repaired);
136
+ result.stepsRemoved = removalSet.indices.size;
137
+ result.timestampRepairs = removalSet.indices.size;
138
+ result.removalMatches = removalSet.matches;
139
+ modified = true;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ if (!modified && !config.remove?.dryRun) {
145
+ logger_js_1.logger.info(`No changes made to ${inputPath}`);
146
+ }
147
+ // Write output (unless dry-run)
148
+ if (!config.remove?.dryRun) {
149
+ const newJson = JSON.stringify(reportData);
150
+ const newHtml = html.replace(REPORT_DATA_REGEX, `window.__pw_report_data__ = ${newJson};</script>`);
151
+ (0, utils_js_1.writeOutput)(inputPath, outputPath, newHtml, config);
152
+ }
153
+ return result;
154
+ }
155
+ /**
156
+ * Flattens the nested Playwright HTML report structure into a single array of
157
+ * step/action events that can be processed by the removal pipeline.
158
+ *
159
+ * Playwright HTML reports nest steps under `suites → tests → results → steps`.
160
+ * This function performs a depth-first traversal, collecting any node that
161
+ * looks like a step (has `startTime`/`endTime`, `title`, or `action` fields)
162
+ * and recursing into known container keys (`steps`, `actions`, `suites`,
163
+ * `tests`, `results`, `attachments`).
164
+ *
165
+ * @param data - The parsed `window.__pw_report_data__` object.
166
+ * @returns A flat array of event-like objects cast to {@link TraceEvent}.
167
+ */
168
+ function extractEventsFromReport(data) {
169
+ const events = [];
170
+ function traverse(node) {
171
+ if (!node || typeof node !== 'object')
172
+ return;
173
+ if (Array.isArray(node)) {
174
+ for (const item of node) {
175
+ traverse(item);
176
+ }
177
+ return;
178
+ }
179
+ const obj = node;
180
+ // Check if this looks like a step/action event
181
+ if (('startTime' in obj && 'endTime' in obj) ||
182
+ 'title' in obj ||
183
+ 'action' in obj) {
184
+ events.push(obj);
185
+ }
186
+ // Recurse into common containers
187
+ for (const key of ['steps', 'actions', 'suites', 'tests', 'results', 'attachments']) {
188
+ if (key in obj && Array.isArray(obj[key])) {
189
+ traverse(obj[key]);
190
+ }
191
+ }
192
+ }
193
+ traverse(data);
194
+ return events;
195
+ }
196
+ /**
197
+ * Placeholder for post-removal tree reconstruction in HTML reports.
198
+ *
199
+ * In the current implementation, step mutations during the redact walk phase
200
+ * are applied directly to object references within the report tree, which is
201
+ * sufficient for the redaction use-case.
202
+ *
203
+ * Full step-removal support for HTML reports would require rebuilding the
204
+ * nested `steps` arrays in each test result to exclude the removed events —
205
+ * this is tracked as a future enhancement.
206
+ *
207
+ * @param _data - The parsed report data (unused — present for future implementation).
208
+ * @param _repairedEvents - The repaired event array (unused — present for future implementation).
209
+ */
210
+ function replaceEventsInReport(_data, _repairedEvents) {
211
+ // The events extracted from the report are object references.
212
+ // removeSteps returns a new array but the original tree still contains
213
+ // the old references. For a full implementation, we'd need to rebuild
214
+ // the tree structure. For now, the walked-and-redacted data is sufficient
215
+ // since we modify the objects in place during the walk phase.
216
+ //
217
+ // A more complete implementation would rebuild the steps arrays in the
218
+ // report tree to match the filtered events.
219
+ }
220
+ //# sourceMappingURL=html-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-report.js","sourceRoot":"","sources":["../../src/processors/html-report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Optional screenshot redaction module.
3
+ *
4
+ * When `output.redactScreenshots` is `true`, this module is used to blur
5
+ * pixel regions of screenshots captured during a Playwright test run. Regions
6
+ * are identified by mapping CSS selectors from redact patterns to pixel
7
+ * coordinates recorded in the trace.
8
+ *
9
+ * **Current status**: placeholder implementation. The function signature and
10
+ * `sharp` integration skeleton are in place, but the coordinate-mapping logic
11
+ * and blur overlay are not yet implemented. Requires the optional `sharp`
12
+ * peer dependency (`npm install sharp`).
13
+ */
14
+ /**
15
+ * Applies pixel-level redaction to a screenshot buffer by blurring the
16
+ * specified rectangular regions.
17
+ *
18
+ * @remarks
19
+ * This is a **placeholder** — the function currently returns the original
20
+ * buffer unchanged. A full implementation would use `sharp` to composite
21
+ * blurred rectangles over the matching coordinates.
22
+ *
23
+ * If `sharp` is not installed, a warning is logged and the original buffer
24
+ * is returned (no-op behaviour).
25
+ *
26
+ * @param _screenshotBuffer - The raw PNG/JPEG screenshot buffer from the trace archive.
27
+ * @param _regions - Pixel-coordinate rectangles to blur (x, y, width, height — all in px).
28
+ * @returns The (potentially blurred) screenshot buffer.
29
+ * Currently always returns `_screenshotBuffer` unchanged.
30
+ */
31
+ export declare function redactScreenshot(_screenshotBuffer: Buffer, _regions: Array<{
32
+ x: number;
33
+ y: number;
34
+ width: number;
35
+ height: number;
36
+ }>): Promise<Buffer>;
37
+ //# sourceMappingURL=screenshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.d.ts","sourceRoot":"","sources":["../../src/processors/screenshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CACpC,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,KAAK,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GACvE,OAAO,CAAC,MAAM,CAAC,CAkBjB"}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * Optional screenshot redaction module.
4
+ *
5
+ * When `output.redactScreenshots` is `true`, this module is used to blur
6
+ * pixel regions of screenshots captured during a Playwright test run. Regions
7
+ * are identified by mapping CSS selectors from redact patterns to pixel
8
+ * coordinates recorded in the trace.
9
+ *
10
+ * **Current status**: placeholder implementation. The function signature and
11
+ * `sharp` integration skeleton are in place, but the coordinate-mapping logic
12
+ * and blur overlay are not yet implemented. Requires the optional `sharp`
13
+ * peer dependency (`npm install sharp`).
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.redactScreenshot = redactScreenshot;
17
+ const logger_js_1 = require("../logger.js");
18
+ /**
19
+ * Applies pixel-level redaction to a screenshot buffer by blurring the
20
+ * specified rectangular regions.
21
+ *
22
+ * @remarks
23
+ * This is a **placeholder** — the function currently returns the original
24
+ * buffer unchanged. A full implementation would use `sharp` to composite
25
+ * blurred rectangles over the matching coordinates.
26
+ *
27
+ * If `sharp` is not installed, a warning is logged and the original buffer
28
+ * is returned (no-op behaviour).
29
+ *
30
+ * @param _screenshotBuffer - The raw PNG/JPEG screenshot buffer from the trace archive.
31
+ * @param _regions - Pixel-coordinate rectangles to blur (x, y, width, height — all in px).
32
+ * @returns The (potentially blurred) screenshot buffer.
33
+ * Currently always returns `_screenshotBuffer` unchanged.
34
+ */
35
+ async function redactScreenshot(_screenshotBuffer, _regions) {
36
+ try {
37
+ // Dynamic import to respect optional peer dependency
38
+ // Use a variable to prevent TypeScript from resolving the module at compile time
39
+ const sharpModule = 'sharp';
40
+ await import(sharpModule);
41
+ logger_js_1.logger.verbose('Screenshot redaction: sharp module loaded');
42
+ // Placeholder: actual implementation would overlay blur regions
43
+ // onto the screenshot at the specified pixel coordinates.
44
+ return _screenshotBuffer;
45
+ }
46
+ catch {
47
+ logger_js_1.logger.warn('Screenshot redaction requires the "sharp" package. ' +
48
+ 'Install it with: npm install sharp');
49
+ return _screenshotBuffer;
50
+ }
51
+ }
52
+ //# sourceMappingURL=screenshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.js","sourceRoot":"","sources":["../../src/processors/screenshot.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAqBH,4CAqBC;AAxCD,4CAAsC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,gBAAgB,CACpC,iBAAyB,EACzB,QAAwE;IAExE,IAAI,CAAC;QACH,qDAAqD;QACrD,iFAAiF;QACjF,MAAM,WAAW,GAAG,OAAO,CAAC;QAC5B,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC1B,kBAAM,CAAC,OAAO,CAAC,2CAA2C,CAAC,CAAC;QAE5D,gEAAgE;QAChE,0DAA0D;QAC1D,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,kBAAM,CAAC,IAAI,CACT,qDAAqD;YACrD,oCAAoC,CACrC,CAAC;QACF,OAAO,iBAAiB,CAAC;IAC3B,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { SanitizerConfig, RedactPattern, RemoveRule, ProcessResult } from '../config/types.js';
2
+ /**
3
+ * Sanitizes a single Playwright trace `.zip` file.
4
+ *
5
+ * Processing pipeline:
6
+ * 1. Read and parse the `.zip` archive with JSZip.
7
+ * 2. Extract `trace.json` (primary event stream) and `network.json` (request log).
8
+ * 3. **Redact phase** (if `config.redact` and patterns are loaded):
9
+ * - Walk and redact `trace.json` events.
10
+ * - Walk and redact `network.json` entries.
11
+ * - Walk and redact `.json` / `.txt` files inside the `resources/` folder.
12
+ * 4. **Remove phase** (if `config.remove` and rules are loaded):
13
+ * - Run {@link findStepsToRemove} on the trace events.
14
+ * - Run {@link removeSteps} and {@link repairTimestamps}.
15
+ * - Remove corresponding `network.json` entries by `requestId`.
16
+ * 5. Write modified `trace.json` and `network.json` back into the archive.
17
+ * 6. Re-generate the `.zip` buffer and write it according to `config.output.mode`.
18
+ *
19
+ * Unreadable files and non-JSON resources are skipped gracefully with warnings.
20
+ *
21
+ * @param inputPath - Absolute path to the source trace `.zip` file.
22
+ * @param outputPath - Destination path for the sanitized output archive.
23
+ * @param config - The full sanitizer configuration.
24
+ * @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
25
+ * @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
26
+ * @returns A {@link ProcessResult} with counts and match details for this file.
27
+ */
28
+ export declare function processTraceFile(inputPath: string, outputPath: string, config: SanitizerConfig, patterns: RedactPattern[], rules: RemoveRule[]): Promise<ProcessResult>;
29
+ //# sourceMappingURL=trace-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-file.d.ts","sourceRoot":"","sources":["../../src/processors/trace-file.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EACf,aAAa,EACb,UAAU,EACV,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAQ5B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,QAAQ,EAAE,aAAa,EAAE,EACzB,KAAK,EAAE,UAAU,EAAE,GAClB,OAAO,CAAC,aAAa,CAAC,CA8MxB"}
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.processTraceFile = processTraceFile;
40
+ const fs = __importStar(require("node:fs"));
41
+ const jszip_1 = __importDefault(require("jszip"));
42
+ const json_walker_js_1 = require("../redact/json-walker.js");
43
+ const detector_js_1 = require("../remove/detector.js");
44
+ const remover_js_1 = require("../remove/remover.js");
45
+ const timestamp_repair_js_1 = require("../remove/timestamp-repair.js");
46
+ const logger_js_1 = require("../logger.js");
47
+ const utils_js_1 = require("../utils.js");
48
+ /**
49
+ * Sanitizes a single Playwright trace `.zip` file.
50
+ *
51
+ * Processing pipeline:
52
+ * 1. Read and parse the `.zip` archive with JSZip.
53
+ * 2. Extract `trace.json` (primary event stream) and `network.json` (request log).
54
+ * 3. **Redact phase** (if `config.redact` and patterns are loaded):
55
+ * - Walk and redact `trace.json` events.
56
+ * - Walk and redact `network.json` entries.
57
+ * - Walk and redact `.json` / `.txt` files inside the `resources/` folder.
58
+ * 4. **Remove phase** (if `config.remove` and rules are loaded):
59
+ * - Run {@link findStepsToRemove} on the trace events.
60
+ * - Run {@link removeSteps} and {@link repairTimestamps}.
61
+ * - Remove corresponding `network.json` entries by `requestId`.
62
+ * 5. Write modified `trace.json` and `network.json` back into the archive.
63
+ * 6. Re-generate the `.zip` buffer and write it according to `config.output.mode`.
64
+ *
65
+ * Unreadable files and non-JSON resources are skipped gracefully with warnings.
66
+ *
67
+ * @param inputPath - Absolute path to the source trace `.zip` file.
68
+ * @param outputPath - Destination path for the sanitized output archive.
69
+ * @param config - The full sanitizer configuration.
70
+ * @param patterns - Pre-built list of redact patterns (from {@link buildPatternRegistry}).
71
+ * @param rules - Pre-built list of removal rules (from {@link buildRuleRegistry}).
72
+ * @returns A {@link ProcessResult} with counts and match details for this file.
73
+ */
74
+ async function processTraceFile(inputPath, outputPath, config, patterns, rules) {
75
+ const result = {
76
+ file: inputPath,
77
+ redactionsApplied: 0,
78
+ stepsRemoved: 0,
79
+ timestampRepairs: 0,
80
+ redactionMatches: [],
81
+ removalMatches: [],
82
+ };
83
+ let zipData;
84
+ try {
85
+ zipData = fs.readFileSync(inputPath);
86
+ }
87
+ catch (err) {
88
+ logger_js_1.logger.warn(`Could not read trace file ${inputPath}: ` +
89
+ `${err instanceof Error ? err.message : String(err)}`);
90
+ return result;
91
+ }
92
+ let zip;
93
+ try {
94
+ zip = await jszip_1.default.loadAsync(zipData);
95
+ }
96
+ catch (err) {
97
+ logger_js_1.logger.warn(`Could not parse trace zip ${inputPath}: ` +
98
+ `${err instanceof Error ? err.message : String(err)}`);
99
+ return result;
100
+ }
101
+ let modified = false;
102
+ // Load trace.json
103
+ let traceEvents = null;
104
+ const traceFile = zip.file('trace.json');
105
+ if (traceFile) {
106
+ try {
107
+ const traceContent = await traceFile.async('string');
108
+ traceEvents = JSON.parse(traceContent);
109
+ }
110
+ catch (err) {
111
+ logger_js_1.logger.warn(`Failed to parse trace.json in ${inputPath}: ` +
112
+ `${err instanceof Error ? err.message : String(err)}`);
113
+ }
114
+ }
115
+ // Load network.json
116
+ let networkData = null;
117
+ const networkFile = zip.file('network.json');
118
+ if (networkFile) {
119
+ try {
120
+ const networkContent = await networkFile.async('string');
121
+ networkData = JSON.parse(networkContent);
122
+ }
123
+ catch {
124
+ // network.json might not exist in all traces
125
+ }
126
+ }
127
+ // ── Redact phase ──
128
+ if (config.redact && patterns.length > 0) {
129
+ // Redact trace.json
130
+ if (traceEvents) {
131
+ const traceWalk = (0, json_walker_js_1.walkAndRedact)(traceEvents, patterns, config.redact);
132
+ if (traceWalk.count > 0) {
133
+ traceEvents = traceWalk.result;
134
+ result.redactionsApplied += traceWalk.count;
135
+ result.redactionMatches.push(...traceWalk.matches);
136
+ modified = true;
137
+ }
138
+ }
139
+ // Redact network.json
140
+ if (networkData) {
141
+ const networkWalk = (0, json_walker_js_1.walkAndRedact)(networkData, patterns, config.redact);
142
+ if (networkWalk.count > 0) {
143
+ networkData = networkWalk.result;
144
+ result.redactionsApplied += networkWalk.count;
145
+ result.redactionMatches.push(...networkWalk.matches);
146
+ modified = true;
147
+ }
148
+ }
149
+ // Redact JSON files in resources/
150
+ const resourceFiles = zip.folder('resources');
151
+ if (resourceFiles) {
152
+ const jsonResources = [];
153
+ resourceFiles.forEach((relativePath, file) => {
154
+ if (!file.dir &&
155
+ (relativePath.endsWith('.json') || relativePath.endsWith('.txt'))) {
156
+ jsonResources.push(`resources/${relativePath}`);
157
+ }
158
+ });
159
+ for (const resPath of jsonResources) {
160
+ const resFile = zip.file(resPath);
161
+ if (resFile) {
162
+ try {
163
+ const content = await resFile.async('string');
164
+ const parsed = JSON.parse(content);
165
+ const resWalk = (0, json_walker_js_1.walkAndRedact)(parsed, patterns, config.redact);
166
+ if (resWalk.count > 0) {
167
+ zip.file(resPath, JSON.stringify(parsed));
168
+ result.redactionsApplied += resWalk.count;
169
+ result.redactionMatches.push(...resWalk.matches);
170
+ modified = true;
171
+ // Update with redacted content
172
+ zip.file(resPath, JSON.stringify(resWalk.result));
173
+ }
174
+ }
175
+ catch {
176
+ // Not valid JSON — skip
177
+ }
178
+ }
179
+ }
180
+ }
181
+ }
182
+ // ── Remove phase ──
183
+ if (config.remove && rules.length > 0 && traceEvents) {
184
+ const removalSet = (0, detector_js_1.findStepsToRemove)(traceEvents, rules);
185
+ if (removalSet.indices.size > 0) {
186
+ if (config.remove.dryRun) {
187
+ logger_js_1.logger.info(`[DRY RUN] Would remove ${removalSet.indices.size} steps from ${inputPath}`);
188
+ for (const m of removalSet.matches) {
189
+ logger_js_1.logger.info(` - Rule "${m.ruleLabel}": step at index ${m.index} ` +
190
+ `("${m.event.title ?? m.event.action ?? 'unknown'}")`);
191
+ }
192
+ result.removalMatches = removalSet.matches;
193
+ result.stepsRemoved = removalSet.indices.size;
194
+ }
195
+ else {
196
+ // Collect removed events before removal
197
+ const removedEvents = Array.from(removalSet.indices).map((i) => traceEvents[i]);
198
+ // Collect requestIds of removed events for network cleanup
199
+ const removedRequestIds = new Set();
200
+ for (const event of removedEvents) {
201
+ if (event.requestId) {
202
+ removedRequestIds.add(event.requestId);
203
+ }
204
+ }
205
+ // Remove steps
206
+ const cleaned = (0, remover_js_1.removeSteps)(traceEvents, removalSet);
207
+ // Repair timestamps
208
+ const strategy = config.remove.timestampStrategy ?? 'absorb-into-prev';
209
+ traceEvents = (0, timestamp_repair_js_1.repairTimestamps)(cleaned, removedEvents, strategy);
210
+ // Remove corresponding network.json entries
211
+ if (networkData && removedRequestIds.size > 0) {
212
+ networkData = networkData.filter((entry) => {
213
+ if (entry &&
214
+ typeof entry === 'object' &&
215
+ 'requestId' in entry) {
216
+ const reqId = entry.requestId;
217
+ return !removedRequestIds.has(reqId);
218
+ }
219
+ return true;
220
+ });
221
+ }
222
+ result.stepsRemoved = removalSet.indices.size;
223
+ result.timestampRepairs = removalSet.indices.size;
224
+ result.removalMatches = removalSet.matches;
225
+ modified = true;
226
+ }
227
+ }
228
+ }
229
+ if (!modified && !config.remove?.dryRun) {
230
+ logger_js_1.logger.info(`No changes made to ${inputPath}`);
231
+ }
232
+ // Write output (unless dry-run)
233
+ if (!config.remove?.dryRun) {
234
+ // Update files in the zip
235
+ if (traceEvents) {
236
+ zip.file('trace.json', JSON.stringify(traceEvents));
237
+ }
238
+ if (networkData) {
239
+ zip.file('network.json', JSON.stringify(networkData));
240
+ }
241
+ // Generate zip buffer
242
+ const outputBuffer = await zip.generateAsync({
243
+ type: 'nodebuffer',
244
+ compression: 'DEFLATE',
245
+ });
246
+ (0, utils_js_1.writeOutput)(inputPath, outputPath, outputBuffer, config);
247
+ }
248
+ return result;
249
+ }
250
+ //# sourceMappingURL=trace-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-file.js","sourceRoot":"","sources":["../../src/processors/trace-file.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,4CAoNC;AA/PD,4CAA8B;AAE9B,kDAA0B;AAQ1B,6DAAyD;AACzD,uDAA0D;AAC1D,qDAAmD;AACnD,uEAAiE;AACjE,4CAAsC;AACtC,0CAA0C;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACI,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,UAAkB,EAClB,MAAuB,EACvB,QAAyB,EACzB,KAAmB;IAEnB,MAAM,MAAM,GAAkB;QAC5B,IAAI,EAAE,SAAS;QACf,iBAAiB,EAAE,CAAC;QACpB,YAAY,EAAE,CAAC;QACf,gBAAgB,EAAE,CAAC;QACnB,gBAAgB,EAAE,EAAE;QACpB,cAAc,EAAE,EAAE;KACnB,CAAC;IAEF,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kBAAM,CAAC,IAAI,CACT,6BAA6B,SAAS,IAAI;YAC1C,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtD,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,GAAU,CAAC;IACf,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,eAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,kBAAM,CAAC,IAAI,CACT,6BAA6B,SAAS,IAAI;YAC1C,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtD,CAAC;QACF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,kBAAkB;IAClB,IAAI,WAAW,GAAwB,IAAI,CAAC;IAC5C,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzC,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC;YACH,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACrD,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAiB,CAAC;QACzD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,kBAAM,CAAC,IAAI,CACT,iCAAiC,SAAS,IAAI;gBAC9C,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACtD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,IAAI,WAAW,GAAqB,IAAI,CAAC;IACzC,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7C,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,cAAc,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACzD,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAc,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,6CAA6C;QAC/C,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,oBAAoB;QACpB,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,SAAS,GAAG,IAAA,8BAAa,EAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YACtE,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBACxB,WAAW,GAAG,SAAS,CAAC,MAAsB,CAAC;gBAC/C,MAAM,CAAC,iBAAiB,IAAI,SAAS,CAAC,KAAK,CAAC;gBAC5C,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;gBACnD,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,WAAW,GAAG,IAAA,8BAAa,EAAC,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YACxE,IAAI,WAAW,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBAC1B,WAAW,GAAG,WAAW,CAAC,MAAmB,CAAC;gBAC9C,MAAM,CAAC,iBAAiB,IAAI,WAAW,CAAC,KAAK,CAAC;gBAC9C,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;gBACrD,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,aAAa,GAAa,EAAE,CAAC;YACnC,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE;gBAC3C,IACE,CAAC,IAAI,CAAC,GAAG;oBACT,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,EACjE,CAAC;oBACD,aAAa,CAAC,IAAI,CAAC,aAAa,YAAY,EAAE,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,KAAK,MAAM,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,OAAO,EAAE,CAAC;oBACZ,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;wBAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACnC,MAAM,OAAO,GAAG,IAAA,8BAAa,EAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;wBAC/D,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;4BACtB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;4BAC1C,MAAM,CAAC,iBAAiB,IAAI,OAAO,CAAC,KAAK,CAAC;4BAC1C,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;4BACjD,QAAQ,GAAG,IAAI,CAAC;4BAChB,+BAA+B;4BAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;wBACpD,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,wBAAwB;oBAC1B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;QACrD,MAAM,UAAU,GAAG,IAAA,+BAAiB,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAEzD,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAChC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;gBACzB,kBAAM,CAAC,IAAI,CACT,0BAA0B,UAAU,CAAC,OAAO,CAAC,IAAI,eAAe,SAAS,EAAE,CAC5E,CAAC;gBACF,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;oBACnC,kBAAM,CAAC,IAAI,CACT,aAAa,CAAC,CAAC,SAAS,oBAAoB,CAAC,CAAC,KAAK,GAAG;wBACtD,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,IAAI,CACtD,CAAC;gBACJ,CAAC;gBACD,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC;gBAC3C,MAAM,CAAC,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACN,wCAAwC;gBACxC,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,GAAG,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,WAAY,CAAC,CAAC,CAAE,CACxB,CAAC;gBAEF,2DAA2D;gBAC3D,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;gBAC5C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;oBAClC,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;wBACpB,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC;gBAED,eAAe;gBACf,MAAM,OAAO,GAAG,IAAA,wBAAW,EAAC,WAAW,EAAE,UAAU,CAAC,CAAC;gBAErD,oBAAoB;gBACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,iBAAiB,IAAI,kBAAkB,CAAC;gBACvE,WAAW,GAAG,IAAA,sCAAgB,EAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC;gBAEjE,4CAA4C;gBAC5C,IAAI,WAAW,IAAI,iBAAiB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBAC9C,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;wBACzC,IACE,KAAK;4BACL,OAAO,KAAK,KAAK,QAAQ;4BACzB,WAAW,IAAI,KAAK,EACpB,CAAC;4BACD,MAAM,KAAK,GAAI,KAA+B,CAAC,SAAS,CAAC;4BACzD,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;wBACvC,CAAC;wBACD,OAAO,IAAI,CAAC;oBACd,CAAC,CAAC,CAAC;gBACL,CAAC;gBAED,MAAM,CAAC,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC9C,MAAM,CAAC,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;gBAClD,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC;gBAC3C,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACxC,kBAAM,CAAC,IAAI,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,gCAAgC;IAChC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC3B,0BAA0B;QAC1B,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,WAAW,EAAE,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;QACxD,CAAC;QAED,sBAAsB;QACtB,MAAM,YAAY,GAAG,MAAM,GAAG,CAAC,aAAa,CAAC;YAC3C,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,SAAS;SACvB,CAAC,CAAC;QAEH,IAAA,sBAAW,EAAC,SAAS,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { RedactConfig, RedactPattern, WalkResult } from '../config/types.js';
2
+ /**
3
+ * Recursively traverses a JSON-like structure and redacts any string values
4
+ * that match the provided patterns.
5
+ *
6
+ * Traversal rules:
7
+ * - **Arrays**: each element is walked with an indexed path (e.g. `items[0].token`).
8
+ * - **Objects**: each property is visited; the key is tested against patterns.
9
+ * - **Strings**: tested via {@link redactValue}. If not redacted, the value is also
10
+ * tested as embedded JSON (a string that is itself a JSON object/array) and, if
11
+ * parseable, the inner structure is walked recursively and re-serialised.
12
+ * - **Base64 JSON bodies**: if an object has a `Content-Type: application/json`
13
+ * sibling and a body-like field containing base64 data, the decoded JSON is
14
+ * walked and the field is re-encoded after redaction.
15
+ * - **Numbers / booleans**: copied through as-is (never redacted).
16
+ * - **`null` / `undefined`**: returned unchanged.
17
+ *
18
+ * The input is **never mutated** — a new tree is produced for each call.
19
+ *
20
+ * @param obj - The JSON value to walk. Typically a parsed `trace.json` array
21
+ * or the `window.__pw_report_data__` object extracted from an HTML report.
22
+ * @param patterns - Ordered list of {@link RedactPattern}s to apply.
23
+ * @param config - The redact config, forwarded to {@link redactValue} for placeholder resolution.
24
+ * @returns A {@link WalkResult} containing the transformed tree, total redaction count,
25
+ * and the list of individual {@link RedactionMatch}es.
26
+ */
27
+ export declare function walkAndRedact(obj: unknown, patterns: RedactPattern[], config: RedactConfig): WalkResult;
28
+ //# sourceMappingURL=json-walker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-walker.d.ts","sourceRoot":"","sources":["../../src/redact/json-walker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EAEb,UAAU,EACX,MAAM,oBAAoB,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,OAAO,EACZ,QAAQ,EAAE,aAAa,EAAE,EACzB,MAAM,EAAE,YAAY,GACnB,UAAU,CA4FZ"}