euredact 0.3.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,20 @@
1
1
  export declare enum EntityType {
2
- NAME = "NAME",
2
+ /**
3
+ * Canonical name for a person's name. `NAME` is kept below as a legacy alias
4
+ * with the same value, exactly as `IBAN` aliases `BANK_ACCOUNT`, so
5
+ * `EntityType.NAME === EntityType.PERSON_NAME` and existing code keeps
6
+ * working — but the emitted value, and therefore the `[PERSON_NAME]`
7
+ * placeholder written into redacted text, is canonical.
8
+ *
9
+ * Renamed rather than translated at the cloud boundary: two names for one
10
+ * type is how a whole category goes missing when someone filters on the
11
+ * spelling they happened to know. Nothing could have depended on the old
12
+ * value — the type is cloud-only and the cloud tier was stubbed, so it was
13
+ * never emitted.
14
+ */
15
+ PERSON_NAME = "PERSON_NAME",
16
+ /** @deprecated legacy alias of {@link EntityType.PERSON_NAME} */
17
+ NAME = "PERSON_NAME",
3
18
  ADDRESS = "ADDRESS",
4
19
  /**
5
20
  * Canonical name for a bank account identifier. `IBAN` is kept below as a
@@ -47,6 +62,15 @@ export declare enum EntityType {
47
62
  UUID = "UUID",
48
63
  SOCIAL_HANDLE = "SOCIAL_HANDLE",
49
64
  SECRET = "SECRET",
65
+ ORGANISATION_NAME = "ORGANISATION_NAME",
66
+ JOB_TITLE = "JOB_TITLE",
67
+ MEDICAL_CONDITION = "MEDICAL_CONDITION",
68
+ SENSITIVE_ATTRIBUTE = "SENSITIVE_ATTRIBUTE",
69
+ BIOMETRIC_REF = "BIOMETRIC_REF",
70
+ FINANCIAL_AMOUNT = "FINANCIAL_AMOUNT",
71
+ QUASI_IDENTIFIER = "QUASI_IDENTIFIER",
72
+ CREDENTIAL = "CREDENTIAL",
73
+ URL = "URL",
50
74
  OTHER = "OTHER"
51
75
  }
52
76
  /**
@@ -55,6 +79,14 @@ export declare enum EntityType {
55
79
  * legacy_aliases). The engine never *emits* these names.
56
80
  */
57
81
  export declare const LEGACY_TYPE_ALIASES: Record<string, string>;
82
+ /**
83
+ * Resolve a possibly-legacy type name to its canonical form.
84
+ *
85
+ * Mirrors `EntityType._missing_` in the Python SDK. An unrecognised name is
86
+ * returned unchanged rather than dropped: a client one release behind the
87
+ * service must not silently lose a whole category of PII.
88
+ */
89
+ export declare function canonicalType(name: string): string;
58
90
  export declare enum DetectionSource {
59
91
  RULES = "rules",
60
92
  CLOUD = "cloud"
@@ -101,6 +133,24 @@ export interface Detection {
101
133
  */
102
134
  outOfScope?: boolean;
103
135
  }
136
+ /**
137
+ * A detection the allowlist kept out of the redacted output.
138
+ *
139
+ * An exemption is a deliberate decision to leave a direct identifier in a
140
+ * document that otherwise claims to be redacted, so it is reported rather than
141
+ * silently dropped: without this, "never detected" and "detected and kept"
142
+ * look identical on the result.
143
+ */
144
+ export interface Exemption {
145
+ entityType: EntityType | string;
146
+ start: number;
147
+ end: number;
148
+ text: string;
149
+ /** The allowlist entry that matched, as the caller wrote it. */
150
+ rule: string;
151
+ /** `"value"` for the literal allowlist, `"domain"` for allowlistDomains. */
152
+ ruleKind: "value" | "domain";
153
+ }
104
154
  export interface RedactResult {
105
155
  redactedText: string;
106
156
  detections: Detection[];
@@ -126,6 +176,18 @@ export interface RedactResult {
126
176
  * already means the tier selector, which {@link RedactResult.source} reports.
127
177
  */
128
178
  detectionMode: string;
179
+ /**
180
+ * Token -> original text, populated by `redact(text, { tokenize: true })`.
181
+ *
182
+ * Hand it to `restore()` with the text that came back from wherever the
183
+ * redacted text went. Every token is unique to this call: the same value in
184
+ * another document gets a different token. Treat the mapping as read-only —
185
+ * a cached result shares it with every caller.
186
+ */
187
+ tokens: Record<string, string>;
188
+ /** Detections the allowlist kept out of the output, with the rule that
189
+ * matched. Empty unless an allowlist was in force. */
190
+ exempted: Exemption[];
129
191
  }
130
192
  export interface PatternDef {
131
193
  entityType: EntityType | string;
package/dist/esm/types.js CHANGED
@@ -1,6 +1,21 @@
1
1
  export var EntityType;
2
2
  (function (EntityType) {
3
- EntityType["NAME"] = "NAME";
3
+ /**
4
+ * Canonical name for a person's name. `NAME` is kept below as a legacy alias
5
+ * with the same value, exactly as `IBAN` aliases `BANK_ACCOUNT`, so
6
+ * `EntityType.NAME === EntityType.PERSON_NAME` and existing code keeps
7
+ * working — but the emitted value, and therefore the `[PERSON_NAME]`
8
+ * placeholder written into redacted text, is canonical.
9
+ *
10
+ * Renamed rather than translated at the cloud boundary: two names for one
11
+ * type is how a whole category goes missing when someone filters on the
12
+ * spelling they happened to know. Nothing could have depended on the old
13
+ * value — the type is cloud-only and the cloud tier was stubbed, so it was
14
+ * never emitted.
15
+ */
16
+ EntityType["PERSON_NAME"] = "PERSON_NAME";
17
+ /** @deprecated legacy alias of {@link EntityType.PERSON_NAME} */
18
+ EntityType["NAME"] = "PERSON_NAME";
4
19
  EntityType["ADDRESS"] = "ADDRESS";
5
20
  /**
6
21
  * Canonical name for a bank account identifier. `IBAN` is kept below as a
@@ -48,6 +63,20 @@ export var EntityType;
48
63
  EntityType["UUID"] = "UUID";
49
64
  EntityType["SOCIAL_HANDLE"] = "SOCIAL_HANDLE";
50
65
  EntityType["SECRET"] = "SECRET";
66
+ // ── [CLOUD EXTENSION] ────────────────────────────────────────────────────
67
+ // Types only the cloud tier can detect. The rule engine never emits these —
68
+ // there is no shape to match on — which is exactly why they exist: the
69
+ // model's job is what the rules cannot catch. Named to match the detection
70
+ // canon the service is trained and evaluated against.
71
+ EntityType["ORGANISATION_NAME"] = "ORGANISATION_NAME";
72
+ EntityType["JOB_TITLE"] = "JOB_TITLE";
73
+ EntityType["MEDICAL_CONDITION"] = "MEDICAL_CONDITION";
74
+ EntityType["SENSITIVE_ATTRIBUTE"] = "SENSITIVE_ATTRIBUTE";
75
+ EntityType["BIOMETRIC_REF"] = "BIOMETRIC_REF";
76
+ EntityType["FINANCIAL_AMOUNT"] = "FINANCIAL_AMOUNT";
77
+ EntityType["QUASI_IDENTIFIER"] = "QUASI_IDENTIFIER";
78
+ EntityType["CREDENTIAL"] = "CREDENTIAL";
79
+ EntityType["URL"] = "URL";
51
80
  EntityType["OTHER"] = "OTHER";
52
81
  })(EntityType || (EntityType = {}));
53
82
  /**
@@ -57,7 +86,21 @@ export var EntityType;
57
86
  */
58
87
  export const LEGACY_TYPE_ALIASES = {
59
88
  IBAN: "BANK_ACCOUNT",
89
+ NAME: "PERSON_NAME",
90
+ STREET_ADDRESS: "ADDRESS",
91
+ NATIONALITY_ETHNICITY: "SENSITIVE_ATTRIBUTE",
60
92
  };
93
+ /**
94
+ * Resolve a possibly-legacy type name to its canonical form.
95
+ *
96
+ * Mirrors `EntityType._missing_` in the Python SDK. An unrecognised name is
97
+ * returned unchanged rather than dropped: a client one release behind the
98
+ * service must not silently lose a whole category of PII.
99
+ */
100
+ export function canonicalType(name) {
101
+ const upper = String(name ?? "").trim().toUpperCase();
102
+ return LEGACY_TYPE_ALIASES[upper] ?? upper;
103
+ }
61
104
  export var DetectionSource;
62
105
  (function (DetectionSource) {
63
106
  DetectionSource["RULES"] = "rules";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "euredact",
3
- "version": "0.3.9",
3
+ "version": "0.5.0",
4
4
  "description": "European PII redaction SDK -- fast, zero-dependency, rule-based detection and redaction of personal data across 31 European countries",
5
5
  "homepage": "https://euredact.dev",
6
6
  "license": "Apache-2.0",
@@ -54,7 +54,7 @@
54
54
  "build:cjs": "tsc -p tsconfig.cjs.json",
55
55
  "postbuild:cjs": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
56
56
  "build": "rm -rf dist && npm run build:esm && npm run build:cjs",
57
- "test": "npm run test:spec && npm run test:inference && npm run test:conformance",
57
+ "test": "npm run test:spec && npm run test:inference && npm run test:cloud && npm run test:tokenize && npm run test:allowlist && npm run test:eval-scoring && npm run test:conformance",
58
58
  "benchmark": "node --import tsx src/__tests__/benchmark.ts",
59
59
  "prepublishOnly": "npm run build",
60
60
  "test:spec": "node --import tsx src/__tests__/spec.ts",
@@ -62,7 +62,11 @@
62
62
  "test:eval:full": "node --max-old-space-size=8192 --import tsx src/__tests__/evalFull.ts",
63
63
  "test:conformance": "node --import tsx src/__tests__/conformance.ts",
64
64
  "test:inference": "node --import tsx src/__tests__/inference.ts",
65
- "dump": "node --import tsx src/__tests__/dump.ts"
65
+ "dump": "node --import tsx src/__tests__/dump.ts",
66
+ "test:cloud": "node --import tsx src/__tests__/cloud.ts",
67
+ "test:tokenize": "node --import tsx src/__tests__/tokenize.ts",
68
+ "test:allowlist": "node --import tsx src/__tests__/allowlist.ts",
69
+ "test:eval-scoring": "node --import tsx src/__tests__/evalScoring.ts"
66
70
  },
67
71
  "devDependencies": {
68
72
  "@types/node": "22.10.2",