bidi2pdf 0.1.15 → 0.1.16
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +22 -2
- data/README.md +196 -11
- data/docker/Dockerfile +4 -0
- data/docker/Dockerfile.slim +5 -1
- data/lib/bidi2pdf/cli/json_output.rb +30 -0
- data/lib/bidi2pdf/cli.rb +559 -17
- data/lib/bidi2pdf/diagnose.rb +119 -0
- data/lib/bidi2pdf/error_codes.rb +59 -0
- data/lib/bidi2pdf/exit_codes.rb +44 -0
- data/lib/bidi2pdf/launcher.rb +23 -0
- data/lib/bidi2pdf/manifest.rb +65 -0
- data/lib/bidi2pdf/notifications/json_subscriber.rb +78 -0
- data/lib/bidi2pdf/pdf_inspection.rb +62 -0
- data/lib/bidi2pdf/recipe/loader.rb +44 -0
- data/lib/bidi2pdf/recipe/runner.rb +229 -0
- data/lib/bidi2pdf/recipe/schema_shape.rb +228 -0
- data/lib/bidi2pdf/recipe/validator.rb +138 -0
- data/lib/bidi2pdf/recipe.rb +83 -0
- data/lib/bidi2pdf/result.rb +67 -0
- data/lib/bidi2pdf/result_collector.rb +150 -0
- data/lib/bidi2pdf/schema.rb +382 -0
- data/lib/bidi2pdf/session_runner.rb +42 -0
- data/lib/bidi2pdf/version.rb +1 -1
- data/lib/bidi2pdf.rb +90 -8
- data/sig/bidi2pdf/cli/json_output.rbs +19 -0
- data/sig/bidi2pdf/cli.rbs +112 -2
- data/sig/bidi2pdf/diagnose.rbs +30 -0
- data/sig/bidi2pdf/error_codes.rbs +21 -0
- data/sig/bidi2pdf/exit_codes.rbs +21 -0
- data/sig/bidi2pdf/launcher.rbs +9 -0
- data/sig/bidi2pdf/manifest.rbs +38 -0
- data/sig/bidi2pdf/notifications/json_subscriber.rbs +45 -0
- data/sig/bidi2pdf/pdf_inspection.rbs +33 -0
- data/sig/bidi2pdf/recipe/loader.rbs +20 -0
- data/sig/bidi2pdf/recipe/runner.rbs +92 -0
- data/sig/bidi2pdf/recipe/schema_shape.rbs +85 -0
- data/sig/bidi2pdf/recipe/validator.rbs +54 -0
- data/sig/bidi2pdf/recipe.rbs +72 -0
- data/sig/bidi2pdf/result.rbs +71 -0
- data/sig/bidi2pdf/result_collector.rbs +106 -0
- data/sig/bidi2pdf/schema.rbs +45 -0
- data/sig/bidi2pdf/session_runner.rbs +17 -0
- data/sig/bidi2pdf/version.rbs +1 -1
- data/sig/bidi2pdf.rbs +66 -0
- metadata +31 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3533d126bc13406c70b6931112c07952aac0c19b718f3100258fb2182da8fcea
|
|
4
|
+
data.tar.gz: a761495802d5507fba3469405a571555547ed58891b216575f947e2b6a0c63be
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb29c3bf90a6a6dbd6fcf488980c51b9f666206ea18748d0c670e6fc2a64c453ca0f20043dce113094e74eb34d4b45f6be8b7d7a433522a59ac6ebab2d6ba8bb
|
|
7
|
+
data.tar.gz: bb9c384545c42d45630576b523c3c82025b1df2a2fc8975b8959276566173ad684b9423e7f30fc46b7834c61328ef68f9ddb1ee73d83b08e0ec8ea10b93f117f
|
data/.rubocop.yml
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
# Keep RuboCop's own default excludes (vendor/**, tmp/**, node_modules/**, .git/**) when adding to
|
|
2
|
+
# AllCops/Exclude below - without this, a project-level Exclude replaces them and vendor/bundle gets
|
|
3
|
+
# linted.
|
|
4
|
+
inherit_mode:
|
|
5
|
+
merge:
|
|
6
|
+
- Exclude
|
|
7
|
+
|
|
1
8
|
AllCops:
|
|
2
9
|
NewCops: enable
|
|
3
10
|
TargetRubyVersion: 3.4
|
|
11
|
+
Exclude:
|
|
12
|
+
# Local Claude devbox (gitignored). Its Dockerfile.ruby ends in ".ruby", which RuboCop takes for
|
|
13
|
+
# a Ruby source file and then fails to parse.
|
|
14
|
+
- 'docker-claude/**/*'
|
|
4
15
|
|
|
5
16
|
Style/StringLiterals:
|
|
6
17
|
EnforcedStyle: double_quotes
|
|
@@ -79,6 +90,15 @@ RSpec/DescribeClass:
|
|
|
79
90
|
Exclude:
|
|
80
91
|
- 'spec/acceptance/**/*_spec.rb'
|
|
81
92
|
|
|
93
|
+
# Matches bidi2pdf-rails' own spec/rails_helper.rb: scenario/when_ are custom
|
|
94
|
+
# alias_example_group_to groups there (and here, see spec/spec_helper.rb), not the single example
|
|
95
|
+
# Capybara's own `scenario` conventionally means - this cop doesn't know that and miscounts every
|
|
96
|
+
# then_/and_ nested underneath as belonging to one example.
|
|
97
|
+
RSpec/MultipleExpectations:
|
|
98
|
+
Enabled: true
|
|
99
|
+
Exclude:
|
|
100
|
+
- 'spec/acceptance/**/*_spec.rb'
|
|
101
|
+
|
|
82
102
|
plugins:
|
|
83
103
|
- rubocop-rake
|
|
84
104
|
- rubocop-rspec
|
data/CHANGELOG.md
CHANGED
|
@@ -8,10 +8,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
-
[unreleased]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.
|
|
11
|
+
[unreleased]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.16..HEAD
|
|
12
12
|
|
|
13
13
|
<!-- generated by git-cliff end -->
|
|
14
14
|
|
|
15
|
+
## [0.1.16] - 2026-09-22
|
|
16
|
+
|
|
17
|
+
### 🐛 Fixed
|
|
18
|
+
- Give NavigationDNSError its own initializer
|
|
19
|
+
- Enforce the complete recipe shape in --validate, not just semantic checks
|
|
20
|
+
- Close schema/validator mismatches in recipe schema
|
|
21
|
+
- Document and address blank PDFs from Chrome's network checks
|
|
22
|
+
- Add browser tab cookie integration specs
|
|
23
|
+
|
|
24
|
+
### 🔄 Changed
|
|
25
|
+
- Merge pull request #134 from dieter-medium/feat/llm-friendly-cli
|
|
26
|
+
- Merge pull request #133 from dieter-medium/feat/llm-friendly-cli
|
|
27
|
+
- Merge pull request #131 from dieter-medium/docs/local-network-access
|
|
28
|
+
- Merge pull request #130 from dieter-medium/fix/host-only-cookie-domain
|
|
29
|
+
- Merge pull request #126 from dieter-medium/chore-fix-release-creds-check
|
|
30
|
+
|
|
31
|
+
### 🚀 Added
|
|
32
|
+
- Agent-friendly CLI - structured JSON, diagnose, and recipes
|
|
33
|
+
|
|
15
34
|
## [0.1.15] - 2026-09-20
|
|
16
35
|
|
|
17
36
|
### 🎨 Refactored
|
|
@@ -453,7 +472,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
453
472
|
|
|
454
473
|
### 🔄 Released
|
|
455
474
|
|
|
456
|
-
- [unreleased](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.
|
|
475
|
+
- [unreleased](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.16..HEAD)
|
|
476
|
+
- [0.1.16](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.15..v0.1.16)
|
|
457
477
|
- [0.1.15](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.14..v0.1.15)
|
|
458
478
|
- [0.1.14](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.13..v0.1.14)
|
|
459
479
|
- [0.1.13](https://github.com/dieter-medium/bidi2pdf/compare/v0.1.12..v0.1.13)
|
data/README.md
CHANGED
|
@@ -20,16 +20,17 @@ Bidi2pdf gives you **precision, flexibility, and full control**.
|
|
|
20
20
|
3. [Why BiDi?](#why-bidi-instead-of-cdp)
|
|
21
21
|
4. [Installation](#installation)
|
|
22
22
|
5. [CLI Usage](#cli-usage)
|
|
23
|
-
6. [
|
|
24
|
-
7. [
|
|
25
|
-
8. [
|
|
26
|
-
9. [
|
|
27
|
-
10. [
|
|
28
|
-
11. [
|
|
29
|
-
12. [
|
|
30
|
-
13. [
|
|
31
|
-
14. [
|
|
32
|
-
15. [
|
|
23
|
+
6. [Agent and Automation Usage](#agent-and-automation-usage)
|
|
24
|
+
7. [Library API](#library-api)
|
|
25
|
+
8. [Architecture](#architecture)
|
|
26
|
+
9. [Docker](#docker)
|
|
27
|
+
10. [Configuration Options](#configuration-options)
|
|
28
|
+
11. [Programmatic Configuration](#programmatic-configuration)
|
|
29
|
+
12. [Rails Integration](#rails-integration)
|
|
30
|
+
13. [Test Helpers](#test-helpers)
|
|
31
|
+
14. [Development](#development)
|
|
32
|
+
15. [Contributing](#contributing)
|
|
33
|
+
16. [License](#license)
|
|
33
34
|
|
|
34
35
|
## ✨ Key Features
|
|
35
36
|
|
|
@@ -40,7 +41,9 @@ Bidi2pdf gives you **precision, flexibility, and full control**.
|
|
|
40
41
|
✅ **Docker-ready** – Plug and play with containers
|
|
41
42
|
✅ **Modern architecture** – Built on Chrome's next-gen BiDi protocol
|
|
42
43
|
✅ **Network logging** – Know which requests fail during rendering
|
|
43
|
-
✅ **Console log capture** – See what goes wrong inside the browser
|
|
44
|
+
✅ **Console log capture** – See what goes wrong inside the browser
|
|
45
|
+
✅ **Agent-ready** – Structured JSON output, NDJSON progress streaming, a page diagnostic, and
|
|
46
|
+
declarative recipes, so LLM agents and CI can drive it without parsing logs
|
|
44
47
|
|
|
45
48
|
---
|
|
46
49
|
|
|
@@ -109,6 +112,152 @@ bidi2pdf render \
|
|
|
109
112
|
|
|
110
113
|
---
|
|
111
114
|
|
|
115
|
+
## 🤖 Agent and Automation Usage
|
|
116
|
+
|
|
117
|
+
Every command below also works without `--json` (human-readable output on stdout); with it, stdout
|
|
118
|
+
carries exactly one JSON document and nothing else - safe to pipe into `jq` or parse directly.
|
|
119
|
+
Human-readable logs move to stderr for the duration of any `--json`/`--output -` call, never
|
|
120
|
+
mixing into stdout. `--json-stream` works independently of the two: it always writes progress
|
|
121
|
+
events to stderr, whether or not `--json` is also given - in human mode, that just means
|
|
122
|
+
human-readable output keeps going to stdout as usual, alongside the stream. Full JSON Schema for
|
|
123
|
+
every shape is built into the gem, so an agent can discover it without reading this file:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# 1. Check compatibility first - no browser launched
|
|
127
|
+
bidi2pdf version --json
|
|
128
|
+
|
|
129
|
+
# 2. Discover the shape of each command's own result, a manifest, an NDJSON event, or a recipe file
|
|
130
|
+
bidi2pdf schema render
|
|
131
|
+
bidi2pdf schema diagnose
|
|
132
|
+
bidi2pdf schema run
|
|
133
|
+
bidi2pdf schema manifest
|
|
134
|
+
bidi2pdf schema event
|
|
135
|
+
bidi2pdf schema recipe
|
|
136
|
+
|
|
137
|
+
# 3. Validate a recipe - no browser launched, the cheapest way to iterate on one
|
|
138
|
+
bidi2pdf run recipe.yml --validate
|
|
139
|
+
|
|
140
|
+
# 4. Run it for real
|
|
141
|
+
bidi2pdf run recipe.yml --json
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Structured render output
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
bidi2pdf render --url https://example.com/invoice/14432423 --output example.pdf --json
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
"schema_version": 1,
|
|
153
|
+
"ok": true,
|
|
154
|
+
"command": "render",
|
|
155
|
+
"output": "example.pdf",
|
|
156
|
+
"bytes": 182734,
|
|
157
|
+
"sha256": "abcd...",
|
|
158
|
+
"pages": 2,
|
|
159
|
+
"duration_ms": 842,
|
|
160
|
+
"navigation": { "requested_url": "https://example.com/invoice/14432423", "final_url": "https://example.com/invoice/14432423", "status": 200 },
|
|
161
|
+
"console": [],
|
|
162
|
+
"network_failures": [],
|
|
163
|
+
"warnings": [],
|
|
164
|
+
"error": null
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`pages` is `null`, with a warning explaining why, when the optional `pdf-reader` gem isn't
|
|
169
|
+
installed - see [Docker](#docker) for why the published images always have it. A failed render
|
|
170
|
+
still emits exactly this shape, with `ok: false` and a structured `error` (`code`, `message`,
|
|
171
|
+
`retryable`, `hint`, `details`) instead of a stack trace:
|
|
172
|
+
|
|
173
|
+
| Exit code | Meaning |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `0` | success |
|
|
176
|
+
| `2` | CLI, configuration, or recipe-validation error |
|
|
177
|
+
| `3` | browser or navigation error |
|
|
178
|
+
| `4` | page not as expected (a recipe action/assertion, or a diagnose selector, failed) |
|
|
179
|
+
| `6` | output or PDF generation failure |
|
|
180
|
+
| `70` | unexpected internal error |
|
|
181
|
+
|
|
182
|
+
### stdin/stdout, manifests, and progress streaming
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Render HTML piped on stdin, PDF bytes piped out on stdout - no files touched
|
|
186
|
+
cat page.html | bidi2pdf render --stdin --output - > page.pdf
|
|
187
|
+
|
|
188
|
+
# A render manifest: enough to reproduce and diagnose the render later
|
|
189
|
+
bidi2pdf render --url https://example.com --output example.pdf --manifest render.json
|
|
190
|
+
|
|
191
|
+
# One JSON progress event per stderr line as the render happens - works with human-readable
|
|
192
|
+
# output too, not just --json
|
|
193
|
+
bidi2pdf render --url https://example.com --output example.pdf --json-stream
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Diagnosing a page before trusting its PDF
|
|
197
|
+
|
|
198
|
+
`bidi2pdf diagnose` loads a page like `render` does but produces no PDF - it answers *why does the
|
|
199
|
+
PDF not look like the page* (console errors, failed requests, font-loading status, `@media
|
|
200
|
+
print`/`@page` rules, fixed/sticky elements, Paged.js detection), not what the page's content is:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
bidi2pdf diagnose --url https://example.com/invoice/14432423 --json
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Declarative recipes
|
|
207
|
+
|
|
208
|
+
A recipe is a rendering contract - the waits a page needs before it's printed, and the properties
|
|
209
|
+
the resulting PDF must have - not a general browser-automation script:
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
# invoice.yml
|
|
213
|
+
version: 1
|
|
214
|
+
|
|
215
|
+
source:
|
|
216
|
+
url: https://example.com/invoice/123
|
|
217
|
+
|
|
218
|
+
actions:
|
|
219
|
+
- wait_for:
|
|
220
|
+
selector: "#invoice"
|
|
221
|
+
timeout: 10
|
|
222
|
+
- click:
|
|
223
|
+
selector: "#show-details"
|
|
224
|
+
- wait_network_idle:
|
|
225
|
+
timeout: 10
|
|
226
|
+
|
|
227
|
+
assert:
|
|
228
|
+
- selector_exists:
|
|
229
|
+
selector: "#total"
|
|
230
|
+
- no_console_errors: true
|
|
231
|
+
- page_count: 2
|
|
232
|
+
- pdf_text_present:
|
|
233
|
+
text: "Invoice #123"
|
|
234
|
+
|
|
235
|
+
output:
|
|
236
|
+
pdf: invoice.pdf
|
|
237
|
+
manifest: invoice.json
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
bidi2pdf run invoice.yml --validate # schema + known actions/assertions, no browser
|
|
242
|
+
bidi2pdf run invoice.yml --json # actions, then the PDF, then assertions against it
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Actions (`wait_for`, `click`, `evaluate`, `inject_script`, `inject_style`, `set_viewport`,
|
|
246
|
+
`wait_network_idle`) and page assertions (`selector_exists`, `text_present`, `no_console_errors`,
|
|
247
|
+
`no_network_failures`, `fonts_loaded`) are a thin layer over the same `BrowserTab` methods the
|
|
248
|
+
[Programmatic API](#-programmatic-api) below uses directly. PDF assertions (`page_count`,
|
|
249
|
+
`pdf_text_present`, `pdf_not_blank`) need the `pdf-reader` gem - a recipe using one fails
|
|
250
|
+
`--validate` immediately, before any browser launches, when it isn't installed.
|
|
251
|
+
|
|
252
|
+
`no_console_errors`, `no_network_failures`, `fonts_loaded`, and `pdf_not_blank` are presence-only
|
|
253
|
+
assertions - the step is either there or it isn't, nothing reads the value beside it - so they must
|
|
254
|
+
be written as `true` exactly, e.g. `- no_console_errors: true`; `false` (or any other value) is
|
|
255
|
+
rejected by both `bidi2pdf schema recipe` and `--validate` rather than being silently ignored.
|
|
256
|
+
`wait_for` needs exactly one of `selector`, `paged_js`, `script` - zero or more than one is
|
|
257
|
+
rejected the same way, before any browser launches.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
112
261
|
## 🧠 Programmatic API
|
|
113
262
|
|
|
114
263
|
### Classic Approach
|
|
@@ -286,6 +435,11 @@ docker run -it --rm \
|
|
|
286
435
|
|
|
287
436
|
✅ Tip: Mount your local directory (e.g. ./output) to /reports in the container to easily access the generated PDFs.
|
|
288
437
|
|
|
438
|
+
✅ Both published images also install [`pdf-reader`](https://github.com/yob/pdf-reader) - not a
|
|
439
|
+
runtime dependency of the gem itself (see [Agent and Automation Usage](#agent-and-automation-usage)) -
|
|
440
|
+
so `pages` and the `page_count`/`pdf_text_present`/`pdf_not_blank` recipe assertions work out of
|
|
441
|
+
the box in either image, no extra install step needed.
|
|
442
|
+
|
|
289
443
|
### Docker Compose
|
|
290
444
|
|
|
291
445
|
```bash
|
|
@@ -332,6 +486,15 @@ docker compose -f docker/docker-compose.yml down
|
|
|
332
486
|
| `--log_level` | Log level: debug, info, warn, error, fatal |
|
|
333
487
|
| `--remote_browser_url` | Connect to remote Chrome session |
|
|
334
488
|
| `--default_timeout` | Operation timeout (default: 60s) |
|
|
489
|
+
| `--json` | Emit a single structured JSON result document (see `bidi2pdf schema render`) |
|
|
490
|
+
| `--json_stream` | Emit one JSON progress event per line to stderr (see `bidi2pdf schema event`) - works with or without `--json` |
|
|
491
|
+
| `--stdin` | Read the HTML document from stdin, instead of `--url`/`--html-file` |
|
|
492
|
+
| `--output -` | Write raw PDF bytes to stdout instead of a file |
|
|
493
|
+
| `--manifest FILE` | Write a render manifest (see `bidi2pdf schema manifest`) to `FILE` |
|
|
494
|
+
|
|
495
|
+
See [Agent and Automation Usage](#agent-and-automation-usage) above for `bidi2pdf diagnose`,
|
|
496
|
+
`bidi2pdf run recipe.yml`, `bidi2pdf schema <kind>`, and `bidi2pdf version --json` - a separate
|
|
497
|
+
set of commands with their own options, not additional flags on `render`.
|
|
335
498
|
|
|
336
499
|
---
|
|
337
500
|
|
|
@@ -395,6 +558,28 @@ Bidi2pdf::SessionWarmer.shutdown
|
|
|
395
558
|
> nothing else can reach those ports. With `remote_browser_url`, who can reach that endpoint on the
|
|
396
559
|
> network is what matters, exactly as it does without the warmer.
|
|
397
560
|
|
|
561
|
+
### Customizing Chrome arguments (and blank PDFs from inline HTML)
|
|
562
|
+
|
|
563
|
+
`Bidi2pdf::Bidi::Session::DEFAULT_CHROME_ARGS` already contains one `--disable-features=...` entry,
|
|
564
|
+
and Chrome only honors the **last** occurrence of that switch. To turn another feature off, extend
|
|
565
|
+
that entry instead of appending a second switch, which would silently drop the defaults:
|
|
566
|
+
|
|
567
|
+
```ruby
|
|
568
|
+
chrome_args = Bidi2pdf::Bidi::Session::DEFAULT_CHROME_ARGS.map do |arg|
|
|
569
|
+
arg.start_with?("--disable-features=") ? "#{arg},LocalNetworkAccessChecks" : arg
|
|
570
|
+
end
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
`LocalNetworkAccessChecks` is the one you are most likely to need. HTML rendered through
|
|
574
|
+
`BrowserTab#render_html_content` is loaded as a `data:` URL, which Chrome treats as a public origin;
|
|
575
|
+
if that HTML references assets on a private address (`localhost`, a Docker hostname, ...), recent
|
|
576
|
+
Chrome versions (confirmed with Chrome 153) block those requests before they are sent. Nothing
|
|
577
|
+
raises - the assets show up as failed network events, the server never sees a request, and the PDF
|
|
578
|
+
comes out unstyled or blank. Disable the check only where the asset host really is private, and keep
|
|
579
|
+
it on when rendering pages you do not control.
|
|
580
|
+
The [bidi2pdf-rails README](https://github.com/dieter-medium/bidi2pdf-rails#readme) has the full
|
|
581
|
+
walkthrough under "Blank PDFs: Chrome's Local Network Access Check".
|
|
582
|
+
|
|
398
583
|
---
|
|
399
584
|
|
|
400
585
|
## 🚂 Rails Integration
|
data/docker/Dockerfile
CHANGED
|
@@ -34,7 +34,11 @@ WORKDIR /app
|
|
|
34
34
|
# Copy your gem into container
|
|
35
35
|
COPY ./pkg/bidi2pdf-*.gem ./
|
|
36
36
|
|
|
37
|
+
# pdf-reader is deliberately not a bidi2pdf runtime dependency - it is installed here, as its own
|
|
38
|
+
# step, so the published image always has `pages`/PDF assertions available, the environment an
|
|
39
|
+
# agent or CI job actually renders in.
|
|
37
40
|
RUN gem install ./bidi2pdf-*.gem && \
|
|
41
|
+
gem install pdf-reader -v "~> 2.14" && \
|
|
38
42
|
chown -R appuser:appuser /app
|
|
39
43
|
|
|
40
44
|
# Switch to non-root user
|
data/docker/Dockerfile.slim
CHANGED
|
@@ -26,7 +26,11 @@ WORKDIR /app
|
|
|
26
26
|
# Copy your gem into container
|
|
27
27
|
COPY ./pkg/bidi2pdf-*.gem ./
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# pdf-reader is deliberately not a bidi2pdf runtime dependency - it is installed here, as its own
|
|
30
|
+
# step, so the published image always has `pages`/PDF assertions available, the environment an
|
|
31
|
+
# agent or CI job actually renders in.
|
|
32
|
+
RUN gem install ./bidi2pdf-*.gem && \
|
|
33
|
+
gem install pdf-reader -v "~> 2.14"
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
# Stage 2
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Bidi2pdf
|
|
4
|
+
class CLI < Thor
|
|
5
|
+
# Shared machinery for --json/--json-stream/--output - across render/diagnose/run: reserving
|
|
6
|
+
# stdout for exactly one machine-readable payload, and mapping a Result to a process exit
|
|
7
|
+
# status.
|
|
8
|
+
module JsonOutput
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# Bidi2pdf.logger (and friends) default to $stdout (see lib/bidi2pdf.rb), so a
|
|
12
|
+
# --json/--output - render has to redirect them for its duration or every log line would
|
|
13
|
+
# land in the same stream as the JSON document / PDF bytes it is trying to keep pure.
|
|
14
|
+
# Logger#reopen swaps the destination in place, so nothing else holding a reference to
|
|
15
|
+
# these loggers needs to know.
|
|
16
|
+
def reserve_stdout_for_machine_output
|
|
17
|
+
loggers = [Bidi2pdf.logger, Bidi2pdf.network_events_logger, Bidi2pdf.browser_console_logger].compact
|
|
18
|
+
loggers.each { |logger| logger.logger.reopen($stderr) }
|
|
19
|
+
|
|
20
|
+
yield
|
|
21
|
+
ensure
|
|
22
|
+
loggers.each { |logger| logger.logger.reopen($stdout) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def exit_for_result(result)
|
|
26
|
+
exit(result.ok? ? Bidi2pdf::ExitCodes::SUCCESS : Bidi2pdf::ExitCodes.for(result.error[:code]))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|