@midscene/core 1.12.10-beta-20260920031616.0 → 1.13.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/dist/es/agent/agent.mjs +103 -6
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/index.mjs +4 -3
- package/dist/es/agent/tasks.mjs +2 -2
- package/dist/es/agent/tasks.mjs.map +1 -1
- package/dist/es/agent/test-runner-nodes.mjs +291 -40
- package/dist/es/agent/test-runner-nodes.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/device/index.mjs +15 -2
- package/dist/es/device/index.mjs.map +1 -1
- package/dist/es/dump/html-utils.mjs +37 -4
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/dump/screenshot-store.mjs +8 -1
- package/dist/es/dump/screenshot-store.mjs.map +1 -1
- package/dist/es/report-cli.mjs +9 -4
- package/dist/es/report-cli.mjs.map +1 -1
- package/dist/es/report-generator.mjs +117 -4
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-html-template.mjs +1 -1
- package/dist/es/report.mjs +190 -41
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/test-run-report.mjs.map +1 -1
- package/dist/es/test-runner/engine/case-runner.mjs +52 -0
- package/dist/es/test-runner/engine/case-runner.mjs.map +1 -0
- package/dist/es/test-runner/engine/document-runtime.mjs +273 -0
- package/dist/es/test-runner/engine/document-runtime.mjs.map +1 -0
- package/dist/es/test-runner/engine/execute-step.mjs +177 -0
- package/dist/es/test-runner/engine/execute-step.mjs.map +1 -0
- package/dist/es/test-runner/engine/execution-failure.mjs +39 -0
- package/dist/es/test-runner/engine/execution-failure.mjs.map +1 -0
- package/dist/es/test-runner/engine/index.mjs +12 -0
- package/dist/es/test-runner/engine/project-runtime.mjs +142 -0
- package/dist/es/test-runner/engine/project-runtime.mjs.map +1 -0
- package/dist/es/test-runner/engine/registry.mjs +61 -0
- package/dist/es/test-runner/engine/registry.mjs.map +1 -0
- package/dist/es/test-runner/engine/resource-operations.mjs +211 -0
- package/dist/es/test-runner/engine/resource-operations.mjs.map +1 -0
- package/dist/es/test-runner/engine/run-collected-case.mjs +193 -0
- package/dist/es/test-runner/engine/run-collected-case.mjs.map +1 -0
- package/dist/es/test-runner/engine/run-workflow-document.mjs +155 -0
- package/dist/es/test-runner/engine/run-workflow-document.mjs.map +1 -0
- package/dist/es/test-runner/engine/scheduler.mjs +27 -0
- package/dist/es/test-runner/engine/scheduler.mjs.map +1 -0
- package/dist/es/test-runner/engine/scope-teardown.mjs +16 -0
- package/dist/es/test-runner/engine/scope-teardown.mjs.map +1 -0
- package/dist/es/test-runner/engine/types.mjs +0 -0
- package/dist/es/test-runner/errors.mjs +201 -0
- package/dist/es/test-runner/errors.mjs.map +1 -0
- package/dist/es/test-runner/execution-record.mjs +83 -0
- package/dist/es/test-runner/execution-record.mjs.map +1 -0
- package/dist/es/test-runner/index.mjs +12 -0
- package/dist/es/test-runner/node/define-node.mjs +44 -0
- package/dist/es/test-runner/node/define-node.mjs.map +1 -0
- package/dist/es/test-runner/node/index.mjs +2 -0
- package/dist/es/test-runner/node/types.mjs +0 -0
- package/dist/es/test-runner/parser/document-format.mjs +21 -0
- package/dist/es/test-runner/parser/document-format.mjs.map +1 -0
- package/dist/es/test-runner/parser/normalize.mjs +87 -0
- package/dist/es/test-runner/parser/normalize.mjs.map +1 -0
- package/dist/es/test-runner/parser/types.mjs +0 -0
- package/dist/es/test-runner/project.mjs +0 -0
- package/dist/es/test-runner/reporting/agent-report.mjs +23 -0
- package/dist/es/test-runner/reporting/agent-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/execution-record.mjs +73 -0
- package/dist/es/test-runner/reporting/execution-record.mjs.map +1 -0
- package/dist/es/test-runner/reporting/merge-report.mjs +231 -0
- package/dist/es/test-runner/reporting/merge-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/sanitize.mjs +162 -0
- package/dist/es/test-runner/reporting/sanitize.mjs.map +1 -0
- package/dist/es/test-runner/reporting/test-run-report.mjs +327 -0
- package/dist/es/test-runner/reporting/test-run-report.mjs.map +1 -0
- package/dist/es/test-runner/reporting/types.mjs +0 -0
- package/dist/es/utils.mjs +1 -1
- package/dist/es/yaml/execution-context.node.mjs +6 -0
- package/dist/es/yaml/execution-context.node.mjs.map +1 -0
- package/dist/es/yaml/execution-context.stub.mjs +8 -0
- package/dist/es/yaml/execution-context.stub.mjs.map +1 -0
- package/dist/es/yaml/execution-session.mjs +90 -0
- package/dist/es/yaml/execution-session.mjs.map +1 -0
- package/dist/es/yaml/index.mjs +2 -1
- package/dist/es/yaml/legacy-yaml-execution-record.mjs +47 -0
- package/dist/es/yaml/legacy-yaml-execution-record.mjs.map +1 -0
- package/dist/es/yaml/legacy-yaml-report.mjs +52 -0
- package/dist/es/yaml/legacy-yaml-report.mjs.map +1 -0
- package/dist/es/yaml/legacy-yaml-runtime.mjs +119 -0
- package/dist/es/yaml/legacy-yaml-runtime.mjs.map +1 -0
- package/dist/es/yaml/player-state.mjs +15 -0
- package/dist/es/yaml/player-state.mjs.map +1 -0
- package/dist/es/yaml/player.mjs +214 -348
- package/dist/es/yaml/player.mjs.map +1 -1
- package/dist/es/yaml/report-policy.mjs +7 -0
- package/dist/es/yaml/report-policy.mjs.map +1 -0
- package/dist/es/yaml/test-runner-compat.mjs +301 -0
- package/dist/es/yaml/test-runner-compat.mjs.map +1 -0
- package/dist/es/yaml/test-runner-nodes.mjs +147 -0
- package/dist/es/yaml/test-runner-nodes.mjs.map +1 -0
- package/dist/es/yaml/utils.mjs +12 -1
- package/dist/es/yaml/utils.mjs.map +1 -1
- package/dist/es/yaml-runtime.mjs +7 -0
- package/dist/es/yaml.mjs.map +1 -1
- package/dist/lib/agent/agent.js +103 -6
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/index.js +37 -3
- package/dist/lib/agent/tasks.js +2 -2
- package/dist/lib/agent/tasks.js.map +1 -1
- package/dist/lib/agent/test-runner-nodes.js +329 -45
- package/dist/lib/agent/test-runner-nodes.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/device/index.js +15 -2
- package/dist/lib/device/index.js.map +1 -1
- package/dist/lib/dump/html-utils.js +43 -4
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/dump/screenshot-store.js +8 -1
- package/dist/lib/dump/screenshot-store.js.map +1 -1
- package/dist/lib/report-cli.js +8 -3
- package/dist/lib/report-cli.js.map +1 -1
- package/dist/lib/report-generator.js +114 -1
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-html-template.js +1 -1
- package/dist/lib/report.js +187 -38
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/test-run-report.js.map +1 -1
- package/dist/lib/test-runner/engine/case-runner.js +89 -0
- package/dist/lib/test-runner/engine/case-runner.js.map +1 -0
- package/dist/lib/test-runner/engine/document-runtime.js +307 -0
- package/dist/lib/test-runner/engine/document-runtime.js.map +1 -0
- package/dist/lib/test-runner/engine/execute-step.js +211 -0
- package/dist/lib/test-runner/engine/execute-step.js.map +1 -0
- package/dist/lib/test-runner/engine/execution-failure.js +79 -0
- package/dist/lib/test-runner/engine/execution-failure.js.map +1 -0
- package/dist/lib/test-runner/engine/index.js +137 -0
- package/dist/lib/test-runner/engine/index.js.map +1 -0
- package/dist/lib/test-runner/engine/project-runtime.js +176 -0
- package/dist/lib/test-runner/engine/project-runtime.js.map +1 -0
- package/dist/lib/test-runner/engine/registry.js +95 -0
- package/dist/lib/test-runner/engine/registry.js.map +1 -0
- package/dist/lib/test-runner/engine/resource-operations.js +272 -0
- package/dist/lib/test-runner/engine/resource-operations.js.map +1 -0
- package/dist/lib/test-runner/engine/run-collected-case.js +227 -0
- package/dist/lib/test-runner/engine/run-collected-case.js.map +1 -0
- package/dist/lib/test-runner/engine/run-workflow-document.js +189 -0
- package/dist/lib/test-runner/engine/run-workflow-document.js.map +1 -0
- package/dist/lib/test-runner/engine/scheduler.js +64 -0
- package/dist/lib/test-runner/engine/scheduler.js.map +1 -0
- package/dist/lib/test-runner/engine/scope-teardown.js +50 -0
- package/dist/lib/test-runner/engine/scope-teardown.js.map +1 -0
- package/dist/lib/test-runner/engine/types.js +20 -0
- package/dist/lib/test-runner/engine/types.js.map +1 -0
- package/dist/lib/test-runner/errors.js +283 -0
- package/dist/lib/test-runner/errors.js.map +1 -0
- package/dist/lib/test-runner/execution-record.js +123 -0
- package/dist/lib/test-runner/execution-record.js.map +1 -0
- package/dist/lib/test-runner/index.js +137 -0
- package/dist/lib/test-runner/index.js.map +1 -0
- package/dist/lib/test-runner/node/define-node.js +78 -0
- package/dist/lib/test-runner/node/define-node.js.map +1 -0
- package/dist/lib/test-runner/node/index.js +67 -0
- package/dist/lib/test-runner/node/index.js.map +1 -0
- package/dist/lib/test-runner/node/types.js +20 -0
- package/dist/lib/test-runner/node/types.js.map +1 -0
- package/dist/lib/test-runner/parser/document-format.js +58 -0
- package/dist/lib/test-runner/parser/document-format.js.map +1 -0
- package/dist/lib/test-runner/parser/normalize.js +124 -0
- package/dist/lib/test-runner/parser/normalize.js.map +1 -0
- package/dist/lib/test-runner/parser/types.js +20 -0
- package/dist/lib/test-runner/parser/types.js.map +1 -0
- package/dist/lib/test-runner/project.js +20 -0
- package/dist/lib/test-runner/project.js.map +1 -0
- package/dist/lib/test-runner/reporting/agent-report.js +57 -0
- package/dist/lib/test-runner/reporting/agent-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/execution-record.js +107 -0
- package/dist/lib/test-runner/reporting/execution-record.js.map +1 -0
- package/dist/lib/test-runner/reporting/merge-report.js +265 -0
- package/dist/lib/test-runner/reporting/merge-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/sanitize.js +202 -0
- package/dist/lib/test-runner/reporting/sanitize.js.map +1 -0
- package/dist/lib/test-runner/reporting/test-run-report.js +364 -0
- package/dist/lib/test-runner/reporting/test-run-report.js.map +1 -0
- package/dist/lib/test-runner/reporting/types.js +20 -0
- package/dist/lib/test-runner/reporting/types.js.map +1 -0
- package/dist/lib/utils.js +1 -1
- package/dist/lib/yaml/execution-context.node.js +43 -0
- package/dist/lib/yaml/execution-context.node.js.map +1 -0
- package/dist/lib/yaml/execution-context.stub.js +45 -0
- package/dist/lib/yaml/execution-context.stub.js.map +1 -0
- package/dist/lib/yaml/execution-session.js +136 -0
- package/dist/lib/yaml/execution-session.js.map +1 -0
- package/dist/lib/yaml/index.js +49 -7
- package/dist/lib/yaml/legacy-yaml-execution-record.js +81 -0
- package/dist/lib/yaml/legacy-yaml-execution-record.js.map +1 -0
- package/dist/lib/yaml/legacy-yaml-report.js +86 -0
- package/dist/lib/yaml/legacy-yaml-report.js.map +1 -0
- package/dist/lib/yaml/legacy-yaml-runtime.js +156 -0
- package/dist/lib/yaml/legacy-yaml-runtime.js.map +1 -0
- package/dist/lib/yaml/player-state.js +52 -0
- package/dist/lib/yaml/player-state.js.map +1 -0
- package/dist/lib/yaml/player.js +213 -347
- package/dist/lib/yaml/player.js.map +1 -1
- package/dist/lib/yaml/report-policy.js +41 -0
- package/dist/lib/yaml/report-policy.js.map +1 -0
- package/dist/lib/yaml/test-runner-compat.js +344 -0
- package/dist/lib/yaml/test-runner-compat.js.map +1 -0
- package/dist/lib/yaml/test-runner-nodes.js +184 -0
- package/dist/lib/yaml/test-runner-nodes.js.map +1 -0
- package/dist/lib/yaml/utils.js +18 -1
- package/dist/lib/yaml/utils.js.map +1 -1
- package/dist/lib/yaml-runtime.js +67 -0
- package/dist/lib/yaml-runtime.js.map +1 -0
- package/dist/lib/yaml.js.map +1 -1
- package/dist/types/agent/agent.d.ts +14 -1
- package/dist/types/agent/agent.d.ts.map +1 -1
- package/dist/types/agent/index.d.ts +4 -3
- package/dist/types/agent/index.d.ts.map +1 -1
- package/dist/types/agent/tasks.d.ts +1 -1
- package/dist/types/agent/tasks.d.ts.map +1 -1
- package/dist/types/agent/test-runner-nodes.d.ts +226 -0
- package/dist/types/agent/test-runner-nodes.d.ts.map +1 -1
- package/dist/types/device/index.d.ts +1 -1
- package/dist/types/device/index.d.ts.map +1 -1
- package/dist/types/dump/html-utils.d.ts +4 -0
- package/dist/types/dump/html-utils.d.ts.map +1 -1
- package/dist/types/dump/screenshot-store.d.ts +2 -1
- package/dist/types/dump/screenshot-store.d.ts.map +1 -1
- package/dist/types/report-cli.d.ts.map +1 -1
- package/dist/types/report-generator.d.ts +10 -0
- package/dist/types/report-generator.d.ts.map +1 -1
- package/dist/types/report.d.ts +3 -1
- package/dist/types/report.d.ts.map +1 -1
- package/dist/types/test-run-report.d.ts +18 -2
- package/dist/types/test-run-report.d.ts.map +1 -1
- package/dist/types/test-runner/engine/case-runner.d.ts +13 -0
- package/dist/types/test-runner/engine/case-runner.d.ts.map +1 -0
- package/dist/types/test-runner/engine/document-runtime.d.ts +4 -0
- package/dist/types/test-runner/engine/document-runtime.d.ts.map +1 -0
- package/dist/types/test-runner/engine/execute-step.d.ts +17 -0
- package/dist/types/test-runner/engine/execute-step.d.ts.map +1 -0
- package/dist/types/test-runner/engine/execution-failure.d.ts +13 -0
- package/dist/types/test-runner/engine/execution-failure.d.ts.map +1 -0
- package/dist/types/test-runner/engine/index.d.ts +13 -0
- package/dist/types/test-runner/engine/index.d.ts.map +1 -0
- package/dist/types/test-runner/engine/project-runtime.d.ts +3 -0
- package/dist/types/test-runner/engine/project-runtime.d.ts.map +1 -0
- package/dist/types/test-runner/engine/registry.d.ts +12 -0
- package/dist/types/test-runner/engine/registry.d.ts.map +1 -0
- package/dist/types/test-runner/engine/resource-operations.d.ts +32 -0
- package/dist/types/test-runner/engine/resource-operations.d.ts.map +1 -0
- package/dist/types/test-runner/engine/run-collected-case.d.ts +4 -0
- package/dist/types/test-runner/engine/run-collected-case.d.ts.map +1 -0
- package/dist/types/test-runner/engine/run-workflow-document.d.ts +4 -0
- package/dist/types/test-runner/engine/run-workflow-document.d.ts.map +1 -0
- package/dist/types/test-runner/engine/scheduler.d.ts +12 -0
- package/dist/types/test-runner/engine/scheduler.d.ts.map +1 -0
- package/dist/types/test-runner/engine/scope-teardown.d.ts +3 -0
- package/dist/types/test-runner/engine/scope-teardown.d.ts.map +1 -0
- package/dist/types/test-runner/engine/types.d.ts +226 -0
- package/dist/types/test-runner/engine/types.d.ts.map +1 -0
- package/dist/types/test-runner/errors.d.ts +79 -0
- package/dist/types/test-runner/errors.d.ts.map +1 -0
- package/dist/types/test-runner/execution-record.d.ts +43 -0
- package/dist/types/test-runner/execution-record.d.ts.map +1 -0
- package/dist/types/test-runner/index.d.ts +20 -0
- package/dist/types/test-runner/index.d.ts.map +1 -0
- package/dist/types/test-runner/node/define-node.d.ts +4 -0
- package/dist/types/test-runner/node/define-node.d.ts.map +1 -0
- package/dist/types/test-runner/node/index.d.ts +3 -0
- package/dist/types/test-runner/node/index.d.ts.map +1 -0
- package/dist/types/test-runner/node/types.d.ts +66 -0
- package/dist/types/test-runner/node/types.d.ts.map +1 -0
- package/dist/types/test-runner/parser/document-format.d.ts +8 -0
- package/dist/types/test-runner/parser/document-format.d.ts.map +1 -0
- package/dist/types/test-runner/parser/normalize.d.ts +9 -0
- package/dist/types/test-runner/parser/normalize.d.ts.map +1 -0
- package/dist/types/test-runner/parser/types.d.ts +69 -0
- package/dist/types/test-runner/parser/types.d.ts.map +1 -0
- package/dist/types/test-runner/project.d.ts +75 -0
- package/dist/types/test-runner/project.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/agent-report.d.ts +9 -0
- package/dist/types/test-runner/reporting/agent-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/execution-record.d.ts +9 -0
- package/dist/types/test-runner/reporting/execution-record.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/merge-report.d.ts +15 -0
- package/dist/types/test-runner/reporting/merge-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/sanitize.d.ts +6 -0
- package/dist/types/test-runner/reporting/sanitize.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/test-run-report.d.ts +5 -0
- package/dist/types/test-runner/reporting/test-run-report.d.ts.map +1 -0
- package/dist/types/test-runner/reporting/types.d.ts +34 -0
- package/dist/types/test-runner/reporting/types.d.ts.map +1 -0
- package/dist/types/yaml/execution-context.node.d.ts +4 -0
- package/dist/types/yaml/execution-context.node.d.ts.map +1 -0
- package/dist/types/yaml/execution-context.stub.d.ts +6 -0
- package/dist/types/yaml/execution-context.stub.d.ts.map +1 -0
- package/dist/types/yaml/execution-session.d.ts +17 -0
- package/dist/types/yaml/execution-session.d.ts.map +1 -0
- package/dist/types/yaml/index.d.ts +1 -1
- package/dist/types/yaml/index.d.ts.map +1 -1
- package/dist/types/yaml/legacy-yaml-execution-record.d.ts +24 -0
- package/dist/types/yaml/legacy-yaml-execution-record.d.ts.map +1 -0
- package/dist/types/yaml/legacy-yaml-report.d.ts +19 -0
- package/dist/types/yaml/legacy-yaml-report.d.ts.map +1 -0
- package/dist/types/yaml/legacy-yaml-runtime.d.ts +23 -0
- package/dist/types/yaml/legacy-yaml-runtime.d.ts.map +1 -0
- package/dist/types/yaml/player-state.d.ts +11 -0
- package/dist/types/yaml/player-state.d.ts.map +1 -0
- package/dist/types/yaml/player.d.ts +11 -3
- package/dist/types/yaml/player.d.ts.map +1 -1
- package/dist/types/yaml/report-policy.d.ts +4 -0
- package/dist/types/yaml/report-policy.d.ts.map +1 -0
- package/dist/types/yaml/test-runner-compat.d.ts +17 -0
- package/dist/types/yaml/test-runner-compat.d.ts.map +1 -0
- package/dist/types/yaml/test-runner-nodes.d.ts +6 -0
- package/dist/types/yaml/test-runner-nodes.d.ts.map +1 -0
- package/dist/types/yaml/utils.d.ts +9 -0
- package/dist/types/yaml/utils.d.ts.map +1 -1
- package/dist/types/yaml-runtime.d.ts +13 -0
- package/dist/types/yaml-runtime.d.ts.map +1 -0
- package/dist/types/yaml.d.ts +25 -7
- package/dist/types/yaml.d.ts.map +1 -1
- package/package.json +28 -2
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { getDebug } from "@midscene/shared/logger";
|
|
2
|
+
import { ProjectSetupError, ProjectTeardownError, WorkflowLifecycleError } from "../errors.mjs";
|
|
3
|
+
import { ResourceCleanupDeferredError, cleanupScopeResources, linkResourceSignal } from "./resource-operations.mjs";
|
|
4
|
+
const createProjectRuntime = (options)=>{
|
|
5
|
+
const startedAt = new Date();
|
|
6
|
+
const controller = new AbortController();
|
|
7
|
+
const parentSignal = options.signal;
|
|
8
|
+
linkResourceSignal(controller.signal, parentSignal);
|
|
9
|
+
const abortFromParent = ()=>controller.abort(parentSignal?.reason);
|
|
10
|
+
if (parentSignal?.aborted) abortFromParent();
|
|
11
|
+
else parentSignal?.addEventListener('abort', abortFromParent, {
|
|
12
|
+
once: true
|
|
13
|
+
});
|
|
14
|
+
const teardownStack = [];
|
|
15
|
+
let context;
|
|
16
|
+
let setupError;
|
|
17
|
+
let started = false;
|
|
18
|
+
let acceptingTeardowns = void 0 !== options.setup;
|
|
19
|
+
let finishedResult;
|
|
20
|
+
let finishPromise;
|
|
21
|
+
const createResult = (requestedStatus, teardownErrors = [])=>{
|
|
22
|
+
const endedAt = new Date();
|
|
23
|
+
return {
|
|
24
|
+
projectName: options.project.name,
|
|
25
|
+
status: 'failed' === requestedStatus || setupError || teardownErrors.length > 0 ? 'failed' : 'success',
|
|
26
|
+
...setupError ? {
|
|
27
|
+
setupError
|
|
28
|
+
} : {},
|
|
29
|
+
...teardownErrors.length > 0 ? {
|
|
30
|
+
teardownErrors: [
|
|
31
|
+
...teardownErrors
|
|
32
|
+
]
|
|
33
|
+
} : {},
|
|
34
|
+
startedAt: startedAt.toISOString(),
|
|
35
|
+
endedAt: endedAt.toISOString(),
|
|
36
|
+
durationMs: Math.max(0, endedAt.getTime() - startedAt.getTime())
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const onTeardown = (teardown)=>{
|
|
40
|
+
if (!acceptingTeardowns) throw new WorkflowLifecycleError('onTeardown() can only be called while Project setup is running.', {
|
|
41
|
+
projectName: options.project.name
|
|
42
|
+
});
|
|
43
|
+
if ('function' != typeof teardown) throw new WorkflowLifecycleError('Project onTeardown() requires a teardown function.', {
|
|
44
|
+
projectName: options.project.name
|
|
45
|
+
});
|
|
46
|
+
teardownStack.push({
|
|
47
|
+
registrationIndex: teardownStack.length,
|
|
48
|
+
teardown
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
get context () {
|
|
53
|
+
return context;
|
|
54
|
+
},
|
|
55
|
+
get signal () {
|
|
56
|
+
return controller.signal;
|
|
57
|
+
},
|
|
58
|
+
get canRun () {
|
|
59
|
+
return started && !setupError && !controller.signal.aborted;
|
|
60
|
+
},
|
|
61
|
+
async start () {
|
|
62
|
+
if (started) throw new WorkflowLifecycleError('Project runtime has already started.', {
|
|
63
|
+
projectName: options.project.name
|
|
64
|
+
});
|
|
65
|
+
started = true;
|
|
66
|
+
if (controller.signal.aborted) {
|
|
67
|
+
acceptingTeardowns = false;
|
|
68
|
+
return createResult('failed');
|
|
69
|
+
}
|
|
70
|
+
if (options.setup) try {
|
|
71
|
+
context = await options.setup.setup({
|
|
72
|
+
project: options.project,
|
|
73
|
+
env: Object.freeze({
|
|
74
|
+
...process.env
|
|
75
|
+
}),
|
|
76
|
+
signal: controller.signal,
|
|
77
|
+
onTeardown
|
|
78
|
+
});
|
|
79
|
+
} catch (error) {
|
|
80
|
+
setupError = new ProjectSetupError(error, {
|
|
81
|
+
projectName: options.project.name
|
|
82
|
+
});
|
|
83
|
+
} finally{
|
|
84
|
+
acceptingTeardowns = false;
|
|
85
|
+
}
|
|
86
|
+
return createResult(setupError ? 'failed' : 'success');
|
|
87
|
+
},
|
|
88
|
+
async finish (requestedStatus = 'success') {
|
|
89
|
+
if (finishPromise) return finishPromise;
|
|
90
|
+
if (!started) throw new WorkflowLifecycleError('Project runtime must start before it can finish.', {
|
|
91
|
+
projectName: options.project.name
|
|
92
|
+
});
|
|
93
|
+
finishPromise = (async ()=>{
|
|
94
|
+
const statusBeforeTeardown = createResult(requestedStatus).status;
|
|
95
|
+
const teardownErrors = [];
|
|
96
|
+
let deferredCleanup = false;
|
|
97
|
+
const cleanup = async ()=>{
|
|
98
|
+
const priorErrors = teardownErrors.length;
|
|
99
|
+
for (const { registrationIndex, teardown } of teardownStack.reverse())try {
|
|
100
|
+
await teardown({
|
|
101
|
+
project: options.project,
|
|
102
|
+
context,
|
|
103
|
+
status: statusBeforeTeardown,
|
|
104
|
+
...setupError ? {
|
|
105
|
+
setupError
|
|
106
|
+
} : {}
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
teardownErrors.push(new ProjectTeardownError(error, {
|
|
110
|
+
projectName: options.project.name,
|
|
111
|
+
registrationIndex
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
if (deferredCleanup && teardownErrors.length > priorErrors) throw new AggregateError(teardownErrors.slice(priorErrors), 'Deferred Project cleanup failed');
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
if (teardownStack.length) await cleanupScopeResources(controller.signal, cleanup, {
|
|
118
|
+
onDeferredError: (error)=>getDebug('runner:cleanup', {
|
|
119
|
+
console: true
|
|
120
|
+
})(`Deferred Project cleanup failed: ${String(error)}`)
|
|
121
|
+
});
|
|
122
|
+
} catch (error) {
|
|
123
|
+
deferredCleanup = error instanceof ResourceCleanupDeferredError;
|
|
124
|
+
teardownErrors.push(new ProjectTeardownError(error, {
|
|
125
|
+
projectName: options.project.name,
|
|
126
|
+
registrationIndex: -1
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
parentSignal?.removeEventListener('abort', abortFromParent);
|
|
130
|
+
finishedResult = createResult(requestedStatus, teardownErrors);
|
|
131
|
+
return finishedResult;
|
|
132
|
+
})();
|
|
133
|
+
return finishPromise;
|
|
134
|
+
},
|
|
135
|
+
abort (reason) {
|
|
136
|
+
controller.abort(reason);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
export { createProjectRuntime };
|
|
141
|
+
|
|
142
|
+
//# sourceMappingURL=project-runtime.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner/engine/project-runtime.mjs","sources":["../../../../src/test-runner/engine/project-runtime.ts"],"sourcesContent":["import { getDebug } from '@midscene/shared/logger';\nimport {\n ProjectSetupError,\n ProjectTeardownError,\n WorkflowLifecycleError,\n} from '../errors';\nimport {\n ResourceCleanupDeferredError,\n cleanupScopeResources,\n linkResourceSignal,\n} from './resource-operations';\nimport type {\n ProjectRuntime,\n ProjectRuntimeOptions,\n ProjectRuntimeResult,\n} from './types';\n\nexport const createProjectRuntime = <TProjectContext = unknown>(\n options: ProjectRuntimeOptions<TProjectContext>,\n): ProjectRuntime<TProjectContext> => {\n const startedAt = new Date();\n const controller = new AbortController();\n const parentSignal = options.signal;\n linkResourceSignal(controller.signal, parentSignal);\n const abortFromParent = () => controller.abort(parentSignal?.reason);\n if (parentSignal?.aborted) abortFromParent();\n else parentSignal?.addEventListener('abort', abortFromParent, { once: true });\n\n const teardownStack: Array<{\n registrationIndex: number;\n teardown: Parameters<\n Parameters<NonNullable<typeof options.setup>['setup']>[0]['onTeardown']\n >[0];\n }> = [];\n let context: TProjectContext | undefined;\n let setupError: ProjectSetupError | undefined;\n let started = false;\n let acceptingTeardowns = options.setup !== undefined;\n let finishedResult: ProjectRuntimeResult<TProjectContext> | undefined;\n let finishPromise: Promise<ProjectRuntimeResult<TProjectContext>> | undefined;\n\n const createResult = (\n requestedStatus: 'success' | 'failed',\n teardownErrors: readonly ProjectTeardownError[] = [],\n ): ProjectRuntimeResult<TProjectContext> => {\n const endedAt = new Date();\n return {\n projectName: options.project.name,\n status:\n requestedStatus === 'failed' || setupError || teardownErrors.length > 0\n ? 'failed'\n : 'success',\n ...(setupError ? { setupError } : {}),\n ...(teardownErrors.length > 0\n ? { teardownErrors: [...teardownErrors] }\n : {}),\n startedAt: startedAt.toISOString(),\n endedAt: endedAt.toISOString(),\n durationMs: Math.max(0, endedAt.getTime() - startedAt.getTime()),\n };\n };\n\n const onTeardown = (\n teardown: (typeof teardownStack)[number]['teardown'],\n ): void => {\n if (!acceptingTeardowns) {\n throw new WorkflowLifecycleError(\n 'onTeardown() can only be called while Project setup is running.',\n { projectName: options.project.name },\n );\n }\n if (typeof teardown !== 'function') {\n throw new WorkflowLifecycleError(\n 'Project onTeardown() requires a teardown function.',\n { projectName: options.project.name },\n );\n }\n teardownStack.push({\n registrationIndex: teardownStack.length,\n teardown,\n });\n };\n\n return {\n get context() {\n return context;\n },\n get signal() {\n return controller.signal;\n },\n get canRun() {\n return started && !setupError && !controller.signal.aborted;\n },\n async start() {\n if (started) {\n throw new WorkflowLifecycleError(\n 'Project runtime has already started.',\n {\n projectName: options.project.name,\n },\n );\n }\n started = true;\n if (controller.signal.aborted) {\n acceptingTeardowns = false;\n return createResult('failed');\n }\n if (options.setup) {\n try {\n context = await options.setup.setup({\n project: options.project,\n env: Object.freeze({ ...process.env }),\n signal: controller.signal,\n onTeardown,\n });\n } catch (error) {\n setupError = new ProjectSetupError(error, {\n projectName: options.project.name,\n });\n } finally {\n acceptingTeardowns = false;\n }\n }\n return createResult(setupError ? 'failed' : 'success');\n },\n async finish(requestedStatus = 'success') {\n if (finishPromise) return finishPromise;\n if (!started) {\n throw new WorkflowLifecycleError(\n 'Project runtime must start before it can finish.',\n { projectName: options.project.name },\n );\n }\n finishPromise = (async () => {\n const statusBeforeTeardown = createResult(requestedStatus).status;\n const teardownErrors: ProjectTeardownError[] = [];\n let deferredCleanup = false;\n const cleanup = async () => {\n const priorErrors = teardownErrors.length;\n for (const {\n registrationIndex,\n teardown,\n } of teardownStack.reverse()) {\n try {\n await teardown({\n project: options.project,\n context,\n status: statusBeforeTeardown,\n ...(setupError ? { setupError } : {}),\n });\n } catch (error) {\n teardownErrors.push(\n new ProjectTeardownError(error, {\n projectName: options.project.name,\n registrationIndex,\n }),\n );\n }\n }\n if (deferredCleanup && teardownErrors.length > priorErrors)\n throw new AggregateError(\n teardownErrors.slice(priorErrors),\n 'Deferred Project cleanup failed',\n );\n };\n try {\n if (teardownStack.length)\n await cleanupScopeResources(controller.signal, cleanup, {\n onDeferredError: (error) =>\n getDebug('runner:cleanup', { console: true })(\n `Deferred Project cleanup failed: ${String(error)}`,\n ),\n });\n } catch (error) {\n deferredCleanup = error instanceof ResourceCleanupDeferredError;\n teardownErrors.push(\n new ProjectTeardownError(error, {\n projectName: options.project.name,\n registrationIndex: -1,\n }),\n );\n }\n parentSignal?.removeEventListener('abort', abortFromParent);\n finishedResult = createResult(requestedStatus, teardownErrors);\n return finishedResult;\n })();\n return finishPromise;\n },\n abort(reason) {\n controller.abort(reason);\n },\n };\n};\n"],"names":["createProjectRuntime","options","startedAt","Date","controller","AbortController","parentSignal","linkResourceSignal","abortFromParent","teardownStack","context","setupError","started","acceptingTeardowns","undefined","finishedResult","finishPromise","createResult","requestedStatus","teardownErrors","endedAt","Math","onTeardown","teardown","WorkflowLifecycleError","Object","process","error","ProjectSetupError","statusBeforeTeardown","deferredCleanup","cleanup","priorErrors","registrationIndex","ProjectTeardownError","AggregateError","cleanupScopeResources","getDebug","String","ResourceCleanupDeferredError","reason"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { DuplicateNodeError, NodeNotFoundError } from "../errors.mjs";
|
|
2
|
+
import { defineNode } from "../node/define-node.mjs";
|
|
3
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
4
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
5
|
+
}
|
|
6
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
7
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
8
|
+
return descriptor.value;
|
|
9
|
+
}
|
|
10
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
11
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
12
|
+
return privateMap.get(receiver);
|
|
13
|
+
}
|
|
14
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
15
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
16
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
17
|
+
}
|
|
18
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
19
|
+
_check_private_redeclaration(obj, privateMap);
|
|
20
|
+
privateMap.set(obj, value);
|
|
21
|
+
}
|
|
22
|
+
var _nodes = /*#__PURE__*/ new WeakMap();
|
|
23
|
+
class NodeRegistry {
|
|
24
|
+
register(node) {
|
|
25
|
+
defineNode(node);
|
|
26
|
+
if (_class_private_field_get(this, _nodes).has(node.name)) throw new DuplicateNodeError(node.name);
|
|
27
|
+
_class_private_field_get(this, _nodes).set(node.name, node);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
get(name) {
|
|
31
|
+
return _class_private_field_get(this, _nodes).get(name);
|
|
32
|
+
}
|
|
33
|
+
require(name) {
|
|
34
|
+
const node = this.get(name);
|
|
35
|
+
if (!node) throw new NodeNotFoundError(name);
|
|
36
|
+
return node;
|
|
37
|
+
}
|
|
38
|
+
has(name) {
|
|
39
|
+
return _class_private_field_get(this, _nodes).has(name);
|
|
40
|
+
}
|
|
41
|
+
names() {
|
|
42
|
+
return [
|
|
43
|
+
..._class_private_field_get(this, _nodes).keys()
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
definitions() {
|
|
47
|
+
return [
|
|
48
|
+
..._class_private_field_get(this, _nodes).values()
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
constructor(nodes = []){
|
|
52
|
+
_class_private_field_init(this, _nodes, {
|
|
53
|
+
writable: true,
|
|
54
|
+
value: new Map()
|
|
55
|
+
});
|
|
56
|
+
for (const node of nodes)this.register(node);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export { NodeRegistry };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner/engine/registry.mjs","sources":["../../../../src/test-runner/engine/registry.ts"],"sourcesContent":["import { DuplicateNodeError, NodeNotFoundError } from '../errors';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition } from '../node/types';\n\nexport class NodeRegistry {\n readonly #nodes = new Map<string, NodeDefinition<any, any, any>>();\n\n constructor(nodes: readonly NodeDefinition<any, any>[] = []) {\n for (const node of nodes) {\n this.register(node);\n }\n }\n\n register<TInput, TData>(node: NodeDefinition<TInput, TData>): this {\n defineNode(node);\n\n if (this.#nodes.has(node.name)) {\n throw new DuplicateNodeError(node.name);\n }\n\n this.#nodes.set(node.name, node);\n return this;\n }\n\n get(name: string): NodeDefinition<any, any> | undefined {\n return this.#nodes.get(name);\n }\n\n require(name: string): NodeDefinition<any, any> {\n const node = this.get(name);\n if (!node) {\n throw new NodeNotFoundError(name);\n }\n return node;\n }\n\n has(name: string): boolean {\n return this.#nodes.has(name);\n }\n\n names(): string[] {\n return [...this.#nodes.keys()];\n }\n\n definitions(): readonly NodeDefinition<any, any, any>[] {\n return [...this.#nodes.values()];\n }\n}\n"],"names":["_nodes","NodeRegistry","node","defineNode","DuplicateNodeError","name","NodeNotFoundError","nodes","Map"],"mappings":";;;;;;;;;;;;;;;;;;;;;IAKWA,SAAAA,WAAAA,GAAAA,IAAAA;AADJ,MAAMC;IASX,SAAwBC,IAAmC,EAAQ;QACjEC,WAAWD;QAEX,IAAI,6BAAI,EAACF,QAAO,GAAG,CAACE,KAAK,IAAI,GAC3B,MAAM,IAAIE,mBAAmBF,KAAK,IAAI;QAGxC,6BAAI,EAACF,QAAO,GAAG,CAACE,KAAK,IAAI,EAAEA;QAC3B,OAAO,IAAI;IACb;IAEA,IAAIG,IAAY,EAAwC;QACtD,OAAO,6BAAI,EAACL,QAAO,GAAG,CAACK;IACzB;IAEA,QAAQA,IAAY,EAA4B;QAC9C,MAAMH,OAAO,IAAI,CAAC,GAAG,CAACG;QACtB,IAAI,CAACH,MACH,MAAM,IAAII,kBAAkBD;QAE9B,OAAOH;IACT;IAEA,IAAIG,IAAY,EAAW;QACzB,OAAO,6BAAI,EAACL,QAAO,GAAG,CAACK;IACzB;IAEA,QAAkB;QAChB,OAAO;eAAI,6BAAI,EAACL,QAAO,IAAI;SAAG;IAChC;IAEA,cAAwD;QACtD,OAAO;eAAI,6BAAI,EAACA,QAAO,MAAM;SAAG;IAClC;IAvCA,YAAYO,QAA6C,EAAE,CAAE;QAF7D,gCAASP,QAAAA;;mBAAS,IAAIQ;;QAGpB,KAAK,MAAMN,QAAQK,MACjB,IAAI,CAAC,QAAQ,CAACL;IAElB;AAoCF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { WorkflowError } from "../errors.mjs";
|
|
2
|
+
const stateKey = Symbol.for('@midscene/core/resource-operations/v3');
|
|
3
|
+
const host = globalThis;
|
|
4
|
+
host[stateKey] ??= {
|
|
5
|
+
resources: new WeakMap(),
|
|
6
|
+
scopes: new WeakMap(),
|
|
7
|
+
parents: new WeakMap(),
|
|
8
|
+
cleanupOwners: new WeakMap()
|
|
9
|
+
};
|
|
10
|
+
const { resources: resource_operations_resources, scopes, parents, cleanupOwners } = host[stateKey];
|
|
11
|
+
const resourceHandle = (resource)=>{
|
|
12
|
+
let handle = resource_operations_resources.get(resource);
|
|
13
|
+
if (!handle) {
|
|
14
|
+
handle = {
|
|
15
|
+
operations: new Map(),
|
|
16
|
+
retiring: new Set()
|
|
17
|
+
};
|
|
18
|
+
resource_operations_resources.set(resource, handle);
|
|
19
|
+
}
|
|
20
|
+
return handle;
|
|
21
|
+
};
|
|
22
|
+
const getResourceCleanupCompletion = (owner)=>resource_operations_resources.get(owner)?.cleanup;
|
|
23
|
+
const RESOURCE_CLEANUP_GRACE_MS = 1000;
|
|
24
|
+
function linkResourceSignal(signal, parent) {
|
|
25
|
+
if (parent && parent !== signal) parents.set(signal, parent);
|
|
26
|
+
}
|
|
27
|
+
function* ownerSignals(signal) {
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
for(let owner = signal; owner && !seen.has(owner); owner = parents.get(owner)){
|
|
30
|
+
seen.add(owner);
|
|
31
|
+
yield owner;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createResourceScope(parent) {
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
const scope = {
|
|
37
|
+
operations: new Map(),
|
|
38
|
+
resources: new Set()
|
|
39
|
+
};
|
|
40
|
+
scopes.set(controller.signal, scope);
|
|
41
|
+
linkResourceSignal(controller.signal, parent);
|
|
42
|
+
const abort = ()=>controller.abort(parent?.reason);
|
|
43
|
+
if (parent?.aborted) abort();
|
|
44
|
+
else parent?.addEventListener('abort', abort, {
|
|
45
|
+
once: true
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
signal: controller.signal,
|
|
49
|
+
dispose () {
|
|
50
|
+
parent?.removeEventListener('abort', abort);
|
|
51
|
+
scope.resources = void 0;
|
|
52
|
+
if (!scope.operations.size) scopes.delete(controller.signal);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function assertResourceAvailable(resource, exclusive = false, signal) {
|
|
57
|
+
const retiringOwners = resource_operations_resources.get(resource)?.retiring;
|
|
58
|
+
const isOwnerCleanup = [
|
|
59
|
+
...ownerSignals(signal)
|
|
60
|
+
].some((ownerSignal)=>{
|
|
61
|
+
const owner = cleanupOwners.get(ownerSignal);
|
|
62
|
+
return void 0 !== owner && retiringOwners?.has(owner);
|
|
63
|
+
});
|
|
64
|
+
if (retiringOwners?.size && !isOwnerCleanup) throw new WorkflowError('A resource cannot execute overlapping Runner operations while its cleanup is pending.', {
|
|
65
|
+
code: 'RESOURCE_CLEANUP_PENDING'
|
|
66
|
+
});
|
|
67
|
+
const pending = resource_operations_resources.get(resource)?.operations;
|
|
68
|
+
if (exclusive && pending?.size && !isOwnerCleanup) throw new WorkflowError('The same Agent instance cannot execute overlapping Runner operations.', {
|
|
69
|
+
code: 'RESOURCE_OPERATION_PENDING'
|
|
70
|
+
});
|
|
71
|
+
if (pending && !isOwnerCleanup && [
|
|
72
|
+
...pending.values()
|
|
73
|
+
].some((signal)=>signal.aborted)) throw new WorkflowError('Cannot reuse an Agent while an aborted YAML action or Runner operation is still running.', {
|
|
74
|
+
code: 'RESOURCE_OPERATION_PENDING'
|
|
75
|
+
});
|
|
76
|
+
return isOwnerCleanup;
|
|
77
|
+
}
|
|
78
|
+
const retainForCleanup = (owner, resource)=>{
|
|
79
|
+
owner.resources.add(resource);
|
|
80
|
+
resourceHandle(resource).retiring.add(owner);
|
|
81
|
+
};
|
|
82
|
+
function trackResourceOperation(resource, operation, signal) {
|
|
83
|
+
const active = resourceHandle(resource).operations;
|
|
84
|
+
active.set(operation, signal);
|
|
85
|
+
const ownerScopes = [];
|
|
86
|
+
let retainedByScope = false;
|
|
87
|
+
for (const ownerSignal of ownerSignals(signal)){
|
|
88
|
+
const scope = scopes.get(ownerSignal) ?? {
|
|
89
|
+
operations: new Map()
|
|
90
|
+
};
|
|
91
|
+
scopes.set(ownerSignal, scope);
|
|
92
|
+
scope.operations.set(resource, (scope.operations.get(resource) ?? 0) + 1);
|
|
93
|
+
ownerScopes.push([
|
|
94
|
+
ownerSignal,
|
|
95
|
+
scope
|
|
96
|
+
]);
|
|
97
|
+
if (!retainedByScope && scope.resources) {
|
|
98
|
+
scope.resources.add(resource);
|
|
99
|
+
retainedByScope = true;
|
|
100
|
+
}
|
|
101
|
+
const cleanupOwner = cleanupOwners.get(ownerSignal);
|
|
102
|
+
if (cleanupOwner) retainForCleanup(cleanupOwner, resource);
|
|
103
|
+
}
|
|
104
|
+
const finish = ()=>{
|
|
105
|
+
active.delete(operation);
|
|
106
|
+
for (const [ownerSignal, scope] of ownerScopes){
|
|
107
|
+
const count = scope.operations.get(resource) - 1;
|
|
108
|
+
if (count) scope.operations.set(resource, count);
|
|
109
|
+
else scope.operations.delete(resource);
|
|
110
|
+
if (!scope.operations.size && !scope.resources) scopes.delete(ownerSignal);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
operation.then(finish, finish);
|
|
114
|
+
return operation;
|
|
115
|
+
}
|
|
116
|
+
async function waitForResourceIdle(resource) {
|
|
117
|
+
while(resource_operations_resources.get(resource)?.operations?.size)await Promise.allSettled([
|
|
118
|
+
...resource_operations_resources.get(resource).operations.keys()
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
class ResourceCleanupDeferredError extends WorkflowError {
|
|
122
|
+
constructor(graceMs, resourceCount){
|
|
123
|
+
super('Resource cleanup was deferred because an operation did not stop after cancellation. The resource remains quarantined and cleanup will run when that operation settles.', {
|
|
124
|
+
code: 'RESOURCE_CLEANUP_DEFERRED',
|
|
125
|
+
details: {
|
|
126
|
+
graceMs,
|
|
127
|
+
resourceCount
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function runResourceCleanup(resources, cleanup, options, beforeCleanup) {
|
|
133
|
+
const owner = {
|
|
134
|
+
resources: new Set(),
|
|
135
|
+
signal: beforeCleanup?.signal
|
|
136
|
+
};
|
|
137
|
+
for (const resource of resources)retainForCleanup(owner, resource);
|
|
138
|
+
if (owner.signal) cleanupOwners.set(owner.signal, owner);
|
|
139
|
+
let defer;
|
|
140
|
+
const deferred = new Promise((resolve)=>{
|
|
141
|
+
defer = ()=>resolve({
|
|
142
|
+
deferred: true
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
const graceMs = options.graceMs ?? RESOURCE_CLEANUP_GRACE_MS;
|
|
146
|
+
const drain = async ()=>{
|
|
147
|
+
const pending = [
|
|
148
|
+
...owner.resources
|
|
149
|
+
].filter((resource)=>resourceHandle(resource).operations.size);
|
|
150
|
+
if (!pending.length) return;
|
|
151
|
+
const timer = setTimeout(defer, graceMs);
|
|
152
|
+
try {
|
|
153
|
+
await Promise.all(pending.map(waitForResourceIdle));
|
|
154
|
+
} finally{
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const completion = (async ()=>{
|
|
159
|
+
try {
|
|
160
|
+
if (beforeCleanup) await beforeCleanup.run(beforeCleanup.signal);
|
|
161
|
+
await drain();
|
|
162
|
+
return await cleanup();
|
|
163
|
+
} finally{
|
|
164
|
+
if (owner.signal) cleanupOwners.delete(owner.signal);
|
|
165
|
+
for (const resource of owner.resources){
|
|
166
|
+
const owners = resourceHandle(resource).retiring;
|
|
167
|
+
owners.delete(owner);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
})();
|
|
171
|
+
const ownerKey = options.owner ?? beforeCleanup?.signal ?? resources[0];
|
|
172
|
+
if (ownerKey) resourceHandle(ownerKey).cleanup = completion;
|
|
173
|
+
const outcome = await Promise.race([
|
|
174
|
+
completion.then((value)=>({
|
|
175
|
+
value
|
|
176
|
+
})),
|
|
177
|
+
deferred
|
|
178
|
+
]);
|
|
179
|
+
if ('deferred' in outcome) {
|
|
180
|
+
completion.catch((error)=>{
|
|
181
|
+
try {
|
|
182
|
+
options.onDeferredError(error);
|
|
183
|
+
} catch {}
|
|
184
|
+
});
|
|
185
|
+
if (options.signal) trackResourceOperation({}, completion, options.signal);
|
|
186
|
+
throw new ResourceCleanupDeferredError(graceMs, owner.resources.size);
|
|
187
|
+
}
|
|
188
|
+
return outcome.value;
|
|
189
|
+
}
|
|
190
|
+
function cleanupResources(resources, cleanup, options) {
|
|
191
|
+
return runResourceCleanup(resources, cleanup, options);
|
|
192
|
+
}
|
|
193
|
+
async function cleanupScopeResources(signal, cleanup, options) {
|
|
194
|
+
const cleanupSignal = new AbortController().signal;
|
|
195
|
+
linkResourceSignal(cleanupSignal, signal);
|
|
196
|
+
const scope = scopes.get(signal);
|
|
197
|
+
return runResourceCleanup([
|
|
198
|
+
...scope?.resources ?? [],
|
|
199
|
+
...scope?.operations.keys() ?? []
|
|
200
|
+
], cleanup, {
|
|
201
|
+
...options,
|
|
202
|
+
owner: signal,
|
|
203
|
+
signal
|
|
204
|
+
}, options.beforeCleanup ? {
|
|
205
|
+
signal: cleanupSignal,
|
|
206
|
+
run: options.beforeCleanup
|
|
207
|
+
} : void 0);
|
|
208
|
+
}
|
|
209
|
+
export { RESOURCE_CLEANUP_GRACE_MS, ResourceCleanupDeferredError, assertResourceAvailable, cleanupResources, cleanupScopeResources, createResourceScope, getResourceCleanupCompletion, linkResourceSignal, trackResourceOperation, waitForResourceIdle };
|
|
210
|
+
|
|
211
|
+
//# sourceMappingURL=resource-operations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner/engine/resource-operations.mjs","sources":["../../../../src/test-runner/engine/resource-operations.ts"],"sourcesContent":["import { WorkflowError } from '../errors';\n\ninterface CleanupOwner {\n resources: Set<object>;\n signal?: AbortSignal;\n}\n\ninterface ResourceScope {\n operations: Map<object, number>;\n resources?: Set<object>;\n}\n\ninterface ResourceHandle {\n operations: Map<Promise<unknown>, AbortSignal>;\n retiring: Set<CleanupOwner>;\n cleanup?: Promise<unknown>;\n}\n\ninterface ResourceState {\n resources: WeakMap<object, ResourceHandle>;\n scopes: WeakMap<AbortSignal, ResourceScope>;\n parents: WeakMap<AbortSignal, AbortSignal>;\n cleanupOwners: WeakMap<AbortSignal, CleanupOwner>;\n}\n\n// CJS and ESM hosts must agree about ownership of the same Agent instance.\nconst stateKey = Symbol.for('@midscene/core/resource-operations/v3');\nconst host = globalThis as typeof globalThis & { [stateKey]?: ResourceState };\nhost[stateKey] ??= {\n resources: new WeakMap(),\n scopes: new WeakMap(),\n parents: new WeakMap(),\n cleanupOwners: new WeakMap(),\n};\nconst { resources, scopes, parents, cleanupOwners } = host[stateKey];\nconst resourceHandle = (resource: object): ResourceHandle => {\n let handle = resources.get(resource);\n if (!handle) {\n handle = { operations: new Map(), retiring: new Set() };\n resources.set(resource, handle);\n }\n return handle;\n};\n\n/** Actual teardown completion belongs to the owner, never to a thrown error. */\nexport const getResourceCleanupCompletion = (\n owner: object,\n): Promise<unknown> | undefined => resources.get(owner)?.cleanup;\n\nexport const RESOURCE_CLEANUP_GRACE_MS = 1000;\n\n/** Resource ancestry is independent of cancellation: cleanup can outlive abort. */\nexport function linkResourceSignal(signal: AbortSignal, parent?: AbortSignal) {\n if (parent && parent !== signal) parents.set(signal, parent);\n}\n\nfunction* ownerSignals(signal?: AbortSignal): Generator<AbortSignal> {\n const seen = new Set<AbortSignal>();\n for (\n let owner = signal;\n owner && !seen.has(owner);\n owner = parents.get(owner)\n ) {\n seen.add(owner);\n yield owner;\n }\n}\n\n/** Each Case/document owns its cleanup, even when cancellation is shared. */\nexport function createResourceScope(parent?: AbortSignal) {\n const controller = new AbortController();\n const scope: ResourceScope = { operations: new Map(), resources: new Set() };\n scopes.set(controller.signal, scope);\n linkResourceSignal(controller.signal, parent);\n const abort = () => controller.abort(parent?.reason);\n if (parent?.aborted) abort();\n else parent?.addEventListener('abort', abort, { once: true });\n return {\n signal: controller.signal,\n dispose() {\n parent?.removeEventListener('abort', abort);\n scope.resources = undefined;\n if (!scope.operations.size) scopes.delete(controller.signal);\n },\n };\n}\n\nexport function assertResourceAvailable(\n resource: object,\n exclusive = false,\n signal?: AbortSignal,\n): boolean {\n const retiringOwners = resources.get(resource)?.retiring;\n const isOwnerCleanup = [...ownerSignals(signal)].some((ownerSignal) => {\n const owner = cleanupOwners.get(ownerSignal);\n return owner !== undefined && retiringOwners?.has(owner);\n });\n if (retiringOwners?.size && !isOwnerCleanup)\n throw new WorkflowError(\n 'A resource cannot execute overlapping Runner operations while its cleanup is pending.',\n { code: 'RESOURCE_CLEANUP_PENDING' },\n );\n const pending = resources.get(resource)?.operations;\n if (exclusive && pending?.size && !isOwnerCleanup)\n throw new WorkflowError(\n 'The same Agent instance cannot execute overlapping Runner operations.',\n { code: 'RESOURCE_OPERATION_PENDING' },\n );\n if (\n pending &&\n !isOwnerCleanup &&\n [...pending.values()].some((signal) => signal.aborted)\n )\n throw new WorkflowError(\n 'Cannot reuse an Agent while an aborted YAML action or Runner operation is still running.',\n { code: 'RESOURCE_OPERATION_PENDING' },\n );\n return isOwnerCleanup;\n}\n\nconst retainForCleanup = (owner: CleanupOwner, resource: object) => {\n owner.resources.add(resource);\n resourceHandle(resource).retiring.add(owner);\n};\n\n/** Track actual completion, not the Runner timeout race. */\nexport function trackResourceOperation<T>(\n resource: object,\n operation: Promise<T>,\n signal: AbortSignal,\n): Promise<T> {\n const active = resourceHandle(resource).operations;\n active.set(operation, signal);\n const ownerScopes: Array<[AbortSignal, ResourceScope]> = [];\n let retainedByScope = false;\n for (const ownerSignal of ownerSignals(signal)) {\n const scope: ResourceScope = scopes.get(ownerSignal) ?? {\n operations: new Map(),\n };\n scopes.set(ownerSignal, scope);\n scope.operations.set(resource, (scope.operations.get(resource) ?? 0) + 1);\n ownerScopes.push([ownerSignal, scope]);\n // Only the closest owner retains idle resources for its teardown. Parents\n // wait on active operations, not every Agent used by completed Cases.\n if (!retainedByScope && scope.resources) {\n scope.resources.add(resource);\n retainedByScope = true;\n }\n const cleanupOwner = cleanupOwners.get(ownerSignal);\n if (cleanupOwner) retainForCleanup(cleanupOwner, resource);\n }\n const finish = () => {\n active.delete(operation);\n for (const [ownerSignal, scope] of ownerScopes) {\n const count = scope.operations.get(resource)! - 1;\n if (count) scope.operations.set(resource, count);\n else scope.operations.delete(resource);\n if (!scope.operations.size && !scope.resources)\n scopes.delete(ownerSignal);\n }\n };\n void operation.then(finish, finish);\n return operation;\n}\n\nexport async function waitForResourceIdle(resource: object): Promise<void> {\n while (resources.get(resource)?.operations?.size)\n await Promise.allSettled([...resources.get(resource)!.operations.keys()]);\n}\n\nexport class ResourceCleanupDeferredError extends WorkflowError {\n constructor(graceMs: number, resourceCount: number) {\n super(\n 'Resource cleanup was deferred because an operation did not stop after cancellation. The resource remains quarantined and cleanup will run when that operation settles.',\n {\n code: 'RESOURCE_CLEANUP_DEFERRED',\n details: { graceMs, resourceCount },\n },\n );\n }\n}\n\ninterface CleanupOptions {\n /** Stable owner of this cleanup, distinct from borrowed resource identities. */\n owner?: object;\n /** Parent scope observes deferred completion without host-specific forwarding. */\n signal?: AbortSignal;\n graceMs?: number;\n onDeferredError(error: unknown): void;\n}\n\n/** Bound draining, but keep ownership until the actual cleanup has finished. */\nasync function runResourceCleanup<T>(\n resources: readonly object[],\n cleanup: () => Promise<T>,\n options: CleanupOptions,\n beforeCleanup?: {\n signal: AbortSignal;\n run(signal: AbortSignal): Promise<void>;\n },\n): Promise<T> {\n const owner: CleanupOwner = {\n resources: new Set(),\n signal: beforeCleanup?.signal,\n };\n for (const resource of resources) retainForCleanup(owner, resource);\n if (owner.signal) cleanupOwners.set(owner.signal, owner);\n\n let defer!: () => void;\n const deferred = new Promise<{ deferred: true }>((resolve) => {\n defer = () => resolve({ deferred: true });\n });\n const graceMs = options.graceMs ?? RESOURCE_CLEANUP_GRACE_MS;\n const drain = async () => {\n const pending = [...owner.resources].filter(\n (resource) => resourceHandle(resource).operations.size,\n );\n if (!pending.length) return;\n const timer = setTimeout(defer, graceMs);\n try {\n await Promise.all(pending.map(waitForResourceIdle));\n } finally {\n clearTimeout(timer);\n }\n };\n const completion = (async () => {\n try {\n if (beforeCleanup) {\n // Authored lifecycle cleanup must be allowed to stop or reset a\n // resource whose timed-out operation is still settling. Its signal is\n // registered as the retiring owner's cleanup signal, so unrelated\n // scopes remain quarantined while this hook runs.\n await beforeCleanup.run(beforeCleanup.signal);\n }\n // Lifecycle hooks can themselves time out with an action still running.\n // Drain both the original work and any operation started by the hook\n // before disposing the resource.\n await drain();\n return await cleanup();\n } finally {\n if (owner.signal) cleanupOwners.delete(owner.signal);\n for (const resource of owner.resources) {\n const owners = resourceHandle(resource).retiring;\n owners.delete(owner);\n }\n }\n })();\n const ownerKey = options.owner ?? beforeCleanup?.signal ?? resources[0];\n if (ownerKey) resourceHandle(ownerKey).cleanup = completion;\n const outcome = await Promise.race([\n completion.then((value) => ({ value })),\n deferred,\n ]);\n if ('deferred' in outcome) {\n void completion.catch((error) => {\n try {\n options.onDeferredError(error);\n } catch {\n // The returned completion still carries the original cleanup failure.\n }\n });\n if (options.signal) trackResourceOperation({}, completion, options.signal);\n throw new ResourceCleanupDeferredError(graceMs, owner.resources.size);\n }\n return outcome.value;\n}\n\nexport function cleanupResources<T>(\n resources: readonly object[],\n cleanup: () => Promise<T>,\n options: CleanupOptions,\n): Promise<T> {\n return runResourceCleanup(resources, cleanup, options);\n}\n\nexport async function cleanupScopeResources<T>(\n signal: AbortSignal,\n cleanup: () => Promise<T>,\n options: CleanupOptions & {\n beforeCleanup?(signal: AbortSignal): Promise<void>;\n },\n): Promise<T> {\n const cleanupSignal = new AbortController().signal;\n linkResourceSignal(cleanupSignal, signal);\n const scope = scopes.get(signal);\n return runResourceCleanup(\n [...(scope?.resources ?? []), ...(scope?.operations.keys() ?? [])],\n cleanup,\n { ...options, owner: signal, signal },\n options.beforeCleanup\n ? { signal: cleanupSignal, run: options.beforeCleanup }\n : undefined,\n );\n}\n"],"names":["stateKey","Symbol","host","globalThis","WeakMap","resources","scopes","parents","cleanupOwners","resourceHandle","resource","handle","Map","Set","getResourceCleanupCompletion","owner","RESOURCE_CLEANUP_GRACE_MS","linkResourceSignal","signal","parent","ownerSignals","seen","createResourceScope","controller","AbortController","scope","abort","undefined","assertResourceAvailable","exclusive","retiringOwners","isOwnerCleanup","ownerSignal","WorkflowError","pending","retainForCleanup","trackResourceOperation","operation","active","ownerScopes","retainedByScope","cleanupOwner","finish","count","waitForResourceIdle","Promise","ResourceCleanupDeferredError","graceMs","resourceCount","runResourceCleanup","cleanup","options","beforeCleanup","defer","deferred","resolve","drain","timer","setTimeout","clearTimeout","completion","owners","ownerKey","outcome","value","error","cleanupResources","cleanupScopeResources","cleanupSignal"],"mappings":"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"}
|