@pipelab/core-node 1.0.0-beta.10 → 1.0.0-beta.11

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.10",
3
+ "version": "1.0.0-beta.11",
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.8",
44
- "@pipelab/shared": "1.0.0-beta.6"
43
+ "@pipelab/constants": "1.0.0-beta.9",
44
+ "@pipelab/shared": "1.0.0-beta.7"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/adm-zip": "0.5.7",
@@ -54,7 +54,7 @@
54
54
  "@types/yauzl": "2.10.3",
55
55
  "tsdown": "0.21.2",
56
56
  "typescript": "^5.0.0",
57
- "@pipelab/tsconfig": "1.0.0-beta.6"
57
+ "@pipelab/tsconfig": "1.0.0-beta.7"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsdown",
@@ -30,7 +30,7 @@ const PACKAGES = [
30
30
  "@pipelab/asset-discord",
31
31
  "@pipelab/asset-electron",
32
32
  "@pipelab/asset-netlify",
33
- "@pipelab/asset-tauri"
33
+ "@pipelab/asset-tauri",
34
34
  ];
35
35
 
36
36
  async function simulate() {
@@ -44,7 +44,9 @@ async function simulate() {
44
44
  const stableApp = await fetchLatestDesktopRelease({ allowPrerelease: false });
45
45
  const betaApp = await fetchLatestDesktopRelease({ allowPrerelease: true });
46
46
 
47
- console.log(`[STABLE] Resolved version: ${stableApp ? stableApp.tag_name : "None (Stable users protected)"}`);
47
+ console.log(
48
+ `[STABLE] Resolved version: ${stableApp ? stableApp.tag_name : "None (Stable users protected)"}`,
49
+ );
48
50
  console.log(`[BETA] Resolved version: ${betaApp ? betaApp.tag_name : "None"}`);
49
51
  } catch (error) {
50
52
  console.error("Failed to fetch desktop releases from GitHub:", error);
@@ -99,14 +101,14 @@ async function simulate() {
99
101
  package: pkg,
100
102
  stable: stableVersion,
101
103
  beta: betaVersion,
102
- notes
104
+ notes,
103
105
  });
104
106
  } catch (error: any) {
105
107
  results.push({
106
108
  package: pkg,
107
109
  stable: "ERROR",
108
110
  beta: "ERROR",
109
- notes: `Failed to fetch: ${error.message}`
111
+ notes: `Failed to fetch: ${error.message}`,
110
112
  });
111
113
  }
112
114
  }
@@ -21,12 +21,19 @@ const DEFAULT_PLUGIN_IDS = [
21
21
  ];
22
22
 
23
23
  export const loadPipelabPlugin = async (id: string, options: { context: PipelabContext }) => {
24
+ const start = Date.now();
24
25
  try {
25
26
  const packageName = `@pipelab/plugin-${id}`;
26
- const { packageDir, entryPoint } = await fetchPipelabPlugin(packageName, options.context.releaseTag, {
27
- context: options.context,
28
- installDeps: false,
29
- });
27
+ const fetchStart = Date.now();
28
+ const { packageDir, entryPoint } = await fetchPipelabPlugin(
29
+ packageName,
30
+ options.context.releaseTag,
31
+ {
32
+ context: options.context,
33
+ installDeps: false,
34
+ },
35
+ );
36
+ const fetchDuration = Date.now() - fetchStart;
30
37
 
31
38
  console.log(`[Plugins] [${id}] Attempting to import from: ${entryPoint}`);
32
39
  if (!existsSync(entryPoint)) {
@@ -37,11 +44,16 @@ export const loadPipelabPlugin = async (id: string, options: { context: PipelabC
37
44
  } catch (e) {}
38
45
  }
39
46
 
47
+ const importStart = Date.now();
40
48
  const pluginModule = await import(pathToFileURL(entryPoint).href);
41
- console.log(`[Plugins] [${id}] Successfully loaded from: ${packageDir}`);
49
+ const importDuration = Date.now() - importStart;
50
+ const totalDuration = Date.now() - start;
51
+ console.log(
52
+ `[Plugins] [${id}] Successfully loaded from: ${packageDir} (fetch: ${fetchDuration}ms, import: ${importDuration}ms, total: ${totalDuration}ms)`,
53
+ );
42
54
  return pluginModule.default;
43
55
  } catch (e: any) {
44
- console.error(`[Plugins] [${id}] CRITICAL: Failed to load:`, e);
56
+ console.error(`[Plugins] [${id}] CRITICAL: Failed to load after ${Date.now() - start}ms:`, e);
45
57
  if (e.code === "ERR_MODULE_NOT_FOUND") {
46
58
  console.error(
47
59
  `[Plugins] [${id}] This usually means a dependency is missing in the plugin's node_modules.`,
@@ -56,7 +68,9 @@ export const builtInPlugins = async (options: { context: PipelabContext }) => {
56
68
 
57
69
  // Pre-ensure Node.js and PNPM once in parallel so plugins don't have to wait for them
58
70
  sendStartupProgress("Preparing environment...");
71
+ const envStart = Date.now();
59
72
  await Promise.all([ensureNodeJS(options.context), ensurePNPM(options.context)]);
73
+ console.log(`[Plugins] Environment preparation took ${Date.now() - envStart}ms`);
60
74
 
61
75
  const { usePlugins } = await import("@pipelab/shared");
62
76
  const { registerPlugins } = usePlugins();
@@ -64,15 +78,20 @@ export const builtInPlugins = async (options: { context: PipelabContext }) => {
64
78
 
65
79
  // Load plugins asynchronously in the background
66
80
  (async () => {
81
+ const totalStart = Date.now();
67
82
  for (const id of DEFAULT_PLUGIN_IDS) {
68
83
  sendStartupProgress(`Loading plugin: ${id}`);
84
+ const pluginStart = Date.now();
69
85
  const plugin = await loadPipelabPlugin(id, options);
86
+ console.log(
87
+ `[Plugins] [${id}] loadPipelabPlugin loop step took ${Date.now() - pluginStart}ms`,
88
+ );
70
89
  if (plugin) {
71
90
  registerPlugins([plugin]);
72
91
  webSocketServer.broadcast("plugin:loaded", { plugin });
73
92
  }
74
93
  }
75
- console.log("[Plugins] All default plugins loaded.");
94
+ console.log(`[Plugins] All default plugins loaded in ${Date.now() - totalStart}ms.`);
76
95
  sendStartupProgress("All plugins loaded.");
77
96
  setTimeout(() => {
78
97
  webSocketServer.broadcast("startup:progress", { type: "ready" });
@@ -1,6 +1,16 @@
1
1
  import { dirname, delimiter, join } from "node:path";
2
2
  import { tmpdir } from "node:os";
3
- import { mkdir, readdir, readFile, writeFile, access, chmod, rm, cp, rename } from "node:fs/promises";
3
+ import {
4
+ mkdir,
5
+ readdir,
6
+ readFile,
7
+ writeFile,
8
+ access,
9
+ chmod,
10
+ rm,
11
+ cp,
12
+ rename,
13
+ } from "node:fs/promises";
4
14
  import { existsSync, constants, statSync, readdirSync } from "node:fs";
5
15
  import pacote from "pacote";
6
16
  import semver from "semver";
@@ -80,12 +90,16 @@ export async function fetchPackage(
80
90
  isLocal?: boolean;
81
91
  entryPoint?: string;
82
92
  }> {
93
+ const start = Date.now();
83
94
  // 0. Check for local monorepo package in development
84
95
  if (isDev && projectRoot && process.env.PIPELAB_FORCE_NPM !== "true") {
85
96
  if (packageName.startsWith("@pipelab/")) {
97
+ const localStart = Date.now();
86
98
  const local = await tryResolveMonorepoPackage(packageName);
87
99
  if (local) {
88
- console.log(`[Fetcher] ${packageName}: Resolved to local source at ${local.packageDir}`);
100
+ console.log(
101
+ `[Fetcher] ${packageName}: Resolved to local source at ${local.packageDir} (${Date.now() - localStart}ms)`,
102
+ );
89
103
  return {
90
104
  ...local,
91
105
  resolvedVersion: "workspace",
@@ -99,6 +113,7 @@ export async function fetchPackage(
99
113
  let resolvedVersion: string;
100
114
 
101
115
  console.log(`[Fetcher] Resolving ${packageName}@${versionOrRange || "latest"}...`);
116
+ const resolveStart = Date.now();
102
117
 
103
118
  try {
104
119
  // 1. Resolve version/range using npm with session-wide memoization and disk cache
@@ -122,12 +137,20 @@ export async function fetchPackage(
122
137
  );
123
138
  }
124
139
  resolvedVersion = foundVersion;
125
- console.log(`[Fetcher] ${packageName}: Resolved to v${resolvedVersion} via npm`);
140
+ console.log(
141
+ `[Fetcher] ${packageName}: Resolved to v${resolvedVersion} via npm (${Date.now() - resolveStart}ms)`,
142
+ );
126
143
  } catch (error) {
127
- console.warn(`[Fetcher] ${packageName}: remote resolution failed, trying local fallback...`);
144
+ console.warn(
145
+ `[Fetcher] ${packageName}: remote resolution failed (${Date.now() - resolveStart}ms), trying local fallback...`,
146
+ );
147
+ const fallbackStart = Date.now();
128
148
  const fallbackVersion = await tryLocalFallback(versionOrRange, error, baseDir, packageName);
129
149
  if (fallbackVersion) {
130
150
  resolvedVersion = fallbackVersion;
151
+ console.log(
152
+ `[Fetcher] ${packageName}: Resolved to local fallback ${resolvedVersion} (${Date.now() - fallbackStart}ms)`,
153
+ );
131
154
  } else {
132
155
  throw error;
133
156
  }
@@ -136,12 +159,17 @@ export async function fetchPackage(
136
159
  const cachePath = join(ctx.userDataPath, "cache", "pacote");
137
160
  const packageDir = join(baseDir, resolvedVersion);
138
161
 
162
+ const checkStart = Date.now();
139
163
  // If the package already exists and we don't need to install dependencies (or they are already installed), return immediately
140
164
  const isInstalled = options?.installDeps
141
- ? (isPackageComplete(packageDir) && isDependenciesInstalledSync(packageDir))
165
+ ? isPackageComplete(packageDir) && isDependenciesInstalledSync(packageDir)
142
166
  : isPackageComplete(packageDir);
167
+ const checkDuration = Date.now() - checkStart;
143
168
 
144
169
  if (isInstalled) {
170
+ console.log(
171
+ `[Fetcher] ${packageName}@${resolvedVersion}: Already installed (check took ${checkDuration}ms, fetchPackage took ${Date.now() - start}ms)`,
172
+ );
145
173
  return { packageDir, resolvedVersion };
146
174
  }
147
175
 
@@ -149,8 +177,12 @@ export async function fetchPackage(
149
177
  return withLock(lockKey, async () => {
150
178
  if (!isPackageComplete(packageDir)) {
151
179
  console.log(`[Fetcher] ${packageName}@${resolvedVersion}: Downloading to ${packageDir}...`);
152
-
153
- const tempDir = join(baseDir, `.tmp-${resolvedVersion}-${Math.random().toString(36).slice(2)}`);
180
+ const downloadStart = Date.now();
181
+
182
+ const tempDir = join(
183
+ baseDir,
184
+ `.tmp-${resolvedVersion}-${Math.random().toString(36).slice(2)}`,
185
+ );
154
186
  await mkdir(tempDir, { recursive: true });
155
187
  try {
156
188
  await pacote.extract(`${packageName}@${resolvedVersion}`, tempDir, {
@@ -175,6 +207,9 @@ export async function fetchPackage(
175
207
  throw err;
176
208
  }
177
209
  }
210
+ console.log(
211
+ `[Fetcher] ${packageName}@${resolvedVersion}: Downloaded and extracted in ${Date.now() - downloadStart}ms`,
212
+ );
178
213
  } catch (err) {
179
214
  await rm(tempDir, { recursive: true, force: true }).catch(() => {});
180
215
  throw err;
@@ -182,12 +217,23 @@ export async function fetchPackage(
182
217
  }
183
218
 
184
219
  // 2. Resolve entry point from package.json for downloaded package
220
+ const entryStart = Date.now();
185
221
  const entryPoint = await resolveEntryPoint(packageDir, packageName);
222
+ console.log(
223
+ `[Fetcher] ${packageName}@${resolvedVersion}: Resolved entry point in ${Date.now() - entryStart}ms`,
224
+ );
186
225
 
187
226
  if (options?.installDeps) {
227
+ const depsStart = Date.now();
188
228
  await installDependencies(packageDir, packageName, options);
229
+ console.log(
230
+ `[Fetcher] ${packageName}@${resolvedVersion}: Installed dependencies in ${Date.now() - depsStart}ms`,
231
+ );
189
232
  }
190
233
 
234
+ console.log(
235
+ `[Fetcher] ${packageName}@${resolvedVersion}: FetchPackage complete in ${Date.now() - start}ms`,
236
+ );
191
237
  return { packageDir, resolvedVersion, entryPoint };
192
238
  });
193
239
  }
@@ -245,11 +291,15 @@ export async function runPnpm(
245
291
  * Installs a specific version of Node.js if not already present.
246
292
  */
247
293
  export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NODE_VERSION) {
294
+ const checkStart = Date.now();
248
295
  const isWindows = process.platform === "win32";
249
296
  const nodeDir = context.getThirdPartyPath("node", version);
250
297
  const finalNodePath = join(nodeDir, isWindows ? "node.exe" : "bin/node");
251
298
 
252
299
  if (isNodeJSComplete(finalNodePath)) {
300
+ console.log(
301
+ `[Environment] Node.js check took ${Date.now() - checkStart}ms (found at ${finalNodePath})`,
302
+ );
253
303
  return finalNodePath;
254
304
  }
255
305
 
@@ -269,10 +319,13 @@ export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NO
269
319
 
270
320
  sendStartupProgress(`Downloading Node.js v${version}...`);
271
321
  console.log(`Downloading Node.js from ${downloadUrl}...`);
322
+ const dlStart = Date.now();
272
323
  await downloadFile(downloadUrl, archivePath);
324
+ console.log(`[Environment] Node.js download took ${Date.now() - dlStart}ms`);
273
325
 
274
326
  sendStartupProgress(`Extracting Node.js v${version}...`);
275
327
  console.log(`Extracting Node.js to ${tempDir}...`);
328
+ const extStart = Date.now();
276
329
  const extractTempDir = join(tempDir, "extracted");
277
330
  await mkdir(extractTempDir, { recursive: true });
278
331
 
@@ -290,7 +343,10 @@ export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NO
290
343
  const parentDir = dirname(nodeDir);
291
344
  await mkdir(parentDir, { recursive: true });
292
345
 
293
- const tempNodeDir = join(parentDir, `.tmp-node-${version}-${Math.random().toString(36).slice(2)}`);
346
+ const tempNodeDir = join(
347
+ parentDir,
348
+ `.tmp-node-${version}-${Math.random().toString(36).slice(2)}`,
349
+ );
294
350
  await mkdir(tempNodeDir, { recursive: true });
295
351
 
296
352
  try {
@@ -313,11 +369,13 @@ export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NO
313
369
  throw err;
314
370
  }
315
371
  }
372
+ console.log(`[Environment] Node.js extraction took ${Date.now() - extStart}ms`);
316
373
  } finally {
317
374
  await rm(tempNodeDir, { recursive: true, force: true }).catch(() => {});
318
375
  await rm(tempDir, { recursive: true, force: true }).catch(() => {});
319
376
  }
320
377
 
378
+ console.log(`[Environment] Node.js set up complete in ${Date.now() - checkStart}ms`);
321
379
  return finalNodePath;
322
380
  });
323
381
  }
@@ -326,10 +384,14 @@ export async function ensureNodeJS(context: PipelabContext, version = DEFAULT_NO
326
384
  * Installs the PNPM package from npm if not already present.
327
385
  */
328
386
  export async function ensurePNPM(context: PipelabContext, version = DEFAULT_PNPM_VERSION) {
387
+ const checkStart = Date.now();
329
388
  const pnpmDir = context.getPackagesPath("pnpm", version);
330
389
  const pnpmPath = join(pnpmDir, "bin", "pnpm.cjs");
331
390
 
332
391
  if (existsSync(pnpmPath)) {
392
+ console.log(
393
+ `[Environment] PNPM check took ${Date.now() - checkStart}ms (found at ${pnpmPath})`,
394
+ );
333
395
  return pnpmPath;
334
396
  }
335
397
 
@@ -340,11 +402,13 @@ export async function ensurePNPM(context: PipelabContext, version = DEFAULT_PNPM
340
402
  const { packageDir } = await fetchPackage("pnpm", version, {
341
403
  context,
342
404
  });
405
+ console.log(`[Environment] PNPM set up complete in ${Date.now() - checkStart}ms`);
343
406
  return join(packageDir, "bin", "pnpm.cjs");
344
407
  });
345
408
  }
346
409
 
347
410
  async function installDependencies(packageDir: string, packageName: string, options: FetchOptions) {
411
+ const start = Date.now();
348
412
  const nodeModulesPath = join(packageDir, "node_modules");
349
413
 
350
414
  if (isDependenciesInstalledSync(packageDir)) {
@@ -359,12 +423,14 @@ async function installDependencies(packageDir: string, packageName: string, opti
359
423
  try {
360
424
  // Copy package.json to tempDir so pnpm can install dependencies
361
425
  await cp(join(packageDir, "package.json"), join(tempDir, "package.json"));
362
-
426
+
363
427
  console.log(`[Fetcher] ${packageName}: Ensuring dependencies are installed...`);
428
+ const pnpmStart = Date.now();
364
429
  const { all } = await runPnpm(tempDir, {
365
430
  signal: options.signal,
366
431
  context: options.context,
367
432
  });
433
+ console.log(`[Fetcher] ${packageName}: pnpm install command took ${Date.now() - pnpmStart}ms`);
368
434
 
369
435
  if (all) console.log(`[Fetcher] ${packageName}: Installation trace:\n${all}`);
370
436
 
@@ -373,8 +439,11 @@ async function installDependencies(packageDir: string, packageName: string, opti
373
439
  if (existsSync(nodeModulesPath)) {
374
440
  await rm(nodeModulesPath, { recursive: true, force: true }).catch(() => {});
375
441
  }
442
+ const renameStart = Date.now();
376
443
  await rename(tempNodeModules, nodeModulesPath);
377
- console.log(`[Fetcher] ${packageName}: Dependencies installed successfully.`);
444
+ console.log(
445
+ `[Fetcher] ${packageName}: Dependencies installed successfully (rename took ${Date.now() - renameStart}ms, total installDependencies took ${Date.now() - start}ms).`,
446
+ );
378
447
  } catch (err: any) {
379
448
  console.error(
380
449
  `[Fetcher] ${packageName}: CRITICAL ERROR during dependency installation: ${err.message}`,