@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipelab/plugin-core",
3
- "version": "1.0.1-beta.9",
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-beta.10",
47
- "@pipelab/shared": "2.0.1-beta.11",
48
- "@pipelab/tsconfig": "1.0.1-beta.10"
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 type RunnerCallbackFnArgument = {
21
- done: () => void;
22
- id: string;
23
- log: (...args: Parameters<(typeof console)["log"]>) => void;
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 type ActionRunnerData<ACTION extends Action> = {
27
- log: typeof console.log;
28
- setOutput: SetOutputActionFn<ACTION>;
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: ConditionRunner<CONDITION>,
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
- export type LoopRunner<LOOP extends Loop> = (data: {
69
- log: typeof console.log;
70
- setOutput: SetOutputLoopFn<LOOP>;
71
- inputs: ExtractInputsFromLoop<LOOP>;
72
- setMeta: (callback: (data: LOOP["meta"]) => LOOP["meta"]) => void;
73
- meta: LOOP["meta"];
74
- cwd: string;
75
- }) => Promise<"step" | "exit">;
76
- export const createLoopRunner = <LOOP extends Loop>(runner: LoopRunner<LOOP>) => runner;
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: ExpressionRunner<EXPRESSION>,
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 type EventRunner<EVENT extends Event> = (data: {
91
- log: typeof console.log;
92
- inputs: ExtractInputsFromEvent<EVENT>;
93
- setMeta: (callback: (data: EVENT["meta"]) => EVENT["meta"]) => void;
94
- meta: EVENT["meta"];
95
- cwd: string;
96
- }) => Promise<void>;
97
- export const createEventRunner = <EVENT extends Event>(runner: EventRunner<EVENT>) => runner;
98
-
99
- export type Runner = ActionRunner<any> | LoopRunner<any> | EventRunner<any> | ConditionRunner<any>;
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 { execa, Options, Subprocess } from "execa";
2
- import { ExternalCommandError } from "./custom-errors.js";
3
- import { join } from "node:path";
4
- import { access, mkdir, writeFile, rm } from "node:fs/promises";
5
- import { createWriteStream } from "node:fs";
6
- import { pipeline } from "node:stream/promises";
7
- import pacote from "pacote";
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
- };