@outcrawl/sdk 0.1.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.
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Human input — the default path, not a flag.
3
+ *
4
+ * `page.click()` lands here; `page.raw.click()` is Playwright's. That ordering
5
+ * is deliberate: the failure mode we care about is someone forgetting to opt
6
+ * in, not someone forgetting to opt out. An agent that reasons perfectly and
7
+ * clicks like a robot is still a robot.
8
+ *
9
+ * The constants below are the measured ones from the product surface (§6.4),
10
+ * taken from real human sessions rather than guessed, alongside what Playwright
11
+ * does by default:
12
+ *
13
+ * | | human | Playwright default |
14
+ * |---|---|---|
15
+ * | click landing offset | mean 8.1px, sd 15.0 | 0.0, sd 0.0 — exact bbox centre |
16
+ * | key flight | mean 127ms, sd 89.4 | sd 34.3 |
17
+ * | sub-movements per stroke | median 3 | 30, with per-sample tremor |
18
+ * | peak-velocity position | 0.40 | 0.50 for any eased curve |
19
+ * | fractional coordinates | ~100% | 0% in some stacks |
20
+ *
21
+ * Two things this cannot fix from the client — `getCoalescedEvents()` returning
22
+ * 1 and `PointerEvent.pressure` always 0 — are properties of where the event
23
+ * enters the stack, and are fixed in the browser's C++.
24
+ *
25
+ * `agenthands` (aeonmindai/agenthands v1.1.1) is the reference implementation of
26
+ * this interface. It is not vendored here: {@link Hands} is the seam, and a
27
+ * caller passes `new Outcrawl({ hands })` to swap the driver. The built-in
28
+ * {@link createPlaywrightHands} drives the same measured model through
29
+ * Playwright's mouse and keyboard so the SDK is not inert without it.
30
+ *
31
+ * `scroll` is the one method that does NOT re-derive its model here, and the
32
+ * asymmetry is deliberate. Pointer and keyboard timing reduce to the five
33
+ * constants above; a scroll is a sequence of GESTURES with a phase per event, a
34
+ * per-device granularity and three measured distributions behind it, and a
35
+ * second copy of that would be a second thing to recalibrate. So `scroll`
36
+ * delegates to `agenthands`, which owns the model, and supplies the
37
+ * `Outcrawl.dispatchWheelPath` dispatcher the session hands it. Without a
38
+ * dispatcher the library falls back to `mouse.wheel()` on its own, which is what
39
+ * a caller driving a stock browser gets.
40
+ */
41
+ export interface BoundingBox {
42
+ x: number;
43
+ y: number;
44
+ width: number;
45
+ height: number;
46
+ }
47
+ export interface RawLocator {
48
+ boundingBox(options?: {
49
+ timeout?: number;
50
+ }): Promise<BoundingBox | null>;
51
+ scrollIntoViewIfNeeded(options?: {
52
+ timeout?: number;
53
+ }): Promise<void>;
54
+ focus(options?: {
55
+ timeout?: number;
56
+ }): Promise<void>;
57
+ fill(value: string, options?: {
58
+ timeout?: number;
59
+ }): Promise<void>;
60
+ selectOption(values: string[], options?: {
61
+ timeout?: number;
62
+ }): Promise<string[]>;
63
+ }
64
+ export interface RawMouse {
65
+ move(x: number, y: number, options?: {
66
+ steps?: number;
67
+ }): Promise<void>;
68
+ down(options?: {
69
+ button?: 'left' | 'right' | 'middle';
70
+ clickCount?: number;
71
+ }): Promise<void>;
72
+ up(options?: {
73
+ button?: 'left' | 'right' | 'middle';
74
+ clickCount?: number;
75
+ }): Promise<void>;
76
+ /**
77
+ * `Input.dispatchMouseWheel`, one event per call. Here because it is the
78
+ * fallback route for {@link Hands.scroll} — the one a caller gets when the
79
+ * browser has no batched wheel entry point, which is every browser but ours.
80
+ */
81
+ wheel(deltaX: number, deltaY: number): Promise<void>;
82
+ }
83
+ export interface RawKeyboard {
84
+ press(key: string, options?: {
85
+ delay?: number;
86
+ }): Promise<void>;
87
+ insertText(text: string): Promise<void>;
88
+ }
89
+ /**
90
+ * The slice of Playwright's `Page` this package types against.
91
+ *
92
+ * Two jobs. It is what the human-input driver calls — `mouse`, `keyboard`,
93
+ * `locator` — and it is the floor under `page.raw`, so the escape hatch is
94
+ * usable without a caller having to parameterise the page type. A caller who
95
+ * does supply their real `Page` gets all of it: `OutcrawlPage` is generic in
96
+ * the page type and never narrows it.
97
+ *
98
+ * Options are typed loosely on purpose. This is a floor, not a re-declaration
99
+ * of Playwright's API, and pinning every option object here would mean
100
+ * tracking Playwright's releases to keep an assignability check passing.
101
+ */
102
+ export interface RawPage {
103
+ readonly mouse: RawMouse;
104
+ readonly keyboard: RawKeyboard;
105
+ locator(selector: string): RawLocator;
106
+ url(): string;
107
+ close(options?: {
108
+ runBeforeUnload?: boolean;
109
+ }): Promise<void>;
110
+ click(selector: string, options?: Record<string, unknown>): Promise<void>;
111
+ dblclick(selector: string, options?: Record<string, unknown>): Promise<void>;
112
+ fill(selector: string, value: string, options?: Record<string, unknown>): Promise<void>;
113
+ hover(selector: string, options?: Record<string, unknown>): Promise<void>;
114
+ press(selector: string, key: string, options?: Record<string, unknown>): Promise<void>;
115
+ type(selector: string, text: string, options?: Record<string, unknown>): Promise<void>;
116
+ check(selector: string, options?: Record<string, unknown>): Promise<void>;
117
+ uncheck(selector: string, options?: Record<string, unknown>): Promise<void>;
118
+ focus(selector: string, options?: Record<string, unknown>): Promise<void>;
119
+ selectOption(selector: string, values: unknown, options?: Record<string, unknown>): Promise<string[]>;
120
+ goto(url: string, options?: Record<string, unknown>): Promise<unknown>;
121
+ content(): Promise<string>;
122
+ title(): Promise<string>;
123
+ waitForSelector(selector: string, options?: Record<string, unknown>): Promise<unknown>;
124
+ }
125
+ export type WheelPhase = 'began' | 'changed' | 'stationary' | 'ended' | 'cancelled';
126
+ export interface WheelSample {
127
+ /** Milliseconds from the start of the path. Non-decreasing; the first is 0. */
128
+ offsetMs: number;
129
+ /** CSS pixels. Positive `deltaY` scrolls the content down. */
130
+ deltaX: number;
131
+ deltaY: number;
132
+ phase: WheelPhase;
133
+ /** macOS momentum, for a caller replaying a recorded gesture that had one. */
134
+ momentumPhase?: 'began' | 'changed' | 'ended' | 'cancelled';
135
+ }
136
+ export interface WheelPath {
137
+ /** Viewport-relative CSS pixels. One point for the whole path: the browser's
138
+ * own wheel-latching slop region is 10 CSS pixels, and a cursor that moves
139
+ * during a scroll is a pointer path, not a wheel one. */
140
+ x: number;
141
+ y: number;
142
+ path: WheelSample[];
143
+ granularity: 'precisePixel' | 'pixel';
144
+ }
145
+ /** Dispatches a whole gesture through a browser entry point that takes phases. */
146
+ export type WheelPathDispatcher = (path: WheelPath) => Promise<unknown>;
147
+ /**
148
+ * Input the browser refused to deliver, rather than input that failed.
149
+ *
150
+ * `Outcrawl.dispatchWheelPath` refuses while `Outcrawl.lock` is held, by design:
151
+ * the lock's `ScopedIgnoreInputEvents` drops every event before the renderer
152
+ * sees it, so a command that reported success would be lying. That refusal is a
153
+ * statement about the caller's own lock discipline and not about the page, so it
154
+ * arrives as itself instead of as a failed step.
155
+ */
156
+ export declare class InputRefusedError extends Error {
157
+ /** The refusal as the browser worded it. */
158
+ readonly refusal: string;
159
+ constructor(what: string, refusal: string);
160
+ }
161
+ /**
162
+ * One bound set of hands. Bound, not static: personas bind to the profile, so
163
+ * the same identity keeps the same typing pace and click character across
164
+ * sessions. Real typing pace varies 3.6x between people, and an identity that
165
+ * returns at a different speed every visit is describing someone who is not the
166
+ * same person.
167
+ */
168
+ export interface Hands {
169
+ click(page: RawPage, selector: string): Promise<void>;
170
+ fill(page: RawPage, selector: string, value: string): Promise<void>;
171
+ type(page: RawPage, selector: string, text: string): Promise<void>;
172
+ hover(page: RawPage, selector: string): Promise<void>;
173
+ press(page: RawPage, selector: string, key: string): Promise<void>;
174
+ selectOption(page: RawPage, selector: string, values: readonly string[]): Promise<void>;
175
+ /**
176
+ * Scroll `deltaY` CSS pixels; positive scrolls down.
177
+ *
178
+ * `selector` decides only WHERE the gesture happens — the browser latches the
179
+ * scroll to whatever is under the cursor — so it is optional and its absence
180
+ * means "where the cursor already is", which is what a page scroll is.
181
+ *
182
+ * Throws {@link InputRefusedError} when the browser refused the gesture rather
183
+ * than failing to deliver it, which today means the session is holding
184
+ * `Outcrawl.lock`.
185
+ */
186
+ scroll(page: RawPage, deltaY: number, selector?: string): Promise<void>;
187
+ }
188
+ /**
189
+ * What a set of hands is bound to when the session mints it.
190
+ *
191
+ * An object rather than a bare persona string because the persona is not the
192
+ * only thing a driver needs from the session: the batched wheel entry point is
193
+ * a property of the browser on the other end of the connection, and passing it
194
+ * per call would make a session-wide capability look like a per-call option.
195
+ */
196
+ export interface HandsBinding {
197
+ /**
198
+ * Persona token minted with the session. Opaque, and never chosen by the
199
+ * caller — identity is not customer-visible.
200
+ */
201
+ readonly persona: string;
202
+ /**
203
+ * The browser's batched wheel entry point, when the connection has one. Absent
204
+ * for any browser but ours, and a driver must still scroll without it.
205
+ */
206
+ readonly wheelPath?: WheelPathDispatcher;
207
+ }
208
+ /** Binds hands to one session. */
209
+ export type HandsFactory = (binding: HandsBinding) => Hands;
210
+ export type Sleep = (ms: number) => Promise<void>;
211
+ /** What `createHands` hands back, narrowed to the one method used here. */
212
+ export interface AgentHandsScroller {
213
+ scroll(deltaY: number): Promise<void>;
214
+ }
215
+ export interface AgentHandsOptions {
216
+ /** Binds the gesture model to one identity, as the persona binds typing pace. */
217
+ persona?: string | number;
218
+ seed?: number;
219
+ /** Where the gesture happens. One point for the whole path. */
220
+ start?: {
221
+ x: number;
222
+ y: number;
223
+ };
224
+ wheelPath?: WheelPathDispatcher;
225
+ }
226
+ /**
227
+ * The slice of `agenthands` the built-in driver calls.
228
+ *
229
+ * `scroll()` reaches for `mouse.wheel` and an optional `evaluate` probe and
230
+ * nothing else, so the page is typed as that much. A real Playwright `Page`
231
+ * satisfies the library's own `PageLike` in full; {@link RawPage} is the
232
+ * narrower floor this package types against and does not declare the keyboard
233
+ * methods `PageLike` asks for, none of which a scroll touches.
234
+ */
235
+ export interface AgentHandsModule {
236
+ createHands(page: {
237
+ readonly mouse: Pick<RawMouse, 'wheel'>;
238
+ }, options?: AgentHandsOptions): AgentHandsScroller;
239
+ }
240
+ export type AgentHandsLoader = () => Promise<AgentHandsModule>;
241
+ export interface PlaywrightHandsOptions {
242
+ /**
243
+ * Injected so timing can be collapsed in tests. Nothing else about the model
244
+ * changes: the same samples are drawn, they are just not waited out.
245
+ */
246
+ sleep?: Sleep;
247
+ /**
248
+ * Loads the scroll model. Injected so the seam is testable without resolving
249
+ * the package, and overridable by a caller who vendors it.
250
+ */
251
+ loadAgentHands?: AgentHandsLoader;
252
+ }
253
+ /**
254
+ * The built-in driver. Same measured model as `agenthands`, expressed through
255
+ * Playwright's mouse and keyboard, so the SDK produces human input out of the
256
+ * box rather than only when a caller remembers to install a second package.
257
+ * `scroll` is the exception and delegates — see the note at the top of this file.
258
+ */
259
+ export declare function createPlaywrightHands(options?: PlaywrightHandsOptions): HandsFactory;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * `@outcrawl/sdk` — the typed client, and the Playwright integration.
3
+ *
4
+ * ```ts
5
+ * import { Outcrawl } from '@outcrawl/sdk';
6
+ * const oc = new Outcrawl({ apiKey: process.env.OUTCRAWL_KEY });
7
+ *
8
+ * const browser = await oc.browser({ profile: 'acme-user-42' });
9
+ * const page = await browser.newPage();
10
+ * await page.click('#login'); // human input, by default
11
+ * await page.raw.click('#login'); // Playwright's, and recorded
12
+ * ```
13
+ *
14
+ * The API is the truth; this is a transport over it. Every capability in
15
+ * `@outcrawl/core`'s registry is reachable from this client under its own
16
+ * dotted name, and a test in this package fails if one is not.
17
+ *
18
+ * The one thing here that is not in the API, MCP or the CLI is the live page —
19
+ * `page.act`, `page.observe`, `page.extract` — because it needs a CDP
20
+ * connection in the caller's own process. That is a difference in kind, not an
21
+ * omission: the other surfaces reach the same capabilities through `agent` and
22
+ * `scrape`, which run the loop on our side.
23
+ */
24
+ /**
25
+ * `API_KEY_ENV` and `API_URL_ENV` are exported because a caller who wants to
26
+ * say "set OUTCRAWL_API_KEY" in their own error message should read the name
27
+ * off the client rather than retyping it — a retyped variable name is a
28
+ * customer told to set a variable nothing reads.
29
+ */
30
+ export { API_KEY_ENV, API_URL_ENV, Outcrawl, type OutcrawlOptions } from './client.js';
31
+ export { Browser, IdentityOverrideError, assertNoIdentityOverride, openBrowser, resolveExit, type BrowserDeps, type BrowserOptions, } from './browser.js';
32
+ export { OutcrawlPage, type ActResult, type ExtractResult, type ObservedActions } from './page.js';
33
+ export { Session, SessionControl, Sessions, UnsupportedSessionFilterError, assertSupportedFilter, } from './sessions.js';
34
+ export { Integrations } from './integrations.js';
35
+ export { Profiles } from './profiles.js';
36
+ export { Rules } from './rules.js';
37
+ export { Secrets } from './secrets.js';
38
+ /**
39
+ * Which declared capabilities this SDK actually serves. Exported because a
40
+ * caller integrating against `monitors.*` deserves to discover it from the
41
+ * types rather than from a 503 at runtime.
42
+ */
43
+ export { CAPABILITY_AVAILABILITY, assertAvailable, type Unavailable, } from './availability.js';
44
+ export { Monitors } from './monitors.js';
45
+ export { AgentEvents, AgentHandle, AgentJob, InvalidAgentRequestError, agent, createAgentApi, type AgentApi, type AgentEventOptions, type AgentResultsOptions, } from './agent.js';
46
+ export { CrawlHandle, crawl, scrape, search, type CrawlOptions, type ScrapeOptions, type SearchHits, type SearchOptions, } from './scrape.js';
47
+ export { deletedFrom, inlineUsage, pagedFrom, queryOf, unwrapItem, withUsage, type ClientContext, type Deleted, type Paged, type Result, } from './result.js';
48
+ export { HttpTransport, OutcrawlApiError, alwaysStreams, errorFromWire, resolveRequest, streamSwitch, type CdpBrowser, type CdpBrowserContext, type CdpSession, type Connection, type ConnectSpec, type ExtractResponse, type HttpTransportOptions, type ObserveResponse, type RawInputMark, type RequestSpec, type Transport, } from './transport.js';
49
+ export { createPlaywrightHands, InputRefusedError, type AgentHandsLoader, type AgentHandsModule, type AgentHandsOptions, type AgentHandsScroller, type BoundingBox, type Hands, type HandsBinding, type HandsFactory, type PlaywrightHandsOptions, type RawKeyboard, type RawLocator, type RawMouse, type RawPage, type Sleep, type WheelPath, type WheelPathDispatcher, type WheelPhase, type WheelSample, } from './hands.js';
50
+ /**
51
+ * Re-exported so a caller catching a leased profile does not need a second
52
+ * import to name the error, and so `instanceof` is against the same class the
53
+ * SDK threw.
54
+ *
55
+ * EVERY CLASS `errorFromWire` CAN RETURN IS HERE, and the list was audited
56
+ * rather than extended by taste: eight of the fifteen were missing while the
57
+ * transport was already handing them to customers, so the errors a caller is
58
+ * most likely to meet in production — over their plan's rate limit, at their
59
+ * concurrency ceiling, on a key with no plan — were errors they could not name
60
+ * or `instanceof`. `OUTCRAWL_ERROR_CODES` and `isKnownErrorCode` come with
61
+ * them, because branching on `code` is the documented way to handle these and
62
+ * a caller cannot write an exhaustive switch against a union they cannot see.
63
+ */
64
+ export { BadRequestError, CapExceededError, CapabilityUnavailableError, ConcurrencyLimitError, ExitUnavailableError, InternalError, MethodNotAllowedError, NoCapacityError, NotFoundError, OutcrawlError, PlanRequiredError, ProfileInUseError, ProfileNotFoundError, QuotaExceededError, TenantScopeError, UnauthorizedError, isOutcrawlError, isKnownErrorCode, OUTCRAWL_ERROR_CODES, CAPABILITIES, getCapability, PROFILE_KEYS, type Capability, type CapabilityName, type OutcrawlErrorCode, type QuotaCeiling, } from './_deps/core/index.js';
65
+ /**
66
+ * The wire contract.
67
+ *
68
+ * Re-exported because this package is a customer's only door: `@outcrawl/core`
69
+ * is not on npm and is not going to be, so a type that is only nameable from
70
+ * there is a type nobody outside this repository can name.
71
+ *
72
+ * It was not a theoretical gap. `oc.scrape()` is declared to return
73
+ * `Result<ScrapeResult>` and `ScrapeResult` was not exported, so the first
74
+ * thing a customer does with a typed client — annotate the value they just
75
+ * got, or write a helper that takes it — did not compile. Same for
76
+ * `AgentRequest`, which `oc.agent()` takes as its only argument. A typed
77
+ * client whose types cannot be referenced is a client with no types.
78
+ *
79
+ * `scripts/build.ts` asserts this list stays complete: it reads the core types
80
+ * the published declarations actually reference and fails the build if one of
81
+ * them is not exported here, so a new method that returns a new wire type
82
+ * cannot ship unnameable.
83
+ *
84
+ * `PageMetadata`, `PageChallenge`, `PageChallengeOutcome` and `ChallengeWatch`
85
+ * arrived on 2026-09-06 because the assertion is over DIRECT references and
86
+ * these are one hop further: `ScrapeResult.metadata` is a `PageMetadata`, so a
87
+ * customer could always READ `result.metadata.challengeWatch` and could never
88
+ * name its type to switch exhaustively over it. A three-value union a caller
89
+ * is expected to branch on, whose union type is unnameable, is the same defect
90
+ * this block exists to close, one level down.
91
+ *
92
+ * `Secret`, `RulesView` and their one-hop companions arrived with the secrets
93
+ * and rules clients: `oc.secrets.create()` answers a `Result<Secret>` and
94
+ * `oc.rules.get()` a `Result<RulesView>`, and `RulesViewRule.class` and
95
+ * `.gate` are exactly the fields a caller is told to branch on — so the union
96
+ * types behind them have to be nameable or the branch cannot be written.
97
+ */
98
+ export type { AgentEventLevel, AgentRecord, AgentRecordKind, AgentRequest, AgentResult, AgentRun, AgentRunStatus, AgentStep, AgentStopReason, AgentSubmission, BilledResources, ChallengeWatch, CrawlJob, CrawlPage, CrawlRequest, CreditBalance, ExitSpec, ExitTarget, HttpMethod, JsonSchema, Monitor, MonitorQuery, MonitorSpec, ObservedAction, PageChallenge, PageChallengeOutcome, PageMetadata, Profile, ProfileCreateRequest, ProfileQuery, ResolvedExit, RuleClass, RuleGate, RulesView, RulesViewRule, ScrapeRequest, ScrapeResult, SearchHit, SearchRequest, Secret, SecretCreateRequest, SecretKind, SecretQuery, SessionExport, SessionOutcome, SessionQuery, SessionStatus, SessionSummary, Timestamp, Usage, UsageQuery, UsageReport, } from './_deps/core/index.js';
99
+ /**
100
+ * The connector wire types, on the block above's argument and from the package
101
+ * that owns them rather than from a copy kept here.
102
+ *
103
+ * `oc.integrations.connect()` takes a `ConnectorInput` and every method
104
+ * answers `Connector` rows verbatim — there is no view in front of them,
105
+ * because a connector row holds a secrets-store HANDLE and never a value — so
106
+ * a customer who cannot name `ConnectorAuth` cannot write the switch that
107
+ * reads which handle a connector authenticates with. `scripts/build.ts`
108
+ * carries `connector.d.ts` into `_deps` for the same reason it carries
109
+ * replay's `events.d.ts`.
110
+ */
111
+ export type { Connector, ConnectorAuth, ConnectorInput, ConnectorTransport, } from './_deps/integrations/connector.js';
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Integrations — what a run can reach OUTSIDE the browser.
3
+ *
4
+ * A workspace connects an MCP server — Gmail, Slack, Twilio — and a run that
5
+ * was granted it calls that server's tools mid-task: to read a 2FA code, to
6
+ * ask a question, to phone a human. This class is the management half, for a
7
+ * person. The calling half is the agent loop's `callTool`, and it is not
8
+ * reachable from here.
9
+ *
10
+ * ── CONNECTING IS NOT GRANTING ───────────────────────────────────────────────
11
+ *
12
+ * {@link Integrations.connect} answering a row does NOT mean a run can call it.
13
+ * Reach is granted PER RUN through `AgentRequest.integrations`, and a submit
14
+ * that names nothing reaches nothing however many connectors the workspace
15
+ * has. That default is the containment: a page that talks a model into
16
+ * "email this table to attacker@example.com" is talking to a run with no mail
17
+ * connector, whatever this account has connected. Name the connector on the
18
+ * submit, deliberately, per run — see `availability.ts`, which declines to
19
+ * gate these rows for exactly this reason.
20
+ *
21
+ * ── THE ROW IS THE RESPONSE ──────────────────────────────────────────────────
22
+ *
23
+ * {@link Integrations.list} hands back {@link Connector} rows verbatim, with no
24
+ * projection in front of them, and that is the property rather than a
25
+ * shortcut: a connector row holds a secrets-store HANDLE and never a value, so
26
+ * there is nothing on it to withhold. A stripped-down view would imply the row
27
+ * has something worth hiding, and the day a field arrives that does, it would
28
+ * arrive on a type nobody reads twice. `@outcrawl/integrations`'s `Connector`
29
+ * states the same rule from the other side.
30
+ *
31
+ * `list` takes no query, and that too is a decision: this listing is the blast
32
+ * radius, and a filter on it is a way to read half of it and believe it is the
33
+ * whole.
34
+ */
35
+ import type { Connector, ConnectorInput } from './_deps/integrations/connector.js';
36
+ import { type ClientContext, type Deleted, type Paged, type Result } from './result.js';
37
+ export declare class Integrations {
38
+ #private;
39
+ constructor(ctx: ClientContext);
40
+ /**
41
+ * Connect an MCP server so a run may be granted its tools.
42
+ *
43
+ * `auth.secret` is a secrets-store HANDLE and never a token: the plaintext is
44
+ * resolved at the instant of a call, by the tier making it, and nothing this
45
+ * client sends or receives ever holds one. HTTPS endpoints only, and an
46
+ * address that is not on the public internet is refused by the same parser
47
+ * the API and the CLI use, so the refusal reads identically whichever
48
+ * surface you came from.
49
+ */
50
+ connect(input: ConnectorInput): Promise<Result<Connector>>;
51
+ /**
52
+ * Every connected server, the tools it exposes, and the handle it
53
+ * authenticates with. `tools: null` means every tool the remote advertises.
54
+ */
55
+ list(): Promise<Paged<Connector>>;
56
+ /**
57
+ * Disconnect a server. Takes effect on the next call: a run already holding
58
+ * a grant finds the connector gone and is told so, rather than being cut off
59
+ * mid-step. The credential is untouched — it lives in the secrets store and
60
+ * is deleted there.
61
+ */
62
+ delete(id: string): Promise<Result<Deleted>>;
63
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Monitors — declared, and not served.
3
+ *
4
+ * Every method here refuses with {@link CapabilityUnavailableError}. The
5
+ * methods still exist, and that is deliberate: the registry declares these
6
+ * rows, the coverage test in this package walks the registry to the client, and
7
+ * a capability that is silently absent from the client is the same omission in
8
+ * the other direction. A named refusal that says what is missing is reachable,
9
+ * greppable and honest; a missing property is a `TypeError` about `undefined`.
10
+ *
11
+ * The refusal is raised inside `resolveRequest`, not written out per method, so
12
+ * it cannot be forgotten by a method added later. See `availability.ts` for
13
+ * what is missing — in short: nothing runs a monitor's schedule, so a created
14
+ * monitor would be stored and never checked.
15
+ */
16
+ import type { Monitor, MonitorQuery, MonitorSpec } from './_deps/core/index.js';
17
+ import { type ClientContext, type Deleted, type Paged, type Result } from './result.js';
18
+ export declare class Monitors {
19
+ #private;
20
+ constructor(ctx: ClientContext);
21
+ create(spec: MonitorSpec): Promise<Result<Monitor>>;
22
+ list(query?: MonitorQuery): Promise<Paged<Monitor>>;
23
+ delete(id: string): Promise<Result<Deleted>>;
24
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The live page — the one surface that exists in the SDK and nowhere else.
3
+ *
4
+ * `page.click()` goes through human input. `page.raw.click()` is Playwright's,
5
+ * untouched, for setup where speed matters. Both are supported; only one is the
6
+ * default, and it is the safe one, because the failure mode that costs a
7
+ * customer their account is someone forgetting to opt *in*.
8
+ *
9
+ * `observe()` and `act()` are the other half. `observe()` resolves an
10
+ * instruction to actions and executes none of them, which makes it both the
11
+ * review point and the action-cache unit: a hit replays the resolved action with
12
+ * zero model tokens.
13
+ */
14
+ import type { JsonSchema, ObservedAction, Usage } from './_deps/core/index.js';
15
+ import type { Hands, RawPage } from './hands.js';
16
+ import type { Connection, RawInputMark } from './transport.js';
17
+ /**
18
+ * Reviewable actions, with the usage the resolution cost carried on the array
19
+ * itself — the same shape as search hits, and for the same reason: usage rides
20
+ * on the result that caused it.
21
+ */
22
+ export type ObservedActions = readonly ObservedAction[] & {
23
+ readonly usage: Usage;
24
+ };
25
+ export interface ExtractResult<T> {
26
+ data: T;
27
+ usage: Usage;
28
+ }
29
+ /** What `act()` actually did. One action, named, with what it cost. */
30
+ export interface ActResult {
31
+ action: ObservedAction;
32
+ usage: Usage;
33
+ }
34
+ export interface OutcrawlPageInit<TRaw extends RawPage> {
35
+ page: TRaw;
36
+ hands: Hands;
37
+ connection: Connection;
38
+ onRaw: (mark: RawInputMark) => void;
39
+ }
40
+ /**
41
+ * A Playwright page with human input under the familiar names.
42
+ *
43
+ * Generic in the page type so `page.raw` is the caller's real Playwright
44
+ * `Page` — everything an existing script does keeps working, and the SDK never
45
+ * narrows the escape hatch to the subset it happens to call itself.
46
+ */
47
+ export declare class OutcrawlPage<TRaw extends RawPage = RawPage> {
48
+ #private;
49
+ /**
50
+ * Playwright's own surface, untouched, and recorded. Every input call through
51
+ * here is marked on the session: a checkout run that reached for `raw` is
52
+ * visibly flagged rather than silently different, so whoever reads the replay
53
+ * after a block is not guessing.
54
+ */
55
+ readonly raw: TRaw;
56
+ constructor(init: OutcrawlPageInit<TRaw>);
57
+ get sessionId(): string;
58
+ url(): string;
59
+ click(selector: string): Promise<void>;
60
+ fill(selector: string, value: string): Promise<void>;
61
+ type(selector: string, text: string): Promise<void>;
62
+ hover(selector: string): Promise<void>;
63
+ press(selector: string, key: string): Promise<void>;
64
+ selectOption(selector: string, values: readonly string[]): Promise<void>;
65
+ /**
66
+ * Scroll `deltaY` CSS pixels; positive scrolls down. `selector` aims the
67
+ * gesture at an element, because the browser latches a scroll to whatever is
68
+ * under the cursor; without one the gesture happens where the pointer is,
69
+ * which is what a page scroll is.
70
+ *
71
+ * Not `page.raw.mouse.wheel()`, and not a `scrollIntoView()` jump. Both land
72
+ * as `Input.dispatchMouseWheel` or as no wheel event at all, and this goes
73
+ * through the browser's own gesture entry point — see {@link Hands.scroll}.
74
+ */
75
+ scroll(deltaY: number, selector?: string): Promise<void>;
76
+ /**
77
+ * Resolve an instruction to the actions that *could* be taken. Executes none
78
+ * of them — that is the whole contract, and it is what makes the returned
79
+ * array reviewable and cacheable.
80
+ */
81
+ observe(instruction: string, options?: {
82
+ cache?: boolean;
83
+ }): Promise<ObservedActions>;
84
+ /**
85
+ * Perform exactly one action.
86
+ *
87
+ * Given an {@link ObservedAction} from `observe()`, it replays that action
88
+ * with no model call at all. Given a string, it resolves the instruction
89
+ * first and performs the best candidate — one inference, one action.
90
+ */
91
+ act(action: ObservedAction | string, options?: {
92
+ cache?: boolean;
93
+ }): Promise<ActResult>;
94
+ extract<T = unknown>(instruction: string, schema?: JsonSchema): Promise<ExtractResult<T>>;
95
+ close(): Promise<void>;
96
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Profiles — a durable identity and its storage.
3
+ *
4
+ * The caller names it and nothing else. Everything that makes the identity —
5
+ * seed, chrome-or-brave, fingerprint, timezone, languages, WebRTC address — is
6
+ * minted by us, pinned for the profile's life, and never appears on this type.
7
+ * `Profile` has no `identity` field and there will never be one: the operator
8
+ * side runs the identity loop, the customer side sees outcomes.
9
+ */
10
+ import { PROFILE_KEYS, type Profile, type ProfileCreateRequest, type ProfileQuery } from './_deps/core/index.js';
11
+ import { type ClientContext, type Deleted, type Paged, type Result } from './result.js';
12
+ export declare class Profiles {
13
+ #private;
14
+ constructor(ctx: ClientContext);
15
+ create(request: ProfileCreateRequest): Promise<Result<Profile>>;
16
+ list(query?: ProfileQuery): Promise<Paged<Profile>>;
17
+ get(id: string): Promise<Result<Profile>>;
18
+ /** Deletes the profile and its stored cookies and site data. Irreversible. */
19
+ delete(id: string): Promise<Result<Deleted>>;
20
+ }
21
+ /**
22
+ * The keys a `Profile` is allowed to have, straight from core. Exported so the
23
+ * "no identity, ever" rule is checkable by anything holding a profile, not only
24
+ * by this package's tests.
25
+ */
26
+ export { PROFILE_KEYS };