gotenberg-client 0.0.0 → 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/README.md ADDED
@@ -0,0 +1,461 @@
1
+ # gotenberg-client
2
+
3
+ Typed, promise-based wrapper for [Gotenberg](https://gotenberg.dev/) with a single public class: `Gotenberg`.
4
+
5
+ - Minimal surface: one entrypoint, one initialization model.
6
+ - Strong request typing built from shared interfaces in `src/types.ts`.
7
+ - Every method returns `Result<T, GotenbergError>`.
8
+
9
+ ## Quick Links
10
+
11
+ - [Install](#install)
12
+ - [Prerequisites Environment Variables](#prerequisites-environment-variables)
13
+ - [Initialization](#initialization)
14
+ - [Where Can You Use This Package](#where-can-you-use-this-package)
15
+ - [Shared Input Types](#shared-input-types)
16
+ - [Response Model](#response-model)
17
+ - [Health and Version](#health-and-version)
18
+ - [Checking service health](#checking-service-health)
19
+ - [Reading server version](#reading-server-version)
20
+ - [Chromium to PDF](#chromium-to-pdf)
21
+ - [Converting URL to PDF](#converting-url-to-pdf)
22
+ - [Converting HTML to PDF](#converting-html-to-pdf)
23
+ - [Converting Markdown to PDF](#converting-markdown-to-pdf)
24
+ - [Chromium to Image](#chromium-to-image)
25
+ - [Taking URL screenshots](#taking-url-screenshots)
26
+ - [Taking HTML screenshots](#taking-html-screenshots)
27
+ - [Taking Markdown screenshots](#taking-markdown-screenshots)
28
+ - [Converting PDF to Images](#converting-pdf-to-images)
29
+ - [LibreOffice](#libreoffice)
30
+ - [Converting Office documents to PDF](#converting-office-documents-to-pdf)
31
+ - [Converting Excel to PDF](#converting-excel-to-pdf)
32
+ - [Converting Word to PDF](#converting-word-to-pdf)
33
+ - [PDF Operations](#pdf-operations)
34
+ - [Merging PDFs](#merging-pdfs)
35
+ - [Splitting PDFs](#splitting-pdfs)
36
+ - [Flattening PDFs](#flattening-pdfs)
37
+ - [Encrypting PDFs](#encrypting-pdfs)
38
+ - [Embedding files in PDFs](#embedding-files-in-pdfs)
39
+ - [Reading PDF metadata](#reading-pdf-metadata)
40
+ - [Writing PDF metadata](#writing-pdf-metadata)
41
+ - [Converting to PDF/A](#converting-to-pdfa)
42
+ - [Error Handling](#error-handling)
43
+ - [Development](#development)
44
+ - [CI Publish to npm](#ci-publish-to-npm)
45
+ - [Deploy Your Own Gotenberg Server](#deploy-your-own-gotenberg-server)
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ npm i gotenberg-client
51
+ ```
52
+
53
+ ```bash
54
+ bun add gotenberg-client
55
+ ```
56
+
57
+ ```bash
58
+ pnpm add gotenberg-client
59
+ ```
60
+
61
+ ## Prerequisites Environment Variables
62
+
63
+ `new Gotenberg()` reads required values from environment variables on construction:
64
+
65
+ - `GOTENBERG_URL`
66
+ - `GOTENBERG_API_BASIC_AUTH_USERNAME`
67
+ - `GOTENBERG_API_BASIC_AUTH_PASSWORD`
68
+
69
+ If any are missing, constructor will throw.
70
+
71
+ ## Initialization
72
+
73
+
74
+ ```ts
75
+ import { Gotenberg } from "gotenberg-client";
76
+
77
+ const gotenberg = new Gotenberg({
78
+ logger: {
79
+ error: (message, meta) => console.error(message, meta),
80
+ warn: (message, meta) => console.warn(message, meta),
81
+ },
82
+ });
83
+ ```
84
+
85
+ Optional logger and limiter are available via `GotenbergOptions`.
86
+
87
+ ## Where Can You Use This Package?
88
+
89
+ This package is built for server-side runtime usage:
90
+
91
+ - Node.js and Bun services
92
+ - serverless functions (if Gotenberg endpoint is accessible)
93
+ - background workers and CLI scripts
94
+ - SSR handlers (for example, Next.js API routes, Nuxt server handlers)
95
+
96
+ It is not intended for browser/client-side frontends because:
97
+
98
+ - credentials are read from environment variables on the server
99
+ - exposing shared secrets in a bundle is unsafe
100
+ - CORS, auth, and network constraints are usually unsuitable for direct browser calls
101
+
102
+ For browser products, call this package from your backend and expose a controlled API to the UI.
103
+
104
+ ### Compatibility Matrix
105
+
106
+ | Runtime | Recommended minimum | `fetch` support | Compatibility notes |
107
+ | --- | --- | --- | --- |
108
+ | **Node.js** | `18+` | Built-in | Recommended runtime. Native `fetch`, `Blob`, `FormData`, `AbortController`, `Headers`, `Request`, and `Response` are available. |
109
+ | **Node.js** | `16.x` (legacy) | Requires polyfill | Use `undici` (or equivalent) to provide global `fetch`, `Request`, `Response`, `Headers`, and streaming body support. |
110
+ | **Bun** | `1.0+` | Built-in | Fully supported with current package APIs. |
111
+ | **Cloudflare Workers / edge runtimes** | Runtime-dependent | Usually built-in | Possible but not officially tested. Ensure runtime provides `fetch` and stream-compatible multipart/form data behavior. |
112
+ | **Browser** | — | Usually built-in | Not recommended for this package because credentials are environment-driven and intended for private/backend use. |
113
+
114
+ ### Runtime Requirements At A Glance
115
+
116
+ - Works best in environments with modern web-fetch globals.
117
+ - If global `fetch` is missing, provide a polyfill before constructing `new Gotenberg()`.
118
+ - In browsers, avoid using env-based credentials directly; add a server proxy instead.
119
+
120
+ ## Shared Input Types
121
+
122
+ Code: type definitions live in [`src/types.ts`](./src/types.ts).
123
+
124
+ Use `GotenbergFile` for any upload field:
125
+
126
+ ```ts
127
+ import type { GotenbergFile } from "gotenberg-client";
128
+
129
+ const index: GotenbergFile = {
130
+ name: "document.docx",
131
+ data: await Bun.file("document.docx").arrayBuffer(),
132
+ contentType:
133
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
134
+ };
135
+ ```
136
+
137
+ ## Response
138
+
139
+ Each method returns:
140
+
141
+ ```ts
142
+ type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
143
+ ```
144
+
145
+ On success, binary methods return:
146
+
147
+ ```ts
148
+ {
149
+ blob: Blob;
150
+ filename: string | null;
151
+ contentType: string | null;
152
+ trace: string | null;
153
+ }
154
+ ```
155
+
156
+ On failure, inspect `error.type` (`config`, `network`, `http`, `invalid-response`).
157
+
158
+ ## Health and Version
159
+
160
+ ### Checking service health
161
+
162
+ #### `health(signal?)`
163
+
164
+ Warm-starting worker pipelines or running readiness checks. Avoid sending expensive transformation jobs when Gotenberg server is down.
165
+ ```ts
166
+ const result = await gotenberg.health();
167
+ if (result.ok) {
168
+ console.log(result.value.status); // "up" | "down"
169
+ }
170
+ ```
171
+
172
+ ### Reading server version
173
+
174
+ #### `version(signal?)`
175
+
176
+ Validating server compatibility during deployment or in diagnostics. Helps with support and incident triage when output behavior changes across server versions.
177
+ ```ts
178
+ const result = await gotenberg.version();
179
+ if (result.ok) {
180
+ console.log("Gotenberg:", result.value);
181
+ }
182
+ ```
183
+
184
+ ## Chromium to PDF
185
+
186
+ ### Converting URL to PDF
187
+ Gotenberg handles page loading, rendering, and output as PDF, removing browser automation work from your app.
188
+ #### `urlToPdf(input: ConvertUrlInput)`
189
+
190
+ Code: wrapper in [`src/gotenberg.ts`](./src/gotenberg.ts), request method `convertUrl` in [`src/client.ts`](./src/client.ts).
191
+
192
+ ```ts
193
+ const result = await gotenberg.urlToPdf({
194
+ url: "https://example.com",
195
+ options: { printBackground: true },
196
+ });
197
+ ```
198
+
199
+ ### Converting HTML to PDF
200
+
201
+ You can generate HTML from templates in your application and need immediate PDF output and convert dynamic HTML directly without writing temporary files.
202
+
203
+ #### `htmlToPdf(input: ConvertHtmlInput)`
204
+
205
+ Code: wrapper in [`src/gotenberg.ts`](./src/gotenberg.ts), request method `convertHtml` in [`src/client.ts`](./src/client.ts).
206
+
207
+ ```ts
208
+ const result = await gotenberg.htmlToPdf({
209
+ indexHtml: "<html><body>hello</body></html>",
210
+ options: { singlePage: true },
211
+ });
212
+ ```
213
+
214
+ ### Converting Markdown to PDF
215
+
216
+ #### `markdownToPdf(input: ConvertMarkdownInput)`
217
+
218
+ ```ts
219
+ const result = await gotenberg.markdownToPdf({
220
+ indexHtml: { name: "index.md", data: "# notes", contentType: "text/markdown" },
221
+ markdownFiles: [
222
+ { name: "appendix.md", data: "# appendix", contentType: "text/markdown" },
223
+ ],
224
+ });
225
+ ```
226
+
227
+ ## Chromium to Image
228
+
229
+ ### Taking URL screenshots
230
+
231
+ #### `screenshotUrl(input: ScreenshotUrlInput)`
232
+
233
+
234
+ ```ts
235
+ const result = await gotenberg.screenshotUrl({
236
+ url: "https://example.com",
237
+ options: { format: "png", width: 1280, height: 720 },
238
+ });
239
+ ```
240
+
241
+ ### Taking HTML screenshots
242
+
243
+ #### `screenshotHtml(input: ScreenshotHtmlInput)`
244
+
245
+ ```ts
246
+ const result = await gotenberg.screenshotHtml({
247
+ indexHtml: "<html><body>visual diff</body></html>",
248
+ options: { format: "webp", optimizeForSpeed: true },
249
+ });
250
+ ```
251
+
252
+ ### Taking Markdown screenshots
253
+
254
+ #### `screenshotMarkdown(input: ScreenshotMarkdownInput)`
255
+
256
+ ```ts
257
+ const result = await gotenberg.screenshotMarkdown({
258
+ indexHtml: { name: "index.md", data: "# screenshot", contentType: "text/markdown" },
259
+ markdownFiles: [{ name: "notes.md", data: "# note", contentType: "text/markdown" }],
260
+ });
261
+ ```
262
+
263
+
264
+ ### Converting PDF to Images
265
+
266
+ #### `pdfToImage(input: ScreenshotUrlInput)`
267
+
268
+
269
+ Alias for URL screenshot flow for convenience:
270
+
271
+ ```ts
272
+ const result = await gotenberg.pdfToImage({
273
+ url: "https://example.com/my.pdf",
274
+ options: { format: "png" },
275
+ });
276
+ ```
277
+
278
+
279
+ ## LibreOffice
280
+
281
+ ### Converting Office documents to PDF
282
+
283
+ #### `officeToPdf(input: ConvertOfficeInput)`
284
+
285
+ ```ts
286
+ const result = await gotenberg.officeToPdf({
287
+ files: [{ name: "report.docx", data: await Bun.file("report.docx").arrayBuffer() }],
288
+ });
289
+ ```
290
+
291
+ ### Converting Excel to PDF
292
+
293
+ #### `excelToPdf(input: ConvertOfficeInput)`
294
+
295
+ Code: wrapper in [`src/gotenberg.ts`](./src/gotenberg.ts), delegates to `convertOffice` in [`src/client.ts`](./src/client.ts).
296
+
297
+ ```ts
298
+ const result = await gotenberg.excelToPdf({ files: [/* ... */] });
299
+ ```
300
+
301
+ Use when: your workflow needs domain naming for spreadsheet processing.
302
+ Why: explicit naming improves readability and intent in business code.
303
+
304
+ ### Converting Word to PDF
305
+
306
+ #### `wordToPdf(input: ConvertOfficeInput)`
307
+
308
+ ```ts
309
+ const result = await gotenberg.wordToPdf({ files: [/* ... */] });
310
+ ```
311
+
312
+ ## PDF Operations
313
+
314
+ ### Merging PDFs
315
+
316
+ #### `mergePdf(input: MergePdfInput)`
317
+
318
+ ```ts
319
+ const result = await gotenberg.mergePdf({
320
+ files: [pdfA, pdfB],
321
+ outputFilename: "merged.pdf",
322
+ });
323
+ ```
324
+
325
+ ### Splitting PDFs
326
+
327
+ #### `splitPdf(input: SplitPdfInput)`
328
+
329
+ ```ts
330
+ const result = await gotenberg.splitPdf({
331
+ files: [pdf],
332
+ splitMode: "pages",
333
+ splitSpan: "1",
334
+ });
335
+ ```
336
+
337
+
338
+ ### Flattening PDFs
339
+
340
+ #### `flattenPdf(input: FlattenPdfInput)`
341
+
342
+ ```ts
343
+ const result = await gotenberg.flattenPdf({
344
+ files: [pdf],
345
+ outputFilename: "flattened.pdf",
346
+ });
347
+ ```
348
+
349
+ ### Encrypting PDFs
350
+
351
+ #### `encryptPdf(input: EncryptPdfInput)`
352
+
353
+ Code: wrapper in [`src/gotenberg.ts`](./src/gotenberg.ts), request method `encryptPdf` in [`src/client.ts`](./src/client.ts).
354
+
355
+ ```ts
356
+ const result = await gotenberg.encryptPdf({
357
+ files: [pdf],
358
+ userPassword: "owner-only",
359
+ });
360
+ ```
361
+
362
+ ### Embedding files in PDFs
363
+
364
+ #### `embedFiles(input: EmbedFilesInput)`
365
+
366
+
367
+ ```ts
368
+ const result = await gotenberg.embedFiles({
369
+ files: [pdf],
370
+ embeds: [overlay],
371
+ outputFilename: "embedded.pdf",
372
+ });
373
+ ```
374
+
375
+
376
+ ### Reading PDF metadata
377
+
378
+ #### `readMetadata(input: ReadMetadataInput)`
379
+
380
+
381
+ ```ts
382
+ const result = await gotenberg.readMetadata({ files: [pdf] });
383
+ if (result.ok) {
384
+ console.log(result.value);
385
+ }
386
+ ```
387
+
388
+
389
+ ### Writing PDF metadata
390
+
391
+ #### `writeMetadata(input: WriteMetadataInput)`
392
+
393
+
394
+ ```ts
395
+ const result = await gotenberg.writeMetadata({
396
+ files: [pdf],
397
+ metadata: { Title: "Quarterly Report", Author: "Ops Team" },
398
+ });
399
+ ```
400
+
401
+
402
+ ### Converting to PDF/A
403
+
404
+ #### `convertToPdfa(input: ConvertToPdfaInput)`
405
+
406
+
407
+ ```ts
408
+ const result = await gotenberg.convertToPdfa({
409
+ files: [pdf],
410
+ pdfa: "PDF/A-2b",
411
+ pdfua: true,
412
+ });
413
+ ```
414
+
415
+ ## Error Handling
416
+
417
+ ```ts
418
+ const result = await gotenberg.version();
419
+ if (!result.ok) {
420
+ const error = result.error;
421
+ console.error(error.type, error.message, error.status, error.trace);
422
+ return;
423
+ }
424
+
425
+ console.log("ready");
426
+ ```
427
+
428
+ ## Development
429
+
430
+ ```bash
431
+ bun install
432
+ bun run format
433
+ bun test
434
+ bun run build
435
+ ```
436
+
437
+
438
+ ## Deploy Your Own Gotenberg Server
439
+
440
+ You must run your own Gotenberg instance and point `GOTENBERG_URL` to it.
441
+
442
+ ### Docker example
443
+
444
+ ```bash
445
+ docker run --rm -p 3000:3000 gotenberg/gotenberg:8
446
+ ```
447
+
448
+ ### Docker with basic auth reverse proxy
449
+
450
+ Use a reverse proxy (for example Nginx, Caddy, Traefik) in front of Gotenberg and enforce basic auth there. Then set:
451
+
452
+ - `GOTENBERG_URL` to proxy URL
453
+ - `GOTENBERG_API_BASIC_AUTH_USERNAME` to proxy username
454
+ - `GOTENBERG_API_BASIC_AUTH_PASSWORD` to proxy password
455
+
456
+ ### Production deployment notes
457
+
458
+ - keep Gotenberg inside a public/private network is fine either case - as long as you set the username and password within the environment
459
+ - set request size/time limits at gateway level
460
+ - monitor CPU and memory because Chromium and LibreOffice conversions are workload-heavy
461
+ - run multiple replicas behind a load balancer for high-throughput conversion workloads
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "gotenberg-client",
3
+ "description": "TypeScript client for the Gotenberg document conversion API.",
4
+ "version": "0.0.1",
5
+ "keywords": [
6
+ "gotenberg",
7
+ "typescript",
8
+ "api-client",
9
+ "pdf",
10
+ "conversion"
11
+ ],
12
+ "module": "dist/index.js",
13
+ "type": "module",
14
+ "private": false,
15
+ "author": {
16
+ "name": "zmzlois",
17
+ "email": "lois@normal-people.com",
18
+ "url": "https://github.com/zmzlois",
19
+ "x": "https://x.com/zmzlois"
20
+ },
21
+ "homepage": "https://github.com/zmzlois/gotenberg-client#readme",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/zmzlois/gotenberg-client.git",
25
+ "directory": "."
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/zmzlois/gotenberg-client/issues"
29
+ },
30
+ "funding": {
31
+ "type": "github",
32
+ "url": "https://github.com/sponsors/zmzlois/dashboard"
33
+ },
34
+ "main": "dist/index.js",
35
+ "types": "dist/index.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "import": "./dist/index.js",
39
+ "types": "./dist/index.d.ts"
40
+ }
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "README.md"
45
+ ],
46
+ "scripts": {
47
+ "format": "biome check --write .",
48
+ "format:code": "biome format --write .",
49
+ "build": "bunx tsc -p tsconfig.build.json",
50
+ "typecheck": "bunx tsc -p tsconfig.json --noEmit",
51
+ "test": "bun test"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public",
55
+ "provenance": true
56
+ },
57
+ "devDependencies": {
58
+ "@biomejs/biome": "^2.0.0",
59
+ "@types/bun": "latest",
60
+ "typescript": "^5"
61
+ },
62
+ "peerDependencies": {
63
+ "typescript": "^5"
64
+ }
65
+ }
@@ -0,0 +1,26 @@
1
+ import type { ConvertHtmlInput, ConvertMarkdownInput, ConvertOfficeInput, ConvertToPdfaInput, ConvertUrlInput, EmbedFilesInput, EncryptPdfInput, FlattenPdfInput, GotenbergClient, GotenbergClientOptions, GotenbergHealth, MergePdfInput, ReadMetadataInput, ScreenshotHtmlInput, ScreenshotMarkdownInput, ScreenshotUrlInput, SplitPdfInput, WriteMetadataInput } from "./types";
2
+ /**
3
+ * Internal request layer used by the public `Gotenberg` class.
4
+ * It focuses purely on transport + payload assembly.
5
+ */
6
+ export declare class GotenbergRequestClient implements GotenbergClient {
7
+ private readonly options;
8
+ constructor(options: GotenbergClientOptions);
9
+ health(signal?: AbortSignal): Promise<import("./types").Result<GotenbergHealth, import("./types").GotenbergError>>;
10
+ version(signal?: AbortSignal): Promise<import("./types").Result<string, import("./types").GotenbergError>>;
11
+ convertUrl(input: ConvertUrlInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
12
+ convertHtml(input: ConvertHtmlInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
13
+ convertMarkdown(input: ConvertMarkdownInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
14
+ screenshotUrl(input: ScreenshotUrlInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
15
+ screenshotHtml(input: ScreenshotHtmlInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
16
+ screenshotMarkdown(input: ScreenshotMarkdownInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
17
+ convertOffice(input: ConvertOfficeInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
18
+ mergePdf(input: MergePdfInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
19
+ splitPdf(input: SplitPdfInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
20
+ flattenPdf(input: FlattenPdfInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
21
+ encryptPdf(input: EncryptPdfInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
22
+ embedFiles(input: EmbedFilesInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
23
+ readMetadata(input: ReadMetadataInput): Promise<import("./types").Result<Record<string, Record<string, string>>, import("./types").GotenbergError>>;
24
+ writeMetadata(input: WriteMetadataInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
25
+ convertToPdfa(input: ConvertToPdfaInput): Promise<import("./types").Result<import("./types").GotenbergBinaryResponse, import("./types").GotenbergError>>;
26
+ }