pseudonym-mcp 0.2.5 → 0.3.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 (96) hide show
  1. package/README.md +53 -15
  2. package/dist/language/detect-language.d.ts +15 -0
  3. package/dist/language/detect-language.d.ts.map +1 -0
  4. package/dist/language/detect-language.js +45 -0
  5. package/dist/language/detect-language.js.map +1 -0
  6. package/dist/language/language-map.d.ts +7 -0
  7. package/dist/language/language-map.d.ts.map +1 -0
  8. package/dist/language/language-map.js +9 -0
  9. package/dist/language/language-map.js.map +1 -0
  10. package/dist/language/types.d.ts +14 -0
  11. package/dist/language/types.d.ts.map +1 -0
  12. package/dist/language/types.js +2 -0
  13. package/dist/language/types.js.map +1 -0
  14. package/dist/languages/en/rules.d.ts.map +1 -1
  15. package/dist/languages/en/rules.js +6 -66
  16. package/dist/languages/en/rules.js.map +1 -1
  17. package/dist/languages/pl/rules.d.ts.map +1 -1
  18. package/dist/languages/pl/rules.js +6 -41
  19. package/dist/languages/pl/rules.js.map +1 -1
  20. package/dist/patterns/engines/balanced.d.ts +4 -0
  21. package/dist/patterns/engines/balanced.d.ts.map +1 -0
  22. package/dist/patterns/engines/balanced.js +4 -0
  23. package/dist/patterns/engines/balanced.js.map +1 -0
  24. package/dist/patterns/engines/paranoid.d.ts +4 -0
  25. package/dist/patterns/engines/paranoid.d.ts.map +1 -0
  26. package/dist/patterns/engines/paranoid.js +4 -0
  27. package/dist/patterns/engines/paranoid.js.map +1 -0
  28. package/dist/patterns/engines/strict.d.ts +4 -0
  29. package/dist/patterns/engines/strict.d.ts.map +1 -0
  30. package/dist/patterns/engines/strict.js +4 -0
  31. package/dist/patterns/engines/strict.js.map +1 -0
  32. package/dist/patterns/global/email.d.ts +3 -0
  33. package/dist/patterns/global/email.d.ts.map +1 -0
  34. package/dist/patterns/global/email.js +9 -0
  35. package/dist/patterns/global/email.js.map +1 -0
  36. package/dist/patterns/global/iban.d.ts +3 -0
  37. package/dist/patterns/global/iban.d.ts.map +1 -0
  38. package/dist/patterns/global/iban.js +11 -0
  39. package/dist/patterns/global/iban.js.map +1 -0
  40. package/dist/patterns/global/ip.d.ts +4 -0
  41. package/dist/patterns/global/ip.d.ts.map +1 -0
  42. package/dist/patterns/global/ip.js +20 -0
  43. package/dist/patterns/global/ip.js.map +1 -0
  44. package/dist/patterns/global/phone.d.ts +3 -0
  45. package/dist/patterns/global/phone.d.ts.map +1 -0
  46. package/dist/patterns/global/phone.js +11 -0
  47. package/dist/patterns/global/phone.js.map +1 -0
  48. package/dist/patterns/global/url.d.ts +3 -0
  49. package/dist/patterns/global/url.d.ts.map +1 -0
  50. package/dist/patterns/global/url.js +10 -0
  51. package/dist/patterns/global/url.js.map +1 -0
  52. package/dist/patterns/index.d.ts +18 -0
  53. package/dist/patterns/index.d.ts.map +1 -0
  54. package/dist/patterns/index.js +50 -0
  55. package/dist/patterns/index.js.map +1 -0
  56. package/dist/patterns/locale/en/credit-card.d.ts +3 -0
  57. package/dist/patterns/locale/en/credit-card.d.ts.map +1 -0
  58. package/dist/patterns/locale/en/credit-card.js +34 -0
  59. package/dist/patterns/locale/en/credit-card.js.map +1 -0
  60. package/dist/patterns/locale/en/phone.d.ts +3 -0
  61. package/dist/patterns/locale/en/phone.d.ts.map +1 -0
  62. package/dist/patterns/locale/en/phone.js +11 -0
  63. package/dist/patterns/locale/en/phone.js.map +1 -0
  64. package/dist/patterns/locale/en/ssn.d.ts +3 -0
  65. package/dist/patterns/locale/en/ssn.d.ts.map +1 -0
  66. package/dist/patterns/locale/en/ssn.js +30 -0
  67. package/dist/patterns/locale/en/ssn.js.map +1 -0
  68. package/dist/patterns/locale/en/zip-code.d.ts +3 -0
  69. package/dist/patterns/locale/en/zip-code.d.ts.map +1 -0
  70. package/dist/patterns/locale/en/zip-code.js +10 -0
  71. package/dist/patterns/locale/en/zip-code.js.map +1 -0
  72. package/dist/patterns/locale/pl/iban.d.ts +3 -0
  73. package/dist/patterns/locale/pl/iban.d.ts.map +1 -0
  74. package/dist/patterns/locale/pl/iban.js +11 -0
  75. package/dist/patterns/locale/pl/iban.js.map +1 -0
  76. package/dist/patterns/locale/pl/nip.d.ts +3 -0
  77. package/dist/patterns/locale/pl/nip.d.ts.map +1 -0
  78. package/dist/patterns/locale/pl/nip.js +26 -0
  79. package/dist/patterns/locale/pl/nip.js.map +1 -0
  80. package/dist/patterns/locale/pl/pesel.d.ts +3 -0
  81. package/dist/patterns/locale/pl/pesel.d.ts.map +1 -0
  82. package/dist/patterns/locale/pl/pesel.js +25 -0
  83. package/dist/patterns/locale/pl/pesel.js.map +1 -0
  84. package/dist/patterns/locale/pl/phone.d.ts +3 -0
  85. package/dist/patterns/locale/pl/phone.d.ts.map +1 -0
  86. package/dist/patterns/locale/pl/phone.js +13 -0
  87. package/dist/patterns/locale/pl/phone.js.map +1 -0
  88. package/dist/patterns/locale/pl/postal-code.d.ts +3 -0
  89. package/dist/patterns/locale/pl/postal-code.d.ts.map +1 -0
  90. package/dist/patterns/locale/pl/postal-code.js +10 -0
  91. package/dist/patterns/locale/pl/postal-code.js.map +1 -0
  92. package/dist/patterns/types.d.ts +21 -0
  93. package/dist/patterns/types.d.ts.map +1 -0
  94. package/dist/patterns/types.js +9 -0
  95. package/dist/patterns/types.js.map +1 -0
  96. package/package.json +2 -1
package/README.md CHANGED
@@ -13,7 +13,7 @@ Sits between your application and any cloud LLM (Claude, GPT-4, Gemini…). Repl
13
13
 
14
14
  ## What you get
15
15
 
16
- - **Multi-language PII detection**: Built-in support for English (SSN, credit cards, US phone) and Polish (PESEL, IBAN, Polish phone). Extensible to any language.
16
+ - **Multi-language PII detection**: Built-in support for English (SSN, credit cards, US phone) and Polish (PESEL, IBAN, Polish phone). New **heuristic language detection** (`detectLanguage()`) infers the language from text content — `--lang` remains the authoritative override but is no longer the only input.
17
17
  - **Hybrid NER engine**: Regex for structured PII (SSN, credit cards, IBAN, email, phone) + local Ollama LLM for unstructured entities (names, organizations).
18
18
  - **Zero-trust architecture**: All detection and substitution happens on your machine. No PII reaches a third-party API.
19
19
  - **Session-keyed mapping store**: Tokens like `[PERSON:1]` map back to originals in an isolated, per-request session. Multiple round-trips preserve token coherence.
@@ -364,6 +364,16 @@ Add to `~/.cursor/mcp.json`:
364
364
 
365
365
  ## Supported PII types
366
366
 
367
+ ### Global (all languages)
368
+
369
+ | Tag | Pattern | Validation |
370
+ | ------- | ------------------------------------ | ------------ |
371
+ | `EMAIL` | RFC 5321-compatible | Format match |
372
+ | `IBAN` | Generic IBAN (`CC` + 2 check + BBAN) | Format match |
373
+ | `IP` | IPv4 (all octets 0–255) | Format match |
374
+ | `URL` | `http://` / `https://` URLs | Format match |
375
+ | `PHONE` | International `+CC` prefix format | Format match |
376
+
367
377
  ### English (`--lang en`, default)
368
378
 
369
379
  | Tag | Pattern | Validation |
@@ -372,19 +382,46 @@ Add to `~/.cursor/mcp.json`:
372
382
  | `CREDIT_CARD` | 13–19 digits (Visa, Mastercard, Amex, Discover) | Luhn checksum |
373
383
  | `EMAIL` | RFC 5321-compatible | Format match |
374
384
  | `PHONE` | `+1 (XXX) XXX-XXXX`, `XXX-XXX-XXXX`, `XXX.XXX.XXXX` | Format match |
385
+ | `ZIP_CODE` | `XXXXX` or `XXXXX-XXXX` (paranoid mode only) | Format match |
375
386
  | `PERSON` | Full names | Ollama NER (hybrid / llm engines) |
376
387
  | `ORG` | Company / organization names | Ollama NER (hybrid / llm engines) |
377
388
 
378
389
  ### Polish (`--lang pl`)
379
390
 
380
- | Tag | Pattern | Validation |
381
- | -------- | ---------------------------------------------------------------- | ----------------------------------------------- |
382
- | `PESEL` | 11-digit national ID | Full checksum (weights `[1,3,7,9,1,3,7,9,1,3]`) |
383
- | `IBAN` | `PL` + 26 digits, compact or spaced | Format match |
384
- | `EMAIL` | RFC 5321-compatible | Format match |
385
- | `PHONE` | `+48` / `0048` prefix, 9-digit mobile, landline `(XX) XXX-XX-XX` | Format match |
386
- | `PERSON` | Full names | Ollama NER (hybrid / llm engines) |
387
- | `ORG` | Company / organization names | Ollama NER (hybrid / llm engines) |
391
+ | Tag | Pattern | Validation |
392
+ | ------------- | ---------------------------------------------------------------- | ----------------------------------------------- |
393
+ | `PESEL` | 11-digit national ID | Full checksum (weights `[1,3,7,9,1,3,7,9,1,3]`) |
394
+ | `IBAN` | `PL` + 26 digits, compact or spaced | Format match |
395
+ | `EMAIL` | RFC 5321-compatible | Format match |
396
+ | `PHONE` | `+48` / `0048` prefix, 9-digit mobile, landline `(XX) XXX-XX-XX` | Format match |
397
+ | `NIP` | 10-digit tax ID (strict / paranoid modes) | Checksum (weights `[6,5,7,2,3,4,5,6,7]`) |
398
+ | `POSTAL_CODE` | `XX-XXX` (paranoid mode only) | Format match |
399
+ | `PERSON` | Full names | Ollama NER (hybrid / llm engines) |
400
+ | `ORG` | Company / organization names | Ollama NER (hybrid / llm engines) |
401
+
402
+ ## Language Detection
403
+
404
+ pseudonym-mcp includes a lightweight heuristic language detector based on [`franc`](https://github.com/wooorm/franc).
405
+ It infers the language from text content and returns a structured result:
406
+
407
+ ```typescript
408
+ detectLanguage('Umowa zostaje zawarta na czas nieokreślony')
409
+ // → { detected: 'pl', source: 'text', raw: 'pol', confidence: 0.94 }
410
+
411
+ detectLanguage('Hello')
412
+ // → { detected: 'unknown', source: 'fallback', raw: null, confidence: null }
413
+ ```
414
+
415
+ | Field | Description |
416
+ | ------------ | -------------------------------------------------------------------------------------- |
417
+ | `detected` | `'pl'`, `'en'`, or `'unknown'` |
418
+ | `source` | `'text'` — franc ran and mapped successfully; `'fallback'` — too short or undetermined |
419
+ | `raw` | Raw ISO 639-3 code from franc (e.g. `'pol'`), or `null` |
420
+ | `confidence` | Score 0–1 from franc, or `null` when franc was not called |
421
+
422
+ Texts shorter than 20 characters or with low confidence return `detected: 'unknown'`.
423
+ The detector does not affect the current pseudonymization pipeline — `--lang` config remains authoritative.
424
+ It is a building block for future multi-language and auto-select modes.
388
425
 
389
426
  ## Engine modes
390
427
 
@@ -411,19 +448,20 @@ git clone https://github.com/woladi/pseudonym-mcp
411
448
  cd pseudonym-mcp
412
449
  npm install
413
450
  npm run build # tsc compile
414
- npm test # vitest (77 tests, no Ollama required)
451
+ npm test # vitest (134 tests, no Ollama required)
415
452
  ```
416
453
 
417
454
  The test suite runs fully offline — Ollama calls are injected via constructor and mocked in all tests. No live LLM required.
418
455
 
419
456
  ### Adding a new language pack
420
457
 
421
- 1. Create `src/languages/<lang>/rules.ts`
422
- 2. Export an object that implements `LanguageRules` from `src/languages/types.ts`
423
- 3. Register it in the `LANGUAGE_MAP` in `src/core/engine.ts`
424
- 4. Pass `--lang <lang>` at startup
458
+ 1. Add locale-specific patterns in `src/patterns/locale/<lang>/` — each file exports a `PatternRule` with `id`, `entityType`, `pattern`, `locales`, `engines`, and optional `validate`
459
+ 2. Register them in `src/patterns/index.ts` (add to `allPatterns` array)
460
+ 3. Create a thin adapter `src/languages/<lang>/rules.ts` that composes from the new patterns using `toPatternDef`
461
+ 4. Register the adapter in `LANGUAGE_MAP` in `src/core/engine.ts`
462
+ 5. Add the ISO 639-3 → short code mapping in `src/language/language-map.ts`
425
463
 
426
- Each language pack defines an array of `PatternDef` entries with a `tag`, `regex`, and optional `validate` callback. See `src/languages/en/rules.ts` and `src/languages/pl/rules.ts` for examples.
464
+ See `src/patterns/locale/pl/` and `src/languages/pl/rules.ts` for a complete example.
427
465
 
428
466
  ## Contributing
429
467
 
@@ -0,0 +1,15 @@
1
+ import type { DetectedLanguageResult } from './types.js';
2
+ /**
3
+ * Heuristically detect the language of the given text using franc.
4
+ *
5
+ * Returns 'unknown' when:
6
+ * - text is shorter than MIN_TEXT_LENGTH characters
7
+ * - franc returns 'und' (undetermined)
8
+ * - the detected language is not in LANGUAGE_CODE_MAP
9
+ * - confidence is below MIN_CONFIDENCE
10
+ *
11
+ * This is a helper heuristic — it does not affect the pseudonymization pipeline.
12
+ * The --lang config flag remains the authoritative language selector.
13
+ */
14
+ export declare function detectLanguage(text: string): DetectedLanguageResult;
15
+ //# sourceMappingURL=detect-language.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-language.d.ts","sourceRoot":"","sources":["../../src/language/detect-language.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAYxD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,sBAAsB,CA8BnE"}
@@ -0,0 +1,45 @@
1
+ import { francAll } from 'franc';
2
+ import { LANGUAGE_CODE_MAP } from './language-map.js';
3
+ const MIN_TEXT_LENGTH = 20;
4
+ const MIN_CONFIDENCE = 0.5;
5
+ const FALLBACK = {
6
+ detected: 'unknown',
7
+ source: 'fallback',
8
+ raw: null,
9
+ confidence: null,
10
+ };
11
+ /**
12
+ * Heuristically detect the language of the given text using franc.
13
+ *
14
+ * Returns 'unknown' when:
15
+ * - text is shorter than MIN_TEXT_LENGTH characters
16
+ * - franc returns 'und' (undetermined)
17
+ * - the detected language is not in LANGUAGE_CODE_MAP
18
+ * - confidence is below MIN_CONFIDENCE
19
+ *
20
+ * This is a helper heuristic — it does not affect the pseudonymization pipeline.
21
+ * The --lang config flag remains the authoritative language selector.
22
+ */
23
+ export function detectLanguage(text) {
24
+ const trimmed = text.trim();
25
+ if (trimmed.length < MIN_TEXT_LENGTH) {
26
+ return FALLBACK;
27
+ }
28
+ const scores = francAll(trimmed);
29
+ if (!scores.length) {
30
+ return FALLBACK;
31
+ }
32
+ const [rawCode, score] = scores[0];
33
+ if (rawCode === 'und') {
34
+ return FALLBACK;
35
+ }
36
+ const mapped = LANGUAGE_CODE_MAP[rawCode];
37
+ if (!mapped) {
38
+ return { detected: 'unknown', source: 'text', raw: rawCode, confidence: score };
39
+ }
40
+ if (score < MIN_CONFIDENCE) {
41
+ return { detected: 'unknown', source: 'fallback', raw: rawCode, confidence: score };
42
+ }
43
+ return { detected: mapped, source: 'text', raw: rawCode, confidence: score };
44
+ }
45
+ //# sourceMappingURL=detect-language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-language.js","sourceRoot":"","sources":["../../src/language/detect-language.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAGrD,MAAM,eAAe,GAAG,EAAE,CAAA;AAC1B,MAAM,cAAc,GAAG,GAAG,CAAA;AAE1B,MAAM,QAAQ,GAA2B;IACvC,QAAQ,EAAE,SAAS;IACnB,MAAM,EAAE,UAAU;IAClB,GAAG,EAAE,IAAI;IACT,UAAU,EAAE,IAAI;CACjB,CAAA;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAE3B,IAAI,OAAO,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;IAEhC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAqB,CAAA;IAEtD,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;IACjF,CAAC;IAED,IAAI,KAAK,GAAG,cAAc,EAAE,CAAC;QAC3B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;IACrF,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;AAC9E,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { SupportedLang } from './types.js';
2
+ /**
3
+ * Maps ISO 639-3 codes (returned by franc) to supported short language codes.
4
+ * Only languages with a corresponding pattern set in src/patterns/ are listed here.
5
+ */
6
+ export declare const LANGUAGE_CODE_MAP: Record<string, SupportedLang>;
7
+ //# sourceMappingURL=language-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-map.d.ts","sourceRoot":"","sources":["../../src/language/language-map.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAG3D,CAAA"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Maps ISO 639-3 codes (returned by franc) to supported short language codes.
3
+ * Only languages with a corresponding pattern set in src/patterns/ are listed here.
4
+ */
5
+ export const LANGUAGE_CODE_MAP = {
6
+ pol: 'pl',
7
+ eng: 'en',
8
+ };
9
+ //# sourceMappingURL=language-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-map.js","sourceRoot":"","sources":["../../src/language/language-map.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAkC;IAC9D,GAAG,EAAE,IAAI;IACT,GAAG,EAAE,IAAI;CACV,CAAA"}
@@ -0,0 +1,14 @@
1
+ export type SupportedLang = 'pl' | 'en';
2
+ export type DetectedLang = SupportedLang | 'unknown';
3
+ export type DetectionSource = 'text' | 'fallback';
4
+ export interface DetectedLanguageResult {
5
+ /** Detected language mapped to a supported code, or 'unknown' */
6
+ detected: DetectedLang;
7
+ /** 'text' = franc ran and returned a mappable language; 'fallback' = text too short or und */
8
+ source: DetectionSource;
9
+ /** Raw ISO 639-3 code from franc (e.g. 'pol'), or null when franc was not called */
10
+ raw: string | null;
11
+ /** Confidence score 0–1 from franc, or null when franc was not called */
12
+ confidence: number | null;
13
+ }
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/language/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,CAAA;AACvC,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,SAAS,CAAA;AACpD,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,CAAA;AAEjD,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,QAAQ,EAAE,YAAY,CAAA;IACtB,8FAA8F;IAC9F,MAAM,EAAE,eAAe,CAAA;IACvB,oFAAoF;IACpF,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,yEAAyE;IACzE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/language/types.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/languages/en/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAwChD,eAAO,MAAM,YAAY,EAAE,aA0B1B,CAAA"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/languages/en/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAOhD,eAAO,MAAM,YAAY,EAAE,aAE1B,CAAA"}
@@ -1,69 +1,9 @@
1
- /**
2
- * Luhn algorithm for credit card number validation.
3
- * Strips spaces and dashes, verifies the checksum digit.
4
- */
5
- function luhnCheck(number) {
6
- const digits = number.replace(/[\s-]/g, '');
7
- if (!/^\d{13,19}$/.test(digits))
8
- return false;
9
- let sum = 0;
10
- let double = false;
11
- for (let i = digits.length - 1; i >= 0; i--) {
12
- let digit = Number(digits[i]);
13
- if (double) {
14
- digit *= 2;
15
- if (digit > 9)
16
- digit -= 9;
17
- }
18
- sum += digit;
19
- double = !double;
20
- }
21
- return sum % 10 === 0;
22
- }
23
- /**
24
- * Basic SSN area-number validation.
25
- * Rejects known invalid patterns: area 000, 666, 900-999.
26
- */
27
- function ssnValidate(ssn) {
28
- const clean = ssn.replace(/[\s-]/g, '');
29
- if (!/^\d{9}$/.test(clean))
30
- return false;
31
- const area = parseInt(clean.substring(0, 3), 10);
32
- const group = parseInt(clean.substring(3, 5), 10);
33
- const serial = parseInt(clean.substring(5, 9), 10);
34
- if (area === 0 || area === 666 || area >= 900)
35
- return false;
36
- if (group === 0)
37
- return false;
38
- if (serial === 0)
39
- return false;
40
- return true;
41
- }
1
+ import { toPatternDef } from '../../patterns/types.js';
2
+ import { ssnRule } from '../../patterns/locale/en/ssn.js';
3
+ import { creditCardRule } from '../../patterns/locale/en/credit-card.js';
4
+ import { emailRule } from '../../patterns/global/email.js';
5
+ import { usPhoneRule } from '../../patterns/locale/en/phone.js';
42
6
  export const EnglishRules = {
43
- patterns: [
44
- {
45
- tag: 'SSN',
46
- // US Social Security Number: XXX-XX-XXXX (with required dashes to avoid false positives)
47
- regex: /\b\d{3}-\d{2}-\d{4}\b/g,
48
- validate: ssnValidate,
49
- },
50
- {
51
- tag: 'CREDIT_CARD',
52
- // 13–19 digits, optionally separated by spaces or dashes in groups of 4
53
- // Covers Visa (4xxx), Mastercard (5[1-5]xx, 2[2-7]xx), Amex (3[47]x), Discover (6xxx)
54
- regex: /\b(?:\d[ -]*?){13,19}\b/g,
55
- validate: luhnCheck,
56
- },
57
- {
58
- tag: 'EMAIL',
59
- regex: /\b[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}\b/g,
60
- },
61
- {
62
- tag: 'PHONE',
63
- // US/international phone formats:
64
- // +1 (XXX) XXX-XXXX, +1-XXX-XXX-XXXX, (XXX) XXX-XXXX, XXX-XXX-XXXX, XXX.XXX.XXXX
65
- regex: /(?:\+1[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b/g,
66
- },
67
- ],
7
+ patterns: [ssnRule, creditCardRule, emailRule, usPhoneRule].map(toPatternDef),
68
8
  };
69
9
  //# sourceMappingURL=rules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/languages/en/rules.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,SAAS,SAAS,CAAC,MAAc;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAC3C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAE7C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,IAAI,CAAC,CAAA;YACV,IAAI,KAAK,GAAG,CAAC;gBAAE,KAAK,IAAI,CAAC,CAAA;QAC3B,CAAC;QACD,GAAG,IAAI,KAAK,CAAA;QACZ,MAAM,GAAG,CAAC,MAAM,CAAA;IAClB,CAAC;IACD,OAAO,GAAG,GAAG,EAAE,KAAK,CAAC,CAAA;AACvB,CAAC;AAED;;;GAGG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IACvC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAClD,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG;QAAE,OAAO,KAAK,CAAA;IAC3D,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC7B,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9B,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,QAAQ,EAAE;QACR;YACE,GAAG,EAAE,KAAK;YACV,yFAAyF;YACzF,KAAK,EAAE,wBAAwB;YAC/B,QAAQ,EAAE,WAAW;SACtB;QACD;YACE,GAAG,EAAE,aAAa;YAClB,wEAAwE;YACxE,sFAAsF;YACtF,KAAK,EAAE,0BAA0B;YACjC,QAAQ,EAAE,SAAS;SACpB;QACD;YACE,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,uDAAuD;SAC/D;QACD;YACE,GAAG,EAAE,OAAO;YACZ,kCAAkC;YAClC,iFAAiF;YACjF,KAAK,EAAE,qDAAqD;SAC7D;KACF;CACF,CAAA"}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/languages/en/rules.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,MAAM,CAAC,MAAM,YAAY,GAAkB;IACzC,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;CAC9E,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/languages/pl/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAgBhD,eAAO,MAAM,WAAW,EAAE,aA6BzB,CAAA"}
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/languages/pl/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAOhD,eAAO,MAAM,WAAW,EAAE,aAEzB,CAAA"}
@@ -1,44 +1,9 @@
1
- /**
2
- * Validates a Polish PESEL number using the official checksum algorithm.
3
- * Weights: [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]
4
- * Check digit = (10 - (weighted_sum % 10)) % 10
5
- */
6
- function peselChecksum(pesel) {
7
- if (!/^\d{11}$/.test(pesel))
8
- return false;
9
- const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
10
- const digits = pesel.split('').map(Number);
11
- const sum = weights.reduce((acc, w, i) => acc + w * digits[i], 0);
12
- const check = (10 - (sum % 10)) % 10;
13
- return check === digits[10];
14
- }
1
+ import { toPatternDef } from '../../patterns/types.js';
2
+ import { peselRule } from '../../patterns/locale/pl/pesel.js';
3
+ import { plIbanRule } from '../../patterns/locale/pl/iban.js';
4
+ import { plPhoneRule } from '../../patterns/locale/pl/phone.js';
5
+ import { emailRule } from '../../patterns/global/email.js';
15
6
  export const PolishRules = {
16
- patterns: [
17
- {
18
- tag: 'PESEL',
19
- // Matches exactly 11 consecutive digits NOT adjacent to another digit
20
- regex: /(?<!\d)\d{11}(?!\d)/g,
21
- validate: peselChecksum,
22
- },
23
- {
24
- tag: 'IBAN',
25
- // Matches PL + 26 digits (2 check + 24 BBAN), optionally space-separated every 4 chars
26
- // e.g. PL27114020040000300201355387 or PL 27 1140 2004 0000 3002 0135 5387
27
- // Structure: PL + \d{2} (check) + (\d{4}){6} (24 BBAN) = 26 total digits
28
- regex: /\bPL\s*\d{2}\s*(?:\d{4}\s*){6}\b/gi,
29
- },
30
- {
31
- tag: 'EMAIL',
32
- regex: /\b[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}\b/g,
33
- },
34
- {
35
- tag: 'PHONE',
36
- // Three alternatives:
37
- // 1. International prefix: +48 or 0048, then 9 digits (with optional spaces/dashes)
38
- // 2. 9-digit mobile starting with 4–8 (Polish numbering plan)
39
- // 3. Landline with area code in parens: (XX) XXX-XX-XX
40
- regex: /(?:\+48|0048)[\s\-]?\d{3}[\s\-]?\d{3}[\s\-]?\d{3}|\b[4-8]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b|\(\d{2}\)[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}/g,
41
- },
42
- ],
7
+ patterns: [peselRule, plIbanRule, emailRule, plPhoneRule].map(toPatternDef),
43
8
  };
44
9
  //# sourceMappingURL=rules.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/languages/pl/rules.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACjE,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAA;IACpC,OAAO,KAAK,KAAK,MAAM,CAAC,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,QAAQ,EAAE;QACR;YACE,GAAG,EAAE,OAAO;YACZ,sEAAsE;YACtE,KAAK,EAAE,sBAAsB;YAC7B,QAAQ,EAAE,aAAa;SACxB;QACD;YACE,GAAG,EAAE,MAAM;YACX,uFAAuF;YACvF,2EAA2E;YAC3E,yEAAyE;YACzE,KAAK,EAAE,oCAAoC;SAC5C;QACD;YACE,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,uDAAuD;SAC/D;QACD;YACE,GAAG,EAAE,OAAO;YACZ,sBAAsB;YACtB,oFAAoF;YACpF,8DAA8D;YAC9D,uDAAuD;YACvD,KAAK,EACH,yIAAyI;SAC5I;KACF;CACF,CAAA"}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/languages/pl/rules.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAA;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAA;AAE1D,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;CAC5E,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { PatternRule } from '../types.js';
2
+ /** Patterns active in balanced mode — low false-positive rules with good coverage */
3
+ export declare const balancedPatterns: PatternRule[];
4
+ //# sourceMappingURL=balanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balanced.d.ts","sourceRoot":"","sources":["../../../src/patterns/engines/balanced.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,qFAAqF;AACrF,eAAO,MAAM,gBAAgB,EAAE,WAAW,EAEzC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { allPatterns } from '../index.js';
2
+ /** Patterns active in balanced mode — low false-positive rules with good coverage */
3
+ export const balancedPatterns = allPatterns.filter((p) => p.engines.includes('balanced'));
4
+ //# sourceMappingURL=balanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balanced.js","sourceRoot":"","sources":["../../../src/patterns/engines/balanced.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,qFAAqF;AACrF,MAAM,CAAC,MAAM,gBAAgB,GAAkB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACtE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAC/B,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { PatternRule } from '../types.js';
2
+ /** All patterns — maximum coverage, higher false-positive risk */
3
+ export declare const paranoidPatterns: PatternRule[];
4
+ //# sourceMappingURL=paranoid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paranoid.d.ts","sourceRoot":"","sources":["../../../src/patterns/engines/paranoid.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,WAAW,EAEzC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { allPatterns } from '../index.js';
2
+ /** All patterns — maximum coverage, higher false-positive risk */
3
+ export const paranoidPatterns = allPatterns.filter((p) => p.engines.includes('paranoid'));
4
+ //# sourceMappingURL=paranoid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paranoid.js","sourceRoot":"","sources":["../../../src/patterns/engines/paranoid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,kEAAkE;AAClE,MAAM,CAAC,MAAM,gBAAgB,GAAkB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACtE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAC/B,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { PatternRule } from '../types.js';
2
+ /** Patterns active in strict mode — balanced rules plus checksum-validated identifiers */
3
+ export declare const strictPatterns: PatternRule[];
4
+ //# sourceMappingURL=strict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict.d.ts","sourceRoot":"","sources":["../../../src/patterns/engines/strict.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,0FAA0F;AAC1F,eAAO,MAAM,cAAc,EAAE,WAAW,EAA4D,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { allPatterns } from '../index.js';
2
+ /** Patterns active in strict mode — balanced rules plus checksum-validated identifiers */
3
+ export const strictPatterns = allPatterns.filter((p) => p.engines.includes('strict'));
4
+ //# sourceMappingURL=strict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strict.js","sourceRoot":"","sources":["../../../src/patterns/engines/strict.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAGzC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,cAAc,GAAkB,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../types.js';
2
+ export declare const emailRule: PatternRule;
3
+ //# sourceMappingURL=email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../../src/patterns/global/email.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,SAAS,EAAE,WAOvB,CAAA"}
@@ -0,0 +1,9 @@
1
+ export const emailRule = {
2
+ id: 'global.email',
3
+ entityType: 'EMAIL',
4
+ pattern: /\b[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}\b/g,
5
+ locales: null,
6
+ engines: ['balanced', 'strict', 'paranoid'],
7
+ description: 'Standard email address (RFC 5321-compatible)',
8
+ };
9
+ //# sourceMappingURL=email.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"email.js","sourceRoot":"","sources":["../../../src/patterns/global/email.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAgB;IACpC,EAAE,EAAE,cAAc;IAClB,UAAU,EAAE,OAAO;IACnB,OAAO,EAAE,uDAAuD;IAChE,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,8CAA8C;CAC5D,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../types.js';
2
+ export declare const globalIbanRule: PatternRule;
3
+ //# sourceMappingURL=iban.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iban.d.ts","sourceRoot":"","sources":["../../../src/patterns/global/iban.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,cAAc,EAAE,WAS5B,CAAA"}
@@ -0,0 +1,11 @@
1
+ export const globalIbanRule = {
2
+ id: 'global.iban',
3
+ entityType: 'IBAN',
4
+ // Generic IBAN: 2-letter country code + 2 check digits + up to 30 alphanumeric chars
5
+ // Covers all IBAN countries (max length 34 chars)
6
+ pattern: /\b[A-Z]{2}\d{2}[A-Z0-9]{1,30}\b/g,
7
+ locales: null,
8
+ engines: ['strict', 'paranoid'],
9
+ description: 'Generic IBAN (any country, compact format)',
10
+ };
11
+ //# sourceMappingURL=iban.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iban.js","sourceRoot":"","sources":["../../../src/patterns/global/iban.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,EAAE,EAAE,aAAa;IACjB,UAAU,EAAE,MAAM;IAClB,qFAAqF;IACrF,kDAAkD;IAClD,OAAO,EAAE,kCAAkC;IAC3C,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC/B,WAAW,EAAE,4CAA4C;CAC1D,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { PatternRule } from '../types.js';
2
+ export declare const ipv4Rule: PatternRule;
3
+ export declare const ipv6Rule: PatternRule;
4
+ //# sourceMappingURL=ip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip.d.ts","sourceRoot":"","sources":["../../../src/patterns/global/ip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,QAAQ,EAAE,WAStB,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,WAStB,CAAA"}
@@ -0,0 +1,20 @@
1
+ export const ipv4Rule = {
2
+ id: 'global.ipv4',
3
+ entityType: 'IP',
4
+ // IPv4: four octets 0–255 separated by dots, not adjacent to other digits/dots
5
+ pattern: /\b(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\b/g,
6
+ locales: null,
7
+ engines: ['strict', 'paranoid'],
8
+ description: 'IPv4 address (0.0.0.0 – 255.255.255.255)',
9
+ };
10
+ export const ipv6Rule = {
11
+ id: 'global.ipv6',
12
+ entityType: 'IP',
13
+ // Full or compressed IPv6: groups of 1–4 hex digits separated by colons
14
+ // Handles :: abbreviation and mixed IPv4-in-IPv6 forms at a basic level
15
+ pattern: /\b(?:[0-9a-fA-F]{1,4}:){2,7}[0-9a-fA-F]{1,4}\b/g,
16
+ locales: null,
17
+ engines: ['paranoid'],
18
+ description: 'IPv6 address (basic hex-colon format)',
19
+ };
20
+ //# sourceMappingURL=ip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ip.js","sourceRoot":"","sources":["../../../src/patterns/global/ip.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,EAAE,EAAE,aAAa;IACjB,UAAU,EAAE,IAAI;IAChB,+EAA+E;IAC/E,OAAO,EACL,4FAA4F;IAC9F,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC/B,WAAW,EAAE,0CAA0C;CACxD,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAgB;IACnC,EAAE,EAAE,aAAa;IACjB,UAAU,EAAE,IAAI;IAChB,wEAAwE;IACxE,wEAAwE;IACxE,OAAO,EAAE,iDAAiD;IAC1D,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,WAAW,EAAE,uCAAuC;CACrD,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../types.js';
2
+ export declare const globalPhoneRule: PatternRule;
3
+ //# sourceMappingURL=phone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../../../src/patterns/global/phone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,eAAe,EAAE,WAS7B,CAAA"}
@@ -0,0 +1,11 @@
1
+ export const globalPhoneRule = {
2
+ id: 'global.phone',
3
+ entityType: 'PHONE',
4
+ // Generic international format: +CC followed by digits/spaces/dashes
5
+ // e.g. +1-800-555-1234, +44 20 7946 0958, +33 1 23 45 67 89
6
+ pattern: /\+\d{1,3}[\s.\-]?\(?\d{1,4}\)?(?:[\s.\-]?\d{1,4}){2,4}\b/g,
7
+ locales: null,
8
+ engines: ['strict', 'paranoid'],
9
+ description: 'Generic international phone number with country code prefix',
10
+ };
11
+ //# sourceMappingURL=phone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.js","sourceRoot":"","sources":["../../../src/patterns/global/phone.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAgB;IAC1C,EAAE,EAAE,cAAc;IAClB,UAAU,EAAE,OAAO;IACnB,qEAAqE;IACrE,4DAA4D;IAC5D,OAAO,EAAE,2DAA2D;IACpE,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC/B,WAAW,EAAE,6DAA6D;CAC3E,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../types.js';
2
+ export declare const urlRule: PatternRule;
3
+ //# sourceMappingURL=url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../../src/patterns/global/url.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,eAAO,MAAM,OAAO,EAAE,WAQrB,CAAA"}
@@ -0,0 +1,10 @@
1
+ export const urlRule = {
2
+ id: 'global.url',
3
+ entityType: 'URL',
4
+ // http/https URLs — stops at whitespace and common delimiter characters
5
+ pattern: /https?:\/\/[^\s<>"{}\\|^[\]]+/g,
6
+ locales: null,
7
+ engines: ['paranoid'],
8
+ description: 'HTTP/HTTPS URL',
9
+ };
10
+ //# sourceMappingURL=url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url.js","sourceRoot":"","sources":["../../../src/patterns/global/url.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,EAAE,EAAE,YAAY;IAChB,UAAU,EAAE,KAAK;IACjB,wEAAwE;IACxE,OAAO,EAAE,gCAAgC;IACzC,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,WAAW,EAAE,gBAAgB;CAC9B,CAAA"}
@@ -0,0 +1,18 @@
1
+ import type { PatternRule } from './types.js';
2
+ export * from './types.js';
3
+ export * from './global/email.js';
4
+ export * from './global/phone.js';
5
+ export * from './global/iban.js';
6
+ export * from './global/ip.js';
7
+ export * from './global/url.js';
8
+ export * from './locale/pl/pesel.js';
9
+ export * from './locale/pl/iban.js';
10
+ export * from './locale/pl/phone.js';
11
+ export * from './locale/pl/nip.js';
12
+ export * from './locale/pl/postal-code.js';
13
+ export * from './locale/en/ssn.js';
14
+ export * from './locale/en/credit-card.js';
15
+ export * from './locale/en/phone.js';
16
+ export * from './locale/en/zip-code.js';
17
+ export declare const allPatterns: PatternRule[];
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C,cAAc,YAAY,CAAA;AAE1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AAEvC,eAAO,MAAM,WAAW,EAAE,WAAW,EAmBpC,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { emailRule } from './global/email.js';
2
+ import { globalPhoneRule } from './global/phone.js';
3
+ import { globalIbanRule } from './global/iban.js';
4
+ import { ipv4Rule, ipv6Rule } from './global/ip.js';
5
+ import { urlRule } from './global/url.js';
6
+ import { peselRule } from './locale/pl/pesel.js';
7
+ import { plIbanRule } from './locale/pl/iban.js';
8
+ import { plPhoneRule } from './locale/pl/phone.js';
9
+ import { nipRule } from './locale/pl/nip.js';
10
+ import { plPostalCodeRule } from './locale/pl/postal-code.js';
11
+ import { ssnRule } from './locale/en/ssn.js';
12
+ import { creditCardRule } from './locale/en/credit-card.js';
13
+ import { usPhoneRule } from './locale/en/phone.js';
14
+ import { usZipCodeRule } from './locale/en/zip-code.js';
15
+ export * from './types.js';
16
+ export * from './global/email.js';
17
+ export * from './global/phone.js';
18
+ export * from './global/iban.js';
19
+ export * from './global/ip.js';
20
+ export * from './global/url.js';
21
+ export * from './locale/pl/pesel.js';
22
+ export * from './locale/pl/iban.js';
23
+ export * from './locale/pl/phone.js';
24
+ export * from './locale/pl/nip.js';
25
+ export * from './locale/pl/postal-code.js';
26
+ export * from './locale/en/ssn.js';
27
+ export * from './locale/en/credit-card.js';
28
+ export * from './locale/en/phone.js';
29
+ export * from './locale/en/zip-code.js';
30
+ export const allPatterns = [
31
+ // Global
32
+ emailRule,
33
+ globalPhoneRule,
34
+ globalIbanRule,
35
+ ipv4Rule,
36
+ ipv6Rule,
37
+ urlRule,
38
+ // Polish locale
39
+ peselRule,
40
+ plIbanRule,
41
+ plPhoneRule,
42
+ nipRule,
43
+ plPostalCodeRule,
44
+ // English locale
45
+ ssnRule,
46
+ creditCardRule,
47
+ usPhoneRule,
48
+ usZipCodeRule,
49
+ ];
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAGvD,cAAc,YAAY,CAAA;AAE1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AAEvC,MAAM,CAAC,MAAM,WAAW,GAAkB;IACxC,SAAS;IACT,SAAS;IACT,eAAe;IACf,cAAc;IACd,QAAQ;IACR,QAAQ;IACR,OAAO;IACP,gBAAgB;IAChB,SAAS;IACT,UAAU;IACV,WAAW;IACX,OAAO;IACP,gBAAgB;IAChB,iBAAiB;IACjB,OAAO;IACP,cAAc;IACd,WAAW;IACX,aAAa;CACd,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const creditCardRule: PatternRule;
3
+ //# sourceMappingURL=credit-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credit-card.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/en/credit-card.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAwBjD,eAAO,MAAM,cAAc,EAAE,WAW5B,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Luhn algorithm for credit card number validation.
3
+ * Strips spaces and dashes, verifies the checksum digit.
4
+ */
5
+ function luhnCheck(number) {
6
+ const digits = number.replace(/[\s\-]/g, '');
7
+ if (!/^\d{13,19}$/.test(digits))
8
+ return false;
9
+ let sum = 0;
10
+ let double = false;
11
+ for (let i = digits.length - 1; i >= 0; i--) {
12
+ let digit = Number(digits[i]);
13
+ if (double) {
14
+ digit *= 2;
15
+ if (digit > 9)
16
+ digit -= 9;
17
+ }
18
+ sum += digit;
19
+ double = !double;
20
+ }
21
+ return sum % 10 === 0;
22
+ }
23
+ export const creditCardRule = {
24
+ id: 'en.credit-card',
25
+ entityType: 'CREDIT_CARD',
26
+ // 13–19 digits, optionally separated by spaces or dashes in groups of 4
27
+ // Covers Visa (4xxx), Mastercard (5[1-5]xx / 2[2-7]xx), Amex (3[47]x), Discover (6xxx)
28
+ pattern: /\b(?:\d[ \-]*?){13,19}\b/g,
29
+ locales: ['en'],
30
+ engines: ['balanced', 'strict', 'paranoid'],
31
+ description: 'Credit card number (13–19 digits, Luhn checksum) — Visa, Mastercard, Amex, Discover',
32
+ validate: luhnCheck,
33
+ };
34
+ //# sourceMappingURL=credit-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credit-card.js","sourceRoot":"","sources":["../../../../src/patterns/locale/en/credit-card.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,SAAS,SAAS,CAAC,MAAc;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAC5C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAE7C,IAAI,GAAG,GAAG,CAAC,CAAA;IACX,IAAI,MAAM,GAAG,KAAK,CAAA;IAClB,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,IAAI,CAAC,CAAA;YACV,IAAI,KAAK,GAAG,CAAC;gBAAE,KAAK,IAAI,CAAC,CAAA;QAC3B,CAAC;QACD,GAAG,IAAI,KAAK,CAAA;QACZ,MAAM,GAAG,CAAC,MAAM,CAAA;IAClB,CAAC;IACD,OAAO,GAAG,GAAG,EAAE,KAAK,CAAC,CAAA;AACvB,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,EAAE,EAAE,gBAAgB;IACpB,UAAU,EAAE,aAAa;IACzB,wEAAwE;IACxE,uFAAuF;IACvF,OAAO,EAAE,2BAA2B;IACpC,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EACT,qFAAqF;IACvF,QAAQ,EAAE,SAAS;CACpB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const usPhoneRule: PatternRule;
3
+ //# sourceMappingURL=phone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/en/phone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,eAAO,MAAM,WAAW,EAAE,WASzB,CAAA"}
@@ -0,0 +1,11 @@
1
+ export const usPhoneRule = {
2
+ id: 'en.phone',
3
+ entityType: 'PHONE',
4
+ // US/North America phone formats:
5
+ // +1 (XXX) XXX-XXXX, +1-XXX-XXX-XXXX, (XXX) XXX-XXXX, XXX-XXX-XXXX, XXX.XXX.XXXX
6
+ pattern: /(?:\+1[\s.\-]?)?\(?\d{3}\)?[\s.\-]\d{3}[\s.\-]\d{4}\b/g,
7
+ locales: ['en'],
8
+ engines: ['balanced', 'strict', 'paranoid'],
9
+ description: 'US/North America phone number in common formats',
10
+ };
11
+ //# sourceMappingURL=phone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.js","sourceRoot":"","sources":["../../../../src/patterns/locale/en/phone.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,EAAE,EAAE,UAAU;IACd,UAAU,EAAE,OAAO;IACnB,kCAAkC;IAClC,iFAAiF;IACjF,OAAO,EAAE,wDAAwD;IACjE,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,iDAAiD;CAC/D,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const ssnRule: PatternRule;
3
+ //# sourceMappingURL=ssn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssn.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/en/ssn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAkBjD,eAAO,MAAM,OAAO,EAAE,WASrB,CAAA"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Basic SSN area-number validation.
3
+ * Rejects known invalid patterns: area 000, 666, 900-999.
4
+ */
5
+ function ssnValidate(ssn) {
6
+ const clean = ssn.replace(/[\s\-]/g, '');
7
+ if (!/^\d{9}$/.test(clean))
8
+ return false;
9
+ const area = parseInt(clean.substring(0, 3), 10);
10
+ const group = parseInt(clean.substring(3, 5), 10);
11
+ const serial = parseInt(clean.substring(5, 9), 10);
12
+ if (area === 0 || area === 666 || area >= 900)
13
+ return false;
14
+ if (group === 0)
15
+ return false;
16
+ if (serial === 0)
17
+ return false;
18
+ return true;
19
+ }
20
+ export const ssnRule = {
21
+ id: 'en.ssn',
22
+ entityType: 'SSN',
23
+ // US Social Security Number: XXX-XX-XXXX (required dashes to avoid false positives)
24
+ pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
25
+ locales: ['en'],
26
+ engines: ['balanced', 'strict', 'paranoid'],
27
+ description: 'US Social Security Number (XXX-XX-XXXX) with area-number validation',
28
+ validate: ssnValidate,
29
+ };
30
+ //# sourceMappingURL=ssn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssn.js","sourceRoot":"","sources":["../../../../src/patterns/locale/en/ssn.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACxC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAClD,IAAI,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG;QAAE,OAAO,KAAK,CAAA;IAC3D,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC7B,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9B,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,EAAE,EAAE,QAAQ;IACZ,UAAU,EAAE,KAAK;IACjB,oFAAoF;IACpF,OAAO,EAAE,wBAAwB;IACjC,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,qEAAqE;IAClF,QAAQ,EAAE,WAAW;CACtB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const usZipCodeRule: PatternRule;
3
+ //# sourceMappingURL=zip-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-code.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/en/zip-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,eAAO,MAAM,aAAa,EAAE,WAQ3B,CAAA"}
@@ -0,0 +1,10 @@
1
+ export const usZipCodeRule = {
2
+ id: 'en.zip-code',
3
+ entityType: 'ZIP_CODE',
4
+ // US ZIP code: 5 digits, or ZIP+4 (XXXXX-XXXX)
5
+ pattern: /\b\d{5}(?:-\d{4})?\b/g,
6
+ locales: ['en'],
7
+ engines: ['paranoid'],
8
+ description: 'US ZIP code (XXXXX or XXXXX-XXXX)',
9
+ };
10
+ //# sourceMappingURL=zip-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip-code.js","sourceRoot":"","sources":["../../../../src/patterns/locale/en/zip-code.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAgB;IACxC,EAAE,EAAE,aAAa;IACjB,UAAU,EAAE,UAAU;IACtB,+CAA+C;IAC/C,OAAO,EAAE,uBAAuB;IAChC,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,WAAW,EAAE,mCAAmC;CACjD,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const plIbanRule: PatternRule;
3
+ //# sourceMappingURL=iban.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iban.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/iban.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,eAAO,MAAM,UAAU,EAAE,WASxB,CAAA"}
@@ -0,0 +1,11 @@
1
+ export const plIbanRule = {
2
+ id: 'pl.iban',
3
+ entityType: 'IBAN',
4
+ // PL + 2 check digits + 24 BBAN digits, optionally space-separated every 4 chars
5
+ // e.g. PL27114020040000300201355387 or PL 27 1140 2004 0000 3002 0135 5387
6
+ pattern: /\bPL\s*\d{2}\s*(?:\d{4}\s*){6}\b/gi,
7
+ locales: ['pl'],
8
+ engines: ['balanced', 'strict', 'paranoid'],
9
+ description: 'Polish IBAN (PL prefix + 26 digits, compact or spaced)',
10
+ };
11
+ //# sourceMappingURL=iban.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iban.js","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/iban.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAgB;IACrC,EAAE,EAAE,SAAS;IACb,UAAU,EAAE,MAAM;IAClB,iFAAiF;IACjF,2EAA2E;IAC3E,OAAO,EAAE,oCAAoC;IAC7C,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,wDAAwD;CACtE,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const nipRule: PatternRule;
3
+ //# sourceMappingURL=nip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nip.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/nip.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAiBjD,eAAO,MAAM,OAAO,EAAE,WASrB,CAAA"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Validates a Polish NIP (Numer Identyfikacji Podatkowej — Tax ID).
3
+ * 10 digits, weights: [6, 5, 7, 2, 3, 4, 5, 6, 7]
4
+ * Check digit = weighted_sum % 11; valid if result equals last digit (and != 10)
5
+ */
6
+ function nipChecksum(raw) {
7
+ const digits = raw.replace(/[\s\-]/g, '');
8
+ if (!/^\d{10}$/.test(digits))
9
+ return false;
10
+ const weights = [6, 5, 7, 2, 3, 4, 5, 6, 7];
11
+ const d = digits.split('').map(Number);
12
+ const sum = weights.reduce((acc, w, i) => acc + w * d[i], 0);
13
+ const check = sum % 11;
14
+ return check !== 10 && check === d[9];
15
+ }
16
+ export const nipRule = {
17
+ id: 'pl.nip',
18
+ entityType: 'NIP',
19
+ // 10 digits, optionally separated by spaces or dashes in groups: XXX-XXX-XX-XX or XXX-XX-XX-XXX
20
+ pattern: /\b\d{3}[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}\b/g,
21
+ locales: ['pl'],
22
+ engines: ['strict', 'paranoid'],
23
+ description: 'Polish tax identification number (NIP) — 10 digits with checksum',
24
+ validate: nipChecksum,
25
+ };
26
+ //# sourceMappingURL=nip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nip.js","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/nip.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACzC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1C,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3C,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACtC,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC5D,MAAM,KAAK,GAAG,GAAG,GAAG,EAAE,CAAA;IACtB,OAAO,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAgB;IAClC,EAAE,EAAE,QAAQ;IACZ,UAAU,EAAE,KAAK;IACjB,gGAAgG;IAChG,OAAO,EAAE,gDAAgD;IACzD,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC/B,WAAW,EAAE,kEAAkE;IAC/E,QAAQ,EAAE,WAAW;CACtB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const peselRule: PatternRule;
3
+ //# sourceMappingURL=pesel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pesel.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/pesel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAgBjD,eAAO,MAAM,SAAS,EAAE,WASvB,CAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Validates a Polish PESEL number using the official checksum algorithm.
3
+ * Weights: [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]
4
+ * Check digit = (10 - (weighted_sum % 10)) % 10
5
+ */
6
+ function peselChecksum(pesel) {
7
+ if (!/^\d{11}$/.test(pesel))
8
+ return false;
9
+ const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
10
+ const digits = pesel.split('').map(Number);
11
+ const sum = weights.reduce((acc, w, i) => acc + w * digits[i], 0);
12
+ const check = (10 - (sum % 10)) % 10;
13
+ return check === digits[10];
14
+ }
15
+ export const peselRule = {
16
+ id: 'pl.pesel',
17
+ entityType: 'PESEL',
18
+ // Exactly 11 consecutive digits NOT adjacent to another digit
19
+ pattern: /(?<!\d)\d{11}(?!\d)/g,
20
+ locales: ['pl'],
21
+ engines: ['balanced', 'strict', 'paranoid'],
22
+ description: 'Polish national identification number (PESEL) — 11 digits with checksum',
23
+ validate: peselChecksum,
24
+ };
25
+ //# sourceMappingURL=pesel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pesel.js","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/pesel.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACjE,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAA;IACpC,OAAO,KAAK,KAAK,MAAM,CAAC,EAAE,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAgB;IACpC,EAAE,EAAE,UAAU;IACd,UAAU,EAAE,OAAO;IACnB,8DAA8D;IAC9D,OAAO,EAAE,sBAAsB;IAC/B,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,yEAAyE;IACtF,QAAQ,EAAE,aAAa;CACxB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const plPhoneRule: PatternRule;
3
+ //# sourceMappingURL=phone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/phone.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,eAAO,MAAM,WAAW,EAAE,WAYzB,CAAA"}
@@ -0,0 +1,13 @@
1
+ export const plPhoneRule = {
2
+ id: 'pl.phone',
3
+ entityType: 'PHONE',
4
+ // Three alternatives:
5
+ // 1. International prefix: +48 or 0048, then 9 digits (with optional spaces/dashes)
6
+ // 2. 9-digit mobile starting with 4–8 (Polish numbering plan)
7
+ // 3. Landline with area code in parens: (XX) XXX-XX-XX
8
+ pattern: /(?:\+48|0048)[\s\-]?\d{3}[\s\-]?\d{3}[\s\-]?\d{3}|\b[4-8]\d{2}[\s\-]?\d{3}[\s\-]?\d{3}\b|\(\d{2}\)[\s\-]?\d{3}[\s\-]?\d{2}[\s\-]?\d{2}/g,
9
+ locales: ['pl'],
10
+ engines: ['balanced', 'strict', 'paranoid'],
11
+ description: 'Polish phone number (+48 / 0048 prefix, 9-digit mobile, landline)',
12
+ };
13
+ //# sourceMappingURL=phone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.js","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/phone.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAgB;IACtC,EAAE,EAAE,UAAU;IACd,UAAU,EAAE,OAAO;IACnB,sBAAsB;IACtB,oFAAoF;IACpF,8DAA8D;IAC9D,uDAAuD;IACvD,OAAO,EACL,yIAAyI;IAC3I,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC;IAC3C,WAAW,EAAE,mEAAmE;CACjF,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { PatternRule } from '../../types.js';
2
+ export declare const plPostalCodeRule: PatternRule;
3
+ //# sourceMappingURL=postal-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postal-code.d.ts","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/postal-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAEjD,eAAO,MAAM,gBAAgB,EAAE,WAQ9B,CAAA"}
@@ -0,0 +1,10 @@
1
+ export const plPostalCodeRule = {
2
+ id: 'pl.postal-code',
3
+ entityType: 'POSTAL_CODE',
4
+ // Polish postal code: XX-XXX (e.g. 00-001, 80-952)
5
+ pattern: /\b\d{2}-\d{3}\b/g,
6
+ locales: ['pl'],
7
+ engines: ['paranoid'],
8
+ description: 'Polish postal code (XX-XXX format)',
9
+ };
10
+ //# sourceMappingURL=postal-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postal-code.js","sourceRoot":"","sources":["../../../../src/patterns/locale/pl/postal-code.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAgB;IAC3C,EAAE,EAAE,gBAAgB;IACpB,UAAU,EAAE,aAAa;IACzB,mDAAmD;IACnD,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,WAAW,EAAE,oCAAoC;CAClD,CAAA"}
@@ -0,0 +1,21 @@
1
+ import type { PatternDef } from '../languages/types.js';
2
+ export type EngineLevel = 'balanced' | 'strict' | 'paranoid';
3
+ export type SupportedLocale = 'pl' | 'en';
4
+ export interface PatternRule {
5
+ /** Unique identifier, e.g. 'global.email' or 'pl.pesel' */
6
+ id: string;
7
+ /** Token tag used in replacement, e.g. 'EMAIL', 'PESEL' */
8
+ entityType: string;
9
+ /** Regex with 'g' flag */
10
+ pattern: RegExp;
11
+ /** null = applies to all locales (global); otherwise locale-specific */
12
+ locales: SupportedLocale[] | null;
13
+ /** Which engine levels activate this rule */
14
+ engines: EngineLevel[];
15
+ description: string;
16
+ /** Optional post-match validator. Receives the match with whitespace stripped. */
17
+ validate?: (match: string) => boolean;
18
+ }
19
+ /** Adapter: converts a PatternRule to the PatternDef format used by Engine */
20
+ export declare function toPatternDef(rule: PatternRule): PatternDef;
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/patterns/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAEvD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAA;AAC5D,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,CAAA;AAEzC,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAA;IACV,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAA;IAClB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,wEAAwE;IACxE,OAAO,EAAE,eAAe,EAAE,GAAG,IAAI,CAAA;IACjC,6CAA6C;IAC7C,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAA;CACtC;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CAM1D"}
@@ -0,0 +1,9 @@
1
+ /** Adapter: converts a PatternRule to the PatternDef format used by Engine */
2
+ export function toPatternDef(rule) {
3
+ return {
4
+ tag: rule.entityType,
5
+ regex: rule.pattern,
6
+ validate: rule.validate,
7
+ };
8
+ }
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/patterns/types.ts"],"names":[],"mappings":"AAqBA,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,IAAiB;IAC5C,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,UAAU;QACpB,KAAK,EAAE,IAAI,CAAC,OAAO;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pseudonym-mcp",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "mcpName": "io.github.woladi/pseudonym-mcp",
5
5
  "description": "MCP server for privacy-preserving pseudonymization of sensitive data before cloud LLM processing",
6
6
  "type": "module",
@@ -84,6 +84,7 @@
84
84
  "dependencies": {
85
85
  "@modelcontextprotocol/sdk": "^1.29.0",
86
86
  "commander": "^14.0.0",
87
+ "franc": "^6.2.0",
87
88
  "zod": "^3.25.0"
88
89
  },
89
90
  "devDependencies": {