agl 1.0.17 → 21.0.2
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 +55 -0
- package/changelog.md +1026 -0
- package/cli.js +14 -0
- package/dist_serve/bundle.js +44778 -0
- package/dist_serve/index.html +13 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.authmodels.d.ts +126 -0
- package/dist_ts/classes.authmodels.js +1422 -0
- package/dist_ts/classes.authstore.d.ts +160 -0
- package/dist_ts/classes.authstore.js +2483 -0
- package/dist_ts/classes.browserresourcehost.d.ts +85 -0
- package/dist_ts/classes.browserresourcehost.js +912 -0
- package/dist_ts/classes.cli.d.ts +21 -0
- package/dist_ts/classes.cli.js +1082 -0
- package/dist_ts/classes.config.d.ts +23 -0
- package/dist_ts/classes.config.js +267 -0
- package/dist_ts/classes.controller.d.ts +523 -0
- package/dist_ts/classes.controller.js +10611 -0
- package/dist_ts/classes.controllermanagement.d.ts +32 -0
- package/dist_ts/classes.controllermanagement.js +222 -0
- package/dist_ts/classes.draftmanager.d.ts +30 -0
- package/dist_ts/classes.draftmanager.js +179 -0
- package/dist_ts/classes.embeddeddb.d.ts +30 -0
- package/dist_ts/classes.embeddeddb.js +159 -0
- package/dist_ts/classes.flexframedtransport.d.ts +56 -0
- package/dist_ts/classes.flexframedtransport.js +275 -0
- package/dist_ts/classes.flexmodels.private.d.ts +231 -0
- package/dist_ts/classes.flexmodels.private.js +985 -0
- package/dist_ts/classes.flexmodels.public.d.ts +207 -0
- package/dist_ts/classes.flexmodels.public.js +885 -0
- package/dist_ts/classes.flexprojectionreader.d.ts +89 -0
- package/dist_ts/classes.flexprojectionreader.js +580 -0
- package/dist_ts/classes.flexservice.d.ts +196 -0
- package/dist_ts/classes.flexservice.js +3704 -0
- package/dist_ts/classes.flexstore.d.ts +174 -0
- package/dist_ts/classes.flexstore.js +3400 -0
- package/dist_ts/classes.flexsupervisor.d.ts +105 -0
- package/dist_ts/classes.flexsupervisor.js +1191 -0
- package/dist_ts/classes.gitreversion.d.ts +431 -0
- package/dist_ts/classes.gitreversion.js +10592 -0
- package/dist_ts/classes.harnessoperationmanager.d.ts +113 -0
- package/dist_ts/classes.harnessoperationmanager.js +602 -0
- package/dist_ts/classes.opencodeclient.d.ts +146 -0
- package/dist_ts/classes.opencodeclient.js +3003 -0
- package/dist_ts/classes.opencodesupervisor.d.ts +60 -0
- package/dist_ts/classes.opencodesupervisor.js +1003 -0
- package/dist_ts/classes.passkeymanager.d.ts +34 -0
- package/dist_ts/classes.passkeymanager.js +456 -0
- package/dist_ts/classes.processinspection.d.ts +50 -0
- package/dist_ts/classes.processinspection.js +484 -0
- package/dist_ts/classes.resourcecoordinator.d.ts +64 -0
- package/dist_ts/classes.resourcecoordinator.js +294 -0
- package/dist_ts/classes.sessionintelligencereader.d.ts +13 -0
- package/dist_ts/classes.sessionintelligencereader.js +40 -0
- package/dist_ts/classes.systemmetricssampler.d.ts +53 -0
- package/dist_ts/classes.systemmetricssampler.js +168 -0
- package/dist_ts/classes.terminalmanager.d.ts +95 -0
- package/dist_ts/classes.terminalmanager.js +981 -0
- package/dist_ts/classes.terminalresourcehost.d.ts +20 -0
- package/dist_ts/classes.terminalresourcehost.js +84 -0
- package/dist_ts/classes.upgradecoordinator.d.ts +244 -0
- package/dist_ts/classes.upgradecoordinator.js +2155 -0
- package/dist_ts/classes.upgradetransaction.d.ts +92 -0
- package/dist_ts/classes.upgradetransaction.js +2125 -0
- package/dist_ts/classes.uploadmanager.d.ts +24 -0
- package/dist_ts/classes.uploadmanager.js +210 -0
- package/dist_ts/classes.validation.d.ts +91 -0
- package/dist_ts/classes.validation.js +1087 -0
- package/dist_ts/flexharness.child.d.ts +1 -0
- package/dist_ts/flexharness.child.js +28 -0
- package/dist_ts/functions.canonicaldirectory.d.ts +21 -0
- package/dist_ts/functions.canonicaldirectory.js +144 -0
- package/dist_ts/functions.controllerdataroot.d.ts +15 -0
- package/dist_ts/functions.controllerdataroot.js +76 -0
- package/dist_ts/functions.embeddeddb.d.ts +2 -0
- package/dist_ts/functions.embeddeddb.js +21 -0
- package/dist_ts/functions.flexcredentialstore.d.ts +16 -0
- package/dist_ts/functions.flexcredentialstore.js +93 -0
- package/dist_ts/functions.opencodeauth.d.ts +3 -0
- package/dist_ts/functions.opencodeauth.js +31 -0
- package/dist_ts/functions.runtimeenvironment.d.ts +2 -0
- package/dist_ts/functions.runtimeenvironment.js +79 -0
- package/dist_ts/functions.upgradefollower.d.ts +3 -0
- package/dist_ts/functions.upgradefollower.js +95 -0
- package/dist_ts/index.d.ts +24 -0
- package/dist_ts/index.js +25 -0
- package/dist_ts/interfaces.auth.d.ts +181 -0
- package/dist_ts/interfaces.auth.js +82 -0
- package/dist_ts/interfaces.config.d.ts +34 -0
- package/dist_ts/interfaces.config.js +2 -0
- package/dist_ts/interfaces.flexipc.d.ts +939 -0
- package/dist_ts/interfaces.flexipc.js +1492 -0
- package/dist_ts/interfaces.gitreversion.d.ts +246 -0
- package/dist_ts/interfaces.gitreversion.js +2 -0
- package/dist_ts/interfaces.lifecycle.d.ts +37 -0
- package/dist_ts/interfaces.lifecycle.js +2 -0
- package/dist_ts/interfaces.opencode.d.ts +101 -0
- package/dist_ts/interfaces.opencode.js +3 -0
- package/dist_ts/interfaces.projects.d.ts +156 -0
- package/dist_ts/interfaces.projects.js +5 -0
- package/dist_ts/plugins.d.ts +36 -0
- package/dist_ts/plugins.js +40 -0
- package/dist_ts_interfaces/index.d.ts +2 -0
- package/dist_ts_interfaces/index.js +3 -0
- package/dist_ts_interfaces/interfaces.d.ts +747 -0
- package/dist_ts_interfaces/interfaces.js +47 -0
- package/dist_ts_interfaces/plugins.d.ts +4 -0
- package/dist_ts_interfaces/plugins.js +3 -0
- package/dist_ts_interfaces/requests.d.ts +806 -0
- package/dist_ts_interfaces/requests.js +2 -0
- package/dist_ts_migration/classes.documentmigrationrunner.d.ts +8 -0
- package/dist_ts_migration/classes.documentmigrationrunner.js +24 -0
- package/dist_ts_migration/classes.flexmigrationrunner.d.ts +11 -0
- package/dist_ts_migration/classes.flexmigrationrunner.js +25 -0
- package/dist_ts_migration/classes.flexpostharnessmigrationrunner.d.ts +10 -0
- package/dist_ts_migration/classes.flexpostharnessmigrationrunner.js +15 -0
- package/dist_ts_migration/classes.migrationrunner.d.ts +8 -0
- package/dist_ts_migration/classes.migrationrunner.js +34 -0
- package/dist_ts_migration/index.d.ts +12 -0
- package/dist_ts_migration/index.js +13 -0
- package/dist_ts_migration/v10_flexharnessv3migration.d.ts +11 -0
- package/dist_ts_migration/v10_flexharnessv3migration.js +23 -0
- package/dist_ts_migration/v13_flexprojectionorder.d.ts +11 -0
- package/dist_ts_migration/v13_flexprojectionorder.js +23 -0
- package/dist_ts_migration/v16_flexprovidercredentials.d.ts +22 -0
- package/dist_ts_migration/v16_flexprovidercredentials.js +149 -0
- package/dist_ts_migration/v18_resourcelayout.d.ts +22 -0
- package/dist_ts_migration/v18_resourcelayout.js +23 -0
- package/dist_ts_migration/v18_resourcelayoutmigration.d.ts +6 -0
- package/dist_ts_migration/v18_resourcelayoutmigration.js +61 -0
- package/dist_ts_migration/v19_flexprojectmanagement.d.ts +11 -0
- package/dist_ts_migration/v19_flexprojectmanagement.js +21 -0
- package/dist_ts_migration/v1_embeddeddatabaselocation.d.ts +28 -0
- package/dist_ts_migration/v1_embeddeddatabaselocation.js +415 -0
- package/dist_ts_migration/v22_projectfilesystemidentitymigration.d.ts +7 -0
- package/dist_ts_migration/v22_projectfilesystemidentitymigration.js +105 -0
- package/dist_ts_migration/v2_controllerdataroot.d.ts +130 -0
- package/dist_ts_migration/v2_controllerdataroot.js +1887 -0
- package/dist_ts_migration/v6_protocoldocumentmigration.d.ts +7 -0
- package/dist_ts_migration/v6_protocoldocumentmigration.js +100 -0
- package/dist_ts_migration/v6_protocoldocuments.d.ts +7 -0
- package/dist_ts_migration/v6_protocoldocuments.js +138 -0
- package/html/index.html +13 -0
- package/{LICENSE → license.md} +2 -2
- package/package.json +86 -48
- package/readme.md +480 -0
- package/readme.plan.md +188 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.authmodels.ts +1245 -0
- package/ts/classes.authstore.ts +3274 -0
- package/ts/classes.browserresourcehost.ts +1205 -0
- package/ts/classes.cli.ts +1254 -0
- package/ts/classes.config.ts +351 -0
- package/ts/classes.controller.ts +14426 -0
- package/ts/classes.controllermanagement.ts +330 -0
- package/ts/classes.draftmanager.ts +232 -0
- package/ts/classes.embeddeddb.ts +166 -0
- package/ts/classes.flexframedtransport.ts +283 -0
- package/ts/classes.flexmodels.private.ts +823 -0
- package/ts/classes.flexmodels.public.ts +732 -0
- package/ts/classes.flexprojectionreader.ts +816 -0
- package/ts/classes.flexservice.ts +4302 -0
- package/ts/classes.flexstore.ts +4565 -0
- package/ts/classes.flexsupervisor.ts +1453 -0
- package/ts/classes.gitreversion.ts +13353 -0
- package/ts/classes.harnessoperationmanager.ts +870 -0
- package/ts/classes.opencodeclient.ts +4110 -0
- package/ts/classes.opencodesupervisor.ts +1280 -0
- package/ts/classes.passkeymanager.ts +570 -0
- package/ts/classes.processinspection.ts +623 -0
- package/ts/classes.resourcecoordinator.ts +436 -0
- package/ts/classes.sessionintelligencereader.ts +52 -0
- package/ts/classes.systemmetricssampler.ts +215 -0
- package/ts/classes.terminalmanager.ts +1207 -0
- package/ts/classes.terminalresourcehost.ts +122 -0
- package/ts/classes.upgradecoordinator.ts +2675 -0
- package/ts/classes.upgradetransaction.ts +2900 -0
- package/ts/classes.uploadmanager.ts +240 -0
- package/ts/classes.validation.ts +1409 -0
- package/ts/flexharness.child.ts +35 -0
- package/ts/functions.canonicaldirectory.ts +213 -0
- package/ts/functions.controllerdataroot.ts +107 -0
- package/ts/functions.embeddeddb.ts +22 -0
- package/ts/functions.flexcredentialstore.ts +128 -0
- package/ts/functions.opencodeauth.ts +34 -0
- package/ts/functions.runtimeenvironment.ts +90 -0
- package/ts/functions.upgradefollower.ts +115 -0
- package/ts/index.ts +36 -6
- package/ts/interfaces.auth.ts +316 -0
- package/ts/interfaces.config.ts +37 -0
- package/ts/interfaces.flexipc.ts +2586 -0
- package/ts/interfaces.gitreversion.ts +336 -0
- package/ts/interfaces.lifecycle.ts +46 -0
- package/ts/interfaces.opencode.ts +153 -0
- package/ts/interfaces.projects.ts +182 -0
- package/ts/plugins.ts +64 -0
- package/ts_interfaces/index.ts +2 -0
- package/ts_interfaces/interfaces.ts +827 -0
- package/ts_interfaces/plugins.ts +15 -0
- package/ts_interfaces/requests.ts +1186 -0
- package/ts_migration/classes.documentmigrationrunner.ts +32 -0
- package/ts_migration/classes.flexmigrationrunner.ts +33 -0
- package/ts_migration/classes.flexpostharnessmigrationrunner.ts +22 -0
- package/ts_migration/classes.migrationrunner.ts +40 -0
- package/ts_migration/index.ts +12 -0
- package/ts_migration/v10_flexharnessv3migration.ts +35 -0
- package/ts_migration/v13_flexprojectionorder.ts +33 -0
- package/ts_migration/v16_flexprovidercredentials.ts +196 -0
- package/ts_migration/v18_resourcelayout.ts +55 -0
- package/ts_migration/v18_resourcelayoutmigration.ts +68 -0
- package/ts_migration/v19_flexprojectmanagement.ts +28 -0
- package/ts_migration/v1_embeddeddatabaselocation.ts +560 -0
- package/ts_migration/v22_projectfilesystemidentitymigration.ts +121 -0
- package/ts_migration/v2_controllerdataroot.ts +2349 -0
- package/ts_migration/v6_protocoldocumentmigration.ts +144 -0
- package/ts_migration/v6_protocoldocuments.ts +198 -0
- package/ts_web/00_commitinfo_data.ts +8 -0
- package/ts_web/classes.controllersocketclient.ts +517 -0
- package/ts_web/classes.sessiondraftsync.ts +390 -0
- package/ts_web/elements.harnesscontrollerapp.ts +11494 -0
- package/ts_web/index.ts +2 -0
- package/ts_web/plugins.ts +31 -0
- package/.gitlab-ci.yml +0 -71
- package/.npmignore +0 -5
- package/README.md +0 -40
- package/dist/cli.js +0 -2
- package/dist/index.d.ts +0 -0
- package/dist/index.js +0 -9
- package/dist/mod_bundle/index.d.ts +0 -1
- package/dist/mod_bundle/index.js +0 -18
- package/dist/mod_bundle/mod.plugins.d.ts +0 -4
- package/dist/mod_bundle/mod.plugins.js +0 -11
- package/dist/mod_install/index.d.ts +0 -4
- package/dist/mod_install/index.js +0 -21
- package/dist/mod_install/mod.plugins.d.ts +0 -1
- package/dist/mod_install/mod.plugins.js +0 -7
- package/dist/mod_standard/index.d.ts +0 -4
- package/dist/mod_standard/index.js +0 -21
- package/dist/mod_standard/mod.browser.d.ts +0 -6
- package/dist/mod_standard/mod.browser.js +0 -14
- package/dist/mod_standard/mod.clean.d.ts +0 -4
- package/dist/mod_standard/mod.clean.js +0 -12
- package/dist/mod_standard/mod.compile.d.ts +0 -4
- package/dist/mod_standard/mod.compile.js +0 -21
- package/dist/mod_standard/mod.plugins.d.ts +0 -8
- package/dist/mod_standard/mod.plugins.js +0 -19
- package/dist/mod_standard/mod.test.d.ts +0 -4
- package/dist/mod_standard/mod.test.js +0 -12
- package/dist/plr.cli.d.ts +0 -3
- package/dist/plr.cli.js +0 -57
- package/dist/plr.config.d.ts +0 -11
- package/dist/plr.config.js +0 -26
- package/dist/plr.mods.d.ts +0 -17
- package/dist/plr.mods.js +0 -17
- package/dist/plr.paths.d.ts +0 -19
- package/dist/plr.paths.js +0 -26
- package/dist/plr.plugins.d.ts +0 -8
- package/dist/plr.plugins.js +0 -16
- package/npmextra.json +0 -10
- package/ts/mod_bundle/index.ts +0 -20
- package/ts/mod_bundle/mod.plugins.ts +0 -9
- package/ts/mod_install/index.ts +0 -20
- package/ts/mod_install/mod.plugins.ts +0 -1
- package/ts/mod_standard/index.ts +0 -23
- package/ts/mod_standard/mod.browser.ts +0 -17
- package/ts/mod_standard/mod.clean.ts +0 -13
- package/ts/mod_standard/mod.compile.ts +0 -23
- package/ts/mod_standard/mod.plugins.ts +0 -17
- package/ts/mod_standard/mod.test.ts +0 -13
- package/ts/plr.cli.ts +0 -60
- package/ts/plr.config.ts +0 -36
- package/ts/plr.mods.ts +0 -25
- package/ts/plr.paths.ts +0 -29
- package/ts/plr.plugins.ts +0 -17
- package/tslint.json +0 -3
- package/yarn.lock +0 -3464
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { flexIpcMaximumBrowserChannels, } from './interfaces.flexipc.js';
|
|
3
|
+
const maximumPendingFlexCapabilityIssuances = 128;
|
|
4
|
+
const maximumActiveHumanBrowserViews = 64;
|
|
5
|
+
const maximumTrackedCapabilityRevocations = 512;
|
|
6
|
+
const maximumCleanupOperationWaiters = 512;
|
|
7
|
+
const browserCapabilityAuthorizationTimeoutMs = 10_000;
|
|
8
|
+
const browserResourceCleanupTimeoutMs = 40_000;
|
|
9
|
+
const waitForSignal = async (promiseArg, signalArg) => new Promise((resolve, reject) => {
|
|
10
|
+
const abort = () => {
|
|
11
|
+
signalArg.removeEventListener('abort', abort);
|
|
12
|
+
reject(signalArg.reason ?? new DOMException('The operation was aborted.', 'AbortError'));
|
|
13
|
+
};
|
|
14
|
+
signalArg.addEventListener('abort', abort, { once: true });
|
|
15
|
+
if (signalArg.aborted) {
|
|
16
|
+
abort();
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
void promiseArg.then((value) => {
|
|
20
|
+
signalArg.removeEventListener('abort', abort);
|
|
21
|
+
resolve(value);
|
|
22
|
+
}, (errorArg) => {
|
|
23
|
+
signalArg.removeEventListener('abort', abort);
|
|
24
|
+
reject(errorArg);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
const waitForCleanupDeadline = async (promiseArg, deadlineAtArg, messageArg, signalArg) => new Promise((resolve, reject) => {
|
|
28
|
+
let timeout;
|
|
29
|
+
let settled = false;
|
|
30
|
+
const finish = (operationArg) => {
|
|
31
|
+
if (settled)
|
|
32
|
+
return;
|
|
33
|
+
settled = true;
|
|
34
|
+
if (timeout)
|
|
35
|
+
clearTimeout(timeout);
|
|
36
|
+
signalArg?.removeEventListener('abort', abort);
|
|
37
|
+
operationArg();
|
|
38
|
+
};
|
|
39
|
+
const abort = () => finish(() => reject(signalArg?.reason ?? new DOMException('The operation was aborted.', 'AbortError')));
|
|
40
|
+
void promiseArg.then((value) => finish(() => resolve(value)), (errorArg) => finish(() => reject(errorArg)));
|
|
41
|
+
if (signalArg?.aborted) {
|
|
42
|
+
abort();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
signalArg?.addEventListener('abort', abort, { once: true });
|
|
46
|
+
const remainingMs = deadlineAtArg - Date.now();
|
|
47
|
+
if (remainingMs <= 0) {
|
|
48
|
+
finish(() => reject(new Error(messageArg)));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
timeout = setTimeout(() => finish(() => reject(new Error(messageArg))), remainingMs);
|
|
52
|
+
});
|
|
53
|
+
const observeCleanupOperation = (operationArg, onSettledArg) => {
|
|
54
|
+
const operation = { waiters: new Set() };
|
|
55
|
+
const settle = (outcomeArg) => {
|
|
56
|
+
if (operation.outcome)
|
|
57
|
+
return;
|
|
58
|
+
operation.outcome = outcomeArg;
|
|
59
|
+
onSettledArg?.(outcomeArg);
|
|
60
|
+
const waiters = [...operation.waiters];
|
|
61
|
+
operation.waiters.clear();
|
|
62
|
+
for (const waiter of waiters)
|
|
63
|
+
waiter(outcomeArg);
|
|
64
|
+
};
|
|
65
|
+
void Promise.resolve().then(operationArg).then(() => settle({ status: 'fulfilled' }), (reason) => settle({ status: 'rejected', reason }));
|
|
66
|
+
return operation;
|
|
67
|
+
};
|
|
68
|
+
const waitForObservedCleanup = async (operationArg, deadlineAtArg, messageArg, signalArg) => {
|
|
69
|
+
if (operationArg.outcome)
|
|
70
|
+
return operationArg.outcome;
|
|
71
|
+
signalArg?.throwIfAborted();
|
|
72
|
+
const remainingMs = deadlineAtArg - Date.now();
|
|
73
|
+
if (remainingMs <= 0)
|
|
74
|
+
throw new Error(messageArg);
|
|
75
|
+
if (operationArg.waiters.size >= maximumCleanupOperationWaiters) {
|
|
76
|
+
throw new Error('Browser cleanup waiter capacity was reached.');
|
|
77
|
+
}
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
let timeout;
|
|
80
|
+
let settled = false;
|
|
81
|
+
const finish = (finishArg) => {
|
|
82
|
+
if (settled)
|
|
83
|
+
return;
|
|
84
|
+
settled = true;
|
|
85
|
+
if (timeout)
|
|
86
|
+
clearTimeout(timeout);
|
|
87
|
+
operationArg.waiters.delete(complete);
|
|
88
|
+
signalArg?.removeEventListener('abort', abort);
|
|
89
|
+
finishArg();
|
|
90
|
+
};
|
|
91
|
+
const complete = (outcomeArg) => {
|
|
92
|
+
finish(() => resolve(outcomeArg));
|
|
93
|
+
};
|
|
94
|
+
const abort = () => finish(() => reject(signalArg?.reason ?? new DOMException('The operation was aborted.', 'AbortError')));
|
|
95
|
+
operationArg.waiters.add(complete);
|
|
96
|
+
signalArg?.addEventListener('abort', abort, { once: true });
|
|
97
|
+
if (operationArg.outcome) {
|
|
98
|
+
complete(operationArg.outcome);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (signalArg?.aborted) {
|
|
102
|
+
abort();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
timeout = setTimeout(() => finish(() => reject(new Error(messageArg))), remainingMs);
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
export class ControllerBrowserResourceHost {
|
|
109
|
+
options;
|
|
110
|
+
runtime;
|
|
111
|
+
started = false;
|
|
112
|
+
unavailable = false;
|
|
113
|
+
stopping = false;
|
|
114
|
+
cleanupTimeoutMs = browserResourceCleanupTimeoutMs;
|
|
115
|
+
startPromise;
|
|
116
|
+
stopPromise;
|
|
117
|
+
flexAuthorizationBindings = new Map();
|
|
118
|
+
flexChannels = new Map();
|
|
119
|
+
flexChannelAdmissions = new Map();
|
|
120
|
+
capabilityRevocationOperations = new Map();
|
|
121
|
+
lateCapabilityIssuanceTasks = new Map();
|
|
122
|
+
humanViews = new Set();
|
|
123
|
+
humanViewAdmissions = new Set();
|
|
124
|
+
admissionAbortController = new AbortController();
|
|
125
|
+
runtimeStopOperations = new WeakMap();
|
|
126
|
+
constructor(options) {
|
|
127
|
+
this.options = options;
|
|
128
|
+
}
|
|
129
|
+
async start(signalArg) {
|
|
130
|
+
if (this.started || this.unavailable)
|
|
131
|
+
return;
|
|
132
|
+
if (this.startPromise)
|
|
133
|
+
return await waitForSignal(this.startPromise, signalArg ?? new AbortController().signal);
|
|
134
|
+
if (this.stopping)
|
|
135
|
+
throw new Error('Browser resource host cleanup is incomplete.');
|
|
136
|
+
if (this.admissionAbortController.signal.aborted) {
|
|
137
|
+
this.admissionAbortController = new AbortController();
|
|
138
|
+
}
|
|
139
|
+
const startPromise = this.performStart(signalArg);
|
|
140
|
+
this.startPromise = startPromise;
|
|
141
|
+
try {
|
|
142
|
+
await startPromise;
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
if (this.startPromise === startPromise)
|
|
146
|
+
this.startPromise = undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async performStart(signalArg) {
|
|
150
|
+
signalArg?.throwIfAborted();
|
|
151
|
+
const runtime = new plugins.browserRuntime.BrowserRuntime({
|
|
152
|
+
runtimeDirectory: this.options.runtimeDirectory,
|
|
153
|
+
authorizationTimeoutMs: browserCapabilityAuthorizationTimeoutMs,
|
|
154
|
+
authorizeCapability: this.options.authorizeCapability,
|
|
155
|
+
...(this.options.beforeOperation === undefined ? {} : {
|
|
156
|
+
beforeOperation: this.options.beforeOperation,
|
|
157
|
+
}),
|
|
158
|
+
...(this.options.audit === undefined ? {} : { audit: this.options.audit }),
|
|
159
|
+
});
|
|
160
|
+
this.runtime = runtime;
|
|
161
|
+
try {
|
|
162
|
+
await (signalArg ? waitForSignal(runtime.start(), signalArg) : runtime.start());
|
|
163
|
+
signalArg?.throwIfAborted();
|
|
164
|
+
if (this.stopping)
|
|
165
|
+
throw new Error('Browser resource host cleanup began during startup.');
|
|
166
|
+
this.started = true;
|
|
167
|
+
}
|
|
168
|
+
catch (errorArg) {
|
|
169
|
+
if (errorArg instanceof plugins.browserRuntime.BrowserRuntimeError
|
|
170
|
+
&& (errorArg.code === 'CONFINEMENT_FAILED' || errorArg.code === 'INVALID_INPUT')) {
|
|
171
|
+
await runtime.stop().catch((cleanupErrorArg) => {
|
|
172
|
+
throw new AggregateError([errorArg, cleanupErrorArg], 'BrowserRuntime startup and cleanup failed.');
|
|
173
|
+
});
|
|
174
|
+
if (this.runtime === runtime)
|
|
175
|
+
this.runtime = undefined;
|
|
176
|
+
this.unavailable = true;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
await runtime.stop().catch((cleanupErrorArg) => {
|
|
180
|
+
throw new AggregateError([errorArg, cleanupErrorArg], 'BrowserRuntime startup and cleanup failed.');
|
|
181
|
+
});
|
|
182
|
+
if (this.runtime === runtime)
|
|
183
|
+
this.runtime = undefined;
|
|
184
|
+
throw errorArg;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async stop() {
|
|
188
|
+
if (this.stopPromise)
|
|
189
|
+
return this.stopPromise;
|
|
190
|
+
const stopPromise = this.performStop();
|
|
191
|
+
this.stopPromise = stopPromise;
|
|
192
|
+
try {
|
|
193
|
+
await stopPromise;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
if (this.stopPromise === stopPromise)
|
|
197
|
+
this.stopPromise = undefined;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async performStop() {
|
|
201
|
+
const runtime = this.runtime;
|
|
202
|
+
if (!runtime) {
|
|
203
|
+
if (this.humanViews.size > 0
|
|
204
|
+
|| this.flexChannels.size > 0
|
|
205
|
+
|| this.flexChannelAdmissions.size > 0
|
|
206
|
+
|| this.humanViewAdmissions.size > 0
|
|
207
|
+
|| this.capabilityRevocationOperations.size > 0
|
|
208
|
+
|| this.lateCapabilityIssuanceTasks.size > 0)
|
|
209
|
+
throw new Error('Browser resource host cleanup has no runtime owner.');
|
|
210
|
+
this.stopping = false;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
this.stopping = true;
|
|
214
|
+
if (!this.admissionAbortController.signal.aborted) {
|
|
215
|
+
this.admissionAbortController.abort(new Error('Browser resource host is stopping.'));
|
|
216
|
+
}
|
|
217
|
+
const deadlineAt = Date.now() + this.cleanupTimeoutMs;
|
|
218
|
+
const cleanupErrors = [];
|
|
219
|
+
for (const cleanup of [
|
|
220
|
+
() => this.cancelAndDrainFlexChannelAdmissions(deadlineAt),
|
|
221
|
+
() => this.drainHumanViewAdmissions(deadlineAt),
|
|
222
|
+
() => this.closeAllHumanViews(deadlineAt),
|
|
223
|
+
() => this.closeAllFlexChannels(undefined, deadlineAt),
|
|
224
|
+
() => this.drainLateCapabilityIssuanceTasks(deadlineAt),
|
|
225
|
+
() => this.retryPendingCapabilityRevocations(deadlineAt),
|
|
226
|
+
]) {
|
|
227
|
+
await cleanup().catch((errorArg) => cleanupErrors.push(errorArg));
|
|
228
|
+
}
|
|
229
|
+
if (cleanupErrors.length > 0) {
|
|
230
|
+
throw new AggregateError(cleanupErrors, 'Browser resource host cleanup is incomplete.');
|
|
231
|
+
}
|
|
232
|
+
await this.stopRuntime(runtime, deadlineAt);
|
|
233
|
+
if (this.runtime === runtime)
|
|
234
|
+
this.runtime = undefined;
|
|
235
|
+
this.started = false;
|
|
236
|
+
this.stopping = false;
|
|
237
|
+
}
|
|
238
|
+
authorizeFlexCapability(requestArg) {
|
|
239
|
+
if (requestArg.role !== 'agent' || requestArg.source !== 'flex')
|
|
240
|
+
return false;
|
|
241
|
+
const expected = this.flexAuthorizationBindings.get(requestArg.channelId);
|
|
242
|
+
return expected !== undefined
|
|
243
|
+
&& this.isFlexRunActive(expected.binding, expected.runId)
|
|
244
|
+
&& expected.binding.projectId === requestArg.projectId
|
|
245
|
+
&& expected.binding.browserResourceId === requestArg.browserResourceId
|
|
246
|
+
&& expected.binding.attachmentAuthorityId === requestArg.attachmentAuthorityId
|
|
247
|
+
&& expected.binding.attachmentRevision === requestArg.attachmentRevision
|
|
248
|
+
&& expected.binding.actorId === requestArg.actorId
|
|
249
|
+
&& expected.binding.peerId === requestArg.peerId
|
|
250
|
+
&& expected.binding.scopeId === requestArg.scopeId
|
|
251
|
+
&& expected.binding.channelId === requestArg.channelId
|
|
252
|
+
&& expected.binding.runId === requestArg.runId
|
|
253
|
+
&& expected.binding.sessionId.harnessId === requestArg.sessionId.harnessId
|
|
254
|
+
&& expected.binding.sessionId.nativeId === requestArg.sessionId.nativeId;
|
|
255
|
+
}
|
|
256
|
+
async openFlexChannel(inputArg) {
|
|
257
|
+
const runtime = this.runtime;
|
|
258
|
+
const resource = inputArg.resource;
|
|
259
|
+
if (!runtime
|
|
260
|
+
|| !this.started
|
|
261
|
+
|| resource.kind !== 'browser'
|
|
262
|
+
|| resource.lifecycle !== 'active'
|
|
263
|
+
|| resource.pendingAttachment !== undefined
|
|
264
|
+
|| resource.sessionId?.harnessId !== 'flex'
|
|
265
|
+
|| resource.sessionId.nativeId !== inputArg.sessionId
|
|
266
|
+
|| resource.projectId !== inputArg.scopeId
|
|
267
|
+
|| this.flexChannels.has(inputArg.channelId)
|
|
268
|
+
|| this.flexChannelAdmissions.has(inputArg.channelId)
|
|
269
|
+
|| this.stopping)
|
|
270
|
+
throw new Error('The Flex browser channel is unavailable.');
|
|
271
|
+
if (this.flexChannels.size + this.flexChannelAdmissions.size
|
|
272
|
+
>= flexIpcMaximumBrowserChannels)
|
|
273
|
+
throw new Error('The Flex browser channel capacity was reached.');
|
|
274
|
+
inputArg.signal?.throwIfAborted();
|
|
275
|
+
this.admissionAbortController.signal.throwIfAborted();
|
|
276
|
+
let resolveAdmissionSettled;
|
|
277
|
+
const admission = {
|
|
278
|
+
projectId: resource.projectId,
|
|
279
|
+
sessionId: inputArg.sessionId,
|
|
280
|
+
runId: inputArg.runId,
|
|
281
|
+
peerId: inputArg.peerId,
|
|
282
|
+
abortController: new AbortController(),
|
|
283
|
+
settled: new Promise((resolve) => { resolveAdmissionSettled = resolve; }),
|
|
284
|
+
resolveSettled: () => resolveAdmissionSettled(),
|
|
285
|
+
};
|
|
286
|
+
const abortAdmission = (signalArg) => {
|
|
287
|
+
if (!admission.abortController.signal.aborted) {
|
|
288
|
+
admission.abortController.abort(signalArg.reason ?? new DOMException('The operation was aborted.', 'AbortError'));
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const abortFromInput = () => abortAdmission(inputArg.signal);
|
|
292
|
+
const abortFromHost = () => abortAdmission(this.admissionAbortController.signal);
|
|
293
|
+
inputArg.signal?.addEventListener('abort', abortFromInput, { once: true });
|
|
294
|
+
this.admissionAbortController.signal.addEventListener('abort', abortFromHost, { once: true });
|
|
295
|
+
this.flexChannelAdmissions.set(inputArg.channelId, admission);
|
|
296
|
+
if (inputArg.signal?.aborted)
|
|
297
|
+
abortFromInput();
|
|
298
|
+
if (this.admissionAbortController.signal.aborted)
|
|
299
|
+
abortFromHost();
|
|
300
|
+
const binding = {
|
|
301
|
+
projectId: resource.projectId,
|
|
302
|
+
browserResourceId: resource.id,
|
|
303
|
+
attachmentAuthorityId: resource.attachmentAuthorityId,
|
|
304
|
+
attachmentRevision: resource.attachmentRevision,
|
|
305
|
+
actorId: `flex-run:${plugins.crypto.createHash('sha256')
|
|
306
|
+
.update(JSON.stringify([inputArg.scopeId, inputArg.sessionId, inputArg.runId]))
|
|
307
|
+
.digest('hex')}`,
|
|
308
|
+
peerId: inputArg.peerId,
|
|
309
|
+
role: 'agent',
|
|
310
|
+
source: 'flex',
|
|
311
|
+
scopeId: inputArg.scopeId,
|
|
312
|
+
channelId: inputArg.channelId,
|
|
313
|
+
runId: inputArg.runId,
|
|
314
|
+
sessionId: { harnessId: 'flex', nativeId: inputArg.sessionId },
|
|
315
|
+
};
|
|
316
|
+
const inbound = new plugins.stream.PassThrough();
|
|
317
|
+
const outbound = new plugins.stream.Writable({
|
|
318
|
+
write: (chunkArg, _encodingArg, callbackArg) => {
|
|
319
|
+
const bytes = Buffer.from(chunkArg);
|
|
320
|
+
void inputArg.sendFrame(inputArg.channelId, bytes).then(() => callbackArg(), (errorArg) => callbackArg(errorArg instanceof Error ? errorArg : new Error('Frame send failed.')));
|
|
321
|
+
},
|
|
322
|
+
destroy: (errorArg, callbackArg) => {
|
|
323
|
+
const channel = this.flexChannels.get(inputArg.channelId);
|
|
324
|
+
if (channel?.notifyClosed) {
|
|
325
|
+
channel.notifyClosed = false;
|
|
326
|
+
void inputArg.notifyClosed(inputArg.channelId).catch(() => undefined);
|
|
327
|
+
void this.closeFlexChannel(inputArg.channelId, true).catch(() => undefined);
|
|
328
|
+
}
|
|
329
|
+
callbackArg(errorArg);
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
this.flexAuthorizationBindings.set(inputArg.channelId, {
|
|
333
|
+
binding,
|
|
334
|
+
runId: inputArg.runId,
|
|
335
|
+
});
|
|
336
|
+
let capabilityId = '';
|
|
337
|
+
let issuancePromise;
|
|
338
|
+
let channelRegistered = false;
|
|
339
|
+
try {
|
|
340
|
+
admission.abortController.signal.throwIfAborted();
|
|
341
|
+
if (!this.isFlexRunActive(binding, inputArg.runId)) {
|
|
342
|
+
throw new Error('The Flex browser run is no longer active.');
|
|
343
|
+
}
|
|
344
|
+
await this.retryPendingCapabilityRevocations(Date.now() + browserCapabilityAuthorizationTimeoutMs, admission.abortController.signal);
|
|
345
|
+
if (this.lateCapabilityIssuanceTasks.size >= maximumPendingFlexCapabilityIssuances) {
|
|
346
|
+
throw new Error('Browser capability issuance capacity was reached.');
|
|
347
|
+
}
|
|
348
|
+
issuancePromise = runtime.issueCapability({
|
|
349
|
+
...binding,
|
|
350
|
+
expiresInMs: 24 * 60 * 60 * 1000,
|
|
351
|
+
});
|
|
352
|
+
const issued = await waitForSignal(issuancePromise, admission.abortController.signal);
|
|
353
|
+
issuancePromise = undefined;
|
|
354
|
+
capabilityId = issued.capabilityId;
|
|
355
|
+
const peer = runtime.attachTrustedFramedPeer({
|
|
356
|
+
...binding,
|
|
357
|
+
readable: inbound,
|
|
358
|
+
writable: outbound,
|
|
359
|
+
});
|
|
360
|
+
this.flexChannels.set(inputArg.channelId, {
|
|
361
|
+
binding,
|
|
362
|
+
runId: inputArg.runId,
|
|
363
|
+
capabilityId,
|
|
364
|
+
inbound,
|
|
365
|
+
peer,
|
|
366
|
+
notifyClosed: true,
|
|
367
|
+
closing: false,
|
|
368
|
+
peerClosed: false,
|
|
369
|
+
capabilityRevoked: false,
|
|
370
|
+
});
|
|
371
|
+
channelRegistered = true;
|
|
372
|
+
admission.abortController.signal.throwIfAborted();
|
|
373
|
+
if (!this.isFlexRunActive(binding, inputArg.runId)) {
|
|
374
|
+
throw new Error('The Flex browser run is no longer active.');
|
|
375
|
+
}
|
|
376
|
+
return { binding, capabilityToken: issued.capabilityToken };
|
|
377
|
+
}
|
|
378
|
+
catch (errorArg) {
|
|
379
|
+
const cleanupErrors = [];
|
|
380
|
+
if (issuancePromise) {
|
|
381
|
+
this.trackLateCapabilityIssuance(runtime, issuancePromise, 'flex');
|
|
382
|
+
issuancePromise = undefined;
|
|
383
|
+
}
|
|
384
|
+
if (channelRegistered) {
|
|
385
|
+
const channel = this.flexChannels.get(inputArg.channelId);
|
|
386
|
+
if (channel)
|
|
387
|
+
channel.notifyClosed = false;
|
|
388
|
+
await this.closeFlexChannel(inputArg.channelId, false, undefined, Date.now() + this.cleanupTimeoutMs).catch((cleanupErrorArg) => cleanupErrors.push(cleanupErrorArg));
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
this.flexAuthorizationBindings.delete(inputArg.channelId);
|
|
392
|
+
inbound.destroy();
|
|
393
|
+
outbound.destroy();
|
|
394
|
+
if (capabilityId) {
|
|
395
|
+
this.trackCapabilityRevocation(runtime, capabilityId, 'flex');
|
|
396
|
+
await this.awaitCapabilityRevocation(capabilityId, Date.now() + this.cleanupTimeoutMs).catch((cleanupErrorArg) => cleanupErrors.push(cleanupErrorArg));
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (cleanupErrors.length > 0) {
|
|
400
|
+
throw new AggregateError([errorArg, ...cleanupErrors], 'Flex browser channel admission and cleanup failed.');
|
|
401
|
+
}
|
|
402
|
+
throw errorArg;
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
inputArg.signal?.removeEventListener('abort', abortFromInput);
|
|
406
|
+
this.admissionAbortController.signal.removeEventListener('abort', abortFromHost);
|
|
407
|
+
this.flexChannelAdmissions.delete(inputArg.channelId);
|
|
408
|
+
admission.resolveSettled();
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
async receiveFlexFrame(channelIdArg, bytesArg, peerIdArg) {
|
|
412
|
+
const channel = this.flexChannels.get(channelIdArg);
|
|
413
|
+
if (!channel
|
|
414
|
+
|| channel.binding.peerId !== peerIdArg
|
|
415
|
+
|| channel.closing
|
|
416
|
+
|| !this.isFlexRunActive(channel.binding, channel.runId)) {
|
|
417
|
+
if (channel && !channel.closing && !this.isFlexRunActive(channel.binding, channel.runId)) {
|
|
418
|
+
void this.closeFlexChannel(channelIdArg, true).catch(() => undefined);
|
|
419
|
+
}
|
|
420
|
+
throw new Error('The Flex browser channel is unavailable.');
|
|
421
|
+
}
|
|
422
|
+
await new Promise((resolve, reject) => {
|
|
423
|
+
channel.inbound.write(bytesArg, (errorArg) => errorArg ? reject(errorArg) : resolve());
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
async closeFlexChannel(channelIdArg, notifyChildArg = false, peerIdArg, deadlineAtArg = Date.now() + this.cleanupTimeoutMs) {
|
|
427
|
+
const channel = this.flexChannels.get(channelIdArg);
|
|
428
|
+
if (!channel)
|
|
429
|
+
return;
|
|
430
|
+
if (peerIdArg !== undefined && channel.binding.peerId !== peerIdArg) {
|
|
431
|
+
throw new Error('The Flex browser channel is unavailable.');
|
|
432
|
+
}
|
|
433
|
+
if (notifyChildArg)
|
|
434
|
+
channel.notifyClosed = true;
|
|
435
|
+
else
|
|
436
|
+
channel.notifyClosed = false;
|
|
437
|
+
channel.closing = true;
|
|
438
|
+
this.flexAuthorizationBindings.delete(channelIdArg);
|
|
439
|
+
const peerCleanup = (async () => {
|
|
440
|
+
if (channel.peerClosed)
|
|
441
|
+
return;
|
|
442
|
+
channel.peerCloseOperation ??= observeCleanupOperation(() => channel.peer.close(), (outcomeArg) => {
|
|
443
|
+
if (outcomeArg.status === 'fulfilled')
|
|
444
|
+
channel.peerClosed = true;
|
|
445
|
+
});
|
|
446
|
+
const outcome = await waitForObservedCleanup(channel.peerCloseOperation, deadlineAtArg, 'Flex browser peer cleanup timed out.');
|
|
447
|
+
if (outcome.status === 'rejected') {
|
|
448
|
+
channel.peerCloseOperation = undefined;
|
|
449
|
+
throw outcome.reason;
|
|
450
|
+
}
|
|
451
|
+
})();
|
|
452
|
+
const capabilityCleanup = (async () => {
|
|
453
|
+
if (channel.capabilityRevoked)
|
|
454
|
+
return;
|
|
455
|
+
const runtime = this.runtime;
|
|
456
|
+
if (!runtime)
|
|
457
|
+
throw new Error('BrowserRuntime is unavailable during channel cleanup.');
|
|
458
|
+
this.trackCapabilityRevocation(runtime, channel.capabilityId, 'flex', () => { channel.capabilityRevoked = true; });
|
|
459
|
+
await this.awaitCapabilityRevocation(channel.capabilityId, deadlineAtArg);
|
|
460
|
+
channel.capabilityRevoked = true;
|
|
461
|
+
})();
|
|
462
|
+
const results = await Promise.allSettled([peerCleanup, capabilityCleanup]);
|
|
463
|
+
if (channel.peerClosed && channel.capabilityRevoked) {
|
|
464
|
+
channel.inbound.destroy();
|
|
465
|
+
this.flexChannels.delete(channelIdArg);
|
|
466
|
+
}
|
|
467
|
+
const errors = results
|
|
468
|
+
.filter((result) => result.status === 'rejected')
|
|
469
|
+
.map((result) => result.reason);
|
|
470
|
+
if (errors.length > 0) {
|
|
471
|
+
throw new AggregateError(errors, 'Flex browser channel cleanup is incomplete.');
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
async closeAllFlexChannels(peerIdArg, deadlineAtArg = Date.now() + this.cleanupTimeoutMs) {
|
|
475
|
+
const admissions = [...this.flexChannelAdmissions.entries()].filter(([, admission]) => (peerIdArg === undefined || admission.peerId === peerIdArg));
|
|
476
|
+
for (const [channelId, admission] of admissions) {
|
|
477
|
+
this.flexAuthorizationBindings.delete(channelId);
|
|
478
|
+
if (!admission.abortController.signal.aborted) {
|
|
479
|
+
admission.abortController.abort(new Error('Flex browser channel admission was cancelled.'));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
const admissionResults = await Promise.allSettled(admissions.map(([, admission]) => (waitForCleanupDeadline(admission.settled, deadlineAtArg, 'Flex browser channel admission cleanup timed out.'))));
|
|
483
|
+
const channels = [...this.flexChannels.values()].filter((channel) => (peerIdArg === undefined || channel.binding.peerId === peerIdArg));
|
|
484
|
+
const results = await Promise.allSettled(channels.map((channel) => this.closeFlexChannel(channel.binding.channelId, true, undefined, deadlineAtArg)));
|
|
485
|
+
const errors = [...admissionResults, ...results]
|
|
486
|
+
.filter((result) => result.status === 'rejected')
|
|
487
|
+
.map((result) => result.reason);
|
|
488
|
+
if (peerIdArg === undefined) {
|
|
489
|
+
await this.drainLateCapabilityIssuanceTasks(deadlineAtArg, 'flex')
|
|
490
|
+
.catch((errorArg) => errors.push(errorArg));
|
|
491
|
+
await this.retryPendingCapabilityRevocations(deadlineAtArg, undefined, 'flex')
|
|
492
|
+
.catch((errorArg) => errors.push(errorArg));
|
|
493
|
+
}
|
|
494
|
+
if (errors.length > 0)
|
|
495
|
+
throw new AggregateError(errors, 'Flex browser channel cleanup is incomplete.');
|
|
496
|
+
}
|
|
497
|
+
async closeFlexChannelsForRun(projectIdArg, sessionIdArg, runIdArg) {
|
|
498
|
+
const deadlineAt = Date.now() + this.cleanupTimeoutMs;
|
|
499
|
+
const admissions = [...this.flexChannelAdmissions.entries()].filter(([, admission]) => (admission.projectId === projectIdArg
|
|
500
|
+
&& admission.sessionId === sessionIdArg
|
|
501
|
+
&& admission.runId === runIdArg));
|
|
502
|
+
for (const [channelId, admission] of admissions) {
|
|
503
|
+
this.flexAuthorizationBindings.delete(channelId);
|
|
504
|
+
if (!admission.abortController.signal.aborted) {
|
|
505
|
+
admission.abortController.abort(new Error('Flex browser run ended.'));
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
const admissionResults = await Promise.allSettled(admissions.map(([, admission]) => (waitForCleanupDeadline(admission.settled, deadlineAt, 'Flex browser channel admission cleanup timed out.'))));
|
|
509
|
+
const channels = [...this.flexChannels.values()].filter((channel) => (channel.binding.projectId === projectIdArg
|
|
510
|
+
&& channel.binding.sessionId.nativeId === sessionIdArg
|
|
511
|
+
&& channel.runId === runIdArg));
|
|
512
|
+
const channelResults = await Promise.allSettled(channels.map((channel) => (this.closeFlexChannel(channel.binding.channelId, true, undefined, deadlineAt))));
|
|
513
|
+
const errors = [...admissionResults, ...channelResults]
|
|
514
|
+
.filter((result) => result.status === 'rejected')
|
|
515
|
+
.map((result) => result.reason);
|
|
516
|
+
if (errors.length > 0) {
|
|
517
|
+
throw new AggregateError(errors, 'Flex browser run channel cleanup is incomplete.');
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
async disconnectPeer(peerIdArg) {
|
|
521
|
+
await this.runtime?.disconnectPeer(peerIdArg);
|
|
522
|
+
}
|
|
523
|
+
async openHumanView(inputArg) {
|
|
524
|
+
const runtime = this.runtime;
|
|
525
|
+
if (!runtime || !this.started || inputArg.resource.kind !== 'browser' || this.stopping) {
|
|
526
|
+
throw new Error('BrowserRuntime is unavailable.');
|
|
527
|
+
}
|
|
528
|
+
if (this.humanViews.size + this.humanViewAdmissions.size >= maximumActiveHumanBrowserViews) {
|
|
529
|
+
throw new Error('Human browser view capacity was reached.');
|
|
530
|
+
}
|
|
531
|
+
inputArg.signal.throwIfAborted();
|
|
532
|
+
this.admissionAbortController.signal.throwIfAborted();
|
|
533
|
+
let resolveAdmissionSettled;
|
|
534
|
+
const admission = {
|
|
535
|
+
abortController: new AbortController(),
|
|
536
|
+
settled: new Promise((resolve) => { resolveAdmissionSettled = resolve; }),
|
|
537
|
+
resolveSettled: () => resolveAdmissionSettled(),
|
|
538
|
+
};
|
|
539
|
+
const abortAdmission = (signalArg) => {
|
|
540
|
+
if (!admission.abortController.signal.aborted) {
|
|
541
|
+
admission.abortController.abort(signalArg.reason ?? new DOMException('The operation was aborted.', 'AbortError'));
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
const abortFromInput = () => abortAdmission(inputArg.signal);
|
|
545
|
+
const abortFromHost = () => abortAdmission(this.admissionAbortController.signal);
|
|
546
|
+
inputArg.signal.addEventListener('abort', abortFromInput, { once: true });
|
|
547
|
+
this.admissionAbortController.signal.addEventListener('abort', abortFromHost, { once: true });
|
|
548
|
+
this.humanViewAdmissions.add(admission);
|
|
549
|
+
if (inputArg.signal.aborted)
|
|
550
|
+
abortFromInput();
|
|
551
|
+
if (this.admissionAbortController.signal.aborted)
|
|
552
|
+
abortFromHost();
|
|
553
|
+
const binding = {
|
|
554
|
+
projectId: inputArg.resource.projectId,
|
|
555
|
+
browserResourceId: inputArg.resource.id,
|
|
556
|
+
attachmentAuthorityId: inputArg.resource.attachmentAuthorityId,
|
|
557
|
+
attachmentRevision: inputArg.resource.attachmentRevision,
|
|
558
|
+
actorId: inputArg.actorId,
|
|
559
|
+
peerId: inputArg.peerId,
|
|
560
|
+
role: 'human',
|
|
561
|
+
source: 'human',
|
|
562
|
+
};
|
|
563
|
+
let humanView;
|
|
564
|
+
let subscription;
|
|
565
|
+
let activationPromise;
|
|
566
|
+
let subscriptionCloseOperation;
|
|
567
|
+
let subscriptionClosed = false;
|
|
568
|
+
let capabilityRevoked = false;
|
|
569
|
+
let closing = false;
|
|
570
|
+
let runtimeDisconnectActive = false;
|
|
571
|
+
let runtimeDisconnectComplete = false;
|
|
572
|
+
let capabilityId = '';
|
|
573
|
+
let issuancePromise;
|
|
574
|
+
const closeSubscription = async (deadlineAtArg) => {
|
|
575
|
+
if (subscriptionClosed || !subscription)
|
|
576
|
+
return;
|
|
577
|
+
subscriptionCloseOperation ??= observeCleanupOperation(() => subscription.close(), (outcomeArg) => {
|
|
578
|
+
if (outcomeArg.status === 'fulfilled')
|
|
579
|
+
subscriptionClosed = true;
|
|
580
|
+
});
|
|
581
|
+
const outcome = await waitForObservedCleanup(subscriptionCloseOperation, deadlineAtArg, 'Browser view subscription cleanup timed out.');
|
|
582
|
+
if (outcome.status === 'rejected') {
|
|
583
|
+
subscriptionCloseOperation = undefined;
|
|
584
|
+
throw outcome.reason;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
try {
|
|
588
|
+
await this.retryPendingCapabilityRevocations(Date.now() + browserCapabilityAuthorizationTimeoutMs, admission.abortController.signal);
|
|
589
|
+
if (this.lateCapabilityIssuanceTasks.size >= maximumPendingFlexCapabilityIssuances) {
|
|
590
|
+
throw new Error('Browser capability issuance capacity was reached.');
|
|
591
|
+
}
|
|
592
|
+
issuancePromise = runtime.issueCapability({
|
|
593
|
+
...binding,
|
|
594
|
+
disconnect: async (signalArg) => {
|
|
595
|
+
closing = true;
|
|
596
|
+
runtimeDisconnectActive = true;
|
|
597
|
+
try {
|
|
598
|
+
await inputArg.onDisconnect(signalArg);
|
|
599
|
+
}
|
|
600
|
+
finally {
|
|
601
|
+
runtimeDisconnectActive = false;
|
|
602
|
+
runtimeDisconnectComplete = true;
|
|
603
|
+
subscriptionClosed = true;
|
|
604
|
+
capabilityRevoked = true;
|
|
605
|
+
if (humanView)
|
|
606
|
+
this.humanViews.delete(humanView);
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
});
|
|
610
|
+
const issued = await waitForSignal(issuancePromise, admission.abortController.signal);
|
|
611
|
+
issuancePromise = undefined;
|
|
612
|
+
capabilityId = issued.capabilityId;
|
|
613
|
+
const lease = await runtime.acquireLease({
|
|
614
|
+
...binding,
|
|
615
|
+
capabilityToken: issued.capabilityToken,
|
|
616
|
+
signal: admission.abortController.signal,
|
|
617
|
+
});
|
|
618
|
+
admission.abortController.signal.throwIfAborted();
|
|
619
|
+
humanView = {
|
|
620
|
+
lease,
|
|
621
|
+
activate: (listenerArg) => {
|
|
622
|
+
if (closing)
|
|
623
|
+
return Promise.reject(new Error('Browser view cleanup has begun.'));
|
|
624
|
+
if (subscription && !subscriptionClosed)
|
|
625
|
+
return Promise.resolve();
|
|
626
|
+
if (subscriptionClosed) {
|
|
627
|
+
subscription = undefined;
|
|
628
|
+
subscriptionCloseOperation = undefined;
|
|
629
|
+
subscriptionClosed = false;
|
|
630
|
+
}
|
|
631
|
+
activationPromise ??= (async () => {
|
|
632
|
+
let initialStateReceived = false;
|
|
633
|
+
const candidate = await lease.subscribeEvents((eventArg) => {
|
|
634
|
+
if (!initialStateReceived) {
|
|
635
|
+
if (eventArg.type !== 'state') {
|
|
636
|
+
throw new Error('BrowserRuntime did not publish an initial state event.');
|
|
637
|
+
}
|
|
638
|
+
initialStateReceived = true;
|
|
639
|
+
}
|
|
640
|
+
listenerArg(eventArg);
|
|
641
|
+
});
|
|
642
|
+
subscription = candidate;
|
|
643
|
+
if (!initialStateReceived) {
|
|
644
|
+
await closeSubscription(Date.now() + this.cleanupTimeoutMs);
|
|
645
|
+
throw new Error('BrowserRuntime did not publish an initial state event.');
|
|
646
|
+
}
|
|
647
|
+
if (closing) {
|
|
648
|
+
await closeSubscription(Date.now() + this.cleanupTimeoutMs);
|
|
649
|
+
throw new Error('Browser view cleanup began during activation.');
|
|
650
|
+
}
|
|
651
|
+
})().finally(() => {
|
|
652
|
+
if (!subscription || subscriptionClosed)
|
|
653
|
+
activationPromise = undefined;
|
|
654
|
+
});
|
|
655
|
+
return activationPromise;
|
|
656
|
+
},
|
|
657
|
+
close: async () => {
|
|
658
|
+
closing = true;
|
|
659
|
+
const deadlineAt = Date.now() + this.cleanupTimeoutMs;
|
|
660
|
+
if (runtimeDisconnectActive) {
|
|
661
|
+
await closeSubscription(deadlineAt);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const errors = [];
|
|
665
|
+
if (activationPromise) {
|
|
666
|
+
await waitForCleanupDeadline(activationPromise.catch(() => undefined), deadlineAt, 'Browser view activation cleanup timed out.').catch((errorArg) => errors.push(errorArg));
|
|
667
|
+
}
|
|
668
|
+
if (!subscriptionClosed) {
|
|
669
|
+
if (subscription) {
|
|
670
|
+
await closeSubscription(deadlineAt).catch((errorArg) => errors.push(errorArg));
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
subscriptionClosed = true;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (!capabilityRevoked) {
|
|
677
|
+
this.trackCapabilityRevocation(runtime, capabilityId, 'human', () => { capabilityRevoked = true; });
|
|
678
|
+
await this.awaitCapabilityRevocation(capabilityId, deadlineAt).then(() => { capabilityRevoked = true; }, (errorArg) => errors.push(errorArg));
|
|
679
|
+
}
|
|
680
|
+
if (runtimeDisconnectComplete || capabilityRevoked)
|
|
681
|
+
subscriptionClosed = true;
|
|
682
|
+
if (errors.length > 0)
|
|
683
|
+
throw new AggregateError(errors, 'Browser view cleanup is incomplete.');
|
|
684
|
+
this.humanViews.delete(humanView);
|
|
685
|
+
},
|
|
686
|
+
};
|
|
687
|
+
this.humanViews.add(humanView);
|
|
688
|
+
return humanView;
|
|
689
|
+
}
|
|
690
|
+
catch (errorArg) {
|
|
691
|
+
const cleanupErrors = [];
|
|
692
|
+
if (issuancePromise) {
|
|
693
|
+
this.trackLateCapabilityIssuance(runtime, issuancePromise, 'human');
|
|
694
|
+
}
|
|
695
|
+
else if (capabilityId && !capabilityRevoked) {
|
|
696
|
+
this.trackCapabilityRevocation(runtime, capabilityId, 'human');
|
|
697
|
+
await this.awaitCapabilityRevocation(capabilityId, Date.now() + this.cleanupTimeoutMs).catch((cleanupErrorArg) => cleanupErrors.push(cleanupErrorArg));
|
|
698
|
+
}
|
|
699
|
+
if (humanView)
|
|
700
|
+
this.humanViews.delete(humanView);
|
|
701
|
+
if (cleanupErrors.length > 0) {
|
|
702
|
+
throw new AggregateError([errorArg, ...cleanupErrors], 'Browser view admission and cleanup failed.');
|
|
703
|
+
}
|
|
704
|
+
throw errorArg;
|
|
705
|
+
}
|
|
706
|
+
finally {
|
|
707
|
+
inputArg.signal.removeEventListener('abort', abortFromInput);
|
|
708
|
+
this.admissionAbortController.signal.removeEventListener('abort', abortFromHost);
|
|
709
|
+
this.humanViewAdmissions.delete(admission);
|
|
710
|
+
admission.resolveSettled();
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
async startResource(resourceArg, signalArg) {
|
|
714
|
+
signalArg.throwIfAborted();
|
|
715
|
+
await this.reconcileAttachment(resourceArg, signalArg);
|
|
716
|
+
}
|
|
717
|
+
async stopResource(resourceArg, signalArg) {
|
|
718
|
+
signalArg.throwIfAborted();
|
|
719
|
+
if (!this.runtime || this.stopping)
|
|
720
|
+
return;
|
|
721
|
+
await this.runtime.terminateResource(resourceArg.projectId, resourceArg.id);
|
|
722
|
+
}
|
|
723
|
+
isRunning(resourceArg) {
|
|
724
|
+
if (!this.runtime || this.stopping)
|
|
725
|
+
return false;
|
|
726
|
+
const registration = this.runtime.listResources().find((candidate) => (candidate.projectId === resourceArg.projectId
|
|
727
|
+
&& candidate.browserResourceId === resourceArg.id));
|
|
728
|
+
return registration?.incarnationStatus === 'running';
|
|
729
|
+
}
|
|
730
|
+
isAvailable() {
|
|
731
|
+
return this.started && !this.stopping;
|
|
732
|
+
}
|
|
733
|
+
async reconcileAttachment(resourceArg, signalArg) {
|
|
734
|
+
signalArg.throwIfAborted();
|
|
735
|
+
if (resourceArg.kind !== 'browser')
|
|
736
|
+
return;
|
|
737
|
+
if (this.unavailable)
|
|
738
|
+
return;
|
|
739
|
+
if (!this.runtime || this.stopping)
|
|
740
|
+
throw new Error('BrowserRuntime is not started.');
|
|
741
|
+
const attachmentBinding = {
|
|
742
|
+
attachmentAuthorityId: resourceArg.attachmentAuthorityId,
|
|
743
|
+
attachmentRevision: resourceArg.attachmentRevision,
|
|
744
|
+
sessionId: resourceArg.sessionId,
|
|
745
|
+
};
|
|
746
|
+
const existing = this.runtime.listResources().find((candidate) => (candidate.projectId === resourceArg.projectId
|
|
747
|
+
&& candidate.browserResourceId === resourceArg.id));
|
|
748
|
+
if (!existing) {
|
|
749
|
+
this.runtime.registerResource({
|
|
750
|
+
projectId: resourceArg.projectId,
|
|
751
|
+
browserResourceId: resourceArg.id,
|
|
752
|
+
attachmentBinding,
|
|
753
|
+
});
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
await this.runtime.applyAttachmentBinding({
|
|
757
|
+
projectId: resourceArg.projectId,
|
|
758
|
+
browserResourceId: resourceArg.id,
|
|
759
|
+
attachmentBinding,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
async retireResource(resourceArg, signalArg) {
|
|
763
|
+
signalArg.throwIfAborted();
|
|
764
|
+
if (!this.runtime || this.stopping || resourceArg.kind !== 'browser')
|
|
765
|
+
return;
|
|
766
|
+
const registered = this.runtime.listResources().some((candidate) => (candidate.projectId === resourceArg.projectId
|
|
767
|
+
&& candidate.browserResourceId === resourceArg.id));
|
|
768
|
+
if (!registered) {
|
|
769
|
+
this.runtime.registerResource({
|
|
770
|
+
projectId: resourceArg.projectId,
|
|
771
|
+
browserResourceId: resourceArg.id,
|
|
772
|
+
attachmentBinding: {
|
|
773
|
+
attachmentAuthorityId: resourceArg.attachmentAuthorityId,
|
|
774
|
+
attachmentRevision: resourceArg.attachmentRevision,
|
|
775
|
+
sessionId: resourceArg.sessionId,
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
await this.runtime.retireResource(resourceArg.projectId, resourceArg.id);
|
|
780
|
+
}
|
|
781
|
+
get availability() {
|
|
782
|
+
return this.started && !this.stopping ? 'available' : 'unavailable';
|
|
783
|
+
}
|
|
784
|
+
isFlexRunActive(bindingArg, runIdArg) {
|
|
785
|
+
if (bindingArg.runId !== runIdArg)
|
|
786
|
+
return false;
|
|
787
|
+
return this.options.isFlexRunActive?.(bindingArg, runIdArg) ?? true;
|
|
788
|
+
}
|
|
789
|
+
trackCapabilityRevocation(runtimeArg, capabilityIdArg, ownerArg, onFulfilledArg) {
|
|
790
|
+
const existing = this.capabilityRevocationOperations.get(capabilityIdArg);
|
|
791
|
+
if (existing && existing.owner !== ownerArg) {
|
|
792
|
+
throw new Error('Browser capability cleanup ownership changed unexpectedly.');
|
|
793
|
+
}
|
|
794
|
+
if (existing && existing.outcome?.status !== 'rejected') {
|
|
795
|
+
if (onFulfilledArg)
|
|
796
|
+
existing.onFulfilled.add(onFulfilledArg);
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
const onFulfilled = new Set(existing?.onFulfilled ?? []);
|
|
800
|
+
if (onFulfilledArg)
|
|
801
|
+
onFulfilled.add(onFulfilledArg);
|
|
802
|
+
if (existing)
|
|
803
|
+
this.capabilityRevocationOperations.delete(capabilityIdArg);
|
|
804
|
+
if (this.capabilityRevocationOperations.size >= maximumTrackedCapabilityRevocations) {
|
|
805
|
+
throw new Error('Browser capability cleanup capacity was reached.');
|
|
806
|
+
}
|
|
807
|
+
const operation = observeCleanupOperation(() => runtimeArg.revokeCapability(capabilityIdArg), (outcomeArg) => {
|
|
808
|
+
if (outcomeArg.status === 'fulfilled') {
|
|
809
|
+
for (const callback of operation.onFulfilled)
|
|
810
|
+
callback();
|
|
811
|
+
operation.onFulfilled.clear();
|
|
812
|
+
if (this.capabilityRevocationOperations.get(capabilityIdArg) === operation) {
|
|
813
|
+
this.capabilityRevocationOperations.delete(capabilityIdArg);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
operation.runtime = runtimeArg;
|
|
818
|
+
operation.owner = ownerArg;
|
|
819
|
+
operation.onFulfilled = onFulfilled;
|
|
820
|
+
this.capabilityRevocationOperations.set(capabilityIdArg, operation);
|
|
821
|
+
}
|
|
822
|
+
async awaitCapabilityRevocation(capabilityIdArg, deadlineAtArg, signalArg) {
|
|
823
|
+
const operation = this.capabilityRevocationOperations.get(capabilityIdArg);
|
|
824
|
+
if (!operation)
|
|
825
|
+
return;
|
|
826
|
+
const outcome = await waitForObservedCleanup(operation, deadlineAtArg, 'Browser capability cleanup timed out.', signalArg);
|
|
827
|
+
if (outcome.status === 'rejected')
|
|
828
|
+
throw outcome.reason;
|
|
829
|
+
}
|
|
830
|
+
trackLateCapabilityIssuance(runtimeArg, issuancePromiseArg, ownerArg) {
|
|
831
|
+
const task = (async () => {
|
|
832
|
+
const issued = await issuancePromiseArg;
|
|
833
|
+
this.trackCapabilityRevocation(runtimeArg, issued.capabilityId, ownerArg);
|
|
834
|
+
await this.awaitCapabilityRevocation(issued.capabilityId, Date.now() + this.cleanupTimeoutMs);
|
|
835
|
+
})();
|
|
836
|
+
this.lateCapabilityIssuanceTasks.set(task, ownerArg);
|
|
837
|
+
void task.catch(() => undefined).finally(() => this.lateCapabilityIssuanceTasks.delete(task));
|
|
838
|
+
}
|
|
839
|
+
async closeAllHumanViews(deadlineAtArg) {
|
|
840
|
+
const results = await Promise.allSettled([...this.humanViews].map((view) => waitForCleanupDeadline(view.close(), deadlineAtArg, 'Human browser view cleanup timed out.')));
|
|
841
|
+
const errors = results
|
|
842
|
+
.filter((result) => result.status === 'rejected')
|
|
843
|
+
.map((result) => result.reason);
|
|
844
|
+
if (errors.length > 0) {
|
|
845
|
+
throw new AggregateError(errors, 'Human browser view cleanup is incomplete.');
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
async retryPendingCapabilityRevocations(deadlineAtArg, signalArg, ownerArg) {
|
|
849
|
+
const entries = [...this.capabilityRevocationOperations.entries()].filter(([, operation]) => (ownerArg === undefined || operation.owner === ownerArg));
|
|
850
|
+
for (const [capabilityId, operation] of entries) {
|
|
851
|
+
if (operation.outcome?.status === 'rejected') {
|
|
852
|
+
this.trackCapabilityRevocation(operation.runtime, capabilityId, operation.owner);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const results = await Promise.allSettled([...this.capabilityRevocationOperations.entries()]
|
|
856
|
+
.filter(([, operation]) => ownerArg === undefined || operation.owner === ownerArg)
|
|
857
|
+
.map(([capabilityId]) => (this.awaitCapabilityRevocation(capabilityId, deadlineAtArg, signalArg))));
|
|
858
|
+
const errors = results
|
|
859
|
+
.filter((result) => result.status === 'rejected')
|
|
860
|
+
.map((result) => result.reason);
|
|
861
|
+
if (errors.length > 0) {
|
|
862
|
+
throw new AggregateError(errors, 'Pending browser capability cleanup is incomplete.');
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
async cancelAndDrainFlexChannelAdmissions(deadlineAtArg) {
|
|
866
|
+
const admissions = [...this.flexChannelAdmissions.entries()];
|
|
867
|
+
for (const [channelId, admission] of admissions) {
|
|
868
|
+
this.flexAuthorizationBindings.delete(channelId);
|
|
869
|
+
if (!admission.abortController.signal.aborted) {
|
|
870
|
+
admission.abortController.abort(new Error('Browser resource host is stopping.'));
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
await Promise.all(admissions.map(([, admission]) => waitForCleanupDeadline(admission.settled, deadlineAtArg, 'Flex browser channel admission cleanup timed out.')));
|
|
874
|
+
}
|
|
875
|
+
async drainHumanViewAdmissions(deadlineAtArg) {
|
|
876
|
+
const admissions = [...this.humanViewAdmissions];
|
|
877
|
+
for (const admission of admissions) {
|
|
878
|
+
if (!admission.abortController.signal.aborted) {
|
|
879
|
+
admission.abortController.abort(new Error('Browser resource host is stopping.'));
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
await Promise.all(admissions.map((admission) => waitForCleanupDeadline(admission.settled, deadlineAtArg, 'Human browser view admission cleanup timed out.')));
|
|
883
|
+
}
|
|
884
|
+
async drainLateCapabilityIssuanceTasks(deadlineAtArg, ownerArg) {
|
|
885
|
+
const tasks = [...this.lateCapabilityIssuanceTasks.entries()]
|
|
886
|
+
.filter(([, owner]) => ownerArg === undefined || owner === ownerArg)
|
|
887
|
+
.map(([task]) => task);
|
|
888
|
+
const results = await Promise.allSettled(tasks.map((task) => waitForCleanupDeadline(task, deadlineAtArg, 'Late browser capability issuance cleanup timed out.')));
|
|
889
|
+
const errors = results
|
|
890
|
+
.filter((result) => result.status === 'rejected')
|
|
891
|
+
.map((result) => result.reason);
|
|
892
|
+
if (errors.length > 0) {
|
|
893
|
+
throw new AggregateError(errors, 'Late browser capability issuance cleanup is incomplete.');
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
async stopRuntime(runtimeArg, deadlineAtArg) {
|
|
897
|
+
let operation = this.runtimeStopOperations.get(runtimeArg);
|
|
898
|
+
if (operation?.outcome?.status === 'rejected') {
|
|
899
|
+
this.runtimeStopOperations.delete(runtimeArg);
|
|
900
|
+
operation = undefined;
|
|
901
|
+
}
|
|
902
|
+
if (!operation) {
|
|
903
|
+
operation = observeCleanupOperation(() => runtimeArg.stop());
|
|
904
|
+
operation.runtime = runtimeArg;
|
|
905
|
+
this.runtimeStopOperations.set(runtimeArg, operation);
|
|
906
|
+
}
|
|
907
|
+
const outcome = await waitForObservedCleanup(operation, deadlineAtArg, 'BrowserRuntime shutdown timed out.');
|
|
908
|
+
if (outcome.status === 'rejected')
|
|
909
|
+
throw outcome.reason;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5icm93c2VycmVzb3VyY2Vob3N0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvY2xhc3Nlcy5icm93c2VycmVzb3VyY2Vob3N0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBR3hDLE9BQU8sRUFDTCw2QkFBNkIsR0FFOUIsTUFBTSx5QkFBeUIsQ0FBQztBQUVqQyxNQUFNLHFDQUFxQyxHQUFHLEdBQUcsQ0FBQztBQUNsRCxNQUFNLDhCQUE4QixHQUFHLEVBQUUsQ0FBQztBQUMxQyxNQUFNLG1DQUFtQyxHQUFHLEdBQUcsQ0FBQztBQUNoRCxNQUFNLDhCQUE4QixHQUFHLEdBQUcsQ0FBQztBQUMzQyxNQUFNLHVDQUF1QyxHQUFHLE1BQU0sQ0FBQztBQUN2RCxNQUFNLCtCQUErQixHQUFHLE1BQU0sQ0FBQztBQUUvQyxNQUFNLGFBQWEsR0FBRyxLQUFLLEVBQ3pCLFVBQTJCLEVBQzNCLFNBQXNCLEVBQ0wsRUFBRSxDQUFDLElBQUksT0FBTyxDQUFTLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO0lBQzVELE1BQU0sS0FBSyxHQUFHLEdBQUcsRUFBRTtRQUNqQixTQUFTLENBQUMsbUJBQW1CLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzlDLE1BQU0sQ0FBQyxTQUFTLENBQUMsTUFBTSxJQUFJLElBQUksWUFBWSxDQUFDLDRCQUE0QixFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDM0YsQ0FBQyxDQUFDO0lBQ0YsU0FBUyxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUMzRCxJQUFJLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUN0QixLQUFLLEVBQUUsQ0FBQztRQUNSLE9BQU87SUFDVCxDQUFDO0lBQ0QsS0FBSyxVQUFVLENBQUMsSUFB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
|