@powerlines/engine 0.9.1 → 0.9.3
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/api/build.cjs +1 -1
- package/dist/api/build.d.cts +2 -2
- package/dist/api/build.d.mts +2 -2
- package/dist/api/build.mjs +1 -1
- package/dist/api/clean.d.cts +2 -2
- package/dist/api/clean.d.mts +2 -2
- package/dist/api/create.d.cts +2 -2
- package/dist/api/create.d.mts +2 -2
- package/dist/api/deploy.d.cts +2 -2
- package/dist/api/deploy.d.mts +2 -2
- package/dist/api/docs.d.cts +2 -2
- package/dist/api/docs.d.mts +2 -2
- package/dist/api/lint.d.cts +2 -2
- package/dist/api/lint.d.mts +2 -2
- package/dist/api/prepare.d.cts +2 -2
- package/dist/api/prepare.d.mts +2 -2
- package/dist/api/test.d.cts +2 -2
- package/dist/api/test.d.mts +2 -2
- package/dist/api/types.d.cts +2 -2
- package/dist/api/types.d.mts +2 -2
- package/dist/{api-Bw-RpQgX.d.cts → api-6w4hZL6n.d.cts} +5 -4
- package/dist/api-6w4hZL6n.d.cts.map +1 -0
- package/dist/{api-D9bpSxPB.d.mts → api-CcNgO71y.d.mts} +5 -4
- package/dist/api-CcNgO71y.d.mts.map +1 -0
- package/dist/{config-B_E_HMcT.d.cts → config-C9AD-erz.d.mts} +8 -4
- package/dist/{config-B_E_HMcT.d.cts.map → config-C9AD-erz.d.mts.map} +1 -1
- package/dist/{config-FB8Zqjjz.d.mts → config-D6xUniHh.d.cts} +8 -4
- package/dist/{config-FB8Zqjjz.d.mts.map → config-D6xUniHh.d.cts.map} +1 -1
- package/dist/context/index.d.cts +1 -1
- package/dist/context/index.d.mts +1 -1
- package/dist/{context-C_P-KYJX.d.cts → context-S3XH2DWP.d.mts} +3 -3
- package/dist/{context-C_P-KYJX.d.cts.map → context-S3XH2DWP.d.mts.map} +1 -1
- package/dist/{context-DrNGEC0b.d.mts → context-epL7NPvL.d.cts} +3 -3
- package/dist/{context-DrNGEC0b.d.mts.map → context-epL7NPvL.d.cts.map} +1 -1
- package/dist/{engine-context-BXjBJuHe.d.mts → engine-context-BiDxBwme.d.mts} +3 -3
- package/dist/{engine-context-BXjBJuHe.d.mts.map → engine-context-BiDxBwme.d.mts.map} +1 -1
- package/dist/{engine-context-CPYw-aGB.d.cts → engine-context-Dw8odBCo.d.cts} +3 -3
- package/dist/{engine-context-CPYw-aGB.d.cts.map → engine-context-Dw8odBCo.d.cts.map} +1 -1
- package/dist/engine.cjs +1 -0
- package/dist/engine.d.cts +4 -4
- package/dist/engine.d.mts +4 -4
- package/dist/engine.mjs +1 -0
- package/dist/engine.mjs.map +1 -1
- package/dist/helpers/create-execution-host.cjs +27 -2
- package/dist/helpers/create-execution-host.d.cts +3 -3
- package/dist/helpers/create-execution-host.d.cts.map +1 -1
- package/dist/helpers/create-execution-host.d.mts +3 -3
- package/dist/helpers/create-execution-host.d.mts.map +1 -1
- package/dist/helpers/create-execution-host.mjs +27 -2
- package/dist/helpers/create-execution-host.mjs.map +1 -1
- package/dist/helpers/execution-host-worker.cjs +2 -1
- package/dist/helpers/execution-host-worker.d.cts +6 -2
- package/dist/helpers/execution-host-worker.d.cts.map +1 -1
- package/dist/helpers/execution-host-worker.d.mts +6 -2
- package/dist/helpers/execution-host-worker.d.mts.map +1 -1
- package/dist/helpers/execution-host-worker.mjs +2 -1
- package/dist/helpers/execution-host-worker.mjs.map +1 -1
- package/dist/helpers/rpc.d.cts +1 -1
- package/dist/helpers/rpc.d.mts +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/worker/execution-host.cjs +160 -2
- package/dist/worker/execution-host.d.cts +52 -2
- package/dist/worker/execution-host.d.cts.map +1 -1
- package/dist/worker/execution-host.d.mts +52 -2
- package/dist/worker/execution-host.d.mts.map +1 -1
- package/dist/worker/execution-host.mjs +161 -3
- package/dist/worker/execution-host.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/api-Bw-RpQgX.d.cts.map +0 -1
- package/dist/api-D9bpSxPB.d.mts.map +0 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
const require_chunk = require('../chunk-C0xms8kb.cjs');
|
|
3
|
+
const require_helpers_rpc = require('./rpc.cjs');
|
|
4
|
+
let _powerlines_core_plugin_utils = require("@powerlines/core/plugin-utils");
|
|
5
|
+
let _stryke_unique_id_uuid = require("@stryke/unique-id/uuid");
|
|
6
|
+
let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object");
|
|
3
7
|
let _powerlines_core_context_execution_context = require("@powerlines/core/context/execution-context");
|
|
4
8
|
let _powerlines_core_lib_context_helpers = require("@powerlines/core/lib/context-helpers");
|
|
9
|
+
let _stryke_string_format_title_case = require("@stryke/string-format/title-case");
|
|
5
10
|
|
|
6
11
|
//#region src/helpers/create-execution-host.ts
|
|
7
12
|
/**
|
|
@@ -12,8 +17,28 @@ let _powerlines_core_lib_context_helpers = require("@powerlines/core/lib/context
|
|
|
12
17
|
*/
|
|
13
18
|
function createExecutionHost(methods) {
|
|
14
19
|
return Object.fromEntries(Object.entries(methods).map(([method, fn]) => [method, async (params) => {
|
|
15
|
-
const
|
|
16
|
-
|
|
20
|
+
const { options, inlineConfig } = params;
|
|
21
|
+
let rpc;
|
|
22
|
+
if (options.baseURL && options.connection) rpc = require_helpers_rpc.createRpcClient(options);
|
|
23
|
+
else throw new Error(`Execution RPC client could not be created - Missing ${!options.baseURL ? `baseURL${options.connection ? ` and connection information` : ""}` : "connection"} or connection information.`);
|
|
24
|
+
const logFn = (meta, message) => {
|
|
25
|
+
(0, _powerlines_core_plugin_utils.consoleLogger)(meta, message);
|
|
26
|
+
if (rpc) rpc.callEvent("powerlines:log", {
|
|
27
|
+
meta: {
|
|
28
|
+
category: "general",
|
|
29
|
+
...options,
|
|
30
|
+
...(0, _stryke_type_checks_is_set_object.isSetObject)(meta) ? meta : { type: meta },
|
|
31
|
+
logId: (0, _stryke_unique_id_uuid.uuid)(),
|
|
32
|
+
timestamp: Date.now()
|
|
33
|
+
},
|
|
34
|
+
message
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
const context = await _powerlines_core_context_execution_context.PowerlinesExecutionContext.from({
|
|
38
|
+
...options,
|
|
39
|
+
logFn
|
|
40
|
+
}, inlineConfig ?? {}, { rpc });
|
|
41
|
+
context.logger.info(`Starting ${(0, _stryke_string_format_title_case.titleCase)(options.framework?.name) || "Powerlines"} - ${(0, _stryke_string_format_title_case.titleCase)(method)} execution (${options.executionId})`);
|
|
17
42
|
await (0, _powerlines_core_lib_context_helpers.resolvePluginConfig)(context);
|
|
18
43
|
await fn(context);
|
|
19
44
|
}]));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as EngineResolvedConfig } from "../config-
|
|
2
|
-
import { r as EngineSystemContext } from "../context-
|
|
3
|
-
import { r as ExecutionHostParams } from "../api-
|
|
1
|
+
import { r as EngineResolvedConfig } from "../config-D6xUniHh.cjs";
|
|
2
|
+
import { r as EngineSystemContext } from "../context-epL7NPvL.cjs";
|
|
3
|
+
import { r as ExecutionHostParams } from "../api-6w4hZL6n.cjs";
|
|
4
4
|
import { PowerlinesExecutionContext } from "@powerlines/core/context/execution-context";
|
|
5
5
|
|
|
6
6
|
//#region src/helpers/create-execution-host.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-execution-host.d.cts","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"create-execution-host.d.cts","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"mappings":";;;;;;;;AAqCA;;;;iBAAgB,mBAAA,kBACG,0BAAA,CACf,oBAAA,EACA,mBAAA,IACE,0BAAA,CAA2B,oBAAA,EAAsB,mBAAA,EAAA,CACrD,OAAA,EAAS,MAAA,UAAgB,OAAA,EAAS,QAAA,KAAa,OAAA;EAAA,sBAI5B,mBAAA,KAAmB,OAAA;AAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { r as EngineResolvedConfig } from "../config-
|
|
2
|
-
import { r as EngineSystemContext } from "../context-
|
|
3
|
-
import { r as ExecutionHostParams } from "../api-
|
|
1
|
+
import { r as EngineResolvedConfig } from "../config-C9AD-erz.mjs";
|
|
2
|
+
import { r as EngineSystemContext } from "../context-S3XH2DWP.mjs";
|
|
3
|
+
import { r as ExecutionHostParams } from "../api-CcNgO71y.mjs";
|
|
4
4
|
import { PowerlinesExecutionContext } from "@powerlines/core/context/execution-context";
|
|
5
5
|
|
|
6
6
|
//#region src/helpers/create-execution-host.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-execution-host.d.mts","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"create-execution-host.d.mts","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"mappings":";;;;;;;;AAqCA;;;;iBAAgB,mBAAA,kBACG,0BAAA,CACf,oBAAA,EACA,mBAAA,IACE,0BAAA,CAA2B,oBAAA,EAAsB,mBAAA,EAAA,CACrD,OAAA,EAAS,MAAA,UAAgB,OAAA,EAAS,QAAA,KAAa,OAAA;EAAA,sBAI5B,mBAAA,KAAmB,OAAA;AAAA"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { createRpcClient } from "./rpc.mjs";
|
|
2
|
+
import { consoleLogger } from "@powerlines/core/plugin-utils";
|
|
3
|
+
import { uuid } from "@stryke/unique-id/uuid";
|
|
4
|
+
import { isSetObject } from "@stryke/type-checks/is-set-object";
|
|
1
5
|
import { PowerlinesExecutionContext } from "@powerlines/core/context/execution-context";
|
|
2
6
|
import { resolvePluginConfig } from "@powerlines/core/lib/context-helpers";
|
|
7
|
+
import { titleCase } from "@stryke/string-format/title-case";
|
|
3
8
|
|
|
4
9
|
//#region src/helpers/create-execution-host.ts
|
|
5
10
|
/**
|
|
@@ -10,8 +15,28 @@ import { resolvePluginConfig } from "@powerlines/core/lib/context-helpers";
|
|
|
10
15
|
*/
|
|
11
16
|
function createExecutionHost(methods) {
|
|
12
17
|
return Object.fromEntries(Object.entries(methods).map(([method, fn]) => [method, async (params) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
18
|
+
const { options, inlineConfig } = params;
|
|
19
|
+
let rpc;
|
|
20
|
+
if (options.baseURL && options.connection) rpc = createRpcClient(options);
|
|
21
|
+
else throw new Error(`Execution RPC client could not be created - Missing ${!options.baseURL ? `baseURL${options.connection ? ` and connection information` : ""}` : "connection"} or connection information.`);
|
|
22
|
+
const logFn = (meta, message) => {
|
|
23
|
+
consoleLogger(meta, message);
|
|
24
|
+
if (rpc) rpc.callEvent("powerlines:log", {
|
|
25
|
+
meta: {
|
|
26
|
+
category: "general",
|
|
27
|
+
...options,
|
|
28
|
+
...isSetObject(meta) ? meta : { type: meta },
|
|
29
|
+
logId: uuid(),
|
|
30
|
+
timestamp: Date.now()
|
|
31
|
+
},
|
|
32
|
+
message
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const context = await PowerlinesExecutionContext.from({
|
|
36
|
+
...options,
|
|
37
|
+
logFn
|
|
38
|
+
}, inlineConfig ?? {}, { rpc });
|
|
39
|
+
context.logger.info(`Starting ${titleCase(options.framework?.name) || "Powerlines"} - ${titleCase(method)} execution (${options.executionId})`);
|
|
15
40
|
await resolvePluginConfig(context);
|
|
16
41
|
await fn(context);
|
|
17
42
|
}]));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-execution-host.mjs","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Powerlines\n\n This code was released as part of the Powerlines project. Powerlines\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/powerlines.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/powerlines\n Documentation: https://docs.stormsoftware.com/projects/powerlines\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { PowerlinesExecutionContext } from \"@powerlines/core/context/execution-context\";\nimport { resolvePluginConfig } from \"@powerlines/core/lib/context-helpers\";\nimport { ExecutionHostParams } from \"../types/api\";\nimport { EngineResolvedConfig } from \"../types/config\";\nimport { EngineSystemContext } from \"../types/context\";\n\n/**\n * Creates an execution host with the provided methods. Each method will be wrapped to create an execution context and handle errors appropriately.\n *\n * @param methods - An object where keys are method names and values are functions that take an execution context and return a promise.\n * @returns An object with the same keys as the input methods, but each function is wrapped to create an execution context and handle errors.\n */\nexport function createExecutionHost<\n TContext extends PowerlinesExecutionContext<\n EngineResolvedConfig,\n EngineSystemContext\n > = PowerlinesExecutionContext<EngineResolvedConfig, EngineSystemContext>\n>(methods: Record<string, (context: TContext) => Promise<void>>) {\n return Object.fromEntries(\n Object.entries(methods).map(([method, fn]) => [\n method,\n async (params: ExecutionHostParams) => {\n const
|
|
1
|
+
{"version":3,"file":"create-execution-host.mjs","names":[],"sources":["../../src/helpers/create-execution-host.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Powerlines\n\n This code was released as part of the Powerlines project. Powerlines\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/powerlines.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/powerlines\n Documentation: https://docs.stormsoftware.com/projects/powerlines\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { LogFnMeta } from \"@powerlines/core\";\nimport { PowerlinesExecutionContext } from \"@powerlines/core/context/execution-context\";\nimport { resolvePluginConfig } from \"@powerlines/core/lib/context-helpers\";\nimport { consoleLogger } from \"@powerlines/core/plugin-utils\";\nimport { titleCase } from \"@stryke/string-format/title-case\";\nimport { isSetObject } from \"@stryke/type-checks/is-set-object\";\nimport { uuid } from \"@stryke/unique-id/uuid\";\nimport { RpcClient } from \"../types\";\nimport { ExecutionHostParams } from \"../types/api\";\nimport { EngineResolvedConfig } from \"../types/config\";\nimport { EngineSystemContext } from \"../types/context\";\nimport { createRpcClient } from \"./rpc\";\n\n/**\n * Creates an execution host with the provided methods. Each method will be wrapped to create an execution context and handle errors appropriately.\n *\n * @param methods - An object where keys are method names and values are functions that take an execution context and return a promise.\n * @returns An object with the same keys as the input methods, but each function is wrapped to create an execution context and handle errors.\n */\nexport function createExecutionHost<\n TContext extends PowerlinesExecutionContext<\n EngineResolvedConfig,\n EngineSystemContext\n > = PowerlinesExecutionContext<EngineResolvedConfig, EngineSystemContext>\n>(methods: Record<string, (context: TContext) => Promise<void>>) {\n return Object.fromEntries(\n Object.entries(methods).map(([method, fn]) => [\n method,\n async (params: ExecutionHostParams) => {\n const { options, inlineConfig } = params;\n\n let rpc!: RpcClient;\n if (options.baseURL && options.connection) {\n rpc = createRpcClient(options);\n } else {\n throw new Error(\n `Execution RPC client could not be created - Missing ${\n !options.baseURL\n ? `baseURL${options.connection ? ` and connection information` : \"\"}`\n : \"connection\"\n } or connection information.`\n );\n }\n\n const logFn = (meta: LogFnMeta, message: string) => {\n consoleLogger(meta, message);\n if (rpc) {\n void rpc.callEvent(\"powerlines:log\", {\n meta: {\n category: \"general\",\n ...options,\n ...(isSetObject(meta) ? meta : { type: meta }),\n logId: uuid(),\n timestamp: Date.now()\n },\n message\n });\n }\n };\n\n const context = (await PowerlinesExecutionContext.from<\n EngineResolvedConfig,\n EngineSystemContext\n >({ ...options, logFn }, inlineConfig ?? {}, {\n rpc\n })) as TContext;\n\n context.logger.info(\n `Starting ${\n titleCase(options.framework?.name) || \"Powerlines\"\n } - ${titleCase(method)} execution (${options.executionId})`\n );\n\n await resolvePluginConfig(context as PowerlinesExecutionContext<any>);\n\n await fn(context);\n }\n ])\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;AAqCA,SAAgB,oBAKd,SAA+D;AAC/D,QAAO,OAAO,YACZ,OAAO,QAAQ,QAAQ,CAAC,KAAK,CAAC,QAAQ,QAAQ,CAC5C,QACA,OAAO,WAAgC;EACrC,MAAM,EAAE,SAAS,iBAAiB;EAElC,IAAI;AACJ,MAAI,QAAQ,WAAW,QAAQ,WAC7B,OAAM,gBAAgB,QAAQ;MAE9B,OAAM,IAAI,MACR,uDACE,CAAC,QAAQ,UACL,UAAU,QAAQ,aAAa,gCAAgC,OAC/D,aACL,6BACF;EAGH,MAAM,SAAS,MAAiB,YAAoB;AAClD,iBAAc,MAAM,QAAQ;AAC5B,OAAI,IACF,CAAK,IAAI,UAAU,kBAAkB;IACnC,MAAM;KACJ,UAAU;KACV,GAAG;KACH,GAAI,YAAY,KAAK,GAAG,OAAO,EAAE,MAAM,MAAM;KAC7C,OAAO,MAAM;KACb,WAAW,KAAK,KAAK;KACtB;IACD;IACD,CAAC;;EAIN,MAAM,UAAW,MAAM,2BAA2B,KAGhD;GAAE,GAAG;GAAS;GAAO,EAAE,gBAAgB,EAAE,EAAE,EAC3C,KACD,CAAC;AAEF,UAAQ,OAAO,KACb,YACE,UAAU,QAAQ,WAAW,KAAK,IAAI,aACvC,KAAK,UAAU,OAAO,CAAC,cAAc,QAAQ,YAAY,GAC3D;AAED,QAAM,oBAAoB,QAA2C;AAErE,QAAM,GAAG,QAAQ;GAEpB,CAAC,CACH"}
|
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_chunk = require('../chunk-C0xms8kb.cjs');
|
|
3
3
|
let _powerlines_core_lib_config = require("@powerlines/core/lib/config");
|
|
4
4
|
let _stryke_fs_resolve = require("@stryke/fs/resolve");
|
|
5
|
+
let _stryke_path_append = require("@stryke/path/append");
|
|
5
6
|
let _stryke_type_checks_is_number = require("@stryke/type-checks/is-number");
|
|
6
7
|
let _stryke_type_checks_is_set = require("@stryke/type-checks/is-set");
|
|
7
8
|
let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object");
|
|
@@ -65,7 +66,7 @@ var ExecutionHostWorker = class ExecutionHostWorker {
|
|
|
65
66
|
*/
|
|
66
67
|
static async from(executionHostPath, options) {
|
|
67
68
|
const mode = await (0, _powerlines_core_lib_config.getDefaultMode)(options.context.cwd);
|
|
68
|
-
const resolvedPath = await (0, _stryke_fs_resolve.resolve)(executionHostPath, { paths: [options.context.cwd] });
|
|
69
|
+
const resolvedPath = await (0, _stryke_fs_resolve.resolve)(executionHostPath, { paths: [options.context.cwd, options.root ? (0, _stryke_path_append.appendPath)(options.root, options.context.cwd) : void 0].filter(Boolean) });
|
|
69
70
|
if (!resolvedPath) throw new Error(`Could not resolve the provided Execution Host path: \`${executionHostPath}\`.`);
|
|
70
71
|
return new ExecutionHostWorker(resolvedPath, {
|
|
71
72
|
mode,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as EngineContext } from "../context-
|
|
2
|
-
import { n as ExecutionHost } from "../api-
|
|
1
|
+
import { t as EngineContext } from "../context-epL7NPvL.cjs";
|
|
2
|
+
import { n as ExecutionHost } from "../api-6w4hZL6n.cjs";
|
|
3
3
|
import { Mode } from "@powerlines/core";
|
|
4
4
|
import { Worker } from "jest-worker";
|
|
5
5
|
|
|
@@ -20,6 +20,10 @@ interface ExecutionHostWorkerOptions<TExecutionAPI extends ReadonlyArray<string>
|
|
|
20
20
|
* The mode to run the worker in, which can affect how the worker is initialized and how it behaves. This is determined based on the resolved configuration of the engine, and can be used to optimize the worker for different environments (e.g., development, production, etc.).
|
|
21
21
|
*/
|
|
22
22
|
mode?: Mode;
|
|
23
|
+
/**
|
|
24
|
+
* An optional root to resolve the execution host path from, which can be used to specify a custom root directory for the worker to use when resolving paths and loading configuration files. If this option is not provided, the worker will use the current working directory as the root directory by default.
|
|
25
|
+
*/
|
|
26
|
+
root?: string;
|
|
23
27
|
/**
|
|
24
28
|
* The context of the {@link @powerlines/engine#Engine | Engine instance}, which can be used to access the engine's state and services within the worker.
|
|
25
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-host-worker.d.cts","names":[],"sources":["../../src/helpers/execution-host-worker.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"execution-host-worker.d.cts","names":[],"sources":["../../src/helpers/execution-host-worker.ts"],"mappings":";;;;;;KAmDY,WAAA,GAAc,MAAA;AAAA,UAqDT,0BAAA,uBACO,aAAA;EAtDZ;;;;;EAuEV,OAAA;EAlByC;;;EAuBzC,cAAA;EAeS;;;EAVT,IAAA,GAAO,IAAA;EA3BP;;;EAgCA,IAAA;EALA;;;EAUA,OAAA,EAAS,aAAA;EAAA;;;EAKT,gBAAA,EAAkB,aAAA;AAAA;AAAA,cAGP,mBAAA,uBAA0C,aAAA;EAAA;YAyCzC,iBAAA;EAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA;EAAA;;;;;;;EAAA,OAhC5B,IAAA,uBAA2B,aAAA,SAAA,CAC7C,iBAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA,IAAc,OAAA,CAAA,aAAA,CAAA,aAAA;EA8BJ;;;;;;cADpC,iBAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA;EA1CK;;;;;EAkbxC,GAAA,CAAA,GAAO,UAAA,CAAW,MAAA;EAxaX;;;EAsbb,KAAA,CAAA;AAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as EngineContext } from "../context-
|
|
2
|
-
import { n as ExecutionHost } from "../api-
|
|
1
|
+
import { t as EngineContext } from "../context-S3XH2DWP.mjs";
|
|
2
|
+
import { n as ExecutionHost } from "../api-CcNgO71y.mjs";
|
|
3
3
|
import { Worker } from "jest-worker";
|
|
4
4
|
import { Mode } from "@powerlines/core";
|
|
5
5
|
|
|
@@ -20,6 +20,10 @@ interface ExecutionHostWorkerOptions<TExecutionAPI extends ReadonlyArray<string>
|
|
|
20
20
|
* The mode to run the worker in, which can affect how the worker is initialized and how it behaves. This is determined based on the resolved configuration of the engine, and can be used to optimize the worker for different environments (e.g., development, production, etc.).
|
|
21
21
|
*/
|
|
22
22
|
mode?: Mode;
|
|
23
|
+
/**
|
|
24
|
+
* An optional root to resolve the execution host path from, which can be used to specify a custom root directory for the worker to use when resolving paths and loading configuration files. If this option is not provided, the worker will use the current working directory as the root directory by default.
|
|
25
|
+
*/
|
|
26
|
+
root?: string;
|
|
23
27
|
/**
|
|
24
28
|
* The context of the {@link @powerlines/engine#Engine | Engine instance}, which can be used to access the engine's state and services within the worker.
|
|
25
29
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-host-worker.d.mts","names":[],"sources":["../../src/helpers/execution-host-worker.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"execution-host-worker.d.mts","names":[],"sources":["../../src/helpers/execution-host-worker.ts"],"mappings":";;;;;;KAmDY,WAAA,GAAc,MAAA;AAAA,UAqDT,0BAAA,uBACO,aAAA;EAtDZ;;;;;EAuEV,OAAA;EAlByC;;;EAuBzC,cAAA;EAeS;;;EAVT,IAAA,GAAO,IAAA;EA3BP;;;EAgCA,IAAA;EALA;;;EAUA,OAAA,EAAS,aAAA;EAAA;;;EAKT,gBAAA,EAAkB,aAAA;AAAA;AAAA,cAGP,mBAAA,uBAA0C,aAAA;EAAA;YAyCzC,iBAAA;EAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA;EAAA;;;;;;;EAAA,OAhC5B,IAAA,uBAA2B,aAAA,SAAA,CAC7C,iBAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA,IAAc,OAAA,CAAA,aAAA,CAAA,aAAA;EA8BJ;;;;;;cADpC,iBAAA,UACA,OAAA,EAAS,0BAAA,CAA2B,aAAA;EA1CK;;;;;EAkbxC,GAAA,CAAA,GAAO,UAAA,CAAW,MAAA;EAxaX;;;EAsbb,KAAA,CAAA;AAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getDefaultMode } from "@powerlines/core/lib/config";
|
|
2
2
|
import { resolve } from "@stryke/fs/resolve";
|
|
3
|
+
import { appendPath } from "@stryke/path/append";
|
|
3
4
|
import { isNumber } from "@stryke/type-checks/is-number";
|
|
4
5
|
import { isSet } from "@stryke/type-checks/is-set";
|
|
5
6
|
import { isSetObject } from "@stryke/type-checks/is-set-object";
|
|
@@ -63,7 +64,7 @@ var ExecutionHostWorker = class ExecutionHostWorker {
|
|
|
63
64
|
*/
|
|
64
65
|
static async from(executionHostPath, options) {
|
|
65
66
|
const mode = await getDefaultMode(options.context.cwd);
|
|
66
|
-
const resolvedPath = await resolve(executionHostPath, { paths: [options.context.cwd] });
|
|
67
|
+
const resolvedPath = await resolve(executionHostPath, { paths: [options.context.cwd, options.root ? appendPath(options.root, options.context.cwd) : void 0].filter(Boolean) });
|
|
67
68
|
if (!resolvedPath) throw new Error(`Could not resolve the provided Execution Host path: \`${executionHostPath}\`.`);
|
|
68
69
|
return new ExecutionHostWorker(resolvedPath, {
|
|
69
70
|
mode,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution-host-worker.mjs","names":["#worker","JestWorker"],"sources":["../../src/helpers/execution-host-worker.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Powerlines\n\n This code was released as part of the Powerlines project. Powerlines\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/powerlines.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/powerlines\n Documentation: https://docs.stormsoftware.com/projects/powerlines\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { Mode } from \"@powerlines/core\";\nimport { getDefaultMode } from \"@powerlines/core/lib/config\";\nimport { resolve } from \"@stryke/fs/resolve\";\nimport { isNumber } from \"@stryke/type-checks/is-number\";\nimport { isSet } from \"@stryke/type-checks/is-set\";\nimport { isSetObject } from \"@stryke/type-checks/is-set-object\";\nimport { isString } from \"@stryke/type-checks/is-string\";\nimport { formatDuration } from \"date-fns/formatDuration\";\nimport { Worker as JestWorker } from \"jest-worker\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { Transform } from \"node:stream\";\nimport { parseArgs } from \"node:util\";\nimport { ExecutionHost, ExecutionHostParams } from \"../types/api\";\nimport { EngineContext } from \"../types/context\";\n\nconst RESTARTED = Symbol(\"powerlines-worker:restarted\");\n\n/**\n * The debug address is in the form of `[host:]port`. The host is optional.\n */\ninterface DebugAddress {\n host?: string;\n port: number;\n}\n\n/**\n * Formats the debug address into a string.\n */\nconst formatDebugAddress = ({ host, port }: DebugAddress): string => {\n return host ? `${host}:${port}` : `${port}`;\n};\n\nexport type NodeOptions = Record<string, string | boolean | undefined>;\n\n/**\n * Get's the debug address from the `NODE_OPTIONS` environment variable. If the\n * address is not found, it returns the default host (`undefined`) and port\n * (`9229`).\n *\n * @returns An object with the host and port of the debug address.\n */\nconst getParsedDebugAddress = (\n address: string | boolean | undefined\n): DebugAddress => {\n if (!address || !isString(address)) {\n return { host: undefined, port: 9229 };\n }\n\n // The address is in the form of `[host:]port`. Let's parse the address.\n if (address.includes(\":\")) {\n const [host, port] = address.split(\":\");\n if (!host || !port) {\n throw new Error(`Invalid debug address: ${address}`);\n }\n\n return { host, port: Number.parseInt(port, 10) };\n }\n\n return { host: undefined, port: Number.parseInt(address, 10) };\n};\n\ntype NodeInspectType = \"inspect\" | \"inspect-brk\" | undefined;\n\n/**\n * Get the debug type from the `NODE_OPTIONS` environment variable.\n */\nfunction getNodeDebugType(nodeOptions: NodeOptions): NodeInspectType {\n if (nodeOptions.inspect) {\n return \"inspect\";\n }\n if (nodeOptions[\"inspect-brk\"] || nodeOptions.inspect_brk) {\n return \"inspect-brk\";\n }\n\n return undefined;\n}\n\nconst cleanupWorkers = (worker: JestWorker) => {\n for (const curWorker of ((worker as any)._workerPool?._workers || []) as {\n _child?: ChildProcess;\n }[]) {\n curWorker._child?.kill(\"SIGINT\");\n }\n};\n\nexport interface ExecutionHostWorkerOptions<\n TExecutionAPI extends ReadonlyArray<string>\n> {\n // /**\n // * `-1` if not inspectable\n // */\n // debuggerPortOffset?: number;\n\n // /**\n // * Whether to enable source maps support in the worker, which can improve the quality of stack traces at the cost of increased memory usage and slower performance. Defaults to `false`.\n // */\n // enableSourceMaps?: boolean;\n\n /**\n * The maximum time in milliseconds a worker can run before being terminated.\n *\n * @defaultValue 900000 (15 minutes)\n */\n timeout?: number;\n\n /**\n * True if `--max-old-space-size` should not be forwarded to the worker.\n */\n isolatedMemory?: boolean;\n\n /**\n * The mode to run the worker in, which can affect how the worker is initialized and how it behaves. This is determined based on the resolved configuration of the engine, and can be used to optimize the worker for different environments (e.g., development, production, etc.).\n */\n mode?: Mode;\n\n /**\n * The context of the {@link @powerlines/engine#Engine | Engine instance}, which can be used to access the engine's state and services within the worker.\n */\n context: EngineContext;\n\n /**\n * An array of method names that the worker exposes. These methods will be available on the Worker instance and can be called to execute tasks in the worker process.\n */\n executionMethods: TExecutionAPI;\n}\n\nexport class ExecutionHostWorker<TExecutionAPI extends ReadonlyArray<string>> {\n #worker: JestWorker | undefined;\n\n /**\n * Creates a new instance of the ExecutionHostWorker class, which manages a worker process for executing tasks related to the Powerlines Engine. The worker is initialized with the specified options and can be used to run tasks in an isolated environment, with support for automatic restarts and activity monitoring.\n *\n * @param executionHostPath - The path to the Execution Host file.\n * @param options - The options for configuring the worker, including the execution context, exposed methods, timeout, and mode.\n * @returns A promise that resolves to an instance of the ExecutionHostWorker class.\n */\n public static async from<TExecutionAPI extends ReadonlyArray<string>>(\n executionHostPath: string,\n options: ExecutionHostWorkerOptions<TExecutionAPI>\n ) {\n const mode = await getDefaultMode(options.context.cwd);\n\n const resolvedPath = await resolve(executionHostPath, {\n paths: [options.context.cwd]\n });\n if (!resolvedPath) {\n throw new Error(\n `Could not resolve the provided Execution Host path: \\`${executionHostPath}\\`.`\n );\n }\n\n return new ExecutionHostWorker<TExecutionAPI>(resolvedPath, {\n mode,\n ...options\n }) as unknown as ExecutionHost<TExecutionAPI>;\n }\n\n /**\n * Create a new worker instance.\n *\n * @param executionHostPath - The path to the worker file.\n * @param options - The options for the worker, including exposed methods, timeout, and hooks for activity and restart.\n */\n public constructor(\n protected executionHostPath: string,\n protected options: ExecutionHostWorkerOptions<TExecutionAPI>\n ) {\n const {\n timeout = 900_000,\n isolatedMemory = false,\n mode = \"production\",\n context,\n executionMethods\n } = this.options;\n\n const logger = context.extendLogger({ category: \"communication\" });\n\n let restartPromise: Promise<typeof RESTARTED>;\n let resolveRestartPromise: (arg: typeof RESTARTED) => void;\n let activeTasks = 0;\n\n this.#worker = undefined;\n\n // ensure we end workers if they weren't before exit\n process.on(\"exit\", () => {\n this.close();\n });\n\n let nodeOptions = {} as {\n [longOption: string]: string | boolean | undefined;\n };\n\n const args: string[] = [...process.execArgv];\n if (process.env.NODE_OPTIONS) {\n let isInString = false;\n let willStartNewArg = true;\n for (let i = 0; i < process.env.NODE_OPTIONS.length; i++) {\n let char = process.env.NODE_OPTIONS[i];\n if (char) {\n // Skip any escaped characters in strings.\n if (char === \"\\\\\" && isInString) {\n // Ensure we don't have an escape character at the end.\n if (process.env.NODE_OPTIONS.length === i + 1) {\n throw new Error(\"Invalid escape character at the end.\");\n }\n\n // Skip the next character.\n char = process.env.NODE_OPTIONS[++i];\n if (!char) {\n continue;\n }\n }\n // If we find a space outside of a string, we should start a new argument.\n else if (char === \" \" && !isInString) {\n willStartNewArg = true;\n continue;\n }\n\n // If we find a quote, we should toggle the string flag.\n else if (char === '\"') {\n isInString = !isInString;\n continue;\n }\n\n // If we're starting a new argument, we should add it to the array.\n if (willStartNewArg) {\n args.push(char);\n willStartNewArg = false;\n }\n // Otherwise, add it to the last argument.\n else {\n args[args.length - 1] += char;\n }\n }\n }\n\n if (isInString) {\n throw new Error(\"Unterminated string\");\n }\n }\n\n if (args.length > 0) {\n const { values, tokens } = parseArgs({\n args,\n strict: false,\n tokens: true\n });\n nodeOptions = values;\n\n // For the `NODE_OPTIONS`, we support arguments with values without the `=`\n // sign. We need to parse them manually.\n let orphan = null;\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token) continue;\n\n if (token.kind === \"option-terminator\") {\n break;\n }\n\n // When we encounter an option, if it's value is undefined, we should check\n // to see if the following tokens are positional parameters. If they are,\n // then the option is orphaned, and we can assign it.\n if (token.kind === \"option\") {\n orphan = !isSet(token.value) ? token : null;\n continue;\n }\n\n // If the token isn't a positional one, then we can't assign it to the found\n // orphaned option.\n if (token.kind !== \"positional\") {\n orphan = null;\n continue;\n }\n\n // If we don't have an orphan, then we can skip this token.\n if (!orphan) {\n continue;\n }\n\n // If the token is a positional one, and it has a value, so add it to the\n // values object. If it already exists, append it with a space.\n if (orphan.name in nodeOptions && isString(nodeOptions[orphan.name])) {\n nodeOptions[orphan.name] += ` ${token.value}`;\n } else {\n nodeOptions[orphan.name] = token.value;\n }\n }\n }\n\n const originalOptions = { ...nodeOptions };\n\n delete nodeOptions.inspect;\n delete nodeOptions[\"inspect-brk\"];\n delete nodeOptions.inspect_brk;\n\n if (mode === \"development\") {\n const nodeDebugType = getNodeDebugType(originalOptions);\n if (nodeDebugType) {\n const debuggerAddress = getParsedDebugAddress(\n originalOptions[nodeDebugType]\n );\n const address: DebugAddress = {\n host: debuggerAddress.host,\n // current process runs on `address.port`\n port: debuggerAddress.port === 0 ? 0 : debuggerAddress.port + 1 + 1\n };\n nodeOptions[nodeDebugType] = formatDebugAddress(address);\n }\n\n nodeOptions[\"enable-source-maps\"] = true;\n }\n\n if (isolatedMemory) {\n delete nodeOptions[\"max-old-space-size\"];\n delete nodeOptions.max_old_space_size;\n }\n\n const execArgv: string[] = [];\n const nodeOptionsParts: string[] = [];\n for (const [key, value] of Object.entries(nodeOptions)) {\n let formatted: string | null = null;\n if (value === true) {\n formatted = `--${key}`;\n } else if (value) {\n formatted = `--${key}=${\n // Values with spaces need to be quoted. We use JSON.stringify to\n // also escape any nested quotes.\n value.includes(\" \") && !value.startsWith('\"')\n ? JSON.stringify(value)\n : value\n }`;\n }\n\n if (formatted === null) {\n continue;\n }\n\n if (\n [\n \"experimental-network-inspection\",\n \"experimental-storage-inspection\",\n \"experimental-worker-inspection\",\n \"experimental-inspector-network-resource\"\n ].includes(key)\n ) {\n execArgv.push(formatted);\n } else {\n nodeOptionsParts.push(formatted);\n }\n }\n\n const onHanging = () => {\n const worker = this.#worker;\n if (!worker) {\n return;\n }\n\n const resolve = resolveRestartPromise;\n // eslint-disable-next-line ts/no-use-before-define\n createWorker();\n\n logger.warn(\n `Sending SIGTERM signal to worker due to timeout${\n timeout ? ` of ${formatDuration({ seconds: timeout / 1000 })}` : \"\"\n }. Subsequent errors may be a result of the worker exiting.`\n );\n\n void worker.end().then(() => {\n resolve(RESTARTED);\n });\n };\n\n let hangingTimer: NodeJS.Timeout | false = false;\n\n const onActivity = () => {\n if (hangingTimer) {\n clearTimeout(hangingTimer);\n }\n\n hangingTimer = activeTasks > 0 && setTimeout(onHanging, timeout);\n };\n\n const createWorker = () => {\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n NODE_ENV: mode,\n NODE_OPTIONS: nodeOptionsParts.join(\" \"),\n POWERLINES_EXECUTION_HOST_WORKER: \"true\"\n };\n\n if (env.FORCE_COLOR === undefined) {\n // Mirror the enablement heuristic from picocolors (see https://github.com/vercel/next.js/blob/6a40da0345939fe4f7b1ae519b296a86dd103432/packages/next/src/lib/picocolors.ts#L21-L24).\n // Picocolors snapshots `process.env`/`stdout.isTTY` at module load time, so when the worker\n // process bootstraps with piped stdio its own check would disable colors. Re-evaluating the\n // same conditions here lets us opt the worker into color output only when the parent would\n // have seen colors, while still respecting explicit opt-outs like NO_COLOR.\n const supportsColors =\n !env.NO_COLOR &&\n !env.CI &&\n env.TERM !== \"dumb\" &&\n (process.stdout.isTTY || process.stderr?.isTTY);\n\n if (supportsColors) {\n env.FORCE_COLOR = \"1\";\n }\n }\n\n this.#worker = new JestWorker(executionHostPath, {\n maxRetries: 0,\n computeWorkerKey: (_, ...args: Array<unknown>) => {\n let executionId = \"default\";\n let configIndex = 0;\n if (args.length > 0 && isSetObject(args[0])) {\n const arg = args[0] as ExecutionHostParams;\n if (isSetObject(arg.options)) {\n configIndex = arg.options.configIndex ?? 0;\n executionId = arg.options.executionId || \"default\";\n }\n }\n\n return `${executionId}-${configIndex}`;\n },\n forkOptions: {\n execArgv,\n env\n }\n });\n restartPromise = new Promise(resolve => {\n resolveRestartPromise = resolve;\n });\n\n for (const worker of ((this.#worker as any)._workerPool?._workers ||\n []) as {\n _child?: ChildProcess;\n }[]) {\n worker._child?.on(\"exit\", (code, signal) => {\n logger.debug(\n `Worker process exited with code ${code} and signal ${signal}`\n );\n\n if ((code || (signal && signal !== \"SIGINT\")) && this.#worker) {\n const error = new Error(\n `Execution Host Worker exited unexpectedly with code ${\n code\n } and signal ${signal}`\n );\n logger.error(error);\n\n throw error;\n }\n });\n\n worker._child?.on(\"error\", error => {\n logger.error({\n meta: { category: \"communication\" },\n message: `Worker process emitted an error: ${error.message}`,\n error\n });\n });\n\n // if a child process emits a particular message, we track that as activity\n // so the parent process can keep track of progress\n worker._child?.on(\"message\", data => {\n onActivity();\n\n if (Array.isArray(data) && data.length > 1 && isNumber(data[0])) {\n if (data[0] === 0) {\n logger.trace(\n `Received message from worker: ${JSON.stringify(data.slice(1), null, 2)}`\n );\n } else {\n logger.debug(\n `Received error message from worker: ${JSON.stringify(\n data.slice(1),\n null,\n 2\n )}`\n );\n }\n }\n\n logger.trace(\n `Received message from worker: ${JSON.stringify(data, null, 2)}`\n );\n });\n }\n\n let aborted = false;\n const onActivityAbort = () => {\n if (!aborted) {\n aborted = true;\n }\n };\n\n // Listen to the worker's stdout and stderr, if there's any thing logged, abort the activity first\n const abortActivityStreamOnLog = new Transform({\n transform(_chunk, _encoding, callback) {\n onActivityAbort();\n callback();\n }\n });\n // Stop the activity if there's any output from the worker\n this.#worker.getStdout().pipe(abortActivityStreamOnLog);\n this.#worker.getStderr().pipe(abortActivityStreamOnLog);\n\n // Pipe the worker's stdout and stderr to the parent process\n this.#worker.getStdout().pipe(process.stdout);\n this.#worker.getStderr().pipe(process.stderr);\n };\n createWorker();\n\n for (const method of executionMethods) {\n if (method.startsWith(\"_\")) {\n continue;\n }\n\n (this as any)[method] = timeout\n ? async (...args: any[]) => {\n activeTasks++;\n try {\n let attempts = 0;\n for (;;) {\n onActivity();\n\n const result = await Promise.race([\n // eslint-disable-next-line ts/no-unsafe-call\n (this.#worker as any)[method](\n args.length > 0 && args[0] ? args[0] : {}\n ),\n restartPromise\n ]);\n if (result !== RESTARTED) {\n return result;\n }\n\n logger.warn(\n `Execution Host Worker was restarted while calling method \"${\n method\n }\" (attempt ${attempts++}). Retrying the call...`\n );\n }\n } finally {\n activeTasks--;\n onActivity();\n }\n }\n : // eslint-disable-next-line ts/no-unsafe-call\n (this.#worker as any)[method].bind(this.#worker);\n }\n }\n\n /**\n * Ends the worker process and cleans up any resources associated with it. This method should be called when the worker is no longer needed, to ensure that it is properly terminated and does not continue to consume system resources. If the worker is already terminated or was never initialized, this method will throw an error.\n *\n * @returns A promise that resolves when the worker has been successfully terminated.\n */\n public async end(): ReturnType<JestWorker[\"end\"]> {\n const worker = this.#worker;\n if (!worker) {\n throw new Error(\"Execution Host Worker is not initialized\");\n }\n\n cleanupWorkers(worker);\n this.#worker = undefined;\n return worker.end();\n }\n\n /**\n * Quietly end the worker if it exists\n */\n public close(): void {\n if (this.#worker) {\n cleanupWorkers(this.#worker);\n void this.#worker.end();\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"execution-host-worker.mjs","names":["#worker","JestWorker"],"sources":["../../src/helpers/execution-host-worker.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Powerlines\n\n This code was released as part of the Powerlines project. Powerlines\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/powerlines.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/powerlines\n Documentation: https://docs.stormsoftware.com/projects/powerlines\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { Mode } from \"@powerlines/core\";\nimport { getDefaultMode } from \"@powerlines/core/lib/config\";\nimport { resolve } from \"@stryke/fs/resolve\";\nimport { appendPath } from \"@stryke/path/append\";\nimport { isNumber } from \"@stryke/type-checks/is-number\";\nimport { isSet } from \"@stryke/type-checks/is-set\";\nimport { isSetObject } from \"@stryke/type-checks/is-set-object\";\nimport { isString } from \"@stryke/type-checks/is-string\";\nimport { formatDuration } from \"date-fns/formatDuration\";\nimport { Worker as JestWorker } from \"jest-worker\";\nimport type { ChildProcess } from \"node:child_process\";\nimport { Transform } from \"node:stream\";\nimport { parseArgs } from \"node:util\";\nimport { ExecutionHost, ExecutionHostParams } from \"../types/api\";\nimport { EngineContext } from \"../types/context\";\n\nconst RESTARTED = Symbol(\"powerlines-worker:restarted\");\n\n/**\n * The debug address is in the form of `[host:]port`. The host is optional.\n */\ninterface DebugAddress {\n host?: string;\n port: number;\n}\n\n/**\n * Formats the debug address into a string.\n */\nconst formatDebugAddress = ({ host, port }: DebugAddress): string => {\n return host ? `${host}:${port}` : `${port}`;\n};\n\nexport type NodeOptions = Record<string, string | boolean | undefined>;\n\n/**\n * Get's the debug address from the `NODE_OPTIONS` environment variable. If the\n * address is not found, it returns the default host (`undefined`) and port\n * (`9229`).\n *\n * @returns An object with the host and port of the debug address.\n */\nconst getParsedDebugAddress = (\n address: string | boolean | undefined\n): DebugAddress => {\n if (!address || !isString(address)) {\n return { host: undefined, port: 9229 };\n }\n\n // The address is in the form of `[host:]port`. Let's parse the address.\n if (address.includes(\":\")) {\n const [host, port] = address.split(\":\");\n if (!host || !port) {\n throw new Error(`Invalid debug address: ${address}`);\n }\n\n return { host, port: Number.parseInt(port, 10) };\n }\n\n return { host: undefined, port: Number.parseInt(address, 10) };\n};\n\ntype NodeInspectType = \"inspect\" | \"inspect-brk\" | undefined;\n\n/**\n * Get the debug type from the `NODE_OPTIONS` environment variable.\n */\nfunction getNodeDebugType(nodeOptions: NodeOptions): NodeInspectType {\n if (nodeOptions.inspect) {\n return \"inspect\";\n }\n if (nodeOptions[\"inspect-brk\"] || nodeOptions.inspect_brk) {\n return \"inspect-brk\";\n }\n\n return undefined;\n}\n\nconst cleanupWorkers = (worker: JestWorker) => {\n for (const curWorker of ((worker as any)._workerPool?._workers || []) as {\n _child?: ChildProcess;\n }[]) {\n curWorker._child?.kill(\"SIGINT\");\n }\n};\n\nexport interface ExecutionHostWorkerOptions<\n TExecutionAPI extends ReadonlyArray<string>\n> {\n // /**\n // * `-1` if not inspectable\n // */\n // debuggerPortOffset?: number;\n\n // /**\n // * Whether to enable source maps support in the worker, which can improve the quality of stack traces at the cost of increased memory usage and slower performance. Defaults to `false`.\n // */\n // enableSourceMaps?: boolean;\n\n /**\n * The maximum time in milliseconds a worker can run before being terminated.\n *\n * @defaultValue 900000 (15 minutes)\n */\n timeout?: number;\n\n /**\n * True if `--max-old-space-size` should not be forwarded to the worker.\n */\n isolatedMemory?: boolean;\n\n /**\n * The mode to run the worker in, which can affect how the worker is initialized and how it behaves. This is determined based on the resolved configuration of the engine, and can be used to optimize the worker for different environments (e.g., development, production, etc.).\n */\n mode?: Mode;\n\n /**\n * An optional root to resolve the execution host path from, which can be used to specify a custom root directory for the worker to use when resolving paths and loading configuration files. If this option is not provided, the worker will use the current working directory as the root directory by default.\n */\n root?: string;\n\n /**\n * The context of the {@link @powerlines/engine#Engine | Engine instance}, which can be used to access the engine's state and services within the worker.\n */\n context: EngineContext;\n\n /**\n * An array of method names that the worker exposes. These methods will be available on the Worker instance and can be called to execute tasks in the worker process.\n */\n executionMethods: TExecutionAPI;\n}\n\nexport class ExecutionHostWorker<TExecutionAPI extends ReadonlyArray<string>> {\n #worker: JestWorker | undefined;\n\n /**\n * Creates a new instance of the ExecutionHostWorker class, which manages a worker process for executing tasks related to the Powerlines Engine. The worker is initialized with the specified options and can be used to run tasks in an isolated environment, with support for automatic restarts and activity monitoring.\n *\n * @param executionHostPath - The path to the Execution Host file.\n * @param options - The options for configuring the worker, including the execution context, exposed methods, timeout, and mode.\n * @returns A promise that resolves to an instance of the ExecutionHostWorker class.\n */\n public static async from<TExecutionAPI extends ReadonlyArray<string>>(\n executionHostPath: string,\n options: ExecutionHostWorkerOptions<TExecutionAPI>\n ) {\n const mode = await getDefaultMode(options.context.cwd);\n\n const resolvedPath = await resolve(executionHostPath, {\n paths: [\n options.context.cwd,\n options.root ? appendPath(options.root, options.context.cwd) : undefined\n ].filter(Boolean) as string[]\n });\n if (!resolvedPath) {\n throw new Error(\n `Could not resolve the provided Execution Host path: \\`${executionHostPath}\\`.`\n );\n }\n\n return new ExecutionHostWorker<TExecutionAPI>(resolvedPath, {\n mode,\n ...options\n }) as unknown as ExecutionHost<TExecutionAPI>;\n }\n\n /**\n * Create a new worker instance.\n *\n * @param executionHostPath - The path to the worker file.\n * @param options - The options for the worker, including exposed methods, timeout, and hooks for activity and restart.\n */\n public constructor(\n protected executionHostPath: string,\n protected options: ExecutionHostWorkerOptions<TExecutionAPI>\n ) {\n const {\n timeout = 900_000,\n isolatedMemory = false,\n mode = \"production\",\n context,\n executionMethods\n } = this.options;\n\n const logger = context.extendLogger({ category: \"communication\" });\n\n let restartPromise: Promise<typeof RESTARTED>;\n let resolveRestartPromise: (arg: typeof RESTARTED) => void;\n let activeTasks = 0;\n\n this.#worker = undefined;\n\n // ensure we end workers if they weren't before exit\n process.on(\"exit\", () => {\n this.close();\n });\n\n let nodeOptions = {} as {\n [longOption: string]: string | boolean | undefined;\n };\n\n const args: string[] = [...process.execArgv];\n if (process.env.NODE_OPTIONS) {\n let isInString = false;\n let willStartNewArg = true;\n for (let i = 0; i < process.env.NODE_OPTIONS.length; i++) {\n let char = process.env.NODE_OPTIONS[i];\n if (char) {\n // Skip any escaped characters in strings.\n if (char === \"\\\\\" && isInString) {\n // Ensure we don't have an escape character at the end.\n if (process.env.NODE_OPTIONS.length === i + 1) {\n throw new Error(\"Invalid escape character at the end.\");\n }\n\n // Skip the next character.\n char = process.env.NODE_OPTIONS[++i];\n if (!char) {\n continue;\n }\n }\n // If we find a space outside of a string, we should start a new argument.\n else if (char === \" \" && !isInString) {\n willStartNewArg = true;\n continue;\n }\n\n // If we find a quote, we should toggle the string flag.\n else if (char === '\"') {\n isInString = !isInString;\n continue;\n }\n\n // If we're starting a new argument, we should add it to the array.\n if (willStartNewArg) {\n args.push(char);\n willStartNewArg = false;\n }\n // Otherwise, add it to the last argument.\n else {\n args[args.length - 1] += char;\n }\n }\n }\n\n if (isInString) {\n throw new Error(\"Unterminated string\");\n }\n }\n\n if (args.length > 0) {\n const { values, tokens } = parseArgs({\n args,\n strict: false,\n tokens: true\n });\n nodeOptions = values;\n\n // For the `NODE_OPTIONS`, we support arguments with values without the `=`\n // sign. We need to parse them manually.\n let orphan = null;\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (!token) continue;\n\n if (token.kind === \"option-terminator\") {\n break;\n }\n\n // When we encounter an option, if it's value is undefined, we should check\n // to see if the following tokens are positional parameters. If they are,\n // then the option is orphaned, and we can assign it.\n if (token.kind === \"option\") {\n orphan = !isSet(token.value) ? token : null;\n continue;\n }\n\n // If the token isn't a positional one, then we can't assign it to the found\n // orphaned option.\n if (token.kind !== \"positional\") {\n orphan = null;\n continue;\n }\n\n // If we don't have an orphan, then we can skip this token.\n if (!orphan) {\n continue;\n }\n\n // If the token is a positional one, and it has a value, so add it to the\n // values object. If it already exists, append it with a space.\n if (orphan.name in nodeOptions && isString(nodeOptions[orphan.name])) {\n nodeOptions[orphan.name] += ` ${token.value}`;\n } else {\n nodeOptions[orphan.name] = token.value;\n }\n }\n }\n\n const originalOptions = { ...nodeOptions };\n\n delete nodeOptions.inspect;\n delete nodeOptions[\"inspect-brk\"];\n delete nodeOptions.inspect_brk;\n\n if (mode === \"development\") {\n const nodeDebugType = getNodeDebugType(originalOptions);\n if (nodeDebugType) {\n const debuggerAddress = getParsedDebugAddress(\n originalOptions[nodeDebugType]\n );\n const address: DebugAddress = {\n host: debuggerAddress.host,\n // current process runs on `address.port`\n port: debuggerAddress.port === 0 ? 0 : debuggerAddress.port + 1 + 1\n };\n nodeOptions[nodeDebugType] = formatDebugAddress(address);\n }\n\n nodeOptions[\"enable-source-maps\"] = true;\n }\n\n if (isolatedMemory) {\n delete nodeOptions[\"max-old-space-size\"];\n delete nodeOptions.max_old_space_size;\n }\n\n const execArgv: string[] = [];\n const nodeOptionsParts: string[] = [];\n for (const [key, value] of Object.entries(nodeOptions)) {\n let formatted: string | null = null;\n if (value === true) {\n formatted = `--${key}`;\n } else if (value) {\n formatted = `--${key}=${\n // Values with spaces need to be quoted. We use JSON.stringify to\n // also escape any nested quotes.\n value.includes(\" \") && !value.startsWith('\"')\n ? JSON.stringify(value)\n : value\n }`;\n }\n\n if (formatted === null) {\n continue;\n }\n\n if (\n [\n \"experimental-network-inspection\",\n \"experimental-storage-inspection\",\n \"experimental-worker-inspection\",\n \"experimental-inspector-network-resource\"\n ].includes(key)\n ) {\n execArgv.push(formatted);\n } else {\n nodeOptionsParts.push(formatted);\n }\n }\n\n const onHanging = () => {\n const worker = this.#worker;\n if (!worker) {\n return;\n }\n\n const resolve = resolveRestartPromise;\n // eslint-disable-next-line ts/no-use-before-define\n createWorker();\n\n logger.warn(\n `Sending SIGTERM signal to worker due to timeout${\n timeout ? ` of ${formatDuration({ seconds: timeout / 1000 })}` : \"\"\n }. Subsequent errors may be a result of the worker exiting.`\n );\n\n void worker.end().then(() => {\n resolve(RESTARTED);\n });\n };\n\n let hangingTimer: NodeJS.Timeout | false = false;\n\n const onActivity = () => {\n if (hangingTimer) {\n clearTimeout(hangingTimer);\n }\n\n hangingTimer = activeTasks > 0 && setTimeout(onHanging, timeout);\n };\n\n const createWorker = () => {\n const env: NodeJS.ProcessEnv = {\n ...process.env,\n NODE_ENV: mode,\n NODE_OPTIONS: nodeOptionsParts.join(\" \"),\n POWERLINES_EXECUTION_HOST_WORKER: \"true\"\n };\n\n if (env.FORCE_COLOR === undefined) {\n // Mirror the enablement heuristic from picocolors (see https://github.com/vercel/next.js/blob/6a40da0345939fe4f7b1ae519b296a86dd103432/packages/next/src/lib/picocolors.ts#L21-L24).\n // Picocolors snapshots `process.env`/`stdout.isTTY` at module load time, so when the worker\n // process bootstraps with piped stdio its own check would disable colors. Re-evaluating the\n // same conditions here lets us opt the worker into color output only when the parent would\n // have seen colors, while still respecting explicit opt-outs like NO_COLOR.\n const supportsColors =\n !env.NO_COLOR &&\n !env.CI &&\n env.TERM !== \"dumb\" &&\n (process.stdout.isTTY || process.stderr?.isTTY);\n\n if (supportsColors) {\n env.FORCE_COLOR = \"1\";\n }\n }\n\n this.#worker = new JestWorker(executionHostPath, {\n maxRetries: 0,\n computeWorkerKey: (_, ...args: Array<unknown>) => {\n let executionId = \"default\";\n let configIndex = 0;\n if (args.length > 0 && isSetObject(args[0])) {\n const arg = args[0] as ExecutionHostParams;\n if (isSetObject(arg.options)) {\n configIndex = arg.options.configIndex ?? 0;\n executionId = arg.options.executionId || \"default\";\n }\n }\n\n return `${executionId}-${configIndex}`;\n },\n forkOptions: {\n execArgv,\n env\n }\n });\n restartPromise = new Promise(resolve => {\n resolveRestartPromise = resolve;\n });\n\n for (const worker of ((this.#worker as any)._workerPool?._workers ||\n []) as {\n _child?: ChildProcess;\n }[]) {\n worker._child?.on(\"exit\", (code, signal) => {\n logger.debug(\n `Worker process exited with code ${code} and signal ${signal}`\n );\n\n if ((code || (signal && signal !== \"SIGINT\")) && this.#worker) {\n const error = new Error(\n `Execution Host Worker exited unexpectedly with code ${\n code\n } and signal ${signal}`\n );\n logger.error(error);\n\n throw error;\n }\n });\n\n worker._child?.on(\"error\", error => {\n logger.error({\n meta: { category: \"communication\" },\n message: `Worker process emitted an error: ${error.message}`,\n error\n });\n });\n\n // if a child process emits a particular message, we track that as activity\n // so the parent process can keep track of progress\n worker._child?.on(\"message\", data => {\n onActivity();\n\n if (Array.isArray(data) && data.length > 1 && isNumber(data[0])) {\n if (data[0] === 0) {\n logger.trace(\n `Received message from worker: ${JSON.stringify(data.slice(1), null, 2)}`\n );\n } else {\n logger.debug(\n `Received error message from worker: ${JSON.stringify(\n data.slice(1),\n null,\n 2\n )}`\n );\n }\n }\n\n logger.trace(\n `Received message from worker: ${JSON.stringify(data, null, 2)}`\n );\n });\n }\n\n let aborted = false;\n const onActivityAbort = () => {\n if (!aborted) {\n aborted = true;\n }\n };\n\n // Listen to the worker's stdout and stderr, if there's any thing logged, abort the activity first\n const abortActivityStreamOnLog = new Transform({\n transform(_chunk, _encoding, callback) {\n onActivityAbort();\n callback();\n }\n });\n // Stop the activity if there's any output from the worker\n this.#worker.getStdout().pipe(abortActivityStreamOnLog);\n this.#worker.getStderr().pipe(abortActivityStreamOnLog);\n\n // Pipe the worker's stdout and stderr to the parent process\n this.#worker.getStdout().pipe(process.stdout);\n this.#worker.getStderr().pipe(process.stderr);\n };\n createWorker();\n\n for (const method of executionMethods) {\n if (method.startsWith(\"_\")) {\n continue;\n }\n\n (this as any)[method] = timeout\n ? async (...args: any[]) => {\n activeTasks++;\n try {\n let attempts = 0;\n for (;;) {\n onActivity();\n\n const result = await Promise.race([\n // eslint-disable-next-line ts/no-unsafe-call\n (this.#worker as any)[method](\n args.length > 0 && args[0] ? args[0] : {}\n ),\n restartPromise\n ]);\n if (result !== RESTARTED) {\n return result;\n }\n\n logger.warn(\n `Execution Host Worker was restarted while calling method \"${\n method\n }\" (attempt ${attempts++}). Retrying the call...`\n );\n }\n } finally {\n activeTasks--;\n onActivity();\n }\n }\n : // eslint-disable-next-line ts/no-unsafe-call\n (this.#worker as any)[method].bind(this.#worker);\n }\n }\n\n /**\n * Ends the worker process and cleans up any resources associated with it. This method should be called when the worker is no longer needed, to ensure that it is properly terminated and does not continue to consume system resources. If the worker is already terminated or was never initialized, this method will throw an error.\n *\n * @returns A promise that resolves when the worker has been successfully terminated.\n */\n public async end(): ReturnType<JestWorker[\"end\"]> {\n const worker = this.#worker;\n if (!worker) {\n throw new Error(\"Execution Host Worker is not initialized\");\n }\n\n cleanupWorkers(worker);\n this.#worker = undefined;\n return worker.end();\n }\n\n /**\n * Quietly end the worker if it exists\n */\n public close(): void {\n if (this.#worker) {\n cleanupWorkers(this.#worker);\n void this.#worker.end();\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/helpers/rpc.d.cts
CHANGED
package/dist/helpers/rpc.d.mts
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as RpcServerFunctions, D as WrappedRpcFunctions, E as WrappedRpcFunction, S as RpcPayloadMetadata, T as WrapRpcFunctions, _ as RpcClientRemoteFunctions, a as ExtractRpcFunction, b as RpcFunctions, c as InputRpcFunctions, d as RpcClientCall, f as RpcClientCallEvent, g as RpcClientHost, h as RpcClientFunctions, i as RpcClientOptions, l as LogPayload, m as RpcClientEvents, n as EngineOptions, o as ExtractRpcFunctions, p as RpcClientCallOptional, r as EngineResolvedConfig, s as InputRpcFunction, t as EngineExecutionOptions, u as RpcClient, v as RpcContext, w as WrapRpcFunction, x as RpcPayloadEnvelop, y as RpcFunction } from "./config-
|
|
2
|
-
import { a as ExecutionHookScopeState, c as ExecutionScopeType, i as ExecutionCommandScopeState, l as ExecutionState, n as EngineExecutionItem, o as ExecutionPluginScopeState, r as EngineSystemContext, s as ExecutionScopeState, t as EngineContext } from "./context-
|
|
3
|
-
import { a as PowerlinesExecutionHost, i as ExecutionInterface, n as ExecutionHost, o as Worker, r as ExecutionHostParams, t as Engine } from "./api-
|
|
1
|
+
import { C as RpcServerFunctions, D as WrappedRpcFunctions, E as WrappedRpcFunction, S as RpcPayloadMetadata, T as WrapRpcFunctions, _ as RpcClientRemoteFunctions, a as ExtractRpcFunction, b as RpcFunctions, c as InputRpcFunctions, d as RpcClientCall, f as RpcClientCallEvent, g as RpcClientHost, h as RpcClientFunctions, i as RpcClientOptions, l as LogPayload, m as RpcClientEvents, n as EngineOptions, o as ExtractRpcFunctions, p as RpcClientCallOptional, r as EngineResolvedConfig, s as InputRpcFunction, t as EngineExecutionOptions, u as RpcClient, v as RpcContext, w as WrapRpcFunction, x as RpcPayloadEnvelop, y as RpcFunction } from "./config-D6xUniHh.cjs";
|
|
2
|
+
import { a as ExecutionHookScopeState, c as ExecutionScopeType, i as ExecutionCommandScopeState, l as ExecutionState, n as EngineExecutionItem, o as ExecutionPluginScopeState, r as EngineSystemContext, s as ExecutionScopeState, t as EngineContext } from "./context-epL7NPvL.cjs";
|
|
3
|
+
import { a as PowerlinesExecutionHost, i as ExecutionInterface, n as ExecutionHost, o as Worker, r as ExecutionHostParams, t as Engine } from "./api-6w4hZL6n.cjs";
|
|
4
4
|
import { PowerlinesEngine, createContext, createEngine } from "./engine.cjs";
|
|
5
5
|
export { Engine, EngineContext, EngineExecutionItem, EngineExecutionOptions, EngineOptions, EngineResolvedConfig, EngineSystemContext, ExecutionCommandScopeState, ExecutionHookScopeState, ExecutionHost, ExecutionHostParams, ExecutionInterface, ExecutionPluginScopeState, ExecutionScopeState, ExecutionScopeType, ExecutionState, ExtractRpcFunction, ExtractRpcFunctions, InputRpcFunction, InputRpcFunctions, LogPayload, type PowerlinesEngine, PowerlinesExecutionHost, RpcClient, RpcClientCall, RpcClientCallEvent, RpcClientCallOptional, RpcClientEvents, RpcClientFunctions, RpcClientHost, RpcClientOptions, RpcClientRemoteFunctions, RpcContext, RpcFunction, RpcFunctions, RpcPayloadEnvelop, RpcPayloadMetadata, RpcServerFunctions, Worker, WrapRpcFunction, WrapRpcFunctions, WrappedRpcFunction, WrappedRpcFunctions, createContext, createEngine };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as RpcServerFunctions, D as WrappedRpcFunctions, E as WrappedRpcFunction, S as RpcPayloadMetadata, T as WrapRpcFunctions, _ as RpcClientRemoteFunctions, a as ExtractRpcFunction, b as RpcFunctions, c as InputRpcFunctions, d as RpcClientCall, f as RpcClientCallEvent, g as RpcClientHost, h as RpcClientFunctions, i as RpcClientOptions, l as LogPayload, m as RpcClientEvents, n as EngineOptions, o as ExtractRpcFunctions, p as RpcClientCallOptional, r as EngineResolvedConfig, s as InputRpcFunction, t as EngineExecutionOptions, u as RpcClient, v as RpcContext, w as WrapRpcFunction, x as RpcPayloadEnvelop, y as RpcFunction } from "./config-
|
|
2
|
-
import { a as ExecutionHookScopeState, c as ExecutionScopeType, i as ExecutionCommandScopeState, l as ExecutionState, n as EngineExecutionItem, o as ExecutionPluginScopeState, r as EngineSystemContext, s as ExecutionScopeState, t as EngineContext } from "./context-
|
|
3
|
-
import { a as PowerlinesExecutionHost, i as ExecutionInterface, n as ExecutionHost, o as Worker, r as ExecutionHostParams, t as Engine } from "./api-
|
|
1
|
+
import { C as RpcServerFunctions, D as WrappedRpcFunctions, E as WrappedRpcFunction, S as RpcPayloadMetadata, T as WrapRpcFunctions, _ as RpcClientRemoteFunctions, a as ExtractRpcFunction, b as RpcFunctions, c as InputRpcFunctions, d as RpcClientCall, f as RpcClientCallEvent, g as RpcClientHost, h as RpcClientFunctions, i as RpcClientOptions, l as LogPayload, m as RpcClientEvents, n as EngineOptions, o as ExtractRpcFunctions, p as RpcClientCallOptional, r as EngineResolvedConfig, s as InputRpcFunction, t as EngineExecutionOptions, u as RpcClient, v as RpcContext, w as WrapRpcFunction, x as RpcPayloadEnvelop, y as RpcFunction } from "./config-C9AD-erz.mjs";
|
|
2
|
+
import { a as ExecutionHookScopeState, c as ExecutionScopeType, i as ExecutionCommandScopeState, l as ExecutionState, n as EngineExecutionItem, o as ExecutionPluginScopeState, r as EngineSystemContext, s as ExecutionScopeState, t as EngineContext } from "./context-S3XH2DWP.mjs";
|
|
3
|
+
import { a as PowerlinesExecutionHost, i as ExecutionInterface, n as ExecutionHost, o as Worker, r as ExecutionHostParams, t as Engine } from "./api-CcNgO71y.mjs";
|
|
4
4
|
import { PowerlinesEngine, createContext, createEngine } from "./engine.mjs";
|
|
5
5
|
export { Engine, EngineContext, EngineExecutionItem, EngineExecutionOptions, EngineOptions, EngineResolvedConfig, EngineSystemContext, ExecutionCommandScopeState, ExecutionHookScopeState, ExecutionHost, ExecutionHostParams, ExecutionInterface, ExecutionPluginScopeState, ExecutionScopeState, ExecutionScopeType, ExecutionState, ExtractRpcFunction, ExtractRpcFunctions, InputRpcFunction, InputRpcFunctions, LogPayload, type PowerlinesEngine, PowerlinesExecutionHost, RpcClient, RpcClientCall, RpcClientCallEvent, RpcClientCallOptional, RpcClientEvents, RpcClientFunctions, RpcClientHost, RpcClientOptions, RpcClientRemoteFunctions, RpcContext, RpcFunction, RpcFunctions, RpcPayloadEnvelop, RpcPayloadMetadata, RpcServerFunctions, Worker, WrapRpcFunction, WrapRpcFunctions, WrappedRpcFunction, WrappedRpcFunctions, createContext, createEngine };
|
|
@@ -55,6 +55,19 @@ let _stryke_helpers_omit = require("@stryke/helpers/omit");
|
|
|
55
55
|
let _stryke_type_checks_is_set_object = require("@stryke/type-checks/is-set-object");
|
|
56
56
|
let _powerlines_core_context_execution_context = require("@powerlines/core/context/execution-context");
|
|
57
57
|
let _powerlines_core_lib_context_helpers = require("@powerlines/core/lib/context-helpers");
|
|
58
|
+
let _stryke_string_format_title_case = require("@stryke/string-format/title-case");
|
|
59
|
+
let _stryke_unique_id_uuid = require("@stryke/unique-id/uuid");
|
|
60
|
+
let _powerlines_core_lib_events = require("@powerlines/core/lib/events");
|
|
61
|
+
let _stryke_type_checks_is_number = require("@stryke/type-checks/is-number");
|
|
62
|
+
let _stryke_type_checks_is_set = require("@stryke/type-checks/is-set");
|
|
63
|
+
let _stryke_url = require("@stryke/url");
|
|
64
|
+
let devframe_client = require("devframe/client");
|
|
65
|
+
let devframe_rpc = require("devframe/rpc");
|
|
66
|
+
let devframe_rpc_client = require("devframe/rpc/client");
|
|
67
|
+
let devframe_rpc_transports_ws_client = require("devframe/rpc/transports/ws-client");
|
|
68
|
+
let devframe_utils_promise = require("devframe/utils/promise");
|
|
69
|
+
let human_id = require("human-id");
|
|
70
|
+
let node_events = require("node:events");
|
|
58
71
|
|
|
59
72
|
//#region src/api/prepare.ts
|
|
60
73
|
/**
|
|
@@ -367,6 +380,131 @@ async function types$1(context) {
|
|
|
367
380
|
timer();
|
|
368
381
|
}
|
|
369
382
|
|
|
383
|
+
//#endregion
|
|
384
|
+
//#region src/helpers/rpc.ts
|
|
385
|
+
function createWsRpcClientMode(baseURL, connectionMeta, events, clientRpc, authToken = (0, human_id.humanId)({
|
|
386
|
+
separator: "-",
|
|
387
|
+
capitalize: false
|
|
388
|
+
}), rpcOptions = {}, wsOptions = {}) {
|
|
389
|
+
let isTrusted = false;
|
|
390
|
+
const trustedPromise = (0, devframe_utils_promise.promiseWithResolver)();
|
|
391
|
+
const url = (0, _stryke_type_checks_is_number.isNumber)(connectionMeta.websocket) || (0, _stryke_type_checks_is_set.isSet)(connectionMeta.websocket) && `${+connectionMeta.websocket}` === `${connectionMeta.websocket}` ? `${baseURL.protocol.replace("http", "ws")}//${baseURL.hostname}:${connectionMeta.websocket}` : connectionMeta.websocket;
|
|
392
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
393
|
+
for (const name of connectionMeta.jsonSerializableMethods ?? []) definitions.set(name, { jsonSerializable: true });
|
|
394
|
+
const serverRpc = (0, devframe_rpc_client.createRpcClient)(clientRpc.functions, {
|
|
395
|
+
channel: (0, devframe_rpc_transports_ws_client.createWsRpcChannel)({
|
|
396
|
+
url,
|
|
397
|
+
authToken,
|
|
398
|
+
definitions,
|
|
399
|
+
...wsOptions
|
|
400
|
+
}),
|
|
401
|
+
rpcOptions
|
|
402
|
+
});
|
|
403
|
+
clientRpc.register({
|
|
404
|
+
name: "devframe:auth:revoked",
|
|
405
|
+
type: "event",
|
|
406
|
+
handler: () => {
|
|
407
|
+
isTrusted = false;
|
|
408
|
+
events.emit("rpc:is-trusted:updated", false);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
let currentAuthToken = authToken;
|
|
412
|
+
async function requestTrustWithToken(token) {
|
|
413
|
+
currentAuthToken = token;
|
|
414
|
+
return true;
|
|
415
|
+
}
|
|
416
|
+
async function requestTrust() {
|
|
417
|
+
if (isTrusted) return true;
|
|
418
|
+
return requestTrustWithToken(currentAuthToken);
|
|
419
|
+
}
|
|
420
|
+
async function ensureTrusted(timeout = 6e4) {
|
|
421
|
+
if (isTrusted) trustedPromise.resolve(true);
|
|
422
|
+
if (timeout <= 0) return trustedPromise.promise;
|
|
423
|
+
let clear = () => {};
|
|
424
|
+
await Promise.race([trustedPromise.promise.then(clear), new Promise((resolve, reject) => {
|
|
425
|
+
const id = setTimeout(() => {
|
|
426
|
+
reject(/* @__PURE__ */ new Error("Timeout waiting for rpc to be trusted"));
|
|
427
|
+
}, timeout);
|
|
428
|
+
clear = () => clearTimeout(id);
|
|
429
|
+
})]);
|
|
430
|
+
return isTrusted;
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
get isTrusted() {
|
|
434
|
+
return isTrusted;
|
|
435
|
+
},
|
|
436
|
+
requestTrust,
|
|
437
|
+
requestTrustWithToken,
|
|
438
|
+
ensureTrusted,
|
|
439
|
+
call: (...args) => {
|
|
440
|
+
return serverRpc.$call(...args);
|
|
441
|
+
},
|
|
442
|
+
callEvent: (...args) => {
|
|
443
|
+
return serverRpc.$callEvent(...args);
|
|
444
|
+
},
|
|
445
|
+
callOptional: (...args) => {
|
|
446
|
+
return serverRpc.$callOptional(...args);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const CONNECTION_AUTH_TOKEN_KEY = "__DEVTOOLS_CONNECTION_AUTH_TOKEN__";
|
|
451
|
+
function createRpcClient(options) {
|
|
452
|
+
const baseURL = new _stryke_url.StormURL(options.baseURL);
|
|
453
|
+
const cacheManager = new devframe_rpc.RpcCacheManager({
|
|
454
|
+
functions: [],
|
|
455
|
+
...typeof options.cacheOptions === "object" ? options.cacheOptions : {}
|
|
456
|
+
});
|
|
457
|
+
const context = { rpc: void 0 };
|
|
458
|
+
const clientRpc = new devframe_rpc.RpcFunctionsCollectorBase(context);
|
|
459
|
+
node_events.EventEmitter.setMaxListeners(100);
|
|
460
|
+
const events = (0, _powerlines_core_lib_events.createEventEmitter)();
|
|
461
|
+
const mode = createWsRpcClientMode(baseURL, options.connection, events, clientRpc, void 0, {
|
|
462
|
+
...options.rpcOptions,
|
|
463
|
+
async onRequest(req, next, resolve) {
|
|
464
|
+
await options.rpcOptions?.onRequest?.call(this, req, next, resolve);
|
|
465
|
+
if (options.cacheOptions && cacheManager?.validate(req.m)) {
|
|
466
|
+
const cached = cacheManager.cached(req.m, req.a);
|
|
467
|
+
if (cached) return resolve(cached);
|
|
468
|
+
else {
|
|
469
|
+
const res = await next(req);
|
|
470
|
+
cacheManager?.apply(req, res);
|
|
471
|
+
}
|
|
472
|
+
} else await next(req);
|
|
473
|
+
}
|
|
474
|
+
}, options.wsOptions);
|
|
475
|
+
const rpc = {
|
|
476
|
+
events,
|
|
477
|
+
get isTrusted() {
|
|
478
|
+
return mode.isTrusted;
|
|
479
|
+
},
|
|
480
|
+
connectionMeta: options.connection,
|
|
481
|
+
ensureTrusted: mode.ensureTrusted,
|
|
482
|
+
requestTrust: mode.requestTrust,
|
|
483
|
+
requestTrustWithToken: async (token) => {
|
|
484
|
+
localStorage.setItem(CONNECTION_AUTH_TOKEN_KEY, token);
|
|
485
|
+
globalThis[CONNECTION_AUTH_TOKEN_KEY] = token;
|
|
486
|
+
return mode.requestTrustWithToken(token);
|
|
487
|
+
},
|
|
488
|
+
call: mode.call,
|
|
489
|
+
callEvent: mode.callEvent,
|
|
490
|
+
callOptional: mode.callOptional,
|
|
491
|
+
client: clientRpc,
|
|
492
|
+
sharedState: void 0,
|
|
493
|
+
streaming: void 0,
|
|
494
|
+
cacheManager
|
|
495
|
+
};
|
|
496
|
+
rpc.streaming = (0, devframe_client.createRpcStreamingClientHost)(rpc);
|
|
497
|
+
context.rpc = rpc;
|
|
498
|
+
mode.requestTrust();
|
|
499
|
+
try {
|
|
500
|
+
const bc = new BroadcastChannel("vite-devtools-auth");
|
|
501
|
+
bc.onmessage = (event) => {
|
|
502
|
+
if (event.data?.type === "auth-update" && event.data.authToken) rpc.requestTrustWithToken(event.data.authToken);
|
|
503
|
+
};
|
|
504
|
+
} catch {}
|
|
505
|
+
return rpc;
|
|
506
|
+
}
|
|
507
|
+
|
|
370
508
|
//#endregion
|
|
371
509
|
//#region src/helpers/create-execution-host.ts
|
|
372
510
|
/**
|
|
@@ -377,8 +515,28 @@ async function types$1(context) {
|
|
|
377
515
|
*/
|
|
378
516
|
function createExecutionHost(methods) {
|
|
379
517
|
return Object.fromEntries(Object.entries(methods).map(([method, fn]) => [method, async (params) => {
|
|
380
|
-
const
|
|
381
|
-
|
|
518
|
+
const { options, inlineConfig } = params;
|
|
519
|
+
let rpc;
|
|
520
|
+
if (options.baseURL && options.connection) rpc = createRpcClient(options);
|
|
521
|
+
else throw new Error(`Execution RPC client could not be created - Missing ${!options.baseURL ? `baseURL${options.connection ? ` and connection information` : ""}` : "connection"} or connection information.`);
|
|
522
|
+
const logFn = (meta, message) => {
|
|
523
|
+
(0, _powerlines_core_plugin_utils.consoleLogger)(meta, message);
|
|
524
|
+
if (rpc) rpc.callEvent("powerlines:log", {
|
|
525
|
+
meta: {
|
|
526
|
+
category: "general",
|
|
527
|
+
...options,
|
|
528
|
+
...(0, _stryke_type_checks_is_set_object.isSetObject)(meta) ? meta : { type: meta },
|
|
529
|
+
logId: (0, _stryke_unique_id_uuid.uuid)(),
|
|
530
|
+
timestamp: Date.now()
|
|
531
|
+
},
|
|
532
|
+
message
|
|
533
|
+
});
|
|
534
|
+
};
|
|
535
|
+
const context = await _powerlines_core_context_execution_context.PowerlinesExecutionContext.from({
|
|
536
|
+
...options,
|
|
537
|
+
logFn
|
|
538
|
+
}, inlineConfig ?? {}, { rpc });
|
|
539
|
+
context.logger.info(`Starting ${(0, _stryke_string_format_title_case.titleCase)(options.framework?.name) || "Powerlines"} - ${(0, _stryke_string_format_title_case.titleCase)(method)} execution (${options.executionId})`);
|
|
382
540
|
await (0, _powerlines_core_lib_context_helpers.resolvePluginConfig)(context);
|
|
383
541
|
await fn(context);
|
|
384
542
|
}]));
|