bidi2pdf 0.1.6 → 0.1.8

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +63 -8
  4. data/README.md +28 -0
  5. data/docker/Dockerfile +1 -1
  6. data/docker/Dockerfile.chromedriver +9 -2
  7. data/docker/Dockerfile.slim +2 -2
  8. data/lib/bidi2pdf/bidi/browser_console_logger.rb +92 -0
  9. data/lib/bidi2pdf/bidi/browser_tab.rb +431 -41
  10. data/lib/bidi2pdf/bidi/client.rb +85 -23
  11. data/lib/bidi2pdf/bidi/command_manager.rb +46 -60
  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/connection_manager.rb +3 -9
  18. data/lib/bidi2pdf/bidi/event_manager.rb +2 -2
  19. data/lib/bidi2pdf/bidi/interceptor.rb +1 -1
  20. data/lib/bidi2pdf/bidi/js_logger_helper.rb +16 -0
  21. data/lib/bidi2pdf/bidi/logger_events.rb +25 -45
  22. data/lib/bidi2pdf/bidi/navigation_failed_events.rb +41 -0
  23. data/lib/bidi2pdf/bidi/network_event.rb +15 -0
  24. data/lib/bidi2pdf/bidi/network_event_formatters/network_event_console_formatter.rb +4 -3
  25. data/lib/bidi2pdf/bidi/network_events.rb +27 -17
  26. data/lib/bidi2pdf/bidi/session.rb +123 -13
  27. data/lib/bidi2pdf/bidi/user_context.rb +62 -0
  28. data/lib/bidi2pdf/bidi/web_socket_dispatcher.rb +7 -7
  29. data/lib/bidi2pdf/chromedriver_manager.rb +48 -21
  30. data/lib/bidi2pdf/cli.rb +10 -2
  31. data/lib/bidi2pdf/dsl.rb +33 -0
  32. data/lib/bidi2pdf/launcher.rb +30 -0
  33. data/lib/bidi2pdf/notifications/event.rb +52 -0
  34. data/lib/bidi2pdf/notifications/instrumenter.rb +65 -0
  35. data/lib/bidi2pdf/notifications/logging_subscriber.rb +136 -0
  36. data/lib/bidi2pdf/notifications.rb +78 -0
  37. data/lib/bidi2pdf/session_runner.rb +35 -3
  38. data/lib/bidi2pdf/test_helpers/matchers/contains_pdf_text.rb +50 -0
  39. data/lib/bidi2pdf/test_helpers/matchers/have_pdf_page_count.rb +50 -0
  40. data/lib/bidi2pdf/test_helpers/matchers/match_pdf_text.rb +45 -0
  41. data/lib/bidi2pdf/test_helpers/pdf_reader_utils.rb +89 -0
  42. data/lib/bidi2pdf/test_helpers/pdf_text_sanitizer.rb +232 -0
  43. data/lib/bidi2pdf/test_helpers/testcontainers/chromedriver_container.rb +87 -0
  44. data/lib/bidi2pdf/test_helpers.rb +13 -0
  45. data/lib/bidi2pdf/verbose_logger.rb +79 -0
  46. data/lib/bidi2pdf/version.rb +1 -1
  47. data/lib/bidi2pdf.rb +131 -10
  48. data/sig/bidi2pdf/bidi/client.rbs +1 -1
  49. metadata +67 -4
  50. data/lib/bidi2pdf/utils.rb +0 -15
data/lib/bidi2pdf.rb CHANGED
@@ -1,14 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "bidi2pdf/utils"
3
+ require "concurrent-ruby"
4
+ require "logger"
5
+
4
6
  require_relative "bidi2pdf/process_tree"
5
7
  require_relative "bidi2pdf/launcher"
6
8
  require_relative "bidi2pdf/bidi/session"
7
9
  require_relative "bidi2pdf/dsl"
8
-
9
- require "logger"
10
+ require_relative "bidi2pdf/notifications"
11
+ require_relative "bidi2pdf/notifications/logging_subscriber"
12
+ require_relative "bidi2pdf/verbose_logger"
10
13
 
11
14
  module Bidi2pdf
15
+ PAPER_FORMATS_CM = {
16
+ letter: { width: 21.59, height: 27.94 },
17
+ legal: { width: 21.59, height: 35.56 },
18
+ tabloid: { width: 27.94, height: 43.18 },
19
+ ledger: { width: 43.18, height: 27.94 },
20
+ a0: { width: 84.1, height: 118.9 },
21
+ a1: { width: 59.4, height: 84.1 },
22
+ a2: { width: 42.0, height: 59.4 },
23
+ a3: { width: 29.7, height: 42.0 },
24
+ a4: { width: 21.0, height: 29.7 },
25
+ a5: { width: 14.8, height: 21.0 },
26
+ a6: { width: 10.5, height: 14.8 }
27
+ }.freeze
28
+
12
29
  class Error < StandardError; end
13
30
 
14
31
  class SessionNotStartedError < Error; end
@@ -17,7 +34,16 @@ module Bidi2pdf
17
34
 
18
35
  class ClientError < WebsocketError; end
19
36
 
20
- class CmdError < ClientError; end
37
+ class CmdError < ClientError
38
+ attr_reader :cmd, :response
39
+
40
+ def initialize(cmd, response)
41
+ @cmd = cmd
42
+ @response = response
43
+
44
+ super("Error response: #{response["error"]} #{cmd.inspect}")
45
+ end
46
+ end
21
47
 
22
48
  class CmdResponseNotStoredError < ClientError; end
23
49
 
@@ -25,19 +51,114 @@ module Bidi2pdf
25
51
 
26
52
  class PrintError < Error; end
27
53
 
28
- @logger = Logger.new($stdout)
29
- @network_events_logger = Logger.new($stdout)
30
- @logger.level = Logger::INFO
31
- @network_events_logger.level = Logger::FATAL
54
+ class ScriptInjectionError < Error; end
55
+
56
+ class StyleInjectionError < Error; end
57
+
58
+ class NotificationsError < Error
59
+ attr_reader :causes
60
+
61
+ def initialize(causes)
62
+ @causes = causes
63
+ exception_class_names = causes.map { |e| e.class.name }
64
+ super("Notifications errors: #{exception_class_names.join(", ")}")
65
+ end
66
+ end
67
+
68
+ class NavigationError < Error; end
69
+
70
+ class NavigationAuthError < NavigationError
71
+ attr_reader :url
72
+
73
+ def initialize(url, message = nil)
74
+ @url = url
75
+ super("Navigation to #{url} failed due to authentication error. #{message}")
76
+ end
77
+ end
78
+
79
+ class NavigationTimeoutError < NavigationError; end
32
80
 
33
- @default_timeout = 60
81
+ class NavigationNotFoundError < NavigationError; end
82
+
83
+ class NavigationDNSError < NavigationError; end
84
+
85
+ # Global configuration for Bidi2pdf
34
86
 
35
87
  class << self
36
- attr_accessor :logger, :default_timeout, :network_events_logger
88
+ attr_accessor :default_timeout, :enable_default_logging_subscriber
89
+ attr_reader :logging_subscriber, :logger, :network_events_logger, :browser_console_logger, :notification_service
37
90
 
38
91
  # Allow configuration through a block
39
92
  def configure
40
93
  yield self if block_given?
94
+
95
+ init
41
96
  end
97
+
98
+ def init
99
+ self.logging_subscriber = (Notifications::LoggingSubscriber.new(logger: logger) if enable_default_logging_subscriber)
100
+ begin
101
+ require "websocket-native"
102
+
103
+ logger.debug "websocket-native available; use enhance performance."
104
+ rescue LoadError => e
105
+ raise unless e.message =~ /websocket-native/
106
+
107
+ logger.warn "websocket-native not available; installing it may enhance performance."
108
+ end
109
+ end
110
+
111
+ def translate_paper_format(format)
112
+ format = format.to_s.downcase.to_sym
113
+
114
+ dim = PAPER_FORMATS_CM[format]
115
+
116
+ raise ArgumentError, "Invalid paper format: #{format}" unless dim
117
+
118
+ width = dim[:width] || 0
119
+ height = dim[:height] || 0
120
+
121
+ { width: width, height: height }
122
+ end
123
+
124
+ def logger=(new_logger)
125
+ @logger = Bidi2pdf::VerboseLogger.new new_logger
126
+ end
127
+
128
+ def network_events_logger=(new_network_events_logger)
129
+ @network_events_logger = Bidi2pdf::VerboseLogger.new(new_network_events_logger)
130
+ end
131
+
132
+ def browser_console_logger=(new_browser_console_logger)
133
+ @browser_console_logger = Bidi2pdf::VerboseLogger.new(new_browser_console_logger)
134
+ end
135
+
136
+ def logging_subscriber=(new_logging_subscriber)
137
+ @logging_subscriber&.unsubscribe
138
+ @logging_subscriber = new_logging_subscriber
139
+ end
140
+
141
+ def notification_service=(new_notification_service)
142
+ @logging_subscriber&.unsubscribe
143
+
144
+ @notification_service = new_notification_service
145
+ end
146
+ end
147
+
148
+ configure do |config|
149
+ config.logger = Logger.new($stdout)
150
+ config.logger.level = Logger::INFO
151
+
152
+ config.network_events_logger = Logger.new($stdout)
153
+ config.network_events_logger.level = Logger::FATAL
154
+
155
+ config.browser_console_logger = Logger.new($stdout)
156
+ config.browser_console_logger.level = Logger::WARN
157
+
158
+ config.enable_default_logging_subscriber = true
159
+
160
+ config.default_timeout = 60
161
+
162
+ config.notification_service = Notifications
42
163
  end
43
164
  end
@@ -34,7 +34,7 @@ module Bidi2pdf
34
34
 
35
35
  def wait_until_open: (?timeout: untyped) -> untyped
36
36
 
37
- def send_cmd: (untyped method, ?::Hash[untyped, untyped] params) -> untyped
37
+ def send_cmd: (Bidi2pdf::Bidi::Commands::Base cmd) -> untyped
38
38
 
39
39
  # rubocop:disable Metrics/AbcSize
40
40
  def send_cmd_and_wait: (untyped method, ?::Hash[untyped, untyped] params, ?timeout: untyped) ?{ (untyped) -> untyped } -> untyped
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bidi2pdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dieter S.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-04-12 00:00:00.000000000 Z
11
+ date: 2025-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -38,6 +38,26 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: concurrent-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 1.3.1
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.3.1
41
61
  - !ruby/object:Gem::Dependency
42
62
  name: json
43
63
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +198,20 @@ dependencies:
178
198
  - - "~>"
179
199
  - !ruby/object:Gem::Version
180
200
  version: '3.0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: rspec-benchmark
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '0.6'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '0.6'
181
215
  - !ruby/object:Gem::Dependency
182
216
  name: rubocop
183
217
  requirement: !ruby/object:Gem::Requirement
@@ -276,6 +310,20 @@ dependencies:
276
310
  - - "~>"
277
311
  - !ruby/object:Gem::Version
278
312
  version: '1.4'
313
+ - !ruby/object:Gem::Dependency
314
+ name: websocket-native
315
+ requirement: !ruby/object:Gem::Requirement
316
+ requirements:
317
+ - - "~>"
318
+ - !ruby/object:Gem::Version
319
+ version: '1.0'
320
+ type: :development
321
+ prerelease: false
322
+ version_requirements: !ruby/object:Gem::Requirement
323
+ requirements:
324
+ - - "~>"
325
+ - !ruby/object:Gem::Version
326
+ version: '1.0'
279
327
  description: |
280
328
  Bidi2pdf is a powerful PDF generation tool that uses Chrome's BiDirectional Protocol
281
329
  to render web pages as high-quality PDF documents. It offers:
@@ -320,6 +368,7 @@ files:
320
368
  - lib/bidi2pdf/bidi/add_headers_interceptor.rb
321
369
  - lib/bidi2pdf/bidi/auth_interceptor.rb
322
370
  - lib/bidi2pdf/bidi/browser.rb
371
+ - lib/bidi2pdf/bidi/browser_console_logger.rb
323
372
  - lib/bidi2pdf/bidi/browser_tab.rb
324
373
  - lib/bidi2pdf/bidi/client.rb
325
374
  - lib/bidi2pdf/bidi/command_manager.rb
@@ -328,6 +377,7 @@ files:
328
377
  - lib/bidi2pdf/bidi/commands/base.rb
329
378
  - lib/bidi2pdf/bidi/commands/browser_close.rb
330
379
  - lib/bidi2pdf/bidi/commands/browser_create_user_context.rb
380
+ - lib/bidi2pdf/bidi/commands/browser_remove_user_context.rb
331
381
  - lib/bidi2pdf/bidi/commands/browsing_context_close.rb
332
382
  - lib/bidi2pdf/bidi/commands/browsing_context_navigate.rb
333
383
  - lib/bidi2pdf/bidi/commands/browsing_context_print.rb
@@ -347,7 +397,9 @@ files:
347
397
  - lib/bidi2pdf/bidi/connection_manager.rb
348
398
  - lib/bidi2pdf/bidi/event_manager.rb
349
399
  - lib/bidi2pdf/bidi/interceptor.rb
400
+ - lib/bidi2pdf/bidi/js_logger_helper.rb
350
401
  - lib/bidi2pdf/bidi/logger_events.rb
402
+ - lib/bidi2pdf/bidi/navigation_failed_events.rb
351
403
  - lib/bidi2pdf/bidi/network_event.rb
352
404
  - lib/bidi2pdf/bidi/network_event_formatters.rb
353
405
  - lib/bidi2pdf/bidi/network_event_formatters/network_event_console_formatter.rb
@@ -361,9 +413,20 @@ files:
361
413
  - lib/bidi2pdf/cli.rb
362
414
  - lib/bidi2pdf/dsl.rb
363
415
  - lib/bidi2pdf/launcher.rb
416
+ - lib/bidi2pdf/notifications.rb
417
+ - lib/bidi2pdf/notifications/event.rb
418
+ - lib/bidi2pdf/notifications/instrumenter.rb
419
+ - lib/bidi2pdf/notifications/logging_subscriber.rb
364
420
  - lib/bidi2pdf/process_tree.rb
365
421
  - lib/bidi2pdf/session_runner.rb
366
- - lib/bidi2pdf/utils.rb
422
+ - lib/bidi2pdf/test_helpers.rb
423
+ - lib/bidi2pdf/test_helpers/matchers/contains_pdf_text.rb
424
+ - lib/bidi2pdf/test_helpers/matchers/have_pdf_page_count.rb
425
+ - lib/bidi2pdf/test_helpers/matchers/match_pdf_text.rb
426
+ - lib/bidi2pdf/test_helpers/pdf_reader_utils.rb
427
+ - lib/bidi2pdf/test_helpers/pdf_text_sanitizer.rb
428
+ - lib/bidi2pdf/test_helpers/testcontainers/chromedriver_container.rb
429
+ - lib/bidi2pdf/verbose_logger.rb
367
430
  - lib/bidi2pdf/version.rb
368
431
  - sig/bidi2pdf.rbs
369
432
  - sig/bidi2pdf/bidi/add_headers_interceptor.rbs
@@ -429,7 +492,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
429
492
  requirements:
430
493
  - - ">="
431
494
  - !ruby/object:Gem::Version
432
- version: 3.0.0
495
+ version: 3.3.0
433
496
  required_rubygems_version: !ruby/object:Gem::Requirement
434
497
  requirements:
435
498
  - - ">="
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bidi2pdf
4
- module Utils
5
- def timed(operation_name)
6
- start_time = Time.now
7
- result = yield
8
- elapsed = Time.now - start_time
9
- Bidi2pdf.logger.debug "#{operation_name} completed in #{elapsed.round(3)}s"
10
- result
11
- end
12
-
13
- module_function :timed
14
- end
15
- end