autoform-mcp-server 1.3.0 → 1.4.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.js +7 -3
- package/dist/services/pdfService.d.ts +10 -0
- package/dist/services/pdfService.js +80 -0
- package/dist/tools/detectFields.js +12 -1
- package/dist/tools/fillAtCoordinates.js +3 -1
- package/dist/tools/fillBatchAcroForm.d.ts +52 -0
- package/dist/tools/fillBatchAcroForm.js +96 -0
- package/dist/tools/fillPdf.js +9 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,11 +6,12 @@ import { handleDetectFields, detectFieldsSchema } from './tools/detectFields.js'
|
|
|
6
6
|
import { handleFillPdf, fillPdfSchema } from './tools/fillPdf.js';
|
|
7
7
|
import { handleFillAtCoordinates, fillAtCoordinatesSchema, handleGetPdfInfo, getPdfInfoSchema } from './tools/fillAtCoordinates.js';
|
|
8
8
|
import { handleFillBatchAtCoordinates, fillBatchAtCoordinatesSchema } from './tools/fillBatchAtCoordinates.js';
|
|
9
|
+
import { handleFillBatchAcroForm, fillBatchAcroFormSchema } from './tools/fillBatchAcroForm.js';
|
|
9
10
|
import { handleSaveCoordinatesAsTemplate, saveCoordinatesAsTemplateSchema } from './tools/saveCoordinatesAsTemplate.js';
|
|
10
11
|
import { handleGenerateBatch, generateBatchSchema } from './tools/generateBatch.js';
|
|
11
12
|
import { handleListTemplates, listTemplatesSchema } from './tools/manageTemplates.js';
|
|
12
13
|
import { handleImportTemplate, importTemplateSchema } from './tools/importTemplate.js';
|
|
13
|
-
const server = new Server({ name: 'autoform', version: '1.
|
|
14
|
+
const server = new Server({ name: 'autoform', version: '1.4.0' }, { capabilities: { tools: {} } });
|
|
14
15
|
// Register all tools
|
|
15
16
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
16
17
|
tools: [
|
|
@@ -20,7 +21,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
20
21
|
// Single fill
|
|
21
22
|
fillPdfSchema,
|
|
22
23
|
fillAtCoordinatesSchema,
|
|
23
|
-
// Batch fill
|
|
24
|
+
// Batch fill (preferred for multiple documents)
|
|
25
|
+
fillBatchAcroFormSchema,
|
|
24
26
|
fillBatchAtCoordinatesSchema,
|
|
25
27
|
generateBatchSchema,
|
|
26
28
|
// Template management
|
|
@@ -44,6 +46,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
44
46
|
return await handleFillAtCoordinates(args);
|
|
45
47
|
case 'autoform_fill_batch_at_coordinates':
|
|
46
48
|
return await handleFillBatchAtCoordinates(args);
|
|
49
|
+
case 'autoform_fill_batch_acroform':
|
|
50
|
+
return await handleFillBatchAcroForm(args);
|
|
47
51
|
case 'autoform_save_coordinates_as_template':
|
|
48
52
|
return await handleSaveCoordinatesAsTemplate(args);
|
|
49
53
|
case 'autoform_generate_batch':
|
|
@@ -66,4 +70,4 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
66
70
|
// Start server
|
|
67
71
|
const transport = new StdioServerTransport();
|
|
68
72
|
await server.connect(transport);
|
|
69
|
-
console.error('[AutoForm MCP] Server v1.
|
|
73
|
+
console.error('[AutoForm MCP] Server v1.4.0 started — 10 tools registered');
|
|
@@ -11,6 +11,16 @@ export declare class PdfService {
|
|
|
11
11
|
}>;
|
|
12
12
|
/** Fill AcroForm fields and save */
|
|
13
13
|
static fillAcroForm(pdfPath: string, values: Record<string, string>, outputPath: string): Promise<number>;
|
|
14
|
+
/**
|
|
15
|
+
* Batch fill AcroForm: generate N PDFs from the same base PDF, one per data row.
|
|
16
|
+
* If merge=true, all outputs are concatenated into a single PDF and temp files are cleaned.
|
|
17
|
+
* Optionally accepts a fieldMap to translate logical data keys → technical AcroForm field names.
|
|
18
|
+
*/
|
|
19
|
+
static batchFillAcroForm(pdfPath: string, dataRows: Array<Record<string, string>>, outputDir: string, baseName: string, merge?: boolean, fieldMap?: Record<string, string>): Promise<{
|
|
20
|
+
outputPaths: string[];
|
|
21
|
+
mergedPath?: string;
|
|
22
|
+
errors: string[];
|
|
23
|
+
}>;
|
|
14
24
|
/** Fill PDF using template coordinates (drawText), same logic as web app's pdfGenerator */
|
|
15
25
|
static fillWithTemplate(pdfPath: string, fields: FieldBox[], values: Record<string, string>, outputPath: string): Promise<number>;
|
|
16
26
|
/**
|
|
@@ -98,6 +98,86 @@ export class PdfService {
|
|
|
98
98
|
fs.writeFileSync(outputPath, savedBytes);
|
|
99
99
|
return filled;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Batch fill AcroForm: generate N PDFs from the same base PDF, one per data row.
|
|
103
|
+
* If merge=true, all outputs are concatenated into a single PDF and temp files are cleaned.
|
|
104
|
+
* Optionally accepts a fieldMap to translate logical data keys → technical AcroForm field names.
|
|
105
|
+
*/
|
|
106
|
+
static async batchFillAcroForm(pdfPath, dataRows, outputDir, baseName, merge = false, fieldMap) {
|
|
107
|
+
const outputPaths = [];
|
|
108
|
+
const errors = [];
|
|
109
|
+
const timestamp = new Date().toISOString().slice(0, 10);
|
|
110
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
111
|
+
const workingDir = merge
|
|
112
|
+
? fs.mkdtempSync(path.join(outputDir, '.tmp_batch_'))
|
|
113
|
+
: outputDir;
|
|
114
|
+
// Load the base PDF once
|
|
115
|
+
const bytes = fs.readFileSync(pdfPath);
|
|
116
|
+
for (let i = 0; i < dataRows.length; i++) {
|
|
117
|
+
try {
|
|
118
|
+
const row = dataRows[i];
|
|
119
|
+
// Translate logical keys to technical field names if a map is provided
|
|
120
|
+
const resolvedValues = {};
|
|
121
|
+
for (const [key, value] of Object.entries(row)) {
|
|
122
|
+
const technicalName = fieldMap?.[key] ?? key;
|
|
123
|
+
resolvedValues[technicalName] = String(value ?? '');
|
|
124
|
+
}
|
|
125
|
+
const num = String(i + 1).padStart(3, '0');
|
|
126
|
+
const outPath = path.join(workingDir, `${baseName}_${num}_${timestamp}.pdf`);
|
|
127
|
+
// Re-load each iteration to get a fresh form instance
|
|
128
|
+
const pdfDoc = await PDFDocument.load(bytes);
|
|
129
|
+
const form = pdfDoc.getForm();
|
|
130
|
+
for (const [name, value] of Object.entries(resolvedValues)) {
|
|
131
|
+
try {
|
|
132
|
+
const field = form.getField(name);
|
|
133
|
+
if (field instanceof PDFTextField) {
|
|
134
|
+
field.setText(value);
|
|
135
|
+
}
|
|
136
|
+
else if (field instanceof PDFCheckBox) {
|
|
137
|
+
if (['true', '1', 'yes', 'si', 'sí'].includes(value.toLowerCase()))
|
|
138
|
+
field.check();
|
|
139
|
+
else
|
|
140
|
+
field.uncheck();
|
|
141
|
+
}
|
|
142
|
+
else if (field instanceof PDFDropdown) {
|
|
143
|
+
field.select(value);
|
|
144
|
+
}
|
|
145
|
+
else if (field instanceof PDFRadioGroup) {
|
|
146
|
+
field.select(value);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Field not found — skip silently
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
form.flatten();
|
|
154
|
+
const savedBytes = await pdfDoc.save();
|
|
155
|
+
fs.writeFileSync(outPath, savedBytes);
|
|
156
|
+
outputPaths.push(outPath);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
errors.push(`Fila ${i + 1}: ${err instanceof Error ? err.message : String(err)}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let mergedPath;
|
|
163
|
+
if (merge && outputPaths.length > 0) {
|
|
164
|
+
mergedPath = path.join(outputDir, `${baseName}_merged_${timestamp}.pdf`);
|
|
165
|
+
await this.mergePdfs(outputPaths, mergedPath);
|
|
166
|
+
// Clean up temp files and dir
|
|
167
|
+
for (const p of outputPaths) {
|
|
168
|
+
try {
|
|
169
|
+
fs.unlinkSync(p);
|
|
170
|
+
}
|
|
171
|
+
catch { /* ignore */ }
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
fs.rmdirSync(workingDir);
|
|
175
|
+
}
|
|
176
|
+
catch { /* ignore */ }
|
|
177
|
+
return { outputPaths: [], mergedPath, errors };
|
|
178
|
+
}
|
|
179
|
+
return { outputPaths, mergedPath, errors };
|
|
180
|
+
}
|
|
101
181
|
/** Fill PDF using template coordinates (drawText), same logic as web app's pdfGenerator */
|
|
102
182
|
static async fillWithTemplate(pdfPath, fields, values, outputPath) {
|
|
103
183
|
const bytes = fs.readFileSync(pdfPath);
|
|
@@ -5,7 +5,18 @@ export const detectFieldsSchema = {
|
|
|
5
5
|
|
|
6
6
|
CUANDO USAR: El PDF es un formulario donde puedes hacer click y escribir. Si el PDF es una imagen/diseño estatico (certificado, diploma), esta tool dira "sin campos" — en ese caso usa autoform_get_pdf_info + analisis visual.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
⚠️ IMPORTANTE — Los nombres tecnicos NO son los labels visibles:
|
|
9
|
+
- Esta tool devuelve nombres TECNICOS internos del PDF (ej: "Text1", "fld_001", "untitled_field"), que pueden NO coincidir con los labels visibles ("Nombre:", "Apellido:", "DNI:").
|
|
10
|
+
- NO asumas el significado de cada campo por su nombre tecnico ni por su posicion.
|
|
11
|
+
- DESPUES de detectar los campos, DEBES mirar el PDF visualmente (ya puedes ver PDFs como imagenes) y correlacionar cada campo tecnico con su label visible usando las coordenadas (x, y, page) que devuelve esta tool.
|
|
12
|
+
- Solo DESPUES de esa correlacion visual procede a llenar con los datos correctos.
|
|
13
|
+
|
|
14
|
+
FLUJO RECOMENDADO:
|
|
15
|
+
1. autoform_detect_fields → obtienes lista de campos tecnicos con coordenadas
|
|
16
|
+
2. MIRAS EL PDF VISUALMENTE → asocias cada coordenada con el label visible cercano
|
|
17
|
+
3. Decides que dato va en que campo tecnico
|
|
18
|
+
4. Para UN documento: autoform_fill_pdf con field_values={"nombre_tecnico": "valor"}
|
|
19
|
+
5. Para MULTIPLES documentos (batch): autoform_fill_batch_acroform con data_rows y field_map si las claves son logicas.`,
|
|
9
20
|
inputSchema: {
|
|
10
21
|
type: 'object',
|
|
11
22
|
properties: {
|
|
@@ -4,9 +4,11 @@ import { PdfService } from '../services/pdfService.js';
|
|
|
4
4
|
const OUTPUT_DIR = path.join(os.homedir(), '.autoform-mcp', 'output');
|
|
5
5
|
export const fillAtCoordinatesSchema = {
|
|
6
6
|
name: 'autoform_fill_at_coordinates',
|
|
7
|
-
description: `Escribe texto en posiciones exactas de
|
|
7
|
+
description: `Escribe texto en posiciones exactas de UN PDF usando coordenadas en puntos PDF (origen: esquina inferior-izquierda).
|
|
8
8
|
Ideal cuando Claude analiza visualmente un PDF y determina dónde colocar el texto.
|
|
9
9
|
|
|
10
|
+
⚠️ ESTA TOOL ES PARA UN UNICO DOCUMENTO. Si necesitas generar multiples PDFs con los mismos campos pero datos diferentes, USA autoform_fill_batch_at_coordinates (mas eficiente, una sola llamada).
|
|
11
|
+
|
|
10
12
|
IMPORTANTE — Codificación de texto:
|
|
11
13
|
- El texto se pasa EXACTAMENTE como lo envías. NO simplifiques ni modifiques caracteres.
|
|
12
14
|
- Acentos españoles (á é í ó ú ñ Ñ ü) están soportados completamente.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare const fillBatchAcroFormSchema: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
pdf_path: {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
data_rows: {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
items: {
|
|
15
|
+
type: string;
|
|
16
|
+
additionalProperties: {
|
|
17
|
+
type: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
field_map: {
|
|
22
|
+
type: string;
|
|
23
|
+
description: string;
|
|
24
|
+
additionalProperties: {
|
|
25
|
+
type: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
merge_into_single: {
|
|
29
|
+
type: string;
|
|
30
|
+
description: string;
|
|
31
|
+
};
|
|
32
|
+
output_dir: {
|
|
33
|
+
type: string;
|
|
34
|
+
description: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
required: string[];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export declare function handleFillBatchAcroForm(args: any): Promise<{
|
|
41
|
+
content: {
|
|
42
|
+
type: "text";
|
|
43
|
+
text: string;
|
|
44
|
+
}[];
|
|
45
|
+
isError: boolean;
|
|
46
|
+
} | {
|
|
47
|
+
content: {
|
|
48
|
+
type: "text";
|
|
49
|
+
text: string;
|
|
50
|
+
}[];
|
|
51
|
+
isError?: undefined;
|
|
52
|
+
}>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import * as os from 'os';
|
|
3
|
+
import { PdfService } from '../services/pdfService.js';
|
|
4
|
+
const OUTPUT_DIR = path.join(os.homedir(), '.autoform-mcp', 'output');
|
|
5
|
+
export const fillBatchAcroFormSchema = {
|
|
6
|
+
name: 'autoform_fill_batch_acroform',
|
|
7
|
+
description: `Genera MULTIPLES PDFs a partir de un PDF con campos AcroForm (formulario interactivo) + array de datos. Una sola llamada genera N documentos.
|
|
8
|
+
|
|
9
|
+
CUANDO USAR: El PDF base tiene campos AcroForm (detectados con autoform_detect_fields) y el usuario quiere llenarlos con datos de varias personas/filas. Escalable a cientos de documentos en una sola llamada.
|
|
10
|
+
|
|
11
|
+
NO USAR SI: El PDF es estatico (sin AcroForm) → usa autoform_fill_batch_at_coordinates.
|
|
12
|
+
NO USAR SI: Solo necesitas llenar UN documento → usa autoform_fill_pdf.
|
|
13
|
+
|
|
14
|
+
IMPORTANTE sobre nombres de campos:
|
|
15
|
+
- Los campos AcroForm tienen nombres TECNICOS (ej: "Text1", "fld_nombre", "field_001") que NO siempre coinciden con los labels visibles del PDF.
|
|
16
|
+
- DESPUES de llamar autoform_detect_fields, DEBES MIRAR EL PDF VISUALMENTE para correlacionar cada campo tecnico con su label visible segun sus coordenadas.
|
|
17
|
+
- Si las claves de tus data_rows NO coinciden con los nombres tecnicos, usa el parametro field_map para traducir: { "nombre_logico": "nombre_tecnico" }
|
|
18
|
+
- Ejemplo: si el campo tecnico es "Text1" pero visualmente corresponde al label "Nombre:", pasa field_map={"nombre": "Text1"} y data_rows=[{"nombre": "Juan"}]
|
|
19
|
+
|
|
20
|
+
MERGE: Si merge_into_single=true, se genera SOLO el PDF unificado (los individuales son temporales y se borran automaticamente).
|
|
21
|
+
|
|
22
|
+
CODIFICACION: Los datos se escriben EXACTAMENTE como los envias. Acentos espanoles (a e i o u n N u con tildes) estan completamente soportados. NO simplifiques caracteres.`,
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
pdf_path: {
|
|
27
|
+
type: 'string',
|
|
28
|
+
description: 'Ruta absoluta al PDF con AcroForm'
|
|
29
|
+
},
|
|
30
|
+
data_rows: {
|
|
31
|
+
type: 'array',
|
|
32
|
+
description: 'Array de objetos, cada objeto es un documento. Claves = nombre del campo (tecnico o logico si usas field_map), valores = texto a escribir.',
|
|
33
|
+
items: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
additionalProperties: { type: 'string' }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
field_map: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
description: '(Opcional) Mapeo de nombres logicos a nombres tecnicos de AcroForm. Formato: {"nombre_logico": "nombre_tecnico"}. Usalo cuando las claves de data_rows son mas legibles que los nombres tecnicos reales del PDF.',
|
|
41
|
+
additionalProperties: { type: 'string' }
|
|
42
|
+
},
|
|
43
|
+
merge_into_single: {
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
description: '(Opcional) Si true, une todos los PDFs en uno solo y elimina los individuales. Default: false.'
|
|
46
|
+
},
|
|
47
|
+
output_dir: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: '(Opcional) Directorio de salida. Default: ~/.autoform-mcp/output/'
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
required: ['pdf_path', 'data_rows']
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
export async function handleFillBatchAcroForm(args) {
|
|
56
|
+
const { pdf_path, output_dir, merge_into_single = false } = args;
|
|
57
|
+
let data_rows = args.data_rows;
|
|
58
|
+
if (typeof data_rows === 'string') {
|
|
59
|
+
try {
|
|
60
|
+
data_rows = JSON.parse(data_rows);
|
|
61
|
+
}
|
|
62
|
+
catch { /* keep */ }
|
|
63
|
+
}
|
|
64
|
+
let field_map = args.field_map;
|
|
65
|
+
if (typeof field_map === 'string') {
|
|
66
|
+
try {
|
|
67
|
+
field_map = JSON.parse(field_map);
|
|
68
|
+
}
|
|
69
|
+
catch { /* keep */ }
|
|
70
|
+
}
|
|
71
|
+
if (!data_rows || !Array.isArray(data_rows) || data_rows.length === 0) {
|
|
72
|
+
return {
|
|
73
|
+
content: [{ type: 'text', text: JSON.stringify({ error: true, message: 'data_rows es requerido (array de objetos con datos)' }, null, 2) }],
|
|
74
|
+
isError: true
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const outDir = output_dir || OUTPUT_DIR;
|
|
78
|
+
const baseName = path.basename(pdf_path, '.pdf').replace(/[^a-zA-Z0-9_\-]/g, '_');
|
|
79
|
+
const result = await PdfService.batchFillAcroForm(pdf_path, data_rows, outDir, baseName, merge_into_single, field_map);
|
|
80
|
+
return {
|
|
81
|
+
content: [{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: JSON.stringify({
|
|
84
|
+
documents_generated: merge_into_single ? data_rows.length - result.errors.length : result.outputPaths.length,
|
|
85
|
+
output_paths: result.outputPaths,
|
|
86
|
+
merged_path: result.mergedPath,
|
|
87
|
+
errors: result.errors,
|
|
88
|
+
message: result.mergedPath
|
|
89
|
+
? `Generados ${data_rows.length - result.errors.length} documentos unidos en: ${result.mergedPath}`
|
|
90
|
+
: result.outputPaths.length > 0
|
|
91
|
+
? `Generados ${result.outputPaths.length} documentos en ${outDir}`
|
|
92
|
+
: `Error: ${result.errors.join(', ')}`
|
|
93
|
+
}, null, 2)
|
|
94
|
+
}]
|
|
95
|
+
};
|
|
96
|
+
}
|
package/dist/tools/fillPdf.js
CHANGED
|
@@ -5,11 +5,16 @@ import { TemplateStore } from '../services/templateStore.js';
|
|
|
5
5
|
const OUTPUT_DIR = path.join(os.homedir(), '.autoform-mcp', 'output');
|
|
6
6
|
export const fillPdfSchema = {
|
|
7
7
|
name: 'autoform_fill_pdf',
|
|
8
|
-
description: `Llena UN PDF con valores. Detecta automaticamente si tiene AcroForm o usa un template guardado.
|
|
8
|
+
description: `Llena UN SOLO PDF con valores. Detecta automaticamente si tiene AcroForm o usa un template guardado.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
⚠️ ESTA TOOL ES PARA UN UNICO DOCUMENTO. Si necesitas generar 2 o mas documentos, USA UNA TOOL BATCH (mas eficiente, menos llamadas):
|
|
11
|
+
- PDF con AcroForm + multiples filas → autoform_fill_batch_acroform
|
|
12
|
+
- PDF estatico + multiples filas → autoform_fill_batch_at_coordinates
|
|
13
|
+
- Template guardado + multiples filas → autoform_generate_batch
|
|
14
|
+
|
|
15
|
+
CUANDO USAR: Solo cuando el usuario pide llenar UN documento especifico.
|
|
16
|
+
NO USAR PARA BATCH: Nunca llames esta tool en loop para generar multiples PDFs — usa las tools batch que existen para eso.
|
|
17
|
+
NO USAR SI: El PDF es estatico sin template → usa autoform_fill_at_coordinates.`,
|
|
13
18
|
inputSchema: {
|
|
14
19
|
type: 'object',
|
|
15
20
|
properties: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autoform-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "MCP server for bulk PDF form filling. Detect fields, fill templates, and generate hundreds of PDFs from data — directly from Claude.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|