@krutai/excel-comparison 0.0.6
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/AI_REFERENCE.md +353 -0
- package/README.md +161 -0
- package/dist/index.d.mts +187 -0
- package/dist/index.d.ts +187 -0
- package/dist/index.js +34745 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +34711 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/AI_REFERENCE.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# AI Reference Guide for @krutai/excel-comparison
|
|
2
|
+
|
|
3
|
+
This document provides comprehensive context for AI assistants to help users integrate and use the excel-comparison library effectively.
|
|
4
|
+
|
|
5
|
+
## Library Purpose
|
|
6
|
+
|
|
7
|
+
The `@krutai/excel-comparison` library compares Excel (.xlsx, .xls) and CSV files, finding:
|
|
8
|
+
- Matching rows between two files
|
|
9
|
+
- Different values in matching rows
|
|
10
|
+
- Unique rows in each file
|
|
11
|
+
- Generates downloadable Excel reports with differences highlighted
|
|
12
|
+
|
|
13
|
+
## Core Classes and Exports
|
|
14
|
+
|
|
15
|
+
// Main class - use this for comparing files via API
|
|
16
|
+
import { krutExcelComparison, createComparisonClient } from "@krutai/excel-comparison";
|
|
17
|
+
|
|
18
|
+
// Create client using convenience factory (recommended)
|
|
19
|
+
const client = krutExcelComparison({
|
|
20
|
+
serverUrl: "https://api.krut.ai",
|
|
21
|
+
apiKey: "your-krut-api-key"
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Or using createComparisonClient
|
|
25
|
+
const client2 = createComparisonClient({
|
|
26
|
+
apiKey: "..."
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// API client class
|
|
30
|
+
import { ComparisonApiClient } from "@krutai/excel-comparison";
|
|
31
|
+
|
|
32
|
+
### Type Exports
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import type {
|
|
36
|
+
ComparisonApiResponse, // Result from API comparison
|
|
37
|
+
PreviewResponse, // Preview info for files
|
|
38
|
+
CompareFilesOptions, // Configuration options
|
|
39
|
+
DataRecord, // Row data as object (used in reporting/engine)
|
|
40
|
+
} from "@krutai/excel-comparison";
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Common Use Cases
|
|
44
|
+
|
|
45
|
+
### 1. Basic File Comparison (via API)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { krutExcelComparison } from "@krutai/excel-comparison";
|
|
49
|
+
|
|
50
|
+
const client = krutExcelComparison({
|
|
51
|
+
apiKey: "your-api-key"
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// For browser - using File objects
|
|
55
|
+
const result = await client.compareFilesFromFileObjects(file1, file2);
|
|
56
|
+
|
|
57
|
+
// For Node.js/Server - using Buffer
|
|
58
|
+
const result2 = await client.compareFiles(buffer1, "file1.xlsx", buffer2, "file2.xlsx");
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. With Comparison Options
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const result = await client.compareFilesFromFileObjects(file1, file2, {
|
|
65
|
+
matchColumn: "Invoice", // Optional: column to match rows
|
|
66
|
+
tolerance: 0.01, // Optional: numeric tolerance
|
|
67
|
+
caseSensitive: false, // Optional: case insensitive
|
|
68
|
+
ignoreColumns: ["Timestamp"] // Optional: ignore these columns
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Preview Files Before Comparison
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// Get preview metadata and suggested match columns
|
|
76
|
+
const preview = await client.previewFiles(file1, file2);
|
|
77
|
+
|
|
78
|
+
// Returns:
|
|
79
|
+
{
|
|
80
|
+
success: true,
|
|
81
|
+
file1: { name: "sales.xlsx", rowCount: 100, columns: [...], sample: [...] },
|
|
82
|
+
file2: { name: "sales2.xlsx", rowCount: 95, columns: [...], sample: [...] },
|
|
83
|
+
suggestedMatchColumn: "Invoice"
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 4. Generate Excel Report
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { StyledReporter } from "@krutai/excel-comparison";
|
|
91
|
+
|
|
92
|
+
const reporter = new StyledReporter({
|
|
93
|
+
headerColor: "4472C4", // Blue header
|
|
94
|
+
differenceColor: "FFCCCC", // Red for differences
|
|
95
|
+
matchColor: "CCFFCC", // Green for matches
|
|
96
|
+
includeSummary: true
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Transform comparison results for report
|
|
100
|
+
const reportData = result.results.map((r, i) => ({
|
|
101
|
+
Row: i + 1,
|
|
102
|
+
Status: r.status,
|
|
103
|
+
"Match %": `${r.matchPercentage}%`,
|
|
104
|
+
...Object.fromEntries(
|
|
105
|
+
result.allColumns.flatMap(col => [
|
|
106
|
+
[`File1_${col}`, r.file1Row?.[col] ?? 'N/A'],
|
|
107
|
+
[`File2_${col}`, r.file2Row?.[col] ?? 'N/A'],
|
|
108
|
+
])
|
|
109
|
+
)
|
|
110
|
+
}));
|
|
111
|
+
|
|
112
|
+
const report = await reporter.generateReport({
|
|
113
|
+
data: reportData,
|
|
114
|
+
summary: result.summary,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Download as base64
|
|
118
|
+
const downloadUrl = `data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,${report.toString('base64')}`;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 5. Next.js API Route Integration (Recommended)
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// app/api/compare/route.ts
|
|
125
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
126
|
+
import {
|
|
127
|
+
createComparisonClient,
|
|
128
|
+
type CompareFilesOptions,
|
|
129
|
+
} from "@krutai/excel-comparison";
|
|
130
|
+
|
|
131
|
+
const SUPPORTED_EXTENSIONS = new Set(["xlsx", "xls", "csv"]);
|
|
132
|
+
|
|
133
|
+
function getFileExtension(fileName: string): string {
|
|
134
|
+
const parts = fileName.toLowerCase().split(".");
|
|
135
|
+
return parts.length > 1 ? parts[parts.length - 1] : "";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function isSupportedFile(file: File): boolean {
|
|
139
|
+
return SUPPORTED_EXTENSIONS.has(getFileExtension(file.name));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getComparisonErrorMessage(raw: string): string {
|
|
143
|
+
const lower = raw.toLowerCase();
|
|
144
|
+
if (lower.includes("can't find end of central directory") || lower.includes("zip file")) {
|
|
145
|
+
return "One of the uploaded files is not a valid .xlsx file archive. For Excel inputs, use a valid .xlsx or .xls file.";
|
|
146
|
+
}
|
|
147
|
+
if (lower.includes("request timed out")) {
|
|
148
|
+
return "Comparison request timed out. Please try smaller files or increase the timeout.";
|
|
149
|
+
}
|
|
150
|
+
return raw;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function parseIgnoreColumns(value?: string): string[] | undefined {
|
|
154
|
+
if (!value?.trim()) return undefined;
|
|
155
|
+
|
|
156
|
+
if (value.trim().startsWith("[")) {
|
|
157
|
+
try {
|
|
158
|
+
const parsed = JSON.parse(value) as unknown;
|
|
159
|
+
if (Array.isArray(parsed)) {
|
|
160
|
+
return parsed
|
|
161
|
+
.filter((item): item is string => typeof item === "string")
|
|
162
|
+
.map((item) => item.trim())
|
|
163
|
+
.filter(Boolean);
|
|
164
|
+
}
|
|
165
|
+
} catch { }
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return value.split(",").map(i => i.trim()).filter(Boolean);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function POST(req: NextRequest) {
|
|
172
|
+
try {
|
|
173
|
+
const formData = await req.formData();
|
|
174
|
+
const file1 = formData.get("file1") as File | null;
|
|
175
|
+
const file2 = formData.get("file2") as File | null;
|
|
176
|
+
const matchColumn = formData.get("matchColumn") as string | undefined;
|
|
177
|
+
const ignoreColumns = formData.get("ignoreColumns") as string | undefined;
|
|
178
|
+
const tolerance = formData.get("tolerance") as string | undefined;
|
|
179
|
+
const caseSensitive = formData.get("caseSensitive") as string | undefined;
|
|
180
|
+
|
|
181
|
+
if (!file1 || !file2) {
|
|
182
|
+
return NextResponse.json({ error: "Both file1 and file2 are required" }, { status: 400 });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!isSupportedFile(file1) || !isSupportedFile(file2)) {
|
|
186
|
+
return NextResponse.json({ error: "Unsupported file type. Use .xlsx, .xls, or .csv files." }, { status: 400 });
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const options: CompareFilesOptions = {};
|
|
190
|
+
if (matchColumn?.trim()) options.matchColumn = matchColumn.trim();
|
|
191
|
+
const parsedIgnore = parseIgnoreColumns(ignoreColumns);
|
|
192
|
+
if (parsedIgnore) options.ignoreColumns = parsedIgnore;
|
|
193
|
+
if (tolerance?.trim()) options.tolerance = Number(tolerance);
|
|
194
|
+
if (caseSensitive !== undefined) options.caseSensitive = caseSensitive === "true";
|
|
195
|
+
|
|
196
|
+
const client = createComparisonClient({
|
|
197
|
+
apiKey: process.env.KRUTAI_API_KEY || '',
|
|
198
|
+
serverUrl: process.env.KRUTAI_SERVER_URL || "http://localhost:8000",
|
|
199
|
+
validateOnInit: false,
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const apiResponse = await client.compareFilesFromFileObjects(file1, file2, options);
|
|
203
|
+
|
|
204
|
+
if (!apiResponse.success || !apiResponse.result) {
|
|
205
|
+
return NextResponse.json({ error: apiResponse.error ?? "Comparison failed" }, { status: 500 });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return NextResponse.json({
|
|
209
|
+
success: true,
|
|
210
|
+
result: apiResponse.result,
|
|
211
|
+
results: [],
|
|
212
|
+
allColumns: [...new Set([
|
|
213
|
+
...(apiResponse.result.metadata.file1Columns ?? []),
|
|
214
|
+
...(apiResponse.result.metadata.file2Columns ?? []),
|
|
215
|
+
])],
|
|
216
|
+
columnsWithDiffs: [],
|
|
217
|
+
downloadUrl: apiResponse.downloadUrl,
|
|
218
|
+
fileName: apiResponse.fileName,
|
|
219
|
+
});
|
|
220
|
+
} catch (err: unknown) {
|
|
221
|
+
const msg = err instanceof Error ? err.message : "Comparison failed";
|
|
222
|
+
return NextResponse.json({ error: getComparisonErrorMessage(msg) }, { status: 500 });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 6. Express.js Integration
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
import express from 'express';
|
|
231
|
+
import multer from 'multer';
|
|
232
|
+
import { krutExcelComparison } from "@krutai/excel-comparison";
|
|
233
|
+
|
|
234
|
+
const app = express();
|
|
235
|
+
const upload = multer({ storage: multer.memoryStorage() });
|
|
236
|
+
const client = krutExcelComparison({ apiKey: process.env.KRUTAI_API_KEY });
|
|
237
|
+
|
|
238
|
+
app.post('/compare', upload.fields([
|
|
239
|
+
{ name: 'file1', maxCount: 1 },
|
|
240
|
+
{ name: 'file2', maxCount: 1 }
|
|
241
|
+
]), async (req, res) => {
|
|
242
|
+
const files = req.files as { [fieldname: string]: Express.Multer.File[] };
|
|
243
|
+
|
|
244
|
+
const result = await client.compareFiles(
|
|
245
|
+
files.file1[0].buffer, files.file1[0].originalname,
|
|
246
|
+
files.file2[0].buffer, files.file2[0].originalname,
|
|
247
|
+
{
|
|
248
|
+
matchColumn: req.body.matchColumn,
|
|
249
|
+
tolerance: req.body.tolerance ? parseFloat(req.body.tolerance) : undefined
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
res.json(result);
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## ComparisonApiResponse Structure
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
{
|
|
261
|
+
success: boolean, // true if comparison succeeded
|
|
262
|
+
result?: {
|
|
263
|
+
summary: {
|
|
264
|
+
totalRows: number, // Total rows compared
|
|
265
|
+
matchesFound: number, // Rows with all values matching
|
|
266
|
+
differencesFound: number,// Rows with differences
|
|
267
|
+
uniqueToFile1: number, // Rows only in first file
|
|
268
|
+
uniqueToFile2: number, // Rows only in second file
|
|
269
|
+
status: 'SUCCESS' | 'PARTIAL' | 'NO_MATCH'
|
|
270
|
+
},
|
|
271
|
+
matchColumn: string,
|
|
272
|
+
metadata: {
|
|
273
|
+
file1Name: string,
|
|
274
|
+
file1Columns: string[],
|
|
275
|
+
file1RowCount: number,
|
|
276
|
+
file2Name: string,
|
|
277
|
+
file2Columns: string[],
|
|
278
|
+
file2RowCount: number
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
downloadUrl?: string, // URL to download the Excel report
|
|
282
|
+
fileName?: string, // Suggested file name for download
|
|
283
|
+
error?: string // Error message if success is false
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Key Behaviors
|
|
288
|
+
|
|
289
|
+
### API Comparison
|
|
290
|
+
- The package now acts as a client for a backend comparison service.
|
|
291
|
+
- It offloads heavy Excel processing and comparison logic to the server.
|
|
292
|
+
- It returns a summary of results and a link to a professionally styled Excel report.
|
|
293
|
+
|
|
294
|
+
### Column Matching
|
|
295
|
+
- If `matchColumn` is provided, uses that column to match rows
|
|
296
|
+
- If not provided, auto-detects: prioritizes id, invoice, gstin, number, name, code
|
|
297
|
+
- Falls back to first column if no match found
|
|
298
|
+
|
|
299
|
+
### Value Comparison (Backend)
|
|
300
|
+
- Done on the server side using intelligent algorithms.
|
|
301
|
+
- Supports fuzzy matching, numeric tolerance, and case sensitivity.
|
|
302
|
+
|
|
303
|
+
## Common Integration Patterns
|
|
304
|
+
|
|
305
|
+
### Pattern 1: Basic Comparison
|
|
306
|
+
```typescript
|
|
307
|
+
const client = krutExcelComparison({ apiKey: "..." });
|
|
308
|
+
const result = await client.compareFilesFromFileObjects(f1, f2);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Pattern 2: Comparison with Options
|
|
312
|
+
```typescript
|
|
313
|
+
const result = await client.compareFilesFromFileObjects(f1, f2, {
|
|
314
|
+
matchColumn: "Invoice No",
|
|
315
|
+
tolerance: 0.001,
|
|
316
|
+
caseSensitive: false
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Error Handling
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
try {
|
|
324
|
+
const result = await client.compareFilesFromFileObjects(file1, file2);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (error.message.includes("Request timed out")) {
|
|
327
|
+
// Handle timeout
|
|
328
|
+
} else {
|
|
329
|
+
// Generic error
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Package Dependencies
|
|
335
|
+
|
|
336
|
+
The library is lightweight and depends on:
|
|
337
|
+
- `exceljs` - For local reporting (optional)
|
|
338
|
+
|
|
339
|
+
## Environment Notes
|
|
340
|
+
|
|
341
|
+
- Works in Node.js (v14+) and modern browsers
|
|
342
|
+
- Uses dynamic imports for xlsx to support Next.js
|
|
343
|
+
- File objects from HTML inputs work in browser
|
|
344
|
+
- Buffer objects work in Node.js
|
|
345
|
+
|
|
346
|
+
## Contributing Guidelines for AI Assistants
|
|
347
|
+
|
|
348
|
+
When helping users with this library:
|
|
349
|
+
|
|
350
|
+
1. Use `krutExcelComparison` or `ComparisonApiClient`.
|
|
351
|
+
2. Emphasize that comparison is done via API.
|
|
352
|
+
3. Show Next.js API route as the primary integration example.
|
|
353
|
+
4. Note that heavy parsing (xlsx) is done on the backend.
|
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# @krutai/excel-comparison
|
|
2
|
+
|
|
3
|
+
A powerful library for comparing Excel and CSV files by leveraging Backend APIs for high-performance processing.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **API-Driven Comparison**: Offloads heavy Excel processing to a dedicated comparison service.
|
|
8
|
+
- **Smart Column Matching**: Automatically detects matching columns between files on the server.
|
|
9
|
+
- **Detailed Summaries**: Get row counts, matches, and differences instantly.
|
|
10
|
+
- **Professional Reports**: Automatically generates styled Excel reports with highlighted differences.
|
|
11
|
+
- **Next.js & Serverless Ready**: Optimized for modern web frameworks with zero heavy dependencies like `xlsx`.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @krutai/excel-comparison
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Basic Usage (Server-side)
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { krutExcelComparison } from "@krutai/excel-comparison";
|
|
25
|
+
|
|
26
|
+
// Create client
|
|
27
|
+
const client = krutExcelComparison({
|
|
28
|
+
apiKey: process.env.KRUTAI_API_KEY,
|
|
29
|
+
serverUrl: process.env.KRUTAI_SERVER_URL || "https://api.krut.ai"
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Compare files using buffers
|
|
33
|
+
const result = await client.compareFiles(
|
|
34
|
+
file1Buffer, "file1.xlsx",
|
|
35
|
+
file2Buffer, "file2.xlsx",
|
|
36
|
+
{ matchColumn: "Invoice" }
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
if (result.success) {
|
|
40
|
+
console.log('Report URL:', result.downloadUrl);
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Next.js API Route Integration
|
|
45
|
+
|
|
46
|
+
This is the recommended way to use the library in a Next.js application.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// app/api/compare/route.ts
|
|
50
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
51
|
+
import {
|
|
52
|
+
createComparisonClient,
|
|
53
|
+
type CompareFilesOptions,
|
|
54
|
+
} from "@krutai/excel-comparison";
|
|
55
|
+
|
|
56
|
+
const SUPPORTED_EXTENSIONS = new Set(["xlsx", "xls", "csv"]);
|
|
57
|
+
|
|
58
|
+
function getFileExtension(fileName: string): string {
|
|
59
|
+
const parts = fileName.toLowerCase().split(".");
|
|
60
|
+
return parts.length > 1 ? parts[parts.length - 1] : "";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isSupportedFile(file: File): boolean {
|
|
64
|
+
return SUPPORTED_EXTENSIONS.has(getFileExtension(file.name));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function parseIgnoreColumns(value?: string): string[] | undefined {
|
|
68
|
+
if (!value?.trim()) return undefined;
|
|
69
|
+
if (value.trim().startsWith("[")) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(value);
|
|
72
|
+
if (Array.isArray(parsed)) return parsed.filter(i => typeof i === "string");
|
|
73
|
+
} catch { }
|
|
74
|
+
}
|
|
75
|
+
return value.split(",").map(i => i.trim()).filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function POST(req: NextRequest) {
|
|
79
|
+
try {
|
|
80
|
+
const formData = await req.formData();
|
|
81
|
+
const file1 = formData.get("file1") as File | null;
|
|
82
|
+
const file2 = formData.get("file2") as File | null;
|
|
83
|
+
const matchColumn = formData.get("matchColumn") as string | undefined;
|
|
84
|
+
|
|
85
|
+
if (!file1 || !file2) {
|
|
86
|
+
return NextResponse.json({ error: "Both file1 and file2 are required" }, { status: 400 });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const client = createComparisonClient({
|
|
90
|
+
apiKey: process.env.KRUTAI_API_KEY || '',
|
|
91
|
+
serverUrl: process.env.KRUTAI_SERVER_URL || "http://localhost:8000"
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const apiResponse = await client.compareFilesFromFileObjects(file1, file2, {
|
|
95
|
+
matchColumn: matchColumn?.trim()
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return NextResponse.json(apiResponse);
|
|
99
|
+
} catch (err: unknown) {
|
|
100
|
+
return NextResponse.json({ error: "Comparison failed" }, { status: 500 });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## API Reference
|
|
106
|
+
|
|
107
|
+
### krutExcelComparison(config)
|
|
108
|
+
|
|
109
|
+
Convenience factory to create a `ComparisonApiClient`.
|
|
110
|
+
|
|
111
|
+
### ComparisonApiClient
|
|
112
|
+
|
|
113
|
+
#### `compareFiles(buffer1, name1, buffer2, name2, options)`
|
|
114
|
+
Compare files using Node.js Buffers.
|
|
115
|
+
|
|
116
|
+
#### `compareFilesFromFileObjects(file1, file2, options)`
|
|
117
|
+
Compare files using Web File objects (useful in Browser or Next.js).
|
|
118
|
+
|
|
119
|
+
#### `previewFiles(file1, file2)`
|
|
120
|
+
Get a preview of the files (columns, row counts, and sample data) before committing to a full comparison.
|
|
121
|
+
|
|
122
|
+
### Types
|
|
123
|
+
|
|
124
|
+
#### ComparisonApiResponse
|
|
125
|
+
```typescript
|
|
126
|
+
interface ComparisonApiResponse {
|
|
127
|
+
success: boolean;
|
|
128
|
+
result?: {
|
|
129
|
+
summary: {
|
|
130
|
+
totalRows: number;
|
|
131
|
+
matchesFound: number;
|
|
132
|
+
differencesFound: number;
|
|
133
|
+
uniqueToFile1: number;
|
|
134
|
+
uniqueToFile2: number;
|
|
135
|
+
status: 'SUCCESS' | 'PARTIAL' | 'NO_MATCH';
|
|
136
|
+
};
|
|
137
|
+
matchColumn: string;
|
|
138
|
+
metadata: {
|
|
139
|
+
file1Name: string;
|
|
140
|
+
file1Columns: string[];
|
|
141
|
+
file1RowCount: number;
|
|
142
|
+
file2Name: string;
|
|
143
|
+
file2Columns: string[];
|
|
144
|
+
file2RowCount: number;
|
|
145
|
+
};
|
|
146
|
+
};
|
|
147
|
+
downloadUrl?: string; // Link to the Excel report
|
|
148
|
+
fileName?: string;
|
|
149
|
+
error?: string;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Supported File Formats
|
|
154
|
+
|
|
155
|
+
- `.xlsx` (Excel 2007+)
|
|
156
|
+
- `.xls` (Excel 97-2003)
|
|
157
|
+
- `.csv` (Comma Separated Values)
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
interface ComparisonClientConfig {
|
|
2
|
+
/**
|
|
3
|
+
* KrutAI API key.
|
|
4
|
+
* Optional: defaults to process.env.KRUTAI_API_KEY
|
|
5
|
+
*/
|
|
6
|
+
apiKey?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Base URL of your deployed comparison backend server.
|
|
9
|
+
* @default "http://localhost:8000"
|
|
10
|
+
* @example "https://api.krut.ai"
|
|
11
|
+
*/
|
|
12
|
+
serverUrl?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Request timeout in milliseconds.
|
|
15
|
+
* @default 60000
|
|
16
|
+
*/
|
|
17
|
+
timeout?: number;
|
|
18
|
+
/**
|
|
19
|
+
* Whether to validate the API key against the server on initialization.
|
|
20
|
+
* @default true
|
|
21
|
+
*/
|
|
22
|
+
validateOnInit?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface CompareFilesOptions {
|
|
25
|
+
matchColumn?: string;
|
|
26
|
+
ignoreColumns?: string[];
|
|
27
|
+
tolerance?: number;
|
|
28
|
+
caseSensitive?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface FilePreview {
|
|
31
|
+
name: string;
|
|
32
|
+
rowCount: number;
|
|
33
|
+
columns: string[];
|
|
34
|
+
sample: Record<string, unknown>[];
|
|
35
|
+
}
|
|
36
|
+
interface PreviewResponse {
|
|
37
|
+
success: boolean;
|
|
38
|
+
file1?: FilePreview;
|
|
39
|
+
file2?: FilePreview;
|
|
40
|
+
suggestedMatchColumn?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}
|
|
43
|
+
interface ComparisonApiResponse {
|
|
44
|
+
success: boolean;
|
|
45
|
+
result?: {
|
|
46
|
+
summary: {
|
|
47
|
+
totalRows: number;
|
|
48
|
+
matchesFound: number;
|
|
49
|
+
differencesFound: number;
|
|
50
|
+
uniqueToFile1: number;
|
|
51
|
+
uniqueToFile2: number;
|
|
52
|
+
status: 'SUCCESS' | 'PARTIAL' | 'NO_MATCH';
|
|
53
|
+
};
|
|
54
|
+
matchColumn: string;
|
|
55
|
+
metadata: {
|
|
56
|
+
file1Name: string;
|
|
57
|
+
file1Columns: string[];
|
|
58
|
+
file1RowCount: number;
|
|
59
|
+
file2Name: string;
|
|
60
|
+
file2Columns: string[];
|
|
61
|
+
file2RowCount: number;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
downloadUrl?: string;
|
|
65
|
+
fileName?: string;
|
|
66
|
+
error?: string;
|
|
67
|
+
}
|
|
68
|
+
declare class ComparisonApiClient {
|
|
69
|
+
private serverUrl;
|
|
70
|
+
private apiKey?;
|
|
71
|
+
private timeout;
|
|
72
|
+
private initialized;
|
|
73
|
+
private validateOnInit;
|
|
74
|
+
private initializationPromise;
|
|
75
|
+
constructor(config: ComparisonClientConfig);
|
|
76
|
+
/**
|
|
77
|
+
* Initialize the client.
|
|
78
|
+
* Validates the API key against the server if validateOnInit is true.
|
|
79
|
+
* @throws {Error} If validation fails or API key is missing
|
|
80
|
+
*/
|
|
81
|
+
initialize(): Promise<void>;
|
|
82
|
+
private getHeaders;
|
|
83
|
+
private request;
|
|
84
|
+
compareFiles(file1Buffer: Buffer, file1Name: string, file2Buffer: Buffer, file2Name: string, compareOptions?: CompareFilesOptions): Promise<ComparisonApiResponse>;
|
|
85
|
+
compareFilesFromFileObjects(file1: File, file2: File, compareOptions?: CompareFilesOptions): Promise<ComparisonApiResponse>;
|
|
86
|
+
previewFiles(file1: File, file2: File): Promise<PreviewResponse>;
|
|
87
|
+
previewFilesFromBuffers(file1Buffer: Buffer, file1Name: string, file2Buffer: Buffer, file2Name: string): Promise<PreviewResponse>;
|
|
88
|
+
}
|
|
89
|
+
declare function createComparisonClient(config: ComparisonClientConfig): ComparisonApiClient;
|
|
90
|
+
|
|
91
|
+
interface DataRecord {
|
|
92
|
+
[key: string]: unknown;
|
|
93
|
+
}
|
|
94
|
+
interface ComparisonResult {
|
|
95
|
+
data: DataRecord[];
|
|
96
|
+
summary: {
|
|
97
|
+
totalRows: number;
|
|
98
|
+
differencesFound: number;
|
|
99
|
+
matchesFound: number;
|
|
100
|
+
status: 'SUCCESS' | 'PARTIAL' | 'NO_MATCH';
|
|
101
|
+
};
|
|
102
|
+
metadata?: {
|
|
103
|
+
file1Columns?: string[];
|
|
104
|
+
file2Columns?: string[];
|
|
105
|
+
executionTime?: number;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
interface ExcelLoaderOptions {
|
|
109
|
+
sheetIndex?: number;
|
|
110
|
+
sheetName?: string;
|
|
111
|
+
headerRow?: number;
|
|
112
|
+
skipRows?: number;
|
|
113
|
+
sampleRows?: number;
|
|
114
|
+
}
|
|
115
|
+
interface LoaderOptions {
|
|
116
|
+
sheetName?: string;
|
|
117
|
+
headerRow?: number;
|
|
118
|
+
skipRows?: number;
|
|
119
|
+
}
|
|
120
|
+
interface ReporterOptions {
|
|
121
|
+
headerColor?: string;
|
|
122
|
+
differenceColor?: string;
|
|
123
|
+
matchColor?: string;
|
|
124
|
+
sheetName?: string;
|
|
125
|
+
includeSummary?: boolean;
|
|
126
|
+
}
|
|
127
|
+
interface EngineOptions {
|
|
128
|
+
timeout?: number;
|
|
129
|
+
maxMemory?: number;
|
|
130
|
+
}
|
|
131
|
+
interface CodeGenerationResult {
|
|
132
|
+
code: string;
|
|
133
|
+
humanExplanation: string[];
|
|
134
|
+
constants?: Record<string, unknown>;
|
|
135
|
+
}
|
|
136
|
+
interface ComparisonRequest {
|
|
137
|
+
file1Data: DataRecord[];
|
|
138
|
+
file2Data: DataRecord[];
|
|
139
|
+
file1Columns?: string[];
|
|
140
|
+
file2Columns?: string[];
|
|
141
|
+
file1Sample?: DataRecord[];
|
|
142
|
+
file2Sample?: DataRecord[];
|
|
143
|
+
prompt?: string;
|
|
144
|
+
}
|
|
145
|
+
interface ExcelSchema {
|
|
146
|
+
headers: string[];
|
|
147
|
+
rowCount: number;
|
|
148
|
+
columnCount: number;
|
|
149
|
+
sample: DataRecord[];
|
|
150
|
+
data: DataRecord[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
declare class StyledReporter {
|
|
154
|
+
private options;
|
|
155
|
+
constructor(options?: ReporterOptions);
|
|
156
|
+
generateReport(result: ComparisonResult, _file1Columns?: string[], _file2Columns?: string[]): Promise<Buffer>;
|
|
157
|
+
private addSummarySheet;
|
|
158
|
+
private addResultSheet;
|
|
159
|
+
private formatValue;
|
|
160
|
+
generateDetailedReport(result: ComparisonResult, file1Columns?: string[], file2Columns?: string[]): Promise<Buffer>;
|
|
161
|
+
private addDataSheet;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface ExcelDataFrame {
|
|
165
|
+
headers: string[];
|
|
166
|
+
data: DataRecord[];
|
|
167
|
+
rowCount: number;
|
|
168
|
+
columnCount: number;
|
|
169
|
+
sample: DataRecord[];
|
|
170
|
+
}
|
|
171
|
+
declare class DataLoader {
|
|
172
|
+
static loadFromBuffer(buffer: Buffer, fileName: string, options?: ExcelLoaderOptions): Promise<ExcelDataFrame>;
|
|
173
|
+
static getColumnNames(data: DataRecord[]): string[];
|
|
174
|
+
static getSampleData(data: DataRecord[], count?: number): DataRecord[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* krutExcelComparison — convenience factory.
|
|
179
|
+
*
|
|
180
|
+
* Creates a `ComparisonApiClient` instance configured to call the Krut comparison server.
|
|
181
|
+
*
|
|
182
|
+
* @param config - Client configuration (apiKey and serverUrl)
|
|
183
|
+
* @returns A `ComparisonApiClient` instance
|
|
184
|
+
*/
|
|
185
|
+
declare function krutExcelComparison(config: ComparisonClientConfig): ComparisonApiClient;
|
|
186
|
+
|
|
187
|
+
export { type FilePreview as ApiFilePreview, type CodeGenerationResult, type CompareFilesOptions, ComparisonApiClient, type ComparisonApiResponse, type ComparisonClientConfig, type ComparisonRequest, type ComparisonResult, DataLoader, type DataRecord, type EngineOptions, type ExcelLoaderOptions, type ExcelSchema, type LoaderOptions, type PreviewResponse, type ReporterOptions, StyledReporter, createComparisonClient, krutExcelComparison };
|