nx 23.1.1 → 23.1.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 (128) hide show
  1. package/dist/release/changelog-renderer/index.js +4 -5
  2. package/dist/release/index.d.ts +1 -1
  3. package/dist/src/command-line/add/add.js +5 -0
  4. package/dist/src/command-line/affected/affected.js +1 -0
  5. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
  6. package/dist/src/command-line/import/import.js +1 -2
  7. package/dist/src/command-line/init/init-v2.js +4 -5
  8. package/dist/src/command-line/migrate/migrate.d.ts +4 -0
  9. package/dist/src/command-line/migrate/migrate.js +89 -26
  10. package/dist/src/command-line/release/changelog.js +5 -0
  11. package/dist/src/command-line/release/index.d.ts +1 -1
  12. package/dist/src/command-line/release/utils/git.js +1 -1
  13. package/dist/src/command-line/release/utils/release-graph.d.ts +17 -0
  14. package/dist/src/command-line/release/utils/release-graph.js +71 -19
  15. package/dist/src/command-line/release/utils/remote-release-clients/github.js +6 -0
  16. package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
  17. package/dist/src/command-line/release/version/release-group-processor.js +80 -6
  18. package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
  19. package/dist/src/command-line/release/version/version-actions.js +9 -1
  20. package/dist/src/command-line/release/version.js +9 -5
  21. package/dist/src/command-line/reset/reset.js +6 -1
  22. package/dist/src/command-line/run/run-one.js +1 -0
  23. package/dist/src/command-line/run-many/run-many.js +1 -0
  24. package/dist/src/command-line/watch/watch.js +13 -0
  25. package/dist/src/core/graph/main.js +1 -1
  26. package/dist/src/core/graph/styles.js +1 -1
  27. package/dist/src/daemon/client/client.d.ts +52 -1
  28. package/dist/src/daemon/client/client.js +160 -36
  29. package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
  30. package/dist/src/daemon/client/daemon-environment.js +110 -2
  31. package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
  32. package/dist/src/daemon/message-types/daemon-message.d.ts +33 -0
  33. package/dist/src/daemon/message-types/daemon-message.js +48 -0
  34. package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
  35. package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
  36. package/dist/src/daemon/server/latest-nx.js +5 -2
  37. package/dist/src/daemon/server/server.js +24 -0
  38. package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
  39. package/dist/src/daemon/server/shutdown-utils.js +11 -4
  40. package/dist/src/daemon/socket-utils.d.ts +1 -0
  41. package/dist/src/daemon/socket-utils.js +24 -3
  42. package/dist/src/daemon/tmp-dir.d.ts +43 -3
  43. package/dist/src/daemon/tmp-dir.js +437 -15
  44. package/dist/src/devkit-internals.d.ts +94 -4
  45. package/dist/src/devkit-internals.js +194 -5
  46. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
  47. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
  48. package/dist/src/generators/tree.d.ts +4 -2
  49. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  50. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  51. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  52. package/dist/src/native/index.d.ts +10 -0
  53. package/dist/src/native/index.js +71 -28
  54. package/dist/src/native/native-bindings.js +1 -0
  55. package/dist/src/native/native-file-cache-location.d.ts +17 -1
  56. package/dist/src/native/native-file-cache-location.js +86 -12
  57. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  58. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  59. package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
  60. package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
  61. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  62. package/dist/src/plugins/js/lock-file/pnpm-parser.js +60 -0
  63. package/dist/src/plugins/js/lock-file/project-graph-pruning.js +14 -8
  64. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
  65. package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +2 -0
  66. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
  67. package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
  68. package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
  69. package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
  70. package/dist/src/project-graph/error-types.d.ts +12 -1
  71. package/dist/src/project-graph/error-types.js +27 -2
  72. package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
  73. package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
  74. package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
  75. package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
  76. package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
  77. package/dist/src/project-graph/project-graph.js +20 -0
  78. package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +5 -1
  79. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +133 -3
  80. package/dist/src/tasks-runner/task-env.js +5 -2
  81. package/dist/src/tasks-runner/utils.js +2 -6
  82. package/dist/src/utils/assert-workspace-validity.js +7 -2
  83. package/dist/src/utils/fileutils.d.ts +5 -0
  84. package/dist/src/utils/fileutils.js +7 -2
  85. package/dist/src/utils/git-worktrees.d.ts +30 -0
  86. package/dist/src/utils/git-worktrees.js +212 -0
  87. package/dist/src/utils/ignore.d.ts +128 -1
  88. package/dist/src/utils/ignore.js +182 -12
  89. package/dist/src/utils/long-running-target.d.ts +10 -0
  90. package/dist/src/utils/long-running-target.js +19 -0
  91. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  92. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  93. package/dist/src/utils/min-release-age/packument.js +1 -1
  94. package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
  95. package/dist/src/utils/nx-tmp-dir.js +40 -0
  96. package/dist/src/utils/owned-private-dir.d.ts +132 -0
  97. package/dist/src/utils/owned-private-dir.js +323 -0
  98. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  99. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  100. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  101. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  102. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  103. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  104. package/dist/src/utils/package-manager.d.ts +21 -2
  105. package/dist/src/utils/package-manager.js +244 -47
  106. package/dist/src/utils/provenance.js +6 -14
  107. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  108. package/dist/src/utils/registry-config/bun.js +257 -0
  109. package/dist/src/utils/registry-config/index.d.ts +13 -0
  110. package/dist/src/utils/registry-config/index.js +102 -0
  111. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  112. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  113. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  114. package/dist/src/utils/registry-config/utils.js +496 -0
  115. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  116. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  117. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  118. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  119. package/dist/src/utils/safe-spawn.d.ts +24 -0
  120. package/dist/src/utils/safe-spawn.js +104 -0
  121. package/dist/src/utils/shell-quoting.d.ts +15 -0
  122. package/dist/src/utils/shell-quoting.js +35 -0
  123. package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
  124. package/dist/src/utils/wait-for-socket-connection.js +14 -8
  125. package/migrations.json +6 -0
  126. package/package.json +12 -12
  127. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  128. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -1,6 +1,39 @@
1
1
  export type DaemonMessage = {
2
2
  type: string;
3
3
  env?: Record<string, string>;
4
+ /**
5
+ * Stamped centrally by `DaemonSocketMessenger.sendMessage`, not by the ~30
6
+ * sites that construct messages — hence optional. It can also be absent on a
7
+ * message that predates the field, which is why `isForeignWorkspaceMessage`
8
+ * treats `undefined` as "not foreign".
9
+ */
10
+ workspaceRoot?: string;
4
11
  data?: any;
5
12
  };
6
13
  export declare function isDaemonMessage(msg: unknown): msg is DaemonMessage;
14
+ /**
15
+ * Any message carrying the sender's workspace root. Structural so the checks
16
+ * below serve the daemon and the plugin worker without either importing the
17
+ * other's message type. `type` is required only so the type is not all-optional,
18
+ * which would accept `{}`.
19
+ */
20
+ type WorkspaceScopedMessage = {
21
+ type: string;
22
+ workspaceRoot?: string;
23
+ };
24
+ /**
25
+ * A message from a different workspace — two sharing an NX_SOCKET_DIR — must not
26
+ * be processed. Roots are normalized first so that a workspace does not look
27
+ * foreign to itself; see {@link normalizeWorkspaceRoot}.
28
+ */
29
+ export declare function isForeignWorkspaceMessage(msg: WorkspaceScopedMessage, receiverWorkspaceRoot: string): boolean;
30
+ /**
31
+ * Throws on a message this receiver must not act on. The daemon catches it and
32
+ * responds with the mismatch; the plugin worker catches it and drops the
33
+ * message. `receiverDescription` names whichever raised it.
34
+ *
35
+ * An unstamped message is deliberately accepted: this is accident detection,
36
+ * not a control.
37
+ */
38
+ export declare function assertNotForeignWorkspaceMessage(msg: WorkspaceScopedMessage, receiverWorkspaceRoot: string, receiverDescription?: string): void;
39
+ export {};
@@ -1,6 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isDaemonMessage = isDaemonMessage;
4
+ exports.isForeignWorkspaceMessage = isForeignWorkspaceMessage;
5
+ exports.assertNotForeignWorkspaceMessage = assertNotForeignWorkspaceMessage;
6
+ const node_path_1 = require("node:path");
4
7
  function isDaemonMessage(msg) {
5
8
  return typeof msg === 'object' && msg && 'type' in msg;
6
9
  }
10
+ /**
11
+ * Puts a workspace root into a form two independently-resolved spellings of the
12
+ * same directory agree on.
13
+ *
14
+ * The sender's root and the receiver's root do not always come out of the same
15
+ * branch of `workspaceRootInner`: one side can be handed `NX_WORKSPACE_ROOT_PATH`
16
+ * verbatim while the other walks up from `process.cwd()`. On Windows those two
17
+ * sources routinely disagree on the case of the drive letter — an editor or
18
+ * agent may export `d:\repo` while `process.cwd()` reports `D:\repo` — and on
19
+ * separators. Both address the same directory: Windows paths are
20
+ * case-insensitive, and a drive letter is case-insensitive without exception.
21
+ *
22
+ * POSIX roots keep their case, where `/repo` and `/REPO` really can be two
23
+ * directories.
24
+ */
25
+ function normalizeWorkspaceRoot(workspaceRoot) {
26
+ return process.platform === 'win32'
27
+ ? node_path_1.win32.normalize(workspaceRoot).toLowerCase()
28
+ : node_path_1.posix.normalize(workspaceRoot);
29
+ }
30
+ /**
31
+ * A message from a different workspace — two sharing an NX_SOCKET_DIR — must not
32
+ * be processed. Roots are normalized first so that a workspace does not look
33
+ * foreign to itself; see {@link normalizeWorkspaceRoot}.
34
+ */
35
+ function isForeignWorkspaceMessage(msg, receiverWorkspaceRoot) {
36
+ if (msg.workspaceRoot === undefined) {
37
+ return false;
38
+ }
39
+ return (normalizeWorkspaceRoot(msg.workspaceRoot) !==
40
+ normalizeWorkspaceRoot(receiverWorkspaceRoot));
41
+ }
42
+ /**
43
+ * Throws on a message this receiver must not act on. The daemon catches it and
44
+ * responds with the mismatch; the plugin worker catches it and drops the
45
+ * message. `receiverDescription` names whichever raised it.
46
+ *
47
+ * An unstamped message is deliberately accepted: this is accident detection,
48
+ * not a control.
49
+ */
50
+ function assertNotForeignWorkspaceMessage(msg, receiverWorkspaceRoot, receiverDescription = `The Nx Daemon for '${receiverWorkspaceRoot}'`) {
51
+ if (isForeignWorkspaceMessage(msg, receiverWorkspaceRoot)) {
52
+ throw new Error(`${receiverDescription} received a message from a different workspace ('${msg.workspaceRoot}') and refused to process it. This usually means multiple workspaces are sharing a socket directory; ensure NX_SOCKET_DIR (or NX_DAEMON_SOCKET_DIR) is not set to a shared location.`);
53
+ }
54
+ }
@@ -9,4 +9,9 @@ export declare let registeredFileWatcherSockets: {
9
9
  }[];
10
10
  export declare function removeRegisteredFileWatcherSocket(socket: Socket): void;
11
11
  export declare function hasRegisteredFileWatcherSockets(): boolean;
12
+ /**
13
+ * The workspace watcher has died; no further change events will ever arrive.
14
+ * Registered clients are passive, so without this push they wait forever.
15
+ */
16
+ export declare function notifyFileWatcherSocketsOfError(error: Error): void;
12
17
  export declare function notifyFileWatcherSockets(createdFiles: string[] | null, updatedFiles: string[], deletedFiles: string[]): void;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.registeredFileWatcherSockets = void 0;
4
4
  exports.removeRegisteredFileWatcherSocket = removeRegisteredFileWatcherSocket;
5
5
  exports.hasRegisteredFileWatcherSockets = hasRegisteredFileWatcherSockets;
6
+ exports.notifyFileWatcherSocketsOfError = notifyFileWatcherSocketsOfError;
6
7
  exports.notifyFileWatcherSockets = notifyFileWatcherSockets;
7
8
  const find_matching_projects_1 = require("../../../utils/find-matching-projects");
8
9
  const project_graph_utils_1 = require("../../../utils/project-graph-utils");
@@ -18,6 +19,21 @@ function removeRegisteredFileWatcherSocket(socket) {
18
19
  function hasRegisteredFileWatcherSockets() {
19
20
  return exports.registeredFileWatcherSockets.length > 0;
20
21
  }
22
+ /**
23
+ * The workspace watcher has died; no further change events will ever arrive.
24
+ * Registered clients are passive, so without this push they wait forever.
25
+ */
26
+ function notifyFileWatcherSocketsOfError(error) {
27
+ if (!hasRegisteredFileWatcherSockets()) {
28
+ return;
29
+ }
30
+ queue.sendToQueue(async () => {
31
+ await Promise.all(exports.registeredFileWatcherSockets.map(({ socket }) => (0, server_1.handleResult)(socket, 'FILE-WATCH-CHANGED', () => Promise.resolve({
32
+ description: 'File watch error',
33
+ response: JSON.stringify({ watcherError: error.message }),
34
+ }), 'json')));
35
+ });
36
+ }
21
37
  function notifyFileWatcherSockets(createdFiles, updatedFiles, deletedFiles) {
22
38
  if (!hasRegisteredFileWatcherSockets()) {
23
39
  return;
@@ -2,7 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getLatestNxTmpPath = getLatestNxTmpPath;
4
4
  exports.cleanupLatestNx = cleanupLatestNx;
5
- const devkit_internals_1 = require("../../devkit-internals");
5
+ // Import from the defining module, not the devkit-internals barrel: the barrel
6
+ // eagerly pulls in the task-execution subsystem and instantiates a daemon
7
+ // client, all of which would stay resident for the daemon server's lifetime.
8
+ const package_json_1 = require("../../utils/package-json");
6
9
  const package_manager_1 = require("../../utils/package-manager");
7
10
  const provenance_1 = require("../../utils/provenance");
8
11
  const workspace_root_1 = require("../../utils/workspace-root");
@@ -28,7 +31,7 @@ async function getLatestNxTmpPath() {
28
31
  try {
29
32
  logger_1.serverLogger.log('[LATEST-NX]: Pulling latest Nx...');
30
33
  await (0, provenance_1.ensurePackageHasProvenance)('nx', 'latest');
31
- const result = await (0, devkit_internals_1.installPackageToTmpAsync)('nx', 'latest', (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot));
34
+ const result = await (0, package_json_1.installPackageToTmpAsync)('nx', 'latest', (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot));
32
35
  latestNxTmpPath = result.tempDir;
33
36
  cleanupFn = result.cleanup;
34
37
  logger_1.serverLogger.log('[LATEST-NX]: Successfully pulled latest Nx to', latestNxTmpPath);
@@ -119,6 +119,17 @@ async function handleMessage(socket, data) {
119
119
  await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));
120
120
  }
121
121
  logger_1.serverLogger.log(`Received ${mode} message of type ${payload.type}`);
122
+ // A mismatch means the client reached the wrong daemon (e.g. a shared
123
+ // NX_SOCKET_DIR). Respond, but stay alive for our own workspace.
124
+ if ((0, daemon_message_1.isDaemonMessage)(payload)) {
125
+ try {
126
+ (0, daemon_message_1.assertNotForeignWorkspaceMessage)(payload, workspace_root_1.workspaceRoot);
127
+ }
128
+ catch (e) {
129
+ await (0, shutdown_utils_1.respondWithError)(socket, `Workspace root mismatch`, e);
130
+ return;
131
+ }
132
+ }
122
133
  if ((0, daemon_message_1.isDaemonMessage)(payload) && payload.env) {
123
134
  const changedEnvKeys = (0, daemon_environment_1.applyDaemonEnvFromClient)(payload.env);
124
135
  if (changedEnvKeys.length > 0) {
@@ -325,6 +336,7 @@ const handleWorkspaceChanges = async (err, changeEvents) => {
325
336
  logger_1.serverLogger.watcherLog('Unexpected workspace watcher error', error.message);
326
337
  console.error(error);
327
338
  workspaceWatcherError = error;
339
+ (0, file_watcher_sockets_1.notifyFileWatcherSocketsOfError)(error);
328
340
  return;
329
341
  }
330
342
  logger_1.serverLogger.watcherLog((0, watcher_1.convertChangeEventsToLogMessage)(changeEvents));
@@ -334,6 +346,7 @@ const handleWorkspaceChanges = async (err, changeEvents) => {
334
346
  logger_1.serverLogger.watcherLog(`Unexpected workspace error`, err.message);
335
347
  console.error(err);
336
348
  workspaceWatcherError = err;
349
+ (0, file_watcher_sockets_1.notifyFileWatcherSocketsOfError)(err);
337
350
  }
338
351
  };
339
352
  const handleOutputsChanges = async (err, changeEvents) => {
@@ -423,6 +436,17 @@ async function startServer() {
423
436
  server.listen(socketPath, async () => {
424
437
  try {
425
438
  logger_1.serverLogger.log(`Started listening on: ${socketPath}`);
439
+ // Linux gates connect() on write permission to the socket file; macOS/BSD gate
440
+ // on the directory, which is already 0700. Done after listen because
441
+ // net.Server.listen takes no mode and umask is process-global.
442
+ if (!socket_utils_1.isWindows) {
443
+ try {
444
+ (0, fs_1.chmodSync)(socketPath, 0o600);
445
+ }
446
+ catch {
447
+ // Best effort; the 0700 socket directory is the primary control.
448
+ }
449
+ }
426
450
  // this triggers the storage of the lock file hash
427
451
  daemonIsOutdated();
428
452
  if (!(0, shutdown_utils_1.getOutputWatcherInstance)()) {
@@ -14,5 +14,10 @@ export declare function handleServerProcessTermination({ server, reason, sockets
14
14
  export declare function handleServerProcessTerminationWithRestart({ server, reason, sockets, }: HandleServerProcessTerminationParams): Promise<void>;
15
15
  export declare function resetInactivityTimeout(cb: () => void): void;
16
16
  export declare function respondToClient(socket: Socket, response: string, description: string): Promise<unknown>;
17
+ /**
18
+ * Send an error to the client without terminating the daemon. Use this when the
19
+ * daemon should keep running for other clients after refusing a request.
20
+ */
21
+ export declare function respondWithError(socket: Socket, description: string, error: Error): Promise<void>;
17
22
  export declare function respondWithErrorAndExit(socket: Socket, description: string, error: Error): Promise<void>;
18
23
  export {};
@@ -9,6 +9,7 @@ exports.handleServerProcessTermination = handleServerProcessTermination;
9
9
  exports.handleServerProcessTerminationWithRestart = handleServerProcessTerminationWithRestart;
10
10
  exports.resetInactivityTimeout = resetInactivityTimeout;
11
11
  exports.respondToClient = respondToClient;
12
+ exports.respondWithError = respondWithError;
12
13
  exports.respondWithErrorAndExit = respondWithErrorAndExit;
13
14
  const workspace_root_1 = require("../../utils/workspace-root");
14
15
  const logger_1 = require("../logger");
@@ -135,9 +136,12 @@ function respondToClient(socket, response, description) {
135
136
  });
136
137
  });
137
138
  }
138
- async function respondWithErrorAndExit(socket, description, error) {
139
- const isProjectGraphError = error instanceof error_types_1.DaemonProjectGraphError;
140
- const normalizedError = isProjectGraphError
139
+ /**
140
+ * Send an error to the client without terminating the daemon. Use this when the
141
+ * daemon should keep running for other clients after refusing a request.
142
+ */
143
+ async function respondWithError(socket, description, error) {
144
+ const normalizedError = error instanceof error_types_1.DaemonProjectGraphError
141
145
  ? error_types_1.ProjectGraphError.fromDaemonProjectGraphError(error)
142
146
  : error;
143
147
  // print some extra stuff in the error message
@@ -145,8 +149,11 @@ async function respondWithErrorAndExit(socket, description, error) {
145
149
  console.error(normalizedError.stack);
146
150
  // Respond with the original error
147
151
  await respondToClient(socket, (0, socket_utils_1.serializeResult)(error, null, null), null);
152
+ }
153
+ async function respondWithErrorAndExit(socket, description, error) {
154
+ await respondWithError(socket, description, error);
148
155
  // Project Graph errors are okay. Restarting the daemon won't help with this.
149
- if (!isProjectGraphError) {
156
+ if (!(error instanceof error_types_1.DaemonProjectGraphError)) {
150
157
  process.exit(1);
151
158
  }
152
159
  }
@@ -8,6 +8,7 @@ export declare const isWindows: boolean;
8
8
  export declare const getFullOsSocketPath: () => string;
9
9
  export declare const getForkedProcessOsSocketPath: (id: string) => string;
10
10
  export declare const getPluginOsSocketPath: (id: string) => string;
11
+ export declare function getPluginSocketFileName(id: string): string;
11
12
  export declare function killSocketOrPath(): void;
12
13
  export declare function serializeResult(error: Error | null, serializedProjectGraph: string | null, serializedSourceMaps: string | null): string | null;
13
14
  /**
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPluginOsSocketPath = exports.getForkedProcessOsSocketPath = exports.getFullOsSocketPath = exports.isWindows = void 0;
4
+ exports.getPluginSocketFileName = getPluginSocketFileName;
4
5
  exports.killSocketOrPath = killSocketOrPath;
5
6
  exports.serializeResult = serializeResult;
6
7
  exports.serialize = serialize;
@@ -31,18 +32,38 @@ const getForkedProcessOsSocketPath = (id) => {
31
32
  };
32
33
  exports.getForkedProcessOsSocketPath = getForkedProcessOsSocketPath;
33
34
  const getPluginOsSocketPath = (id) => {
34
- let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(true), 'plugin' + id + '.sock'));
35
+ let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getPluginSocketDir)(), getPluginSocketFileName(id)));
35
36
  assertValidSocketPath(path);
36
37
  return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
37
38
  };
38
39
  exports.getPluginOsSocketPath = getPluginOsSocketPath;
40
+ function getPluginSocketFileName(id) {
41
+ return `p${id}.sock`;
42
+ }
39
43
  function assertValidSocketPath(path) {
40
44
  if (path.length > 95) {
45
+ const fallbackCause = (0, tmp_dir_1.getSocketDirFallbackCause)();
46
+ const refusedConfiguredSocketDir = (0, tmp_dir_1.getRefusedConfiguredSocketDir)();
41
47
  throw new Error([
42
48
  'Attempted to open socket that exceeds the maximum socket length.',
49
+ ...(fallbackCause === undefined
50
+ ? []
51
+ : [
52
+ `Nx fell back to ${(0, path_1.dirname)(path)} because the default socket directory could not be used.`,
53
+ 'Run the command with --verbose to see why the default directory was rejected.',
54
+ ]),
43
55
  '',
44
- `Set NX_SOCKET_DIR to a shorter path (e.g. ${exports.isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'}) to avoid this issue.`,
45
- ].join('\n'));
56
+ ...(refusedConfiguredSocketDir === undefined
57
+ ? [
58
+ `Set NX_SOCKET_DIR to a shorter path (e.g. ${exports.isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'}) to avoid this issue.`,
59
+ ]
60
+ : [
61
+ // Saying "set a shorter path" here would be advice they already
62
+ // followed: they set one, and it was refused for another reason.
63
+ `The directory set in NX_SOCKET_DIR (${refusedConfiguredSocketDir}) could not be used — see the warning above — so Nx fell back to a longer path.`,
64
+ 'Point NX_SOCKET_DIR at a short directory your user owns.',
65
+ ]),
66
+ ].join('\n'), fallbackCause === undefined ? undefined : { cause: fallbackCause });
46
67
  }
47
68
  }
48
69
  function killSocketOrPath() {
@@ -1,12 +1,52 @@
1
+ /**
2
+ * Why a directory was refused. Named rather than a boolean so a table entry
3
+ * reads as its own reason: picking the wrong one tells a user their private
4
+ * directory is a code-execution risk, which is the one claim here that most
5
+ * needs to be true.
6
+ */
7
+ export type SocketDirRefusal = 'shared-with-other-users' | 'nx-managed' | 'os-temp-root';
8
+ /**
9
+ * Thrown when the socket dir resolves to a directory Nx will not accept.
10
+ * Invalid configuration, not a recoverable failure.
11
+ *
12
+ * Three reasons, and they are not interchangeable. A directory other users can
13
+ * reach is a security problem; the OS temp root is the user's own but holds
14
+ * everything else that uses it, and Nx deletes the socket directory
15
+ * recursively; an Nx container or cache root is refused because Nx manages what
16
+ * lives there. Telling someone their own `0700` directory lets a local attacker
17
+ * execute code would be false, which is why the reason is derived from the
18
+ * directory rather than the platform.
19
+ */
20
+ export declare class InvalidSocketDirConfigured extends Error {
21
+ readonly dir: string;
22
+ readonly reason: SocketDirRefusal;
23
+ constructor(dir: string, reason: SocketDirRefusal);
24
+ }
1
25
  export declare const DAEMON_DIR_FOR_CURRENT_WORKSPACE: string;
2
26
  export declare const DAEMON_OUTPUT_LOG_FILE: string;
3
27
  export declare const getDaemonSocketDir: () => string;
4
28
  export declare function writeDaemonLogs(error?: string): string;
5
29
  export declare function markDaemonAsDisabled(reason: string): void;
6
30
  export declare function isDaemonDisabled(): boolean;
31
+ export declare function getSocketDir(): string;
32
+ /**
33
+ * Plugin worker sockets get their own workspace-scoped directory rather than
34
+ * sitting in the shared system temp dir, which cannot be locked down.
35
+ */
36
+ export declare function getPluginSocketDir(): string;
37
+ /**
38
+ * Exported for tests: both fallback warnings fire once per process, so a suite
39
+ * that stages either fallback more than once has to clear the latches between
40
+ * cases.
41
+ */
42
+ export declare function resetSocketDirWarningsForTesting(): void;
43
+ export declare function getSocketDirFallbackCause(): unknown;
7
44
  /**
8
- * We try to create a socket file in a tmp dir, but if it doesn't work because
9
- * for instance we don't have permissions, we create it in DAEMON_DIR_FOR_CURRENT_WORKSPACE
45
+ * The NX_SOCKET_DIR that was refused, if that is why we are in the fallback.
46
+ * Reflects the most recent resolution only — both accessors are cleared at the
47
+ * top of every `createOwnerOnlySocketDir` call, and the daemon and plugin socket
48
+ * paths each drive one. Read it immediately after the call that produced the
49
+ * path, which is what `assertValidSocketPath` does.
10
50
  */
11
- export declare function getSocketDir(alreadyUnique?: boolean): string;
51
+ export declare function getRefusedConfiguredSocketDir(): string | undefined;
12
52
  export declare function removeSocketDir(): void;