bidi2pdf 0.1.5 → 0.1.7

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +61 -1
  4. data/README.md +47 -10
  5. data/docker/Dockerfile +11 -3
  6. data/docker/Dockerfile.chromedriver +4 -2
  7. data/docker/Dockerfile.slim +75 -0
  8. data/lib/bidi2pdf/bidi/browser_console_logger.rb +92 -0
  9. data/lib/bidi2pdf/bidi/browser_tab.rb +415 -39
  10. data/lib/bidi2pdf/bidi/client.rb +85 -23
  11. data/lib/bidi2pdf/bidi/command_manager.rb +46 -48
  12. data/lib/bidi2pdf/bidi/commands/base.rb +39 -1
  13. data/lib/bidi2pdf/bidi/commands/browser_remove_user_context.rb +27 -0
  14. data/lib/bidi2pdf/bidi/commands/browsing_context_print.rb +4 -0
  15. data/lib/bidi2pdf/bidi/commands/print_parameters_validator.rb +5 -0
  16. data/lib/bidi2pdf/bidi/commands.rb +1 -0
  17. data/lib/bidi2pdf/bidi/event_manager.rb +1 -1
  18. data/lib/bidi2pdf/bidi/interceptor.rb +1 -1
  19. data/lib/bidi2pdf/bidi/js_logger_helper.rb +16 -0
  20. data/lib/bidi2pdf/bidi/logger_events.rb +66 -0
  21. data/lib/bidi2pdf/bidi/network_event.rb +40 -7
  22. data/lib/bidi2pdf/bidi/network_event_formatters/network_event_console_formatter.rb +110 -0
  23. data/lib/bidi2pdf/bidi/network_event_formatters/network_event_formatter_utils.rb +53 -0
  24. data/lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb +125 -0
  25. data/lib/bidi2pdf/bidi/network_event_formatters.rb +11 -0
  26. data/lib/bidi2pdf/bidi/network_events.rb +46 -17
  27. data/lib/bidi2pdf/bidi/session.rb +120 -13
  28. data/lib/bidi2pdf/bidi/user_context.rb +62 -0
  29. data/lib/bidi2pdf/bidi/web_socket_dispatcher.rb +7 -7
  30. data/lib/bidi2pdf/chromedriver_manager.rb +48 -21
  31. data/lib/bidi2pdf/cli.rb +27 -3
  32. data/lib/bidi2pdf/dsl.rb +33 -0
  33. data/lib/bidi2pdf/launcher.rb +34 -2
  34. data/lib/bidi2pdf/notifications/event.rb +52 -0
  35. data/lib/bidi2pdf/notifications/instrumenter.rb +65 -0
  36. data/lib/bidi2pdf/notifications/logging_subscriber.rb +136 -0
  37. data/lib/bidi2pdf/notifications.rb +78 -0
  38. data/lib/bidi2pdf/session_runner.rb +49 -7
  39. data/lib/bidi2pdf/verbose_logger.rb +79 -0
  40. data/lib/bidi2pdf/version.rb +1 -1
  41. data/lib/bidi2pdf.rb +99 -5
  42. data/sig/bidi2pdf/bidi/client.rbs +1 -1
  43. metadata +45 -4
  44. data/lib/bidi2pdf/utils.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b92ff566ca3ae322033cd9602818c94ae30da2594c7075bbb86f4c16351d58ce
4
- data.tar.gz: 1b4d46aa7fe35c1810522a51400c3558f04d8fdc4093c7b3efa0f507a4959392
3
+ metadata.gz: 766b41f0ee642cd7316d0f72d8dd707b0f45aae4a315a46c2b27fb6bb2d176a6
4
+ data.tar.gz: aeec0549f82ff7bdd68d1aa658ea6ad2033e5310fd5936f40b94007b4ae6c38f
5
5
  SHA512:
6
- metadata.gz: 63aa303c4dc6245510cb212adaf22523190d8e00892f4ffe9dc9ba9b65e966f74517ee748f4a232736701a3271ae086879fcbf0adc02ce9f9cd82d103ea3e70d
7
- data.tar.gz: 320a0a03c399541157bd192b6389fecf5541c994cdcaa186694085887ecc8de0829b63badc2be5fa0cd2b8c9baa4ee60bfe7a2f457743d4f21506f1d4bb44850
6
+ metadata.gz: cc7f1da58549b642521808b9ea2acc4b04068bdb7c877cf52943d2ae69bb989f2ade02601b8bfd0e409440ad8644206bba1e6e16603eb56099b8963a2136e350
7
+ data.tar.gz: 6258250ac5de22034cbb7816d3ff33c62680747a3eaee171fdd784d309bf1cd7880ca60e45342da8ee9195814ef1c78ca9b45b2c435f9fcbc4aaa43a8d7f95e6
data/.rubocop.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
- TargetRubyVersion: 3.0
3
+ TargetRubyVersion: 3.3
4
4
 
5
5
  Style/StringLiterals:
6
6
  EnforcedStyle: double_quotes
@@ -44,6 +44,9 @@ Layout/ArrayAlignment:
44
44
  Layout/LineLength:
45
45
  Enabled: false
46
46
 
47
+ Layout/LineEndStringConcatenationIndentation:
48
+ Enabled: false
49
+
47
50
  RSpec/MultipleMemoizedHelpers:
48
51
  Max: 10
49
52
 
data/CHANGELOG.md CHANGED
@@ -6,10 +6,60 @@ All notable changes to this project will be documented in this file.
6
6
 
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
8
8
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
9
- [unreleased]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.5..HEAD
10
9
 
11
10
  <!-- generated by git-cliff end -->
12
11
 
12
+ ## [0.1.7] - 2025-04-17
13
+
14
+ ### 🎨 Refactored
15
+
16
+ - Move notification releated classes to new folder by @dieter-medium
17
+
18
+ ### 🔄 Changed
19
+
20
+ - Refactore custom check script in wait_until_page_loaded by @dieter-medium
21
+ - Add logger support to NetworkEventConsoleFormatter by @dieter-medium
22
+ - Refactore browser console logger support for enhanced logging by @dieter-medium
23
+
24
+ ### 🚀 Added
25
+
26
+ - Add support for predefined paper formats by @dieter-medium
27
+ - Add support for websocket-native for performance boost by @dieter-medium
28
+ - Add logging for print events by @dieter-medium
29
+ - Add configurable logging and notification service by @dieter-medium
30
+ - Introduce VerboseLogger for configurable debug levels by @dieter-medium
31
+ - Instrument Bidi2pdf methods with notification service for enhanced logging by @dieter-medium
32
+ - Introduce notifications system with event instrumentation and logging compatible to rails by @dieter-medium
33
+ - Enhance ChromedriverManager with chrome_args and improve session handling by @dieter-medium
34
+ - Add wait_until_page_loaded method for improved page load handling by @dieter-medium
35
+ - Enhance Chromedriver process management with platform-specific options by @dieter-medium
36
+ - Implement BrowserRemoveUserContext command and enhance user context cleanup by @dieter-medium
37
+ - Add style injection functionality to BrowserTab class by @dieter-medium
38
+ - Add script injection functionality to BrowserTab class by @dieter-medium
39
+
40
+ ## [0.1.6] - 2025-04-12
41
+
42
+ ### ⚠️ Breaking Changes
43
+
44
+ - Rename view_html_page to render_html by @dieter-medium
45
+ - Rename wait_until_all_finished to wait_until_network_idle by @dieter-medium
46
+
47
+ ### 📝 Docs
48
+
49
+ - Update Docker instructions in README by @dieter-medium
50
+
51
+ ### 🔄 Changed
52
+
53
+ - Add details on network logging and console capture by @dieter-medium
54
+
55
+ ### 🚀 Added
56
+
57
+ - Add PDF network log formatting and customizable outputs by @dieter-medium
58
+ - Add option to log network traffic and handle failures within the cli command by @dieter-medium
59
+ - Add structured network traffic logging by @dieter-medium
60
+ - Add slim variant Dockerfile and build matrix for CI by @dieter-medium
61
+ - Add official image at [Docker Hub](https://hub.docker.com/r/dieters877565/bidi2pdf) by @dieter-medium
62
+
13
63
  ## [0.1.5] - 2025-04-10
14
64
 
15
65
  ### 📝 Docs
@@ -92,3 +142,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
92
142
  ## [0.1.0] - 2025-03-26
93
143
 
94
144
  - Initial release
145
+
146
+ [unreleased]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.7..HEAD
147
+
148
+ [unreleased]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.6..v0.1.7
149
+
150
+ [0.1.6]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.5..v0.1.6
151
+
152
+ [0.1.5]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.4..v0.1.5
153
+
154
+ [0.1.4]: https://github.com/dieter-medium/bidi2pdf/compare/v0.1.3..v0.1.4
data/README.md CHANGED
@@ -2,13 +2,14 @@
2
2
  [![Maintainability](https://api.codeclimate.com/v1/badges/6425d9893aa3a9ca243e/maintainability)](https://codeclimate.com/github/dieter-medium/bidi2pdf/maintainability)
3
3
  [![Gem Version](https://badge.fury.io/rb/bidi2pdf.svg)](https://badge.fury.io/rb/bidi2pdf)
4
4
  [![Test Coverage](https://api.codeclimate.com/v1/badges/6425d9893aa3a9ca243e/test_coverage)](https://codeclimate.com/github/dieter-medium/bidi2pdf/test_coverage)
5
+ [![Open Source Helpers](https://www.codetriage.com/dieter-medium/bidi2pdf/badges/users.svg)](https://www.codetriage.com/dieter-medium/bidi2pdf)
5
6
 
6
7
  ---
7
8
 
8
9
  # 📄 Bidi2pdf – Bulletproof PDF generation via Chrome's BiDi Protocol
9
10
 
10
- **Bidi2pdf** is a powerful Ruby gem that transforms modern web pages into high-fidelity PDFs using Chrome’s *
11
- *BiDirectional (BiDi)** protocol. Whether you're automating reports, archiving websites, or shipping documentation,
11
+ **Bidi2pdf** is a powerful Ruby gem that transforms modern web pages into high-fidelity PDFs using Chrome’s
12
+ **BiDirectional (BiDi)** protocol. Whether you're automating reports, archiving websites, or shipping documentation,
12
13
  Bidi2pdf gives you **precision, flexibility, and full control**.
13
14
 
14
15
  ---
@@ -20,7 +21,9 @@ Bidi2pdf gives you **precision, flexibility, and full control**.
20
21
  ✅ **Smart waiting** – Wait for complete page load or network idle
21
22
  ✅ **Headless support** – Run quietly in the background
22
23
  ✅ **Docker-ready** – Plug and play with containers
23
- ✅ **Modern architecture** – Built on Chrome's next-gen BiDi protocol
24
+ ✅ **Modern architecture** – Built on Chrome's next-gen BiDi protocol
25
+ ✅ **Network logging** – Know which requests fail during rendering
26
+ ✅ **Console log capture** – See what goes wrong inside the browser
24
27
 
25
28
  ---
26
29
 
@@ -96,8 +99,8 @@ launcher.launch
96
99
  require "bidi2pdf"
97
100
 
98
101
  Bidi2pdf::DSL.with_tab(headless: true) do |tab|
99
- tab.open_page("https://example.com")
100
- tab.wait_until_all_finished
102
+ tab.navigate_to("https://example.com")
103
+ tab.wait_until_network_idle
101
104
  tab.print("example.pdf")
102
105
  end
103
106
  ```
@@ -142,17 +145,30 @@ tab.basic_auth(url_patterns: [{ type: "pattern", protocol: "https", hostname: "e
142
145
  username: "username", password: "secret")
143
146
 
144
147
  # 4. Render PDF
145
- tab.open_page "https://example.com"
148
+ tab.navigate_to "https://example.com"
146
149
 
147
150
  # Alternative: send html code to the browser
148
- # tab.view_html_page("<html>...</html>")
151
+ # tab.render_html_content("<html>...</html>")
149
152
 
150
- tab.wait_until_all_finished
153
+ # Inject JavaScript if, needed
154
+ # as an url
155
+ # tab.inject_script "https://example.com/script.js"
156
+ # or inline
157
+ # tab.inject_script "console.log('Hello from injected script!')"
158
+
159
+ # Inject CSS if needed
160
+ # as an url
161
+ # tab.inject_style url: "https://example.com/simple.css"
162
+ # or inline
163
+ # tab.inject_style content: "body { background-color: red; }"
164
+
165
+ tab.wait_until_network_idle
151
166
  tab.print("my.pdf")
152
167
 
153
168
  # 5. Cleanup
154
169
  tab.close
155
170
  window.close
171
+ context.close
156
172
  session.close
157
173
  ```
158
174
 
@@ -162,15 +178,36 @@ session.close
162
178
 
163
179
  ## 🐳 Docker Support
164
180
 
165
- ### Build & Run
181
+ ### 🛠️ Build & Run Locally
166
182
 
167
183
  ```bash
184
+ # Prepare the environment
168
185
  rake build
186
+
187
+ # Build the Docker image
169
188
  docker build -t bidi2pdf -f docker/Dockerfile .
170
- docker run -it --rm -v ./output:/reports bidi2pdf \
189
+
190
+ # Run the container and generate a PDF
191
+ docker run -it --rm \
192
+ -v ./output:/reports \
193
+ bidi2pdf \
194
+ bidi2pdf render --url=https://example.com --output /reports/example.pdf
195
+
196
+ ```
197
+
198
+ ### ⚡ Use the Prebuilt Image (Recommended for Fast Start)
199
+
200
+ Grab it directly from [Docker Hub](https://hub.docker.com/r/dieters877565/bidi2pdf)
201
+
202
+ ```bash
203
+ docker run -it --rm \
204
+ -v ./output:/reports \
205
+ dieters877565/bidi2pdf:main-slim \
171
206
  bidi2pdf render --url=https://example.com --output /reports/example.pdf
172
207
  ```
173
208
 
209
+ ✅ Tip: Mount your local directory (e.g. ./output) to /reports in the container to easily access the generated PDFs.
210
+
174
211
  ### Docker Compose
175
212
 
176
213
  ```bash
data/docker/Dockerfile CHANGED
@@ -1,9 +1,11 @@
1
1
  FROM ruby:3.3
2
2
 
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+
3
5
  # Install dependencies
4
- RUN apt-get update && \
5
- apt-get install -y \
6
- chromium \
6
+ RUN apt-get update && apt-get upgrade -y &&\
7
+ apt-get install -y --no-install-recommends\
8
+ chromium chromium-driver\
7
9
  libglib2.0-0 \
8
10
  libnss3 \
9
11
  libxss1 \
@@ -19,6 +21,12 @@ RUN apt-get update && \
19
21
  # Create a non-root user
20
22
  RUN groupadd -r appuser && useradd -r -g appuser -m -d /home/appuser appuser
21
23
 
24
+ # ARM compatibility workaround:
25
+ # On ARM architectures (such as Apple Silicon), downloading chromedriver via automated scripts may fail or cause ELF binary errors,
26
+ # such as "rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2".
27
+ # To avoid these issues, we directly install 'chromium-driver' via the package manager and explicitly create a symlink in the expected location.
28
+
29
+ RUN mkdir -p /home/appuser/.webdrivers && ln -s /usr/bin/chromedriver /home/appuser/.webdrivers/chromedriver
22
30
 
23
31
  # Set working directory
24
32
  WORKDIR /app
@@ -2,9 +2,11 @@ FROM ruby:3.3
2
2
 
3
3
  ARG CHROMEDRIVER_PORT=3000
4
4
 
5
+ ENV DEBIAN_FRONTEND=noninteractive
6
+
5
7
  # Install dependencies
6
- RUN apt-get update && \
7
- apt-get install -y \
8
+ RUN apt-get update && apt-get upgrade -y && \
9
+ apt-get install -y --no-install-recommends\
8
10
  chromium \
9
11
  libglib2.0-0 \
10
12
  libnss3 \
@@ -0,0 +1,75 @@
1
+ FROM ruby:3.3-slim AS builder
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+
5
+ # Install dependencies
6
+ RUN apt-get update && apt-get upgrade -y && \
7
+ apt-get install -y --no-install-recommends \
8
+ chromium \
9
+ libglib2.0-0 \
10
+ libnss3 \
11
+ libxss1 \
12
+ libasound2 \
13
+ libatk-bridge2.0-0 \
14
+ libgtk-3-0 \
15
+ libdrm2 \
16
+ curl \
17
+ unzip \
18
+ xvfb \
19
+ build-essential \
20
+ libpq-dev pkg-config \
21
+ && rm -rf /var/lib/apt/lists/*
22
+
23
+ # Set working directory
24
+ WORKDIR /app
25
+
26
+ # Copy your gem into container
27
+ COPY ./pkg/bidi2pdf-*.gem ./
28
+
29
+ RUN gem install ./bidi2pdf-*.gem
30
+
31
+
32
+ # Stage 2
33
+
34
+ FROM ruby:3.3-slim
35
+
36
+ ENV DEBIAN_FRONTEND=noninteractive
37
+
38
+ # Install dependencies
39
+ RUN apt-get update && apt-get upgrade -y &&\
40
+ apt-get install -y --no-install-recommends\
41
+ chromium chromium-driver\
42
+ libglib2.0-0 \
43
+ libnss3 \
44
+ libxss1 \
45
+ libasound2 \
46
+ libatk-bridge2.0-0 \
47
+ libgtk-3-0 \
48
+ libdrm2 \
49
+ curl \
50
+ unzip \
51
+ xvfb \
52
+ && rm -rf /var/lib/apt/lists/*
53
+
54
+ COPY --from=builder /usr/local/bundle /usr/local/bundle
55
+
56
+ # Create a non-root user
57
+ RUN groupadd -r appuser && useradd -r -g appuser -m -d /home/appuser appuser
58
+
59
+ # ARM compatibility workaround:
60
+ # On ARM architectures (such as Apple Silicon), downloading chromedriver via automated scripts may fail or cause ELF binary errors,
61
+ # such as "rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2".
62
+ # To avoid these issues, we directly install 'chromium-driver' via the package manager and explicitly create a symlink in the expected location.
63
+
64
+ RUN mkdir -p /home/appuser/.webdrivers && ln -s /usr/bin/chromedriver /home/appuser/.webdrivers/chromedriver
65
+
66
+ # Set working directory
67
+ WORKDIR /app
68
+
69
+ RUN chown -R appuser:appuser /app
70
+
71
+ # Switch to non-root user
72
+ USER appuser
73
+
74
+ CMD ["/usr/bin/bash"]
75
+
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "js_logger_helper"
4
+
5
+ module Bidi2pdf
6
+ module Bidi
7
+ class BrowserConsoleLoggerSuggar
8
+ attr_reader :browser_console_logger
9
+
10
+ def initialize(browser_console_logger)
11
+ @browser_console_logger = browser_console_logger
12
+ end
13
+
14
+ def with_level(level)
15
+ @level = level
16
+ self
17
+ end
18
+
19
+ def with_prefix(prefix)
20
+ @prefix = prefix
21
+ self
22
+ end
23
+
24
+ def with_timestamp(timestamp)
25
+ @timestamp = timestamp
26
+ self
27
+ end
28
+
29
+ def with_text(text)
30
+ @text = text
31
+ self
32
+ end
33
+
34
+ def with_args(args)
35
+ @args = args
36
+ self
37
+ end
38
+
39
+ def with_stack_trace(stack_trace)
40
+ @stack_trace = stack_trace
41
+ self
42
+ end
43
+
44
+ def log_event
45
+ browser_console_logger.log_message(@level, @prefix, @text)
46
+ browser_console_logger.log_args(@prefix, @args)
47
+ browser_console_logger.log_stack_trace(@prefix, @stack_trace) if @stack_trace && @level == :error
48
+ end
49
+
50
+ def prefix
51
+ @prefix ||= "[#{BrowserConsoleLogger.format_timestamp(@timestamp)}][Browser Console Log]"
52
+ end
53
+ end
54
+
55
+ class BrowserConsoleLogger
56
+ include JsLoggerHelper
57
+
58
+ attr_accessor :logger
59
+
60
+ def initialize(logger)
61
+ @logger = logger
62
+ end
63
+
64
+ def builder
65
+ BrowserConsoleLoggerSuggar.new(self)
66
+ end
67
+
68
+ def log_message(level, prefix, text)
69
+ return unless text
70
+
71
+ logger.send(level, "#{prefix} #{text}")
72
+ end
73
+
74
+ def log_args(prefix, args)
75
+ return if args.empty?
76
+
77
+ logger.debug("#{prefix} Args: #{args.inspect}")
78
+ end
79
+
80
+ def log_stack_trace(prefix, trace)
81
+ formatted_trace = format_stack_trace(trace)
82
+ logger.error("#{prefix} Stack trace captured:\n#{formatted_trace}")
83
+ end
84
+
85
+ def self.format_timestamp(timestamp)
86
+ return "N/A" unless timestamp
87
+
88
+ Time.at(timestamp.to_f / 1000).utc.strftime("%Y-%m-%d %H:%M:%S.%L UTC")
89
+ end
90
+ end
91
+ end
92
+ end