nx 22.7.10 → 22.7.12

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 (45) hide show
  1. package/dist/src/daemon/client/client.d.ts +2 -0
  2. package/dist/src/daemon/client/client.js +73 -7
  3. package/dist/src/daemon/client/daemon-environment.d.ts +11 -0
  4. package/dist/src/daemon/client/daemon-environment.js +20 -0
  5. package/dist/src/daemon/client/daemon-socket-messenger.d.ts +1 -1
  6. package/dist/src/daemon/client/daemon-socket-messenger.js +8 -3
  7. package/dist/src/daemon/is-v8-serializer-enabled.d.ts +2 -2
  8. package/dist/src/daemon/is-v8-serializer-enabled.js +2 -2
  9. package/dist/src/daemon/server/client-socket-context.d.ts +1 -1
  10. package/dist/src/daemon/server/client-socket-context.js +2 -3
  11. package/dist/src/daemon/server/handle-hash-tasks.js +1 -1
  12. package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -4
  13. package/dist/src/daemon/server/project-graph-incremental-recomputation.js +1 -14
  14. package/dist/src/daemon/server/server.js +17 -24
  15. package/dist/src/daemon/server/shutdown-utils.d.ts +1 -1
  16. package/dist/src/daemon/server/shutdown-utils.js +2 -2
  17. package/dist/src/daemon/socket-utils.d.ts +26 -7
  18. package/dist/src/daemon/socket-utils.js +45 -31
  19. package/dist/src/hasher/create-task-hasher.js +1 -1
  20. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  21. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  22. package/dist/src/project-graph/build-project-graph.d.ts +2 -4
  23. package/dist/src/project-graph/build-project-graph.js +2 -7
  24. package/dist/src/project-graph/file-map-utils.d.ts +2 -4
  25. package/dist/src/project-graph/file-map-utils.js +0 -3
  26. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -2
  27. package/dist/src/project-graph/plugins/isolation/messaging.js +1 -3
  28. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +9 -1
  29. package/dist/src/project-graph/project-graph.js +4 -4
  30. package/dist/src/project-graph/utils/retrieve-workspace-files.d.ts +1 -2
  31. package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -3
  32. package/dist/src/tasks-runner/forked-process-task-runner.d.ts +3 -0
  33. package/dist/src/tasks-runner/forked-process-task-runner.js +15 -6
  34. package/dist/src/tasks-runner/init-tasks-runner.js +32 -2
  35. package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -11
  36. package/dist/src/tasks-runner/pseudo-ipc.js +14 -13
  37. package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -0
  38. package/dist/src/tasks-runner/running-tasks/shared-running-task.d.ts +1 -0
  39. package/dist/src/tasks-runner/running-tasks/shared-running-task.js +12 -1
  40. package/dist/src/tasks-runner/task-orchestrator.d.ts +3 -0
  41. package/dist/src/tasks-runner/task-orchestrator.js +40 -6
  42. package/dist/src/utils/consume-messages-from-socket.d.ts +42 -7
  43. package/dist/src/utils/consume-messages-from-socket.js +272 -38
  44. package/dist/src/utils/params.js +1 -1
  45. package/package.json +11 -11
@@ -33,10 +33,12 @@ export declare class DaemonClient {
33
33
  private _daemonReady;
34
34
  private fileWatcherMessenger;
35
35
  private fileWatcherReconnecting;
36
+ private fileWatcherFramingFailures;
36
37
  private fileWatcherCallbacks;
37
38
  private fileWatcherConfigs;
38
39
  private projectGraphListenerMessenger;
39
40
  private projectGraphListenerReconnecting;
41
+ private projectGraphListenerFramingFailures;
40
42
  private projectGraphListenerCallbacks;
41
43
  enabled(): boolean;
42
44
  reset(): void;
@@ -54,6 +54,11 @@ const WAIT_FOR_SERVER_CONFIG = {
54
54
  delayMs: 10,
55
55
  maxAttempts: 6000, // 6000 * 10ms = 60 seconds
56
56
  };
57
+ /**
58
+ * A framing failure repeats on every redial, so the watcher channels stop
59
+ * re-dialing once this many land back to back without a message in between.
60
+ */
61
+ const MAX_CONSECUTIVE_FRAMING_FAILURES = 3;
57
62
  class DaemonClient {
58
63
  constructor() {
59
64
  // Tracks the spinner owned by the in-flight request so streamed
@@ -65,9 +70,11 @@ class DaemonClient {
65
70
  this._waitForDaemonReady = null;
66
71
  this._daemonReady = null;
67
72
  this.fileWatcherReconnecting = false;
73
+ this.fileWatcherFramingFailures = 0;
68
74
  this.fileWatcherCallbacks = new Map();
69
75
  this.fileWatcherConfigs = new Map();
70
76
  this.projectGraphListenerReconnecting = false;
77
+ this.projectGraphListenerFramingFailures = 0;
71
78
  this.projectGraphListenerCallbacks = new Map();
72
79
  this.envReflectionSent = false;
73
80
  try {
@@ -220,6 +227,8 @@ class DaemonClient {
220
227
  this.fileWatcherMessenger = new daemon_socket_messenger_1.DaemonSocketMessenger((0, net_1.connect)(socketPath)).listen((message) => {
221
228
  try {
222
229
  const parsedMessage = (0, consume_messages_from_socket_1.parseMessage)(message);
230
+ // A delivered message means the stream is healthy again.
231
+ this.fileWatcherFramingFailures = 0;
223
232
  // Notify all callbacks
224
233
  for (const cb of this.fileWatcherCallbacks.values()) {
225
234
  cb(null, parsedMessage);
@@ -248,6 +257,12 @@ class DaemonClient {
248
257
  for (const cb of this.fileWatcherCallbacks.values()) {
249
258
  cb(err, null);
250
259
  }
260
+ if (err instanceof consume_messages_from_socket_1.MessageFramingError) {
261
+ this.fileWatcherFramingFailures++;
262
+ }
263
+ // Close so 'close' fires and the reconnect path runs; a framing
264
+ // failure would otherwise leave this channel silent forever.
265
+ this.fileWatcherMessenger?.close();
251
266
  });
252
267
  this.fileWatcherMessenger.sendMessage({
253
268
  type: 'REGISTER_FILE_WATCHER',
@@ -270,6 +285,19 @@ class DaemonClient {
270
285
  if (this.fileWatcherReconnecting) {
271
286
  return;
272
287
  }
288
+ // The concurrency guard above is cleared before this method recurses, so it
289
+ // bounds overlap rather than iterations. A framing failure is deterministic
290
+ // — re-dialing replays it — so without this the channel would reconnect and
291
+ // re-fail forever. Reaching a payload over NX_MAX_MESSAGE_SIZE does exactly
292
+ // that on every notification.
293
+ if (this.fileWatcherFramingFailures >= MAX_CONSECUTIVE_FRAMING_FAILURES) {
294
+ logger_1.clientLogger.log(`[FileWatcher] Giving up after ${this.fileWatcherFramingFailures} consecutive framing failures`);
295
+ this.fileWatcherReconnecting = false;
296
+ for (const cb of this.fileWatcherCallbacks.values()) {
297
+ cb('closed', null);
298
+ }
299
+ return;
300
+ }
273
301
  if (this.fileWatcherCallbacks.size === 0) {
274
302
  return; // No callbacks to reconnect
275
303
  }
@@ -306,6 +334,8 @@ class DaemonClient {
306
334
  this.fileWatcherMessenger = new daemon_socket_messenger_1.DaemonSocketMessenger((0, net_1.connect)(socketPath)).listen((message) => {
307
335
  try {
308
336
  const parsedMessage = (0, consume_messages_from_socket_1.parseMessage)(message);
337
+ // A delivered message means the stream is healthy again.
338
+ this.fileWatcherFramingFailures = 0;
309
339
  for (const cb of this.fileWatcherCallbacks.values()) {
310
340
  cb(null, parsedMessage);
311
341
  }
@@ -331,7 +361,12 @@ class DaemonClient {
331
361
  }
332
362
  process.exit(1);
333
363
  }
334
- // Other errors during reconnection - let retry loop handle
364
+ if (err instanceof consume_messages_from_socket_1.MessageFramingError) {
365
+ this.fileWatcherFramingFailures++;
366
+ }
367
+ // The retry loop is driven by 'close', which a framing failure does
368
+ // not emit, so close explicitly to hand off to it.
369
+ this.fileWatcherMessenger?.close();
335
370
  });
336
371
  // Re-register all stored configs
337
372
  for (const cfg of this.fileWatcherConfigs.values()) {
@@ -374,6 +409,8 @@ class DaemonClient {
374
409
  this.projectGraphListenerMessenger = new daemon_socket_messenger_1.DaemonSocketMessenger((0, net_1.connect)(socketPath)).listen((message) => {
375
410
  try {
376
411
  const parsedMessage = (0, consume_messages_from_socket_1.parseMessage)(message);
412
+ // A delivered message means the stream is healthy again.
413
+ this.projectGraphListenerFramingFailures = 0;
377
414
  // Notify all callbacks
378
415
  for (const cb of this.projectGraphListenerCallbacks.values()) {
379
416
  cb(null, parsedMessage);
@@ -402,6 +439,10 @@ class DaemonClient {
402
439
  for (const cb of this.projectGraphListenerCallbacks.values()) {
403
440
  cb(err, null);
404
441
  }
442
+ if (err instanceof consume_messages_from_socket_1.MessageFramingError) {
443
+ this.projectGraphListenerFramingFailures++;
444
+ }
445
+ this.projectGraphListenerMessenger?.close();
405
446
  });
406
447
  this.projectGraphListenerMessenger.sendMessage({
407
448
  type: register_project_graph_listener_1.REGISTER_PROJECT_GRAPH_LISTENER,
@@ -422,6 +463,17 @@ class DaemonClient {
422
463
  if (this.projectGraphListenerReconnecting) {
423
464
  return;
424
465
  }
466
+ // See reconnectFileWatcher: a framing failure repeats on every redial, so
467
+ // the concurrency guard alone cannot bound it.
468
+ if (this.projectGraphListenerFramingFailures >=
469
+ MAX_CONSECUTIVE_FRAMING_FAILURES) {
470
+ logger_1.clientLogger.log(`[ProjectGraphListener] Giving up after ${this.projectGraphListenerFramingFailures} consecutive framing failures`);
471
+ this.projectGraphListenerReconnecting = false;
472
+ for (const cb of this.projectGraphListenerCallbacks.values()) {
473
+ cb('closed', null);
474
+ }
475
+ return;
476
+ }
425
477
  if (this.projectGraphListenerCallbacks.size === 0) {
426
478
  return; // No callbacks to reconnect
427
479
  }
@@ -458,6 +510,8 @@ class DaemonClient {
458
510
  this.projectGraphListenerMessenger = new daemon_socket_messenger_1.DaemonSocketMessenger((0, net_1.connect)(socketPath)).listen((message) => {
459
511
  try {
460
512
  const parsedMessage = (0, consume_messages_from_socket_1.parseMessage)(message);
513
+ // A delivered message means the stream is healthy again.
514
+ this.projectGraphListenerFramingFailures = 0;
461
515
  for (const cb of this.projectGraphListenerCallbacks.values()) {
462
516
  cb(null, parsedMessage);
463
517
  }
@@ -483,7 +537,12 @@ class DaemonClient {
483
537
  }
484
538
  process.exit(1);
485
539
  }
486
- // Other errors during reconnection - let retry loop handle
540
+ if (err instanceof consume_messages_from_socket_1.MessageFramingError) {
541
+ this.projectGraphListenerFramingFailures++;
542
+ }
543
+ // The retry loop is driven by 'close', which a framing failure does
544
+ // not emit, so close explicitly to hand off to it.
545
+ this.projectGraphListenerMessenger?.close();
487
546
  });
488
547
  // Re-register
489
548
  this.projectGraphListenerMessenger.sendMessage({
@@ -768,8 +827,14 @@ class DaemonClient {
768
827
  this.handleConnectionError(daemonProcessException('Daemon process terminated and closed the connection'));
769
828
  }
770
829
  }, (err) => {
830
+ // Every recovery path below is keyed on the socket 'close' event, and a
831
+ // framing failure emits neither 'close' nor 'error'. Without the
832
+ // teardown at the end of this handler the connection stays open and
833
+ // permanently deaf, and the next request waits out the keep-alive.
771
834
  if (!err.message) {
772
- return this.currentReject(daemonProcessException(err.toString()));
835
+ this.currentReject(daemonProcessException(err.toString()));
836
+ this.socketMessenger?.close();
837
+ return;
773
838
  }
774
839
  let error;
775
840
  if (err.message.startsWith('connect ENOENT')) {
@@ -790,6 +855,7 @@ class DaemonClient {
790
855
  error = daemonProcessException(err.toString());
791
856
  }
792
857
  this.currentReject(error);
858
+ this.socketMessenger?.close();
793
859
  });
794
860
  }
795
861
  async handleConnectionError(error) {
@@ -960,9 +1026,9 @@ class DaemonClient {
960
1026
  }
961
1027
  }
962
1028
  catch (e) {
963
- const endOfResponse = serializedResult.length > 300
964
- ? serializedResult.substring(serializedResult.length - 300)
965
- : serializedResult;
1029
+ const endOfResponse = (0, consume_messages_from_socket_1.describeMessage)(serializedResult, {
1030
+ from: 'end',
1031
+ });
966
1032
  this.currentReject(daemonProcessException([
967
1033
  'Could not deserialize response from Nx daemon.',
968
1034
  `Message: ${e.message}`,
@@ -999,7 +1065,7 @@ class DaemonClient {
999
1065
  detached: true,
1000
1066
  windowsHide: true,
1001
1067
  shell: false,
1002
- env: (0, daemon_environment_1.getDaemonEnv)(),
1068
+ env: (0, daemon_environment_1.getDaemonSpawnEnv)(),
1003
1069
  });
1004
1070
  // The child now owns dup'd copies of the descriptors, so release ours.
1005
1071
  (0, node_fs_1.closeSync)(outFd);
@@ -2,3 +2,14 @@ export declare function getDaemonEnv(): NodeJS.ProcessEnv & {
2
2
  NX_PROJECT_GLOB_CACHE: string;
3
3
  NX_CACHE_PROJECTS_CONFIG: string;
4
4
  };
5
+ /**
6
+ * Env for spawning the daemon process. On top of the reflected env it re-adds
7
+ * NX_MAX_MESSAGE_SIZE, which is excluded from reflection (see above) so one
8
+ * client cannot change the ceiling for another. The value here therefore holds
9
+ * for the daemon's whole lifetime, and changing it needs a daemon restart
10
+ * (`nx reset`).
11
+ */
12
+ export declare function getDaemonSpawnEnv(): NodeJS.ProcessEnv & {
13
+ NX_PROJECT_GLOB_CACHE: string;
14
+ NX_CACHE_PROJECTS_CONFIG: string;
15
+ };
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDaemonEnv = getDaemonEnv;
4
+ exports.getDaemonSpawnEnv = getDaemonSpawnEnv;
4
5
  const DAEMON_ENV_REQUIRED_SETTINGS = {
5
6
  NX_PROJECT_GLOB_CACHE: 'false',
6
7
  NX_CACHE_PROJECTS_CONFIG: 'false',
@@ -16,6 +17,11 @@ const DAEMON_ENV_OVERRIDABLE_SETTINGS = {
16
17
  * (e.g. PATH, JAVA_HOME, GRADLE_HOME) should be allowed through.
17
18
  */
18
19
  const DAEMON_ENV_VARS_EXCLUSIONS = new Set([
20
+ // The message-size ceiling is read when a connection is accepted, before the
21
+ // client's env could apply, so reflecting it would hand one client's value to
22
+ // the next client's connection. Pinned at daemon spawn instead; see
23
+ // getDaemonSpawnEnv.
24
+ 'NX_MAX_MESSAGE_SIZE',
19
25
  // Nx task-scoped vars
20
26
  'NX_TASK_TARGET_CONFIGURATION',
21
27
  'NX_TASK_TARGET_PROJECT',
@@ -119,3 +125,17 @@ function getDaemonEnv() {
119
125
  }
120
126
  return Object.assign(env, DAEMON_ENV_REQUIRED_SETTINGS);
121
127
  }
128
+ /**
129
+ * Env for spawning the daemon process. On top of the reflected env it re-adds
130
+ * NX_MAX_MESSAGE_SIZE, which is excluded from reflection (see above) so one
131
+ * client cannot change the ceiling for another. The value here therefore holds
132
+ * for the daemon's whole lifetime, and changing it needs a daemon restart
133
+ * (`nx reset`).
134
+ */
135
+ function getDaemonSpawnEnv() {
136
+ const env = getDaemonEnv();
137
+ if (process.env.NX_MAX_MESSAGE_SIZE !== undefined) {
138
+ env.NX_MAX_MESSAGE_SIZE = process.env.NX_MAX_MESSAGE_SIZE;
139
+ }
140
+ return env;
141
+ }
@@ -7,6 +7,6 @@ export declare class DaemonSocketMessenger {
7
7
  private socket;
8
8
  constructor(socket: Socket);
9
9
  sendMessage<T extends DaemonMessage>(messageToDaemon: T, force?: 'v8' | 'json'): void;
10
- listen(onData: (message: string) => void, onClose?: () => void, onError?: (err: Error) => void): DaemonSocketMessenger;
10
+ listen(onData: (message: Buffer) => void, onClose?: () => void, onError?: (err: Error) => void): DaemonSocketMessenger;
11
11
  close(): void;
12
12
  }
@@ -30,9 +30,7 @@ class DaemonSocketMessenger {
30
30
  const serialized = (0, socket_utils_1.serialize)(messageToDaemon, force);
31
31
  perf_hooks_1.performance.mark('daemon-message-serialization-end-' + messageToDaemon.type);
32
32
  perf_hooks_1.performance.measure('daemon-message-serialization-' + messageToDaemon.type, 'daemon-message-serialization-start-' + messageToDaemon.type, 'daemon-message-serialization-end-' + messageToDaemon.type);
33
- this.socket.write(serialized);
34
- // send EOT to indicate that the message has been fully written
35
- this.socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
33
+ (0, consume_messages_from_socket_1.writeMessage)(this.socket, serialized);
36
34
  logger_1.clientLogger.log('[Messenger] Message sent');
37
35
  }
38
36
  listen(onData, onClose = () => { }, onError = () => { }) {
@@ -45,6 +43,13 @@ class DaemonSocketMessenger {
45
43
  this.socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(async (message) => {
46
44
  logger_1.clientLogger.log('[Messenger] Received message, length:', message.length);
47
45
  onData(message);
46
+ },
47
+ // A framing failure leaves the socket open and writable, so nothing
48
+ // else settles the in-flight request. Route it to the same handler as
49
+ // a socket error rather than waiting for the keep-alive timeout.
50
+ (err) => {
51
+ logger_1.clientLogger.log('[Messenger] Framing error:', err.message);
52
+ onError(err);
48
53
  }));
49
54
  logger_1.clientLogger.log('[Messenger] listen() complete');
50
55
  return this;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Check if v8 serializer is enabled for daemon communication.
3
- * V8 serializer is enabled by default unless explicitly disabled.
2
+ * Off by default; set `NX_USE_V8_SERIALIZER=true` to opt in. Governs every Nx
3
+ * socket channel: the daemon client and server, plugin workers, and pseudo-IPC.
4
4
  */
5
5
  export declare function isV8SerializerEnabled(): boolean;
@@ -2,8 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isV8SerializerEnabled = isV8SerializerEnabled;
4
4
  /**
5
- * Check if v8 serializer is enabled for daemon communication.
6
- * V8 serializer is enabled by default unless explicitly disabled.
5
+ * Off by default; set `NX_USE_V8_SERIALIZER=true` to opt in. Governs every Nx
6
+ * socket channel: the daemon client and server, plugin workers, and pseudo-IPC.
7
7
  */
8
8
  function isV8SerializerEnabled() {
9
9
  return process.env.NX_USE_V8_SERIALIZER === 'true';
@@ -7,7 +7,7 @@ export declare function getTopicSubscribers(topic: ProgressTopic): Set<Socket>;
7
7
  export declare function assertOnDaemon(helperName: string): void;
8
8
  /**
9
9
  * Writes a streaming message over the given socket using the daemon's
10
- * configured serialization format and terminated with MESSAGE_END_SEQ.
10
+ * configured serialization format, length-prefixed like any other message.
11
11
  * Errors are logged to the daemon's stdout (redirected to the daemon
12
12
  * log) rather than propagated — a disconnected client shouldn't tear
13
13
  * down the current request handler or other subscribers.
@@ -7,7 +7,6 @@ exports.assertOnDaemon = assertOnDaemon;
7
7
  exports.writeStreamingMessage = writeStreamingMessage;
8
8
  exports.sendProgressMessageToTopic = sendProgressMessageToTopic;
9
9
  exports.sendEmitLogMessageToTopic = sendEmitLogMessageToTopic;
10
- const consume_messages_from_socket_1 = require("../../utils/consume-messages-from-socket");
11
10
  const is_on_daemon_1 = require("../is-on-daemon");
12
11
  const logger_1 = require("../logger");
13
12
  const streaming_messages_1 = require("../message-types/streaming-messages");
@@ -43,7 +42,7 @@ function assertOnDaemon(helperName) {
43
42
  }
44
43
  /**
45
44
  * Writes a streaming message over the given socket using the daemon's
46
- * configured serialization format and terminated with MESSAGE_END_SEQ.
45
+ * configured serialization format, length-prefixed like any other message.
47
46
  * Errors are logged to the daemon's stdout (redirected to the daemon
48
47
  * log) rather than propagated — a disconnected client shouldn't tear
49
48
  * down the current request handler or other subscribers.
@@ -51,7 +50,7 @@ function assertOnDaemon(helperName) {
51
50
  function writeStreamingMessage(socket, payload, description) {
52
51
  try {
53
52
  logger_1.serverLogger.log('Streaming message to client:', description);
54
- socket.write((0, socket_utils_1.serialize)(payload) + consume_messages_from_socket_1.MESSAGE_END_SEQ, (err) => {
53
+ (0, socket_utils_1.sendMessage)(socket, payload, undefined, (err) => {
55
54
  if (err) {
56
55
  console.log(`Streaming message write error (client likely disconnected): ${err.message}`);
57
56
  }
@@ -11,7 +11,7 @@ const configuration_1 = require("../../config/configuration");
11
11
  let storedProjectGraph = null;
12
12
  let storedHasher = null;
13
13
  async function handleHashTasks(payload) {
14
- const { error, projectGraph, allWorkspaceFiles, fileMap, rustReferences } = await (0, project_graph_incremental_recomputation_1.getCachedSerializedProjectGraphPromise)();
14
+ const { error, projectGraph, rustReferences } = await (0, project_graph_incremental_recomputation_1.getCachedSerializedProjectGraphPromise)();
15
15
  if (error) {
16
16
  throw error;
17
17
  }
@@ -1,5 +1,5 @@
1
1
  import { Socket } from 'net';
2
- import { FileData, FileMap, ProjectGraph } from '../../config/project-graph';
2
+ import { FileMap, ProjectGraph } from '../../config/project-graph';
3
3
  import { NxWorkspaceFilesExternals } from '../../native';
4
4
  import { FileMapCache } from '../../project-graph/nx-deps-cache';
5
5
  import { ConfigurationSourceMaps } from '../../project-graph/utils/project-configuration/source-maps';
@@ -7,8 +7,6 @@ interface SerializedProjectGraph {
7
7
  error: Error | null;
8
8
  projectGraph: ProjectGraph | null;
9
9
  projectFileMapCache: FileMapCache | null;
10
- fileMap: FileMap | null;
11
- allWorkspaceFiles: FileData[] | null;
12
10
  serializedProjectGraph: string | null;
13
11
  serializedSourceMaps: string | null;
14
12
  sourceMaps: ConfigurationSourceMaps | null;
@@ -16,7 +14,6 @@ interface SerializedProjectGraph {
16
14
  }
17
15
  export declare let fileMapWithFiles: {
18
16
  fileMap: FileMap;
19
- allWorkspaceFiles: FileData[];
20
17
  rustReferences: NxWorkspaceFilesExternals;
21
18
  } | undefined;
22
19
  export declare let currentProjectFileMapCache: FileMapCache | undefined;
@@ -113,8 +113,6 @@ async function getCachedSerializedProjectGraphPromise(socket) {
113
113
  sourceMaps: null,
114
114
  projectGraph: null,
115
115
  projectFileMapCache: null,
116
- fileMap: null,
117
- allWorkspaceFiles: null,
118
116
  rustReferences: null,
119
117
  };
120
118
  }
@@ -277,9 +275,7 @@ async function processFilesAndCreateAndSerializeProjectGraph(plugins) {
277
275
  error: g.error,
278
276
  projectGraph: null,
279
277
  projectFileMapCache: null,
280
- fileMap: null,
281
278
  rustReferences: null,
282
- allWorkspaceFiles: null,
283
279
  serializedProjectGraph: null,
284
280
  serializedSourceMaps: null,
285
281
  sourceMaps: null,
@@ -291,9 +287,7 @@ async function processFilesAndCreateAndSerializeProjectGraph(plugins) {
291
287
  error: new error_types_1.DaemonProjectGraphError(errors, g.projectGraph, projectConfigurationsResult.sourceMaps),
292
288
  projectGraph: null,
293
289
  projectFileMapCache: null,
294
- fileMap: null,
295
290
  rustReferences: null,
296
- allWorkspaceFiles: null,
297
291
  serializedProjectGraph: null,
298
292
  serializedSourceMaps: null,
299
293
  sourceMaps: null,
@@ -308,9 +302,7 @@ async function processFilesAndCreateAndSerializeProjectGraph(plugins) {
308
302
  error: err,
309
303
  projectGraph: null,
310
304
  projectFileMapCache: null,
311
- fileMap: null,
312
305
  rustReferences: null,
313
- allWorkspaceFiles: null,
314
306
  serializedProjectGraph: null,
315
307
  serializedSourceMaps: null,
316
308
  sourceMaps: null,
@@ -334,9 +326,8 @@ async function createAndSerializeProjectGraph({ projects, sourceMaps, }) {
334
326
  try {
335
327
  perf_hooks_1.performance.mark('create-project-graph-start');
336
328
  const fileMap = copyFileMap(exports.fileMapWithFiles.fileMap);
337
- const allWorkspaceFiles = copyFileData(exports.fileMapWithFiles.allWorkspaceFiles);
338
329
  const rustReferences = exports.fileMapWithFiles.rustReferences;
339
- const { projectGraph, projectFileMapCache } = await (0, build_project_graph_1.buildProjectGraphUsingProjectFileMap)(projects, knownExternalNodes, fileMap, allWorkspaceFiles, rustReferences, exports.currentProjectFileMapCache || (0, nx_deps_cache_1.readFileMapCache)(), await (0, get_plugins_1.getPlugins)(), sourceMaps);
330
+ const { projectGraph, projectFileMapCache } = await (0, build_project_graph_1.buildProjectGraphUsingProjectFileMap)(projects, knownExternalNodes, fileMap, rustReferences, exports.currentProjectFileMapCache || (0, nx_deps_cache_1.readFileMapCache)(), await (0, get_plugins_1.getPlugins)(), sourceMaps);
340
331
  exports.currentProjectFileMapCache = projectFileMapCache;
341
332
  exports.currentProjectGraph = projectGraph;
342
333
  exports.currentSourceMaps = sourceMaps;
@@ -351,8 +342,6 @@ async function createAndSerializeProjectGraph({ projects, sourceMaps, }) {
351
342
  error: null,
352
343
  projectGraph,
353
344
  projectFileMapCache,
354
- fileMap,
355
- allWorkspaceFiles,
356
345
  serializedProjectGraph,
357
346
  serializedSourceMaps,
358
347
  sourceMaps,
@@ -365,8 +354,6 @@ async function createAndSerializeProjectGraph({ projects, sourceMaps, }) {
365
354
  error: e,
366
355
  projectGraph: null,
367
356
  projectFileMapCache: null,
368
- fileMap: null,
369
- allWorkspaceFiles: null,
370
357
  serializedProjectGraph: null,
371
358
  serializedSourceMaps: null,
372
359
  sourceMaps: null,
@@ -6,7 +6,6 @@ exports.startServer = startServer;
6
6
  const fs_1 = require("fs");
7
7
  const net_1 = require("net");
8
8
  const path_1 = require("path");
9
- const v8_1 = require("v8");
10
9
  const analytics_1 = require("../../analytics");
11
10
  const file_hasher_1 = require("../../hasher/file-hasher");
12
11
  const native_1 = require("../../native");
@@ -76,7 +75,16 @@ const server = (0, net_1.createServer)(async (socket) => {
76
75
  logger_1.serverLogger.log(`Established a connection. Number of open connections: ${numberOfOpenConnections}`);
77
76
  (0, shutdown_utils_1.resetInactivityTimeout)(handleInactivityTimeout);
78
77
  socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(async (message) => {
79
- await handleMessage(socket, message);
78
+ // A rejection here would otherwise be unhandled and take the daemon
79
+ // down with it, failing every other client's request too.
80
+ await handleMessage(socket, message).catch(async (e) => {
81
+ await (0, shutdown_utils_1.respondWithError)(socket, 'Error handling message', e);
82
+ });
83
+ }, (err) => {
84
+ logger_1.serverLogger.log(`Framing error: ${err.message}`);
85
+ // The stream cannot resynchronize, so close it and let the client
86
+ // observe the disconnect instead of waiting on a reply.
87
+ (0, shutdown_utils_1.respondWithError)(socket, 'Malformed message', err).finally(() => socket.destroy());
80
88
  }));
81
89
  socket.on('error', (e) => {
82
90
  logger_1.serverLogger.log(`Socket error: ${e.message}`);
@@ -99,21 +107,14 @@ async function handleMessage(socket, data) {
99
107
  (0, shutdown_utils_1.resetInactivityTimeout)(handleInactivityTimeout);
100
108
  const unparsedPayload = data;
101
109
  let payload;
102
- let mode = 'json';
110
+ // Reply in the format the client used.
111
+ const mode = (0, consume_messages_from_socket_1.isJsonMessage)(unparsedPayload) ? 'json' : 'v8';
103
112
  logger_1.serverLogger.log(`Received raw message of length ${unparsedPayload.length}`);
104
113
  try {
105
- // JSON Message
106
- if ((0, consume_messages_from_socket_1.isJsonMessage)(unparsedPayload)) {
107
- payload = JSON.parse(unparsedPayload);
108
- }
109
- else {
110
- // V8 Serialized Message
111
- payload = (0, v8_1.deserialize)(Buffer.from(unparsedPayload, 'binary'));
112
- mode = 'v8';
113
- }
114
+ payload = (0, consume_messages_from_socket_1.parseMessage)(unparsedPayload);
114
115
  }
115
116
  catch (e) {
116
- await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));
117
+ await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${(0, consume_messages_from_socket_1.describeMessage)(unparsedPayload, { maxBytes: 200 })}`));
117
118
  }
118
119
  logger_1.serverLogger.log(`Received ${mode} message of type ${payload.type}`);
119
120
  // A mismatch means the client reached the wrong daemon (e.g. a shared
@@ -233,7 +234,7 @@ async function handleMessage(socket, data) {
233
234
  await handleResult(socket, configure_ai_agents_1.RESET_CONFIGURE_AI_AGENTS_STATUS, () => (0, handle_configure_ai_agents_1.handleResetConfigureAiAgentsStatus)(), mode);
234
235
  }
235
236
  else {
236
- await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));
237
+ await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${(0, consume_messages_from_socket_1.describeMessage)(unparsedPayload, { maxBytes: 200 })}`));
237
238
  }
238
239
  }
239
240
  async function handleResult(socket, type, hrFn, mode) {
@@ -252,8 +253,8 @@ async function handleResult(socket, type, hrFn, mode) {
252
253
  else {
253
254
  logger_1.serverLogger.log(`Serializing response for ${type} message in ${mode} mode`);
254
255
  const response = typeof hr.response === 'string'
255
- ? hr.response
256
- : serializeUnserializedResult(hr.response, mode);
256
+ ? Buffer.from(hr.response, 'utf8')
257
+ : (0, socket_utils_1.serializeWithFallback)(hr.response, mode);
257
258
  logger_1.serverLogger.log(`Responding to ${type} message`);
258
259
  await (0, shutdown_utils_1.respondToClient)(socket, response, hr.description);
259
260
  }
@@ -531,11 +532,3 @@ function forwardEnvToPluginWorkers(env) {
531
532
  // Plugins may not be loaded yet — env will be picked up on next load
532
533
  });
533
534
  }
534
- function serializeUnserializedResult(response, mode) {
535
- if (mode === 'json') {
536
- return JSON.stringify(response);
537
- }
538
- else {
539
- return (0, v8_1.serialize)(response).toString('binary');
540
- }
541
- }
@@ -13,7 +13,7 @@ interface HandleServerProcessTerminationParams {
13
13
  export declare function handleServerProcessTermination({ server, reason, sockets, }: HandleServerProcessTerminationParams): Promise<void>;
14
14
  export declare function handleServerProcessTerminationWithRestart({ server, reason, sockets, }: HandleServerProcessTerminationParams): Promise<void>;
15
15
  export declare function resetInactivityTimeout(cb: () => void): void;
16
- export declare function respondToClient(socket: Socket, response: string, description: string): Promise<unknown>;
16
+ export declare function respondToClient(socket: Socket, response: Buffer, description: string): Promise<unknown>;
17
17
  /**
18
18
  * Send an error to the client without terminating the daemon. Use this when the
19
19
  * daemon should keep running for other clients after refusing a request.
@@ -127,7 +127,7 @@ function respondToClient(socket, response, description) {
127
127
  if (description) {
128
128
  logger_1.serverLogger.requestLog(`Responding to the client.`, description);
129
129
  }
130
- socket.write(response + consume_messages_from_socket_1.MESSAGE_END_SEQ, (err) => {
130
+ (0, consume_messages_from_socket_1.writeMessage)(socket, response, (err) => {
131
131
  if (err) {
132
132
  logger_1.serverLogger.log(`Socket write error (client likely disconnected): ${err.message}`);
133
133
  }
@@ -148,7 +148,7 @@ async function respondWithError(socket, description, error) {
148
148
  logger_1.serverLogger.requestLog(`Responding to the client with an error.`, description, normalizedError.message);
149
149
  console.error(normalizedError.stack);
150
150
  // Respond with the original error
151
- await respondToClient(socket, (0, socket_utils_1.serializeResult)(error, null, null), null);
151
+ await respondToClient(socket, Buffer.from((0, socket_utils_1.serializeResult)(error, null, null), 'utf8'), null);
152
152
  }
153
153
  async function respondWithErrorAndExit(socket, description, error) {
154
154
  await respondWithError(socket, description, error);
@@ -1,3 +1,4 @@
1
+ import type { Socket } from 'net';
1
2
  export declare const isWindows: boolean;
2
3
  /**
3
4
  * For IPC with the daemon server we use unix sockets or windows named pipes, depending on the user's operating system.
@@ -12,13 +13,31 @@ export declare function getPluginSocketFileName(id: string): string;
12
13
  export declare function killSocketOrPath(): void;
13
14
  export declare function serializeResult(error: Error | null, serializedProjectGraph: string | null, serializedSourceMaps: string | null): string | null;
14
15
  /**
15
- * Helper to serialize data either using v8 serialization or JSON serialization, based on
16
- * the user's preference and the success of each method. Should only be used by "client" side
17
- * connections, daemon or other servers should respond based on the type of serialization used
18
- * by the client it is communicating with.
16
+ * Serialize using `preferred`, falling back to the other format when it throws.
17
+ * Neither format subsumes the other: JSON cannot represent a BigInt and hits the
18
+ * max string length far sooner, while v8 cannot clone a function.
19
19
  *
20
20
  * @param data Data to serialize
21
- * @param force Forces one serialization method over the other
22
- * @returns Serialized data as a string
21
+ * @param preferred Format to attempt first
22
+ * @returns Serialized data as bytes ready to be framed onto a socket
23
23
  */
24
- export declare function serialize(data: any, force?: 'v8' | 'json'): string;
24
+ export declare function serializeWithFallback(data: any, preferred: 'v8' | 'json'): Buffer;
25
+ /**
26
+ * Serialize data for IPC using the format the user configured.
27
+ *
28
+ * @param data Data to serialize
29
+ * @param force Use this format without falling back. For callers whose data is
30
+ * known to be unrepresentable in the other format, where a fallback
31
+ * would only swap one failure for a less obvious one.
32
+ * @returns Serialized data as bytes ready to be framed onto a socket
33
+ */
34
+ export declare function serialize(data: any, force?: 'v8' | 'json'): Buffer;
35
+ /**
36
+ * Serialize `data` and write it as one framed message.
37
+ *
38
+ * Lives here rather than in `writeMessage` so the framing stays a byte-level
39
+ * primitive: `utils/consume-messages-from-socket` is shared by callers that
40
+ * already hold bytes, and having it reach back into the daemon's serializer
41
+ * would invert the dependency.
42
+ */
43
+ export declare function sendMessage(socket: Socket, data: any, force?: 'v8' | 'json', callback?: (err?: Error) => void): void;