euredact 0.0.1 → 0.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.
@@ -0,0 +1,76 @@
1
+ import { ResultCache } from "./cache.js";
2
+ import { normalize, mapOffsetToOriginal } from "./normalizer.js";
3
+ import { RuleEngine } from "./rules/engine.js";
4
+ import { EntityType } from "./types.js";
5
+ const DATE_TYPES = new Set([EntityType.DOB, EntityType.DATE_OF_DEATH]);
6
+ class ReferentialMapper {
7
+ counters = new Map();
8
+ mapping = new Map();
9
+ getLabel(text, entityType) {
10
+ if (!this.mapping.has(text)) {
11
+ const count = (this.counters.get(entityType) ?? 0) + 1;
12
+ this.counters.set(entityType, count);
13
+ this.mapping.set(text, `${entityType}_${count}`);
14
+ }
15
+ return this.mapping.get(text);
16
+ }
17
+ }
18
+ export class EuRedact {
19
+ engine = new RuleEngine();
20
+ cache = new ResultCache();
21
+ referentialMapper = new ReferentialMapper();
22
+ addCustomPattern(name, pattern) {
23
+ this.engine.addCustomPattern(name, pattern);
24
+ this.cache.clear();
25
+ }
26
+ redact(text, options = {}) {
27
+ const { countries = null, mode = "rules", referentialIntegrity = false, detectDates = false, cache = true, } = options;
28
+ const [normalizedText, offsetMapping] = normalize(text);
29
+ const countriesTuple = countries
30
+ ? countries.map(c => c.toUpperCase()).sort()
31
+ : ["ALL"];
32
+ const cacheMode = `${mode}|dates=${detectDates}`;
33
+ let cacheKey;
34
+ if (cache) {
35
+ cacheKey = this.cache.key(normalizedText, countriesTuple, cacheMode);
36
+ const cached = this.cache.get(cacheKey);
37
+ if (cached !== null)
38
+ return cached;
39
+ }
40
+ let detections = this.engine.detect(normalizedText, countries);
41
+ if (offsetMapping !== null) {
42
+ detections = detections.map(d => ({
43
+ ...d,
44
+ start: mapOffsetToOriginal(d.start, offsetMapping),
45
+ end: mapOffsetToOriginal(d.end, offsetMapping),
46
+ }));
47
+ }
48
+ if (!detectDates) {
49
+ detections = detections.filter(d => !DATE_TYPES.has(d.entityType));
50
+ }
51
+ detections.sort((a, b) => a.start - b.start || b.end - a.end);
52
+ let redacted = text;
53
+ for (let i = detections.length - 1; i >= 0; i--) {
54
+ const det = detections[i];
55
+ const replacement = referentialIntegrity
56
+ ? this.referentialMapper.getLabel(det.text, det.entityType)
57
+ : `[${det.entityType}]`;
58
+ redacted = redacted.slice(0, det.start) + replacement + redacted.slice(det.end);
59
+ }
60
+ const result = {
61
+ redactedText: redacted,
62
+ detections,
63
+ source: "rules",
64
+ degraded: false,
65
+ };
66
+ if (cache && cacheKey) {
67
+ this.cache.put(cacheKey, result);
68
+ }
69
+ return result;
70
+ }
71
+ redactBatch(texts, options = {}) {
72
+ const countries = options.countries ?? null;
73
+ this.engine.loadCountries(countries ? countries.map(c => c.toUpperCase()) : null);
74
+ return texts.map(text => this.redact(text, options));
75
+ }
76
+ }
@@ -0,0 +1,65 @@
1
+ export declare enum EntityType {
2
+ NAME = "NAME",
3
+ ADDRESS = "ADDRESS",
4
+ IBAN = "IBAN",
5
+ BIC = "BIC",
6
+ CREDIT_CARD = "CREDIT_CARD",
7
+ PHONE = "PHONE",
8
+ EMAIL = "EMAIL",
9
+ DOB = "DOB",
10
+ DATE_OF_DEATH = "DATE_OF_DEATH",
11
+ NATIONAL_ID = "NATIONAL_ID",
12
+ SSN = "SSN",
13
+ TAX_ID = "TAX_ID",
14
+ PASSPORT = "PASSPORT",
15
+ DRIVERS_LICENSE = "DRIVERS_LICENSE",
16
+ RESIDENCE_PERMIT = "RESIDENCE_PERMIT",
17
+ LICENSE_PLATE = "LICENSE_PLATE",
18
+ VIN = "VIN",
19
+ VAT = "VAT",
20
+ POSTAL_CODE = "POSTAL_CODE",
21
+ IP_ADDRESS = "IP_ADDRESS",
22
+ IPV6_ADDRESS = "IPV6_ADDRESS",
23
+ MAC_ADDRESS = "MAC_ADDRESS",
24
+ HEALTH_INSURANCE = "HEALTH_INSURANCE",
25
+ HEALTHCARE_PROVIDER = "HEALTHCARE_PROVIDER",
26
+ CHAMBER_OF_COMMERCE = "CHAMBER_OF_COMMERCE",
27
+ IMEI = "IMEI",
28
+ GPS_COORDINATES = "GPS_COORDINATES",
29
+ UUID = "UUID",
30
+ SOCIAL_HANDLE = "SOCIAL_HANDLE",
31
+ SECRET = "SECRET",
32
+ OTHER = "OTHER"
33
+ }
34
+ export declare enum DetectionSource {
35
+ RULES = "rules",
36
+ CLOUD = "cloud"
37
+ }
38
+ export interface Detection {
39
+ entityType: EntityType | string;
40
+ start: number;
41
+ end: number;
42
+ text: string;
43
+ source: DetectionSource;
44
+ country: string | null;
45
+ confidence: string;
46
+ }
47
+ export interface RedactResult {
48
+ redactedText: string;
49
+ detections: Detection[];
50
+ source: string;
51
+ degraded: boolean;
52
+ }
53
+ export interface PatternDef {
54
+ entityType: EntityType | string;
55
+ pattern: string;
56
+ validator: string | null;
57
+ description: string;
58
+ contextKeywords: string[];
59
+ requiresContext: boolean;
60
+ }
61
+ export interface CountryConfig {
62
+ code: string;
63
+ name: string;
64
+ patterns: PatternDef[];
65
+ }
@@ -0,0 +1,39 @@
1
+ export var EntityType;
2
+ (function (EntityType) {
3
+ EntityType["NAME"] = "NAME";
4
+ EntityType["ADDRESS"] = "ADDRESS";
5
+ EntityType["IBAN"] = "IBAN";
6
+ EntityType["BIC"] = "BIC";
7
+ EntityType["CREDIT_CARD"] = "CREDIT_CARD";
8
+ EntityType["PHONE"] = "PHONE";
9
+ EntityType["EMAIL"] = "EMAIL";
10
+ EntityType["DOB"] = "DOB";
11
+ EntityType["DATE_OF_DEATH"] = "DATE_OF_DEATH";
12
+ EntityType["NATIONAL_ID"] = "NATIONAL_ID";
13
+ EntityType["SSN"] = "SSN";
14
+ EntityType["TAX_ID"] = "TAX_ID";
15
+ EntityType["PASSPORT"] = "PASSPORT";
16
+ EntityType["DRIVERS_LICENSE"] = "DRIVERS_LICENSE";
17
+ EntityType["RESIDENCE_PERMIT"] = "RESIDENCE_PERMIT";
18
+ EntityType["LICENSE_PLATE"] = "LICENSE_PLATE";
19
+ EntityType["VIN"] = "VIN";
20
+ EntityType["VAT"] = "VAT";
21
+ EntityType["POSTAL_CODE"] = "POSTAL_CODE";
22
+ EntityType["IP_ADDRESS"] = "IP_ADDRESS";
23
+ EntityType["IPV6_ADDRESS"] = "IPV6_ADDRESS";
24
+ EntityType["MAC_ADDRESS"] = "MAC_ADDRESS";
25
+ EntityType["HEALTH_INSURANCE"] = "HEALTH_INSURANCE";
26
+ EntityType["HEALTHCARE_PROVIDER"] = "HEALTHCARE_PROVIDER";
27
+ EntityType["CHAMBER_OF_COMMERCE"] = "CHAMBER_OF_COMMERCE";
28
+ EntityType["IMEI"] = "IMEI";
29
+ EntityType["GPS_COORDINATES"] = "GPS_COORDINATES";
30
+ EntityType["UUID"] = "UUID";
31
+ EntityType["SOCIAL_HANDLE"] = "SOCIAL_HANDLE";
32
+ EntityType["SECRET"] = "SECRET";
33
+ EntityType["OTHER"] = "OTHER";
34
+ })(EntityType || (EntityType = {}));
35
+ export var DetectionSource;
36
+ (function (DetectionSource) {
37
+ DetectionSource["RULES"] = "rules";
38
+ DetectionSource["CLOUD"] = "cloud";
39
+ })(DetectionSource || (DetectionSource = {}));
package/package.json CHANGED
@@ -1,17 +1,63 @@
1
1
  {
2
2
  "name": "euredact",
3
- "version": "0.0.1",
4
- "description": "European PII redaction SDK — rule engine + cloud tier",
5
- "main": "index.js",
6
- "keywords": ["pii", "redaction", "gdpr", "privacy", "europe", "nlp"],
7
- "author": "Joren Janssens <joren.janssens@proton.me>",
3
+ "version": "0.2.0",
4
+ "description": "European PII redaction SDK -- fast, zero-dependency, rule-based detection and redaction of personal data across 31 European countries",
8
5
  "license": "Apache-2.0",
9
- "homepage": "https://euredact.eu",
6
+ "type": "module",
7
+ "main": "./dist/cjs/index.js",
8
+ "module": "./dist/esm/index.js",
9
+ "types": "./dist/esm/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/esm/index.d.ts",
14
+ "default": "./dist/esm/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/esm/index.d.ts",
18
+ "default": "./dist/cjs/index.js"
19
+ }
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "engines": {
28
+ "node": ">=16.0.0"
29
+ },
30
+ "keywords": [
31
+ "pii",
32
+ "redaction",
33
+ "gdpr",
34
+ "privacy",
35
+ "europe",
36
+ "eu",
37
+ "iban",
38
+ "bsn",
39
+ "national-id",
40
+ "phone",
41
+ "email",
42
+ "anonymization",
43
+ "data-protection",
44
+ "personal-data",
45
+ "regex"
46
+ ],
10
47
  "repository": {
11
48
  "type": "git",
12
- "url": "https://github.com/euredact/euredact.git"
49
+ "url": "https://github.com/euredact/euredact"
50
+ },
51
+ "scripts": {
52
+ "build:esm": "tsc",
53
+ "build:cjs": "tsc -p tsconfig.cjs.json",
54
+ "postbuild:cjs": "echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
55
+ "build": "rm -rf dist && npm run build:esm && npm run build:cjs",
56
+ "test": "node --import tsx src/__tests__/run.ts",
57
+ "prepublishOnly": "npm run build"
13
58
  },
14
- "bugs": {
15
- "url": "https://github.com/euredact/euredact/issues"
59
+ "devDependencies": {
60
+ "typescript": "^5.4.0",
61
+ "tsx": "^4.7.0"
16
62
  }
17
63
  }
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- // EUREdact — European PII redaction SDK
2
- // TypeScript/Node SDK coming soon. See https://euredact.eu
3
- throw new Error("euredact: Node.js SDK not yet available. Use the Python SDK: pip install euredact");