Skip to content

[js] Ensure BiDi is not exposed on driver - #17829

Closed
pujagani wants to merge 84 commits into
SeleniumHQ:trunkfrom
pujagani:bidi-access-js
Closed

[js] Ensure BiDi is not exposed on driver#17829
pujagani wants to merge 84 commits into
SeleniumHQ:trunkfrom
pujagani:bidi-access-js

Conversation

@pujagani

Copy link
Copy Markdown
Contributor

🔗 Related Issues

Related to #17814

💥 What does this PR do?

Ensure that BiDi connection is not accessible on driver.

🔧 Implementation Notes

🤖 AI assistance

  • No substantial AI assistance used
  • AI assisted (complete below)
    • Tool(s):
    • What was generated:
    • I reviewed all AI output and can explain the change

💡 Additional Considerations

🔄 Types of changes

  • Deprecation

@selenium-ci selenium-ci added the C-nodejs JavaScript Bindings label Jul 28, 2026
cgoldberg and others added 28 commits July 28, 2026 10:25
* [js] parse BiDi CDDL in generate_bidi.mjs, drop py/private merge_cddl dependency
… custom Firefox webExtension options (SeleniumHQ#17840)

* [build] add local CDDL overlays for webExtension.install SeleniumHQ#1140 extension point and moz vendor params

* [js] implement in schema not in merged cddl file that is sent to cddl2ts

* [rb] generate a browser-scoped webExtension vendor subclass (WebExtension::Moz)
…C URLs (SeleniumHQ#17790)

* [grid] honor client-advertised se:remoteUrl in the Node with grid-url precedence

* [grid] advertise se:remoteUrl from the language bindings

* [grid] fix se:remoteUrl on URL constructor, https scheme casing, and builder capability conflict

* [grid] strip se:remoteUrl from returned session caps

* [grid] use only the origin of se:remoteUrl for proxied URLs
…Q#17838)

* [rust] locate Chrome and Edge in known install directories

* [rust] honor --skip-browser-in-path and keep WebView2 out of Edge browser lookup
* [dotnet] throw instead of warn for CDP on Firefox

* [py] raise for CDP methods on Firefox

* [rb] remove CDP extensions from Firefox so methods are unavailable
… match severity (SeleniumHQ#17848)

* [rb] match log entries by id and severity, add missing log ids, drop logger stubs

* [rb] match message assertions against entries carrying multiple ids
* [rb] glob spec sources into //rb/spec:spec for rubocop and clear hidden offenses

* [rb] remove unnecessary rb_library from rb_integration_test now that //rb/spec:spec globs sources
…date primitives outbound in Ruby (SeleniumHQ#17852)

* [build] bump cddl to 0.21.1 so float BiDi ranges type as number, not integer

* [build] hoist nullable inline enums to named enums so their vocabulary is validated

* [rb] validate outbound BiDi primitive types at construction
…eleniumHQ#17853)

* [build] drop preserveExtras schema signal; extensibility alone gates wire extras

* [rb] retain wire extras on every extensible BiDi type, not only re-sendable ones

* [rb] keep extensible extras without warning and reject extras shadowing declared fields
…e map (SeleniumHQ#17855)

* [rb] raise typed WebDriver errors for BiDi from a generated error-code map

* [rb] declare RBS only for BiDi-only error classes to avoid redeclaring classic ones
…DEO_SESSION_SUBFOLDER (SeleniumHQ#17856)

Signed-off-by: Viet Nguyen Duc <nguyenducviet4496@gmail.com>
…SeleniumHQ#17859)

* [rb] add exception-aware pending_if guard matching

* [rb] keep pending_exception_guard spec deterministic under SKIP_PENDING
…LE is set (SeleniumHQ#17858)

[dotnet][java][py][rb] pass --enable-chrome-logs unless CHROME_LOG_FILE is set or on Windows (SeleniumHQ#16201)
…eleniumHQ#17862)

* [rb] add add_chromium_option/add_firefox_option escape hatches and merge hand-built vendor options

* [rb] normalize vendor option names to string keys
…eleniumHQ#17861)

* [rb] validate BiDi outbound ref fields against their declared type

* [rb] reject a non-variant object at a scalar-arm BiDi union

* [rb] validate BiDi union bare-scalar arms against their schema literals
…17863)

* [rb] capture log matcher output under SE_DEBUG and keep service specs env-agnostic

* [rb] drop the SE_DEBUG output lock in the spec log-capture helper
selenium-ci and others added 21 commits August 10, 2026 18:41
[js] normalize empty custom locator results

Co-authored-by: Diego Molina <diemol@users.noreply.github.com>
Update pinned browser versions

Co-authored-by: Selenium CI Bot <selenium-ci@users.noreply.github.com>
* [rb] scaffold BiDi protocol integration specs from schema

* [build] run edge-bidi targets in ci-ruby full suite

* [rb] raise BiDi SerializationError on wire deserialization mismatches

* [rb] guard bidi protocol specs for unsupported browser commands and timeouts

* [rb] skip unsupported BiDi modules on Safari with per-module support probes

* [rb] enable strict BiDi serialization for all bidi specs via the test environment
Update pinned browser versions

Co-authored-by: Selenium CI Bot <selenium-ci@users.noreply.github.com>
SeleniumHQ#17909)

[build] trim no-op gh-cache triggers and prune CodeQL caches from PR runs
…#17910)

Update pinned browser versions

Co-authored-by: Selenium CI Bot <selenium-ci@users.noreply.github.com>
[py] disable nightly TestPyPI publishing and add twine --verbose
[rb] fix Safari set_viewport spec guard and update Homebrew before STP install
…g last release (SeleniumHQ#17921)

* [build] fix release mirror push target and poll Maven Central when verifying Java
@pujagani
pujagani marked this pull request as ready for review August 18, 2026 07:01
@qodo-code-review

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Deprecate direct JavaScript WebDriver BiDi connection access

✨ Enhancement 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Moves BiDi connection ownership outside the WebDriver instance.
• Deprecates direct raw transport access while preserving backward compatibility.
• Adds concurrency and cleanup coverage for internally managed connections.
Diagram

sequenceDiagram
  participant Module as BiDi Module
  participant Driver as WebDriver
  participant Store as Connection Store
  participant Caps as Capabilities
  participant Socket as BiDi Socket
  Module->>Driver: Request BiDi
  Driver->>Store: Get shared promise
  alt First access
    Store->>Caps: Read WebSocket URL
    Caps-->>Store: Return URL
    Store->>Socket: Open connection
  end
  Store-->>Driver: Return connection
  Driver-->>Module: Return connection
  Driver->>Store: Close on quit
  Store->>Socket: Close connection
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Migrate composed modules immediately
  • ➕ Prevents recommended BiDi APIs from invoking the deprecated WebDriver accessor
  • ➕ More completely enforces the intended implementation boundary
  • ➖ Touches every existing JavaScript BiDi module
  • ➖ Creates a larger compatibility-sensitive change
2. Store a private WebDriver field
  • ➕ Keeps connection lifecycle logic colocated with WebDriver
  • ➕ Uses native language privacy instead of an external WeakMap
  • ➖ Still couples raw BiDi transport ownership to WebDriver
  • ➖ Requires private-field accessors for composed modules

Recommendation: The WeakMap-backed manager is appropriate because it removes connection state from WebDriver, avoids concurrent initialization races, and supports gradual deprecation. Composed BiDi modules should subsequently call the internal manager directly so normal use of the recommended APIs does not pass through the deprecated accessor.

Files changed (3) +210 / -19

Enhancement (1) +32 / -19
webdriver.jsDelegate BiDi ownership and deprecate direct access +32/-19

Delegate BiDi ownership and deprecate direct access

• Removes BiDi connection state from WebDriver and delegates creation and shutdown to the internal manager. The existing getBidi method becomes a deprecated compatibility shim directing consumers toward composed BiDi modules.

javascript/selenium-webdriver/lib/webdriver.js

Refactor (1) +82 / -0
bidi_connection.jsAdd internal BiDi connection lifecycle manager +82/-0

Add internal BiDi connection lifecycle manager

• Introduces a WeakMap-backed manager that stores one in-flight connection promise per driver, preventing concurrent initialization races. It validates BiDi capability support and safely closes only connections that were previously requested.

javascript/selenium-webdriver/lib/bidi_connection.js

Tests (1) +96 / -0
bidi_connection_test.jsTest BiDi connection deduplication and cleanup +96/-0

Test BiDi connection deduplication and cleanup

• Adds WebSocket-backed tests confirming concurrent callers share one connection. Also verifies cleanup is harmless before initialization and after failed connection attempts.

javascript/selenium-webdriver/test/lib/bidi_connection_test.js

@qodo-code-review

qodo-code-review Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (6) 📜 Skill insights (0)

Grey Divider


Action required

1. Raw BiDi remains exposed 🐞 Bug ≡ Correctness
Description
Assigning getBidi to WebDriver.prototype leaves the raw transport publicly discoverable and
callable, contrary to the PR's stated boundary. Recommended composed modules still call
_driver.getBidi(), so ordinary module use also invokes the deprecated API and emits its warning.
Code

javascript/selenium-webdriver/lib/webdriver.js[R1790-1792]

+WebDriver.prototype.getBidi = util.deprecate(function () {
+  return getBidiConnection(this)
+}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")
Evidence
The changed prototype assignment directly returns the raw connection. Composed modules documented as
the replacement still initialize through that same public method, so the method remains exposed and
the deprecation wrapper is exercised by supported usage.

javascript/selenium-webdriver/lib/webdriver.js[1778-1792]
javascript/selenium-webdriver/lib/bidi_connection.js[38-55]
javascript/selenium-webdriver/bidi/network.js[93-95]
javascript/selenium-webdriver/bidi/browser.js[29-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Remove the raw BiDi transport accessor from the public `WebDriver` prototype and prevent composed BiDi modules from invoking a deprecated public API.

## Issue Context
`WebDriver.prototype.getBidi` still exposes the transport, while composed modules such as Network and Browser depend on it. Introduce an internal connection mechanism and migrate those modules before removing the prototype accessor.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1792]
- javascript/selenium-webdriver/lib/bidi_connection.js[38-55]
- javascript/selenium-webdriver/bidi/network.js[93-95]
- javascript/selenium-webdriver/bidi/browser.js[29-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. BiDi cleanup bypassed or unawaited 🐞 Bug ☼ Reliability
Description
quit() reaches the added cleanup only when onQuit_ is absent, and even then it does not return
or await the asynchronous close promise. Consequently await driver.quit() can finish without
completing BiDi cleanup, while drivers with an onQuit_ callback skip explicit cleanup entirely.
Code

javascript/selenium-webdriver/lib/webdriver.js[R798-799]

+      // Close the BiDi websocket connection, if one was ever opened
+      closeBidiConnection(this)
Evidence
The quit finalizer returns from the onQuit_ branch before the added close call; Chromium and
Firefox local sessions both provide such callbacks. On other paths, closeBidiConnection awaits the
pending connection and WebSocket close event, but its promise is discarded by quit().

javascript/selenium-webdriver/lib/webdriver.js[771-800]
javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
javascript/selenium-webdriver/bidi/index.js[318-337]
javascript/selenium-webdriver/chromium.js[640-654]
javascript/selenium-webdriver/firefox.js[580-604]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Ensure WebDriver quit always performs and awaits BiDi connection cleanup, including when an `onQuit_` callback is configured.

## Issue Context
The finalizer returns early for `onQuit_`, and the new asynchronous close call is otherwise invoked without returning its promise. Browser-specific local drivers configure `onQuit_` to stop their services.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[775-800]
- javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
- javascript/selenium-webdriver/bidi/index.js[318-337]
- javascript/selenium-webdriver/chromium.js[640-654]
- javascript/selenium-webdriver/firefox.js[580-604]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Remote credentials logged 🐞 Bug ⛨ Security
Description
When se:remoteUrl is unusable, resolvePublicGridUri logs its complete untrusted value, including
any embedded username or password. JavaScript now sends the configured remote URL verbatim as this
capability, allowing malformed or unsupported credential-bearing URLs to disclose secrets in Grid
logs.
Code

java/src/org/openqa/selenium/grid/node/local/LocalNode.java[R1349-1351]

+              String.format(
+                  "Ignoring unusable se:remoteUrl '%s'; using %s for proxied URLs",
+                  value, gridUri));
Evidence
The JavaScript builder stores the full URL as se:remoteUrl, and capability serialization sends
vendor-prefixed values. Grid copies that raw string into value and interpolates it into the added
warning whenever parsing or validation fails, without removing URI userinfo first.

javascript/selenium-webdriver/index.js[658-667]
javascript/selenium-webdriver/lib/webdriver.js[720-727]
java/src/org/openqa/selenium/grid/node/local/LocalNode.java[1329-1353]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Prevent credentials embedded in `se:remoteUrl` from being written to Grid logs when the URL cannot be used.

## Issue Context
The JavaScript builder advertises the complete configured server URL. Grid's invalid-value warning interpolates that raw capability after URI validation fails or rejects the scheme.

## Fix Focus Areas
- javascript/selenium-webdriver/index.js[661-664]
- java/src/org/openqa/selenium/grid/node/local/LocalNode.java[1329-1353]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. pending_if guards omit reasons 📘 Rule violation ▣ Testability ⭐ New
Description
Multiple modified Ruby integration-test guards omit the mandatory reason, leaving skipped or
pending tests without an explicit explanation. This affects pending_if, skip_if, and flaky
guards across several integration specs.
Code

rb/spec/integration/selenium/webdriver/action_builder_spec.rb[28]

+        it 'sends keys to the active element', pending_if: {browser_family: :safari} do
Evidence
Rule 922483 requires every integration-test guard to include an explicit reason. The changed guards
shown in the cited files provide browser conditions but no reason, such as `pending_if:
{browser_family: :safari}`.

Rule 922483: Require explicit reason in integration test guards
rb/spec/integration/selenium/webdriver/action_builder_spec.rb[28-28]
rb/spec/integration/selenium/webdriver/driver_spec.rb[33-33]
rb/spec/integration/selenium/webdriver/element_spec.rb[32-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Modified integration-test guards omit the required explicit `reason` value.

## Issue Context
Every integration guard that supports a reason must provide a string literal or numeric issue identifier explaining why the test is guarded.

## Fix Focus Areas
- rb/spec/integration/selenium/webdriver/action_builder_spec.rb[28-160]
- rb/spec/integration/selenium/webdriver/driver_spec.rb[33-356]
- rb/spec/integration/selenium/webdriver/element_spec.rb[32-351]
- rb/spec/integration/selenium/webdriver/fedcm_spec.rb[70-70]
- rb/spec/integration/selenium/webdriver/manager_spec.rb[82-166]
- rb/spec/integration/selenium/webdriver/navigation_spec.rb[25-25]
- rb/spec/integration/selenium/webdriver/target_locator_spec.rb[171-171]
- rb/spec/integration/selenium/webdriver/timeout_spec.rb[89-89]
- rb/spec/integration/selenium/webdriver/window_spec.rb[116-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. addExtensions lacks runtime warning 📘 Rule violation ◔ Observability ⭐ New
Description
Options#addExtensions is newly documented as deprecated, but its body emits no warning naming the
method and replacement API. Callers therefore receive no runtime migration guidance as required for
deprecated APIs.
Code

javascript/selenium-webdriver/firefox.js[320]

+   * @deprecated Use {@link Driver#installAddon} instead.
Evidence
Rule 389260 requires every deprecated API to execute a warning that identifies both the deprecated
method and its replacement. The cited method adds only @deprecated Use Driver#installAddon instead
while its implementation directly delegates and returns without emitting any diagnostic.

Rule 389260: Log deprecation warnings with guidance to replacement APIs
javascript/selenium-webdriver/firefox.js[315-324]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`Options#addExtensions` is marked deprecated only in JSDoc and emits no runtime deprecation warning.

## Issue Context
The warning should be emitted at most once, identify `Options#addExtensions`, and recommend `Driver#installAddon`. Use the project-standard deprecation mechanism rather than an ad-hoc print or log statement.

## Fix Focus Areas
- javascript/selenium-webdriver/firefox.js[315-324]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. BiDi reopens during shutdown 🐞 Bug ☼ Reliability ⭐ New
Description
closeBidiConnection() deletes the cached entry before the existing connection finishes closing, so
concurrent BiDi access creates a replacement connection. That replacement is not tracked by the
active cleanup operation and can remain open after driver shutdown.
Code

javascript/selenium-webdriver/lib/bidi_connection.js[73]

+  connections.delete(driver)
Evidence
The accessor creates a connection whenever the WeakMap lacks an entry, while shutdown removes that
entry before awaiting both pending creation and connection.close(). BiDi.close() itself resolves
only after the websocket close event, leaving a concrete interval in which another accessor can
create an unclosed replacement.

javascript/selenium-webdriver/lib/bidi_connection.js[38-42]
javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
javascript/selenium-webdriver/bidi/index.js[318-337]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`closeBidiConnection()` removes the driver's cache entry before the pending connection has closed. A concurrent `getBidiConnection()` therefore creates a second websocket that is outside the active cleanup and may leak after shutdown.

## Issue Context
Preserve a closing/tombstone state for the driver so access cannot create another connection while shutdown is underway. Only clear lifecycle state when doing so cannot permit a connection to reopen for a quitting driver.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/bidi_connection.js[38-42]
- javascript/selenium-webdriver/lib/bidi_connection.js[68-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (4)
7. Third-party file added 📘 Rule violation § Compliance
Description
The PR adds third_party/bazel/rules_ruby_windows_batch_crlf.patch, despite the checklist
prohibiting additions or modifications under third_party/. The underlying integration or vendoring
configuration must be changed outside that directory instead.
Code

third_party/bazel/rules_ruby_windows_batch_crlf.patch[1]

+diff --git a/ruby/private/utils.bzl b/ruby/private/utils.bzl
Evidence
PR Compliance 389269 disallows every added, removed, or modified path under third_party/. This PR
adds a 39-line file at such a path.

Rule 389269: Disallow modifications to third_party directory
third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new patch file is committed under `third_party/`, which is a prohibited path for direct additions or modifications.

## Issue Context
Move the required Windows batch handling to project-owned source or vendoring configuration outside `third_party/`, then remove this generated/vendor patch from the PR.

## Fix Focus Areas
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Deprecation bypasses project logger 📘 Rule violation ✧ Quality
Description
WebDriver#getBidi uses Node's util.deprecate instead of WebDriver.logger.deprecate and
supplies no unique deprecation ID. This bypasses the required standardized deprecation mechanism.
Code

javascript/selenium-webdriver/lib/webdriver.js[R1790-1792]

+WebDriver.prototype.getBidi = util.deprecate(function () {
+  return getBidiConnection(this)
+}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")
Evidence
PR Compliance 389235 requires all modified deprecation notices to use
WebDriver.logger.deprecate(...) with the old API, replacement API, and a non-empty id. The added
wrapper instead calls util.deprecate with only a message.

Rule 389235: Standardize deprecation notices using WebDriver.logger.deprecate
javascript/selenium-webdriver/lib/webdriver.js[1790-1792]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`WebDriver#getBidi` emits its deprecation through `util.deprecate` rather than `WebDriver.logger.deprecate`, and the notice has no unique ID.

## Issue Context
Keep the existing guidance to composed BiDi modules, but emit it through the project-standard deprecation logger with a stable, non-empty identifier.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1790-1792]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. getBidi return undocumented 📘 Rule violation ✧ Quality
Description
The public WebDriver#getBidi JSDoc has an @returns type but no description of the returned
value. Public API JSDoc requires a typed return tag with non-empty descriptive text.
Code

javascript/selenium-webdriver/lib/webdriver.js[1788]

+ * @returns {Promise<import('../bidi')>}
Evidence
PR Compliance 389257 requires a public JavaScript method returning a value to have one @return or
@returns tag containing both a type and a brief description. The added tag contains only the type.

Rule 389257: Document public API functions with complete JSDoc blocks
javascript/selenium-webdriver/lib/webdriver.js[1778-1788]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new JSDoc for public `WebDriver#getBidi` uses `@returns {Promise<import('../bidi')>}` without the required return-value description.

## Issue Context
Retain the existing type and add concise text explaining that the promise resolves to the session's BiDi connection.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1789]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. PR contains unrelated changes 📘 Rule violation ✧ Quality
Description
The diff spans hundreds of files across JavaScript, Java, .NET, Python, Ruby, Rust, build
infrastructure, protocol schemas, and dependencies, far beyond hiding the JavaScript BiDi
connection. It also changes unrelated user-visible policy such as the minimum Node.js version,
making the PR difficult to review or revert safely.
Code

javascript/selenium-webdriver/package.json[23]

+    "node": ">= 22.0.0"
Evidence
PR Compliance 389267 requires the diff to remain narrowly related to its stated purpose. The branch
includes an unrelated Node runtime increase, a broad release changelog roll-up, and a new
third-party Bazel patch in addition to extensive changes across other language bindings.

Rule 389267: Avoid large, cross-cutting changes in a single pull request
javascript/selenium-webdriver/package.json[3-51]
javascript/selenium-webdriver/CHANGES.md[1-20]
third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR includes a large collection of unrelated release, dependency, runtime-policy, protocol, and cross-language changes alongside the JavaScript BiDi change.

## Issue Context
Rebase the branch onto the intended target and retain only the narrowly related JavaScript BiDi implementation, documentation, build entries, and regression tests. Submit unrelated accumulated changes separately.

## Fix Focus Areas
- javascript/selenium-webdriver/package.json[3-51]
- javascript/selenium-webdriver/CHANGES.md[1-20]
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 42 rules

Grey Divider

Tip of the day
💡 Did you know, you can keep summaries lean with Finding overflow, which tucks the rest behind 'View more'

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Previous review results

Review updated until commit 6288b65 ⚖️ Balanced

Results up to commit 324f9d7 ⚖️ Balanced


🐞 Bugs (3) 📘 Rule violations (4) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)


Action required
1. Raw BiDi remains exposed 🐞 Bug ≡ Correctness
Description
Assigning getBidi to WebDriver.prototype leaves the raw transport publicly discoverable and
callable, contrary to the PR's stated boundary. Recommended composed modules still call
_driver.getBidi(), so ordinary module use also invokes the deprecated API and emits its warning.
Code

javascript/selenium-webdriver/lib/webdriver.js[R1790-1792]

+WebDriver.prototype.getBidi = util.deprecate(function () {
+  return getBidiConnection(this)
+}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")
Evidence
The changed prototype assignment directly returns the raw connection. Composed modules documented as
the replacement still initialize through that same public method, so the method remains exposed and
the deprecation wrapper is exercised by supported usage.

javascript/selenium-webdriver/lib/webdriver.js[1778-1792]
javascript/selenium-webdriver/lib/bidi_connection.js[38-55]
javascript/selenium-webdriver/bidi/network.js[93-95]
javascript/selenium-webdriver/bidi/browser.js[29-35]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Remove the raw BiDi transport accessor from the public `WebDriver` prototype and prevent composed BiDi modules from invoking a deprecated public API.

## Issue Context
`WebDriver.prototype.getBidi` still exposes the transport, while composed modules such as Network and Browser depend on it. Introduce an internal connection mechanism and migrate those modules before removing the prototype accessor.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1792]
- javascript/selenium-webdriver/lib/bidi_connection.js[38-55]
- javascript/selenium-webdriver/bidi/network.js[93-95]
- javascript/selenium-webdriver/bidi/browser.js[29-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. BiDi cleanup bypassed or unawaited 🐞 Bug ☼ Reliability
Description
quit() reaches the added cleanup only when onQuit_ is absent, and even then it does not return
or await the asynchronous close promise. Consequently await driver.quit() can finish without
completing BiDi cleanup, while drivers with an onQuit_ callback skip explicit cleanup entirely.
Code

javascript/selenium-webdriver/lib/webdriver.js[R798-799]

+      // Close the BiDi websocket connection, if one was ever opened
+      closeBidiConnection(this)
Evidence
The quit finalizer returns from the onQuit_ branch before the added close call; Chromium and
Firefox local sessions both provide such callbacks. On other paths, closeBidiConnection awaits the
pending connection and WebSocket close event, but its promise is discarded by quit().

javascript/selenium-webdriver/lib/webdriver.js[771-800]
javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
javascript/selenium-webdriver/bidi/index.js[318-337]
javascript/selenium-webdriver/chromium.js[640-654]
javascript/selenium-webdriver/firefox.js[580-604]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Ensure WebDriver quit always performs and awaits BiDi connection cleanup, including when an `onQuit_` callback is configured.

## Issue Context
The finalizer returns early for `onQuit_`, and the new asynchronous close call is otherwise invoked without returning its promise. Browser-specific local drivers configure `onQuit_` to stop their services.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[775-800]
- javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
- javascript/selenium-webdriver/bidi/index.js[318-337]
- javascript/selenium-webdriver/chromium.js[640-654]
- javascript/selenium-webdriver/firefox.js[580-604]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Remote credentials logged 🐞 Bug ⛨ Security
Description
When se:remoteUrl is unusable, resolvePublicGridUri logs its complete untrusted value, including
any embedded username or password. JavaScript now sends the configured remote URL verbatim as this
capability, allowing malformed or unsupported credential-bearing URLs to disclose secrets in Grid
logs.
Code

java/src/org/openqa/selenium/grid/node/local/LocalNode.java[R1349-1351]

+              String.format(
+                  "Ignoring unusable se:remoteUrl '%s'; using %s for proxied URLs",
+                  value, gridUri));
Evidence
The JavaScript builder stores the full URL as se:remoteUrl, and capability serialization sends
vendor-prefixed values. Grid copies that raw string into value and interpolates it into the added
warning whenever parsing or validation fails, without removing URI userinfo first.

javascript/selenium-webdriver/index.js[658-667]
javascript/selenium-webdriver/lib/webdriver.js[720-727]
java/src/org/openqa/selenium/grid/node/local/LocalNode.java[1329-1353]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Prevent credentials embedded in `se:remoteUrl` from being written to Grid logs when the URL cannot be used.

## Issue Context
The JavaScript builder advertises the complete configured server URL. Grid's invalid-value warning interpolates that raw capability after URI validation fails or rejects the scheme.

## Fix Focus Areas
- javascript/selenium-webdriver/index.js[661-664]
- java/src/org/openqa/selenium/grid/node/local/LocalNode.java[1329-1353]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
4. Deprecation bypasses project logger 📘 Rule violation ✧ Quality
Description
WebDriver#getBidi uses Node's util.deprecate instead of WebDriver.logger.deprecate and
supplies no unique deprecation ID. This bypasses the required standardized deprecation mechanism.
Code

javascript/selenium-webdriver/lib/webdriver.js[R1790-1792]

+WebDriver.prototype.getBidi = util.deprecate(function () {
+  return getBidiConnection(this)
+}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")
Evidence
PR Compliance 389235 requires all modified deprecation notices to use
WebDriver.logger.deprecate(...) with the old API, replacement API, and a non-empty id. The added
wrapper instead calls util.deprecate with only a message.

Rule 389235: Standardize deprecation notices using WebDriver.logger.deprecate
javascript/selenium-webdriver/lib/webdriver.js[1790-1792]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`WebDriver#getBidi` emits its deprecation through `util.deprecate` rather than `WebDriver.logger.deprecate`, and the notice has no unique ID.

## Issue Context
Keep the existing guidance to composed BiDi modules, but emit it through the project-standard deprecation logger with a stable, non-empty identifier.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1790-1792]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. getBidi return undocumented 📘 Rule violation ✧ Quality
Description
The public WebDriver#getBidi JSDoc has an @returns type but no description of the returned
value. Public API JSDoc requires a typed return tag with non-empty descriptive text.
Code

javascript/selenium-webdriver/lib/webdriver.js[1788]

+ * @returns {Promise<import('../bidi')>}
Evidence
PR Compliance 389257 requires a public JavaScript method returning a value to have one @return or
@returns tag containing both a type and a brief description. The added tag contains only the type.

Rule 389257: Document public API functions with complete JSDoc blocks
javascript/selenium-webdriver/lib/webdriver.js[1778-1788]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new JSDoc for public `WebDriver#getBidi` uses `@returns {Promise<import('../bidi')>}` without the required return-value description.

## Issue Context
Retain the existing type and add concise text explaining that the promise resolves to the session's BiDi connection.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1789]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Third-party file added 📘 Rule violation § Compliance
Description
The PR adds third_party/bazel/rules_ruby_windows_batch_crlf.patch, despite the checklist
prohibiting additions or modifications under third_party/. The underlying integration or vendoring
configuration must be changed outside that directory instead.
Code

third_party/bazel/rules_ruby_windows_batch_crlf.patch[1]

+diff --git a/ruby/private/utils.bzl b/ruby/private/utils.bzl
Evidence
PR Compliance 389269 disallows every added, removed, or modified path under third_party/. This PR
adds a 39-line file at such a path.

Rule 389269: Disallow modifications to third_party directory
third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new patch file is committed under `third_party/`, which is a prohibited path for direct additions or modifications.

## Issue Context
Move the required Windows batch handling to project-owned source or vendoring configuration outside `third_party/`, then remove this generated/vendor patch from the PR.

## Fix Focus Areas
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (1)
7. PR contains unrelated changes 📘 Rule violation ✧ Quality
Description
The diff spans hundreds of files across JavaScript, Java, .NET, Python, Ruby, Rust, build
infrastructure, protocol schemas, and dependencies, far beyond hiding the JavaScript BiDi
connection. It also changes unrelated user-visible policy such as the minimum Node.js version,
making the PR difficult to review or revert safely.
Code

javascript/selenium-webdriver/package.json[23]

+    "node": ">= 22.0.0"
Evidence
PR Compliance 389267 requires the diff to remain narrowly related to its stated purpose. The branch
includes an unrelated Node runtime increase, a broad release changelog roll-up, and a new
third-party Bazel patch in addition to extensive changes across other language bindings.

Rule 389267: Avoid large, cross-cutting changes in a single pull request
javascript/selenium-webdriver/package.json[3-51]
javascript/selenium-webdriver/CHANGES.md[1-20]
third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR includes a large collection of unrelated release, dependency, runtime-policy, protocol, and cross-language changes alongside the JavaScript BiDi change.

## Issue Context
Rebase the branch onto the intended target and retain only the narrowly related JavaScript BiDi implementation, documentation, build entries, and regression tests. Submit unrelated accumulated changes separately.

## Fix Focus Areas
- javascript/selenium-webdriver/package.json[3-51]
- javascript/selenium-webdriver/CHANGES.md[1-20]
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

Comment on lines +1790 to +1792
WebDriver.prototype.getBidi = util.deprecate(function () {
return getBidiConnection(this)
}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Deprecation bypasses project logger 📘 Rule violation ✧ Quality

WebDriver#getBidi uses Node's util.deprecate instead of WebDriver.logger.deprecate and
supplies no unique deprecation ID. This bypasses the required standardized deprecation mechanism.
Agent Prompt
## Issue description
`WebDriver#getBidi` emits its deprecation through `util.deprecate` rather than `WebDriver.logger.deprecate`, and the notice has no unique ID.

## Issue Context
Keep the existing guidance to composed BiDi modules, but emit it through the project-standard deprecation logger with a stable, non-empty identifier.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1790-1792]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

* `require('selenium-webdriver/bidi/network')`.
* @function
* @name WebDriver#getBidi
* @returns {Promise<import('../bidi')>}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. getbidi return undocumented 📘 Rule violation ✧ Quality

The public WebDriver#getBidi JSDoc has an @returns type but no description of the returned
value. Public API JSDoc requires a typed return tag with non-empty descriptive text.
Agent Prompt
## Issue description
The new JSDoc for public `WebDriver#getBidi` uses `@returns {Promise<import('../bidi')>}` without the required return-value description.

## Issue Context
Retain the existing type and add concise text explaining that the promise resolves to the session's BiDi connection.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1789]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@@ -0,0 +1,39 @@
diff --git a/ruby/private/utils.bzl b/ruby/private/utils.bzl

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Third-party file added 📘 Rule violation § Compliance

The PR adds third_party/bazel/rules_ruby_windows_batch_crlf.patch, despite the checklist
prohibiting additions or modifications under third_party/. The underlying integration or vendoring
configuration must be changed outside that directory instead.
Agent Prompt
## Issue description
A new patch file is committed under `third_party/`, which is a prohibited path for direct additions or modifications.

## Issue Context
Move the required Windows batch handling to project-owned source or vendoring configuration outside `third_party/`, then remove this generated/vendor patch from the PR.

## Fix Focus Areas
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

},
"engines": {
"node": ">= 20.0.0"
"node": ">= 22.0.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Pr contains unrelated changes 📘 Rule violation ✧ Quality

The diff spans hundreds of files across JavaScript, Java, .NET, Python, Ruby, Rust, build
infrastructure, protocol schemas, and dependencies, far beyond hiding the JavaScript BiDi
connection. It also changes unrelated user-visible policy such as the minimum Node.js version,
making the PR difficult to review or revert safely.
Agent Prompt
## Issue description
The PR includes a large collection of unrelated release, dependency, runtime-policy, protocol, and cross-language changes alongside the JavaScript BiDi change.

## Issue Context
Rebase the branch onto the intended target and retain only the narrowly related JavaScript BiDi implementation, documentation, build entries, and regression tests. Submit unrelated accumulated changes separately.

## Fix Focus Areas
- javascript/selenium-webdriver/package.json[3-51]
- javascript/selenium-webdriver/CHANGES.md[1-20]
- third_party/bazel/rules_ruby_windows_batch_crlf.patch[1-39]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1790 to +1792
WebDriver.prototype.getBidi = util.deprecate(function () {
return getBidiConnection(this)
}, 'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' + "require('selenium-webdriver/bidi/network'). See docs/decisions/17670-bidi-implementation-boundaries.md.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. Raw bidi remains exposed 🐞 Bug ≡ Correctness

Assigning getBidi to WebDriver.prototype leaves the raw transport publicly discoverable and
callable, contrary to the PR's stated boundary. Recommended composed modules still call
_driver.getBidi(), so ordinary module use also invokes the deprecated API and emits its warning.
Agent Prompt
## Issue description
Remove the raw BiDi transport accessor from the public `WebDriver` prototype and prevent composed BiDi modules from invoking a deprecated public API.

## Issue Context
`WebDriver.prototype.getBidi` still exposes the transport, while composed modules such as Network and Browser depend on it. Introduce an internal connection mechanism and migrate those modules before removing the prototype accessor.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[1778-1792]
- javascript/selenium-webdriver/lib/bidi_connection.js[38-55]
- javascript/selenium-webdriver/bidi/network.js[93-95]
- javascript/selenium-webdriver/bidi/browser.js[29-35]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +798 to +799
// Close the BiDi websocket connection, if one was ever opened
closeBidiConnection(this)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Bidi cleanup bypassed or unawaited 🐞 Bug ☼ Reliability

quit() reaches the added cleanup only when onQuit_ is absent, and even then it does not return
or await the asynchronous close promise. Consequently await driver.quit() can finish without
completing BiDi cleanup, while drivers with an onQuit_ callback skip explicit cleanup entirely.
Agent Prompt
## Issue description
Ensure WebDriver quit always performs and awaits BiDi connection cleanup, including when an `onQuit_` callback is configured.

## Issue Context
The finalizer returns early for `onQuit_`, and the new asynchronous close call is otherwise invoked without returning its promise. Browser-specific local drivers configure `onQuit_` to stop their services.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/webdriver.js[775-800]
- javascript/selenium-webdriver/lib/bidi_connection.js[68-79]
- javascript/selenium-webdriver/bidi/index.js[318-337]
- javascript/selenium-webdriver/chromium.js[640-654]
- javascript/selenium-webdriver/firefox.js[580-604]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1349 to +1351
String.format(
"Ignoring unusable se:remoteUrl '%s'; using %s for proxied URLs",
value, gridUri));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Remote credentials logged 🐞 Bug ⛨ Security

When se:remoteUrl is unusable, resolvePublicGridUri logs its complete untrusted value, including
any embedded username or password. JavaScript now sends the configured remote URL verbatim as this
capability, allowing malformed or unsupported credential-bearing URLs to disclose secrets in Grid
logs.
Agent Prompt
## Issue description
Prevent credentials embedded in `se:remoteUrl` from being written to Grid logs when the URL cannot be used.

## Issue Context
The JavaScript builder advertises the complete configured server URL. Grid's invalid-value warning interpolates that raw capability after URI validation fails or rejects the scheme.

## Fix Focus Areas
- javascript/selenium-webdriver/index.js[661-664]
- java/src/org/openqa/selenium/grid/node/local/LocalNode.java[1329-1353]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@pujagani pujagani closed this Aug 18, 2026

describe '#send_keys' do
it 'sends keys to the active element', pending_if: {browser: %i[safari safari_preview]} do
it 'sends keys to the active element', pending_if: {browser_family: :safari} do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. pending_if guards omit reasons 📘 Rule violation ▣ Testability

Multiple modified Ruby integration-test guards omit the mandatory reason, leaving skipped or
pending tests without an explicit explanation. This affects pending_if, skip_if, and flaky
guards across several integration specs.
Agent Prompt
## Issue description
Modified integration-test guards omit the required explicit `reason` value.

## Issue Context
Every integration guard that supports a reason must provide a string literal or numeric issue identifier explaining why the test is guarded.

## Fix Focus Areas
- rb/spec/integration/selenium/webdriver/action_builder_spec.rb[28-160]
- rb/spec/integration/selenium/webdriver/driver_spec.rb[33-356]
- rb/spec/integration/selenium/webdriver/element_spec.rb[32-351]
- rb/spec/integration/selenium/webdriver/fedcm_spec.rb[70-70]
- rb/spec/integration/selenium/webdriver/manager_spec.rb[82-166]
- rb/spec/integration/selenium/webdriver/navigation_spec.rb[25-25]
- rb/spec/integration/selenium/webdriver/target_locator_spec.rb[171-171]
- rb/spec/integration/selenium/webdriver/timeout_spec.rb[89-89]
- rb/spec/integration/selenium/webdriver/window_spec.rb[116-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

*
* @param {...string} paths The paths to the extension XPI files to install.
* @return {!Options} A self reference.
* @deprecated Use {@link Driver#installAddon} instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

2. addextensions lacks runtime warning 📘 Rule violation ◔ Observability

Options#addExtensions is newly documented as deprecated, but its body emits no warning naming the
method and replacement API. Callers therefore receive no runtime migration guidance as required for
deprecated APIs.
Agent Prompt
## Issue description
`Options#addExtensions` is marked deprecated only in JSDoc and emits no runtime deprecation warning.

## Issue Context
The warning should be emitted at most once, identify `Options#addExtensions`, and recommend `Driver#installAddon`. Use the project-standard deprecation mechanism rather than an ad-hoc print or log statement.

## Fix Focus Areas
- javascript/selenium-webdriver/firefox.js[315-324]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

if (pending === undefined) {
return
}
connections.delete(driver)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

3. Bidi reopens during shutdown 🐞 Bug ☼ Reliability

closeBidiConnection() deletes the cached entry before the existing connection finishes closing, so
concurrent BiDi access creates a replacement connection. That replacement is not tracked by the
active cleanup operation and can remain open after driver shutdown.
Agent Prompt
## Issue description
`closeBidiConnection()` removes the driver's cache entry before the pending connection has closed. A concurrent `getBidiConnection()` therefore creates a second websocket that is outside the active cleanup and may leak after shutdown.

## Issue Context
Preserve a closing/tombstone state for the driver so access cannot create another connection while shutdown is underway. Only clear lifecycle state when doing so cannot permit a connection to reopen for a quitting driver.

## Fix Focus Areas
- javascript/selenium-webdriver/lib/bidi_connection.js[38-42]
- javascript/selenium-webdriver/lib/bidi_connection.js[68-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review

Copy link
Copy Markdown
Contributor

Code review by qodo was updated up to the latest commit 6288b65

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-nodejs JavaScript Bindings

Projects

None yet

Development

Successfully merging this pull request may close these issues.