@stll/anonymize-wasm 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/dist/wasm.d.mts +75 -11
  2. package/dist/wasm.mjs +89 -136
  3. package/dist/wasm.mjs.map +1 -1
  4. package/package.json +1 -1
  5. package/dist/AT.mjs +0 -282
  6. package/dist/AT.mjs.map +0 -1
  7. package/dist/AT2.mjs +0 -343
  8. package/dist/AT2.mjs.map +0 -1
  9. package/dist/AU.mjs +0 -122
  10. package/dist/AU.mjs.map +0 -1
  11. package/dist/AU2.mjs +0 -90
  12. package/dist/AU2.mjs.map +0 -1
  13. package/dist/BE.mjs +0 -144
  14. package/dist/BE.mjs.map +0 -1
  15. package/dist/BE2.mjs +0 -107
  16. package/dist/BE2.mjs.map +0 -1
  17. package/dist/BG.mjs +0 -73
  18. package/dist/BG.mjs.map +0 -1
  19. package/dist/BG2.mjs +0 -42
  20. package/dist/BG2.mjs.map +0 -1
  21. package/dist/BR.mjs +0 -226
  22. package/dist/BR.mjs.map +0 -1
  23. package/dist/BR2.mjs +0 -339
  24. package/dist/BR2.mjs.map +0 -1
  25. package/dist/CA.mjs +0 -275
  26. package/dist/CA.mjs.map +0 -1
  27. package/dist/CA2.mjs +0 -222
  28. package/dist/CA2.mjs.map +0 -1
  29. package/dist/CZ.mjs +0 -212
  30. package/dist/CZ.mjs.map +0 -1
  31. package/dist/CZ2.mjs +0 -619
  32. package/dist/CZ2.mjs.map +0 -1
  33. package/dist/CZ3.mjs +0 -127
  34. package/dist/CZ3.mjs.map +0 -1
  35. package/dist/DE.mjs +0 -1652
  36. package/dist/DE.mjs.map +0 -1
  37. package/dist/DE2.mjs +0 -3885
  38. package/dist/DE2.mjs.map +0 -1
  39. package/dist/DE3.mjs +0 -669
  40. package/dist/DE3.mjs.map +0 -1
  41. package/dist/DK.mjs +0 -218
  42. package/dist/DK.mjs.map +0 -1
  43. package/dist/DK2.mjs +0 -162
  44. package/dist/DK2.mjs.map +0 -1
  45. package/dist/ES.mjs +0 -522
  46. package/dist/ES.mjs.map +0 -1
  47. package/dist/ES2.mjs +0 -352
  48. package/dist/ES2.mjs.map +0 -1
  49. package/dist/FI.mjs +0 -267
  50. package/dist/FI.mjs.map +0 -1
  51. package/dist/FI2.mjs +0 -107
  52. package/dist/FI2.mjs.map +0 -1
  53. package/dist/FR.mjs +0 -224
  54. package/dist/FR.mjs.map +0 -1
  55. package/dist/FR2.mjs +0 -1823
  56. package/dist/FR2.mjs.map +0 -1
  57. package/dist/GB.mjs +0 -298
  58. package/dist/GB.mjs.map +0 -1
  59. package/dist/GB2.mjs +0 -208
  60. package/dist/GB2.mjs.map +0 -1
  61. package/dist/HR.mjs +0 -37
  62. package/dist/HR.mjs.map +0 -1
  63. package/dist/HR2.mjs +0 -16
  64. package/dist/HR2.mjs.map +0 -1
  65. package/dist/HU.mjs +0 -59
  66. package/dist/HU.mjs.map +0 -1
  67. package/dist/HU2.mjs +0 -29
  68. package/dist/HU2.mjs.map +0 -1
  69. package/dist/IE.mjs +0 -35
  70. package/dist/IE.mjs.map +0 -1
  71. package/dist/IE2.mjs +0 -19
  72. package/dist/IE2.mjs.map +0 -1
  73. package/dist/IT.mjs +0 -341
  74. package/dist/IT.mjs.map +0 -1
  75. package/dist/IT2.mjs +0 -46
  76. package/dist/IT2.mjs.map +0 -1
  77. package/dist/NL.mjs +0 -298
  78. package/dist/NL.mjs.map +0 -1
  79. package/dist/NL2.mjs +0 -305
  80. package/dist/NL2.mjs.map +0 -1
  81. package/dist/NO.mjs +0 -178
  82. package/dist/NO.mjs.map +0 -1
  83. package/dist/NO2.mjs +0 -346
  84. package/dist/NO2.mjs.map +0 -1
  85. package/dist/PL.mjs +0 -175
  86. package/dist/PL.mjs.map +0 -1
  87. package/dist/PL2.mjs +0 -107
  88. package/dist/PL2.mjs.map +0 -1
  89. package/dist/PT.mjs +0 -78
  90. package/dist/PT.mjs.map +0 -1
  91. package/dist/PT2.mjs +0 -657
  92. package/dist/PT2.mjs.map +0 -1
  93. package/dist/RO.mjs +0 -181
  94. package/dist/RO.mjs.map +0 -1
  95. package/dist/RO2.mjs +0 -46
  96. package/dist/RO2.mjs.map +0 -1
  97. package/dist/SE.mjs +0 -270
  98. package/dist/SE.mjs.map +0 -1
  99. package/dist/SE2.mjs +0 -369
  100. package/dist/SE2.mjs.map +0 -1
  101. package/dist/SI.mjs +0 -27
  102. package/dist/SI.mjs.map +0 -1
  103. package/dist/SI2.mjs +0 -88
  104. package/dist/SI2.mjs.map +0 -1
  105. package/dist/SK.mjs +0 -61
  106. package/dist/SK.mjs.map +0 -1
  107. package/dist/SK2.mjs +0 -26
  108. package/dist/SK2.mjs.map +0 -1
  109. package/dist/US.mjs +0 -1061
  110. package/dist/US.mjs.map +0 -1
  111. package/dist/US2.mjs +0 -518
  112. package/dist/US2.mjs.map +0 -1
  113. package/dist/cs.mjs +0 -5080
  114. package/dist/cs.mjs.map +0 -1
  115. package/dist/cs2.mjs +0 -17609
  116. package/dist/cs2.mjs.map +0 -1
  117. package/dist/de4.mjs +0 -8214
  118. package/dist/de4.mjs.map +0 -1
  119. package/dist/de5.mjs +0 -8197
  120. package/dist/de5.mjs.map +0 -1
  121. package/dist/dist.mjs +0 -619
  122. package/dist/dist.mjs.map +0 -1
  123. package/dist/en.mjs +0 -9977
  124. package/dist/en.mjs.map +0 -1
  125. package/dist/en2.mjs +0 -5014
  126. package/dist/en2.mjs.map +0 -1
  127. package/dist/es3.mjs +0 -9059
  128. package/dist/es3.mjs.map +0 -1
  129. package/dist/es4.mjs +0 -8254
  130. package/dist/es4.mjs.map +0 -1
  131. package/dist/eu-institutions.mjs +0 -518
  132. package/dist/eu-institutions.mjs.map +0 -1
  133. package/dist/fr3.mjs +0 -9999
  134. package/dist/fr3.mjs.map +0 -1
  135. package/dist/fr4.mjs +0 -9975
  136. package/dist/fr4.mjs.map +0 -1
  137. package/dist/global.mjs +0 -195368
  138. package/dist/global.mjs.map +0 -1
  139. package/dist/hospitals-CZ.mjs +0 -747
  140. package/dist/hospitals-CZ.mjs.map +0 -1
  141. package/dist/hospitals-DE.mjs +0 -3356
  142. package/dist/hospitals-DE.mjs.map +0 -1
  143. package/dist/hu3.mjs +0 -9964
  144. package/dist/hu3.mjs.map +0 -1
  145. package/dist/hu4.mjs +0 -5031
  146. package/dist/hu4.mjs.map +0 -1
  147. package/dist/it3.mjs +0 -5037
  148. package/dist/it3.mjs.map +0 -1
  149. package/dist/it4.mjs +0 -9989
  150. package/dist/it4.mjs.map +0 -1
  151. package/dist/ministries-AT.mjs +0 -180
  152. package/dist/ministries-AT.mjs.map +0 -1
  153. package/dist/ministries-CZ.mjs +0 -201
  154. package/dist/ministries-CZ.mjs.map +0 -1
  155. package/dist/ministries-DE.mjs +0 -859
  156. package/dist/ministries-DE.mjs.map +0 -1
  157. package/dist/ministries-SK.mjs +0 -174
  158. package/dist/ministries-SK.mjs.map +0 -1
  159. package/dist/pl3.mjs +0 -5059
  160. package/dist/pl3.mjs.map +0 -1
  161. package/dist/pl4.mjs +0 -9991
  162. package/dist/pl4.mjs.map +0 -1
  163. package/dist/ro3.mjs +0 -10000
  164. package/dist/ro3.mjs.map +0 -1
  165. package/dist/ro4.mjs +0 -5037
  166. package/dist/ro4.mjs.map +0 -1
  167. package/dist/sk3.mjs +0 -9205
  168. package/dist/sk3.mjs.map +0 -1
  169. package/dist/sk4.mjs +0 -15242
  170. package/dist/sk4.mjs.map +0 -1
  171. package/dist/sv.mjs +0 -8312
  172. package/dist/sv.mjs.map +0 -1
  173. package/dist/sv2.mjs +0 -8439
  174. package/dist/sv2.mjs.map +0 -1
  175. package/dist/translations.mjs +0 -603
  176. package/dist/translations.mjs.map +0 -1
  177. package/dist/universities-AT.mjs +0 -410
  178. package/dist/universities-AT.mjs.map +0 -1
  179. package/dist/universities-CZ.mjs +0 -427
  180. package/dist/universities-CZ.mjs.map +0 -1
  181. package/dist/universities-DE.mjs +0 -3393
  182. package/dist/universities-DE.mjs.map +0 -1
  183. package/dist/universities-SK.mjs +0 -215
  184. package/dist/universities-SK.mjs.map +0 -1
package/dist/wasm.d.mts CHANGED
@@ -174,6 +174,59 @@ type RedactionResult = {
174
174
  * Configuration for the detection pipeline.
175
175
  */
176
176
  type DenyListCategory = "Names" | "Places" | "Addresses" | "Courts" | "Financial" | "Government" | "Healthcare" | "Education" | "Political" | "Organizations" | "International";
177
+ /**
178
+ * Metadata for a single dictionary entry in the
179
+ * deny-list system. Mirrors the shape from
180
+ * `@stll/anonymize-data` so consumers can pass
181
+ * pre-loaded data without the runtime dependency.
182
+ */
183
+ type DictionaryMeta = {
184
+ label: string;
185
+ category: DenyListCategory;
186
+ country: string | null;
187
+ };
188
+ /**
189
+ * Pre-loaded dictionary data for dependency injection.
190
+ * Consumers that want name/city/deny-list detection
191
+ * import from `@stll/anonymize-data` themselves and
192
+ * pass the data here; the anonymize package itself
193
+ * has zero cross-package imports.
194
+ *
195
+ * All fields are optional. When a field is absent,
196
+ * the corresponding detection path is skipped (same
197
+ * behavior as when `@stll/anonymize-data` was not
198
+ * installed).
199
+ */
200
+ type Dictionaries = {
201
+ /**
202
+ * First names per language code (e.g., "cs", "de").
203
+ * Merged with legacy config names at init time.
204
+ */
205
+ firstNames?: Readonly<Record<string, readonly string[]>>;
206
+ /**
207
+ * Surnames per language code.
208
+ * Merged with legacy config names at init time.
209
+ */
210
+ surnames?: Readonly<Record<string, readonly string[]>>;
211
+ /**
212
+ * Pre-loaded deny-list dictionaries keyed by
213
+ * dictionary ID (e.g., "courts/CZ", "banks/DE").
214
+ * Each value is the array of terms for that
215
+ * dictionary.
216
+ */
217
+ denyList?: Readonly<Record<string, readonly string[]>>;
218
+ /**
219
+ * Metadata per dictionary ID. Required when
220
+ * `denyList` is provided so the pipeline knows
221
+ * labels, categories, and country filters.
222
+ */
223
+ denyListMeta?: Readonly<Record<string, DictionaryMeta>>;
224
+ /**
225
+ * Pre-loaded city names, already merged across
226
+ * all desired countries.
227
+ */
228
+ cities?: readonly string[];
229
+ };
177
230
  type PipelineConfig = {
178
231
  threshold: number;
179
232
  enableTriggerPhrases: boolean;
@@ -209,6 +262,13 @@ type PipelineConfig = {
209
262
  */
210
263
  labels: string[];
211
264
  workspaceId: string;
265
+ /**
266
+ * Pre-loaded dictionary data for name, deny-list,
267
+ * and city detection. When omitted, dictionary-based
268
+ * detection paths are skipped. Consumers load from
269
+ * `@stll/anonymize-data` and pass the data here.
270
+ */
271
+ dictionaries?: Dictionaries;
212
272
  };
213
273
  /**
214
274
  * Canonical entity labels used across the pipeline.
@@ -261,7 +321,7 @@ declare const CURRENCY_PATTERN_META: Readonly<RegexMeta>;
261
321
  declare const processRegexMatches: (allMatches: Match[], sliceStart: number, sliceEnd: number, meta_: readonly RegexMeta[]) => Entity[];
262
322
  //#endregion
263
323
  //#region src/detectors/deny-list.d.ts
264
- type DenyListConfig = Pick<PipelineConfig, "enableDenyList" | "enableNameCorpus" | "denyListCountries" | "denyListRegions" | "denyListExcludeCategories">;
324
+ type DenyListConfig = Pick<PipelineConfig, "enableDenyList" | "enableNameCorpus" | "denyListCountries" | "denyListRegions" | "denyListExcludeCategories" | "dictionaries">;
265
325
  /**
266
326
  * Source tag for each pattern in the automaton.
267
327
  * "deny-list" = standard deny list entry
@@ -289,13 +349,13 @@ type DenyListData = {
289
349
  };
290
350
  /**
291
351
  * Resolve which dictionaries to load based on country
292
- * and category filters, load them, and build the deny
293
- * list data. The returned data provides PatternEntry[]
294
- * for the unified builder and parallel arrays for
352
+ * and category filters, then build the deny list data.
353
+ * The returned data provides PatternEntry[] for the
354
+ * unified builder and parallel arrays for
295
355
  * post-processing.
296
356
  *
297
- * Requires `@stll/anonymize-data` to be installed.
298
- * Returns null if the data package is not available.
357
+ * Dictionary data is injected via `config.dictionaries`.
358
+ * Returns null if no dictionaries are provided.
299
359
  */
300
360
  declare const buildDenyList: (config: DenyListConfig, ctx?: PipelineContext) => Promise<DenyListData | null>;
301
361
  /**
@@ -306,7 +366,7 @@ declare const buildDenyList: (config: DenyListConfig, ctx?: PipelineContext) =>
306
366
  * the search instance was built on a different context
307
367
  * (e.g. cachedSearch).
308
368
  */
309
- declare const ensureDenyListData: (ctx?: PipelineContext) => Promise<void>;
369
+ declare const ensureDenyListData: (ctx?: PipelineContext, dictionaries?: Dictionaries) => Promise<void>;
310
370
  /**
311
371
  * Process deny list matches from the unified search.
312
372
  * Receives all matches; filters to the deny list slice
@@ -647,14 +707,18 @@ declare const propagateOrgNames: (entities: Entity[], fullText: string) => Entit
647
707
  //#endregion
648
708
  //#region src/detectors/names.d.ts
649
709
  /**
650
- * Load name corpus data from per-language dictionary
651
- * files and legacy config files. Merges all sources.
710
+ * Load name corpus data from injected dictionaries
711
+ * and legacy config files. Merges all sources.
652
712
  *
653
713
  * Safe to call multiple times; only loads once per
654
714
  * context. Must be called before detectNameCorpus or
655
715
  * the getNameCorpus*() accessors are used.
716
+ *
717
+ * @param dictionaries Optional pre-loaded dictionaries
718
+ * with per-language first names and surnames. When
719
+ * omitted, only legacy config files are used.
656
720
  */
657
- declare const initNameCorpus: (ctx?: PipelineContext) => Promise<void>;
721
+ declare const initNameCorpus: (ctx?: PipelineContext, dictionaries?: Dictionaries) => Promise<void>;
658
722
  /**
659
723
  * Detect person names by looking up tokens against the
660
724
  * name corpus, then chaining adjacent name-like tokens.
@@ -933,5 +997,5 @@ declare const levenshtein: (rawA: string, rawB: string) => number;
933
997
  */
934
998
  declare const normalizeForSearch: (text: string) => string;
935
999
  //#endregion
936
- export { type AnonymisationOperator, CURRENCY_PATTERN_META, type CountryCode, DATE_PATTERN_META, DEFAULT_ENTITY_LABELS, DEFAULT_OPERATOR_CONFIG, DETECTION_SOURCES, DETECTOR_PRIORITY, type DefinitionPattern, type DenyListCategory, type DenyListData, type DetectionSource, type DocumentZone, type Entity, type EntityResult, type GazetteerData, type GazetteerEntry, type HotwordRule, type NameCorpusData, type NerInferenceFn, OPERATOR_REGISTRY, OPERATOR_TYPES, type OperatorConfig, type OperatorType, type PipelineConfig, type PipelineContext, type PipelineOptions, REGEX_META, REGEX_PATTERNS, REGIONS, type RawInferenceResult, type RedactionResult, type RegexMeta, type RegionId, type ReviewDecision, type ReviewedEntity, type TriggerExtension, type TriggerGroupConfig, type TriggerRule, type TriggerStrategy, type TriggerValidation, type UnifiedResult, type UnifiedSearchInstance, ZONE_SCORE_ADJUSTMENTS, type ZoneSpan, applyHotwordRules, applyZoneAdjustments, boostNearMissEntities, buildDenyList, buildGazetteerPatterns, buildLegalFormPatterns, buildPlaceholderMap, buildStreetTypePatterns, buildTriggerPatterns, buildUnifiedSearch, chunkText, classifyZones, computeChunkOffsets, corefKey, createPipelineContext, deanonymise, decodeSpans, decodeTokenSpans, detectNameCorpus, ensureDenyListData, exportRedactionKey, extractDefinedTerms, filterFalsePositives, findCoreferenceSpans, getCurrencyPatterns, getDatePatterns, initHotwordRules, initNameCorpus, initZoneClassifier, levenshtein, mergeAndDedup, mergeChunkEntities, normalizeForSearch, prepareBatch, processAddressSeeds, processDenyListMatches, processGazetteerMatches, processLegalFormMatches, processRegexMatches, processTriggerMatches, propagateOrgNames, redactText, resolveCountries, resolveOperator, runPipeline, runUnifiedSearch, sanitizeEntities, tokenizeText };
1000
+ export { type AnonymisationOperator, CURRENCY_PATTERN_META, type CountryCode, DATE_PATTERN_META, DEFAULT_ENTITY_LABELS, DEFAULT_OPERATOR_CONFIG, DETECTION_SOURCES, DETECTOR_PRIORITY, type DefinitionPattern, type DenyListCategory, type DenyListData, type DetectionSource, type Dictionaries, type DictionaryMeta, type DocumentZone, type Entity, type EntityResult, type GazetteerData, type GazetteerEntry, type HotwordRule, type NameCorpusData, type NerInferenceFn, OPERATOR_REGISTRY, OPERATOR_TYPES, type OperatorConfig, type OperatorType, type PipelineConfig, type PipelineContext, type PipelineOptions, REGEX_META, REGEX_PATTERNS, REGIONS, type RawInferenceResult, type RedactionResult, type RegexMeta, type RegionId, type ReviewDecision, type ReviewedEntity, type TriggerExtension, type TriggerGroupConfig, type TriggerRule, type TriggerStrategy, type TriggerValidation, type UnifiedResult, type UnifiedSearchInstance, ZONE_SCORE_ADJUSTMENTS, type ZoneSpan, applyHotwordRules, applyZoneAdjustments, boostNearMissEntities, buildDenyList, buildGazetteerPatterns, buildLegalFormPatterns, buildPlaceholderMap, buildStreetTypePatterns, buildTriggerPatterns, buildUnifiedSearch, chunkText, classifyZones, computeChunkOffsets, corefKey, createPipelineContext, deanonymise, decodeSpans, decodeTokenSpans, detectNameCorpus, ensureDenyListData, exportRedactionKey, extractDefinedTerms, filterFalsePositives, findCoreferenceSpans, getCurrencyPatterns, getDatePatterns, initHotwordRules, initNameCorpus, initZoneClassifier, levenshtein, mergeAndDedup, mergeChunkEntities, normalizeForSearch, prepareBatch, processAddressSeeds, processDenyListMatches, processGazetteerMatches, processLegalFormMatches, processRegexMatches, processTriggerMatches, propagateOrgNames, redactText, resolveCountries, resolveOperator, runPipeline, runUnifiedSearch, sanitizeEntities, tokenizeText };
937
1001
  //# sourceMappingURL=wasm.d.mts.map
package/dist/wasm.mjs CHANGED
@@ -606,42 +606,18 @@ const getNameCorpusFirstNames = (ctx = defaultContext) => ctx.nameCorpus?.firstN
606
606
  const getNameCorpusSurnames = (ctx = defaultContext) => ctx.nameCorpus?.surnamesList ?? [];
607
607
  const getNameCorpusTitles = (ctx = defaultContext) => ctx.nameCorpus?.titlesList ?? [];
608
608
  /**
609
- * Languages with per-language first/surname
610
- * dictionaries from @stll/anonymize-data (optional).
611
- */
612
- const NAME_LANGUAGES = [
613
- "cs",
614
- "sk",
615
- "de",
616
- "pl",
617
- "hu",
618
- "ro",
619
- "fr",
620
- "es",
621
- "it",
622
- "en",
623
- "sv"
624
- ];
625
- /**
626
- * Try importing a JSON module; return empty array
627
- * if not found.
628
- */
629
- const tryImportArray = async (path) => {
630
- try {
631
- return (await import(path)).default;
632
- } catch {
633
- return [];
634
- }
635
- };
636
- /**
637
- * Load name corpus data from per-language dictionary
638
- * files and legacy config files. Merges all sources.
609
+ * Load name corpus data from injected dictionaries
610
+ * and legacy config files. Merges all sources.
639
611
  *
640
612
  * Safe to call multiple times; only loads once per
641
613
  * context. Must be called before detectNameCorpus or
642
614
  * the getNameCorpus*() accessors are used.
615
+ *
616
+ * @param dictionaries Optional pre-loaded dictionaries
617
+ * with per-language first names and surnames. When
618
+ * omitted, only legacy config files are used.
643
619
  */
644
- const initNameCorpus = (ctx = defaultContext) => {
620
+ const initNameCorpus = (ctx = defaultContext, dictionaries) => {
645
621
  if (ctx.nameCorpusPromise) return ctx.nameCorpusPromise;
646
622
  const promise = (async () => {
647
623
  try {
@@ -651,13 +627,10 @@ const initNameCorpus = (ctx = defaultContext) => {
651
627
  import("./names-title-tokens.mjs"),
652
628
  import("./names-exclusions.mjs")
653
629
  ]);
654
- const firstImports = NAME_LANGUAGES.map((lang) => tryImportArray(`@stll/anonymize-data/dictionaries/names/first/${lang}.json`));
655
- const surnameImports = NAME_LANGUAGES.map((lang) => tryImportArray(`@stll/anonymize-data/dictionaries/names/surnames/${lang}.json`));
656
- const [firstResults, surnameResults] = await Promise.all([Promise.all(firstImports), Promise.all(surnameImports)]);
657
630
  const firstNames = [...legacyFirstMod.default.names];
658
- for (const names of firstResults) for (const name of names) firstNames.push(name);
631
+ if (dictionaries?.firstNames) for (const names of Object.values(dictionaries.firstNames)) for (const name of names) firstNames.push(name);
659
632
  const surnames = [...legacySurnameMod.default.names];
660
- for (const names of surnameResults) for (const name of names) surnames.push(name);
633
+ if (dictionaries?.surnames) for (const names of Object.values(dictionaries.surnames)) for (const name of names) surnames.push(name);
661
634
  const dedup = (arr) => {
662
635
  const seen = /* @__PURE__ */ new Set();
663
636
  const result = [];
@@ -3156,17 +3129,6 @@ const normalizeForSearch = (text) => {
3156
3129
  };
3157
3130
  //#endregion
3158
3131
  //#region src/detectors/deny-list.ts
3159
- /**
3160
- * Try to load the optional @stll/anonymize-data package.
3161
- * Returns null if not installed.
3162
- */
3163
- const loadDataModule = async () => {
3164
- try {
3165
- return await import("./dist.mjs");
3166
- } catch {
3167
- return null;
3168
- }
3169
- };
3170
3132
  const loadAllowList = (ctx) => {
3171
3133
  if (ctx.allowListPromise) return ctx.allowListPromise;
3172
3134
  ctx.allowListPromise = (async () => {
@@ -3285,46 +3247,33 @@ const PERSON_CHAIN_BREAK_RE = /[!?;:]|,/u;
3285
3247
  const isInitialContinuationGap = (text, gap) => /^\p{Lu}$/u.test(text) && /^\.[^\S\n]{1,2}$/u.test(gap) || /^[^\S\n]{1,2}(?:\p{Lu}\.[^\S\n]{1,2})+$/u.test(gap);
3286
3248
  /**
3287
3249
  * Resolve which dictionaries to load based on country
3288
- * and category filters, load them, and build the deny
3289
- * list data. The returned data provides PatternEntry[]
3290
- * for the unified builder and parallel arrays for
3250
+ * and category filters, then build the deny list data.
3251
+ * The returned data provides PatternEntry[] for the
3252
+ * unified builder and parallel arrays for
3291
3253
  * post-processing.
3292
3254
  *
3293
- * Requires `@stll/anonymize-data` to be installed.
3294
- * Returns null if the data package is not available.
3255
+ * Dictionary data is injected via `config.dictionaries`.
3256
+ * Returns null if no dictionaries are provided.
3295
3257
  */
3296
3258
  const buildDenyList = async (config, ctx = defaultContext) => {
3297
- await initNameCorpus(ctx);
3259
+ await initNameCorpus(ctx, config.dictionaries);
3298
3260
  await Promise.all([
3299
3261
  loadStopwords(ctx),
3300
3262
  loadAllowList(ctx),
3301
3263
  loadPersonStopwords(ctx),
3302
3264
  loadGenericRoles(ctx)
3303
3265
  ]);
3304
- const dataModule = await loadDataModule();
3305
- if (!dataModule) return null;
3266
+ const dictionaries = config.dictionaries;
3267
+ const hasDenyList = dictionaries?.denyList && dictionaries?.denyListMeta;
3268
+ const hasCities = dictionaries?.cities && dictionaries.cities.length > 0;
3269
+ if (!hasDenyList && !hasCities) return buildNameCorpusOnly(config, ctx);
3306
3270
  const allowedCountries = resolveCountries(config.denyListRegions, config.denyListCountries);
3307
3271
  const excluded = config.denyListExcludeCategories;
3308
3272
  const excludeCategories = excluded ? new Set(excluded) : /* @__PURE__ */ new Set();
3309
- const ids = [...dataModule.ALL_DICTIONARY_IDS].filter((id) => {
3310
- const meta = dataModule.DICTIONARY_META[id];
3311
- if (!meta) return false;
3312
- if (!config.enableNameCorpus && meta.category === "Names") return false;
3313
- if (excludeCategories.has(meta.category)) return false;
3314
- if (allowedCountries === null) return true;
3315
- if (meta.country === null) return true;
3316
- return allowedCountries.has(meta.country);
3317
- });
3318
3273
  const patternList = [];
3319
3274
  const labelList = [];
3320
3275
  const sourceList = [];
3321
3276
  const patternIndex = /* @__PURE__ */ new Map();
3322
- const results = await Promise.all(ids.map(async (id) => {
3323
- return {
3324
- id,
3325
- entries: await dataModule.loadDictionary(id)
3326
- };
3327
- }));
3328
3277
  const addDenyListEntry = (entry, label) => {
3329
3278
  const normalized = normalizeForSearch(entry).replace(/[|\\]/g, "");
3330
3279
  if (normalized.length === 0) return;
@@ -3340,47 +3289,59 @@ const buildDenyList = async (config, ctx = defaultContext) => {
3340
3289
  sourceList.push(["deny-list"]);
3341
3290
  }
3342
3291
  };
3343
- for (const { id, entries } of results) {
3344
- const meta = dataModule.DICTIONARY_META[id];
3345
- if (!meta) continue;
3346
- for (const entry of entries) addDenyListEntry(entry, meta.label);
3347
- }
3348
- if (!excludeCategories.has("Places")) {
3349
- const cityCountries = allowedCountries !== null ? [...allowedCountries] : [
3350
- "AT",
3351
- "AU",
3352
- "BE",
3353
- "BG",
3354
- "BR",
3355
- "CA",
3356
- "CH",
3357
- "CZ",
3358
- "DE",
3359
- "DK",
3360
- "ES",
3361
- "FI",
3362
- "FR",
3363
- "GB",
3364
- "GR",
3365
- "HR",
3366
- "HU",
3367
- "IE",
3368
- "IT",
3369
- "LU",
3370
- "NL",
3371
- "NO",
3372
- "NZ",
3373
- "PL",
3374
- "PT",
3375
- "RO",
3376
- "SE",
3377
- "SI",
3378
- "SK",
3379
- "US"
3380
- ];
3381
- const cityEntries = await dataModule.loadCityDictionaries(cityCountries);
3382
- for (const entry of cityEntries) addDenyListEntry(entry, "address");
3292
+ if (hasDenyList) {
3293
+ const denyListData = dictionaries.denyList;
3294
+ const metaData = dictionaries.denyListMeta;
3295
+ for (const [id, entries] of Object.entries(denyListData)) {
3296
+ const meta = metaData[id];
3297
+ if (!meta) continue;
3298
+ if (!config.enableNameCorpus && meta.category === "Names") continue;
3299
+ if (excludeCategories.has(meta.category)) continue;
3300
+ if (allowedCountries !== null && meta.country !== null) {
3301
+ if (!allowedCountries.has(meta.country)) continue;
3302
+ }
3303
+ for (const entry of entries) addDenyListEntry(entry, meta.label);
3304
+ }
3383
3305
  }
3306
+ if (hasCities && !excludeCategories.has("Places")) for (const entry of dictionaries.cities) addDenyListEntry(entry, "address");
3307
+ appendNameCorpusEntries(config, ctx, patternList, labelList, sourceList, patternIndex);
3308
+ if (patternList.length === 0) return null;
3309
+ return {
3310
+ labels: labelList,
3311
+ originals: patternList,
3312
+ sources: sourceList
3313
+ };
3314
+ };
3315
+ /**
3316
+ * Build deny-list data containing only name corpus
3317
+ * entries (no external dictionaries). Used when no
3318
+ * dictionary data is injected but name corpus is
3319
+ * enabled.
3320
+ */
3321
+ const buildNameCorpusOnly = (config, ctx) => {
3322
+ if (!config.enableNameCorpus) return null;
3323
+ const excluded = config.denyListExcludeCategories;
3324
+ if ((excluded ? new Set(excluded) : /* @__PURE__ */ new Set()).has("Names")) return null;
3325
+ const patternList = [];
3326
+ const labelList = [];
3327
+ const sourceList = [];
3328
+ appendNameCorpusEntries(config, ctx, patternList, labelList, sourceList, /* @__PURE__ */ new Map());
3329
+ if (patternList.length === 0) return null;
3330
+ return {
3331
+ labels: labelList,
3332
+ originals: patternList,
3333
+ sources: sourceList
3334
+ };
3335
+ };
3336
+ /**
3337
+ * Append name corpus entries (first names, surnames,
3338
+ * titles) to the pattern arrays. Shared between
3339
+ * buildDenyList and buildNameCorpusOnly.
3340
+ */
3341
+ const appendNameCorpusEntries = (config, ctx, patternList, labelList, sourceList, patternIndex) => {
3342
+ const excluded = config.denyListExcludeCategories;
3343
+ const excludeCategories = excluded ? new Set(excluded) : /* @__PURE__ */ new Set();
3344
+ if (!config.enableNameCorpus || excludeCategories.has("Names")) return;
3384
3345
  const addNameEntry = (name, source) => {
3385
3346
  const normalized = normalizeForSearch(name).replace(/[|\\]/g, "");
3386
3347
  if (normalized.length === 0) return;
@@ -3396,30 +3357,22 @@ const buildDenyList = async (config, ctx = defaultContext) => {
3396
3357
  sourceList.push([source]);
3397
3358
  }
3398
3359
  };
3399
- if (config.enableNameCorpus && !excludeCategories.has("Names")) {
3400
- for (const name of getNameCorpusFirstNames(ctx)) addNameEntry(name, "first-name");
3401
- for (const name of getNameCorpusSurnames(ctx)) addNameEntry(name, "surname");
3402
- for (const title of getNameCorpusTitles(ctx)) {
3403
- const norm = normalizeForSearch(title).replace(/[|\\]/g, "");
3404
- if (norm.length === 0) continue;
3405
- const lower = norm.toLowerCase();
3406
- const existing = patternIndex.get(lower);
3407
- if (existing !== void 0) {
3408
- if (!sourceList[existing].includes("title")) sourceList[existing].push("title");
3409
- } else {
3410
- patternIndex.set(lower, patternList.length);
3411
- patternList.push(norm);
3412
- labelList.push(["person"]);
3413
- sourceList.push(["title"]);
3414
- }
3360
+ for (const name of getNameCorpusFirstNames(ctx)) addNameEntry(name, "first-name");
3361
+ for (const name of getNameCorpusSurnames(ctx)) addNameEntry(name, "surname");
3362
+ for (const title of getNameCorpusTitles(ctx)) {
3363
+ const norm = normalizeForSearch(title).replace(/[|\\]/g, "");
3364
+ if (norm.length === 0) continue;
3365
+ const lower = norm.toLowerCase();
3366
+ const existing = patternIndex.get(lower);
3367
+ if (existing !== void 0) {
3368
+ if (!sourceList[existing].includes("title")) sourceList[existing].push("title");
3369
+ } else {
3370
+ patternIndex.set(lower, patternList.length);
3371
+ patternList.push(norm);
3372
+ labelList.push(["person"]);
3373
+ sourceList.push(["title"]);
3415
3374
  }
3416
3375
  }
3417
- if (patternList.length === 0) return null;
3418
- return {
3419
- labels: labelList,
3420
- originals: patternList,
3421
- sources: sourceList
3422
- };
3423
3376
  };
3424
3377
  /**
3425
3378
  * Ensure all deny-list support data (stopwords, allow
@@ -3429,8 +3382,8 @@ const buildDenyList = async (config, ctx = defaultContext) => {
3429
3382
  * the search instance was built on a different context
3430
3383
  * (e.g. cachedSearch).
3431
3384
  */
3432
- const ensureDenyListData = async (ctx = defaultContext) => {
3433
- await initNameCorpus(ctx);
3385
+ const ensureDenyListData = async (ctx = defaultContext, dictionaries) => {
3386
+ await initNameCorpus(ctx, dictionaries);
3434
3387
  await Promise.all([
3435
3388
  loadStopwords(ctx),
3436
3389
  loadAllowList(ctx),
@@ -5186,7 +5139,7 @@ const runPipeline = async (options) => {
5186
5139
  initStreetAbbrevs(),
5187
5140
  hotwordInit
5188
5141
  ]);
5189
- if (cachedSearch && config.enableDenyList) await ensureDenyListData(ctx);
5142
+ if (cachedSearch && config.enableDenyList) await ensureDenyListData(ctx, config.dictionaries);
5190
5143
  let zones = [];
5191
5144
  if (config.enableZoneClassification && zoneInitOk) {
5192
5145
  zones = classifyZones(fullText, ctx);
@@ -5212,7 +5165,7 @@ const runPipeline = async (options) => {
5212
5165
  let rawNameCorpusEntities = [];
5213
5166
  let nameCorpusEntities = [];
5214
5167
  if (config.enableNameCorpus && !config.enableDenyList) {
5215
- await initNameCorpus(ctx);
5168
+ await initNameCorpus(ctx, config.dictionaries);
5216
5169
  checkAbort(signal);
5217
5170
  rawNameCorpusEntities = detectNameCorpus(fullText, ctx);
5218
5171
  nameCorpusEntities = filterAllowedLabels(rawNameCorpusEntities, preHotwordAllowedLabels);