@mercuryo-ai/agentbrowse 0.2.60 → 0.2.63
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/CHANGELOG.md +33 -1
- package/README.md +132 -14
- package/dist/browser-session-state.d.ts +40 -10
- package/dist/browser-session-state.d.ts.map +1 -1
- package/dist/browser-session-state.js +63 -5
- package/dist/commands/act.d.ts.map +1 -1
- package/dist/commands/act.js +548 -535
- package/dist/commands/attach.d.ts +1 -3
- package/dist/commands/attach.d.ts.map +1 -1
- package/dist/commands/attach.js +5 -12
- package/dist/commands/browser-connection-failure.d.ts +9 -0
- package/dist/commands/browser-connection-failure.d.ts.map +1 -0
- package/dist/commands/browser-connection-failure.js +15 -0
- package/dist/commands/browser-status.d.ts +0 -2
- package/dist/commands/browser-status.d.ts.map +1 -1
- package/dist/commands/browser-status.js +27 -37
- package/dist/commands/close.d.ts.map +1 -1
- package/dist/commands/close.js +5 -0
- package/dist/commands/extract.d.ts.map +1 -1
- package/dist/commands/extract.js +147 -144
- package/dist/commands/interaction-kernel.d.ts +1 -1
- package/dist/commands/interaction-kernel.d.ts.map +1 -1
- package/dist/commands/interaction-kernel.js +1 -1
- package/dist/commands/launch.d.ts +0 -1
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +11 -12
- package/dist/commands/navigate.d.ts.map +1 -1
- package/dist/commands/navigate.js +79 -73
- package/dist/commands/observe-accessibility.d.ts.map +1 -1
- package/dist/commands/observe-accessibility.js +36 -2
- package/dist/commands/observe-inventory.d.ts +50 -7
- package/dist/commands/observe-inventory.d.ts.map +1 -1
- package/dist/commands/observe-inventory.js +822 -99
- package/dist/commands/observe-persistence.d.ts.map +1 -1
- package/dist/commands/observe-persistence.js +49 -6
- package/dist/commands/observe-projection.d.ts +6 -2
- package/dist/commands/observe-projection.d.ts.map +1 -1
- package/dist/commands/observe-projection.js +251 -27
- package/dist/commands/observe-semantics.d.ts +1 -0
- package/dist/commands/observe-semantics.d.ts.map +1 -1
- package/dist/commands/observe-semantics.js +541 -135
- package/dist/commands/observe-signals.d.ts +4 -4
- package/dist/commands/observe-signals.d.ts.map +1 -1
- package/dist/commands/observe-signals.js +2 -2
- package/dist/commands/observe-surfaces.d.ts +2 -1
- package/dist/commands/observe-surfaces.d.ts.map +1 -1
- package/dist/commands/observe-surfaces.js +143 -45
- package/dist/commands/observe.d.ts +5 -1
- package/dist/commands/observe.d.ts.map +1 -1
- package/dist/commands/observe.js +266 -274
- package/dist/commands/screenshot.d.ts.map +1 -1
- package/dist/commands/screenshot.js +50 -64
- package/dist/commands/semantic-observe.d.ts.map +1 -1
- package/dist/commands/semantic-observe.js +43 -0
- package/dist/library.d.ts +3 -1
- package/dist/library.d.ts.map +1 -1
- package/dist/library.js +3 -1
- package/dist/match-resolve-fill.d.ts +196 -0
- package/dist/match-resolve-fill.d.ts.map +1 -0
- package/dist/match-resolve-fill.js +700 -0
- package/dist/match-resolve-fill.test-support.d.ts +34 -0
- package/dist/match-resolve-fill.test-support.d.ts.map +1 -0
- package/dist/match-resolve-fill.test-support.js +81 -0
- package/dist/protected-fill.d.ts.map +1 -1
- package/dist/protected-fill.js +46 -7
- package/dist/runtime-protected-state.d.ts.map +1 -1
- package/dist/runtime-protected-state.js +12 -0
- package/dist/runtime-state.d.ts +6 -0
- package/dist/runtime-state.d.ts.map +1 -1
- package/dist/runtime-state.js +6 -0
- package/dist/secrets/form-matcher.d.ts.map +1 -1
- package/dist/secrets/form-matcher.js +76 -27
- package/dist/secrets/protected-exact-value-redaction.d.ts.map +1 -1
- package/dist/secrets/protected-exact-value-redaction.js +6 -0
- package/dist/secrets/protected-fill.js +3 -3
- package/dist/session.d.ts +3 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +2 -2
- package/dist/solver/browser-launcher.d.ts.map +1 -1
- package/dist/solver/browser-launcher.js +2 -1
- package/dist/sticky-owner-host-entry.d.ts +2 -0
- package/dist/sticky-owner-host-entry.d.ts.map +1 -0
- package/dist/sticky-owner-host-entry.js +97 -0
- package/dist/sticky-owner.d.ts +15 -0
- package/dist/sticky-owner.d.ts.map +1 -0
- package/dist/sticky-owner.js +431 -0
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/docs/README.md +28 -11
- package/docs/api-reference.md +311 -19
- package/docs/assistive-runtime.md +41 -16
- package/docs/configuration.md +36 -4
- package/docs/getting-started.md +73 -5
- package/docs/integration-checklist.md +32 -3
- package/docs/match-resolve-fill.md +699 -0
- package/docs/protected-fill.md +373 -91
- package/docs/testing.md +147 -15
- package/docs/troubleshooting.md +47 -6
- package/examples/README.md +7 -0
- package/examples/match-resolve-fill.ts +107 -0
- package/package.json +4 -2
- package/dist/protected-fill-browser.d.ts +0 -22
- package/dist/protected-fill-browser.d.ts.map +0 -1
- package/dist/protected-fill-browser.js +0 -52
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
- added `match`, `resolve`, and `fill` primitives for deciding which
|
|
6
|
+
caller-supplied value belongs in which observed field and applying it
|
|
7
|
+
through the existing browser runtime. Default match results expose
|
|
8
|
+
opaque value/artifact refs and never carry raw values through JSON
|
|
9
|
+
serialization
|
|
10
|
+
- two resolver shapes accepted at the `fill(...)` `{ resolver }` slot:
|
|
11
|
+
the main `AgentbrowseMatchResolver` (required `resolve`, optional
|
|
12
|
+
`resolveBatch`, optional `fill`) and the narrow
|
|
13
|
+
`AgentbrowseGroupFillHandler` (just `fill`) for callers that only
|
|
14
|
+
apply ready grouped artifacts. `resolve(plan, { with })` only
|
|
15
|
+
accepts the main interface so `.resolve` is compile-time guaranteed.
|
|
16
|
+
Runtime picks the right capability through type guards and raises
|
|
17
|
+
`match_resolver_required` when a passed object lacks a capability
|
|
18
|
+
the current plan needs
|
|
19
|
+
- `matchGroup` returns `ambiguous_group` when several candidates tie on
|
|
20
|
+
overlap and confidence, instead of silently picking the first by sort
|
|
21
|
+
order
|
|
22
|
+
- stable resolved value/artifact refs (`value:${candidateRef}:resolved`,
|
|
23
|
+
`artifact:${candidateRef}:resolved`) so repeated resolves produce the
|
|
24
|
+
same refs
|
|
25
|
+
- `ObserveTarget` now carries `pageRef` so observed targets flow
|
|
26
|
+
directly into `match(...)` without extra glue; `MatchableTarget` was
|
|
27
|
+
also relaxed to accept minimal target objects
|
|
28
|
+
- `/testing` subpath now also exports `createFixtureMatchStore`,
|
|
29
|
+
`createFixtureGroupStore`, `createFixtureResolver`,
|
|
30
|
+
`fixtureResolvedValue`, and `fixtureResolvedArtifact` for wrapper
|
|
31
|
+
packages that test against the new primitives
|
|
32
|
+
- added `docs/match-resolve-fill.md` and an `examples/match-resolve-fill.ts`
|
|
33
|
+
runnable example; repositioned the README as «browser runtime plus
|
|
34
|
+
deterministic field data-plane primitives»
|
|
35
|
+
- `tsconfig.examples.json` and a `check-types:examples` script keep
|
|
36
|
+
example files type-checked against the project's public surface,
|
|
37
|
+
mirroring the pattern in `@mercuryo-ai/magicpay-sdk`
|
|
6
38
|
|
|
7
39
|
## 0.2.52
|
|
8
40
|
|
package/README.md
CHANGED
|
@@ -2,18 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@mercuryo-ai/agentbrowse) [](LICENSE) [](https://nodejs.org)
|
|
4
4
|
|
|
5
|
-
Give your AI agent a real browser
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
Give your AI agent a real browser — and a deterministic way to fill fields
|
|
6
|
+
on it.
|
|
7
|
+
|
|
8
|
+
AgentBrowse is the browser runtime for agent systems that need to work with
|
|
9
|
+
real web pages, plus a small set of data-plane primitives for deciding which
|
|
10
|
+
value belongs in which observed field without routing the values through
|
|
11
|
+
the LLM prompt. Your app keeps full control of orchestration and business
|
|
12
|
+
logic; AgentBrowse handles the page and the deterministic apply step.
|
|
13
|
+
|
|
14
|
+
The package has two main parts:
|
|
15
|
+
|
|
16
|
+
- **Browser runtime** — launch or attach a browser, `observe(...)` the page,
|
|
17
|
+
`act(...)` on targets, `extract(...)` structured data, `close(...)` when
|
|
18
|
+
done.
|
|
19
|
+
- **Data-plane primitives** — `match(subject, { from })` picks a candidate
|
|
20
|
+
for an observed target or form, `resolve(plan, { with })` turns a plan
|
|
21
|
+
into a ready value or artifact through a caller-supplied adapter, and
|
|
22
|
+
`fill(session, subject, plan, { resolver? })` applies the result to the
|
|
23
|
+
browser deterministically. Default match results never expose raw values
|
|
24
|
+
to serializable output.
|
|
11
25
|
|
|
12
26
|
Typical workflow:
|
|
13
27
|
|
|
14
28
|
1. open a browser (or attach to an existing one) and get a `session`;
|
|
15
29
|
2. ask AgentBrowse what's on the page with `observe(...)`;
|
|
16
|
-
3. act
|
|
30
|
+
3. either `act(...)` directly, or `match(...) → fill(...)` when you want
|
|
31
|
+
a deterministic field-value decision;
|
|
17
32
|
4. use `extract(...)` when you need structured data instead of an action;
|
|
18
33
|
5. close the session when you are done.
|
|
19
34
|
|
|
@@ -25,9 +40,13 @@ runtime you already have.
|
|
|
25
40
|
Three terms come up repeatedly in the API:
|
|
26
41
|
|
|
27
42
|
- **`session`** — the handle AgentBrowse returns from `launch(...)` or
|
|
28
|
-
`attach(...)`. You pass it into every later call.
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
`attach(...)`. You pass it into every later call. The session carries
|
|
44
|
+
browser identity, runtime state, and sticky-owner metadata so healthy
|
|
45
|
+
commands reuse one browser owner instead of opening a fresh root CDP
|
|
46
|
+
attach for every call. If you persist a session across process runs,
|
|
47
|
+
the next command may repair that owner while the underlying browser is
|
|
48
|
+
still alive; otherwise the session fails closed and you should
|
|
49
|
+
`launch(...)` or `attach(...)` again.
|
|
31
50
|
- **`ref`** (also `targetRef`, `scopeRef`, `fillRef`) — a stable reference
|
|
32
51
|
returned by `observe(...)`. You act on references, never on raw CSS
|
|
33
52
|
selectors. **Refs are valid for the page state that produced them, not
|
|
@@ -105,8 +124,8 @@ try {
|
|
|
105
124
|
}
|
|
106
125
|
|
|
107
126
|
const statusResult = await status(session);
|
|
108
|
-
if (!statusResult.
|
|
109
|
-
throw new Error(
|
|
127
|
+
if (!statusResult.alive) {
|
|
128
|
+
throw new Error('Browser is no longer reachable.');
|
|
110
129
|
}
|
|
111
130
|
} finally {
|
|
112
131
|
await close(session);
|
|
@@ -119,10 +138,86 @@ Runnable examples live in [`examples/`](./examples/README.md):
|
|
|
119
138
|
- `npx tsx examples/basic.ts`
|
|
120
139
|
- `npx tsx examples/attach.ts`
|
|
121
140
|
- `npx tsx examples/extract.ts`
|
|
141
|
+
- `npx tsx examples/match-resolve-fill.ts`
|
|
122
142
|
|
|
123
143
|
The library entrypoint does not load `.env` files. Environment loading only
|
|
124
144
|
happens in the CLI entrypoint.
|
|
125
145
|
|
|
146
|
+
Both `launch(...)` and `attach(...)` bootstrap the same sticky-owner
|
|
147
|
+
lifecycle. That owner may live in-process or in an internal detached host,
|
|
148
|
+
but it is not a user-managed daemon contract.
|
|
149
|
+
|
|
150
|
+
## Match, Resolve, Fill
|
|
151
|
+
|
|
152
|
+
Once `observe(...)` has returned a target or a fillable form, three
|
|
153
|
+
primitives cover the end-to-end decision of putting a value into a field:
|
|
154
|
+
|
|
155
|
+
- **`match`** decides which candidate value fits the observed target or
|
|
156
|
+
fillable form. Pure and local.
|
|
157
|
+
- **`resolve`** turns a `needs_resolution` plan into a ready value by
|
|
158
|
+
calling a caller-supplied adapter. This is the only step that may reach
|
|
159
|
+
a network, a vault, or an approval UI.
|
|
160
|
+
- **`fill`** applies the matched value to the browser through the same
|
|
161
|
+
deterministic path as `act(...)`.
|
|
162
|
+
|
|
163
|
+
Simplest case — the value is already in memory:
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
import { match, resolve, fill } from '@mercuryo-ai/agentbrowse';
|
|
167
|
+
|
|
168
|
+
const matched = await match(emailTarget, {
|
|
169
|
+
from: { email: 'traveler@example.com' },
|
|
170
|
+
});
|
|
171
|
+
// matched.kind === 'ready'
|
|
172
|
+
await fill(session, emailTarget, matched);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
When the value lives behind a lookup, the candidate carries a `resolve`
|
|
176
|
+
plan and your adapter handles the fetch:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const pending = await match(passwordTarget, {
|
|
180
|
+
from: [
|
|
181
|
+
{
|
|
182
|
+
fieldKey: 'password',
|
|
183
|
+
type: 'secret',
|
|
184
|
+
resolve: { kind: 'vault_lookup', key: 'login.password' },
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
// pending.kind === 'needs_resolution'
|
|
189
|
+
|
|
190
|
+
const ready = await resolve(pending, { with: vaultResolver });
|
|
191
|
+
await fill(session, passwordTarget, ready);
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Core rules:
|
|
195
|
+
|
|
196
|
+
- **No raw values in public results.** `match` returns plans and refs, not
|
|
197
|
+
secrets; dereferencing happens inside `fill(...)` through a non-enumerable
|
|
198
|
+
accessor. Serialising a `ready` result across a process boundary drops
|
|
199
|
+
the value — ship the `needs_resolution` plan instead and let the
|
|
200
|
+
downstream side run `resolve → fill`.
|
|
201
|
+
- **One resolver slot, two accepted shapes.** The main
|
|
202
|
+
`AgentbrowseMatchResolver` has a required `resolve` plus optional
|
|
203
|
+
`resolveBatch` and optional `fill`; the narrow
|
|
204
|
+
`AgentbrowseGroupFillHandler` has just `fill`. Both are accepted in
|
|
205
|
+
the same `{ resolver }` slot on `fill(...)`; `resolve(plan, { with })`
|
|
206
|
+
only accepts the main interface. Use the narrow handler when the
|
|
207
|
+
caller already has the grouped artifact in hand and only needs to
|
|
208
|
+
apply it.
|
|
209
|
+
- **Determinism first.** Resolved value/artifact refs are stable
|
|
210
|
+
(`value:${candidateRef}:resolved`), so the same plan produces the same
|
|
211
|
+
refs across calls — safe to use in snapshot tests and trace correlation.
|
|
212
|
+
|
|
213
|
+
See:
|
|
214
|
+
|
|
215
|
+
- [Match / Resolve / Fill Guide](./docs/match-resolve-fill.md) for the
|
|
216
|
+
full mental model, walk-throughs, and design rules.
|
|
217
|
+
- [Testing Guide](./docs/testing.md) for fixture builders
|
|
218
|
+
(`createFixtureMatchStore`, `createFixtureResolver`, …) used in unit
|
|
219
|
+
tests for wrappers around these primitives.
|
|
220
|
+
|
|
126
221
|
## Attach To An Existing Browser
|
|
127
222
|
|
|
128
223
|
If you already have a browser that exposes a CDP WebSocket URL, use
|
|
@@ -158,6 +253,11 @@ const attached = await attach(remoteCdpUrl, {
|
|
|
158
253
|
});
|
|
159
254
|
```
|
|
160
255
|
|
|
256
|
+
`attach(...)` is not a separate reconnect mode. It is the second bootstrap
|
|
257
|
+
path into the same sticky-owner execution model as `launch(...)`. After
|
|
258
|
+
attach succeeds, later browser commands reuse or repair that owner instead of
|
|
259
|
+
performing a fresh provider-level root attach on every healthy command.
|
|
260
|
+
|
|
161
261
|
## What Each Main API Does
|
|
162
262
|
|
|
163
263
|
| API | Use it when | Typical result |
|
|
@@ -166,6 +266,9 @@ const attached = await attach(remoteCdpUrl, {
|
|
|
166
266
|
| `attach(cdpUrl, options?)` | You already have a running browser that exposes CDP | `session`, current `url`, current `title` |
|
|
167
267
|
| `observe(session, goal?)` | You want to understand the page | targets, scopes, signals, fillable forms |
|
|
168
268
|
| `act(session, targetRef, action, value?)` | You want to click, type, select, fill, or press | action result and target metadata |
|
|
269
|
+
| `match(subject, { from })` | You want to pick a deterministic candidate for an observed target or fillable form | match result (plan or ready ref; no raw value) |
|
|
270
|
+
| `resolve(plan, { with })` | You want to turn one or many `needs_resolution` plans into ready refs through a caller-supplied adapter | match result(s) marked as `ready` |
|
|
271
|
+
| `fill(session, subject, plan, { resolver? })` | You want to apply a match result to the browser through the deterministic path | browser action result or structured failure |
|
|
169
272
|
| `navigate(session, url)` | You want to move to another page | page metadata after navigation |
|
|
170
273
|
| `extract(session, schema, scopeRef?)` | You want structured JSON from the page | `data` that matches your schema |
|
|
171
274
|
| `screenshot(session, path?)` | You want a screenshot artifact | saved path and page metadata |
|
|
@@ -175,8 +278,10 @@ const attached = await attach(remoteCdpUrl, {
|
|
|
175
278
|
Two common questions:
|
|
176
279
|
|
|
177
280
|
- `observe(session)` gives you a general inventory of the page.
|
|
178
|
-
- `observe(session, goal)` focuses that inventory around a
|
|
179
|
-
`"find
|
|
281
|
+
- `observe(session, goal)` focuses that inventory around a single control
|
|
282
|
+
to find. Goals shaped as `"find <target> in <surface>"` (`"find the
|
|
283
|
+
email field"`, `"find May 5 in the open calendar"`) give the strongest
|
|
284
|
+
match. For multi-step work, run one goal per `observe` call.
|
|
180
285
|
|
|
181
286
|
All main APIs return the same broad result shape:
|
|
182
287
|
|
|
@@ -240,6 +345,18 @@ store.save(session);
|
|
|
240
345
|
const restoredFromCustomRoot = store.load();
|
|
241
346
|
```
|
|
242
347
|
|
|
348
|
+
Persisted session files contain versioned sticky-owner metadata, not a live
|
|
349
|
+
Playwright connection. `loadBrowserSession()` and custom stores intentionally
|
|
350
|
+
return `null` for incompatible reconnect-era records or incomplete owner
|
|
351
|
+
metadata instead of auto-migrating them. After loading a session, call
|
|
352
|
+
`status(restored)` or let the next browser command verify or repair
|
|
353
|
+
ownership. If the underlying browser is gone, the session fails closed and
|
|
354
|
+
you start fresh with `launch(...)` or `attach(...)`.
|
|
355
|
+
|
|
356
|
+
There is no separate daemon API to supervise. `close(session)` is the public
|
|
357
|
+
lifecycle boundary for shutting down the internal owner host and, when
|
|
358
|
+
applicable, the managed browser itself.
|
|
359
|
+
|
|
243
360
|
If you want to use a proxy, pass it directly to `launch(...)`:
|
|
244
361
|
|
|
245
362
|
```ts
|
|
@@ -305,6 +422,7 @@ See:
|
|
|
305
422
|
|
|
306
423
|
- [Getting Started](./docs/getting-started.md)
|
|
307
424
|
- [API Reference](./docs/api-reference.md)
|
|
425
|
+
- [Match / Resolve / Fill Guide](./docs/match-resolve-fill.md)
|
|
308
426
|
- [Configuration Guide](./docs/configuration.md)
|
|
309
427
|
- [Assistive Runtime Guide](./docs/assistive-runtime.md)
|
|
310
428
|
- [Protected Fill Guide](./docs/protected-fill.md)
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import type { BrowseRuntimeState } from './runtime-state.js';
|
|
2
2
|
import type { ProxyConfig } from './solver/types.js';
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
3
|
+
export declare const STICKY_OWNER_SCHEMA_VERSION: 1;
|
|
4
|
+
export type StickyOwnerState = 'bootstrapping' | 'active' | 'recovering' | 'dead';
|
|
5
|
+
export interface StickyOwnerPlaywrightBindTransport {
|
|
6
|
+
type: 'playwright_bind';
|
|
7
|
+
endpoint: string;
|
|
8
|
+
mode: 'pipe' | 'ws';
|
|
9
|
+
}
|
|
10
|
+
export interface StickyOwnerInProcessTransport {
|
|
11
|
+
type: 'in_process';
|
|
12
|
+
}
|
|
13
|
+
export type StickyOwnerTransport = StickyOwnerPlaywrightBindTransport | StickyOwnerInProcessTransport;
|
|
14
|
+
export interface StickyOwnerMetadata {
|
|
15
|
+
version: typeof STICKY_OWNER_SCHEMA_VERSION;
|
|
16
|
+
hostId: string;
|
|
17
|
+
state: StickyOwnerState;
|
|
18
|
+
startedAt: string;
|
|
19
|
+
lastUsedAt?: string;
|
|
20
|
+
ttlMs?: number;
|
|
21
|
+
touchPath?: string;
|
|
22
|
+
browserSessionId: string;
|
|
23
|
+
transport: StickyOwnerTransport;
|
|
24
|
+
pid?: number;
|
|
6
25
|
}
|
|
7
26
|
/** Persisted browser session state shared across AgentBrowse commands. */
|
|
8
27
|
export interface BrowserSessionState {
|
|
@@ -13,8 +32,8 @@ export interface BrowserSessionState {
|
|
|
13
32
|
profile?: string;
|
|
14
33
|
identity?: BrowseSessionIdentity;
|
|
15
34
|
transport?: BrowseSessionTransport;
|
|
16
|
-
capabilities?: BrowserSessionCapabilities;
|
|
17
35
|
runtime?: BrowseRuntimeState;
|
|
36
|
+
stickyOwner?: StickyOwnerMetadata;
|
|
18
37
|
}
|
|
19
38
|
/** Browser session state plus transient run-scoped metadata. */
|
|
20
39
|
export interface BrowserCommandSession extends BrowserSessionState {
|
|
@@ -44,15 +63,28 @@ export interface BrowserSessionStore {
|
|
|
44
63
|
load(): BrowserSessionState | null;
|
|
45
64
|
delete(): void;
|
|
46
65
|
}
|
|
47
|
-
type ManagedBrowserSessionInput = Omit<BrowserSessionState, 'port' | 'identity' | 'pid'
|
|
66
|
+
type ManagedBrowserSessionInput = Omit<BrowserSessionState, 'port' | 'identity' | 'pid'> & {
|
|
48
67
|
pid: number;
|
|
49
|
-
capabilities?: BrowserSessionCapabilities;
|
|
50
68
|
};
|
|
51
|
-
type AttachedBrowserSessionInput = Omit<BrowserSessionState, 'port' | 'identity' | 'pid' | 'profile'
|
|
52
|
-
capabilities?: BrowserSessionCapabilities;
|
|
69
|
+
type AttachedBrowserSessionInput = Omit<BrowserSessionState, 'port' | 'identity' | 'pid' | 'profile'> & {
|
|
53
70
|
browserInstanceRef?: string;
|
|
54
71
|
provider?: string;
|
|
55
72
|
};
|
|
73
|
+
export declare function isStickyOwnerMetadata(value: unknown): value is StickyOwnerMetadata;
|
|
74
|
+
export declare function canPersistStickyOwnerMetadata(value: unknown): value is StickyOwnerMetadata & {
|
|
75
|
+
transport: StickyOwnerPlaywrightBindTransport;
|
|
76
|
+
};
|
|
77
|
+
export declare function buildStickyOwnerMetadata(input: {
|
|
78
|
+
hostId: string;
|
|
79
|
+
state: StickyOwnerState;
|
|
80
|
+
startedAt: string;
|
|
81
|
+
lastUsedAt?: string;
|
|
82
|
+
ttlMs?: number;
|
|
83
|
+
touchPath?: string;
|
|
84
|
+
browserSessionId: string;
|
|
85
|
+
transport: StickyOwnerTransport;
|
|
86
|
+
pid?: number;
|
|
87
|
+
}): StickyOwnerMetadata;
|
|
56
88
|
export declare function parseSessionPort(cdpUrl: string): number | undefined;
|
|
57
89
|
/** Converts a CDP websocket or HTTP endpoint into the matching DevTools HTTP endpoint. */
|
|
58
90
|
export declare function buildCdpHttpEndpointUrl(cdpUrl: string, resourcePath?: '/json/version' | '/json/list'): string | null;
|
|
@@ -79,8 +111,6 @@ export declare function buildOwnedSession(session: ManagedBrowserSessionInput):
|
|
|
79
111
|
export declare function buildAttachedSession(session: AttachedBrowserSessionInput): BrowserSessionState;
|
|
80
112
|
/** Returns the most likely DevTools port for the current session. */
|
|
81
113
|
export declare function getSessionPort(session: BrowserSessionState | null): number;
|
|
82
|
-
/** Returns `true` when the session advertises captcha-solving capability. */
|
|
83
|
-
export declare function supportsCaptchaSolve(session: BrowserSessionState | null): boolean;
|
|
84
114
|
/** Returns `true` when the session belongs to an AgentBrowse-managed browser. */
|
|
85
115
|
export declare function isOwnedSession(session: BrowserSessionState | null | undefined): session is BrowserSessionState & {
|
|
86
116
|
identity: BrowseSessionIdentity;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-session-state.d.ts","sourceRoot":"","sources":["../src/browser-session-state.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,
|
|
1
|
+
{"version":3,"file":"browser-session-state.d.ts","sourceRoot":"","sources":["../src/browser-session-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, unlinkSync, wr
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { scrubProtectedExactValues } from './secrets/protected-exact-value-redaction.js';
|
|
5
|
+
export const STICKY_OWNER_SCHEMA_VERSION = 1;
|
|
5
6
|
const BLOCKED_SESSION_KEYS = new Set([
|
|
6
7
|
'rawValue',
|
|
7
8
|
'rawValues',
|
|
@@ -21,6 +22,67 @@ function ensureStateDir(stateDir) {
|
|
|
21
22
|
mkdirSync(stateDir, { recursive: true });
|
|
22
23
|
}
|
|
23
24
|
}
|
|
25
|
+
function isStickyOwnerTransport(value) {
|
|
26
|
+
if (!value || typeof value !== 'object') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const candidate = value;
|
|
30
|
+
if (candidate.type === 'in_process') {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
if (candidate.type !== 'playwright_bind') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
const endpointCandidate = candidate.endpoint;
|
|
37
|
+
const endpoint = typeof endpointCandidate === 'string' ? endpointCandidate.trim() : '';
|
|
38
|
+
const mode = candidate.mode;
|
|
39
|
+
return endpoint.length > 0 && (mode === 'pipe' || mode === 'ws');
|
|
40
|
+
}
|
|
41
|
+
function isStickyOwnerState(value) {
|
|
42
|
+
return (value === 'bootstrapping' || value === 'active' || value === 'recovering' || value === 'dead');
|
|
43
|
+
}
|
|
44
|
+
export function isStickyOwnerMetadata(value) {
|
|
45
|
+
if (!value || typeof value !== 'object') {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const candidate = value;
|
|
49
|
+
return (candidate.version === STICKY_OWNER_SCHEMA_VERSION &&
|
|
50
|
+
typeof candidate.hostId === 'string' &&
|
|
51
|
+
candidate.hostId.trim().length > 0 &&
|
|
52
|
+
isStickyOwnerState(candidate.state) &&
|
|
53
|
+
typeof candidate.startedAt === 'string' &&
|
|
54
|
+
candidate.startedAt.trim().length > 0 &&
|
|
55
|
+
(candidate.lastUsedAt === undefined ||
|
|
56
|
+
(typeof candidate.lastUsedAt === 'string' && candidate.lastUsedAt.trim().length > 0)) &&
|
|
57
|
+
(candidate.ttlMs === undefined ||
|
|
58
|
+
(typeof candidate.ttlMs === 'number' &&
|
|
59
|
+
Number.isFinite(candidate.ttlMs) &&
|
|
60
|
+
candidate.ttlMs > 0)) &&
|
|
61
|
+
(candidate.touchPath === undefined ||
|
|
62
|
+
(typeof candidate.touchPath === 'string' && candidate.touchPath.trim().length > 0)) &&
|
|
63
|
+
typeof candidate.browserSessionId === 'string' &&
|
|
64
|
+
candidate.browserSessionId.trim().length > 0 &&
|
|
65
|
+
isStickyOwnerTransport(candidate.transport) &&
|
|
66
|
+
(candidate.pid === undefined ||
|
|
67
|
+
(typeof candidate.pid === 'number' && Number.isFinite(candidate.pid) && candidate.pid > 0)));
|
|
68
|
+
}
|
|
69
|
+
export function canPersistStickyOwnerMetadata(value) {
|
|
70
|
+
return isStickyOwnerMetadata(value) && value.transport.type === 'playwright_bind';
|
|
71
|
+
}
|
|
72
|
+
export function buildStickyOwnerMetadata(input) {
|
|
73
|
+
return {
|
|
74
|
+
version: STICKY_OWNER_SCHEMA_VERSION,
|
|
75
|
+
hostId: input.hostId,
|
|
76
|
+
state: input.state,
|
|
77
|
+
startedAt: input.startedAt,
|
|
78
|
+
...(input.lastUsedAt ? { lastUsedAt: input.lastUsedAt } : {}),
|
|
79
|
+
...(typeof input.ttlMs === 'number' ? { ttlMs: input.ttlMs } : {}),
|
|
80
|
+
...(input.touchPath ? { touchPath: input.touchPath } : {}),
|
|
81
|
+
browserSessionId: input.browserSessionId,
|
|
82
|
+
transport: input.transport,
|
|
83
|
+
...(typeof input.pid === 'number' ? { pid: input.pid } : {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
24
86
|
function atomicWriteJson(path, contents) {
|
|
25
87
|
const tempPath = `${path}.${process.pid}.tmp`;
|
|
26
88
|
try {
|
|
@@ -136,7 +198,7 @@ export function createBrowserSessionStore(options = {}) {
|
|
|
136
198
|
}
|
|
137
199
|
try {
|
|
138
200
|
const raw = JSON.parse(readFileSync(sessionPath, 'utf-8'));
|
|
139
|
-
if (!raw.cdpUrl) {
|
|
201
|
+
if (!raw.cdpUrl || !canPersistStickyOwnerMetadata(raw.stickyOwner)) {
|
|
140
202
|
return null;
|
|
141
203
|
}
|
|
142
204
|
return raw;
|
|
@@ -221,10 +283,6 @@ export function getSessionPort(session) {
|
|
|
221
283
|
}
|
|
222
284
|
return 9222;
|
|
223
285
|
}
|
|
224
|
-
/** Returns `true` when the session advertises captcha-solving capability. */
|
|
225
|
-
export function supportsCaptchaSolve(session) {
|
|
226
|
-
return session?.capabilities?.captchaSolve === true;
|
|
227
|
-
}
|
|
228
286
|
/** Returns `true` when the session belongs to an AgentBrowse-managed browser. */
|
|
229
287
|
export function isOwnedSession(session) {
|
|
230
288
|
if (!session?.identity) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../../src/commands/act.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAgBzE,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AA6BtB,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"act.d.ts","sourceRoot":"","sources":["../../src/commands/act.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAgBzE,OAAO,EAIL,KAAK,qBAAqB,EAC1B,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AA6BtB,OAAO,EAAE,cAAc,EAAE,KAAK,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAwCxF,2DAA2D;AAC3D,eAAO,MAAM,eAAe,oWAgBlB,CAAC;AAEX,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,8FAMpB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5D,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,8CAA8C;AAC9C,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAC5C,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,yEAAyE;AACzE,MAAM,MAAM,yBAAyB,GAAG,qBAAqB,GAAG;IAC9D,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,EAAE,UAAU,CAAC;IAC3B,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC,cAAc,EAAE,eAAe,GAAG,SAAS,GAAG,aAAa,CAAC,CAAC;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,6EAA6E;AAC7E,MAAM,MAAM,yBAAyB,GAAG,YAAY,GAAG;IACrD,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,EAAE,QAAQ,CAAC;IACzB,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC,cAAc,EAAE,eAAe,GAAG,SAAS,CAAC,CAAC;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,yBAAyB,GAAG,yBAAyB,CAAC;AAErF,MAAM,MAAM,SAAS,GAAG,gBAAgB,GAAG,gBAAgB,CAAC;AAmK5D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC1C,YAAY,EAAE,YAAY,EAAE,CAAC;AA+Q7B,wBAAsB,UAAU,CAC9B,OAAO,EAAE,qBAAqB,EAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,CAAC,CA24BpB;AAED,wBAAsB,GAAG,CACvB,OAAO,EAAE,qBAAqB,EAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAaf"}
|