@modelprofile.com/browser-runtime 2.1.2 → 3.0.1
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 +18 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexprovider.js +10 -10
- package/dist_ts/classes.framed.d.ts +3 -0
- package/dist_ts/classes.framed.js +16 -3
- package/dist_ts/classes.runtime.d.ts +47 -6
- package/dist_ts/classes.runtime.js +436 -123
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/interfaces.d.ts +15 -0
- package/package.json +2 -2
- package/readme.hints.md +9 -5
- package/readme.md +11 -5
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexprovider.ts +10 -11
- package/ts/classes.framed.ts +16 -2
- package/ts/classes.runtime.ts +581 -150
- package/ts/index.ts +2 -0
- package/ts/interfaces.ts +22 -0
package/dist_ts/index.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ export { BrowserRuntimeError } from './errors.js';
|
|
|
8
8
|
export { createBrowserRuntimeMcpHttpHandler } from './mcp.js';
|
|
9
9
|
export type { TAcquireBrowserRuntimeLeaseOptions } from './classes.runtime.js';
|
|
10
10
|
export type { TBrowserRuntimeErrorCode } from './errors.js';
|
|
11
|
-
export type { IAttachTrustedFramedPeerOptions, IApplyBrowserAttachmentBindingRequest, IBrowserAttachmentBinding, IBrowserActionStateResult, IBrowserArtifactMetadata, IBrowserArtifactStoreOptions, IBrowserMcpAuthenticatedBinding, TBrowserCapabilityAuthorizationRequest, TBrowserCapabilityDescriptor, IBrowserClickAction, IBrowserEgressConnectionOptions, IBrowserEgressProxyOptions, IBrowserEgressProxyStats, IBrowserFlexCapabilityBinding, IBrowserFlexSessionId, IBrowserFillAction, IBrowserNavigateAction, IBrowserObservationResult, IBrowserOpenCodeSessionId, IBrowserPressAction, TBrowserRuntimeAuditEvent, TBrowserRuntimeOperationIdentity, IBrowserRuntimeFlexToolProviderOptions, IBrowserRuntimeFrameSubscription, IBrowserRuntimeFramedClientOptions, IBrowserRuntimeMcpOptions, IBrowserRuntimeOperationOptions, IBrowserRuntimeOptions, IBrowserResourceKey, IBrowserResourceRegistration, IBrowserRuntimeState, IBrowserRuntimeTabState, IBrowserScreenshotAction, IBrowserScreenshotResult, IBrowserSnapshotAction, ICreateBrowserResourceRequest, TIssueBrowserCapabilityRequest, TIssuedBrowserCapability, TQualifiedBrowserSessionId, IRegisterBrowserResourceRequest, IResolvedBrowserFlexCapability, TBrowserActorRole, TBrowserAgentAction, TBrowserAgentActionResult, TBrowserCapabilitySource, TBrowserDnsResolver, TBrowserEgressConnector, TBrowserHarnessId, TBrowserRuntimeEvent, } from './interfaces.js';
|
|
11
|
+
export type { IAttachTrustedFramedPeerOptions, IApplyBrowserAttachmentBindingRequest, IBrowserAttachmentBinding, IBrowserActionStateResult, IBrowserArtifactMetadata, IBrowserArtifactStoreOptions, IBrowserMcpAuthenticatedBinding, TBrowserCapabilityAuthorizationRequest, TBrowserCapabilityDescriptor, IBrowserClickAction, IBrowserEgressConnectionOptions, IBrowserEgressProxyOptions, IBrowserEgressProxyStats, IBrowserFlexCapabilityBinding, IBrowserFlexSessionId, IBrowserFillAction, IBrowserNavigateAction, IBrowserObservationResult, IBrowserOpenCodeSessionId, IBrowserPressAction, TBrowserRuntimeAuditEvent, TBrowserRuntimeLeaseAuthority, TBrowserRuntimeOperationClassification, TBrowserRuntimeOperationIdentity, IBrowserRuntimeFlexToolProviderOptions, IBrowserRuntimeFrameSubscription, IBrowserRuntimeFramedClientOptions, IBrowserRuntimeMcpOptions, IBrowserRuntimeOperationOptions, IBrowserRuntimeOptions, IBrowserResourceKey, IBrowserResourceRegistration, IBrowserRuntimeState, IBrowserRuntimeTabState, IBrowserScreenshotAction, IBrowserScreenshotResult, IBrowserSnapshotAction, ICreateBrowserResourceRequest, TIssueBrowserCapabilityRequest, TIssuedBrowserCapability, TQualifiedBrowserSessionId, IRegisterBrowserResourceRequest, IResolvedBrowserFlexCapability, TBrowserActorRole, TBrowserAgentAction, TBrowserAgentActionResult, TBrowserCapabilitySource, TBrowserDnsResolver, TBrowserEgressConnector, TBrowserHarnessId, TBrowserRuntimeEvent, } from './interfaces.js';
|
package/dist_ts/interfaces.d.ts
CHANGED
|
@@ -51,6 +51,7 @@ export interface IBrowserHumanCapabilityBinding extends IBrowserCapabilityBindin
|
|
|
51
51
|
sessionId?: never;
|
|
52
52
|
scopeId?: never;
|
|
53
53
|
channelId?: never;
|
|
54
|
+
runId?: never;
|
|
54
55
|
}
|
|
55
56
|
export interface IBrowserFlexCapabilityBinding extends IBrowserCapabilityBindingBase {
|
|
56
57
|
role: 'agent';
|
|
@@ -58,6 +59,7 @@ export interface IBrowserFlexCapabilityBinding extends IBrowserCapabilityBinding
|
|
|
58
59
|
sessionId: IBrowserFlexSessionId;
|
|
59
60
|
scopeId: string;
|
|
60
61
|
channelId: string;
|
|
62
|
+
runId: string;
|
|
61
63
|
}
|
|
62
64
|
export interface IBrowserMcpCapabilityBinding extends IBrowserCapabilityBindingBase {
|
|
63
65
|
role: 'agent';
|
|
@@ -65,6 +67,7 @@ export interface IBrowserMcpCapabilityBinding extends IBrowserCapabilityBindingB
|
|
|
65
67
|
sessionId: IBrowserOpenCodeSessionId;
|
|
66
68
|
scopeId?: never;
|
|
67
69
|
channelId?: never;
|
|
70
|
+
runId?: never;
|
|
68
71
|
}
|
|
69
72
|
export type TBrowserCapabilityAuthorizationRequest = IBrowserHumanCapabilityBinding | IBrowserFlexCapabilityBinding | IBrowserMcpCapabilityBinding;
|
|
70
73
|
export type TIssueBrowserCapabilityRequest = TBrowserCapabilityAuthorizationRequest & {
|
|
@@ -91,8 +94,17 @@ export type TBrowserRuntimeOperationIdentity = TReadonlyBrowserCapabilityAuthori
|
|
|
91
94
|
readonly capabilityId: string;
|
|
92
95
|
readonly leaseId: string;
|
|
93
96
|
readonly action: string;
|
|
97
|
+
readonly classification: TBrowserRuntimeOperationClassification;
|
|
94
98
|
readonly startedAt: number;
|
|
95
99
|
};
|
|
100
|
+
export type TBrowserRuntimeOperationClassification = 'raw-input' | 'viewport' | 'navigation' | 'tab' | 'agent-action';
|
|
101
|
+
export type TBrowserRuntimeLeaseAuthority = TReadonlyBrowserCapabilityAuthorizationRequest & {
|
|
102
|
+
readonly runtimeAuthorityId: string;
|
|
103
|
+
readonly authorityGeneration: number;
|
|
104
|
+
readonly incarnationGeneration: number;
|
|
105
|
+
readonly capabilityId: string;
|
|
106
|
+
readonly leaseId: string;
|
|
107
|
+
};
|
|
96
108
|
export type TBrowserRuntimeAuditEvent = TBrowserRuntimeOperationIdentity & {
|
|
97
109
|
readonly phase: 'completed' | 'failed';
|
|
98
110
|
readonly finishedAt: number;
|
|
@@ -151,14 +163,17 @@ export interface IBrowserRuntimeOptions {
|
|
|
151
163
|
authorizationTimeoutMs?: number;
|
|
152
164
|
beforeOperationTimeoutMs?: number;
|
|
153
165
|
maxTabsPerResource?: number;
|
|
166
|
+
maxQueuedOperationsPerLease?: number;
|
|
154
167
|
operationTimeoutMs?: number;
|
|
155
168
|
quiescenceTimeoutMs?: number;
|
|
156
169
|
terminationGraceMs?: number;
|
|
157
170
|
terminationForceMs?: number;
|
|
171
|
+
cleanupTimeoutMs?: number;
|
|
158
172
|
auditTimeoutMs?: number;
|
|
159
173
|
confinementProbeTimeoutMs?: number;
|
|
160
174
|
idleTerminationMs?: number;
|
|
161
175
|
maxFrameBytes?: number;
|
|
176
|
+
maxOutstandingFrames?: number;
|
|
162
177
|
frameAcknowledgementTimeoutMs?: number;
|
|
163
178
|
egress?: Omit<IBrowserEgressProxyOptions, 'projectId' | 'browserResourceId'>;
|
|
164
179
|
artifacts?: Omit<IBrowserArtifactStoreOptions, 'rootDirectory'>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modelprofile.com/browser-runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Parent-owned, resource-centric Chromium runtime with revisioned attachment fencing, authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@modelprofile.com/flexharness": "^4.0.0",
|
|
30
30
|
"@push.rocks/smartagent": "^4.8.0",
|
|
31
31
|
"@push.rocks/smartmcp": "^0.3.0",
|
|
32
|
-
"@push.rocks/smartpuppeteer": "^2.
|
|
32
|
+
"@push.rocks/smartpuppeteer": "^2.4.0",
|
|
33
33
|
"ipaddr.js": "^2.5.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
package/readme.hints.md
CHANGED
|
@@ -5,7 +5,7 @@ Durable implementation findings for `@modelprofile.com/browser-runtime`.
|
|
|
5
5
|
## Ownership and lifecycle
|
|
6
6
|
|
|
7
7
|
- Controller durable truth is a logical resource with immutable `projectId`, stable random `browserResourceId`, and a revisioned attachment binding. Runtime state is process-local and must be re-registered after every restart.
|
|
8
|
-
- A resource slot owns only incarnation and arbitration state: its transition mutex, arbitration and
|
|
8
|
+
- A resource slot owns only incarnation and arbitration state: its transition mutex, arbitration, incarnation, and process-local authority generations, lease, bounded operation FIFO, bounded frame window, Chromium session, authenticated egress proxy, private profile, and idle termination timer.
|
|
9
9
|
- `terminateResource()` and idle termination remove only the incarnation. They preserve registration, attachment, capabilities, and artifacts. `retireResource()` permanently fences, revokes, terminates, purges exact-resource artifacts, then unregisters only after all cleanup succeeds. Durable retirement remains Controller truth; Runtime tombstones are bounded and process-local.
|
|
10
10
|
- Failed retirement retains a fenced, retryable registration. Unknown profile, lock, or artifact ownership remains fail closed.
|
|
11
11
|
- Launch quota admission uses synchronous pending reservations across global and per-project running-resource limits.
|
|
@@ -16,8 +16,10 @@ Durable implementation findings for `@modelprofile.com/browser-runtime`.
|
|
|
16
16
|
- Any `sessionId: null` binding is detached; revision zero is specifically the initial detached/no-agent-authority state. A newer attachment synchronously closes admission before waiting for the resource mutex, revokes its capabilities, and quiesces its active work. Work that ignores cancellation escalates only that resource incarnation.
|
|
17
17
|
- Agent capabilities require the exact current non-detached qualified session. Human capabilities bind the exact resource, project, attachment authority, and revision but intentionally carry no session ID and may be issued while detached. Any attachment advance revokes both human and agent capabilities.
|
|
18
18
|
- Capability tokens are returned once. Runtime records retain only SHA-256 digests and use `timingSafeEqual`. Authorization is rechecked after asynchronous host authorization, during lease acquisition, and before and after every operation.
|
|
19
|
-
- Capability, audit, and lease identity includes immutable project, resource, attachment authority and revision, actor, peer, role, source, qualified agent session, and Flex scope/channel where applicable.
|
|
20
|
-
-
|
|
19
|
+
- Capability, audit, and lease identity includes immutable project, resource, attachment authority and revision, actor, peer, role, source, qualified agent session, and Flex scope/channel/run where applicable.
|
|
20
|
+
- Same-lease operations use a strict bounded FIFO. Queue cancellation composes external abort, lease revocation, attachment transition, resource termination, and runtime shutdown. Only dequeued work reaches `beforeOperation`; started uncertain work must quiesce or fence its exact incarnation before terminal audit and queue advancement.
|
|
21
|
+
- `beforeOperation` reserves the exact resource and lets the host persist policy/audit through an awaited fail-closed gate. Runtime then atomically revalidates lease, attachment, session, arbitration generation, and incarnation before starting the side effect. Both host hooks carry the same exact operation ID and classification; terminal audit remains best effort and runs after bounded cleanup releases or fences the exact reservation.
|
|
22
|
+
- Lease authority snapshots are immutable process-local revalidation tokens. They expose `authorityGeneration` and bind the runtime instance, incarnation, exact `capabilityId`, exact `leaseId`, and attachment, but never replace Controller durable attachment truth.
|
|
21
23
|
|
|
22
24
|
## Browser confinement
|
|
23
25
|
|
|
@@ -34,7 +36,9 @@ Durable implementation findings for `@modelprofile.com/browser-runtime`.
|
|
|
34
36
|
|
|
35
37
|
## Adapter boundary
|
|
36
38
|
|
|
37
|
-
- Framed messages contain no identity selectors. The parent binds project, resource, attachment authority/revision, actor, peer, role, source, qualified session, Flex scope, and
|
|
39
|
+
- Framed messages contain no identity selectors. The parent binds project, resource, attachment authority/revision, actor, peer, role, source, qualified session, Flex scope, channel, and exact run out of band.
|
|
38
40
|
- One qualified session can own multiple resource-specific framed channels. Capability revocation owns server-peer disconnect; peer-initiated release/close revokes only that channel's capability without recursively disconnecting itself.
|
|
39
|
-
-
|
|
41
|
+
- Framed request counts and queued write bytes are bounded. Runtime shutdown has a bounded caller-visible cleanup deadline while retaining in-flight cleanup ownership for retry.
|
|
42
|
+
- Frame delivery owns a bounded map of exact identities and configures SmartPuppeteer's separate private CDP-to-ack map to the same limit. Equal limits prevent private eviction while the application map has spare capacity, but private-first retirement at full capacity can make an exact acknowledgement fulfill `{ accepted: false }`. Both fulfilled booleans settle the application entry without proving successful upstream retirement; rejection or timeout fails closed. Application acknowledgement timeout and failed delivery deliberately fail the lease regardless of a fulfilled boolean. There is no cumulative frame protocol.
|
|
43
|
+
- Flex resolves only a capability token, and the provider's run must exactly match its trusted framed client. SmartAgent exposes exactly navigate, snapshot, screenshot, click, fill, and press.
|
|
40
44
|
- MCP independent authentication returns the complete expected binding. The binding is retained in server-owned auth context and tool schemas expose no resource, session, revision, or authority selector.
|
package/readme.md
CHANGED
|
@@ -71,9 +71,9 @@ try {
|
|
|
71
71
|
}
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
Projects and qualified sessions may each own many resources. Human/agent arbitration, mutexes, leases,
|
|
74
|
+
Projects and qualified sessions may each own many resources. Human/agent arbitration, mutexes, leases, operation queues, profiles, proxies, frame subscriptions, and idle timers are per resource.
|
|
75
75
|
|
|
76
|
-
`registerResource()` is idempotent only for the same project/resource key and identical attachment. `listResources()` reports process-local registration and incarnation metadata. `terminateResource()` terminates only the current incarnation and preserves registration, attachment, and artifacts. `retireResource()` permanently fences the process-local registration, revokes and quiesces authority, terminates its incarnation, purges exact-resource artifacts, and unregisters only after cleanup succeeds. The Controller separately owns durable retirement truth and must not rehydrate retired resources. Runtime tombstones and registrations are ephemeral, bounded process state. `stop()` revokes all process-local capabilities, terminates every incarnation, removes the Runtime-owned artifact root and registrations, and releases the lock without deleting Controller durable truth.
|
|
76
|
+
`registerResource()` is idempotent only for the same project/resource key and identical attachment. `listResources()` reports process-local registration and incarnation metadata. `terminateResource()` terminates only the current incarnation and preserves registration, attachment, and artifacts. `retireResource()` permanently fences the process-local registration, revokes and quiesces authority, terminates its incarnation, purges exact-resource artifacts, and unregisters only after cleanup succeeds. The Controller separately owns durable retirement truth and must not rehydrate retired resources. Runtime tombstones and registrations are ephemeral, bounded process state. `stop()` revokes all process-local capabilities, terminates every incarnation, removes the Runtime-owned artifact root and registrations, and releases the lock without deleting Controller durable truth. `cleanupTimeoutMs` defaults to 30,000 milliseconds and accepts values from 100 through 120,000. If that caller-visible deadline expires, `stop()` rejects with `TIMEOUT` while Runtime retains ownership of the cleanup still in flight; a later `stop()` rejoins it, and `start()` waits for it to finish before restarting.
|
|
77
77
|
|
|
78
78
|
## Attachment Fencing
|
|
79
79
|
|
|
@@ -97,13 +97,19 @@ Agent capabilities require the exact current non-detached qualified session. Hum
|
|
|
97
97
|
|
|
98
98
|
Agent actions are exactly `navigate`, `snapshot`, `screenshot`, `click`, `fill`, and `press`. Human leases additionally expose tab lifecycle, viewport, raw input, frame subscription/acknowledgement, and exact-resource artifact reads/deletes. JavaScript evaluation is not public.
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
Operations from one valid lease enter a strict bounded FIFO. `maxQueuedOperationsPerLease` defaults to 128 and accepts values from 1 through 1,024. Queue overflow fails with `QUOTA_EXCEEDED`; `BUSY` remains resource arbitration. A queued operation aborted by its caller, lease revocation, attachment transition, resource termination, or runtime shutdown never starts. Started work is never superseded, and cancellation does not complete until the work quiesces or the exact resource incarnation is fenced.
|
|
101
|
+
|
|
102
|
+
`beforeOperation` is an optional awaited fail-closed gate. It receives the complete immutable authority, operation/capability/lease IDs, action, classification, start time, and an `AbortSignal` after dequeue but before the browser side effect starts. Classifications are `raw-input`, `viewport`, `navigation`, `tab`, and `agent-action`. Hosts that require durable attempt-before-side-effect auditing should persist the attempt there. Rejection denies the operation. The default `beforeOperationTimeoutMs` is 10,000 milliseconds and accepts values from 100 through 120,000; timeout fails with `TIMEOUT`. The terminal `audit` callback remains a best-effort `completed`/`failed` notification correlated by the same operation ID and classification and runs after bounded operation cleanup releases or fences the exact reservation.
|
|
103
|
+
|
|
104
|
+
`lease.getAuthority()` returns an immutable process-local lease authority containing the runtime authority ID, exported `authorityGeneration`, incarnation generation, and complete capability binding. Every snapshot also binds the exact `capabilityId` and `leaseId`. `lease.isAuthorityCurrent(authority)` performs an exact synchronous revalidation suitable for a host-owned virtual stream. These values are not durable Controller state and do not replace attachment checks against the Controller database.
|
|
105
|
+
|
|
106
|
+
Human frame delivery keeps a bounded exact-identity application window. `maxOutstandingFrames` defaults to 4 and accepts values from 1 through 32. Runtime passes the same bound to SmartPuppeteer's private CDP-to-ack window; the windows remain separately owned, but equal limits prevent private eviction while the application window still has spare capacity. At full capacity SmartPuppeteer retires its oldest private entry before publishing the next frame, so a later exact acknowledgement can fulfill with `{ accepted: false }`. A fulfilled `true` or `false` settles the Runtime entry locally without fencing; `false` does not prove that upstream retirement succeeded. Rejected or timed-out acknowledgement operations fail closed, as do application acknowledgement timeout and failed-delivery retirement regardless of a fulfilled boolean. Frame acknowledgement stays outside the operation FIFO.
|
|
101
107
|
|
|
102
108
|
## Trusted Pipe And Flex
|
|
103
109
|
|
|
104
|
-
Trusted framed peers and clients receive the complete authority out of band: project, resource, attachment authority/revision, actor, peer, role, source, qualified session, Flex scope, and resource-specific channel. Incoming frames cannot select identity. One session may use multiple resource-specific channels concurrently.
|
|
110
|
+
Trusted framed peers and clients receive the complete authority out of band: project, resource, attachment authority/revision, actor, peer, role, source, qualified session, Flex scope, exact run, and resource-specific channel. Incoming frames cannot select identity. One session may use multiple resource-specific channels concurrently. Framed client/server request work and queued writes are bounded under backpressure.
|
|
105
111
|
|
|
106
|
-
`BrowserRuntimeFlexToolProvider<TScope>` resolves only a capability token and exposes the six approved SmartAgent actions. The framed server validates the token against its complete trusted binding.
|
|
112
|
+
`BrowserRuntimeFlexToolProvider<TScope>` resolves only a capability token and exposes the six approved SmartAgent actions. The provider requires its client run ID to match the exact Flex tool-provider context, and every runtime operation hook retains that run ID. The framed server validates the token against its complete trusted binding.
|
|
107
113
|
|
|
108
114
|
## MCP Handler
|
|
109
115
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/browser-runtime',
|
|
6
|
-
version: '
|
|
6
|
+
version: '3.0.1',
|
|
7
7
|
description: 'Parent-owned, resource-centric Chromium runtime with revisioned attachment fencing, authenticated human and agent control, fail-closed egress, bounded artifacts, and Flex/MCP adapters.'
|
|
8
8
|
}
|
|
@@ -34,17 +34,16 @@ implements plugins.flexharness.IFlexToolProvider<TScope> {
|
|
|
34
34
|
): Promise<plugins.flexharness.IFlexToolHandle> {
|
|
35
35
|
if (this.state !== 'unused') throw new BrowserRuntimeError('BUSY');
|
|
36
36
|
this.state = 'provisioning';
|
|
37
|
-
const scopeId = validateBoundedString(context.scopeId, 'scopeId', 1, 128);
|
|
38
|
-
const sessionId = validateBoundedString(context.sessionId, 'sessionId', 1, 128);
|
|
39
|
-
if (
|
|
40
|
-
this.client.scopeId !== scopeId
|
|
41
|
-
|| this.client.sessionId.harnessId !== 'flex'
|
|
42
|
-
|| this.client.sessionId.nativeId !== sessionId
|
|
43
|
-
) {
|
|
44
|
-
this.state = 'closed';
|
|
45
|
-
throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
46
|
-
}
|
|
47
37
|
try {
|
|
38
|
+
const scopeId = validateBoundedString(context.scopeId, 'scopeId', 1, 128);
|
|
39
|
+
const sessionId = validateBoundedString(context.sessionId, 'sessionId', 1, 128);
|
|
40
|
+
const runId = validateBoundedString(context.runId, 'runId', 1, 256);
|
|
41
|
+
if (
|
|
42
|
+
this.client.scopeId !== scopeId
|
|
43
|
+
|| this.client.sessionId.harnessId !== 'flex'
|
|
44
|
+
|| this.client.sessionId.nativeId !== sessionId
|
|
45
|
+
|| this.client.runId !== runId
|
|
46
|
+
) throw new BrowserRuntimeError('CAPABILITY_INVALID');
|
|
48
47
|
context.signal.throwIfAborted();
|
|
49
48
|
const resolved = validateExactKeys(
|
|
50
49
|
await this.resolveCapability(context),
|
|
@@ -61,9 +60,9 @@ implements plugins.flexharness.IFlexToolProvider<TScope> {
|
|
|
61
60
|
await this.client.acquire(capabilityToken, context.signal);
|
|
62
61
|
context.signal.throwIfAborted();
|
|
63
62
|
} catch (error) {
|
|
63
|
+
this.state = 'closed';
|
|
64
64
|
await this.client.release().catch(() => undefined);
|
|
65
65
|
await this.client.close().catch(() => undefined);
|
|
66
|
-
this.state = 'closed';
|
|
67
66
|
throw error;
|
|
68
67
|
}
|
|
69
68
|
this.state = 'active';
|
package/ts/classes.framed.ts
CHANGED
|
@@ -207,6 +207,7 @@ export class BrowserRuntimeFramedServerPeer {
|
|
|
207
207
|
private readonly trustedSource: 'flex';
|
|
208
208
|
private readonly trustedScopeId: string;
|
|
209
209
|
private readonly trustedChannelId: string;
|
|
210
|
+
private readonly trustedRunId: string;
|
|
210
211
|
private readonly trustedSessionId: IBrowserFlexSessionId;
|
|
211
212
|
private readonly channel: JsonFramedChannel;
|
|
212
213
|
private readonly activeRequests = new Map<string, AbortController>();
|
|
@@ -253,6 +254,7 @@ export class BrowserRuntimeFramedServerPeer {
|
|
|
253
254
|
this.trustedSource = options.source;
|
|
254
255
|
this.trustedScopeId = validateBoundedString(options.scopeId, 'scopeId', 1, 256);
|
|
255
256
|
this.trustedChannelId = validateBoundedString(options.channelId, 'channelId', 1, 256);
|
|
257
|
+
this.trustedRunId = validateBoundedString(options.runId, 'runId', 1, 256);
|
|
256
258
|
if (options.sessionId?.harnessId !== 'flex') throw new BrowserRuntimeError('INVALID_INPUT');
|
|
257
259
|
this.trustedSessionId = {
|
|
258
260
|
harnessId: 'flex',
|
|
@@ -353,7 +355,7 @@ export class BrowserRuntimeFramedServerPeer {
|
|
|
353
355
|
const method = validateBoundedString(request.method, 'method', 1, 32);
|
|
354
356
|
if (
|
|
355
357
|
this.activeRequests.size >= hardMaxPendingRequests
|
|
356
|
-
&& (method !== 'cancel' || this.activeRequests.size >= hardMaxPendingRequests
|
|
358
|
+
&& (method !== 'cancel' || this.activeRequests.size >= hardMaxPendingRequests * 2)
|
|
357
359
|
) {
|
|
358
360
|
throw new BrowserRuntimeError('BUSY');
|
|
359
361
|
}
|
|
@@ -399,6 +401,7 @@ export class BrowserRuntimeFramedServerPeer {
|
|
|
399
401
|
source: this.trustedSource,
|
|
400
402
|
scopeId: this.trustedScopeId,
|
|
401
403
|
channelId: this.trustedChannelId,
|
|
404
|
+
runId: this.trustedRunId,
|
|
402
405
|
sessionId: this.trustedSessionId,
|
|
403
406
|
} as const;
|
|
404
407
|
const descriptor = this.runtime.authorizeCapability(capabilityToken, authority);
|
|
@@ -446,6 +449,7 @@ export class BrowserRuntimeFramedServerPeer {
|
|
|
446
449
|
attachmentRevision: this.trustedAttachmentRevision,
|
|
447
450
|
scopeId: this.trustedScopeId,
|
|
448
451
|
channelId: this.trustedChannelId,
|
|
452
|
+
runId: this.trustedRunId,
|
|
449
453
|
sessionId: { ...this.trustedSessionId },
|
|
450
454
|
};
|
|
451
455
|
} else if (method === 'execute') {
|
|
@@ -562,6 +566,7 @@ export class BrowserRuntimeFramedClient {
|
|
|
562
566
|
private closePromise?: Promise<void>;
|
|
563
567
|
private readonly scopeIdValue: string;
|
|
564
568
|
private readonly channelIdValue: string;
|
|
569
|
+
private readonly runIdValue: string;
|
|
565
570
|
private readonly sessionIdValue: IBrowserFlexSessionId;
|
|
566
571
|
private readonly authority: TBrowserCapabilityAuthorizationRequest;
|
|
567
572
|
private readonly afterAcquireResponse?: IBrowserRuntimeFramedClientTestingOptions['afterAcquireResponse'];
|
|
@@ -572,6 +577,7 @@ export class BrowserRuntimeFramedClient {
|
|
|
572
577
|
}
|
|
573
578
|
this.scopeIdValue = validateBoundedString(options.scopeId, 'scopeId', 1, 256);
|
|
574
579
|
this.channelIdValue = validateBoundedString(options.channelId, 'channelId', 1, 256);
|
|
580
|
+
this.runIdValue = validateBoundedString(options.runId, 'runId', 1, 256);
|
|
575
581
|
this.sessionIdValue = {
|
|
576
582
|
harnessId: 'flex',
|
|
577
583
|
nativeId: validateBoundedString(options.sessionId.nativeId, 'sessionId.nativeId', 1, 256),
|
|
@@ -597,6 +603,7 @@ export class BrowserRuntimeFramedClient {
|
|
|
597
603
|
source: 'flex',
|
|
598
604
|
scopeId: this.scopeIdValue,
|
|
599
605
|
channelId: this.channelIdValue,
|
|
606
|
+
runId: this.runIdValue,
|
|
600
607
|
sessionId: this.sessionIdValue,
|
|
601
608
|
};
|
|
602
609
|
this.afterAcquireResponse = browserRuntimeTesting in options
|
|
@@ -647,6 +654,10 @@ export class BrowserRuntimeFramedClient {
|
|
|
647
654
|
return this.channelIdValue;
|
|
648
655
|
}
|
|
649
656
|
|
|
657
|
+
public get runId(): string {
|
|
658
|
+
return this.runIdValue;
|
|
659
|
+
}
|
|
660
|
+
|
|
650
661
|
public get sessionId(): IBrowserFlexSessionId {
|
|
651
662
|
return { ...this.sessionIdValue };
|
|
652
663
|
}
|
|
@@ -790,7 +801,10 @@ export class BrowserRuntimeFramedClient {
|
|
|
790
801
|
fields: Record<string, unknown>,
|
|
791
802
|
): Promise<unknown> {
|
|
792
803
|
this.start();
|
|
793
|
-
|
|
804
|
+
const pendingLimit = method === 'cancel'
|
|
805
|
+
? this.maxPendingRequests * 2
|
|
806
|
+
: this.maxPendingRequests;
|
|
807
|
+
if (this.pending.size >= pendingLimit) throw new BrowserRuntimeError('BUSY');
|
|
794
808
|
const responsePromise = new Promise<unknown>((resolve, reject) => {
|
|
795
809
|
const timer = setTimeout(() => {
|
|
796
810
|
this.pending.delete(id);
|