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
@@ -15,17 +15,20 @@ const en = {
15
15
  howToFix: 'How to fix',
16
16
  disclaimer: 'Automated checks only. A clean result is not proof of GDPR compliance.',
17
17
  consent(consent) {
18
+ if (consent.state === 'interaction-failed') {
19
+ return `Consent check: interaction failed (${consent.error ?? 'browser-failure'}); reject path untested`;
20
+ }
18
21
  if (!consent.bannerFound) {
19
- return 'Consent banner: none found';
22
+ return 'Consent banner: none detected; reject path untested (not a privacy finding)';
20
23
  }
21
24
  const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
22
25
  if (consent.error !== undefined) {
23
26
  return `Consent banner${vendor}: found, but rejecting failed: ${consent.error}`;
24
27
  }
25
28
  if (consent.rejected) {
26
- return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded`;
29
+ return `Consent banner${vendor}: clicked "${consent.rejectLabel}" and reloaded${consent.afterRejectComplete === false ? '; observation incomplete' : ''}`;
27
30
  }
28
- return `Consent banner${vendor}: found, no reject button`;
31
+ return `Consent banner${vendor}: found, no supported reject option; reject path untested`;
29
32
  },
30
33
  };
31
34
  const de = {
@@ -44,17 +47,20 @@ const de = {
44
47
  howToFix: 'So beheben Sie es',
45
48
  disclaimer: 'Nur automatisierte Prüfungen. Ein sauberes Ergebnis ist kein Nachweis der DSGVO-Konformität.',
46
49
  consent(consent) {
50
+ if (consent.state === 'interaction-failed') {
51
+ return `Consent-Prüfung: Interaktion fehlgeschlagen (${consent.error ?? 'browser-failure'}); Ablehnen-Pfad ungeprüft`;
52
+ }
47
53
  if (!consent.bannerFound) {
48
- return 'Cookie-Banner: keines gefunden';
54
+ return 'Cookie-Banner: keines erkannt; Ablehnen-Pfad ungeprüft (kein Datenschutzbefund)';
49
55
  }
50
56
  const vendor = consent.cmp === undefined ? '' : ` (${consent.cmp})`;
51
57
  if (consent.error !== undefined) {
52
58
  return `Cookie-Banner${vendor}: gefunden, aber Ablehnen ist fehlgeschlagen: ${consent.error}`;
53
59
  }
54
60
  if (consent.rejected) {
55
- return `Cookie-Banner${vendor}: „${consent.rejectLabel}“ geklickt und neu geladen`;
61
+ return `Cookie-Banner${vendor}: „${consent.rejectLabel}“ geklickt und neu geladen${consent.afterRejectComplete === false ? '; Erfassung unvollständig' : ''}`;
56
62
  }
57
- return `Cookie-Banner${vendor}: gefunden, kein Ablehnen-Button`;
63
+ return `Cookie-Banner${vendor}: gefunden, keine unterstützte Ablehnen-Möglichkeit; Ablehnen-Pfad ungeprüft`;
58
64
  },
59
65
  };
60
66
  const MESSAGES = { en, de };
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/reporters/messages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/reporters/messages.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { REPOSITORY_URL, ruleDocsUrl, VERSION } from '../meta.js';
3
+ import { coverageMessage, isPartial } from './capture.js';
3
4
  const LEVELS = {
4
5
  error: 'error',
5
6
  warning: 'warning',
@@ -39,6 +40,29 @@ export function formatSarif(result) {
39
40
  },
40
41
  },
41
42
  results: result.findings.map(toResult),
43
+ invocations: [
44
+ {
45
+ executionSuccessful: !isPartial(result),
46
+ toolExecutionNotifications: isPartial(result)
47
+ ? [
48
+ {
49
+ descriptor: { id: 'incomplete-observation' },
50
+ level: 'warning',
51
+ message: { text: coverageMessage(result) },
52
+ },
53
+ ]
54
+ : [],
55
+ },
56
+ ],
57
+ properties: {
58
+ coverage: result.coverage,
59
+ observations: result.pages.map(({ url, capture, ruleEvaluations }) => ({
60
+ url,
61
+ capture,
62
+ ruleEvaluations,
63
+ })),
64
+ consent: result.consent,
65
+ },
42
66
  },
43
67
  ],
44
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../src/reporters/sarif.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { styleText } from 'node:util';
2
+ import { captureLines, coverageMessage, isPartial } from './capture.js';
2
3
  import { messagesFor } from './messages.js';
3
4
  import { countBySeverity, groupByPage } from './shared.js';
4
5
  const MARKS = {
@@ -27,13 +28,16 @@ export function formatText(result, color = false) {
27
28
  const pages = m.pages(result.pages.length);
28
29
  const duration = m.duration(result.durationMs);
29
30
  lines.push('');
31
+ lines.push(...captureLines(result));
32
+ if (isPartial(result))
33
+ lines.push(paint('yellow', coverageMessage(result)));
30
34
  if (result.consent !== undefined) {
31
35
  lines.push(paint('dim', m.consent(result.consent)));
32
36
  }
33
- if (result.findings.length === 0) {
37
+ if (result.findings.length === 0 && !isPartial(result)) {
34
38
  lines.push(paint('green', `✔ ${m.noProblems(pages, duration)}`));
35
39
  }
36
- else {
40
+ else if (result.findings.length > 0) {
37
41
  lines.push(`${paint('red', m.errors(counts.error))}, ${paint('yellow', m.warnings(counts.warning))} ${m.on} ${pages} (${duration}).`);
38
42
  }
39
43
  lines.push(paint('dim', m.disclaimer));
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/reporters/text.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { say } from '../i18n.js';
2
+ import { observedRequests } from '../observations.js';
2
3
  import { hostMatches, safeHost } from '../url.js';
3
4
  const ID = 'google-fonts';
4
5
  const GOOGLE_FONT_HOSTS = ['fonts.googleapis.com', 'fonts.gstatic.com'];
@@ -25,7 +26,7 @@ export const googleFonts = {
25
26
  'consent. LG München I awarded a visitor damages for this in 2022.',
26
27
  references: ['Art. 6(1) GDPR', 'LG München I, 20.01.2022, Az. 3 O 17493/20'],
27
28
  check({ page, lang }) {
28
- const requests = page.requests.filter((request) => isGoogleFontUrl(request.url));
29
+ const requests = observedRequests(page.requests).filter((request) => isGoogleFontUrl(request.url));
29
30
  if (requests.length > 0) {
30
31
  const count = requests.length;
31
32
  return [
@@ -1 +1 @@
1
- {"version":3,"file":"google-fonts.js","sourceRoot":"","sources":["../../src/rules/google-fonts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"google-fonts.js","sourceRoot":"","sources":["../../src/rules/google-fonts.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@ import { say } from '../i18n.js';
2
2
  const ID = 'reject-option';
3
3
  export const rejectOption = {
4
4
  id: ID,
5
- title: 'No way to reject on the first layer of the banner',
5
+ title: 'No supported reject control detected on the first layer of the banner',
6
6
  description: 'Rejecting cookies must be as easy as accepting them. Most European regulators treat a banner ' +
7
7
  'that offers "accept" on its first layer, but hides "reject" in the settings or behind a ' +
8
8
  'link, as invalid consent.',
@@ -50,8 +50,8 @@ export const rejectOption = {
50
50
  ruleId: ID,
51
51
  severity: 'warning',
52
52
  message: say(lang, {
53
- en: `The consent banner${vendor} offers "${accept}" but no reject button next to it.`,
54
- de: `Das Cookie-Banner${vendor} bietet „${accept}“, aber keinen Ablehnen-Button daneben.`,
53
+ en: `The consent banner${vendor} offers "${accept}"; no supported first-layer reject control was detected. Verify the banner manually.`,
54
+ de: `Das Cookie-Banner${vendor} bietet „${accept}“; eine unterstützte Ablehnen-Steuerung auf der ersten Ebene wurde nicht erkannt. Das Banner manuell prüfen.`,
55
55
  }),
56
56
  pageUrl: page.finalUrl,
57
57
  evidence,
@@ -1 +1 @@
1
- {"version":3,"file":"reject-option.js","sourceRoot":"","sources":["../../src/rules/reject-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGjC,MAAM,EAAE,GAAG,eAAe,CAAC;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,mDAAmD;IAC1D,WAAW,EACT,+FAA+F;QAC/F,0FAA0F;QAC1F,2BAA2B;IAC7B,UAAU,EAAE;QACV,iDAAiD;QACjD,wEAAwE;QACxE,+CAA+C;QAC/C,iBAAiB;QACjB,gBAAgB;QAChB,mBAAmB;KACpB;IACD,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,GAAG,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QACnF,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,IAAI,EAAE;gBACR,EAAE,EAAE,kBAAkB,OAAO,CAAC,WAAW,IAAI,YAAY,EAAE;gBAC3D,EAAE,EAAE,qBAAqB,OAAO,CAAC,WAAW,IAAI,mBAAmB,EAAE;aACtE,CAAC;SACH,CAAC;QACF,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO;gBACL;oBACE,MAAM,EAAE,EAAE;oBACV,QAAQ,EAAE,MAAM;oBAChB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;wBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,+DAA+D;wBAChH,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,+DAA+D;qBAChH,CAAC;oBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,QAAQ;oBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;wBACb,EAAE,EAAE,sQAAsQ;wBAC1Q,EAAE,EAAE,0UAA0U;qBAC/U,CAAC;iBACH;aACF,CAAC;QACJ,CAAC;QACD,OAAO;YACL;gBACE,MAAM,EAAE,EAAE;gBACV,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;oBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,oCAAoC;oBACrF,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,yCAAyC;iBAC1F,CAAC;gBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;gBACtB,QAAQ;gBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;oBACb,EAAE,EAAE,sIAAsI;oBAC1I,EAAE,EAAE,+IAA+I;iBACpJ,CAAC;aACH;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"reject-option.js","sourceRoot":"","sources":["../../src/rules/reject-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAGjC,MAAM,EAAE,GAAG,eAAe,CAAC;AAE3B,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,uEAAuE;IAC9E,WAAW,EACT,+FAA+F;QAC/F,0FAA0F;QAC1F,2BAA2B;IAC7B,UAAU,EAAE;QACV,iDAAiD;QACjD,wEAAwE;QACxE,+CAA+C;QAC/C,iBAAiB;QACjB,gBAAgB;QAChB,mBAAmB;KACpB;IACD,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACvE,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,GAAG,GAAG,CAAC;QACpE,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;QACnF,MAAM,QAAQ,GAAG;YACf,GAAG,CAAC,IAAI,EAAE;gBACR,EAAE,EAAE,kBAAkB,OAAO,CAAC,WAAW,IAAI,YAAY,EAAE;gBAC3D,EAAE,EAAE,qBAAqB,OAAO,CAAC,WAAW,IAAI,mBAAmB,EAAE;aACtE,CAAC;SACH,CAAC;QACF,IAAI,OAAO,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC7B,OAAO;gBACL;oBACE,MAAM,EAAE,EAAE;oBACV,QAAQ,EAAE,MAAM;oBAChB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;wBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,+DAA+D;wBAChH,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,+DAA+D;qBAChH,CAAC;oBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;oBACtB,QAAQ;oBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;wBACb,EAAE,EAAE,sQAAsQ;wBAC1Q,EAAE,EAAE,0UAA0U;qBAC/U,CAAC;iBACH;aACF,CAAC;QACJ,CAAC;QACD,OAAO;YACL;gBACE,MAAM,EAAE,EAAE;gBACV,QAAQ,EAAE,SAAS;gBACnB,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;oBACjB,EAAE,EAAE,qBAAqB,MAAM,YAAY,MAAM,sFAAsF;oBACvI,EAAE,EAAE,oBAAoB,MAAM,YAAY,MAAM,8GAA8G;iBAC/J,CAAC;gBACF,OAAO,EAAE,IAAI,CAAC,QAAQ;gBACtB,QAAQ;gBACR,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE;oBACb,EAAE,EAAE,sIAAsI;oBAC1I,EAAE,EAAE,+IAA+I;iBACpJ,CAAC;aACH;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -1,8 +1,9 @@
1
+ import { observedRequests } from '../observations.js';
1
2
  const MAX_EVIDENCE = 5;
2
3
  /** Groups requests by the vendor `find` resolves them to. */
3
4
  export function groupRequestsByVendor(requests, find) {
4
5
  const byVendor = new Map();
5
- for (const request of requests) {
6
+ for (const request of observedRequests(requests)) {
6
7
  const vendor = find(request.url)?.vendor;
7
8
  if (vendor !== undefined) {
8
9
  byVendor.set(vendor, (byVendor.get(vendor) ?? new Set()).add(request.url));
@@ -1 +1 @@
1
- {"version":3,"file":"third-party-hits.js","sourceRoot":"","sources":["../../src/rules/third-party-hits.ts"],"names":[],"mappings":"AAGA,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,6DAA6D;AAC7D,MAAM,UAAU,qBAAqB,CACnC,QAAoC,EACpC,IAA6C;IAE7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
1
+ {"version":3,"file":"third-party-hits.js","sourceRoot":"","sources":["../../src/rules/third-party-hits.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,YAAY,GAAG,CAAC,CAAC;AAEvB,6DAA6D;AAC7D,MAAM,UAAU,qBAAqB,CACnC,QAAoC,EACpC,IAA6C;IAE7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { findTrackerByCookie, findTrackerByUrl, } from '../data/trackers.js';
2
2
  import { say } from '../i18n.js';
3
+ import { observedRequests } from '../observations.js';
3
4
  const MAX_EVIDENCE = 5;
4
5
  /** Matches requests and cookies against the tracker list, grouped by vendor. */
5
6
  export function findTrackerHits(requests, cookies, lang) {
@@ -10,7 +11,7 @@ export function findTrackerHits(requests, cookies, lang) {
10
11
  hit.evidence.add(evidence);
11
12
  hits.set(tracker.vendor, hit);
12
13
  };
13
- for (const request of requests) {
14
+ for (const request of observedRequests(requests)) {
14
15
  const tracker = findTrackerByUrl(request.url);
15
16
  if (tracker !== undefined) {
16
17
  record(tracker, `${requestLabel} ${request.url}`);
@@ -1 +1 @@
1
- {"version":3,"file":"tracker-hits.js","sourceRoot":"","sources":["../../src/rules/tracker-hits.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,GAAG,EAAa,MAAM,YAAY,CAAC;AAGvD,MAAM,YAAY,GAAG,CAAC,CAAC;AAQvB,gFAAgF;AAChF,MAAM,UAAU,eAAe,CAC7B,QAAoC,EACpC,OAAkC,EAClC,IAAU;IAEV,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC5E,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAE,QAAgB,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;QACjF,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,GAAG,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GACX,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;YAChC,gBAAgB,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,UAAU,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO;QACP,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;KAC/C,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,eAAe,GAAkC;IACrD,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE;IAC7C,WAAW,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE;IACjD,gBAAgB,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,gBAAgB,EAAE;IAChE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE;IAC5C,sBAAsB,EAAE,EAAE,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,2BAA2B,EAAE;IACvF,aAAa,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE;CACxD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAyB,EAAE,IAAU,EAAE,EAAE,CACrE,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"tracker-hits.js","sourceRoot":"","sources":["../../src/rules/tracker-hits.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,gBAAgB,GAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAa,GAAG,EAAa,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,MAAM,YAAY,GAAG,CAAC,CAAC;AAQvB,gFAAgF;AAChF,MAAM,UAAU,eAAe,CAC7B,QAAoC,EACpC,OAAkC,EAClC,IAAU;IAEV,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC5E,MAAM,MAAM,GAAG,CAAC,OAAgB,EAAE,QAAgB,EAAE,EAAE;QACpD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,GAAG,EAAU,EAAE,CAAC;QACjF,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,GAAG,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GACX,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC;YAChC,gBAAgB,CAAC,WAAW,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACnE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,EAAE,UAAU,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO;QACP,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;KAC/C,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,eAAe,GAAkC;IACrD,SAAS,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE;IAC7C,WAAW,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE;IACjD,gBAAgB,EAAE,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,gBAAgB,EAAE;IAChE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,cAAc,EAAE;IAC5C,sBAAsB,EAAE,EAAE,EAAE,EAAE,sBAAsB,EAAE,EAAE,EAAE,2BAA2B,EAAE;IACvF,aAAa,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,aAAa,EAAE;CACxD,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAAyB,EAAE,IAAU,EAAE,EAAE,CACrE,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { Lang } from './i18n.js';
2
+ import type { Region } from './legal.js';
3
+ import type { NetworkAdapter, NetworkLimits } from './network.js';
4
+ import type { PageSnapshot, Rule } from './types.js';
5
+ export interface ScanOptions {
6
+ maxPages?: number | undefined;
7
+ settleMs?: number | undefined;
8
+ /** Navigation/network-idle timeout, distinct from transport and capture deadlines. */
9
+ timeoutMs?: number | undefined;
10
+ locale?: string | undefined;
11
+ lang?: Lang | undefined;
12
+ /** Tool classification profile; does not determine which law applies. */
13
+ region?: Region | undefined;
14
+ rules?: readonly Rule[];
15
+ /** Legacy test helper: third-party requests receive synthetic empty responses. */
16
+ offline?: boolean;
17
+ consentCheck?: boolean | undefined;
18
+ headed?: boolean | undefined;
19
+ channel?: string | undefined;
20
+ /** Trusted hook receiving RAW observations. Do not log/expose without redaction. */
21
+ onPage?: (snapshot: PageSnapshot) => void;
22
+ /** Caller-owned transport; scan owns browser, fresh per-page contexts and request signals. */
23
+ networkAdapter?: NetworkAdapter;
24
+ /** Per-page budgets across initial loading and rejection. Requires networkAdapter. */
25
+ networkLimits?: NetworkLimits;
26
+ signal?: AbortSignal;
27
+ /** Entire capture including queue wait and consent; default 60s with an adapter. */
28
+ captureTimeoutMs?: number;
29
+ /** Stored issue details per page; counters are never truncated. Default 100. */
30
+ maxDiagnostics?: number;
31
+ /** Legacy default: throw on start-page navigation failure. Adapter default: report it. */
32
+ failureMode?: 'throw' | 'report';
33
+ }
34
+ export declare const DEFAULTS: {
35
+ maxPages: number;
36
+ settleMs: number;
37
+ timeoutMs: number;
38
+ locale: string;
39
+ };
@@ -0,0 +1,2 @@
1
+ export const DEFAULTS = { maxPages: 1, settleMs: 2_000, timeoutMs: 30_000, locale: 'de-DE' };
2
+ //# sourceMappingURL=scan-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-options.js","sourceRoot":"","sources":["../src/scan-options.ts"],"names":[],"mappings":"AAkCA,MAAM,CAAC,MAAM,QAAQ,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC"}
package/dist/scanner.d.ts CHANGED
@@ -1,39 +1,5 @@
1
- import type { Lang } from './i18n.js';
2
- import { type Region } from './legal.js';
3
- import type { PageSnapshot, Rule, ScanResult } from './types.js';
4
- export interface ScanOptions {
5
- /** Maximum number of pages on the same site to visit, starting with the given URL. */
6
- maxPages?: number | undefined;
7
- /** Extra time to wait after the network is idle, to catch delayed tags. */
8
- settleMs?: number | undefined;
9
- /** Navigation timeout per page. */
10
- timeoutMs?: number | undefined;
11
- locale?: string | undefined;
12
- /** Language of messages and fixes in the findings. */
13
- lang?: Lang | undefined;
14
- /** Country whose law the findings are judged by. */
15
- region?: Region | undefined;
16
- rules?: readonly Rule[];
17
- /**
18
- * Answer every third-party request with an empty response instead of fetching it.
19
- * Requests are still recorded. Used by the test suite to stay off the network.
20
- */
21
- offline?: boolean;
22
- /**
23
- * Click "reject" on the start page's consent banner and record what still loads.
24
- * On by default.
25
- */
26
- consentCheck?: boolean | undefined;
27
- /**
28
- * Open a visible browser window instead of running headless. Some sites only show their
29
- * consent banner to regular browsers. Needs a display, so it doesn't work on CI runners.
30
- */
31
- headed?: boolean | undefined;
32
- /**
33
- * Use an installed browser instead of Playwright's bundled Chromium,
34
- * e.g. `chrome` or `msedge`.
35
- */
36
- channel?: string | undefined;
37
- onPage?: (snapshot: PageSnapshot) => void;
38
- }
1
+ import { type ScanOptions } from './scan-options.js';
2
+ import type { ScanResult } from './types.js';
3
+ export type { ScanOptions } from './scan-options.js';
4
+ export declare function throwIfAborted(signal?: AbortSignal): void;
39
5
  export declare function scan(target: string, options?: ScanOptions): Promise<ScanResult>;
package/dist/scanner.js CHANGED
@@ -1,44 +1,67 @@
1
1
  import { chromium } from 'playwright';
2
- import { observeConsent } from './consent.js';
2
+ import { assessPage } from './assessment.js';
3
+ import { capturePage } from './capture.js';
4
+ import { diagnosticUrl } from './diagnostics.js';
3
5
  import { applyRegion } from './legal.js';
6
+ import { networkLimits } from './network.js';
4
7
  import { defaultRules } from './rules/index.js';
5
- import { crawlTarget, isFirstParty, withoutHash } from './url.js';
6
- const DEFAULTS = {
7
- maxPages: 1,
8
- settleMs: 2_000,
9
- timeoutMs: 30_000,
10
- locale: 'de-DE',
11
- lang: 'en',
12
- region: 'de',
13
- };
8
+ import { DEFAULTS } from './scan-options.js';
9
+ import { crawlTarget, withoutHash } from './url.js';
10
+ function integer(value, name, minimum) {
11
+ if (!Number.isSafeInteger(value) || value < minimum) {
12
+ throw new RangeError(`${name} must be a safe integer of at least ${minimum}`);
13
+ }
14
+ }
15
+ export function throwIfAborted(signal) {
16
+ if (signal?.aborted)
17
+ throw new DOMException('Scan aborted', 'AbortError');
18
+ }
14
19
  export async function scan(target, options = {}) {
20
+ throwIfAborted(options.signal);
15
21
  const startedAt = Date.now();
16
22
  const rules = options.rules ?? defaultRules;
17
- const maxPages = Math.max(1, options.maxPages ?? DEFAULTS.maxPages);
18
- const lang = options.lang ?? DEFAULTS.lang;
19
- const region = options.region ?? DEFAULTS.region;
23
+ const maxPages = options.maxPages ?? DEFAULTS.maxPages;
24
+ integer(maxPages, 'maxPages', 1);
25
+ integer(options.settleMs ?? DEFAULTS.settleMs, 'settleMs', 0);
26
+ integer(options.timeoutMs ?? DEFAULTS.timeoutMs, 'timeoutMs', 1);
27
+ integer(options.maxDiagnostics ?? 100, 'maxDiagnostics', 0);
28
+ if (options.captureTimeoutMs !== undefined)
29
+ integer(options.captureTimeoutMs, 'captureTimeoutMs', 1);
30
+ if (options.networkLimits && !options.networkAdapter) {
31
+ throw new TypeError('networkLimits requires networkAdapter');
32
+ }
33
+ if (options.networkAdapter && options.offline) {
34
+ throw new TypeError('offline cannot be combined with networkAdapter');
35
+ }
36
+ if (options.networkAdapter)
37
+ networkLimits(options.networkLimits);
38
+ const lang = options.lang ?? 'en';
39
+ const region = options.region ?? 'de';
20
40
  let siteUrl = new URL(target);
41
+ if (!/^https?:$/.test(siteUrl.protocol))
42
+ throw new TypeError('Expected an HTTP(S) target');
21
43
  const browser = await chromium.launch({
22
44
  headless: options.headed !== true,
23
45
  ...(options.channel === undefined ? {} : { channel: options.channel }),
24
46
  });
25
47
  try {
48
+ throwIfAborted(options.signal);
26
49
  const snapshots = [];
27
50
  const queue = [siteUrl.href];
28
51
  const seen = new Set(queue);
29
52
  const captured = new Set();
30
53
  let url = queue.shift();
31
54
  while (url !== undefined && snapshots.length < maxPages) {
55
+ throwIfAborted(options.signal);
32
56
  const isStart = snapshots.length === 0;
33
57
  const snapshot = await capturePage(browser, url, siteUrl, options, isStart);
34
58
  if (isStart) {
35
- if (snapshot.error !== undefined) {
36
- throw new Error(`Could not load ${url}: ${snapshot.error}`);
59
+ const failureMode = options.failureMode ?? (options.networkAdapter ? 'report' : 'throw');
60
+ if (snapshot.error !== undefined && failureMode === 'throw') {
61
+ throw new Error(`Could not load ${diagnosticUrl(url)}: ${snapshot.error}`);
37
62
  }
38
- // Follow redirects like http -> https or apex -> www for the rest of the crawl.
39
63
  siteUrl = new URL(snapshot.finalUrl);
40
64
  }
41
- // Several links can redirect to the same page; only lint it once.
42
65
  const finalUrl = withoutHash(snapshot.finalUrl);
43
66
  if (!captured.has(finalUrl)) {
44
67
  captured.add(finalUrl);
@@ -55,121 +78,73 @@ export async function scan(target, options = {}) {
55
78
  }
56
79
  url = queue.shift();
57
80
  }
58
- // Pages that failed, returned an error status or redirected off-site are listed but not linted.
59
- const observed = snapshots
60
- .filter((page) => page.error === undefined &&
61
- (page.status === null || page.status < 400) &&
62
- isFirstParty(page.finalUrl, siteUrl))
63
- .flatMap((page) => rules.flatMap((rule) => rule.check({ siteUrl, page, lang })));
64
- const findings = applyRegion(observed, region);
65
- return {
81
+ throwIfAborted(options.signal);
82
+ const assessments = snapshots.map((page, index) => assessPage(page, rules, siteUrl, lang, index === 0, options.consentCheck !== false));
83
+ const partial = assessments.some((assessment) => assessment.evaluations.some((evaluation) => evaluation.partial || evaluation.reason === 'consent-disabled')) || snapshots.some((page) => !page.capture?.complete);
84
+ const result = {
66
85
  siteUrl: siteUrl.href,
67
86
  lang,
68
87
  region,
69
88
  scannedAt: new Date(startedAt).toISOString(),
70
89
  durationMs: Date.now() - startedAt,
71
- pages: snapshots.map((page) => ({
90
+ pages: snapshots.map((page, index) => ({
72
91
  url: page.url,
73
92
  finalUrl: page.finalUrl,
74
93
  status: page.status,
75
- requestCount: page.requests.length,
94
+ requestCount: page.requestCount ?? page.requests.length,
76
95
  cookieCount: page.cookies.length,
77
96
  ...(page.error === undefined ? {} : { error: page.error }),
97
+ ...(page.capture === undefined ? {} : { capture: page.capture }),
98
+ ruleEvaluations: assessments[index]?.evaluations ?? [],
78
99
  })),
79
100
  ...consentSummary(snapshots[0]),
80
- findings,
101
+ findings: applyRegion(assessments.flatMap((assessment) => assessment.findings), region),
81
102
  rules: rules.map(({ check: _check, ...meta }) => meta),
103
+ coverage: partial ? 'partial' : 'complete',
82
104
  };
105
+ return options.networkAdapter ? redactReport(result) : result;
83
106
  }
84
107
  finally {
85
108
  await browser.close();
86
109
  }
87
110
  }
88
111
  function consentSummary(start) {
89
- if (start?.consent === undefined) {
112
+ if (start?.consent === undefined)
90
113
  return {};
91
- }
92
114
  const { afterReject: _afterReject, ...summary } = start.consent;
93
115
  return { consent: summary };
94
116
  }
95
- async function capturePage(browser, url, siteUrl, options, checkConsent) {
96
- // A fresh context per page means no cookies or storage carry over:
97
- // every page is seen the way a first-time visitor sees it.
98
- const context = await browser.newContext({ locale: options.locale ?? DEFAULTS.locale });
99
- const requests = [];
100
- try {
101
- if (options.offline) {
102
- await context.route('**/*', (route) => isFirstParty(route.request().url(), siteUrl)
103
- ? route.continue()
104
- : route.fulfill({ status: 200, body: '' }));
105
- }
106
- const page = await context.newPage();
107
- page.on('request', (request) => {
108
- requests.push({ url: request.url(), resourceType: request.resourceType() });
109
- });
110
- const response = await page.goto(url, {
111
- waitUntil: 'load',
112
- timeout: options.timeoutMs ?? DEFAULTS.timeoutMs,
113
- });
114
- await page
115
- .waitForLoadState('networkidle', { timeout: options.timeoutMs ?? DEFAULTS.timeoutMs })
116
- .catch(() => {
117
- // Long-polling or streaming pages never go idle; carry on with what we have.
118
- });
119
- await page.waitForTimeout(options.settleMs ?? DEFAULTS.settleMs);
120
- const links = await page.$$eval('a[href]', (anchors) => anchors.map((a) => ({
121
- href: a.href,
122
- text: [a.textContent, a.getAttribute('aria-label'), a.getAttribute('title')]
123
- .filter(Boolean)
124
- .join(' ')
125
- .replace(/\s+/g, ' ')
126
- .trim()
127
- .slice(0, 200),
128
- })));
129
- const resourceHints = await page.$$eval('link[rel][href]', (elements) => elements.map((link) => ({
130
- rel: (link.getAttribute('rel') ?? '').toLowerCase(),
131
- href: link.href,
132
- })));
133
- const cookies = (await context.cookies()).map(({ name, domain, path, expires }) => ({
134
- name,
135
- domain,
136
- path,
137
- expires,
138
- }));
139
- const snapshot = {
140
- url,
141
- finalUrl: page.url(),
142
- status: response?.status() ?? null,
143
- // Copy: the listener keeps writing to `requests` during the consent check.
144
- requests: [...requests],
145
- cookies,
146
- links,
147
- resourceHints,
148
- };
149
- if (checkConsent && options.consentCheck !== false) {
150
- snapshot.consent = await observeConsent(page, context, requests, {
151
- settleMs: options.settleMs ?? DEFAULTS.settleMs,
152
- timeoutMs: options.timeoutMs ?? DEFAULTS.timeoutMs,
153
- });
154
- }
155
- return snapshot;
156
- }
157
- catch (error) {
158
- // Downloads, timeouts and crashed pages should not end the whole crawl.
159
- const message = error instanceof Error ? error.message : String(error);
160
- return {
161
- url,
162
- finalUrl: url,
163
- status: null,
164
- requests,
165
- cookies: [],
166
- links: [],
167
- resourceHints: [],
168
- error: message.split('\n')[0] ?? message,
169
- };
170
- }
171
- finally {
172
- await context.close();
173
- }
117
+ /** Adapter reports omit URL credentials, paths, queries and fragments by default. */
118
+ function redactReport(result) {
119
+ const redactText = (text) => text.replace(/https?:\/\/[^\s<>"']+/gi, diagnosticUrl);
120
+ return {
121
+ ...result,
122
+ siteUrl: diagnosticUrl(result.siteUrl),
123
+ ...(result.consent === undefined
124
+ ? {}
125
+ : {
126
+ consent: {
127
+ ...result.consent,
128
+ ...(result.consent.acceptLabel === undefined
129
+ ? {}
130
+ : { acceptLabel: redactText(result.consent.acceptLabel) }),
131
+ ...(result.consent.rejectLabel === undefined
132
+ ? {}
133
+ : { rejectLabel: redactText(result.consent.rejectLabel) }),
134
+ },
135
+ }),
136
+ pages: result.pages.map((page) => ({
137
+ ...page,
138
+ url: diagnosticUrl(page.url),
139
+ finalUrl: diagnosticUrl(page.finalUrl),
140
+ })),
141
+ findings: result.findings.map((finding) => ({
142
+ ...finding,
143
+ pageUrl: diagnosticUrl(finding.pageUrl),
144
+ message: redactText(finding.message),
145
+ evidence: finding.evidence.map(redactText),
146
+ ...(finding.fix === undefined ? {} : { fix: redactText(finding.fix) }),
147
+ })),
148
+ };
174
149
  }
175
150
  //# sourceMappingURL=scanner.js.map