nx 22.5.0-beta.2 → 22.5.0-beta.3

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.
Files changed (42) hide show
  1. package/README.md +3 -3
  2. package/package.json +13 -13
  3. package/src/command-line/nx-commands.js +1 -1
  4. package/src/command-line/release/changelog/version-plan-filtering.d.ts +6 -3
  5. package/src/command-line/release/changelog/version-plan-filtering.d.ts.map +1 -1
  6. package/src/command-line/release/changelog/version-plan-filtering.js +4 -3
  7. package/src/command-line/release/changelog.d.ts.map +1 -1
  8. package/src/command-line/release/changelog.js +11 -9
  9. package/src/command-line/release/utils/git.d.ts +3 -2
  10. package/src/command-line/release/utils/git.d.ts.map +1 -1
  11. package/src/command-line/release/utils/git.js +3 -69
  12. package/src/command-line/release/utils/release-graph.d.ts +10 -0
  13. package/src/command-line/release/utils/release-graph.d.ts.map +1 -1
  14. package/src/command-line/release/utils/release-graph.js +32 -1
  15. package/src/command-line/release/utils/repository-git-tags.d.ts +26 -0
  16. package/src/command-line/release/utils/repository-git-tags.d.ts.map +1 -0
  17. package/src/command-line/release/utils/repository-git-tags.js +125 -0
  18. package/src/command-line/release/utils/resolve-semver-specifier.d.ts +2 -1
  19. package/src/command-line/release/utils/resolve-semver-specifier.d.ts.map +1 -1
  20. package/src/command-line/release/utils/resolve-semver-specifier.js +2 -2
  21. package/src/command-line/release/utils/shared.d.ts +3 -2
  22. package/src/command-line/release/utils/shared.d.ts.map +1 -1
  23. package/src/command-line/release/utils/shared.js +4 -10
  24. package/src/command-line/release/version/derive-specifier-from-conventional-commits.d.ts +2 -1
  25. package/src/command-line/release/version/derive-specifier-from-conventional-commits.d.ts.map +1 -1
  26. package/src/command-line/release/version/derive-specifier-from-conventional-commits.js +2 -2
  27. package/src/command-line/release/version/release-group-processor.d.ts.map +1 -1
  28. package/src/command-line/release/version/release-group-processor.js +1 -1
  29. package/src/core/graph/main.js +1 -1
  30. package/src/daemon/client/client.js +4 -4
  31. package/src/native/nx.wasm32-wasi.wasm +0 -0
  32. package/src/project-graph/plugins/get-plugins.d.ts.map +1 -1
  33. package/src/project-graph/plugins/get-plugins.js +81 -11
  34. package/src/project-graph/plugins/isolation/plugin-pool.d.ts.map +1 -1
  35. package/src/project-graph/plugins/isolation/plugin-pool.js +78 -27
  36. package/src/project-graph/plugins/isolation/plugin-worker.js +33 -17
  37. package/src/project-graph/project-graph.js +1 -1
  38. package/src/utils/consume-messages-from-socket.d.ts.map +1 -1
  39. package/src/utils/consume-messages-from-socket.js +3 -1
  40. package/src/utils/promised-based-queue.d.ts +0 -7
  41. package/src/utils/promised-based-queue.d.ts.map +1 -1
  42. package/src/utils/promised-based-queue.js +0 -9
@@ -790,13 +790,13 @@ class DaemonClient {
790
790
  this.establishConnection();
791
791
  // Resend the pending message if one exists
792
792
  if (this.currentMessage && this.currentResolve && this.currentReject) {
793
- // Decrement the queue counter that was incremented when the error occurred
794
- this.queue.decrementQueueCounter();
795
- // Retry the message through the normal queue
793
+ // Retry the message directly (not through the queue) to resolve the
794
+ // pending promise that the original queue entry is waiting on.
795
+ // This allows the original queue entry to complete naturally.
796
796
  const msg = this.currentMessage;
797
797
  const res = this.currentResolve;
798
798
  const rej = this.currentReject;
799
- this.sendToDaemonViaQueue(msg).then(res, rej);
799
+ this.sendMessageToDaemon(msg).then(res, rej);
800
800
  }
801
801
  }
802
802
  else {
Binary file
@@ -1 +1 @@
1
- {"version":3,"file":"get-plugins.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/project-graph/plugins/get-plugins.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAwBzD,wBAAsB,UAAU,CAC9B,IAAI,SAAgB,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CAwB3B;AAaD,wBAAsB,qBAAqB,CAAC,IAAI,SAAgB,6BAyB/D;AAED,wBAAgB,cAAc,SAK7B"}
1
+ {"version":3,"file":"get-plugins.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/project-graph/plugins/get-plugins.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAwBzD,wBAAsB,UAAU,CAC9B,IAAI,SAAgB,GACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CA6C3B;AAaD,wBAAsB,qBAAqB,CAAC,IAAI,SAAgB,6BAyB/D;AAED,wBAAgB,cAAc,SAK7B"}
@@ -31,10 +31,27 @@ async function getPlugins(root = workspace_root_1.workspaceRoot) {
31
31
  return loadedPlugins;
32
32
  }
33
33
  currentPluginsConfigurationHash = pluginsConfigurationHash;
34
- const [defaultPlugins, specifiedPlugins] = await Promise.all([
34
+ const results = await Promise.allSettled([
35
35
  getOnlyDefaultPlugins(root),
36
36
  (pendingPluginsPromise ??= loadSpecifiedNxPlugins(pluginsConfiguration, root)),
37
37
  ]);
38
+ const errors = [];
39
+ const defaultPlugins = [];
40
+ const specifiedPlugins = [];
41
+ for (let i = 0; i < results.length; i++) {
42
+ const result = results[i];
43
+ if (result.status === 'fulfilled') {
44
+ (i === 0 ? defaultPlugins : specifiedPlugins).push(...result.value);
45
+ }
46
+ else {
47
+ errors.push(result.reason instanceof Error
48
+ ? result.reason
49
+ : new Error(String(result.reason)));
50
+ }
51
+ }
52
+ if (errors.length > 0) {
53
+ throw new AggregateError(errors, errors.map((e) => e.message).join('\n'));
54
+ }
38
55
  loadedPlugins = specifiedPlugins.concat(defaultPlugins);
39
56
  return loadedPlugins;
40
57
  }
@@ -79,16 +96,42 @@ async function loadDefaultNxPlugins(root = workspace_root_1.workspaceRoot) {
79
96
  performance.mark('loadDefaultNxPlugins:start');
80
97
  const plugins = getDefaultPlugins(root);
81
98
  const cleanupFunctions = [];
99
+ const results = await Promise.allSettled(plugins.map(async (plugin) => {
100
+ performance.mark(`Load Nx Plugin: ${plugin} - start`);
101
+ const [loadedPluginPromise, cleanup] = await loadingMethod(plugin, root);
102
+ cleanupFunctions.push(cleanup);
103
+ const res = await loadedPluginPromise;
104
+ performance.mark(`Load Nx Plugin: ${plugin} - end`);
105
+ performance.measure(`Load Nx Plugin: ${plugin}`, `Load Nx Plugin: ${plugin} - start`, `Load Nx Plugin: ${plugin} - end`);
106
+ return res;
107
+ }));
108
+ const defaultPluginResults = [];
109
+ const errors = [];
110
+ for (let i = 0; i < results.length; i++) {
111
+ const result = results[i];
112
+ if (result.status === 'fulfilled') {
113
+ defaultPluginResults.push(result.value);
114
+ }
115
+ else {
116
+ errors.push({
117
+ pluginName: plugins[i],
118
+ error: result.reason instanceof Error
119
+ ? result.reason
120
+ : new Error(String(result.reason)),
121
+ });
122
+ }
123
+ }
124
+ if (errors.length > 0) {
125
+ for (const fn of cleanupFunctions) {
126
+ fn();
127
+ }
128
+ const errorMessage = errors
129
+ .map((e) => ` - ${e.pluginName}: ${e.error.message}`)
130
+ .join('\n');
131
+ throw new AggregateError(errors.map((e) => e.error), `Failed to load ${errors.length} default Nx plugin(s):\n${errorMessage}`);
132
+ }
82
133
  const ret = [
83
- await Promise.all(plugins.map(async (plugin) => {
84
- performance.mark(`Load Nx Plugin: ${plugin} - start`);
85
- const [loadedPluginPromise, cleanup] = await loadingMethod(plugin, root);
86
- cleanupFunctions.push(cleanup);
87
- const res = await loadedPluginPromise;
88
- performance.mark(`Load Nx Plugin: ${plugin} - end`);
89
- performance.measure(`Load Nx Plugin: ${plugin}`, `Load Nx Plugin: ${plugin} - start`, `Load Nx Plugin: ${plugin} - end`);
90
- return res;
91
- })),
134
+ defaultPluginResults,
92
135
  () => {
93
136
  for (const fn of cleanupFunctions) {
94
137
  fn();
@@ -111,7 +154,7 @@ async function loadSpecifiedNxPlugins(pluginsConfigurations, root = workspace_ro
111
154
  performance.mark('loadSpecifiedNxPlugins:start');
112
155
  pluginsConfigurations ??= [];
113
156
  const cleanupFunctions = [];
114
- const plugins = await Promise.all(pluginsConfigurations.map(async (plugin, index) => {
157
+ const results = await Promise.allSettled(pluginsConfigurations.map(async (plugin, index) => {
115
158
  const pluginPath = typeof plugin === 'string' ? plugin : plugin.plugin;
116
159
  performance.mark(`Load Nx Plugin: ${pluginPath} - start`);
117
160
  const [loadedPluginPromise, cleanup] = await loadingMethod(plugin, root, index);
@@ -124,6 +167,33 @@ async function loadSpecifiedNxPlugins(pluginsConfigurations, root = workspace_ro
124
167
  }));
125
168
  performance.mark('loadSpecifiedNxPlugins:end');
126
169
  performance.measure('loadSpecifiedNxPlugins', 'loadSpecifiedNxPlugins:start', 'loadSpecifiedNxPlugins:end');
170
+ const plugins = [];
171
+ const errors = [];
172
+ for (let i = 0; i < results.length; i++) {
173
+ const result = results[i];
174
+ if (result.status === 'fulfilled') {
175
+ plugins.push(result.value);
176
+ }
177
+ else {
178
+ const pluginConfig = pluginsConfigurations[i];
179
+ const pluginName = typeof pluginConfig === 'string' ? pluginConfig : pluginConfig.plugin;
180
+ errors.push({
181
+ pluginName,
182
+ error: result.reason instanceof Error
183
+ ? result.reason
184
+ : new Error(String(result.reason)),
185
+ });
186
+ }
187
+ }
188
+ if (errors.length > 0) {
189
+ for (const fn of cleanupFunctions) {
190
+ fn();
191
+ }
192
+ const errorMessage = errors
193
+ .map((e) => ` - ${e.pluginName}: ${e.error.message}`)
194
+ .join('\n');
195
+ throw new AggregateError(errors.map((e) => e.error), `Failed to load ${errors.length} Nx plugin(s):\n${errorMessage}`);
196
+ }
127
197
  cleanupSpecifiedPlugins = () => {
128
198
  for (const fn of cleanupFunctions) {
129
199
  fn();
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-pool.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAO9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA4C1D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,CAmGhD"}
1
+ {"version":3,"file":"plugin-pool.d.ts","sourceRoot":"","sources":["../../../../../../../packages/nx/src/project-graph/plugins/isolation/plugin-pool.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAM9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA4C1D,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,mBAAmB,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,CAmGhD"}
@@ -4,8 +4,7 @@ exports.loadRemoteNxPlugin = loadRemoteNxPlugin;
4
4
  const child_process_1 = require("child_process");
5
5
  const net_1 = require("net");
6
6
  const path = require("path");
7
- // TODO (@AgentEnder): After scoped verbose logging is implemented, re-add verbose logs here.
8
- // import { logger } from '../../utils/logger';
7
+ const logger_1 = require("../../../utils/logger");
9
8
  const socket_utils_1 = require("../../../daemon/socket-utils");
10
9
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
11
10
  const installation_directory_1 = require("../../../utils/installation-directory");
@@ -116,6 +115,7 @@ function createWorkerHandler(worker, pending, onload, onloadError, socket) {
116
115
  const { name, createNodesPattern, include, exclude } = result;
117
116
  pluginName = name;
118
117
  pluginNames.set(worker, pluginName);
118
+ logger_1.logger.verbose(`[plugin-pool] loaded plugin "${name}" from worker (pid: ${worker.pid})`);
119
119
  onload({
120
120
  name,
121
121
  include,
@@ -298,6 +298,7 @@ function registerPendingPromise(tx, pending, callback, context) {
298
298
  }
299
299
  global.nxPluginWorkerCount ??= 0;
300
300
  async function startPluginWorker(name) {
301
+ performance.mark(`start-plugin-worker:${name}`);
301
302
  // this should only really be true when running unit tests within
302
303
  // the Nx repo. We still need to start the worker in this case,
303
304
  // but its typescript.
@@ -325,6 +326,7 @@ async function startPluginWorker(name) {
325
326
  shell: false,
326
327
  windowsHide: true,
327
328
  });
329
+ logger_1.logger.verbose(`[plugin-pool] spawned worker for "${name}" (pid: ${worker.pid}, socket: ${ipcPath})`);
328
330
  // To make debugging easier and allow plugins to communicate things
329
331
  // like performance metrics, we pipe the stdout/stderr of the worker
330
332
  // to the main process.
@@ -343,32 +345,11 @@ async function startPluginWorker(name) {
343
345
  if (stderrMaxListeners !== 0) {
344
346
  process.stderr.setMaxListeners(stderrMaxListeners + 1);
345
347
  }
346
- worker.stdout.pipe(process.stdout);
347
- worker.stderr.pipe(process.stderr);
348
+ // Pipe and unref the worker streams. The utility handles cross-runtime compatibility.
349
+ pipeAndUnrefChildStream(worker.stdout, process.stdout, 'stdout');
350
+ pipeAndUnrefChildStream(worker.stderr, process.stderr, 'stderr');
348
351
  // Unref the worker process so it doesn't prevent the parent from exiting.
349
- // IMPORTANT: We must also unref the stdout/stderr streams. When streams are
350
- // piped, they maintain internal references in Node's event loop. Without
351
- // unreferencing them, the parent process will wait for the worker to exit
352
- // even after worker.unref() is called. This causes e2e tests to hang on CI
353
- // where test frameworks wait for all handles to be released.
354
- //
355
- // Although TypeScript types these as Readable/Writable, they are actually
356
- // net.Socket instances at runtime. Node.js internally creates sockets for
357
- // stdio pipes (see lib/internal/child_process.js createSocket function).
358
- // Socket.unref() allows the event loop to exit if these are the only handles.
359
352
  worker.unref();
360
- if (worker.stdout instanceof net_1.Socket) {
361
- worker.stdout.unref();
362
- }
363
- else {
364
- throw new Error(`Expected worker.stdout to be an instance of Socket, but got ${getTypeName(worker.stdout)}`);
365
- }
366
- if (worker.stderr instanceof net_1.Socket) {
367
- worker.stderr.unref();
368
- }
369
- else {
370
- throw new Error(`Expected worker.stderr to be an instance of Socket, but got ${getTypeName(worker.stderr)}`);
371
- }
372
353
  let attempts = 0;
373
354
  return new Promise((resolve, reject) => {
374
355
  const id = setInterval(async () => {
@@ -376,6 +357,7 @@ async function startPluginWorker(name) {
376
357
  if (socket) {
377
358
  socket.unref();
378
359
  clearInterval(id);
360
+ logger_1.logger.verbose(`[plugin-pool] connected to worker for "${name}" (pid: ${worker.pid}) after ${attempts} attempt(s)`);
379
361
  resolve({
380
362
  worker,
381
363
  socket,
@@ -384,12 +366,16 @@ async function startPluginWorker(name) {
384
366
  else if (attempts > 10000) {
385
367
  // daemon fails to start, the process probably exited
386
368
  // we print the logs and exit the client
387
- reject('Failed to start plugin worker.');
369
+ clearInterval(id);
370
+ reject(new Error(`Failed to start plugin worker for plugin ${name}`));
388
371
  }
389
372
  else {
390
373
  attempts++;
391
374
  }
392
375
  }, 10);
376
+ }).finally(() => {
377
+ performance.mark(`start-plugin-worker-end:${name}`);
378
+ performance.measure(`start-plugin-worker:${name}`, `start-plugin-worker:${name}`, `start-plugin-worker-end:${name}`);
393
379
  });
394
380
  }
395
381
  function isServerAvailable(ipcPath) {
@@ -420,3 +406,68 @@ function getTypeName(u) {
420
406
  }
421
407
  return u.constructor?.name ?? 'unknown object';
422
408
  }
409
+ /**
410
+ * Detects if we're running under an alternative JavaScript runtime (Bun or Deno).
411
+ * Returns the runtime name for helpful error messages, or null if running on Node.js.
412
+ */
413
+ function detectAlternativeRuntime() {
414
+ // Check for Bun runtime - the Bun global is only available in Bun
415
+ if ('Bun' in globalThis && typeof globalThis.Bun !== 'undefined') {
416
+ return 'bun';
417
+ }
418
+ // Check for Deno runtime - the Deno global is only available in Deno
419
+ if ('Deno' in globalThis && typeof globalThis.Deno !== 'undefined') {
420
+ return 'deno';
421
+ }
422
+ return null;
423
+ }
424
+ /**
425
+ * Pipes a child process stream to a destination and attempts to unref it to prevent
426
+ * the stream from keeping the parent process alive.
427
+ *
428
+ * In Node.js, child process stdio streams are actually net.Socket instances when
429
+ * using 'pipe' stdio option. However, alternative runtimes like Bun and Deno may
430
+ * use standard Readable/Writable streams instead.
431
+ *
432
+ * This function:
433
+ * 1. Pipes the source to the destination
434
+ * 2. Attempts to unref the source stream to allow the parent process to exit
435
+ * 3. Uses duck-typing to check for unref support when not a Socket instance
436
+ * 4. Emits helpful warnings for alternative runtimes if unref is not available
437
+ *
438
+ * @param source - The child process stream (stdout or stderr)
439
+ * @param destination - The process stream to pipe to (process.stdout or process.stderr)
440
+ * @param streamName - Name of the stream for warning messages ('stdout' or 'stderr')
441
+ */
442
+ function pipeAndUnrefChildStream(source, destination, streamName) {
443
+ if (!source) {
444
+ return;
445
+ }
446
+ source.pipe(destination);
447
+ // Node.js creates net.Socket instances for stdio pipes. Use instanceof check first.
448
+ if (source instanceof net_1.Socket) {
449
+ source.unref();
450
+ return;
451
+ }
452
+ // For non-Socket streams (e.g., in Bun/Deno), use duck-typing to check for unref
453
+ // NOTE: These should also be a Socket, but alternative runtimes may implement differently...
454
+ // See:
455
+ // - https://github.com/denoland/deno/issues/31961
456
+ // - https://github.com/oven-sh/bun/issues/26505
457
+ if (typeof source.unref === 'function') {
458
+ source.unref();
459
+ return;
460
+ }
461
+ // Stream doesn't support unref - emit a warning with runtime-specific guidance
462
+ const runtime = detectAlternativeRuntime();
463
+ if (runtime) {
464
+ console.warn(`[NX] worker.${streamName} does not support unref() in ${runtime}. ` +
465
+ `This may cause the process to hang when waiting for plugin workers to exit. ` +
466
+ `This is a known limitation of ${runtime}'s Node.js compatibility layer.`);
467
+ }
468
+ else {
469
+ console.warn(`[NX] worker.${streamName} is not a net.Socket and does not have an unref() method. ` +
470
+ `Expected Socket, got ${getTypeName(source)}. ` +
471
+ `This may cause the process to hang when waiting for plugin workers to exit.`);
472
+ }
473
+ }
@@ -2,30 +2,35 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const node_perf_hooks_1 = require("node:perf_hooks");
4
4
  node_perf_hooks_1.performance.mark(`plugin worker ${process.pid} code loading -- start`);
5
- const messaging_1 = require("./messaging");
6
- const serializable_error_1 = require("../../../utils/serializable-error");
7
5
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
8
- const net_1 = require("net");
6
+ const logger_1 = require("../../../utils/logger");
7
+ const serializable_error_1 = require("../../../utils/serializable-error");
8
+ const messaging_1 = require("./messaging");
9
9
  const fs_1 = require("fs");
10
- if (process.env.NX_PERF_LOGGING === 'true') {
10
+ const net_1 = require("net");
11
+ const environment = process.env;
12
+ if (environment.NX_PERF_LOGGING === 'true') {
11
13
  require('../../../utils/perf-logging');
12
14
  }
13
15
  node_perf_hooks_1.performance.mark(`plugin worker ${process.pid} code loading -- end`);
14
16
  node_perf_hooks_1.performance.measure(`plugin worker ${process.pid} code loading`, `plugin worker ${process.pid} code loading -- start`, `plugin worker ${process.pid} code loading -- end`);
15
17
  global.NX_GRAPH_CREATION = true;
16
18
  global.NX_PLUGIN_WORKER = true;
17
- let connected = false;
18
19
  let plugin;
19
20
  const socketPath = process.argv[2];
21
+ const expectedPluginName = process.argv[3];
22
+ let connectErrorTimeout = setErrorTimeout(5000, `The plugin worker for ${expectedPluginName} is exiting as it was not connected to within 5 seconds. ` +
23
+ 'Plugin workers expect to receive a socket connection from the parent process shortly after being started. ' +
24
+ 'If you are seeing this issue, please report it to the Nx team at https://github.com/nrwl/nx/issues.');
20
25
  const server = (0, net_1.createServer)((socket) => {
21
- connected = true;
26
+ connectErrorTimeout?.clear();
27
+ logger_1.logger.verbose(`[plugin-worker] "${expectedPluginName}" (pid: ${process.pid}) connected`);
22
28
  // This handles cases where the host process was killed
23
29
  // after the worker connected but before the worker was
24
30
  // instructed to load the plugin.
25
- const loadTimeout = setTimeout(() => {
26
- console.error(`Plugin Worker exited because no plugin was loaded within 10 seconds of starting up.`);
27
- process.exit(1);
28
- }, 10000).unref();
31
+ let loadErrorTimeout = setErrorTimeout(10_000, `Plugin Worker for ${expectedPluginName} is exiting as it did not receive a load message within 10 seconds of connecting. ` +
32
+ 'This likely indicates that the host process was terminated before the worker could be instructed to load the plugin. ' +
33
+ 'If you are seeing this issue, please report it to the Nx team at https://github.com/nrwl/nx/issues.');
29
34
  socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)((raw) => {
30
35
  const message = JSON.parse(raw.toString());
31
36
  if (!(0, messaging_1.isPluginWorkerMessage)(message)) {
@@ -33,8 +38,7 @@ const server = (0, net_1.createServer)((socket) => {
33
38
  }
34
39
  return (0, messaging_1.consumeMessage)(socket, message, {
35
40
  load: async ({ plugin: pluginConfiguration, root, name, pluginPath, shouldRegisterTSTranspiler, }) => {
36
- if (loadTimeout)
37
- clearTimeout(loadTimeout);
41
+ loadErrorTimeout?.clear();
38
42
  process.chdir(root);
39
43
  try {
40
44
  const { loadResolvedNxPluginAsync } = await Promise.resolve().then(() => require('../load-resolved-plugin'));
@@ -44,6 +48,7 @@ const server = (0, net_1.createServer)((socket) => {
44
48
  require('../transpiler').registerPluginTSTranspiler();
45
49
  }
46
50
  plugin = await loadResolvedNxPluginAsync(pluginConfiguration, pluginPath, name);
51
+ logger_1.logger.verbose(`[plugin-worker] "${name}" (pid: ${process.pid}) loaded successfully`);
47
52
  return {
48
53
  type: 'load-result',
49
54
  payload: {
@@ -186,13 +191,24 @@ const server = (0, net_1.createServer)((socket) => {
186
191
  });
187
192
  });
188
193
  server.listen(socketPath);
189
- if (process.env.NX_PLUGIN_NO_TIMEOUTS !== 'true') {
190
- setTimeout(() => {
191
- if (!connected) {
192
- console.error('The plugin worker is exiting as it was not connected to within 5 seconds.');
194
+ logger_1.logger.verbose(`[plugin-worker] "${expectedPluginName}" (pid: ${process.pid}) listening on ${socketPath}`);
195
+ function setErrorTimeout(timeoutMs, errorMessage) {
196
+ if (environment.NX_PLUGIN_NO_TIMEOUTS === 'true') {
197
+ return;
198
+ }
199
+ let cleared = false;
200
+ const timeout = setTimeout(() => {
201
+ if (!cleared) {
202
+ console.error(errorMessage);
193
203
  process.exit(1);
194
204
  }
195
- }, 5000).unref();
205
+ }, timeoutMs).unref();
206
+ return {
207
+ clear: () => {
208
+ cleared = true;
209
+ clearTimeout(timeout);
210
+ },
211
+ };
196
212
  }
197
213
  const exitHandler = (exitCode) => () => {
198
214
  server.close();
@@ -40,7 +40,7 @@ function readCachedProjectGraph(minimumComputedAt) {
40
40
  ? (0, strip_indents_1.stripIndents) `
41
41
  Make sure invoke 'node ./decorate-angular-cli.js' in your postinstall script.
42
42
  The decorated CLI will compute the project graph.
43
- 'ng --help' should say 'Smart Repos · Fast Builds'.
43
+ 'ng --help' should say 'Smart Monorepos · Fast Builds'.
44
44
  `
45
45
  : '';
46
46
  throw new Error((0, strip_indents_1.stripIndents) `
@@ -1 +1 @@
1
- {"version":3,"file":"consume-messages-from-socket.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/utils/consume-messages-from-socket.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,eAAe,QACuB,CAAC;AAEpD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,IAEnE,SAAI,UA4Bb;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAYtD"}
1
+ {"version":3,"file":"consume-messages-from-socket.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/utils/consume-messages-from-socket.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,eAAe,QACuB,CAAC;AAEpD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,IAGnE,SAAI,UA4Bb;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAYtD"}
@@ -3,12 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MESSAGE_END_SEQ = void 0;
4
4
  exports.consumeMessagesFromSocket = consumeMessagesFromSocket;
5
5
  exports.isJsonMessage = isJsonMessage;
6
+ const string_decoder_1 = require("string_decoder");
6
7
  const VERY_END_CODE = 4;
7
8
  exports.MESSAGE_END_SEQ = 'NX_MSG_END' + String.fromCharCode(VERY_END_CODE);
8
9
  function consumeMessagesFromSocket(callback) {
9
10
  let message = '';
11
+ const decoder = new string_decoder_1.StringDecoder('utf8');
10
12
  return (data) => {
11
- const chunk = data.toString();
13
+ const chunk = decoder.write(data);
12
14
  message += chunk;
13
15
  // Check if accumulated message ends with MESSAGE_END_SEQ (not just the chunk)
14
16
  // This handles TCP packet fragmentation where MESSAGE_END_SEQ may be split across packets
@@ -3,12 +3,5 @@ export declare class PromisedBasedQueue {
3
3
  private promise;
4
4
  sendToQueue(fn: () => Promise<any>): Promise<any>;
5
5
  isEmpty(): boolean;
6
- /**
7
- * Used to decrement the internal counter representing the number of active promises in the queue.
8
- * This is useful for retrying a failed daemon message, as we want to be able to shut the daemon down
9
- * without marking the promise that represents the failed message as settled. To do so, we store
10
- * the promise in a separate variable and only resolve or reject it later.
11
- */
12
- decrementQueueCounter(): void;
13
6
  }
14
7
  //# sourceMappingURL=promised-based-queue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"promised-based-queue.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/utils/promised-based-queue.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAyB;IAExC,WAAW,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IA8BjD,OAAO;IAIP;;;;;OAKG;IACH,qBAAqB;CAGtB"}
1
+ {"version":3,"file":"promised-based-queue.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/utils/promised-based-queue.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAyB;IAExC,WAAW,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC;IA8BjD,OAAO;CAGR"}
@@ -39,14 +39,5 @@ class PromisedBasedQueue {
39
39
  isEmpty() {
40
40
  return this.counter === 0;
41
41
  }
42
- /**
43
- * Used to decrement the internal counter representing the number of active promises in the queue.
44
- * This is useful for retrying a failed daemon message, as we want to be able to shut the daemon down
45
- * without marking the promise that represents the failed message as settled. To do so, we store
46
- * the promise in a separate variable and only resolve or reject it later.
47
- */
48
- decrementQueueCounter() {
49
- this.counter--;
50
- }
51
42
  }
52
43
  exports.PromisedBasedQueue = PromisedBasedQueue;