@pipelab/core-node 1.0.0-beta.13 → 1.0.0-beta.15

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/core-node",
3
- "version": "1.0.0-beta.13",
3
+ "version": "1.0.0-beta.15",
4
4
  "private": false,
5
5
  "description": "The Pipelab automation engine for Node.js",
6
6
  "license": "FSL-1.1-MIT",
@@ -40,8 +40,8 @@
40
40
  "type-fest": "4.39.0",
41
41
  "ws": "8.18.3",
42
42
  "yauzl": "2.10.0",
43
- "@pipelab/constants": "1.0.0-beta.11",
44
- "@pipelab/shared": "1.0.0-beta.9"
43
+ "@pipelab/constants": "1.0.0-beta.13",
44
+ "@pipelab/shared": "1.0.0-beta.11"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/adm-zip": "0.5.7",
@@ -52,13 +52,17 @@
52
52
  "@types/tar": "7.0.87",
53
53
  "@types/ws": "8.18.1",
54
54
  "@types/yauzl": "2.10.3",
55
+ "memfs": "4.57.6",
55
56
  "tsdown": "0.21.2",
56
57
  "typescript": "^5.0.0",
57
- "@pipelab/tsconfig": "1.0.0-beta.9"
58
+ "vitest": "3.1.4",
59
+ "@pipelab/tsconfig": "1.0.0-beta.11"
58
60
  },
59
61
  "scripts": {
60
62
  "build": "tsdown",
61
63
  "format": "oxfmt .",
62
- "lint": "oxlint ."
64
+ "lint": "oxlint .",
65
+ "typecheck": "tsc -b",
66
+ "test": "vitest run"
63
67
  }
64
68
  }
@@ -0,0 +1,176 @@
1
+ import { describe, test, expect, beforeEach, vi } from "vitest";
2
+ import { setupConfigFile } from "./config";
3
+ import { FileRepo } from "@pipelab/shared";
4
+ import { PipelabContext } from "./context";
5
+ import fs from "node:fs/promises";
6
+ import { existsSync } from "node:fs";
7
+ import path from "node:path";
8
+ import { vol } from "memfs";
9
+
10
+ // Mock the node:fs and node:fs/promises modules to use memfs
11
+ vi.mock("node:fs", async () => {
12
+ const memfs = await import("memfs");
13
+ return {
14
+ ...memfs.fs,
15
+ default: memfs.fs,
16
+ };
17
+ });
18
+
19
+ vi.mock("node:fs/promises", async () => {
20
+ const memfs = await import("memfs");
21
+ return {
22
+ ...memfs.fs.promises,
23
+ default: memfs.fs.promises,
24
+ };
25
+ });
26
+
27
+ describe("setupConfigFile & Backup Creation", () => {
28
+ let tempDir: string;
29
+ let context: PipelabContext;
30
+
31
+ beforeEach(() => {
32
+ vol.reset();
33
+ tempDir = "/tmp/pipelab-test-config";
34
+ context = new PipelabContext({ userDataPath: tempDir });
35
+ });
36
+
37
+ test("should migrate config and create backup files on disk", async () => {
38
+ // 1. Setup V1 configuration file in the context's config path
39
+ const configDir = context.getConfigPath();
40
+ await fs.mkdir(configDir, { recursive: true });
41
+
42
+ const projectsFilePath = path.join(configDir, "projects.json");
43
+
44
+ const v1Config = {
45
+ version: "1.0.0",
46
+ data: {
47
+ "pipeline-1": {
48
+ project: "main",
49
+ type: "internal",
50
+ configName: "pipeline-1",
51
+ lastModified: "2026-06-04",
52
+ }
53
+ }
54
+ };
55
+
56
+ await fs.writeFile(projectsFilePath, JSON.stringify(v1Config));
57
+
58
+ // 2. Initialize setupConfigFile
59
+ const configInstance = await setupConfigFile<FileRepo>("projects", { context });
60
+
61
+ // Verify file exists
62
+ expect(existsSync(projectsFilePath)).toBe(true);
63
+
64
+ // 3. Retrieve config (this triggers the migration process and onStep callback)
65
+ const migratedConfig = await configInstance.getConfig();
66
+
67
+ // 4. Assert the main config is updated on disk to version 2.0.0
68
+ expect(migratedConfig.version).toBe("2.0.0");
69
+
70
+ const updatedContent = JSON.parse(await fs.readFile(projectsFilePath, "utf8"));
71
+ expect(updatedContent.version).toBe("2.0.0");
72
+
73
+ // 5. Assert that the intermediate backup file was created on disk
74
+ const backupFilePath = path.join(configDir, "projects.v2.0.0.json");
75
+ expect(existsSync(backupFilePath)).toBe(true);
76
+
77
+ const backupContent = JSON.parse(await fs.readFile(backupFilePath, "utf8"));
78
+ expect(backupContent.version).toBe("2.0.0");
79
+ expect(backupContent.projects).toHaveLength(1);
80
+ expect(backupContent.pipelines).toHaveLength(1);
81
+ });
82
+
83
+ test("should create default config file if missing on setup", async () => {
84
+ const configDir = context.getConfigPath();
85
+ const projectsFilePath = path.join(configDir, "projects.json");
86
+
87
+ expect(existsSync(projectsFilePath)).toBe(false);
88
+
89
+ // Initialize setupConfigFile
90
+ await setupConfigFile<FileRepo>("projects", { context });
91
+
92
+ // Should create file with default value
93
+ expect(existsSync(projectsFilePath)).toBe(true);
94
+ const content = JSON.parse(await fs.readFile(projectsFilePath, "utf8"));
95
+ expect(content.version).toBe("2.0.0");
96
+ expect(content.projects).toHaveLength(1);
97
+ expect(content.pipelines).toEqual([]);
98
+ });
99
+
100
+ test("should fallback to default config and preserve corrupted file if parsing fails", async () => {
101
+ const configDir = context.getConfigPath();
102
+ await fs.mkdir(configDir, { recursive: true });
103
+ const projectsFilePath = path.join(configDir, "projects.json");
104
+
105
+ await fs.writeFile(projectsFilePath, "{ corrupted json... }");
106
+
107
+ const configInstance = await setupConfigFile<FileRepo>("projects", { context });
108
+ const config = await configInstance.getConfig();
109
+
110
+ expect(config.version).toBe("2.0.0");
111
+ expect(config.projects).toHaveLength(1);
112
+ expect(config.pipelines).toEqual([]);
113
+
114
+ // Verify a timestamped corrupted backup file exists
115
+ const files = await fs.readdir(configDir);
116
+ const corruptedFile = files.find(f => f.startsWith("projects.corrupted.") && f.endsWith(".json"));
117
+ expect(corruptedFile).toBeDefined();
118
+ const corruptedContent = await fs.readFile(path.join(configDir, corruptedFile!), "utf8");
119
+ expect(corruptedContent).toBe("{ corrupted json... }");
120
+ });
121
+
122
+ test("should fallback to default config and preserve file if migration throws", async () => {
123
+ const configDir = context.getConfigPath();
124
+ await fs.mkdir(configDir, { recursive: true });
125
+ const projectsFilePath = path.join(configDir, "projects.json");
126
+
127
+ const customMigrator = {
128
+ defaultValue: { version: "2.0.0", projects: [], pipelines: [] } as any,
129
+ migrate: async () => {
130
+ throw new Error("Migration failed!");
131
+ },
132
+ };
133
+
134
+ await fs.writeFile(projectsFilePath, JSON.stringify({ version: "1.0.0", invalidData: true }));
135
+
136
+ const configInstance = await setupConfigFile<any>("projects", {
137
+ context,
138
+ migrator: customMigrator,
139
+ });
140
+ const config = await configInstance.getConfig();
141
+
142
+ expect(config.version).toBe("2.0.0");
143
+
144
+ // Verify a timestamped corrupted backup file exists
145
+ const files = await fs.readdir(configDir);
146
+ const corruptedFile = files.find(f => f.startsWith("projects.corrupted.") && f.endsWith(".json"));
147
+ expect(corruptedFile).toBeDefined();
148
+ const corruptedContent = JSON.parse(await fs.readFile(path.join(configDir, corruptedFile!), "utf8"));
149
+ expect(corruptedContent.invalidData).toBe(true);
150
+ });
151
+
152
+ test("should save config to disk via setConfig", async () => {
153
+ const configInstance = await setupConfigFile<FileRepo>("projects", { context });
154
+ const initialConfig = await configInstance.getConfig();
155
+
156
+ const newConfig: FileRepo = {
157
+ ...initialConfig,
158
+ pipelines: [
159
+ {
160
+ id: "pipeline-new",
161
+ project: "main",
162
+ type: "internal",
163
+ configName: "pipeline-new",
164
+ lastModified: "2026-06-05",
165
+ },
166
+ ],
167
+ };
168
+
169
+ const success = await configInstance.setConfig(newConfig);
170
+ expect(success).toBe(true);
171
+
172
+ const savedContent = JSON.parse(await fs.readFile(path.join(context.getConfigPath(), "projects.json"), "utf8"));
173
+ expect(savedContent.pipelines).toHaveLength(1);
174
+ expect(savedContent.pipelines[0].id).toBe("pipeline-new");
175
+ });
176
+ });
package/src/config.ts CHANGED
@@ -6,15 +6,7 @@ import { useLogger } from "@pipelab/shared";
6
6
  import { configRegistry, Migrator, normalizePipelineConfig } from "@pipelab/shared";
7
7
 
8
8
  export const getMigrator = <T>(name: string) => {
9
- if (configRegistry[name]) {
10
- return configRegistry[name] as Migrator<T>;
11
- }
12
-
13
- if (name.startsWith("pipeline-") || path.isAbsolute(name) || name.endsWith(".json")) {
14
- return configRegistry["pipeline"] as Migrator<T>;
15
- }
16
-
17
- return undefined;
9
+ return (configRegistry[name] || configRegistry["pipeline"]) as Migrator<T>;
18
10
  };
19
11
 
20
12
  export const setupConfigFile = async <T>(
@@ -63,22 +55,28 @@ export const setupConfigFile = async <T>(
63
55
  }
64
56
 
65
57
  let json: any = undefined;
58
+ let migrationFailed = false;
66
59
  try {
67
- json = await migrator.migrate(originalJson, {
68
- debug: false,
69
- onStep: async (state: any, version: string) => {
70
- const parsedPath = path.parse(filesPath);
71
- const versionedPath = path.join(parsedPath.dir, `${parsedPath.name}.v${version}.json`);
72
- try {
73
- await fs.writeFile(versionedPath, JSON.stringify(state));
74
- logger().info(`Intermediate backup created for ${name} at ${versionedPath}`);
75
- } catch (e) {
76
- logger().error(`Failed to create intermediate backup for ${name} at v${version}:`, e);
77
- }
78
- },
79
- });
60
+ if (!parseFailed) {
61
+ json = await migrator.migrate(originalJson, {
62
+ debug: false,
63
+ onStep: async (state: any, version: string) => {
64
+ const parsedPath = path.parse(filesPath);
65
+ const versionedPath = path.join(parsedPath.dir, `${parsedPath.name}.v${version}.json`);
66
+ try {
67
+ await fs.writeFile(versionedPath, JSON.stringify(state));
68
+ logger().info(`Intermediate backup created for ${name} at ${versionedPath}`);
69
+ } catch (e) {
70
+ logger().error(`Failed to create intermediate backup for ${name} at v${version}:`, e);
71
+ }
72
+ },
73
+ });
74
+ } else {
75
+ json = migrator.defaultValue;
76
+ }
80
77
  } catch (e) {
81
78
  logger().error(`Error migrating config ${name}:`, e);
79
+ migrationFailed = true;
82
80
  json = migrator.defaultValue;
83
81
  }
84
82
 
@@ -95,8 +93,30 @@ export const setupConfigFile = async <T>(
95
93
  const originalVersion = originalJson?.version;
96
94
  const newVersion = json?.version;
97
95
 
98
- // Save back migrated config if changed, if normalized, if it's a new file, or if parse failed
99
- if (originalVersion !== newVersion || normalized || content === undefined || parseFailed) {
96
+ const shouldSaveBack =
97
+ originalVersion !== newVersion ||
98
+ normalized ||
99
+ content === undefined ||
100
+ parseFailed ||
101
+ migrationFailed;
102
+
103
+ if (shouldSaveBack) {
104
+ if (parseFailed || migrationFailed) {
105
+ try {
106
+ const parsedPath = path.parse(filesPath);
107
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
108
+ const corruptedPath = path.join(
109
+ parsedPath.dir,
110
+ `${parsedPath.name}.corrupted.${timestamp}.json`,
111
+ );
112
+ const backupContent = parseFailed ? (content || "") : JSON.stringify(originalJson, null, 2);
113
+ await fs.writeFile(corruptedPath, backupContent);
114
+ logger().info(`Corrupted config file preserved at ${corruptedPath}`);
115
+ } catch (e) {
116
+ logger().error(`Failed to backup corrupted config ${name}:`, e);
117
+ }
118
+ }
119
+
100
120
  try {
101
121
  await fs.writeFile(filesPath, JSON.stringify(json));
102
122
  } catch (e) {
package/src/context.ts CHANGED
@@ -2,12 +2,17 @@ import { join, dirname, resolve } from "node:path";
2
2
  import { homedir, platform } from "node:os";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { existsSync } from "node:fs";
5
+ import { mkdir, realpath, mkdtemp } from "node:fs/promises";
6
+ import { SandboxFolder, DEFAULT_NODE_VERSION, DEFAULT_PNPM_VERSION } from "@pipelab/constants";
7
+
8
+ // @ts-ignore import.meta is only allowed in ES Modules
9
+ const metaUrl = typeof import.meta !== "undefined" ? import.meta.url : undefined;
5
10
 
6
11
  const _dirname =
7
12
  typeof __dirname !== "undefined"
8
13
  ? __dirname
9
- : typeof import.meta !== "undefined" && import.meta.url
10
- ? dirname(fileURLToPath(import.meta.url))
14
+ : metaUrl
15
+ ? dirname(fileURLToPath(metaUrl))
11
16
  : process.cwd();
12
17
 
13
18
  export const isDev = process.env.NODE_ENV === "development";
@@ -71,4 +76,48 @@ export class PipelabContext {
71
76
  getConfigPath(...subpaths: string[]) {
72
77
  return join(this.userDataPath, "config", ...subpaths);
73
78
  }
79
+
80
+ getTempPath(...subpaths: string[]) {
81
+ return join(this.userDataPath, "temp", ...subpaths);
82
+ }
83
+
84
+ async createTempFolder(prefix = "pipelab-") {
85
+ const baseDir = this.getTempPath();
86
+ await mkdir(baseDir, { recursive: true });
87
+ const realBaseDir = await realpath(baseDir);
88
+ return await mkdtemp(join(realBaseDir, prefix));
89
+ }
90
+
91
+ getCachePath(...subpaths: string[]) {
92
+ return join(this.userDataPath, "cache", ...subpaths);
93
+ }
94
+
95
+ getPnpmPath(...subpaths: string[]) {
96
+ return join(this.userDataPath, "pnpm", ...subpaths);
97
+ }
98
+
99
+ getNodePath(version = DEFAULT_NODE_VERSION) {
100
+ const isWindows = process.platform === "win32";
101
+ return this.getThirdPartyPath("node", version, isWindows ? "node.exe" : "bin/node");
102
+ }
103
+
104
+ getPnpmBinPath(version = DEFAULT_PNPM_VERSION) {
105
+ return this.getPackagesPath("pnpm", version, "bin", "pnpm.cjs");
106
+ }
107
+
108
+ getSandboxFolders(): Array<{ name: SandboxFolder; label: string; path: string }> {
109
+ const foldersRecord: Record<SandboxFolder, { label: string; path: string }> = {
110
+ [SandboxFolder.Packages]: { label: "Packages", path: this.getPackagesPath() },
111
+ [SandboxFolder.ThirdParty]: { label: "Third-Party Tools", path: this.getThirdPartyPath() },
112
+ [SandboxFolder.Config]: { label: "Configuration", path: this.getConfigPath() },
113
+ [SandboxFolder.Temp]: { label: "Temporary Files", path: this.getTempPath() },
114
+ [SandboxFolder.Cache]: { label: "Cache", path: this.getCachePath() },
115
+ [SandboxFolder.Pnpm]: { label: "PNPM Home", path: this.getPnpmPath() },
116
+ };
117
+
118
+ return (Object.keys(foldersRecord) as SandboxFolder[]).map((key) => ({
119
+ name: key,
120
+ ...foldersRecord[key],
121
+ }));
122
+ }
74
123
  }
@@ -1,11 +1,11 @@
1
1
  import { PipelabContext } from "../context";
2
2
  import { join } from "node:path";
3
3
  import { writeFile, readFile, unlink, mkdir, stat, readdir } from "node:fs/promises";
4
- import { tmpdir } from "node:os";
5
4
  import { useLogger, BuildHistoryEntry, IBuildHistoryStorage, AppConfig } from "@pipelab/shared";
6
5
  import { setupConfigFile } from "../config";
7
6
  import checkDiskSpace from "check-disk-space";
8
7
  import { getFolderSize } from "../utils/fs-extras";
8
+ import { SandboxFolder } from "@pipelab/constants";
9
9
 
10
10
  // Simplified storage - one file per pipeline containing array of build entries
11
11
 
@@ -294,6 +294,7 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
294
294
  total: number;
295
295
  free: number;
296
296
  pipelab: number;
297
+ folders: Array<{ name: SandboxFolder; label: string; size: number }>;
297
298
  };
298
299
  }> {
299
300
  try {
@@ -303,6 +304,16 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
303
304
  const diskSpace = await checkDiskSpace(this.context.userDataPath);
304
305
  const pipelabSize = await getFolderSize(this.context.userDataPath);
305
306
 
307
+ const folders = [];
308
+ for (const folder of this.context.getSandboxFolders()) {
309
+ const size = await getFolderSize(folder.path);
310
+ folders.push({
311
+ name: folder.name,
312
+ label: folder.label,
313
+ size,
314
+ });
315
+ }
316
+
306
317
  const settings = await setupConfigFile<AppConfig>("settings", { context: this.context });
307
318
  const config = await settings.getConfig();
308
319
  const policy = config?.buildHistory?.retentionPolicy || {
@@ -326,6 +337,7 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
326
337
  total: diskSpace.size,
327
338
  free: diskSpace.free,
328
339
  pipelab: pipelabSize,
340
+ folders,
329
341
  },
330
342
  };
331
343
  }
@@ -359,6 +371,7 @@ export class BuildHistoryStorage implements IBuildHistoryStorage {
359
371
  total: diskSpace.size,
360
372
  free: diskSpace.free,
361
373
  pipelab: pipelabSize,
374
+ folders,
362
375
  },
363
376
  };
364
377
  } catch (error) {
@@ -4,8 +4,7 @@ import { useLogger } from "@pipelab/shared";
4
4
  import { getFinalPlugins, executeGraphWithHistory } from "../utils";
5
5
  import { presets } from "../presets/list";
6
6
  import { handleActionExecute } from "../handler-func";
7
- import { generateTempFolder } from "../utils/fs-extras";
8
- import { tmpdir } from "node:os";
7
+ import { join } from "node:path";
9
8
  import { setupConfigFile } from "../config";
10
9
  import { AppConfig } from "@pipelab/shared";
11
10
 
@@ -82,10 +81,10 @@ export const registerEngineHandlers = (context: PipelabContext) => {
82
81
  const settings = await setupConfigFile<AppConfig>("settings", { context });
83
82
  const config = await settings.getConfig();
84
83
 
85
- const cachePath = config?.cacheFolder || tmpdir();
86
- const cwd = await generateTempFolder(cachePath);
84
+ const cachePath = join(context.userDataPath, "cache", "actions", pluginId, nodeId);
85
+ const cwd = await context.createTempFolder("action-execute-");
87
86
 
88
- const mainWindow = undefined;
87
+ const mainWindow: undefined = undefined;
89
88
  abortControllerGraph = new AbortController();
90
89
 
91
90
  const signalPromise = new Promise((resolve, reject) => {
@@ -145,9 +144,9 @@ export const registerEngineHandlers = (context: PipelabContext) => {
145
144
  const effectiveProjectName = projectName || "Unnamed Project";
146
145
  const effectiveProjectPath = projectPath || "";
147
146
  const effectivePipelineId = pipelineId || "unknown";
148
- const effectiveCachePath = config?.cacheFolder || tmpdir();
147
+ const effectiveCachePath = join(context.userDataPath, "cache", effectivePipelineId);
149
148
 
150
- const mainWindow = undefined;
149
+ const mainWindow: undefined = undefined;
151
150
  abortControllerGraph = new AbortController();
152
151
 
153
152
  try {
@@ -304,7 +304,7 @@ export const registerHistoryHandlers = (context: PipelabContext) => {
304
304
  },
305
305
  };
306
306
 
307
- await settings.saveConfig(newConfig);
307
+ await settings.setConfig(newConfig);
308
308
 
309
309
  send({
310
310
  type: "end",
@@ -249,17 +249,12 @@ export const registerPluginsHandlers = (context: PipelabContext) => {
249
249
  // Ensures all required plugin IDs are loaded, JIT-installing any that are missing.
250
250
  // Called before opening a pipeline in the editor.
251
251
  handle("plugin:ensure-loaded", async (_, { send, value }) => {
252
- const { pluginIds, plugins } = value;
252
+ const { plugins } = value;
253
253
  const { plugins: registeredPlugins, registerPlugins } = usePlugins();
254
254
  const loaded: string[] = [];
255
255
  const failed: string[] = [];
256
256
 
257
257
  const pluginsToEnsure = new Set<string>();
258
- if (Array.isArray(pluginIds)) {
259
- for (const id of pluginIds) {
260
- if (id) pluginsToEnsure.add(id);
261
- }
262
- }
263
258
  if (plugins && typeof plugins === "object") {
264
259
  for (const id of Object.keys(plugins)) {
265
260
  if (id) pluginsToEnsure.add(id);
package/src/migrations.ts CHANGED
@@ -1,12 +1,7 @@
1
1
  import { useAPI } from "./ipc-core";
2
2
  import { PipelabContext } from "./context";
3
- import { setupConfigFile } from "./config";
4
- import {
5
- savedFileMigrator,
6
- fileRepoMigrations,
7
- appSettingsMigrator,
8
- useLogger,
9
- } from "@pipelab/shared";
3
+ import { setupConfigFile, getMigrator } from "./config";
4
+ import { useLogger } from "@pipelab/shared";
10
5
 
11
6
  /**
12
7
  * Registers migration handlers for the CLI/Standalone server.
@@ -23,14 +18,7 @@ export function registerMigrationHandlers(context: PipelabContext) {
23
18
 
24
19
  try {
25
20
  // Determine which migrator to use
26
- let migrator: any = null;
27
- if (name === "projects") {
28
- migrator = fileRepoMigrations;
29
- } else if (name === "settings") {
30
- migrator = appSettingsMigrator;
31
- } else if (name.startsWith("pipeline-") || name.endsWith(".plb")) {
32
- migrator = savedFileMigrator;
33
- }
21
+ const migrator = getMigrator(name);
34
22
 
35
23
  if (!migrator) {
36
24
  throw new Error(
@@ -203,7 +203,7 @@ export async function findInstalledPlugins(
203
203
  return installed;
204
204
  }
205
205
 
206
- export const builtInPlugins = async (options: { context: PipelabContext }) => {
206
+ export const builtInPlugins = async (options: { context: PipelabContext }): Promise<void> => {
207
207
  console.log("[Plugins] Starting background plugin loading...");
208
208
 
209
209
  // Pre-ensure Node.js and PNPM once in parallel so plugins don't have to wait for them
@@ -318,6 +318,4 @@ export const builtInPlugins = async (options: { context: PipelabContext }) => {
318
318
  webSocketServer.broadcast("startup:progress", { type: "ready" });
319
319
  }, 2000);
320
320
  })();
321
-
322
- return [];
323
321
  };
package/src/runner.ts CHANGED
@@ -3,7 +3,6 @@ import { setupConfigFile } from "./config";
3
3
  import { isDev, PipelabContext } from "./context";
4
4
  import { readFile, access, writeFile, mkdir } from "node:fs/promises";
5
5
  import { resolve, isAbsolute, join, dirname } from "node:path";
6
- import { tmpdir } from "node:os";
7
6
  import { savedFileMigrator } from "@pipelab/shared";
8
7
  import type { AppConfig } from "@pipelab/shared";
9
8
  import { registerMigrationHandlers } from "./migrations";
package/src/server.ts CHANGED
@@ -11,6 +11,7 @@ import { existsSync } from "node:fs";
11
11
  import { readFile } from "node:fs/promises";
12
12
  import { join } from "node:path";
13
13
  import http from "http";
14
+ // @ts-expect-error serve-handler has no type definitions
14
15
  import handler from "serve-handler";
15
16
  import { registerMigrationHandlers } from "./migrations";
16
17
 
@@ -35,6 +35,7 @@ export type ActionRunnerData<ACTION extends Action> = {
35
35
  setMeta: (callback: (data: ACTION["meta"]) => ACTION["meta"]) => void;
36
36
  meta: ACTION["meta"];
37
37
  cwd: string;
38
+ /** @deprecated Use `context` instead to resolve sandboxed folders and binary paths. */
38
39
  paths: {
39
40
  cache: string;
40
41
  pnpm: string;
@@ -1,17 +1,7 @@
1
- import { mkdir, createWriteStream, createReadStream } from "node:fs";
1
+ import { createWriteStream } from "node:fs";
2
2
  import { execa, Options, Subprocess } from "execa";
3
- import {
4
- mkdir as mkdirP,
5
- access,
6
- writeFile,
7
- realpath,
8
- mkdtemp,
9
- chmod,
10
- stat,
11
- readdir,
12
- } from "node:fs/promises";
3
+ import { mkdir as mkdirP, writeFile, stat, readdir } from "node:fs/promises";
13
4
  import { join, dirname } from "node:path";
14
- import { tmpdir } from "node:os";
15
5
  import tar from "tar";
16
6
  import yauzl from "yauzl";
17
7
  import archiver from "archiver";
@@ -32,17 +22,6 @@ export const ensure = async (filesPath: string, defaultContent = "{}") => {
32
22
  }
33
23
  };
34
24
 
35
- /**
36
- * Generates a unique temporary folder.
37
- */
38
- export const generateTempFolder = async (base?: string) => {
39
- const targetBase = base || tmpdir();
40
- await mkdirP(targetBase, { recursive: true });
41
- const realPath = await realpath(targetBase);
42
- const tempFolder = await mkdtemp(join(realPath, "pipelab-"));
43
- return tempFolder;
44
- };
45
-
46
25
  /**
47
26
  * Extracts a .tar.gz archive.
48
27
  */