@thegetty/quire-cli 1.0.0-rc.35 → 1.0.0-rc.36

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 (158) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +9 -0
  3. package/bin/cli.js +19 -1
  4. package/package.json +21 -8
  5. package/patches/README.md +19 -0
  6. package/patches/install-npm-version+1.0.9.patch +12119 -0
  7. package/schemas/objects.schema.json +12 -38
  8. package/schemas/publication.schema.json +0 -22
  9. package/schemas/references.schema.json +0 -1
  10. package/src/Command.js +26 -6
  11. package/src/Command.spec.js +99 -0
  12. package/src/commands/README.md +213 -122
  13. package/src/commands/build.js +46 -37
  14. package/src/commands/build.spec.js +113 -0
  15. package/src/commands/build.test.js +402 -0
  16. package/src/commands/clean.js +25 -19
  17. package/src/commands/clean.spec.js +108 -0
  18. package/src/commands/clean.test.js +260 -0
  19. package/src/commands/config.js +251 -0
  20. package/src/commands/config.spec.js +107 -0
  21. package/src/commands/config.test.js +715 -0
  22. package/src/commands/create.js +42 -14
  23. package/src/commands/create.spec.js +112 -0
  24. package/src/commands/create.test.js +415 -0
  25. package/src/commands/epub.js +59 -30
  26. package/src/commands/epub.spec.js +114 -0
  27. package/src/commands/epub.test.js +503 -0
  28. package/src/commands/index.js +9 -2
  29. package/src/commands/info.js +18 -24
  30. package/src/commands/info.spec.js +64 -0
  31. package/src/commands/info.test.js +415 -0
  32. package/src/commands/pdf.js +58 -84
  33. package/src/commands/pdf.spec.js +114 -0
  34. package/src/commands/pdf.test.js +464 -0
  35. package/src/commands/preview.js +26 -31
  36. package/src/commands/preview.spec.js +97 -0
  37. package/src/commands/preview.test.js +250 -0
  38. package/src/commands/use.js +56 -0
  39. package/src/commands/use.spec.js +61 -0
  40. package/src/commands/use.test.js +280 -0
  41. package/src/commands/validate.js +31 -19
  42. package/src/commands/validate.spec.js +82 -0
  43. package/src/commands/validate.test.js +234 -0
  44. package/src/commands/workflows.js +70 -0
  45. package/src/errors/build/build-failed-error.js +19 -0
  46. package/src/errors/build/config-field-missing-error.js +20 -0
  47. package/src/errors/build/config-file-not-found-error.js +20 -0
  48. package/src/errors/build/index.js +11 -0
  49. package/src/errors/index.js +48 -0
  50. package/src/errors/install/dependency-install-error.js +19 -0
  51. package/src/errors/install/directory-not-empty-error.js +25 -0
  52. package/src/errors/install/index.js +12 -0
  53. package/src/errors/install/invalid-path-error.js +31 -0
  54. package/src/errors/install/invalid-starter-error.js +27 -0
  55. package/src/errors/install/version-not-found-error.js +35 -0
  56. package/src/errors/output/epub-generation-error.js +19 -0
  57. package/src/errors/output/index.js +14 -0
  58. package/src/errors/output/invalid-epub-library-error.js +20 -0
  59. package/src/errors/output/invalid-pdf-library-error.js +20 -0
  60. package/src/errors/output/missing-build-output-error.js +21 -0
  61. package/src/errors/output/pdf-generation-error.js +24 -0
  62. package/src/errors/output/tool-not-found-error.js +37 -0
  63. package/src/errors/project/index.js +10 -0
  64. package/src/errors/project/not-in-project-error.js +20 -0
  65. package/src/errors/project/project-create-error.js +21 -0
  66. package/src/errors/quire-error.js +27 -0
  67. package/src/errors/validation/validation-error.js +20 -11
  68. package/src/helpers/clean.js +1 -1
  69. package/src/helpers/docs-url.js +32 -0
  70. package/src/helpers/test-cwd.js +5 -6
  71. package/src/helpers/test-cwd.test.js +192 -0
  72. package/src/helpers/which.js +10 -4
  73. package/src/lib/11ty/README.md +135 -19
  74. package/src/lib/11ty/api.js +176 -93
  75. package/src/lib/11ty/cli.js +77 -35
  76. package/src/lib/11ty/index.js +64 -5
  77. package/src/lib/11ty/index.test.js +655 -0
  78. package/src/lib/README.md +275 -0
  79. package/src/lib/commander/index.js +100 -0
  80. package/src/lib/commander/index.test.js +86 -0
  81. package/src/lib/commander/options.js +195 -0
  82. package/src/lib/commander/options.test.js +109 -0
  83. package/src/lib/conf/README.md +84 -73
  84. package/src/lib/conf/config.js +5 -3
  85. package/src/lib/conf/config.test.js +281 -0
  86. package/src/lib/conf/defaults.js +44 -0
  87. package/src/lib/conf/format.js +60 -0
  88. package/src/lib/conf/format.test.js +106 -0
  89. package/src/lib/conf/helpers.js +91 -0
  90. package/src/lib/conf/helpers.test.js +136 -0
  91. package/src/lib/conf/index.js +22 -0
  92. package/src/lib/conf/schema.js +53 -8
  93. package/src/lib/epub/README.md +133 -2
  94. package/src/lib/epub/engines.js +46 -0
  95. package/src/lib/epub/epub.js +36 -11
  96. package/src/lib/epub/index.js +111 -21
  97. package/src/lib/epub/index.test.js +518 -0
  98. package/src/lib/epub/pandoc.js +33 -4
  99. package/src/lib/epub/pandoc.test.js +122 -0
  100. package/src/lib/epub/schema.js +21 -0
  101. package/src/lib/error/README.md +170 -0
  102. package/src/lib/error/handler.js +107 -0
  103. package/src/lib/git/README.md +151 -2
  104. package/src/lib/git/index.js +217 -13
  105. package/src/lib/git/index.spec.js +80 -0
  106. package/src/lib/git/index.test.js +453 -0
  107. package/src/lib/installer/index.js +309 -0
  108. package/src/lib/installer/index.spec.js +83 -0
  109. package/src/lib/installer/index.test.js +545 -0
  110. package/src/lib/logger/README.md +424 -0
  111. package/src/lib/logger/debug.js +90 -0
  112. package/src/lib/logger/debug.spec.js +130 -0
  113. package/src/lib/logger/index.js +228 -0
  114. package/src/lib/logger/index.spec.js +131 -0
  115. package/src/lib/logger/index.test.js +477 -0
  116. package/src/lib/npm/README.md +127 -0
  117. package/src/lib/npm/index.js +198 -0
  118. package/src/lib/npm/index.spec.js +60 -0
  119. package/src/lib/npm/index.test.js +355 -0
  120. package/src/lib/pdf/README.md +131 -0
  121. package/src/lib/pdf/engines.js +46 -0
  122. package/src/lib/pdf/index.js +124 -21
  123. package/src/lib/pdf/index.test.js +708 -0
  124. package/src/lib/pdf/paged.js +100 -52
  125. package/src/lib/pdf/paged.test.js +366 -0
  126. package/src/lib/pdf/prince.js +115 -37
  127. package/src/lib/pdf/prince.test.js +202 -0
  128. package/src/lib/pdf/schema.js +21 -0
  129. package/src/lib/pdf/split.js +61 -33
  130. package/src/lib/pdf/split.test.js +445 -0
  131. package/src/lib/process/manager.js +110 -0
  132. package/src/lib/process/manager.test.js +55 -0
  133. package/src/lib/project/build.js +143 -0
  134. package/src/lib/project/build.test.js +253 -0
  135. package/src/lib/project/config.js +48 -0
  136. package/src/lib/project/config.test.js +134 -0
  137. package/src/{helpers/is-quire.js → lib/project/detect.js} +5 -3
  138. package/src/lib/project/detect.test.js +157 -0
  139. package/src/lib/project/index.js +40 -0
  140. package/src/lib/project/paths.js +224 -0
  141. package/src/lib/project/version.js +110 -0
  142. package/src/lib/project/version.test.js +350 -0
  143. package/src/lib/reporter/README.md +211 -2
  144. package/src/lib/reporter/index.js +512 -0
  145. package/src/lib/reporter/index.test.js +593 -0
  146. package/src/main.js +134 -47
  147. package/src/main.spec.js +61 -0
  148. package/src/main.test.js +347 -0
  149. package/src/validators/utils.js +2 -1
  150. package/src/commands/conf.js +0 -43
  151. package/src/commands/version.js +0 -43
  152. package/src/lib/11ty/paths.js +0 -103
  153. package/src/lib/i18n/README.md +0 -3
  154. package/src/lib/i18n/config.js +0 -53
  155. package/src/lib/i18n/index.js +0 -43
  156. package/src/lib/i18n/localeService.js +0 -58
  157. package/src/lib/quire/README.md +0 -19
  158. package/src/lib/quire/index.js +0 -350
@@ -2,6 +2,66 @@
2
2
 
3
3
  This module provides an abstraction to ease PDF generation across PrinceXML and Paged.js. The exported module dynamically loads a wrapper to align the libraries' JS APIs by exporting a single method that accepts a `lib` option and returns an async function that takes input, output, and option params.
4
4
 
5
+ ### Architecture
6
+
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────────┐
9
+ │ lib/pdf/index.js │
10
+ │ • Façade: resolves engine, validates prerequisites │
11
+ │ • Checks engine availability (fail-fast before reporter) │
12
+ │ • Owns reporter lifecycle (start/succeed/fail) │
13
+ └─────────────────┬─────────────────────────┬─────────────────┘
14
+ │ │
15
+ ┌─────────┴─────────┐ ┌─────────┴─────────┐
16
+ │ paged.js │ │ prince.js │
17
+ │ (Paged.js CLI) │ │ (Prince CLI) │
18
+ └─────────┬─────────┘ └─────────┬─────────┘
19
+ │ │
20
+ └───────────┬─────────────┘
21
+
22
+ ┌─────────┴─────────┐
23
+ │ split.js │
24
+ │ (pdf-lib logic) │
25
+ └───────────────────┘
26
+ ```
27
+
28
+ ### Usage
29
+
30
+ ```javascript
31
+ import generatePdf from '#lib/pdf/index.js'
32
+
33
+ // Basic usage (uses project config for output path)
34
+ const pdfPath = await generatePdf({ lib: 'pagedjs' })
35
+
36
+ // With custom output path
37
+ const pdfPath = await generatePdf({
38
+ lib: 'prince',
39
+ output: 'downloads/my-book.pdf' // relative to project root
40
+ })
41
+
42
+ // With absolute path
43
+ const pdfPath = await generatePdf({
44
+ lib: 'pagedjs',
45
+ output: '/tmp/publication.pdf'
46
+ })
47
+ ```
48
+
49
+ ### Options
50
+
51
+ | Option | Type | Default | Description |
52
+ |--------|------|---------|-------------|
53
+ | `lib` | string | `'pagedjs'` | PDF engine: `'pagedjs'` or `'prince'` |
54
+ | `output` | string | from config | Output path (overrides project config) |
55
+ | `debug` | boolean | `false` | Enable debug output |
56
+
57
+ ### Output Path Resolution
58
+
59
+ 1. If `options.output` is provided, it is used (relative paths resolved against project root)
60
+ 2. Otherwise, uses `config.pdf.outputDir` + `config.pdf.filename` from project config
61
+ 3. If no config, falls back to `{projectRoot}/{libName}.pdf`
62
+
63
+ ### Page Mapping
64
+
5
65
  The module also provides plugins for Prince and Paged.js to map quire webpages to PDF pages. In both cases this is achieved after PDF rendering by querying the HTML document that was printed for `.quire-page` elements and using the PDF generator's APIs to determine content page ids, page data like titles and contributors, and first / last pages. They then use a simple stripping algorithm with `pdf-lib` to split the pages for `--page-pdf` flagged runs.
6
66
 
7
67
  ### Paged.js Façade
@@ -17,3 +77,74 @@ The Prince abstraction wraps the command line execution of the Prince executable
17
77
  See the [Prince Command-line Reference](https://www.princexml.com/doc/command-line/). Prince's [scripting documentation](https://www.princexml.com/doc/javascript/) has details on its runtime Javascript implementation, *which is only compatible up to ES5*.
18
78
 
19
79
  The Prince plugin passes page map data as JSON to STDOUT.
80
+
81
+ ### Test Strategy
82
+
83
+ The PDF module uses a layered testing approach:
84
+
85
+ | Layer | Test Type | Coverage |
86
+ |-------|-----------|----------|
87
+ | `index.js` | Unit tests | Engine resolution, path resolution, availability checks |
88
+ | `paged.js` | Integration tests | Error paths (Puppeteer failures, file write errors) |
89
+ | `prince.js` | Integration tests | Error paths (Prince failures, cancellation handling) |
90
+ | `split.js` | Unit tests | Pure PDF manipulation logic with mocked pdf-lib |
91
+ | Full flow | E2E tests | Happy paths with real tools |
92
+
93
+ #### Why This Strategy?
94
+
95
+ **Façade (`index.js`)** - Unit tests verify:
96
+ - Engine name normalization (`pagedjs`, `paged`, `paged.js` → same engine)
97
+ - Output path resolution priority (CLI > config > fallback)
98
+ - Engine availability checking (Prince binary in PATH)
99
+ - Error handling for missing prerequisites
100
+
101
+ **Engine implementations (`paged.js`, `prince.js`)** - Integration tests for error paths:
102
+ - These are orchestration code that wire external tools (Puppeteer, Prince CLI) with reporter updates
103
+ - Happy paths are well-covered by E2E tests with real tools
104
+ - Error paths (tool crashes, permission errors, cancellation) are hard to trigger in E2E
105
+ - Tests mock `execa`/`pagedjs-cli` to verify error wrapping and cleanup
106
+
107
+ **PDF splitting (`split.js`)** - Unit tests:
108
+ - Pure logic that manipulates PDFs using pdf-lib
109
+ - No external tool dependencies
110
+ - Tests mock pdf-lib's `PDFDocument` to verify page extraction, cover insertion, and error handling
111
+
112
+ **E2E tests** - Full integration:
113
+ - Test the complete `quire pdf` command with real publications
114
+ - Verify actual PDF output with both engines (when available)
115
+ - Cover the happy path that unit/integration tests intentionally skip
116
+
117
+ #### Running Tests
118
+
119
+ ```bash
120
+ # All PDF module tests
121
+ npm run test:unit -- src/lib/pdf/
122
+
123
+ # Specific test files
124
+ npm run test:unit -- src/lib/pdf/index.test.js # façade tests
125
+ npm run test:unit -- src/lib/pdf/paged.test.js # Paged.js error paths
126
+ npm run test:unit -- src/lib/pdf/prince.test.js # Prince error paths
127
+ npm run test:unit -- src/lib/pdf/split.test.js # PDF splitting logic
128
+ ```
129
+
130
+ ### Error Handling
131
+
132
+ All errors are wrapped in typed `PdfGenerationError` with:
133
+ - Tool name (`'Prince'`, `'Paged.js'`)
134
+ - Operation that failed (`'PDF rendering'`, `'page map extraction'`, etc.)
135
+ - Underlying error details
136
+
137
+ Example error flow:
138
+ ```
139
+ Prince CLI fails → execa rejects with stderr
140
+ → prince.js catches, wraps in PdfGenerationError
141
+ → index.js catches, calls reporter.fail(), re-throws
142
+ → Command handler displays formatted error to user
143
+ ```
144
+
145
+ ### Graceful Shutdown
146
+
147
+ Both engines support Ctrl+C cancellation:
148
+ - `prince.js` uses `execa`'s `cancelSignal` option
149
+ - `paged.js` registers cleanup with `processManager.onShutdown()`
150
+ - On cancellation, `reporter.warn('PDF generation cancelled')` notifies the user
@@ -0,0 +1,46 @@
1
+ /**
2
+ * PDF Engine Registry
3
+ *
4
+ * Centralized metadata for PDF engines. Each engine module re-exports
5
+ * its metadata from here, ensuring single source of truth.
6
+ *
7
+ * The façade imports this registry to:
8
+ * 1. Resolve engine names to implementations
9
+ * 2. Check binary availability before loading heavy modules
10
+ * 3. Provide helpful error messages with install URLs
11
+ */
12
+ import { docsUrl } from '#helpers/docs-url.js'
13
+
14
+ /**
15
+ * @typedef {Object} EngineMetadata
16
+ * @property {string} name - Human-readable display name
17
+ * @property {string} module - Module filename (e.g., 'paged.js')
18
+ * @property {string|null} requiresBinary - CLI binary name, or null if built-in
19
+ * @property {Object} [toolInfo] - Error metadata (only for engines requiring binaries)
20
+ * @property {string} [toolInfo.displayName] - Display name for error messages
21
+ * @property {string} [toolInfo.installUrl] - URL to download the tool
22
+ * @property {string} [toolInfo.docsUrl] - Quire docs URL
23
+ * @property {string} [toolInfo.fallback] - Alternative suggestion
24
+ */
25
+
26
+ /** @type {Record<string, EngineMetadata>} */
27
+ const ENGINES = {
28
+ pagedjs: {
29
+ name: 'Paged.js',
30
+ module: 'paged.js',
31
+ requiresBinary: null, // Built-in Node.js library
32
+ },
33
+ prince: {
34
+ name: 'Prince',
35
+ module: 'prince.js',
36
+ requiresBinary: 'prince',
37
+ toolInfo: {
38
+ displayName: 'PrinceXML',
39
+ installUrl: 'https://www.princexml.com/download/',
40
+ docsUrl: docsUrl('pdf-output'),
41
+ fallback: 'Or use the default PDF engine: quire pdf --engine pagedjs',
42
+ },
43
+ },
44
+ }
45
+
46
+ export default ENGINES
@@ -1,42 +1,145 @@
1
1
  import { dynamicImport } from '#helpers/os-utils.js'
2
+ import which from '#helpers/which.js'
2
3
  import { fileURLToPath } from 'node:url'
3
4
  import path from 'node:path'
5
+ import fs from 'fs-extra'
6
+ import paths, { loadProjectConfig } from '#lib/project/index.js'
7
+ import reporter from '#lib/reporter/index.js'
8
+ import { InvalidPdfLibraryError, MissingBuildOutputError } from '#src/errors/index.js'
9
+ import ENGINE_METADATA from './engines.js'
10
+ import createDebug from '#debug'
11
+ import { ENGINES } from './schema.js'
12
+
13
+ export { ENGINES }
4
14
 
5
15
  const __filename = fileURLToPath(import.meta.url)
6
16
  const __dirname = path.dirname(__filename)
7
17
 
18
+ const debug = createDebug('lib:pdf')
19
+
8
20
  /**
9
- * A façade delegation module for PDF generation libraries
21
+ * Resolve the PDF library implementation
22
+ *
23
+ * @param {string} name - Library name to resolve
24
+ * @returns {Object} Resolved engine with absolute module path
25
+ * @throws {InvalidPdfLibraryError} When library name is not recognized
10
26
  */
11
- export default async (name = 'pagedjs', options = {}) => {
12
- const lib = { name, options, path }
13
-
27
+ function resolveLibrary(name) {
14
28
  const normalizedName = name.replace(/[-_.\s]/g, '').toLowerCase()
15
29
 
16
30
  switch (normalizedName) {
17
31
  case 'paged':
18
- case 'pagedjs': {
19
- lib.name = 'Paged.js'
20
- lib.options = options
21
- lib.path = path.join(__dirname, 'paged.js')
22
- break
23
- }
32
+ case 'pagedjs':
33
+ return { ...ENGINE_METADATA.pagedjs, path: path.join(__dirname, ENGINE_METADATA.pagedjs.module) }
24
34
  case 'prince':
25
- case 'princexml': {
26
- lib.name = 'Prince'
27
- lib.options = options
28
- lib.path = path.join(__dirname, 'prince.js')
29
- break
30
- }
35
+ case 'princexml':
36
+ return { ...ENGINE_METADATA.prince, path: path.join(__dirname, ENGINE_METADATA.prince.module) }
31
37
  default:
32
- console.error(`[CLI:lib/pdf] Unrecognized PDF library '${name}'`)
33
- return
38
+ throw new InvalidPdfLibraryError(name)
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Check if the required binary for an engine is available
44
+ *
45
+ * @param {Object} engine - Engine definition from ENGINES
46
+ * @throws {ToolNotFoundError} When required binary is not in PATH
47
+ */
48
+ function checkEngineAvailable(engine) {
49
+ if (!engine.requiresBinary) {
50
+ return // No binary required (e.g., pagedjs uses Node.js)
51
+ }
52
+
53
+ const result = which(engine.requiresBinary, engine.toolInfo)
54
+ debug('found %s at %s', engine.requiresBinary, result)
55
+ }
56
+
57
+ /**
58
+ * Construct the default output path for the PDF from project config
59
+ *
60
+ * @param {string} projectRoot - Project root directory
61
+ * @param {string} outputDir - Build output directory
62
+ * @param {Object} [pdfConfig] - PDF configuration from project config
63
+ * @param {string} libName - Library name for fallback filename
64
+ * @returns {string} Default output path
65
+ */
66
+ function getDefaultOutputPath(projectRoot, outputDir, pdfConfig, libName) {
67
+ if (pdfConfig) {
68
+ return path.join(projectRoot, outputDir, pdfConfig.outputDir, `${pdfConfig.filename}.pdf`)
69
+ }
70
+ return path.join(projectRoot, `${libName}.pdf`)
71
+ }
72
+
73
+ /**
74
+ * Resolve the final output path, allowing CLI override
75
+ *
76
+ * @param {string} [userOutput] - User-specified output path from --output option
77
+ * @param {string} defaultPath - Default path from project config
78
+ * @param {string} projectRoot - Project root for resolving relative paths
79
+ * @returns {string} Resolved absolute output path
80
+ */
81
+ function resolveOutputPath(userOutput, defaultPath, projectRoot) {
82
+ if (!userOutput) {
83
+ return defaultPath
84
+ }
85
+
86
+ // Resolve relative paths against project root
87
+ if (path.isAbsolute(userOutput)) {
88
+ return userOutput
89
+ }
90
+
91
+ return path.join(projectRoot, userOutput)
92
+ }
93
+
94
+ /**
95
+ * Generate a PDF from the built publication
96
+ *
97
+ * @param {Object} options - Generation options
98
+ * @param {string} [options.lib='pagedjs'] - PDF library to use ('pagedjs' or 'prince')
99
+ * @param {string} [options.output] - Custom output path (overrides project config)
100
+ * @param {boolean} [options.debug] - Enable debug output
101
+ * @returns {Promise<string>} Absolute path to the generated PDF file
102
+ */
103
+ export default async function generatePdf(options = {}) {
104
+ const libName = options.lib || 'pagedjs'
105
+ const lib = resolveLibrary(libName)
106
+
107
+ debug('resolved library: %s → %s', libName, lib.name)
108
+
109
+ // Check engine availability BEFORE starting reporter (fail fast with clean error)
110
+ checkEngineAvailable(lib)
111
+
112
+ const projectRoot = paths.getProjectRoot()
113
+ const buildOutputDir = paths.getOutputDir()
114
+ const config = await loadProjectConfig(projectRoot)
115
+
116
+ const publicationInput = path.join(projectRoot, buildOutputDir, 'pdf.html')
117
+ const coversInput = path.join(projectRoot, buildOutputDir, 'pdf-covers.html')
118
+
119
+ debug('input: %s', publicationInput)
120
+ debug('covers: %s', coversInput)
121
+
122
+ if (!fs.existsSync(publicationInput)) {
123
+ throw new MissingBuildOutputError('pdf.html', publicationInput)
34
124
  }
35
125
 
126
+ const defaultPath = getDefaultOutputPath(projectRoot, buildOutputDir, config.pdf, libName)
127
+ const pdfPath = resolveOutputPath(options.output, defaultPath, projectRoot)
128
+ debug('output: %s (user: %s, default: %s)', pdfPath, options.output || 'none', defaultPath)
129
+
36
130
  const { default: pdfLib } = await dynamicImport(lib.path)
37
131
 
38
- return async (publicationInput, coversInput, output) => {
39
- console.info(`[CLI:lib/pdf] generating PDF using ${lib.name}`)
40
- return await pdfLib(publicationInput, coversInput, output, lib.options)
132
+ reporter.start(`Generating PDF using ${lib.name}...`, { showElapsed: true })
133
+ reporter.detail(`Input: ${publicationInput}`)
134
+ reporter.detail(`Output: ${pdfPath}`)
135
+
136
+ try {
137
+ await pdfLib(publicationInput, coversInput, pdfPath, { ...options, pdfConfig: config.pdf })
138
+ reporter.succeed(`PDF saved to ${pdfPath}`)
139
+ } catch (error) {
140
+ reporter.fail(`PDF generation failed`)
141
+ throw error
41
142
  }
143
+
144
+ return pdfPath
42
145
  }