@memberjunction/remote-browser-base 0.0.1 → 5.42.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.
package/README.md CHANGED
@@ -1,45 +1,162 @@
1
1
  # @memberjunction/remote-browser-base
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
4
-
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
6
-
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
8
-
9
- ## Purpose
10
-
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@memberjunction/remote-browser-base`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
-
16
- ## What is OIDC Trusted Publishing?
17
-
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
-
20
- ## Setup Instructions
21
-
22
- To properly configure OIDC trusted publishing for this package:
23
-
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
28
-
29
- ## DO NOT USE THIS PACKAGE
30
-
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
36
-
37
- ## More Information
38
-
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
42
-
43
- ---
44
-
45
- **Maintained for OIDC setup purposes only**
3
+ Universal (client **and** server), **metadata-only** base layer for the MemberJunction **Remote
4
+ Browser channel** — the in-house channel where an agent **spins up a real Chromium browser, drives it
5
+ over CDP while it talks, screen-shares it live, and can hand the wheel to a human** (a sales agent
6
+ running an interactive product demo, a support agent walking a user through a UI, a trainer agent that
7
+ demonstrates a task then watches you try).
8
+
9
+ This package holds everything the Remote Browser channel needs that carries **no execution** — the
10
+ backend-provider registry cache, the abstract `BaseRemoteBrowserProvider` driver contract, the live
11
+ CDP-backed `IRemoteBrowserSession` interface plus its self-contained action / input / frame types, the
12
+ control-mode/strategy helpers, and the capability-error type. It is the base half of the
13
+ `RemoteBrowserEngineBase` / `RemoteBrowserEngine` pair, exactly mirroring how
14
+ [`@memberjunction/ai-bridge-base`](../../RealtimeBridge/Base)'s `BaseRealtimeBridge` /
15
+ `AIBridgeEngineBase` underpin the bridge server tier. The server tier that actually *runs* a
16
+ remote-browser session (CDP-connect via `@memberjunction/computer-use`, the live sessions, control
17
+ arbitration, the viewport→screen-track encode) lives in the Server package; the five backend drivers
18
+ (Self-Hosted Chrome, Browserbase, Steel, Browserless, Hyperbrowser) live alongside it.
19
+
20
+ > See the architecture plan at `/plans/realtime/realtime-bridges-architecture.md` §4d (the Remote
21
+ > Browser channel) and §4d-i (the option-3 build decision: one CDP primitive, pluggable backends, the
22
+ > MJ way) for the full design.
23
+
24
+ ## What's in the box
25
+
26
+ | Export | Purpose |
27
+ |---|---|
28
+ | `BaseRemoteBrowserProvider` | The abstract driver. A concrete backend (`BrowserbaseRemoteBrowser`, `SelfHostedChromeRemoteBrowser`, …) implements only the irreducibly backend-specific primitives (`Connect` → returns a live `IRemoteBrowserSession`, `Disconnect`). Drivers self-register via `@RegisterClass(BaseRemoteBrowserProvider, '<X>RemoteBrowser')`. |
29
+ | `RemoteBrowserEngineBase` | A `BaseEngine` singleton caching the backend registry (`MJ: AI Remote Browser Providers` + capability flags) with synchronous resolution helpers (`ProviderByName`, `ProviderByDriverClass`, `ActiveProviders`, `FeaturesFor`). No execution. |
30
+ | `IRemoteBrowserSession` | The live-session contract — core CDP methods (`GetCdpEndpoint`, `Navigate`, `ExecuteAction`, `CaptureScreenshot`, `GetCurrentUrl`, `Close`), capability-gated ones (`GetLiveViewUrl`, `StartScreencast`/`StopScreencast`, `RouteHumanInput`, `InvokeNativeAIControl`), and the **goal-driven** `RunComputerUseGoal(goal, options)` (set a high-level goal; computer-use plans + executes it — see [§ Goal-driven control](#goal-driven-control-set-a-goal-not-clicks)). |
31
+ | Action / input / frame types | `RemoteBrowserAction` (discriminated union: navigate / click / type / key / scroll / back / forward / wait), `RemoteBrowserActionResult`, `RemoteBrowserScreencastFrame`, `RemoteBrowserHumanInput` (pointer-move / pointer-click / key) — all strongly typed, **self-contained** (no Playwright / computer-use dependency). |
32
+ | Goal types | `RunComputerUseGoalOptions` (transport-neutral: `StartUrl`, `MaxSteps`, model overrides, model-blind `Context`, `OnProgress`, `Signal`, `ContextUser`) + `RemoteBrowserGoalResult` (`Success` / `Strategy` / `Status` / `StepCount` / `Detail`) — carry **no** computer-use SDK types, so model selection stays in the CDP/engine tier. |
33
+ | `RemoteBrowserControlMode` + `RemoteBrowserControlStrategy` + helpers | `isControlModeSupported(mode, features)`, `resolveControlStrategy(features, preferred?)` — pure, capability-aware helpers. |
34
+ | `RemoteBrowserCapabilityNotSupportedError` | The defense-in-depth error thrown when a capability-gated method is called on a backend that doesn't support it (carries `FeatureName` + `ProviderName`). |
35
+ | `IRemoteBrowserProviderFeatures` + `featuresOf` + `KNOWN_REMOTE_BROWSER_FEATURE_KEYS` | Typed alias of the generated `MJ: AI Remote Browser Providers.SupportedFeatures` shape, a null-safe reader, and the full key list for validators/iteration. |
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install @memberjunction/remote-browser-base
41
+ ```
42
+
43
+ ## The universal CDP substrate
44
+
45
+ Every backend — self-hosted headless Chrome **and** every browser-as-a-service (Browserbase, Steel,
46
+ Browserless, Hyperbrowser) — exposes a **Chrome DevTools Protocol** endpoint. The Remote Browser
47
+ subsystem standardizes on **CDP-connect** as its one primitive: the server engine connects over CDP
48
+ (reusing `@memberjunction/computer-use`'s `PlaywrightBrowserAdapter`) and drives a clean
49
+ click/type/scroll/screenshot vocabulary — no hand-rolled raw CDP. This Base package itself stays
50
+ dependency-light and universal precisely because it only *declares* the `IRemoteBrowserSession`
51
+ contract both sides agree on; the Playwright/CDP machinery lives in the server tier.
52
+
53
+ ## The driver contract
54
+
55
+ `BaseRemoteBrowserProvider` is intentionally tiny — two abstract methods:
56
+
57
+ - **`Connect(ctx)`** — open or attach a browser over CDP and return the live `IRemoteBrowserSession`.
58
+ Call `this.applyContext(ctx)` first to capture the backend's capability flags + name.
59
+ - **`Disconnect()`** — release the driver's own backend resources (tear down the container, end the
60
+ service session).
61
+
62
+ Protected helpers for driver authors: `applyContext(ctx)` (capture features + provider name — call it
63
+ first in `Connect`), `RequireFeature(flag)` (re-assert a capability flag before gated work), and
64
+ `notSupported(name)` (build the standard error).
65
+
66
+ ```typescript
67
+ import { RegisterClass } from '@memberjunction/global';
68
+ import {
69
+ BaseRemoteBrowserProvider,
70
+ IRemoteBrowserSession,
71
+ RemoteBrowserProviderContext,
72
+ } from '@memberjunction/remote-browser-base';
73
+
74
+ @RegisterClass(BaseRemoteBrowserProvider, 'BrowserbaseRemoteBrowser')
75
+ export class BrowserbaseRemoteBrowser extends BaseRemoteBrowserProvider {
76
+ public async Connect(ctx: RemoteBrowserProviderContext): Promise<IRemoteBrowserSession> {
77
+ this.applyContext(ctx); // capture features + provider name (do this first)
78
+ // ...request a session from the backend, obtain its CDP endpoint, and return a session that
79
+ // implements IRemoteBrowserSession (the actual CDP wiring lives in the server tier).
80
+ throw new Error('implemented in the server / driver package');
81
+ }
82
+
83
+ public async Disconnect(): Promise<void> {
84
+ // ...release the backend session.
85
+ }
86
+ }
87
+ ```
88
+
89
+ A provider row whose `DriverClass = 'BrowserbaseRemoteBrowser'` resolves to this driver through the
90
+ `ClassFactory`: `MJGlobal.ClassFactory.CreateInstance(BaseRemoteBrowserProvider, provider.DriverClass)`.
91
+
92
+ ## Capability gating (two layers, defense-in-depth)
93
+
94
+ A backend's capabilities live in the `MJ: AI Remote Browser Providers.SupportedFeatures` JSON column,
95
+ strongly typed via `IRemoteBrowserProviderFeatures`. It holds **control/transport** concerns only:
96
+
97
+ - **Control substrate & strategies** — `RawCdpControl` (the universal substrate), `NativeAIControl` (a
98
+ backend's own AI-control harness, e.g. Stagehand).
99
+ - **Viewing & collaboration** — `LiveView`, `HumanTakeover`, `ScreenStreaming`.
100
+ - **Operational** — `Stealth`, `ProxyEgress`, `SessionRecording`, `PersistentContext`, `MultiTab`,
101
+ `FileDownloads`, `CaptchaSolving`.
102
+
103
+ The engine checks the matching flag **first** and never calls a capability-gated session method whose
104
+ feature is off; the capability-gated method's own throw is the **second**, defense-in-depth layer for
105
+ when a metadata flag lies or a caller bypasses the gate. New backend features need no schema migration
106
+ — extend the interface. Read flags via `provider.SupportedFeaturesObject` (or the null-safe
107
+ `featuresOf(provider)`), never `JSON.parse(provider.SupportedFeatures)`.
108
+
109
+ ## Control modes vs. control strategies
110
+
111
+ These are **orthogonal** axes — keep them straight:
112
+
113
+ | Axis | Type | Meaning |
114
+ |---|---|---|
115
+ | **Control mode** | `RemoteBrowserControlMode` | *Who* drives: `AgentOnly` (no takeover) · `ViewOnly` (humans watch — needs `LiveView`) · `Collaborative` (a human can grab the wheel — needs `LiveView` + `HumanTakeover`). A per-provider `DefaultControlMode`, overridable per-channel and at runtime. |
116
+ | **Control strategy** | `RemoteBrowserControlStrategy` | *How* the agent decides what to do: `ComputerUse` (MJ's perception→action loop over CDP — the universal default) · `NativeAI` (delegate intents to the backend's own harness — needs `NativeAIControl`). |
117
+
118
+ ```typescript
119
+ import {
120
+ isControlModeSupported,
121
+ resolveControlStrategy,
122
+ } from '@memberjunction/remote-browser-base';
123
+
124
+ const features = provider.SupportedFeaturesObject ?? {};
125
+
126
+ isControlModeSupported('Collaborative', features); // true only if LiveView && HumanTakeover
127
+ resolveControlStrategy(features); // 'NativeAI' iff features.NativeAIControl, else 'ComputerUse'
128
+ resolveControlStrategy(features, 'ComputerUse'); // always 'ComputerUse' — explicit ComputerUse pins the universal loop
129
+ ```
130
+
131
+ ## Goal-driven control (set a goal, not clicks)
132
+
133
+ Beyond driving the page one action at a time, a caller can hand the session a **high-level goal** —
134
+ *"log into this site and download the latest invoice"* — and let MJ's **computer-use** loop plan and
135
+ execute it. `IRemoteBrowserSession.RunComputerUseGoal(goal, options)` is that contract; the
136
+ `resolveControlStrategy` above decides whether the goal runs through the universal `ComputerUse` loop or
137
+ is delegated to a backend's `NativeAI` harness. This Base package declares only the **transport-neutral**
138
+ types (`RunComputerUseGoalOptions`, `RemoteBrowserGoalResult`) — the actual loop, model selection, and the
139
+ **model-blind credential injection** (`{{label}}` references resolved at the keystroke boundary, never seen
140
+ by any model) live in the CDP + server tiers. See the [Remote Browser Channel Guide §9](../../../../guides/REMOTE_BROWSER_GUIDE.md).
141
+
142
+ ## How it composes
143
+
144
+ | Layer | Package | Role |
145
+ |---|---|---|
146
+ | **Registry cache + abstract driver + session contract + control helpers** | **`@memberjunction/remote-browser-base`** (this) | provider cache, `BaseRemoteBrowserProvider`, `IRemoteBrowserSession`, action/input types, control mode/strategy, capability types |
147
+ | Coordination + execution (CDP-connect, control arbiter, screen-track encode) | server package | `RemoteBrowserEngine` (composes this base), live sessions, the `RemoteBrowserChannel` |
148
+ | Browser control vocabulary | [`@memberjunction/computer-use`](../../ComputerUse) | the `PlaywrightBrowserAdapter` the server tier uses to drive CDP — **not** a dependency of this base |
149
+
150
+ The server `RemoteBrowserEngine` **composes** (does not extend) `RemoteBrowserEngineBase`, so the
151
+ startup manager warms exactly one `BaseEngine` cache — the same composition-over-inheritance pattern
152
+ `AIBridgeEngine` uses over `AIBridgeEngineBase`.
153
+
154
+ ## Further reading
155
+
156
+ - **Architecture plan:** `/plans/realtime/realtime-bridges-architecture.md` §4d / §4d-i.
157
+ - **Sibling subsystem:** [`@memberjunction/ai-bridge-base`](../../RealtimeBridge/Base/README.md) — the
158
+ realtime media bridge this package mirrors in structure and style.
159
+
160
+ ## License
161
+
162
+ ISC
@@ -0,0 +1,149 @@
1
+ import { UserInfo } from '@memberjunction/core';
2
+ import { IRemoteBrowserProviderFeatures } from './remote-browser-features.js';
3
+ import { RemoteBrowserControlMode } from './control.js';
4
+ import { IRemoteBrowserSession } from './remote-browser-session.js';
5
+ import { RemoteBrowserCapabilityNotSupportedError } from './capability-errors.js';
6
+ /**
7
+ * The set of host services a remote-browser driver sees while running.
8
+ *
9
+ * The engine (`RemoteBrowserEngine`, server package) constructs this and hands it to {@link
10
+ * BaseRemoteBrowserProvider.Connect}. It is deliberately small: a driver should depend only on what it
11
+ * truly needs, and everything richer (the realtime session, the channel plane, the control arbiter)
12
+ * is wired by the engine AROUND the driver, not handed into it. This keeps drivers thin and
13
+ * backend-focused.
14
+ */
15
+ export interface RemoteBrowserProviderContext {
16
+ /**
17
+ * The backend's `SupportedFeatures` — the capability flags the engine and the driver's
18
+ * `RequireFeature` guard gate on. Sourced from the provider metadata row's typed
19
+ * `SupportedFeaturesObject` accessor (never `JSON.parse`).
20
+ */
21
+ Features: IRemoteBrowserProviderFeatures;
22
+ /**
23
+ * The backend's display name (e.g. `'Browserbase'`, `'Self-Hosted Chrome'`), used in
24
+ * capability-error messages and logging.
25
+ */
26
+ ProviderName: string;
27
+ /**
28
+ * How the browser is hosted: `'SelfHost'` (MJ orchestrates a lightweight headless-Chrome
29
+ * container we connect to over CDP) or `'Service'` (a browser-as-a-service exposes a CDP connect
30
+ * endpoint). Mirrors `MJ: AI Remote Browser Providers.ProviderType`.
31
+ */
32
+ ProviderType: 'SelfHost' | 'Service';
33
+ /**
34
+ * The resolved control mode for this session (`AgentOnly` / `ViewOnly` / `Collaborative`) — the
35
+ * provider default overridden per-channel / at runtime. The driver uses it to decide whether to
36
+ * stand up live-view / takeover plumbing on connect.
37
+ */
38
+ ControlMode: RemoteBrowserControlMode;
39
+ /**
40
+ * Opaque, backend-specific connection configuration (resolved credential references, region,
41
+ * Chrome image, proxy settings, …) as a parsed JSON object. Typed as a record of unknown values
42
+ * rather than `any` so it stays inspectable without losing type-safety at the boundary; the
43
+ * driver narrows the fields it understands. Never carries inline secrets — credentials resolve
44
+ * through MJ's credential system upstream and arrive here already resolved or as references.
45
+ */
46
+ Configuration?: Record<string, unknown>;
47
+ /**
48
+ * The MJ user the remote-browser session runs as. Every session is owned by a user and fully
49
+ * audited; the driver uses this for any server-side operations that require a context user.
50
+ */
51
+ ContextUser?: UserInfo;
52
+ }
53
+ /**
54
+ * Abstract base class for a **Remote Browser** provider driver — a pluggable backend that opens (or
55
+ * attaches to) a real Chromium browser over the Chrome DevTools Protocol and returns a live
56
+ * {@link IRemoteBrowserSession} the agent drives.
57
+ *
58
+ * This is the sibling of `BaseRealtimeBridge`: the Remote Browser channel is built exactly like the
59
+ * bridge subsystem (registry table + base driver + EngineBase/Engine pair + pluggable backends). A
60
+ * concrete driver (`SelfHostedChromeRemoteBrowser`, `BrowserbaseRemoteBrowser`, …) implements only the
61
+ * irreducibly backend-specific primitives — everything generic (control arbitration, the
62
+ * viewport→screen-track encode, session bookkeeping) lives in the server engine above. Drivers
63
+ * self-register with the MemberJunction `ClassFactory` — e.g.
64
+ * `@RegisterClass(BaseRemoteBrowserProvider, 'BrowserbaseRemoteBrowser')`. The base class itself is
65
+ * abstract and unregistered; the engine resolves a driver via
66
+ * `MJGlobal.ClassFactory.CreateInstance(BaseRemoteBrowserProvider, provider.DriverClass)`.
67
+ *
68
+ * **Capability gating (two layers, defense-in-depth).** The engine FIRST checks a provider's
69
+ * `SupportedFeatures` flag and never calls a session method whose feature is off. The driver's own
70
+ * capability-gated work is the SECOND layer: it calls {@link BaseRemoteBrowserProvider.RequireFeature}
71
+ * (or builds an error via {@link BaseRemoteBrowserProvider.notSupported}) so a metadata flag that
72
+ * lied — or a caller that bypassed the gate — fails loudly rather than silently degrading.
73
+ *
74
+ * **Universal CDP substrate.** Every backend (self-hosted Chrome and every browser-as-a-service)
75
+ * exposes a CDP endpoint; the engine standardizes on CDP-connect (reusing `@memberjunction/computer-use`
76
+ * server-side) so this Base package itself stays dependency-light and universal.
77
+ *
78
+ * @see `/plans/realtime/realtime-bridges-architecture.md` §4d / §4d-i.
79
+ * @abstract
80
+ */
81
+ export declare abstract class BaseRemoteBrowserProvider {
82
+ /**
83
+ * The capability flags for the backend this driver instance serves. Populated from the
84
+ * {@link RemoteBrowserProviderContext} at {@link BaseRemoteBrowserProvider.Connect} time (call
85
+ * `this.applyContext(ctx)` first). Drives {@link BaseRemoteBrowserProvider.RequireFeature}.
86
+ */
87
+ protected features: IRemoteBrowserProviderFeatures;
88
+ /**
89
+ * The backend's display name for this driver instance, used in capability-error messages.
90
+ * Populated from the {@link RemoteBrowserProviderContext}; falls back to the driver class name.
91
+ */
92
+ protected providerName: string;
93
+ /**
94
+ * The backend's supported-feature flags for this driver instance.
95
+ *
96
+ * Read-only accessor over the internally-held {@link BaseRemoteBrowserProvider.features}. The
97
+ * engine consults this (and the underlying provider metadata) to decide which capability-gated
98
+ * session methods are safe to call; a driver consults it via
99
+ * {@link BaseRemoteBrowserProvider.RequireFeature}.
100
+ */
101
+ get Features(): IRemoteBrowserProviderFeatures;
102
+ /**
103
+ * Opens or attaches a browser session on the backend over CDP and returns the live handle.
104
+ *
105
+ * Implementations must normalize the backend's capability flags + provider name into the
106
+ * instance (typically by calling `this.applyContext(ctx)` first), then establish the CDP-connected
107
+ * browser and return an {@link IRemoteBrowserSession} wrapping it.
108
+ *
109
+ * @param ctx The host services and connection parameters for this session.
110
+ * @returns A promise resolving to the live remote-browser session handle.
111
+ */
112
+ abstract Connect(ctx: RemoteBrowserProviderContext): Promise<IRemoteBrowserSession>;
113
+ /**
114
+ * Tears down / releases the backend session this driver opened (closes the container, ends the
115
+ * browser-as-a-service session, …). Distinct from {@link IRemoteBrowserSession.Close}, which the
116
+ * engine may call on the session handle; `Disconnect` releases the driver's own backend resources.
117
+ *
118
+ * @returns A promise that resolves once the backend session has been released.
119
+ */
120
+ abstract Disconnect(): Promise<void>;
121
+ /**
122
+ * Captures the connection context onto the instance so {@link BaseRemoteBrowserProvider.Features},
123
+ * {@link BaseRemoteBrowserProvider.RequireFeature}, and capability-error messages have the
124
+ * backend's flags and name. A concrete {@link BaseRemoteBrowserProvider.Connect} should call this
125
+ * first.
126
+ *
127
+ * @param ctx The provider context handed to `Connect`.
128
+ */
129
+ protected applyContext(ctx: RemoteBrowserProviderContext): void;
130
+ /**
131
+ * Defense-in-depth guard: asserts a `SupportedFeatures` flag is enabled before the driver performs
132
+ * a capability-gated action, throwing {@link RemoteBrowserCapabilityNotSupportedError} if it is
133
+ * false/omitted. A driver should call this at the top of any capability-gated work so that even a
134
+ * direct (engine-bypassing) caller cannot run an action the metadata says is off.
135
+ *
136
+ * @param featureName The `IRemoteBrowserProviderFeatures` flag to require.
137
+ * @throws {RemoteBrowserCapabilityNotSupportedError} when the flag is not enabled.
138
+ */
139
+ protected RequireFeature(featureName: keyof IRemoteBrowserProviderFeatures): void;
140
+ /**
141
+ * Builds the standard {@link RemoteBrowserCapabilityNotSupportedError} for an un-overridden
142
+ * capability or a failed feature requirement, stamped with this driver's backend name.
143
+ *
144
+ * @param featureName The feature / method name to report.
145
+ * @returns The error to throw or reject with.
146
+ */
147
+ protected notSupported(featureName: string): RemoteBrowserCapabilityNotSupportedError;
148
+ }
149
+ //# sourceMappingURL=base-remote-browser-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-remote-browser-provider.d.ts","sourceRoot":"","sources":["../src/base-remote-browser-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAC3E,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,wCAAwC,EAAE,MAAM,qBAAqB,CAAC;AAE/E;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA4B;IACzC;;;;OAIG;IACH,QAAQ,EAAE,8BAA8B,CAAC;IAEzC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,YAAY,EAAE,UAAU,GAAG,SAAS,CAAC;IAErC;;;;OAIG;IACH,WAAW,EAAE,wBAAwB,CAAC;IAEtC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAExC;;;OAGG;IACH,WAAW,CAAC,EAAE,QAAQ,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,8BAAsB,yBAAyB;IAC3C;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,8BAA8B,CAAM;IAExD;;;OAGG;IACH,SAAS,CAAC,YAAY,EAAE,MAAM,CAAM;IAEpC;;;;;;;OAOG;IACH,IAAW,QAAQ,IAAI,8BAA8B,CAEpD;IAMD;;;;;;;;;OASG;aACa,OAAO,CAAC,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAE1F;;;;;;OAMG;aACa,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3C;;;;;;;OAOG;IACH,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,4BAA4B,GAAG,IAAI;IAK/D;;;;;;;;OAQG;IACH,SAAS,CAAC,cAAc,CAAC,WAAW,EAAE,MAAM,8BAA8B,GAAG,IAAI;IASjF;;;;;;OAMG;IACH,SAAS,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,wCAAwC;CAMxF"}
@@ -0,0 +1,95 @@
1
+ import { RemoteBrowserCapabilityNotSupportedError } from './capability-errors.js';
2
+ /**
3
+ * Abstract base class for a **Remote Browser** provider driver — a pluggable backend that opens (or
4
+ * attaches to) a real Chromium browser over the Chrome DevTools Protocol and returns a live
5
+ * {@link IRemoteBrowserSession} the agent drives.
6
+ *
7
+ * This is the sibling of `BaseRealtimeBridge`: the Remote Browser channel is built exactly like the
8
+ * bridge subsystem (registry table + base driver + EngineBase/Engine pair + pluggable backends). A
9
+ * concrete driver (`SelfHostedChromeRemoteBrowser`, `BrowserbaseRemoteBrowser`, …) implements only the
10
+ * irreducibly backend-specific primitives — everything generic (control arbitration, the
11
+ * viewport→screen-track encode, session bookkeeping) lives in the server engine above. Drivers
12
+ * self-register with the MemberJunction `ClassFactory` — e.g.
13
+ * `@RegisterClass(BaseRemoteBrowserProvider, 'BrowserbaseRemoteBrowser')`. The base class itself is
14
+ * abstract and unregistered; the engine resolves a driver via
15
+ * `MJGlobal.ClassFactory.CreateInstance(BaseRemoteBrowserProvider, provider.DriverClass)`.
16
+ *
17
+ * **Capability gating (two layers, defense-in-depth).** The engine FIRST checks a provider's
18
+ * `SupportedFeatures` flag and never calls a session method whose feature is off. The driver's own
19
+ * capability-gated work is the SECOND layer: it calls {@link BaseRemoteBrowserProvider.RequireFeature}
20
+ * (or builds an error via {@link BaseRemoteBrowserProvider.notSupported}) so a metadata flag that
21
+ * lied — or a caller that bypassed the gate — fails loudly rather than silently degrading.
22
+ *
23
+ * **Universal CDP substrate.** Every backend (self-hosted Chrome and every browser-as-a-service)
24
+ * exposes a CDP endpoint; the engine standardizes on CDP-connect (reusing `@memberjunction/computer-use`
25
+ * server-side) so this Base package itself stays dependency-light and universal.
26
+ *
27
+ * @see `/plans/realtime/realtime-bridges-architecture.md` §4d / §4d-i.
28
+ * @abstract
29
+ */
30
+ export class BaseRemoteBrowserProvider {
31
+ constructor() {
32
+ /**
33
+ * The capability flags for the backend this driver instance serves. Populated from the
34
+ * {@link RemoteBrowserProviderContext} at {@link BaseRemoteBrowserProvider.Connect} time (call
35
+ * `this.applyContext(ctx)` first). Drives {@link BaseRemoteBrowserProvider.RequireFeature}.
36
+ */
37
+ this.features = {};
38
+ /**
39
+ * The backend's display name for this driver instance, used in capability-error messages.
40
+ * Populated from the {@link RemoteBrowserProviderContext}; falls back to the driver class name.
41
+ */
42
+ this.providerName = '';
43
+ }
44
+ /**
45
+ * The backend's supported-feature flags for this driver instance.
46
+ *
47
+ * Read-only accessor over the internally-held {@link BaseRemoteBrowserProvider.features}. The
48
+ * engine consults this (and the underlying provider metadata) to decide which capability-gated
49
+ * session methods are safe to call; a driver consults it via
50
+ * {@link BaseRemoteBrowserProvider.RequireFeature}.
51
+ */
52
+ get Features() {
53
+ return this.features;
54
+ }
55
+ // ──────────────────────────────────────────────────────────────────────────────
56
+ // Protected helpers for driver authors.
57
+ // ──────────────────────────────────────────────────────────────────────────────
58
+ /**
59
+ * Captures the connection context onto the instance so {@link BaseRemoteBrowserProvider.Features},
60
+ * {@link BaseRemoteBrowserProvider.RequireFeature}, and capability-error messages have the
61
+ * backend's flags and name. A concrete {@link BaseRemoteBrowserProvider.Connect} should call this
62
+ * first.
63
+ *
64
+ * @param ctx The provider context handed to `Connect`.
65
+ */
66
+ applyContext(ctx) {
67
+ this.features = ctx.Features ?? {};
68
+ this.providerName = ctx.ProviderName || this.constructor.name;
69
+ }
70
+ /**
71
+ * Defense-in-depth guard: asserts a `SupportedFeatures` flag is enabled before the driver performs
72
+ * a capability-gated action, throwing {@link RemoteBrowserCapabilityNotSupportedError} if it is
73
+ * false/omitted. A driver should call this at the top of any capability-gated work so that even a
74
+ * direct (engine-bypassing) caller cannot run an action the metadata says is off.
75
+ *
76
+ * @param featureName The `IRemoteBrowserProviderFeatures` flag to require.
77
+ * @throws {RemoteBrowserCapabilityNotSupportedError} when the flag is not enabled.
78
+ */
79
+ RequireFeature(featureName) {
80
+ if (this.features[featureName] !== true) {
81
+ throw new RemoteBrowserCapabilityNotSupportedError(String(featureName), this.providerName || this.constructor.name);
82
+ }
83
+ }
84
+ /**
85
+ * Builds the standard {@link RemoteBrowserCapabilityNotSupportedError} for an un-overridden
86
+ * capability or a failed feature requirement, stamped with this driver's backend name.
87
+ *
88
+ * @param featureName The feature / method name to report.
89
+ * @returns The error to throw or reject with.
90
+ */
91
+ notSupported(featureName) {
92
+ return new RemoteBrowserCapabilityNotSupportedError(featureName, this.providerName || this.constructor.name);
93
+ }
94
+ }
95
+ //# sourceMappingURL=base-remote-browser-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-remote-browser-provider.js","sourceRoot":"","sources":["../src/base-remote-browser-provider.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,wCAAwC,EAAE,MAAM,qBAAqB,CAAC;AAuD/E;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAgB,yBAAyB;IAA/C;QACI;;;;WAIG;QACO,aAAQ,GAAmC,EAAE,CAAC;QAExD;;;WAGG;QACO,iBAAY,GAAW,EAAE,CAAC;IAuFxC,CAAC;IArFG;;;;;;;OAOG;IACH,IAAW,QAAQ;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IA2BD,iFAAiF;IACjF,wCAAwC;IACxC,iFAAiF;IAEjF;;;;;;;OAOG;IACO,YAAY,CAAC,GAAiC;QACpD,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAClE,CAAC;IAED;;;;;;;;OAQG;IACO,cAAc,CAAC,WAAiD;QACtE,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,wCAAwC,CAC9C,MAAM,CAAC,WAAW,CAAC,EACnB,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAC7C,CAAC;QACN,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACO,YAAY,CAAC,WAAmB;QACtC,OAAO,IAAI,wCAAwC,CAC/C,WAAW,EACX,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAC7C,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Error types for the remote-browser capability-gating flow.
3
+ *
4
+ * See `/plans/realtime/realtime-bridges-architecture.md` §4d-i — the Remote Browser channel is built
5
+ * exactly like the bridge subsystem (registry table + base driver + EngineBase/Engine pair +
6
+ * pluggable backends), with the same two-layer capability gating. The engine checks a provider's
7
+ * `SupportedFeatures` flag BEFORE calling an optional driver method; this error is the
8
+ * **defense-in-depth** layer that fires when a feature is claimed in metadata but the concrete driver
9
+ * never implemented it (or a caller skipped the metadata gate). Metadata says "don't call this"; the
10
+ * throw means the code refuses to pretend a capability exists.
11
+ */
12
+ /**
13
+ * Thrown when a capability-gated remote-browser feature is invoked on a driver that does not support it.
14
+ *
15
+ * Two distinct failure modes both surface as this error:
16
+ * 1. A `BaseRemoteBrowserProvider` **virtual** method (e.g. `GetLiveViewUrl`, `StartScreencast`) was
17
+ * called but the concrete driver did not override the base implementation — the base throws this.
18
+ * 2. The driver's `RequireFeature(...)` defense-in-depth guard found the matching
19
+ * `IRemoteBrowserProviderFeatures` flag false/omitted — the metadata claims the feature is off, so
20
+ * the call must not proceed.
21
+ *
22
+ * Carrying both the `FeatureName` and the `ProviderName` makes the loud failure actionable: it points
23
+ * at exactly which capability flag lied (or which driver method is missing) for which backend.
24
+ */
25
+ export declare class RemoteBrowserCapabilityNotSupportedError extends Error {
26
+ /**
27
+ * The name of the unsupported feature — by convention an `IRemoteBrowserProviderFeatures` key
28
+ * (e.g. `'LiveView'`, `'HumanTakeover'`, `'NativeAIControl'`) or the virtual method name when the
29
+ * throw originates from an un-overridden base method.
30
+ */
31
+ readonly FeatureName: string;
32
+ /**
33
+ * The remote-browser backend the call targeted (e.g. `'Browserbase'`, `'Self-Hosted Chrome'`).
34
+ * Sourced from the provider metadata row's `Name`, or the driver's own identifier when the
35
+ * provider name is not available at the throw site.
36
+ */
37
+ readonly ProviderName: string;
38
+ /**
39
+ * Constructs a {@link RemoteBrowserCapabilityNotSupportedError}.
40
+ *
41
+ * @param featureName The unsupported feature / method name (an `IRemoteBrowserProviderFeatures` key by convention).
42
+ * @param providerName The backend the call targeted (e.g. `'Browserbase'`, `'Steel'`).
43
+ * @param message Optional override for the human-readable message; a sensible default is built from the two names.
44
+ */
45
+ constructor(featureName: string, providerName: string, message?: string);
46
+ }
47
+ //# sourceMappingURL=capability-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-errors.d.ts","sourceRoot":"","sources":["../src/capability-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;GAYG;AACH,qBAAa,wCAAyC,SAAQ,KAAK;IAC/D;;;;OAIG;IACH,SAAgB,WAAW,EAAE,MAAM,CAAC;IAEpC;;;;OAIG;IACH,SAAgB,YAAY,EAAE,MAAM,CAAC;IAErC;;;;;;OAMG;gBACS,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAY1E"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Error types for the remote-browser capability-gating flow.
3
+ *
4
+ * See `/plans/realtime/realtime-bridges-architecture.md` §4d-i — the Remote Browser channel is built
5
+ * exactly like the bridge subsystem (registry table + base driver + EngineBase/Engine pair +
6
+ * pluggable backends), with the same two-layer capability gating. The engine checks a provider's
7
+ * `SupportedFeatures` flag BEFORE calling an optional driver method; this error is the
8
+ * **defense-in-depth** layer that fires when a feature is claimed in metadata but the concrete driver
9
+ * never implemented it (or a caller skipped the metadata gate). Metadata says "don't call this"; the
10
+ * throw means the code refuses to pretend a capability exists.
11
+ */
12
+ /**
13
+ * Thrown when a capability-gated remote-browser feature is invoked on a driver that does not support it.
14
+ *
15
+ * Two distinct failure modes both surface as this error:
16
+ * 1. A `BaseRemoteBrowserProvider` **virtual** method (e.g. `GetLiveViewUrl`, `StartScreencast`) was
17
+ * called but the concrete driver did not override the base implementation — the base throws this.
18
+ * 2. The driver's `RequireFeature(...)` defense-in-depth guard found the matching
19
+ * `IRemoteBrowserProviderFeatures` flag false/omitted — the metadata claims the feature is off, so
20
+ * the call must not proceed.
21
+ *
22
+ * Carrying both the `FeatureName` and the `ProviderName` makes the loud failure actionable: it points
23
+ * at exactly which capability flag lied (or which driver method is missing) for which backend.
24
+ */
25
+ export class RemoteBrowserCapabilityNotSupportedError extends Error {
26
+ /**
27
+ * Constructs a {@link RemoteBrowserCapabilityNotSupportedError}.
28
+ *
29
+ * @param featureName The unsupported feature / method name (an `IRemoteBrowserProviderFeatures` key by convention).
30
+ * @param providerName The backend the call targeted (e.g. `'Browserbase'`, `'Steel'`).
31
+ * @param message Optional override for the human-readable message; a sensible default is built from the two names.
32
+ */
33
+ constructor(featureName, providerName, message) {
34
+ super(message ??
35
+ `Remote browser capability '${featureName}' is not supported by provider '${providerName}'. ` +
36
+ `Either the provider's SupportedFeatures does not enable it, or its driver does not implement it.`);
37
+ this.name = 'RemoteBrowserCapabilityNotSupportedError';
38
+ this.FeatureName = featureName;
39
+ this.ProviderName = providerName;
40
+ // Restore the prototype chain — required when extending built-ins under ES2015+ down-compilation.
41
+ Object.setPrototypeOf(this, RemoteBrowserCapabilityNotSupportedError.prototype);
42
+ }
43
+ }
44
+ //# sourceMappingURL=capability-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability-errors.js","sourceRoot":"","sources":["../src/capability-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,wCAAyC,SAAQ,KAAK;IAe/D;;;;;;OAMG;IACH,YAAY,WAAmB,EAAE,YAAoB,EAAE,OAAgB;QACnE,KAAK,CACD,OAAO;YACH,8BAA8B,WAAW,mCAAmC,YAAY,KAAK;gBACzF,kGAAkG,CAC7G,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0CAA0C,CAAC;QACvD,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,kGAAkG;QAClG,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,wCAAwC,CAAC,SAAS,CAAC,CAAC;IACpF,CAAC;CACJ"}
@@ -0,0 +1,69 @@
1
+ import { IRemoteBrowserProviderFeatures } from './remote-browser-features.js';
2
+ /**
3
+ * How control of the remote browser is shared between the agent and humans — a per-provider default
4
+ * (`MJ: AI Remote Browser Providers.DefaultControlMode`) that the `RemoteBrowserChannel` config
5
+ * overrides per-channel and at runtime.
6
+ *
7
+ * This is **distinct from** {@link RemoteBrowserControlStrategy}: the *mode* is the human/agent
8
+ * sharing policy, the *strategy* is the mechanism by which the agent decides what to do.
9
+ *
10
+ * - `AgentOnly` — only the agent drives; no human takeover (e.g. a hands-off sales demo).
11
+ * - `ViewOnly` — the agent drives while humans **watch** the live view but cannot take the wheel.
12
+ * Requires the backend's `LiveView` capability.
13
+ * - `Collaborative` — a human can **grab the wheel** (e.g. a trainer agent: demonstrate a task, then
14
+ * "your turn, try X"). Requires both `LiveView` (to watch) and `HumanTakeover` (to drive).
15
+ *
16
+ * @see `/plans/realtime/realtime-bridges-architecture.md` §4d-i.
17
+ */
18
+ export type RemoteBrowserControlMode = 'AgentOnly' | 'ViewOnly' | 'Collaborative';
19
+ /**
20
+ * The mechanism by which the agent decides *what to click/type/navigate* — a pluggable strategy
21
+ * gated by capability, orthogonal to the {@link RemoteBrowserControlMode}.
22
+ *
23
+ * - `ComputerUse` — MJ's own perception→action loop over the universal CDP substrate
24
+ * (`@memberjunction/computer-use`). The default; works on every backend that exposes
25
+ * `RawCdpControl`. The right fit for a realtime co-agent that is already a powerful brain emitting
26
+ * tool calls while it talks.
27
+ * - `NativeAI` — delegate high-level intents to the backend's own first-party AI-control harness
28
+ * (e.g. Browserbase Stagehand, Hyperbrowser agent). An optional accelerator for heavy, robust
29
+ * autonomous automation; it runs its own model loop, so it is offered, never the default. Requires
30
+ * the backend's `NativeAIControl` capability.
31
+ *
32
+ * @see `/plans/realtime/realtime-bridges-architecture.md` §4d-i ("Control is a pluggable STRATEGY").
33
+ */
34
+ export type RemoteBrowserControlStrategy = 'ComputerUse' | 'NativeAI';
35
+ /**
36
+ * Determines whether a {@link RemoteBrowserControlMode} is valid given a backend's capabilities.
37
+ *
38
+ * A mode is only valid when the backend supports the capabilities it requires:
39
+ * - `AgentOnly` — always valid (the agent drives; no viewing/takeover prerequisite).
40
+ * - `ViewOnly` — requires `LiveView` (humans must be able to watch).
41
+ * - `Collaborative` — requires `LiveView` **and** `HumanTakeover` (humans watch *and* can take over).
42
+ *
43
+ * @param mode The control mode to validate.
44
+ * @param features The backend's capability flags.
45
+ * @returns `true` when the backend can support the mode, `false` otherwise.
46
+ */
47
+ export declare function isControlModeSupported(mode: RemoteBrowserControlMode, features: IRemoteBrowserProviderFeatures): boolean;
48
+ /**
49
+ * Resolves which {@link RemoteBrowserControlStrategy} the engine should use for a backend, honoring an
50
+ * optional caller preference.
51
+ *
52
+ * **Precedence (highest to lowest):**
53
+ * 1. **`NativeAI`** — chosen *only* when the backend advertises `NativeAIControl` **and** the caller
54
+ * did not explicitly pin `ComputerUse`. (A caller preference of `'NativeAI'` is honored only if the
55
+ * backend actually supports it; an explicit `'ComputerUse'` always suppresses native delegation.)
56
+ * 2. **`ComputerUse`** — the universal default, chosen whenever the backend exposes the
57
+ * `RawCdpControl` substrate and native control was not selected above.
58
+ * 3. **`ComputerUse`** — also the fallback when neither flag is set, because CDP-connect is the one
59
+ * primitive every backend is expected to provide; emitting `ComputerUse` lets the caller surface a
60
+ * clear downstream error if the backend genuinely cannot be driven, rather than this helper
61
+ * inventing an unsupported strategy.
62
+ *
63
+ * @param features The backend's capability flags.
64
+ * @param preferred An optional caller preference; `'ComputerUse'` pins the universal loop and
65
+ * suppresses native delegation even when the backend supports it.
66
+ * @returns The resolved control strategy.
67
+ */
68
+ export declare function resolveControlStrategy(features: IRemoteBrowserProviderFeatures, preferred?: RemoteBrowserControlStrategy): RemoteBrowserControlStrategy;
69
+ //# sourceMappingURL=control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAE3E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,wBAAwB,GAAG,WAAW,GAAG,UAAU,GAAG,eAAe,CAAC;AAElF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,4BAA4B,GAAG,aAAa,GAAG,UAAU,CAAC;AAEtE;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,wBAAwB,EAC9B,QAAQ,EAAE,8BAA8B,GACzC,OAAO,CAYT;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CAClC,QAAQ,EAAE,8BAA8B,EACxC,SAAS,CAAC,EAAE,4BAA4B,GACzC,4BAA4B,CAK9B"}