rehydra 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +24 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/anonymize.d.ts +3 -0
- package/dist/cli/commands/anonymize.d.ts.map +1 -0
- package/dist/cli/commands/anonymize.js +132 -0
- package/dist/cli/commands/anonymize.js.map +1 -0
- package/dist/cli/commands/inspect.d.ts +3 -0
- package/dist/cli/commands/inspect.d.ts.map +1 -0
- package/dist/cli/commands/inspect.js +73 -0
- package/dist/cli/commands/inspect.js.map +1 -0
- package/dist/cli/commands/rehydrate.d.ts +3 -0
- package/dist/cli/commands/rehydrate.d.ts.map +1 -0
- package/dist/cli/commands/rehydrate.js +30 -0
- package/dist/cli/commands/rehydrate.js.map +1 -0
- package/dist/cli/commands/setup-ner.d.ts +3 -0
- package/dist/cli/commands/setup-ner.d.ts.map +1 -0
- package/dist/cli/commands/setup-ner.js +41 -0
- package/dist/cli/commands/setup-ner.js.map +1 -0
- package/dist/cli/main.d.ts +14 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +135 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/utils/color.d.ts +12 -0
- package/dist/cli/utils/color.d.ts.map +1 -0
- package/dist/cli/utils/color.js +46 -0
- package/dist/cli/utils/color.js.map +1 -0
- package/dist/cli/utils/errors.d.ts +8 -0
- package/dist/cli/utils/errors.d.ts.map +1 -0
- package/dist/cli/utils/errors.js +12 -0
- package/dist/cli/utils/errors.js.map +1 -0
- package/dist/cli/utils/format.d.ts +14 -0
- package/dist/cli/utils/format.d.ts.map +1 -0
- package/dist/cli/utils/format.js +63 -0
- package/dist/cli/utils/format.js.map +1 -0
- package/dist/cli/utils/io.d.ts +10 -0
- package/dist/cli/utils/io.d.ts.map +1 -0
- package/dist/cli/utils/io.js +37 -0
- package/dist/cli/utils/io.js.map +1 -0
- package/dist/cli/utils/pii-map-file.d.ts +14 -0
- package/dist/cli/utils/pii-map-file.d.ts.map +1 -0
- package/dist/cli/utils/pii-map-file.js +32 -0
- package/dist/cli/utils/pii-map-file.js.map +1 -0
- package/dist/cli/utils/progress.d.ts +4 -0
- package/dist/cli/utils/progress.d.ts.map +1 -0
- package/dist/cli/utils/progress.js +21 -0
- package/dist/cli/utils/progress.js.map +1 -0
- package/dist/storage/browser.d.ts +1 -1
- package/dist/storage/browser.d.ts.map +1 -1
- package/dist/storage/browser.js +2 -2
- package/dist/storage/browser.js.map +1 -1
- package/dist/storage/session-base.d.ts +31 -0
- package/dist/storage/session-base.d.ts.map +1 -0
- package/dist/storage/session-base.js +112 -0
- package/dist/storage/session-base.js.map +1 -0
- package/dist/storage/session.d.ts +9 -23
- package/dist/storage/session.d.ts.map +1 -1
- package/dist/storage/session.js +8 -105
- package/dist/storage/session.js.map +1 -1
- package/package.json +7 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;aAGf,QAAQ,EAAE,MAAM;gBADhC,OAAO,EAAE,MAAM,EACC,QAAQ,GAAE,MAAU;CAKvC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI-specific error with exit code
|
|
3
|
+
*/
|
|
4
|
+
export class CLIError extends Error {
|
|
5
|
+
exitCode;
|
|
6
|
+
constructor(message, exitCode = 1) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.exitCode = exitCode;
|
|
9
|
+
this.name = "CLIError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/cli/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IAFlB,YACE,OAAe,EACC,WAAmB,CAAC;QAEpC,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,aAAQ,GAAR,QAAQ,CAAY;QAGpC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AnonymizationResult, AnonymizationStats, PIIType } from "../../types/index.js";
|
|
2
|
+
export declare function formatText(result: AnonymizationResult): string;
|
|
3
|
+
export declare function formatJson(result: AnonymizationResult): string;
|
|
4
|
+
export declare function formatNdjson(result: AnonymizationResult): string;
|
|
5
|
+
interface InspectEntity {
|
|
6
|
+
type: PIIType;
|
|
7
|
+
original: string;
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
}
|
|
11
|
+
export declare function formatInspect(originalText: string, entities: InspectEntity[]): string;
|
|
12
|
+
export declare function formatStats(stats: AnonymizationStats): string;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,OAAO,EACR,MAAM,sBAAsB,CAAC;AAG9B,wBAAgB,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAE9D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAiB9D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAoBhE;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,aAAa,CAC3B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,aAAa,EAAE,GACxB,MAAM,CAYR;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAa7D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { bold, dim, piiTypeColor } from "./color.js";
|
|
2
|
+
export function formatText(result) {
|
|
3
|
+
return result.anonymizedText;
|
|
4
|
+
}
|
|
5
|
+
export function formatJson(result) {
|
|
6
|
+
const output = {
|
|
7
|
+
anonymizedText: result.anonymizedText,
|
|
8
|
+
entities: result.entities.map((e) => ({
|
|
9
|
+
type: e.type,
|
|
10
|
+
id: e.id,
|
|
11
|
+
confidence: e.confidence,
|
|
12
|
+
source: e.source,
|
|
13
|
+
...(e.semantic !== undefined ? { semantic: e.semantic } : {}),
|
|
14
|
+
})),
|
|
15
|
+
stats: {
|
|
16
|
+
totalEntities: result.stats.totalEntities,
|
|
17
|
+
countsByType: result.stats.countsByType,
|
|
18
|
+
processingTimeMs: result.stats.processingTimeMs,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
return JSON.stringify(output, null, 2);
|
|
22
|
+
}
|
|
23
|
+
export function formatNdjson(result) {
|
|
24
|
+
const lines = result.entities.map((e) => JSON.stringify({
|
|
25
|
+
type: e.type,
|
|
26
|
+
id: e.id,
|
|
27
|
+
confidence: e.confidence,
|
|
28
|
+
source: e.source,
|
|
29
|
+
...(e.semantic !== undefined ? { semantic: e.semantic } : {}),
|
|
30
|
+
}));
|
|
31
|
+
// Also include a summary line
|
|
32
|
+
lines.push(JSON.stringify({
|
|
33
|
+
_type: "summary",
|
|
34
|
+
anonymizedText: result.anonymizedText,
|
|
35
|
+
totalEntities: result.stats.totalEntities,
|
|
36
|
+
processingTimeMs: result.stats.processingTimeMs,
|
|
37
|
+
}));
|
|
38
|
+
return lines.join("\n");
|
|
39
|
+
}
|
|
40
|
+
export function formatInspect(originalText, entities) {
|
|
41
|
+
// Sort entities by position descending so replacements don't shift offsets
|
|
42
|
+
const sorted = [...entities].sort((a, b) => b.start - a.start);
|
|
43
|
+
let result = originalText;
|
|
44
|
+
for (const entity of sorted) {
|
|
45
|
+
const colorFn = piiTypeColor(entity.type);
|
|
46
|
+
const label = colorFn(`[${entity.type}: ${entity.original}]`);
|
|
47
|
+
result = result.slice(0, entity.start) + label + result.slice(entity.end);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
export function formatStats(stats) {
|
|
52
|
+
const lines = [];
|
|
53
|
+
lines.push(` ${bold("Found")} ${stats.totalEntities} PII ${stats.totalEntities === 1 ? "entity" : "entities"}:`);
|
|
54
|
+
for (const [type, count] of Object.entries(stats.countsByType)) {
|
|
55
|
+
if (count > 0) {
|
|
56
|
+
const colorFn = piiTypeColor(type);
|
|
57
|
+
lines.push(` ${colorFn(type)} ${count}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
lines.push(dim(` Processing time: ${stats.processingTimeMs}ms`));
|
|
61
|
+
return lines.join("\n");
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/cli/utils/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read input from a file path or stdin.
|
|
3
|
+
* Throws CLIError if no file and stdin is a TTY (no piped data).
|
|
4
|
+
*/
|
|
5
|
+
export declare function readInput(filePath?: string): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Write output to a file path or stdout.
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeOutput(data: string, filePath?: string): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/io.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBlE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { text } from "node:stream/consumers";
|
|
3
|
+
import { CLIError } from "./errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read input from a file path or stdin.
|
|
6
|
+
* Throws CLIError if no file and stdin is a TTY (no piped data).
|
|
7
|
+
*/
|
|
8
|
+
export async function readInput(filePath) {
|
|
9
|
+
if (filePath !== undefined) {
|
|
10
|
+
try {
|
|
11
|
+
return await readFile(filePath, "utf-8");
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
const code = err.code;
|
|
15
|
+
if (code === "ENOENT") {
|
|
16
|
+
throw new CLIError(`File not found: ${filePath}`);
|
|
17
|
+
}
|
|
18
|
+
throw new CLIError(`Failed to read file: ${filePath}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (process.stdin.isTTY === true) {
|
|
22
|
+
throw new CLIError("No input: provide a file argument or pipe data via stdin");
|
|
23
|
+
}
|
|
24
|
+
return text(process.stdin);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Write output to a file path or stdout.
|
|
28
|
+
*/
|
|
29
|
+
export async function writeOutput(data, filePath) {
|
|
30
|
+
if (filePath !== undefined) {
|
|
31
|
+
await writeFile(filePath, data, "utf-8");
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
process.stdout.write(data);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../../src/cli/utils/io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAiB;IAC/C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACtB,MAAM,IAAI,QAAQ,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;YACpD,CAAC;YACD,MAAM,IAAI,QAAQ,CAAC,wBAAwB,QAAQ,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACjC,MAAM,IAAI,QAAQ,CAChB,0DAA0D,CAC3D,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,QAAiB;IAEjB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EncryptedPIIMap } from "../../types/index.js";
|
|
2
|
+
export interface PIIMapFile {
|
|
3
|
+
version: 1;
|
|
4
|
+
createdAt: string;
|
|
5
|
+
key?: string;
|
|
6
|
+
piiMap: EncryptedPIIMap;
|
|
7
|
+
stats: {
|
|
8
|
+
totalEntities: number;
|
|
9
|
+
countsByType: Record<string, number>;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare function savePIIMapFile(path: string, data: PIIMapFile): Promise<void>;
|
|
13
|
+
export declare function loadPIIMapFile(path: string): Promise<PIIMapFile>;
|
|
14
|
+
//# sourceMappingURL=pii-map-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-map-file.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/pii-map-file.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE;QACL,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtC,CAAC;CACH;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA2BtE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { CLIError } from "./errors.js";
|
|
3
|
+
export async function savePIIMapFile(path, data) {
|
|
4
|
+
const json = JSON.stringify(data, null, 2) + "\n";
|
|
5
|
+
await writeFile(path, json, "utf-8");
|
|
6
|
+
}
|
|
7
|
+
export async function loadPIIMapFile(path) {
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
raw = await readFile(path, "utf-8");
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
const code = err.code;
|
|
14
|
+
if (code === "ENOENT") {
|
|
15
|
+
throw new CLIError(`PII map file not found: ${path}`);
|
|
16
|
+
}
|
|
17
|
+
throw new CLIError(`Failed to read PII map file: ${path}`);
|
|
18
|
+
}
|
|
19
|
+
let parsed;
|
|
20
|
+
try {
|
|
21
|
+
parsed = JSON.parse(raw);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new CLIError(`Invalid JSON in PII map file: ${path}`);
|
|
25
|
+
}
|
|
26
|
+
const file = parsed;
|
|
27
|
+
if (file.version !== 1 || file.piiMap === undefined) {
|
|
28
|
+
throw new CLIError(`Invalid PII map file format: ${path}`);
|
|
29
|
+
}
|
|
30
|
+
return file;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=pii-map-file.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-map-file.js","sourceRoot":"","sources":["../../../src/cli/utils/pii-map-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAavC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,IAAgB;IAEhB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;IAClD,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,IAAI,QAAQ,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,QAAQ,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,IAAI,GAAG,MAAoB,CAAC;IAClC,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACpD,MAAM,IAAI,QAAQ,CAChB,gCAAgC,IAAI,EAAE,CACvC,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/progress.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GAAG,IAAI,GACrB,MAAM,CASR;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIhD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const BAR_WIDTH = 30;
|
|
2
|
+
export function formatProgress(file, percent) {
|
|
3
|
+
if (percent === null) {
|
|
4
|
+
return ` Downloading ${file}...`;
|
|
5
|
+
}
|
|
6
|
+
const filled = Math.round((percent / 100) * BAR_WIDTH);
|
|
7
|
+
const empty = BAR_WIDTH - filled;
|
|
8
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
9
|
+
return ` ${file} [${bar}] ${percent.toFixed(0)}%`;
|
|
10
|
+
}
|
|
11
|
+
export function writeProgress(line) {
|
|
12
|
+
if (process.stderr.isTTY === true) {
|
|
13
|
+
process.stderr.write(`\r\x1b[K${line}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function clearProgress() {
|
|
17
|
+
if (process.stderr.isTTY === true) {
|
|
18
|
+
process.stderr.write("\r\x1b[K");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=progress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress.js","sourceRoot":"","sources":["../../../src/cli/utils/progress.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,OAAsB;IAEtB,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,iBAAiB,IAAI,KAAK,CAAC;IACpC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7D,OAAO,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;AACH,CAAC"}
|
|
@@ -9,5 +9,5 @@ export type { PIIStorageProvider, PIIMapMetadata, StoredPIIMap, ListOptions, Ano
|
|
|
9
9
|
export type { EncryptedPIIMap } from "../types/index.js";
|
|
10
10
|
export { InMemoryPIIStorageProvider } from "./in-memory.js";
|
|
11
11
|
export { IndexedDBPIIStorageProvider } from "./indexeddb.js";
|
|
12
|
-
export { AnonymizerSessionImpl } from "./session.js";
|
|
12
|
+
export { AnonymizerSessionImpl } from "./session-base.js";
|
|
13
13
|
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGzD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAG7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/storage/browser.js
CHANGED
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
// Export browser-compatible implementations only
|
|
9
9
|
export { InMemoryPIIStorageProvider } from "./in-memory.js";
|
|
10
10
|
export { IndexedDBPIIStorageProvider } from "./indexeddb.js";
|
|
11
|
-
// Export session implementation
|
|
12
|
-
export { AnonymizerSessionImpl } from "./session.js";
|
|
11
|
+
// Export session implementation (browser-safe, without streaming support)
|
|
12
|
+
export { AnonymizerSessionImpl } from "./session-base.js";
|
|
13
13
|
//# sourceMappingURL=browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,iDAAiD;AACjD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAcH,iDAAiD;AACjD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0EAA0E;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymizer Session Base Implementation
|
|
3
|
+
* Browser-safe session wrapper for automatic PII map storage.
|
|
4
|
+
* Does NOT include createStream() to avoid pulling in node:stream.
|
|
5
|
+
*/
|
|
6
|
+
import type { AnonymizationResult, AnonymizationPolicy } from "../types/index.js";
|
|
7
|
+
import type { KeyProvider } from "../crypto/index.js";
|
|
8
|
+
import type { RawPIIMap } from "../pipeline/tagger.js";
|
|
9
|
+
import type { AnonymizerSession, PIIStorageProvider, StoredPIIMap } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Interface for the parent Anonymizer (to avoid circular dependency)
|
|
12
|
+
*/
|
|
13
|
+
export interface IAnonymizer {
|
|
14
|
+
anonymize(text: string, locale?: string, policy?: Partial<AnonymizationPolicy>, existingPiiMap?: RawPIIMap): Promise<AnonymizationResult>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Session implementation that wraps an Anonymizer with automatic storage
|
|
18
|
+
*/
|
|
19
|
+
export declare class AnonymizerSessionImpl implements AnonymizerSession {
|
|
20
|
+
protected readonly anonymizer: IAnonymizer;
|
|
21
|
+
protected readonly storage: PIIStorageProvider;
|
|
22
|
+
protected readonly keyProvider: KeyProvider;
|
|
23
|
+
readonly sessionId: string;
|
|
24
|
+
constructor(anonymizer: IAnonymizer, sessionId: string, storage: PIIStorageProvider, keyProvider: KeyProvider);
|
|
25
|
+
anonymize(text: string, locale?: string, policy?: Partial<AnonymizationPolicy>): Promise<AnonymizationResult>;
|
|
26
|
+
rehydrate(text: string): Promise<string>;
|
|
27
|
+
load(): Promise<StoredPIIMap | null>;
|
|
28
|
+
delete(): Promise<boolean>;
|
|
29
|
+
exists(): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=session-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-base.d.ts","sourceRoot":"","sources":["../../src/storage/session-base.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,EACrC,cAAc,CAAC,EAAE,SAAS,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,qBAAa,qBAAsB,YAAW,iBAAiB;IAI3D,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,WAAW;IAE1C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,kBAAkB;IAC9C,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW;IAN7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAGN,UAAU,EAAE,WAAW,EAC1C,SAAS,EAAE,MAAM,EACE,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,WAAW;IAKvC,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GACpC,OAAO,CAAC,mBAAmB,CAAC;IAuFzB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBxC,IAAI,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAIpC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAI1B,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;CAGjC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anonymizer Session Base Implementation
|
|
3
|
+
* Browser-safe session wrapper for automatic PII map storage.
|
|
4
|
+
* Does NOT include createStream() to avoid pulling in node:stream.
|
|
5
|
+
*/
|
|
6
|
+
import { decryptPIIMap, encryptPIIMap } from "../crypto/index.js";
|
|
7
|
+
import { rehydrate as rehydrateText } from "../pipeline/tagger.js";
|
|
8
|
+
/**
|
|
9
|
+
* Session implementation that wraps an Anonymizer with automatic storage
|
|
10
|
+
*/
|
|
11
|
+
export class AnonymizerSessionImpl {
|
|
12
|
+
anonymizer;
|
|
13
|
+
storage;
|
|
14
|
+
keyProvider;
|
|
15
|
+
sessionId;
|
|
16
|
+
constructor(anonymizer, sessionId, storage, keyProvider) {
|
|
17
|
+
this.anonymizer = anonymizer;
|
|
18
|
+
this.storage = storage;
|
|
19
|
+
this.keyProvider = keyProvider;
|
|
20
|
+
this.sessionId = sessionId;
|
|
21
|
+
}
|
|
22
|
+
async anonymize(text, locale, policy) {
|
|
23
|
+
// Get the encryption key
|
|
24
|
+
const key = await this.keyProvider.getKey();
|
|
25
|
+
// Load existing PII map for ID reuse (before calling anonymizer)
|
|
26
|
+
const existing = await this.storage.load(this.sessionId);
|
|
27
|
+
let existingPiiMap;
|
|
28
|
+
let createdAt;
|
|
29
|
+
let existingEntityCounts;
|
|
30
|
+
if (existing !== null) {
|
|
31
|
+
try {
|
|
32
|
+
existingPiiMap = await decryptPIIMap(existing.piiMap, key);
|
|
33
|
+
createdAt = existing.metadata.createdAt;
|
|
34
|
+
existingEntityCounts = existing.metadata.entityCounts;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// Decryption failed - likely key mismatch
|
|
38
|
+
const isKeyMismatch = error instanceof Error &&
|
|
39
|
+
(error.name === "OperationError" ||
|
|
40
|
+
error.message.includes("decrypt"));
|
|
41
|
+
if (isKeyMismatch) {
|
|
42
|
+
throw new Error(`Failed to decrypt existing session data for "${this.sessionId}". ` +
|
|
43
|
+
`The encryption key may have changed since this session was created.\n\n` +
|
|
44
|
+
`To fix this, either:\n` +
|
|
45
|
+
` 1. Use the same key that was used to create the session\n` +
|
|
46
|
+
` 2. Delete the old session: await session.delete()\n` +
|
|
47
|
+
` 3. Use a persistent key provider (e.g., ConfigKeyProvider)`);
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
existingPiiMap = undefined;
|
|
54
|
+
createdAt = Date.now();
|
|
55
|
+
existingEntityCounts = {};
|
|
56
|
+
}
|
|
57
|
+
// Call the parent anonymizer with existing PII map for ID reuse
|
|
58
|
+
const result = await this.anonymizer.anonymize(text, locale, policy, existingPiiMap);
|
|
59
|
+
// Sessions require a PII map (only available in pseudonymize mode)
|
|
60
|
+
if (result.piiMap === undefined) {
|
|
61
|
+
throw new Error("Session anonymize() failed: no PII map returned.\n\n" +
|
|
62
|
+
"This can happen if the anonymizer is in 'anonymize' mode.\n" +
|
|
63
|
+
"Sessions require 'pseudonymize' mode for PII map storage.");
|
|
64
|
+
}
|
|
65
|
+
// Decrypt the new PII map
|
|
66
|
+
const newPiiMap = await decryptPIIMap(result.piiMap, key);
|
|
67
|
+
// Merge maps: start with existing (if any), add new entries
|
|
68
|
+
const mergedPiiMap = existingPiiMap
|
|
69
|
+
? new Map(existingPiiMap)
|
|
70
|
+
: new Map();
|
|
71
|
+
for (const [k, v] of newPiiMap) {
|
|
72
|
+
mergedPiiMap.set(k, v);
|
|
73
|
+
}
|
|
74
|
+
// Merge entity counts
|
|
75
|
+
const mergedEntityCounts = { ...existingEntityCounts };
|
|
76
|
+
for (const [type, count] of Object.entries(result.stats.countsByType)) {
|
|
77
|
+
mergedEntityCounts[type] = (mergedEntityCounts[type] ?? 0) + count;
|
|
78
|
+
}
|
|
79
|
+
// Re-encrypt the merged PII map
|
|
80
|
+
const encryptedMergedMap = await encryptPIIMap(mergedPiiMap, key);
|
|
81
|
+
// Save the merged PII map to storage
|
|
82
|
+
await this.storage.save(this.sessionId, encryptedMergedMap, {
|
|
83
|
+
createdAt,
|
|
84
|
+
entityCounts: mergedEntityCounts,
|
|
85
|
+
modelVersion: result.stats.modelVersion,
|
|
86
|
+
});
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
async rehydrate(text) {
|
|
90
|
+
// Load from storage
|
|
91
|
+
const stored = await this.storage.load(this.sessionId);
|
|
92
|
+
if (stored === null) {
|
|
93
|
+
throw new Error(`No PII map found for session: ${this.sessionId}. ` +
|
|
94
|
+
`Make sure to call anonymize() before rehydrate().`);
|
|
95
|
+
}
|
|
96
|
+
// Decrypt the PII map
|
|
97
|
+
const key = await this.keyProvider.getKey();
|
|
98
|
+
const piiMap = await decryptPIIMap(stored.piiMap, key);
|
|
99
|
+
// Rehydrate the text
|
|
100
|
+
return rehydrateText(text, piiMap);
|
|
101
|
+
}
|
|
102
|
+
async load() {
|
|
103
|
+
return this.storage.load(this.sessionId);
|
|
104
|
+
}
|
|
105
|
+
async delete() {
|
|
106
|
+
return this.storage.delete(this.sessionId);
|
|
107
|
+
}
|
|
108
|
+
async exists() {
|
|
109
|
+
return this.storage.exists(this.sessionId);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=session-base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-base.js","sourceRoot":"","sources":["../../src/storage/session-base.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,33 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Anonymizer Session Implementation
|
|
3
|
-
*
|
|
2
|
+
* Anonymizer Session Implementation (Node.js)
|
|
3
|
+
* Extends the base session with streaming support (requires node:stream).
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
export { type IAnonymizer } from "./session-base.js";
|
|
6
|
+
import { AnonymizerSessionImpl as BaseSessionImpl } from "./session-base.js";
|
|
6
7
|
import type { KeyProvider } from "../crypto/index.js";
|
|
7
|
-
import type {
|
|
8
|
-
import
|
|
9
|
-
import type { AnonymizerStream } from "../streaming/anonymizer-stream.js";
|
|
8
|
+
import type { PIIStorageProvider } from "./types.js";
|
|
9
|
+
import { AnonymizerStream } from "../streaming/anonymizer-stream.js";
|
|
10
10
|
import type { StreamConfig } from "../streaming/types.js";
|
|
11
|
+
import type { IAnonymizer } from "./session-base.js";
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* Node.js session implementation with streaming support
|
|
13
14
|
*/
|
|
14
|
-
export
|
|
15
|
-
anonymize(text: string, locale?: string, policy?: Partial<AnonymizationPolicy>, existingPiiMap?: RawPIIMap): Promise<AnonymizationResult>;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Session implementation that wraps an Anonymizer with automatic storage
|
|
19
|
-
*/
|
|
20
|
-
export declare class AnonymizerSessionImpl implements AnonymizerSession {
|
|
21
|
-
private readonly anonymizer;
|
|
22
|
-
private readonly storage;
|
|
23
|
-
private readonly keyProvider;
|
|
24
|
-
readonly sessionId: string;
|
|
15
|
+
export declare class AnonymizerSessionImpl extends BaseSessionImpl {
|
|
25
16
|
constructor(anonymizer: IAnonymizer, sessionId: string, storage: PIIStorageProvider, keyProvider: KeyProvider);
|
|
26
|
-
anonymize(text: string, locale?: string, policy?: Partial<AnonymizationPolicy>): Promise<AnonymizationResult>;
|
|
27
|
-
rehydrate(text: string): Promise<string>;
|
|
28
|
-
load(): Promise<StoredPIIMap | null>;
|
|
29
|
-
delete(): Promise<boolean>;
|
|
30
|
-
exists(): Promise<boolean>;
|
|
31
17
|
createStream(config?: Partial<StreamConfig>): Promise<AnonymizerStream>;
|
|
32
18
|
}
|
|
33
19
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/storage/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/storage/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,qBAAqB,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,eAAe;gBAEtD,UAAU,EAAE,WAAW,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,kBAAkB,EAC3B,WAAW,EAAE,WAAW;IAKpB,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAoB9E"}
|
package/dist/storage/session.js
CHANGED
|
@@ -1,115 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Anonymizer Session Implementation
|
|
3
|
-
*
|
|
2
|
+
* Anonymizer Session Implementation (Node.js)
|
|
3
|
+
* Extends the base session with streaming support (requires node:stream).
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { AnonymizerSessionImpl as BaseSessionImpl } from "./session-base.js";
|
|
6
|
+
import { decryptPIIMap } from "../crypto/index.js";
|
|
7
|
+
import { AnonymizerStream } from "../streaming/anonymizer-stream.js";
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* Node.js session implementation with streaming support
|
|
9
10
|
*/
|
|
10
|
-
export class AnonymizerSessionImpl {
|
|
11
|
-
anonymizer;
|
|
12
|
-
storage;
|
|
13
|
-
keyProvider;
|
|
14
|
-
sessionId;
|
|
11
|
+
export class AnonymizerSessionImpl extends BaseSessionImpl {
|
|
15
12
|
constructor(anonymizer, sessionId, storage, keyProvider) {
|
|
16
|
-
|
|
17
|
-
this.storage = storage;
|
|
18
|
-
this.keyProvider = keyProvider;
|
|
19
|
-
this.sessionId = sessionId;
|
|
20
|
-
}
|
|
21
|
-
async anonymize(text, locale, policy) {
|
|
22
|
-
// Get the encryption key
|
|
23
|
-
const key = await this.keyProvider.getKey();
|
|
24
|
-
// Load existing PII map for ID reuse (before calling anonymizer)
|
|
25
|
-
const existing = await this.storage.load(this.sessionId);
|
|
26
|
-
let existingPiiMap;
|
|
27
|
-
let createdAt;
|
|
28
|
-
let existingEntityCounts;
|
|
29
|
-
if (existing !== null) {
|
|
30
|
-
try {
|
|
31
|
-
existingPiiMap = await decryptPIIMap(existing.piiMap, key);
|
|
32
|
-
createdAt = existing.metadata.createdAt;
|
|
33
|
-
existingEntityCounts = existing.metadata.entityCounts;
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
// Decryption failed - likely key mismatch
|
|
37
|
-
const isKeyMismatch = error instanceof Error &&
|
|
38
|
-
(error.name === "OperationError" ||
|
|
39
|
-
error.message.includes("decrypt"));
|
|
40
|
-
if (isKeyMismatch) {
|
|
41
|
-
throw new Error(`Failed to decrypt existing session data for "${this.sessionId}". ` +
|
|
42
|
-
`The encryption key may have changed since this session was created.\n\n` +
|
|
43
|
-
`To fix this, either:\n` +
|
|
44
|
-
` 1. Use the same key that was used to create the session\n` +
|
|
45
|
-
` 2. Delete the old session: await session.delete()\n` +
|
|
46
|
-
` 3. Use a persistent key provider (e.g., ConfigKeyProvider)`);
|
|
47
|
-
}
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
existingPiiMap = undefined;
|
|
53
|
-
createdAt = Date.now();
|
|
54
|
-
existingEntityCounts = {};
|
|
55
|
-
}
|
|
56
|
-
// Call the parent anonymizer with existing PII map for ID reuse
|
|
57
|
-
const result = await this.anonymizer.anonymize(text, locale, policy, existingPiiMap);
|
|
58
|
-
// Sessions require a PII map (only available in pseudonymize mode)
|
|
59
|
-
if (result.piiMap === undefined) {
|
|
60
|
-
throw new Error("Session anonymize() failed: no PII map returned.\n\n" +
|
|
61
|
-
"This can happen if the anonymizer is in 'anonymize' mode.\n" +
|
|
62
|
-
"Sessions require 'pseudonymize' mode for PII map storage.");
|
|
63
|
-
}
|
|
64
|
-
// Decrypt the new PII map
|
|
65
|
-
const newPiiMap = await decryptPIIMap(result.piiMap, key);
|
|
66
|
-
// Merge maps: start with existing (if any), add new entries
|
|
67
|
-
const mergedPiiMap = existingPiiMap
|
|
68
|
-
? new Map(existingPiiMap)
|
|
69
|
-
: new Map();
|
|
70
|
-
for (const [k, v] of newPiiMap) {
|
|
71
|
-
mergedPiiMap.set(k, v);
|
|
72
|
-
}
|
|
73
|
-
// Merge entity counts
|
|
74
|
-
const mergedEntityCounts = { ...existingEntityCounts };
|
|
75
|
-
for (const [type, count] of Object.entries(result.stats.countsByType)) {
|
|
76
|
-
mergedEntityCounts[type] = (mergedEntityCounts[type] ?? 0) + count;
|
|
77
|
-
}
|
|
78
|
-
// Re-encrypt the merged PII map
|
|
79
|
-
const encryptedMergedMap = await encryptPIIMap(mergedPiiMap, key);
|
|
80
|
-
// Save the merged PII map to storage
|
|
81
|
-
await this.storage.save(this.sessionId, encryptedMergedMap, {
|
|
82
|
-
createdAt,
|
|
83
|
-
entityCounts: mergedEntityCounts,
|
|
84
|
-
modelVersion: result.stats.modelVersion,
|
|
85
|
-
});
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
async rehydrate(text) {
|
|
89
|
-
// Load from storage
|
|
90
|
-
const stored = await this.storage.load(this.sessionId);
|
|
91
|
-
if (stored === null) {
|
|
92
|
-
throw new Error(`No PII map found for session: ${this.sessionId}. ` +
|
|
93
|
-
`Make sure to call anonymize() before rehydrate().`);
|
|
94
|
-
}
|
|
95
|
-
// Decrypt the PII map
|
|
96
|
-
const key = await this.keyProvider.getKey();
|
|
97
|
-
const piiMap = await decryptPIIMap(stored.piiMap, key);
|
|
98
|
-
// Rehydrate the text
|
|
99
|
-
return rehydrateText(text, piiMap);
|
|
100
|
-
}
|
|
101
|
-
async load() {
|
|
102
|
-
return this.storage.load(this.sessionId);
|
|
103
|
-
}
|
|
104
|
-
async delete() {
|
|
105
|
-
return this.storage.delete(this.sessionId);
|
|
106
|
-
}
|
|
107
|
-
async exists() {
|
|
108
|
-
return this.storage.exists(this.sessionId);
|
|
13
|
+
super(anonymizer, sessionId, storage, keyProvider);
|
|
109
14
|
}
|
|
110
15
|
async createStream(config) {
|
|
111
|
-
// Dynamic import to avoid pulling node:stream into browser bundles
|
|
112
|
-
const { AnonymizerStream } = await import("../streaming/anonymizer-stream.js");
|
|
113
16
|
// Load existing PII map to seed the stream for ID continuity
|
|
114
17
|
let initialPiiMap;
|
|
115
18
|
const existing = await this.storage.load(this.sessionId);
|