puppeteer-ruby 0.52.1 → 0.53.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/docs/api_coverage.md +16 -15
  3. data/lib/puppeteer/accessibility.rb +300 -0
  4. data/lib/puppeteer/browser.rb +107 -8
  5. data/lib/puppeteer/browser_connector.rb +1 -0
  6. data/lib/puppeteer/browser_context.rb +0 -1
  7. data/lib/puppeteer/cdp_session.rb +29 -8
  8. data/lib/puppeteer/chrome_target_manager.rb +145 -34
  9. data/lib/puppeteer/connection.rb +19 -0
  10. data/lib/puppeteer/coverage.rb +5 -0
  11. data/lib/puppeteer/css_coverage.rb +4 -0
  12. data/lib/puppeteer/dialog.rb +5 -0
  13. data/lib/puppeteer/element_handle.rb +2 -3
  14. data/lib/puppeteer/emulation_manager.rb +70 -9
  15. data/lib/puppeteer/events.rb +2 -0
  16. data/lib/puppeteer/execution_context.rb +7 -0
  17. data/lib/puppeteer/extension.rb +20 -6
  18. data/lib/puppeteer/frame.rb +7 -3
  19. data/lib/puppeteer/frame_manager.rb +71 -26
  20. data/lib/puppeteer/http_response.rb +15 -1
  21. data/lib/puppeteer/isolated_world.rb +10 -4
  22. data/lib/puppeteer/js_coverage.rb +4 -0
  23. data/lib/puppeteer/keyboard.rb +6 -0
  24. data/lib/puppeteer/launcher/browser_options.rb +13 -1
  25. data/lib/puppeteer/launcher/chrome.rb +48 -4
  26. data/lib/puppeteer/lifecycle_watcher.rb +1 -6
  27. data/lib/puppeteer/locators.rb +54 -26
  28. data/lib/puppeteer/mouse.rb +12 -24
  29. data/lib/puppeteer/network_manager.rb +16 -4
  30. data/lib/puppeteer/page.rb +259 -33
  31. data/lib/puppeteer/puppeteer.rb +6 -5
  32. data/lib/puppeteer/screen_recorder.rb +269 -0
  33. data/lib/puppeteer/target.rb +7 -3
  34. data/lib/puppeteer/touch_screen.rb +6 -0
  35. data/lib/puppeteer/tracing.rb +4 -0
  36. data/lib/puppeteer/version.rb +2 -2
  37. data/lib/puppeteer/wait_task.rb +1 -2
  38. data/lib/puppeteer/web_mcp.rb +227 -0
  39. data/lib/puppeteer/web_worker.rb +135 -9
  40. data/lib/puppeteer.rb +11 -1
  41. data/puppeteer-ruby.gemspec +1 -0
  42. data/sig/_supplementary.rbs +33 -1
  43. data/sig/puppeteer/accessibility.rbs +73 -0
  44. data/sig/puppeteer/browser.rbs +27 -3
  45. data/sig/puppeteer/cdp_session.rbs +4 -0
  46. data/sig/puppeteer/dialog.rbs +3 -0
  47. data/sig/puppeteer/element_handle.rbs +1 -2
  48. data/sig/puppeteer/execution_context.rbs +5 -0
  49. data/sig/puppeteer/extension.rbs +4 -0
  50. data/sig/puppeteer/frame.rbs +4 -2
  51. data/sig/puppeteer/http_response.rbs +4 -0
  52. data/sig/puppeteer/keyboard.rbs +4 -0
  53. data/sig/puppeteer/locators.rbs +3 -4
  54. data/sig/puppeteer/mouse.rbs +5 -6
  55. data/sig/puppeteer/page.rbs +48 -4
  56. data/sig/puppeteer/puppeteer.rbs +4 -5
  57. data/sig/puppeteer/screen_recorder.rbs +48 -0
  58. data/sig/puppeteer/touch_screen.rbs +4 -0
  59. data/sig/puppeteer/web_mcp.rbs +112 -0
  60. data/sig/puppeteer/web_worker.rbs +39 -0
  61. metadata +22 -2
@@ -99,6 +99,7 @@ class Puppeteer::NetworkManager
99
99
  @extra_http_headers = {}
100
100
  @user_agent = nil
101
101
  @user_agent_metadata = nil
102
+ @accept_language = nil
102
103
 
103
104
  @attempted_authentications = Set.new
104
105
  @user_request_interception_enabled = false
@@ -146,12 +147,12 @@ class Puppeteer::NetworkManager
146
147
  end
147
148
 
148
149
  private def ignore_client_error?(error)
150
+ return true if error.is_a?(Puppeteer::TargetCloseError)
151
+
149
152
  message = error&.message
150
153
  return false unless message
151
154
 
152
155
  lowered = message.downcase
153
- return true if lowered.include?('target closed')
154
- return true if lowered.include?('session closed')
155
156
  return true if lowered.include?('not supported')
156
157
  return true if lowered.include?("wasn't found")
157
158
 
@@ -175,10 +176,12 @@ class Puppeteer::NetworkManager
175
176
  end
176
177
 
177
178
  private def apply_user_agent(client)
178
- return unless @user_agent
179
+ user_agent = @user_agent || @frame_manager.page.browser.user_agent
180
+ return unless user_agent
179
181
 
180
182
  safe_send_message(client, 'Network.setUserAgentOverride', {
181
- userAgent: @user_agent,
183
+ userAgent: user_agent,
184
+ acceptLanguage: @accept_language,
182
185
  userAgentMetadata: @user_agent_metadata,
183
186
  }.compact)
184
187
  end
@@ -212,6 +215,8 @@ class Puppeteer::NetworkManager
212
215
  if @internal_network_condition.active?
213
216
  safe_send_message(client, 'Network.emulateNetworkConditions', @internal_network_condition.params)
214
217
  end
218
+ rescue => err
219
+ raise unless ignore_client_error?(err)
215
220
  end
216
221
 
217
222
  # @param username [String|NilClass]
@@ -281,6 +286,13 @@ class Puppeteer::NetworkManager
281
286
  end
282
287
  alias_method :user_agent=, :set_user_agent
283
288
 
289
+ # @rbs accept_language: String? -- Accept-Language override
290
+ # @rbs return: void -- No return value
291
+ def set_accept_language(accept_language)
292
+ @accept_language = accept_language
293
+ apply_to_clients { |client| apply_user_agent(client) }
294
+ end
295
+
284
296
  def cache_enabled=(enabled)
285
297
  @user_cache_disabled = !enabled
286
298
  update_protocol_cache_disabled
@@ -40,32 +40,46 @@ class Puppeteer::Page
40
40
  @closed = false
41
41
  @client = client
42
42
  @target = target
43
- @tab_id = nil
43
+ @tab_session = client.parent_session || client
44
+ @tab_target = @tab_session.target || target
45
+ @tab_id = @tab_target.target_id
44
46
  @keyboard = Puppeteer::Keyboard.new(client)
45
47
  @mouse = Puppeteer::Mouse.new(client, @keyboard)
46
48
  @timeout_settings = Puppeteer::TimeoutSettings.new
47
49
  @touchscreen = Puppeteer::TouchScreen.new(client, @keyboard)
48
- # @accessibility = Accessibility.new(client)
49
50
  @frame_manager = Puppeteer::FrameManager.new(client, self, ignore_https_errors, @timeout_settings, network_enabled: network_enabled)
50
51
  @emulation_manager = Puppeteer::EmulationManager.new(client)
51
52
  @tracing = Puppeteer::Tracing.new(client)
53
+ @webmcp = Puppeteer::WebMCP.new(client, @frame_manager)
52
54
  @page_bindings = {}
53
55
  @page_binding_ids = {}
54
56
  @coverage = Puppeteer::Coverage.new(client)
55
57
  @javascript_enabled = true
56
58
  @screenshot_task_queue = ScreenshotTaskQueue.new
59
+ @screencast_session_count = 0
60
+ @screencast_start_promise = nil
61
+ @screencast_mutex = Mutex.new
57
62
  @inflight_requests = Set.new
58
63
  @request_intercepted_listener_map = ObjectSpace::WeakMap.new
59
64
  @attached_sessions = Set.new
65
+ @primary_session_listener_ids = []
60
66
 
61
67
  @workers = {}
62
68
  @user_drag_interception_enabled = false
63
69
  @service_worker_bypassed = false
64
70
 
65
- @attached_session_listener_id = @client.add_event_listener(CDPSessionEmittedEvents::Ready) do |session|
66
- handle_attached_to_session(session)
71
+ @swapped_session_listener_id = @tab_session.add_event_listener(CDPSessionEmittedEvents::Swapped) do |session|
72
+ Async do
73
+ handle_activation(session)
74
+ rescue => err
75
+ debug_puts(err)
76
+ end
67
77
  end
68
- @target_gone_listener_id = @target.target_manager.add_event_listener(
78
+ @secondary_session_listener_id = @tab_session.add_event_listener(CDPSessionEmittedEvents::Ready) do |session|
79
+ handle_secondary_target(session)
80
+ end
81
+ @target_manager = @target.target_manager
82
+ @target_gone_listener_id = @target_manager.add_event_listener(
69
83
  TargetManagerEmittedEvents::TargetGone,
70
84
  &method(:handle_detached_from_target)
71
85
  )
@@ -102,47 +116,95 @@ class Puppeteer::Page
102
116
  @file_chooser_interception_is_disabled = false
103
117
  @file_chooser_interceptors = Set.new
104
118
 
105
- @client.on_event('Page.domContentEventFired') do |event|
119
+ setup_primary_target_listeners(@client)
120
+ end
121
+
122
+ private def setup_primary_target_listeners(client)
123
+ listener_id = client.add_event_listener(CDPSessionEmittedEvents::Ready) do |session|
124
+ handle_attached_to_session(session)
125
+ end
126
+ @primary_session_listener_ids << [client, listener_id]
127
+
128
+ client.on_event('Page.domContentEventFired') do |event|
106
129
  emit_event(PageEmittedEvents::DOMContentLoaded)
107
130
  end
108
- @client.on_event('Page.loadEventFired') do |event|
131
+ client.on_event('Page.loadEventFired') do |event|
109
132
  emit_event(PageEmittedEvents::Load)
110
133
  end
111
- @client.add_event_listener('Runtime.consoleAPICalled') do |event|
134
+ client.add_event_listener('Runtime.consoleAPICalled') do |event|
112
135
  handle_console_api(event)
113
136
  end
114
- @client.add_event_listener('Runtime.bindingCalled') do |event|
137
+ client.add_event_listener('Runtime.bindingCalled') do |event|
115
138
  handle_binding_called(event)
116
139
  end
117
- @client.on_event('Page.javascriptDialogOpening') do |event|
140
+ client.on_event('Page.javascriptDialogOpening') do |event|
118
141
  handle_dialog_opening(event)
119
142
  end
120
- @client.on_event('Runtime.exceptionThrown') do |exception|
143
+ client.on_event('Runtime.exceptionThrown') do |exception|
121
144
  handle_exception(exception['exceptionDetails'])
122
145
  end
123
- @client.on_event('Inspector.targetCrashed') do |event|
146
+ client.on_event('Inspector.targetCrashed') do |event|
124
147
  handle_target_crashed
125
148
  end
126
- @client.on_event('Performance.metrics') do |event|
149
+ client.on_event('Performance.metrics') do |event|
127
150
  emit_event(PageEmittedEvents::Metrics, MetricsEvent.new(event))
128
151
  end
129
- @client.on_event('Log.entryAdded') do |event|
152
+ client.on_event('Log.entryAdded') do |event|
130
153
  handle_log_entry_added(event)
131
154
  end
132
- @client.on_event('Page.fileChooserOpened') do |event|
155
+ client.on_event('Page.fileChooserOpened') do |event|
133
156
  handle_file_chooser(event)
134
157
  end
135
- Async do
136
- @target.is_closed_promise.wait
137
- @client.remove_event_listener(@attached_session_listener_id)
138
- @target.target_manager.remove_event_listener(@target_gone_listener_id)
158
+ end
159
+
160
+ private def handle_activation(session)
161
+ @client = session
162
+ @target = session.target
163
+ @target.instance_variable_set(:@page, self)
164
+ @keyboard.update_client(session)
165
+ @mouse.update_client(session)
166
+ @touchscreen.update_client(session)
167
+ @emulation_manager.update_client(session)
168
+ @tracing.update_client(session)
169
+ @webmcp.update_client(session)
170
+ @coverage.update_client(session)
171
+ @frame_manager.swap_frame_tree(session)
172
+ setup_primary_target_listeners(session)
173
+ end
174
+
175
+ private def handle_secondary_target(session)
176
+ target = session.target
177
+ return unless target&.target_info&.subtype == 'prerender'
139
178
 
140
- emit_event(PageEmittedEvents::Close)
141
- @closed = true
179
+ @frame_manager.register_speculative_session(session)
180
+ @emulation_manager.register_speculative_session(session)
181
+ end
182
+
183
+ private def mark_closed
184
+ return if @closed
185
+
186
+ cleanup_page_listeners
187
+ @closed = true
188
+ emit_event(PageEmittedEvents::Close)
189
+ end
190
+
191
+ private def cleanup_page_listeners
192
+ return if @page_listeners_cleaned
193
+
194
+ @page_listeners_cleaned = true
195
+ @primary_session_listener_ids.each do |session, listener_id|
196
+ session.remove_event_listener(listener_id)
142
197
  end
198
+ @tab_session.remove_event_listener(@swapped_session_listener_id, @secondary_session_listener_id)
199
+ @target_manager.remove_event_listener(@target_gone_listener_id)
143
200
  end
144
201
 
145
202
  private def handle_detached_from_target(target)
203
+ if target == @tab_target
204
+ mark_closed
205
+ return
206
+ end
207
+
146
208
  session_id = target.session&.id
147
209
  @frame_manager.handle_detached_from_target(target)
148
210
  return unless session_id
@@ -201,6 +263,7 @@ class Puppeteer::Page
201
263
  @frame_manager.async_init(@target.target_id),
202
264
  @client.async_send_message('Performance.enable'),
203
265
  @client.async_send_message('Log.enable'),
266
+ @webmcp.async_initialize_domain,
204
267
  )
205
268
  end
206
269
 
@@ -360,10 +423,23 @@ class Puppeteer::Page
360
423
  end
361
424
 
362
425
  # @rbs return: bool -- Whether DevTools is attached to this page
363
- def has_devtools
426
+ def has_dev_tools
364
427
  !!browser._has_devtools_target(@target.target_id)
365
428
  end
366
429
 
430
+ # @rbs return: Puppeteer::Page -- Existing or newly opened DevTools page
431
+ def open_dev_tools
432
+ page_target_id = @target.target_id
433
+ devtools_target_id = browser._has_devtools_target(page_target_id)
434
+ if devtools_target_id
435
+ return browser._get_devtools_target_page(devtools_target_id)
436
+ end
437
+
438
+ browser._create_devtools_page(page_target_id)
439
+ end
440
+
441
+ define_async_method :async_open_dev_tools
442
+
367
443
  # @rbs extension: Puppeteer::Extension -- Extension to trigger
368
444
  # @rbs return: void -- No return value
369
445
  def trigger_extension_action(extension)
@@ -409,9 +485,14 @@ class Puppeteer::Page
409
485
  @frame_manager.main_frame
410
486
  end
411
487
 
412
- attr_reader :touchscreen, :coverage, :tracing, :accessibility
488
+ attr_reader :touchscreen, :coverage, :tracing, :webmcp
413
489
  alias_method :touch_screen, :touchscreen
414
490
 
491
+ # @rbs return: Puppeteer::Accessibility -- Main-frame accessibility tree
492
+ def accessibility
493
+ main_frame.accessibility
494
+ end
495
+
415
496
  # @rbs block: Proc? -- Optional block for instance_eval
416
497
  # @rbs return: Puppeteer::Keyboard -- Keyboard instance
417
498
  def keyboard(&block)
@@ -1324,6 +1405,13 @@ class Puppeteer::Page
1324
1405
  end
1325
1406
  end
1326
1407
 
1408
+ # @rbs locale: String? -- Locale to emulate, or nil to disable emulation
1409
+ # @rbs return: void -- No return value
1410
+ def emulate_locale(locale = nil)
1411
+ @emulation_manager.emulate_locale(locale)
1412
+ @frame_manager.network_manager.set_accept_language(locale)
1413
+ end
1414
+
1327
1415
  VISION_DEFICIENCY_TYPES = %w[
1328
1416
  none
1329
1417
  achromatopsia
@@ -1369,6 +1457,151 @@ class Puppeteer::Page
1369
1457
 
1370
1458
  attr_reader :viewport
1371
1459
 
1460
+ # @rbs path: String? -- Output file path
1461
+ # @rbs overwrite: bool -- Overwrite an existing output file
1462
+ # @rbs format: String? -- webm, gif, or mp4
1463
+ # @rbs crop: Hash[Symbol, Numeric]? -- Viewport crop rectangle
1464
+ # @rbs scale: Numeric? -- Output scale
1465
+ # @rbs speed: Numeric? -- Playback speed
1466
+ # @rbs fps: Numeric? -- Output frame rate
1467
+ # @rbs loop: Numeric? -- GIF loop count
1468
+ # @rbs delay: Numeric? -- GIF loop delay
1469
+ # @rbs quality: Numeric? -- VP9 CRF value
1470
+ # @rbs colors: Numeric? -- GIF palette size
1471
+ # @rbs ffmpeg_path: String? -- FFmpeg executable path
1472
+ # @rbs return: Puppeteer::ScreenRecorder -- Active recorder
1473
+ def screencast(
1474
+ path: nil,
1475
+ overwrite: true,
1476
+ format: nil,
1477
+ crop: nil,
1478
+ scale: nil,
1479
+ speed: nil,
1480
+ fps: nil,
1481
+ loop: nil,
1482
+ delay: nil,
1483
+ quality: nil,
1484
+ colors: nil,
1485
+ ffmpeg_path: nil
1486
+ )
1487
+ raise ArgumentError.new('`speed` must be greater than 0.') if speed && speed <= 0
1488
+ raise ArgumentError.new('`scale` must be greater than 0.') if scale && scale <= 0
1489
+ width, height, device_pixel_ratio = native_pixel_dimensions
1490
+ normalized_crop = normalize_screencast_crop(crop, width, height, device_pixel_ratio)
1491
+ options = {
1492
+ path: path,
1493
+ overwrite: overwrite,
1494
+ format: format,
1495
+ crop: normalized_crop,
1496
+ scale: scale,
1497
+ speed: speed,
1498
+ fps: fps,
1499
+ loop: loop,
1500
+ delay: delay,
1501
+ quality: quality,
1502
+ colors: colors,
1503
+ ffmpeg_path: ffmpeg_path,
1504
+ }.compact
1505
+ recorder = Puppeteer::ScreenRecorder.new(self, width, height, options)
1506
+ begin
1507
+ _start_screencast
1508
+ rescue
1509
+ recorder.stop
1510
+ raise
1511
+ end
1512
+ recorder
1513
+ end
1514
+
1515
+ # @rbs return: void -- Start a shared CDP screencast session
1516
+ def _start_screencast
1517
+ start_promise, first_session = @screencast_mutex.synchronize do
1518
+ @screencast_session_count += 1
1519
+ next [@screencast_start_promise, false] if @screencast_start_promise
1520
+
1521
+ @screencast_start_promise = Async::Promise.new
1522
+ [@screencast_start_promise, true]
1523
+ end
1524
+ if first_session
1525
+ first_frame = Async::Promise.new
1526
+ client = main_frame.client
1527
+ listener_id = client.once('Page.screencastFrame') do
1528
+ first_frame.resolve(nil) unless first_frame.resolved?
1529
+ end
1530
+ begin
1531
+ client.send_message('Page.startScreencast', format: 'png')
1532
+ first_frame.wait
1533
+ start_promise.resolve(nil)
1534
+ rescue => error
1535
+ start_promise.reject(error) unless start_promise.resolved?
1536
+ ensure
1537
+ client.remove_event_listener(listener_id) if listener_id
1538
+ end
1539
+ end
1540
+ start_promise.wait
1541
+ end
1542
+
1543
+ # @rbs return: void -- Stop a shared CDP screencast session
1544
+ def _stop_screencast
1545
+ should_stop = @screencast_mutex.synchronize do
1546
+ @screencast_session_count -= 1 if @screencast_session_count.positive?
1547
+ next false unless @screencast_start_promise
1548
+
1549
+ @screencast_start_promise = nil
1550
+ @screencast_session_count.zero?
1551
+ end
1552
+ main_frame.client.send_message('Page.stopScreencast') if should_stop
1553
+ end
1554
+
1555
+ private def native_pixel_dimensions
1556
+ original_viewport = @viewport
1557
+ if original_viewport && original_viewport.device_scale_factor != 0
1558
+ self.viewport = original_viewport.merge(device_scale_factor: 0)
1559
+ end
1560
+ main_frame.puppeteer_world.evaluate(<<~JAVASCRIPT)
1561
+ () => [
1562
+ window.visualViewport.width * window.devicePixelRatio,
1563
+ window.visualViewport.height * window.devicePixelRatio,
1564
+ window.devicePixelRatio,
1565
+ ]
1566
+ JAVASCRIPT
1567
+ ensure
1568
+ self.viewport = original_viewport if original_viewport && @viewport != original_viewport
1569
+ end
1570
+
1571
+ private def normalize_screencast_crop(crop, width, height, device_pixel_ratio)
1572
+ return nil unless crop
1573
+
1574
+ value = ->(name) do
1575
+ crop.respond_to?(name) ? crop.public_send(name) : crop[name] || crop[name.to_s]
1576
+ end
1577
+ x = value.call(:x).floor
1578
+ y = value.call(:y).floor
1579
+ crop_width = value.call(:width).ceil
1580
+ crop_height = value.call(:height).ceil
1581
+ if x.negative? || y.negative?
1582
+ raise ArgumentError.new('`crop.x` and `crop.y` must be greater than or equal to 0.')
1583
+ end
1584
+ if crop_width <= 0 || crop_height <= 0
1585
+ raise ArgumentError.new(
1586
+ '`crop.height` and `crop.width` must be greater than or equal to 0.',
1587
+ )
1588
+ end
1589
+ viewport_width = width / device_pixel_ratio
1590
+ viewport_height = height / device_pixel_ratio
1591
+ if x + crop_width > viewport_width
1592
+ raise ArgumentError.new("`crop.width` cannot be larger than the viewport width (#{viewport_width}).")
1593
+ end
1594
+ if y + crop_height > viewport_height
1595
+ raise ArgumentError.new("`crop.height` cannot be larger than the viewport height (#{viewport_height}).")
1596
+ end
1597
+ {
1598
+ x: x * device_pixel_ratio,
1599
+ y: y * device_pixel_ratio,
1600
+ width: crop_width * device_pixel_ratio,
1601
+ height: crop_height * device_pixel_ratio,
1602
+ }
1603
+ end
1604
+
1372
1605
  # @rbs page_function: String -- page_function parameter
1373
1606
  # @rbs args: Array[untyped] -- args parameter
1374
1607
  # @rbs return: untyped -- Result
@@ -1619,13 +1852,7 @@ class Puppeteer::Page
1619
1852
  @client.send_message('Page.close')
1620
1853
  else
1621
1854
  @client.connection.send_message('Target.closeTarget', targetId: @target.target_id)
1622
- @target.is_closed_promise.wait
1623
-
1624
- # @closed sometimes remains false, so wait for @closed = true with 100ms timeout.
1625
- 25.times do
1626
- break if @closed
1627
- Puppeteer::AsyncUtils.sleep_seconds(0.004)
1628
- end
1855
+ @tab_target.is_closed_promise.wait
1629
1856
  end
1630
1857
  rescue Puppeteer::Connection::ProtocolError => err
1631
1858
  raise unless err.message.match?(/Target closed/i)
@@ -1644,11 +1871,10 @@ class Puppeteer::Page
1644
1871
  # @rbs selector: String -- CSS selector
1645
1872
  # @rbs delay: Numeric? -- Delay between down and up (ms)
1646
1873
  # @rbs button: String? -- Mouse button
1647
- # @rbs click_count: Integer? -- Deprecated: use count (click_count only sets clickCount)
1648
1874
  # @rbs count: Integer? -- Number of clicks to perform
1649
1875
  # @rbs return: void -- No return value
1650
- def click(selector, delay: nil, button: nil, click_count: nil, count: nil)
1651
- main_frame.click(selector, delay: delay, button: button, click_count: click_count, count: count)
1876
+ def click(selector, delay: nil, button: nil, count: nil)
1877
+ main_frame.click(selector, delay: delay, button: button, count: count)
1652
1878
  end
1653
1879
 
1654
1880
  define_async_method :async_click
@@ -33,6 +33,7 @@ class Puppeteer::Puppeteer
33
33
  # @rbs network_enabled: bool? -- Enable network domain
34
34
  # @rbs issues_enabled: bool? -- Enable issues domain
35
35
  # @rbs block_list: Array[String]? -- URL block list patterns
36
+ # @rbs allow_list: Array[String]? -- URL allow list patterns
36
37
  # @rbs enable_extensions: (bool | Array[String])? -- Enable extensions or load unpacked extensions
37
38
  # @rbs default_viewport: Puppeteer::Viewport? -- Default viewport
38
39
  # @rbs slow_mo: Integer? -- Delay between operations (ms)
@@ -61,6 +62,7 @@ class Puppeteer::Puppeteer
61
62
  network_enabled: true,
62
63
  issues_enabled: true,
63
64
  block_list: nil,
65
+ allow_list: nil,
64
66
  enable_extensions: false,
65
67
  default_viewport: NoViewport.new,
66
68
  slow_mo: nil,
@@ -93,6 +95,7 @@ class Puppeteer::Puppeteer
93
95
  network_enabled: network_enabled,
94
96
  issues_enabled: issues_enabled,
95
97
  block_list: block_list,
98
+ allow_list: allow_list,
96
99
  enable_extensions: enable_extensions,
97
100
  default_viewport: default_viewport,
98
101
  slow_mo: slow_mo,
@@ -145,6 +148,7 @@ class Puppeteer::Puppeteer
145
148
  # @rbs network_enabled: bool? -- Enable network domain
146
149
  # @rbs issues_enabled: bool? -- Enable issues domain
147
150
  # @rbs block_list: Array[String]? -- URL block list patterns
151
+ # @rbs allow_list: Array[String]? -- URL allow list patterns
148
152
  # @rbs default_viewport: Puppeteer::Viewport? -- Default viewport
149
153
  # @rbs slow_mo: Integer? -- Delay between operations (ms)
150
154
  # @rbs protocol_timeout: Integer? -- CDP protocol timeout in milliseconds
@@ -159,6 +163,7 @@ class Puppeteer::Puppeteer
159
163
  network_enabled: true,
160
164
  issues_enabled: true,
161
165
  block_list: nil,
166
+ allow_list: nil,
162
167
  default_viewport: NoViewport.new,
163
168
  slow_mo: nil,
164
169
  protocol_timeout: nil,
@@ -173,6 +178,7 @@ class Puppeteer::Puppeteer
173
178
  network_enabled: network_enabled,
174
179
  issues_enabled: issues_enabled,
175
180
  block_list: block_list,
181
+ allow_list: allow_list,
176
182
  slow_mo: slow_mo,
177
183
  protocol_timeout: protocol_timeout,
178
184
  }.compact
@@ -226,11 +232,6 @@ class Puppeteer::Puppeteer
226
232
  )
227
233
  end
228
234
 
229
- # @rbs return: String -- Product name
230
- def product
231
- launcher.product
232
- end
233
-
234
235
  private def async_context?
235
236
  task = Async::Task.current
236
237
  !task.nil?