@modelprofile.com/browser-runtime 1.0.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.
Files changed (51) hide show
  1. package/.smartconfig.json +34 -0
  2. package/changelog.md +11 -0
  3. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  4. package/dist_ts/00_commitinfo_data.js +9 -0
  5. package/dist_ts/actions.d.ts +3 -0
  6. package/dist_ts/actions.js +215 -0
  7. package/dist_ts/classes.artifactstore.d.ts +38 -0
  8. package/dist_ts/classes.artifactstore.js +344 -0
  9. package/dist_ts/classes.egressproxy.d.ts +67 -0
  10. package/dist_ts/classes.egressproxy.js +830 -0
  11. package/dist_ts/classes.flexprovider.d.ts +9 -0
  12. package/dist_ts/classes.flexprovider.js +117 -0
  13. package/dist_ts/classes.framed.d.ts +52 -0
  14. package/dist_ts/classes.framed.js +557 -0
  15. package/dist_ts/classes.runtime.d.ts +202 -0
  16. package/dist_ts/classes.runtime.js +1667 -0
  17. package/dist_ts/confinement.d.ts +2 -0
  18. package/dist_ts/confinement.js +63 -0
  19. package/dist_ts/errors.d.ts +7 -0
  20. package/dist_ts/errors.js +40 -0
  21. package/dist_ts/index.d.ts +11 -0
  22. package/dist_ts/index.js +9 -0
  23. package/dist_ts/interfaces.d.ts +287 -0
  24. package/dist_ts/interfaces.js +2 -0
  25. package/dist_ts/internal.testing.d.ts +9 -0
  26. package/dist_ts/internal.testing.js +2 -0
  27. package/dist_ts/mcp.d.ts +4 -0
  28. package/dist_ts/mcp.js +196 -0
  29. package/dist_ts/plugins.d.ts +20 -0
  30. package/dist_ts/plugins.js +24 -0
  31. package/dist_ts/utils.d.ts +25 -0
  32. package/dist_ts/utils.js +143 -0
  33. package/license.md +21 -0
  34. package/package.json +59 -0
  35. package/readme.hints.md +35 -0
  36. package/readme.md +181 -0
  37. package/ts/00_commitinfo_data.ts +8 -0
  38. package/ts/actions.ts +241 -0
  39. package/ts/classes.artifactstore.ts +432 -0
  40. package/ts/classes.egressproxy.ts +1005 -0
  41. package/ts/classes.flexprovider.ts +134 -0
  42. package/ts/classes.framed.ts +649 -0
  43. package/ts/classes.runtime.ts +2135 -0
  44. package/ts/confinement.ts +90 -0
  45. package/ts/errors.ts +63 -0
  46. package/ts/index.ts +52 -0
  47. package/ts/interfaces.ts +375 -0
  48. package/ts/internal.testing.ts +18 -0
  49. package/ts/mcp.ts +230 -0
  50. package/ts/plugins.ts +28 -0
  51. package/ts/utils.ts +188 -0
@@ -0,0 +1,90 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IBrowserConfinementProbeContext } from './interfaces.js';
3
+ import { BrowserRuntimeError } from './errors.js';
4
+
5
+ const listenOnUnsupportedPort = async (
6
+ allowedPorts: ReadonlySet<number>,
7
+ onRequest: () => void,
8
+ ): Promise<{ server: plugins.http.Server; port: number }> => {
9
+ for (let attempt = 0; attempt < 8; attempt += 1) {
10
+ const server = plugins.http.createServer((_request, response) => {
11
+ onRequest();
12
+ response.writeHead(204);
13
+ response.end();
14
+ });
15
+ await new Promise<void>((resolve, reject) => {
16
+ server.once('error', reject);
17
+ server.listen(0, '127.0.0.1', resolve);
18
+ });
19
+ const address = server.address();
20
+ if (address && typeof address !== 'string' && !allowedPorts.has(address.port)) {
21
+ return { server, port: address.port };
22
+ }
23
+ await new Promise<void>((resolve) => server.close(() => resolve()));
24
+ }
25
+ throw new BrowserRuntimeError('CONFINEMENT_FAILED');
26
+ };
27
+
28
+ export const runProductionConfinementProbe = async (
29
+ context: IBrowserConfinementProbeContext,
30
+ ): Promise<void> => {
31
+ let originHits = 0;
32
+ const fixture = await listenOnUnsupportedPort(
33
+ new Set(context.proxy.allowedTargetPorts),
34
+ () => { originHits += 1; },
35
+ );
36
+ const closeFixture = async (): Promise<void> => new Promise((resolve) => {
37
+ fixture.server.close(() => resolve());
38
+ });
39
+ try {
40
+ const beforeLoopback = context.proxy.getStats();
41
+ await context.session.navigate(
42
+ { url: `http://127.0.0.1:${fixture.port}/browser-runtime-probe`, timeoutMs: 3000 },
43
+ { signal: context.signal },
44
+ ).catch(() => undefined);
45
+ const afterLoopback = context.proxy.getStats();
46
+ if (
47
+ originHits !== 0
48
+ || afterLoopback.ordinaryRequests <= beforeLoopback.ordinaryRequests
49
+ || afterLoopback.rejectedRequests <= beforeLoopback.rejectedRequests
50
+ ) {
51
+ throw new BrowserRuntimeError('CONFINEMENT_FAILED');
52
+ }
53
+
54
+ const beforeInvalid = context.proxy.getStats();
55
+ await context.session.navigate(
56
+ { url: 'http://browser-runtime-confinement.invalid/', timeoutMs: 3000 },
57
+ { signal: context.signal },
58
+ ).catch(() => undefined);
59
+ const afterInvalid = context.proxy.getStats();
60
+ if (
61
+ afterInvalid.ordinaryRequests <= beforeInvalid.ordinaryRequests
62
+ || afterInvalid.rejectedRequests <= beforeInvalid.rejectedRequests
63
+ ) {
64
+ throw new BrowserRuntimeError('CONFINEMENT_FAILED');
65
+ }
66
+
67
+ const result = await context.session.evaluate(
68
+ `new Promise(async (resolve) => {
69
+ const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:1.1.1.1:3478' }] });
70
+ let emitted = false;
71
+ pc.onicecandidate = (event) => { if (event.candidate) emitted = true; };
72
+ pc.createDataChannel('probe');
73
+ try { await pc.setLocalDescription(await pc.createOffer()); } catch {}
74
+ setTimeout(() => { pc.close(); resolve({ candidateEmitted: emitted }); }, 1000);
75
+ })`,
76
+ { timeoutMs: 2500, maxOutputBytes: 1024 },
77
+ { signal: context.signal },
78
+ );
79
+ if (
80
+ !result
81
+ || typeof result !== 'object'
82
+ || Array.isArray(result)
83
+ || (result as Record<string, unknown>).candidateEmitted !== false
84
+ ) {
85
+ throw new BrowserRuntimeError('CONFINEMENT_FAILED');
86
+ }
87
+ } finally {
88
+ await closeFixture();
89
+ }
90
+ };
package/ts/errors.ts ADDED
@@ -0,0 +1,63 @@
1
+ export type TBrowserRuntimeErrorCode =
2
+ | 'ABORTED'
3
+ | 'AUTHORIZATION_DENIED'
4
+ | 'BUSY'
5
+ | 'CAPABILITY_EXPIRED'
6
+ | 'CAPABILITY_INVALID'
7
+ | 'CAPABILITY_REVOKED'
8
+ | 'CONFINEMENT_FAILED'
9
+ | 'EGRESS_DENIED'
10
+ | 'FENCED'
11
+ | 'FRAME_TOO_LARGE'
12
+ | 'INVALID_INPUT'
13
+ | 'LOCKED'
14
+ | 'NOT_RUNNING'
15
+ | 'PROTOCOL_ERROR'
16
+ | 'QUOTA_EXCEEDED'
17
+ | 'TIMEOUT';
18
+
19
+ const publicMessages: Record<TBrowserRuntimeErrorCode, string> = {
20
+ ABORTED: 'The operation was aborted.',
21
+ AUTHORIZATION_DENIED: 'Capability authorization was denied.',
22
+ BUSY: 'The browser project is busy.',
23
+ CAPABILITY_EXPIRED: 'The capability has expired.',
24
+ CAPABILITY_INVALID: 'The capability is invalid.',
25
+ CAPABILITY_REVOKED: 'The capability has been revoked.',
26
+ CONFINEMENT_FAILED: 'Browser confinement could not be confirmed.',
27
+ EGRESS_DENIED: 'The egress target was denied.',
28
+ FENCED: 'The browser project is permanently fenced.',
29
+ FRAME_TOO_LARGE: 'The browser frame exceeded its limit.',
30
+ INVALID_INPUT: 'The request is invalid.',
31
+ LOCKED: 'The browser runtime is already locked.',
32
+ NOT_RUNNING: 'The browser runtime is not running.',
33
+ PROTOCOL_ERROR: 'The framed protocol request is invalid.',
34
+ QUOTA_EXCEEDED: 'A browser runtime quota was exceeded.',
35
+ TIMEOUT: 'The operation timed out.',
36
+ };
37
+
38
+ export class BrowserRuntimeError extends Error {
39
+ public readonly code: TBrowserRuntimeErrorCode;
40
+
41
+ constructor(code: TBrowserRuntimeErrorCode, internalMessage?: string) {
42
+ super(internalMessage ?? publicMessages[code]);
43
+ this.name = 'BrowserRuntimeError';
44
+ this.code = code;
45
+ }
46
+
47
+ public get publicMessage(): string {
48
+ return publicMessages[this.code];
49
+ }
50
+ }
51
+
52
+ export const toBrowserRuntimeError = (error: unknown): BrowserRuntimeError => {
53
+ if (error instanceof BrowserRuntimeError) {
54
+ return error;
55
+ }
56
+ if (
57
+ error instanceof Error
58
+ && (error.name === 'AbortError' || error.name === 'TimeoutError')
59
+ ) {
60
+ return new BrowserRuntimeError(error.name === 'TimeoutError' ? 'TIMEOUT' : 'ABORTED');
61
+ }
62
+ return new BrowserRuntimeError('ABORTED');
63
+ };
package/ts/index.ts ADDED
@@ -0,0 +1,52 @@
1
+ export { validateAgentAction, validateAgentActionResult } from './actions.js';
2
+ export { BrowserArtifactStore } from './classes.artifactstore.js';
3
+ export { BrowserEgressProxy } from './classes.egressproxy.js';
4
+ export { BrowserRuntimeFlexToolProvider } from './classes.flexprovider.js';
5
+ export {
6
+ BrowserRuntimeFramedClient,
7
+ BrowserRuntimeFramedServerPeer,
8
+ } from './classes.framed.js';
9
+ export { BrowserRuntime, BrowserRuntimeLease } from './classes.runtime.js';
10
+ export { BrowserRuntimeError } from './errors.js';
11
+ export { createBrowserRuntimeMcpHttpHandler } from './mcp.js';
12
+
13
+ export type { IAcquireBrowserRuntimeLeaseOptions } from './classes.runtime.js';
14
+ export type { TBrowserRuntimeErrorCode } from './errors.js';
15
+ export type {
16
+ IAttachTrustedFramedPeerOptions,
17
+ IBrowserActionStateResult,
18
+ IBrowserArtifactMetadata,
19
+ IBrowserArtifactStoreOptions,
20
+ IBrowserCapabilityAuthorizationRequest,
21
+ IBrowserCapabilityDescriptor,
22
+ IBrowserClickAction,
23
+ IBrowserEgressConnectionOptions,
24
+ IBrowserEgressProxyOptions,
25
+ IBrowserEgressProxyStats,
26
+ IBrowserFillAction,
27
+ IBrowserNavigateAction,
28
+ IBrowserObservationResult,
29
+ IBrowserPressAction,
30
+ IBrowserRuntimeAuditEvent,
31
+ IBrowserRuntimeFlexToolProviderOptions,
32
+ IBrowserRuntimeFrameSubscription,
33
+ IBrowserRuntimeFramedClientOptions,
34
+ IBrowserRuntimeMcpOptions,
35
+ IBrowserRuntimeOperationOptions,
36
+ IBrowserRuntimeOptions,
37
+ IBrowserRuntimeState,
38
+ IBrowserRuntimeTabState,
39
+ IBrowserScreenshotAction,
40
+ IBrowserScreenshotResult,
41
+ IBrowserSnapshotAction,
42
+ IIssueBrowserCapabilityRequest,
43
+ IIssuedBrowserCapability,
44
+ IResolvedBrowserFlexCapability,
45
+ TBrowserActorRole,
46
+ TBrowserAgentAction,
47
+ TBrowserAgentActionResult,
48
+ TBrowserCapabilitySource,
49
+ TBrowserDnsResolver,
50
+ TBrowserEgressConnector,
51
+ TBrowserRuntimeEvent,
52
+ } from './interfaces.js';
@@ -0,0 +1,375 @@
1
+ import type * as plugins from './plugins.js';
2
+
3
+ export type TBrowserActorRole = 'human' | 'agent';
4
+ export type TBrowserCapabilitySource = 'human' | 'flex' | 'mcp';
5
+
6
+ export interface IBrowserCapabilityAuthorizationRequest {
7
+ projectId: string;
8
+ actorId: string;
9
+ role: TBrowserActorRole;
10
+ peerId: string;
11
+ source: TBrowserCapabilitySource;
12
+ scopeId?: string;
13
+ sessionId?: string;
14
+ }
15
+
16
+ export interface IIssueBrowserCapabilityRequest extends IBrowserCapabilityAuthorizationRequest {
17
+ expiresInMs?: number;
18
+ disconnect?: (signal: AbortSignal) => Promise<void> | void;
19
+ }
20
+
21
+ export interface IBrowserCapabilityDescriptor extends IBrowserCapabilityAuthorizationRequest {
22
+ capabilityId: string;
23
+ expiresAt: number;
24
+ }
25
+
26
+ export interface IIssuedBrowserCapability extends IBrowserCapabilityDescriptor {
27
+ capabilityToken: string;
28
+ }
29
+
30
+ export interface IResolvedBrowserFlexCapability {
31
+ capabilityToken: string;
32
+ }
33
+
34
+ export interface IBrowserRuntimeAuditEvent {
35
+ operationId: string;
36
+ capabilityId: string;
37
+ projectId: string;
38
+ actorId: string;
39
+ role: TBrowserActorRole;
40
+ source: TBrowserCapabilitySource;
41
+ action: string;
42
+ phase: 'completed' | 'failed';
43
+ startedAt: number;
44
+ finishedAt: number;
45
+ errorCode?: string;
46
+ }
47
+
48
+ export interface ILiveBrowserSessionLike {
49
+ start(options?: plugins.smartpuppeteer.ILiveBrowserOperationOptions): Promise<void>;
50
+ stop(): Promise<void>;
51
+ terminate(
52
+ options?: plugins.smartpuppeteer.ILiveBrowserTerminationOptions,
53
+ ): Promise<plugins.smartpuppeteer.ILiveBrowserTerminationResult>;
54
+ getState(): plugins.smartpuppeteer.ILiveBrowserState;
55
+ getProcessState(): plugins.smartpuppeteer.ILiveBrowserProcessState;
56
+ onEvent(listener: plugins.smartpuppeteer.TLiveBrowserEventListener): () => void;
57
+ acknowledgeFrame(
58
+ request: plugins.smartpuppeteer.ILiveBrowserFrameAcknowledgementRequest,
59
+ ): Promise<plugins.smartpuppeteer.ILiveBrowserFrameAcknowledgement>;
60
+ createTab(
61
+ options?: plugins.smartpuppeteer.ILiveBrowserCreateTabOptions,
62
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
63
+ ): Promise<plugins.smartpuppeteer.ILiveBrowserTabState>;
64
+ activateTab(
65
+ tabId: string,
66
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
67
+ ): Promise<void>;
68
+ closeTab(
69
+ tabId: string,
70
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
71
+ ): Promise<void>;
72
+ navigate(
73
+ options: plugins.smartpuppeteer.ILiveBrowserNavigateOptions,
74
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
75
+ ): Promise<void>;
76
+ back(
77
+ options?: plugins.smartpuppeteer.ILiveBrowserNavigationOptions,
78
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
79
+ ): Promise<void>;
80
+ forward(
81
+ options?: plugins.smartpuppeteer.ILiveBrowserNavigationOptions,
82
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
83
+ ): Promise<void>;
84
+ reload(
85
+ options?: plugins.smartpuppeteer.ILiveBrowserNavigationOptions,
86
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
87
+ ): Promise<void>;
88
+ setViewport(
89
+ viewport: plugins.smartpuppeteer.ILiveBrowserViewport,
90
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
91
+ ): Promise<void>;
92
+ dispatchMouse(input: plugins.smartpuppeteer.ILiveBrowserMouseInput): Promise<void>;
93
+ dispatchWheel(input: plugins.smartpuppeteer.ILiveBrowserWheelInput): Promise<void>;
94
+ dispatchKey(input: plugins.smartpuppeteer.ILiveBrowserKeyInput): Promise<void>;
95
+ insertText(input: plugins.smartpuppeteer.ILiveBrowserInsertTextInput): Promise<void>;
96
+ captureSnapshot(
97
+ options?: plugins.smartpuppeteer.ILiveBrowserSnapshotOptions,
98
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
99
+ ): Promise<plugins.smartpuppeteer.ILiveBrowserSnapshot>;
100
+ observe(
101
+ options?: plugins.smartpuppeteer.ILiveBrowserObserveOptions,
102
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
103
+ ): Promise<plugins.smartpuppeteer.ILiveBrowserObservation>;
104
+ evaluate(
105
+ expression: string,
106
+ options?: plugins.smartpuppeteer.ILiveBrowserEvaluateOptions,
107
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
108
+ ): Promise<plugins.smartpuppeteer.TLiveBrowserJsonValue>;
109
+ click(
110
+ options: plugins.smartpuppeteer.ILiveBrowserClickOptions,
111
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
112
+ ): Promise<void>;
113
+ fill(
114
+ options: plugins.smartpuppeteer.ILiveBrowserFillOptions,
115
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
116
+ ): Promise<void>;
117
+ press(
118
+ options: plugins.smartpuppeteer.ILiveBrowserPressOptions,
119
+ operationOptions?: plugins.smartpuppeteer.ILiveBrowserOperationOptions,
120
+ ): Promise<void>;
121
+ }
122
+
123
+ export interface IBrowserConfinementProbeContext {
124
+ session: ILiveBrowserSessionLike;
125
+ proxy: import('./classes.egressproxy.js').BrowserEgressProxy;
126
+ signal: AbortSignal;
127
+ }
128
+
129
+ export interface IBrowserRuntimeEnvironment {
130
+ platform: NodeJS.Platform;
131
+ uid: number | undefined;
132
+ }
133
+
134
+ export interface IBrowserRuntimeOptions {
135
+ runtimeDirectory: string;
136
+ authorizeCapability(
137
+ request: IBrowserCapabilityAuthorizationRequest,
138
+ signal: AbortSignal,
139
+ ): Promise<boolean> | boolean;
140
+ audit?(event: IBrowserRuntimeAuditEvent, signal: AbortSignal): Promise<void> | void;
141
+ maxProjectSlots?: number;
142
+ maxCapabilities?: number;
143
+ maxCapabilitiesPerProject?: number;
144
+ capabilityDefaultTtlMs?: number;
145
+ capabilityMaximumTtlMs?: number;
146
+ authorizationTimeoutMs?: number;
147
+ maxTabsPerProject?: number;
148
+ operationTimeoutMs?: number;
149
+ quiescenceTimeoutMs?: number;
150
+ terminationGraceMs?: number;
151
+ terminationForceMs?: number;
152
+ auditTimeoutMs?: number;
153
+ confinementProbeTimeoutMs?: number;
154
+ idleRetirementMs?: number;
155
+ maxFrameBytes?: number;
156
+ frameAcknowledgementTimeoutMs?: number;
157
+ egress?: Omit<IBrowserEgressProxyOptions, 'projectId'>;
158
+ artifacts?: Omit<IBrowserArtifactStoreOptions, 'rootDirectory'>;
159
+ }
160
+
161
+ export interface IBrowserRuntimeTabState {
162
+ id: string;
163
+ url: string;
164
+ title: string;
165
+ active: boolean;
166
+ status: 'open' | 'crashed';
167
+ generation: number;
168
+ appliedViewportRevision: number;
169
+ streaming: boolean;
170
+ }
171
+
172
+ export interface IBrowserRuntimeState {
173
+ status: 'stopped' | 'starting' | 'running' | 'stopping';
174
+ activeTabId: string | null;
175
+ viewportRevision: number;
176
+ viewport: {
177
+ width: number;
178
+ height: number;
179
+ deviceScaleFactor: number;
180
+ };
181
+ tabs: IBrowserRuntimeTabState[];
182
+ lastError?: {
183
+ code: string;
184
+ fatal: boolean;
185
+ tabId?: string;
186
+ };
187
+ }
188
+
189
+ export interface IBrowserArtifactMetadata {
190
+ artifactId: string;
191
+ projectId: string;
192
+ mimeType: string;
193
+ size: number;
194
+ createdAt: number;
195
+ expiresAt: number;
196
+ }
197
+
198
+ export interface IBrowserArtifactStoreOptions {
199
+ rootDirectory: string;
200
+ maxFileBytes?: number;
201
+ maxArtifactsPerProject?: number;
202
+ maxProjectBytes?: number;
203
+ maxProjects?: number;
204
+ maxTotalArtifacts?: number;
205
+ maxTotalBytes?: number;
206
+ artifactTtlMs?: number;
207
+ now?: () => number;
208
+ }
209
+
210
+ export interface IBrowserNavigateAction {
211
+ action: 'navigate';
212
+ url: string;
213
+ tabId?: string;
214
+ timeoutMs?: number;
215
+ }
216
+
217
+ export interface IBrowserSnapshotAction {
218
+ action: 'snapshot';
219
+ tabId?: string;
220
+ maxCharacters?: number;
221
+ }
222
+
223
+ export interface IBrowserScreenshotAction {
224
+ action: 'screenshot';
225
+ tabId?: string;
226
+ format?: 'jpeg' | 'png';
227
+ quality?: number;
228
+ }
229
+
230
+ export interface IBrowserClickAction {
231
+ action: 'click';
232
+ selector: string;
233
+ tabId?: string;
234
+ timeoutMs?: number;
235
+ }
236
+
237
+ export interface IBrowserFillAction {
238
+ action: 'fill';
239
+ selector: string;
240
+ text: string;
241
+ tabId?: string;
242
+ timeoutMs?: number;
243
+ }
244
+
245
+ export interface IBrowserPressAction {
246
+ action: 'press';
247
+ selector: string;
248
+ key: string;
249
+ tabId?: string;
250
+ timeoutMs?: number;
251
+ }
252
+
253
+ export type TBrowserAgentAction =
254
+ | IBrowserNavigateAction
255
+ | IBrowserSnapshotAction
256
+ | IBrowserScreenshotAction
257
+ | IBrowserClickAction
258
+ | IBrowserFillAction
259
+ | IBrowserPressAction;
260
+
261
+ export interface IBrowserActionStateResult {
262
+ action: 'navigate' | 'click' | 'fill' | 'press';
263
+ state: IBrowserRuntimeState;
264
+ }
265
+
266
+ export interface IBrowserObservationResult {
267
+ action: 'snapshot';
268
+ tabId: string;
269
+ url: string;
270
+ title: string;
271
+ text: string;
272
+ truncated: boolean;
273
+ state: IBrowserRuntimeState;
274
+ }
275
+
276
+ export interface IBrowserScreenshotResult {
277
+ action: 'screenshot';
278
+ artifact: IBrowserArtifactMetadata;
279
+ }
280
+
281
+ export type TBrowserAgentActionResult =
282
+ | IBrowserActionStateResult
283
+ | IBrowserObservationResult
284
+ | IBrowserScreenshotResult;
285
+
286
+ export type TBrowserRuntimeEvent =
287
+ | { type: 'state'; state: IBrowserRuntimeState }
288
+ | { type: 'error'; error: { code: string; fatal: boolean; tabId?: string } }
289
+ | { type: 'frame'; frame: plugins.smartpuppeteer.ILiveBrowserFrame };
290
+
291
+ export interface IBrowserRuntimeOperationOptions {
292
+ signal?: AbortSignal;
293
+ timeoutMs?: number;
294
+ onOperationStarted?(operationId: string): void;
295
+ }
296
+
297
+ export interface IBrowserRuntimeFrameSubscription {
298
+ close(): Promise<void>;
299
+ }
300
+
301
+ export type TBrowserDnsResolver = (
302
+ hostname: string,
303
+ options: { all: true; verbatim: true; signal: AbortSignal },
304
+ ) => Promise<plugins.dns.LookupAddress[]>;
305
+
306
+ export interface IBrowserEgressConnectionOptions {
307
+ address: string;
308
+ family: 4 | 6;
309
+ port: number;
310
+ hostname: string;
311
+ signal: AbortSignal;
312
+ }
313
+
314
+ export type TBrowserEgressConnector = (
315
+ options: IBrowserEgressConnectionOptions,
316
+ ) => plugins.net.Socket;
317
+
318
+ export interface IBrowserEgressProxyOptions {
319
+ projectId: string;
320
+ allowedPorts?: number[];
321
+ maxConnections?: number;
322
+ maxActiveRequests?: number;
323
+ maxHeaderBytes?: number;
324
+ connectTimeoutMs?: number;
325
+ idleTimeoutMs?: number;
326
+ tunnelLifetimeMs?: number;
327
+ requestTimeoutMs?: number;
328
+ maxRequestBytes?: number;
329
+ maxResponseBytes?: number;
330
+ maxTunnelBytes?: number;
331
+ resolver?: TBrowserDnsResolver;
332
+ connector?: TBrowserEgressConnector;
333
+ }
334
+
335
+ export interface IBrowserEgressProxyStats {
336
+ ordinaryRequests: number;
337
+ upgradeRequests: number;
338
+ connectRequests: number;
339
+ rejectedRequests: number;
340
+ activeConnections: number;
341
+ }
342
+
343
+ export interface IAttachTrustedFramedPeerOptions {
344
+ peerId: string;
345
+ scopeId: string;
346
+ sessionId: string;
347
+ readable: plugins.stream.Readable;
348
+ writable: plugins.stream.Writable;
349
+ }
350
+
351
+ export interface IBrowserRuntimeFramedClientOptions {
352
+ scopeId: string;
353
+ sessionId: string;
354
+ readable: plugins.stream.Readable;
355
+ writable: plugins.stream.Writable;
356
+ maxFrameBytes?: number;
357
+ maxPendingRequests?: number;
358
+ requestTimeoutMs?: number;
359
+ }
360
+
361
+ export interface IBrowserRuntimeMcpOptions {
362
+ authenticateMcpRequest(request: Request): Promise<{ peerId: string }>;
363
+ trustedOrigins?: string[];
364
+ allowedHosts?: string[];
365
+ allowMissingOrigin?: boolean;
366
+ maxRequestBytes?: number;
367
+ maxToolResultBytes?: number;
368
+ }
369
+
370
+ export interface IBrowserRuntimeFlexToolProviderOptions<TScope> {
371
+ client: import('./classes.framed.js').BrowserRuntimeFramedClient;
372
+ resolveCapability(
373
+ context: plugins.flexharness.IFlexToolProviderContext<TScope>,
374
+ ): Promise<IResolvedBrowserFlexCapability> | IResolvedBrowserFlexCapability;
375
+ }
@@ -0,0 +1,18 @@
1
+ import type * as plugins from './plugins.js';
2
+ import type {
3
+ IBrowserConfinementProbeContext,
4
+ IBrowserRuntimeOptions,
5
+ IBrowserRuntimeEnvironment,
6
+ ILiveBrowserSessionLike,
7
+ } from './interfaces.js';
8
+
9
+ export const browserRuntimeTesting = Symbol('browserRuntimeTesting');
10
+
11
+ export interface IBrowserRuntimeTestingOptions extends IBrowserRuntimeOptions {
12
+ [browserRuntimeTesting]: true;
13
+ environment: IBrowserRuntimeEnvironment;
14
+ sessionFactory(
15
+ options: plugins.smartpuppeteer.ILiveBrowserSessionOptions,
16
+ ): ILiveBrowserSessionLike;
17
+ confinementProbe(context: IBrowserConfinementProbeContext): Promise<void>;
18
+ }