@modelprofile.com/browser-runtime 5.4.0 → 5.5.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/changelog.md +17 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.operationscheduler.d.ts +25 -0
- package/dist_ts/classes.operationscheduler.js +86 -0
- package/dist_ts/classes.runtime.d.ts +2 -4
- package/dist_ts/classes.runtime.js +10 -67
- package/package.json +2 -2
- package/readme.md +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.operationscheduler.ts +81 -0
- package/ts/classes.runtime.ts +11 -54
package/changelog.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-09-14 - 5.5.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- decouple video statistics from mutation scheduling (runtime)
|
|
8
|
+
- Introduce a resource-owned operation scheduler for pending and active browser operations
|
|
9
|
+
- Allow one getVideoStatistics read to run independently so telemetry cannot block input, navigation, or dialog replies
|
|
10
|
+
- Preserve ordered mutation admission and bounded concurrent wheel dispatch
|
|
11
|
+
- Bump @push.rocks/smartpuppeteer to ^2.12.1
|
|
12
|
+
|
|
13
|
+
## 2026-09-14 - 5.4.1
|
|
14
|
+
|
|
15
|
+
### Fixes
|
|
16
|
+
|
|
17
|
+
- bump @push.rocks/smartpuppeteer to ^2.12.0 (deps)
|
|
18
|
+
- Updates @push.rocks/smartpuppeteer from ^2.11.1 to ^2.12.0.
|
|
19
|
+
|
|
3
20
|
## 2026-09-14 - 5.4.0
|
|
4
21
|
|
|
5
22
|
### Features
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/browser-runtime',
|
|
6
|
-
version: '5.
|
|
6
|
+
version: '5.5.0',
|
|
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
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxtQ0FBbUM7SUFDekMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDBMQUEwTDtDQUN4TSxDQUFBIn0=
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface IQueuedBrowserOperation {
|
|
2
|
+
action: string;
|
|
3
|
+
state: 'queued' | 'starting' | 'active' | 'settled';
|
|
4
|
+
signal: AbortSignal;
|
|
5
|
+
onQueuedAbort?: () => void;
|
|
6
|
+
resolve(value: unknown): void;
|
|
7
|
+
reject(error: unknown): void;
|
|
8
|
+
}
|
|
9
|
+
/** Resource-owned execution order. Telemetry never owns a mutation slot. */
|
|
10
|
+
export declare class BrowserOperationScheduler<T extends IQueuedBrowserOperation> {
|
|
11
|
+
private execute;
|
|
12
|
+
readonly pending: T[];
|
|
13
|
+
private readonly active;
|
|
14
|
+
private admitting?;
|
|
15
|
+
private draining;
|
|
16
|
+
constructor(execute: (operation: T, dispatched: () => void) => Promise<unknown>);
|
|
17
|
+
enqueue(operation: T): void;
|
|
18
|
+
remove(operation: T): void;
|
|
19
|
+
canStart(action: string, active: readonly {
|
|
20
|
+
action: string;
|
|
21
|
+
}[]): boolean;
|
|
22
|
+
private nextIndex;
|
|
23
|
+
private drain;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Resource-owned execution order. Telemetry never owns a mutation slot. */
|
|
2
|
+
export class BrowserOperationScheduler {
|
|
3
|
+
execute;
|
|
4
|
+
pending = [];
|
|
5
|
+
active = new Set();
|
|
6
|
+
admitting;
|
|
7
|
+
draining = false;
|
|
8
|
+
constructor(execute) {
|
|
9
|
+
this.execute = execute;
|
|
10
|
+
}
|
|
11
|
+
enqueue(operation) {
|
|
12
|
+
this.pending.push(operation);
|
|
13
|
+
this.drain();
|
|
14
|
+
}
|
|
15
|
+
remove(operation) {
|
|
16
|
+
const index = this.pending.indexOf(operation);
|
|
17
|
+
if (index >= 0)
|
|
18
|
+
this.pending.splice(index, 1);
|
|
19
|
+
this.drain();
|
|
20
|
+
}
|
|
21
|
+
canStart(action, active) {
|
|
22
|
+
if (action === 'getVideoStatistics') {
|
|
23
|
+
return !active.some(operation => operation.action === 'getVideoStatistics');
|
|
24
|
+
}
|
|
25
|
+
const mutations = active.filter(operation => operation.action !== 'getVideoStatistics');
|
|
26
|
+
if (action === 'respondToDialog') {
|
|
27
|
+
return !mutations.some(operation => operation.action === 'respondToDialog');
|
|
28
|
+
}
|
|
29
|
+
return mutations.length === 0 || action === 'dispatchWheel' && mutations.length < 4
|
|
30
|
+
&& mutations.every(operation => operation.action === 'dispatchWheel');
|
|
31
|
+
}
|
|
32
|
+
nextIndex() {
|
|
33
|
+
const active = [...this.active];
|
|
34
|
+
// A paused page cannot service its queue until the dialog is answered.
|
|
35
|
+
const dialog = this.pending.findIndex(operation => operation.action === 'respondToDialog');
|
|
36
|
+
if (dialog >= 0 && this.canStart('respondToDialog', active))
|
|
37
|
+
return dialog;
|
|
38
|
+
const mutation = this.pending.findIndex(operation => operation.action !== 'getVideoStatistics');
|
|
39
|
+
if (!this.admitting && mutation >= 0 && this.canStart(this.pending[mutation].action, active))
|
|
40
|
+
return mutation;
|
|
41
|
+
const telemetry = this.pending.findIndex(operation => operation.action === 'getVideoStatistics');
|
|
42
|
+
return telemetry >= 0 && this.canStart('getVideoStatistics', active) ? telemetry : -1;
|
|
43
|
+
}
|
|
44
|
+
drain() {
|
|
45
|
+
if (this.draining)
|
|
46
|
+
return;
|
|
47
|
+
this.draining = true;
|
|
48
|
+
try {
|
|
49
|
+
for (let index = this.nextIndex(); index >= 0; index = this.nextIndex()) {
|
|
50
|
+
const operation = this.pending.splice(index, 1)[0];
|
|
51
|
+
if (operation.state === 'settled')
|
|
52
|
+
continue;
|
|
53
|
+
operation.state = 'starting';
|
|
54
|
+
this.active.add(operation);
|
|
55
|
+
if (operation.action !== 'getVideoStatistics' && operation.action !== 'respondToDialog') {
|
|
56
|
+
this.admitting = operation;
|
|
57
|
+
}
|
|
58
|
+
const dispatched = () => {
|
|
59
|
+
if (this.admitting === operation)
|
|
60
|
+
this.admitting = undefined;
|
|
61
|
+
this.drain();
|
|
62
|
+
};
|
|
63
|
+
void this.execute(operation, dispatched).then(result => {
|
|
64
|
+
if (operation.state !== 'settled') {
|
|
65
|
+
operation.state = 'settled';
|
|
66
|
+
operation.resolve(result);
|
|
67
|
+
}
|
|
68
|
+
}, error => {
|
|
69
|
+
if (operation.state !== 'settled') {
|
|
70
|
+
operation.state = 'settled';
|
|
71
|
+
operation.reject(error);
|
|
72
|
+
}
|
|
73
|
+
}).finally(() => {
|
|
74
|
+
if (operation.onQueuedAbort)
|
|
75
|
+
operation.signal.removeEventListener('abort', operation.onQueuedAbort);
|
|
76
|
+
this.active.delete(operation);
|
|
77
|
+
dispatched();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
this.draining = false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcGVyYXRpb25zY2hlZHVsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm9wZXJhdGlvbnNjaGVkdWxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSw0RUFBNEU7QUFDNUUsTUFBTSxPQUFPLHlCQUF5QjtJQU1oQjtJQUxKLE9BQU8sR0FBUSxFQUFFLENBQUM7SUFDakIsTUFBTSxHQUFHLElBQUksR0FBRyxFQUFLLENBQUM7SUFDL0IsU0FBUyxDQUFLO0lBQ2QsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUV6QixZQUFvQixPQUFtRTtRQUFuRSxZQUFPLEdBQVAsT0FBTyxDQUE0RDtJQUFHLENBQUM7SUFFcEYsT0FBTyxDQUFDLFNBQVk7UUFDekIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2YsQ0FBQztJQUVNLE1BQU0sQ0FBQyxTQUFZO1FBQ3hCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzlDLElBQUksS0FBSyxJQUFJLENBQUM7WUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ2YsQ0FBQztJQUVNLFFBQVEsQ0FBQyxNQUFjLEVBQUUsTUFBcUM7UUFDbkUsSUFBSSxNQUFNLEtBQUssb0JBQW9CLEVBQUUsQ0FBQztZQUNwQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLEtBQUssb0JBQW9CLENBQUMsQ0FBQztRQUM5RSxDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNB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
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
2
|
import { BrowserArtifactStore } from './classes.artifactstore.js';
|
|
3
3
|
import { BrowserEgressProxy } from './classes.egressproxy.js';
|
|
4
|
+
import { BrowserOperationScheduler } from './classes.operationscheduler.js';
|
|
4
5
|
import { BrowserRuntimeError } from './errors.js';
|
|
5
6
|
import { type IBrowserRuntimeTestingOptions } from './internal.testing.js';
|
|
6
7
|
import type { IAttachTrustedFramedPeerOptions, IApplyBrowserAttachmentBindingRequest, IBrowserAttachmentBinding, TBrowserCapabilityDescriptor, TBrowserCapabilityAuthorizationRequest, TBrowserRuntimeLeaseAuthority, TBrowserRuntimeOperationClassification, IBrowserRuntimeFrameSubscription, IBrowserRuntimeOperationOptions, IBrowserRuntimeOptions, IBrowserResourceRegistration, IBrowserRuntimeState, IBrowserRuntimeViewportResult, IBrowserRuntimeEventSubscriptionOptions, TBrowserRuntimeVideoOffer, ICreateBrowserResourceRequest, IRegisterBrowserResourceRequest, TIssueBrowserCapabilityRequest, TIssuedBrowserCapability, ILiveBrowserSessionLike, TBrowserActorRole, TBrowserAgentAction, TBrowserAgentActionResult, TBrowserRuntimeEvent } from './interfaces.js';
|
|
@@ -148,14 +149,12 @@ interface IResourceSlot {
|
|
|
148
149
|
unsubscribeSession?: () => void;
|
|
149
150
|
leases: Map<string, ILeaseRecord>;
|
|
150
151
|
operations: Set<IOperationRecord>;
|
|
151
|
-
activeQueuedOperations: Set<IQueuedOperationRecord>;
|
|
152
152
|
inputCleanup?: {
|
|
153
153
|
session: ILiveBrowserSessionLike;
|
|
154
154
|
incarnationGeneration: number;
|
|
155
155
|
promise: Promise<void>;
|
|
156
156
|
};
|
|
157
|
-
|
|
158
|
-
operationSchedulerRunning: boolean;
|
|
157
|
+
operationScheduler: BrowserOperationScheduler<IQueuedOperationRecord>;
|
|
159
158
|
frameSubscriptions: Map<string, IFrameSubscriptionRecord>;
|
|
160
159
|
frameCaptureEnabled?: boolean;
|
|
161
160
|
highestFrameSequence: number;
|
|
@@ -303,7 +302,6 @@ export declare class BrowserRuntime {
|
|
|
303
302
|
private createLeaseRecord;
|
|
304
303
|
private ensureSession;
|
|
305
304
|
private runOperation;
|
|
306
|
-
private drainOperationQueue;
|
|
307
305
|
private executeQueuedOperation;
|
|
308
306
|
private queuedOperationAbortError;
|
|
309
307
|
private normalizeOperationError;
|