@apart-tech/intelligence-core 1.21.0 → 1.21.1
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 +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/services/__tests__/node-service.test.js +3 -3
- package/dist/services/__tests__/node-service.test.js.map +1 -1
- package/dist/services/agent-cli-reference.d.ts +1 -1
- package/dist/services/agent-cli-reference.d.ts.map +1 -1
- package/dist/services/agent-cli-reference.js +2 -2
- package/dist/services/chat-capture-service.d.ts.map +1 -1
- package/dist/services/chat-capture-service.js +1 -0
- package/dist/services/chat-capture-service.js.map +1 -1
- package/dist/services/chat-tool-definitions.d.ts +178 -0
- package/dist/services/chat-tool-definitions.d.ts.map +1 -0
- package/dist/services/chat-tool-definitions.js +120 -0
- package/dist/services/chat-tool-definitions.js.map +1 -0
- package/dist/services/chat-tool-definitions.test.d.ts +2 -0
- package/dist/services/chat-tool-definitions.test.d.ts.map +1 -0
- package/dist/services/chat-tool-definitions.test.js +150 -0
- package/dist/services/chat-tool-definitions.test.js.map +1 -0
- package/dist/services/document-post-check-service.d.ts +47 -0
- package/dist/services/document-post-check-service.d.ts.map +1 -0
- package/dist/services/document-post-check-service.js +130 -0
- package/dist/services/document-post-check-service.js.map +1 -0
- package/dist/services/document-post-check-service.test.d.ts +2 -0
- package/dist/services/document-post-check-service.test.d.ts.map +1 -0
- package/dist/services/document-post-check-service.test.js +150 -0
- package/dist/services/document-post-check-service.test.js.map +1 -0
- package/dist/services/document-render-service.d.ts +27 -0
- package/dist/services/document-render-service.d.ts.map +1 -0
- package/dist/services/document-render-service.js +186 -0
- package/dist/services/document-render-service.js.map +1 -0
- package/dist/services/document-render-service.test.d.ts +2 -0
- package/dist/services/document-render-service.test.d.ts.map +1 -0
- package/dist/services/document-render-service.test.js +144 -0
- package/dist/services/document-render-service.test.js.map +1 -0
- package/dist/services/document-service.d.ts +4 -1
- package/dist/services/document-service.d.ts.map +1 -1
- package/dist/services/document-service.js +24 -1
- package/dist/services/document-service.js.map +1 -1
- package/dist/services/document-tool-handler.d.ts +44 -0
- package/dist/services/document-tool-handler.d.ts.map +1 -0
- package/dist/services/document-tool-handler.js +179 -0
- package/dist/services/document-tool-handler.js.map +1 -0
- package/dist/services/document-tool-handler.test.d.ts +2 -0
- package/dist/services/document-tool-handler.test.d.ts.map +1 -0
- package/dist/services/document-tool-handler.test.js +149 -0
- package/dist/services/document-tool-handler.test.js.map +1 -0
- package/dist/services/node-service.js +2 -2
- package/dist/services/node-service.js.map +1 -1
- package/dist/services/quota-service.d.ts +2 -0
- package/dist/services/quota-service.d.ts.map +1 -1
- package/dist/services/quota-service.js +17 -1
- package/dist/services/quota-service.js.map +1 -1
- package/dist/services/usage-service.d.ts +21 -1
- package/dist/services/usage-service.d.ts.map +1 -1
- package/dist/services/usage-service.js +37 -1
- package/dist/services/usage-service.js.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +11 -1
- package/prisma/schema.prisma +24 -18
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { CreateSpreadsheetSchema, CreatePresentationSchema, CreateDocumentSchema, CreateCsvSchema, extractTextFromToolArgs, } from "./chat-tool-definitions.js";
|
|
3
|
+
describe("CreateSpreadsheetSchema", () => {
|
|
4
|
+
it("accepts valid input", () => {
|
|
5
|
+
const input = {
|
|
6
|
+
fileName: "report",
|
|
7
|
+
sheets: [
|
|
8
|
+
{
|
|
9
|
+
name: "Q1",
|
|
10
|
+
columns: [{ header: "Name" }, { header: "Revenue", width: 15 }],
|
|
11
|
+
rows: [["Acme", 1000, true, null]],
|
|
12
|
+
formulas: [{ cell: "B3", formula: "=SUM(B1:B2)" }],
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
expect(CreateSpreadsheetSchema.safeParse(input).success).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("rejects missing fileName", () => {
|
|
19
|
+
const input = { sheets: [] };
|
|
20
|
+
expect(CreateSpreadsheetSchema.safeParse(input).success).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
it("rejects invalid row cell type", () => {
|
|
23
|
+
const input = {
|
|
24
|
+
fileName: "x",
|
|
25
|
+
sheets: [
|
|
26
|
+
{
|
|
27
|
+
name: "S1",
|
|
28
|
+
columns: [{ header: "A" }],
|
|
29
|
+
rows: [[{ nested: true }]],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
expect(CreateSpreadsheetSchema.safeParse(input).success).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("CreatePresentationSchema", () => {
|
|
37
|
+
it("accepts valid input with all layout types", () => {
|
|
38
|
+
const input = {
|
|
39
|
+
fileName: "deck",
|
|
40
|
+
slides: [
|
|
41
|
+
{ layout: "title", title: "Hello", subtitle: "World" },
|
|
42
|
+
{ layout: "content", title: "Details", body: ["Point 1", "Point 2"] },
|
|
43
|
+
{ layout: "two-column", leftColumn: ["L1"], rightColumn: ["R1"] },
|
|
44
|
+
{ layout: "blank" },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
expect(CreatePresentationSchema.safeParse(input).success).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it("rejects invalid layout", () => {
|
|
50
|
+
const input = {
|
|
51
|
+
fileName: "deck",
|
|
52
|
+
slides: [{ layout: "invalid" }],
|
|
53
|
+
};
|
|
54
|
+
expect(CreatePresentationSchema.safeParse(input).success).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe("CreateDocumentSchema", () => {
|
|
58
|
+
it("accepts valid markdown content", () => {
|
|
59
|
+
const input = { fileName: "notes", content: "# Hello\n\nSome text" };
|
|
60
|
+
expect(CreateDocumentSchema.safeParse(input).success).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it("rejects missing content", () => {
|
|
63
|
+
const input = { fileName: "notes" };
|
|
64
|
+
expect(CreateDocumentSchema.safeParse(input).success).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("CreateCsvSchema", () => {
|
|
68
|
+
it("accepts valid input with default delimiter", () => {
|
|
69
|
+
const input = {
|
|
70
|
+
fileName: "data",
|
|
71
|
+
headers: ["Name", "Age"],
|
|
72
|
+
rows: [["Alice", 30]],
|
|
73
|
+
};
|
|
74
|
+
const result = CreateCsvSchema.safeParse(input);
|
|
75
|
+
expect(result.success).toBe(true);
|
|
76
|
+
if (result.success) {
|
|
77
|
+
expect(result.data.delimiter).toBe(",");
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
it("accepts custom delimiter", () => {
|
|
81
|
+
const input = {
|
|
82
|
+
fileName: "data",
|
|
83
|
+
headers: ["A"],
|
|
84
|
+
rows: [["x"]],
|
|
85
|
+
delimiter: ";",
|
|
86
|
+
};
|
|
87
|
+
expect(CreateCsvSchema.safeParse(input).success).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe("extractTextFromToolArgs", () => {
|
|
91
|
+
it("extracts text from spreadsheet args", () => {
|
|
92
|
+
const args = {
|
|
93
|
+
fileName: "report",
|
|
94
|
+
sheets: [
|
|
95
|
+
{
|
|
96
|
+
name: "Sheet1",
|
|
97
|
+
columns: [{ header: "Name" }, { header: "Value" }],
|
|
98
|
+
rows: [["Alice", 100], ["Bob", null]],
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
const text = extractTextFromToolArgs("create_spreadsheet", args);
|
|
103
|
+
expect(text).toContain("report");
|
|
104
|
+
expect(text).toContain("Sheet1");
|
|
105
|
+
expect(text).toContain("Name");
|
|
106
|
+
expect(text).toContain("Alice");
|
|
107
|
+
expect(text).toContain("100");
|
|
108
|
+
expect(text).not.toContain("null");
|
|
109
|
+
});
|
|
110
|
+
it("extracts text from presentation args", () => {
|
|
111
|
+
const args = {
|
|
112
|
+
fileName: "deck",
|
|
113
|
+
slides: [
|
|
114
|
+
{ layout: "title", title: "Welcome", subtitle: "Intro", notes: "Speaker note" },
|
|
115
|
+
{ layout: "two-column", leftColumn: ["Left item"], rightColumn: ["Right item"] },
|
|
116
|
+
],
|
|
117
|
+
};
|
|
118
|
+
const text = extractTextFromToolArgs("create_presentation", args);
|
|
119
|
+
expect(text).toContain("deck");
|
|
120
|
+
expect(text).toContain("Welcome");
|
|
121
|
+
expect(text).toContain("Intro");
|
|
122
|
+
expect(text).toContain("Speaker note");
|
|
123
|
+
expect(text).toContain("Left item");
|
|
124
|
+
expect(text).toContain("Right item");
|
|
125
|
+
});
|
|
126
|
+
it("extracts text from document args", () => {
|
|
127
|
+
const args = { fileName: "notes", content: "# Heading\n\nParagraph text" };
|
|
128
|
+
const text = extractTextFromToolArgs("create_document", args);
|
|
129
|
+
expect(text).toContain("notes");
|
|
130
|
+
expect(text).toContain("# Heading");
|
|
131
|
+
expect(text).toContain("Paragraph text");
|
|
132
|
+
});
|
|
133
|
+
it("extracts text from CSV args", () => {
|
|
134
|
+
const args = {
|
|
135
|
+
fileName: "export",
|
|
136
|
+
headers: ["City", "Pop"],
|
|
137
|
+
rows: [["London", 9000000], ["Paris", null]],
|
|
138
|
+
delimiter: ",",
|
|
139
|
+
};
|
|
140
|
+
const text = extractTextFromToolArgs("create_csv", args);
|
|
141
|
+
expect(text).toContain("export");
|
|
142
|
+
expect(text).toContain("City");
|
|
143
|
+
expect(text).toContain("London");
|
|
144
|
+
expect(text).toContain("9000000");
|
|
145
|
+
});
|
|
146
|
+
it("returns empty string for unknown tool", () => {
|
|
147
|
+
expect(extractTextFromToolArgs("unknown_tool", {})).toBe("");
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=chat-tool-definitions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-tool-definitions.test.js","sourceRoot":"","sources":["../../src/services/chat-tool-definitions.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-check service for document editing.
|
|
3
|
+
*
|
|
4
|
+
* Extracts text from rendered document buffers and runs policy/PII checks.
|
|
5
|
+
* Used after sandbox editing completes to verify the output meets org policies.
|
|
6
|
+
*/
|
|
7
|
+
import type { ContentPolicyService } from "./content-policy-service.js";
|
|
8
|
+
import type { PiiDetectorService } from "./pii-detector-service.js";
|
|
9
|
+
export interface PostCheckInput {
|
|
10
|
+
buffer: Buffer;
|
|
11
|
+
mimeType: string;
|
|
12
|
+
piiOutputPolicy: "warn" | "block" | "strip";
|
|
13
|
+
contentPolicyService?: ContentPolicyService;
|
|
14
|
+
piiDetector?: PiiDetectorService;
|
|
15
|
+
}
|
|
16
|
+
export interface PostCheckResult {
|
|
17
|
+
allowed: boolean;
|
|
18
|
+
piiDetected: boolean;
|
|
19
|
+
piiWarning: boolean;
|
|
20
|
+
policyViolation?: string;
|
|
21
|
+
extractedTextLength: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class DocumentPostCheckService {
|
|
24
|
+
/**
|
|
25
|
+
* Extract user-visible text from a document buffer.
|
|
26
|
+
* Format-aware: handles XLSX, DOCX, PPTX, and CSV.
|
|
27
|
+
*/
|
|
28
|
+
extractText(buffer: Buffer, mimeType: string): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
* Run post-check: extract text → policy check → PII check.
|
|
31
|
+
*/
|
|
32
|
+
postCheck(input: PostCheckInput): Promise<PostCheckResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Extract text from an XLSX buffer using ExcelJS.
|
|
35
|
+
*/
|
|
36
|
+
private extractXlsxText;
|
|
37
|
+
/**
|
|
38
|
+
* Extract text from a DOCX buffer using mammoth.
|
|
39
|
+
*/
|
|
40
|
+
private extractDocxText;
|
|
41
|
+
/**
|
|
42
|
+
* Extract text from a PPTX buffer by parsing the OOXML zip.
|
|
43
|
+
* Uses jszip to read slide XML files and extracts text content.
|
|
44
|
+
*/
|
|
45
|
+
private extractPptxText;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=document-post-check-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-post-check-service.d.ts","sourceRoot":"","sources":["../../src/services/document-post-check-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGpE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC5C,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,wBAAwB;IACnC;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAepE;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAuDhE;;OAEG;YACW,eAAe;IAwB7B;;OAEG;YACW,eAAe;IAM7B;;;OAGG;YACW,eAAe;CAuB9B"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export class DocumentPostCheckService {
|
|
2
|
+
/**
|
|
3
|
+
* Extract user-visible text from a document buffer.
|
|
4
|
+
* Format-aware: handles XLSX, DOCX, PPTX, and CSV.
|
|
5
|
+
*/
|
|
6
|
+
async extractText(buffer, mimeType) {
|
|
7
|
+
switch (mimeType) {
|
|
8
|
+
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
|
9
|
+
return this.extractXlsxText(buffer);
|
|
10
|
+
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
|
11
|
+
return this.extractDocxText(buffer);
|
|
12
|
+
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
|
13
|
+
return this.extractPptxText(buffer);
|
|
14
|
+
case "text/csv":
|
|
15
|
+
return buffer.toString("utf-8");
|
|
16
|
+
default:
|
|
17
|
+
return buffer.toString("utf-8");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Run post-check: extract text → policy check → PII check.
|
|
22
|
+
*/
|
|
23
|
+
async postCheck(input) {
|
|
24
|
+
const text = await this.extractText(input.buffer, input.mimeType);
|
|
25
|
+
// Content policy check
|
|
26
|
+
if (input.contentPolicyService) {
|
|
27
|
+
try {
|
|
28
|
+
const evaluation = await input.contentPolicyService.evaluate(text);
|
|
29
|
+
if (!evaluation.allowed) {
|
|
30
|
+
const block = evaluation.violations.find((v) => v.action === "block");
|
|
31
|
+
return {
|
|
32
|
+
allowed: false,
|
|
33
|
+
piiDetected: false,
|
|
34
|
+
piiWarning: false,
|
|
35
|
+
policyViolation: `Blocked by policy "${block?.policyName ?? "unknown"}"`,
|
|
36
|
+
extractedTextLength: text.length,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.error("[DocumentPostCheck] Policy evaluation failed, proceeding:", err);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// PII check
|
|
45
|
+
let piiDetected = false;
|
|
46
|
+
let piiWarning = false;
|
|
47
|
+
if (input.piiDetector) {
|
|
48
|
+
try {
|
|
49
|
+
const piiResult = input.piiDetector.detect(text);
|
|
50
|
+
piiDetected = piiResult.matches.length > 0;
|
|
51
|
+
if (piiDetected) {
|
|
52
|
+
if (input.piiOutputPolicy === "block") {
|
|
53
|
+
return {
|
|
54
|
+
allowed: false,
|
|
55
|
+
piiDetected: true,
|
|
56
|
+
piiWarning: false,
|
|
57
|
+
policyViolation: "Edited document contains PII that is not allowed by organization policy.",
|
|
58
|
+
extractedTextLength: text.length,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
piiWarning = input.piiOutputPolicy === "warn";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
console.error("[DocumentPostCheck] PII detection failed, proceeding:", err);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
allowed: true,
|
|
70
|
+
piiDetected,
|
|
71
|
+
piiWarning,
|
|
72
|
+
extractedTextLength: text.length,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Extract text from an XLSX buffer using ExcelJS.
|
|
77
|
+
*/
|
|
78
|
+
async extractXlsxText(buffer) {
|
|
79
|
+
const ExcelJS = await import("exceljs");
|
|
80
|
+
const workbook = new ExcelJS.default.Workbook();
|
|
81
|
+
await workbook.xlsx.load(buffer);
|
|
82
|
+
const parts = [];
|
|
83
|
+
workbook.eachSheet((sheet) => {
|
|
84
|
+
parts.push(`[Sheet: ${sheet.name}]`);
|
|
85
|
+
sheet.eachRow((row) => {
|
|
86
|
+
const values = [];
|
|
87
|
+
row.eachCell((cell) => {
|
|
88
|
+
if (cell.value != null) {
|
|
89
|
+
values.push(String(cell.value));
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (values.length > 0) {
|
|
93
|
+
parts.push(values.join("\t"));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
return parts.join("\n");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Extract text from a DOCX buffer using mammoth.
|
|
101
|
+
*/
|
|
102
|
+
async extractDocxText(buffer) {
|
|
103
|
+
const mammoth = await import("mammoth");
|
|
104
|
+
const result = await mammoth.extractRawText({ buffer });
|
|
105
|
+
return result.value;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Extract text from a PPTX buffer by parsing the OOXML zip.
|
|
109
|
+
* Uses jszip to read slide XML files and extracts text content.
|
|
110
|
+
*/
|
|
111
|
+
async extractPptxText(buffer) {
|
|
112
|
+
const JSZip = (await import("jszip")).default;
|
|
113
|
+
const zip = await JSZip.loadAsync(buffer);
|
|
114
|
+
const parts = [];
|
|
115
|
+
const slideFiles = Object.keys(zip.files)
|
|
116
|
+
.filter((name) => /^ppt\/slides\/slide\d+\.xml$/.test(name))
|
|
117
|
+
.sort();
|
|
118
|
+
for (const slidePath of slideFiles) {
|
|
119
|
+
const xml = await zip.files[slidePath].async("text");
|
|
120
|
+
// Extract text content from XML using regex (lightweight, no XML parser needed)
|
|
121
|
+
const textMatches = xml.match(/<a:t[^>]*>([^<]*)<\/a:t>/g);
|
|
122
|
+
if (textMatches) {
|
|
123
|
+
const slideTexts = textMatches.map((m) => m.replace(/<a:t[^>]*>/, "").replace(/<\/a:t>/, ""));
|
|
124
|
+
parts.push(slideTexts.join(" "));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return parts.join("\n");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=document-post-check-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-post-check-service.js","sourceRoot":"","sources":["../../src/services/document-post-check-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-post-check-service.test.d.ts","sourceRoot":"","sources":["../../src/services/document-post-check-service.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { DocumentPostCheckService } from "./document-post-check-service.js";
|
|
3
|
+
describe("DocumentPostCheckService", () => {
|
|
4
|
+
const service = new DocumentPostCheckService();
|
|
5
|
+
describe("extractText", () => {
|
|
6
|
+
it("should extract text from CSV as-is", async () => {
|
|
7
|
+
const csv = "Name,Age\nAlice,30\nBob,25";
|
|
8
|
+
const buffer = Buffer.from(csv, "utf-8");
|
|
9
|
+
const result = await service.extractText(buffer, "text/csv");
|
|
10
|
+
expect(result).toBe(csv);
|
|
11
|
+
});
|
|
12
|
+
it("should extract text from XLSX", async () => {
|
|
13
|
+
// Create a minimal XLSX using ExcelJS
|
|
14
|
+
const ExcelJS = await import("exceljs");
|
|
15
|
+
const workbook = new ExcelJS.default.Workbook();
|
|
16
|
+
const sheet = workbook.addWorksheet("Test");
|
|
17
|
+
sheet.columns = [{ header: "Name", key: "name" }];
|
|
18
|
+
sheet.addRow(["Alice"]);
|
|
19
|
+
sheet.addRow(["Bob"]);
|
|
20
|
+
const arrayBuffer = await workbook.xlsx.writeBuffer();
|
|
21
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
22
|
+
const result = await service.extractText(buffer, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
23
|
+
expect(result).toContain("Name");
|
|
24
|
+
expect(result).toContain("Alice");
|
|
25
|
+
expect(result).toContain("Bob");
|
|
26
|
+
expect(result).toContain("[Sheet: Test]");
|
|
27
|
+
});
|
|
28
|
+
it("should extract text from PPTX", async () => {
|
|
29
|
+
// Create a minimal PPTX using jszip (OOXML structure)
|
|
30
|
+
const JSZip = (await import("jszip")).default;
|
|
31
|
+
const zip = new JSZip();
|
|
32
|
+
// Minimal PPTX slide with text
|
|
33
|
+
const slideXml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
34
|
+
<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
|
|
35
|
+
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
|
|
36
|
+
<p:cSld>
|
|
37
|
+
<p:spTree>
|
|
38
|
+
<p:sp>
|
|
39
|
+
<p:txBody>
|
|
40
|
+
<a:p><a:r><a:t>Hello World</a:t></a:r></a:p>
|
|
41
|
+
<a:p><a:r><a:t>Test Slide</a:t></a:r></a:p>
|
|
42
|
+
</p:txBody>
|
|
43
|
+
</p:sp>
|
|
44
|
+
</p:spTree>
|
|
45
|
+
</p:cSld>
|
|
46
|
+
</p:sld>`;
|
|
47
|
+
zip.file("ppt/slides/slide1.xml", slideXml);
|
|
48
|
+
const buffer = await zip.generateAsync({ type: "nodebuffer" });
|
|
49
|
+
const result = await service.extractText(buffer, "application/vnd.openxmlformats-officedocument.presentationml.presentation");
|
|
50
|
+
expect(result).toContain("Hello World");
|
|
51
|
+
expect(result).toContain("Test Slide");
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("postCheck", () => {
|
|
55
|
+
it("should return allowed for clean content", async () => {
|
|
56
|
+
const buffer = Buffer.from("Just some clean text", "utf-8");
|
|
57
|
+
const result = await service.postCheck({
|
|
58
|
+
buffer,
|
|
59
|
+
mimeType: "text/csv",
|
|
60
|
+
piiOutputPolicy: "warn",
|
|
61
|
+
});
|
|
62
|
+
expect(result.allowed).toBe(true);
|
|
63
|
+
expect(result.piiDetected).toBe(false);
|
|
64
|
+
expect(result.piiWarning).toBe(false);
|
|
65
|
+
expect(result.extractedTextLength).toBeGreaterThan(0);
|
|
66
|
+
});
|
|
67
|
+
it("should block when content policy rejects", async () => {
|
|
68
|
+
const buffer = Buffer.from("some content", "utf-8");
|
|
69
|
+
const mockPolicySvc = {
|
|
70
|
+
evaluate: vi.fn().mockResolvedValue({
|
|
71
|
+
allowed: false,
|
|
72
|
+
violations: [{ action: "block", policyName: "TestPolicy", category: "test" }],
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
const result = await service.postCheck({
|
|
76
|
+
buffer,
|
|
77
|
+
mimeType: "text/csv",
|
|
78
|
+
piiOutputPolicy: "warn",
|
|
79
|
+
contentPolicyService: mockPolicySvc,
|
|
80
|
+
});
|
|
81
|
+
expect(result.allowed).toBe(false);
|
|
82
|
+
expect(result.policyViolation).toContain("TestPolicy");
|
|
83
|
+
});
|
|
84
|
+
it("should block when PII detected and policy is 'block'", async () => {
|
|
85
|
+
const buffer = Buffer.from("My SSN is 123-45-6789", "utf-8");
|
|
86
|
+
const mockPiiDetector = {
|
|
87
|
+
detect: vi.fn().mockReturnValue({
|
|
88
|
+
matches: [{ type: "ssn", value: "123-45-6789" }],
|
|
89
|
+
}),
|
|
90
|
+
};
|
|
91
|
+
const result = await service.postCheck({
|
|
92
|
+
buffer,
|
|
93
|
+
mimeType: "text/csv",
|
|
94
|
+
piiOutputPolicy: "block",
|
|
95
|
+
piiDetector: mockPiiDetector,
|
|
96
|
+
});
|
|
97
|
+
expect(result.allowed).toBe(false);
|
|
98
|
+
expect(result.piiDetected).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
it("should warn when PII detected and policy is 'warn'", async () => {
|
|
101
|
+
const buffer = Buffer.from("My email is test@example.com", "utf-8");
|
|
102
|
+
const mockPiiDetector = {
|
|
103
|
+
detect: vi.fn().mockReturnValue({
|
|
104
|
+
matches: [{ type: "email", value: "test@example.com" }],
|
|
105
|
+
}),
|
|
106
|
+
};
|
|
107
|
+
const result = await service.postCheck({
|
|
108
|
+
buffer,
|
|
109
|
+
mimeType: "text/csv",
|
|
110
|
+
piiOutputPolicy: "warn",
|
|
111
|
+
piiDetector: mockPiiDetector,
|
|
112
|
+
});
|
|
113
|
+
expect(result.allowed).toBe(true);
|
|
114
|
+
expect(result.piiDetected).toBe(true);
|
|
115
|
+
expect(result.piiWarning).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
it("should not warn when PII detected and policy is 'strip'", async () => {
|
|
118
|
+
const buffer = Buffer.from("My email is test@example.com", "utf-8");
|
|
119
|
+
const mockPiiDetector = {
|
|
120
|
+
detect: vi.fn().mockReturnValue({
|
|
121
|
+
matches: [{ type: "email", value: "test@example.com" }],
|
|
122
|
+
}),
|
|
123
|
+
};
|
|
124
|
+
const result = await service.postCheck({
|
|
125
|
+
buffer,
|
|
126
|
+
mimeType: "text/csv",
|
|
127
|
+
piiOutputPolicy: "strip",
|
|
128
|
+
piiDetector: mockPiiDetector,
|
|
129
|
+
});
|
|
130
|
+
expect(result.allowed).toBe(true);
|
|
131
|
+
expect(result.piiDetected).toBe(true);
|
|
132
|
+
expect(result.piiWarning).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
it("should handle policy evaluation failure gracefully", async () => {
|
|
135
|
+
const buffer = Buffer.from("some content", "utf-8");
|
|
136
|
+
const mockPolicySvc = {
|
|
137
|
+
evaluate: vi.fn().mockRejectedValue(new Error("DB down")),
|
|
138
|
+
};
|
|
139
|
+
const result = await service.postCheck({
|
|
140
|
+
buffer,
|
|
141
|
+
mimeType: "text/csv",
|
|
142
|
+
piiOutputPolicy: "warn",
|
|
143
|
+
contentPolicyService: mockPolicySvc,
|
|
144
|
+
});
|
|
145
|
+
// Should proceed without blocking
|
|
146
|
+
expect(result.allowed).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
//# sourceMappingURL=document-post-check-service.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-post-check-service.test.js","sourceRoot":"","sources":["../../src/services/document-post-check-service.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CreateSpreadsheetArgs, CreatePresentationArgs, CreateDocumentArgs, CreateCsvArgs } from "./chat-tool-definitions.js";
|
|
2
|
+
export interface RenderResult {
|
|
3
|
+
buffer: Buffer;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
extension: string;
|
|
6
|
+
fileName: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class DocumentRenderService {
|
|
9
|
+
/**
|
|
10
|
+
* Render an Excel spreadsheet (.xlsx) from structured data.
|
|
11
|
+
*/
|
|
12
|
+
renderSpreadsheet(args: CreateSpreadsheetArgs): Promise<RenderResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Render a PowerPoint presentation (.pptx) from slide definitions.
|
|
15
|
+
*/
|
|
16
|
+
renderPresentation(args: CreatePresentationArgs): Promise<RenderResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Render a Word document (.docx) from markdown content.
|
|
19
|
+
* Converts markdown → HTML → DOCX via @turbodocx/html-to-docx.
|
|
20
|
+
*/
|
|
21
|
+
renderDocument(args: CreateDocumentArgs): Promise<RenderResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Render a CSV file from structured data.
|
|
24
|
+
*/
|
|
25
|
+
renderCsv(args: CreateCsvArgs): Promise<RenderResult>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=document-render-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-render-service.d.ts","sourceRoot":"","sources":["../../src/services/document-render-service.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,qBAAqB,EACrB,sBAAsB,EACtB,kBAAkB,EAClB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,qBAAa,qBAAqB;IAChC;;OAEG;IACG,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IAsC3E;;OAEG;IACG,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,YAAY,CAAC;IA+G7E;;;OAGG;IACG,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBrE;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAiB5D"}
|