nz-privacy-auditor 0.8.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 (67) hide show
  1. package/README.md +152 -0
  2. package/data/llm_cache/cache.json +1 -0
  3. package/dist/cli.d.ts +16 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +233 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/detectors/address.d.ts +48 -0
  8. package/dist/detectors/address.d.ts.map +1 -0
  9. package/dist/detectors/address.js +262 -0
  10. package/dist/detectors/address.js.map +1 -0
  11. package/dist/detectors/base.d.ts +43 -0
  12. package/dist/detectors/base.d.ts.map +1 -0
  13. package/dist/detectors/base.js +6 -0
  14. package/dist/detectors/base.js.map +1 -0
  15. package/dist/detectors/driver_licence.d.ts +38 -0
  16. package/dist/detectors/driver_licence.d.ts.map +1 -0
  17. package/dist/detectors/driver_licence.js +80 -0
  18. package/dist/detectors/driver_licence.js.map +1 -0
  19. package/dist/detectors/ird.d.ts +37 -0
  20. package/dist/detectors/ird.d.ts.map +1 -0
  21. package/dist/detectors/ird.js +103 -0
  22. package/dist/detectors/ird.js.map +1 -0
  23. package/dist/detectors/maori_name.d.ts +36 -0
  24. package/dist/detectors/maori_name.d.ts.map +1 -0
  25. package/dist/detectors/maori_name.js +251 -0
  26. package/dist/detectors/maori_name.js.map +1 -0
  27. package/dist/detectors/nhi.d.ts +44 -0
  28. package/dist/detectors/nhi.d.ts.map +1 -0
  29. package/dist/detectors/nhi.js +147 -0
  30. package/dist/detectors/nhi.js.map +1 -0
  31. package/dist/detectors/phone.d.ts +49 -0
  32. package/dist/detectors/phone.d.ts.map +1 -0
  33. package/dist/detectors/phone.js +126 -0
  34. package/dist/detectors/phone.js.map +1 -0
  35. package/dist/index.d.ts +25 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +52 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/report.d.ts +14 -0
  40. package/dist/report.d.ts.map +1 -0
  41. package/dist/report.js +90 -0
  42. package/dist/report.js.map +1 -0
  43. package/dist/scanner.d.ts +51 -0
  44. package/dist/scanner.d.ts.map +1 -0
  45. package/dist/scanner.js +114 -0
  46. package/dist/scanner.js.map +1 -0
  47. package/dist/verification.d.ts +25 -0
  48. package/dist/verification.d.ts.map +1 -0
  49. package/dist/verification.js +89 -0
  50. package/dist/verification.js.map +1 -0
  51. package/dist/verifiers/base.d.ts +27 -0
  52. package/dist/verifiers/base.d.ts.map +1 -0
  53. package/dist/verifiers/base.js +24 -0
  54. package/dist/verifiers/base.js.map +1 -0
  55. package/dist/verifiers/cache.d.ts +23 -0
  56. package/dist/verifiers/cache.d.ts.map +1 -0
  57. package/dist/verifiers/cache.js +103 -0
  58. package/dist/verifiers/cache.js.map +1 -0
  59. package/dist/verifiers/gemini.d.ts +38 -0
  60. package/dist/verifiers/gemini.d.ts.map +1 -0
  61. package/dist/verifiers/gemini.js +121 -0
  62. package/dist/verifiers/gemini.js.map +1 -0
  63. package/dist/verifiers/index.d.ts +8 -0
  64. package/dist/verifiers/index.d.ts.map +1 -0
  65. package/dist/verifiers/index.js +16 -0
  66. package/dist/verifiers/index.js.map +1 -0
  67. package/package.json +96 -0
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # nz-privacy-auditor
2
+
3
+ [![npm version](https://img.shields.io/npm/v/nz-privacy-auditor?style=for-the-badge&color=a78bfa)](https://www.npmjs.com/package/nz-privacy-auditor)
4
+ [![npm downloads](https://img.shields.io/npm/dm/nz-privacy-auditor?style=for-the-badge&color=22c55e)](https://www.npmjs.com/package/nz-privacy-auditor)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-a78bfa?style=for-the-badge)](./LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-22c55e?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org)
7
+ [![Privacy Act 2020](https://img.shields.io/badge/Privacy%20Act-2020-3b82f6?style=for-the-badge)](https://www.legislation.govt.nz/act/public/2020/0031/latest/LMS23223.html)
8
+ [![QAPulse by SK](https://img.shields.io/badge/QAPulse%20by%20SK-Compliance%20Tools-3b82f6?style=for-the-badge)](https://skakarh.com)
9
+
10
+ > **Privacy Act 2020 compliance auditor for ML datasets.**
11
+ > Scans text for New-Zealand-specific PII — IRD, NHI, driver licence, phone, address, te reo Māori names.
12
+ > Zero dependencies. Works in Node, Deno, and browsers.
13
+
14
+ ---
15
+
16
+ ## ✨ Why nz-privacy-auditor?
17
+
18
+ NZ practitioners working with health records, government data, or customer corpora need to verify that datasets are free of regulated identifiers **before** they reach an ML pipeline or third-party service. Generic tools miss what actually matters under the [Privacy Act 2020](https://www.legislation.govt.nz/act/public/2020/0031/latest/LMS23223.html) and the Health Information Privacy Code 2020.
19
+
20
+ | Feature | nz-privacy-auditor | Generic PII tools |
21
+ |---|---|---|
22
+ | IRD number + mod-11 checksum | ✅ | ❌ |
23
+ | NHI number (legacy + new format) | ✅ | ❌ |
24
+ | NZ driver licence | ✅ | Regex only |
25
+ | NZ phone (NSN validation) | ✅ | Partial |
26
+ | NZ address (postcode + gazetteer) | ✅ | ❌ |
27
+ | Te reo Māori names (macron-aware) | ✅ | ❌ |
28
+ | Zero runtime dependencies | ✅ | Usually not |
29
+ | TypeScript-native | ✅ | Varies |
30
+
31
+ The full Python package (`pip install nz-privacy-auditor`) has [additional detectors, a CLI, Gemini LLM verification, HuggingFace loader, and a live demo](https://github.com/ShahnawazKakarh/nz-privacy-auditor). This TypeScript package is a port focused on the browser and Node ecosystems.
32
+
33
+ ---
34
+
35
+ ## 🚀 Install
36
+
37
+ ```bash
38
+ npm install nz-privacy-auditor
39
+ ```
40
+
41
+ Or with yarn / pnpm:
42
+
43
+ ```bash
44
+ yarn add nz-privacy-auditor
45
+ pnpm add nz-privacy-auditor
46
+ ```
47
+
48
+ Requires Node.js 18+.
49
+
50
+ ### CLI
51
+
52
+ A `nz-privacy-auditor` binary ships with the package:
53
+
54
+ ```bash
55
+ npx nz-privacy-auditor scan path/to/data.csv
56
+ npx nz-privacy-auditor scan path/to/data.csv --format json --output report.json
57
+ npx nz-privacy-auditor scan data.csv --detector ird,nhi --min-confidence 0.7
58
+ npx nz-privacy-auditor scan data.csv --fail-on-finding # exit 1 if any PII; CI gate
59
+ npx nz-privacy-auditor scan data.csv --verify-llm # Gemini second-pass on low-confidence findings
60
+ ```
61
+
62
+ For `--verify-llm`, set `GOOGLE_API_KEY` in your environment (get a free key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)). Findings are cached at `data/llm_cache/cache.json` so repeat runs cost nothing.
63
+
64
+ ---
65
+
66
+ ## 📖 Usage
67
+
68
+ ### Scan a whole CSV file (programmatic)
69
+
70
+ ```typescript
71
+ import { readFileSync } from "fs";
72
+ import { Scanner, parseCsv, toJson } from "nz-privacy-auditor";
73
+
74
+ const text = readFileSync("patients.csv", "utf-8");
75
+ const rows = parseCsv(text);
76
+ const result = new Scanner().scanRows(rows);
77
+
78
+ console.log(`${result.totalFindings} findings across ${result.columnsScanned.length} columns`);
79
+ console.log(toJson(result));
80
+ ```
81
+
82
+ ### Detect IRD numbers
83
+
84
+ ```typescript
85
+ import { IRDDetector } from "nz-privacy-auditor";
86
+
87
+ const detector = new IRDDetector();
88
+ const findings = detector.scan("Please reference IRD 49-091-850 on the form.");
89
+
90
+ console.log(findings);
91
+ // [{
92
+ // detector: "ird",
93
+ // severity: "high",
94
+ // value: "49-091-850",
95
+ // start: 17,
96
+ // end: 27,
97
+ // confidence: 1.0,
98
+ // context: { normalised: "49091850" }
99
+ // }]
100
+ ```
101
+
102
+ Only checksum-validated matches are emitted — no false positives on random 8-digit strings.
103
+
104
+ ### CommonJS
105
+
106
+ ```javascript
107
+ const { IRDDetector } = require("nz-privacy-auditor");
108
+ ```
109
+
110
+ ### Standalone checksum helper
111
+
112
+ If you just need to validate an IRD without the detection pipeline:
113
+
114
+ ```typescript
115
+ import { irdChecksumOk } from "nz-privacy-auditor";
116
+
117
+ irdChecksumOk("49091850"); // true
118
+ irdChecksumOk("49091851"); // false (bad check digit)
119
+ irdChecksumOk("00000000"); // false (below MIN_IRD)
120
+ ```
121
+
122
+ ---
123
+
124
+ ## 🗺️ Detector roadmap
125
+
126
+ | Detector | Approach | Status |
127
+ |---|---|---|
128
+ | **IRD number** | Regex + IR-published mod-11 (primary + secondary weights) | ✅ v0.1.0 |
129
+ | **NHI number** | Regex + Health NZ mod-11 (legacy) / mod-23 (new format per HISO 10046:2024) | ✅ v0.2.0 |
130
+ | **Driver licence** | `[A-Z]{2}\d{6}` + 300-char keyword proximity | ✅ v0.3.0 |
131
+ | **NZ phone** | `+64` / `0x` patterns + NSN validation, E.164 output | ✅ v0.4.0 |
132
+ | **NZ address** | Suffix + postcode + region / suburb gazetteer | ✅ v0.5.0 |
133
+ | **Te reo Māori names** | Macron-aware curated gazetteer | ✅ v0.6.0 |
134
+ | **LLM verification** | Gemini 2.5 Flash second-pass over low-confidence findings | ✅ v0.8.0 |
135
+
136
+ Test vectors are shared 1:1 with the Python implementation via [`fixtures/*.json`](https://github.com/ShahnawazKakarh/nz-privacy-auditor/tree/master/fixtures) — spec parity is enforced by construction, not by discipline.
137
+
138
+ ---
139
+
140
+ ## 🔗 See also
141
+
142
+ - **Python package** with full CLI, LLM verification, and HuggingFace loader: [github.com/ShahnawazKakarh/nz-privacy-auditor](https://github.com/ShahnawazKakarh/nz-privacy-auditor)
143
+ - **Live demo** on HuggingFace Spaces: [huggingface.co/spaces/Shahnawazkakarh/nz-privacy-auditor](https://huggingface.co/spaces/Shahnawazkakarh/nz-privacy-auditor)
144
+ - **Privacy Act 2020 mapping doc**: [docs/privacy-act-mapping.md](https://github.com/ShahnawazKakarh/nz-privacy-auditor/blob/master/docs/privacy-act-mapping.md)
145
+
146
+ ---
147
+
148
+ ## 📄 License
149
+
150
+ MIT © 2026 [QAPulse by SK](https://skakarh.com).
151
+
152
+ The library reflects publicly available NZ government identifier specifications (Inland Revenue IRD checksum, Health NZ NHI standard HISO 10046:2024) but is **not affiliated with or endorsed by** any NZ government agency. Consult the [Office of the Privacy Commissioner](https://www.privacy.org.nz/) for compliance decisions on production systems.
@@ -0,0 +1 @@
1
+ {"1f49c20f5f9ede6ae1048353f9ef4024427fa29e3314cc21d3ba3bcdd3409040":{"verdict":"rejected","confidence":1,"reason":"The value is explicitly referred to as an SKU in the context, not an NZ driver licence number.","created_at":1783314580473}}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Command-line interface for nz-privacy-auditor.
4
+ *
5
+ * Usage:
6
+ * nz-privacy-auditor scan path/to/data.csv
7
+ * nz-privacy-auditor scan path/to/data.csv --format json --output report.json
8
+ * nz-privacy-auditor scan data.csv --detector ird,nhi --min-confidence 0.7
9
+ */
10
+ /**
11
+ * Minimal RFC 4180 CSV parser. Handles quoted fields, embedded commas,
12
+ * embedded newlines, and escaped double-quotes. Comma-separated only.
13
+ */
14
+ export declare function parseCsv(text: string): Record<string, string>[];
15
+ export declare function main(argv?: string[]): void;
16
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AA+BH;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAoD/D;AAkBD,wBAAgB,IAAI,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,IAAI,CAyGxD"}
package/dist/cli.js ADDED
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Command-line interface for nz-privacy-auditor.
5
+ *
6
+ * Usage:
7
+ * nz-privacy-auditor scan path/to/data.csv
8
+ * nz-privacy-auditor scan path/to/data.csv --format json --output report.json
9
+ * nz-privacy-auditor scan data.csv --detector ird,nhi --min-confidence 0.7
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.parseCsv = parseCsv;
46
+ exports.main = main;
47
+ const fs = __importStar(require("fs"));
48
+ const path = __importStar(require("path"));
49
+ const commander_1 = require("commander");
50
+ const report_1 = require("./report");
51
+ const scanner_1 = require("./scanner");
52
+ const verification_1 = require("./verification");
53
+ const gemini_1 = require("./verifiers/gemini");
54
+ const address_1 = require("./detectors/address");
55
+ const driver_licence_1 = require("./detectors/driver_licence");
56
+ const ird_1 = require("./detectors/ird");
57
+ const maori_name_1 = require("./detectors/maori_name");
58
+ const nhi_1 = require("./detectors/nhi");
59
+ const phone_1 = require("./detectors/phone");
60
+ const index_1 = require("./index");
61
+ const DETECTOR_CLASSES = {
62
+ ird: ird_1.IRDDetector,
63
+ nhi: nhi_1.NHIDetector,
64
+ driver_licence: driver_licence_1.DriverLicenceDetector,
65
+ phone: phone_1.PhoneDetector,
66
+ address: address_1.AddressDetector,
67
+ maori_name: maori_name_1.MaoriNameDetector,
68
+ };
69
+ /**
70
+ * Minimal RFC 4180 CSV parser. Handles quoted fields, embedded commas,
71
+ * embedded newlines, and escaped double-quotes. Comma-separated only.
72
+ */
73
+ function parseCsv(text) {
74
+ const rows = [];
75
+ let cur = [];
76
+ let field = "";
77
+ let inQuotes = false;
78
+ for (let i = 0; i < text.length; i++) {
79
+ const ch = text[i];
80
+ if (inQuotes) {
81
+ if (ch === '"') {
82
+ if (text[i + 1] === '"') {
83
+ field += '"';
84
+ i++;
85
+ }
86
+ else {
87
+ inQuotes = false;
88
+ }
89
+ }
90
+ else {
91
+ field += ch;
92
+ }
93
+ continue;
94
+ }
95
+ if (ch === '"') {
96
+ inQuotes = true;
97
+ }
98
+ else if (ch === ",") {
99
+ cur.push(field);
100
+ field = "";
101
+ }
102
+ else if (ch === "\n" || ch === "\r") {
103
+ // Handle \r\n
104
+ if (ch === "\r" && text[i + 1] === "\n")
105
+ i++;
106
+ cur.push(field);
107
+ field = "";
108
+ rows.push(cur);
109
+ cur = [];
110
+ }
111
+ else {
112
+ field += ch;
113
+ }
114
+ }
115
+ // Trailing field / row
116
+ if (field.length > 0 || cur.length > 0) {
117
+ cur.push(field);
118
+ rows.push(cur);
119
+ }
120
+ if (rows.length === 0)
121
+ return [];
122
+ const header = rows[0];
123
+ return rows.slice(1).map((r) => {
124
+ const obj = {};
125
+ header.forEach((h, idx) => {
126
+ obj[h] = r[idx] ?? "";
127
+ });
128
+ return obj;
129
+ });
130
+ }
131
+ function resolveDetectors(csv) {
132
+ if (!csv)
133
+ return (0, scanner_1.defaultDetectors)();
134
+ const keys = csv
135
+ .split(",")
136
+ .map((k) => k.trim())
137
+ .filter(Boolean);
138
+ const unknown = keys.filter((k) => !(k in DETECTOR_CLASSES));
139
+ if (unknown.length > 0) {
140
+ throw new Error(`Unknown detector(s): ${unknown.join(", ")}. ` +
141
+ `Valid: ${Object.keys(DETECTOR_CLASSES).sort().join(", ")}`);
142
+ }
143
+ return keys.map((k) => new DETECTOR_CLASSES[k]());
144
+ }
145
+ function main(argv = process.argv) {
146
+ const program = new commander_1.Command();
147
+ program
148
+ .name("nz-privacy-auditor")
149
+ .description("Privacy Act 2020 compliance auditor for ML datasets")
150
+ .version(index_1.VERSION);
151
+ program
152
+ .command("scan")
153
+ .description("Scan a CSV file for Privacy Act 2020 PII issues")
154
+ .argument("<path>", "Path to CSV file")
155
+ .option("--format <format>", "Output format: console or json", "console")
156
+ .option("-o, --output <file>", "Write output to a file (JSON only)")
157
+ .option("--detector <names>", "Comma-separated detector names. Default: all. Choices: " +
158
+ Object.keys(DETECTOR_CLASSES).sort().join(", "))
159
+ .option("--min-confidence <n>", "Drop findings below this confidence threshold (0-1)", "0.0")
160
+ .option("--fail-on-finding", "Exit with status 1 if any findings emitted", false)
161
+ .option("--verify-llm", "Run Gemini second-pass over low-confidence findings. Requires GOOGLE_API_KEY.", false)
162
+ .option("--llm-threshold <n>", "Only findings with confidence below this threshold are verified", "0.8")
163
+ .action(async (filePath, opts) => {
164
+ const abs = path.resolve(filePath);
165
+ if (!fs.existsSync(abs)) {
166
+ console.error(`Error: file not found: ${abs}`);
167
+ process.exit(2);
168
+ }
169
+ const detectors = resolveDetectors(opts.detector);
170
+ const minConfidence = Number(opts.minConfidence);
171
+ if (Number.isNaN(minConfidence) || minConfidence < 0 || minConfidence > 1) {
172
+ console.error("Error: --min-confidence must be a number in [0, 1]");
173
+ process.exit(2);
174
+ }
175
+ const text = fs.readFileSync(abs, "utf-8");
176
+ const rows = parseCsv(text);
177
+ const scanner = new scanner_1.Scanner({ detectors, minConfidence });
178
+ let result = scanner.scanRows(rows);
179
+ if (opts.verifyLlm) {
180
+ const llmThreshold = Number(opts.llmThreshold);
181
+ if (Number.isNaN(llmThreshold) || llmThreshold < 0 || llmThreshold > 1) {
182
+ console.error("Error: --llm-threshold must be a number in [0, 1]");
183
+ process.exit(2);
184
+ }
185
+ try {
186
+ const verifier = new gemini_1.GeminiVerifier();
187
+ try {
188
+ result = await (0, verification_1.applyVerification)(result, verifier, {
189
+ threshold: llmThreshold,
190
+ });
191
+ }
192
+ finally {
193
+ verifier.close();
194
+ }
195
+ }
196
+ catch (exc) {
197
+ console.error(`Error: LLM verification failed: ${exc instanceof Error ? exc.message : String(exc)}`);
198
+ process.exit(2);
199
+ }
200
+ }
201
+ const outputFormat = String(opts.format);
202
+ if (outputFormat === "json") {
203
+ const payload = (0, report_1.toJson)(result);
204
+ if (opts.output) {
205
+ fs.writeFileSync(String(opts.output), payload, "utf-8");
206
+ console.log(`Wrote report to ${opts.output}`);
207
+ }
208
+ else {
209
+ console.log(payload);
210
+ }
211
+ }
212
+ else if (outputFormat === "console") {
213
+ if (opts.output) {
214
+ console.error("Error: --output is only supported with --format json");
215
+ process.exit(2);
216
+ }
217
+ console.log((0, report_1.renderConsole)(result));
218
+ }
219
+ else {
220
+ console.error(`Error: unknown --format value: ${outputFormat}`);
221
+ process.exit(2);
222
+ }
223
+ if (opts.failOnFinding && result.totalFindings > 0) {
224
+ process.exit(1);
225
+ }
226
+ });
227
+ program.parse(argv);
228
+ }
229
+ // Node's ESM/CJS detection: run main if invoked directly, not when required.
230
+ if (require.main === module) {
231
+ main();
232
+ }
233
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * NZ address detector.
3
+ *
4
+ * Address detection combines three signals to flag values that look like a
5
+ * New Zealand street address:
6
+ *
7
+ * 1. **Street-suffix shape** — a numeric prefix followed by 1–4 words and a
8
+ * recognised NZ street-type suffix (`Street`, `Road`, `Avenue`, `Drive`,
9
+ * `Lane`, etc., and their common abbreviations).
10
+ * 2. **NZ postcode** — a 4-digit token (NZ Post uses 4-digit postcodes).
11
+ * 3. **NZ location name** — one of the 16 regions, major cities, or common
12
+ * metropolitan suburbs from the bundled gazetteer.
13
+ *
14
+ * Severity is MEDIUM because an address is a quasi-identifier under the
15
+ * Privacy Act 2020. Confidence scales with the number of corroborating
16
+ * signals:
17
+ *
18
+ * - 0.5 — street-suffix shape only
19
+ * - 0.7 — street-suffix shape + postcode OR location
20
+ * - 0.9 — street-suffix shape + postcode + location
21
+ *
22
+ * TypeScript port of `src/nz_privacy_auditor/detectors/address.py`. The
23
+ * NZ_LOCATIONS list is a verbatim mirror of the Python `_NZ_LOCATIONS`
24
+ * frozenset — any change to one must be applied to the other. A parity
25
+ * check across the two lists lives in the JS test suite.
26
+ */
27
+ import type { Detector, Finding, Severity } from "./base";
28
+ /**
29
+ * NZ regions, major cities, and common metropolitan suburbs.
30
+ *
31
+ * IMPORTANT: this list is a mirror of `_NZ_LOCATIONS` in the Python
32
+ * detector at `src/nz_privacy_auditor/detectors/address.py`. Any addition
33
+ * or removal must be applied to both files simultaneously.
34
+ */
35
+ export declare const NZ_LOCATIONS: readonly string[];
36
+ /**
37
+ * Detects NZ street addresses via shape + postcode + gazetteer signals.
38
+ *
39
+ * Emits a finding for each street-shape match. Confidence reflects how
40
+ * many corroborating signals (postcode, NZ region / city / suburb) are
41
+ * present in the same value.
42
+ */
43
+ export declare class AddressDetector implements Detector {
44
+ readonly name = "address";
45
+ readonly severity: Severity;
46
+ scan(value: string): Finding[];
47
+ }
48
+ //# sourceMappingURL=address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../../src/detectors/address.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AA8C1D;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,MAAM,EA2FzC,CAAC;AA0EF;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAY;IAEvC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE;CAuB/B"}