@apart-tech/intelligence-core 1.0.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/__tests__/crypto.test.d.ts +2 -0
- package/dist/lib/__tests__/crypto.test.d.ts.map +1 -0
- package/dist/lib/__tests__/crypto.test.js +63 -0
- package/dist/lib/__tests__/crypto.test.js.map +1 -0
- package/dist/lib/crypto.d.ts +14 -0
- package/dist/lib/crypto.d.ts.map +1 -0
- package/dist/lib/crypto.js +33 -0
- package/dist/lib/crypto.js.map +1 -0
- package/dist/services/__tests__/pii-detector-service.test.d.ts +2 -0
- package/dist/services/__tests__/pii-detector-service.test.d.ts.map +1 -0
- package/dist/services/__tests__/pii-detector-service.test.js +75 -0
- package/dist/services/__tests__/pii-detector-service.test.js.map +1 -0
- package/dist/services/__tests__/pii-encryption-service.test.d.ts +2 -0
- package/dist/services/__tests__/pii-encryption-service.test.d.ts.map +1 -0
- package/dist/services/__tests__/pii-encryption-service.test.js +151 -0
- package/dist/services/__tests__/pii-encryption-service.test.js.map +1 -0
- package/dist/services/cleaning-service.d.ts.map +1 -1
- package/dist/services/cleaning-service.js +6 -0
- package/dist/services/cleaning-service.js.map +1 -1
- package/dist/services/node-service.d.ts +10 -1
- package/dist/services/node-service.d.ts.map +1 -1
- package/dist/services/node-service.js +57 -22
- package/dist/services/node-service.js.map +1 -1
- package/dist/services/org-embedding-config-service.d.ts.map +1 -1
- package/dist/services/org-embedding-config-service.js +4 -21
- package/dist/services/org-embedding-config-service.js.map +1 -1
- package/dist/services/org-pii-config-service.d.ts +30 -0
- package/dist/services/org-pii-config-service.d.ts.map +1 -0
- package/dist/services/org-pii-config-service.js +97 -0
- package/dist/services/org-pii-config-service.js.map +1 -0
- package/dist/services/pii-detector-service.d.ts +24 -0
- package/dist/services/pii-detector-service.d.ts.map +1 -0
- package/dist/services/pii-detector-service.js +89 -0
- package/dist/services/pii-detector-service.js.map +1 -0
- package/dist/services/pii-encryption-service.d.ts +55 -0
- package/dist/services/pii-encryption-service.d.ts.map +1 -0
- package/dist/services/pii-encryption-service.js +216 -0
- package/dist/services/pii-encryption-service.js.map +1 -0
- package/package.json +13 -12
- package/prisma/schema.prisma +17 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { PiiSanitizer, defaultPatterns } from "@cdssnc/sanitize-pii";
|
|
2
|
+
/** Additional patterns not included in @cdssnc/sanitize-pii defaults */
|
|
3
|
+
const extraPatterns = [
|
|
4
|
+
{
|
|
5
|
+
name: "email",
|
|
6
|
+
regex: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
|
|
7
|
+
description: "Email address",
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
name: "ssn_us",
|
|
11
|
+
regex: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
12
|
+
description: "US Social Security Number",
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
export class PiiDetectorService {
|
|
16
|
+
sanitizer;
|
|
17
|
+
constructor(customPatterns) {
|
|
18
|
+
this.sanitizer = new PiiSanitizer({
|
|
19
|
+
patterns: [...defaultPatterns, ...extraPatterns, ...(customPatterns ?? [])],
|
|
20
|
+
useDefaultPatterns: false,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Detect PII in a text string. Returns matches with their positions.
|
|
25
|
+
*/
|
|
26
|
+
detect(text) {
|
|
27
|
+
if (!text)
|
|
28
|
+
return { hasPii: false, matches: [] };
|
|
29
|
+
const detections = this.sanitizer.detectPii(text);
|
|
30
|
+
const matches = [];
|
|
31
|
+
for (const detection of detections) {
|
|
32
|
+
// Find all occurrences of this match in the text
|
|
33
|
+
let searchFrom = 0;
|
|
34
|
+
while (searchFrom < text.length) {
|
|
35
|
+
const idx = text.indexOf(detection.match, searchFrom);
|
|
36
|
+
if (idx === -1)
|
|
37
|
+
break;
|
|
38
|
+
matches.push({
|
|
39
|
+
type: detection.pattern,
|
|
40
|
+
value: detection.match,
|
|
41
|
+
start: idx,
|
|
42
|
+
end: idx + detection.match.length,
|
|
43
|
+
});
|
|
44
|
+
searchFrom = idx + detection.match.length;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Sort by position (start offset) and deduplicate overlapping matches
|
|
48
|
+
matches.sort((a, b) => a.start - b.start);
|
|
49
|
+
const deduplicated = deduplicateMatches(matches);
|
|
50
|
+
return {
|
|
51
|
+
hasPii: deduplicated.length > 0,
|
|
52
|
+
matches: deduplicated,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Detect PII in all string values of an object (shallow — top-level keys only).
|
|
57
|
+
*/
|
|
58
|
+
detectInObject(obj) {
|
|
59
|
+
const results = {};
|
|
60
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
61
|
+
if (typeof value === "string") {
|
|
62
|
+
results[key] = this.detect(value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return results;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Remove overlapping matches, keeping the longer (more specific) one.
|
|
70
|
+
*/
|
|
71
|
+
function deduplicateMatches(sorted) {
|
|
72
|
+
if (sorted.length <= 1)
|
|
73
|
+
return sorted;
|
|
74
|
+
const result = [sorted[0]];
|
|
75
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
76
|
+
const prev = result[result.length - 1];
|
|
77
|
+
const curr = sorted[i];
|
|
78
|
+
if (curr.start >= prev.end) {
|
|
79
|
+
result.push(curr);
|
|
80
|
+
}
|
|
81
|
+
else if (curr.end - curr.start > prev.end - prev.start) {
|
|
82
|
+
// Current match is longer — replace previous
|
|
83
|
+
result[result.length - 1] = curr;
|
|
84
|
+
}
|
|
85
|
+
// Otherwise skip (previous match covers this one)
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=pii-detector-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-detector-service.js","sourceRoot":"","sources":["../../src/services/pii-detector-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { PiiDetectorService } from "./pii-detector-service.js";
|
|
2
|
+
export interface PiiEncryptionOptions {
|
|
3
|
+
orgKey?: Buffer;
|
|
4
|
+
mode: "encrypt" | "detect-warn" | "disabled";
|
|
5
|
+
allowedPiiTypes?: string[];
|
|
6
|
+
bypass?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface PiiReport {
|
|
9
|
+
matchCount: number;
|
|
10
|
+
encryptedCount: number;
|
|
11
|
+
bypassedCount: number;
|
|
12
|
+
types: string[];
|
|
13
|
+
mode: string;
|
|
14
|
+
bypassed: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface PiiProcessingResult {
|
|
17
|
+
text: string;
|
|
18
|
+
report: PiiReport;
|
|
19
|
+
}
|
|
20
|
+
export declare class PiiEncryptionService {
|
|
21
|
+
private detector;
|
|
22
|
+
constructor(detector: PiiDetectorService);
|
|
23
|
+
/**
|
|
24
|
+
* Process a text string: detect PII and optionally encrypt matches.
|
|
25
|
+
*/
|
|
26
|
+
processText(text: string, options: PiiEncryptionOptions): PiiProcessingResult;
|
|
27
|
+
/**
|
|
28
|
+
* Process node fields (title, content, metadata) for PII.
|
|
29
|
+
*/
|
|
30
|
+
processNodeFields(input: {
|
|
31
|
+
title: string;
|
|
32
|
+
content: string;
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}, options: PiiEncryptionOptions): {
|
|
35
|
+
title: string;
|
|
36
|
+
content: string;
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
report: PiiReport;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Decrypt all PII tokens in a text string.
|
|
42
|
+
*/
|
|
43
|
+
decryptText(text: string, orgKey: Buffer): string;
|
|
44
|
+
/**
|
|
45
|
+
* Decrypt PII tokens in node fields.
|
|
46
|
+
*/
|
|
47
|
+
decryptNodeFields<T extends {
|
|
48
|
+
title: string;
|
|
49
|
+
content: string;
|
|
50
|
+
metadata: unknown;
|
|
51
|
+
}>(node: T, orgKey: Buffer): T;
|
|
52
|
+
private processMetadata;
|
|
53
|
+
private decryptMetadataValues;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=pii-encryption-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-encryption-service.d.ts","sourceRoot":"","sources":["../../src/services/pii-encryption-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AAKD,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,kBAAkB;IAEhD;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,mBAAmB;IAkE7E;;OAEG;IACH,iBAAiB,CACf,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAC7E,OAAO,EAAE,oBAAoB,GAC5B;QACD,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACnC,MAAM,EAAE,SAAS,CAAC;KACnB;IAkED;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAWjD;;OAEG;IACH,iBAAiB,CAAC,CAAC,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,EAC/E,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,MAAM,GACb,CAAC;IASJ,OAAO,CAAC,eAAe;IAyDvB,OAAO,CAAC,qBAAqB;CAqB9B"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { encryptAesGcm, decryptAesGcm } from "../lib/crypto.js";
|
|
2
|
+
const PII_TOKEN_REGEX = /\[PII:(\w+):([A-Za-z0-9+/=]+:[A-Za-z0-9+/=]+:[A-Za-z0-9+/=]+)\]/g;
|
|
3
|
+
const MAX_METADATA_DEPTH = 5;
|
|
4
|
+
export class PiiEncryptionService {
|
|
5
|
+
detector;
|
|
6
|
+
constructor(detector) {
|
|
7
|
+
this.detector = detector;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Process a text string: detect PII and optionally encrypt matches.
|
|
11
|
+
*/
|
|
12
|
+
processText(text, options) {
|
|
13
|
+
const emptyReport = {
|
|
14
|
+
matchCount: 0,
|
|
15
|
+
encryptedCount: 0,
|
|
16
|
+
bypassedCount: 0,
|
|
17
|
+
types: [],
|
|
18
|
+
mode: options.mode,
|
|
19
|
+
bypassed: options.bypass ?? false,
|
|
20
|
+
};
|
|
21
|
+
if (options.mode === "disabled") {
|
|
22
|
+
return { text, report: emptyReport };
|
|
23
|
+
}
|
|
24
|
+
const detection = this.detector.detect(text);
|
|
25
|
+
if (!detection.hasPii) {
|
|
26
|
+
return { text, report: emptyReport };
|
|
27
|
+
}
|
|
28
|
+
const types = [...new Set(detection.matches.map((m) => m.type))];
|
|
29
|
+
const allowedTypes = new Set(options.allowedPiiTypes ?? []);
|
|
30
|
+
// Filter out matches whose type is explicitly allowed
|
|
31
|
+
const matchesToProcess = detection.matches.filter((m) => !allowedTypes.has(m.type));
|
|
32
|
+
const skippedCount = detection.matches.length - matchesToProcess.length;
|
|
33
|
+
if (options.mode === "detect-warn" || options.bypass || !options.orgKey) {
|
|
34
|
+
return {
|
|
35
|
+
text,
|
|
36
|
+
report: {
|
|
37
|
+
matchCount: detection.matches.length,
|
|
38
|
+
encryptedCount: 0,
|
|
39
|
+
bypassedCount: detection.matches.length,
|
|
40
|
+
types,
|
|
41
|
+
mode: options.mode,
|
|
42
|
+
bypassed: options.bypass ?? (options.mode === "detect-warn"),
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Mode is "encrypt" — replace PII matches with encrypted tokens
|
|
47
|
+
// Process matches in reverse order to preserve string offsets
|
|
48
|
+
let result = text;
|
|
49
|
+
let encryptedCount = 0;
|
|
50
|
+
const reversedMatches = [...matchesToProcess].reverse();
|
|
51
|
+
for (const match of reversedMatches) {
|
|
52
|
+
const encrypted = encryptAesGcm(match.value, options.orgKey);
|
|
53
|
+
const token = `[PII:${match.type}:${encrypted}]`;
|
|
54
|
+
result = result.slice(0, match.start) + token + result.slice(match.end);
|
|
55
|
+
encryptedCount++;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
text: result,
|
|
59
|
+
report: {
|
|
60
|
+
matchCount: detection.matches.length,
|
|
61
|
+
encryptedCount,
|
|
62
|
+
bypassedCount: skippedCount,
|
|
63
|
+
types,
|
|
64
|
+
mode: options.mode,
|
|
65
|
+
bypassed: false,
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Process node fields (title, content, metadata) for PII.
|
|
71
|
+
*/
|
|
72
|
+
processNodeFields(input, options) {
|
|
73
|
+
if (options.mode === "disabled") {
|
|
74
|
+
return {
|
|
75
|
+
...input,
|
|
76
|
+
report: {
|
|
77
|
+
matchCount: 0,
|
|
78
|
+
encryptedCount: 0,
|
|
79
|
+
bypassedCount: 0,
|
|
80
|
+
types: [],
|
|
81
|
+
mode: "disabled",
|
|
82
|
+
bypassed: false,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const titleResult = this.processText(input.title, options);
|
|
87
|
+
const contentResult = this.processText(input.content, options);
|
|
88
|
+
let processedMetadata = input.metadata;
|
|
89
|
+
let metadataMatchCount = 0;
|
|
90
|
+
let metadataEncryptedCount = 0;
|
|
91
|
+
const metadataTypes = [];
|
|
92
|
+
if (input.metadata && options.mode === "encrypt" && !options.bypass && options.orgKey) {
|
|
93
|
+
const { result, matchCount, encryptedCount, types } = this.processMetadata(input.metadata, options, 0);
|
|
94
|
+
processedMetadata = result;
|
|
95
|
+
metadataMatchCount = matchCount;
|
|
96
|
+
metadataEncryptedCount = encryptedCount;
|
|
97
|
+
metadataTypes.push(...types);
|
|
98
|
+
}
|
|
99
|
+
const allTypes = [
|
|
100
|
+
...new Set([
|
|
101
|
+
...titleResult.report.types,
|
|
102
|
+
...contentResult.report.types,
|
|
103
|
+
...metadataTypes,
|
|
104
|
+
]),
|
|
105
|
+
];
|
|
106
|
+
return {
|
|
107
|
+
title: titleResult.text,
|
|
108
|
+
content: contentResult.text,
|
|
109
|
+
metadata: processedMetadata,
|
|
110
|
+
report: {
|
|
111
|
+
matchCount: titleResult.report.matchCount +
|
|
112
|
+
contentResult.report.matchCount +
|
|
113
|
+
metadataMatchCount,
|
|
114
|
+
encryptedCount: titleResult.report.encryptedCount +
|
|
115
|
+
contentResult.report.encryptedCount +
|
|
116
|
+
metadataEncryptedCount,
|
|
117
|
+
bypassedCount: titleResult.report.bypassedCount +
|
|
118
|
+
contentResult.report.bypassedCount,
|
|
119
|
+
types: allTypes,
|
|
120
|
+
mode: options.mode,
|
|
121
|
+
bypassed: options.bypass ?? false,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Decrypt all PII tokens in a text string.
|
|
127
|
+
*/
|
|
128
|
+
decryptText(text, orgKey) {
|
|
129
|
+
return text.replace(PII_TOKEN_REGEX, (_fullMatch, _type, encrypted) => {
|
|
130
|
+
try {
|
|
131
|
+
return decryptAesGcm(encrypted, orgKey);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// If decryption fails (wrong key, corrupted), leave token as-is
|
|
135
|
+
return _fullMatch;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Decrypt PII tokens in node fields.
|
|
141
|
+
*/
|
|
142
|
+
decryptNodeFields(node, orgKey) {
|
|
143
|
+
return {
|
|
144
|
+
...node,
|
|
145
|
+
title: this.decryptText(node.title, orgKey),
|
|
146
|
+
content: this.decryptText(node.content, orgKey),
|
|
147
|
+
metadata: this.decryptMetadataValues(node.metadata, orgKey, 0),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
processMetadata(value, options, depth) {
|
|
151
|
+
if (depth > MAX_METADATA_DEPTH) {
|
|
152
|
+
return { result: value, matchCount: 0, encryptedCount: 0, types: [] };
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === "string") {
|
|
155
|
+
const processed = this.processText(value, options);
|
|
156
|
+
return {
|
|
157
|
+
result: processed.text,
|
|
158
|
+
matchCount: processed.report.matchCount,
|
|
159
|
+
encryptedCount: processed.report.encryptedCount,
|
|
160
|
+
types: processed.report.types,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
if (Array.isArray(value)) {
|
|
164
|
+
let totalMatches = 0;
|
|
165
|
+
let totalEncrypted = 0;
|
|
166
|
+
const allTypes = [];
|
|
167
|
+
const result = value.map((item) => {
|
|
168
|
+
const processed = this.processMetadata(item, options, depth + 1);
|
|
169
|
+
totalMatches += processed.matchCount;
|
|
170
|
+
totalEncrypted += processed.encryptedCount;
|
|
171
|
+
allTypes.push(...processed.types);
|
|
172
|
+
return processed.result;
|
|
173
|
+
});
|
|
174
|
+
return { result, matchCount: totalMatches, encryptedCount: totalEncrypted, types: allTypes };
|
|
175
|
+
}
|
|
176
|
+
if (value !== null && typeof value === "object") {
|
|
177
|
+
let totalMatches = 0;
|
|
178
|
+
let totalEncrypted = 0;
|
|
179
|
+
const allTypes = [];
|
|
180
|
+
const result = {};
|
|
181
|
+
for (const [key, val] of Object.entries(value)) {
|
|
182
|
+
// Skip internal PII report field
|
|
183
|
+
if (key === "_piiReport") {
|
|
184
|
+
result[key] = val;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const processed = this.processMetadata(val, options, depth + 1);
|
|
188
|
+
result[key] = processed.result;
|
|
189
|
+
totalMatches += processed.matchCount;
|
|
190
|
+
totalEncrypted += processed.encryptedCount;
|
|
191
|
+
allTypes.push(...processed.types);
|
|
192
|
+
}
|
|
193
|
+
return { result, matchCount: totalMatches, encryptedCount: totalEncrypted, types: allTypes };
|
|
194
|
+
}
|
|
195
|
+
return { result: value, matchCount: 0, encryptedCount: 0, types: [] };
|
|
196
|
+
}
|
|
197
|
+
decryptMetadataValues(value, orgKey, depth) {
|
|
198
|
+
if (depth > MAX_METADATA_DEPTH)
|
|
199
|
+
return value;
|
|
200
|
+
if (typeof value === "string") {
|
|
201
|
+
return this.decryptText(value, orgKey);
|
|
202
|
+
}
|
|
203
|
+
if (Array.isArray(value)) {
|
|
204
|
+
return value.map((item) => this.decryptMetadataValues(item, orgKey, depth + 1));
|
|
205
|
+
}
|
|
206
|
+
if (value !== null && typeof value === "object") {
|
|
207
|
+
const result = {};
|
|
208
|
+
for (const [key, val] of Object.entries(value)) {
|
|
209
|
+
result[key] = this.decryptMetadataValues(val, orgKey, depth + 1);
|
|
210
|
+
}
|
|
211
|
+
return result;
|
|
212
|
+
}
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=pii-encryption-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-encryption-service.js","sourceRoot":"","sources":["../../src/services/pii-encryption-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apart-tech/intelligence-core",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Core library: database, services, and providers for Apart Intelligence",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,7 +18,18 @@
|
|
|
18
18
|
"publishConfig": {
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"postinstall": "prisma generate --schema ./prisma/schema.prisma 2>/dev/null || true",
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"dev": "tsc --watch",
|
|
25
|
+
"lint": "tsc --noEmit",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"db:generate": "prisma generate",
|
|
28
|
+
"db:migrate": "prisma migrate dev",
|
|
29
|
+
"db:push": "prisma db push"
|
|
30
|
+
},
|
|
21
31
|
"dependencies": {
|
|
32
|
+
"@cdssnc/sanitize-pii": "^2.1.2",
|
|
22
33
|
"@prisma/client": "^6.6.0",
|
|
23
34
|
"@prisma/extension-accelerate": "^3.0.1",
|
|
24
35
|
"prisma": "^6.6.0",
|
|
@@ -29,15 +40,5 @@
|
|
|
29
40
|
"@types/node": "^25.5.0",
|
|
30
41
|
"typescript": "^5.7.0",
|
|
31
42
|
"vitest": "^3.0.0"
|
|
32
|
-
},
|
|
33
|
-
"scripts": {
|
|
34
|
-
"postinstall": "prisma generate --schema ./prisma/schema.prisma 2>/dev/null || true",
|
|
35
|
-
"build": "tsc",
|
|
36
|
-
"dev": "tsc --watch",
|
|
37
|
-
"lint": "tsc --noEmit",
|
|
38
|
-
"test": "vitest run",
|
|
39
|
-
"db:generate": "prisma generate",
|
|
40
|
-
"db:migrate": "prisma migrate dev",
|
|
41
|
-
"db:push": "prisma db push"
|
|
42
43
|
}
|
|
43
|
-
}
|
|
44
|
+
}
|
package/prisma/schema.prisma
CHANGED
|
@@ -20,6 +20,7 @@ model Organization {
|
|
|
20
20
|
apiKeys ApiKey[]
|
|
21
21
|
workspaces Workspace[]
|
|
22
22
|
embeddingConfig OrgEmbeddingConfig?
|
|
23
|
+
piiConfig OrgPiiConfig?
|
|
23
24
|
|
|
24
25
|
@@map("organizations")
|
|
25
26
|
}
|
|
@@ -39,6 +40,21 @@ model OrgEmbeddingConfig {
|
|
|
39
40
|
@@map("org_embedding_config")
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
model OrgPiiConfig {
|
|
44
|
+
id String @id @default(uuid()) @db.Uuid
|
|
45
|
+
organizationId String @unique @map("organization_id") @db.Uuid
|
|
46
|
+
mode String @default("encrypt") @db.VarChar(20)
|
|
47
|
+
piiKeyEncrypted String @map("pii_key_encrypted") @db.Text
|
|
48
|
+
allowedPiiTypes Json @default("[]") @map("allowed_pii_types")
|
|
49
|
+
allowBypass Boolean @default(false) @map("allow_bypass")
|
|
50
|
+
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz
|
|
51
|
+
updatedBy String @default("api") @map("updated_by") @db.VarChar(255)
|
|
52
|
+
|
|
53
|
+
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
|
54
|
+
|
|
55
|
+
@@map("org_pii_config")
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
model Domain {
|
|
43
59
|
id String @id @default(uuid()) @db.Uuid
|
|
44
60
|
name String @db.VarChar(200)
|
|
@@ -75,6 +91,7 @@ model Node {
|
|
|
75
91
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
|
|
76
92
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz
|
|
77
93
|
version Int @default(1)
|
|
94
|
+
hasPii Boolean @default(false) @map("has_pii")
|
|
78
95
|
domainId String? @map("domain_id") @db.Uuid
|
|
79
96
|
organizationId String @map("organization_id") @db.Uuid
|
|
80
97
|
|