@pipelab/plugin-core 1.0.1-beta.9 → 1.0.1-latest.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -0
- package/dist/index.cjs +78 -114
- package/dist/index.d.cts +39 -73
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +39 -73
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +35 -110
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
- package/src/pipelab.ts +62 -70
- package/src/utils.ts +17 -167
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipelab/plugin-core",
|
|
3
|
-
"version": "1.0.1-
|
|
3
|
+
"version": "1.0.1-latest.30",
|
|
4
4
|
"description": "Core library for building Pipelab plugins",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"author": "CynToolkit",
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"tar": "6.2.1",
|
|
35
35
|
"type-fest": "4.26.1",
|
|
36
36
|
"yauzl": "2.10.0",
|
|
37
|
-
"zod": "4.3.6"
|
|
37
|
+
"zod": "4.3.6",
|
|
38
|
+
"@pipelab/core-node": "1.0.1-latest.34"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/archiver": "7.0.0",
|
|
@@ -43,9 +44,9 @@
|
|
|
43
44
|
"@types/yauzl": "2.10.3",
|
|
44
45
|
"tsdown": "0.21.2",
|
|
45
46
|
"typescript": "5.9.3",
|
|
46
|
-
"@pipelab/constants": "1.0.1-
|
|
47
|
-
"@pipelab/shared": "2.0.1-
|
|
48
|
-
"@pipelab/tsconfig": "1.0.1-
|
|
47
|
+
"@pipelab/constants": "1.0.1-latest.30",
|
|
48
|
+
"@pipelab/shared": "2.0.1-latest.31",
|
|
49
|
+
"@pipelab/tsconfig": "1.0.1-latest.30"
|
|
49
50
|
},
|
|
50
51
|
"scripts": {
|
|
51
52
|
"build": "tsdown",
|
package/src/pipelab.ts
CHANGED
|
@@ -16,87 +16,79 @@ import type {
|
|
|
16
16
|
} from "@pipelab/shared";
|
|
17
17
|
|
|
18
18
|
export * from "@pipelab/shared";
|
|
19
|
+
import {
|
|
20
|
+
type RunnerCallbackFnArgument,
|
|
21
|
+
type ActionRunnerData,
|
|
22
|
+
type ActionRunner,
|
|
23
|
+
type ConditionRunner,
|
|
24
|
+
type LoopRunner,
|
|
25
|
+
type ExpressionRunner,
|
|
26
|
+
type EventRunner,
|
|
27
|
+
type Runner,
|
|
28
|
+
PipelabContext,
|
|
29
|
+
} from "@pipelab/core-node";
|
|
19
30
|
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
31
|
+
export {
|
|
32
|
+
type RunnerCallbackFnArgument,
|
|
33
|
+
type ActionRunnerData,
|
|
34
|
+
type ActionRunner,
|
|
35
|
+
type ConditionRunner,
|
|
36
|
+
type LoopRunner,
|
|
37
|
+
type ExpressionRunner,
|
|
38
|
+
type EventRunner,
|
|
39
|
+
type Runner,
|
|
40
|
+
PipelabContext,
|
|
24
41
|
};
|
|
25
42
|
|
|
26
|
-
export
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
inputs: ExtractInputsFromAction<ACTION>;
|
|
30
|
-
setMeta: (callback: (data: ACTION["meta"]) => ACTION["meta"]) => void;
|
|
31
|
-
meta: ACTION["meta"];
|
|
32
|
-
cwd: string;
|
|
33
|
-
paths: {
|
|
34
|
-
assets: string;
|
|
35
|
-
cache: string;
|
|
36
|
-
pnpm: string;
|
|
37
|
-
node: string;
|
|
38
|
-
userData: string;
|
|
39
|
-
modules: string;
|
|
40
|
-
thirdparty: string;
|
|
41
|
-
};
|
|
42
|
-
api: {
|
|
43
|
-
fetchAsset: (packageName: string, version?: string) => Promise<string>;
|
|
44
|
-
[key: string]: any;
|
|
45
|
-
};
|
|
46
|
-
browserWindow: BrowserWindow;
|
|
47
|
-
abortSignal: AbortSignal;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export type ActionRunner<ACTION extends Action> = (data: ActionRunnerData<ACTION>) => Promise<void>;
|
|
51
|
-
export const createActionRunner = <ACTION extends Action>(runner: ActionRunner<ACTION>) => runner;
|
|
52
|
-
|
|
53
|
-
// ---
|
|
43
|
+
export const createActionRunner = <ACTION extends Action>(
|
|
44
|
+
runner: (data: ActionRunnerData<ACTION>) => Promise<void>,
|
|
45
|
+
) => runner;
|
|
54
46
|
|
|
55
|
-
export type ConditionRunner<CONDITION extends Condition> = (data: {
|
|
56
|
-
log: typeof console.log;
|
|
57
|
-
inputs: ExtractInputsFromCondition<CONDITION>;
|
|
58
|
-
setMeta: (callback: (data: CONDITION["meta"]) => CONDITION["meta"]) => void;
|
|
59
|
-
meta: CONDITION["meta"];
|
|
60
|
-
cwd: string;
|
|
61
|
-
}) => Promise<boolean>;
|
|
62
47
|
export const createConditionRunner = <CONDITION extends Condition>(
|
|
63
|
-
runner:
|
|
48
|
+
runner: (data: {
|
|
49
|
+
log: typeof console.log;
|
|
50
|
+
inputs: ExtractInputsFromCondition<CONDITION>;
|
|
51
|
+
setMeta: (callback: (data: CONDITION["meta"]) => CONDITION["meta"]) => void;
|
|
52
|
+
meta: CONDITION["meta"];
|
|
53
|
+
cwd: string;
|
|
54
|
+
context: PipelabContext;
|
|
55
|
+
}) => Promise<boolean>,
|
|
64
56
|
) => runner;
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}) => Promise<"step" | "exit"
|
|
76
|
-
|
|
58
|
+
export const createLoopRunner = <LOOP extends Loop>(
|
|
59
|
+
runner: (data: {
|
|
60
|
+
log: typeof console.log;
|
|
61
|
+
setOutput: SetOutputLoopFn<LOOP>;
|
|
62
|
+
inputs: ExtractInputsFromLoop<LOOP>;
|
|
63
|
+
setMeta: (callback: (data: LOOP["meta"]) => LOOP["meta"]) => void;
|
|
64
|
+
meta: LOOP["meta"];
|
|
65
|
+
cwd: string;
|
|
66
|
+
context: PipelabContext;
|
|
67
|
+
}) => Promise<"step" | "exit">,
|
|
68
|
+
) => runner;
|
|
77
69
|
|
|
78
|
-
export type ExpressionRunner<EXPRESSION extends Expression> = (data: {
|
|
79
|
-
log: typeof console.log;
|
|
80
|
-
setOutput: SetOutputExpressionFn<EXPRESSION>;
|
|
81
|
-
inputs: ExtractInputsFromExpression<EXPRESSION>;
|
|
82
|
-
setMeta: (callback: (data: EXPRESSION["meta"]) => EXPRESSION["meta"]) => void;
|
|
83
|
-
meta: EXPRESSION["meta"];
|
|
84
|
-
cwd: string;
|
|
85
|
-
}) => Promise<string>;
|
|
86
70
|
export const createExpressionRunner = <EXPRESSION extends Expression>(
|
|
87
|
-
runner:
|
|
71
|
+
runner: (data: {
|
|
72
|
+
log: typeof console.log;
|
|
73
|
+
setOutput: SetOutputExpressionFn<EXPRESSION>;
|
|
74
|
+
inputs: ExtractInputsFromExpression<EXPRESSION>;
|
|
75
|
+
setMeta: (callback: (data: EXPRESSION["meta"]) => EXPRESSION["meta"]) => void;
|
|
76
|
+
meta: EXPRESSION["meta"];
|
|
77
|
+
cwd: string;
|
|
78
|
+
context: PipelabContext;
|
|
79
|
+
}) => Promise<string>,
|
|
88
80
|
) => runner;
|
|
89
81
|
|
|
90
|
-
export
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
82
|
+
export const createEventRunner = <EVENT extends Event>(
|
|
83
|
+
runner: (data: {
|
|
84
|
+
log: typeof console.log;
|
|
85
|
+
inputs: ExtractInputsFromEvent<EVENT>;
|
|
86
|
+
setMeta: (callback: (data: EVENT["meta"]) => EVENT["meta"]) => void;
|
|
87
|
+
meta: EVENT["meta"];
|
|
88
|
+
cwd: string;
|
|
89
|
+
context: PipelabContext;
|
|
90
|
+
}) => Promise<void>,
|
|
91
|
+
) => runner;
|
|
100
92
|
|
|
101
93
|
export const sleep = (duration: number) => {
|
|
102
94
|
return new Promise((resolve) => setTimeout(resolve, duration));
|
package/src/utils.ts
CHANGED
|
@@ -1,176 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { Options, Subprocess } from "execa";
|
|
2
|
+
export {
|
|
3
|
+
fetchPackage,
|
|
4
|
+
fetchPipelabAsset,
|
|
5
|
+
fetchPipelabPlugin,
|
|
6
|
+
fetchPipelabCli,
|
|
7
|
+
runPnpm,
|
|
8
|
+
downloadFile,
|
|
9
|
+
runWithLiveLogs,
|
|
10
|
+
} from "@pipelab/core-node";
|
|
8
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Re-exporting hooks type for backward compatibility
|
|
14
|
+
*/
|
|
15
|
+
export type { DownloadHooks as Hooks } from "@pipelab/core-node";
|
|
16
|
+
|
|
17
|
+
// Keep runtime-only utilities that don't depend on complex engine state
|
|
9
18
|
export const fileExists = async (path: string): Promise<boolean> => {
|
|
10
19
|
try {
|
|
20
|
+
const { access } = await import("node:fs/promises");
|
|
11
21
|
await access(path);
|
|
12
22
|
return true;
|
|
13
23
|
} catch {
|
|
14
24
|
return false;
|
|
15
25
|
}
|
|
16
26
|
};
|
|
17
|
-
|
|
18
|
-
export const runWithLiveLogs = async (
|
|
19
|
-
command: string,
|
|
20
|
-
args: string[],
|
|
21
|
-
execaOptions: Options,
|
|
22
|
-
log: typeof console.log,
|
|
23
|
-
hooks?: {
|
|
24
|
-
onStdout?: (data: string, subprocess: Subprocess) => void;
|
|
25
|
-
onStderr?: (data: string, subprocess: Subprocess) => void;
|
|
26
|
-
onExit?: (code: number) => void;
|
|
27
|
-
onCreated?: (subprocess: Subprocess) => void;
|
|
28
|
-
},
|
|
29
|
-
abortSignal?: AbortSignal,
|
|
30
|
-
): Promise<void> => {
|
|
31
|
-
console.log("command: ", command, args.join(" "));
|
|
32
|
-
|
|
33
|
-
const subprocess = execa(command, args, {
|
|
34
|
-
...execaOptions,
|
|
35
|
-
stdout: "pipe",
|
|
36
|
-
stderr: "pipe",
|
|
37
|
-
stdin: "pipe",
|
|
38
|
-
env: {
|
|
39
|
-
...process.env,
|
|
40
|
-
...execaOptions.env,
|
|
41
|
-
TERM: "xterm-256color",
|
|
42
|
-
FORCE_STDERR_LOGGING: "1",
|
|
43
|
-
},
|
|
44
|
-
cancelSignal: abortSignal,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
hooks?.onCreated?.(subprocess);
|
|
48
|
-
|
|
49
|
-
subprocess.stdout?.on("data", (data: Buffer) => {
|
|
50
|
-
hooks?.onStdout?.(data.toString(), subprocess);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
subprocess.stderr?.on("data", (data: Buffer) => {
|
|
54
|
-
hooks?.onStderr?.(data.toString(), subprocess);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const { exitCode } = await subprocess;
|
|
59
|
-
hooks?.onExit?.(exitCode ?? 0);
|
|
60
|
-
} catch (error: any) {
|
|
61
|
-
const code = error.exitCode ?? 1;
|
|
62
|
-
hooks?.onExit?.(code);
|
|
63
|
-
throw new ExternalCommandError(error.message, code);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export interface Hooks {
|
|
68
|
-
onProgress?: (data: { progress: number; downloadedSize: number }) => void;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Downloads a file from a given URL to a specified local path with progress tracking.
|
|
73
|
-
*
|
|
74
|
-
* @param url - The URL of the file to download.
|
|
75
|
-
* @param localPath - The local file path to save the downloaded file.
|
|
76
|
-
* @returns A promise that resolves when the file is downloaded.
|
|
77
|
-
*/
|
|
78
|
-
export const downloadFile = async (
|
|
79
|
-
url: string,
|
|
80
|
-
localPath: string,
|
|
81
|
-
hooks?: Hooks,
|
|
82
|
-
abortSignal?: AbortSignal,
|
|
83
|
-
): Promise<void> => {
|
|
84
|
-
// Fetch the resource
|
|
85
|
-
const response = await fetch(url, {
|
|
86
|
-
signal: abortSignal,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Check if the fetch was successful
|
|
90
|
-
if (!response.ok) {
|
|
91
|
-
throw new Error(`Failed to fetch file: ${response.statusText}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Get the total size of the file
|
|
95
|
-
const contentLength = response.headers.get("content-length");
|
|
96
|
-
if (!contentLength) {
|
|
97
|
-
throw new Error("Content-Length header is missing");
|
|
98
|
-
}
|
|
99
|
-
const totalSize = parseInt(contentLength, 10);
|
|
100
|
-
|
|
101
|
-
// Track progress
|
|
102
|
-
let downloadedSize = 0;
|
|
103
|
-
const fileStream = createWriteStream(localPath);
|
|
104
|
-
|
|
105
|
-
// Create a readable stream to monitor progress
|
|
106
|
-
const progressStream = new TransformStream({
|
|
107
|
-
transform(chunk, controller) {
|
|
108
|
-
downloadedSize += chunk.length;
|
|
109
|
-
const progress = (downloadedSize / totalSize) * 100;
|
|
110
|
-
if (hooks?.onProgress) {
|
|
111
|
-
hooks.onProgress({
|
|
112
|
-
progress,
|
|
113
|
-
downloadedSize,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
controller.enqueue(chunk);
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Pipe the response through the progress tracker and into the file
|
|
121
|
-
const readable = response.body?.pipeThrough(progressStream);
|
|
122
|
-
if (!readable) {
|
|
123
|
-
throw new Error("Failed to create a readable stream");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
await pipeline(readable, fileStream);
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Installs an NPM package from the npm registry as a tarball if not already present.
|
|
131
|
-
* @param thirdpartyDir The directory where third-party tools are stored.
|
|
132
|
-
* @param name The name of the package (e.g., 'pnpm' or '@poki/cli').
|
|
133
|
-
* @param version The version of the package.
|
|
134
|
-
* @param options (Optional) configuration for dependency installation.
|
|
135
|
-
* @returns A Promise that resolves to the path of the extracted package (the 'package' subfolder).
|
|
136
|
-
*/
|
|
137
|
-
export const ensureNPMPackage = async (
|
|
138
|
-
thirdpartyDir: string,
|
|
139
|
-
name: string,
|
|
140
|
-
version: string,
|
|
141
|
-
options?: {
|
|
142
|
-
nodePath?: string;
|
|
143
|
-
pnpmPath?: string;
|
|
144
|
-
installDeps?: boolean;
|
|
145
|
-
},
|
|
146
|
-
) => {
|
|
147
|
-
const packageDir = join(thirdpartyDir, name, version);
|
|
148
|
-
const finalPath = join(packageDir, "package");
|
|
149
|
-
|
|
150
|
-
// 1. Check if already installed
|
|
151
|
-
if (await fileExists(finalPath)) {
|
|
152
|
-
return finalPath;
|
|
153
|
-
}
|
|
154
|
-
console.log(`NPM package ${name}@${version} not found at ${finalPath}, installing...`);
|
|
155
|
-
|
|
156
|
-
// 2. Extract using pacote
|
|
157
|
-
console.log(`Extracting ${name}@${version} to ${finalPath}...`);
|
|
158
|
-
await mkdir(packageDir, { recursive: true });
|
|
159
|
-
await pacote.extract(`${name}@${version}`, finalPath);
|
|
160
|
-
|
|
161
|
-
// 3. Install dependencies if requested
|
|
162
|
-
if (options?.installDeps && options.pnpmPath) {
|
|
163
|
-
console.log(
|
|
164
|
-
`Installing dependencies for ${name}@${version} using pnpm at ${options.pnpmPath}...`,
|
|
165
|
-
);
|
|
166
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
167
|
-
// We use the pnpm .cjs bundle directly with node
|
|
168
|
-
const node = options.nodePath || process.execPath;
|
|
169
|
-
await execa(node, [options.pnpmPath, "install", "--prod"], {
|
|
170
|
-
cwd: finalPath,
|
|
171
|
-
stdio: "inherit",
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return finalPath;
|
|
176
|
-
};
|