@stll/anonymize-wasm 2.1.0 → 2.2.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.
@@ -3,9 +3,9 @@
3
3
  * Runtime-free constants for the anonymization pipeline.
4
4
  *
5
5
  * This module is the SSR-safe / browser-safe entrypoint:
6
- * importing it must not pull in `@stll/text-search`,
7
- * `@stll/anonymize-wasm`, or any other runtime-bearing
8
- * module. Consumers that only need the static label list,
6
+ * importing it must not pull in `@stll/anonymize-wasm`
7
+ * or any other runtime-bearing module.
8
+ * Consumers that only need the static label list,
9
9
  * detection-source identifiers, or operator names import
10
10
  * from `@stll/anonymize/constants` (or
11
11
  * `@stll/anonymize-wasm/constants`) without paying the
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/constants.ts"],"sourcesContent":["/**\n * Runtime-free constants for the anonymization pipeline.\n *\n * This module is the SSR-safe / browser-safe entrypoint:\n * importing it must not pull in `@stll/text-search`,\n * `@stll/anonymize-wasm`, or any other runtime-bearing\n * module. Consumers that only need the static label list,\n * detection-source identifiers, or operator names import\n * from `@stll/anonymize/constants` (or\n * `@stll/anonymize-wasm/constants`) without paying the\n * wasm / regex-set startup cost.\n *\n * `types.ts` re-exports these for back-compat, so existing\n * `import { DEFAULT_ENTITY_LABELS } from \"@stll/anonymize\"`\n * call sites keep working.\n */\n\n/**\n * Source of a detected entity span.\n * Ordered by detection layer in the pipeline.\n */\nexport const DETECTION_SOURCES = {\n TRIGGER: \"trigger\",\n REGEX: \"regex\",\n DENY_LIST: \"deny-list\",\n LEGAL_FORM: \"legal-form\",\n GAZETTEER: \"gazetteer\",\n COUNTRY: \"country\",\n NER: \"ner\",\n COREFERENCE: \"coreference\",\n} as const;\n\nexport type DetectionSource =\n (typeof DETECTION_SOURCES)[keyof typeof DETECTION_SOURCES];\n\n/**\n * Priority levels for detection sources.\n * Higher = more structurally reliable. Used during\n * overlap resolution so deterministic detectors beat\n * probabilistic ones regardless of raw score.\n */\nexport const DETECTOR_PRIORITY = {\n [DETECTION_SOURCES.GAZETTEER]: 5,\n [DETECTION_SOURCES.TRIGGER]: 4,\n [DETECTION_SOURCES.LEGAL_FORM]: 3,\n [DETECTION_SOURCES.REGEX]: 3,\n [DETECTION_SOURCES.COUNTRY]: 3,\n [DETECTION_SOURCES.DENY_LIST]: 2,\n [DETECTION_SOURCES.COREFERENCE]: 2,\n [DETECTION_SOURCES.NER]: 1,\n} as const satisfies Record<DetectionSource, number>;\n\n/**\n * Anonymization operator types. Each operator defines\n * how a confirmed entity is replaced in the output.\n */\nexport const OPERATOR_TYPES = [\"replace\", \"redact\", \"keep\", \"mask\"] as const;\n\nexport type OperatorType = (typeof OPERATOR_TYPES)[number];\n\nexport const ENTITY_SELECTIONS = {\n DEFAULT: \"default\",\n OPT_IN: \"opt-in\",\n} as const;\n\nexport type EntitySelection =\n (typeof ENTITY_SELECTIONS)[keyof typeof ENTITY_SELECTIONS];\n\nexport type EntityCapability = {\n label: string;\n selection: EntitySelection;\n detectionSources: readonly DetectionSource[];\n};\n\n/**\n * Canonical entity capabilities exposed by the deterministic native pipeline.\n * `selection` describes whether the default package requests the label; opt-in\n * labels have built-in detection rules but must be requested explicitly.\n *\n * These labels are ephemeral: entities are regenerated on\n * every pipeline run and never persisted to the database.\n * Renaming a label here requires no migration.\n */\nexport const ENTITY_CAPABILITIES = [\n {\n label: \"person\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.REGEX,\n DETECTION_SOURCES.DENY_LIST,\n DETECTION_SOURCES.COREFERENCE,\n ],\n },\n {\n label: \"organization\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.DENY_LIST,\n DETECTION_SOURCES.LEGAL_FORM,\n DETECTION_SOURCES.GAZETTEER,\n DETECTION_SOURCES.COREFERENCE,\n ],\n },\n {\n label: \"phone number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"address\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.REGEX,\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.DENY_LIST,\n ],\n },\n {\n label: \"country\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.COUNTRY],\n },\n {\n label: \"email address\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"date\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"date of birth\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"bank account number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"iban\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"tax identification number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"identity card number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"birth number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"national identification number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"social security number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"registration number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"credit card number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"passport number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"crypto\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"monetary amount\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"land parcel\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"misc\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.DENY_LIST],\n },\n {\n label: \"ip address\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"mac address\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"url\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n] as const satisfies readonly EntityCapability[];\n\ntype KnownEntityCapability = (typeof ENTITY_CAPABILITIES)[number];\n\nexport type EntityLabel = KnownEntityCapability[\"label\"];\n\nexport const ENTITY_LABELS: readonly EntityLabel[] = ENTITY_CAPABILITIES.map(\n ({ label }) => label,\n);\n\nconst isDefaultEntityCapability = (\n capability: KnownEntityCapability,\n): capability is Extract<\n KnownEntityCapability,\n { selection: typeof ENTITY_SELECTIONS.DEFAULT }\n> => capability.selection === ENTITY_SELECTIONS.DEFAULT;\n\nexport type DefaultEntityLabel = Extract<\n KnownEntityCapability,\n { selection: typeof ENTITY_SELECTIONS.DEFAULT }\n>[\"label\"];\n\nexport const DEFAULT_ENTITY_LABELS: readonly DefaultEntityLabel[] =\n ENTITY_CAPABILITIES.filter(isDefaultEntityCapability).map(\n ({ label }) => label,\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/constants.ts"],"sourcesContent":["/**\n * Runtime-free constants for the anonymization pipeline.\n *\n * This module is the SSR-safe / browser-safe entrypoint:\n * importing it must not pull in `@stll/anonymize-wasm`\n * or any other runtime-bearing module.\n * Consumers that only need the static label list,\n * detection-source identifiers, or operator names import\n * from `@stll/anonymize/constants` (or\n * `@stll/anonymize-wasm/constants`) without paying the\n * wasm / regex-set startup cost.\n *\n * `types.ts` re-exports these for back-compat, so existing\n * `import { DEFAULT_ENTITY_LABELS } from \"@stll/anonymize\"`\n * call sites keep working.\n */\n\n/**\n * Source of a detected entity span.\n * Ordered by detection layer in the pipeline.\n */\nexport const DETECTION_SOURCES = {\n TRIGGER: \"trigger\",\n REGEX: \"regex\",\n DENY_LIST: \"deny-list\",\n LEGAL_FORM: \"legal-form\",\n GAZETTEER: \"gazetteer\",\n COUNTRY: \"country\",\n NER: \"ner\",\n COREFERENCE: \"coreference\",\n} as const;\n\nexport type DetectionSource =\n (typeof DETECTION_SOURCES)[keyof typeof DETECTION_SOURCES];\n\n/**\n * Priority levels for detection sources.\n * Higher = more structurally reliable. Used during\n * overlap resolution so deterministic detectors beat\n * probabilistic ones regardless of raw score.\n */\nexport const DETECTOR_PRIORITY = {\n [DETECTION_SOURCES.GAZETTEER]: 5,\n [DETECTION_SOURCES.TRIGGER]: 4,\n [DETECTION_SOURCES.LEGAL_FORM]: 3,\n [DETECTION_SOURCES.REGEX]: 3,\n [DETECTION_SOURCES.COUNTRY]: 3,\n [DETECTION_SOURCES.DENY_LIST]: 2,\n [DETECTION_SOURCES.COREFERENCE]: 2,\n [DETECTION_SOURCES.NER]: 1,\n} as const satisfies Record<DetectionSource, number>;\n\n/**\n * Anonymization operator types. Each operator defines\n * how a confirmed entity is replaced in the output.\n */\nexport const OPERATOR_TYPES = [\"replace\", \"redact\", \"keep\", \"mask\"] as const;\n\nexport type OperatorType = (typeof OPERATOR_TYPES)[number];\n\nexport const ENTITY_SELECTIONS = {\n DEFAULT: \"default\",\n OPT_IN: \"opt-in\",\n} as const;\n\nexport type EntitySelection =\n (typeof ENTITY_SELECTIONS)[keyof typeof ENTITY_SELECTIONS];\n\nexport type EntityCapability = {\n label: string;\n selection: EntitySelection;\n detectionSources: readonly DetectionSource[];\n};\n\n/**\n * Canonical entity capabilities exposed by the deterministic native pipeline.\n * `selection` describes whether the default package requests the label; opt-in\n * labels have built-in detection rules but must be requested explicitly.\n *\n * These labels are ephemeral: entities are regenerated on\n * every pipeline run and never persisted to the database.\n * Renaming a label here requires no migration.\n */\nexport const ENTITY_CAPABILITIES = [\n {\n label: \"person\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.REGEX,\n DETECTION_SOURCES.DENY_LIST,\n DETECTION_SOURCES.COREFERENCE,\n ],\n },\n {\n label: \"organization\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.DENY_LIST,\n DETECTION_SOURCES.LEGAL_FORM,\n DETECTION_SOURCES.GAZETTEER,\n DETECTION_SOURCES.COREFERENCE,\n ],\n },\n {\n label: \"phone number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"address\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [\n DETECTION_SOURCES.REGEX,\n DETECTION_SOURCES.TRIGGER,\n DETECTION_SOURCES.DENY_LIST,\n ],\n },\n {\n label: \"country\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.COUNTRY],\n },\n {\n label: \"email address\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"date\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"date of birth\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"bank account number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"iban\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"tax identification number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"identity card number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"birth number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"national identification number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"social security number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"registration number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"credit card number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"passport number\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"crypto\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"monetary amount\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"land parcel\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.TRIGGER],\n },\n {\n label: \"misc\",\n selection: ENTITY_SELECTIONS.DEFAULT,\n detectionSources: [DETECTION_SOURCES.REGEX, DETECTION_SOURCES.DENY_LIST],\n },\n {\n label: \"ip address\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"mac address\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n {\n label: \"url\",\n selection: ENTITY_SELECTIONS.OPT_IN,\n detectionSources: [DETECTION_SOURCES.REGEX],\n },\n] as const satisfies readonly EntityCapability[];\n\ntype KnownEntityCapability = (typeof ENTITY_CAPABILITIES)[number];\n\nexport type EntityLabel = KnownEntityCapability[\"label\"];\n\nexport const ENTITY_LABELS: readonly EntityLabel[] = ENTITY_CAPABILITIES.map(\n ({ label }) => label,\n);\n\nconst isDefaultEntityCapability = (\n capability: KnownEntityCapability,\n): capability is Extract<\n KnownEntityCapability,\n { selection: typeof ENTITY_SELECTIONS.DEFAULT }\n> => capability.selection === ENTITY_SELECTIONS.DEFAULT;\n\nexport type DefaultEntityLabel = Extract<\n KnownEntityCapability,\n { selection: typeof ENTITY_SELECTIONS.DEFAULT }\n>[\"label\"];\n\nexport const DEFAULT_ENTITY_LABELS: readonly DefaultEntityLabel[] =\n ENTITY_CAPABILITIES.filter(isDefaultEntityCapability).map(\n ({ label }) => label,\n );\n"],"mappings":"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"}
@@ -3,9 +3,9 @@
3
3
  * Runtime-free constants for the anonymization pipeline.
4
4
  *
5
5
  * This module is the SSR-safe / browser-safe entrypoint:
6
- * importing it must not pull in `@stll/text-search`,
7
- * `@stll/anonymize-wasm`, or any other runtime-bearing
8
- * module. Consumers that only need the static label list,
6
+ * importing it must not pull in `@stll/anonymize-wasm`
7
+ * or any other runtime-bearing module.
8
+ * Consumers that only need the static label list,
9
9
  * detection-source identifiers, or operator names import
10
10
  * from `@stll/anonymize/constants` (or
11
11
  * `@stll/anonymize-wasm/constants`) without paying the
Binary file
package/dist/wasm.d.mts CHANGED
@@ -442,9 +442,9 @@ type CustomDenyListEntry = {
442
442
  };
443
443
  /**
444
444
  * Caller-supplied regex detector. The pattern is passed
445
- * to the underlying text-search regex engine, so use its
446
- * supported regex syntax. Inline flags such as `(?i)` are
447
- * accepted when supported by that engine.
445
+ * to the native Rust regex engine, so use its supported
446
+ * regex syntax. Inline flags such as `(?i)` are accepted
447
+ * when supported by that engine.
448
448
  */
449
449
  type CustomRegexPattern = {
450
450
  pattern: string;
@@ -466,12 +466,10 @@ type CustomRegexPattern = {
466
466
  type Dictionaries = {
467
467
  /**
468
468
  * First names per language code (e.g., "cs", "de").
469
- * Merged with legacy config names at init time.
470
469
  */
471
470
  firstNames?: Readonly<Record<string, readonly string[]>>;
472
471
  /**
473
472
  * Surnames per language code.
474
- * Merged with legacy config names at init time.
475
473
  */
476
474
  surnames?: Readonly<Record<string, readonly string[]>>;
477
475
  /**
@@ -572,14 +570,6 @@ type PipelineConfig = {
572
570
  * additions (Dutch, Russian, Chinese, Arabic, etc.).
573
571
  */
574
572
  enableCountries?: boolean;
575
- /**
576
- * Reserved for compatibility with the removed TypeScript pipeline.
577
- * The native pipeline rejects `true`; supply deterministic custom rules today
578
- * and use the future caller-detection API for model-produced spans.
579
- *
580
- * @deprecated Native NER is not implemented.
581
- */
582
- enableNer?: boolean;
583
573
  enableConfidenceBoost: boolean;
584
574
  enableCoreference: boolean;
585
575
  enableZoneClassification?: boolean;
package/dist/wasm.mjs CHANGED
@@ -706,12 +706,31 @@ const pipelineConfigKey = (config, gazetteerEntries) => {
706
706
  const gazFingerprint = config.enableGazetteer && gazetteerEntries.length > 0 ? gazetteerEntries.map((entry) => `${entry.id}:${entry.canonical}:${entry.label}:${[...entry.variants].sort().join(",")}`).toSorted().join(";") : "";
707
707
  return `${config.enableDenyList}:${config.enableTriggerPhrases}:${legalFormsEnabled}:${config.enableNameCorpus}:${contentLanguageFingerprint(config)}:${config.nameCorpusLanguages?.toSorted().join(",") ?? ""}:${config.enableRegex}:${config.threshold}:${config.enableConfidenceBoost}:${config.enableHotwordRules === true}:${config.enableCoreference === true}:${config.enableZoneClassification === true}:${config.labels.toSorted().join(",")}:${config.denyListCountries?.toSorted().join(",") ?? ""}:${config.denyListRegions?.toSorted().join(",") ?? ""}:${config.denyListExcludeCategories?.toSorted().join(",") ?? ""}:${customDenyFingerprint}:${customRegexFingerprint}:${config.enableGazetteer}:${gazFingerprint}:${config.enableCountries !== false}`;
708
708
  };
709
- //#endregion
710
- //#region src/native-pipeline.ts
711
709
  const sharedPackageByDictionaries = /* @__PURE__ */ new WeakMap();
712
710
  const sharedPackageWithoutDictionaries = /* @__PURE__ */ new Map();
713
711
  const dictionaryCacheIds = /* @__PURE__ */ new WeakMap();
714
712
  let nextDictionaryCacheId = 0;
713
+ /** Record `key` as most-recently-used in `cache`, evicting the
714
+ * least-recently-used entry first once the cache is at capacity. A `Map`'s
715
+ * insertion order doubles as recency order here: touching an existing key
716
+ * deletes then re-sets it to move it to the end, and eviction drops the
717
+ * first (oldest) key.
718
+ *
719
+ * Evicting a still-in-flight build only drops the cache's reference to its
720
+ * promise; the caller that started the build (and any concurrent caller that
721
+ * already read the promise before eviction) still resolves it correctly via
722
+ * the guarded `sharedCache.get(key) === promise` checks in
723
+ * `getCachedNativePipelinePackage`. A later caller for the same key just
724
+ * misses the dedupe and starts a fresh build — bounded memory takes priority
725
+ * over perfect dedupe under cache pressure. */
726
+ const touchSharedPackageCacheEntry = (cache, key, value) => {
727
+ cache.delete(key);
728
+ if (cache.size >= 32) {
729
+ const oldestKey = cache.keys().next().value;
730
+ if (oldestKey !== void 0) cache.delete(oldestKey);
731
+ }
732
+ cache.set(key, value);
733
+ };
715
734
  const dictionaryCacheKey = (dictionaries) => {
716
735
  if (dictionaries === void 0) return "none";
717
736
  const existing = dictionaryCacheIds.get(dictionaries);
@@ -730,7 +749,7 @@ const sharedPackageCacheFor = (dictionaries) => {
730
749
  };
731
750
  const getNativePipelineCompatibility = (config) => {
732
751
  const unsupportedFeatures = [];
733
- if (config.enableNer) unsupportedFeatures.push("enableNer");
752
+ if ("enableNer" in config && Boolean(config.enableNer)) unsupportedFeatures.push("enableNer");
734
753
  if (unsupportedFeatures.length === 0) return { status: "supported" };
735
754
  return {
736
755
  status: "unsupported",
@@ -749,11 +768,8 @@ const encoder = new TextEncoder();
749
768
  * the separate bundle preferentially, and keeping the (large) dictionaries out
750
769
  * of the config JSON avoids serializing them twice.
751
770
  */
752
- const toAssembleInputs = ({ dictionaries, enableNer = false, ...config }, gazetteerEntries) => ({
753
- pipelineConfigJson: encoder.encode(JSON.stringify({
754
- ...config,
755
- enableNer
756
- })),
771
+ const toAssembleInputs = ({ dictionaries, ...config }, gazetteerEntries) => ({
772
+ pipelineConfigJson: encoder.encode(JSON.stringify(config)),
757
773
  dictionariesJson: dictionaries === void 0 ? void 0 : encoder.encode(JSON.stringify(dictionaries)),
758
774
  gazetteerJson: gazetteerEntries.length === 0 ? void 0 : encoder.encode(JSON.stringify(gazetteerEntries))
759
775
  });
@@ -807,6 +823,7 @@ const getCachedNativePipelinePackage = async ({ binding, config, gazetteerEntrie
807
823
  const sharedCache = sharedPackageCacheFor(scopedConfig.dictionaries);
808
824
  const shared = sharedCache.get(key);
809
825
  if (shared !== void 0) {
826
+ touchSharedPackageCacheEntry(sharedCache, key, shared);
810
827
  const packageBytes = await shared;
811
828
  ctx.nativePipelinePackage = packageBytes;
812
829
  ctx.nativePipelinePackageKey = key;
@@ -822,7 +839,7 @@ const getCachedNativePipelinePackage = async ({ binding, config, gazetteerEntrie
822
839
  compressed
823
840
  });
824
841
  ctx.nativePipelinePackagePromise = promise;
825
- sharedCache.set(key, promise);
842
+ touchSharedPackageCacheEntry(sharedCache, key, promise);
826
843
  let packageBytes;
827
844
  try {
828
845
  packageBytes = await promise;
@@ -856,6 +873,8 @@ const NODE_FS_MODULE = "node:fs/promises";
856
873
  const NATIVE_ASSET_DIR = "native";
857
874
  const DEFAULT_PACKAGE_FILE = "native-pipeline.stlanonpkg";
858
875
  const LANGUAGE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
876
+ const DEFAULT_PIPELINE_CACHE_KEY = "<default>";
877
+ const DEFAULT_PIPELINE_CACHE_MAX_ENTRIES = 32;
859
878
  let bindingPromise;
860
879
  const defaultPipelineCache = /* @__PURE__ */ new Map();
861
880
  /** Instantiate (once) and return the wasm binding. Safe to call repeatedly:
@@ -933,6 +952,26 @@ const loadDefaultPipeline = async (language, options) => {
933
952
  return loadPipeline(defaultPackageUrl(baseLanguage), options);
934
953
  }
935
954
  };
955
+ /** Normalized cache key for {@link defaultPipelineCache}: `undefined` maps to
956
+ * the bundled-default sentinel, everything else goes through the same
957
+ * {@link normalizeLanguage} helper `loadDefaultPipeline`/`defaultPackageUrl`
958
+ * already validate against, so aliases that differ only by case or whitespace
959
+ * (e.g. `"EN"` vs `"en"`) share one cached pipeline instead of each minting
960
+ * their own. */
961
+ const defaultPipelineCacheKey = (language) => language === void 0 ? DEFAULT_PIPELINE_CACHE_KEY : normalizeLanguage(language);
962
+ /** Record `key` as most-recently-used in {@link defaultPipelineCache},
963
+ * evicting the least-recently-used entry first once the cache is at
964
+ * capacity. A `Map`'s insertion order doubles as recency order here: touching
965
+ * an existing key deletes then re-sets it to move it to the end, and
966
+ * eviction drops the first (oldest) key. */
967
+ const touchDefaultPipelineCacheEntry = (key, pipeline) => {
968
+ defaultPipelineCache.delete(key);
969
+ if (defaultPipelineCache.size >= DEFAULT_PIPELINE_CACHE_MAX_ENTRIES) {
970
+ const oldestKey = defaultPipelineCache.keys().next().value;
971
+ if (oldestKey !== void 0) defaultPipelineCache.delete(oldestKey);
972
+ }
973
+ defaultPipelineCache.set(key, pipeline);
974
+ };
936
975
  /** Cached variant of {@link loadDefaultPipeline}: the default pipeline for a
937
976
  * given language is fetched and prepared once, then reused.
938
977
  *
@@ -943,14 +982,22 @@ const loadDefaultPipeline = async (language, options) => {
943
982
  * alive. Injected-binding callers get a fresh pipeline each call. */
944
983
  const getDefaultPipeline = (language, options) => {
945
984
  if (options?.binding) return loadDefaultPipeline(language, options);
946
- const key = language ?? "<default>";
985
+ let key;
986
+ try {
987
+ key = defaultPipelineCacheKey(language);
988
+ } catch (error) {
989
+ return Promise.reject(error);
990
+ }
947
991
  const cached = defaultPipelineCache.get(key);
948
- if (cached !== void 0) return cached;
992
+ if (cached !== void 0) {
993
+ touchDefaultPipelineCacheEntry(key, cached);
994
+ return cached;
995
+ }
949
996
  const pipeline = loadDefaultPipeline(language).catch((error) => {
950
997
  defaultPipelineCache.delete(key);
951
998
  throw error;
952
999
  });
953
- defaultPipelineCache.set(key, pipeline);
1000
+ touchDefaultPipelineCacheEntry(key, pipeline);
954
1001
  return pipeline;
955
1002
  };
956
1003
  const redactDefaultText = async (fullText, operators, language) => (await getDefaultPipeline(language)).redactText(fullText, operators);
package/dist/wasm.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"wasm.mjs","names":["#session","#plan","#prepared","#anonymizer","native_package_version","normalize_for_search","prepare_search_package","redact_text_json","redact_text","redact_text_stream_json","diagnostics_json","diagnostics_stream_json","summary_diagnostics_json","languageScopes","normalizeLanguage","nativePackageVersionWithBinding","normalizeForSearchWithBinding","prepareSearchPackageWithBinding","redactTextWithBinding","redactTextJsonWithBinding","redactTextStreamJsonWithBinding","diagnosticsJsonWithBinding","diagnosticsStreamJsonWithBinding","summaryDiagnosticsJsonWithBinding"],"sources":["../../src/native.ts","../../src/context.ts","../../src/redact.ts","../../src/types.ts","../../src/data/language-scopes.json","../../src/language-scope.ts","../../src/util/language-selection.ts","../../src/pipeline-cache-key.ts","../../src/native-pipeline.ts","../../src/wasm.ts"],"sourcesContent":["import type { NativePreparedSearchConfig } from \"./native-search-config\";\nimport type { OperatorSelection, OperatorType } from \"./types\";\n\nexport type { NativePreparedSearchConfig } from \"./native-search-config\";\n\ntype NativeBindingOperatorConfig = {\n operators?: Record<string, OperatorSelection>;\n redactString?: string;\n};\n\ntype NativeBindingCallerRedactionOptions = {\n requestJson: string;\n operators?: NativeBindingOperatorConfig;\n};\n\ntype NativeBindingSessionCallerRedactionInput = {\n fullText: string;\n requestJson: string;\n};\n\ntype NativeBindingSessionCallerRedactionPlanOptions = {\n inputs: NativeBindingSessionCallerRedactionInput[];\n operators?: NativeBindingOperatorConfig;\n observedAtEpochSeconds?: number;\n};\n\ntype NativeBindingOpenSessionArchiveOptions = {\n archive: Uint8Array;\n key: Uint8Array;\n expectedSessionId: string;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativeDiagnosticsBatchCallback = (diagnosticsJson: string) => void;\nexport type NativeResultEventCallback = (eventJson: string) => void;\n\ntype NativeBindingRedactionEntry = {\n placeholder: string;\n original: string;\n};\n\ntype NativeBindingOperatorEntry = {\n placeholder: string;\n operator: OperatorType;\n};\n\ntype NativeBindingPipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n sourceDetail?: string | null;\n providerId?: string | null;\n detectionId?: string | null;\n};\n\ntype NativeBindingRedactionResult = {\n redactedText: string;\n redactionMap: NativeBindingRedactionEntry[];\n operatorMap: NativeBindingOperatorEntry[];\n entityCount: number;\n};\n\ntype NativeBindingStaticRedactionResult = {\n resolvedEntities: NativeBindingPipelineEntity[];\n redaction: NativeBindingRedactionResult;\n};\n\ntype CanonicalPipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n source_detail?: string | null;\n provider_id?: string | null;\n detection_id?: string | null;\n};\n\ntype CanonicalStaticRedactionResult = {\n resolved_entities: CanonicalPipelineEntity[];\n redaction: {\n redacted_text: string;\n redaction_map: NativeBindingRedactionEntry[];\n operator_map: NativeBindingOperatorEntry[];\n entity_count: number;\n };\n};\n\ntype CanonicalSessionMetadata = {\n session_id: string;\n created_at_epoch_seconds: number | null;\n expires_at_epoch_seconds: number | null;\n mapping_count: number;\n status: NativeSessionStatus;\n};\n\ntype CanonicalSessionDeletionSummary = {\n session_id: string;\n deleted_mapping_count: number;\n};\n\ntype CanonicalSessionRedactionPlanResult = {\n replacements: Array<{\n start: number;\n end: number;\n replacement: string;\n }>;\n entity_count: number;\n caller_entity_count: number;\n};\n\nexport type NativeSessionStatus =\n | \"active\"\n | \"not_yet_active\"\n | \"expired\"\n | \"deleted\";\n\nexport type NativeSessionLifecycle = {\n createdAtEpochSeconds: number;\n expiresAtEpochSeconds?: number;\n};\n\nexport type NativeSessionMetadata = {\n sessionId: string;\n createdAtEpochSeconds: number | null;\n expiresAtEpochSeconds: number | null;\n mappingCount: number;\n status: NativeSessionStatus;\n};\n\nexport type NativeSessionDeletionSummary = {\n sessionId: string;\n deletedMappingCount: number;\n};\n\nexport type NativeSessionRedactionAtOptions = {\n fullText: string;\n observedAtEpochSeconds: number;\n operators?: NativeOperatorConfig;\n};\n\nexport type NativeCreateSessionWithLifecycleOptions = NativeSessionLifecycle & {\n sessionId: string;\n};\n\nexport type NativeOpenSessionArchiveOptions = {\n archive: Uint8Array;\n key: Uint8Array;\n expectedSessionId: string;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativePreparedRedactionSessionBinding = {\n sessionId: () => string;\n mappingCount: () => number;\n restoreText?: (fullText: string) => string;\n restoreTextAt?: (fullText: string, observedAtEpochSeconds: number) => string;\n toPlaintextJson: () => string;\n toPlaintextJsonAt?: (observedAtEpochSeconds: number) => string;\n toEncryptedArchive?: (key: Uint8Array) => Uint8Array;\n toEncryptedArchiveAt?: (\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ) => Uint8Array;\n inspectJson?: (observedAtEpochSeconds?: number) => string;\n deleteJson?: () => string;\n redactStaticEntitiesJson: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesJsonAt?: (\n fullText: string,\n observedAtEpochSeconds: number,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n planStaticEntitiesWithCallerDetections?: (\n options: NativeBindingSessionCallerRedactionPlanOptions,\n ) => NativePreparedSessionRedactionPlanBinding;\n};\n\nexport type NativePreparedSessionRedactionPlanBinding = {\n resultJson: () => string;\n commit: () => void;\n};\n\nexport type NativePreparedSearchBinding = {\n prepareDiagnosticsJson?: () => string;\n warmLazyRegex?: () => void;\n warm_lazy_regex?: () => void;\n warmLazyRegexDiagnosticsJson?: () => string;\n warm_lazy_regex_diagnostics_json?: () => string;\n createRedactionSession?: (\n sessionId: string,\n ) => NativePreparedRedactionSessionBinding;\n createRedactionSessionWithLifecycle?: (\n sessionId: string,\n createdAtEpochSeconds: number,\n expiresAtEpochSeconds?: number,\n ) => NativePreparedRedactionSessionBinding;\n restoreRedactionSession?: (\n plaintextJson: string,\n ) => NativePreparedRedactionSessionBinding;\n restoreEncryptedRedactionSession?: (\n options: NativeBindingOpenSessionArchiveOptions,\n ) => NativePreparedRedactionSessionBinding;\n redactStaticEntities: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => NativeBindingStaticRedactionResult;\n redactStaticEntitiesJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesWithCallerDetectionsJson?: (\n fullText: string,\n options: NativeBindingCallerRedactionOptions,\n ) => string;\n redactStaticEntitiesWithCallerDetectionsDiagnosticsJson?: (\n fullText: string,\n options: NativeBindingCallerRedactionOptions,\n ) => string;\n redactStaticEntitiesResultStreamJson?: (\n fullText: string,\n operators: NativeBindingOperatorConfig | undefined,\n onEvent: NativeResultEventCallback,\n ) => string;\n redactStaticEntitiesDiagnosticsJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesDiagnosticsStreamJson?: (\n fullText: string,\n operators: NativeBindingOperatorConfig | undefined,\n onBatch: NativeDiagnosticsBatchCallback,\n ) => string;\n redactStaticEntitiesSummaryDiagnosticsJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n};\n\nexport type NativeAnonymizeBinding = {\n normalizeForSearch: (text: string) => string;\n nativePackageVersion: () => string;\n NativePreparedSearch: {\n fromConfigJsonBytes: (\n configJson: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromPreparedPackageBytes: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromPreparedPackageBytesWithoutCache?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromTrustedPreparedPackageBytes?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromTrustedPreparedPackageBytesWithoutCache?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n };\n prepareStaticSearchPackageBytes: (configJson: Uint8Array) => Uint8Array;\n prepareStaticSearchCompressedPackageBytes: (\n configJson: Uint8Array,\n ) => Uint8Array;\n // Rust config assembler (replaces the retired TypeScript config-assembly\n // layer). Takes the pipeline config plus out-of-band dictionaries and\n // gazetteer JSON and returns either the assembled config JSON or ready\n // package bytes. Optional so older bindings without the assembler still\n // satisfy the type; native-node loads them from the same `.node`.\n assembleStaticSearchConfigJson?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n assembleStaticSearchPackageBytes?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n assembleStaticSearchCompressedPackageBytes?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n};\n\nexport type NativeOperatorConfig = {\n operators?: Record<string, OperatorSelection>;\n redactString?: string;\n};\n\nexport const CALLER_DETECTION_CONTRACT_VERSION = 2;\n\nexport type NativeCallerDetection = {\n start: number;\n end: number;\n label: string;\n score: number;\n providerId: string;\n detectionId: string;\n};\n\nexport type NativeCallerRedactionOptions = {\n detections: readonly NativeCallerDetection[];\n operators?: NativeOperatorConfig;\n};\n\nexport type NativeSessionCallerRedactionInput = {\n fullText: string;\n detections: readonly NativeCallerDetection[];\n};\n\nexport type NativeSessionCallerRedactionPlanOptions = {\n inputs: readonly NativeSessionCallerRedactionInput[];\n operators?: NativeOperatorConfig;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativeTextReplacement = {\n start: number;\n end: number;\n replacement: string;\n};\n\nexport type NativeSessionBlockRedactionPlan = {\n replacements: readonly NativeTextReplacement[];\n entityCount: number;\n callerEntityCount: number;\n};\n\nconst callerDetectionRequestJson = (\n detections: readonly NativeCallerDetection[],\n): string =>\n JSON.stringify({\n version: CALLER_DETECTION_CONTRACT_VERSION,\n detections: detections.map((detection) => ({\n start: detection.start,\n end: detection.end,\n label: detection.label,\n score: detection.score,\n provider_id: detection.providerId,\n detection_id: detection.detectionId,\n })),\n });\n\nexport type NativePipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n sourceDetail?: string;\n providerId?: string;\n detectionId?: string;\n};\n\nexport type NativeRedactionResult = {\n redactedText: string;\n redactionMap: Map<string, string>;\n operatorMap: Map<string, OperatorType>;\n entityCount: number;\n};\n\nexport type NativeStaticRedactionResult = {\n resolvedEntities: NativePipelineEntity[];\n redaction: NativeRedactionResult;\n};\n\nexport type NativeSearchPackageOptions = {\n binding: NativeAnonymizeBinding;\n config: NativePreparedSearchConfig;\n compressed?: boolean;\n};\n\nexport type NativeSearchPackageInput =\n | NativePreparedSearchConfig\n | string\n | Uint8Array;\n\nexport type SharedNativeSearchPackageOptions = {\n binding: NativeAnonymizeBinding;\n config: NativeSearchPackageInput;\n compressed?: boolean;\n};\n\nexport type SharedNativePreparedPackageOptions = {\n binding: NativeAnonymizeBinding;\n packageBytes: Uint8Array;\n};\n\nexport type SharedNativeRedactTextJsonOptions = {\n binding: NativeAnonymizeBinding;\n config: NativeSearchPackageInput;\n fullText: string;\n operators?: NativeOperatorConfig;\n};\n\nexport type SharedNativeRedactTextOptions = SharedNativeRedactTextJsonOptions;\n\nexport type SharedNativeDiagnosticsJsonOptions =\n SharedNativeRedactTextJsonOptions;\n\nexport type SharedNativeDiagnosticsStreamJsonOptions =\n SharedNativeRedactTextJsonOptions & {\n onBatch: NativeDiagnosticsBatchCallback;\n };\n\nexport type SharedNativeRedactTextStreamJsonOptions =\n SharedNativeRedactTextJsonOptions & {\n onEvent: NativeResultEventCallback;\n };\n\nexport type NativeNormalizeOptions = {\n binding: NativeAnonymizeBinding;\n text: string;\n};\n\nexport type NativeAnonymizerFromConfigOptions = {\n binding: NativeAnonymizeBinding;\n config: NativePreparedSearchConfig;\n};\n\nexport type NativeAnonymizerFromPackageOptions = {\n binding: NativeAnonymizeBinding;\n packageBytes: Uint8Array;\n};\n\nexport type NativePipelineFromPackageOptions =\n NativeAnonymizerFromPackageOptions;\n\nexport type NativeBindingVersionOptions = {\n binding: NativeAnonymizeBinding;\n expectedVersion: string;\n};\n\nexport class PreparedNativeRedactionSession {\n readonly #session: NativePreparedRedactionSessionBinding;\n\n constructor(session: NativePreparedRedactionSessionBinding) {\n this.#session = session;\n }\n\n sessionId(): string {\n return this.#session.sessionId();\n }\n\n session_id(): string {\n return this.sessionId();\n }\n\n mappingCount(): number {\n return this.#session.mappingCount();\n }\n\n mapping_count(): number {\n return this.mappingCount();\n }\n\n restoreText(fullText: string, observedAtEpochSeconds?: number): string {\n if (observedAtEpochSeconds === undefined) {\n const restore = this.#session.restoreText;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support session restoration\",\n );\n }\n return restore.call(this.#session, fullText);\n }\n const restore = this.#session.restoreTextAt;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support session restoration lifecycle controls\",\n );\n }\n return restore.call(this.#session, fullText, observedAtEpochSeconds);\n }\n\n restore_text(fullText: string, observedAtEpochSeconds?: number): string {\n return this.restoreText(fullText, observedAtEpochSeconds);\n }\n\n toPlaintextJson(): string {\n return this.#session.toPlaintextJson();\n }\n\n to_plaintext_json(): string {\n return this.toPlaintextJson();\n }\n\n toPlaintextJsonAt(observedAtEpochSeconds: number): string {\n const serialize = this.#session.toPlaintextJsonAt;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return serialize.call(this.#session, observedAtEpochSeconds);\n }\n\n to_plaintext_json_at(observedAtEpochSeconds: number): string {\n return this.toPlaintextJsonAt(observedAtEpochSeconds);\n }\n\n toEncryptedArchive(key: Uint8Array): Uint8Array {\n const serialize = this.#session.toEncryptedArchive;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return serialize.call(this.#session, key);\n }\n\n to_encrypted_archive(key: Uint8Array): Uint8Array {\n return this.toEncryptedArchive(key);\n }\n\n toEncryptedArchiveAt(\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ): Uint8Array {\n const serialize = this.#session.toEncryptedArchiveAt;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return serialize.call(this.#session, key, observedAtEpochSeconds);\n }\n\n to_encrypted_archive_at(\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ): Uint8Array {\n return this.toEncryptedArchiveAt(key, observedAtEpochSeconds);\n }\n\n inspect(observedAtEpochSeconds?: number): NativeSessionMetadata {\n const inspect = this.#session.inspectJson;\n if (!inspect) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n const metadata: CanonicalSessionMetadata = JSON.parse(\n inspect.call(this.#session, observedAtEpochSeconds),\n );\n return {\n sessionId: metadata.session_id,\n createdAtEpochSeconds: metadata.created_at_epoch_seconds,\n expiresAtEpochSeconds: metadata.expires_at_epoch_seconds,\n mappingCount: metadata.mapping_count,\n status: metadata.status,\n };\n }\n\n delete(): NativeSessionDeletionSummary {\n const deleteSession = this.#session.deleteJson;\n if (!deleteSession) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n const summary: CanonicalSessionDeletionSummary = JSON.parse(\n deleteSession.call(this.#session),\n );\n return {\n sessionId: summary.session_id,\n deletedMappingCount: summary.deleted_mapping_count,\n };\n }\n\n redactStaticEntities(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.redact_text_json(fullText, operators),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redactText(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntities(fullText, operators);\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactText(fullText, operators);\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n return this.#session.redactStaticEntitiesJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n redactStaticEntitiesAt(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.redactTextJsonAt(options),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redactTextAt(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesAt(options);\n }\n\n redact_text_at(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactTextAt(options);\n }\n\n redact_static_entities_at(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesAt(options);\n }\n\n redactTextJsonAt({\n fullText,\n observedAtEpochSeconds,\n operators,\n }: NativeSessionRedactionAtOptions): string {\n const redact = this.#session.redactStaticEntitiesJsonAt;\n if (!redact) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return redact.call(\n this.#session,\n fullText,\n observedAtEpochSeconds,\n toBindingOperatorConfig(operators),\n );\n }\n\n redact_text_json_at(options: NativeSessionRedactionAtOptions): string {\n return this.redactTextJsonAt(options);\n }\n\n planTextBatchWithCallerDetections({\n inputs,\n operators,\n observedAtEpochSeconds,\n }: NativeSessionCallerRedactionPlanOptions): PreparedNativeSessionRedactionPlan {\n const plan = this.#session.planStaticEntitiesWithCallerDetections;\n if (!plan) {\n throw new Error(\n \"Native anonymize binding does not support transactional caller-detection session plans\",\n );\n }\n const bindingOperators = toBindingOperatorConfig(operators);\n const bindingPlan = plan.call(this.#session, {\n inputs: inputs.map(({ detections, fullText }) => ({\n fullText,\n requestJson: callerDetectionRequestJson(detections),\n })),\n ...(bindingOperators === undefined\n ? {}\n : { operators: bindingOperators }),\n ...(observedAtEpochSeconds === undefined\n ? {}\n : { observedAtEpochSeconds }),\n });\n return new PreparedNativeSessionRedactionPlan(bindingPlan);\n }\n}\n\nexport class PreparedNativeSessionRedactionPlan {\n readonly blocks: readonly NativeSessionBlockRedactionPlan[];\n readonly #plan: NativePreparedSessionRedactionPlanBinding;\n\n constructor(plan: NativePreparedSessionRedactionPlanBinding) {\n this.#plan = plan;\n const blocks: CanonicalSessionRedactionPlanResult[] = JSON.parse(\n plan.resultJson(),\n );\n this.blocks = blocks.map(\n ({ caller_entity_count, entity_count, replacements }) => ({\n replacements,\n entityCount: entity_count,\n callerEntityCount: caller_entity_count,\n }),\n );\n }\n\n commit(): void {\n this.#plan.commit();\n }\n}\n\nexport class PreparedNativeAnonymizer {\n readonly #prepared: NativePreparedSearchBinding;\n\n constructor(prepared: NativePreparedSearchBinding) {\n this.#prepared = prepared;\n }\n\n prepareDiagnosticsJson(): string | null {\n return this.#prepared.prepareDiagnosticsJson?.() ?? null;\n }\n\n prepare_diagnostics_json(): string | null {\n return this.prepareDiagnosticsJson();\n }\n\n warmLazyRegex(): void {\n if (this.#prepared.warmLazyRegex) {\n this.#prepared.warmLazyRegex();\n return;\n }\n this.#prepared.warm_lazy_regex?.();\n }\n\n warm_lazy_regex(): void {\n this.warmLazyRegex();\n }\n\n warmLazyRegexDiagnosticsJson(): string | null {\n if (this.#prepared.warmLazyRegexDiagnosticsJson) {\n return this.#prepared.warmLazyRegexDiagnosticsJson();\n }\n return this.#prepared.warm_lazy_regex_diagnostics_json?.() ?? null;\n }\n\n warm_lazy_regex_diagnostics_json(): string | null {\n return this.warmLazyRegexDiagnosticsJson();\n }\n\n createRedactionSession(sessionId: string): PreparedNativeRedactionSession {\n const create = this.#prepared.createRedactionSession;\n if (!create) {\n throw new Error(\n \"Native anonymize binding does not support redaction sessions\",\n );\n }\n return new PreparedNativeRedactionSession(\n create.call(this.#prepared, sessionId),\n );\n }\n\n create_redaction_session(sessionId: string): PreparedNativeRedactionSession {\n return this.createRedactionSession(sessionId);\n }\n\n createRedactionSessionWithLifecycle({\n sessionId,\n createdAtEpochSeconds,\n expiresAtEpochSeconds,\n }: NativeCreateSessionWithLifecycleOptions): PreparedNativeRedactionSession {\n const create = this.#prepared.createRedactionSessionWithLifecycle;\n if (!create) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return new PreparedNativeRedactionSession(\n create.call(\n this.#prepared,\n sessionId,\n createdAtEpochSeconds,\n expiresAtEpochSeconds,\n ),\n );\n }\n\n create_redaction_session_with_lifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.createRedactionSessionWithLifecycle(options);\n }\n\n restoreRedactionSession(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n const restore = this.#prepared.restoreRedactionSession;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support redaction sessions\",\n );\n }\n return new PreparedNativeRedactionSession(\n restore.call(this.#prepared, plaintextJson),\n );\n }\n\n restore_redaction_session(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.restoreRedactionSession(plaintextJson);\n }\n\n restoreEncryptedRedactionSession({\n archive,\n key,\n expectedSessionId,\n observedAtEpochSeconds,\n }: NativeOpenSessionArchiveOptions): PreparedNativeRedactionSession {\n const restore = this.#prepared.restoreEncryptedRedactionSession;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return new PreparedNativeRedactionSession(\n restore.call(this.#prepared, {\n archive,\n key,\n expectedSessionId,\n ...(observedAtEpochSeconds === undefined\n ? {}\n : { observedAtEpochSeconds }),\n }),\n );\n }\n\n restore_encrypted_redaction_session(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.restoreEncryptedRedactionSession(options);\n }\n\n redactStaticEntities(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return toNativeStaticRedactionResult(\n this.#prepared.redactStaticEntities(\n fullText,\n toBindingOperatorConfig(operators),\n ),\n );\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntities(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n const bindingOperators = toBindingOperatorConfig(operators);\n if (this.#prepared.redactStaticEntitiesJson) {\n return this.#prepared.redactStaticEntitiesJson(\n fullText,\n bindingOperators,\n );\n }\n return JSON.stringify(\n toBindingStaticRedactionResult(\n toNativeStaticRedactionResult(\n this.#prepared.redactStaticEntities(fullText, bindingOperators),\n ),\n ),\n );\n }\n\n redactStaticEntitiesWithCallerDetections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n if (!this.#prepared.redactStaticEntitiesWithCallerDetectionsJson) {\n throw new Error(\n \"Native anonymize binding does not support caller detections\",\n );\n }\n const requestJson = callerDetectionRequestJson(options.detections);\n const operators = toBindingOperatorConfig(options.operators);\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.#prepared.redactStaticEntitiesWithCallerDetectionsJson(fullText, {\n requestJson,\n ...(operators ? { operators } : {}),\n }),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redact_text_with_caller_detections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesWithCallerDetections(fullText, options);\n }\n\n redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n const redact =\n this.#prepared.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson;\n if (!redact) {\n return null;\n }\n const requestJson = callerDetectionRequestJson(options.detections);\n const operators = toBindingOperatorConfig(options.operators);\n return redact.call(this.#prepared, fullText, {\n requestJson,\n ...(operators ? { operators } : {}),\n });\n }\n\n redact_static_entities_with_caller_detections_diagnostics_json(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redactTextStreamJson(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesResultStreamJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesResultStreamJson(\n fullText,\n toBindingOperatorConfig(operators),\n onEvent,\n );\n }\n\n redact_text_stream_json(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redactStaticEntitiesDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesDiagnosticsJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesDiagnosticsJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactStaticEntitiesDiagnosticsJson(fullText, operators);\n }\n\n diagnosticsStreamJson(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesDiagnosticsStreamJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesDiagnosticsStreamJson(\n fullText,\n toBindingOperatorConfig(operators),\n onBatch,\n );\n }\n\n diagnostics_stream_json(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n redactStaticEntitiesSummaryDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesSummaryDiagnosticsJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesSummaryDiagnosticsJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n summary_diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactStaticEntitiesSummaryDiagnosticsJson(fullText, operators);\n }\n}\n\nexport class PreparedNativePipeline {\n readonly #anonymizer: PreparedNativeAnonymizer;\n\n constructor(anonymizer: PreparedNativeAnonymizer) {\n this.#anonymizer = anonymizer;\n }\n\n prepareDiagnosticsJson(): string | null {\n return this.#anonymizer.prepareDiagnosticsJson();\n }\n\n prepare_diagnostics_json(): string | null {\n return this.prepareDiagnosticsJson();\n }\n\n warmLazyRegex(): void {\n this.#anonymizer.warmLazyRegex();\n }\n\n warm_lazy_regex(): void {\n this.warmLazyRegex();\n }\n\n warmLazyRegexDiagnosticsJson(): string | null {\n return this.#anonymizer.warmLazyRegexDiagnosticsJson();\n }\n\n warm_lazy_regex_diagnostics_json(): string | null {\n return this.warmLazyRegexDiagnosticsJson();\n }\n\n createRedactionSession(sessionId: string): PreparedNativeRedactionSession {\n return this.#anonymizer.createRedactionSession(sessionId);\n }\n\n create_redaction_session(sessionId: string): PreparedNativeRedactionSession {\n return this.createRedactionSession(sessionId);\n }\n\n createRedactionSessionWithLifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.createRedactionSessionWithLifecycle(options);\n }\n\n create_redaction_session_with_lifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.createRedactionSessionWithLifecycle(options);\n }\n\n restoreRedactionSession(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.restoreRedactionSession(plaintextJson);\n }\n\n restore_redaction_session(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.restoreRedactionSession(plaintextJson);\n }\n\n restoreEncryptedRedactionSession(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.restoreEncryptedRedactionSession(options);\n }\n\n restore_encrypted_redaction_session(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.restoreEncryptedRedactionSession(options);\n }\n\n redactText(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.#anonymizer.redactStaticEntities(fullText, operators);\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactText(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n return this.#anonymizer.redact_text_json(fullText, operators);\n }\n\n redactTextWithCallerDetections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.#anonymizer.redactStaticEntitiesWithCallerDetections(\n fullText,\n options,\n );\n }\n\n redact_text_with_caller_detections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.redactTextWithCallerDetections(fullText, options);\n }\n\n redactTextWithCallerDetectionsDiagnosticsJson(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redact_text_with_caller_detections_diagnostics_json(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.redactTextWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redactTextStreamJson(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redact_text_stream_json(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redactTextDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesDiagnosticsJson(\n fullText,\n operators,\n );\n }\n\n diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextDiagnosticsJson(fullText, operators);\n }\n\n diagnosticsStreamJson(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n diagnostics_stream_json(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n redactTextSummaryDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesSummaryDiagnosticsJson(\n fullText,\n operators,\n );\n }\n\n summary_diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextSummaryDiagnosticsJson(fullText, operators);\n }\n}\n\nexport const encodeNativeSearchConfig = (\n config: NativePreparedSearchConfig,\n): Uint8Array => new TextEncoder().encode(JSON.stringify(config));\n\nexport const encodeNativeSearchConfigInput = (\n config: NativeSearchPackageInput,\n): Uint8Array => {\n if (typeof config === \"string\") {\n return new TextEncoder().encode(config);\n }\n if (config instanceof Uint8Array) {\n return config;\n }\n return encodeNativeSearchConfig(config);\n};\n\nexport const getNativeBindingVersion = (\n binding: NativeAnonymizeBinding,\n): string => binding.nativePackageVersion();\n\nexport const native_package_version = getNativeBindingVersion;\n\nexport const normalize_for_search = ({\n binding,\n text,\n}: NativeNormalizeOptions): string => binding.normalizeForSearch(text);\n\nexport const assertNativeBindingVersion = ({\n binding,\n expectedVersion,\n}: NativeBindingVersionOptions): void => {\n const actualVersion = getNativeBindingVersion(binding);\n if (actualVersion !== expectedVersion) {\n throw new Error(\n `Native anonymize binding version ${actualVersion} does not match ${expectedVersion}`,\n );\n }\n};\n\nexport const prepareNativeSearchPackage = ({\n binding,\n config,\n compressed = false,\n}: NativeSearchPackageOptions): Uint8Array => {\n const configBytes = encodeNativeSearchConfig(config);\n return compressed\n ? binding.prepareStaticSearchCompressedPackageBytes(configBytes)\n : binding.prepareStaticSearchPackageBytes(configBytes);\n};\n\nexport const prepare_search_package = ({\n binding,\n config,\n compressed = false,\n}: SharedNativeSearchPackageOptions): Uint8Array => {\n const configBytes = encodeNativeSearchConfigInput(config);\n return compressed\n ? binding.prepareStaticSearchCompressedPackageBytes(configBytes)\n : binding.prepareStaticSearchPackageBytes(configBytes);\n};\n\nexport const createNativeAnonymizerFromConfig = ({\n binding,\n config,\n}: NativeAnonymizerFromConfigOptions): PreparedNativeAnonymizer =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfig(config),\n ),\n );\n\nexport const createNativeAnonymizerFromPackage = ({\n binding,\n packageBytes,\n}: NativeAnonymizerFromPackageOptions): PreparedNativeAnonymizer =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromPreparedPackageBytes(packageBytes),\n );\n\nexport const load_prepared_package = ({\n binding,\n packageBytes,\n}: SharedNativePreparedPackageOptions): PreparedNativeAnonymizer =>\n createNativeAnonymizerFromPackage({ binding, packageBytes });\n\nexport const redact_text_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeRedactTextJsonOptions): string =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text_json(fullText, operators);\n\nexport const redact_text = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeRedactTextOptions): NativeStaticRedactionResult =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text(fullText, operators);\n\nexport const redact_text_stream_json = ({\n binding,\n config,\n fullText,\n operators,\n onEvent,\n}: SharedNativeRedactTextStreamJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text_stream_json(fullText, onEvent, operators);\n\nexport const diagnostics_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeDiagnosticsJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).diagnostics_json(fullText, operators);\n\nexport const diagnostics_stream_json = ({\n binding,\n config,\n fullText,\n operators,\n onBatch,\n}: SharedNativeDiagnosticsStreamJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).diagnostics_stream_json(fullText, onBatch, operators);\n\nexport const summary_diagnostics_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeDiagnosticsJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).summary_diagnostics_json(fullText, operators);\n\nexport const createNativePipelineFromPackage = ({\n binding,\n packageBytes,\n}: NativePipelineFromPackageOptions): PreparedNativePipeline =>\n new PreparedNativePipeline(\n createNativeAnonymizerFromPackage({ binding, packageBytes }),\n );\n\nexport const PreparedSearch = PreparedNativeAnonymizer;\nexport type PreparedSearch = PreparedNativeAnonymizer;\nexport const PreparedAnonymizer = PreparedNativeAnonymizer;\nexport type PreparedAnonymizer = PreparedNativeAnonymizer;\n\nconst toBindingOperatorConfig = (\n config: NativeOperatorConfig | undefined,\n): NativeBindingOperatorConfig | undefined => {\n if (!config) {\n return undefined;\n }\n const bindingConfig: NativeBindingOperatorConfig = {};\n if (config.operators !== undefined) {\n bindingConfig.operators = config.operators;\n }\n if (config.redactString !== undefined) {\n bindingConfig.redactString = config.redactString;\n }\n return bindingConfig;\n};\n\nconst toNativeStaticRedactionResult = (\n result: NativeBindingStaticRedactionResult,\n): NativeStaticRedactionResult => ({\n resolvedEntities: result.resolvedEntities.map(toNativePipelineEntity),\n redaction: toNativeRedactionResult(result.redaction),\n});\n\nconst fromCanonicalStaticRedactionResult = (\n result: CanonicalStaticRedactionResult,\n): NativeStaticRedactionResult => ({\n resolvedEntities: result.resolved_entities.map(\n ({ source_detail, provider_id, detection_id, ...entity }) => ({\n ...entity,\n ...(source_detail ? { sourceDetail: source_detail } : {}),\n ...(provider_id ? { providerId: provider_id } : {}),\n ...(detection_id ? { detectionId: detection_id } : {}),\n }),\n ),\n redaction: {\n redactedText: result.redaction.redacted_text,\n redactionMap: toRedactionMap(result.redaction.redaction_map),\n operatorMap: toOperatorMap(result.redaction.operator_map),\n entityCount: result.redaction.entity_count,\n },\n});\n\nconst toBindingStaticRedactionResult = (\n result: NativeStaticRedactionResult,\n): CanonicalStaticRedactionResult => ({\n resolved_entities: result.resolvedEntities.map(toBindingPipelineEntity),\n redaction: {\n redacted_text: result.redaction.redactedText,\n redaction_map: [...result.redaction.redactionMap.entries()].map(\n ([placeholder, original]) => ({ placeholder, original }),\n ),\n operator_map: [...result.redaction.operatorMap.entries()].map(\n ([placeholder, operator]) => ({ placeholder, operator }),\n ),\n entity_count: result.redaction.entityCount,\n },\n});\n\nconst toNativePipelineEntity = (\n entity: NativeBindingPipelineEntity,\n): NativePipelineEntity => ({\n start: entity.start,\n end: entity.end,\n label: entity.label,\n text: entity.text,\n score: entity.score,\n source: entity.source,\n ...(entity.sourceDetail ? { sourceDetail: entity.sourceDetail } : {}),\n ...(entity.providerId ? { providerId: entity.providerId } : {}),\n ...(entity.detectionId ? { detectionId: entity.detectionId } : {}),\n});\n\nconst toBindingPipelineEntity = ({\n sourceDetail,\n providerId,\n detectionId,\n ...entity\n}: NativePipelineEntity): CanonicalPipelineEntity => ({\n ...entity,\n source_detail: sourceDetail ?? null,\n provider_id: providerId ?? null,\n detection_id: detectionId ?? null,\n});\n\nconst toNativeRedactionResult = (\n result: NativeBindingRedactionResult,\n): NativeRedactionResult => ({\n redactedText: result.redactedText,\n redactionMap: toRedactionMap(result.redactionMap),\n operatorMap: toOperatorMap(result.operatorMap),\n entityCount: result.entityCount,\n});\n\nconst toRedactionMap = (\n entries: readonly NativeBindingRedactionEntry[],\n): Map<string, string> => {\n const map = new Map<string, string>();\n for (const entry of entries) {\n map.set(entry.placeholder, entry.original);\n }\n return map;\n};\n\nconst toOperatorMap = (\n entries: readonly NativeBindingOperatorEntry[],\n): Map<string, OperatorType> => {\n const map = new Map<string, OperatorType>();\n for (const entry of entries) {\n map.set(entry.placeholder, entry.operator);\n }\n return map;\n};\n","/**\n * Cached state for a single pipeline run (or a sequence of runs sharing the\n * same config). The native pipeline builds its prepared package once and reuses\n * it across calls with the same config; the package bytes and the key/promise\n * that guard concurrent builds live here so callers can share one warmed\n * context.\n */\nexport type PipelineContext = {\n // ── Native prepared-package cache ─────────────\n nativePipelinePackage: Uint8Array | null;\n nativePipelinePackageKey: string;\n nativePipelinePackagePromise: Promise<Uint8Array> | null;\n};\n\n/** Create a fresh, empty pipeline context. */\nexport const createPipelineContext = (): PipelineContext => ({\n nativePipelinePackage: null,\n nativePipelinePackageKey: \"\",\n nativePipelinePackagePromise: null,\n});\n\n/**\n * Module-level default context. Used when callers\n * don't provide an explicit context, preserving full\n * backward compatibility with the existing API.\n */\nexport const defaultContext: PipelineContext = createPipelineContext();\n","import {\n DEFAULT_OPERATOR_CONFIG,\n maskReplacementSpans,\n OPERATOR_REGISTRY,\n operatorType,\n requireMaskSelection,\n resolveOperator,\n} from \"./operators\";\nimport type {\n Entity,\n OperatorConfig,\n OperatorType,\n RedactionResult,\n} from \"./types\";\nimport type { PipelineContext } from \"./context\";\nimport { defaultContext } from \"./context\";\n\nconst WHITESPACE_RE = /\\s+/g;\nconst PHONE_NOISE_RE = /[()\\s-]/g;\nconst ETHEREUM_ADDRESS_RE = /0x[0-9A-Fa-f]{40}/;\nconst BECH32_ADDRESS_RE = /\\bbc1[ac-hj-np-z02-9]{11,71}\\b/i;\nconst BASE58_ADDRESS_RE = /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/;\nconst NHS_NUMBER_CUE_RE = /\\b(?:NHS|National\\s+Health\\s+Service)\\b/i;\nconst PLACEHOLDER_TOKEN_RE = /\\[[^\\s[\\]]+_[1-9]\\d*\\]/g;\nconst PASSPORT_IDENTIFIER_RE =\n /\\b(?:[A-Za-z]{1,2}\\d{6,8}|\\d{2}[A-Za-z]{2}\\d{5}|\\d{7,9})\\b/;\n// Strip all separators the ID detectors accept so the\n// same real-world value canonicalises to one placeholder:\n// - whitespace and `-` for IBAN, NIP, REGON, etc.\n// - `/` for birth numbers (\"900101/1234\") and Czech\n// bank accounts (\"123-4567/0100\").\n// - `.` for credit cards (\"4111.1111.1111.1111\") and\n// other dotted IDs.\nconst ID_SEPARATOR_RE = /[\\s\\-/.]/g;\n\nconst nextPlaceholder = (\n labelKey: string,\n counters: Map<string, number>,\n reservedPlaceholders: ReadonlySet<string>,\n): string => {\n let count = counters.get(labelKey) ?? 0;\n\n while (true) {\n count += 1;\n const placeholder = `[${labelKey}_${count}]`;\n if (reservedPlaceholders.has(placeholder)) continue;\n\n counters.set(labelKey, count);\n return placeholder;\n }\n};\n\nconst collectReservedPlaceholders = (\n reservedText: string,\n): ReadonlySet<string> => new Set(reservedText.match(PLACEHOLDER_TOKEN_RE));\n\nconst normalizeCryptoText = (text: string): string => {\n const trimmed = text.trim();\n\n const ethereumAddress = ETHEREUM_ADDRESS_RE.exec(trimmed)?.[0];\n if (ethereumAddress) {\n return ethereumAddress.toLowerCase();\n }\n\n const bech32Address = BECH32_ADDRESS_RE.exec(trimmed)?.[0];\n if (bech32Address) {\n return bech32Address.toLowerCase();\n }\n\n const base58Address = BASE58_ADDRESS_RE.exec(trimmed)?.[0];\n return base58Address ?? trimmed;\n};\n\nconst normalizePassportText = (text: string): string => {\n const passportIdentifier = PASSPORT_IDENTIFIER_RE.exec(text)?.[0] ?? text;\n return passportIdentifier.replace(ID_SEPARATOR_RE, \"\").toUpperCase();\n};\n\n/**\n * Normalize entity text so that surface-form variations\n * of the same real-world value map to a single canonical\n * key. Lowercased emails, stripped phone formatting, etc.\n */\nconst normalizeEntityText = (label: string, text: string): string => {\n const upper = label.toUpperCase().replace(WHITESPACE_RE, \"_\");\n\n if (upper === \"EMAIL_ADDRESS\" || upper === \"EMAIL\") {\n return text.toLowerCase().trim();\n }\n if (upper === \"PHONE_NUMBER\" || upper === \"PHONE\") {\n return text.replace(PHONE_NOISE_RE, \"\");\n }\n if (upper === \"CRYPTO\") {\n return normalizeCryptoText(text);\n }\n if (\n upper === \"NATIONAL_IDENTIFICATION_NUMBER\" &&\n NHS_NUMBER_CUE_RE.test(text)\n ) {\n return text.replace(/\\D/g, \"\");\n }\n if (\n upper === \"IBAN\" ||\n upper === \"BANK_ACCOUNT_NUMBER\" ||\n upper === \"TAX_IDENTIFICATION_NUMBER\" ||\n upper === \"REGISTRATION_NUMBER\" ||\n upper === \"NATIONAL_IDENTIFICATION_NUMBER\" ||\n upper === \"SOCIAL_SECURITY_NUMBER\" ||\n upper === \"BIRTH_NUMBER\" ||\n upper === \"IDENTITY_CARD_NUMBER\" ||\n upper === \"CREDIT_CARD_NUMBER\"\n ) {\n return text.replace(ID_SEPARATOR_RE, \"\").toUpperCase();\n }\n if (upper === \"PASSPORT_NUMBER\") {\n return normalizePassportText(text);\n }\n if (\n upper === \"PERSON\" ||\n upper === \"ORGANIZATION\" ||\n upper === \"ADDRESS\" ||\n upper === \"LAND_PARCEL\" ||\n upper === \"MISC\"\n ) {\n return text.replace(WHITESPACE_RE, \" \").toLowerCase().trim();\n }\n return text.trim();\n};\n\nconst nonOverlappingEntities = (entities: Entity[]): Entity[] => {\n const result: Entity[] = [];\n let lastEnd = 0;\n for (const entity of entities) {\n if (entity.start < lastEnd) continue;\n result.push(entity);\n lastEnd = entity.end;\n }\n return result;\n};\n\ntype MaskReplacementSpan = {\n start: number;\n end: number;\n replacement: string;\n};\n\nconst removeRedactedMaskOverlaps = (\n replacements: MaskReplacementSpan[],\n redacted: Entity[],\n): MaskReplacementSpan[] => {\n const result: MaskReplacementSpan[] = [];\n let redactedIndex = 0;\n for (const replacement of replacements) {\n while (true) {\n const candidate = redacted.at(redactedIndex);\n if (candidate === undefined || candidate.end > replacement.start) break;\n redactedIndex += 1;\n }\n const redactedEntity = redacted.at(redactedIndex);\n const overlaps =\n redactedEntity !== undefined &&\n redactedEntity.start < replacement.end &&\n replacement.start < redactedEntity.end;\n if (!overlaps) result.push(replacement);\n }\n return result;\n};\n\n/**\n * Build a stable mapping from entity text to numbered\n * placeholders. Same real-world value always maps to the\n * same placeholder (e.g., \"Dr. Muller\" and \"Dr. Muller\"\n * share one person placeholder).\n *\n * Placeholder format: [LABEL_N] where LABEL is uppercase.\n * N is allocated per label and skips tokens already present\n * in reserved text.\n *\n * @param _ctx Unused. Kept for signature compatibility;\n * coref alias links now travel on the entities\n * themselves (`corefSourceText`).\n */\ntype PlaceholderMapOptions = {\n reservedText?: string;\n};\n\nexport const buildPlaceholderMap = (\n entities: Entity[],\n _ctx: PipelineContext = defaultContext,\n { reservedText = \"\" }: PlaceholderMapOptions = {},\n): Map<string, string> => {\n const counters = new Map<string, number>();\n const textLabelToPlaceholder = new Map<string, string>();\n const normalizedToPlaceholder = new Map<string, string>();\n const reservedPlaceholders = collectReservedPlaceholders(reservedText);\n\n const sorted = entities.toSorted((a, b) => a.start - b.start);\n\n for (const entity of sorted) {\n const compositeKey = `${entity.label}\\0${entity.text}`;\n if (textLabelToPlaceholder.has(compositeKey)) {\n continue;\n }\n\n const labelKey = entity.label.toUpperCase().replace(WHITESPACE_RE, \"_\");\n\n // If this entity is a coref alias, unify its key\n // with the source entity's key so both get the same\n // number — in either direction: a backward alias\n // joins the source's existing placeholder, and a\n // forward alias (bare mention before the full form)\n // reserves its placeholder under the source key so\n // the source joins it when numbered later. The link\n // is carried on the entity itself, so it cannot be\n // lost between detection and redaction.\n const sourceText =\n entity.source === \"coreference\" ? entity.corefSourceText : undefined;\n const sourceNormalizedKey =\n sourceText === undefined\n ? undefined\n : `${labelKey}\\0${normalizeEntityText(entity.label, sourceText)}`;\n if (sourceNormalizedKey !== undefined) {\n const sourceExisting = normalizedToPlaceholder.get(sourceNormalizedKey);\n if (sourceExisting) {\n textLabelToPlaceholder.set(compositeKey, sourceExisting);\n continue;\n }\n }\n\n const normalized = normalizeEntityText(entity.label, entity.text);\n const normalizedKey = `${labelKey}\\0${normalized}`;\n const existing = normalizedToPlaceholder.get(normalizedKey);\n if (existing) {\n textLabelToPlaceholder.set(compositeKey, existing);\n if (sourceNormalizedKey !== undefined) {\n normalizedToPlaceholder.set(sourceNormalizedKey, existing);\n }\n continue;\n }\n\n const placeholder = nextPlaceholder(\n labelKey,\n counters,\n reservedPlaceholders,\n );\n textLabelToPlaceholder.set(compositeKey, placeholder);\n normalizedToPlaceholder.set(normalizedKey, placeholder);\n if (sourceNormalizedKey !== undefined) {\n normalizedToPlaceholder.set(sourceNormalizedKey, placeholder);\n }\n }\n\n return textLabelToPlaceholder;\n};\n\n/**\n * Apply redactions to the source text, replacing each\n * confirmed entity span using the configured operator.\n *\n * Co-references are consistent: if the same text appears\n * multiple times, all occurrences get the same placeholder.\n *\n * @param ctx Pipeline context. Must be the same instance\n * passed to `runPipeline` (or `findCoreferenceSpans`)\n * so coreference placeholder links are preserved.\n * Defaults to `defaultContext` for single-tenant usage.\n */\nexport const redactText = (\n fullText: string,\n entities: Entity[],\n config: OperatorConfig = DEFAULT_OPERATOR_CONFIG,\n ctx: PipelineContext = defaultContext,\n): RedactionResult => {\n if (entities.length === 0) {\n return {\n redactedText: fullText,\n redactionMap: new Map(),\n operatorMap: new Map(),\n entityCount: 0,\n };\n }\n\n const placeholderMap = buildPlaceholderMap(entities, ctx, {\n reservedText: fullText,\n });\n\n const sorted = entities.toSorted((a, b) => a.start - b.start);\n\n const kept: Entity[] = [];\n const masked: Entity[] = [];\n const redacted: Entity[] = [];\n for (const entity of sorted) {\n const opType = operatorType(resolveOperator(config, entity.label));\n if (opType === \"keep\") {\n kept.push(entity);\n } else if (opType === \"mask\") {\n masked.push(entity);\n } else {\n redacted.push(entity);\n }\n }\n const selectedKept = nonOverlappingEntities(kept);\n const selectedMasked = nonOverlappingEntities(masked);\n const selectedRedacted = nonOverlappingEntities(redacted);\n\n const maskReplacements: MaskReplacementSpan[] = [];\n for (const entity of selectedMasked) {\n const selection = resolveOperator(config, entity.label);\n const sourceText = fullText.slice(entity.start, entity.end);\n for (const replacement of maskReplacementSpans(\n sourceText,\n requireMaskSelection(selection),\n )) {\n maskReplacements.push({\n start: entity.start + replacement.start,\n end: entity.start + replacement.end,\n replacement: replacement.replacement,\n });\n }\n }\n const visibleMaskReplacements = removeRedactedMaskOverlaps(\n maskReplacements,\n selectedRedacted,\n );\n\n const parts: string[] = [];\n const redactionMap = new Map<string, string>();\n const operatorMap = new Map<string, OperatorType>();\n let cursor = 0;\n\n const placeholderFor = (entity: Entity): string =>\n placeholderMap.get(`${entity.label}\\0${entity.text}`) ??\n `[${entity.label.toUpperCase().replace(/\\s+/g, \"_\")}]`;\n const processed = [\n ...selectedKept,\n ...selectedMasked,\n ...selectedRedacted,\n ].toSorted((a, b) => a.start - b.start);\n for (const entity of processed) {\n operatorMap.set(\n placeholderFor(entity),\n operatorType(resolveOperator(config, entity.label)),\n );\n }\n\n let redactedIndex = 0;\n let maskIndex = 0;\n while (\n redactedIndex < selectedRedacted.length ||\n maskIndex < visibleMaskReplacements.length\n ) {\n const redactedEntity = selectedRedacted.at(redactedIndex);\n const maskReplacement = visibleMaskReplacements.at(maskIndex);\n const useRedacted =\n redactedEntity !== undefined &&\n (maskReplacement === undefined ||\n redactedEntity.start <= maskReplacement.start);\n const start = useRedacted\n ? (redactedEntity?.start ?? cursor)\n : (maskReplacement?.start ?? cursor);\n const end = useRedacted\n ? (redactedEntity?.end ?? start)\n : (maskReplacement?.end ?? start);\n if (start > cursor) parts.push(fullText.slice(cursor, start));\n\n if (!useRedacted && maskReplacement !== undefined) {\n parts.push(maskReplacement.replacement);\n cursor = end;\n maskIndex += 1;\n continue;\n }\n if (redactedEntity === undefined) break;\n\n const entity = redactedEntity;\n const placeholder = placeholderFor(entity);\n\n const selection = resolveOperator(config, entity.label);\n const opType = operatorType(selection);\n const operator = OPERATOR_REGISTRY[opType];\n\n const replacement = operator.apply(\n entity.text,\n entity.label,\n placeholder,\n config.redactString,\n selection,\n );\n\n parts.push(replacement);\n // Only populate redactionMap for reversible operators.\n // A coref alias contributes its source's full text, so\n // a forward alias (\"Acme\" before \"Acme Corporation\")\n // cannot pin the shortened surface form as the key's\n // canonical value for the shared placeholder.\n if (\n operator.reversibility === \"reversible\" &&\n !redactionMap.has(placeholder)\n ) {\n redactionMap.set(\n placeholder,\n entity.source === \"coreference\" ? entity.corefSourceText : entity.text,\n );\n }\n\n cursor = end;\n redactedIndex += 1;\n }\n\n if (cursor < fullText.length) {\n parts.push(fullText.slice(cursor));\n }\n\n return {\n redactedText: parts.join(\"\"),\n redactionMap,\n operatorMap,\n entityCount:\n selectedKept.length + selectedMasked.length + selectedRedacted.length,\n };\n};\n\n/**\n * Serialize the redaction key to JSON for export.\n * Includes operator metadata so the export is self-describing.\n */\nexport const exportRedactionKey = (\n redactionMap: Map<string, string>,\n operatorMap: Map<string, OperatorType>,\n): string => {\n const entries: Record<string, { original: string; operator: OperatorType }> =\n {};\n\n for (const [placeholder, value] of redactionMap) {\n entries[placeholder] = {\n original: value,\n operator: operatorMap.get(placeholder) ?? \"replace\",\n };\n }\n\n return JSON.stringify({ entries }, null, 2);\n};\n\n/**\n * De-anonymise text using a redaction key.\n * Replaces placeholders back with original values.\n * Only works for reversible operators (replace).\n */\nexport const deanonymise = (\n redactedText: string,\n redactionMap: Map<string, string>,\n): string => {\n let result = redactedText;\n\n for (const [placeholder, original] of redactionMap) {\n result = result.replaceAll(placeholder, original);\n }\n\n return result;\n};\n","// Runtime-free constants live in `./constants`; re-exported\n// here for back-compat with existing call sites that import\n// from `@stll/anonymize` directly.\n//\n// `verbatimModuleSyntax` requires an explicit type-only\n// import for any name used locally as a type even when it\n// is also re-exported below — applies to `DetectionSource`\n// (used by `Entity`) and `OperatorType` (used by\n// `OperatorConfig`).\nimport type { DetectionSource, OperatorType } from \"./constants\";\nimport { DETECTION_SOURCES } from \"./constants\";\n\nexport {\n DETECTION_SOURCES,\n DETECTOR_PRIORITY,\n type DetectionSource,\n} from \"./constants\";\n\n/**\n * Fields shared by every entity span in the source text.\n */\ntype EntityBase = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n sourceDetail?: \"custom-deny-list\" | \"custom-regex\" | \"gazetteer-extension\";\n};\n\n/**\n * A PII entity span found by a primary detection layer\n * (regex, NER, legal forms, deny list, ...).\n */\nexport type DetectedEntity = EntityBase & {\n source: Exclude<DetectionSource, typeof DETECTION_SOURCES.COREFERENCE>;\n};\n\n/**\n * An alias mention of a previously detected entity: a\n * defined term (\"the Seller\") or a propagated bare\n * mention (\"Acme\" after \"Acme Corp.\").\n *\n * `corefSourceText` is required by construction, so an\n * alias cannot exist without the link back to its source\n * entity. Placeholder numbering reads it to give the\n * alias the same placeholder as the source. The link\n * travels with the entity instead of living in a\n * side-channel map that a producer could forget to\n * write — or that a later pass could clear.\n */\nexport type CorefAliasEntity = EntityBase & {\n source: typeof DETECTION_SOURCES.COREFERENCE;\n /** Full text of the source entity this alias refers to. */\n corefSourceText: string;\n};\n\n/**\n * A detected PII entity span in the source text.\n * Every detection layer produces these.\n */\nexport type Entity = DetectedEntity | CorefAliasEntity;\n\n/**\n * Entity after human review. Extends the base Entity\n * with a review decision.\n */\nexport type ReviewDecision = \"confirmed\" | \"rejected\" | \"relabeled\";\n\nexport type ReviewedEntity = Entity & {\n decision?: ReviewDecision;\n originalLabel?: string;\n};\n\n/**\n * A single entry in the workspace-scoped gazetteer\n * (deny list). Persisted in IndexedDB.\n */\nexport type GazetteerEntry = {\n id: string;\n canonical: string;\n label: string;\n variants: string[];\n workspaceId: string;\n createdAt: number;\n source: \"manual\" | \"confirmed-from-model\";\n};\n\n/** Extraction strategy — closed discriminated union. */\nexport type TriggerStrategy =\n | {\n type: \"to-next-comma\";\n /**\n * Optional list of lowercase keywords that terminate\n * the value scan, in addition to commas/newlines. Useful\n * for triggers like court names that may continue past\n * a missing comma into adjacent clause text (\"Městským\n * soudem v Praze dne 1. 1. 2020\"); listing `\"dne\"` here\n * stops the scan at the date boundary. Matched on a\n * word-boundary, case-insensitive.\n */\n stopWords?: string[];\n /**\n * Hard cap on the captured span length, in characters,\n * regardless of where the next comma / stop char sits.\n * Use for triggers that label short formulaic phrases\n * (\"State of Delaware\") and must not absorb the rest\n * of a long forum-selection clause when the comma is\n * sentences away. Falls back to the default 100-char\n * fallback when omitted.\n */\n maxLength?: number;\n }\n | { type: \"to-end-of-line\" }\n | { type: \"n-words\"; count: number }\n | { type: \"company-id-value\" }\n | { type: \"address\"; maxChars?: number }\n | {\n /**\n * Extract the first regex match in the value text.\n * Useful for shape-bounded values that follow a\n * label on the same line as other fields, where\n * `to-end-of-line` would over-capture. The pattern\n * is anchored to the start of the (already\n * leading-whitespace-stripped) value, so use\n * `(?:.*?)` prefix only when intentional.\n */\n type: \"match-pattern\";\n pattern: string;\n flags?: string;\n };\n\n/** Validation rules — closed discriminated union. */\nexport type TriggerValidation =\n | { type: \"starts-uppercase\" }\n | { type: \"min-length\"; min: number }\n | { type: \"max-length\"; max: number }\n | { type: \"no-digits\" }\n | { type: \"has-digits\" }\n | {\n type: \"matches-pattern\";\n pattern: string;\n flags?: string;\n }\n /**\n * Run a named stdnum validator (checksum + length)\n * against the captured value. Keeps the trigger\n * path symmetrical with the formatted-regex\n * detectors so e.g. `CPF nº 00000000000` does not\n * survive as a tax-ID entity.\n */\n | { type: \"valid-id\"; validator: ValidIdValidator };\n\n/** Built-in stdnum validators that can be referenced\n * by `valid-id` validations. */\nexport type ValidIdValidator = \"br.cpf\" | \"br.cnpj\" | \"us.rtn\";\n\n/** Auto-generated trigger variants — closed set. */\nexport type TriggerExtension =\n | \"add-colon\"\n | \"add-trailing-space\"\n | \"add-colon-space\"\n | \"normalize-spaces\";\n\n/** V2 trigger config entry (JSON shape). */\nexport type TriggerGroupConfig = {\n id?: string;\n triggers: string[];\n label: string;\n strategy: TriggerStrategy;\n extensions?: TriggerExtension[];\n validations?: TriggerValidation[];\n /** When true, include the trigger text in the\n * entity span (e.g., court names). */\n includeTrigger?: boolean;\n};\n\n/** Compiled validation with pre-built regex. */\nexport type CompiledValidation =\n | { type: \"starts-uppercase\"; re: RegExp }\n | { type: \"min-length\"; min: number }\n | { type: \"max-length\"; max: number }\n | { type: \"no-digits\"; re: RegExp }\n | { type: \"has-digits\"; re: RegExp }\n | { type: \"matches-pattern\"; re: RegExp }\n | {\n type: \"valid-id\";\n validator: ValidIdValidator;\n check: (value: string) => boolean;\n };\n\n/**\n * Runtime rule — one per trigger string after\n * expansion. Fed to the Aho-Corasick automaton.\n */\nexport type TriggerRule = {\n trigger: string;\n label: string;\n strategy: TriggerStrategy;\n validations: CompiledValidation[];\n includeTrigger: boolean;\n};\n\nexport {\n ENTITY_CAPABILITIES,\n ENTITY_LABELS,\n ENTITY_SELECTIONS,\n OPERATOR_TYPES,\n type DefaultEntityLabel,\n type EntityCapability,\n type EntityLabel,\n type EntitySelection,\n type OperatorType,\n} from \"./constants\";\n\n/** Per-label operator selection. Key is the entity label. */\nexport type MaskDirection = \"start\" | \"end\";\n\nexport type MaskOperatorConfig = {\n type: \"mask\";\n maskingCharacter: string;\n charactersToMask: number;\n direction: MaskDirection;\n};\n\nexport type OperatorSelection =\n | Exclude<OperatorType, \"mask\">\n | MaskOperatorConfig;\n\nexport type OperatorConfig = {\n /** Operator per label. Missing labels default to \"replace\". */\n operators: Record<string, OperatorSelection>;\n /** Custom replacement string for the redact operator. */\n redactString: string;\n};\n\n/** Whether an operator produces a reversible redaction entry. */\ntype OperatorReversibility = \"reversible\" | \"irreversible\" | \"preserving\";\n\nexport type AnonymisationOperator = {\n type: OperatorType;\n reversibility: OperatorReversibility;\n /**\n * Apply the operator to a single entity occurrence.\n * Returns the replacement string to embed in the document.\n */\n apply: (\n text: string,\n label: string,\n placeholder: string,\n redactString: string,\n selection: OperatorSelection,\n ) => string;\n};\n\n/**\n * Redacted document output with stable entity mapping.\n */\nexport type RedactionResult = {\n redactedText: string;\n /**\n * Maps placeholder to original text. Only populated for\n * reversible operators (replace). Empty for redact, keep, and mask.\n */\n redactionMap: Map<string, string>;\n /** Maps placeholder to the operator that produced it. */\n operatorMap: Map<string, OperatorType>;\n entityCount: number;\n};\n\n/**\n * Configuration for the detection pipeline.\n */\nexport type DenyListCategory =\n | \"Names\"\n | \"Places\"\n | \"Addresses\"\n | \"Courts\"\n | \"Financial\"\n | \"Government\"\n | \"Healthcare\"\n | \"Education\"\n | \"Political\"\n | \"Organizations\"\n | \"International\";\n\n/**\n * Metadata for a single dictionary entry in the\n * deny-list system. Mirrors the shape from\n * the anonymize-data package so consumers can pass\n * pre-loaded data without a runtime dependency.\n */\nexport type DictionaryMeta = {\n label: string;\n category: DenyListCategory;\n country: string | null;\n};\n\n/**\n * Caller-supplied exact terms for deny-list matching.\n * These entries are merged with the published deny-list\n * dictionaries when `enableDenyList` is enabled.\n */\nexport type CustomDenyListEntry = {\n value: string;\n label: string;\n variants?: readonly string[];\n};\n\n/**\n * Caller-supplied regex detector. The pattern is passed\n * to the underlying text-search regex engine, so use its\n * supported regex syntax. Inline flags such as `(?i)` are\n * accepted when supported by that engine.\n */\nexport type CustomRegexPattern = {\n pattern: string;\n label: string;\n score?: number;\n preparedArtifactPolicy?: \"include\" | \"omit\";\n};\n\n/**\n * Pre-loaded dictionary data for dependency injection.\n * Consumers that want name/city/deny-list detection\n * load dictionaries themselves (e.g. from the\n * anonymize-data package) and pass them here; the\n * anonymize package has zero cross-package imports.\n *\n * All fields are optional. When a field is absent,\n * the corresponding detection path is skipped (same\n * behavior as when no dictionaries are available).\n */\nexport type Dictionaries = {\n /**\n * First names per language code (e.g., \"cs\", \"de\").\n * Merged with legacy config names at init time.\n */\n firstNames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Surnames per language code.\n * Merged with legacy config names at init time.\n */\n surnames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Non-Western name tokens per locale code\n * (e.g., \"in\", \"ar\", \"ja-latn\", \"ko\", \"zh-latn\",\n * \"th\", \"vi\", \"fil\", \"id\"). Merged with bundled\n * names-nw-*.json data at init time.\n */\n nonWesternNames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Pre-loaded deny-list dictionaries keyed by\n * dictionary ID (e.g., \"courts/CZ\", \"banks/DE\").\n * Each value is the array of terms for that\n * dictionary.\n */\n denyList?: Readonly<Record<string, readonly string[]>>;\n /**\n * Metadata per dictionary ID. Required when\n * `denyList` is provided so the pipeline knows\n * labels, categories, and country filters.\n */\n denyListMeta?: Readonly<Record<string, DictionaryMeta>>;\n /**\n * Pre-loaded city names, already merged across\n * all desired countries.\n *\n * Prefer `citiesByCountry` when callers also pass\n * `denyListCountries` / `denyListRegions`; merged\n * city arrays cannot be scoped after injection.\n */\n cities?: readonly string[];\n /**\n * Pre-loaded city names keyed by ISO 3166-1 alpha-2\n * country code. When provided, the deny-list builder\n * applies `denyListCountries` / `denyListRegions`\n * before adding city patterns to the search automaton.\n */\n citiesByCountry?: Readonly<Record<string, readonly string[]>>;\n};\n\nexport type PipelineConfig = {\n threshold: number;\n enableTriggerPhrases: boolean;\n enableRegex: boolean;\n /**\n * Expected content language codes. When present, these\n * derive default dictionary scopes for name corpus and\n * deny-list matching unless the lower-level scope fields\n * below are set explicitly.\n */\n languages?: string[];\n /**\n * Convenience form for single-language documents. Ignored\n * when `languages` is also provided.\n */\n language?: string;\n /**\n * Enables legal-form organization detection.\n * Required for typed callers; legacy untyped\n * callers that omit this field are treated as\n * enabled at runtime for backward compatibility.\n */\n enableLegalForms: boolean;\n /**\n * Enables first-name/surname/title corpus matching.\n * When deny-list mode is enabled, this also controls\n * whether name-corpus entries are injected into the\n * deny-list search automaton.\n */\n enableNameCorpus: boolean;\n /**\n * Optional language scope for first-name/surname\n * dictionaries, using the keys present in\n * `dictionaries.firstNames` / `dictionaries.surnames`\n * (for example `[\"en\", \"de\"]`). When omitted, all\n * injected name languages are used for backward\n * compatibility.\n */\n nameCorpusLanguages?: string[];\n enableDenyList: boolean;\n denyListCountries?: string[];\n denyListRegions?: string[];\n denyListExcludeCategories?: string[];\n /**\n * Caller-owned exact terms to match through the\n * deny-list layer. Requires `enableDenyList: true`.\n */\n customDenyList?: readonly CustomDenyListEntry[];\n /**\n * Caller-owned regex detectors. Requires\n * `enableRegex: true`.\n */\n customRegexes?: readonly CustomRegexPattern[];\n enableGazetteer: boolean;\n /**\n * Detect country names (ISO 3166-1 names, curated\n * aliases, alpha-3 codes). Defaults to true. Names\n * span all manifest languages plus widely-used\n * additions (Dutch, Russian, Chinese, Arabic, etc.).\n */\n enableCountries?: boolean;\n /**\n * Reserved for compatibility with the removed TypeScript pipeline.\n * The native pipeline rejects `true`; supply deterministic custom rules today\n * and use the future caller-detection API for model-produced spans.\n *\n * @deprecated Native NER is not implemented.\n */\n enableNer?: boolean;\n enableConfidenceBoost: boolean;\n enableCoreference: boolean;\n enableZoneClassification?: boolean;\n enableHotwordRules?: boolean;\n /**\n * Requested output labels. An empty array means\n * \"do not filter by label\" for deterministic detectors.\n */\n labels: string[];\n workspaceId: string;\n /**\n * Pre-loaded dictionary data for name, deny-list,\n * and city detection. When omitted, dictionary-based\n * detection paths are skipped. Consumers load from\n * the anonymize-data package and pass the data here.\n */\n dictionaries?: Dictionaries;\n};\n\nexport { DEFAULT_ENTITY_LABELS } from \"./constants\";\n\nexport const isLegalFormsEnabled = (\n config: Pick<PipelineConfig, \"enableLegalForms\">,\n): boolean => config.enableLegalForms !== false;\n","","import languageScopes from \"./data/language-scopes.json\";\n\nimport type { PipelineConfig } from \"./types\";\n\ntype LanguageScope = {\n nameCorpusLanguages?: readonly string[];\n denyListCountries?: readonly string[];\n};\n\ntype LanguageScopeData = {\n languages: Record<string, LanguageScope>;\n};\n\nconst scopeData = languageScopes as LanguageScopeData;\n\nconst normalizeLanguage = (language: string): string =>\n language.trim().toLowerCase();\n\nconst fallbackLanguage = (language: string): string | null => {\n const index = language.indexOf(\"-\");\n return index === -1 ? null : language.slice(0, index);\n};\n\nconst uniquePush = (target: string[], values: readonly string[]): void => {\n const seen = new Set(target);\n for (const value of values) {\n if (seen.has(value)) {\n continue;\n }\n seen.add(value);\n target.push(value);\n }\n};\n\nconst resolveLanguageScope = (language: string): LanguageScope | null => {\n const normalized = normalizeLanguage(language);\n if (normalized.length === 0) {\n return null;\n }\n const exact = scopeData.languages[normalized];\n if (exact !== undefined) {\n return exact;\n }\n const fallback = fallbackLanguage(normalized);\n return fallback === null ? null : (scopeData.languages[fallback] ?? null);\n};\n\nconst configuredLanguages = (config: PipelineConfig): readonly string[] => {\n if (config.languages !== undefined) {\n return config.languages;\n }\n return config.language === undefined ? [] : [config.language];\n};\n\nexport const configuredContentLanguages = (\n config: Pick<PipelineConfig, \"language\" | \"languages\">,\n): readonly string[] | undefined => {\n if (config.languages !== undefined) {\n return config.languages;\n }\n return config.language === undefined ? undefined : [config.language];\n};\n\nexport const applyPipelineLanguageScope = (\n config: PipelineConfig,\n): PipelineConfig => {\n const languages = configuredLanguages(config);\n if (languages.length === 0) {\n return config;\n }\n\n const nameCorpusLanguages: string[] = [];\n const denyListCountries: string[] = [];\n for (const language of languages) {\n const scope = resolveLanguageScope(language);\n if (scope === null) {\n continue;\n }\n uniquePush(nameCorpusLanguages, scope.nameCorpusLanguages ?? []);\n uniquePush(denyListCountries, scope.denyListCountries ?? []);\n }\n\n const next: Partial<PipelineConfig> = {};\n if (\n config.nameCorpusLanguages === undefined &&\n nameCorpusLanguages.length > 0\n ) {\n next.nameCorpusLanguages = nameCorpusLanguages;\n }\n if (config.denyListCountries === undefined && denyListCountries.length > 0) {\n next.denyListCountries = denyListCountries;\n }\n\n return Object.keys(next).length === 0 ? config : { ...config, ...next };\n};\n","const normalizeLanguageCode = (language: string): string =>\n language.trim().toLowerCase();\n\nconst normalizeLanguageSelection = (\n languages: readonly string[] | undefined,\n): string[] =>\n languages === undefined\n ? []\n : languages\n .map(normalizeLanguageCode)\n .filter((language) => language.length > 0);\n\nexport const languageSelectionKey = (\n languages: readonly string[] | undefined,\n): string => {\n const normalized = normalizeLanguageSelection(languages).toSorted();\n return normalized.length === 0 ? \"*\" : normalized.join(\",\");\n};\n\nconst baseLanguage = (language: string): string => {\n const index = language.indexOf(\"-\");\n return index === -1 ? language : language.slice(0, index);\n};\n\nexport const languageConfigMatches = (\n configLanguage: string,\n selectedLanguages: readonly string[] | undefined,\n): boolean => {\n if (selectedLanguages === undefined || selectedLanguages.length === 0) {\n return true;\n }\n const normalizedSelectedLanguages =\n normalizeLanguageSelection(selectedLanguages);\n if (normalizedSelectedLanguages.length === 0) {\n return true;\n }\n\n const normalizedConfigLanguage = normalizeLanguageCode(configLanguage);\n if (normalizedConfigLanguage.length === 0) {\n return false;\n }\n\n const genericConfig =\n baseLanguage(normalizedConfigLanguage) === normalizedConfigLanguage;\n for (const normalizedLanguage of normalizedSelectedLanguages) {\n if (normalizedLanguage === normalizedConfigLanguage) {\n return true;\n }\n if (\n genericConfig &&\n baseLanguage(normalizedLanguage) === normalizedConfigLanguage\n ) {\n return true;\n }\n }\n\n return false;\n};\n","import {\n isLegalFormsEnabled,\n type GazetteerEntry,\n type PipelineConfig,\n} from \"./types\";\nimport { languageSelectionKey } from \"./util/language-selection\";\n\nconst DEFAULT_CUSTOM_REGEX_SCORE = 0.9;\n\nconst contentLanguageFingerprint = (\n config: Pick<PipelineConfig, \"language\" | \"languages\">,\n): string => {\n const languages =\n config.languages ??\n (config.language === undefined ? [] : [config.language]);\n return languageSelectionKey(languages);\n};\n\nexport const pipelineConfigKey = (\n config: PipelineConfig,\n gazetteerEntries: readonly GazetteerEntry[],\n): string => {\n const legalFormsEnabled = isLegalFormsEnabled(config);\n const customDenyFingerprint =\n config.enableDenyList && config.customDenyList\n ? config.customDenyList\n .map((entry) =>\n JSON.stringify({\n label: entry.label,\n value: entry.value,\n variants: [...(entry.variants ?? [])].sort(),\n }),\n )\n .sort()\n .join(\"\\n\")\n : \"\";\n const customRegexFingerprint =\n config.enableRegex && config.customRegexes\n ? config.customRegexes\n .map((entry) =>\n JSON.stringify({\n label: entry.label,\n pattern: entry.pattern,\n preparedArtifactPolicy: entry.preparedArtifactPolicy ?? null,\n score: entry.score ?? DEFAULT_CUSTOM_REGEX_SCORE,\n }),\n )\n .sort()\n .join(\"\\n\")\n : \"\";\n const gazFingerprint =\n config.enableGazetteer && gazetteerEntries.length > 0\n ? gazetteerEntries\n .map(\n (entry) =>\n `${entry.id}:${entry.canonical}:${entry.label}:${[\n ...entry.variants,\n ]\n .sort()\n .join(\",\")}`,\n )\n .toSorted()\n .join(\";\")\n : \"\";\n\n return (\n `${config.enableDenyList}:` +\n `${config.enableTriggerPhrases}:` +\n `${legalFormsEnabled}:` +\n `${config.enableNameCorpus}:` +\n `${contentLanguageFingerprint(config)}:` +\n `${config.nameCorpusLanguages?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.enableRegex}:` +\n `${config.threshold}:` +\n `${config.enableConfidenceBoost}:` +\n `${config.enableHotwordRules === true}:` +\n `${config.enableCoreference === true}:` +\n `${config.enableZoneClassification === true}:` +\n `${config.labels.toSorted().join(\",\")}:` +\n `${config.denyListCountries?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.denyListRegions?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.denyListExcludeCategories?.toSorted().join(\",\") ?? \"\"}:` +\n `${customDenyFingerprint}:` +\n `${customRegexFingerprint}:` +\n `${config.enableGazetteer}:${gazFingerprint}:` +\n `${config.enableCountries !== false}`\n );\n};\n","import type { PipelineContext } from \"./context\";\nimport { defaultContext } from \"./context\";\nimport { applyPipelineLanguageScope } from \"./language-scope\";\nimport type { NativePreparedSearchConfig } from \"./native-search-config\";\nimport { pipelineConfigKey } from \"./pipeline-cache-key\";\nimport type { Dictionaries, GazetteerEntry, PipelineConfig } from \"./types\";\nimport {\n createNativePipelineFromPackage,\n PreparedNativePipeline,\n type NativeAnonymizeBinding,\n} from \"./native\";\n\nexport {\n PreparedNativePipeline,\n createNativePipelineFromPackage,\n} from \"./native\";\n\nexport type NativePipelineUnsupportedFeature = \"enableNer\";\n\nexport type NativePipelineCompatibility =\n | { status: \"supported\" }\n | {\n status: \"unsupported\";\n unsupportedFeatures: NativePipelineUnsupportedFeature[];\n };\n\nexport type NativePipelineBuildOptions = {\n binding: NativeAnonymizeBinding;\n config: PipelineConfig;\n gazetteerEntries?: GazetteerEntry[];\n context?: PipelineContext;\n};\n\nexport type NativePipelinePackageOptions = NativePipelineBuildOptions & {\n compressed?: boolean;\n};\n\nexport type { NativePipelineFromPackageOptions } from \"./native\";\n\ntype NativePipelinePackageCacheValue = Promise<Uint8Array> | Uint8Array;\n\nconst sharedPackageByDictionaries = new WeakMap<\n Dictionaries,\n Map<string, NativePipelinePackageCacheValue>\n>();\nconst sharedPackageWithoutDictionaries = new Map<\n string,\n NativePipelinePackageCacheValue\n>();\nconst dictionaryCacheIds = new WeakMap<Dictionaries, number>();\nlet nextDictionaryCacheId = 0;\n\nconst dictionaryCacheKey = (dictionaries: Dictionaries | undefined): string => {\n if (dictionaries === undefined) {\n return \"none\";\n }\n const existing = dictionaryCacheIds.get(dictionaries);\n if (existing !== undefined) {\n return `dict:${existing}`;\n }\n nextDictionaryCacheId += 1;\n dictionaryCacheIds.set(dictionaries, nextDictionaryCacheId);\n return `dict:${nextDictionaryCacheId}`;\n};\n\nconst sharedPackageCacheFor = (\n dictionaries: Dictionaries | undefined,\n): Map<string, NativePipelinePackageCacheValue> => {\n if (dictionaries === undefined) {\n return sharedPackageWithoutDictionaries;\n }\n const cached = sharedPackageByDictionaries.get(dictionaries);\n if (cached !== undefined) {\n return cached;\n }\n const created = new Map<string, NativePipelinePackageCacheValue>();\n sharedPackageByDictionaries.set(dictionaries, created);\n return created;\n};\n\nexport const getNativePipelineCompatibility = (\n config: PipelineConfig,\n): NativePipelineCompatibility => {\n const unsupportedFeatures: NativePipelineUnsupportedFeature[] = [];\n\n if (config.enableNer) unsupportedFeatures.push(\"enableNer\");\n if (unsupportedFeatures.length === 0) {\n return { status: \"supported\" };\n }\n return { status: \"unsupported\", unsupportedFeatures };\n};\n\nexport const assertNativePipelineSupported = (config: PipelineConfig): void => {\n const compatibility = getNativePipelineCompatibility(config);\n if (compatibility.status === \"supported\") {\n return;\n }\n throw new Error(\n `Native pipeline does not yet support: ${compatibility.unsupportedFeatures.join(\", \")}`,\n );\n};\n\nconst encoder = new TextEncoder();\n\ntype AssembleInputs = {\n pipelineConfigJson: Uint8Array;\n dictionariesJson: Uint8Array | undefined;\n gazetteerJson: Uint8Array | undefined;\n};\n\n/**\n * Serialize the assembler inputs the Rust binding expects. Dictionaries are\n * stripped from the pipeline config and passed out of band: the assembler reads\n * the separate bundle preferentially, and keeping the (large) dictionaries out\n * of the config JSON avoids serializing them twice.\n */\nconst toAssembleInputs = (\n { dictionaries, enableNer = false, ...config }: PipelineConfig,\n gazetteerEntries: readonly GazetteerEntry[],\n): AssembleInputs => ({\n pipelineConfigJson: encoder.encode(JSON.stringify({ ...config, enableNer })),\n dictionariesJson:\n dictionaries === undefined\n ? undefined\n : encoder.encode(JSON.stringify(dictionaries)),\n gazetteerJson:\n gazetteerEntries.length === 0\n ? undefined\n : encoder.encode(JSON.stringify(gazetteerEntries)),\n});\n\nconst assemblePackageBytes = (\n binding: NativeAnonymizeBinding,\n { pipelineConfigJson, dictionariesJson, gazetteerJson }: AssembleInputs,\n compressed: boolean,\n): Uint8Array => {\n const assemble = compressed\n ? binding.assembleStaticSearchCompressedPackageBytes\n : binding.assembleStaticSearchPackageBytes;\n if (assemble === undefined) {\n throw new Error(\n \"Native anonymize binding does not support static-search config assembly\",\n );\n }\n return assemble(pipelineConfigJson, dictionariesJson, gazetteerJson);\n};\n\nexport const prepareNativePipelineConfig = async ({\n binding,\n config,\n gazetteerEntries = [],\n}: Omit<\n NativePipelineBuildOptions,\n \"context\"\n>): Promise<NativePreparedSearchConfig> => {\n const scopedConfig = applyPipelineLanguageScope(config);\n assertNativePipelineSupported(scopedConfig);\n const assemble = binding.assembleStaticSearchConfigJson;\n if (assemble === undefined) {\n throw new Error(\n \"Native anonymize binding does not support static-search config assembly\",\n );\n }\n const { pipelineConfigJson, dictionariesJson, gazetteerJson } =\n toAssembleInputs(scopedConfig, gazetteerEntries);\n const configJson = assemble(\n pipelineConfigJson,\n dictionariesJson,\n gazetteerJson,\n );\n return JSON.parse(new TextDecoder().decode(configJson));\n};\n\nexport const prepareNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n compressed = false,\n}: NativePipelinePackageOptions): Promise<Uint8Array> => {\n const packageBytes = await getCachedNativePipelinePackage({\n config,\n binding,\n gazetteerEntries,\n ...(context ? { context } : {}),\n compressed,\n });\n // Return a genuine copy: with the real NAPI binding packageBytes is a Node\n // Buffer, and Buffer.prototype.slice() yields a memory-sharing view, so a\n // caller mutating it would corrupt the shared cache and ctx.nativePipelinePackage.\n return new Uint8Array(packageBytes);\n};\n\nexport const createNativePipelineFromConfig = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n}: NativePipelineBuildOptions): Promise<PreparedNativePipeline> => {\n const packageBytes = await getCachedNativePipelinePackage({\n binding,\n config,\n gazetteerEntries,\n ...(context ? { context } : {}),\n });\n return createNativePipelineFromPackage({ binding, packageBytes });\n};\n\nconst getCachedNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n compressed = false,\n}: NativePipelinePackageOptions): Promise<Uint8Array> => {\n const scopedConfig = applyPipelineLanguageScope(config);\n assertNativePipelineSupported(scopedConfig);\n const ctx = context ?? defaultContext;\n const key = nativePackageCacheKey({\n binding,\n config: scopedConfig,\n gazetteerEntries,\n compressed,\n });\n if (ctx.nativePipelinePackage && ctx.nativePipelinePackageKey === key) {\n return ctx.nativePipelinePackage;\n }\n if (\n ctx.nativePipelinePackagePromise &&\n ctx.nativePipelinePackageKey === key\n ) {\n return ctx.nativePipelinePackagePromise;\n }\n\n const sharedCache = sharedPackageCacheFor(scopedConfig.dictionaries);\n const shared = sharedCache.get(key);\n if (shared !== undefined) {\n const packageBytes = await shared;\n ctx.nativePipelinePackage = packageBytes;\n ctx.nativePipelinePackageKey = key;\n ctx.nativePipelinePackagePromise = null;\n return packageBytes;\n }\n\n ctx.nativePipelinePackage = null;\n ctx.nativePipelinePackageKey = key;\n const promise = buildNativePipelinePackage({\n binding,\n config: scopedConfig,\n gazetteerEntries,\n compressed,\n });\n ctx.nativePipelinePackagePromise = promise;\n sharedCache.set(key, promise);\n let packageBytes: Uint8Array;\n try {\n packageBytes = await promise;\n } catch (error) {\n if (sharedCache.get(key) === promise) {\n sharedCache.delete(key);\n }\n if (\n ctx.nativePipelinePackageKey === key &&\n ctx.nativePipelinePackagePromise === promise\n ) {\n ctx.nativePipelinePackage = null;\n ctx.nativePipelinePackagePromise = null;\n }\n throw error;\n }\n if (sharedCache.get(key) === promise) {\n sharedCache.set(key, packageBytes);\n }\n if (ctx.nativePipelinePackageKey === key) {\n ctx.nativePipelinePackage = packageBytes;\n ctx.nativePipelinePackagePromise = null;\n }\n return packageBytes;\n};\n\n// `async` so the shared package cache can store the in-flight value and dedupe\n// concurrent builds for the same key, and so assembly failures (an older\n// binding without the assemble functions, or a config the assembler rejects)\n// surface as a rejected promise rather than a synchronous throw mid-cache-flow.\nconst buildNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries,\n compressed,\n}: Required<\n Omit<NativePipelinePackageOptions, \"context\">\n>): Promise<Uint8Array> =>\n assemblePackageBytes(\n binding,\n toAssembleInputs(config, gazetteerEntries),\n compressed,\n );\n\ntype NativePackageCacheKeyOptions = {\n binding: NativeAnonymizeBinding;\n config: PipelineConfig;\n gazetteerEntries: readonly GazetteerEntry[];\n compressed: boolean;\n};\n\nconst nativePackageCacheKey = ({\n binding,\n config,\n gazetteerEntries,\n compressed,\n}: NativePackageCacheKeyOptions): string =>\n [\n binding.nativePackageVersion(),\n compressed ? \"compressed\" : \"raw\",\n dictionaryCacheKey(config.dictionaries),\n pipelineConfigKey(config, gazetteerEntries),\n ].join(\":\");\n","/* @stll/anonymize-wasm — browser / WebAssembly entry.\n *\n * Exposes the same native-SDK surface as `@stll/anonymize/native` (the\n * runtime-agnostic layer in `native.ts`), backed by the napi-rs\n * wasm32-wasip1-threads binding instead of the `.node` sidecars. The old\n * TS-pipeline surface (`runPipeline` and friends) is intentionally gone here:\n * this package now redacts entirely through the wasm binding and PREBUILT\n * prepared packages.\n *\n * Browsers can either load prepared packages (pass package bytes, an\n * `ArrayBuffer`, or a URL to fetch, or call `loadDefaultPipeline()` for the\n * default package bundled in the tarball) or build a config in-browser: the\n * wasm binding exposes the same static-search config assembly the Node\n * binding does, so `prepareNativePipelineConfig` / `createNativePipelineFromConfig`\n * / `prepareNativePipelinePackage` work here too.\n *\n * No module-level side effects: the wasm binding is instantiated lazily on\n * first use via `getBinding()`. The napi-generated glue is loaded from the\n * package's own `native/` asset directory — `index.wasi.cjs` under Node's WASI\n * runtime, `index.wasi-browser.js` (fetch + Worker) in browsers.\n */\n\nimport {\n createNativeAnonymizerFromPackage,\n createNativePipelineFromPackage,\n diagnostics_json as diagnosticsJsonWithBinding,\n diagnostics_stream_json as diagnosticsStreamJsonWithBinding,\n type NativeAnonymizeBinding,\n type NativeDiagnosticsBatchCallback,\n type NativeOperatorConfig,\n type NativeResultEventCallback,\n type NativeSearchPackageInput,\n type NativeStaticRedactionResult,\n native_package_version as nativePackageVersionWithBinding,\n normalize_for_search as normalizeForSearchWithBinding,\n PreparedNativeAnonymizer,\n PreparedNativePipeline,\n prepare_search_package as prepareSearchPackageWithBinding,\n redact_text as redactTextWithBinding,\n redact_text_json as redactTextJsonWithBinding,\n redact_text_stream_json as redactTextStreamJsonWithBinding,\n summary_diagnostics_json as summaryDiagnosticsJsonWithBinding,\n} from \"./native\";\n\nexport * from \"./native\";\nexport { deanonymise, exportRedactionKey } from \"./redact\";\nexport {\n CAPABILITY_MANIFEST,\n CAPABILITY_MANIFEST_SCHEMA_VERSION,\n CAPABILITY_RUNTIMES,\n} from \"./capabilities\";\nexport type { CapabilityManifest, CapabilityRuntime } from \"./capabilities\";\nexport {\n DEFAULT_ENTITY_LABELS,\n DETECTION_SOURCES,\n DETECTOR_PRIORITY,\n ENTITY_CAPABILITIES,\n ENTITY_LABELS,\n ENTITY_SELECTIONS,\n OPERATOR_TYPES,\n} from \"./types\";\nexport type {\n AnonymisationOperator,\n DetectionSource,\n Dictionaries,\n DefaultEntityLabel,\n Entity,\n EntityCapability,\n EntityLabel,\n EntitySelection,\n GazetteerEntry,\n OperatorConfig,\n OperatorType,\n PipelineConfig,\n RedactionResult,\n ReviewDecision,\n ReviewedEntity,\n} from \"./types\";\n// Config-driven pipeline surface: pure TS that delegates to\n// `binding.assembleStaticSearchConfigJson` / `assembleStaticSearchPackageBytes`,\n// which the wasm binding exposes with no cfg gating (crates/anonymize-napi/src/lib.rs),\n// so browser callers can assemble packages from a `PipelineConfig` (e.g. live\n// gazetteer entries and dictionaries) instead of only loading prebuilt packages.\nexport {\n assertNativePipelineSupported,\n createNativePipelineFromConfig,\n getNativePipelineCompatibility,\n prepareNativePipelineConfig,\n prepareNativePipelinePackage,\n} from \"./native-pipeline\";\nexport type {\n NativePipelineBuildOptions,\n NativePipelineCompatibility,\n NativePipelinePackageOptions,\n NativePipelineUnsupportedFeature,\n} from \"./native-pipeline\";\nexport { createPipelineContext } from \"./context\";\nexport type { PipelineContext } from \"./context\";\n\n/** A prepared package the caller supplies: raw bytes, an ArrayBuffer, or a URL\n * (string or `URL`) that resolves to the package and is fetched. */\nexport type PreparedPackageSource = Uint8Array | ArrayBuffer | URL | string;\n\n/** Escape hatch for callers that already hold a binding (e.g. a custom sidecar\n * or a test double). When omitted, the lazily-instantiated wasm binding is\n * used. */\nexport type WasmBindingOptions = {\n binding?: NativeAnonymizeBinding;\n};\n\nconst NODE_GLUE_MODULE = \"index.wasi.cjs\";\nconst BROWSER_GLUE_MODULE = \"index.wasi-browser.js\";\nconst NODE_FS_MODULE = \"node:fs/promises\";\nconst NATIVE_ASSET_DIR = \"native\";\nconst DEFAULT_PACKAGE_FILE = \"native-pipeline.stlanonpkg\";\nconst LANGUAGE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;\n\nlet bindingPromise: Promise<NativeAnonymizeBinding> | undefined;\nconst defaultPipelineCache = new Map<string, Promise<PreparedNativePipeline>>();\n\n/** Instantiate (once) and return the wasm binding. Safe to call repeatedly:\n * the underlying wasm module is instantiated a single time and cached. */\nexport const getBinding = (): Promise<NativeAnonymizeBinding> => {\n bindingPromise ??= loadWasmBinding();\n return bindingPromise;\n};\n\nconst loadWasmBinding = async (): Promise<NativeAnonymizeBinding> => {\n const glueModule = isNodeRuntime() ? NODE_GLUE_MODULE : BROWSER_GLUE_MODULE;\n const glueUrl = assetUrl(glueModule);\n // The specifier is deliberately a runtime asset URL (resolved against the\n // package's own `native/` directory), not a module the bundler should follow:\n // the napi-rs glue lives outside src and is copied in at build time.\n // eslint-disable-next-line stll/no-dynamic-import-specifier\n const loaded: unknown = await import(/* @vite-ignore */ glueUrl.href);\n return toNativeAnonymizeBinding(loaded);\n};\n\ntype RuntimeGlobals = {\n process?: { versions?: { node?: string } };\n window?: unknown;\n};\n\nconst isNodeRuntime = (): boolean => {\n const globals: RuntimeGlobals = globalThis;\n return (\n globals.window === undefined &&\n typeof globals.process?.versions?.node === \"string\"\n );\n};\n\nconst assetUrl = (fileName: string): URL =>\n new URL(`./${NATIVE_ASSET_DIR}/${fileName}`, import.meta.url);\n\nconst resolveBinding = (\n options?: WasmBindingOptions,\n): Promise<NativeAnonymizeBinding> =>\n options?.binding ? Promise.resolve(options.binding) : getBinding();\n\nconst toPackageBytes = async (\n source: PreparedPackageSource,\n): Promise<Uint8Array> => {\n if (source instanceof Uint8Array) {\n return source;\n }\n if (source instanceof ArrayBuffer) {\n return new Uint8Array(source);\n }\n const href = source instanceof URL ? source.href : source;\n // Node's global fetch (undici) rejects file: URLs, so package URLs resolved\n // from import.meta.url (loadDefaultPipeline, `new URL(..., import.meta.url)`)\n // fail there. Read those through node:fs instead of fetch.\n if (href.startsWith(\"file:\")) {\n return readFileUrlBytes(href);\n }\n const response = await fetch(href);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch prepared package (${response.status} ${response.statusText})`,\n );\n }\n return new Uint8Array(await response.arrayBuffer());\n};\n\n/** Read a `file:` URL through node:fs. The import is dynamic and gated behind\n * the `file:` check (never reached in browsers); the specifier is a runtime\n * value so the bundler leaves it alone, mirroring the runtime glue import in\n * {@link loadWasmBinding}, so browser bundles never pull in node:fs. */\nconst readFileUrlBytes = async (fileUrl: string): Promise<Uint8Array> => {\n // eslint-disable-next-line stll/no-dynamic-import-specifier\n const { readFile } = await import(/* @vite-ignore */ NODE_FS_MODULE);\n return new Uint8Array(await readFile(new URL(fileUrl)));\n};\n\n// --- Prepared-package loaders (the primary browser flow) ---------------------\n\nexport type LoadPreparedPackageOptions = WasmBindingOptions;\n\n/** Load a prepared package and return a pipeline ready to redact text. */\nexport const loadPipeline = async (\n source: PreparedPackageSource,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n const [binding, packageBytes] = await Promise.all([\n resolveBinding(options),\n toPackageBytes(source),\n ]);\n return createNativePipelineFromPackage({ binding, packageBytes });\n};\n\n/** Load a prepared package and return the lower-level anonymizer. */\nexport const load_prepared_package = async (\n source: PreparedPackageSource,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativeAnonymizer> => {\n const [binding, packageBytes] = await Promise.all([\n resolveBinding(options),\n toPackageBytes(source),\n ]);\n return createNativeAnonymizerFromPackage({ binding, packageBytes });\n};\n\n// --- Default package bundled in the tarball ----------------------------------\n\n/** URL of a bundled default prepared package, resolved against this module so\n * it points at the `native/` asset directory shipped in the tarball. */\nexport const defaultPackageUrl = (language?: string): URL =>\n language === undefined\n ? assetUrl(DEFAULT_PACKAGE_FILE)\n : assetUrl(`native-pipeline.${normalizeLanguage(language)}.stlanonpkg`);\n\n/** Load a fresh pipeline from the bundled default prepared package.\n *\n * Mirrors the node loader's regional-tag fallback: when an exact package for\n * a locale tag such as `en-US` is not shipped, the base-language package\n * (`en`) is loaded instead. The browser cannot check asset existence up\n * front, so the fallback triggers on a failed load of the exact package. */\nexport const loadDefaultPipeline = async (\n language?: string,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n try {\n return await loadPipeline(defaultPackageUrl(language), options);\n } catch (error) {\n const normalized =\n language === undefined ? undefined : normalizeLanguage(language);\n const baseLanguage = normalized?.split(\"-\").at(0);\n if (baseLanguage === undefined || baseLanguage === normalized) {\n throw error;\n }\n return loadPipeline(defaultPackageUrl(baseLanguage), options);\n }\n};\n\n/** Cached variant of {@link loadDefaultPipeline}: the default pipeline for a\n * given language is fetched and prepared once, then reused.\n *\n * Only the ambient-binding case is cached. The cache key is language-only, so a\n * caller that injects its own `options.binding` bypasses the cache entirely:\n * reusing a pipeline built against a different binding would be wrong, and\n * folding the binding into the key would keep unbounded per-binding entries\n * alive. Injected-binding callers get a fresh pipeline each call. */\nexport const getDefaultPipeline = (\n language?: string,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n if (options?.binding) {\n return loadDefaultPipeline(language, options);\n }\n const key = language ?? \"<default>\";\n const cached = defaultPipelineCache.get(key);\n if (cached !== undefined) {\n return cached;\n }\n // Evict the entry on rejection so a failed load (e.g. a transient fetch/read\n // error) is retried on the next call instead of caching the rejection.\n const pipeline = loadDefaultPipeline(language).catch((error: unknown) => {\n defaultPipelineCache.delete(key);\n throw error;\n });\n defaultPipelineCache.set(key, pipeline);\n return pipeline;\n};\n\nexport const redactDefaultText = async (\n fullText: string,\n operators?: NativeOperatorConfig,\n language?: string,\n): Promise<NativeStaticRedactionResult> =>\n (await getDefaultPipeline(language)).redactText(fullText, operators);\n\nexport const redactDefaultTextJson = async (\n fullText: string,\n operators?: NativeOperatorConfig,\n language?: string,\n): Promise<string> =>\n (await getDefaultPipeline(language)).redact_text_json(fullText, operators);\n\n// --- Binding-injected SDK surface (async parity with native-node) ------------\n\nexport const native_package_version = async (\n options?: WasmBindingOptions,\n): Promise<string> =>\n nativePackageVersionWithBinding(await resolveBinding(options));\n\nexport const normalize_for_search = async (\n text: string,\n options?: WasmBindingOptions,\n): Promise<string> =>\n normalizeForSearchWithBinding({\n binding: await resolveBinding(options),\n text,\n });\n\nexport type PrepareSearchPackageOptions = WasmBindingOptions & {\n compressed?: boolean;\n};\n\nexport const prepare_search_package = async (\n config: NativeSearchPackageInput,\n { compressed = false, ...options }: PrepareSearchPackageOptions = {},\n): Promise<Uint8Array> =>\n prepareSearchPackageWithBinding({\n binding: await resolveBinding(options),\n config,\n compressed,\n });\n\nexport const redact_text = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<NativeStaticRedactionResult> =>\n redactTextWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const redact_text_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string> =>\n redactTextJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const redact_text_stream_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n redactTextStreamJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n onEvent,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const diagnostics_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n diagnosticsJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const diagnostics_stream_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n diagnosticsStreamJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n onBatch,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const summary_diagnostics_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n summaryDiagnosticsJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\n// --- Binding extraction ------------------------------------------------------\n\nconst toNativeAnonymizeBinding = (loaded: unknown): NativeAnonymizeBinding => {\n const candidate = pickBindingCandidate(loaded);\n if (!isNativeAnonymizeBinding(candidate)) {\n throw new Error(\n \"wasm binding module does not expose the native anonymize surface\",\n );\n }\n return candidate;\n};\n\nconst pickBindingCandidate = (loaded: unknown): unknown => {\n if (isRecord(loaded) && isNativeAnonymizeBinding(loaded[\"default\"])) {\n return loaded[\"default\"];\n }\n return loaded;\n};\n\nconst isNativeAnonymizeBinding = (\n value: unknown,\n): value is NativeAnonymizeBinding => {\n if (!isRecord(value)) {\n return false;\n }\n if (typeof value[\"nativePackageVersion\"] !== \"function\") {\n return false;\n }\n if (typeof value[\"normalizeForSearch\"] !== \"function\") {\n return false;\n }\n if (typeof value[\"prepareStaticSearchPackageBytes\"] !== \"function\") {\n return false;\n }\n if (\n typeof value[\"prepareStaticSearchCompressedPackageBytes\"] !== \"function\"\n ) {\n return false;\n }\n const preparedSearch = value[\"NativePreparedSearch\"];\n if (!isRecord(preparedSearch)) {\n return false;\n }\n if (typeof preparedSearch[\"fromConfigJsonBytes\"] !== \"function\") {\n return false;\n }\n return typeof preparedSearch[\"fromPreparedPackageBytes\"] === \"function\";\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n (typeof value === \"object\" && value !== null) || typeof value === \"function\";\n\nconst normalizeLanguage = (language: string): string => {\n const normalized = language.trim().toLowerCase();\n if (!LANGUAGE_PATTERN.test(normalized)) {\n throw new Error(`Language must match ${LANGUAGE_PATTERN.source}`);\n }\n return normalized;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"wasm.mjs","names":["#session","#plan","#prepared","#anonymizer","native_package_version","normalize_for_search","prepare_search_package","redact_text_json","redact_text","redact_text_stream_json","diagnostics_json","diagnostics_stream_json","summary_diagnostics_json","languageScopes","normalizeLanguage","nativePackageVersionWithBinding","normalizeForSearchWithBinding","prepareSearchPackageWithBinding","redactTextWithBinding","redactTextJsonWithBinding","redactTextStreamJsonWithBinding","diagnosticsJsonWithBinding","diagnosticsStreamJsonWithBinding","summaryDiagnosticsJsonWithBinding"],"sources":["../../src/native.ts","../../src/context.ts","../../src/redact.ts","../../src/types.ts","../../src/data/language-scopes.json","../../src/language-scope.ts","../../src/util/language-selection.ts","../../src/pipeline-cache-key.ts","../../src/native-pipeline.ts","../../src/wasm.ts"],"sourcesContent":["import type { NativePreparedSearchConfig } from \"./native-search-config\";\nimport type { OperatorSelection, OperatorType } from \"./types\";\n\nexport type { NativePreparedSearchConfig } from \"./native-search-config\";\n\ntype NativeBindingOperatorConfig = {\n operators?: Record<string, OperatorSelection>;\n redactString?: string;\n};\n\ntype NativeBindingCallerRedactionOptions = {\n requestJson: string;\n operators?: NativeBindingOperatorConfig;\n};\n\ntype NativeBindingSessionCallerRedactionInput = {\n fullText: string;\n requestJson: string;\n};\n\ntype NativeBindingSessionCallerRedactionPlanOptions = {\n inputs: NativeBindingSessionCallerRedactionInput[];\n operators?: NativeBindingOperatorConfig;\n observedAtEpochSeconds?: number;\n};\n\ntype NativeBindingOpenSessionArchiveOptions = {\n archive: Uint8Array;\n key: Uint8Array;\n expectedSessionId: string;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativeDiagnosticsBatchCallback = (diagnosticsJson: string) => void;\nexport type NativeResultEventCallback = (eventJson: string) => void;\n\ntype NativeBindingRedactionEntry = {\n placeholder: string;\n original: string;\n};\n\ntype NativeBindingOperatorEntry = {\n placeholder: string;\n operator: OperatorType;\n};\n\ntype NativeBindingPipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n sourceDetail?: string | null;\n providerId?: string | null;\n detectionId?: string | null;\n};\n\ntype NativeBindingRedactionResult = {\n redactedText: string;\n redactionMap: NativeBindingRedactionEntry[];\n operatorMap: NativeBindingOperatorEntry[];\n entityCount: number;\n};\n\ntype NativeBindingStaticRedactionResult = {\n resolvedEntities: NativeBindingPipelineEntity[];\n redaction: NativeBindingRedactionResult;\n};\n\ntype CanonicalPipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n source_detail?: string | null;\n provider_id?: string | null;\n detection_id?: string | null;\n};\n\ntype CanonicalStaticRedactionResult = {\n resolved_entities: CanonicalPipelineEntity[];\n redaction: {\n redacted_text: string;\n redaction_map: NativeBindingRedactionEntry[];\n operator_map: NativeBindingOperatorEntry[];\n entity_count: number;\n };\n};\n\ntype CanonicalSessionMetadata = {\n session_id: string;\n created_at_epoch_seconds: number | null;\n expires_at_epoch_seconds: number | null;\n mapping_count: number;\n status: NativeSessionStatus;\n};\n\ntype CanonicalSessionDeletionSummary = {\n session_id: string;\n deleted_mapping_count: number;\n};\n\ntype CanonicalSessionRedactionPlanResult = {\n replacements: Array<{\n start: number;\n end: number;\n replacement: string;\n }>;\n entity_count: number;\n caller_entity_count: number;\n};\n\nexport type NativeSessionStatus =\n | \"active\"\n | \"not_yet_active\"\n | \"expired\"\n | \"deleted\";\n\nexport type NativeSessionLifecycle = {\n createdAtEpochSeconds: number;\n expiresAtEpochSeconds?: number;\n};\n\nexport type NativeSessionMetadata = {\n sessionId: string;\n createdAtEpochSeconds: number | null;\n expiresAtEpochSeconds: number | null;\n mappingCount: number;\n status: NativeSessionStatus;\n};\n\nexport type NativeSessionDeletionSummary = {\n sessionId: string;\n deletedMappingCount: number;\n};\n\nexport type NativeSessionRedactionAtOptions = {\n fullText: string;\n observedAtEpochSeconds: number;\n operators?: NativeOperatorConfig;\n};\n\nexport type NativeCreateSessionWithLifecycleOptions = NativeSessionLifecycle & {\n sessionId: string;\n};\n\nexport type NativeOpenSessionArchiveOptions = {\n archive: Uint8Array;\n key: Uint8Array;\n expectedSessionId: string;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativePreparedRedactionSessionBinding = {\n sessionId: () => string;\n mappingCount: () => number;\n restoreText?: (fullText: string) => string;\n restoreTextAt?: (fullText: string, observedAtEpochSeconds: number) => string;\n toPlaintextJson: () => string;\n toPlaintextJsonAt?: (observedAtEpochSeconds: number) => string;\n toEncryptedArchive?: (key: Uint8Array) => Uint8Array;\n toEncryptedArchiveAt?: (\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ) => Uint8Array;\n inspectJson?: (observedAtEpochSeconds?: number) => string;\n deleteJson?: () => string;\n redactStaticEntitiesJson: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesJsonAt?: (\n fullText: string,\n observedAtEpochSeconds: number,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n planStaticEntitiesWithCallerDetections?: (\n options: NativeBindingSessionCallerRedactionPlanOptions,\n ) => NativePreparedSessionRedactionPlanBinding;\n};\n\nexport type NativePreparedSessionRedactionPlanBinding = {\n resultJson: () => string;\n commit: () => void;\n};\n\nexport type NativePreparedSearchBinding = {\n prepareDiagnosticsJson?: () => string;\n warmLazyRegex?: () => void;\n warm_lazy_regex?: () => void;\n warmLazyRegexDiagnosticsJson?: () => string;\n warm_lazy_regex_diagnostics_json?: () => string;\n createRedactionSession?: (\n sessionId: string,\n ) => NativePreparedRedactionSessionBinding;\n createRedactionSessionWithLifecycle?: (\n sessionId: string,\n createdAtEpochSeconds: number,\n expiresAtEpochSeconds?: number,\n ) => NativePreparedRedactionSessionBinding;\n restoreRedactionSession?: (\n plaintextJson: string,\n ) => NativePreparedRedactionSessionBinding;\n restoreEncryptedRedactionSession?: (\n options: NativeBindingOpenSessionArchiveOptions,\n ) => NativePreparedRedactionSessionBinding;\n redactStaticEntities: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => NativeBindingStaticRedactionResult;\n redactStaticEntitiesJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesWithCallerDetectionsJson?: (\n fullText: string,\n options: NativeBindingCallerRedactionOptions,\n ) => string;\n redactStaticEntitiesWithCallerDetectionsDiagnosticsJson?: (\n fullText: string,\n options: NativeBindingCallerRedactionOptions,\n ) => string;\n redactStaticEntitiesResultStreamJson?: (\n fullText: string,\n operators: NativeBindingOperatorConfig | undefined,\n onEvent: NativeResultEventCallback,\n ) => string;\n redactStaticEntitiesDiagnosticsJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n redactStaticEntitiesDiagnosticsStreamJson?: (\n fullText: string,\n operators: NativeBindingOperatorConfig | undefined,\n onBatch: NativeDiagnosticsBatchCallback,\n ) => string;\n redactStaticEntitiesSummaryDiagnosticsJson?: (\n fullText: string,\n operators?: NativeBindingOperatorConfig,\n ) => string;\n};\n\nexport type NativeAnonymizeBinding = {\n normalizeForSearch: (text: string) => string;\n nativePackageVersion: () => string;\n NativePreparedSearch: {\n fromConfigJsonBytes: (\n configJson: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromPreparedPackageBytes: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromPreparedPackageBytesWithoutCache?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromTrustedPreparedPackageBytes?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n fromTrustedPreparedPackageBytesWithoutCache?: (\n packageBytes: Uint8Array,\n ) => NativePreparedSearchBinding;\n };\n prepareStaticSearchPackageBytes: (configJson: Uint8Array) => Uint8Array;\n prepareStaticSearchCompressedPackageBytes: (\n configJson: Uint8Array,\n ) => Uint8Array;\n // Rust config assembler (replaces the retired TypeScript config-assembly\n // layer). Takes the pipeline config plus out-of-band dictionaries and\n // gazetteer JSON and returns either the assembled config JSON or ready\n // package bytes. Optional so older bindings without the assembler still\n // satisfy the type; native-node loads them from the same `.node`.\n assembleStaticSearchConfigJson?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n assembleStaticSearchPackageBytes?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n assembleStaticSearchCompressedPackageBytes?: (\n pipelineConfigJson: Uint8Array,\n dictionariesJson?: Uint8Array,\n gazetteerJson?: Uint8Array,\n ) => Uint8Array;\n};\n\nexport type NativeOperatorConfig = {\n operators?: Record<string, OperatorSelection>;\n redactString?: string;\n};\n\nexport const CALLER_DETECTION_CONTRACT_VERSION = 2;\n\nexport type NativeCallerDetection = {\n start: number;\n end: number;\n label: string;\n score: number;\n providerId: string;\n detectionId: string;\n};\n\nexport type NativeCallerRedactionOptions = {\n detections: readonly NativeCallerDetection[];\n operators?: NativeOperatorConfig;\n};\n\nexport type NativeSessionCallerRedactionInput = {\n fullText: string;\n detections: readonly NativeCallerDetection[];\n};\n\nexport type NativeSessionCallerRedactionPlanOptions = {\n inputs: readonly NativeSessionCallerRedactionInput[];\n operators?: NativeOperatorConfig;\n observedAtEpochSeconds?: number;\n};\n\nexport type NativeTextReplacement = {\n start: number;\n end: number;\n replacement: string;\n};\n\nexport type NativeSessionBlockRedactionPlan = {\n replacements: readonly NativeTextReplacement[];\n entityCount: number;\n callerEntityCount: number;\n};\n\nconst callerDetectionRequestJson = (\n detections: readonly NativeCallerDetection[],\n): string =>\n JSON.stringify({\n version: CALLER_DETECTION_CONTRACT_VERSION,\n detections: detections.map((detection) => ({\n start: detection.start,\n end: detection.end,\n label: detection.label,\n score: detection.score,\n provider_id: detection.providerId,\n detection_id: detection.detectionId,\n })),\n });\n\nexport type NativePipelineEntity = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n source: string;\n sourceDetail?: string;\n providerId?: string;\n detectionId?: string;\n};\n\nexport type NativeRedactionResult = {\n redactedText: string;\n redactionMap: Map<string, string>;\n operatorMap: Map<string, OperatorType>;\n entityCount: number;\n};\n\nexport type NativeStaticRedactionResult = {\n resolvedEntities: NativePipelineEntity[];\n redaction: NativeRedactionResult;\n};\n\nexport type NativeSearchPackageOptions = {\n binding: NativeAnonymizeBinding;\n config: NativePreparedSearchConfig;\n compressed?: boolean;\n};\n\nexport type NativeSearchPackageInput =\n | NativePreparedSearchConfig\n | string\n | Uint8Array;\n\nexport type SharedNativeSearchPackageOptions = {\n binding: NativeAnonymizeBinding;\n config: NativeSearchPackageInput;\n compressed?: boolean;\n};\n\nexport type SharedNativePreparedPackageOptions = {\n binding: NativeAnonymizeBinding;\n packageBytes: Uint8Array;\n};\n\nexport type SharedNativeRedactTextJsonOptions = {\n binding: NativeAnonymizeBinding;\n config: NativeSearchPackageInput;\n fullText: string;\n operators?: NativeOperatorConfig;\n};\n\nexport type SharedNativeRedactTextOptions = SharedNativeRedactTextJsonOptions;\n\nexport type SharedNativeDiagnosticsJsonOptions =\n SharedNativeRedactTextJsonOptions;\n\nexport type SharedNativeDiagnosticsStreamJsonOptions =\n SharedNativeRedactTextJsonOptions & {\n onBatch: NativeDiagnosticsBatchCallback;\n };\n\nexport type SharedNativeRedactTextStreamJsonOptions =\n SharedNativeRedactTextJsonOptions & {\n onEvent: NativeResultEventCallback;\n };\n\nexport type NativeNormalizeOptions = {\n binding: NativeAnonymizeBinding;\n text: string;\n};\n\nexport type NativeAnonymizerFromConfigOptions = {\n binding: NativeAnonymizeBinding;\n config: NativePreparedSearchConfig;\n};\n\nexport type NativeAnonymizerFromPackageOptions = {\n binding: NativeAnonymizeBinding;\n packageBytes: Uint8Array;\n};\n\nexport type NativePipelineFromPackageOptions =\n NativeAnonymizerFromPackageOptions;\n\nexport type NativeBindingVersionOptions = {\n binding: NativeAnonymizeBinding;\n expectedVersion: string;\n};\n\nexport class PreparedNativeRedactionSession {\n readonly #session: NativePreparedRedactionSessionBinding;\n\n constructor(session: NativePreparedRedactionSessionBinding) {\n this.#session = session;\n }\n\n sessionId(): string {\n return this.#session.sessionId();\n }\n\n session_id(): string {\n return this.sessionId();\n }\n\n mappingCount(): number {\n return this.#session.mappingCount();\n }\n\n mapping_count(): number {\n return this.mappingCount();\n }\n\n restoreText(fullText: string, observedAtEpochSeconds?: number): string {\n if (observedAtEpochSeconds === undefined) {\n const restore = this.#session.restoreText;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support session restoration\",\n );\n }\n return restore.call(this.#session, fullText);\n }\n const restore = this.#session.restoreTextAt;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support session restoration lifecycle controls\",\n );\n }\n return restore.call(this.#session, fullText, observedAtEpochSeconds);\n }\n\n restore_text(fullText: string, observedAtEpochSeconds?: number): string {\n return this.restoreText(fullText, observedAtEpochSeconds);\n }\n\n toPlaintextJson(): string {\n return this.#session.toPlaintextJson();\n }\n\n to_plaintext_json(): string {\n return this.toPlaintextJson();\n }\n\n toPlaintextJsonAt(observedAtEpochSeconds: number): string {\n const serialize = this.#session.toPlaintextJsonAt;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return serialize.call(this.#session, observedAtEpochSeconds);\n }\n\n to_plaintext_json_at(observedAtEpochSeconds: number): string {\n return this.toPlaintextJsonAt(observedAtEpochSeconds);\n }\n\n toEncryptedArchive(key: Uint8Array): Uint8Array {\n const serialize = this.#session.toEncryptedArchive;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return serialize.call(this.#session, key);\n }\n\n to_encrypted_archive(key: Uint8Array): Uint8Array {\n return this.toEncryptedArchive(key);\n }\n\n toEncryptedArchiveAt(\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ): Uint8Array {\n const serialize = this.#session.toEncryptedArchiveAt;\n if (!serialize) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return serialize.call(this.#session, key, observedAtEpochSeconds);\n }\n\n to_encrypted_archive_at(\n key: Uint8Array,\n observedAtEpochSeconds: number,\n ): Uint8Array {\n return this.toEncryptedArchiveAt(key, observedAtEpochSeconds);\n }\n\n inspect(observedAtEpochSeconds?: number): NativeSessionMetadata {\n const inspect = this.#session.inspectJson;\n if (!inspect) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n const metadata: CanonicalSessionMetadata = JSON.parse(\n inspect.call(this.#session, observedAtEpochSeconds),\n );\n return {\n sessionId: metadata.session_id,\n createdAtEpochSeconds: metadata.created_at_epoch_seconds,\n expiresAtEpochSeconds: metadata.expires_at_epoch_seconds,\n mappingCount: metadata.mapping_count,\n status: metadata.status,\n };\n }\n\n delete(): NativeSessionDeletionSummary {\n const deleteSession = this.#session.deleteJson;\n if (!deleteSession) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n const summary: CanonicalSessionDeletionSummary = JSON.parse(\n deleteSession.call(this.#session),\n );\n return {\n sessionId: summary.session_id,\n deletedMappingCount: summary.deleted_mapping_count,\n };\n }\n\n redactStaticEntities(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.redact_text_json(fullText, operators),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redactText(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntities(fullText, operators);\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactText(fullText, operators);\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n return this.#session.redactStaticEntitiesJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n redactStaticEntitiesAt(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.redactTextJsonAt(options),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redactTextAt(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesAt(options);\n }\n\n redact_text_at(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactTextAt(options);\n }\n\n redact_static_entities_at(\n options: NativeSessionRedactionAtOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesAt(options);\n }\n\n redactTextJsonAt({\n fullText,\n observedAtEpochSeconds,\n operators,\n }: NativeSessionRedactionAtOptions): string {\n const redact = this.#session.redactStaticEntitiesJsonAt;\n if (!redact) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return redact.call(\n this.#session,\n fullText,\n observedAtEpochSeconds,\n toBindingOperatorConfig(operators),\n );\n }\n\n redact_text_json_at(options: NativeSessionRedactionAtOptions): string {\n return this.redactTextJsonAt(options);\n }\n\n planTextBatchWithCallerDetections({\n inputs,\n operators,\n observedAtEpochSeconds,\n }: NativeSessionCallerRedactionPlanOptions): PreparedNativeSessionRedactionPlan {\n const plan = this.#session.planStaticEntitiesWithCallerDetections;\n if (!plan) {\n throw new Error(\n \"Native anonymize binding does not support transactional caller-detection session plans\",\n );\n }\n const bindingOperators = toBindingOperatorConfig(operators);\n const bindingPlan = plan.call(this.#session, {\n inputs: inputs.map(({ detections, fullText }) => ({\n fullText,\n requestJson: callerDetectionRequestJson(detections),\n })),\n ...(bindingOperators === undefined\n ? {}\n : { operators: bindingOperators }),\n ...(observedAtEpochSeconds === undefined\n ? {}\n : { observedAtEpochSeconds }),\n });\n return new PreparedNativeSessionRedactionPlan(bindingPlan);\n }\n}\n\nexport class PreparedNativeSessionRedactionPlan {\n readonly blocks: readonly NativeSessionBlockRedactionPlan[];\n readonly #plan: NativePreparedSessionRedactionPlanBinding;\n\n constructor(plan: NativePreparedSessionRedactionPlanBinding) {\n this.#plan = plan;\n const blocks: CanonicalSessionRedactionPlanResult[] = JSON.parse(\n plan.resultJson(),\n );\n this.blocks = blocks.map(\n ({ caller_entity_count, entity_count, replacements }) => ({\n replacements,\n entityCount: entity_count,\n callerEntityCount: caller_entity_count,\n }),\n );\n }\n\n commit(): void {\n this.#plan.commit();\n }\n}\n\nexport class PreparedNativeAnonymizer {\n readonly #prepared: NativePreparedSearchBinding;\n\n constructor(prepared: NativePreparedSearchBinding) {\n this.#prepared = prepared;\n }\n\n prepareDiagnosticsJson(): string | null {\n return this.#prepared.prepareDiagnosticsJson?.() ?? null;\n }\n\n prepare_diagnostics_json(): string | null {\n return this.prepareDiagnosticsJson();\n }\n\n warmLazyRegex(): void {\n if (this.#prepared.warmLazyRegex) {\n this.#prepared.warmLazyRegex();\n return;\n }\n this.#prepared.warm_lazy_regex?.();\n }\n\n warm_lazy_regex(): void {\n this.warmLazyRegex();\n }\n\n warmLazyRegexDiagnosticsJson(): string | null {\n if (this.#prepared.warmLazyRegexDiagnosticsJson) {\n return this.#prepared.warmLazyRegexDiagnosticsJson();\n }\n return this.#prepared.warm_lazy_regex_diagnostics_json?.() ?? null;\n }\n\n warm_lazy_regex_diagnostics_json(): string | null {\n return this.warmLazyRegexDiagnosticsJson();\n }\n\n createRedactionSession(sessionId: string): PreparedNativeRedactionSession {\n const create = this.#prepared.createRedactionSession;\n if (!create) {\n throw new Error(\n \"Native anonymize binding does not support redaction sessions\",\n );\n }\n return new PreparedNativeRedactionSession(\n create.call(this.#prepared, sessionId),\n );\n }\n\n create_redaction_session(sessionId: string): PreparedNativeRedactionSession {\n return this.createRedactionSession(sessionId);\n }\n\n createRedactionSessionWithLifecycle({\n sessionId,\n createdAtEpochSeconds,\n expiresAtEpochSeconds,\n }: NativeCreateSessionWithLifecycleOptions): PreparedNativeRedactionSession {\n const create = this.#prepared.createRedactionSessionWithLifecycle;\n if (!create) {\n throw new Error(\n \"Native anonymize binding does not support session lifecycle controls\",\n );\n }\n return new PreparedNativeRedactionSession(\n create.call(\n this.#prepared,\n sessionId,\n createdAtEpochSeconds,\n expiresAtEpochSeconds,\n ),\n );\n }\n\n create_redaction_session_with_lifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.createRedactionSessionWithLifecycle(options);\n }\n\n restoreRedactionSession(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n const restore = this.#prepared.restoreRedactionSession;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support redaction sessions\",\n );\n }\n return new PreparedNativeRedactionSession(\n restore.call(this.#prepared, plaintextJson),\n );\n }\n\n restore_redaction_session(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.restoreRedactionSession(plaintextJson);\n }\n\n restoreEncryptedRedactionSession({\n archive,\n key,\n expectedSessionId,\n observedAtEpochSeconds,\n }: NativeOpenSessionArchiveOptions): PreparedNativeRedactionSession {\n const restore = this.#prepared.restoreEncryptedRedactionSession;\n if (!restore) {\n throw new Error(\n \"Native anonymize binding does not support encrypted session archives\",\n );\n }\n return new PreparedNativeRedactionSession(\n restore.call(this.#prepared, {\n archive,\n key,\n expectedSessionId,\n ...(observedAtEpochSeconds === undefined\n ? {}\n : { observedAtEpochSeconds }),\n }),\n );\n }\n\n restore_encrypted_redaction_session(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.restoreEncryptedRedactionSession(options);\n }\n\n redactStaticEntities(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return toNativeStaticRedactionResult(\n this.#prepared.redactStaticEntities(\n fullText,\n toBindingOperatorConfig(operators),\n ),\n );\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntities(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n const bindingOperators = toBindingOperatorConfig(operators);\n if (this.#prepared.redactStaticEntitiesJson) {\n return this.#prepared.redactStaticEntitiesJson(\n fullText,\n bindingOperators,\n );\n }\n return JSON.stringify(\n toBindingStaticRedactionResult(\n toNativeStaticRedactionResult(\n this.#prepared.redactStaticEntities(fullText, bindingOperators),\n ),\n ),\n );\n }\n\n redactStaticEntitiesWithCallerDetections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n if (!this.#prepared.redactStaticEntitiesWithCallerDetectionsJson) {\n throw new Error(\n \"Native anonymize binding does not support caller detections\",\n );\n }\n const requestJson = callerDetectionRequestJson(options.detections);\n const operators = toBindingOperatorConfig(options.operators);\n const result: CanonicalStaticRedactionResult = JSON.parse(\n this.#prepared.redactStaticEntitiesWithCallerDetectionsJson(fullText, {\n requestJson,\n ...(operators ? { operators } : {}),\n }),\n );\n return fromCanonicalStaticRedactionResult(result);\n }\n\n redact_text_with_caller_detections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.redactStaticEntitiesWithCallerDetections(fullText, options);\n }\n\n redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n const redact =\n this.#prepared.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson;\n if (!redact) {\n return null;\n }\n const requestJson = callerDetectionRequestJson(options.detections);\n const operators = toBindingOperatorConfig(options.operators);\n return redact.call(this.#prepared, fullText, {\n requestJson,\n ...(operators ? { operators } : {}),\n });\n }\n\n redact_static_entities_with_caller_detections_diagnostics_json(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redactTextStreamJson(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesResultStreamJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesResultStreamJson(\n fullText,\n toBindingOperatorConfig(operators),\n onEvent,\n );\n }\n\n redact_text_stream_json(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redactStaticEntitiesDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesDiagnosticsJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesDiagnosticsJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactStaticEntitiesDiagnosticsJson(fullText, operators);\n }\n\n diagnosticsStreamJson(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesDiagnosticsStreamJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesDiagnosticsStreamJson(\n fullText,\n toBindingOperatorConfig(operators),\n onBatch,\n );\n }\n\n diagnostics_stream_json(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n redactStaticEntitiesSummaryDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n if (!this.#prepared.redactStaticEntitiesSummaryDiagnosticsJson) {\n return null;\n }\n return this.#prepared.redactStaticEntitiesSummaryDiagnosticsJson(\n fullText,\n toBindingOperatorConfig(operators),\n );\n }\n\n summary_diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactStaticEntitiesSummaryDiagnosticsJson(fullText, operators);\n }\n}\n\nexport class PreparedNativePipeline {\n readonly #anonymizer: PreparedNativeAnonymizer;\n\n constructor(anonymizer: PreparedNativeAnonymizer) {\n this.#anonymizer = anonymizer;\n }\n\n prepareDiagnosticsJson(): string | null {\n return this.#anonymizer.prepareDiagnosticsJson();\n }\n\n prepare_diagnostics_json(): string | null {\n return this.prepareDiagnosticsJson();\n }\n\n warmLazyRegex(): void {\n this.#anonymizer.warmLazyRegex();\n }\n\n warm_lazy_regex(): void {\n this.warmLazyRegex();\n }\n\n warmLazyRegexDiagnosticsJson(): string | null {\n return this.#anonymizer.warmLazyRegexDiagnosticsJson();\n }\n\n warm_lazy_regex_diagnostics_json(): string | null {\n return this.warmLazyRegexDiagnosticsJson();\n }\n\n createRedactionSession(sessionId: string): PreparedNativeRedactionSession {\n return this.#anonymizer.createRedactionSession(sessionId);\n }\n\n create_redaction_session(sessionId: string): PreparedNativeRedactionSession {\n return this.createRedactionSession(sessionId);\n }\n\n createRedactionSessionWithLifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.createRedactionSessionWithLifecycle(options);\n }\n\n create_redaction_session_with_lifecycle(\n options: NativeCreateSessionWithLifecycleOptions,\n ): PreparedNativeRedactionSession {\n return this.createRedactionSessionWithLifecycle(options);\n }\n\n restoreRedactionSession(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.restoreRedactionSession(plaintextJson);\n }\n\n restore_redaction_session(\n plaintextJson: string,\n ): PreparedNativeRedactionSession {\n return this.restoreRedactionSession(plaintextJson);\n }\n\n restoreEncryptedRedactionSession(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.#anonymizer.restoreEncryptedRedactionSession(options);\n }\n\n restore_encrypted_redaction_session(\n options: NativeOpenSessionArchiveOptions,\n ): PreparedNativeRedactionSession {\n return this.restoreEncryptedRedactionSession(options);\n }\n\n redactText(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.#anonymizer.redactStaticEntities(fullText, operators);\n }\n\n redact_text(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): NativeStaticRedactionResult {\n return this.redactText(fullText, operators);\n }\n\n redact_text_json(fullText: string, operators?: NativeOperatorConfig): string {\n return this.#anonymizer.redact_text_json(fullText, operators);\n }\n\n redactTextWithCallerDetections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.#anonymizer.redactStaticEntitiesWithCallerDetections(\n fullText,\n options,\n );\n }\n\n redact_text_with_caller_detections(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): NativeStaticRedactionResult {\n return this.redactTextWithCallerDetections(fullText, options);\n }\n\n redactTextWithCallerDetectionsDiagnosticsJson(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redact_text_with_caller_detections_diagnostics_json(\n fullText: string,\n options: NativeCallerRedactionOptions,\n ): string | null {\n return this.redactTextWithCallerDetectionsDiagnosticsJson(\n fullText,\n options,\n );\n }\n\n redactTextJson(fullText: string, operators?: NativeOperatorConfig): string {\n return this.redact_text_json(fullText, operators);\n }\n\n redactTextStreamJson(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redact_text_stream_json(\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextStreamJson(fullText, onEvent, operators);\n }\n\n redactTextDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesDiagnosticsJson(\n fullText,\n operators,\n );\n }\n\n diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextDiagnosticsJson(fullText, operators);\n }\n\n diagnosticsStreamJson(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n diagnostics_stream_json(\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.diagnosticsStreamJson(fullText, onBatch, operators);\n }\n\n redactTextSummaryDiagnosticsJson(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.#anonymizer.redactStaticEntitiesSummaryDiagnosticsJson(\n fullText,\n operators,\n );\n }\n\n summary_diagnostics_json(\n fullText: string,\n operators?: NativeOperatorConfig,\n ): string | null {\n return this.redactTextSummaryDiagnosticsJson(fullText, operators);\n }\n}\n\nexport const encodeNativeSearchConfig = (\n config: NativePreparedSearchConfig,\n): Uint8Array => new TextEncoder().encode(JSON.stringify(config));\n\nexport const encodeNativeSearchConfigInput = (\n config: NativeSearchPackageInput,\n): Uint8Array => {\n if (typeof config === \"string\") {\n return new TextEncoder().encode(config);\n }\n if (config instanceof Uint8Array) {\n return config;\n }\n return encodeNativeSearchConfig(config);\n};\n\nexport const getNativeBindingVersion = (\n binding: NativeAnonymizeBinding,\n): string => binding.nativePackageVersion();\n\nexport const native_package_version = getNativeBindingVersion;\n\nexport const normalize_for_search = ({\n binding,\n text,\n}: NativeNormalizeOptions): string => binding.normalizeForSearch(text);\n\nexport const assertNativeBindingVersion = ({\n binding,\n expectedVersion,\n}: NativeBindingVersionOptions): void => {\n const actualVersion = getNativeBindingVersion(binding);\n if (actualVersion !== expectedVersion) {\n throw new Error(\n `Native anonymize binding version ${actualVersion} does not match ${expectedVersion}`,\n );\n }\n};\n\nexport const prepareNativeSearchPackage = ({\n binding,\n config,\n compressed = false,\n}: NativeSearchPackageOptions): Uint8Array => {\n const configBytes = encodeNativeSearchConfig(config);\n return compressed\n ? binding.prepareStaticSearchCompressedPackageBytes(configBytes)\n : binding.prepareStaticSearchPackageBytes(configBytes);\n};\n\nexport const prepare_search_package = ({\n binding,\n config,\n compressed = false,\n}: SharedNativeSearchPackageOptions): Uint8Array => {\n const configBytes = encodeNativeSearchConfigInput(config);\n return compressed\n ? binding.prepareStaticSearchCompressedPackageBytes(configBytes)\n : binding.prepareStaticSearchPackageBytes(configBytes);\n};\n\nexport const createNativeAnonymizerFromConfig = ({\n binding,\n config,\n}: NativeAnonymizerFromConfigOptions): PreparedNativeAnonymizer =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfig(config),\n ),\n );\n\nexport const createNativeAnonymizerFromPackage = ({\n binding,\n packageBytes,\n}: NativeAnonymizerFromPackageOptions): PreparedNativeAnonymizer =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromPreparedPackageBytes(packageBytes),\n );\n\nexport const load_prepared_package = ({\n binding,\n packageBytes,\n}: SharedNativePreparedPackageOptions): PreparedNativeAnonymizer =>\n createNativeAnonymizerFromPackage({ binding, packageBytes });\n\nexport const redact_text_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeRedactTextJsonOptions): string =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text_json(fullText, operators);\n\nexport const redact_text = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeRedactTextOptions): NativeStaticRedactionResult =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text(fullText, operators);\n\nexport const redact_text_stream_json = ({\n binding,\n config,\n fullText,\n operators,\n onEvent,\n}: SharedNativeRedactTextStreamJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).redact_text_stream_json(fullText, onEvent, operators);\n\nexport const diagnostics_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeDiagnosticsJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).diagnostics_json(fullText, operators);\n\nexport const diagnostics_stream_json = ({\n binding,\n config,\n fullText,\n operators,\n onBatch,\n}: SharedNativeDiagnosticsStreamJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).diagnostics_stream_json(fullText, onBatch, operators);\n\nexport const summary_diagnostics_json = ({\n binding,\n config,\n fullText,\n operators,\n}: SharedNativeDiagnosticsJsonOptions): string | null =>\n new PreparedNativeAnonymizer(\n binding.NativePreparedSearch.fromConfigJsonBytes(\n encodeNativeSearchConfigInput(config),\n ),\n ).summary_diagnostics_json(fullText, operators);\n\nexport const createNativePipelineFromPackage = ({\n binding,\n packageBytes,\n}: NativePipelineFromPackageOptions): PreparedNativePipeline =>\n new PreparedNativePipeline(\n createNativeAnonymizerFromPackage({ binding, packageBytes }),\n );\n\nexport const PreparedSearch = PreparedNativeAnonymizer;\nexport type PreparedSearch = PreparedNativeAnonymizer;\nexport const PreparedAnonymizer = PreparedNativeAnonymizer;\nexport type PreparedAnonymizer = PreparedNativeAnonymizer;\n\nconst toBindingOperatorConfig = (\n config: NativeOperatorConfig | undefined,\n): NativeBindingOperatorConfig | undefined => {\n if (!config) {\n return undefined;\n }\n const bindingConfig: NativeBindingOperatorConfig = {};\n if (config.operators !== undefined) {\n bindingConfig.operators = config.operators;\n }\n if (config.redactString !== undefined) {\n bindingConfig.redactString = config.redactString;\n }\n return bindingConfig;\n};\n\nconst toNativeStaticRedactionResult = (\n result: NativeBindingStaticRedactionResult,\n): NativeStaticRedactionResult => ({\n resolvedEntities: result.resolvedEntities.map(toNativePipelineEntity),\n redaction: toNativeRedactionResult(result.redaction),\n});\n\nconst fromCanonicalStaticRedactionResult = (\n result: CanonicalStaticRedactionResult,\n): NativeStaticRedactionResult => ({\n resolvedEntities: result.resolved_entities.map(\n ({ source_detail, provider_id, detection_id, ...entity }) => ({\n ...entity,\n ...(source_detail ? { sourceDetail: source_detail } : {}),\n ...(provider_id ? { providerId: provider_id } : {}),\n ...(detection_id ? { detectionId: detection_id } : {}),\n }),\n ),\n redaction: {\n redactedText: result.redaction.redacted_text,\n redactionMap: toRedactionMap(result.redaction.redaction_map),\n operatorMap: toOperatorMap(result.redaction.operator_map),\n entityCount: result.redaction.entity_count,\n },\n});\n\nconst toBindingStaticRedactionResult = (\n result: NativeStaticRedactionResult,\n): CanonicalStaticRedactionResult => ({\n resolved_entities: result.resolvedEntities.map(toBindingPipelineEntity),\n redaction: {\n redacted_text: result.redaction.redactedText,\n redaction_map: [...result.redaction.redactionMap.entries()].map(\n ([placeholder, original]) => ({ placeholder, original }),\n ),\n operator_map: [...result.redaction.operatorMap.entries()].map(\n ([placeholder, operator]) => ({ placeholder, operator }),\n ),\n entity_count: result.redaction.entityCount,\n },\n});\n\nconst toNativePipelineEntity = (\n entity: NativeBindingPipelineEntity,\n): NativePipelineEntity => ({\n start: entity.start,\n end: entity.end,\n label: entity.label,\n text: entity.text,\n score: entity.score,\n source: entity.source,\n ...(entity.sourceDetail ? { sourceDetail: entity.sourceDetail } : {}),\n ...(entity.providerId ? { providerId: entity.providerId } : {}),\n ...(entity.detectionId ? { detectionId: entity.detectionId } : {}),\n});\n\nconst toBindingPipelineEntity = ({\n sourceDetail,\n providerId,\n detectionId,\n ...entity\n}: NativePipelineEntity): CanonicalPipelineEntity => ({\n ...entity,\n source_detail: sourceDetail ?? null,\n provider_id: providerId ?? null,\n detection_id: detectionId ?? null,\n});\n\nconst toNativeRedactionResult = (\n result: NativeBindingRedactionResult,\n): NativeRedactionResult => ({\n redactedText: result.redactedText,\n redactionMap: toRedactionMap(result.redactionMap),\n operatorMap: toOperatorMap(result.operatorMap),\n entityCount: result.entityCount,\n});\n\nconst toRedactionMap = (\n entries: readonly NativeBindingRedactionEntry[],\n): Map<string, string> => {\n const map = new Map<string, string>();\n for (const entry of entries) {\n map.set(entry.placeholder, entry.original);\n }\n return map;\n};\n\nconst toOperatorMap = (\n entries: readonly NativeBindingOperatorEntry[],\n): Map<string, OperatorType> => {\n const map = new Map<string, OperatorType>();\n for (const entry of entries) {\n map.set(entry.placeholder, entry.operator);\n }\n return map;\n};\n","/**\n * Cached state for a single pipeline run (or a sequence of runs sharing the\n * same config). The native pipeline builds its prepared package once and reuses\n * it across calls with the same config; the package bytes and the key/promise\n * that guard concurrent builds live here so callers can share one warmed\n * context.\n */\nexport type PipelineContext = {\n // ── Native prepared-package cache ─────────────\n nativePipelinePackage: Uint8Array | null;\n nativePipelinePackageKey: string;\n nativePipelinePackagePromise: Promise<Uint8Array> | null;\n};\n\n/** Create a fresh, empty pipeline context. */\nexport const createPipelineContext = (): PipelineContext => ({\n nativePipelinePackage: null,\n nativePipelinePackageKey: \"\",\n nativePipelinePackagePromise: null,\n});\n\n/**\n * Module-level default context. Used when callers\n * don't provide an explicit context, preserving full\n * backward compatibility with the existing API.\n */\nexport const defaultContext: PipelineContext = createPipelineContext();\n","import {\n DEFAULT_OPERATOR_CONFIG,\n maskReplacementSpans,\n OPERATOR_REGISTRY,\n operatorType,\n requireMaskSelection,\n resolveOperator,\n} from \"./operators\";\nimport type {\n Entity,\n OperatorConfig,\n OperatorType,\n RedactionResult,\n} from \"./types\";\nimport type { PipelineContext } from \"./context\";\nimport { defaultContext } from \"./context\";\n\nconst WHITESPACE_RE = /\\s+/g;\nconst PHONE_NOISE_RE = /[()\\s-]/g;\nconst ETHEREUM_ADDRESS_RE = /0x[0-9A-Fa-f]{40}/;\nconst BECH32_ADDRESS_RE = /\\bbc1[ac-hj-np-z02-9]{11,71}\\b/i;\nconst BASE58_ADDRESS_RE = /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/;\nconst NHS_NUMBER_CUE_RE = /\\b(?:NHS|National\\s+Health\\s+Service)\\b/i;\nconst PLACEHOLDER_TOKEN_RE = /\\[[^\\s[\\]]+_[1-9]\\d*\\]/g;\nconst PASSPORT_IDENTIFIER_RE =\n /\\b(?:[A-Za-z]{1,2}\\d{6,8}|\\d{2}[A-Za-z]{2}\\d{5}|\\d{7,9})\\b/;\n// Strip all separators the ID detectors accept so the\n// same real-world value canonicalises to one placeholder:\n// - whitespace and `-` for IBAN, NIP, REGON, etc.\n// - `/` for birth numbers (\"900101/1234\") and Czech\n// bank accounts (\"123-4567/0100\").\n// - `.` for credit cards (\"4111.1111.1111.1111\") and\n// other dotted IDs.\nconst ID_SEPARATOR_RE = /[\\s\\-/.]/g;\n\nconst nextPlaceholder = (\n labelKey: string,\n counters: Map<string, number>,\n reservedPlaceholders: ReadonlySet<string>,\n): string => {\n let count = counters.get(labelKey) ?? 0;\n\n while (true) {\n count += 1;\n const placeholder = `[${labelKey}_${count}]`;\n if (reservedPlaceholders.has(placeholder)) continue;\n\n counters.set(labelKey, count);\n return placeholder;\n }\n};\n\nconst collectReservedPlaceholders = (\n reservedText: string,\n): ReadonlySet<string> => new Set(reservedText.match(PLACEHOLDER_TOKEN_RE));\n\nconst normalizeCryptoText = (text: string): string => {\n const trimmed = text.trim();\n\n const ethereumAddress = ETHEREUM_ADDRESS_RE.exec(trimmed)?.[0];\n if (ethereumAddress) {\n return ethereumAddress.toLowerCase();\n }\n\n const bech32Address = BECH32_ADDRESS_RE.exec(trimmed)?.[0];\n if (bech32Address) {\n return bech32Address.toLowerCase();\n }\n\n const base58Address = BASE58_ADDRESS_RE.exec(trimmed)?.[0];\n return base58Address ?? trimmed;\n};\n\nconst normalizePassportText = (text: string): string => {\n const passportIdentifier = PASSPORT_IDENTIFIER_RE.exec(text)?.[0] ?? text;\n return passportIdentifier.replace(ID_SEPARATOR_RE, \"\").toUpperCase();\n};\n\n/**\n * Normalize entity text so that surface-form variations\n * of the same real-world value map to a single canonical\n * key. Lowercased emails, stripped phone formatting, etc.\n */\nconst normalizeEntityText = (label: string, text: string): string => {\n const upper = label.toUpperCase().replace(WHITESPACE_RE, \"_\");\n\n if (upper === \"EMAIL_ADDRESS\" || upper === \"EMAIL\") {\n return text.toLowerCase().trim();\n }\n if (upper === \"PHONE_NUMBER\" || upper === \"PHONE\") {\n return text.replace(PHONE_NOISE_RE, \"\");\n }\n if (upper === \"CRYPTO\") {\n return normalizeCryptoText(text);\n }\n if (\n upper === \"NATIONAL_IDENTIFICATION_NUMBER\" &&\n NHS_NUMBER_CUE_RE.test(text)\n ) {\n return text.replace(/\\D/g, \"\");\n }\n if (\n upper === \"IBAN\" ||\n upper === \"BANK_ACCOUNT_NUMBER\" ||\n upper === \"TAX_IDENTIFICATION_NUMBER\" ||\n upper === \"REGISTRATION_NUMBER\" ||\n upper === \"NATIONAL_IDENTIFICATION_NUMBER\" ||\n upper === \"SOCIAL_SECURITY_NUMBER\" ||\n upper === \"BIRTH_NUMBER\" ||\n upper === \"IDENTITY_CARD_NUMBER\" ||\n upper === \"CREDIT_CARD_NUMBER\"\n ) {\n return text.replace(ID_SEPARATOR_RE, \"\").toUpperCase();\n }\n if (upper === \"PASSPORT_NUMBER\") {\n return normalizePassportText(text);\n }\n if (\n upper === \"PERSON\" ||\n upper === \"ORGANIZATION\" ||\n upper === \"ADDRESS\" ||\n upper === \"LAND_PARCEL\" ||\n upper === \"MISC\"\n ) {\n return text.replace(WHITESPACE_RE, \" \").toLowerCase().trim();\n }\n return text.trim();\n};\n\nconst nonOverlappingEntities = (entities: Entity[]): Entity[] => {\n const result: Entity[] = [];\n let lastEnd = 0;\n for (const entity of entities) {\n if (entity.start < lastEnd) continue;\n result.push(entity);\n lastEnd = entity.end;\n }\n return result;\n};\n\ntype MaskReplacementSpan = {\n start: number;\n end: number;\n replacement: string;\n};\n\nconst removeRedactedMaskOverlaps = (\n replacements: MaskReplacementSpan[],\n redacted: Entity[],\n): MaskReplacementSpan[] => {\n const result: MaskReplacementSpan[] = [];\n let redactedIndex = 0;\n for (const replacement of replacements) {\n while (true) {\n const candidate = redacted.at(redactedIndex);\n if (candidate === undefined || candidate.end > replacement.start) break;\n redactedIndex += 1;\n }\n const redactedEntity = redacted.at(redactedIndex);\n const overlaps =\n redactedEntity !== undefined &&\n redactedEntity.start < replacement.end &&\n replacement.start < redactedEntity.end;\n if (!overlaps) result.push(replacement);\n }\n return result;\n};\n\n/**\n * Build a stable mapping from entity text to numbered\n * placeholders. Same real-world value always maps to the\n * same placeholder (e.g., \"Dr. Muller\" and \"Dr. Muller\"\n * share one person placeholder).\n *\n * Placeholder format: [LABEL_N] where LABEL is uppercase.\n * N is allocated per label and skips tokens already present\n * in reserved text.\n *\n * @param _ctx Unused. Kept for signature compatibility;\n * coref alias links now travel on the entities\n * themselves (`corefSourceText`).\n */\ntype PlaceholderMapOptions = {\n reservedText?: string;\n};\n\nexport const buildPlaceholderMap = (\n entities: Entity[],\n _ctx: PipelineContext = defaultContext,\n { reservedText = \"\" }: PlaceholderMapOptions = {},\n): Map<string, string> => {\n const counters = new Map<string, number>();\n const textLabelToPlaceholder = new Map<string, string>();\n const normalizedToPlaceholder = new Map<string, string>();\n const reservedPlaceholders = collectReservedPlaceholders(reservedText);\n\n const sorted = entities.toSorted((a, b) => a.start - b.start);\n\n for (const entity of sorted) {\n const compositeKey = `${entity.label}\\0${entity.text}`;\n if (textLabelToPlaceholder.has(compositeKey)) {\n continue;\n }\n\n const labelKey = entity.label.toUpperCase().replace(WHITESPACE_RE, \"_\");\n\n // If this entity is a coref alias, unify its key\n // with the source entity's key so both get the same\n // number — in either direction: a backward alias\n // joins the source's existing placeholder, and a\n // forward alias (bare mention before the full form)\n // reserves its placeholder under the source key so\n // the source joins it when numbered later. The link\n // is carried on the entity itself, so it cannot be\n // lost between detection and redaction.\n const sourceText =\n entity.source === \"coreference\" ? entity.corefSourceText : undefined;\n const sourceNormalizedKey =\n sourceText === undefined\n ? undefined\n : `${labelKey}\\0${normalizeEntityText(entity.label, sourceText)}`;\n if (sourceNormalizedKey !== undefined) {\n const sourceExisting = normalizedToPlaceholder.get(sourceNormalizedKey);\n if (sourceExisting) {\n textLabelToPlaceholder.set(compositeKey, sourceExisting);\n continue;\n }\n }\n\n const normalized = normalizeEntityText(entity.label, entity.text);\n const normalizedKey = `${labelKey}\\0${normalized}`;\n const existing = normalizedToPlaceholder.get(normalizedKey);\n if (existing) {\n textLabelToPlaceholder.set(compositeKey, existing);\n if (sourceNormalizedKey !== undefined) {\n normalizedToPlaceholder.set(sourceNormalizedKey, existing);\n }\n continue;\n }\n\n const placeholder = nextPlaceholder(\n labelKey,\n counters,\n reservedPlaceholders,\n );\n textLabelToPlaceholder.set(compositeKey, placeholder);\n normalizedToPlaceholder.set(normalizedKey, placeholder);\n if (sourceNormalizedKey !== undefined) {\n normalizedToPlaceholder.set(sourceNormalizedKey, placeholder);\n }\n }\n\n return textLabelToPlaceholder;\n};\n\n/**\n * Apply redactions to the source text, replacing each\n * confirmed entity span using the configured operator.\n *\n * Co-references are consistent: if the same text appears\n * multiple times, all occurrences get the same placeholder.\n *\n * @param ctx Pipeline context. Must be the same instance\n * passed to `runPipeline` (or `findCoreferenceSpans`)\n * so coreference placeholder links are preserved.\n * Defaults to `defaultContext` for single-tenant usage.\n */\nexport const redactText = (\n fullText: string,\n entities: Entity[],\n config: OperatorConfig = DEFAULT_OPERATOR_CONFIG,\n ctx: PipelineContext = defaultContext,\n): RedactionResult => {\n if (entities.length === 0) {\n return {\n redactedText: fullText,\n redactionMap: new Map(),\n operatorMap: new Map(),\n entityCount: 0,\n };\n }\n\n const placeholderMap = buildPlaceholderMap(entities, ctx, {\n reservedText: fullText,\n });\n\n const sorted = entities.toSorted((a, b) => a.start - b.start);\n\n const kept: Entity[] = [];\n const masked: Entity[] = [];\n const redacted: Entity[] = [];\n for (const entity of sorted) {\n const opType = operatorType(resolveOperator(config, entity.label));\n if (opType === \"keep\") {\n kept.push(entity);\n } else if (opType === \"mask\") {\n masked.push(entity);\n } else {\n redacted.push(entity);\n }\n }\n const selectedKept = nonOverlappingEntities(kept);\n const selectedMasked = nonOverlappingEntities(masked);\n const selectedRedacted = nonOverlappingEntities(redacted);\n\n const maskReplacements: MaskReplacementSpan[] = [];\n for (const entity of selectedMasked) {\n const selection = resolveOperator(config, entity.label);\n const sourceText = fullText.slice(entity.start, entity.end);\n for (const replacement of maskReplacementSpans(\n sourceText,\n requireMaskSelection(selection),\n )) {\n maskReplacements.push({\n start: entity.start + replacement.start,\n end: entity.start + replacement.end,\n replacement: replacement.replacement,\n });\n }\n }\n const visibleMaskReplacements = removeRedactedMaskOverlaps(\n maskReplacements,\n selectedRedacted,\n );\n\n const parts: string[] = [];\n const redactionMap = new Map<string, string>();\n const operatorMap = new Map<string, OperatorType>();\n let cursor = 0;\n\n const placeholderFor = (entity: Entity): string =>\n placeholderMap.get(`${entity.label}\\0${entity.text}`) ??\n `[${entity.label.toUpperCase().replace(/\\s+/g, \"_\")}]`;\n const processed = [\n ...selectedKept,\n ...selectedMasked,\n ...selectedRedacted,\n ].toSorted((a, b) => a.start - b.start);\n for (const entity of processed) {\n operatorMap.set(\n placeholderFor(entity),\n operatorType(resolveOperator(config, entity.label)),\n );\n }\n\n let redactedIndex = 0;\n let maskIndex = 0;\n while (\n redactedIndex < selectedRedacted.length ||\n maskIndex < visibleMaskReplacements.length\n ) {\n const redactedEntity = selectedRedacted.at(redactedIndex);\n const maskReplacement = visibleMaskReplacements.at(maskIndex);\n const useRedacted =\n redactedEntity !== undefined &&\n (maskReplacement === undefined ||\n redactedEntity.start <= maskReplacement.start);\n const start = useRedacted\n ? (redactedEntity?.start ?? cursor)\n : (maskReplacement?.start ?? cursor);\n const end = useRedacted\n ? (redactedEntity?.end ?? start)\n : (maskReplacement?.end ?? start);\n if (start > cursor) parts.push(fullText.slice(cursor, start));\n\n if (!useRedacted && maskReplacement !== undefined) {\n parts.push(maskReplacement.replacement);\n cursor = end;\n maskIndex += 1;\n continue;\n }\n if (redactedEntity === undefined) break;\n\n const entity = redactedEntity;\n const placeholder = placeholderFor(entity);\n\n const selection = resolveOperator(config, entity.label);\n const opType = operatorType(selection);\n const operator = OPERATOR_REGISTRY[opType];\n\n const replacement = operator.apply(\n entity.text,\n entity.label,\n placeholder,\n config.redactString,\n selection,\n );\n\n parts.push(replacement);\n // Only populate redactionMap for reversible operators.\n // A coref alias contributes its source's full text, so\n // a forward alias (\"Acme\" before \"Acme Corporation\")\n // cannot pin the shortened surface form as the key's\n // canonical value for the shared placeholder.\n if (\n operator.reversibility === \"reversible\" &&\n !redactionMap.has(placeholder)\n ) {\n redactionMap.set(\n placeholder,\n entity.source === \"coreference\" ? entity.corefSourceText : entity.text,\n );\n }\n\n cursor = end;\n redactedIndex += 1;\n }\n\n if (cursor < fullText.length) {\n parts.push(fullText.slice(cursor));\n }\n\n return {\n redactedText: parts.join(\"\"),\n redactionMap,\n operatorMap,\n entityCount:\n selectedKept.length + selectedMasked.length + selectedRedacted.length,\n };\n};\n\n/**\n * Serialize the redaction key to JSON for export.\n * Includes operator metadata so the export is self-describing.\n */\nexport const exportRedactionKey = (\n redactionMap: Map<string, string>,\n operatorMap: Map<string, OperatorType>,\n): string => {\n const entries: Record<string, { original: string; operator: OperatorType }> =\n {};\n\n for (const [placeholder, value] of redactionMap) {\n entries[placeholder] = {\n original: value,\n operator: operatorMap.get(placeholder) ?? \"replace\",\n };\n }\n\n return JSON.stringify({ entries }, null, 2);\n};\n\n/**\n * De-anonymise text using a redaction key.\n * Replaces placeholders back with original values.\n * Only works for reversible operators (replace).\n */\nexport const deanonymise = (\n redactedText: string,\n redactionMap: Map<string, string>,\n): string => {\n let result = redactedText;\n\n for (const [placeholder, original] of redactionMap) {\n result = result.replaceAll(placeholder, original);\n }\n\n return result;\n};\n","// Runtime-free constants live in `./constants`; re-exported\n// here for back-compat with existing call sites that import\n// from `@stll/anonymize` directly.\n//\n// `verbatimModuleSyntax` requires an explicit type-only\n// import for any name used locally as a type even when it\n// is also re-exported below — applies to `DetectionSource`\n// (used by `Entity`) and `OperatorType` (used by\n// `OperatorConfig`).\nimport type { DetectionSource, OperatorType } from \"./constants\";\nimport { DETECTION_SOURCES } from \"./constants\";\n\nexport {\n DETECTION_SOURCES,\n DETECTOR_PRIORITY,\n type DetectionSource,\n} from \"./constants\";\n\n/**\n * Fields shared by every entity span in the source text.\n */\ntype EntityBase = {\n start: number;\n end: number;\n label: string;\n text: string;\n score: number;\n sourceDetail?: \"custom-deny-list\" | \"custom-regex\" | \"gazetteer-extension\";\n};\n\n/**\n * A PII entity span found by a primary detection layer\n * (regex, NER, legal forms, deny list, ...).\n */\nexport type DetectedEntity = EntityBase & {\n source: Exclude<DetectionSource, typeof DETECTION_SOURCES.COREFERENCE>;\n};\n\n/**\n * An alias mention of a previously detected entity: a\n * defined term (\"the Seller\") or a propagated bare\n * mention (\"Acme\" after \"Acme Corp.\").\n *\n * `corefSourceText` is required by construction, so an\n * alias cannot exist without the link back to its source\n * entity. Placeholder numbering reads it to give the\n * alias the same placeholder as the source. The link\n * travels with the entity instead of living in a\n * side-channel map that a producer could forget to\n * write — or that a later pass could clear.\n */\nexport type CorefAliasEntity = EntityBase & {\n source: typeof DETECTION_SOURCES.COREFERENCE;\n /** Full text of the source entity this alias refers to. */\n corefSourceText: string;\n};\n\n/**\n * A detected PII entity span in the source text.\n * Every detection layer produces these.\n */\nexport type Entity = DetectedEntity | CorefAliasEntity;\n\n/**\n * Entity after human review. Extends the base Entity\n * with a review decision.\n */\nexport type ReviewDecision = \"confirmed\" | \"rejected\" | \"relabeled\";\n\nexport type ReviewedEntity = Entity & {\n decision?: ReviewDecision;\n originalLabel?: string;\n};\n\n/**\n * A single entry in the workspace-scoped gazetteer\n * (deny list). Persisted in IndexedDB.\n */\nexport type GazetteerEntry = {\n id: string;\n canonical: string;\n label: string;\n variants: string[];\n workspaceId: string;\n createdAt: number;\n source: \"manual\" | \"confirmed-from-model\";\n};\n\n/** Extraction strategy — closed discriminated union. */\nexport type TriggerStrategy =\n | {\n type: \"to-next-comma\";\n /**\n * Optional list of lowercase keywords that terminate\n * the value scan, in addition to commas/newlines. Useful\n * for triggers like court names that may continue past\n * a missing comma into adjacent clause text (\"Městským\n * soudem v Praze dne 1. 1. 2020\"); listing `\"dne\"` here\n * stops the scan at the date boundary. Matched on a\n * word-boundary, case-insensitive.\n */\n stopWords?: string[];\n /**\n * Hard cap on the captured span length, in characters,\n * regardless of where the next comma / stop char sits.\n * Use for triggers that label short formulaic phrases\n * (\"State of Delaware\") and must not absorb the rest\n * of a long forum-selection clause when the comma is\n * sentences away. Falls back to the default 100-char\n * fallback when omitted.\n */\n maxLength?: number;\n }\n | { type: \"to-end-of-line\" }\n | { type: \"n-words\"; count: number }\n | { type: \"company-id-value\" }\n | { type: \"address\"; maxChars?: number }\n | {\n /**\n * Extract the first regex match in the value text.\n * Useful for shape-bounded values that follow a\n * label on the same line as other fields, where\n * `to-end-of-line` would over-capture. The pattern\n * is anchored to the start of the (already\n * leading-whitespace-stripped) value, so use\n * `(?:.*?)` prefix only when intentional.\n */\n type: \"match-pattern\";\n pattern: string;\n flags?: string;\n };\n\n/** Validation rules — closed discriminated union. */\nexport type TriggerValidation =\n | { type: \"starts-uppercase\" }\n | { type: \"min-length\"; min: number }\n | { type: \"max-length\"; max: number }\n | { type: \"no-digits\" }\n | { type: \"has-digits\" }\n | {\n type: \"matches-pattern\";\n pattern: string;\n flags?: string;\n }\n /**\n * Run a named stdnum validator (checksum + length)\n * against the captured value. Keeps the trigger\n * path symmetrical with the formatted-regex\n * detectors so e.g. `CPF nº 00000000000` does not\n * survive as a tax-ID entity.\n */\n | { type: \"valid-id\"; validator: ValidIdValidator };\n\n/** Built-in stdnum validators that can be referenced\n * by `valid-id` validations. */\nexport type ValidIdValidator = \"br.cpf\" | \"br.cnpj\" | \"us.rtn\";\n\n/** Auto-generated trigger variants — closed set. */\nexport type TriggerExtension =\n | \"add-colon\"\n | \"add-trailing-space\"\n | \"add-colon-space\"\n | \"normalize-spaces\";\n\n/** V2 trigger config entry (JSON shape). */\nexport type TriggerGroupConfig = {\n id?: string;\n triggers: string[];\n label: string;\n strategy: TriggerStrategy;\n extensions?: TriggerExtension[];\n validations?: TriggerValidation[];\n /** When true, include the trigger text in the\n * entity span (e.g., court names). */\n includeTrigger?: boolean;\n};\n\n/** Compiled validation with pre-built regex. */\nexport type CompiledValidation =\n | { type: \"starts-uppercase\"; re: RegExp }\n | { type: \"min-length\"; min: number }\n | { type: \"max-length\"; max: number }\n | { type: \"no-digits\"; re: RegExp }\n | { type: \"has-digits\"; re: RegExp }\n | { type: \"matches-pattern\"; re: RegExp }\n | {\n type: \"valid-id\";\n validator: ValidIdValidator;\n check: (value: string) => boolean;\n };\n\n/**\n * Runtime rule — one per trigger string after\n * expansion. Fed to the Aho-Corasick automaton.\n */\nexport type TriggerRule = {\n trigger: string;\n label: string;\n strategy: TriggerStrategy;\n validations: CompiledValidation[];\n includeTrigger: boolean;\n};\n\nexport {\n ENTITY_CAPABILITIES,\n ENTITY_LABELS,\n ENTITY_SELECTIONS,\n OPERATOR_TYPES,\n type DefaultEntityLabel,\n type EntityCapability,\n type EntityLabel,\n type EntitySelection,\n type OperatorType,\n} from \"./constants\";\n\n/** Per-label operator selection. Key is the entity label. */\nexport type MaskDirection = \"start\" | \"end\";\n\nexport type MaskOperatorConfig = {\n type: \"mask\";\n maskingCharacter: string;\n charactersToMask: number;\n direction: MaskDirection;\n};\n\nexport type OperatorSelection =\n | Exclude<OperatorType, \"mask\">\n | MaskOperatorConfig;\n\nexport type OperatorConfig = {\n /** Operator per label. Missing labels default to \"replace\". */\n operators: Record<string, OperatorSelection>;\n /** Custom replacement string for the redact operator. */\n redactString: string;\n};\n\n/** Whether an operator produces a reversible redaction entry. */\ntype OperatorReversibility = \"reversible\" | \"irreversible\" | \"preserving\";\n\nexport type AnonymisationOperator = {\n type: OperatorType;\n reversibility: OperatorReversibility;\n /**\n * Apply the operator to a single entity occurrence.\n * Returns the replacement string to embed in the document.\n */\n apply: (\n text: string,\n label: string,\n placeholder: string,\n redactString: string,\n selection: OperatorSelection,\n ) => string;\n};\n\n/**\n * Redacted document output with stable entity mapping.\n */\nexport type RedactionResult = {\n redactedText: string;\n /**\n * Maps placeholder to original text. Only populated for\n * reversible operators (replace). Empty for redact, keep, and mask.\n */\n redactionMap: Map<string, string>;\n /** Maps placeholder to the operator that produced it. */\n operatorMap: Map<string, OperatorType>;\n entityCount: number;\n};\n\n/**\n * Configuration for the detection pipeline.\n */\nexport type DenyListCategory =\n | \"Names\"\n | \"Places\"\n | \"Addresses\"\n | \"Courts\"\n | \"Financial\"\n | \"Government\"\n | \"Healthcare\"\n | \"Education\"\n | \"Political\"\n | \"Organizations\"\n | \"International\";\n\n/**\n * Metadata for a single dictionary entry in the\n * deny-list system. Mirrors the shape from\n * the anonymize-data package so consumers can pass\n * pre-loaded data without a runtime dependency.\n */\nexport type DictionaryMeta = {\n label: string;\n category: DenyListCategory;\n country: string | null;\n};\n\n/**\n * Caller-supplied exact terms for deny-list matching.\n * These entries are merged with the published deny-list\n * dictionaries when `enableDenyList` is enabled.\n */\nexport type CustomDenyListEntry = {\n value: string;\n label: string;\n variants?: readonly string[];\n};\n\n/**\n * Caller-supplied regex detector. The pattern is passed\n * to the native Rust regex engine, so use its supported\n * regex syntax. Inline flags such as `(?i)` are accepted\n * when supported by that engine.\n */\nexport type CustomRegexPattern = {\n pattern: string;\n label: string;\n score?: number;\n preparedArtifactPolicy?: \"include\" | \"omit\";\n};\n\n/**\n * Pre-loaded dictionary data for dependency injection.\n * Consumers that want name/city/deny-list detection\n * load dictionaries themselves (e.g. from the\n * anonymize-data package) and pass them here; the\n * anonymize package has zero cross-package imports.\n *\n * All fields are optional. When a field is absent,\n * the corresponding detection path is skipped (same\n * behavior as when no dictionaries are available).\n */\nexport type Dictionaries = {\n /**\n * First names per language code (e.g., \"cs\", \"de\").\n */\n firstNames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Surnames per language code.\n */\n surnames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Non-Western name tokens per locale code\n * (e.g., \"in\", \"ar\", \"ja-latn\", \"ko\", \"zh-latn\",\n * \"th\", \"vi\", \"fil\", \"id\"). Merged with bundled\n * names-nw-*.json data at init time.\n */\n nonWesternNames?: Readonly<Record<string, readonly string[]>>;\n /**\n * Pre-loaded deny-list dictionaries keyed by\n * dictionary ID (e.g., \"courts/CZ\", \"banks/DE\").\n * Each value is the array of terms for that\n * dictionary.\n */\n denyList?: Readonly<Record<string, readonly string[]>>;\n /**\n * Metadata per dictionary ID. Required when\n * `denyList` is provided so the pipeline knows\n * labels, categories, and country filters.\n */\n denyListMeta?: Readonly<Record<string, DictionaryMeta>>;\n /**\n * Pre-loaded city names, already merged across\n * all desired countries.\n *\n * Prefer `citiesByCountry` when callers also pass\n * `denyListCountries` / `denyListRegions`; merged\n * city arrays cannot be scoped after injection.\n */\n cities?: readonly string[];\n /**\n * Pre-loaded city names keyed by ISO 3166-1 alpha-2\n * country code. When provided, the deny-list builder\n * applies `denyListCountries` / `denyListRegions`\n * before adding city patterns to the search automaton.\n */\n citiesByCountry?: Readonly<Record<string, readonly string[]>>;\n};\n\nexport type PipelineConfig = {\n threshold: number;\n enableTriggerPhrases: boolean;\n enableRegex: boolean;\n /**\n * Expected content language codes. When present, these\n * derive default dictionary scopes for name corpus and\n * deny-list matching unless the lower-level scope fields\n * below are set explicitly.\n */\n languages?: string[];\n /**\n * Convenience form for single-language documents. Ignored\n * when `languages` is also provided.\n */\n language?: string;\n /**\n * Enables legal-form organization detection.\n * Required for typed callers; legacy untyped\n * callers that omit this field are treated as\n * enabled at runtime for backward compatibility.\n */\n enableLegalForms: boolean;\n /**\n * Enables first-name/surname/title corpus matching.\n * When deny-list mode is enabled, this also controls\n * whether name-corpus entries are injected into the\n * deny-list search automaton.\n */\n enableNameCorpus: boolean;\n /**\n * Optional language scope for first-name/surname\n * dictionaries, using the keys present in\n * `dictionaries.firstNames` / `dictionaries.surnames`\n * (for example `[\"en\", \"de\"]`). When omitted, all\n * injected name languages are used for backward\n * compatibility.\n */\n nameCorpusLanguages?: string[];\n enableDenyList: boolean;\n denyListCountries?: string[];\n denyListRegions?: string[];\n denyListExcludeCategories?: string[];\n /**\n * Caller-owned exact terms to match through the\n * deny-list layer. Requires `enableDenyList: true`.\n */\n customDenyList?: readonly CustomDenyListEntry[];\n /**\n * Caller-owned regex detectors. Requires\n * `enableRegex: true`.\n */\n customRegexes?: readonly CustomRegexPattern[];\n enableGazetteer: boolean;\n /**\n * Detect country names (ISO 3166-1 names, curated\n * aliases, alpha-3 codes). Defaults to true. Names\n * span all manifest languages plus widely-used\n * additions (Dutch, Russian, Chinese, Arabic, etc.).\n */\n enableCountries?: boolean;\n enableConfidenceBoost: boolean;\n enableCoreference: boolean;\n enableZoneClassification?: boolean;\n enableHotwordRules?: boolean;\n /**\n * Requested output labels. An empty array means\n * \"do not filter by label\" for deterministic detectors.\n */\n labels: string[];\n workspaceId: string;\n /**\n * Pre-loaded dictionary data for name, deny-list,\n * and city detection. When omitted, dictionary-based\n * detection paths are skipped. Consumers load from\n * the anonymize-data package and pass the data here.\n */\n dictionaries?: Dictionaries;\n};\n\nexport { DEFAULT_ENTITY_LABELS } from \"./constants\";\n\nexport const isLegalFormsEnabled = (\n config: Pick<PipelineConfig, \"enableLegalForms\">,\n): boolean => config.enableLegalForms !== false;\n","","import languageScopes from \"./data/language-scopes.json\";\n\nimport type { PipelineConfig } from \"./types\";\n\ntype LanguageScope = {\n nameCorpusLanguages?: readonly string[];\n denyListCountries?: readonly string[];\n};\n\ntype LanguageScopeData = {\n languages: Record<string, LanguageScope>;\n};\n\nconst scopeData = languageScopes as LanguageScopeData;\n\nconst normalizeLanguage = (language: string): string =>\n language.trim().toLowerCase();\n\nconst fallbackLanguage = (language: string): string | null => {\n const index = language.indexOf(\"-\");\n return index === -1 ? null : language.slice(0, index);\n};\n\nconst uniquePush = (target: string[], values: readonly string[]): void => {\n const seen = new Set(target);\n for (const value of values) {\n if (seen.has(value)) {\n continue;\n }\n seen.add(value);\n target.push(value);\n }\n};\n\nconst resolveLanguageScope = (language: string): LanguageScope | null => {\n const normalized = normalizeLanguage(language);\n if (normalized.length === 0) {\n return null;\n }\n const exact = scopeData.languages[normalized];\n if (exact !== undefined) {\n return exact;\n }\n const fallback = fallbackLanguage(normalized);\n return fallback === null ? null : (scopeData.languages[fallback] ?? null);\n};\n\nconst configuredLanguages = (config: PipelineConfig): readonly string[] => {\n if (config.languages !== undefined) {\n return config.languages;\n }\n return config.language === undefined ? [] : [config.language];\n};\n\nexport const configuredContentLanguages = (\n config: Pick<PipelineConfig, \"language\" | \"languages\">,\n): readonly string[] | undefined => {\n if (config.languages !== undefined) {\n return config.languages;\n }\n return config.language === undefined ? undefined : [config.language];\n};\n\nexport const applyPipelineLanguageScope = (\n config: PipelineConfig,\n): PipelineConfig => {\n const languages = configuredLanguages(config);\n if (languages.length === 0) {\n return config;\n }\n\n const nameCorpusLanguages: string[] = [];\n const denyListCountries: string[] = [];\n for (const language of languages) {\n const scope = resolveLanguageScope(language);\n if (scope === null) {\n continue;\n }\n uniquePush(nameCorpusLanguages, scope.nameCorpusLanguages ?? []);\n uniquePush(denyListCountries, scope.denyListCountries ?? []);\n }\n\n const next: Partial<PipelineConfig> = {};\n if (\n config.nameCorpusLanguages === undefined &&\n nameCorpusLanguages.length > 0\n ) {\n next.nameCorpusLanguages = nameCorpusLanguages;\n }\n if (config.denyListCountries === undefined && denyListCountries.length > 0) {\n next.denyListCountries = denyListCountries;\n }\n\n return Object.keys(next).length === 0 ? config : { ...config, ...next };\n};\n","const normalizeLanguageCode = (language: string): string =>\n language.trim().toLowerCase();\n\nconst normalizeLanguageSelection = (\n languages: readonly string[] | undefined,\n): string[] =>\n languages === undefined\n ? []\n : languages\n .map(normalizeLanguageCode)\n .filter((language) => language.length > 0);\n\nexport const languageSelectionKey = (\n languages: readonly string[] | undefined,\n): string => {\n const normalized = normalizeLanguageSelection(languages).toSorted();\n return normalized.length === 0 ? \"*\" : normalized.join(\",\");\n};\n\nconst baseLanguage = (language: string): string => {\n const index = language.indexOf(\"-\");\n return index === -1 ? language : language.slice(0, index);\n};\n\nexport const languageConfigMatches = (\n configLanguage: string,\n selectedLanguages: readonly string[] | undefined,\n): boolean => {\n if (selectedLanguages === undefined || selectedLanguages.length === 0) {\n return true;\n }\n const normalizedSelectedLanguages =\n normalizeLanguageSelection(selectedLanguages);\n if (normalizedSelectedLanguages.length === 0) {\n return true;\n }\n\n const normalizedConfigLanguage = normalizeLanguageCode(configLanguage);\n if (normalizedConfigLanguage.length === 0) {\n return false;\n }\n\n const genericConfig =\n baseLanguage(normalizedConfigLanguage) === normalizedConfigLanguage;\n for (const normalizedLanguage of normalizedSelectedLanguages) {\n if (normalizedLanguage === normalizedConfigLanguage) {\n return true;\n }\n if (\n genericConfig &&\n baseLanguage(normalizedLanguage) === normalizedConfigLanguage\n ) {\n return true;\n }\n }\n\n return false;\n};\n","import {\n isLegalFormsEnabled,\n type GazetteerEntry,\n type PipelineConfig,\n} from \"./types\";\nimport { languageSelectionKey } from \"./util/language-selection\";\n\nconst DEFAULT_CUSTOM_REGEX_SCORE = 0.9;\n\nconst contentLanguageFingerprint = (\n config: Pick<PipelineConfig, \"language\" | \"languages\">,\n): string => {\n const languages =\n config.languages ??\n (config.language === undefined ? [] : [config.language]);\n return languageSelectionKey(languages);\n};\n\nexport const pipelineConfigKey = (\n config: PipelineConfig,\n gazetteerEntries: readonly GazetteerEntry[],\n): string => {\n const legalFormsEnabled = isLegalFormsEnabled(config);\n const customDenyFingerprint =\n config.enableDenyList && config.customDenyList\n ? config.customDenyList\n .map((entry) =>\n JSON.stringify({\n label: entry.label,\n value: entry.value,\n variants: [...(entry.variants ?? [])].sort(),\n }),\n )\n .sort()\n .join(\"\\n\")\n : \"\";\n const customRegexFingerprint =\n config.enableRegex && config.customRegexes\n ? config.customRegexes\n .map((entry) =>\n JSON.stringify({\n label: entry.label,\n pattern: entry.pattern,\n preparedArtifactPolicy: entry.preparedArtifactPolicy ?? null,\n score: entry.score ?? DEFAULT_CUSTOM_REGEX_SCORE,\n }),\n )\n .sort()\n .join(\"\\n\")\n : \"\";\n const gazFingerprint =\n config.enableGazetteer && gazetteerEntries.length > 0\n ? gazetteerEntries\n .map(\n (entry) =>\n `${entry.id}:${entry.canonical}:${entry.label}:${[\n ...entry.variants,\n ]\n .sort()\n .join(\",\")}`,\n )\n .toSorted()\n .join(\";\")\n : \"\";\n\n return (\n `${config.enableDenyList}:` +\n `${config.enableTriggerPhrases}:` +\n `${legalFormsEnabled}:` +\n `${config.enableNameCorpus}:` +\n `${contentLanguageFingerprint(config)}:` +\n `${config.nameCorpusLanguages?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.enableRegex}:` +\n `${config.threshold}:` +\n `${config.enableConfidenceBoost}:` +\n `${config.enableHotwordRules === true}:` +\n `${config.enableCoreference === true}:` +\n `${config.enableZoneClassification === true}:` +\n `${config.labels.toSorted().join(\",\")}:` +\n `${config.denyListCountries?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.denyListRegions?.toSorted().join(\",\") ?? \"\"}:` +\n `${config.denyListExcludeCategories?.toSorted().join(\",\") ?? \"\"}:` +\n `${customDenyFingerprint}:` +\n `${customRegexFingerprint}:` +\n `${config.enableGazetteer}:${gazFingerprint}:` +\n `${config.enableCountries !== false}`\n );\n};\n","import type { PipelineContext } from \"./context\";\nimport { defaultContext } from \"./context\";\nimport { applyPipelineLanguageScope } from \"./language-scope\";\nimport type { NativePreparedSearchConfig } from \"./native-search-config\";\nimport { pipelineConfigKey } from \"./pipeline-cache-key\";\nimport type { Dictionaries, GazetteerEntry, PipelineConfig } from \"./types\";\nimport {\n createNativePipelineFromPackage,\n PreparedNativePipeline,\n type NativeAnonymizeBinding,\n} from \"./native\";\n\nexport {\n PreparedNativePipeline,\n createNativePipelineFromPackage,\n} from \"./native\";\n\nexport type NativePipelineUnsupportedFeature = \"enableNer\";\n\nexport type NativePipelineCompatibility =\n | { status: \"supported\" }\n | {\n status: \"unsupported\";\n unsupportedFeatures: NativePipelineUnsupportedFeature[];\n };\n\nexport type NativePipelineBuildOptions = {\n binding: NativeAnonymizeBinding;\n config: PipelineConfig;\n gazetteerEntries?: GazetteerEntry[];\n context?: PipelineContext;\n};\n\nexport type NativePipelinePackageOptions = NativePipelineBuildOptions & {\n compressed?: boolean;\n};\n\nexport type { NativePipelineFromPackageOptions } from \"./native\";\n\ntype NativePipelinePackageCacheValue = Promise<Uint8Array> | Uint8Array;\n\n// Bounds each shared package cache (the dictionary-less bucket below, and\n// each per-`Dictionaries` bucket handed out by `sharedPackageCacheFor`) to a\n// fixed number of entries. `nativePackageCacheKey` fingerprints\n// caller-suppliable config (custom deny lists, custom regexes, gazetteer\n// entries) via `pipelineConfigKey`, so without a cap a caller that varies\n// those fields grows a bucket — and the multi-MB assembled packages it\n// holds — without limit.\nexport const SHARED_PACKAGE_CACHE_MAX_ENTRIES = 32;\n\nconst sharedPackageByDictionaries = new WeakMap<\n Dictionaries,\n Map<string, NativePipelinePackageCacheValue>\n>();\nconst sharedPackageWithoutDictionaries = new Map<\n string,\n NativePipelinePackageCacheValue\n>();\nconst dictionaryCacheIds = new WeakMap<Dictionaries, number>();\nlet nextDictionaryCacheId = 0;\n\n/** Record `key` as most-recently-used in `cache`, evicting the\n * least-recently-used entry first once the cache is at capacity. A `Map`'s\n * insertion order doubles as recency order here: touching an existing key\n * deletes then re-sets it to move it to the end, and eviction drops the\n * first (oldest) key.\n *\n * Evicting a still-in-flight build only drops the cache's reference to its\n * promise; the caller that started the build (and any concurrent caller that\n * already read the promise before eviction) still resolves it correctly via\n * the guarded `sharedCache.get(key) === promise` checks in\n * `getCachedNativePipelinePackage`. A later caller for the same key just\n * misses the dedupe and starts a fresh build — bounded memory takes priority\n * over perfect dedupe under cache pressure. */\nconst touchSharedPackageCacheEntry = (\n cache: Map<string, NativePipelinePackageCacheValue>,\n key: string,\n value: NativePipelinePackageCacheValue,\n): void => {\n cache.delete(key);\n if (cache.size >= SHARED_PACKAGE_CACHE_MAX_ENTRIES) {\n const oldestKey = cache.keys().next().value;\n if (oldestKey !== undefined) {\n cache.delete(oldestKey);\n }\n }\n cache.set(key, value);\n};\n\nconst dictionaryCacheKey = (dictionaries: Dictionaries | undefined): string => {\n if (dictionaries === undefined) {\n return \"none\";\n }\n const existing = dictionaryCacheIds.get(dictionaries);\n if (existing !== undefined) {\n return `dict:${existing}`;\n }\n nextDictionaryCacheId += 1;\n dictionaryCacheIds.set(dictionaries, nextDictionaryCacheId);\n return `dict:${nextDictionaryCacheId}`;\n};\n\nconst sharedPackageCacheFor = (\n dictionaries: Dictionaries | undefined,\n): Map<string, NativePipelinePackageCacheValue> => {\n if (dictionaries === undefined) {\n return sharedPackageWithoutDictionaries;\n }\n const cached = sharedPackageByDictionaries.get(dictionaries);\n if (cached !== undefined) {\n return cached;\n }\n const created = new Map<string, NativePipelinePackageCacheValue>();\n sharedPackageByDictionaries.set(dictionaries, created);\n return created;\n};\n\nexport const getNativePipelineCompatibility = (\n config: PipelineConfig,\n): NativePipelineCompatibility => {\n const unsupportedFeatures: NativePipelineUnsupportedFeature[] = [];\n\n // `enableNer` is no longer part of `PipelineConfig`; untyped callers that\n // still request it (any truthy value, e.g. `1` or `\"true\"` from loose\n // JSON) must fail fast instead of silently losing NER spans.\n if (\"enableNer\" in config && Boolean(config.enableNer)) {\n unsupportedFeatures.push(\"enableNer\");\n }\n if (unsupportedFeatures.length === 0) {\n return { status: \"supported\" };\n }\n return { status: \"unsupported\", unsupportedFeatures };\n};\n\nexport const assertNativePipelineSupported = (config: PipelineConfig): void => {\n const compatibility = getNativePipelineCompatibility(config);\n if (compatibility.status === \"supported\") {\n return;\n }\n throw new Error(\n `Native pipeline does not yet support: ${compatibility.unsupportedFeatures.join(\", \")}`,\n );\n};\n\nconst encoder = new TextEncoder();\n\ntype AssembleInputs = {\n pipelineConfigJson: Uint8Array;\n dictionariesJson: Uint8Array | undefined;\n gazetteerJson: Uint8Array | undefined;\n};\n\n/**\n * Serialize the assembler inputs the Rust binding expects. Dictionaries are\n * stripped from the pipeline config and passed out of band: the assembler reads\n * the separate bundle preferentially, and keeping the (large) dictionaries out\n * of the config JSON avoids serializing them twice.\n */\nconst toAssembleInputs = (\n { dictionaries, ...config }: PipelineConfig,\n gazetteerEntries: readonly GazetteerEntry[],\n): AssembleInputs => ({\n pipelineConfigJson: encoder.encode(JSON.stringify(config)),\n dictionariesJson:\n dictionaries === undefined\n ? undefined\n : encoder.encode(JSON.stringify(dictionaries)),\n gazetteerJson:\n gazetteerEntries.length === 0\n ? undefined\n : encoder.encode(JSON.stringify(gazetteerEntries)),\n});\n\nconst assemblePackageBytes = (\n binding: NativeAnonymizeBinding,\n { pipelineConfigJson, dictionariesJson, gazetteerJson }: AssembleInputs,\n compressed: boolean,\n): Uint8Array => {\n const assemble = compressed\n ? binding.assembleStaticSearchCompressedPackageBytes\n : binding.assembleStaticSearchPackageBytes;\n if (assemble === undefined) {\n throw new Error(\n \"Native anonymize binding does not support static-search config assembly\",\n );\n }\n return assemble(pipelineConfigJson, dictionariesJson, gazetteerJson);\n};\n\nexport const prepareNativePipelineConfig = async ({\n binding,\n config,\n gazetteerEntries = [],\n}: Omit<\n NativePipelineBuildOptions,\n \"context\"\n>): Promise<NativePreparedSearchConfig> => {\n const scopedConfig = applyPipelineLanguageScope(config);\n assertNativePipelineSupported(scopedConfig);\n const assemble = binding.assembleStaticSearchConfigJson;\n if (assemble === undefined) {\n throw new Error(\n \"Native anonymize binding does not support static-search config assembly\",\n );\n }\n const { pipelineConfigJson, dictionariesJson, gazetteerJson } =\n toAssembleInputs(scopedConfig, gazetteerEntries);\n const configJson = assemble(\n pipelineConfigJson,\n dictionariesJson,\n gazetteerJson,\n );\n return JSON.parse(new TextDecoder().decode(configJson));\n};\n\nexport const prepareNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n compressed = false,\n}: NativePipelinePackageOptions): Promise<Uint8Array> => {\n const packageBytes = await getCachedNativePipelinePackage({\n config,\n binding,\n gazetteerEntries,\n ...(context ? { context } : {}),\n compressed,\n });\n // Return a genuine copy: with the real NAPI binding packageBytes is a Node\n // Buffer, and Buffer.prototype.slice() yields a memory-sharing view, so a\n // caller mutating it would corrupt the shared cache and ctx.nativePipelinePackage.\n return new Uint8Array(packageBytes);\n};\n\nexport const createNativePipelineFromConfig = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n}: NativePipelineBuildOptions): Promise<PreparedNativePipeline> => {\n const packageBytes = await getCachedNativePipelinePackage({\n binding,\n config,\n gazetteerEntries,\n ...(context ? { context } : {}),\n });\n return createNativePipelineFromPackage({ binding, packageBytes });\n};\n\nconst getCachedNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries = [],\n context,\n compressed = false,\n}: NativePipelinePackageOptions): Promise<Uint8Array> => {\n const scopedConfig = applyPipelineLanguageScope(config);\n assertNativePipelineSupported(scopedConfig);\n const ctx = context ?? defaultContext;\n const key = nativePackageCacheKey({\n binding,\n config: scopedConfig,\n gazetteerEntries,\n compressed,\n });\n if (ctx.nativePipelinePackage && ctx.nativePipelinePackageKey === key) {\n return ctx.nativePipelinePackage;\n }\n if (\n ctx.nativePipelinePackagePromise &&\n ctx.nativePipelinePackageKey === key\n ) {\n return ctx.nativePipelinePackagePromise;\n }\n\n const sharedCache = sharedPackageCacheFor(scopedConfig.dictionaries);\n const shared = sharedCache.get(key);\n if (shared !== undefined) {\n touchSharedPackageCacheEntry(sharedCache, key, shared);\n const packageBytes = await shared;\n ctx.nativePipelinePackage = packageBytes;\n ctx.nativePipelinePackageKey = key;\n ctx.nativePipelinePackagePromise = null;\n return packageBytes;\n }\n\n ctx.nativePipelinePackage = null;\n ctx.nativePipelinePackageKey = key;\n const promise = buildNativePipelinePackage({\n binding,\n config: scopedConfig,\n gazetteerEntries,\n compressed,\n });\n ctx.nativePipelinePackagePromise = promise;\n touchSharedPackageCacheEntry(sharedCache, key, promise);\n let packageBytes: Uint8Array;\n try {\n packageBytes = await promise;\n } catch (error) {\n if (sharedCache.get(key) === promise) {\n sharedCache.delete(key);\n }\n if (\n ctx.nativePipelinePackageKey === key &&\n ctx.nativePipelinePackagePromise === promise\n ) {\n ctx.nativePipelinePackage = null;\n ctx.nativePipelinePackagePromise = null;\n }\n throw error;\n }\n if (sharedCache.get(key) === promise) {\n sharedCache.set(key, packageBytes);\n }\n if (ctx.nativePipelinePackageKey === key) {\n ctx.nativePipelinePackage = packageBytes;\n ctx.nativePipelinePackagePromise = null;\n }\n return packageBytes;\n};\n\n// `async` so the shared package cache can store the in-flight value and dedupe\n// concurrent builds for the same key, and so assembly failures (an older\n// binding without the assemble functions, or a config the assembler rejects)\n// surface as a rejected promise rather than a synchronous throw mid-cache-flow.\nconst buildNativePipelinePackage = async ({\n binding,\n config,\n gazetteerEntries,\n compressed,\n}: Required<\n Omit<NativePipelinePackageOptions, \"context\">\n>): Promise<Uint8Array> =>\n assemblePackageBytes(\n binding,\n toAssembleInputs(config, gazetteerEntries),\n compressed,\n );\n\ntype NativePackageCacheKeyOptions = {\n binding: NativeAnonymizeBinding;\n config: PipelineConfig;\n gazetteerEntries: readonly GazetteerEntry[];\n compressed: boolean;\n};\n\nconst nativePackageCacheKey = ({\n binding,\n config,\n gazetteerEntries,\n compressed,\n}: NativePackageCacheKeyOptions): string =>\n [\n binding.nativePackageVersion(),\n compressed ? \"compressed\" : \"raw\",\n dictionaryCacheKey(config.dictionaries),\n pipelineConfigKey(config, gazetteerEntries),\n ].join(\":\");\n","/* @stll/anonymize-wasm — browser / WebAssembly entry.\n *\n * Exposes the same native-SDK surface as `@stll/anonymize/native` (the\n * runtime-agnostic layer in `native.ts`), backed by the napi-rs\n * wasm32-wasip1-threads binding instead of the `.node` sidecars. The old\n * TS-pipeline surface (`runPipeline` and friends) is intentionally gone here:\n * this package now redacts entirely through the wasm binding and PREBUILT\n * prepared packages.\n *\n * Browsers can either load prepared packages (pass package bytes, an\n * `ArrayBuffer`, or a URL to fetch, or call `loadDefaultPipeline()` for the\n * default package bundled in the tarball) or build a config in-browser: the\n * wasm binding exposes the same static-search config assembly the Node\n * binding does, so `prepareNativePipelineConfig` / `createNativePipelineFromConfig`\n * / `prepareNativePipelinePackage` work here too.\n *\n * No module-level side effects: the wasm binding is instantiated lazily on\n * first use via `getBinding()`. The napi-generated glue is loaded from the\n * package's own `native/` asset directory — `index.wasi.cjs` under Node's WASI\n * runtime, `index.wasi-browser.js` (fetch + Worker) in browsers.\n */\n\nimport {\n createNativeAnonymizerFromPackage,\n createNativePipelineFromPackage,\n diagnostics_json as diagnosticsJsonWithBinding,\n diagnostics_stream_json as diagnosticsStreamJsonWithBinding,\n type NativeAnonymizeBinding,\n type NativeDiagnosticsBatchCallback,\n type NativeOperatorConfig,\n type NativeResultEventCallback,\n type NativeSearchPackageInput,\n type NativeStaticRedactionResult,\n native_package_version as nativePackageVersionWithBinding,\n normalize_for_search as normalizeForSearchWithBinding,\n PreparedNativeAnonymizer,\n PreparedNativePipeline,\n prepare_search_package as prepareSearchPackageWithBinding,\n redact_text as redactTextWithBinding,\n redact_text_json as redactTextJsonWithBinding,\n redact_text_stream_json as redactTextStreamJsonWithBinding,\n summary_diagnostics_json as summaryDiagnosticsJsonWithBinding,\n} from \"./native\";\n\nexport * from \"./native\";\nexport { deanonymise, exportRedactionKey } from \"./redact\";\nexport {\n CAPABILITY_MANIFEST,\n CAPABILITY_MANIFEST_SCHEMA_VERSION,\n CAPABILITY_RUNTIMES,\n} from \"./capabilities\";\nexport type { CapabilityManifest, CapabilityRuntime } from \"./capabilities\";\nexport {\n DEFAULT_ENTITY_LABELS,\n DETECTION_SOURCES,\n DETECTOR_PRIORITY,\n ENTITY_CAPABILITIES,\n ENTITY_LABELS,\n ENTITY_SELECTIONS,\n OPERATOR_TYPES,\n} from \"./types\";\nexport type {\n AnonymisationOperator,\n DetectionSource,\n Dictionaries,\n DefaultEntityLabel,\n Entity,\n EntityCapability,\n EntityLabel,\n EntitySelection,\n GazetteerEntry,\n OperatorConfig,\n OperatorType,\n PipelineConfig,\n RedactionResult,\n ReviewDecision,\n ReviewedEntity,\n} from \"./types\";\n// Config-driven pipeline surface: pure TS that delegates to\n// `binding.assembleStaticSearchConfigJson` / `assembleStaticSearchPackageBytes`,\n// which the wasm binding exposes with no cfg gating (crates/anonymize-napi/src/lib.rs),\n// so browser callers can assemble packages from a `PipelineConfig` (e.g. live\n// gazetteer entries and dictionaries) instead of only loading prebuilt packages.\nexport {\n assertNativePipelineSupported,\n createNativePipelineFromConfig,\n getNativePipelineCompatibility,\n prepareNativePipelineConfig,\n prepareNativePipelinePackage,\n} from \"./native-pipeline\";\nexport type {\n NativePipelineBuildOptions,\n NativePipelineCompatibility,\n NativePipelinePackageOptions,\n NativePipelineUnsupportedFeature,\n} from \"./native-pipeline\";\nexport { createPipelineContext } from \"./context\";\nexport type { PipelineContext } from \"./context\";\n\n/** A prepared package the caller supplies: raw bytes, an ArrayBuffer, or a URL\n * (string or `URL`) that resolves to the package and is fetched. */\nexport type PreparedPackageSource = Uint8Array | ArrayBuffer | URL | string;\n\n/** Escape hatch for callers that already hold a binding (e.g. a custom sidecar\n * or a test double). When omitted, the lazily-instantiated wasm binding is\n * used. */\nexport type WasmBindingOptions = {\n binding?: NativeAnonymizeBinding;\n};\n\nconst NODE_GLUE_MODULE = \"index.wasi.cjs\";\nconst BROWSER_GLUE_MODULE = \"index.wasi-browser.js\";\nconst NODE_FS_MODULE = \"node:fs/promises\";\nconst NATIVE_ASSET_DIR = \"native\";\nconst DEFAULT_PACKAGE_FILE = \"native-pipeline.stlanonpkg\";\nconst LANGUAGE_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;\nconst DEFAULT_PIPELINE_CACHE_KEY = \"<default>\";\n// Bounds `defaultPipelineCache` to a small, fixed number of prepared\n// pipelines: without a cap, a caller that varies `language` (e.g. many\n// unrecognized tags that all fall back to the same bundled package, see\n// `defaultPipelineCacheKey`) grows this cache — and the prepared pipelines it\n// holds — without limit.\nconst DEFAULT_PIPELINE_CACHE_MAX_ENTRIES = 32;\n\nlet bindingPromise: Promise<NativeAnonymizeBinding> | undefined;\nconst defaultPipelineCache = new Map<string, Promise<PreparedNativePipeline>>();\n\n/** Instantiate (once) and return the wasm binding. Safe to call repeatedly:\n * the underlying wasm module is instantiated a single time and cached. */\nexport const getBinding = (): Promise<NativeAnonymizeBinding> => {\n bindingPromise ??= loadWasmBinding();\n return bindingPromise;\n};\n\nconst loadWasmBinding = async (): Promise<NativeAnonymizeBinding> => {\n const glueModule = isNodeRuntime() ? NODE_GLUE_MODULE : BROWSER_GLUE_MODULE;\n const glueUrl = assetUrl(glueModule);\n // The specifier is deliberately a runtime asset URL (resolved against the\n // package's own `native/` directory), not a module the bundler should follow:\n // the napi-rs glue lives outside src and is copied in at build time.\n // eslint-disable-next-line stll/no-dynamic-import-specifier\n const loaded: unknown = await import(/* @vite-ignore */ glueUrl.href);\n return toNativeAnonymizeBinding(loaded);\n};\n\ntype RuntimeGlobals = {\n process?: { versions?: { node?: string } };\n window?: unknown;\n};\n\nconst isNodeRuntime = (): boolean => {\n const globals: RuntimeGlobals = globalThis;\n return (\n globals.window === undefined &&\n typeof globals.process?.versions?.node === \"string\"\n );\n};\n\nconst assetUrl = (fileName: string): URL =>\n new URL(`./${NATIVE_ASSET_DIR}/${fileName}`, import.meta.url);\n\nconst resolveBinding = (\n options?: WasmBindingOptions,\n): Promise<NativeAnonymizeBinding> =>\n options?.binding ? Promise.resolve(options.binding) : getBinding();\n\nconst toPackageBytes = async (\n source: PreparedPackageSource,\n): Promise<Uint8Array> => {\n if (source instanceof Uint8Array) {\n return source;\n }\n if (source instanceof ArrayBuffer) {\n return new Uint8Array(source);\n }\n const href = source instanceof URL ? source.href : source;\n // Node's global fetch (undici) rejects file: URLs, so package URLs resolved\n // from import.meta.url (loadDefaultPipeline, `new URL(..., import.meta.url)`)\n // fail there. Read those through node:fs instead of fetch.\n if (href.startsWith(\"file:\")) {\n return readFileUrlBytes(href);\n }\n const response = await fetch(href);\n if (!response.ok) {\n throw new Error(\n `Failed to fetch prepared package (${response.status} ${response.statusText})`,\n );\n }\n return new Uint8Array(await response.arrayBuffer());\n};\n\n/** Read a `file:` URL through node:fs. The import is dynamic and gated behind\n * the `file:` check (never reached in browsers); the specifier is a runtime\n * value so the bundler leaves it alone, mirroring the runtime glue import in\n * {@link loadWasmBinding}, so browser bundles never pull in node:fs. */\nconst readFileUrlBytes = async (fileUrl: string): Promise<Uint8Array> => {\n // eslint-disable-next-line stll/no-dynamic-import-specifier\n const { readFile } = await import(/* @vite-ignore */ NODE_FS_MODULE);\n return new Uint8Array(await readFile(new URL(fileUrl)));\n};\n\n// --- Prepared-package loaders (the primary browser flow) ---------------------\n\nexport type LoadPreparedPackageOptions = WasmBindingOptions;\n\n/** Load a prepared package and return a pipeline ready to redact text. */\nexport const loadPipeline = async (\n source: PreparedPackageSource,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n const [binding, packageBytes] = await Promise.all([\n resolveBinding(options),\n toPackageBytes(source),\n ]);\n return createNativePipelineFromPackage({ binding, packageBytes });\n};\n\n/** Load a prepared package and return the lower-level anonymizer. */\nexport const load_prepared_package = async (\n source: PreparedPackageSource,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativeAnonymizer> => {\n const [binding, packageBytes] = await Promise.all([\n resolveBinding(options),\n toPackageBytes(source),\n ]);\n return createNativeAnonymizerFromPackage({ binding, packageBytes });\n};\n\n// --- Default package bundled in the tarball ----------------------------------\n\n/** URL of a bundled default prepared package, resolved against this module so\n * it points at the `native/` asset directory shipped in the tarball. */\nexport const defaultPackageUrl = (language?: string): URL =>\n language === undefined\n ? assetUrl(DEFAULT_PACKAGE_FILE)\n : assetUrl(`native-pipeline.${normalizeLanguage(language)}.stlanonpkg`);\n\n/** Load a fresh pipeline from the bundled default prepared package.\n *\n * Mirrors the node loader's regional-tag fallback: when an exact package for\n * a locale tag such as `en-US` is not shipped, the base-language package\n * (`en`) is loaded instead. The browser cannot check asset existence up\n * front, so the fallback triggers on a failed load of the exact package. */\nexport const loadDefaultPipeline = async (\n language?: string,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n try {\n return await loadPipeline(defaultPackageUrl(language), options);\n } catch (error) {\n const normalized =\n language === undefined ? undefined : normalizeLanguage(language);\n const baseLanguage = normalized?.split(\"-\").at(0);\n if (baseLanguage === undefined || baseLanguage === normalized) {\n throw error;\n }\n return loadPipeline(defaultPackageUrl(baseLanguage), options);\n }\n};\n\n/** Normalized cache key for {@link defaultPipelineCache}: `undefined` maps to\n * the bundled-default sentinel, everything else goes through the same\n * {@link normalizeLanguage} helper `loadDefaultPipeline`/`defaultPackageUrl`\n * already validate against, so aliases that differ only by case or whitespace\n * (e.g. `\"EN\"` vs `\"en\"`) share one cached pipeline instead of each minting\n * their own. */\nconst defaultPipelineCacheKey = (language: string | undefined): string =>\n language === undefined\n ? DEFAULT_PIPELINE_CACHE_KEY\n : normalizeLanguage(language);\n\n/** Record `key` as most-recently-used in {@link defaultPipelineCache},\n * evicting the least-recently-used entry first once the cache is at\n * capacity. A `Map`'s insertion order doubles as recency order here: touching\n * an existing key deletes then re-sets it to move it to the end, and\n * eviction drops the first (oldest) key. */\nconst touchDefaultPipelineCacheEntry = (\n key: string,\n pipeline: Promise<PreparedNativePipeline>,\n): void => {\n defaultPipelineCache.delete(key);\n if (defaultPipelineCache.size >= DEFAULT_PIPELINE_CACHE_MAX_ENTRIES) {\n const oldestKey = defaultPipelineCache.keys().next().value;\n if (oldestKey !== undefined) {\n defaultPipelineCache.delete(oldestKey);\n }\n }\n defaultPipelineCache.set(key, pipeline);\n};\n\n/** Cached variant of {@link loadDefaultPipeline}: the default pipeline for a\n * given language is fetched and prepared once, then reused.\n *\n * Only the ambient-binding case is cached. The cache key is language-only, so a\n * caller that injects its own `options.binding` bypasses the cache entirely:\n * reusing a pipeline built against a different binding would be wrong, and\n * folding the binding into the key would keep unbounded per-binding entries\n * alive. Injected-binding callers get a fresh pipeline each call. */\nexport const getDefaultPipeline = (\n language?: string,\n options?: LoadPreparedPackageOptions,\n): Promise<PreparedNativePipeline> => {\n if (options?.binding) {\n return loadDefaultPipeline(language, options);\n }\n let key: string;\n try {\n key = defaultPipelineCacheKey(language);\n } catch (error) {\n // normalizeLanguage() validates the tag; surface an invalid language as a\n // rejection like the rest of this async surface, not a synchronous throw\n // (this function isn't declared `async`, so an uncaught throw here would\n // escape synchronously instead of rejecting the returned promise).\n return Promise.reject(error);\n }\n const cached = defaultPipelineCache.get(key);\n if (cached !== undefined) {\n touchDefaultPipelineCacheEntry(key, cached);\n return cached;\n }\n // Evict the entry on rejection so a failed load (e.g. a transient fetch/read\n // error) is retried on the next call instead of caching the rejection.\n const pipeline = loadDefaultPipeline(language).catch((error: unknown) => {\n defaultPipelineCache.delete(key);\n throw error;\n });\n touchDefaultPipelineCacheEntry(key, pipeline);\n return pipeline;\n};\n\nexport const redactDefaultText = async (\n fullText: string,\n operators?: NativeOperatorConfig,\n language?: string,\n): Promise<NativeStaticRedactionResult> =>\n (await getDefaultPipeline(language)).redactText(fullText, operators);\n\nexport const redactDefaultTextJson = async (\n fullText: string,\n operators?: NativeOperatorConfig,\n language?: string,\n): Promise<string> =>\n (await getDefaultPipeline(language)).redact_text_json(fullText, operators);\n\n// --- Binding-injected SDK surface (async parity with native-node) ------------\n\nexport const native_package_version = async (\n options?: WasmBindingOptions,\n): Promise<string> =>\n nativePackageVersionWithBinding(await resolveBinding(options));\n\nexport const normalize_for_search = async (\n text: string,\n options?: WasmBindingOptions,\n): Promise<string> =>\n normalizeForSearchWithBinding({\n binding: await resolveBinding(options),\n text,\n });\n\nexport type PrepareSearchPackageOptions = WasmBindingOptions & {\n compressed?: boolean;\n};\n\nexport const prepare_search_package = async (\n config: NativeSearchPackageInput,\n { compressed = false, ...options }: PrepareSearchPackageOptions = {},\n): Promise<Uint8Array> =>\n prepareSearchPackageWithBinding({\n binding: await resolveBinding(options),\n config,\n compressed,\n });\n\nexport const redact_text = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<NativeStaticRedactionResult> =>\n redactTextWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const redact_text_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string> =>\n redactTextJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const redact_text_stream_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n onEvent: NativeResultEventCallback,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n redactTextStreamJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n onEvent,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const diagnostics_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n diagnosticsJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const diagnostics_stream_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n onBatch: NativeDiagnosticsBatchCallback,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n diagnosticsStreamJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n onBatch,\n ...(operators !== undefined ? { operators } : {}),\n });\n\nexport const summary_diagnostics_json = async (\n config: NativeSearchPackageInput,\n fullText: string,\n operators?: NativeOperatorConfig,\n options?: WasmBindingOptions,\n): Promise<string | null> =>\n summaryDiagnosticsJsonWithBinding({\n binding: await resolveBinding(options),\n config,\n fullText,\n ...(operators !== undefined ? { operators } : {}),\n });\n\n// --- Binding extraction ------------------------------------------------------\n\nconst toNativeAnonymizeBinding = (loaded: unknown): NativeAnonymizeBinding => {\n const candidate = pickBindingCandidate(loaded);\n if (!isNativeAnonymizeBinding(candidate)) {\n throw new Error(\n \"wasm binding module does not expose the native anonymize surface\",\n );\n }\n return candidate;\n};\n\nconst pickBindingCandidate = (loaded: unknown): unknown => {\n if (isRecord(loaded) && isNativeAnonymizeBinding(loaded[\"default\"])) {\n return loaded[\"default\"];\n }\n return loaded;\n};\n\nconst isNativeAnonymizeBinding = (\n value: unknown,\n): value is NativeAnonymizeBinding => {\n if (!isRecord(value)) {\n return false;\n }\n if (typeof value[\"nativePackageVersion\"] !== \"function\") {\n return false;\n }\n if (typeof value[\"normalizeForSearch\"] !== \"function\") {\n return false;\n }\n if (typeof value[\"prepareStaticSearchPackageBytes\"] !== \"function\") {\n return false;\n }\n if (\n typeof value[\"prepareStaticSearchCompressedPackageBytes\"] !== \"function\"\n ) {\n return false;\n }\n const preparedSearch = value[\"NativePreparedSearch\"];\n if (!isRecord(preparedSearch)) {\n return false;\n }\n if (typeof preparedSearch[\"fromConfigJsonBytes\"] !== \"function\") {\n return false;\n }\n return typeof preparedSearch[\"fromPreparedPackageBytes\"] === \"function\";\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n (typeof value === \"object\" && value !== null) || typeof value === \"function\";\n\nconst normalizeLanguage = (language: string): string => {\n const normalized = language.trim().toLowerCase();\n if (!LANGUAGE_PATTERN.test(normalized)) {\n throw new Error(`Language must match ${LANGUAGE_PATTERN.source}`);\n }\n return normalized;\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/anonymize-wasm",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "PII detection and anonymization for browsers via WebAssembly. Same native SDK API as @stll/anonymize.",
5
5
  "keywords": [
6
6
  "anonymization",