@skillful-ai/piece-latex-to-pdf 0.0.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/CHECKLIST.md +817 -0
- package/README.md +117 -0
- package/package.json +26 -0
- package/src/index.d.ts +4 -0
- package/src/index.js +19 -0
- package/src/index.js.map +1 -0
- package/src/lib/actions/compile-latex.d.ts +9 -0
- package/src/lib/actions/compile-latex.js +116 -0
- package/src/lib/actions/compile-latex.js.map +1 -0
- package/src/lib/auth.d.ts +8 -0
- package/src/lib/auth.js +21 -0
- package/src/lib/auth.js.map +1 -0
- package/src/lib/common.d.ts +62 -0
- package/src/lib/common.js +103 -0
- package/src/lib/common.js.map +1 -0
package/CHECKLIST.md
ADDED
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
# LaTeX to PDF Piece - Checklist de Implementación
|
|
2
|
+
|
|
3
|
+
## 📋 Contexto
|
|
4
|
+
|
|
5
|
+
Esta pieza permite compilar documentos LaTeX a PDF usando un servicio externo desplegado en AWS Lambda.
|
|
6
|
+
|
|
7
|
+
**Servicio Backend:**
|
|
8
|
+
- URL: `https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev`
|
|
9
|
+
- Documentación: `https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev/docs`
|
|
10
|
+
|
|
11
|
+
**API del servicio:**
|
|
12
|
+
| Método | Endpoint | Descripción |
|
|
13
|
+
|--------|----------|-------------|
|
|
14
|
+
| `POST` | `/compile` | Envía LaTeX para compilar (async, retorna job_id) |
|
|
15
|
+
| `GET` | `/compile/{job_id}` | Obtiene estado del job (polling) |
|
|
16
|
+
| `GET` | `/health` | Health check |
|
|
17
|
+
|
|
18
|
+
**Flujo de compilación:**
|
|
19
|
+
1. `POST /compile` con `file_content` (base64), `filename`, `compiler`, `output_format`
|
|
20
|
+
2. Respuesta: `{ job_id, status: "pending" }`
|
|
21
|
+
3. Polling `GET /compile/{job_id}` hasta `status: "completed"`
|
|
22
|
+
4. Resultado: `{ pdf_url, log_url, duration_ms, ... }`
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 📁 Estructura de Directorios
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
packages/pieces/custom/latex-to-pdf/
|
|
30
|
+
├── .eslintrc.json # [1] Config ESLint
|
|
31
|
+
├── package.json # [2] Dependencias npm
|
|
32
|
+
├── project.json # [3] Config Nx (build, test, lint)
|
|
33
|
+
├── tsconfig.json # [4] TypeScript base
|
|
34
|
+
├── tsconfig.lib.json # [5] TypeScript para build
|
|
35
|
+
├── tsconfig.spec.json # [6] TypeScript para tests
|
|
36
|
+
├── jest.config.ts # [7] Config Jest
|
|
37
|
+
├── README.md # [8] Documentación de la pieza
|
|
38
|
+
├── src/
|
|
39
|
+
│ ├── index.ts # [9] Entry point - exporta la pieza
|
|
40
|
+
│ └── lib/
|
|
41
|
+
│ ├── auth.ts # [10] Autenticación (URL + API key)
|
|
42
|
+
│ ├── common.ts # [11] Helpers (polling, API calls)
|
|
43
|
+
│ └── actions/
|
|
44
|
+
│ └── compile-latex.ts # [12] Acción principal
|
|
45
|
+
└── test/
|
|
46
|
+
└── compile-latex.test.ts # [13] Tests unitarios
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## ✅ Checklist (Orden de Implementación)
|
|
52
|
+
|
|
53
|
+
### Fase 1: Configuración del Proyecto
|
|
54
|
+
|
|
55
|
+
#### [1] `.eslintrc.json`
|
|
56
|
+
**Qué hace:** Configura ESLint para el linting del código.
|
|
57
|
+
**Copiar de:** `packages/pieces/custom/web/.eslintrc.json`
|
|
58
|
+
**Cambios:** Ninguno, es genérico.
|
|
59
|
+
|
|
60
|
+
```jsonc
|
|
61
|
+
{
|
|
62
|
+
"extends": ["../../../../.eslintrc.base.json"],
|
|
63
|
+
"ignorePatterns": ["!**/*"],
|
|
64
|
+
"overrides": [
|
|
65
|
+
{ "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], "rules": {} },
|
|
66
|
+
{ "files": ["*.ts", "*.tsx"], "rules": {} },
|
|
67
|
+
{ "files": ["*.js", "*.jsx"], "rules": {} }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
#### [2] `package.json`
|
|
75
|
+
**Qué hace:** Define el paquete npm, nombre, versión y dependencias.
|
|
76
|
+
**Importante:** El nombre debe seguir el patrón `@skillful-ai/piece-<nombre>`.
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"name": "@skillful-ai/piece-latex-to-pdf",
|
|
81
|
+
"version": "0.0.1",
|
|
82
|
+
"type": "commonjs",
|
|
83
|
+
"main": "./src/index.js",
|
|
84
|
+
"types": "./src/index.d.ts",
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"@activepieces/pieces-common": "*",
|
|
87
|
+
"@activepieces/pieces-framework": "*",
|
|
88
|
+
"@activepieces/shared": "*",
|
|
89
|
+
"tslib": "^2.3.0"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
#### [3] `project.json`
|
|
97
|
+
**Qué hace:** Configura Nx para build, test y lint.
|
|
98
|
+
**Importante:**
|
|
99
|
+
- `name` debe ser `pieces-latex-to-pdf`
|
|
100
|
+
- Actualizar todos los paths a `latex-to-pdf`
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"name": "pieces-latex-to-pdf",
|
|
105
|
+
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
|
106
|
+
"sourceRoot": "packages/pieces/custom/latex-to-pdf/src",
|
|
107
|
+
"projectType": "library",
|
|
108
|
+
"release": {
|
|
109
|
+
"version": {
|
|
110
|
+
"manifestRootsToUpdate": ["dist/{projectRoot}"],
|
|
111
|
+
"currentVersionResolver": "git-tag",
|
|
112
|
+
"fallbackCurrentVersionResolver": "disk"
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"tags": [],
|
|
116
|
+
"targets": {
|
|
117
|
+
"build": {
|
|
118
|
+
"executor": "@nx/js:tsc",
|
|
119
|
+
"outputs": ["{options.outputPath}"],
|
|
120
|
+
"options": {
|
|
121
|
+
"outputPath": "dist/packages/pieces/custom/latex-to-pdf",
|
|
122
|
+
"tsConfig": "packages/pieces/custom/latex-to-pdf/tsconfig.lib.json",
|
|
123
|
+
"packageJson": "packages/pieces/custom/latex-to-pdf/package.json",
|
|
124
|
+
"main": "packages/pieces/custom/latex-to-pdf/src/index.ts",
|
|
125
|
+
"assets": ["packages/pieces/custom/latex-to-pdf/*.md"],
|
|
126
|
+
"buildableProjectDepsInPackageJsonType": "dependencies",
|
|
127
|
+
"updateBuildableProjectDepsInPackageJson": true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"test": {
|
|
131
|
+
"executor": "@nx/jest:jest",
|
|
132
|
+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
133
|
+
"options": {
|
|
134
|
+
"jestConfig": "packages/pieces/custom/latex-to-pdf/jest.config.ts"
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"nx-release-publish": {
|
|
138
|
+
"options": {
|
|
139
|
+
"packageRoot": "dist/{projectRoot}"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"lint": {
|
|
143
|
+
"executor": "@nx/eslint:lint",
|
|
144
|
+
"outputs": ["{options.outputFile}"]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
#### [4] `tsconfig.json`
|
|
153
|
+
**Qué hace:** Config base de TypeScript que extiende del monorepo.
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"extends": "../../../../tsconfig.base.json",
|
|
158
|
+
"compilerOptions": {
|
|
159
|
+
"module": "commonjs",
|
|
160
|
+
"forceConsistentCasingInFileNames": true,
|
|
161
|
+
"strict": true,
|
|
162
|
+
"importHelpers": true,
|
|
163
|
+
"noImplicitOverride": true,
|
|
164
|
+
"noImplicitReturns": true,
|
|
165
|
+
"noFallthroughCasesInSwitch": true,
|
|
166
|
+
"noPropertyAccessFromIndexSignature": true
|
|
167
|
+
},
|
|
168
|
+
"files": [],
|
|
169
|
+
"include": [],
|
|
170
|
+
"references": [
|
|
171
|
+
{ "path": "./tsconfig.lib.json" }
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
#### [5] `tsconfig.lib.json`
|
|
179
|
+
**Qué hace:** Config TypeScript para el build de producción.
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"extends": "./tsconfig.json",
|
|
184
|
+
"compilerOptions": {
|
|
185
|
+
"outDir": "../../../../dist/out-tsc",
|
|
186
|
+
"declaration": true,
|
|
187
|
+
"types": ["node"]
|
|
188
|
+
},
|
|
189
|
+
"include": ["src/**/*.ts"],
|
|
190
|
+
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
#### [6] `tsconfig.spec.json`
|
|
197
|
+
**Qué hace:** Config TypeScript para tests.
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"extends": "./tsconfig.json",
|
|
202
|
+
"compilerOptions": {
|
|
203
|
+
"outDir": "../../../../dist/out-tsc",
|
|
204
|
+
"module": "commonjs",
|
|
205
|
+
"moduleResolution": "node10",
|
|
206
|
+
"types": ["jest", "node"]
|
|
207
|
+
},
|
|
208
|
+
"include": [
|
|
209
|
+
"jest.config.ts",
|
|
210
|
+
"src/**/*.test.ts",
|
|
211
|
+
"src/**/*.spec.ts",
|
|
212
|
+
"test/**/*.test.ts",
|
|
213
|
+
"test/**/*.spec.ts"
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
#### [7] `jest.config.ts`
|
|
221
|
+
**Qué hace:** Configura Jest para tests unitarios.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
export default {
|
|
225
|
+
displayName: 'pieces-latex-to-pdf',
|
|
226
|
+
preset: '../../../../jest.preset.js',
|
|
227
|
+
testEnvironment: 'node',
|
|
228
|
+
transform: {
|
|
229
|
+
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
|
230
|
+
},
|
|
231
|
+
moduleFileExtensions: ['ts', 'js', 'html'],
|
|
232
|
+
coverageDirectory: '../../../../coverage/packages/pieces/custom/latex-to-pdf',
|
|
233
|
+
passWithNoTests: true,
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
#### [8] `README.md`
|
|
240
|
+
**Qué hace:** Documentación de la pieza para desarrolladores.
|
|
241
|
+
|
|
242
|
+
```markdown
|
|
243
|
+
# LaTeX to PDF Piece
|
|
244
|
+
|
|
245
|
+
Compile LaTeX documents to PDF using the Skillful LaTeX Compiler Service.
|
|
246
|
+
|
|
247
|
+
## Features
|
|
248
|
+
|
|
249
|
+
- Compile `.tex` files or `.zip` archives to PDF
|
|
250
|
+
- Support for `pdflatex` and `xelatex` compilers
|
|
251
|
+
- Multiple output formats: URL, base64, or raw bytes
|
|
252
|
+
- Async compilation with automatic polling
|
|
253
|
+
|
|
254
|
+
## Authentication
|
|
255
|
+
|
|
256
|
+
Configure the piece with:
|
|
257
|
+
- **Service URL** (optional): Custom LaTeX service URL. Defaults to Skillful's service.
|
|
258
|
+
- **API Key** (optional): For authenticated requests.
|
|
259
|
+
|
|
260
|
+
## Actions
|
|
261
|
+
|
|
262
|
+
### Compile LaTeX
|
|
263
|
+
|
|
264
|
+
Compiles a LaTeX document and returns the PDF.
|
|
265
|
+
|
|
266
|
+
**Inputs:**
|
|
267
|
+
- `latexContent`: The LaTeX source code
|
|
268
|
+
- `filename`: Filename (e.g., `main.tex`)
|
|
269
|
+
- `compiler`: `pdflatex` or `xelatex`
|
|
270
|
+
- `outputFormat`: `url`, `base64`, or `bytes`
|
|
271
|
+
|
|
272
|
+
**Outputs:**
|
|
273
|
+
- `success`: boolean
|
|
274
|
+
- `pdfUrl`: Presigned URL to download PDF
|
|
275
|
+
- `logUrl`: Presigned URL to download compilation log
|
|
276
|
+
- `durationMs`: Compilation time in milliseconds
|
|
277
|
+
|
|
278
|
+
## Building
|
|
279
|
+
|
|
280
|
+
\`\`\`bash
|
|
281
|
+
npx nx build pieces-latex-to-pdf
|
|
282
|
+
\`\`\`
|
|
283
|
+
|
|
284
|
+
## Testing
|
|
285
|
+
|
|
286
|
+
\`\`\`bash
|
|
287
|
+
npx nx test pieces-latex-to-pdf
|
|
288
|
+
\`\`\`
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
### Fase 2: Código de la Pieza
|
|
294
|
+
|
|
295
|
+
#### [9] `src/index.ts`
|
|
296
|
+
**Qué hace:** Entry point que exporta la pieza con `createPiece()`.
|
|
297
|
+
**Importa:** auth, actions
|
|
298
|
+
**Registra:** La pieza en el sistema de Activepieces.
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { createPiece } from "@activepieces/pieces-framework";
|
|
302
|
+
import { PieceCategory } from "@activepieces/shared";
|
|
303
|
+
import { latexToPdfAuth } from "./lib/auth";
|
|
304
|
+
import { compileLatex } from "./lib/actions/compile-latex";
|
|
305
|
+
|
|
306
|
+
export const latexToPdf = createPiece({
|
|
307
|
+
displayName: "LaTeX to PDF",
|
|
308
|
+
description: "Compile LaTeX documents to PDF using a cloud compilation service.",
|
|
309
|
+
auth: latexToPdfAuth,
|
|
310
|
+
minimumSupportedRelease: "0.36.1",
|
|
311
|
+
logoUrl: "https://cdn.activepieces.com/pieces/latex.png", // TODO: Actualizar con logo real
|
|
312
|
+
categories: [PieceCategory.CORE],
|
|
313
|
+
authors: ["skillful-ai"],
|
|
314
|
+
actions: [compileLatex],
|
|
315
|
+
triggers: [],
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
#### [10] `src/lib/auth.ts`
|
|
322
|
+
**Qué hace:** Define la autenticación de la pieza.
|
|
323
|
+
**Campos:**
|
|
324
|
+
- `serviceUrl` (opcional): URL del servicio LaTeX (default: nuestro servicio)
|
|
325
|
+
- `apiKey` (opcional): API key para autenticación
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
import { PieceAuth, Property } from "@activepieces/pieces-framework";
|
|
329
|
+
|
|
330
|
+
export const latexToPdfAuth = PieceAuth.CustomAuth({
|
|
331
|
+
description: "Configure the LaTeX compilation service connection",
|
|
332
|
+
required: false, // Opcional porque tenemos un default
|
|
333
|
+
props: {
|
|
334
|
+
serviceUrl: Property.ShortText({
|
|
335
|
+
displayName: "Service URL",
|
|
336
|
+
description: "LaTeX compiler service URL. Leave empty to use default Skillful service.",
|
|
337
|
+
required: false,
|
|
338
|
+
defaultValue: "https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev",
|
|
339
|
+
}),
|
|
340
|
+
apiKey: PieceAuth.SecretText({
|
|
341
|
+
displayName: "API Key",
|
|
342
|
+
description: "API key for authenticated requests (optional)",
|
|
343
|
+
required: false,
|
|
344
|
+
}),
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// Tipo para usar en acciones
|
|
349
|
+
export type LatexToPdfAuth = {
|
|
350
|
+
serviceUrl?: string;
|
|
351
|
+
apiKey?: string;
|
|
352
|
+
};
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
#### [11] `src/lib/common.ts`
|
|
358
|
+
**Qué hace:** Funciones helper compartidas.
|
|
359
|
+
**Contiene:**
|
|
360
|
+
- `getServiceUrl()`: Obtiene la URL del servicio (con default)
|
|
361
|
+
- `pollForCompletion()`: Hace polling hasta que el job termine
|
|
362
|
+
- Constantes de configuración
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
import { httpClient, HttpMethod } from "@activepieces/pieces-common";
|
|
366
|
+
import { LatexToPdfAuth } from "./auth";
|
|
367
|
+
|
|
368
|
+
// Constantes
|
|
369
|
+
export const DEFAULT_SERVICE_URL = "https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev";
|
|
370
|
+
export const POLLING_INTERVAL_MS = 2000; // 2 segundos
|
|
371
|
+
export const MAX_POLLING_ATTEMPTS = 150; // 5 minutos máximo (150 * 2s)
|
|
372
|
+
|
|
373
|
+
// Tipos basados en el OpenAPI del servicio
|
|
374
|
+
export type CompilerType = "pdflatex" | "xelatex";
|
|
375
|
+
export type OutputFormat = "url" | "base64" | "bytes";
|
|
376
|
+
export type JobStatus = "pending" | "processing" | "completed" | "failed";
|
|
377
|
+
|
|
378
|
+
export interface CompileRequest {
|
|
379
|
+
file_content: string; // Base64
|
|
380
|
+
filename: string;
|
|
381
|
+
main_file?: string;
|
|
382
|
+
compiler?: CompilerType;
|
|
383
|
+
output_format?: OutputFormat;
|
|
384
|
+
compiler_options?: string[];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
export interface CompileResponse {
|
|
388
|
+
job_id: string;
|
|
389
|
+
status: JobStatus;
|
|
390
|
+
message: string;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface CompilationResult {
|
|
394
|
+
success: boolean;
|
|
395
|
+
output_format: OutputFormat;
|
|
396
|
+
pdf_url?: string;
|
|
397
|
+
pdf_base64?: string;
|
|
398
|
+
log_url?: string;
|
|
399
|
+
error_message?: string;
|
|
400
|
+
exit_code: number;
|
|
401
|
+
duration_ms: number;
|
|
402
|
+
pdf_size_bytes?: number;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export interface JobStatusResponse {
|
|
406
|
+
job_id: string;
|
|
407
|
+
status: JobStatus;
|
|
408
|
+
message: string;
|
|
409
|
+
error_message?: string;
|
|
410
|
+
result?: CompilationResult;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Obtiene la URL del servicio, usando el default si no se configura
|
|
415
|
+
*/
|
|
416
|
+
export function getServiceUrl(auth: LatexToPdfAuth | undefined): string {
|
|
417
|
+
return auth?.serviceUrl?.trim() || DEFAULT_SERVICE_URL;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Construye headers para las peticiones
|
|
422
|
+
*/
|
|
423
|
+
export function buildHeaders(auth: LatexToPdfAuth | undefined): Record<string, string> {
|
|
424
|
+
const headers: Record<string, string> = {
|
|
425
|
+
"Content-Type": "application/json",
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
if (auth?.apiKey?.trim()) {
|
|
429
|
+
headers["X-API-Key"] = auth.apiKey.trim();
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return headers;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Envía el LaTeX para compilar
|
|
437
|
+
*/
|
|
438
|
+
export async function submitCompilation(
|
|
439
|
+
serviceUrl: string,
|
|
440
|
+
request: CompileRequest,
|
|
441
|
+
headers: Record<string, string>
|
|
442
|
+
): Promise<CompileResponse> {
|
|
443
|
+
const response = await httpClient.sendRequest<CompileResponse>({
|
|
444
|
+
method: HttpMethod.POST,
|
|
445
|
+
url: `${serviceUrl}/compile`,
|
|
446
|
+
headers,
|
|
447
|
+
body: request,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
return response.body;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Obtiene el estado de un job
|
|
455
|
+
*/
|
|
456
|
+
export async function getJobStatus(
|
|
457
|
+
serviceUrl: string,
|
|
458
|
+
jobId: string,
|
|
459
|
+
headers: Record<string, string>
|
|
460
|
+
): Promise<JobStatusResponse> {
|
|
461
|
+
const response = await httpClient.sendRequest<JobStatusResponse>({
|
|
462
|
+
method: HttpMethod.GET,
|
|
463
|
+
url: `${serviceUrl}/compile/${jobId}`,
|
|
464
|
+
headers,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
return response.body;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Hace polling hasta que el job termine o falle
|
|
472
|
+
*/
|
|
473
|
+
export async function pollForCompletion(
|
|
474
|
+
serviceUrl: string,
|
|
475
|
+
jobId: string,
|
|
476
|
+
headers: Record<string, string>
|
|
477
|
+
): Promise<JobStatusResponse> {
|
|
478
|
+
let attempts = 0;
|
|
479
|
+
|
|
480
|
+
while (attempts < MAX_POLLING_ATTEMPTS) {
|
|
481
|
+
const status = await getJobStatus(serviceUrl, jobId, headers);
|
|
482
|
+
|
|
483
|
+
if (status.status === "completed" || status.status === "failed") {
|
|
484
|
+
return status;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Esperar antes del siguiente intento
|
|
488
|
+
await new Promise(resolve => setTimeout(resolve, POLLING_INTERVAL_MS));
|
|
489
|
+
attempts++;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
throw new Error(`Compilation timed out after ${MAX_POLLING_ATTEMPTS * POLLING_INTERVAL_MS / 1000} seconds`);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Convierte string a Base64
|
|
497
|
+
*/
|
|
498
|
+
export function toBase64(content: string): string {
|
|
499
|
+
return Buffer.from(content, "utf-8").toString("base64");
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
#### [12] `src/lib/actions/compile-latex.ts`
|
|
506
|
+
**Qué hace:** Acción principal que compila LaTeX a PDF.
|
|
507
|
+
**Props:**
|
|
508
|
+
- `latexContent`: Código LaTeX (LongText)
|
|
509
|
+
- `filename`: Nombre del archivo
|
|
510
|
+
- `compiler`: pdflatex o xelatex
|
|
511
|
+
- `outputFormat`: url, base64, bytes
|
|
512
|
+
|
|
513
|
+
**Lógica:**
|
|
514
|
+
1. Validar inputs
|
|
515
|
+
2. Convertir contenido a Base64
|
|
516
|
+
3. Enviar a `/compile`
|
|
517
|
+
4. Hacer polling hasta completar
|
|
518
|
+
5. Retornar resultado
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
import { createAction, Property } from "@activepieces/pieces-framework";
|
|
522
|
+
import { latexToPdfAuth, LatexToPdfAuth } from "../auth";
|
|
523
|
+
import {
|
|
524
|
+
getServiceUrl,
|
|
525
|
+
buildHeaders,
|
|
526
|
+
submitCompilation,
|
|
527
|
+
pollForCompletion,
|
|
528
|
+
toBase64,
|
|
529
|
+
CompilerType,
|
|
530
|
+
OutputFormat,
|
|
531
|
+
} from "../common";
|
|
532
|
+
|
|
533
|
+
export const compileLatex = createAction({
|
|
534
|
+
name: "compile_latex",
|
|
535
|
+
displayName: "Compile LaTeX",
|
|
536
|
+
description: "Compile a LaTeX document to PDF",
|
|
537
|
+
auth: latexToPdfAuth,
|
|
538
|
+
props: {
|
|
539
|
+
latexContent: Property.LongText({
|
|
540
|
+
displayName: "LaTeX Content",
|
|
541
|
+
description: "The LaTeX source code to compile",
|
|
542
|
+
required: true,
|
|
543
|
+
}),
|
|
544
|
+
filename: Property.ShortText({
|
|
545
|
+
displayName: "Filename",
|
|
546
|
+
description: "Name of the .tex file (e.g., main.tex)",
|
|
547
|
+
required: true,
|
|
548
|
+
defaultValue: "main.tex",
|
|
549
|
+
}),
|
|
550
|
+
compiler: Property.StaticDropdown({
|
|
551
|
+
displayName: "Compiler",
|
|
552
|
+
description: "LaTeX compiler to use",
|
|
553
|
+
required: true,
|
|
554
|
+
defaultValue: "xelatex",
|
|
555
|
+
options: {
|
|
556
|
+
options: [
|
|
557
|
+
{ label: "XeLaTeX (recommended for Unicode)", value: "xelatex" },
|
|
558
|
+
{ label: "pdfLaTeX (traditional)", value: "pdflatex" },
|
|
559
|
+
],
|
|
560
|
+
},
|
|
561
|
+
}),
|
|
562
|
+
outputFormat: Property.StaticDropdown({
|
|
563
|
+
displayName: "Output Format",
|
|
564
|
+
description: "How to return the compiled PDF",
|
|
565
|
+
required: true,
|
|
566
|
+
defaultValue: "url",
|
|
567
|
+
options: {
|
|
568
|
+
options: [
|
|
569
|
+
{ label: "URL (presigned download link)", value: "url" },
|
|
570
|
+
{ label: "Base64 (embedded in response)", value: "base64" },
|
|
571
|
+
],
|
|
572
|
+
},
|
|
573
|
+
}),
|
|
574
|
+
},
|
|
575
|
+
async run(context) {
|
|
576
|
+
const { latexContent, filename, compiler, outputFormat } = context.propsValue;
|
|
577
|
+
const auth = context.auth as LatexToPdfAuth | undefined;
|
|
578
|
+
|
|
579
|
+
// Validaciones
|
|
580
|
+
if (!latexContent?.trim()) {
|
|
581
|
+
return {
|
|
582
|
+
success: false,
|
|
583
|
+
error: "LaTeX content cannot be empty",
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (!filename?.trim()) {
|
|
588
|
+
return {
|
|
589
|
+
success: false,
|
|
590
|
+
error: "Filename is required",
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Asegurar extensión .tex
|
|
595
|
+
const normalizedFilename = filename.endsWith(".tex") ? filename : `${filename}.tex`;
|
|
596
|
+
|
|
597
|
+
try {
|
|
598
|
+
const serviceUrl = getServiceUrl(auth);
|
|
599
|
+
const headers = buildHeaders(auth);
|
|
600
|
+
|
|
601
|
+
// 1. Enviar para compilar
|
|
602
|
+
const submitResponse = await submitCompilation(serviceUrl, {
|
|
603
|
+
file_content: toBase64(latexContent),
|
|
604
|
+
filename: normalizedFilename,
|
|
605
|
+
compiler: compiler as CompilerType,
|
|
606
|
+
output_format: outputFormat as OutputFormat,
|
|
607
|
+
}, headers);
|
|
608
|
+
|
|
609
|
+
// 2. Polling hasta completar
|
|
610
|
+
const result = await pollForCompletion(serviceUrl, submitResponse.job_id, headers);
|
|
611
|
+
|
|
612
|
+
// 3. Procesar resultado
|
|
613
|
+
if (result.status === "failed") {
|
|
614
|
+
return {
|
|
615
|
+
success: false,
|
|
616
|
+
error: result.error_message || result.message || "Compilation failed",
|
|
617
|
+
jobId: result.job_id,
|
|
618
|
+
logUrl: result.result?.log_url,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// Éxito
|
|
623
|
+
return {
|
|
624
|
+
success: true,
|
|
625
|
+
jobId: result.job_id,
|
|
626
|
+
pdfUrl: result.result?.pdf_url,
|
|
627
|
+
pdfBase64: result.result?.pdf_base64,
|
|
628
|
+
logUrl: result.result?.log_url,
|
|
629
|
+
durationMs: result.result?.duration_ms,
|
|
630
|
+
pdfSizeBytes: result.result?.pdf_size_bytes,
|
|
631
|
+
compiler,
|
|
632
|
+
filename: normalizedFilename,
|
|
633
|
+
};
|
|
634
|
+
} catch (error) {
|
|
635
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
636
|
+
return {
|
|
637
|
+
success: false,
|
|
638
|
+
error: errorMessage,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
### Fase 3: Tests
|
|
648
|
+
|
|
649
|
+
#### [13] `test/compile-latex.test.ts`
|
|
650
|
+
**Qué hace:** Tests unitarios para la acción.
|
|
651
|
+
**Mockea:** httpClient para no hacer llamadas reales.
|
|
652
|
+
|
|
653
|
+
```typescript
|
|
654
|
+
import { compileLatex } from "../src/lib/actions/compile-latex";
|
|
655
|
+
|
|
656
|
+
// Mock httpClient
|
|
657
|
+
jest.mock("@activepieces/pieces-common", () => ({
|
|
658
|
+
httpClient: {
|
|
659
|
+
sendRequest: jest.fn(),
|
|
660
|
+
},
|
|
661
|
+
HttpMethod: {
|
|
662
|
+
GET: "GET",
|
|
663
|
+
POST: "POST",
|
|
664
|
+
},
|
|
665
|
+
}));
|
|
666
|
+
|
|
667
|
+
const { httpClient } = jest.requireMock("@activepieces/pieces-common") as {
|
|
668
|
+
httpClient: { sendRequest: jest.Mock };
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
describe("compileLatex action", () => {
|
|
672
|
+
beforeEach(() => {
|
|
673
|
+
jest.clearAllMocks();
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it("returns error when latexContent is empty", async () => {
|
|
677
|
+
const result = await compileLatex.run({
|
|
678
|
+
auth: undefined,
|
|
679
|
+
propsValue: {
|
|
680
|
+
latexContent: "",
|
|
681
|
+
filename: "main.tex",
|
|
682
|
+
compiler: "xelatex",
|
|
683
|
+
outputFormat: "url",
|
|
684
|
+
},
|
|
685
|
+
} as any);
|
|
686
|
+
|
|
687
|
+
expect(result.success).toBe(false);
|
|
688
|
+
expect(result.error).toMatch(/empty/i);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
it("returns error when filename is empty", async () => {
|
|
692
|
+
const result = await compileLatex.run({
|
|
693
|
+
auth: undefined,
|
|
694
|
+
propsValue: {
|
|
695
|
+
latexContent: "\\documentclass{article}",
|
|
696
|
+
filename: "",
|
|
697
|
+
compiler: "xelatex",
|
|
698
|
+
outputFormat: "url",
|
|
699
|
+
},
|
|
700
|
+
} as any);
|
|
701
|
+
|
|
702
|
+
expect(result.success).toBe(false);
|
|
703
|
+
expect(result.error).toMatch(/required/i);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
it("successfully compiles LaTeX and returns PDF URL", async () => {
|
|
707
|
+
// Mock submit response
|
|
708
|
+
httpClient.sendRequest
|
|
709
|
+
.mockResolvedValueOnce({
|
|
710
|
+
body: { job_id: "test-job-123", status: "pending", message: "Job created" },
|
|
711
|
+
})
|
|
712
|
+
// Mock poll response - completed
|
|
713
|
+
.mockResolvedValueOnce({
|
|
714
|
+
body: {
|
|
715
|
+
job_id: "test-job-123",
|
|
716
|
+
status: "completed",
|
|
717
|
+
message: "Compilation successful",
|
|
718
|
+
result: {
|
|
719
|
+
success: true,
|
|
720
|
+
pdf_url: "https://s3.amazonaws.com/bucket/test.pdf",
|
|
721
|
+
log_url: "https://s3.amazonaws.com/bucket/test.log",
|
|
722
|
+
duration_ms: 3500,
|
|
723
|
+
pdf_size_bytes: 125000,
|
|
724
|
+
},
|
|
725
|
+
},
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
const result = await compileLatex.run({
|
|
729
|
+
auth: undefined,
|
|
730
|
+
propsValue: {
|
|
731
|
+
latexContent: "\\documentclass{article}\\begin{document}Hello\\end{document}",
|
|
732
|
+
filename: "main.tex",
|
|
733
|
+
compiler: "xelatex",
|
|
734
|
+
outputFormat: "url",
|
|
735
|
+
},
|
|
736
|
+
} as any);
|
|
737
|
+
|
|
738
|
+
expect(result.success).toBe(true);
|
|
739
|
+
expect(result.pdfUrl).toBe("https://s3.amazonaws.com/bucket/test.pdf");
|
|
740
|
+
expect(result.durationMs).toBe(3500);
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
it("handles compilation failure", async () => {
|
|
744
|
+
httpClient.sendRequest
|
|
745
|
+
.mockResolvedValueOnce({
|
|
746
|
+
body: { job_id: "test-job-456", status: "pending", message: "Job created" },
|
|
747
|
+
})
|
|
748
|
+
.mockResolvedValueOnce({
|
|
749
|
+
body: {
|
|
750
|
+
job_id: "test-job-456",
|
|
751
|
+
status: "failed",
|
|
752
|
+
message: "Compilation failed",
|
|
753
|
+
error_message: "Undefined control sequence",
|
|
754
|
+
result: {
|
|
755
|
+
success: false,
|
|
756
|
+
log_url: "https://s3.amazonaws.com/bucket/error.log",
|
|
757
|
+
},
|
|
758
|
+
},
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
const result = await compileLatex.run({
|
|
762
|
+
auth: undefined,
|
|
763
|
+
propsValue: {
|
|
764
|
+
latexContent: "\\invalid{command}",
|
|
765
|
+
filename: "main.tex",
|
|
766
|
+
compiler: "pdflatex",
|
|
767
|
+
outputFormat: "url",
|
|
768
|
+
},
|
|
769
|
+
} as any);
|
|
770
|
+
|
|
771
|
+
expect(result.success).toBe(false);
|
|
772
|
+
expect(result.error).toMatch(/Undefined control sequence/);
|
|
773
|
+
expect(result.logUrl).toBeDefined();
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
---
|
|
779
|
+
|
|
780
|
+
## 🚀 Pasos para Probar Localmente
|
|
781
|
+
|
|
782
|
+
1. **Agregar a AP_DEV_PIECES** en `packages/server/api/.env`:
|
|
783
|
+
```
|
|
784
|
+
AP_DEV_PIECES="...,latex-to-pdf"
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
2. **Build de la pieza:**
|
|
788
|
+
```bash
|
|
789
|
+
npx nx build pieces-latex-to-pdf
|
|
790
|
+
```
|
|
791
|
+
|
|
792
|
+
3. **Correr tests:**
|
|
793
|
+
```bash
|
|
794
|
+
npx nx test pieces-latex-to-pdf
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
4. **Reiniciar el backend** y refrescar el frontend.
|
|
798
|
+
|
|
799
|
+
---
|
|
800
|
+
|
|
801
|
+
## 📝 Orden de Creación Recomendado
|
|
802
|
+
|
|
803
|
+
1. ✅ `.eslintrc.json` - Config ESLint
|
|
804
|
+
2. ✅ `package.json` - Dependencias
|
|
805
|
+
3. ✅ `project.json` - Config Nx
|
|
806
|
+
4. ✅ `tsconfig.json` - TS base
|
|
807
|
+
5. ✅ `tsconfig.lib.json` - TS build
|
|
808
|
+
6. ✅ `tsconfig.spec.json` - TS tests
|
|
809
|
+
7. ✅ `jest.config.ts` - Config Jest
|
|
810
|
+
8. ✅ `src/lib/auth.ts` - Autenticación
|
|
811
|
+
9. ✅ `src/lib/common.ts` - Helpers
|
|
812
|
+
10. ✅ `src/lib/actions/compile-latex.ts` - Acción principal
|
|
813
|
+
11. ✅ `src/index.ts` - Entry point
|
|
814
|
+
12. ✅ `test/compile-latex.test.ts` - Tests (8/8 passing)
|
|
815
|
+
13. ✅ `README.md` - Documentación
|
|
816
|
+
14. ✅ Build y test local - PASSED
|
|
817
|
+
15. ⬜ Commit y push
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# LaTeX to PDF Piece
|
|
2
|
+
|
|
3
|
+
Compile LaTeX documents to PDF using the Skillful LaTeX Compiler Service.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ Compile `.tex` files to PDF
|
|
8
|
+
- ✅ Support for `pdflatex` and `xelatex` compilers
|
|
9
|
+
- ✅ Multiple output formats: URL (presigned) or Base64
|
|
10
|
+
- ✅ Async compilation with automatic polling
|
|
11
|
+
- ✅ Detailed error messages with compilation logs
|
|
12
|
+
|
|
13
|
+
## Authentication
|
|
14
|
+
|
|
15
|
+
Configure the piece with (all optional):
|
|
16
|
+
|
|
17
|
+
| Field | Description |
|
|
18
|
+
|-------|-------------|
|
|
19
|
+
| **Service URL** | Custom LaTeX service URL. Defaults to Skillful's service. |
|
|
20
|
+
| **API Key** | API key for authenticated requests. |
|
|
21
|
+
|
|
22
|
+
## Actions
|
|
23
|
+
|
|
24
|
+
### Compile LaTeX
|
|
25
|
+
|
|
26
|
+
Compiles a LaTeX document and returns the PDF.
|
|
27
|
+
|
|
28
|
+
**Inputs:**
|
|
29
|
+
|
|
30
|
+
| Property | Type | Required | Default | Description |
|
|
31
|
+
|----------|------|----------|---------|-------------|
|
|
32
|
+
| `latexContent` | Long Text | ✅ | - | The LaTeX source code to compile |
|
|
33
|
+
| `filename` | Short Text | ✅ | `main.tex` | Name of the .tex file |
|
|
34
|
+
| `compiler` | Dropdown | ✅ | `xelatex` | Compiler: `xelatex` or `pdflatex` |
|
|
35
|
+
| `outputFormat` | Dropdown | ✅ | `url` | Output: `url` or `base64` |
|
|
36
|
+
|
|
37
|
+
**Outputs (Success):**
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"success": true,
|
|
42
|
+
"jobId": "550e8400-e29b-41d4-a716-446655440000",
|
|
43
|
+
"pdfUrl": "https://s3.amazonaws.com/.../output.pdf",
|
|
44
|
+
"logUrl": "https://s3.amazonaws.com/.../output.log",
|
|
45
|
+
"durationMs": 3500,
|
|
46
|
+
"pdfSizeBytes": 125000,
|
|
47
|
+
"compiler": "xelatex",
|
|
48
|
+
"filename": "main.tex"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Outputs (Failure):**
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"success": false,
|
|
57
|
+
"error": "Undefined control sequence \\invalid",
|
|
58
|
+
"jobId": "550e8400-e29b-41d4-a716-446655440000",
|
|
59
|
+
"logUrl": "https://s3.amazonaws.com/.../error.log"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Example Usage
|
|
64
|
+
|
|
65
|
+
### Simple Document
|
|
66
|
+
|
|
67
|
+
```latex
|
|
68
|
+
\documentclass{article}
|
|
69
|
+
\begin{document}
|
|
70
|
+
Hello, World!
|
|
71
|
+
\end{document}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Document with Unicode (use XeLaTeX)
|
|
75
|
+
|
|
76
|
+
```latex
|
|
77
|
+
\documentclass{article}
|
|
78
|
+
\usepackage{fontspec}
|
|
79
|
+
\begin{document}
|
|
80
|
+
Hello, 世界! مرحبا
|
|
81
|
+
\end{document}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Building
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx nx build pieces-latex-to-pdf
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Testing
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx nx test pieces-latex-to-pdf
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Development
|
|
97
|
+
|
|
98
|
+
Add to `AP_DEV_PIECES` in `packages/server/api/.env`:
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
AP_DEV_PIECES="...,latex-to-pdf"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then restart the backend and refresh the frontend.
|
|
105
|
+
|
|
106
|
+
## Service API
|
|
107
|
+
|
|
108
|
+
The piece uses the Skillful LaTeX Compiler Service:
|
|
109
|
+
|
|
110
|
+
- **Base URL**: `https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev`
|
|
111
|
+
- **Docs**: `https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev/docs`
|
|
112
|
+
|
|
113
|
+
| Method | Endpoint | Description |
|
|
114
|
+
|--------|----------|-------------|
|
|
115
|
+
| `POST` | `/compile` | Submit LaTeX for compilation |
|
|
116
|
+
| `GET` | `/compile/{job_id}` | Get compilation status |
|
|
117
|
+
| `GET` | `/health` | Health check |
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skillful-ai/piece-latex-to-pdf",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@activepieces/pieces-common": "^0.7.0",
|
|
9
|
+
"@activepieces/pieces-framework": "^0.20.1",
|
|
10
|
+
"tslib": "^2.3.0",
|
|
11
|
+
"@activepieces/shared": "0.22.0"
|
|
12
|
+
},
|
|
13
|
+
"overrides": {
|
|
14
|
+
"@tryfabric/martian": {
|
|
15
|
+
"@notionhq/client": "$@notionhq/client"
|
|
16
|
+
},
|
|
17
|
+
"vite": {
|
|
18
|
+
"rollup": "npm:@rollup/wasm-node"
|
|
19
|
+
},
|
|
20
|
+
"undici": "6.19.8"
|
|
21
|
+
},
|
|
22
|
+
"resolutions": {
|
|
23
|
+
"rollup": "npm:@rollup/wasm-node",
|
|
24
|
+
"undici": "6.19.8"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const latexToPdf: import("@activepieces/pieces-framework").Piece<import("@activepieces/pieces-framework").CustomAuthProperty<{
|
|
2
|
+
serviceUrl: import("@activepieces/pieces-framework").ShortTextProperty<false>;
|
|
3
|
+
apiKey: import("@activepieces/pieces-framework").SecretTextProperty<false>;
|
|
4
|
+
}>>;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.latexToPdf = void 0;
|
|
4
|
+
const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
5
|
+
const shared_1 = require("@activepieces/shared");
|
|
6
|
+
const auth_1 = require("./lib/auth");
|
|
7
|
+
const compile_latex_1 = require("./lib/actions/compile-latex");
|
|
8
|
+
exports.latexToPdf = (0, pieces_framework_1.createPiece)({
|
|
9
|
+
displayName: "LaTeX to PDF",
|
|
10
|
+
description: "Compile LaTeX documents to PDF using a cloud compilation service. Supports pdflatex and xelatex compilers with multiple output formats.",
|
|
11
|
+
auth: auth_1.latexToPdfAuth,
|
|
12
|
+
minimumSupportedRelease: "0.36.1",
|
|
13
|
+
logoUrl: "https://cdn.activepieces.com/pieces/latex.png",
|
|
14
|
+
authors: ["skillful-ai"],
|
|
15
|
+
categories: [shared_1.PieceCategory.CORE],
|
|
16
|
+
actions: [compile_latex_1.compileLatex],
|
|
17
|
+
triggers: [],
|
|
18
|
+
});
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/custom/latex-to-pdf/src/index.ts"],"names":[],"mappings":";;;AAAA,qEAA6D;AAC7D,iDAAqD;AACrD,qCAA4C;AAC5C,+DAA2D;AAE9C,QAAA,UAAU,GAAG,IAAA,8BAAW,EAAC;IACpC,WAAW,EAAE,cAAc;IAC3B,WAAW,EAAE,yIAAyI;IACtJ,IAAI,EAAE,qBAAc;IACpB,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,+CAA+C;IACxD,OAAO,EAAE,CAAC,aAAa,CAAC;IACxB,UAAU,EAAE,CAAC,sBAAa,CAAC,IAAI,CAAC;IAChC,OAAO,EAAE,CAAC,4BAAY,CAAC;IACvB,QAAQ,EAAE,EAAE;CACb,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const compileLatex: import("@activepieces/pieces-framework").IAction<import("@activepieces/pieces-framework").CustomAuthProperty<{
|
|
2
|
+
serviceUrl: import("@activepieces/pieces-framework").ShortTextProperty<false>;
|
|
3
|
+
apiKey: import("@activepieces/pieces-framework").SecretTextProperty<false>;
|
|
4
|
+
}>, {
|
|
5
|
+
latexContent: import("@activepieces/pieces-framework").LongTextProperty<true>;
|
|
6
|
+
filename: import("@activepieces/pieces-framework").ShortTextProperty<true>;
|
|
7
|
+
compiler: import("@activepieces/pieces-framework").StaticDropdownProperty<string, true>;
|
|
8
|
+
outputFormat: import("@activepieces/pieces-framework").StaticDropdownProperty<string, true>;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileLatex = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
6
|
+
const auth_1 = require("../auth");
|
|
7
|
+
const common_1 = require("../common");
|
|
8
|
+
exports.compileLatex = (0, pieces_framework_1.createAction)({
|
|
9
|
+
name: "compile_latex",
|
|
10
|
+
displayName: "Compile LaTeX",
|
|
11
|
+
description: "Compile a LaTeX document to PDF using a cloud compilation service. Supports pdflatex and xelatex compilers.",
|
|
12
|
+
auth: auth_1.latexToPdfAuth,
|
|
13
|
+
props: {
|
|
14
|
+
latexContent: pieces_framework_1.Property.LongText({
|
|
15
|
+
displayName: "LaTeX Content",
|
|
16
|
+
description: "The LaTeX source code to compile. Must be valid LaTeX syntax.",
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
filename: pieces_framework_1.Property.ShortText({
|
|
20
|
+
displayName: "Filename",
|
|
21
|
+
description: "Name of the .tex file (e.g., main.tex, document.tex)",
|
|
22
|
+
required: true,
|
|
23
|
+
defaultValue: "main.tex",
|
|
24
|
+
}),
|
|
25
|
+
compiler: pieces_framework_1.Property.StaticDropdown({
|
|
26
|
+
displayName: "Compiler",
|
|
27
|
+
description: "LaTeX compiler to use for compilation",
|
|
28
|
+
required: true,
|
|
29
|
+
defaultValue: "xelatex",
|
|
30
|
+
options: {
|
|
31
|
+
options: [
|
|
32
|
+
{ label: "XeLaTeX (recommended for Unicode/fonts)", value: "xelatex" },
|
|
33
|
+
{ label: "pdfLaTeX (traditional)", value: "pdflatex" },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
outputFormat: pieces_framework_1.Property.StaticDropdown({
|
|
38
|
+
displayName: "Output Format",
|
|
39
|
+
description: "How to return the compiled PDF",
|
|
40
|
+
required: true,
|
|
41
|
+
defaultValue: "url",
|
|
42
|
+
options: {
|
|
43
|
+
options: [
|
|
44
|
+
{ label: "URL (presigned download link)", value: "url" },
|
|
45
|
+
{ label: "Base64 (embedded in response)", value: "base64" },
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
run(context) {
|
|
51
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
var _a, _b, _c, _d, _e, _f;
|
|
53
|
+
const { latexContent, filename, compiler, outputFormat } = context.propsValue;
|
|
54
|
+
const auth = context.auth;
|
|
55
|
+
// Validate inputs
|
|
56
|
+
if (!(latexContent === null || latexContent === void 0 ? void 0 : latexContent.trim())) {
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: "LaTeX content cannot be empty",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (!(filename === null || filename === void 0 ? void 0 : filename.trim())) {
|
|
63
|
+
return {
|
|
64
|
+
success: false,
|
|
65
|
+
error: "Filename is required",
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Ensure .tex extension
|
|
69
|
+
const normalizedFilename = filename.trim().endsWith(".tex")
|
|
70
|
+
? filename.trim()
|
|
71
|
+
: `${filename.trim()}.tex`;
|
|
72
|
+
try {
|
|
73
|
+
const serviceUrl = (0, common_1.getServiceUrl)(auth);
|
|
74
|
+
const headers = (0, common_1.buildHeaders)(auth);
|
|
75
|
+
// 1. Submit for compilation
|
|
76
|
+
const submitResponse = yield (0, common_1.submitCompilation)(serviceUrl, {
|
|
77
|
+
file_content: (0, common_1.toBase64)(latexContent),
|
|
78
|
+
filename: normalizedFilename,
|
|
79
|
+
compiler: compiler,
|
|
80
|
+
output_format: outputFormat,
|
|
81
|
+
}, headers);
|
|
82
|
+
// 2. Poll until completion
|
|
83
|
+
const result = yield (0, common_1.pollForCompletion)(serviceUrl, submitResponse.job_id, headers);
|
|
84
|
+
// 3. Process result
|
|
85
|
+
if (result.status === "failed") {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: result.error_message || result.message || "Compilation failed",
|
|
89
|
+
jobId: result.job_id,
|
|
90
|
+
logUrl: (_a = result.result) === null || _a === void 0 ? void 0 : _a.log_url,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
// Success
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
jobId: result.job_id,
|
|
97
|
+
pdfUrl: (_b = result.result) === null || _b === void 0 ? void 0 : _b.pdf_url,
|
|
98
|
+
pdfBase64: (_c = result.result) === null || _c === void 0 ? void 0 : _c.pdf_base64,
|
|
99
|
+
logUrl: (_d = result.result) === null || _d === void 0 ? void 0 : _d.log_url,
|
|
100
|
+
durationMs: (_e = result.result) === null || _e === void 0 ? void 0 : _e.duration_ms,
|
|
101
|
+
pdfSizeBytes: (_f = result.result) === null || _f === void 0 ? void 0 : _f.pdf_size_bytes,
|
|
102
|
+
compiler,
|
|
103
|
+
filename: normalizedFilename,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: errorMessage,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=compile-latex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-latex.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/custom/latex-to-pdf/src/lib/actions/compile-latex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const latexToPdfAuth: import("@activepieces/pieces-framework").CustomAuthProperty<{
|
|
2
|
+
serviceUrl: import("@activepieces/pieces-framework").ShortTextProperty<false>;
|
|
3
|
+
apiKey: import("@activepieces/pieces-framework").SecretTextProperty<false>;
|
|
4
|
+
}>;
|
|
5
|
+
export type LatexToPdfAuth = {
|
|
6
|
+
serviceUrl?: string;
|
|
7
|
+
apiKey?: string;
|
|
8
|
+
};
|
package/src/lib/auth.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.latexToPdfAuth = void 0;
|
|
4
|
+
const pieces_framework_1 = require("@activepieces/pieces-framework");
|
|
5
|
+
exports.latexToPdfAuth = pieces_framework_1.PieceAuth.CustomAuth({
|
|
6
|
+
description: 'Configure the LaTeX compilation service connection (optional - defaults are provided)',
|
|
7
|
+
required: true,
|
|
8
|
+
props: {
|
|
9
|
+
serviceUrl: pieces_framework_1.Property.ShortText({
|
|
10
|
+
displayName: 'Service URL',
|
|
11
|
+
description: 'LaTeX compiler service URL. Leave empty to use default Skillful service.',
|
|
12
|
+
required: false,
|
|
13
|
+
}),
|
|
14
|
+
apiKey: pieces_framework_1.PieceAuth.SecretText({
|
|
15
|
+
displayName: 'API Key',
|
|
16
|
+
description: 'API key for authenticated requests (optional)',
|
|
17
|
+
required: false,
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../../../../../packages/pieces/custom/latex-to-pdf/src/lib/auth.ts"],"names":[],"mappings":";;;AAAA,qEAAqE;AAExD,QAAA,cAAc,GAAG,4BAAS,CAAC,UAAU,CAAC;IACjD,WAAW,EAAE,uFAAuF;IACpG,QAAQ,EAAE,IAAI;IACd,KAAK,EAAE;QACL,UAAU,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC7B,WAAW,EAAE,aAAa;YAC1B,WAAW,EAAE,0EAA0E;YACvF,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,MAAM,EAAE,4BAAS,CAAC,UAAU,CAAC;YAC3B,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,+CAA+C;YAC5D,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { LatexToPdfAuth } from "./auth";
|
|
2
|
+
export declare const DEFAULT_SERVICE_URL = "https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev";
|
|
3
|
+
export declare const POLLING_INTERVAL_MS = 2000;
|
|
4
|
+
export declare const MAX_POLLING_ATTEMPTS = 150;
|
|
5
|
+
export type CompilerType = "pdflatex" | "xelatex";
|
|
6
|
+
export type OutputFormat = "url" | "base64" | "bytes";
|
|
7
|
+
export type JobStatus = "pending" | "processing" | "completed" | "failed";
|
|
8
|
+
export interface CompileRequest {
|
|
9
|
+
file_content: string;
|
|
10
|
+
filename: string;
|
|
11
|
+
main_file?: string;
|
|
12
|
+
compiler?: CompilerType;
|
|
13
|
+
output_format?: OutputFormat;
|
|
14
|
+
compiler_options?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface CompileResponse {
|
|
17
|
+
job_id: string;
|
|
18
|
+
status: JobStatus;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CompilationResult {
|
|
22
|
+
success: boolean;
|
|
23
|
+
output_format: OutputFormat;
|
|
24
|
+
pdf_url?: string;
|
|
25
|
+
pdf_base64?: string;
|
|
26
|
+
log_url?: string;
|
|
27
|
+
error_message?: string;
|
|
28
|
+
exit_code: number;
|
|
29
|
+
duration_ms: number;
|
|
30
|
+
pdf_size_bytes?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface JobStatusResponse {
|
|
33
|
+
job_id: string;
|
|
34
|
+
status: JobStatus;
|
|
35
|
+
message: string;
|
|
36
|
+
error_message?: string;
|
|
37
|
+
result?: CompilationResult;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the service URL, using default if not configured
|
|
41
|
+
*/
|
|
42
|
+
export declare function getServiceUrl(auth: LatexToPdfAuth | undefined): string;
|
|
43
|
+
/**
|
|
44
|
+
* Build request headers
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildHeaders(auth: LatexToPdfAuth | undefined): Record<string, string>;
|
|
47
|
+
/**
|
|
48
|
+
* Convert string to Base64
|
|
49
|
+
*/
|
|
50
|
+
export declare function toBase64(content: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* Submit LaTeX for compilation
|
|
53
|
+
*/
|
|
54
|
+
export declare function submitCompilation(serviceUrl: string, request: CompileRequest, headers: Record<string, string>): Promise<CompileResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Get job status
|
|
57
|
+
*/
|
|
58
|
+
export declare function getJobStatus(serviceUrl: string, jobId: string, headers: Record<string, string>): Promise<JobStatusResponse>;
|
|
59
|
+
/**
|
|
60
|
+
* Poll for compilation completion
|
|
61
|
+
*/
|
|
62
|
+
export declare function pollForCompletion(serviceUrl: string, jobId: string, headers: Record<string, string>): Promise<JobStatusResponse>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_POLLING_ATTEMPTS = exports.POLLING_INTERVAL_MS = exports.DEFAULT_SERVICE_URL = void 0;
|
|
4
|
+
exports.getServiceUrl = getServiceUrl;
|
|
5
|
+
exports.buildHeaders = buildHeaders;
|
|
6
|
+
exports.toBase64 = toBase64;
|
|
7
|
+
exports.submitCompilation = submitCompilation;
|
|
8
|
+
exports.getJobStatus = getJobStatus;
|
|
9
|
+
exports.pollForCompletion = pollForCompletion;
|
|
10
|
+
const tslib_1 = require("tslib");
|
|
11
|
+
const pieces_common_1 = require("@activepieces/pieces-common");
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Constants
|
|
14
|
+
// =============================================================================
|
|
15
|
+
exports.DEFAULT_SERVICE_URL = "https://m9tbwb9jhi.execute-api.us-west-2.amazonaws.com/dev";
|
|
16
|
+
exports.POLLING_INTERVAL_MS = 2000; // 2 seconds
|
|
17
|
+
exports.MAX_POLLING_ATTEMPTS = 150; // 5 minutes max (150 * 2s)
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Helper Functions
|
|
20
|
+
// =============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Get the service URL, using default if not configured
|
|
23
|
+
*/
|
|
24
|
+
function getServiceUrl(auth) {
|
|
25
|
+
var _a;
|
|
26
|
+
const url = (_a = auth === null || auth === void 0 ? void 0 : auth.serviceUrl) === null || _a === void 0 ? void 0 : _a.trim();
|
|
27
|
+
if (url) {
|
|
28
|
+
// Remove trailing slash if present
|
|
29
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
30
|
+
}
|
|
31
|
+
return exports.DEFAULT_SERVICE_URL;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build request headers
|
|
35
|
+
*/
|
|
36
|
+
function buildHeaders(auth) {
|
|
37
|
+
var _a;
|
|
38
|
+
const headers = {
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
};
|
|
41
|
+
if ((_a = auth === null || auth === void 0 ? void 0 : auth.apiKey) === null || _a === void 0 ? void 0 : _a.trim()) {
|
|
42
|
+
headers["X-API-Key"] = auth.apiKey.trim();
|
|
43
|
+
}
|
|
44
|
+
return headers;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Convert string to Base64
|
|
48
|
+
*/
|
|
49
|
+
function toBase64(content) {
|
|
50
|
+
return Buffer.from(content, "utf-8").toString("base64");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Submit LaTeX for compilation
|
|
54
|
+
*/
|
|
55
|
+
function submitCompilation(serviceUrl, request, headers) {
|
|
56
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
const response = yield pieces_common_1.httpClient.sendRequest({
|
|
58
|
+
method: pieces_common_1.HttpMethod.POST,
|
|
59
|
+
url: `${serviceUrl}/compile`,
|
|
60
|
+
headers,
|
|
61
|
+
body: request,
|
|
62
|
+
});
|
|
63
|
+
return response.body;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get job status
|
|
68
|
+
*/
|
|
69
|
+
function getJobStatus(serviceUrl, jobId, headers) {
|
|
70
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
const response = yield pieces_common_1.httpClient.sendRequest({
|
|
72
|
+
method: pieces_common_1.HttpMethod.GET,
|
|
73
|
+
url: `${serviceUrl}/compile/${jobId}`,
|
|
74
|
+
headers,
|
|
75
|
+
});
|
|
76
|
+
return response.body;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Sleep helper for polling
|
|
81
|
+
*/
|
|
82
|
+
function sleep(ms) {
|
|
83
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Poll for compilation completion
|
|
87
|
+
*/
|
|
88
|
+
function pollForCompletion(serviceUrl, jobId, headers) {
|
|
89
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
let attempts = 0;
|
|
91
|
+
while (attempts < exports.MAX_POLLING_ATTEMPTS) {
|
|
92
|
+
const status = yield getJobStatus(serviceUrl, jobId, headers);
|
|
93
|
+
if (status.status === "completed" || status.status === "failed") {
|
|
94
|
+
return status;
|
|
95
|
+
}
|
|
96
|
+
// Wait before next attempt
|
|
97
|
+
yield sleep(exports.POLLING_INTERVAL_MS);
|
|
98
|
+
attempts++;
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`Compilation timed out after ${(exports.MAX_POLLING_ATTEMPTS * exports.POLLING_INTERVAL_MS) / 1000} seconds`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=common.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../../../../packages/pieces/custom/latex-to-pdf/src/lib/common.ts"],"names":[],"mappings":"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"}
|