chromiumly 2.7.0 → 2.9.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.
Files changed (77) hide show
  1. package/README.md +129 -8
  2. package/dist/chromium/converters/html.converter.d.ts +12 -2
  3. package/dist/chromium/converters/html.converter.js +5 -3
  4. package/dist/chromium/converters/html.converter.js.map +1 -1
  5. package/dist/chromium/converters/markdown.converter.d.ts +12 -2
  6. package/dist/chromium/converters/markdown.converter.js +5 -3
  7. package/dist/chromium/converters/markdown.converter.js.map +1 -1
  8. package/dist/chromium/converters/url.converter.d.ts +12 -2
  9. package/dist/chromium/converters/url.converter.js +5 -3
  10. package/dist/chromium/converters/url.converter.js.map +1 -1
  11. package/dist/chromium/index.d.ts +3 -0
  12. package/dist/chromium/index.js +7 -1
  13. package/dist/chromium/index.js.map +1 -1
  14. package/dist/chromium/interfaces/converter.types.d.ts +2 -1
  15. package/dist/chromium/interfaces/screenshot.types.d.ts +10 -0
  16. package/dist/chromium/interfaces/screenshot.types.js +3 -0
  17. package/dist/chromium/interfaces/screenshot.types.js.map +1 -0
  18. package/dist/chromium/screenshots/html.screenshot.d.ts +54 -0
  19. package/dist/chromium/screenshots/html.screenshot.js +67 -0
  20. package/dist/chromium/screenshots/html.screenshot.js.map +1 -0
  21. package/dist/chromium/screenshots/markdown.screenshot.d.ts +52 -0
  22. package/dist/chromium/screenshots/markdown.screenshot.js +66 -0
  23. package/dist/chromium/screenshots/markdown.screenshot.js.map +1 -0
  24. package/dist/chromium/screenshots/screenshot.d.ts +18 -0
  25. package/dist/chromium/screenshots/screenshot.js +21 -0
  26. package/dist/chromium/screenshots/screenshot.js.map +1 -0
  27. package/dist/chromium/screenshots/url.screenshot.d.ts +50 -0
  28. package/dist/chromium/screenshots/url.screenshot.js +66 -0
  29. package/dist/chromium/screenshots/url.screenshot.js.map +1 -0
  30. package/dist/chromium/utils/converter.utils.js +3 -0
  31. package/dist/chromium/utils/converter.utils.js.map +1 -1
  32. package/dist/chromium/utils/screenshot.utils.d.ts +22 -0
  33. package/dist/chromium/utils/screenshot.utils.js +75 -0
  34. package/dist/chromium/utils/screenshot.utils.js.map +1 -0
  35. package/dist/common/constants.d.ts +4 -0
  36. package/dist/common/constants.js +4 -0
  37. package/dist/common/constants.js.map +1 -1
  38. package/dist/common/index.d.ts +1 -1
  39. package/dist/common/types.d.ts +3 -0
  40. package/dist/libre-office/utils/constants.js +2 -1
  41. package/dist/libre-office/utils/constants.js.map +1 -1
  42. package/dist/main.config.d.ts +10 -1
  43. package/dist/main.config.js +10 -1
  44. package/dist/main.config.js.map +1 -1
  45. package/dist/main.d.ts +1 -1
  46. package/dist/main.js +4 -1
  47. package/dist/main.js.map +1 -1
  48. package/dist/pdf-engines/pdf.engine.d.ts +23 -1
  49. package/dist/pdf-engines/pdf.engine.js +34 -4
  50. package/dist/pdf-engines/pdf.engine.js.map +1 -1
  51. package/package.json +7 -7
  52. package/src/chromium/converters/html.converter.ts +20 -3
  53. package/src/chromium/converters/markdown.converter.ts +20 -3
  54. package/src/chromium/converters/url.converter.ts +20 -3
  55. package/src/chromium/index.ts +3 -0
  56. package/src/chromium/interfaces/converter.types.ts +2 -1
  57. package/src/chromium/interfaces/screenshot.types.ts +12 -0
  58. package/src/chromium/screenshots/html.screenshot.ts +100 -0
  59. package/src/chromium/screenshots/markdown.screenshot.ts +95 -0
  60. package/src/chromium/screenshots/screenshot.ts +22 -0
  61. package/src/chromium/screenshots/tests/html.screenshot.test.ts +192 -0
  62. package/src/chromium/screenshots/tests/markdown.screenshot.test.ts +176 -0
  63. package/src/chromium/screenshots/tests/url.screenshot.test.ts +166 -0
  64. package/src/chromium/screenshots/url.screenshot.ts +91 -0
  65. package/src/chromium/utils/converter.utils.ts +3 -0
  66. package/src/chromium/utils/screenshot.utils.ts +115 -0
  67. package/src/chromium/utils/tests/converter.utils.test.ts +33 -2
  68. package/src/chromium/utils/tests/screenshot.utils.test.ts +284 -0
  69. package/src/common/constants.ts +4 -0
  70. package/src/common/index.ts +1 -1
  71. package/src/common/tests/gotenberg.utils.test.ts +46 -0
  72. package/src/common/types.ts +4 -0
  73. package/src/libre-office/utils/constants.ts +2 -1
  74. package/src/main.config.ts +12 -2
  75. package/src/main.ts +8 -1
  76. package/src/pdf-engines/pdf.engine.ts +52 -1
  77. package/src/pdf-engines/tests/pdf.engine.test.ts +36 -0
@@ -0,0 +1,115 @@
1
+ import {
2
+ ImageProperties,
3
+ ScreenshotOptions
4
+ } from './../interfaces/screenshot.types';
5
+ import FormData from 'form-data';
6
+
7
+ import { GotenbergUtils } from '../../common';
8
+
9
+ /**
10
+ * Utility class for handling common tasks related to screenshot.
11
+ */
12
+ export class ScreenshotUtils {
13
+ /**
14
+ * Adds page properties to the FormData object based on the provided imageProperties.
15
+ *
16
+ * @param {FormData} data - The FormData object to which page properties will be added.
17
+ * @param {ImageProperties} imageProperties - The page properties to be added to the FormData.
18
+ */
19
+ public static addImageProperties(
20
+ data: FormData,
21
+ imageProperties: ImageProperties
22
+ ): void {
23
+ data.append('format', imageProperties.format);
24
+
25
+ if (imageProperties.quality) {
26
+ GotenbergUtils.assert(
27
+ imageProperties.format === 'jpeg',
28
+ 'Compression quality is exclusively supported for JPEG format.'
29
+ );
30
+ GotenbergUtils.assert(
31
+ imageProperties.quality >= 0 && imageProperties.quality <= 100,
32
+ 'Invalid compression quality. Please provide a value between 0 and 100.'
33
+ );
34
+
35
+ data.append('quality', imageProperties.quality);
36
+ }
37
+
38
+ if (imageProperties.omitBackground) {
39
+ data.append(
40
+ 'omitBackground',
41
+ String(imageProperties.omitBackground)
42
+ );
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Customizes the FormData object based on the provided screenshot options.
48
+ *
49
+ * @param {FormData} data - The FormData object to be customized.
50
+ * @param {ScreenshotOptions} options - The screenshot options to apply to the FormData.
51
+ * @returns {Promise<void>} A Promise that resolves once the customization is complete.
52
+ */
53
+ public static async customize(
54
+ data: FormData,
55
+ options: ScreenshotOptions
56
+ ): Promise<void> {
57
+ if (options.header) {
58
+ const { header } = options;
59
+ await GotenbergUtils.addFile(data, header, 'header.html');
60
+ }
61
+
62
+ if (options.footer) {
63
+ const { footer } = options;
64
+ await GotenbergUtils.addFile(data, footer, 'footer.html');
65
+ }
66
+
67
+ if (options.emulatedMediaType) {
68
+ data.append('emulatedMediaType', options.emulatedMediaType);
69
+ }
70
+
71
+ if (options.properties) {
72
+ ScreenshotUtils.addImageProperties(data, options.properties);
73
+ }
74
+
75
+ if (options.waitDelay) {
76
+ data.append('waitDelay', options.waitDelay);
77
+ }
78
+
79
+ if (options.waitForExpression) {
80
+ data.append('waitForExpression', options.waitForExpression);
81
+ }
82
+
83
+ if (options.extraHttpHeaders) {
84
+ data.append(
85
+ 'extraHttpHeaders',
86
+ JSON.stringify(options.extraHttpHeaders)
87
+ );
88
+ }
89
+
90
+ if (options.failOnHttpStatusCodes) {
91
+ data.append(
92
+ 'failOnHttpStatusCodes',
93
+ JSON.stringify(options.failOnHttpStatusCodes)
94
+ );
95
+ }
96
+
97
+ if (options.failOnConsoleExceptions) {
98
+ data.append(
99
+ 'failOnConsoleExceptions',
100
+ String(options.failOnConsoleExceptions)
101
+ );
102
+ }
103
+
104
+ if (options.skipNetworkIdleEvent) {
105
+ data.append(
106
+ 'skipNetworkIdleEvent',
107
+ String(options.skipNetworkIdleEvent)
108
+ );
109
+ }
110
+
111
+ if (options.optimizeForSpeed) {
112
+ data.append('optimizeForSpeed', String(options.optimizeForSpeed));
113
+ }
114
+ }
115
+ }
@@ -351,6 +351,19 @@ describe('GotenbergUtils', () => {
351
351
  });
352
352
  });
353
353
 
354
+ describe('when metadata parameter is passed', () => {
355
+ it('should append metadata', async () => {
356
+ await ConverterUtils.customize(data, {
357
+ metadata: { Author: 'John Doe' }
358
+ });
359
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
360
+ expect(data.append).toHaveBeenCalledWith(
361
+ 'metadata',
362
+ JSON.stringify({ Author: 'John Doe' })
363
+ );
364
+ });
365
+ });
366
+
354
367
  describe('when all options are passed', () => {
355
368
  it('should append all options', async () => {
356
369
  await ConverterUtils.customize(data, {
@@ -365,9 +378,12 @@ describe('GotenbergUtils', () => {
365
378
  userAgent:
366
379
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36',
367
380
  extraHttpHeaders: { 'X-Custom-Header': 'value' },
368
- failOnConsoleExceptions: true
381
+ failOnHttpStatusCodes: [499, 599],
382
+ skipNetworkIdleEvent: true,
383
+ failOnConsoleExceptions: true,
384
+ metadata: { Author: 'John Doe' }
369
385
  });
370
- expect(mockFormDataAppend).toHaveBeenCalledTimes(12);
386
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(15);
371
387
  expect(data.append).toHaveBeenNthCalledWith(
372
388
  1,
373
389
  'pdfa',
@@ -423,9 +439,24 @@ describe('GotenbergUtils', () => {
423
439
  );
424
440
  expect(data.append).toHaveBeenNthCalledWith(
425
441
  12,
442
+ 'failOnHttpStatusCodes',
443
+ JSON.stringify([499, 599])
444
+ );
445
+ expect(data.append).toHaveBeenNthCalledWith(
446
+ 13,
426
447
  'failOnConsoleExceptions',
427
448
  'true'
428
449
  );
450
+ expect(data.append).toHaveBeenNthCalledWith(
451
+ 14,
452
+ 'skipNetworkIdleEvent',
453
+ 'true'
454
+ );
455
+ expect(data.append).toHaveBeenNthCalledWith(
456
+ 15,
457
+ 'metadata',
458
+ JSON.stringify({ Author: 'John Doe' })
459
+ );
429
460
  });
430
461
  });
431
462
  });
@@ -0,0 +1,284 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
+ import FormData from 'form-data';
3
+ import { ScreenshotUtils } from './../screenshot.utils';
4
+
5
+ describe('GotenbergUtils', () => {
6
+ const mockFormDataAppend = jest.spyOn(FormData.prototype, 'append');
7
+ const data = new FormData();
8
+
9
+ afterEach(() => {
10
+ jest.resetAllMocks();
11
+ });
12
+
13
+ describe('addImageProperties', () => {
14
+ describe('Image format', () => {
15
+ describe('when format parameter is set', () => {
16
+ it('should append format to data', () => {
17
+ ScreenshotUtils.addImageProperties(data, {
18
+ format: 'png'
19
+ });
20
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
21
+ expect(data.append).toHaveBeenCalledWith('format', 'png');
22
+ });
23
+ });
24
+ });
25
+
26
+ describe('Image background', () => {
27
+ describe('when omitBackground parameter is set', () => {
28
+ it('should append omitBackground to data', () => {
29
+ ScreenshotUtils.addImageProperties(data, {
30
+ format: 'png',
31
+ omitBackground: true
32
+ });
33
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(2);
34
+ expect(data.append).toHaveBeenCalledWith('format', 'png');
35
+ expect(data.append).toHaveBeenNthCalledWith(
36
+ 2,
37
+ 'omitBackground',
38
+ 'true'
39
+ );
40
+ });
41
+ });
42
+ });
43
+
44
+ describe('Image quality', () => {
45
+ describe('when omitBackground parameter is set', () => {
46
+ it('should append omitBackground to data', () => {
47
+ ScreenshotUtils.addImageProperties(data, {
48
+ format: 'jpeg',
49
+ quality: 50
50
+ });
51
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(2);
52
+ expect(data.append).toHaveBeenCalledWith('format', 'jpeg');
53
+ expect(data.append).toHaveBeenNthCalledWith(
54
+ 2,
55
+ 'quality',
56
+ 50
57
+ );
58
+ });
59
+ });
60
+ });
61
+ });
62
+
63
+ describe('customize', () => {
64
+ describe('when no option is passed', () => {
65
+ it('should not append anything', async () => {
66
+ await ScreenshotUtils.customize(data, {});
67
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(0);
68
+ });
69
+ });
70
+
71
+ describe('when header parameter is passed', () => {
72
+ it('should append header', async () => {
73
+ await ScreenshotUtils.customize(data, {
74
+ header: Buffer.from('header')
75
+ });
76
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
77
+ expect(data.append).toHaveBeenCalledWith(
78
+ 'files',
79
+ Buffer.from('header'),
80
+ 'header.html'
81
+ );
82
+ });
83
+ });
84
+
85
+ describe('when footer parameter is passed', () => {
86
+ it('should append footer', async () => {
87
+ await ScreenshotUtils.customize(data, {
88
+ footer: Buffer.from('footer')
89
+ });
90
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
91
+ expect(data.append).toHaveBeenCalledWith(
92
+ 'files',
93
+ Buffer.from('footer'),
94
+ 'footer.html'
95
+ );
96
+ });
97
+ });
98
+
99
+ describe('when emulatedMediaType parameter is passed', () => {
100
+ it('should append emulatedMediaType', async () => {
101
+ await ScreenshotUtils.customize(data, {
102
+ emulatedMediaType: 'screen'
103
+ });
104
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
105
+ expect(data.append).toHaveBeenCalledWith(
106
+ 'emulatedMediaType',
107
+ 'screen'
108
+ );
109
+ });
110
+ });
111
+
112
+ describe('when waitDelay parameter is passed', () => {
113
+ it('should append waitDelay', async () => {
114
+ await ScreenshotUtils.customize(data, {
115
+ waitDelay: '5s'
116
+ });
117
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
118
+ expect(data.append).toHaveBeenCalledWith('waitDelay', '5s');
119
+ });
120
+ });
121
+
122
+ describe('when waitForExpression parameter is passed', () => {
123
+ it('should append waitForExpression', async () => {
124
+ await ScreenshotUtils.customize(data, {
125
+ waitForExpression: "document.readyState === 'complete'"
126
+ });
127
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
128
+ expect(data.append).toHaveBeenCalledWith(
129
+ 'waitForExpression',
130
+ "document.readyState === 'complete'"
131
+ );
132
+ });
133
+ });
134
+
135
+ describe('when extraHttpHeaders parameter is passed', () => {
136
+ it('should append extraHttpHeaders', async () => {
137
+ const extraHttpHeaders = {
138
+ 'X-Custom-Header': 'value'
139
+ };
140
+
141
+ await ScreenshotUtils.customize(data, {
142
+ extraHttpHeaders
143
+ });
144
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
145
+ expect(data.append).toHaveBeenCalledWith(
146
+ 'extraHttpHeaders',
147
+ JSON.stringify(extraHttpHeaders)
148
+ );
149
+ });
150
+ });
151
+
152
+ describe('when failOnConsoleExceptions parameter is passed', () => {
153
+ it('should append failOnConsoleExceptions', async () => {
154
+ await ScreenshotUtils.customize(data, {
155
+ failOnConsoleExceptions: true
156
+ });
157
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
158
+ expect(data.append).toHaveBeenCalledWith(
159
+ 'failOnConsoleExceptions',
160
+ 'true'
161
+ );
162
+ });
163
+ });
164
+
165
+ describe('when failOnHttpStatusCodes parameter is passed', () => {
166
+ it('should append failOnHttpStatusCodes', async () => {
167
+ await ScreenshotUtils.customize(data, {
168
+ failOnHttpStatusCodes: [499, 599]
169
+ });
170
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
171
+ expect(data.append).toHaveBeenCalledWith(
172
+ 'failOnHttpStatusCodes',
173
+ JSON.stringify([499, 599])
174
+ );
175
+ });
176
+ });
177
+
178
+ describe('when skipNetworkIdleEvent parameter is passed', () => {
179
+ it('should append skipNetworkIdleEvent', async () => {
180
+ await ScreenshotUtils.customize(data, {
181
+ skipNetworkIdleEvent: true
182
+ });
183
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
184
+ expect(data.append).toHaveBeenCalledWith(
185
+ 'skipNetworkIdleEvent',
186
+ 'true'
187
+ );
188
+ });
189
+ });
190
+
191
+ describe('when optimizeForSpeed parameter is passed', () => {
192
+ it('should append optimizeForSpeed', async () => {
193
+ await ScreenshotUtils.customize(data, {
194
+ optimizeForSpeed: true
195
+ });
196
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
197
+ expect(data.append).toHaveBeenCalledWith(
198
+ 'optimizeForSpeed',
199
+ 'true'
200
+ );
201
+ });
202
+ });
203
+
204
+ describe('when all options are passed', () => {
205
+ it('should append all options', async () => {
206
+ await ScreenshotUtils.customize(data, {
207
+ header: Buffer.from('header.html'),
208
+ footer: Buffer.from('footer.html'),
209
+ emulatedMediaType: 'screen',
210
+ failOnHttpStatusCodes: [499, 599],
211
+ skipNetworkIdleEvent: true,
212
+ failOnConsoleExceptions: true,
213
+ properties: {
214
+ format: 'jpeg',
215
+ quality: 50
216
+ },
217
+ waitDelay: '5s',
218
+ waitForExpression: "document.readyState === 'complete'",
219
+ extraHttpHeaders: { 'X-Custom-Header': 'value' },
220
+ optimizeForSpeed: true
221
+ });
222
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(12);
223
+ expect(data.append).toHaveBeenNthCalledWith(
224
+ 1,
225
+ 'files',
226
+ Buffer.from('header.html'),
227
+ 'header.html'
228
+ );
229
+ expect(data.append).toHaveBeenNthCalledWith(
230
+ 2,
231
+ 'files',
232
+ Buffer.from('footer.html'),
233
+ 'footer.html'
234
+ );
235
+ expect(data.append).toHaveBeenNthCalledWith(
236
+ 3,
237
+ 'emulatedMediaType',
238
+ 'screen'
239
+ );
240
+ expect(data.append).toHaveBeenNthCalledWith(
241
+ 4,
242
+ 'format',
243
+ 'jpeg'
244
+ );
245
+ expect(data.append).toHaveBeenNthCalledWith(5, 'quality', 50);
246
+ expect(data.append).toHaveBeenNthCalledWith(
247
+ 6,
248
+ 'waitDelay',
249
+ '5s'
250
+ );
251
+ expect(data.append).toHaveBeenNthCalledWith(
252
+ 7,
253
+ 'waitForExpression',
254
+ "document.readyState === 'complete'"
255
+ );
256
+ expect(data.append).toHaveBeenNthCalledWith(
257
+ 8,
258
+ 'extraHttpHeaders',
259
+ JSON.stringify({ 'X-Custom-Header': 'value' })
260
+ );
261
+ expect(data.append).toHaveBeenNthCalledWith(
262
+ 9,
263
+ 'failOnHttpStatusCodes',
264
+ JSON.stringify([499, 599])
265
+ );
266
+ expect(data.append).toHaveBeenNthCalledWith(
267
+ 10,
268
+ 'failOnConsoleExceptions',
269
+ 'true'
270
+ );
271
+ expect(data.append).toHaveBeenNthCalledWith(
272
+ 11,
273
+ 'skipNetworkIdleEvent',
274
+ 'true'
275
+ );
276
+ expect(data.append).toHaveBeenNthCalledWith(
277
+ 12,
278
+ 'optimizeForSpeed',
279
+ 'true'
280
+ );
281
+ });
282
+ });
283
+ });
284
+ });
@@ -1,4 +1,8 @@
1
1
  export enum PdfFormat {
2
+ /**
3
+ * @deprecated Starting from Gotenberg version 7.6, LibreOffice no longer provides support for PDF/A-1a.
4
+ * @see {@link https://gotenberg.dev/docs/troubleshooting#pdfa-1a}
5
+ */
2
6
  A_1a = 'PDF/A-1a',
3
7
  A_2b = 'PDF/A-2b',
4
8
  A_3b = 'PDF/A-3b'
@@ -1,3 +1,3 @@
1
1
  export { PdfFormat } from './constants';
2
2
  export { GotenbergUtils } from './gotenberg.utils';
3
- export { PathLikeOrReadStream } from './types';
3
+ export { PathLikeOrReadStream, Metadata } from './types';
@@ -1,3 +1,5 @@
1
+ import { createReadStream, promises } from 'fs';
2
+ import path from 'path';
1
3
  import fetch from 'node-fetch';
2
4
  import FormData from 'form-data';
3
5
 
@@ -8,6 +10,9 @@ const { Response, FetchError } = jest.requireActual('node-fetch');
8
10
  jest.mock('node-fetch', () => jest.fn());
9
11
 
10
12
  describe('GotenbergUtils', () => {
13
+ const mockFormDataAppend = jest.spyOn(FormData.prototype, 'append');
14
+ const data = new FormData();
15
+
11
16
  afterEach(() => {
12
17
  jest.resetAllMocks();
13
18
  });
@@ -75,4 +80,45 @@ describe('GotenbergUtils', () => {
75
80
  });
76
81
  });
77
82
  });
83
+
84
+ describe('addFile', () => {
85
+ const mockPromisesAccess = jest.spyOn(promises, 'access');
86
+ const __tmp__ = path.resolve(process.cwd(), '__tmp__');
87
+ const filePath = path.resolve(__tmp__, 'file.html');
88
+
89
+ beforeAll(async () => {
90
+ mockPromisesAccess.mockResolvedValue();
91
+ await promises.mkdir(path.resolve(__tmp__), { recursive: true });
92
+ await promises.writeFile(filePath, 'data');
93
+ });
94
+
95
+ afterAll(async () => {
96
+ await promises.rm(path.resolve(__tmp__), { recursive: true });
97
+ });
98
+
99
+ describe('when file is passed as read stream', () => {
100
+ it('should append file to data', async () => {
101
+ const file = createReadStream(filePath);
102
+ await GotenbergUtils.addFile(data, file, 'file');
103
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
104
+ expect(data.append).toHaveBeenCalledWith('files', file, 'file');
105
+ });
106
+ });
107
+
108
+ describe('when file is passed as path', () => {
109
+ it('should append file to data', async () => {
110
+ await GotenbergUtils.addFile(data, filePath, 'file');
111
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
112
+ });
113
+ });
114
+
115
+ describe('when file is passed as buffer', () => {
116
+ it('should append file to data', async () => {
117
+ const file = Buffer.from('data');
118
+ await GotenbergUtils.addFile(data, file, 'file');
119
+ expect(mockFormDataAppend).toHaveBeenCalledTimes(1);
120
+ expect(data.append).toHaveBeenCalledWith('files', file, 'file');
121
+ });
122
+ });
123
+ });
78
124
  });
@@ -1,3 +1,7 @@
1
1
  import { PathLike, ReadStream } from 'fs';
2
2
 
3
3
  export type PathLikeOrReadStream = PathLike | ReadStream;
4
+
5
+ export type Metadata = {
6
+ [key: string]: boolean | number | string | string[];
7
+ };
@@ -78,5 +78,6 @@ export const LIBRE_OFFICE_EXTENSIONS = [
78
78
  'odp',
79
79
  'odg',
80
80
  'dotx',
81
- 'xltx'
81
+ 'xltx',
82
+ 'key'
82
83
  ];
@@ -15,7 +15,9 @@ export enum ChromiumRoute {
15
15
  * @enum {string}
16
16
  */
17
17
  enum PdfEngineRoute {
18
- MERGE = 'merge'
18
+ MERGE = 'merge',
19
+ READ_METADATA = 'metadata/read',
20
+ WRITE_METADATA = 'metadata/write'
19
21
  }
20
22
 
21
23
  /**
@@ -42,6 +44,12 @@ export class Chromiumly {
42
44
  */
43
45
  public static readonly CHROMIUM_CONVERT_PATH = 'forms/chromium/convert';
44
46
 
47
+ /**
48
+ * The path for Chromium-related screenshots.
49
+ * @type {string}
50
+ */
51
+ public static readonly CHROMIUM_SCREENSHOT_PATH =
52
+ 'forms/chromium/screenshot';
45
53
  /**
46
54
  * The path for PDF engine-related operations.
47
55
  * @type {string}
@@ -69,7 +77,9 @@ export class Chromiumly {
69
77
  * @type {Object}
70
78
  */
71
79
  public static readonly PDF_ENGINE_ROUTES = {
72
- merge: PdfEngineRoute.MERGE
80
+ merge: PdfEngineRoute.MERGE,
81
+ readMetadata: PdfEngineRoute.READ_METADATA,
82
+ writeMetadata: PdfEngineRoute.WRITE_METADATA
73
83
  };
74
84
 
75
85
  /**
package/src/main.ts CHANGED
@@ -1,3 +1,10 @@
1
1
  export { PdfFormat } from './common/constants';
2
- export { HtmlConverter, MarkdownConverter, UrlConverter } from './chromium';
2
+ export {
3
+ HtmlConverter,
4
+ HtmlScreenshot,
5
+ MarkdownConverter,
6
+ MarkdownScreenshot,
7
+ UrlConverter,
8
+ UrlScreenshot
9
+ } from './chromium';
3
10
  export { PDFEngine } from './pdf-engines';
@@ -4,7 +4,12 @@ import path from 'path';
4
4
  import FormData from 'form-data';
5
5
 
6
6
  import { Chromiumly } from '../main.config';
7
- import { GotenbergUtils, PathLikeOrReadStream, PdfFormat } from '../common';
7
+ import {
8
+ GotenbergUtils,
9
+ PathLikeOrReadStream,
10
+ PdfFormat,
11
+ Metadata
12
+ } from '../common';
8
13
  import { LibreOfficeUtils, PageProperties } from '../libre-office';
9
14
  import { PDFEngineUtils } from './utils/engine.utils';
10
15
 
@@ -50,6 +55,10 @@ export class PDFEngine {
50
55
  }: {
51
56
  files: PathLikeOrReadStream[];
52
57
  properties?: PageProperties;
58
+ /**
59
+ * @deprecated Starting from Gotenberg version 8.0.0, LibreOffice no longer provides support for pdfFormat.
60
+ * @see {@link https://github.com/gotenberg/gotenberg/releases/tag/v8.0.0}
61
+ */
53
62
  pdfFormat?: PdfFormat;
54
63
  pdfUA?: boolean;
55
64
  merge?: boolean;
@@ -79,6 +88,48 @@ export class PDFEngine {
79
88
  return GotenbergUtils.fetch(endpoint, data);
80
89
  }
81
90
 
91
+ /**
92
+ * Reads metadata from the provided files.
93
+ *
94
+ * @param {PathLikeOrReadStream[]} files An array of PathLikes or ReadStreams to the PDF files.
95
+ * @returns {Promise<Buffer>} A Promise resolving to the metadata buffer.
96
+ */
97
+ public static async readMetadata(
98
+ files: PathLikeOrReadStream[]
99
+ ): Promise<Buffer> {
100
+ const data = new FormData();
101
+
102
+ await PDFEngineUtils.addFiles(files, data);
103
+
104
+ const endpoint = `${Chromiumly.GOTENBERG_ENDPOINT}/${Chromiumly.PDF_ENGINES_PATH}/${Chromiumly.PDF_ENGINE_ROUTES.readMetadata}`;
105
+
106
+ return GotenbergUtils.fetch(endpoint, data);
107
+ }
108
+
109
+ /**
110
+ * Writes metadata to the provided PDF files.
111
+ *
112
+ * @param {PathLikeOrReadStream[]} files - An array of PathLikes or ReadStreams to the PDF files.
113
+ * @param {Metadata} metadata - Metadata to be written.
114
+ * @returns {Promise<Buffer>} A Promise that resolves to the PDF file containing metadata as a buffer.
115
+ */
116
+ public static async writeMetadata({
117
+ files,
118
+ metadata
119
+ }: {
120
+ files: PathLikeOrReadStream[];
121
+ metadata: Metadata;
122
+ }): Promise<Buffer> {
123
+ const data = new FormData();
124
+ data.append('metadata', JSON.stringify(metadata));
125
+
126
+ await PDFEngineUtils.addFiles(files, data);
127
+
128
+ const endpoint = `${Chromiumly.GOTENBERG_ENDPOINT}/${Chromiumly.PDF_ENGINES_PATH}/${Chromiumly.PDF_ENGINE_ROUTES.writeMetadata}`;
129
+
130
+ return GotenbergUtils.fetch(endpoint, data);
131
+ }
132
+
82
133
  /**
83
134
  * Generates a PDF file from a buffer and saves it to the "__generated__" directory.
84
135
  *