@socprime/logtotal-sanitizer 0.2.0-beta.2 → 0.2.1-beta.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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkEUNFMCKE_cjs = require('./chunk-EUNFMCKE.cjs');
3
+ var chunkVELXTD3L_cjs = require('./chunk-VELXTD3L.cjs');
4
4
 
5
5
  // src/core/constants.ts
6
6
  var DEFAULT_PREVIEW_BYTES = 256 * 1024;
@@ -200,11 +200,11 @@ function bytesToHex(bytes) {
200
200
  var HEX_PATTERN = /^(?:[0-9a-fA-F]{2})+$/;
201
201
  function generateKey(byteLength = DEFAULT_KEY_BYTES) {
202
202
  if (!Number.isInteger(byteLength) || byteLength < 16) {
203
- throw new chunkEUNFMCKE_cjs.InvalidKeyError(`Key length must be an integer of at least 16 bytes, got ${byteLength}.`);
203
+ throw new chunkVELXTD3L_cjs.InvalidKeyError(`Key length must be an integer of at least 16 bytes, got ${byteLength}.`);
204
204
  }
205
205
  const source = globalThis.crypto;
206
206
  if (typeof source?.getRandomValues !== "function") {
207
- throw new chunkEUNFMCKE_cjs.InvalidKeyError(
207
+ throw new chunkVELXTD3L_cjs.InvalidKeyError(
208
208
  "No secure random source available. Pass an explicit `key` or provide a Web Crypto implementation on globalThis.crypto."
209
209
  );
210
210
  }
@@ -214,10 +214,10 @@ function generateKey(byteLength = DEFAULT_KEY_BYTES) {
214
214
  }
215
215
  function assertKey(key, encoding) {
216
216
  if (key.length === 0) {
217
- throw new chunkEUNFMCKE_cjs.InvalidKeyError("Key must not be empty.");
217
+ throw new chunkVELXTD3L_cjs.InvalidKeyError("Key must not be empty.");
218
218
  }
219
219
  if (encoding === "hex" && !HEX_PATTERN.test(key)) {
220
- throw new chunkEUNFMCKE_cjs.InvalidKeyError(
220
+ throw new chunkVELXTD3L_cjs.InvalidKeyError(
221
221
  'A hex key must contain an even number of hexadecimal characters. Pass `keyEncoding: "utf8"` for a passphrase.'
222
222
  );
223
223
  }
@@ -237,7 +237,7 @@ function normalizePatterns(patterns) {
237
237
  try {
238
238
  new RegExp(source, "u");
239
239
  } catch (cause) {
240
- throw new chunkEUNFMCKE_cjs.InvalidOptionError(
240
+ throw new chunkVELXTD3L_cjs.InvalidOptionError(
241
241
  `alwaysRedact.patterns contains an invalid regular expression: ${String(cause)}`
242
242
  );
243
243
  }
@@ -278,7 +278,7 @@ function compileAnchored(patterns) {
278
278
  try {
279
279
  return new RegExp(`^(?:${combined})$`, "u");
280
280
  } catch (cause) {
281
- throw new chunkEUNFMCKE_cjs.InvalidOptionError(
281
+ throw new chunkVELXTD3L_cjs.InvalidOptionError(
282
282
  `neverRedact.patterns contains an invalid regular expression: ${String(cause)}`
283
283
  );
284
284
  }
@@ -365,13 +365,13 @@ function compileOne(rule, aggressive) {
365
365
  try {
366
366
  fragments.push({
367
367
  regex: new RegExp(pattern, "gu"),
368
- hasValueGroup: chunkEUNFMCKE_cjs.countCapturingGroups(pattern) === 1
368
+ hasValueGroup: chunkVELXTD3L_cjs.countCapturingGroups(pattern) === 1
369
369
  });
370
370
  } catch (cause) {
371
- throw new chunkEUNFMCKE_cjs.InvalidRuleError(`Failed to compile rule "${rule.id}": ${String(cause)}`);
371
+ throw new chunkVELXTD3L_cjs.InvalidRuleError(`Failed to compile rule "${rule.id}": ${String(cause)}`);
372
372
  }
373
373
  }
374
- const gateSource = patterns.map(chunkEUNFMCKE_cjs.deriveGateSource).join("|");
374
+ const gateSource = patterns.map(chunkVELXTD3L_cjs.deriveGateSource).join("|");
375
375
  let gate = null;
376
376
  if (!SKIP_REGEX_GATE.has(rule.id) && gateSource.length > 0 && gateSource !== source) {
377
377
  try {
@@ -431,10 +431,10 @@ function createLineSplitter(options = {}) {
431
431
  const maxLineChars = options.maxLineChars ?? DEFAULT_MAX_LINE_CHARS;
432
432
  const overlapChars = options.overlapChars ?? DEFAULT_LINE_OVERLAP_CHARS;
433
433
  if (maxLineChars < 1) {
434
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("lines.maxLineChars must be at least 1.");
434
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("lines.maxLineChars must be at least 1.");
435
435
  }
436
436
  if (overlapChars < 0 || overlapChars >= maxLineChars) {
437
- throw new chunkEUNFMCKE_cjs.InvalidOptionError(
437
+ throw new chunkVELXTD3L_cjs.InvalidOptionError(
438
438
  `lines.overlapChars must be between 0 and lines.maxLineChars - 1 (${maxLineChars - 1}), got ${overlapChars}.`
439
439
  );
440
440
  }
@@ -461,6 +461,181 @@ function createLineSplitter(options = {}) {
461
461
  return { push, flush };
462
462
  }
463
463
 
464
+ // src/core/jsonKeyMatcher.ts
465
+ var RESOLVE_CACHE_LIMIT = 1e4;
466
+ function normalizeKey2(key) {
467
+ return key.toLowerCase().replace(/[-_.\s]/g, "");
468
+ }
469
+ function shouldPreserveJsonValue(value) {
470
+ return value.length === 0 || value === "-";
471
+ }
472
+ function buildTables(rules) {
473
+ const exact = /* @__PURE__ */ new Map();
474
+ const contains = [];
475
+ for (const rule of rules) {
476
+ for (const key of rule.jsonKeys ?? []) {
477
+ const normalized = normalizeKey2(key);
478
+ if (!exact.has(normalized)) {
479
+ exact.set(normalized, rule);
480
+ }
481
+ }
482
+ for (const fragment of rule.jsonKeyContains ?? []) {
483
+ contains.push({ fragment: normalizeKey2(fragment), rule });
484
+ }
485
+ }
486
+ return { exact, contains };
487
+ }
488
+ function lastSegment(key) {
489
+ const dot = key.lastIndexOf(".");
490
+ return dot === -1 ? key : key.slice(dot + 1);
491
+ }
492
+ function resolveUncached(tables, key, parent) {
493
+ const dot = key.lastIndexOf(".");
494
+ const leaf = normalizeKey2(dot === -1 ? key : key.slice(dot + 1));
495
+ const parentRaw = dot === -1 ? parent : key.slice(0, dot);
496
+ if (leaf.length === 0) {
497
+ return null;
498
+ }
499
+ if (parentRaw !== void 0) {
500
+ const scoped = tables.exact.get(normalizeKey2(lastSegment(parentRaw)) + leaf);
501
+ if (scoped) {
502
+ return scoped;
503
+ }
504
+ }
505
+ const exact = tables.exact.get(leaf);
506
+ if (exact) {
507
+ return exact;
508
+ }
509
+ for (const entry of tables.contains) {
510
+ if (leaf.includes(entry.fragment)) {
511
+ return entry.rule;
512
+ }
513
+ }
514
+ return null;
515
+ }
516
+ function buildMatcher(rules) {
517
+ const tables = buildTables(rules);
518
+ const cache = /* @__PURE__ */ new Map();
519
+ return {
520
+ resolve(key, parent) {
521
+ const cacheKey = parent === void 0 ? key : `${parent}\0${key}`;
522
+ let rule = cache.get(cacheKey);
523
+ if (rule === void 0) {
524
+ rule = resolveUncached(tables, key, parent);
525
+ if (cache.size >= RESOLVE_CACHE_LIMIT) {
526
+ cache.clear();
527
+ }
528
+ cache.set(cacheKey, rule);
529
+ }
530
+ return rule ?? void 0;
531
+ }
532
+ };
533
+ }
534
+ var matcherCache = /* @__PURE__ */ new WeakMap();
535
+ function jsonKeyMatcher(rules) {
536
+ const cached = matcherCache.get(rules);
537
+ if (cached) {
538
+ return cached;
539
+ }
540
+ const matcher = buildMatcher(rules);
541
+ matcherCache.set(rules, matcher);
542
+ return matcher;
543
+ }
544
+
545
+ // src/core/redactKeyValuePairs.ts
546
+ var NUMBER = "(-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?)(?![\\w.:+-])";
547
+ var DOUBLE_QUOTED = new RegExp(
548
+ `(?<![\\\\\\w])"((?:[^"\\\\\\r\\n]|\\\\.){1,128})"\\s*:\\s*(?:"((?:[^"\\\\]|\\\\.)*)"|${NUMBER})`,
549
+ "g"
550
+ );
551
+ var ESCAPED = new RegExp(
552
+ `\\\\"((?:[^"\\\\\\r\\n]|\\\\\\\\){1,128})\\\\"\\s*:\\s*(?:\\\\"((?:\\\\\\\\\\\\"|\\\\\\\\|\\\\[^"\\\\]|[^"\\\\])*)\\\\"|${NUMBER})`,
553
+ "g"
554
+ );
555
+ var SINGLE_QUOTED = new RegExp(
556
+ `(?<![\\\\\\w])'((?:[^'\\\\\\r\\n]|\\\\.){1,128})'\\s*:\\s*(?:'((?:[^'\\\\]|\\\\.)*)'|"((?:[^"\\\\]|\\\\.)*)"|${NUMBER})`,
557
+ "g"
558
+ );
559
+ function decodeJsonString(raw) {
560
+ if (!raw.includes("\\")) {
561
+ return raw;
562
+ }
563
+ try {
564
+ return JSON.parse(`"${raw}"`);
565
+ } catch {
566
+ return raw;
567
+ }
568
+ }
569
+ function decodeEscapedJsonString(raw) {
570
+ return decodeJsonString(decodeJsonString(raw));
571
+ }
572
+ function decodePythonString(raw) {
573
+ return raw.includes("\\") ? raw.replace(/\\(['"\\])/g, "$1") : raw;
574
+ }
575
+ function collect(line, regex, rules, decode, numberQuote, out) {
576
+ const matcher = jsonKeyMatcher(rules);
577
+ regex.lastIndex = 0;
578
+ for (let found = regex.exec(line); found !== null; found = regex.exec(line)) {
579
+ const rawKey = found[1];
580
+ let rawValue;
581
+ let quote = "";
582
+ for (let group = 2; group < found.length; group += 1) {
583
+ if (found[group] !== void 0) {
584
+ rawValue = found[group];
585
+ quote = group === found.length - 1 ? numberQuote : "";
586
+ break;
587
+ }
588
+ }
589
+ if (rawValue === void 0) {
590
+ continue;
591
+ }
592
+ const value = quote === "" ? decode(rawValue) : rawValue;
593
+ if (shouldPreserveJsonValue(value)) {
594
+ continue;
595
+ }
596
+ const rule = matcher.resolve(decode(rawKey));
597
+ if (!rule) {
598
+ continue;
599
+ }
600
+ const end = found.index + found[0].length - (quote === "" ? 1 : 0);
601
+ const valueEnd = quote === "" && regex === ESCAPED ? end - 1 : end;
602
+ out.push({
603
+ keyStart: found.index,
604
+ match: { start: valueEnd - rawValue.length, end: valueEnd, value, rule, quote }
605
+ });
606
+ }
607
+ }
608
+ function findKeyValueMatches(line, rules) {
609
+ const doubleQuoted = line.includes('":') || line.includes('" :');
610
+ const singleQuoted = line.includes("':") || line.includes("' :");
611
+ if (!doubleQuoted && !singleQuoted) {
612
+ return [];
613
+ }
614
+ const candidates = [];
615
+ if (doubleQuoted) {
616
+ collect(line, DOUBLE_QUOTED, rules, decodeJsonString, '"', candidates);
617
+ if (line.includes('\\"')) {
618
+ collect(line, ESCAPED, rules, decodeEscapedJsonString, '\\"', candidates);
619
+ }
620
+ }
621
+ if (singleQuoted) {
622
+ collect(line, SINGLE_QUOTED, rules, decodePythonString, "'", candidates);
623
+ }
624
+ if (candidates.length === 0) {
625
+ return [];
626
+ }
627
+ candidates.sort((left, right) => left.keyStart - right.keyStart);
628
+ const matches = [];
629
+ let floor = 0;
630
+ for (const { keyStart, match } of candidates) {
631
+ if (keyStart >= floor) {
632
+ matches.push(match);
633
+ floor = match.end;
634
+ }
635
+ }
636
+ return matches;
637
+ }
638
+
464
639
  // src/core/redactLine.ts
465
640
  function sliceContext(text, index, length, chars) {
466
641
  return {
@@ -498,7 +673,7 @@ function openCursors(line, compiled) {
498
673
  const cursors = [];
499
674
  for (let ruleIndex = 0; ruleIndex < compiled.length; ruleIndex += 1) {
500
675
  const rule = compiled[ruleIndex];
501
- if (rule.gateChars !== null && !chunkEUNFMCKE_cjs.lineHasAnyChar(line, rule.gateChars)) {
676
+ if (rule.gateChars !== null && !chunkVELXTD3L_cjs.lineHasAnyChar(line, rule.gateChars)) {
502
677
  continue;
503
678
  }
504
679
  if (rule.gate !== null) {
@@ -540,11 +715,21 @@ function pickNext(cursors) {
540
715
  }
541
716
  return best;
542
717
  }
718
+ function blankOut(line, spans) {
719
+ let out = "";
720
+ let cursor = 0;
721
+ for (const span of spans) {
722
+ out += line.slice(cursor, span.start) + " ".repeat(span.end - span.start);
723
+ cursor = span.end;
724
+ }
725
+ return out + line.slice(cursor);
726
+ }
543
727
  function redactLine(line, ctx, options = {}) {
544
728
  const { compiled, rulesById, allow, contextChars } = ctx;
545
729
  const withSegments = options.withSegments ?? false;
546
730
  const withMatches = options.withMatches ?? false;
547
- if (compiled.length === 0) {
731
+ const keyed = ctx.json ? findKeyValueMatches(line, ctx.rules) : [];
732
+ if (compiled.length === 0 && keyed.length === 0) {
548
733
  return {
549
734
  output: line,
550
735
  counts: {},
@@ -552,18 +737,65 @@ function redactLine(line, ctx, options = {}) {
552
737
  segments: withSegments ? { before: [{ text: line, changed: false }], after: [{ text: line, changed: false }] } : void 0
553
738
  };
554
739
  }
555
- const cursors = openCursors(line, compiled);
740
+ const scan = keyed.length === 0 ? line : blankOut(line, keyed);
741
+ const cursors = openCursors(scan, compiled);
556
742
  const counts = {};
557
743
  const matches = [];
558
744
  const before = [];
559
745
  const after = [];
560
746
  let output = "";
561
747
  let cursor = 0;
748
+ let keyedIndex = 0;
562
749
  for (; ; ) {
563
750
  const next = pickNext(cursors);
751
+ const pending = keyed[keyedIndex];
752
+ if (pending !== void 0 && (next === null || pending.start <= next.start)) {
753
+ keyedIndex += 1;
754
+ if (!isAllowed(allow, pending.rule.id, pending.value)) {
755
+ const token = buildReplacement(ctx, pending.rule.id, pending.value);
756
+ const raw = line.slice(pending.start, pending.end);
757
+ if (withSegments) {
758
+ if (pending.start > cursor) {
759
+ const gap = line.slice(cursor, pending.start);
760
+ before.push({ text: gap, changed: false });
761
+ after.push({ text: gap, changed: false });
762
+ }
763
+ before.push({ text: raw, changed: true });
764
+ if (pending.quote) {
765
+ after.push({ text: pending.quote, changed: false });
766
+ }
767
+ after.push({ text: token, changed: true });
768
+ if (pending.quote) {
769
+ after.push({ text: pending.quote, changed: false });
770
+ }
771
+ }
772
+ output += line.slice(cursor, pending.start) + pending.quote + token + pending.quote;
773
+ cursor = pending.end;
774
+ counts[pending.rule.id] = (counts[pending.rule.id] ?? 0) + 1;
775
+ if (withMatches) {
776
+ matches.push({
777
+ ruleId: pending.rule.id,
778
+ original: pending.value,
779
+ replacement: token,
780
+ index: pending.start,
781
+ ...contextChars > 0 ? sliceContext(line, pending.start, raw.length, contextChars) : {}
782
+ });
783
+ }
784
+ }
785
+ for (const candidate of cursors) {
786
+ if (candidate.active && candidate.start < pending.end) {
787
+ advance(candidate, scan, pending.end);
788
+ }
789
+ }
790
+ continue;
791
+ }
564
792
  if (next === null) {
565
793
  break;
566
794
  }
795
+ if (pending !== void 0 && next.start + next.original.length > pending.start) {
796
+ advance(next, scan, next.start + 1);
797
+ continue;
798
+ }
567
799
  const { start, original, ruleId } = next;
568
800
  const spanEnd = start + Math.max(original.length, 1);
569
801
  const rule = rulesById.get(ruleId);
@@ -594,7 +826,7 @@ function redactLine(line, ctx, options = {}) {
594
826
  }
595
827
  for (const candidate of cursors) {
596
828
  if (candidate.active && candidate.start < spanEnd) {
597
- advance(candidate, line, spanEnd);
829
+ advance(candidate, scan, spanEnd);
598
830
  }
599
831
  }
600
832
  }
@@ -618,51 +850,6 @@ function looksLikeJson(line) {
618
850
  const trimmed = line.trim();
619
851
  return trimmed.length > 0 && (trimmed.startsWith("{") || trimmed.startsWith("["));
620
852
  }
621
- function normalizeKey2(key) {
622
- return key.toLowerCase().replace(/[-_]/g, "");
623
- }
624
- function shouldPreserveJsonValue(value) {
625
- return value.length === 0 || value === "-";
626
- }
627
- function buildJsonKeyMatcher(rules) {
628
- const exact = /* @__PURE__ */ new Map();
629
- const contains = [];
630
- for (const rule of rules) {
631
- for (const key of rule.jsonKeys ?? []) {
632
- const normalized = normalizeKey2(key);
633
- if (!exact.has(normalized)) {
634
- exact.set(normalized, rule);
635
- }
636
- }
637
- for (const fragment of rule.jsonKeyContains ?? []) {
638
- contains.push({ fragment: normalizeKey2(fragment), rule });
639
- }
640
- }
641
- return { exact, contains };
642
- }
643
- function resolveJsonKeyRule(matcher, key) {
644
- const normalized = normalizeKey2(key);
645
- const exact = matcher.exact.get(normalized);
646
- if (exact) {
647
- return exact;
648
- }
649
- for (const entry of matcher.contains) {
650
- if (normalized.includes(entry.fragment)) {
651
- return entry.rule;
652
- }
653
- }
654
- return void 0;
655
- }
656
- var jsonKeyMatcherCache = /* @__PURE__ */ new WeakMap();
657
- function jsonKeyMatcher(rules) {
658
- const cached = jsonKeyMatcherCache.get(rules);
659
- if (cached) {
660
- return cached;
661
- }
662
- const matcher = buildJsonKeyMatcher(rules);
663
- jsonKeyMatcherCache.set(rules, matcher);
664
- return matcher;
665
- }
666
853
  function mergeCounts(target, source) {
667
854
  for (const [id, count] of Object.entries(source)) {
668
855
  target[id] = (target[id] ?? 0) + count;
@@ -689,7 +876,27 @@ function highlightReplacements(text) {
689
876
  function jsonStringContent(value) {
690
877
  return JSON.stringify(value).slice(1, -1);
691
878
  }
879
+ function locateJsonNumber(text, value, from = 0) {
880
+ const re = new RegExp(`:\\s*(${escapeRegExp(value)})(?![\\d.eE])`, "g");
881
+ re.lastIndex = from;
882
+ const match = re.exec(text);
883
+ if (match === null) {
884
+ return null;
885
+ }
886
+ return { index: match.index + match[0].length - value.length, length: value.length };
887
+ }
888
+ function locateQuotedJsonValue(text, value, from = 0) {
889
+ const encoded = jsonStringContent(value);
890
+ const quotedAt = text.indexOf(`"${encoded}"`, from);
891
+ if (quotedAt === -1) {
892
+ return null;
893
+ }
894
+ return { index: quotedAt + 1, length: encoded.length };
895
+ }
692
896
  function findOriginal(text, original, from) {
897
+ if (original.number === true) {
898
+ return locateJsonNumber(text, original.value, from);
899
+ }
693
900
  const encoded = jsonStringContent(original.value);
694
901
  if (original.wholeValue) {
695
902
  const quoted = `"${encoded}"`;
@@ -772,31 +979,39 @@ function redactJsonLine(line, ctx, options = {}) {
772
979
  }
773
980
  return { contextBefore: "", contextAfter: "" };
774
981
  };
775
- const redactValue = (value, key) => {
982
+ const redactField = (rule, value, number) => {
983
+ if (isAllowed(ctx.allow, rule.id, value)) {
984
+ return null;
985
+ }
986
+ const replacement = buildReplacement(ctx, rule.id, value);
987
+ counts[rule.id] = (counts[rule.id] ?? 0) + 1;
988
+ if (withSegments) {
989
+ originals.push({ value, wholeValue: true, number });
990
+ }
991
+ if (withMatches) {
992
+ const located = number ? locateJsonNumber(content, value) : locateQuotedJsonValue(content, value);
993
+ matches.push({
994
+ ruleId: rule.id,
995
+ original: value,
996
+ replacement,
997
+ index: located?.index ?? 0,
998
+ ...located && ctx.contextChars > 0 ? sliceContext(content, located.index, located.length, ctx.contextChars) : ctx.contextChars > 0 ? { contextBefore: "", contextAfter: "" } : {}
999
+ });
1000
+ }
1001
+ return replacement;
1002
+ };
1003
+ const redactValue = (value, key, parent) => {
1004
+ if (typeof value === "number") {
1005
+ const fieldRule = key === void 0 || !Number.isFinite(value) ? void 0 : keyMatcher.resolve(key, parent);
1006
+ return fieldRule ? redactField(fieldRule, String(value), true) ?? value : value;
1007
+ }
776
1008
  if (typeof value === "string") {
777
1009
  if (key !== void 0 && shouldPreserveJsonValue(value)) {
778
1010
  return value;
779
1011
  }
780
- const fieldRule = key === void 0 ? void 0 : resolveJsonKeyRule(keyMatcher, key);
1012
+ const fieldRule = key === void 0 ? void 0 : keyMatcher.resolve(key, parent);
781
1013
  if (fieldRule) {
782
- if (isAllowed(ctx.allow, fieldRule.id, value)) {
783
- return value;
784
- }
785
- const replacement = buildReplacement(ctx, fieldRule.id, value);
786
- counts[fieldRule.id] = (counts[fieldRule.id] ?? 0) + 1;
787
- if (withSegments) {
788
- originals.push({ value, wholeValue: true });
789
- }
790
- if (withMatches) {
791
- matches.push({
792
- ruleId: fieldRule.id,
793
- original: value,
794
- replacement,
795
- index: Math.max(content.indexOf(jsonStringContent(value)), 0),
796
- ...contextFor(value)
797
- });
798
- }
799
- return replacement;
1014
+ return redactField(fieldRule, value, false) ?? value;
800
1015
  }
801
1016
  const result = redactLine(value, ctx, { withMatches: collectOriginals });
802
1017
  mergeCounts(counts, result.counts);
@@ -813,12 +1028,12 @@ function redactJsonLine(line, ctx, options = {}) {
813
1028
  return result.output;
814
1029
  }
815
1030
  if (Array.isArray(value)) {
816
- return value.map((item) => redactValue(item));
1031
+ return value.map((item) => redactValue(item, key, parent));
817
1032
  }
818
1033
  if (value !== null && typeof value === "object") {
819
1034
  const out = {};
820
1035
  for (const [entryKey, entryValue] of Object.entries(value)) {
821
- out[entryKey] = redactValue(entryValue, entryKey);
1036
+ out[entryKey] = redactValue(entryValue, entryKey, key);
822
1037
  }
823
1038
  return out;
824
1039
  }
@@ -846,10 +1061,10 @@ function createReportCollector(options = {}) {
846
1061
  const maxPerRule = options.maxReplacementsPerRule;
847
1062
  const limited = maxPerRule !== void 0;
848
1063
  if (previewBytes < 0) {
849
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("report.previewBytes must not be negative.");
1064
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("report.previewBytes must not be negative.");
850
1065
  }
851
1066
  if (limited && (maxPerRule < 0 || !Number.isInteger(maxPerRule))) {
852
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("report.maxReplacementsPerRule must be a non-negative integer.");
1067
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("report.maxReplacementsPerRule must be a non-negative integer.");
853
1068
  }
854
1069
  const counts = {};
855
1070
  const replacements = /* @__PURE__ */ new Map();
@@ -929,15 +1144,15 @@ function createReportCollector(options = {}) {
929
1144
  // src/core/resolveRules.ts
930
1145
  function toRule(selector) {
931
1146
  if (typeof selector === "string") {
932
- const builtin = chunkEUNFMCKE_cjs.getBuiltinRule(selector);
1147
+ const builtin = chunkVELXTD3L_cjs.getBuiltinRule(selector);
933
1148
  if (!builtin) {
934
- throw new chunkEUNFMCKE_cjs.UnknownRuleError(
1149
+ throw new chunkVELXTD3L_cjs.UnknownRuleError(
935
1150
  `Unknown rule "${selector}". Pass a rule object for custom rules, or one of the built-in identifiers.`
936
1151
  );
937
1152
  }
938
1153
  return builtin;
939
1154
  }
940
- return chunkEUNFMCKE_cjs.validateRule(selector);
1155
+ return chunkVELXTD3L_cjs.validateRule(selector);
941
1156
  }
942
1157
  function resolveRules(selectors, extraRules = []) {
943
1158
  const resolved = [];
@@ -975,7 +1190,7 @@ function createSanitizer(options = {}) {
975
1190
  assertKey(key, keyEncoding);
976
1191
  const contextChars = options.report?.contextChars ?? 0;
977
1192
  if (contextChars < 0) {
978
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("report.contextChars must not be negative.");
1193
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("report.contextChars must not be negative.");
979
1194
  }
980
1195
  const selected = resolveWithAlwaysRedact(options);
981
1196
  const ctx = createRuleContext({
@@ -1019,7 +1234,7 @@ function createSanitizer(options = {}) {
1019
1234
  let charsRead = 0;
1020
1235
  const writeLine = async (line) => {
1021
1236
  if (signal?.aborted === true) {
1022
- throw new chunkEUNFMCKE_cjs.SanitizationAbortedError();
1237
+ throw new chunkVELXTD3L_cjs.SanitizationAbortedError();
1023
1238
  }
1024
1239
  await sink.write(processLine(line, ctx, collector));
1025
1240
  };
@@ -1039,13 +1254,13 @@ function createSanitizer(options = {}) {
1039
1254
  return { key, rules, sanitizeText: sanitizeText2, sanitizeStream: sanitizeStream2 };
1040
1255
  }
1041
1256
  function resolveWithAlwaysRedact(options) {
1042
- const selected = resolveRules(options.rules ?? chunkEUNFMCKE_cjs.builtinRuleIds, options.extraRules);
1257
+ const selected = resolveRules(options.rules ?? chunkVELXTD3L_cjs.builtinRuleIds, options.extraRules);
1043
1258
  const alwaysRule = createAlwaysRedactRule(options.alwaysRedact);
1044
1259
  if (!alwaysRule) {
1045
1260
  return selected;
1046
1261
  }
1047
1262
  if (selected.some((rule) => rule.id === alwaysRule.id)) {
1048
- throw new chunkEUNFMCKE_cjs.InvalidOptionError(
1263
+ throw new chunkVELXTD3L_cjs.InvalidOptionError(
1049
1264
  `alwaysRedact.ruleId "${alwaysRule.id}" collides with an active rule. Choose an identifier that is not in use.`
1050
1265
  );
1051
1266
  }
@@ -1238,15 +1453,15 @@ async function snapToNewline(blob, from, probeBytes, maxProbeBytes) {
1238
1453
  }
1239
1454
  async function planLineAlignedRanges(blob, partCount, options = {}) {
1240
1455
  if (!Number.isInteger(partCount) || partCount < 1) {
1241
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("partCount must be an integer >= 1.");
1456
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("partCount must be an integer >= 1.");
1242
1457
  }
1243
1458
  const probeBytes = options.probeBytes ?? DEFAULT_RANGE_PROBE_BYTES;
1244
1459
  const maxProbeBytes = options.maxProbeBytes ?? DEFAULT_RANGE_MAX_PROBE_BYTES;
1245
1460
  if (!Number.isInteger(probeBytes) || probeBytes < 1) {
1246
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("probeBytes must be an integer >= 1.");
1461
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("probeBytes must be an integer >= 1.");
1247
1462
  }
1248
1463
  if (!Number.isInteger(maxProbeBytes) || maxProbeBytes < probeBytes) {
1249
- throw new chunkEUNFMCKE_cjs.InvalidOptionError("maxProbeBytes must be an integer >= probeBytes.");
1464
+ throw new chunkVELXTD3L_cjs.InvalidOptionError("maxProbeBytes must be an integer >= probeBytes.");
1250
1465
  }
1251
1466
  if (blob.size <= 0) {
1252
1467
  return [];
@@ -1308,5 +1523,5 @@ exports.sanitizeText = sanitizeText;
1308
1523
  exports.toCallbackSink = toCallbackSink;
1309
1524
  exports.toNullSink = toNullSink;
1310
1525
  exports.toStringSink = toStringSink;
1311
- //# sourceMappingURL=chunk-XPVOBYVK.cjs.map
1312
- //# sourceMappingURL=chunk-XPVOBYVK.cjs.map
1526
+ //# sourceMappingURL=chunk-ZCWN2P2R.cjs.map
1527
+ //# sourceMappingURL=chunk-ZCWN2P2R.cjs.map