nx 22.7.11 → 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 (36) 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/pseudo-ipc.js +14 -13
  33. package/dist/src/utils/consume-messages-from-socket.d.ts +42 -7
  34. package/dist/src/utils/consume-messages-from-socket.js +272 -38
  35. package/dist/src/utils/params.js +1 -1
  36. package/package.json +11 -11
@@ -4,7 +4,9 @@ exports.getPluginOsSocketPath = exports.getForkedProcessOsSocketPath = exports.g
4
4
  exports.getPluginSocketFileName = getPluginSocketFileName;
5
5
  exports.killSocketOrPath = killSocketOrPath;
6
6
  exports.serializeResult = serializeResult;
7
+ exports.serializeWithFallback = serializeWithFallback;
7
8
  exports.serialize = serialize;
9
+ exports.sendMessage = sendMessage;
8
10
  const fs_1 = require("fs");
9
11
  const os_1 = require("os");
10
12
  const path_1 = require("path");
@@ -12,6 +14,7 @@ const tmp_dir_1 = require("./tmp-dir");
12
14
  const serializable_error_1 = require("../utils/serializable-error");
13
15
  const is_v8_serializer_enabled_1 = require("./is-v8-serializer-enabled");
14
16
  const v8_1 = require("v8");
17
+ const consume_messages_from_socket_1 = require("../utils/consume-messages-from-socket");
15
18
  exports.isWindows = (0, os_1.platform)() === 'win32';
16
19
  /**
17
20
  * For IPC with the daemon server we use unix sockets or windows named pipes, depending on the user's operating system.
@@ -77,41 +80,52 @@ function serializeResult(error, serializedProjectGraph, serializedSourceMaps) {
77
80
  // We do not want to repeat work `JSON.stringify`ing an object containing the potentially large project graph so merge as strings
78
81
  return `{ "error": ${JSON.stringify(error ? (0, serializable_error_1.createSerializableError)(error) : error)}, "projectGraph": ${serializedProjectGraph}, "sourceMaps": ${serializedSourceMaps} }`;
79
82
  }
83
+ function serializeAs(data, format) {
84
+ return format === 'v8'
85
+ ? (0, v8_1.serialize)(data)
86
+ : Buffer.from(JSON.stringify(data), 'utf8');
87
+ }
80
88
  /**
81
- * Helper to serialize data either using v8 serialization or JSON serialization, based on
82
- * the user's preference and the success of each method. Should only be used by "client" side
83
- * connections, daemon or other servers should respond based on the type of serialization used
84
- * by the client it is communicating with.
89
+ * Serialize using `preferred`, falling back to the other format when it throws.
90
+ * Neither format subsumes the other: JSON cannot represent a BigInt and hits the
91
+ * max string length far sooner, while v8 cannot clone a function.
85
92
  *
86
93
  * @param data Data to serialize
87
- * @param force Forces one serialization method over the other
88
- * @returns Serialized data as a string
94
+ * @param preferred Format to attempt first
95
+ * @returns Serialized data as bytes ready to be framed onto a socket
89
96
  */
90
- function serialize(data, force) {
91
- if (force === 'v8' || (0, is_v8_serializer_enabled_1.isV8SerializerEnabled)()) {
92
- try {
93
- return (0, v8_1.serialize)(data).toString('binary');
94
- }
95
- catch (e) {
96
- if (force !== 'v8') {
97
- console.warn(`Data could not be serialized using v8 serialization: ${e}. Falling back to JSON serialization.`);
98
- // Fall back to JSON serialization
99
- return JSON.stringify(data);
100
- }
101
- throw e;
102
- }
97
+ function serializeWithFallback(data, preferred) {
98
+ try {
99
+ return serializeAs(data, preferred);
103
100
  }
104
- else {
105
- try {
106
- return JSON.stringify(data);
107
- }
108
- catch (e) {
109
- if (force !== 'json') {
110
- // Fall back to v8 serialization
111
- console.warn(`Data could not be serialized using JSON.stringify: ${e}. Falling back to v8 serialization.`);
112
- return (0, v8_1.serialize)(data).toString('binary');
113
- }
114
- throw e;
115
- }
101
+ catch (e) {
102
+ const fallback = preferred === 'v8' ? 'json' : 'v8';
103
+ console.warn(`Data could not be serialized using ${preferred} serialization: ${e}. Falling back to ${fallback} serialization.`);
104
+ return serializeAs(data, fallback);
116
105
  }
117
106
  }
107
+ /**
108
+ * Serialize data for IPC using the format the user configured.
109
+ *
110
+ * @param data Data to serialize
111
+ * @param force Use this format without falling back. For callers whose data is
112
+ * known to be unrepresentable in the other format, where a fallback
113
+ * would only swap one failure for a less obvious one.
114
+ * @returns Serialized data as bytes ready to be framed onto a socket
115
+ */
116
+ function serialize(data, force) {
117
+ return force
118
+ ? serializeAs(data, force)
119
+ : serializeWithFallback(data, (0, is_v8_serializer_enabled_1.isV8SerializerEnabled)() ? 'v8' : 'json');
120
+ }
121
+ /**
122
+ * Serialize `data` and write it as one framed message.
123
+ *
124
+ * Lives here rather than in `writeMessage` so the framing stays a byte-level
125
+ * primitive: `utils/consume-messages-from-socket` is shared by callers that
126
+ * already hold bytes, and having it reach back into the daemon's serializer
127
+ * would invert the dependency.
128
+ */
129
+ function sendMessage(socket, data, force, callback) {
130
+ (0, consume_messages_from_socket_1.writeMessage)(socket, serialize(data, force), callback);
131
+ }
@@ -9,7 +9,7 @@ function createTaskHasher(projectGraph, nxJson, runnerOptions) {
9
9
  return new task_hasher_1.DaemonBasedTaskHasher(client_1.daemonClient, runnerOptions);
10
10
  }
11
11
  else {
12
- const { fileMap, allWorkspaceFiles, rustReferences } = (0, build_project_graph_1.getFileMap)();
12
+ const { rustReferences } = (0, build_project_graph_1.getFileMap)();
13
13
  return new task_hasher_1.InProcessTaskHasher(projectGraph, nxJson, rustReferences, runnerOptions);
14
14
  }
15
15
  }
Binary file
@@ -2,18 +2,16 @@ import { FileMap, ProjectGraph, ProjectGraphExternalNode } from '../config/proje
2
2
  import { ProjectConfiguration } from '../config/workspace-json-project-json';
3
3
  import { NxWorkspaceFilesExternals } from '../native';
4
4
  import { CreateMetadataError } from './error-types';
5
- import { FileData } from './file-utils';
6
5
  import { FileMapCache } from './nx-deps-cache';
7
6
  import { CreateMetadataContext } from './plugins';
8
7
  import type { LoadedNxPlugin } from './plugins/loaded-nx-plugin';
9
8
  import type { ConfigurationSourceMaps } from './utils/project-configuration/source-maps';
10
9
  export declare function getFileMap(): {
11
10
  fileMap: FileMap;
12
- allWorkspaceFiles: FileData[];
13
11
  rustReferences: NxWorkspaceFilesExternals | null;
14
12
  };
15
- export declare function hydrateFileMap(fileMap: FileMap, allWorkspaceFiles: FileData[], rustReferences: NxWorkspaceFilesExternals): void;
16
- export declare function buildProjectGraphUsingProjectFileMap(projectRootMap: Record<string, ProjectConfiguration>, externalNodes: Record<string, ProjectGraphExternalNode>, fileMap: FileMap, allWorkspaceFiles: FileData[], rustReferences: NxWorkspaceFilesExternals, fileMapCache: FileMapCache | null, plugins: LoadedNxPlugin[], sourceMap: ConfigurationSourceMaps): Promise<{
13
+ export declare function hydrateFileMap(fileMap: FileMap, rustReferences: NxWorkspaceFilesExternals): void;
14
+ export declare function buildProjectGraphUsingProjectFileMap(projectRootMap: Record<string, ProjectConfiguration>, externalNodes: Record<string, ProjectGraphExternalNode>, fileMap: FileMap, rustReferences: NxWorkspaceFilesExternals, fileMapCache: FileMapCache | null, plugins: LoadedNxPlugin[], sourceMap: ConfigurationSourceMaps): Promise<{
17
15
  projectGraph: ProjectGraph;
18
16
  projectFileMapCache: FileMapCache;
19
17
  }>;
@@ -23,13 +23,11 @@ const implicit_project_dependencies_1 = require("./utils/implicit-project-depend
23
23
  const normalize_project_nodes_1 = require("./utils/normalize-project-nodes");
24
24
  const target_merging_1 = require("./utils/project-configuration/target-merging");
25
25
  let storedFileMap = null;
26
- let storedAllWorkspaceFiles = null;
27
26
  let storedRustReferences = null;
28
27
  function getFileMap() {
29
28
  if (!!storedFileMap) {
30
29
  return {
31
30
  fileMap: storedFileMap,
32
- allWorkspaceFiles: storedAllWorkspaceFiles,
33
31
  rustReferences: storedRustReferences,
34
32
  };
35
33
  }
@@ -39,19 +37,16 @@ function getFileMap() {
39
37
  nonProjectFiles: [],
40
38
  projectFileMap: {},
41
39
  },
42
- allWorkspaceFiles: [],
43
40
  rustReferences: null,
44
41
  };
45
42
  }
46
43
  }
47
- function hydrateFileMap(fileMap, allWorkspaceFiles, rustReferences) {
44
+ function hydrateFileMap(fileMap, rustReferences) {
48
45
  storedFileMap = fileMap;
49
- storedAllWorkspaceFiles = allWorkspaceFiles;
50
46
  storedRustReferences = rustReferences;
51
47
  }
52
- async function buildProjectGraphUsingProjectFileMap(projectRootMap, externalNodes, fileMap, allWorkspaceFiles, rustReferences, fileMapCache, plugins, sourceMap) {
48
+ async function buildProjectGraphUsingProjectFileMap(projectRootMap, externalNodes, fileMap, rustReferences, fileMapCache, plugins, sourceMap) {
53
49
  storedFileMap = fileMap;
54
- storedAllWorkspaceFiles = allWorkspaceFiles;
55
50
  storedRustReferences = rustReferences;
56
51
  const projects = {};
57
52
  for (const root in projectRootMap) {
@@ -1,8 +1,7 @@
1
- import { FileData, FileMap, ProjectFileMap, ProjectGraph } from '../config/project-graph';
2
- import { ProjectConfiguration, ProjectsConfigurations } from '../config/workspace-json-project-json';
1
+ import type { FileData, FileMap, ProjectFileMap, ProjectGraph } from '../config/project-graph';
2
+ import type { ProjectConfiguration, ProjectsConfigurations } from '../config/workspace-json-project-json';
3
3
  import { NxWorkspaceFilesExternals } from '../native';
4
4
  export interface WorkspaceFileMap {
5
- allWorkspaceFiles: FileData[];
6
5
  fileMap: FileMap;
7
6
  }
8
7
  export declare function createProjectFileMapUsingProjectGraph(graph: ProjectGraph): Promise<ProjectFileMap>;
@@ -10,6 +9,5 @@ export declare function createFileMapUsingProjectGraph(graph: ProjectGraph): Pro
10
9
  export declare function createFileMap(projectsConfigurations: ProjectsConfigurations, allWorkspaceFiles: FileData[]): WorkspaceFileMap;
11
10
  export declare function updateFileMap(projectsConfigurations: Record<string, ProjectConfiguration>, rustReferences: NxWorkspaceFilesExternals, updatedFiles: Record<string, string>, deletedFiles: string[]): {
12
11
  fileMap: import("../native").FileMap;
13
- allWorkspaceFiles: FileData[];
14
12
  rustReferences: NxWorkspaceFilesExternals;
15
13
  };
@@ -7,7 +7,6 @@ exports.updateFileMap = updateFileMap;
7
7
  const workspace_context_1 = require("../utils/workspace-context");
8
8
  const workspace_root_1 = require("../utils/workspace-root");
9
9
  const project_graph_1 = require("./project-graph");
10
- const build_all_workspace_files_1 = require("./utils/build-all-workspace-files");
11
10
  const find_project_for_path_1 = require("./utils/find-project-for-path");
12
11
  async function createProjectFileMapUsingProjectGraph(graph) {
13
12
  return (await createFileMapUsingProjectGraph(graph)).fileMap.projectFileMap;
@@ -38,7 +37,6 @@ function createFileMap(projectsConfigurations, allWorkspaceFiles) {
38
37
  }
39
38
  }
40
39
  return {
41
- allWorkspaceFiles,
42
40
  fileMap: {
43
41
  projectFileMap,
44
42
  nonProjectFiles,
@@ -49,7 +47,6 @@ function updateFileMap(projectsConfigurations, rustReferences, updatedFiles, del
49
47
  const updates = (0, workspace_context_1.updateProjectFiles)(Object.fromEntries((0, find_project_for_path_1.createProjectRootMappingsFromProjectConfigurations)(projectsConfigurations)), rustReferences, updatedFiles, deletedFiles);
50
48
  return {
51
49
  fileMap: updates.fileMap,
52
- allWorkspaceFiles: (0, build_all_workspace_files_1.buildAllWorkspaceFiles)(updates.fileMap.projectFileMap, updates.fileMap.nonProjectFiles),
53
50
  rustReferences: updates.externalReferences,
54
51
  };
55
52
  }
@@ -52,7 +52,17 @@ class IsolatedPlugin {
52
52
  this.responseHandlers = new Map();
53
53
  this.exitHandler = null;
54
54
  this.handleSocketData = (raw) => {
55
- const message = (0, consume_messages_from_socket_1.parseMessage)(raw);
55
+ let message;
56
+ try {
57
+ message = (0, consume_messages_from_socket_1.parseMessage)(raw);
58
+ }
59
+ catch (e) {
60
+ // Runs inside a synchronous socket 'data' callback, so a throw here
61
+ // becomes an uncaughtException in the host process rather than a failed
62
+ // plugin call.
63
+ logger_2.logger.error(`[plugin-client] "${this.name}" sent a message that could not be parsed: ${e instanceof Error ? e.message : e}\nReceived: ${(0, consume_messages_from_socket_1.describeMessage)(raw)}`);
64
+ return;
65
+ }
56
66
  if ((0, messaging_1.isPluginWorkerNotification)(message)) {
57
67
  handlePluginWorkerNotification(message);
58
68
  return;
@@ -94,7 +104,13 @@ class IsolatedPlugin {
94
104
  this.responseHandlers.clear();
95
105
  };
96
106
  worker.on('exit', this.exitHandler);
97
- socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(this.handleSocketData));
107
+ socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(this.handleSocketData, (err) => {
108
+ // Nothing else settles the pending hook promises on a framing
109
+ // failure, so surface it the same way a dead worker would.
110
+ this.exitHandler?.();
111
+ socket.destroy();
112
+ console.error(err.message);
113
+ }));
98
114
  return this.sendLoadMessage();
99
115
  }
100
116
  /**
@@ -6,7 +6,6 @@ exports.isPluginWorkerResult = isPluginWorkerResult;
6
6
  exports.consumeMessage = consumeMessage;
7
7
  exports.sendMessageOverSocket = sendMessageOverSocket;
8
8
  const socket_utils_1 = require("../../../daemon/socket-utils");
9
- const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
10
9
  const workspace_root_1 = require("../../../utils/workspace-root");
11
10
  const NOTIFICATION_TYPES = [
12
11
  'emitLog',
@@ -84,6 +83,5 @@ async function consumeMessage(socket, raw, handlers) {
84
83
  function sendMessageOverSocket(socket, message) {
85
84
  // Stamped here rather than in each constructor, mirroring the daemon.
86
85
  message.workspaceRoot = workspace_root_1.workspaceRoot;
87
- socket.write((0, socket_utils_1.serialize)(message));
88
- socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
86
+ (0, socket_utils_1.sendMessage)(socket, message);
89
87
  }
@@ -87,7 +87,8 @@ const server = (0, net_1.createServer)((socket) => {
87
87
  exclude: plugin.exclude,
88
88
  createNodesPattern: plugin.createNodes?.[0],
89
89
  hasCreateDependencies: 'createDependencies' in plugin && !!plugin.createDependencies,
90
- hasProcessProjectGraph: 'processProjectGraph' in plugin && !!plugin.processProjectGraph,
90
+ hasProcessProjectGraph: 'processProjectGraph' in plugin &&
91
+ !!plugin.processProjectGraph,
91
92
  hasCreateMetadata: 'createMetadata' in plugin && !!plugin.createMetadata,
92
93
  hasPreTasksExecution: 'preTasksExecution' in plugin && !!plugin.preTasksExecution,
93
94
  hasPostTasksExecution: 'postTasksExecution' in plugin && !!plugin.postTasksExecution,
@@ -118,6 +119,13 @@ const server = (0, net_1.createServer)((socket) => {
118
119
  }
119
120
  }),
120
121
  });
122
+ }, (err) => {
123
+ // The host link cannot resynchronize. Exit so the host's 'exit' handler
124
+ // rejects the pending hooks instead of waiting on a reply that the
125
+ // framing failure guarantees will never arrive.
126
+ console.error(err.message);
127
+ socket.destroy();
128
+ process.exit(1);
121
129
  }));
122
130
  // When the host disconnects, clean up and exit.
123
131
  socket.on('end', () => {
@@ -104,14 +104,14 @@ async function buildProjectGraphAndSourceMapsWithoutDaemon() {
104
104
  const { projects, externalNodes, sourceMaps, projectRootMap } = configurationResult;
105
105
  perf_hooks_1.performance.mark('retrieve-project-configurations:end');
106
106
  perf_hooks_1.performance.mark('retrieve-workspace-files:start');
107
- const { allWorkspaceFiles, fileMap, rustReferences } = await (0, retrieve_workspace_files_1.retrieveWorkspaceFiles)(workspace_root_1.workspaceRoot, projectRootMap);
107
+ const { fileMap, rustReferences } = await (0, retrieve_workspace_files_1.retrieveWorkspaceFiles)(workspace_root_1.workspaceRoot, projectRootMap);
108
108
  perf_hooks_1.performance.mark('retrieve-workspace-files:end');
109
109
  const cacheEnabled = process.env.NX_CACHE_PROJECT_GRAPH !== 'false';
110
110
  perf_hooks_1.performance.mark('build-project-graph-using-project-file-map:start');
111
111
  let projectGraphError;
112
112
  let projectGraphResult;
113
113
  try {
114
- projectGraphResult = await (0, build_project_graph_1.buildProjectGraphUsingProjectFileMap)(projects, externalNodes, fileMap, allWorkspaceFiles, rustReferences, cacheEnabled ? (0, nx_deps_cache_1.readFileMapCache)() : null, plugins, sourceMaps);
114
+ projectGraphResult = await (0, build_project_graph_1.buildProjectGraphUsingProjectFileMap)(projects, externalNodes, fileMap, rustReferences, cacheEnabled ? (0, nx_deps_cache_1.readFileMapCache)() : null, plugins, sourceMaps);
115
115
  }
116
116
  catch (e) {
117
117
  if ((0, error_types_1.isAggregateProjectGraphError)(e)) {
@@ -180,8 +180,8 @@ async function readCachedGraphAndHydrateFileMap(minimumComputedAt) {
180
180
  data.root,
181
181
  project,
182
182
  ]));
183
- const { allWorkspaceFiles, fileMap, rustReferences } = await (0, retrieve_workspace_files_1.retrieveWorkspaceFiles)(workspace_root_1.workspaceRoot, projectRootMap);
184
- (0, build_project_graph_1.hydrateFileMap)(fileMap, allWorkspaceFiles, rustReferences);
183
+ const { fileMap, rustReferences } = await (0, retrieve_workspace_files_1.retrieveWorkspaceFiles)(workspace_root_1.workspaceRoot, projectRootMap);
184
+ (0, build_project_graph_1.hydrateFileMap)(fileMap, rustReferences);
185
185
  return graph;
186
186
  }
187
187
  /**
@@ -3,13 +3,12 @@ import { NxJsonConfiguration } from '../../config/nx-json';
3
3
  import { ConfigurationResult } from './project-configuration-utils';
4
4
  import type { LoadedNxPlugin } from '../plugins/loaded-nx-plugin';
5
5
  /**
6
- * Walks the workspace directory to create the `projectFileMap`, `ProjectConfigurations` and `allWorkspaceFiles`
6
+ * Walks the workspace directory to create the `projectFileMap` and `ProjectConfigurations`
7
7
  * @throws
8
8
  * @param workspaceRoot
9
9
  * @param nxJson
10
10
  */
11
11
  export declare function retrieveWorkspaceFiles(workspaceRoot: string, projectRootMap: Record<string, string>): Promise<{
12
- allWorkspaceFiles: import("../file-utils").FileData[];
13
12
  fileMap: {
14
13
  projectFileMap: Record<string, import("../../native").FileData[]>;
15
14
  nonProjectFiles: import("../../native").FileData[];
@@ -11,11 +11,10 @@ const angular_json_1 = require("../../adapter/angular-json");
11
11
  const nx_json_1 = require("../../config/nx-json");
12
12
  const project_configuration_utils_1 = require("./project-configuration-utils");
13
13
  const workspace_context_1 = require("../../utils/workspace-context");
14
- const build_all_workspace_files_1 = require("./build-all-workspace-files");
15
14
  const path_1 = require("path");
16
15
  const get_plugins_1 = require("../plugins/get-plugins");
17
16
  /**
18
- * Walks the workspace directory to create the `projectFileMap`, `ProjectConfigurations` and `allWorkspaceFiles`
17
+ * Walks the workspace directory to create the `projectFileMap` and `ProjectConfigurations`
19
18
  * @throws
20
19
  * @param workspaceRoot
21
20
  * @param nxJson
@@ -29,7 +28,6 @@ async function retrieveWorkspaceFiles(workspaceRoot, projectRootMap) {
29
28
  perf_hooks_1.performance.mark('get-workspace-files:end');
30
29
  perf_hooks_1.performance.measure('get-workspace-files', 'get-workspace-files:start', 'get-workspace-files:end');
31
30
  return {
32
- allWorkspaceFiles: (0, build_all_workspace_files_1.buildAllWorkspaceFiles)(projectFileMap, globalFiles),
33
31
  fileMap: {
34
32
  projectFileMap,
35
33
  nonProjectFiles: globalFiles,
@@ -77,6 +77,14 @@ class PseudoIPCServer {
77
77
  this.childReadyMap.get(childId)();
78
78
  }
79
79
  }
80
+ },
81
+ // Nothing resynchronizes a length-prefixed stream, so report it the
82
+ // same way a socket error is reported and let the peer see the close.
83
+ (err) => {
84
+ for (const childMessage of this.childMessages) {
85
+ childMessage.onError?.(err);
86
+ }
87
+ socket.destroy();
80
88
  }));
81
89
  socket.on('close', () => {
82
90
  for (const childMessage of this.childMessages) {
@@ -91,15 +99,12 @@ class PseudoIPCServer {
91
99
  }
92
100
  sendMessageToChildren(message) {
93
101
  this.sockets.forEach((socket) => {
94
- socket.write((0, socket_utils_1.serialize)({ type: 'TO_CHILDREN_FROM_PARENT', message }));
95
- // send EOT to indicate that the message has been fully written
96
- socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
102
+ (0, socket_utils_1.sendMessage)(socket, { type: 'TO_CHILDREN_FROM_PARENT', message });
97
103
  });
98
104
  }
99
105
  sendMessageToChild(id, message) {
100
106
  this.sockets.forEach((socket) => {
101
- socket.write((0, socket_utils_1.serialize)({ type: 'TO_CHILDREN_FROM_PARENT', id, message }));
102
- socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
107
+ (0, socket_utils_1.sendMessage)(socket, { type: 'TO_CHILDREN_FROM_PARENT', id, message });
103
108
  });
104
109
  }
105
110
  onMessageFromChildren(onMessage, onClose = () => { }, onError = (err) => { }) {
@@ -121,17 +126,13 @@ class PseudoIPCClient {
121
126
  this.socket = (0, net_1.connect)(this.path);
122
127
  }
123
128
  sendMessageToParent(message) {
124
- this.socket.write((0, socket_utils_1.serialize)({ type: 'TO_PARENT_FROM_CHILDREN', message }));
125
- // send EOT to indicate that the message has been fully written
126
- this.socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
129
+ (0, socket_utils_1.sendMessage)(this.socket, { type: 'TO_PARENT_FROM_CHILDREN', message });
127
130
  }
128
131
  notifyChildIsReady(id) {
129
- this.socket.write((0, socket_utils_1.serialize)({
132
+ (0, socket_utils_1.sendMessage)(this.socket, {
130
133
  type: 'CHILD_READY',
131
134
  message: id,
132
- }));
133
- // send EOT to indicate that the message has been fully written
134
- this.socket.write(consume_messages_from_socket_1.MESSAGE_END_SEQ);
135
+ });
135
136
  }
136
137
  onMessageFromParent(forkId, onMessage, onClose = () => { }, onError = (err) => { }) {
137
138
  this.socket.on('data', (0, consume_messages_from_socket_1.consumeMessagesFromSocket)(async (rawMessage) => {
@@ -144,7 +145,7 @@ class PseudoIPCClient {
144
145
  onMessage(message);
145
146
  }
146
147
  }
147
- }));
148
+ }, onError));
148
149
  this.socket.on('close', onClose);
149
150
  this.socket.on('error', onError);
150
151
  return this;
@@ -1,9 +1,44 @@
1
- export declare const MESSAGE_END_SEQ: string;
2
- export declare function consumeMessagesFromSocket(callback: (message: string) => void): (data: any) => void;
3
- export declare function isJsonMessage(message: string): boolean;
1
+ import type { Socket } from 'net';
2
+ export declare const MESSAGE_HEADER_PREFIX = "NX_MSG_";
4
3
  /**
5
- * Parse a message that was produced by `serialize()` in
6
- * `daemon/socket-utils.ts`. Auto-detects JSON vs. v8-serialized payloads using
7
- * `isJsonMessage()` and decodes the binary path via `v8.deserialize`.
4
+ * Ceiling on a single message, in bytes. Payloads are buffered outside the V8
5
+ * heap, so `--max-old-space-size` does not bound them and a peer that declares
6
+ * a huge length would otherwise be allowed to stream until the machine gives
7
+ * out. The default is four times the ~0.5GiB string ceiling that used to cap
8
+ * every message, so it clears any payload that previously worked or was meant
9
+ * to. Set `NX_MAX_MESSAGE_SIZE` to another byte count to change it, or to 0 to
10
+ * remove the ceiling. The daemon reads it from the env it was spawned with —
11
+ * clients do not reflect it (see DAEMON_ENV_VARS_EXCLUSIONS) — so changing it
12
+ * needs a daemon restart (`nx reset`).
8
13
  */
9
- export declare function parseMessage<T = unknown>(message: string): T;
14
+ export declare const DEFAULT_MAX_MESSAGE_SIZE: number;
15
+ export declare function getMaxMessageSize(): number;
16
+ export declare function frameHeader(payloadLength: number): Buffer;
17
+ /**
18
+ * Writes a length-prefixed message. The header and payload are written
19
+ * separately so a large payload is never copied to prepend its header.
20
+ */
21
+ export declare function writeMessage(socket: Socket, payload: Buffer, callback?: (err?: Error) => void): void;
22
+ export declare class MessageFramingError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ export declare function consumeMessagesFromSocket(callback: (message: Buffer) => void, onError?: (error: MessageFramingError) => void): (data: Buffer) => void;
26
+ /**
27
+ * v8-serialized payloads always begin with the 0xFF version header, which no
28
+ * JSON document can start with.
29
+ */
30
+ export declare function isJsonMessage(message: Buffer): boolean;
31
+ /**
32
+ * Render part of a message for an error message. A v8 payload is binary rather
33
+ * than utf8 text — its 0xFF header alone can never decode — so it is rendered
34
+ * as hex instead of as U+FFFD-riddled mojibake.
35
+ */
36
+ export declare function describeMessage(message: Buffer, { maxBytes, from }?: DescribeMessageOptions): string;
37
+ export interface DescribeMessageOptions {
38
+ maxBytes?: number;
39
+ from?: 'start' | 'end';
40
+ }
41
+ /**
42
+ * Parse a message produced by `serialize()` in `daemon/socket-utils.ts`.
43
+ */
44
+ export declare function parseMessage<T = unknown>(message: Buffer): T;