@apart-tech/intelligence-core 1.0.6 → 1.1.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/node-service.d.ts +11 -1
- package/dist/services/node-service.d.ts.map +1 -1
- package/dist/services/node-service.js +90 -27
- 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 +2 -1
- package/prisma/schema.prisma +17 -0
|
@@ -2,28 +2,36 @@ import { tenantWhere, SINGLE_TENANT_ORG_ID } from "../db/tenant.js";
|
|
|
2
2
|
export class NodeService {
|
|
3
3
|
db;
|
|
4
4
|
embeddings;
|
|
5
|
+
piiEncryption;
|
|
6
|
+
piiOptions;
|
|
5
7
|
tenantCtx;
|
|
6
|
-
constructor(db, embeddings, tenantCtx) {
|
|
8
|
+
constructor(db, embeddings, tenantCtx, piiEncryption, piiOptions) {
|
|
7
9
|
this.db = db;
|
|
8
10
|
this.embeddings = embeddings;
|
|
11
|
+
this.piiEncryption = piiEncryption;
|
|
12
|
+
this.piiOptions = piiOptions;
|
|
9
13
|
this.tenantCtx = tenantCtx ?? { organizationId: SINGLE_TENANT_ORG_ID };
|
|
10
14
|
}
|
|
11
15
|
async create(input) {
|
|
16
|
+
// Generate embedding from ORIGINAL text (before PII encryption)
|
|
12
17
|
const embedding = await this.embeddings.embed(`${input.title}\n\n${input.content}`);
|
|
13
18
|
const embeddingStr = `[${embedding.join(",")}]`;
|
|
19
|
+
// Process PII if configured
|
|
20
|
+
const { title, content, metadata, hasPii } = this.applyPii(input.title, input.content, input.metadata);
|
|
14
21
|
const node = await this.db.node.create({
|
|
15
22
|
data: {
|
|
16
23
|
type: input.type,
|
|
17
|
-
title
|
|
18
|
-
content
|
|
19
|
-
metadata: (
|
|
24
|
+
title,
|
|
25
|
+
content,
|
|
26
|
+
metadata: (metadata ?? {}),
|
|
20
27
|
status: input.status ?? "draft",
|
|
21
28
|
createdBy: input.createdBy,
|
|
22
29
|
domainId: input.domainId ?? null,
|
|
30
|
+
hasPii,
|
|
23
31
|
organizationId: this.tenantCtx.organizationId,
|
|
24
32
|
},
|
|
25
33
|
});
|
|
26
|
-
// Update embedding and tsvector via raw SQL
|
|
34
|
+
// Update embedding and tsvector via raw SQL using ORIGINAL text
|
|
27
35
|
const orgFilter = tenantWhere(this.tenantCtx);
|
|
28
36
|
await this.db.$executeRaw `
|
|
29
37
|
UPDATE nodes
|
|
@@ -36,15 +44,17 @@ export class NodeService {
|
|
|
36
44
|
}
|
|
37
45
|
async createWithEmbedding(input, embedding) {
|
|
38
46
|
const embeddingStr = `[${embedding.join(",")}]`;
|
|
47
|
+
const { title, content, metadata, hasPii } = this.applyPii(input.title, input.content, input.metadata);
|
|
39
48
|
const node = await this.db.node.create({
|
|
40
49
|
data: {
|
|
41
50
|
type: input.type,
|
|
42
|
-
title
|
|
43
|
-
content
|
|
44
|
-
metadata: (
|
|
51
|
+
title,
|
|
52
|
+
content,
|
|
53
|
+
metadata: (metadata ?? {}),
|
|
45
54
|
status: input.status ?? "draft",
|
|
46
55
|
createdBy: input.createdBy,
|
|
47
56
|
domainId: input.domainId ?? null,
|
|
57
|
+
hasPii,
|
|
48
58
|
organizationId: this.tenantCtx.organizationId,
|
|
49
59
|
},
|
|
50
60
|
});
|
|
@@ -62,16 +72,18 @@ export class NodeService {
|
|
|
62
72
|
const existing = await this.getById(id);
|
|
63
73
|
if (!existing)
|
|
64
74
|
return null;
|
|
65
|
-
const
|
|
66
|
-
const
|
|
75
|
+
const originalTitle = input.title ?? existing.title;
|
|
76
|
+
const originalContent = input.content ?? existing.content;
|
|
77
|
+
const { title, content, metadata, hasPii } = this.applyPii(input.title ?? existing.title, input.content ?? existing.content, input.metadata);
|
|
67
78
|
const updated = await this.db.node.update({
|
|
68
79
|
where: { id },
|
|
69
80
|
data: {
|
|
70
|
-
...(input.title !== undefined && { title
|
|
71
|
-
...(input.content !== undefined && { content
|
|
72
|
-
...(input.metadata !== undefined && { metadata:
|
|
81
|
+
...(input.title !== undefined && { title }),
|
|
82
|
+
...(input.content !== undefined && { content }),
|
|
83
|
+
...(input.metadata !== undefined && { metadata: metadata }),
|
|
73
84
|
...(input.type !== undefined && { type: input.type }),
|
|
74
85
|
...(input.domainId !== undefined && { domainId: input.domainId }),
|
|
86
|
+
hasPii,
|
|
75
87
|
updatedAt: new Date(),
|
|
76
88
|
version: existing.version + 1,
|
|
77
89
|
},
|
|
@@ -81,42 +93,67 @@ export class NodeService {
|
|
|
81
93
|
await this.db.$executeRaw `
|
|
82
94
|
UPDATE nodes
|
|
83
95
|
SET embedding = ${embeddingStr}::vector,
|
|
84
|
-
search_vector = to_tsvector('english', ${
|
|
96
|
+
search_vector = to_tsvector('english', ${originalTitle} || ' ' || ${originalContent})
|
|
85
97
|
WHERE id = ${id}::uuid
|
|
86
98
|
AND ${orgFilter}
|
|
87
99
|
`;
|
|
88
100
|
return updated;
|
|
89
101
|
}
|
|
102
|
+
async resolveId(idOrPrefix) {
|
|
103
|
+
// Full UUID: use as-is
|
|
104
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(idOrPrefix)) {
|
|
105
|
+
return idOrPrefix;
|
|
106
|
+
}
|
|
107
|
+
// Short prefix: find matching nodes
|
|
108
|
+
const orgFilter = tenantWhere(this.tenantCtx);
|
|
109
|
+
const matches = await this.db.$queryRaw `
|
|
110
|
+
SELECT id FROM nodes
|
|
111
|
+
WHERE id::text LIKE ${idOrPrefix + '%'}
|
|
112
|
+
AND ${orgFilter}
|
|
113
|
+
LIMIT 2
|
|
114
|
+
`;
|
|
115
|
+
if (matches.length === 0)
|
|
116
|
+
return null;
|
|
117
|
+
if (matches.length > 1) {
|
|
118
|
+
throw new Error(`Ambiguous ID prefix "${idOrPrefix}" — matches multiple nodes. Use more characters.`);
|
|
119
|
+
}
|
|
120
|
+
return matches[0].id;
|
|
121
|
+
}
|
|
90
122
|
async getById(id) {
|
|
91
|
-
|
|
123
|
+
const resolvedId = await this.resolveId(id);
|
|
124
|
+
if (!resolvedId)
|
|
125
|
+
return null;
|
|
126
|
+
return this.db.node.findUnique({ where: { id: resolvedId } });
|
|
92
127
|
}
|
|
93
128
|
async update(id, input) {
|
|
94
129
|
const existing = await this.getById(id);
|
|
95
130
|
if (!existing)
|
|
96
131
|
return null;
|
|
97
|
-
const
|
|
98
|
-
const
|
|
132
|
+
const originalTitle = input.title ?? existing.title;
|
|
133
|
+
const originalContent = input.content ?? existing.content;
|
|
134
|
+
const { title, content, metadata, hasPii } = this.applyPii(originalTitle, originalContent, input.metadata);
|
|
99
135
|
const updated = await this.db.node.update({
|
|
100
136
|
where: { id },
|
|
101
137
|
data: {
|
|
102
|
-
...(input.title !== undefined && { title
|
|
103
|
-
...(input.content !== undefined && { content
|
|
104
|
-
...(input.metadata !== undefined && { metadata:
|
|
138
|
+
...(input.title !== undefined && { title }),
|
|
139
|
+
...(input.content !== undefined && { content }),
|
|
140
|
+
...(input.metadata !== undefined && { metadata: metadata }),
|
|
105
141
|
...(input.type !== undefined && { type: input.type }),
|
|
106
142
|
...(input.domainId !== undefined && { domainId: input.domainId }),
|
|
143
|
+
hasPii,
|
|
107
144
|
updatedAt: new Date(),
|
|
108
145
|
version: existing.version + 1,
|
|
109
146
|
},
|
|
110
147
|
});
|
|
111
|
-
// Re-embed and update tsvector if content changed
|
|
148
|
+
// Re-embed and update tsvector if content changed (use ORIGINAL text)
|
|
112
149
|
if (input.title || input.content) {
|
|
113
|
-
const embedding = await this.embeddings.embed(`${
|
|
150
|
+
const embedding = await this.embeddings.embed(`${originalTitle}\n\n${originalContent}`);
|
|
114
151
|
const embeddingStr = `[${embedding.join(",")}]`;
|
|
115
152
|
const orgFilter = tenantWhere(this.tenantCtx);
|
|
116
153
|
await this.db.$executeRaw `
|
|
117
154
|
UPDATE nodes
|
|
118
155
|
SET embedding = ${embeddingStr}::vector,
|
|
119
|
-
search_vector = to_tsvector('english', ${
|
|
156
|
+
search_vector = to_tsvector('english', ${originalTitle} || ' ' || ${originalContent})
|
|
120
157
|
WHERE id = ${id}::uuid
|
|
121
158
|
AND ${orgFilter}
|
|
122
159
|
`;
|
|
@@ -125,8 +162,11 @@ export class NodeService {
|
|
|
125
162
|
}
|
|
126
163
|
async setStatus(id, status) {
|
|
127
164
|
try {
|
|
165
|
+
const resolvedId = await this.resolveId(id);
|
|
166
|
+
if (!resolvedId)
|
|
167
|
+
return null;
|
|
128
168
|
return await this.db.node.update({
|
|
129
|
-
where: { id },
|
|
169
|
+
where: { id: resolvedId },
|
|
130
170
|
data: { status, updatedAt: new Date() },
|
|
131
171
|
});
|
|
132
172
|
}
|
|
@@ -143,11 +183,13 @@ export class NodeService {
|
|
|
143
183
|
}
|
|
144
184
|
async delete(id) {
|
|
145
185
|
try {
|
|
146
|
-
|
|
186
|
+
const resolvedId = await this.resolveId(id);
|
|
187
|
+
if (!resolvedId)
|
|
188
|
+
return false;
|
|
147
189
|
await this.db.edge.deleteMany({
|
|
148
|
-
where: { OR: [{ sourceNodeId:
|
|
190
|
+
where: { OR: [{ sourceNodeId: resolvedId }, { targetNodeId: resolvedId }] },
|
|
149
191
|
});
|
|
150
|
-
await this.db.node.delete({ where: { id } });
|
|
192
|
+
await this.db.node.delete({ where: { id: resolvedId } });
|
|
151
193
|
return true;
|
|
152
194
|
}
|
|
153
195
|
catch {
|
|
@@ -162,5 +204,26 @@ export class NodeService {
|
|
|
162
204
|
});
|
|
163
205
|
return result.map((r) => ({ type: r.type, count: r._count.type }));
|
|
164
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Apply PII detection/encryption to node fields.
|
|
209
|
+
* Returns processed fields and whether PII was found.
|
|
210
|
+
*/
|
|
211
|
+
applyPii(title, content, metadata) {
|
|
212
|
+
if (!this.piiEncryption || !this.piiOptions || this.piiOptions.mode === "disabled") {
|
|
213
|
+
return { title, content, metadata, hasPii: false };
|
|
214
|
+
}
|
|
215
|
+
const result = this.piiEncryption.processNodeFields({ title, content, metadata }, this.piiOptions);
|
|
216
|
+
// Store the PII report in metadata
|
|
217
|
+
const finalMetadata = {
|
|
218
|
+
...(result.metadata ?? metadata ?? {}),
|
|
219
|
+
...(result.report.matchCount > 0 ? { _piiReport: result.report } : {}),
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
title: result.title,
|
|
223
|
+
content: result.content,
|
|
224
|
+
metadata: finalMetadata,
|
|
225
|
+
hasPii: result.report.matchCount > 0,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
165
228
|
}
|
|
166
229
|
//# sourceMappingURL=node-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-service.js","sourceRoot":"","sources":["../../src/services/node-service.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAsB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"node-service.js","sourceRoot":"","sources":["../../src/services/node-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"org-embedding-config-service.d.ts","sourceRoot":"","sources":["../../src/services/org-embedding-config-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"org-embedding-config-service.d.ts","sourceRoot":"","sources":["../../src/services/org-embedding-config-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAgBnD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAA0B,SAAQ,kBAAkB;IACnE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,yBAAyB;IACxB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE9B,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAc/D,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,IAAI,CAAC;IAe7E,GAAG,CACP,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACjG,OAAO,CAAC,kBAAkB,CAAC;IA8BxB,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAQvD"}
|
|
@@ -1,30 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const ALGORITHM = "aes-256-gcm";
|
|
3
|
-
const IV_LENGTH = 16;
|
|
4
|
-
const TAG_LENGTH = 16;
|
|
1
|
+
import { encryptAesGcm, decryptAesGcm, deriveKey } from "../lib/crypto.js";
|
|
5
2
|
function getEncryptionKey() {
|
|
6
3
|
const secret = process.env.EMBEDDING_KEY_SECRET ?? "apart-default-embedding-key-secret-change-me";
|
|
7
|
-
|
|
8
|
-
return createHash("sha256").update(secret).digest();
|
|
4
|
+
return deriveKey(secret);
|
|
9
5
|
}
|
|
10
6
|
function encrypt(plaintext) {
|
|
11
|
-
|
|
12
|
-
const iv = randomBytes(IV_LENGTH);
|
|
13
|
-
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
14
|
-
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
15
|
-
const tag = cipher.getAuthTag();
|
|
16
|
-
// Format: iv:tag:ciphertext (all base64)
|
|
17
|
-
return `${iv.toString("base64")}:${tag.toString("base64")}:${encrypted.toString("base64")}`;
|
|
7
|
+
return encryptAesGcm(plaintext, getEncryptionKey());
|
|
18
8
|
}
|
|
19
9
|
function decrypt(encoded) {
|
|
20
|
-
|
|
21
|
-
const [ivB64, tagB64, ciphertextB64] = encoded.split(":");
|
|
22
|
-
const iv = Buffer.from(ivB64, "base64");
|
|
23
|
-
const tag = Buffer.from(tagB64, "base64");
|
|
24
|
-
const ciphertext = Buffer.from(ciphertextB64, "base64");
|
|
25
|
-
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
26
|
-
decipher.setAuthTag(tag);
|
|
27
|
-
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
10
|
+
return decryptAesGcm(encoded, getEncryptionKey());
|
|
28
11
|
}
|
|
29
12
|
export class OrgEmbeddingConfigService {
|
|
30
13
|
db;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"org-embedding-config-service.js","sourceRoot":"","sources":["../../src/services/org-embedding-config-service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"org-embedding-config-service.js","sourceRoot":"","sources":["../../src/services/org-embedding-config-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PrismaClient } from "@prisma/client";
|
|
2
|
+
export type PiiMode = "encrypt" | "detect-warn" | "disabled";
|
|
3
|
+
export interface OrgPiiConfig {
|
|
4
|
+
mode: PiiMode;
|
|
5
|
+
allowedPiiTypes: string[];
|
|
6
|
+
allowBypass: boolean;
|
|
7
|
+
updatedAt: Date;
|
|
8
|
+
updatedBy: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OrgPiiConfigWithKey extends OrgPiiConfig {
|
|
11
|
+
piiKey: Buffer;
|
|
12
|
+
}
|
|
13
|
+
export declare class OrgPiiConfigService {
|
|
14
|
+
private db;
|
|
15
|
+
constructor(db: PrismaClient);
|
|
16
|
+
get(organizationId: string): Promise<OrgPiiConfig | null>;
|
|
17
|
+
getWithKey(organizationId: string): Promise<OrgPiiConfigWithKey | null>;
|
|
18
|
+
set(organizationId: string, input: {
|
|
19
|
+
mode: PiiMode;
|
|
20
|
+
allowedPiiTypes?: string[];
|
|
21
|
+
allowBypass?: boolean;
|
|
22
|
+
updatedBy?: string;
|
|
23
|
+
}): Promise<OrgPiiConfig>;
|
|
24
|
+
delete(organizationId: string): Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Generate a random 32-byte encryption key.
|
|
27
|
+
*/
|
|
28
|
+
generateKey(): Buffer;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=org-pii-config-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-pii-config-service.d.ts","sourceRoot":"","sources":["../../src/services/org-pii-config-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAgBnD,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAoB,SAAQ,YAAY;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,mBAAmB;IAClB,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAE9B,GAAG,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAczD,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAevE,GAAG,CACP,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE;QACL,IAAI,EAAE,OAAO,CAAC;QACd,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GACA,OAAO,CAAC,YAAY,CAAC;IAsClB,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAStD;;OAEG;IACH,WAAW,IAAI,MAAM;CAGtB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import { encryptAesGcm, decryptAesGcm, deriveKey } from "../lib/crypto.js";
|
|
3
|
+
function getPiiEncryptionKey() {
|
|
4
|
+
const secret = process.env.PII_KEY_SECRET ?? "apart-default-pii-key-secret-change-me";
|
|
5
|
+
return deriveKey(secret);
|
|
6
|
+
}
|
|
7
|
+
function encryptPiiKey(plaintext) {
|
|
8
|
+
return encryptAesGcm(plaintext, getPiiEncryptionKey());
|
|
9
|
+
}
|
|
10
|
+
function decryptPiiKey(encoded) {
|
|
11
|
+
return decryptAesGcm(encoded, getPiiEncryptionKey());
|
|
12
|
+
}
|
|
13
|
+
export class OrgPiiConfigService {
|
|
14
|
+
db;
|
|
15
|
+
constructor(db) {
|
|
16
|
+
this.db = db;
|
|
17
|
+
}
|
|
18
|
+
async get(organizationId) {
|
|
19
|
+
const config = await this.db.orgPiiConfig.findUnique({
|
|
20
|
+
where: { organizationId },
|
|
21
|
+
});
|
|
22
|
+
if (!config)
|
|
23
|
+
return null;
|
|
24
|
+
return {
|
|
25
|
+
mode: config.mode,
|
|
26
|
+
allowedPiiTypes: config.allowedPiiTypes,
|
|
27
|
+
allowBypass: config.allowBypass,
|
|
28
|
+
updatedAt: config.updatedAt,
|
|
29
|
+
updatedBy: config.updatedBy,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async getWithKey(organizationId) {
|
|
33
|
+
const config = await this.db.orgPiiConfig.findUnique({
|
|
34
|
+
where: { organizationId },
|
|
35
|
+
});
|
|
36
|
+
if (!config)
|
|
37
|
+
return null;
|
|
38
|
+
return {
|
|
39
|
+
mode: config.mode,
|
|
40
|
+
allowedPiiTypes: config.allowedPiiTypes,
|
|
41
|
+
allowBypass: config.allowBypass,
|
|
42
|
+
piiKey: Buffer.from(decryptPiiKey(config.piiKeyEncrypted), "hex"),
|
|
43
|
+
updatedAt: config.updatedAt,
|
|
44
|
+
updatedBy: config.updatedBy,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async set(organizationId, input) {
|
|
48
|
+
// Check if config already exists to preserve existing key
|
|
49
|
+
const existing = await this.db.orgPiiConfig.findUnique({
|
|
50
|
+
where: { organizationId },
|
|
51
|
+
});
|
|
52
|
+
const piiKeyEncrypted = existing
|
|
53
|
+
? existing.piiKeyEncrypted
|
|
54
|
+
: encryptPiiKey(this.generateKey().toString("hex"));
|
|
55
|
+
const config = await this.db.orgPiiConfig.upsert({
|
|
56
|
+
where: { organizationId },
|
|
57
|
+
create: {
|
|
58
|
+
organizationId,
|
|
59
|
+
mode: input.mode,
|
|
60
|
+
piiKeyEncrypted,
|
|
61
|
+
allowedPiiTypes: (input.allowedPiiTypes ?? []),
|
|
62
|
+
allowBypass: input.allowBypass ?? false,
|
|
63
|
+
updatedBy: input.updatedBy ?? "api",
|
|
64
|
+
},
|
|
65
|
+
update: {
|
|
66
|
+
mode: input.mode,
|
|
67
|
+
allowedPiiTypes: (input.allowedPiiTypes ?? existing?.allowedPiiTypes ?? []),
|
|
68
|
+
allowBypass: input.allowBypass ?? existing?.allowBypass ?? false,
|
|
69
|
+
updatedAt: new Date(),
|
|
70
|
+
updatedBy: input.updatedBy ?? "api",
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
return {
|
|
74
|
+
mode: config.mode,
|
|
75
|
+
allowedPiiTypes: config.allowedPiiTypes,
|
|
76
|
+
allowBypass: config.allowBypass,
|
|
77
|
+
updatedAt: config.updatedAt,
|
|
78
|
+
updatedBy: config.updatedBy,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async delete(organizationId) {
|
|
82
|
+
try {
|
|
83
|
+
await this.db.orgPiiConfig.delete({ where: { organizationId } });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Generate a random 32-byte encryption key.
|
|
92
|
+
*/
|
|
93
|
+
generateKey() {
|
|
94
|
+
return randomBytes(32);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=org-pii-config-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-pii-config-service.js","sourceRoot":"","sources":["../../src/services/org-pii-config-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { PiiPattern } from "@cdssnc/sanitize-pii";
|
|
2
|
+
export interface PiiMatch {
|
|
3
|
+
type: string;
|
|
4
|
+
value: string;
|
|
5
|
+
start: number;
|
|
6
|
+
end: number;
|
|
7
|
+
}
|
|
8
|
+
export interface PiiDetectionResult {
|
|
9
|
+
hasPii: boolean;
|
|
10
|
+
matches: PiiMatch[];
|
|
11
|
+
}
|
|
12
|
+
export declare class PiiDetectorService {
|
|
13
|
+
private sanitizer;
|
|
14
|
+
constructor(customPatterns?: PiiPattern[]);
|
|
15
|
+
/**
|
|
16
|
+
* Detect PII in a text string. Returns matches with their positions.
|
|
17
|
+
*/
|
|
18
|
+
detect(text: string): PiiDetectionResult;
|
|
19
|
+
/**
|
|
20
|
+
* Detect PII in all string values of an object (shallow — top-level keys only).
|
|
21
|
+
*/
|
|
22
|
+
detectInObject(obj: Record<string, unknown>): Record<string, PiiDetectionResult>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=pii-detector-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pii-detector-service.d.ts","sourceRoot":"","sources":["../../src/services/pii-detector-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,QAAQ,EAAE,CAAC;CACrB;AAgBD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAAe;gBAEpB,cAAc,CAAC,EAAE,UAAU,EAAE;IAOzC;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAiCxC;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC;CASjF"}
|
|
@@ -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":"AAAA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAerE,wEAAwE;AACxE,MAAM,aAAa,GAAiB;IAClC;QACE,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,qDAAqD;QAC5D,WAAW,EAAE,eAAe;KAC7B;IACD;QACE,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,2BAA2B;KACzC;CACF,CAAC;AAEF,MAAM,OAAO,kBAAkB;IACrB,SAAS,CAAe;IAEhC,YAAY,cAA6B;QACvC,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC;YAChC,QAAQ,EAAE,CAAC,GAAG,eAAe,EAAE,GAAG,aAAa,EAAE,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;YAC3E,kBAAkB,EAAE,KAAK;SAC1B,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY;QACjB,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAEjD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,OAAO,GAAe,EAAE,CAAC;QAE/B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,iDAAiD;YACjD,IAAI,UAAU,GAAG,CAAC,CAAC;YACnB,OAAO,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;gBACtD,IAAI,GAAG,KAAK,CAAC,CAAC;oBAAE,MAAM;gBAEtB,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,SAAS,CAAC,OAAO;oBACvB,KAAK,EAAE,SAAS,CAAC,KAAK;oBACtB,KAAK,EAAE,GAAG;oBACV,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM;iBAClC,CAAC,CAAC;gBACH,UAAU,GAAG,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,YAAY,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAEjD,OAAO;YACL,MAAM,EAAE,YAAY,CAAC,MAAM,GAAG,CAAC;YAC/B,OAAO,EAAE,YAAY;SACtB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,GAA4B;QACzC,MAAM,OAAO,GAAuC,EAAE,CAAC;QACvD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,MAAkB;IAC5C,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAEtC,MAAM,MAAM,GAAe,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACzD,6CAA6C;YAC7C,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;QACnC,CAAC;QACD,kDAAkD;IACpD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -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"}
|