privalint 0.2.0 → 0.3.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 (52) hide show
  1. package/README.de.md +30 -2
  2. package/README.md +28 -2
  3. package/dist/assessment.d.ts +6 -0
  4. package/dist/assessment.js +79 -0
  5. package/dist/assessment.js.map +1 -0
  6. package/dist/capture.d.ts +5 -0
  7. package/dist/capture.js +155 -0
  8. package/dist/capture.js.map +1 -0
  9. package/dist/cli.js +4 -3
  10. package/dist/cli.js.map +1 -1
  11. package/dist/consent.d.ts +3 -0
  12. package/dist/consent.js +13 -6
  13. package/dist/consent.js.map +1 -1
  14. package/dist/diagnostics.d.ts +27 -0
  15. package/dist/diagnostics.js +187 -0
  16. package/dist/diagnostics.js.map +1 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.js +3 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/network.d.ts +67 -0
  21. package/dist/network.js +235 -0
  22. package/dist/network.js.map +1 -0
  23. package/dist/observations.d.ts +3 -0
  24. package/dist/observations.js +4 -0
  25. package/dist/observations.js.map +1 -0
  26. package/dist/reporters/capture.d.ts +5 -0
  27. package/dist/reporters/capture.js +35 -0
  28. package/dist/reporters/capture.js.map +1 -0
  29. package/dist/reporters/markdown.js +7 -0
  30. package/dist/reporters/markdown.js.map +1 -1
  31. package/dist/reporters/messages.js +12 -6
  32. package/dist/reporters/messages.js.map +1 -1
  33. package/dist/reporters/sarif.js +24 -0
  34. package/dist/reporters/sarif.js.map +1 -1
  35. package/dist/reporters/text.js +6 -2
  36. package/dist/reporters/text.js.map +1 -1
  37. package/dist/rules/google-fonts.js +2 -1
  38. package/dist/rules/google-fonts.js.map +1 -1
  39. package/dist/rules/reject-option.js +3 -3
  40. package/dist/rules/reject-option.js.map +1 -1
  41. package/dist/rules/third-party-hits.js +2 -1
  42. package/dist/rules/third-party-hits.js.map +1 -1
  43. package/dist/rules/tracker-hits.js +2 -1
  44. package/dist/rules/tracker-hits.js.map +1 -1
  45. package/dist/scan-options.d.ts +39 -0
  46. package/dist/scan-options.js +2 -0
  47. package/dist/scan-options.js.map +1 -0
  48. package/dist/scanner.d.ts +4 -38
  49. package/dist/scanner.js +84 -109
  50. package/dist/scanner.js.map +1 -1
  51. package/dist/types.d.ts +62 -0
  52. package/package.json +1 -1
@@ -0,0 +1,187 @@
1
+ /** Safe for diagnostics and operational logs. Raw URLs remain internal rule input. */
2
+ export function diagnosticUrl(raw) {
3
+ try {
4
+ const url = new URL(raw);
5
+ return /^https?:$/.test(url.protocol) ? `${url.origin}/[redacted]` : '[redacted]';
6
+ }
7
+ catch {
8
+ return '[redacted]';
9
+ }
10
+ }
11
+ /** Classify known transport codes; never persist arbitrary exception messages. */
12
+ export function classifyLoadError(error) {
13
+ const parts = [];
14
+ let cause = error;
15
+ for (let depth = 0; depth < 4 && cause instanceof Error; depth++) {
16
+ parts.push(cause.message, 'code' in cause ? String(cause.code) : '');
17
+ cause = cause.cause;
18
+ }
19
+ const text = parts.length > 0 ? parts.join(' ') : String(error);
20
+ if (/ERR_NAME_NOT_RESOLVED|ENOTFOUND|EAI_AGAIN/i.test(text))
21
+ return 'dns';
22
+ if (/ERR_CERT|ERR_SSL|CERT_|TLS|SELF_SIGNED|UNABLE_TO_VERIFY_LEAF/i.test(text))
23
+ return 'tls';
24
+ if (/timeout|timed.?out|ETIMEDOUT/i.test(text))
25
+ return 'timeout';
26
+ if (/ERR_CONNECTION|ECONN|ENETUNREACH|EHOSTUNREACH|socket hang up/i.test(text)) {
27
+ return 'connection';
28
+ }
29
+ return 'browser-failure';
30
+ }
31
+ export class Diagnostics {
32
+ maxIssues;
33
+ maxRecords;
34
+ data = {
35
+ requests: 0,
36
+ omittedRequests: 0,
37
+ responses: 0,
38
+ finished: 0,
39
+ failed: 0,
40
+ blocked: 0,
41
+ httpErrors: 0,
42
+ bytes: 0,
43
+ issueCount: 0,
44
+ dropped: 0,
45
+ issues: [],
46
+ };
47
+ phase = 'before-consent';
48
+ pending = new Map();
49
+ earlyFailures = new Map();
50
+ stopped = false;
51
+ phaseIssues = { 'before-consent': 0, 'after-reject': 0 };
52
+ constructor(maxIssues, maxRecords = 5_000) {
53
+ this.maxIssues = maxIssues;
54
+ this.maxRecords = maxRecords;
55
+ }
56
+ attach(context, records) {
57
+ context.on('request', (request) => {
58
+ if (this.stopped)
59
+ return;
60
+ const record = {
61
+ url: request.url(),
62
+ resourceType: request.resourceType(),
63
+ outcome: 'pending',
64
+ };
65
+ if (records.length < this.maxRecords)
66
+ records.push(record);
67
+ else {
68
+ this.data.omittedRequests++;
69
+ if (this.data.omittedRequests === 1)
70
+ this.add('resource-limit', request.url(), { limit: 'requests' });
71
+ }
72
+ const early = this.earlyFailures.get(request.url());
73
+ const issue = early?.shift();
74
+ if (early?.length === 0)
75
+ this.earlyFailures.delete(request.url());
76
+ this.pending.set(request, { record, phase: this.phase, ...(issue ? { issue } : {}) });
77
+ this.data.requests++;
78
+ });
79
+ context.on('response', (response) => {
80
+ if (this.stopped)
81
+ return;
82
+ const entry = this.pending.get(response.request());
83
+ if (entry === undefined)
84
+ return;
85
+ entry.record.outcome = 'response';
86
+ entry.record.status = response.status();
87
+ this.data.responses++;
88
+ if (response.status() >= 400) {
89
+ this.data.httpErrors++;
90
+ this.add('http-error', response.url(), { status: response.status() }, entry.phase);
91
+ }
92
+ });
93
+ context.on('requestfinished', (request) => this.finish(request));
94
+ context.on('requestfailed', (request) => {
95
+ const entry = this.pending.get(request);
96
+ if (entry === undefined || this.stopped)
97
+ return;
98
+ entry.record.outcome = 'failed';
99
+ const issue = entry.issue ?? {
100
+ kind: classifyLoadError(request.failure()?.errorText),
101
+ url: diagnosticUrl(request.url()),
102
+ phase: entry.phase,
103
+ };
104
+ if (issue.kind === 'security-blocked')
105
+ this.data.blocked++;
106
+ this.store(issue);
107
+ this.data.failed++;
108
+ this.pending.delete(request);
109
+ });
110
+ }
111
+ finish(request) {
112
+ if (this.stopped || !this.pending.delete(request))
113
+ return;
114
+ this.data.finished++;
115
+ }
116
+ /** Defer storage until requestfailed to avoid counting adapter + browser errors twice. */
117
+ fail(request, kind, limit) {
118
+ const entry = this.pending.get(request);
119
+ if (entry === undefined)
120
+ return;
121
+ entry.issue = {
122
+ kind,
123
+ phase: entry.phase,
124
+ url: diagnosticUrl(request.url()),
125
+ ...(limit === undefined ? {} : { limit }),
126
+ };
127
+ }
128
+ failUrl(url, kind, limit) {
129
+ if (this.stopped)
130
+ return;
131
+ for (const [request, entry] of this.pending) {
132
+ if (request.url() === url && entry.issue === undefined) {
133
+ this.fail(request, kind, limit);
134
+ return;
135
+ }
136
+ }
137
+ // CDP can pause a request before Playwright emits it. Associate the reason on arrival.
138
+ const early = this.earlyFailures.get(url) ?? [];
139
+ early.push({
140
+ kind,
141
+ url: diagnosticUrl(url),
142
+ phase: this.phase,
143
+ ...(limit === undefined ? {} : { limit }),
144
+ });
145
+ this.earlyFailures.set(url, early);
146
+ }
147
+ add(kind, url, extra = {}, phase = this.phase) {
148
+ if (!this.stopped)
149
+ this.store({ kind, phase, url: diagnosticUrl(url), ...extra });
150
+ }
151
+ store(issue) {
152
+ this.phaseIssues[issue.phase]++;
153
+ this.data.issueCount++;
154
+ if (this.data.issues.length < this.maxIssues)
155
+ this.data.issues.push(issue);
156
+ else
157
+ this.data.dropped++;
158
+ }
159
+ hasIssues(phase) {
160
+ return this.phaseIssues[phase] > 0;
161
+ }
162
+ /** Freeze before closing the context: teardown errors are not resource failures. */
163
+ stop() {
164
+ if (this.stopped)
165
+ return;
166
+ for (const [request, entry] of this.pending) {
167
+ entry.record.outcome = 'failed';
168
+ const issue = entry.issue ?? {
169
+ kind: 'timeout',
170
+ phase: entry.phase,
171
+ url: diagnosticUrl(request.url()),
172
+ };
173
+ if (issue.kind === 'security-blocked')
174
+ this.data.blocked++;
175
+ this.store(issue);
176
+ this.data.failed++;
177
+ }
178
+ this.pending.clear();
179
+ for (const issues of this.earlyFailures.values()) {
180
+ for (const issue of issues)
181
+ this.store(issue);
182
+ }
183
+ this.earlyFailures.clear();
184
+ this.stopped = true;
185
+ }
186
+ }
187
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,9 @@
1
+ export { type ConsentCheckOptions, observeConsent } from './consent.js';
1
2
  export { type Tracker, type TrackerCategory, trackers } from './data/trackers.js';
3
+ export { diagnosticUrl } from './diagnostics.js';
2
4
  export { LANGS, type Lang, type Text } from './i18n.js';
3
5
  export { legalReferences, REGIONS, type Region } from './legal.js';
6
+ export { type NetworkAdapter, NetworkError, type NetworkLimits, type NetworkRequest, type NetworkResponse, } from './network.js';
4
7
  export { defaultRules, googleFonts, impressumLink, preConsentTrackers, privacyPolicyLink, rejectOption, thirdPartyCdns, thirdPartyEmbeds, trackersAfterReject, } from './rules/index.js';
5
8
  export { type ScanOptions, scan } from './scanner.js';
6
9
  export type * from './types.js';
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
+ export { observeConsent } from './consent.js';
1
2
  export { trackers } from './data/trackers.js';
3
+ export { diagnosticUrl } from './diagnostics.js';
2
4
  export { LANGS } from './i18n.js';
3
5
  export { legalReferences, REGIONS } from './legal.js';
6
+ export { NetworkError, } from './network.js';
4
7
  export { defaultRules, googleFonts, impressumLink, preConsentTrackers, privacyPolicyLink, rejectOption, thirdPartyCdns, thirdPartyEmbeds, trackersAfterReject, } from './rules/index.js';
5
8
  export { scan } from './scanner.js';
6
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,KAAK,EAAwB,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AACnE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAoB,IAAI,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,cAAc,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAsC,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAwB,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AACnE,OAAO,EAEL,YAAY,GAIb,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAoB,IAAI,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,67 @@
1
+ import type { BrowserContext, Page } from 'playwright';
2
+ import { type Diagnostics } from './diagnostics.js';
3
+ import type { LoadDiagnostic, LoadIssueKind } from './types.js';
4
+ export interface NetworkRequest {
5
+ url: string;
6
+ method: string;
7
+ headers: Record<string, string>;
8
+ body: Uint8Array | null;
9
+ resourceType: string;
10
+ /** Covers execution and body consumption. The adapter must honour cancellation. */
11
+ signal: AbortSignal;
12
+ }
13
+ export interface NetworkResponse {
14
+ status: number;
15
+ headers?: Record<string, string | string[]>;
16
+ /** Stream bodies to enforce byte limits before buffering the entire response. */
17
+ body?: string | Uint8Array | AsyncIterable<Uint8Array>;
18
+ }
19
+ /** Fetch exactly ONE HTTP hop, never follow redirects. Caller owns shared transport clients. */
20
+ export type NetworkAdapter = (request: NetworkRequest) => Promise<NetworkResponse>;
21
+ export interface NetworkLimits {
22
+ concurrency?: number;
23
+ maxRequests?: number;
24
+ maxResponseBytes?: number;
25
+ maxTotalBytes?: number;
26
+ maxRedirects?: number;
27
+ /** Starts on dequeue; queue wait is bounded separately by captureTimeoutMs. */
28
+ requestTimeoutMs?: number;
29
+ }
30
+ export declare const NETWORK_DEFAULTS: {
31
+ concurrency: number;
32
+ maxRequests: number;
33
+ maxResponseBytes: number;
34
+ maxTotalBytes: number;
35
+ maxRedirects: number;
36
+ requestTimeoutMs: number;
37
+ };
38
+ export declare class NetworkError extends Error {
39
+ readonly kind: Exclude<LoadIssueKind, 'http-error'>;
40
+ readonly limit?: LoadDiagnostic['limit'];
41
+ constructor(kind: Exclude<LoadIssueKind, 'http-error'>, limit?: LoadDiagnostic['limit']);
42
+ }
43
+ export declare function networkLimits(options?: NetworkLimits): Required<NetworkLimits>;
44
+ /** Chromium Fetch interception includes redirect hops that Playwright route() auto-continues. */
45
+ export declare class ControlledNetwork {
46
+ private readonly adapter;
47
+ private readonly limits;
48
+ private readonly diagnostics;
49
+ private readonly signal;
50
+ private readonly queue;
51
+ private readonly tasks;
52
+ private readonly sessions;
53
+ private active;
54
+ private admitted;
55
+ private closed;
56
+ constructor(adapter: NetworkAdapter, limits: Required<NetworkLimits>, diagnostics: Diagnostics, signal: AbortSignal);
57
+ attach(context: BrowserContext): Promise<void>;
58
+ attachPage(page: Page): Promise<void>;
59
+ private intercept;
60
+ private pump;
61
+ private handle;
62
+ private readBody;
63
+ private abort;
64
+ close(): Promise<void>;
65
+ }
66
+ /** Abort without retaining caller reasons or leaving listeners attached. */
67
+ export declare function withSignal<T>(operation: Promise<T>, signal: AbortSignal): Promise<T>;
@@ -0,0 +1,235 @@
1
+ import { classifyLoadError } from './diagnostics.js';
2
+ export const NETWORK_DEFAULTS = {
3
+ concurrency: 6,
4
+ maxRequests: 500,
5
+ maxResponseBytes: 5 * 1024 * 1024,
6
+ maxTotalBytes: 20 * 1024 * 1024,
7
+ maxRedirects: 10,
8
+ requestTimeoutMs: 10_000,
9
+ };
10
+ export class NetworkError extends Error {
11
+ kind;
12
+ limit;
13
+ constructor(kind, limit) {
14
+ super(kind);
15
+ this.kind = kind;
16
+ this.limit = limit;
17
+ this.name = 'NetworkError';
18
+ }
19
+ }
20
+ export function networkLimits(options = {}) {
21
+ const limits = { ...NETWORK_DEFAULTS, ...options };
22
+ for (const [key, value] of Object.entries(limits)) {
23
+ const min = key === 'maxRedirects' ? 0 : 1;
24
+ if (!Number.isSafeInteger(value) || value < min)
25
+ throw new RangeError(`${key} must be a safe integer of at least ${min}`);
26
+ }
27
+ return limits;
28
+ }
29
+ function requestBody(request) {
30
+ if (request.postDataEntries !== undefined) {
31
+ if (request.postDataEntries.some((entry) => entry.bytes === undefined)) {
32
+ throw new NetworkError('unsupported-method');
33
+ }
34
+ return Buffer.concat(request.postDataEntries.map((entry) => Buffer.from(entry.bytes ?? '', 'base64')));
35
+ }
36
+ if (request.postData !== undefined)
37
+ return Buffer.from(request.postData);
38
+ if (request.hasPostData)
39
+ throw new NetworkError('unsupported-method');
40
+ return null;
41
+ }
42
+ function failureKind(error, signal, timeout) {
43
+ if (signal.aborted) {
44
+ return signal.reason instanceof DOMException && signal.reason.name === 'TimeoutError'
45
+ ? 'timeout'
46
+ : 'aborted';
47
+ }
48
+ if (timeout.aborted)
49
+ return 'timeout';
50
+ return error instanceof NetworkError ? error.kind : classifyLoadError(error);
51
+ }
52
+ /** Chromium Fetch interception includes redirect hops that Playwright route() auto-continues. */
53
+ export class ControlledNetwork {
54
+ adapter;
55
+ limits;
56
+ diagnostics;
57
+ signal;
58
+ queue = [];
59
+ tasks = new Set();
60
+ sessions = new Map();
61
+ active = 0;
62
+ admitted = 0;
63
+ closed = false;
64
+ constructor(adapter, limits, diagnostics, signal) {
65
+ this.adapter = adapter;
66
+ this.limits = limits;
67
+ this.diagnostics = diagnostics;
68
+ this.signal = signal;
69
+ }
70
+ async attach(context) {
71
+ context.on('page', (page) => {
72
+ void this.attachPage(page).catch(() => this.diagnostics.add('browser-failure', page.url()));
73
+ });
74
+ await context.routeWebSocket('**/*', (socket) => {
75
+ this.diagnostics.add('unsupported-protocol', socket.url());
76
+ socket.close();
77
+ });
78
+ }
79
+ attachPage(page) {
80
+ const existing = this.sessions.get(page);
81
+ if (existing)
82
+ return existing;
83
+ const attaching = this.intercept(page);
84
+ this.sessions.set(page, attaching);
85
+ return attaching;
86
+ }
87
+ async intercept(page) {
88
+ const session = await page.context().newCDPSession(page);
89
+ const redirects = new Map();
90
+ session.on('Fetch.requestPaused', (event) => {
91
+ const count = event.redirectedRequestId
92
+ ? (redirects.get(event.redirectedRequestId) ?? 0) + 1
93
+ : 0;
94
+ if (event.redirectedRequestId)
95
+ redirects.delete(event.redirectedRequestId);
96
+ const request = { event, session, redirects: count, redirectCounts: redirects };
97
+ if (this.closed || this.signal.aborted) {
98
+ void this.abort(request, 'aborted');
99
+ return;
100
+ }
101
+ this.admitted++;
102
+ if (this.admitted > this.limits.maxRequests) {
103
+ void this.abort(request, 'resource-limit', 'requests');
104
+ return;
105
+ }
106
+ this.queue.push(request);
107
+ this.pump();
108
+ });
109
+ await session.send('Fetch.enable', {
110
+ patterns: [{ urlPattern: '*', requestStage: 'Request' }],
111
+ });
112
+ }
113
+ pump() {
114
+ while (!this.closed && !this.signal.aborted && this.active < this.limits.concurrency) {
115
+ const request = this.queue.shift();
116
+ if (request === undefined)
117
+ return;
118
+ this.active++;
119
+ const task = this.handle(request).finally(() => {
120
+ this.active--;
121
+ this.tasks.delete(task);
122
+ this.pump();
123
+ });
124
+ this.tasks.add(task);
125
+ }
126
+ }
127
+ async handle(intercepted) {
128
+ const { event, session, redirects, redirectCounts } = intercepted;
129
+ const { request } = event;
130
+ const controller = new AbortController();
131
+ const timeout = AbortSignal.timeout(this.limits.requestTimeoutMs);
132
+ const signal = AbortSignal.any([this.signal, timeout, controller.signal]);
133
+ try {
134
+ if (!/^https?:$/.test(new URL(request.url).protocol))
135
+ throw new NetworkError('unsupported-protocol');
136
+ if (redirects > this.limits.maxRedirects)
137
+ throw new NetworkError('resource-limit', 'redirects');
138
+ if (this.diagnostics.data.bytes >= this.limits.maxTotalBytes)
139
+ throw new NetworkError('resource-limit', 'total-bytes');
140
+ const response = await withSignal(this.adapter({
141
+ url: request.url,
142
+ method: request.method,
143
+ headers: request.headers,
144
+ body: requestBody(request),
145
+ resourceType: event.resourceType.toLowerCase(),
146
+ signal,
147
+ }), signal);
148
+ const body = await this.readBody(response.body, signal);
149
+ signal.throwIfAborted();
150
+ if (!Number.isInteger(response.status) || response.status < 200 || response.status > 599)
151
+ throw new NetworkError('browser-failure');
152
+ if ([301, 302, 303, 307, 308].includes(response.status))
153
+ redirectCounts.set(event.requestId, redirects);
154
+ await session.send('Fetch.fulfillRequest', {
155
+ requestId: event.requestId,
156
+ responseCode: response.status,
157
+ responseHeaders: Object.entries(response.headers ?? {}).flatMap(([name, value]) => (Array.isArray(value) ? value : [value]).map((item) => ({ name, value: item }))),
158
+ body: body.toString('base64'),
159
+ });
160
+ }
161
+ catch (error) {
162
+ const kind = failureKind(error, this.signal, timeout);
163
+ await this.abort(intercepted, kind, error instanceof NetworkError ? error.limit : undefined);
164
+ }
165
+ finally {
166
+ controller.abort();
167
+ }
168
+ }
169
+ async readBody(body, signal) {
170
+ const chunks = [];
171
+ let size = 0;
172
+ const append = (chunk) => {
173
+ size += chunk.byteLength;
174
+ this.diagnostics.data.bytes += chunk.byteLength;
175
+ if (size > this.limits.maxResponseBytes)
176
+ throw new NetworkError('resource-limit', 'response-bytes');
177
+ if (this.diagnostics.data.bytes > this.limits.maxTotalBytes)
178
+ throw new NetworkError('resource-limit', 'total-bytes');
179
+ chunks.push(chunk);
180
+ };
181
+ if (body === undefined)
182
+ return Buffer.alloc(0);
183
+ if (typeof body === 'string' || body instanceof Uint8Array) {
184
+ append(typeof body === 'string' ? Buffer.from(body) : body);
185
+ }
186
+ else {
187
+ const iterator = body[Symbol.asyncIterator]();
188
+ try {
189
+ while (true) {
190
+ const chunk = await withSignal(iterator.next(), signal);
191
+ if (chunk.done)
192
+ break;
193
+ append(chunk.value);
194
+ }
195
+ }
196
+ finally {
197
+ void iterator.return?.().catch(() => { });
198
+ }
199
+ }
200
+ return Buffer.concat(chunks, size);
201
+ }
202
+ async abort(request, kind, limit) {
203
+ this.diagnostics.failUrl(request.event.request.url, kind, limit);
204
+ await request.session
205
+ .send('Fetch.failRequest', {
206
+ requestId: request.event.requestId,
207
+ errorReason: 'BlockedByClient',
208
+ })
209
+ .catch(() => { });
210
+ }
211
+ async close() {
212
+ this.closed = true;
213
+ await Promise.all(this.queue.splice(0).map((request) => this.abort(request, 'aborted')));
214
+ await Promise.all(this.tasks);
215
+ }
216
+ }
217
+ /** Abort without retaining caller reasons or leaving listeners attached. */
218
+ export async function withSignal(operation, signal) {
219
+ if (signal.aborted) {
220
+ void operation.catch(() => { });
221
+ throw new DOMException('Operation aborted', 'AbortError');
222
+ }
223
+ let onAbort = () => { };
224
+ const aborted = new Promise((_resolve, reject) => {
225
+ onAbort = () => reject(new DOMException('Operation aborted', 'AbortError'));
226
+ signal.addEventListener('abort', onAbort, { once: true });
227
+ });
228
+ try {
229
+ return await Promise.race([operation, aborted]);
230
+ }
231
+ finally {
232
+ signal.removeEventListener('abort', onAbort);
233
+ }
234
+ }
235
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RecordedRequest } from './types.js';
2
+ /** Legacy records remain valid; failed, pending and HTTP-error responses are not loaded vendors. */
3
+ export declare const observedRequests: (requests: readonly RecordedRequest[]) => RecordedRequest[];
@@ -0,0 +1,4 @@
1
+ /** Legacy records remain valid; failed, pending and HTTP-error responses are not loaded vendors. */
2
+ export const observedRequests = (requests) => requests.filter((request) => request.outcome === undefined ||
3
+ (request.outcome === 'response' && (request.status ?? 200) < 400));
4
+ //# sourceMappingURL=observations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observations.js","sourceRoot":"","sources":["../src/observations.ts"],"names":[],"mappings":"AAEA,oGAAoG;AACpG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAoC,EAAqB,EAAE,CAC1F,QAAQ,CAAC,MAAM,CACb,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,CAAC,OAAO,KAAK,SAAS;IAC7B,CAAC,OAAO,CAAC,OAAO,KAAK,UAAU,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,CACpE,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ScanResult } from '../types.js';
2
+ export declare function isPartial(result: ScanResult): boolean;
3
+ export declare function coverageMessage(result: ScanResult): string;
4
+ /** Technical observations are reported separately from privacy findings. */
5
+ export declare function captureLines(result: ScanResult): string[];
@@ -0,0 +1,35 @@
1
+ export function isPartial(result) {
2
+ return (result.coverage === 'partial' ||
3
+ result.pages.some((page) => page.error !== undefined ||
4
+ page.capture?.complete === false ||
5
+ (page.status !== null && page.status >= 400)));
6
+ }
7
+ export function coverageMessage(result) {
8
+ return result.lang === 'de'
9
+ ? 'Erfassung unvollständig. Keine Befunde bedeutet hier keine vollständige Prüfung; der Ablehnen-Pfad kann ungeprüft sein.'
10
+ : 'Observation incomplete. No findings does not mean a complete check; the reject path may be untested.';
11
+ }
12
+ /** Technical observations are reported separately from privacy findings. */
13
+ export function captureLines(result) {
14
+ const german = result.lang === 'de';
15
+ const lines = [];
16
+ for (const page of result.pages) {
17
+ const data = page.capture?.diagnostics;
18
+ if (data !== undefined) {
19
+ lines.push(`${german ? 'Erfassung' : 'Capture'} ${page.url}: ` +
20
+ `${data.requests} ${german ? 'Anfragen' : 'requests'}, ${data.responses} ${german ? 'Antworten' : 'responses'}, ` +
21
+ `${data.failed} ${german ? 'fehlgeschlagen' : 'failed'} (${data.blocked} ${german ? 'Sicherheitsblockaden' : 'security blocks'}), ` +
22
+ `${data.httpErrors} HTTP ${german ? 'Fehlerantworten' : 'errors'}.`);
23
+ for (const issue of data.issues) {
24
+ lines.push(` ${issue.phase}: ${issue.kind}${issue.limit ? ` (${issue.limit})` : ''}${issue.status ? ` HTTP ${issue.status}` : ''} ${issue.url}`);
25
+ }
26
+ if (data.dropped)
27
+ lines.push(` ${data.dropped} ${german ? 'weitere Diagnosen nicht gespeichert' : 'additional issue details omitted'}.`);
28
+ }
29
+ for (const evaluation of page.ruleEvaluations ?? []) {
30
+ lines.push(` ${evaluation.ruleId}: ${evaluation.status}${evaluation.reason ? ` (${evaluation.reason})` : ''}${evaluation.partial ? ' [partial]' : ''}`);
31
+ }
32
+ }
33
+ return lines;
34
+ }
35
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/reporters/capture.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { captureLines, coverageMessage, isPartial } from './capture.js';
1
2
  import { messagesFor } from './messages.js';
2
3
  import { countBySeverity, groupByPage } from './shared.js';
3
4
  const ICONS = { error: '🔴', warning: '🟡', info: '🔵' };
@@ -19,6 +20,12 @@ export function formatMarkdown(result) {
19
20
  if (result.consent !== undefined) {
20
21
  lines.push('', escapeText(m.consent(result.consent)));
21
22
  }
23
+ if (isPartial(result))
24
+ lines.push('', escapeText(coverageMessage(result)));
25
+ const observations = captureLines(result);
26
+ if (observations.length > 0) {
27
+ lines.push('', ...observations.map((line) => `- ${escapeText(line)}`));
28
+ }
22
29
  for (const [pageUrl, findings] of groupByPage(result.findings)) {
23
30
  lines.push('', `#### ${code(pageUrl)}`, '', `| | ${m.rule} | ${m.finding} |`, '|---|---|---|');
24
31
  for (const finding of findings) {
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,KAAK,GAA6B,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAEnF;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG;QACZ,kBAAkB,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;QACxC,EAAE;QACF,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE;KACzG,CAAC;IACF,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,IAAI,EAAE,eAAe,CAAC,CAAC;QAC/F,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACR,KAAK,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,OAAO,CAAC,MAAM,QAAQ,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAC1F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;IACvE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAC7E,CAAC;IACF,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC,QAAQ,YAAY,EAAE,EAAE,CAAC,CAAC;QAChE,KAAK,MAAM,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC;YAClD,MAAM,KAAK,GAAG,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,OAAO,UAAU,CAAC,GAAG,GAAG,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACvE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,UAAU,QAAQ,CAAC,CAAC;IAC7C,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC;AAED,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;AAE1F,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,EAAE,CAClC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"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"}