@modelprofile.com/browser-runtime 5.4.1 → 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 CHANGED
@@ -1,5 +1,15 @@
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
+
3
13
  ## 2026-09-14 - 5.4.1
4
14
 
5
15
  ### Fixes
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/browser-runtime',
6
- version: '5.4.1',
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
- operationQueue: IQueuedOperationRecord[];
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;