@pipelab/core-node 1.0.0-beta.17 → 1.0.0-beta.18

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.
@@ -299,24 +299,22 @@ export const builtInPlugins = async (options: { context: PipelabContext }): Prom
299
299
  console.log(`[Plugins] Total plugins to load on startup:`, Array.from(pluginsToLoad.entries()));
300
300
 
301
301
  // Now load all collected plugins in parallel
302
- const loadPromises = Array.from(pluginsToLoad.entries()).map(
303
- async ([packageName, version]) => {
304
- sendStartupProgress(`Loading plugin: ${packageName}`);
305
- const pluginStart = Date.now();
306
- try {
307
- const plugin = await loadCustomPlugin(packageName, version, options);
308
- if (plugin) {
309
- registerPlugins([plugin]);
310
- webSocketServer.broadcast("plugin:loaded", { plugin });
311
- console.log(
312
- `[Plugins] Loaded ${packageName}@${version} in ${Date.now() - pluginStart}ms`,
313
- );
314
- }
315
- } catch (err) {
316
- console.error(`[Plugins] Failed to load plugin ${packageName} at startup:`, err);
302
+ const loadPromises = Array.from(pluginsToLoad.entries()).map(async ([packageName, version]) => {
303
+ sendStartupProgress(`Loading plugin: ${packageName}`);
304
+ const pluginStart = Date.now();
305
+ try {
306
+ const plugin = await loadCustomPlugin(packageName, version, options);
307
+ if (plugin) {
308
+ registerPlugins([plugin]);
309
+ webSocketServer.broadcast("plugin:loaded", { plugin });
310
+ console.log(
311
+ `[Plugins] Loaded ${packageName}@${version} in ${Date.now() - pluginStart}ms`,
312
+ );
317
313
  }
318
- },
319
- );
314
+ } catch (err) {
315
+ console.error(`[Plugins] Failed to load plugin ${packageName} at startup:`, err);
316
+ }
317
+ });
320
318
  await Promise.all(loadPromises);
321
319
 
322
320
  console.log(`[Plugins] All startup plugins loaded in ${Date.now() - totalStart}ms.`);
package/src/runner.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { executeGraphWithHistory } from "./utils";
2
2
  import { setupConfigFile } from "./config";
3
- import { isDev, PipelabContext } from "./context";
3
+ import { isDev, PipelabContext, CacheFolder } from "./context";
4
4
  import { readFile, access, writeFile, mkdir } from "node:fs/promises";
5
5
  import { resolve, isAbsolute, join, dirname } from "node:path";
6
6
  import { savedFileMigrator } from "@pipelab/shared";
@@ -67,9 +67,7 @@ export async function runPipelineCommand(file: string, options: RunOptions, vers
67
67
  await registerAllHandlers({ version, context });
68
68
  registerMigrationHandlers(context);
69
69
 
70
- const settings = await setupConfigFile<AppConfig>("settings", { context });
71
- const config = await settings.getConfig();
72
- const cachePath = join(context.userDataPath, "cache");
70
+ const cachePath = context.getCachePath(CacheFolder.Pipelines, effectivePipelineId);
73
71
  await mkdir(cachePath, { recursive: true });
74
72
 
75
73
  const abortController = new AbortController();
package/src/server.ts CHANGED
@@ -116,6 +116,7 @@ export async function serveCommand(options: ServeOptions, version: string, _dirn
116
116
 
117
117
  return handler(request, response, {
118
118
  public: rawAssetFolder,
119
+ rewrites: [{ source: "/**", destination: "/index.html" }],
119
120
  });
120
121
  });
121
122
 
@@ -29,7 +29,7 @@ describe("GitHub Release Updates API", () => {
29
29
  expect(releases).toEqual([]);
30
30
  expect(fetchSpy).toHaveBeenCalledWith(
31
31
  expect.stringContaining("matching-refs/tags/%40pipelab%2Fapp"),
32
- expect.any(Object)
32
+ expect.any(Object),
33
33
  );
34
34
  });
35
35
 
@@ -153,7 +153,7 @@ describe("GitHub Release Updates API", () => {
153
153
  expect(releases[0].tag_name).toBe("@pipelab/app@1.2.3");
154
154
  expect(fetchSpy).toHaveBeenCalledWith(
155
155
  expect.stringContaining("releases/tags/%40pipelab%2Fapp%401.2.3"),
156
- expect.any(Object)
156
+ expect.any(Object),
157
157
  );
158
158
  });
159
159
 
@@ -189,9 +189,7 @@ describe("GitHub Release Updates API", () => {
189
189
  // Mock matching refs
190
190
  fetchSpy.mockResolvedValueOnce({
191
191
  ok: true,
192
- json: async () => [
193
- { ref: "refs/tags/@pipelab/app@3.0.0" },
194
- ],
192
+ json: async () => [{ ref: "refs/tags/@pipelab/app@3.0.0" }],
195
193
  } as any);
196
194
 
197
195
  // Mock release lookup
@@ -93,13 +93,16 @@ describe("remote utilities & offline mode", () => {
93
93
 
94
94
  test("fetchPipelabPlugin maps latest to releaseTag for official plugins", async () => {
95
95
  vi.advanceTimersByTime(30000); // Bypass 10s caching
96
- const context = new PipelabContext({ userDataPath: "/tmp/pipelab-test-remote", releaseTag: "beta" });
96
+ const context = new PipelabContext({
97
+ userDataPath: "/tmp/pipelab-test-remote",
98
+ releaseTag: "beta",
99
+ });
97
100
  const pluginName = "@pipelab/plugin-poki";
98
101
  const packageBaseDir = context.getPackagesPath(pluginName);
99
102
  const cachedVersionDir = path.join(packageBaseDir, "1.0.0-beta.15");
100
103
 
101
104
  vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
102
-
105
+
103
106
  vi.mocked(pacote.packument).mockResolvedValue({
104
107
  name: pluginName,
105
108
  versions: {
@@ -128,13 +131,16 @@ describe("remote utilities & offline mode", () => {
128
131
 
129
132
  test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if tag is missing", async () => {
130
133
  vi.advanceTimersByTime(40000); // Bypass 10s caching
131
- const context = new PipelabContext({ userDataPath: "/tmp/pipelab-test-remote-custom", releaseTag: "beta" });
134
+ const context = new PipelabContext({
135
+ userDataPath: "/tmp/pipelab-test-remote-custom",
136
+ releaseTag: "beta",
137
+ });
132
138
  const pluginName = "custom-cool-plugin";
133
139
  const packageBaseDir = context.getPackagesPath(pluginName);
134
140
  const cachedVersionDir = path.join(packageBaseDir, "2.0.0");
135
141
 
136
142
  vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
137
-
143
+
138
144
  vi.mocked(pacote.packument).mockResolvedValue({
139
145
  name: pluginName,
140
146
  versions: {
@@ -163,13 +169,16 @@ describe("remote utilities & offline mode", () => {
163
169
 
164
170
  test("fetchPipelabPlugin maps latest to releaseTag for custom plugins and falls back to latest if beta is stale", async () => {
165
171
  vi.advanceTimersByTime(50000); // Bypass 10s caching
166
- const context = new PipelabContext({ userDataPath: "/tmp/pipelab-test-remote-stale", releaseTag: "beta" });
172
+ const context = new PipelabContext({
173
+ userDataPath: "/tmp/pipelab-test-remote-stale",
174
+ releaseTag: "beta",
175
+ });
167
176
  const pluginName = "stale-beta-plugin";
168
177
  const packageBaseDir = context.getPackagesPath(pluginName);
169
178
  const cachedVersionDir = path.join(packageBaseDir, "2.0.0");
170
179
 
171
180
  vi.spyOn(dns, "lookup").mockResolvedValue({ address: "1.2.3.4", family: 4 } as any);
172
-
181
+
173
182
  vi.mocked(pacote.packument).mockResolvedValue({
174
183
  name: pluginName,
175
184
  versions: {
@@ -14,7 +14,7 @@ import { existsSync, constants, statSync, readdirSync } from "node:fs";
14
14
  import dns from "node:dns/promises";
15
15
  import pacote from "pacote";
16
16
  import semver from "semver";
17
- import { isDev, projectRoot, PipelabContext } from "../context";
17
+ import { isDev, projectRoot, PipelabContext, CacheFolder } from "../context";
18
18
  import { execa } from "execa";
19
19
  import { sendStartupProgress } from "../server";
20
20
  import { downloadFile, extractZip, extractTarGz } from "./fs-extras";
@@ -163,7 +163,7 @@ export async function fetchPackage(
163
163
  } else {
164
164
  try {
165
165
  // 1. Resolve version/range using npm with session-wide memoization and disk cache
166
- const cachePath = join(ctx.userDataPath, "cache", "pacote");
166
+ const cachePath = ctx.getCachePath(CacheFolder.Pacote);
167
167
  let packumentPromise = packumentRequests.get(packageName);
168
168
  if (!packumentPromise) {
169
169
  packumentPromise = pacote.packument(packageName, { cache: cachePath });
@@ -183,7 +183,10 @@ export async function fetchPackage(
183
183
  if (range === "latest" && ctx.releaseTag && ctx.releaseTag !== "latest") {
184
184
  const releaseTagVersion = packument["dist-tags"]?.[ctx.releaseTag];
185
185
  if (releaseTagVersion && semver.valid(releaseTagVersion)) {
186
- if (!foundVersion || (semver.valid(foundVersion) && semver.gte(releaseTagVersion, foundVersion))) {
186
+ if (
187
+ !foundVersion ||
188
+ (semver.valid(foundVersion) && semver.gte(releaseTagVersion, foundVersion))
189
+ ) {
187
190
  console.log(
188
191
  `[Fetcher] Using release tag "${ctx.releaseTag}" (${releaseTagVersion}) instead of "latest" (${foundVersion || "none"}) for ${packageName}`,
189
192
  );
@@ -227,7 +230,7 @@ export async function fetchPackage(
227
230
  }
228
231
  }
229
232
 
230
- const cachePath = join(ctx.userDataPath, "cache", "pacote");
233
+ const cachePath = ctx.getCachePath(CacheFolder.Pacote);
231
234
  const packageDir = join(baseDir, resolvedVersion);
232
235
 
233
236
  const checkStart = Date.now();
@@ -351,7 +354,7 @@ export async function runPnpm(
351
354
  ...process.env,
352
355
  NODE_ENV: "production",
353
356
  PATH: nodePath ? `${dirname(nodePath)}${delimiter}${process.env.PATH}` : process.env.PATH,
354
- PNPM_HOME: join(ctx.userDataPath, "pnpm"),
357
+ PNPM_HOME: ctx.getPnpmPath(),
355
358
  PNPM_ONLY_ALLOW_TRUSTED_DEPENDENCIES: "false",
356
359
  ...extraEnv,
357
360
  },
@@ -12,7 +12,8 @@ export class JsonFileStorage {
12
12
  private logger = useLogger().logger;
13
13
 
14
14
  constructor(fileName: string, context: PipelabContext) {
15
- this.filePath = path.join(context.userDataPath, fileName);
15
+ this.filePath = context.getConfigPath(fileName);
16
+
16
17
  const dir = path.dirname(this.filePath);
17
18
  if (!fs.existsSync(dir)) {
18
19
  try {
package/src/utils.ts CHANGED
@@ -102,6 +102,7 @@ export const executeGraphWithHistory = async ({
102
102
  projectName,
103
103
  projectPath,
104
104
  pipelineId,
105
+ cachePath,
105
106
  startTime,
106
107
  status: "running",
107
108
  logs: [],
@@ -247,18 +248,17 @@ export const executeGraphWithHistory = async ({
247
248
 
248
249
  throw error;
249
250
  } finally {
250
- // Apply retention policy regardless of outcome
251
- if (!shouldDisableHistory) {
252
- // Don't await, let it run in the background
253
- buildHistoryStorage.applyRetentionPolicy();
254
- }
255
-
256
251
  if (shouldCleanup) {
257
252
  try {
258
253
  await rm(sandboxPath, { recursive: true, force: true });
259
254
  } catch (e) {
260
255
  console.warn(`Failed to cleanup sandbox at ${sandboxPath}:`, e);
261
256
  }
257
+ try {
258
+ await rm(cachePath, { recursive: true, force: true });
259
+ } catch (e) {
260
+ console.warn(`Failed to cleanup cache at ${cachePath}:`, e);
261
+ }
262
262
  }
263
263
  }
264
264
  };