@allwright.dev/core 0.0.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 allwright contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,336 @@
1
+ # allwright
2
+
3
+ allwright is one automation engine for everything you test.
4
+
5
+ The long-term direction is a single system that can cover web, mobile, desktop, and API automation without forcing teams to stitch together a different tool for every surface. The project is designed so automation can feel consistent across the whole product, not fragmented by platform.
6
+
7
+ That direction also applies to extensibility: allwright should stay one engine at its core, while surface modules like `web`, `mobile-android`, `mobile-ios`, `desktop-mac`, `desktop-windows`, and `desktop-linux` can be installed separately as plugins instead of fragmenting the runtime into multiple engines.
8
+
9
+ Right now, allwright is being built in public and the browser automation engine is the first active layer. The current implementation is focused on a driverless Chrome control path backed by CDP and Chromium BiDi, with high-level client libraries for Rust, Go, Java, Python, and TypeScript/JavaScript.
10
+
11
+ ## Why allwright
12
+
13
+ - One engine instead of a pile of disconnected tools
14
+ - One automation model that can eventually span web, mobile, desktop, and API work
15
+ - One extensibility model where surface plugins plug into the core engine
16
+ - High-level browser and page APIs instead of raw transport plumbing
17
+ - Driverless browser control built around CDP and Chromium BiDi
18
+ - Shared contracts across the engine and all client stacks
19
+
20
+ ## Current Status
21
+
22
+ allwright is under active development and not positioned as a finished multi-surface platform yet.
23
+
24
+ The current stage is:
25
+
26
+ - the core product direction is broader than browser automation alone
27
+ - the first shipped implementation work is centered on the browser engine and its future plugin boundary
28
+ - the Rust workspace now separates a lightweight `allwright-core` from the installable `allwright` CLI and surface crates
29
+ - the `web` surface now ships as a separately installable runtime plugin library
30
+ - the other surface crates already exist as publishable boundaries, but only `web` is currently installable as a standalone runtime artifact
31
+ - the public API and internal architecture are still evolving as the project grows toward wider surface coverage
32
+
33
+ If you are evaluating the repo today, the clearest signal is the direction: allwright is aiming to become a unified automation engine, and browser automation is the first concrete step on that path.
34
+
35
+ ## Direction
36
+
37
+ allwright is being shaped around a simple idea: teams should not need one framework for web, another for mobile, another for desktop, and a separate story for API validation.
38
+
39
+ The project direction is to make those surfaces feel like one automation system:
40
+
41
+ - Web: real browser flows that click, type, and navigate like a person would
42
+ - Mobile: the same test logic extended toward native and hybrid apps
43
+ - Desktop: automation for full desktop application workflows
44
+ - API: backend checks that stay aligned with the same user-facing flows and data
45
+
46
+ That broader direction matters more than the current implementation footprint. The repo may be browser-first today, but the product purpose is cross-surface automation under one roof.
47
+
48
+ ## Extensibility Direction
49
+
50
+ allwright should remain a single engine, not a family of separate engines.
51
+
52
+ As the project grows into more surfaces, extensibility should follow a plugin model:
53
+
54
+ - the core engine stays responsible for lifecycle, sessions, transport, and the shared automation model
55
+ - surface modules such as `web`, `mobile-android`, `mobile-ios`, `desktop-mac`, `desktop-windows`, and `desktop-linux` should be attachable as plugins
56
+ - those plugins should be installable separately so users only take on the surfaces they need
57
+ - plugin boundaries should extend the engine instead of forcing client libraries to learn different runtimes
58
+
59
+ In practice, that means future architecture work should prefer a stable engine core with explicit extension points over splitting web, mobile, desktop, or API support into unrelated executables.
60
+
61
+ ## Plugin Ecosystem
62
+
63
+ For users, the intended install model is simple:
64
+
65
+ - install `allwright` once to get the CLI plus the lightweight engine core
66
+ - add only the surface plugins you need, starting with `web`
67
+ - keep one command-line entrypoint and one engine lifecycle, even as more surfaces arrive
68
+
69
+ Today, the plugin ecosystem looks like this:
70
+
71
+ - `allwright`: installable CLI package that starts the engine server and manages plugin installation
72
+ - `web`: the first installable runtime surface plugin today, loaded by the core at runtime
73
+ - `mobile-android`, `mobile-ios`, `desktop-mac`, `desktop-windows`, and `desktop-linux`: planned surface plugins with publishable crate boundaries, but not yet installable runtime artifacts
74
+
75
+ What `plugin install` means today:
76
+
77
+ - for `web`, it downloads the matching platform archive from GitHub Releases into the local allwright plugin directory and records the installed plugin in the manifest
78
+ - `allwright serve` always starts the engine server
79
+ - when `web` is installed, the core engine loads the installed `web` plugin library at runtime for browser/web commands
80
+ - when `web` is not installed, browser/web commands fail with a plugin-required error while the core server still runs
81
+ - the non-web surface crates are still intentionally behind this installability switch until their runtime binaries are ready
82
+
83
+ So the user-facing install model is now real for `web`, while the broader multi-surface plugin ecosystem is still being completed.
84
+
85
+ Release automation today:
86
+
87
+ - pushing a tag such as `vX.Y.Z` triggers the GitHub Actions release workflow
88
+ - that workflow publishes the root TypeScript package to npm as `@allwright.dev/core` using npm Trusted Publishing via GitHub Actions OIDC
89
+ - that workflow builds both the `allwright` CLI and `allwright-surface-web` plugin for the current release matrix and uploads the archives to the matching GitHub Release
90
+ - `allwright plugin install web` resolves the local OS and architecture, then downloads the matching release asset
91
+ - the release workflow syncs the Rust workspace version from the Git tag before building, so the tag is the release source of truth
92
+
93
+ ## Quick Start
94
+
95
+ Install the CLI:
96
+
97
+ ```bash
98
+ curl -fsSL https://raw.githubusercontent.com/allwright-dev/allwright/main/scripts/install.sh | bash
99
+ ```
100
+
101
+ or:
102
+
103
+ ```bash
104
+ wget -qO- https://raw.githubusercontent.com/allwright-dev/allwright/main/scripts/install.sh | bash
105
+ ```
106
+
107
+ If you already have the repo checked out:
108
+
109
+ ```bash
110
+ chmod +x ./scripts/install.sh
111
+ ./scripts/install.sh
112
+ ```
113
+
114
+ The installer prefers a writable directory that is already on `PATH`. If your shell still says `command not found: allwright`, export the printed install directory into `PATH` for the current session.
115
+
116
+ Windows PowerShell:
117
+
118
+ ```powershell
119
+ irm https://raw.githubusercontent.com/allwright-dev/allwright/main/scripts/install.ps1 | iex
120
+ ```
121
+
122
+ If you already have the repo checked out:
123
+
124
+ ```powershell
125
+ powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1
126
+ ```
127
+
128
+ Start the engine core through the CLI:
129
+
130
+ ```bash
131
+ allwright serve --listen-addr 127.0.0.1:50051
132
+ ```
133
+
134
+ List or install plugins:
135
+
136
+ ```bash
137
+ allwright plugin list
138
+ allwright plugin install web
139
+ ```
140
+
141
+ If you are working from the repo checkout instead:
142
+
143
+ ```bash
144
+ cargo run -p allwright -- serve --listen-addr 127.0.0.1:50051
145
+ cargo run -p allwright -- plugin list
146
+ cargo run -p allwright -- plugin install web
147
+ ```
148
+
149
+ Try the Rust playground against the running engine core:
150
+
151
+ ```bash
152
+ cargo run -p allwright-core --example playground -- --server-addr http://127.0.0.1:50051
153
+ ```
154
+
155
+ Open more tabs during the playground flow:
156
+
157
+ ```bash
158
+ cargo run -p allwright-core --example playground -- --server-addr http://127.0.0.1:50051 --tabs 3
159
+ ```
160
+
161
+ ## What You Can Try Today
162
+
163
+ Today’s working path is browser-focused, with a Rust-powered engine and high-level client libraries layered on top.
164
+
165
+ The practical path today is:
166
+
167
+ - use the `allwright` CLI as the installable entrypoint
168
+ - install the `web` plugin
169
+ - use the Rust, Go, Java, Python, or TypeScript clients against the running engine server
170
+
171
+ At the moment, the `web` runtime path is wired through the installable plugin model and loaded into the core at runtime. The other surface crates and split proto ownership are in place, while additional plugin runtime activation is still follow-up work.
172
+
173
+ ## Client Experience
174
+
175
+ allwright is designed around high-level browser objects rather than asking application code to manage raw gRPC connections.
176
+
177
+ Rust example:
178
+
179
+ ```rust
180
+ let browser = allwright::launch_chrome(Default::default()).await?;
181
+ let tab = browser.initial_tab()?;
182
+ tab.navigate("https://example.com").await?;
183
+ tab.click("a").await?;
184
+ browser.close().await?;
185
+ ```
186
+
187
+ Go example:
188
+
189
+ ```go
190
+ browser, err := allwright.LaunchChrome(ctx, allwright.LaunchOptions{})
191
+ tab := browser.InitialTab()
192
+ _, err = tab.Navigate(ctx, "https://example.com")
193
+ _, err = tab.Click(ctx, "a")
194
+ err = browser.Close(ctx)
195
+ ```
196
+
197
+ TypeScript example:
198
+
199
+ ```ts
200
+ import { chromium } from "./src/index.js";
201
+
202
+ const browser = await chromium.launch({});
203
+ const page = browser.page();
204
+ await page.goto("https://example.com");
205
+ await page.click("a");
206
+ await browser.close();
207
+ ```
208
+
209
+ ## Repository Guide
210
+
211
+ - `rust/allwright`: lightweight `allwright-core` Rust package with the client API, proto bindings, and gRPC engine core
212
+ - `rust/allwright-cli`: installable `allwright` CLI package that depends on `allwright-core` and installs supported plugins
213
+ - `rust/allwright-plugin-sdk`: shared plugin traits and surface metadata
214
+ - `rust/allwright-surface-web`: publishable `web` surface crate that ships the first standalone runtime plugin library
215
+ - `rust/allwright-surface-mobile`: shared mobile surface abstractions
216
+ - `rust/allwright-surface-mobile-android`: publishable `mobile-android` surface crate
217
+ - `rust/allwright-surface-mobile-ios`: publishable `mobile-ios` surface crate
218
+ - `rust/allwright-surface-desktop`: shared desktop surface abstractions
219
+ - `rust/allwright-surface-desktop-mac`: publishable `desktop-mac` surface crate
220
+ - `rust/allwright-surface-desktop-windows`: publishable `desktop-windows` surface crate
221
+ - `rust/allwright-surface-desktop-linux`: publishable `desktop-linux` surface crate
222
+ - `go/`: Go client and Go playground
223
+ - `java/`: Java client project
224
+ - `python/`: Python client package
225
+ - `typescript/`: TypeScript/JavaScript client package and playground
226
+ - `proto/`: shared protobuf and gRPC contracts
227
+ The root service entrypoint remains `proto/engine/v1/engine.proto`, while shared core messages now live under `proto/core/v1/` and the web surface messages now live under `proto/surfaces/web/v1/`.
228
+ - `allwright-dev/`: public website project for `allwright.dev`
229
+
230
+ ## Development Notes
231
+
232
+ - The engine currently runs as a gRPC server.
233
+ - The current implementation focus is browser automation, but the product direction is wider.
234
+ - Installing the `allwright` package is intended to deliver the CLI plus the lightweight engine core together.
235
+ - The project should keep a single engine core even as surface modules become separately installable plugins.
236
+ - The `web` surface plugin is now installable through the CLI via GitHub Release downloads and is loaded by the core engine at runtime.
237
+ - The remaining surface plugins are still intentionally disabled as install targets until their runtime binaries exist.
238
+ - The Rust workspace version is synced from the release tag during GitHub release builds.
239
+ - The browser control path is intended to stay driverless.
240
+ - The repo uses shared proto contracts across all supported client stacks.
241
+ - Bun is the preferred local workflow for the TypeScript stack and the `allwright-dev/` site.
242
+
243
+ ## Releasing Plugins
244
+
245
+ Create and push a version tag:
246
+
247
+ ```bash
248
+ git tag vX.Y.Z
249
+ git push origin vX.Y.Z
250
+ ```
251
+
252
+ That tag triggers `.github/workflows/release-surface-plugins.yml`, which builds and uploads the current web plugin archives for:
253
+
254
+ - `@allwright.dev/core` publish to npm after syncing `package.json` from the tag
255
+ - `allwright` CLI archives for the current OS matrix
256
+ - `allwright-surface-web` plugin archives for the current OS matrix
257
+ - crates.io publish for the Rust `web` profile after syncing every crate version from the tag
258
+
259
+ - Linux `x86_64-unknown-linux-gnu`
260
+ - Windows `x86_64-pc-windows-msvc`
261
+ - macOS `aarch64-apple-darwin`
262
+
263
+ Configure the `CARGO_REGISTRY_TOKEN` repository secret before pushing a release tag if you want the crates.io publish job to succeed.
264
+ The release workflow also sets `CARGO_PUBLISH_ALLOW_DIRTY=1` because it syncs crate versions from the tag inside CI before calling `cargo publish`.
265
+ Configure npm Trusted Publishing for `@allwright.dev/core` on npmjs.com before pushing a release tag:
266
+
267
+ - provider: `GitHub Actions`
268
+ - organization or user: `allwright-dev`
269
+ - repository: `allwright`
270
+ - workflow filename: `release-surface-plugins.yml`
271
+ - allowed action: `npm publish`
272
+
273
+ The npm publish job uses GitHub-hosted runners and OIDC instead of an `NPM_TOKEN`, which avoids bypass-2FA tokens entirely.
274
+
275
+ ## Installer Scripts
276
+
277
+ - `scripts/install.sh`: installs the latest or requested `allwright` CLI release on Linux and macOS
278
+ - `scripts/install.ps1`: installs the latest or requested `allwright` CLI release on Windows PowerShell
279
+ - `scripts/sync-version.sh`: syncs the Rust workspace and internal crate versions from a release version string such as `X.Y.Z`
280
+ - `scripts/sync-npm-version.sh`: syncs the root npm package version from a release version string such as `X.Y.Z`
281
+ - users do not need to clone the repo; both scripts can be run directly from GitHub with `curl`, `wget`, or PowerShell `irm`
282
+
283
+ Both scripts support:
284
+
285
+ - `ALLWRIGHT_VERSION` to pin a specific release tag such as `vX.Y.Z`
286
+ - `ALLWRIGHT_INSTALL_DIR` to override the destination directory
287
+ - `ALLWRIGHT_REPOSITORY` to target a fork or alternate GitHub repository
288
+
289
+ For repo-specific contribution guidance, see [CONTRIBUTING.md](CONTRIBUTING.md).
290
+
291
+ For AI handoff and deeper repo conventions, see [Codex.md](Codex.md).
292
+
293
+ ## Running Other Stacks
294
+
295
+ Go playground:
296
+
297
+ ```bash
298
+ cd go
299
+ go run ./examples/playground --server-addr 127.0.0.1:50051
300
+ ```
301
+
302
+ TypeScript build:
303
+
304
+ ```bash
305
+ bun install
306
+ npm run build
307
+ ```
308
+
309
+ TypeScript playground:
310
+
311
+ ```bash
312
+ bun run typescript/examples/playground.ts --server-addr 127.0.0.1:50051
313
+ ```
314
+
315
+ ## Testing
316
+
317
+ Rust:
318
+
319
+ ```bash
320
+ cargo test
321
+ ```
322
+
323
+ Go:
324
+
325
+ ```bash
326
+ cd go
327
+ go test ./...
328
+ ```
329
+
330
+ ## Contributing
331
+
332
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
333
+
334
+ ## License
335
+
336
+ This project is licensed under the MIT License. See [LICENSE](LICENSE).
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@allwright.dev/core",
3
+ "version": "0.0.1",
4
+ "description": "High-level TypeScript client for the allwright automation engine.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/allwright-dev/allwright.git"
10
+ },
11
+ "homepage": "https://allwright.dev",
12
+ "bugs": {
13
+ "url": "https://github.com/allwright-dev/allwright/issues"
14
+ },
15
+ "keywords": [
16
+ "automation",
17
+ "browser",
18
+ "grpc",
19
+ "testing",
20
+ "typescript"
21
+ ],
22
+ "packageManager": "bun@1.2.20",
23
+ "main": "./typescript/dist/index.js",
24
+ "types": "./typescript/dist/index.d.ts",
25
+ "exports": {
26
+ ".": {
27
+ "types": "./typescript/dist/index.d.ts",
28
+ "import": "./typescript/dist/index.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "typescript/dist",
33
+ "proto",
34
+ "README.md",
35
+ "LICENSE"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p typescript/tsconfig.json",
42
+ "example:playground": "bun run typescript/examples/playground.ts",
43
+ "prepublishOnly": "npm run build"
44
+ },
45
+ "dependencies": {
46
+ "@grpc/grpc-js": "^1.14.0",
47
+ "@grpc/proto-loader": "^0.8.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^24.4.0",
51
+ "typescript": "^5.9.2"
52
+ }
53
+ }
@@ -0,0 +1,55 @@
1
+ syntax = "proto3";
2
+
3
+ package allwright.engine.v1;
4
+ option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
5
+
6
+ import "core/v1/common.proto";
7
+ import "surfaces/web/v1/web.proto";
8
+
9
+ message BrowserSessionCommand {
10
+ oneof command {
11
+ LaunchChromeCommand launch_chrome = 1;
12
+ OpenTabCommand open_tab = 2;
13
+ SessionPingCommand ping = 3;
14
+ CloseBrowserSessionCommand close = 4;
15
+ }
16
+ }
17
+
18
+ message OpenTabCommand {
19
+ optional CommandRetryOptions retry_options = 1;
20
+ }
21
+
22
+ message SessionPingCommand {
23
+ string message = 1;
24
+ }
25
+
26
+ message CloseBrowserSessionCommand {}
27
+
28
+ message BrowserSessionEvent {
29
+ string session_id = 1;
30
+
31
+ oneof event {
32
+ ChromeLaunchedEvent chrome_launched = 2;
33
+ TabOpenedEvent tab_opened = 3;
34
+ SessionPongEvent pong = 4;
35
+ BrowserSessionClosedEvent closed = 5;
36
+ BrowserSessionErrorEvent error = 6;
37
+ }
38
+ }
39
+
40
+ message TabOpenedEvent {
41
+ string tab_session_id = 1;
42
+ string note = 2;
43
+ }
44
+
45
+ message SessionPongEvent {
46
+ string message = 1;
47
+ }
48
+
49
+ message BrowserSessionClosedEvent {
50
+ string reason = 1;
51
+ }
52
+
53
+ message BrowserSessionErrorEvent {
54
+ string message = 1;
55
+ }
@@ -0,0 +1,15 @@
1
+ syntax = "proto3";
2
+
3
+ package allwright.engine.v1;
4
+ option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
5
+
6
+ message PingRequest {}
7
+
8
+ message PingResponse {
9
+ string message = 1;
10
+ }
11
+
12
+ message CommandRetryOptions {
13
+ optional uint32 timeout_ms = 1;
14
+ optional uint32 retry_interval_ms = 2;
15
+ }
@@ -0,0 +1,72 @@
1
+ syntax = "proto3";
2
+
3
+ package allwright.engine.v1;
4
+ option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
5
+
6
+ import "surfaces/web/v1/web.proto";
7
+
8
+ message TabSessionCommand {
9
+ string browser_session_id = 1;
10
+ string tab_session_id = 2;
11
+
12
+ oneof command {
13
+ TabSessionPingCommand ping = 3;
14
+ CloseTabSessionCommand close = 4;
15
+ NavigateTabCommand navigate = 5;
16
+ ClickElementCommand click_element = 6;
17
+ CountElementsCommand count_elements = 7;
18
+ HighlightElementsCommand highlight_elements = 8;
19
+ FocusElementCommand focus_element = 9;
20
+ FillElementCommand fill_element = 10;
21
+ HoverElementCommand hover_element = 11;
22
+ PressKeyCommand press_key = 12;
23
+ GetTextContentCommand get_text_content = 13;
24
+ GetInnerTextCommand get_inner_text = 14;
25
+ WaitForSelectorCommand wait_for_selector = 15;
26
+ }
27
+ }
28
+
29
+ message TabSessionPingCommand {
30
+ string message = 1;
31
+ }
32
+
33
+ message CloseTabSessionCommand {}
34
+
35
+ message TabSessionEvent {
36
+ string tab_session_id = 1;
37
+
38
+ oneof event {
39
+ TabSessionAttachedEvent attached = 2;
40
+ TabSessionPongEvent pong = 3;
41
+ TabSessionClosedEvent closed = 4;
42
+ TabSessionErrorEvent error = 5;
43
+ TabNavigatedEvent navigated = 6;
44
+ ChromiumBidiInjectionEvent chromium_bidi_injection = 7;
45
+ ElementClickedEvent element_clicked = 8;
46
+ ElementCountedEvent element_counted = 9;
47
+ ElementsHighlightedEvent elements_highlighted = 10;
48
+ ElementFocusedEvent element_focused = 11;
49
+ ElementFilledEvent element_filled = 12;
50
+ ElementHoveredEvent element_hovered = 13;
51
+ KeyPressedEvent key_pressed = 14;
52
+ TextContentResolvedEvent text_content_resolved = 15;
53
+ InnerTextResolvedEvent inner_text_resolved = 16;
54
+ SelectorWaitSatisfiedEvent selector_wait_satisfied = 17;
55
+ }
56
+ }
57
+
58
+ message TabSessionAttachedEvent {
59
+ string note = 1;
60
+ }
61
+
62
+ message TabSessionPongEvent {
63
+ string message = 1;
64
+ }
65
+
66
+ message TabSessionClosedEvent {
67
+ string reason = 1;
68
+ }
69
+
70
+ message TabSessionErrorEvent {
71
+ string message = 1;
72
+ }
@@ -0,0 +1,14 @@
1
+ syntax = "proto3";
2
+
3
+ package allwright.engine.v1;
4
+ option go_package = "allwright.dev/gen/allwright/engine/v1;enginev1";
5
+
6
+ import "core/v1/browser.proto";
7
+ import "core/v1/common.proto";
8
+ import "core/v1/tab.proto";
9
+
10
+ service EngineService {
11
+ rpc Ping(PingRequest) returns (PingResponse);
12
+ rpc BrowserSession(stream BrowserSessionCommand) returns (stream BrowserSessionEvent);
13
+ rpc TabSession(stream TabSessionCommand) returns (stream TabSessionEvent);
14
+ }