@stll/anonymize-wasm 2.0.0 → 2.0.2

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.
package/dist/wasm.mjs CHANGED
@@ -1,5 +1,166 @@
1
- import { DEFAULT_ENTITY_LABELS, DETECTION_SOURCES, DETECTOR_PRIORITY, OPERATOR_TYPES } from "./constants.mjs";
1
+ import { DEFAULT_ENTITY_LABELS, DETECTION_SOURCES, DETECTOR_PRIORITY, ENTITY_CAPABILITIES, ENTITY_LABELS, ENTITY_SELECTIONS, OPERATOR_TYPES } from "./constants.mjs";
2
+ import { CAPABILITY_MANIFEST, CAPABILITY_MANIFEST_SCHEMA_VERSION, CAPABILITY_RUNTIMES } from "./capabilities.mjs";
2
3
  //#region src/native.ts
4
+ const CALLER_DETECTION_CONTRACT_VERSION = 2;
5
+ const callerDetectionRequestJson = (detections) => JSON.stringify({
6
+ version: 2,
7
+ detections: detections.map((detection) => ({
8
+ start: detection.start,
9
+ end: detection.end,
10
+ label: detection.label,
11
+ score: detection.score,
12
+ provider_id: detection.providerId,
13
+ detection_id: detection.detectionId
14
+ }))
15
+ });
16
+ var PreparedNativeRedactionSession = class {
17
+ #session;
18
+ constructor(session) {
19
+ this.#session = session;
20
+ }
21
+ sessionId() {
22
+ return this.#session.sessionId();
23
+ }
24
+ session_id() {
25
+ return this.sessionId();
26
+ }
27
+ mappingCount() {
28
+ return this.#session.mappingCount();
29
+ }
30
+ mapping_count() {
31
+ return this.mappingCount();
32
+ }
33
+ restoreText(fullText, observedAtEpochSeconds) {
34
+ if (observedAtEpochSeconds === void 0) {
35
+ const restore = this.#session.restoreText;
36
+ if (!restore) throw new Error("Native anonymize binding does not support session restoration");
37
+ return restore.call(this.#session, fullText);
38
+ }
39
+ const restore = this.#session.restoreTextAt;
40
+ if (!restore) throw new Error("Native anonymize binding does not support session restoration lifecycle controls");
41
+ return restore.call(this.#session, fullText, observedAtEpochSeconds);
42
+ }
43
+ restore_text(fullText, observedAtEpochSeconds) {
44
+ return this.restoreText(fullText, observedAtEpochSeconds);
45
+ }
46
+ toPlaintextJson() {
47
+ return this.#session.toPlaintextJson();
48
+ }
49
+ to_plaintext_json() {
50
+ return this.toPlaintextJson();
51
+ }
52
+ toPlaintextJsonAt(observedAtEpochSeconds) {
53
+ const serialize = this.#session.toPlaintextJsonAt;
54
+ if (!serialize) throw new Error("Native anonymize binding does not support session lifecycle controls");
55
+ return serialize.call(this.#session, observedAtEpochSeconds);
56
+ }
57
+ to_plaintext_json_at(observedAtEpochSeconds) {
58
+ return this.toPlaintextJsonAt(observedAtEpochSeconds);
59
+ }
60
+ toEncryptedArchive(key) {
61
+ const serialize = this.#session.toEncryptedArchive;
62
+ if (!serialize) throw new Error("Native anonymize binding does not support encrypted session archives");
63
+ return serialize.call(this.#session, key);
64
+ }
65
+ to_encrypted_archive(key) {
66
+ return this.toEncryptedArchive(key);
67
+ }
68
+ toEncryptedArchiveAt(key, observedAtEpochSeconds) {
69
+ const serialize = this.#session.toEncryptedArchiveAt;
70
+ if (!serialize) throw new Error("Native anonymize binding does not support encrypted session archives");
71
+ return serialize.call(this.#session, key, observedAtEpochSeconds);
72
+ }
73
+ to_encrypted_archive_at(key, observedAtEpochSeconds) {
74
+ return this.toEncryptedArchiveAt(key, observedAtEpochSeconds);
75
+ }
76
+ inspect(observedAtEpochSeconds) {
77
+ const inspect = this.#session.inspectJson;
78
+ if (!inspect) throw new Error("Native anonymize binding does not support session lifecycle controls");
79
+ const metadata = JSON.parse(inspect.call(this.#session, observedAtEpochSeconds));
80
+ return {
81
+ sessionId: metadata.session_id,
82
+ createdAtEpochSeconds: metadata.created_at_epoch_seconds,
83
+ expiresAtEpochSeconds: metadata.expires_at_epoch_seconds,
84
+ mappingCount: metadata.mapping_count,
85
+ status: metadata.status
86
+ };
87
+ }
88
+ delete() {
89
+ const deleteSession = this.#session.deleteJson;
90
+ if (!deleteSession) throw new Error("Native anonymize binding does not support session lifecycle controls");
91
+ const summary = JSON.parse(deleteSession.call(this.#session));
92
+ return {
93
+ sessionId: summary.session_id,
94
+ deletedMappingCount: summary.deleted_mapping_count
95
+ };
96
+ }
97
+ redactStaticEntities(fullText, operators) {
98
+ const result = JSON.parse(this.redact_text_json(fullText, operators));
99
+ return fromCanonicalStaticRedactionResult(result);
100
+ }
101
+ redactText(fullText, operators) {
102
+ return this.redactStaticEntities(fullText, operators);
103
+ }
104
+ redact_text(fullText, operators) {
105
+ return this.redactText(fullText, operators);
106
+ }
107
+ redactTextJson(fullText, operators) {
108
+ return this.redact_text_json(fullText, operators);
109
+ }
110
+ redact_text_json(fullText, operators) {
111
+ return this.#session.redactStaticEntitiesJson(fullText, toBindingOperatorConfig(operators));
112
+ }
113
+ redactStaticEntitiesAt(options) {
114
+ const result = JSON.parse(this.redactTextJsonAt(options));
115
+ return fromCanonicalStaticRedactionResult(result);
116
+ }
117
+ redactTextAt(options) {
118
+ return this.redactStaticEntitiesAt(options);
119
+ }
120
+ redact_text_at(options) {
121
+ return this.redactTextAt(options);
122
+ }
123
+ redact_static_entities_at(options) {
124
+ return this.redactStaticEntitiesAt(options);
125
+ }
126
+ redactTextJsonAt({ fullText, observedAtEpochSeconds, operators }) {
127
+ const redact = this.#session.redactStaticEntitiesJsonAt;
128
+ if (!redact) throw new Error("Native anonymize binding does not support session lifecycle controls");
129
+ return redact.call(this.#session, fullText, observedAtEpochSeconds, toBindingOperatorConfig(operators));
130
+ }
131
+ redact_text_json_at(options) {
132
+ return this.redactTextJsonAt(options);
133
+ }
134
+ planTextBatchWithCallerDetections({ inputs, operators, observedAtEpochSeconds }) {
135
+ const plan = this.#session.planStaticEntitiesWithCallerDetections;
136
+ if (!plan) throw new Error("Native anonymize binding does not support transactional caller-detection session plans");
137
+ const bindingOperators = toBindingOperatorConfig(operators);
138
+ return new PreparedNativeSessionRedactionPlan(plan.call(this.#session, {
139
+ inputs: inputs.map(({ detections, fullText }) => ({
140
+ fullText,
141
+ requestJson: callerDetectionRequestJson(detections)
142
+ })),
143
+ ...bindingOperators === void 0 ? {} : { operators: bindingOperators },
144
+ ...observedAtEpochSeconds === void 0 ? {} : { observedAtEpochSeconds }
145
+ }));
146
+ }
147
+ };
148
+ var PreparedNativeSessionRedactionPlan = class {
149
+ blocks;
150
+ #plan;
151
+ constructor(plan) {
152
+ this.#plan = plan;
153
+ const blocks = JSON.parse(plan.resultJson());
154
+ this.blocks = blocks.map(({ caller_entity_count, entity_count, replacements }) => ({
155
+ replacements,
156
+ entityCount: entity_count,
157
+ callerEntityCount: caller_entity_count
158
+ }));
159
+ }
160
+ commit() {
161
+ this.#plan.commit();
162
+ }
163
+ };
3
164
  var PreparedNativeAnonymizer = class {
4
165
  #prepared;
5
166
  constructor(prepared) {
@@ -28,6 +189,43 @@ var PreparedNativeAnonymizer = class {
28
189
  warm_lazy_regex_diagnostics_json() {
29
190
  return this.warmLazyRegexDiagnosticsJson();
30
191
  }
192
+ createRedactionSession(sessionId) {
193
+ const create = this.#prepared.createRedactionSession;
194
+ if (!create) throw new Error("Native anonymize binding does not support redaction sessions");
195
+ return new PreparedNativeRedactionSession(create.call(this.#prepared, sessionId));
196
+ }
197
+ create_redaction_session(sessionId) {
198
+ return this.createRedactionSession(sessionId);
199
+ }
200
+ createRedactionSessionWithLifecycle({ sessionId, createdAtEpochSeconds, expiresAtEpochSeconds }) {
201
+ const create = this.#prepared.createRedactionSessionWithLifecycle;
202
+ if (!create) throw new Error("Native anonymize binding does not support session lifecycle controls");
203
+ return new PreparedNativeRedactionSession(create.call(this.#prepared, sessionId, createdAtEpochSeconds, expiresAtEpochSeconds));
204
+ }
205
+ create_redaction_session_with_lifecycle(options) {
206
+ return this.createRedactionSessionWithLifecycle(options);
207
+ }
208
+ restoreRedactionSession(plaintextJson) {
209
+ const restore = this.#prepared.restoreRedactionSession;
210
+ if (!restore) throw new Error("Native anonymize binding does not support redaction sessions");
211
+ return new PreparedNativeRedactionSession(restore.call(this.#prepared, plaintextJson));
212
+ }
213
+ restore_redaction_session(plaintextJson) {
214
+ return this.restoreRedactionSession(plaintextJson);
215
+ }
216
+ restoreEncryptedRedactionSession({ archive, key, expectedSessionId, observedAtEpochSeconds }) {
217
+ const restore = this.#prepared.restoreEncryptedRedactionSession;
218
+ if (!restore) throw new Error("Native anonymize binding does not support encrypted session archives");
219
+ return new PreparedNativeRedactionSession(restore.call(this.#prepared, {
220
+ archive,
221
+ key,
222
+ expectedSessionId,
223
+ ...observedAtEpochSeconds === void 0 ? {} : { observedAtEpochSeconds }
224
+ }));
225
+ }
226
+ restore_encrypted_redaction_session(options) {
227
+ return this.restoreEncryptedRedactionSession(options);
228
+ }
31
229
  redactStaticEntities(fullText, operators) {
32
230
  return toNativeStaticRedactionResult(this.#prepared.redactStaticEntities(fullText, toBindingOperatorConfig(operators)));
33
231
  }
@@ -39,6 +237,32 @@ var PreparedNativeAnonymizer = class {
39
237
  if (this.#prepared.redactStaticEntitiesJson) return this.#prepared.redactStaticEntitiesJson(fullText, bindingOperators);
40
238
  return JSON.stringify(toBindingStaticRedactionResult(toNativeStaticRedactionResult(this.#prepared.redactStaticEntities(fullText, bindingOperators))));
41
239
  }
240
+ redactStaticEntitiesWithCallerDetections(fullText, options) {
241
+ if (!this.#prepared.redactStaticEntitiesWithCallerDetectionsJson) throw new Error("Native anonymize binding does not support caller detections");
242
+ const requestJson = callerDetectionRequestJson(options.detections);
243
+ const operators = toBindingOperatorConfig(options.operators);
244
+ const result = JSON.parse(this.#prepared.redactStaticEntitiesWithCallerDetectionsJson(fullText, {
245
+ requestJson,
246
+ ...operators ? { operators } : {}
247
+ }));
248
+ return fromCanonicalStaticRedactionResult(result);
249
+ }
250
+ redact_text_with_caller_detections(fullText, options) {
251
+ return this.redactStaticEntitiesWithCallerDetections(fullText, options);
252
+ }
253
+ redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(fullText, options) {
254
+ const redact = this.#prepared.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson;
255
+ if (!redact) return null;
256
+ const requestJson = callerDetectionRequestJson(options.detections);
257
+ const operators = toBindingOperatorConfig(options.operators);
258
+ return redact.call(this.#prepared, fullText, {
259
+ requestJson,
260
+ ...operators ? { operators } : {}
261
+ });
262
+ }
263
+ redact_static_entities_with_caller_detections_diagnostics_json(fullText, options) {
264
+ return this.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(fullText, options);
265
+ }
42
266
  redactTextJson(fullText, operators) {
43
267
  return this.redact_text_json(fullText, operators);
44
268
  }
@@ -94,6 +318,30 @@ var PreparedNativePipeline = class {
94
318
  warm_lazy_regex_diagnostics_json() {
95
319
  return this.warmLazyRegexDiagnosticsJson();
96
320
  }
321
+ createRedactionSession(sessionId) {
322
+ return this.#anonymizer.createRedactionSession(sessionId);
323
+ }
324
+ create_redaction_session(sessionId) {
325
+ return this.createRedactionSession(sessionId);
326
+ }
327
+ createRedactionSessionWithLifecycle(options) {
328
+ return this.#anonymizer.createRedactionSessionWithLifecycle(options);
329
+ }
330
+ create_redaction_session_with_lifecycle(options) {
331
+ return this.createRedactionSessionWithLifecycle(options);
332
+ }
333
+ restoreRedactionSession(plaintextJson) {
334
+ return this.#anonymizer.restoreRedactionSession(plaintextJson);
335
+ }
336
+ restore_redaction_session(plaintextJson) {
337
+ return this.restoreRedactionSession(plaintextJson);
338
+ }
339
+ restoreEncryptedRedactionSession(options) {
340
+ return this.#anonymizer.restoreEncryptedRedactionSession(options);
341
+ }
342
+ restore_encrypted_redaction_session(options) {
343
+ return this.restoreEncryptedRedactionSession(options);
344
+ }
97
345
  redactText(fullText, operators) {
98
346
  return this.#anonymizer.redactStaticEntities(fullText, operators);
99
347
  }
@@ -103,6 +351,18 @@ var PreparedNativePipeline = class {
103
351
  redact_text_json(fullText, operators) {
104
352
  return this.#anonymizer.redact_text_json(fullText, operators);
105
353
  }
354
+ redactTextWithCallerDetections(fullText, options) {
355
+ return this.#anonymizer.redactStaticEntitiesWithCallerDetections(fullText, options);
356
+ }
357
+ redact_text_with_caller_detections(fullText, options) {
358
+ return this.redactTextWithCallerDetections(fullText, options);
359
+ }
360
+ redactTextWithCallerDetectionsDiagnosticsJson(fullText, options) {
361
+ return this.#anonymizer.redactStaticEntitiesWithCallerDetectionsDiagnosticsJson(fullText, options);
362
+ }
363
+ redact_text_with_caller_detections_diagnostics_json(fullText, options) {
364
+ return this.redactTextWithCallerDetectionsDiagnosticsJson(fullText, options);
365
+ }
106
366
  redactTextJson(fullText, operators) {
107
367
  return this.redact_text_json(fullText, operators);
108
368
  }
@@ -177,6 +437,20 @@ const toNativeStaticRedactionResult = (result) => ({
177
437
  resolvedEntities: result.resolvedEntities.map(toNativePipelineEntity),
178
438
  redaction: toNativeRedactionResult(result.redaction)
179
439
  });
440
+ const fromCanonicalStaticRedactionResult = (result) => ({
441
+ resolvedEntities: result.resolved_entities.map(({ source_detail, provider_id, detection_id, ...entity }) => ({
442
+ ...entity,
443
+ ...source_detail ? { sourceDetail: source_detail } : {},
444
+ ...provider_id ? { providerId: provider_id } : {},
445
+ ...detection_id ? { detectionId: detection_id } : {}
446
+ })),
447
+ redaction: {
448
+ redactedText: result.redaction.redacted_text,
449
+ redactionMap: toRedactionMap(result.redaction.redaction_map),
450
+ operatorMap: toOperatorMap(result.redaction.operator_map),
451
+ entityCount: result.redaction.entity_count
452
+ }
453
+ });
180
454
  const toBindingStaticRedactionResult = (result) => ({
181
455
  resolved_entities: result.resolvedEntities.map(toBindingPipelineEntity),
182
456
  redaction: {
@@ -199,11 +473,15 @@ const toNativePipelineEntity = (entity) => ({
199
473
  text: entity.text,
200
474
  score: entity.score,
201
475
  source: entity.source,
202
- ...entity.sourceDetail ? { sourceDetail: entity.sourceDetail } : {}
476
+ ...entity.sourceDetail ? { sourceDetail: entity.sourceDetail } : {},
477
+ ...entity.providerId ? { providerId: entity.providerId } : {},
478
+ ...entity.detectionId ? { detectionId: entity.detectionId } : {}
203
479
  });
204
- const toBindingPipelineEntity = ({ sourceDetail, ...entity }) => ({
480
+ const toBindingPipelineEntity = ({ sourceDetail, providerId, detectionId, ...entity }) => ({
205
481
  ...entity,
206
- source_detail: sourceDetail ?? null
482
+ source_detail: sourceDetail ?? null,
483
+ provider_id: providerId ?? null,
484
+ detection_id: detectionId ?? null
207
485
  });
208
486
  const toNativeRedactionResult = (result) => ({
209
487
  redactedText: result.redactedText,
@@ -222,6 +500,20 @@ const toOperatorMap = (entries) => {
222
500
  return map;
223
501
  };
224
502
  //#endregion
503
+ //#region src/context.ts
504
+ /** Create a fresh, empty pipeline context. */
505
+ const createPipelineContext = () => ({
506
+ nativePipelinePackage: null,
507
+ nativePipelinePackageKey: "",
508
+ nativePipelinePackagePromise: null
509
+ });
510
+ /**
511
+ * Module-level default context. Used when callers
512
+ * don't provide an explicit context, preserving full
513
+ * backward compatibility with the existing API.
514
+ */
515
+ const defaultContext = createPipelineContext();
516
+ //#endregion
225
517
  //#region src/redact.ts
226
518
  /**
227
519
  * Serialize the redaction key to JSON for export.
@@ -246,6 +538,317 @@ const deanonymise = (redactedText, redactionMap) => {
246
538
  return result;
247
539
  };
248
540
  //#endregion
541
+ //#region src/types.ts
542
+ const isLegalFormsEnabled = (config) => config.enableLegalForms !== false;
543
+ //#endregion
544
+ //#region src/language-scope.ts
545
+ const scopeData = {
546
+ _comment: "Default dictionary scopes for content language hints. Lower-level caller config can still override name corpus languages and deny-list countries independently.",
547
+ languages: {
548
+ "cs": {
549
+ "nameCorpusLanguages": ["cs", "sk"],
550
+ "denyListCountries": ["CZ", "SK"]
551
+ },
552
+ "de": {
553
+ "nameCorpusLanguages": ["de"],
554
+ "denyListCountries": [
555
+ "DE",
556
+ "AT",
557
+ "CH"
558
+ ]
559
+ },
560
+ "en": {
561
+ "nameCorpusLanguages": ["en"],
562
+ "denyListCountries": [
563
+ "US",
564
+ "GB",
565
+ "CA",
566
+ "AU",
567
+ "IE"
568
+ ]
569
+ },
570
+ "es": {
571
+ "nameCorpusLanguages": ["es"],
572
+ "denyListCountries": [
573
+ "ES",
574
+ "MX",
575
+ "AR",
576
+ "CL",
577
+ "CO",
578
+ "PE",
579
+ "EC",
580
+ "VE",
581
+ "UY",
582
+ "PY",
583
+ "BO",
584
+ "CR",
585
+ "PA",
586
+ "DO",
587
+ "GT",
588
+ "HN",
589
+ "SV",
590
+ "NI",
591
+ "CU"
592
+ ]
593
+ },
594
+ "fr": {
595
+ "nameCorpusLanguages": ["fr"],
596
+ "denyListCountries": [
597
+ "FR",
598
+ "BE",
599
+ "CH",
600
+ "CA",
601
+ "LU",
602
+ "MC"
603
+ ]
604
+ },
605
+ "hu": {
606
+ "nameCorpusLanguages": ["hu"],
607
+ "denyListCountries": ["HU"]
608
+ },
609
+ "it": {
610
+ "nameCorpusLanguages": ["it"],
611
+ "denyListCountries": ["IT", "CH"]
612
+ },
613
+ "pl": {
614
+ "nameCorpusLanguages": ["pl"],
615
+ "denyListCountries": ["PL"]
616
+ },
617
+ "pt-br": {
618
+ "nameCorpusLanguages": ["pt-br"],
619
+ "denyListCountries": ["BR"]
620
+ },
621
+ "ro": {
622
+ "nameCorpusLanguages": ["ro"],
623
+ "denyListCountries": ["RO", "MD"]
624
+ },
625
+ "sk": {
626
+ "nameCorpusLanguages": ["sk", "cs"],
627
+ "denyListCountries": ["SK", "CZ"]
628
+ },
629
+ "sv": {
630
+ "nameCorpusLanguages": ["sv"],
631
+ "denyListCountries": ["SE", "FI"]
632
+ }
633
+ }
634
+ };
635
+ const normalizeLanguage$1 = (language) => language.trim().toLowerCase();
636
+ const fallbackLanguage = (language) => {
637
+ const index = language.indexOf("-");
638
+ return index === -1 ? null : language.slice(0, index);
639
+ };
640
+ const uniquePush = (target, values) => {
641
+ const seen = new Set(target);
642
+ for (const value of values) {
643
+ if (seen.has(value)) continue;
644
+ seen.add(value);
645
+ target.push(value);
646
+ }
647
+ };
648
+ const resolveLanguageScope = (language) => {
649
+ const normalized = normalizeLanguage$1(language);
650
+ if (normalized.length === 0) return null;
651
+ const exact = scopeData.languages[normalized];
652
+ if (exact !== void 0) return exact;
653
+ const fallback = fallbackLanguage(normalized);
654
+ return fallback === null ? null : scopeData.languages[fallback] ?? null;
655
+ };
656
+ const configuredLanguages = (config) => {
657
+ if (config.languages !== void 0) return config.languages;
658
+ return config.language === void 0 ? [] : [config.language];
659
+ };
660
+ const applyPipelineLanguageScope = (config) => {
661
+ const languages = configuredLanguages(config);
662
+ if (languages.length === 0) return config;
663
+ const nameCorpusLanguages = [];
664
+ const denyListCountries = [];
665
+ for (const language of languages) {
666
+ const scope = resolveLanguageScope(language);
667
+ if (scope === null) continue;
668
+ uniquePush(nameCorpusLanguages, scope.nameCorpusLanguages ?? []);
669
+ uniquePush(denyListCountries, scope.denyListCountries ?? []);
670
+ }
671
+ const next = {};
672
+ if (config.nameCorpusLanguages === void 0 && nameCorpusLanguages.length > 0) next.nameCorpusLanguages = nameCorpusLanguages;
673
+ if (config.denyListCountries === void 0 && denyListCountries.length > 0) next.denyListCountries = denyListCountries;
674
+ return Object.keys(next).length === 0 ? config : {
675
+ ...config,
676
+ ...next
677
+ };
678
+ };
679
+ //#endregion
680
+ //#region src/util/language-selection.ts
681
+ const normalizeLanguageCode = (language) => language.trim().toLowerCase();
682
+ const normalizeLanguageSelection = (languages) => languages === void 0 ? [] : languages.map(normalizeLanguageCode).filter((language) => language.length > 0);
683
+ const languageSelectionKey = (languages) => {
684
+ const normalized = normalizeLanguageSelection(languages).toSorted();
685
+ return normalized.length === 0 ? "*" : normalized.join(",");
686
+ };
687
+ //#endregion
688
+ //#region src/pipeline-cache-key.ts
689
+ const DEFAULT_CUSTOM_REGEX_SCORE = .9;
690
+ const contentLanguageFingerprint = (config) => {
691
+ return languageSelectionKey(config.languages ?? (config.language === void 0 ? [] : [config.language]));
692
+ };
693
+ const pipelineConfigKey = (config, gazetteerEntries) => {
694
+ const legalFormsEnabled = isLegalFormsEnabled(config);
695
+ const customDenyFingerprint = config.enableDenyList && config.customDenyList ? config.customDenyList.map((entry) => JSON.stringify({
696
+ label: entry.label,
697
+ value: entry.value,
698
+ variants: [...entry.variants ?? []].sort()
699
+ })).sort().join("\n") : "";
700
+ const customRegexFingerprint = config.enableRegex && config.customRegexes ? config.customRegexes.map((entry) => JSON.stringify({
701
+ label: entry.label,
702
+ pattern: entry.pattern,
703
+ preparedArtifactPolicy: entry.preparedArtifactPolicy ?? null,
704
+ score: entry.score ?? DEFAULT_CUSTOM_REGEX_SCORE
705
+ })).sort().join("\n") : "";
706
+ const gazFingerprint = config.enableGazetteer && gazetteerEntries.length > 0 ? gazetteerEntries.map((entry) => `${entry.id}:${entry.canonical}:${entry.label}:${[...entry.variants].sort().join(",")}`).toSorted().join(";") : "";
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
+ };
709
+ //#endregion
710
+ //#region src/native-pipeline.ts
711
+ const sharedPackageByDictionaries = /* @__PURE__ */ new WeakMap();
712
+ const sharedPackageWithoutDictionaries = /* @__PURE__ */ new Map();
713
+ const dictionaryCacheIds = /* @__PURE__ */ new WeakMap();
714
+ let nextDictionaryCacheId = 0;
715
+ const dictionaryCacheKey = (dictionaries) => {
716
+ if (dictionaries === void 0) return "none";
717
+ const existing = dictionaryCacheIds.get(dictionaries);
718
+ if (existing !== void 0) return `dict:${existing}`;
719
+ nextDictionaryCacheId += 1;
720
+ dictionaryCacheIds.set(dictionaries, nextDictionaryCacheId);
721
+ return `dict:${nextDictionaryCacheId}`;
722
+ };
723
+ const sharedPackageCacheFor = (dictionaries) => {
724
+ if (dictionaries === void 0) return sharedPackageWithoutDictionaries;
725
+ const cached = sharedPackageByDictionaries.get(dictionaries);
726
+ if (cached !== void 0) return cached;
727
+ const created = /* @__PURE__ */ new Map();
728
+ sharedPackageByDictionaries.set(dictionaries, created);
729
+ return created;
730
+ };
731
+ const getNativePipelineCompatibility = (config) => {
732
+ const unsupportedFeatures = [];
733
+ if (config.enableNer) unsupportedFeatures.push("enableNer");
734
+ if (unsupportedFeatures.length === 0) return { status: "supported" };
735
+ return {
736
+ status: "unsupported",
737
+ unsupportedFeatures
738
+ };
739
+ };
740
+ const assertNativePipelineSupported = (config) => {
741
+ const compatibility = getNativePipelineCompatibility(config);
742
+ if (compatibility.status === "supported") return;
743
+ throw new Error(`Native pipeline does not yet support: ${compatibility.unsupportedFeatures.join(", ")}`);
744
+ };
745
+ const encoder = new TextEncoder();
746
+ /**
747
+ * Serialize the assembler inputs the Rust binding expects. Dictionaries are
748
+ * stripped from the pipeline config and passed out of band: the assembler reads
749
+ * the separate bundle preferentially, and keeping the (large) dictionaries out
750
+ * of the config JSON avoids serializing them twice.
751
+ */
752
+ const toAssembleInputs = ({ dictionaries, enableNer = false, ...config }, gazetteerEntries) => ({
753
+ pipelineConfigJson: encoder.encode(JSON.stringify({
754
+ ...config,
755
+ enableNer
756
+ })),
757
+ dictionariesJson: dictionaries === void 0 ? void 0 : encoder.encode(JSON.stringify(dictionaries)),
758
+ gazetteerJson: gazetteerEntries.length === 0 ? void 0 : encoder.encode(JSON.stringify(gazetteerEntries))
759
+ });
760
+ const assemblePackageBytes = (binding, { pipelineConfigJson, dictionariesJson, gazetteerJson }, compressed) => {
761
+ const assemble = compressed ? binding.assembleStaticSearchCompressedPackageBytes : binding.assembleStaticSearchPackageBytes;
762
+ if (assemble === void 0) throw new Error("Native anonymize binding does not support static-search config assembly");
763
+ return assemble(pipelineConfigJson, dictionariesJson, gazetteerJson);
764
+ };
765
+ const prepareNativePipelineConfig = async ({ binding, config, gazetteerEntries = [] }) => {
766
+ const scopedConfig = applyPipelineLanguageScope(config);
767
+ assertNativePipelineSupported(scopedConfig);
768
+ const assemble = binding.assembleStaticSearchConfigJson;
769
+ if (assemble === void 0) throw new Error("Native anonymize binding does not support static-search config assembly");
770
+ const { pipelineConfigJson, dictionariesJson, gazetteerJson } = toAssembleInputs(scopedConfig, gazetteerEntries);
771
+ const configJson = assemble(pipelineConfigJson, dictionariesJson, gazetteerJson);
772
+ return JSON.parse(new TextDecoder().decode(configJson));
773
+ };
774
+ const prepareNativePipelinePackage = async ({ binding, config, gazetteerEntries = [], context, compressed = false }) => {
775
+ const packageBytes = await getCachedNativePipelinePackage({
776
+ config,
777
+ binding,
778
+ gazetteerEntries,
779
+ ...context ? { context } : {},
780
+ compressed
781
+ });
782
+ return new Uint8Array(packageBytes);
783
+ };
784
+ const createNativePipelineFromConfig = async ({ binding, config, gazetteerEntries = [], context }) => {
785
+ return createNativePipelineFromPackage({
786
+ binding,
787
+ packageBytes: await getCachedNativePipelinePackage({
788
+ binding,
789
+ config,
790
+ gazetteerEntries,
791
+ ...context ? { context } : {}
792
+ })
793
+ });
794
+ };
795
+ const getCachedNativePipelinePackage = async ({ binding, config, gazetteerEntries = [], context, compressed = false }) => {
796
+ const scopedConfig = applyPipelineLanguageScope(config);
797
+ assertNativePipelineSupported(scopedConfig);
798
+ const ctx = context ?? defaultContext;
799
+ const key = nativePackageCacheKey({
800
+ binding,
801
+ config: scopedConfig,
802
+ gazetteerEntries,
803
+ compressed
804
+ });
805
+ if (ctx.nativePipelinePackage && ctx.nativePipelinePackageKey === key) return ctx.nativePipelinePackage;
806
+ if (ctx.nativePipelinePackagePromise && ctx.nativePipelinePackageKey === key) return ctx.nativePipelinePackagePromise;
807
+ const sharedCache = sharedPackageCacheFor(scopedConfig.dictionaries);
808
+ const shared = sharedCache.get(key);
809
+ if (shared !== void 0) {
810
+ const packageBytes = await shared;
811
+ ctx.nativePipelinePackage = packageBytes;
812
+ ctx.nativePipelinePackageKey = key;
813
+ ctx.nativePipelinePackagePromise = null;
814
+ return packageBytes;
815
+ }
816
+ ctx.nativePipelinePackage = null;
817
+ ctx.nativePipelinePackageKey = key;
818
+ const promise = buildNativePipelinePackage({
819
+ binding,
820
+ config: scopedConfig,
821
+ gazetteerEntries,
822
+ compressed
823
+ });
824
+ ctx.nativePipelinePackagePromise = promise;
825
+ sharedCache.set(key, promise);
826
+ let packageBytes;
827
+ try {
828
+ packageBytes = await promise;
829
+ } catch (error) {
830
+ if (sharedCache.get(key) === promise) sharedCache.delete(key);
831
+ if (ctx.nativePipelinePackageKey === key && ctx.nativePipelinePackagePromise === promise) {
832
+ ctx.nativePipelinePackage = null;
833
+ ctx.nativePipelinePackagePromise = null;
834
+ }
835
+ throw error;
836
+ }
837
+ if (sharedCache.get(key) === promise) sharedCache.set(key, packageBytes);
838
+ if (ctx.nativePipelinePackageKey === key) {
839
+ ctx.nativePipelinePackage = packageBytes;
840
+ ctx.nativePipelinePackagePromise = null;
841
+ }
842
+ return packageBytes;
843
+ };
844
+ const buildNativePipelinePackage = async ({ binding, config, gazetteerEntries, compressed }) => assemblePackageBytes(binding, toAssembleInputs(config, gazetteerEntries), compressed);
845
+ const nativePackageCacheKey = ({ binding, config, gazetteerEntries, compressed }) => [
846
+ binding.nativePackageVersion(),
847
+ compressed ? "compressed" : "raw",
848
+ dictionaryCacheKey(config.dictionaries),
849
+ pipelineConfigKey(config, gazetteerEntries)
850
+ ].join(":");
851
+ //#endregion
249
852
  //#region src/wasm.ts
250
853
  const NODE_GLUE_MODULE = "index.wasi.cjs";
251
854
  const BROWSER_GLUE_MODULE = "index.wasi-browser.js";
@@ -262,10 +865,12 @@ const getBinding = () => {
262
865
  return bindingPromise;
263
866
  };
264
867
  const loadWasmBinding = async () => {
265
- return toNativeAnonymizeBinding(await import(
868
+ const glueModule = isNodeRuntime() ? NODE_GLUE_MODULE : BROWSER_GLUE_MODULE;
869
+ const loaded = await import(
266
870
  /* @vite-ignore */
267
- assetUrl(isNodeRuntime() ? NODE_GLUE_MODULE : BROWSER_GLUE_MODULE).href
268
- ));
871
+ assetUrl(glueModule).href
872
+ );
873
+ return toNativeAnonymizeBinding(loaded);
269
874
  };
270
875
  const isNodeRuntime = () => {
271
876
  const globals = globalThis;
@@ -425,6 +1030,6 @@ const normalizeLanguage = (language) => {
425
1030
  return normalized;
426
1031
  };
427
1032
  //#endregion
428
- export { DEFAULT_ENTITY_LABELS, DETECTION_SOURCES, DETECTOR_PRIORITY, OPERATOR_TYPES, PreparedAnonymizer, PreparedNativeAnonymizer, PreparedNativePipeline, PreparedSearch, assertNativeBindingVersion, createNativeAnonymizerFromConfig, createNativeAnonymizerFromPackage, createNativePipelineFromPackage, deanonymise, defaultPackageUrl, diagnostics_json, diagnostics_stream_json, encodeNativeSearchConfig, encodeNativeSearchConfigInput, exportRedactionKey, getBinding, getDefaultPipeline, getNativeBindingVersion, loadDefaultPipeline, loadPipeline, load_prepared_package, native_package_version, normalize_for_search, prepareNativeSearchPackage, prepare_search_package, redactDefaultText, redactDefaultTextJson, redact_text, redact_text_json, redact_text_stream_json, summary_diagnostics_json };
1033
+ export { CALLER_DETECTION_CONTRACT_VERSION, CAPABILITY_MANIFEST, CAPABILITY_MANIFEST_SCHEMA_VERSION, CAPABILITY_RUNTIMES, DEFAULT_ENTITY_LABELS, DETECTION_SOURCES, DETECTOR_PRIORITY, ENTITY_CAPABILITIES, ENTITY_LABELS, ENTITY_SELECTIONS, OPERATOR_TYPES, PreparedAnonymizer, PreparedNativeAnonymizer, PreparedNativePipeline, PreparedNativeRedactionSession, PreparedNativeSessionRedactionPlan, PreparedSearch, assertNativeBindingVersion, assertNativePipelineSupported, createNativeAnonymizerFromConfig, createNativeAnonymizerFromPackage, createNativePipelineFromConfig, createNativePipelineFromPackage, createPipelineContext, deanonymise, defaultPackageUrl, diagnostics_json, diagnostics_stream_json, encodeNativeSearchConfig, encodeNativeSearchConfigInput, exportRedactionKey, getBinding, getDefaultPipeline, getNativeBindingVersion, getNativePipelineCompatibility, loadDefaultPipeline, loadPipeline, load_prepared_package, native_package_version, normalize_for_search, prepareNativePipelineConfig, prepareNativePipelinePackage, prepareNativeSearchPackage, prepare_search_package, redactDefaultText, redactDefaultTextJson, redact_text, redact_text_json, redact_text_stream_json, summary_diagnostics_json };
429
1034
 
430
1035
  //# sourceMappingURL=wasm.mjs.map