@modelprofile.com/browser-runtime 1.0.1 → 2.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.
- package/.smartconfig.json +1 -1
- package/changelog.md +19 -0
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/actions.js +12 -3
- package/dist_ts/classes.artifactstore.d.ts +16 -7
- package/dist_ts/classes.artifactstore.js +167 -88
- package/dist_ts/classes.egressproxy.d.ts +2 -0
- package/dist_ts/classes.egressproxy.js +7 -2
- package/dist_ts/classes.flexprovider.js +4 -2
- package/dist_ts/classes.framed.d.ts +30 -3
- package/dist_ts/classes.framed.js +205 -30
- package/dist_ts/classes.runtime.d.ts +86 -22
- package/dist_ts/classes.runtime.js +1060 -230
- package/dist_ts/errors.d.ts +1 -1
- package/dist_ts/errors.js +6 -3
- package/dist_ts/index.d.ts +2 -2
- package/dist_ts/interfaces.d.ts +119 -47
- package/dist_ts/internal.testing.d.ts +10 -1
- package/dist_ts/internal.testing.js +1 -1
- package/dist_ts/mcp.js +45 -11
- package/package.json +2 -2
- package/readme.hints.md +23 -18
- package/readme.md +72 -101
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/actions.ts +11 -2
- package/ts/classes.artifactstore.ts +239 -107
- package/ts/classes.egressproxy.ts +12 -1
- package/ts/classes.flexprovider.ts +5 -1
- package/ts/classes.framed.ts +246 -38
- package/ts/classes.runtime.ts +1350 -320
- package/ts/errors.ts +8 -2
- package/ts/index.ts +19 -6
- package/ts/interfaces.ts +151 -45
- package/ts/internal.testing.ts +12 -0
- package/ts/mcp.ts +67 -16
package/ts/errors.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type TBrowserRuntimeErrorCode =
|
|
2
2
|
| 'ABORTED'
|
|
3
3
|
| 'AUTHORIZATION_DENIED'
|
|
4
|
+
| 'ATTACHMENT_CONFLICT'
|
|
4
5
|
| 'BUSY'
|
|
5
6
|
| 'CAPABILITY_EXPIRED'
|
|
6
7
|
| 'CAPABILITY_INVALID'
|
|
@@ -14,24 +15,29 @@ export type TBrowserRuntimeErrorCode =
|
|
|
14
15
|
| 'NOT_RUNNING'
|
|
15
16
|
| 'PROTOCOL_ERROR'
|
|
16
17
|
| 'QUOTA_EXCEEDED'
|
|
18
|
+
| 'RESOURCE_NOT_FOUND'
|
|
19
|
+
| 'RESOURCE_RETIRED'
|
|
17
20
|
| 'TIMEOUT';
|
|
18
21
|
|
|
19
22
|
const publicMessages: Record<TBrowserRuntimeErrorCode, string> = {
|
|
20
23
|
ABORTED: 'The operation was aborted.',
|
|
21
24
|
AUTHORIZATION_DENIED: 'Capability authorization was denied.',
|
|
22
|
-
|
|
25
|
+
ATTACHMENT_CONFLICT: 'The attachment binding conflicts with the current revision.',
|
|
26
|
+
BUSY: 'The browser resource is busy.',
|
|
23
27
|
CAPABILITY_EXPIRED: 'The capability has expired.',
|
|
24
28
|
CAPABILITY_INVALID: 'The capability is invalid.',
|
|
25
29
|
CAPABILITY_REVOKED: 'The capability has been revoked.',
|
|
26
30
|
CONFINEMENT_FAILED: 'Browser confinement could not be confirmed.',
|
|
27
31
|
EGRESS_DENIED: 'The egress target was denied.',
|
|
28
|
-
FENCED: 'The browser
|
|
32
|
+
FENCED: 'The browser resource is permanently fenced.',
|
|
29
33
|
FRAME_TOO_LARGE: 'The browser frame exceeded its limit.',
|
|
30
34
|
INVALID_INPUT: 'The request is invalid.',
|
|
31
35
|
LOCKED: 'The browser runtime is already locked.',
|
|
32
36
|
NOT_RUNNING: 'The browser runtime is not running.',
|
|
33
37
|
PROTOCOL_ERROR: 'The framed protocol request is invalid.',
|
|
34
38
|
QUOTA_EXCEEDED: 'A browser runtime quota was exceeded.',
|
|
39
|
+
RESOURCE_NOT_FOUND: 'The browser resource is not registered.',
|
|
40
|
+
RESOURCE_RETIRED: 'The browser resource has been retired.',
|
|
35
41
|
TIMEOUT: 'The operation timed out.',
|
|
36
42
|
};
|
|
37
43
|
|
package/ts/index.ts
CHANGED
|
@@ -10,37 +10,49 @@ export { BrowserRuntime, BrowserRuntimeLease } from './classes.runtime.js';
|
|
|
10
10
|
export { BrowserRuntimeError } from './errors.js';
|
|
11
11
|
export { createBrowserRuntimeMcpHttpHandler } from './mcp.js';
|
|
12
12
|
|
|
13
|
-
export type {
|
|
13
|
+
export type { TAcquireBrowserRuntimeLeaseOptions } from './classes.runtime.js';
|
|
14
14
|
export type { TBrowserRuntimeErrorCode } from './errors.js';
|
|
15
15
|
export type {
|
|
16
16
|
IAttachTrustedFramedPeerOptions,
|
|
17
|
+
IApplyBrowserAttachmentBindingRequest,
|
|
18
|
+
IBrowserAttachmentBinding,
|
|
17
19
|
IBrowserActionStateResult,
|
|
18
20
|
IBrowserArtifactMetadata,
|
|
19
21
|
IBrowserArtifactStoreOptions,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
IBrowserMcpAuthenticatedBinding,
|
|
23
|
+
TBrowserCapabilityAuthorizationRequest,
|
|
24
|
+
TBrowserCapabilityDescriptor,
|
|
22
25
|
IBrowserClickAction,
|
|
23
26
|
IBrowserEgressConnectionOptions,
|
|
24
27
|
IBrowserEgressProxyOptions,
|
|
25
28
|
IBrowserEgressProxyStats,
|
|
29
|
+
IBrowserFlexCapabilityBinding,
|
|
30
|
+
IBrowserFlexSessionId,
|
|
26
31
|
IBrowserFillAction,
|
|
27
32
|
IBrowserNavigateAction,
|
|
28
33
|
IBrowserObservationResult,
|
|
34
|
+
IBrowserOpenCodeSessionId,
|
|
29
35
|
IBrowserPressAction,
|
|
30
|
-
|
|
36
|
+
TBrowserRuntimeAuditEvent,
|
|
37
|
+
TBrowserRuntimeOperationIdentity,
|
|
31
38
|
IBrowserRuntimeFlexToolProviderOptions,
|
|
32
39
|
IBrowserRuntimeFrameSubscription,
|
|
33
40
|
IBrowserRuntimeFramedClientOptions,
|
|
34
41
|
IBrowserRuntimeMcpOptions,
|
|
35
42
|
IBrowserRuntimeOperationOptions,
|
|
36
43
|
IBrowserRuntimeOptions,
|
|
44
|
+
IBrowserResourceKey,
|
|
45
|
+
IBrowserResourceRegistration,
|
|
37
46
|
IBrowserRuntimeState,
|
|
38
47
|
IBrowserRuntimeTabState,
|
|
39
48
|
IBrowserScreenshotAction,
|
|
40
49
|
IBrowserScreenshotResult,
|
|
41
50
|
IBrowserSnapshotAction,
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
ICreateBrowserResourceRequest,
|
|
52
|
+
TIssueBrowserCapabilityRequest,
|
|
53
|
+
TIssuedBrowserCapability,
|
|
54
|
+
TQualifiedBrowserSessionId,
|
|
55
|
+
IRegisterBrowserResourceRequest,
|
|
44
56
|
IResolvedBrowserFlexCapability,
|
|
45
57
|
TBrowserActorRole,
|
|
46
58
|
TBrowserAgentAction,
|
|
@@ -48,5 +60,6 @@ export type {
|
|
|
48
60
|
TBrowserCapabilitySource,
|
|
49
61
|
TBrowserDnsResolver,
|
|
50
62
|
TBrowserEgressConnector,
|
|
63
|
+
TBrowserHarnessId,
|
|
51
64
|
TBrowserRuntimeEvent,
|
|
52
65
|
} from './interfaces.js';
|
package/ts/interfaces.ts
CHANGED
|
@@ -1,49 +1,131 @@
|
|
|
1
1
|
import type * as plugins from './plugins.js';
|
|
2
|
+
import type { BrowserEgressProxy } from './classes.egressproxy.js';
|
|
3
|
+
import type { BrowserRuntimeFramedClient } from './classes.framed.js';
|
|
2
4
|
|
|
3
5
|
export type TBrowserActorRole = 'human' | 'agent';
|
|
4
6
|
export type TBrowserCapabilitySource = 'human' | 'flex' | 'mcp';
|
|
7
|
+
export type TBrowserHarnessId = 'opencode' | 'flex';
|
|
5
8
|
|
|
6
|
-
export interface
|
|
9
|
+
export interface IBrowserOpenCodeSessionId {
|
|
10
|
+
harnessId: 'opencode';
|
|
11
|
+
nativeId: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IBrowserFlexSessionId {
|
|
15
|
+
harnessId: 'flex';
|
|
16
|
+
nativeId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type TQualifiedBrowserSessionId = IBrowserOpenCodeSessionId | IBrowserFlexSessionId;
|
|
20
|
+
|
|
21
|
+
export interface IBrowserResourceKey {
|
|
7
22
|
projectId: string;
|
|
23
|
+
browserResourceId: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IBrowserAttachmentBinding {
|
|
27
|
+
attachmentAuthorityId: string;
|
|
28
|
+
attachmentRevision: number;
|
|
29
|
+
sessionId: TQualifiedBrowserSessionId | null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface ICreateBrowserResourceRequest {
|
|
33
|
+
projectId: string;
|
|
34
|
+
attachmentBinding: IBrowserAttachmentBinding;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface IRegisterBrowserResourceRequest extends IBrowserResourceKey {
|
|
38
|
+
attachmentBinding: IBrowserAttachmentBinding;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface IApplyBrowserAttachmentBindingRequest extends IBrowserResourceKey {
|
|
42
|
+
attachmentBinding: IBrowserAttachmentBinding;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface IBrowserResourceRegistration extends IBrowserResourceKey {
|
|
46
|
+
registeredAt: number;
|
|
47
|
+
attachmentBinding: IBrowserAttachmentBinding;
|
|
48
|
+
incarnationStatus: 'absent' | 'running' | 'fenced';
|
|
49
|
+
incarnationGeneration: number;
|
|
50
|
+
retirementPending: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IBrowserCapabilityBindingBase extends IBrowserResourceKey {
|
|
54
|
+
attachmentAuthorityId: string;
|
|
55
|
+
attachmentRevision: number;
|
|
8
56
|
actorId: string;
|
|
9
|
-
role: TBrowserActorRole;
|
|
10
57
|
peerId: string;
|
|
11
|
-
source: TBrowserCapabilitySource;
|
|
12
|
-
scopeId?: string;
|
|
13
|
-
sessionId?: string;
|
|
14
58
|
}
|
|
15
59
|
|
|
16
|
-
export interface
|
|
60
|
+
export interface IBrowserHumanCapabilityBinding extends IBrowserCapabilityBindingBase {
|
|
61
|
+
role: 'human';
|
|
62
|
+
source: 'human';
|
|
63
|
+
sessionId?: never;
|
|
64
|
+
scopeId?: never;
|
|
65
|
+
channelId?: never;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface IBrowserFlexCapabilityBinding extends IBrowserCapabilityBindingBase {
|
|
69
|
+
role: 'agent';
|
|
70
|
+
source: 'flex';
|
|
71
|
+
sessionId: IBrowserFlexSessionId;
|
|
72
|
+
scopeId: string;
|
|
73
|
+
channelId: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface IBrowserMcpCapabilityBinding extends IBrowserCapabilityBindingBase {
|
|
77
|
+
role: 'agent';
|
|
78
|
+
source: 'mcp';
|
|
79
|
+
sessionId: IBrowserOpenCodeSessionId;
|
|
80
|
+
scopeId?: never;
|
|
81
|
+
channelId?: never;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type TBrowserCapabilityAuthorizationRequest =
|
|
85
|
+
| IBrowserHumanCapabilityBinding
|
|
86
|
+
| IBrowserFlexCapabilityBinding
|
|
87
|
+
| IBrowserMcpCapabilityBinding;
|
|
88
|
+
|
|
89
|
+
export type TIssueBrowserCapabilityRequest = TBrowserCapabilityAuthorizationRequest & {
|
|
17
90
|
expiresInMs?: number;
|
|
18
91
|
disconnect?: (signal: AbortSignal) => Promise<void> | void;
|
|
19
|
-
}
|
|
92
|
+
};
|
|
20
93
|
|
|
21
|
-
export
|
|
94
|
+
export type TBrowserCapabilityDescriptor = TBrowserCapabilityAuthorizationRequest & {
|
|
22
95
|
capabilityId: string;
|
|
23
96
|
expiresAt: number;
|
|
24
|
-
}
|
|
97
|
+
};
|
|
25
98
|
|
|
26
|
-
export
|
|
99
|
+
export type TIssuedBrowserCapability = TBrowserCapabilityDescriptor & {
|
|
27
100
|
capabilityToken: string;
|
|
28
|
-
}
|
|
101
|
+
};
|
|
29
102
|
|
|
30
103
|
export interface IResolvedBrowserFlexCapability {
|
|
31
104
|
capabilityToken: string;
|
|
32
105
|
}
|
|
33
106
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
107
|
+
type TReadonlyBrowserCapabilityAuthorizationRequest =
|
|
108
|
+
| Readonly<IBrowserHumanCapabilityBinding>
|
|
109
|
+
| (Omit<Readonly<IBrowserFlexCapabilityBinding>, 'sessionId'> & {
|
|
110
|
+
readonly sessionId: Readonly<IBrowserFlexSessionId>;
|
|
111
|
+
})
|
|
112
|
+
| (Omit<Readonly<IBrowserMcpCapabilityBinding>, 'sessionId'> & {
|
|
113
|
+
readonly sessionId: Readonly<IBrowserOpenCodeSessionId>;
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export type TBrowserRuntimeOperationIdentity = TReadonlyBrowserCapabilityAuthorizationRequest & {
|
|
117
|
+
readonly operationId: string;
|
|
118
|
+
readonly capabilityId: string;
|
|
119
|
+
readonly leaseId: string;
|
|
120
|
+
readonly action: string;
|
|
121
|
+
readonly startedAt: number;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export type TBrowserRuntimeAuditEvent = TBrowserRuntimeOperationIdentity & {
|
|
125
|
+
readonly phase: 'completed' | 'failed';
|
|
126
|
+
readonly finishedAt: number;
|
|
127
|
+
readonly errorCode?: string;
|
|
128
|
+
};
|
|
47
129
|
|
|
48
130
|
export interface ILiveBrowserSessionLike {
|
|
49
131
|
start(options?: plugins.smartpuppeteer.ILiveBrowserOperationOptions): Promise<void>;
|
|
@@ -120,9 +202,9 @@ export interface ILiveBrowserSessionLike {
|
|
|
120
202
|
): Promise<void>;
|
|
121
203
|
}
|
|
122
204
|
|
|
123
|
-
export interface IBrowserConfinementProbeContext {
|
|
205
|
+
export interface IBrowserConfinementProbeContext extends IBrowserResourceKey {
|
|
124
206
|
session: ILiveBrowserSessionLike;
|
|
125
|
-
proxy:
|
|
207
|
+
proxy: BrowserEgressProxy;
|
|
126
208
|
signal: AbortSignal;
|
|
127
209
|
}
|
|
128
210
|
|
|
@@ -134,27 +216,36 @@ export interface IBrowserRuntimeEnvironment {
|
|
|
134
216
|
export interface IBrowserRuntimeOptions {
|
|
135
217
|
runtimeDirectory: string;
|
|
136
218
|
authorizeCapability(
|
|
137
|
-
request:
|
|
219
|
+
request: TBrowserCapabilityAuthorizationRequest,
|
|
138
220
|
signal: AbortSignal,
|
|
139
221
|
): Promise<boolean> | boolean;
|
|
140
|
-
|
|
141
|
-
|
|
222
|
+
beforeOperation?(
|
|
223
|
+
operation: TBrowserRuntimeOperationIdentity,
|
|
224
|
+
signal: AbortSignal,
|
|
225
|
+
): Promise<void> | void;
|
|
226
|
+
audit?(event: TBrowserRuntimeAuditEvent, signal: AbortSignal): Promise<void> | void;
|
|
227
|
+
maxResources?: number;
|
|
228
|
+
maxResourcesPerProject?: number;
|
|
229
|
+
maxRunningResources?: number;
|
|
230
|
+
maxRunningResourcesPerProject?: number;
|
|
142
231
|
maxCapabilities?: number;
|
|
232
|
+
maxCapabilitiesPerResource?: number;
|
|
143
233
|
maxCapabilitiesPerProject?: number;
|
|
144
234
|
capabilityDefaultTtlMs?: number;
|
|
145
235
|
capabilityMaximumTtlMs?: number;
|
|
146
236
|
authorizationTimeoutMs?: number;
|
|
147
|
-
|
|
237
|
+
beforeOperationTimeoutMs?: number;
|
|
238
|
+
maxTabsPerResource?: number;
|
|
148
239
|
operationTimeoutMs?: number;
|
|
149
240
|
quiescenceTimeoutMs?: number;
|
|
150
241
|
terminationGraceMs?: number;
|
|
151
242
|
terminationForceMs?: number;
|
|
152
243
|
auditTimeoutMs?: number;
|
|
153
244
|
confinementProbeTimeoutMs?: number;
|
|
154
|
-
|
|
245
|
+
idleTerminationMs?: number;
|
|
155
246
|
maxFrameBytes?: number;
|
|
156
247
|
frameAcknowledgementTimeoutMs?: number;
|
|
157
|
-
egress?: Omit<IBrowserEgressProxyOptions, 'projectId'>;
|
|
248
|
+
egress?: Omit<IBrowserEgressProxyOptions, 'projectId' | 'browserResourceId'>;
|
|
158
249
|
artifacts?: Omit<IBrowserArtifactStoreOptions, 'rootDirectory'>;
|
|
159
250
|
}
|
|
160
251
|
|
|
@@ -186,9 +277,8 @@ export interface IBrowserRuntimeState {
|
|
|
186
277
|
};
|
|
187
278
|
}
|
|
188
279
|
|
|
189
|
-
export interface IBrowserArtifactMetadata {
|
|
280
|
+
export interface IBrowserArtifactMetadata extends IBrowserResourceKey {
|
|
190
281
|
artifactId: string;
|
|
191
|
-
projectId: string;
|
|
192
282
|
mimeType: string;
|
|
193
283
|
size: number;
|
|
194
284
|
createdAt: number;
|
|
@@ -198,6 +288,8 @@ export interface IBrowserArtifactMetadata {
|
|
|
198
288
|
export interface IBrowserArtifactStoreOptions {
|
|
199
289
|
rootDirectory: string;
|
|
200
290
|
maxFileBytes?: number;
|
|
291
|
+
maxArtifactsPerResource?: number;
|
|
292
|
+
maxResourceBytes?: number;
|
|
201
293
|
maxArtifactsPerProject?: number;
|
|
202
294
|
maxProjectBytes?: number;
|
|
203
295
|
maxProjects?: number;
|
|
@@ -315,8 +407,7 @@ export type TBrowserEgressConnector = (
|
|
|
315
407
|
options: IBrowserEgressConnectionOptions,
|
|
316
408
|
) => plugins.net.Socket;
|
|
317
409
|
|
|
318
|
-
export interface IBrowserEgressProxyOptions {
|
|
319
|
-
projectId: string;
|
|
410
|
+
export interface IBrowserEgressProxyOptions extends IBrowserResourceKey {
|
|
320
411
|
allowedPorts?: number[];
|
|
321
412
|
maxConnections?: number;
|
|
322
413
|
maxActiveRequests?: number;
|
|
@@ -340,17 +431,24 @@ export interface IBrowserEgressProxyStats {
|
|
|
340
431
|
activeConnections: number;
|
|
341
432
|
}
|
|
342
433
|
|
|
343
|
-
export interface IAttachTrustedFramedPeerOptions
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
434
|
+
export interface IAttachTrustedFramedPeerOptions
|
|
435
|
+
extends Omit<
|
|
436
|
+
IBrowserFlexCapabilityBinding,
|
|
437
|
+
'role' | 'source'
|
|
438
|
+
> {
|
|
439
|
+
role: 'agent';
|
|
440
|
+
source: 'flex';
|
|
347
441
|
readable: plugins.stream.Readable;
|
|
348
442
|
writable: plugins.stream.Writable;
|
|
349
443
|
}
|
|
350
444
|
|
|
351
|
-
export interface IBrowserRuntimeFramedClientOptions
|
|
352
|
-
|
|
353
|
-
|
|
445
|
+
export interface IBrowserRuntimeFramedClientOptions
|
|
446
|
+
extends Omit<
|
|
447
|
+
IBrowserFlexCapabilityBinding,
|
|
448
|
+
'role' | 'source'
|
|
449
|
+
> {
|
|
450
|
+
role: 'agent';
|
|
451
|
+
source: 'flex';
|
|
354
452
|
readable: plugins.stream.Readable;
|
|
355
453
|
writable: plugins.stream.Writable;
|
|
356
454
|
maxFrameBytes?: number;
|
|
@@ -358,8 +456,16 @@ export interface IBrowserRuntimeFramedClientOptions {
|
|
|
358
456
|
requestTimeoutMs?: number;
|
|
359
457
|
}
|
|
360
458
|
|
|
459
|
+
export interface IBrowserMcpAuthenticatedBinding extends IBrowserCapabilityBindingBase {
|
|
460
|
+
role: 'agent';
|
|
461
|
+
source: 'mcp';
|
|
462
|
+
sessionId: IBrowserOpenCodeSessionId;
|
|
463
|
+
scopeId?: never;
|
|
464
|
+
channelId?: never;
|
|
465
|
+
}
|
|
466
|
+
|
|
361
467
|
export interface IBrowserRuntimeMcpOptions {
|
|
362
|
-
authenticateMcpRequest(request: Request): Promise<
|
|
468
|
+
authenticateMcpRequest(request: Request): Promise<IBrowserMcpAuthenticatedBinding>;
|
|
363
469
|
trustedOrigins?: string[];
|
|
364
470
|
allowedHosts?: string[];
|
|
365
471
|
allowMissingOrigin?: boolean;
|
|
@@ -368,7 +474,7 @@ export interface IBrowserRuntimeMcpOptions {
|
|
|
368
474
|
}
|
|
369
475
|
|
|
370
476
|
export interface IBrowserRuntimeFlexToolProviderOptions<TScope> {
|
|
371
|
-
client:
|
|
477
|
+
client: BrowserRuntimeFramedClient;
|
|
372
478
|
resolveCapability(
|
|
373
479
|
context: plugins.flexharness.IFlexToolProviderContext<TScope>,
|
|
374
480
|
): Promise<IResolvedBrowserFlexCapability> | IResolvedBrowserFlexCapability;
|
package/ts/internal.testing.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type * as plugins from './plugins.js';
|
|
2
2
|
import type {
|
|
3
3
|
IBrowserConfinementProbeContext,
|
|
4
|
+
IBrowserRuntimeFramedClientOptions,
|
|
4
5
|
IBrowserRuntimeOptions,
|
|
5
6
|
IBrowserRuntimeEnvironment,
|
|
6
7
|
ILiveBrowserSessionLike,
|
|
@@ -15,4 +16,15 @@ export interface IBrowserRuntimeTestingOptions extends IBrowserRuntimeOptions {
|
|
|
15
16
|
options: plugins.smartpuppeteer.ILiveBrowserSessionOptions,
|
|
16
17
|
): ILiveBrowserSessionLike;
|
|
17
18
|
confinementProbe(context: IBrowserConfinementProbeContext): Promise<void>;
|
|
19
|
+
beforeLeasePublication?(): Promise<void>;
|
|
20
|
+
beforeIdleTermination?(): Promise<void>;
|
|
21
|
+
beforeFrameFailureTermination?(): Promise<void>;
|
|
22
|
+
afterFrameFailureFence?(): Promise<void>;
|
|
23
|
+
beforeFramedPeerLeasePublication?(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IBrowserRuntimeFramedClientTestingOptions
|
|
27
|
+
extends IBrowserRuntimeFramedClientOptions {
|
|
28
|
+
[browserRuntimeTesting]: true;
|
|
29
|
+
afterAcquireResponse?(): Promise<void>;
|
|
18
30
|
}
|
package/ts/mcp.ts
CHANGED
|
@@ -2,7 +2,10 @@ import * as plugins from './plugins.js';
|
|
|
2
2
|
import type { BrowserRuntime, BrowserRuntimeLease } from './classes.runtime.js';
|
|
3
3
|
import { BrowserRuntimeError } from './errors.js';
|
|
4
4
|
import { commitinfo } from './00_commitinfo_data.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
IBrowserMcpAuthenticatedBinding,
|
|
7
|
+
IBrowserRuntimeMcpOptions,
|
|
8
|
+
} from './interfaces.js';
|
|
6
9
|
import { validateAgentActionResult } from './actions.js';
|
|
7
10
|
import {
|
|
8
11
|
validateBoundedString,
|
|
@@ -51,19 +54,17 @@ export const createBrowserRuntimeMcpHttpHandler = (
|
|
|
51
54
|
context: plugins.smartmcp.ISmartMcpToolContext,
|
|
52
55
|
action: (lease: BrowserRuntimeLease, signal: AbortSignal) => Promise<T>,
|
|
53
56
|
): Promise<T> => {
|
|
54
|
-
const
|
|
57
|
+
const binding = parseMcpAuthBinding(context.authInfo?.scopes);
|
|
55
58
|
const capabilityToken = parseBearerToken(context.request);
|
|
56
59
|
const signal = AbortSignal.any([context.extra.signal, context.request.signal]);
|
|
57
60
|
signal.throwIfAborted();
|
|
58
|
-
const descriptor = runtime.authorizeCapability(capabilityToken,
|
|
61
|
+
const descriptor = runtime.authorizeCapability(capabilityToken, binding);
|
|
59
62
|
if (descriptor.capabilityId !== context.authInfo?.token) {
|
|
60
63
|
throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
61
64
|
}
|
|
62
65
|
const lease = await runtime.acquireLease({
|
|
63
66
|
capabilityToken,
|
|
64
|
-
|
|
65
|
-
expectedRole: 'agent',
|
|
66
|
-
expectedSource: 'mcp',
|
|
67
|
+
...binding,
|
|
67
68
|
signal,
|
|
68
69
|
});
|
|
69
70
|
try {
|
|
@@ -203,22 +204,16 @@ export const createBrowserRuntimeMcpHttpHandler = (
|
|
|
203
204
|
maxToolResultBytes,
|
|
204
205
|
redactError: () => 'Browser tool execution failed.',
|
|
205
206
|
authorize: async ({ request }) => {
|
|
206
|
-
let peerId: string;
|
|
207
207
|
let capabilityToken: string;
|
|
208
208
|
try {
|
|
209
209
|
const authentication = await options.authenticateMcpRequest(request);
|
|
210
|
-
|
|
210
|
+
const binding = validateMcpBinding(authentication);
|
|
211
211
|
capabilityToken = parseBearerToken(request);
|
|
212
|
-
const descriptor = runtime.authorizeCapability(
|
|
213
|
-
capabilityToken,
|
|
214
|
-
peerId,
|
|
215
|
-
'agent',
|
|
216
|
-
'mcp',
|
|
217
|
-
);
|
|
212
|
+
const descriptor = runtime.authorizeCapability(capabilityToken, binding);
|
|
218
213
|
return {
|
|
219
214
|
token: descriptor.capabilityId,
|
|
220
|
-
clientId: peerId,
|
|
221
|
-
scopes: [
|
|
215
|
+
clientId: binding.peerId,
|
|
216
|
+
scopes: [serializeMcpAuthBinding(binding)],
|
|
222
217
|
expiresAt: descriptor.expiresAt,
|
|
223
218
|
};
|
|
224
219
|
} catch {
|
|
@@ -228,3 +223,59 @@ export const createBrowserRuntimeMcpHttpHandler = (
|
|
|
228
223
|
tools,
|
|
229
224
|
});
|
|
230
225
|
};
|
|
226
|
+
|
|
227
|
+
const validateMcpBinding = (value: unknown): IBrowserMcpAuthenticatedBinding => {
|
|
228
|
+
if (!value || typeof value !== 'object') throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
229
|
+
const binding = value as Record<string, unknown>;
|
|
230
|
+
if (binding.role !== 'agent' || binding.source !== 'mcp') {
|
|
231
|
+
throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
232
|
+
}
|
|
233
|
+
const session = binding.sessionId as Record<string, unknown> | undefined;
|
|
234
|
+
if (session?.harnessId !== 'opencode') throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
235
|
+
return {
|
|
236
|
+
projectId: validateBoundedString(binding.projectId, 'projectId', 1, 256),
|
|
237
|
+
browserResourceId: validateBoundedString(
|
|
238
|
+
binding.browserResourceId,
|
|
239
|
+
'browserResourceId',
|
|
240
|
+
16,
|
|
241
|
+
256,
|
|
242
|
+
),
|
|
243
|
+
attachmentAuthorityId: validateBoundedString(
|
|
244
|
+
binding.attachmentAuthorityId,
|
|
245
|
+
'attachmentAuthorityId',
|
|
246
|
+
1,
|
|
247
|
+
256,
|
|
248
|
+
),
|
|
249
|
+
attachmentRevision: validateInteger(
|
|
250
|
+
binding.attachmentRevision,
|
|
251
|
+
'attachmentRevision',
|
|
252
|
+
0,
|
|
253
|
+
Number.MAX_SAFE_INTEGER,
|
|
254
|
+
),
|
|
255
|
+
actorId: validateBoundedString(binding.actorId, 'actorId', 1, 256),
|
|
256
|
+
role: 'agent',
|
|
257
|
+
peerId: validateBoundedString(binding.peerId, 'peerId', 1, 256),
|
|
258
|
+
source: 'mcp',
|
|
259
|
+
sessionId: {
|
|
260
|
+
harnessId: 'opencode',
|
|
261
|
+
nativeId: validateBoundedString(session.nativeId, 'sessionId.nativeId', 1, 256),
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
const serializeMcpAuthBinding = (
|
|
267
|
+
binding: IBrowserMcpAuthenticatedBinding,
|
|
268
|
+
): string => plugins.Buffer.from(JSON.stringify(binding), 'utf8').toString('base64url');
|
|
269
|
+
|
|
270
|
+
const parseMcpAuthBinding = (scopes: string[] | undefined): IBrowserMcpAuthenticatedBinding => {
|
|
271
|
+
if (!Array.isArray(scopes) || scopes.length !== 1) {
|
|
272
|
+
throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
return validateMcpBinding(JSON.parse(
|
|
276
|
+
plugins.Buffer.from(scopes[0]!, 'base64url').toString('utf8'),
|
|
277
|
+
));
|
|
278
|
+
} catch {
|
|
279
|
+
throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
280
|
+
}
|
|
281
|
+
};
|