nx 22.7.7 → 22.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -1
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +1 -1
- package/dist/src/command-line/init/init-v2.js +1 -1
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/daemon/client/client.d.ts +45 -3
- package/dist/src/daemon/client/client.js +138 -42
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +33 -0
- package/dist/src/daemon/message-types/daemon-message.js +48 -0
- package/dist/src/daemon/server/latest-nx.js +3 -1
- package/dist/src/daemon/server/server.js +22 -0
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +1 -0
- package/dist/src/devkit-internals.js +4 -1
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/project-graph/file-utils.js +5 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/project-graph.js +20 -0
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +1 -3
- package/dist/src/utils/git-utils.js +83 -47
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-json.d.ts +3 -3
- package/dist/src/utils/package-json.js +30 -12
- package/dist/src/utils/package-manager.d.ts +13 -0
- package/dist/src/utils/package-manager.js +27 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/package.json +17 -13
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getLatestNxTmpPath = getLatestNxTmpPath;
|
|
4
4
|
exports.cleanupLatestNx = cleanupLatestNx;
|
|
5
5
|
const devkit_internals_1 = require("../../devkit-internals");
|
|
6
|
+
const package_manager_1 = require("../../utils/package-manager");
|
|
6
7
|
const provenance_1 = require("../../utils/provenance");
|
|
8
|
+
const workspace_root_1 = require("../../utils/workspace-root");
|
|
7
9
|
const logger_1 = require("../logger");
|
|
8
10
|
// Module-level state - persists across invocations within daemon lifecycle
|
|
9
11
|
let latestNxTmpPath = null;
|
|
@@ -26,7 +28,7 @@ async function getLatestNxTmpPath() {
|
|
|
26
28
|
try {
|
|
27
29
|
logger_1.serverLogger.log('[LATEST-NX]: Pulling latest Nx...');
|
|
28
30
|
await (0, provenance_1.ensurePackageHasProvenance)('nx', 'latest');
|
|
29
|
-
const result = await (0, devkit_internals_1.installPackageToTmpAsync)('nx', 'latest');
|
|
31
|
+
const result = await (0, devkit_internals_1.installPackageToTmpAsync)('nx', 'latest', (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot));
|
|
30
32
|
latestNxTmpPath = result.tempDir;
|
|
31
33
|
cleanupFn = result.cleanup;
|
|
32
34
|
logger_1.serverLogger.log('[LATEST-NX]: Successfully pulled latest Nx to', latestNxTmpPath);
|
|
@@ -116,6 +116,17 @@ async function handleMessage(socket, data) {
|
|
|
116
116
|
await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));
|
|
117
117
|
}
|
|
118
118
|
logger_1.serverLogger.log(`Received ${mode} message of type ${payload.type}`);
|
|
119
|
+
// A mismatch means the client reached the wrong daemon (e.g. a shared
|
|
120
|
+
// NX_SOCKET_DIR). Respond, but stay alive for our own workspace.
|
|
121
|
+
if ((0, daemon_message_1.isDaemonMessage)(payload)) {
|
|
122
|
+
try {
|
|
123
|
+
(0, daemon_message_1.assertNotForeignWorkspaceMessage)(payload, workspace_root_1.workspaceRoot);
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
await (0, shutdown_utils_1.respondWithError)(socket, `Workspace root mismatch`, e);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
119
130
|
if ((0, daemon_message_1.isDaemonMessage)(payload) && payload.env) {
|
|
120
131
|
let shouldRecomputeGraph = false;
|
|
121
132
|
for (const key in payload.env) {
|
|
@@ -461,6 +472,17 @@ async function startServer() {
|
|
|
461
472
|
server.listen(socketPath, async () => {
|
|
462
473
|
try {
|
|
463
474
|
logger_1.serverLogger.log(`Started listening on: ${socketPath}`);
|
|
475
|
+
// Linux gates connect() on write permission to the socket file; macOS/BSD gate
|
|
476
|
+
// on the directory, which is already 0700. Done after listen because
|
|
477
|
+
// net.Server.listen takes no mode and umask is process-global.
|
|
478
|
+
if (!socket_utils_1.isWindows) {
|
|
479
|
+
try {
|
|
480
|
+
(0, fs_1.chmodSync)(socketPath, 0o600);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
// Best effort; the 0700 socket directory is the primary control.
|
|
484
|
+
}
|
|
485
|
+
}
|
|
464
486
|
// this triggers the storage of the lock file hash
|
|
465
487
|
daemonIsOutdated();
|
|
466
488
|
if (!(0, shutdown_utils_1.getWatcherInstance)()) {
|
|
@@ -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
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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 (!
|
|
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.
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
*
|
|
9
|
-
*
|
|
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
|
|
51
|
+
export declare function getRefusedConfiguredSocketDir(): string | undefined;
|
|
12
52
|
export declare function removeSocketDir(): void;
|