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.
- package/dist/src/daemon/client/client.d.ts +2 -0
- package/dist/src/daemon/client/client.js +73 -7
- package/dist/src/daemon/client/daemon-environment.d.ts +11 -0
- package/dist/src/daemon/client/daemon-environment.js +20 -0
- package/dist/src/daemon/client/daemon-socket-messenger.d.ts +1 -1
- package/dist/src/daemon/client/daemon-socket-messenger.js +8 -3
- package/dist/src/daemon/is-v8-serializer-enabled.d.ts +2 -2
- package/dist/src/daemon/is-v8-serializer-enabled.js +2 -2
- package/dist/src/daemon/server/client-socket-context.d.ts +1 -1
- package/dist/src/daemon/server/client-socket-context.js +2 -3
- package/dist/src/daemon/server/handle-hash-tasks.js +1 -1
- package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -4
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +1 -14
- package/dist/src/daemon/server/server.js +17 -24
- package/dist/src/daemon/server/shutdown-utils.d.ts +1 -1
- package/dist/src/daemon/server/shutdown-utils.js +2 -2
- package/dist/src/daemon/socket-utils.d.ts +26 -7
- package/dist/src/daemon/socket-utils.js +45 -31
- package/dist/src/hasher/create-task-hasher.js +1 -1
- 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/build-project-graph.d.ts +2 -4
- package/dist/src/project-graph/build-project-graph.js +2 -7
- package/dist/src/project-graph/file-map-utils.d.ts +2 -4
- package/dist/src/project-graph/file-map-utils.js +0 -3
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +18 -2
- package/dist/src/project-graph/plugins/isolation/messaging.js +1 -3
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +9 -1
- package/dist/src/project-graph/project-graph.js +4 -4
- package/dist/src/project-graph/utils/retrieve-workspace-files.d.ts +1 -2
- package/dist/src/project-graph/utils/retrieve-workspace-files.js +1 -3
- package/dist/src/tasks-runner/forked-process-task-runner.d.ts +3 -0
- package/dist/src/tasks-runner/forked-process-task-runner.js +15 -6
- package/dist/src/tasks-runner/init-tasks-runner.js +32 -2
- package/dist/src/tasks-runner/life-cycles/task-history-life-cycle.js +16 -11
- package/dist/src/tasks-runner/pseudo-ipc.js +14 -13
- package/dist/src/tasks-runner/running-tasks/batch-process.js +3 -0
- package/dist/src/tasks-runner/running-tasks/shared-running-task.d.ts +1 -0
- package/dist/src/tasks-runner/running-tasks/shared-running-task.js +12 -1
- package/dist/src/tasks-runner/task-orchestrator.d.ts +3 -0
- package/dist/src/tasks-runner/task-orchestrator.js +40 -6
- package/dist/src/utils/consume-messages-from-socket.d.ts +42 -7
- package/dist/src/utils/consume-messages-from-socket.js +272 -38
- package/dist/src/utils/params.js +1 -1
- package/package.json +11 -11
|
@@ -47,6 +47,7 @@ export declare class TaskOrchestrator {
|
|
|
47
47
|
private discreteTaskExitHandled;
|
|
48
48
|
private continuousTaskExitHandled;
|
|
49
49
|
private cleanupPromise;
|
|
50
|
+
private signalHandlers;
|
|
50
51
|
constructor(hasher: TaskHasher, initiatingProject: string | undefined, initiatingTasks: Task[], projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient, outputStyle: string, taskGraphForHashing?: TaskGraph);
|
|
51
52
|
init(): Promise<void>;
|
|
52
53
|
run(): Promise<{
|
|
@@ -170,6 +171,8 @@ export declare class TaskOrchestrator {
|
|
|
170
171
|
private cleanup;
|
|
171
172
|
private performCleanup;
|
|
172
173
|
private setupSignalHandlers;
|
|
174
|
+
waitForContinuousTaskExit(taskId: string): Promise<void>;
|
|
175
|
+
dispose(): Promise<void>;
|
|
173
176
|
private cleanUpUnneededContinuousTasks;
|
|
174
177
|
}
|
|
175
178
|
export declare function getThreadPoolSize(options: NxArgs & DefaultTasksRunnerOptions, taskGraph: TaskGraph): {
|
|
@@ -86,6 +86,7 @@ class TaskOrchestrator {
|
|
|
86
86
|
this.discreteTaskExitHandled = new Map();
|
|
87
87
|
this.continuousTaskExitHandled = new Map();
|
|
88
88
|
this.cleanupPromise = null;
|
|
89
|
+
this.signalHandlers = [];
|
|
89
90
|
}
|
|
90
91
|
async init() {
|
|
91
92
|
this.setupSignalHandlers();
|
|
@@ -139,6 +140,7 @@ class TaskOrchestrator {
|
|
|
139
140
|
this.cache.removeOldCacheRecords();
|
|
140
141
|
}
|
|
141
142
|
await this.cleanup();
|
|
143
|
+
await this.dispose();
|
|
142
144
|
// Public API (defaultTasksRunner) returns a plain object keyed by
|
|
143
145
|
// task id. Internal state is a Map for faster lookup.
|
|
144
146
|
return Object.fromEntries(this.completedTasks);
|
|
@@ -1184,7 +1186,7 @@ class TaskOrchestrator {
|
|
|
1184
1186
|
await Promise.all(this.discreteTaskExitHandled.values());
|
|
1185
1187
|
}
|
|
1186
1188
|
setupSignalHandlers() {
|
|
1187
|
-
|
|
1189
|
+
const sigintHandler = () => {
|
|
1188
1190
|
this.stopRequested = true;
|
|
1189
1191
|
if (!this.tuiEnabled) {
|
|
1190
1192
|
// Synchronously remove DB entries before async cleanup to prevent
|
|
@@ -1216,23 +1218,55 @@ class TaskOrchestrator {
|
|
|
1216
1218
|
process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
|
|
1217
1219
|
}
|
|
1218
1220
|
});
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
+
};
|
|
1222
|
+
const sigtermHandler = () => {
|
|
1221
1223
|
this.stopRequested = true;
|
|
1222
1224
|
this.cleanup().finally(() => {
|
|
1223
1225
|
if (this.resolveStopPromise) {
|
|
1224
1226
|
this.resolveStopPromise();
|
|
1225
1227
|
}
|
|
1226
1228
|
});
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
+
};
|
|
1230
|
+
const sighupHandler = () => {
|
|
1229
1231
|
this.stopRequested = true;
|
|
1230
1232
|
this.cleanup().finally(() => {
|
|
1231
1233
|
if (this.resolveStopPromise) {
|
|
1232
1234
|
this.resolveStopPromise();
|
|
1233
1235
|
}
|
|
1234
1236
|
});
|
|
1235
|
-
}
|
|
1237
|
+
};
|
|
1238
|
+
for (const [signal, handler] of [
|
|
1239
|
+
['SIGINT', sigintHandler],
|
|
1240
|
+
['SIGTERM', sigtermHandler],
|
|
1241
|
+
['SIGHUP', sighupHandler],
|
|
1242
|
+
]) {
|
|
1243
|
+
this.signalHandlers.push([signal, handler]);
|
|
1244
|
+
process.once(signal, handler);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
// Registered at child creation, so unlike subscribing to RunningTask.onExit
|
|
1248
|
+
// after the fact it cannot miss an exit that already happened.
|
|
1249
|
+
waitForContinuousTaskExit(taskId) {
|
|
1250
|
+
return this.continuousTaskExitHandled.get(taskId) ?? Promise.resolve();
|
|
1251
|
+
}
|
|
1252
|
+
// Releases the process-level listeners registered by setupSignalHandlers.
|
|
1253
|
+
// Each closes over `this`, so a long-lived caller (an Nx Cloud agent creates
|
|
1254
|
+
// an orchestrator per invocation) leaks whole orchestrators until they run.
|
|
1255
|
+
async dispose() {
|
|
1256
|
+
// The forked runner's exit handler is the last-resort kill for child
|
|
1257
|
+
// processes, and a batch child can outlive its results message. Signal the
|
|
1258
|
+
// children first so removing that handler cannot orphan a live one.
|
|
1259
|
+
try {
|
|
1260
|
+
await this.forkedProcessTaskRunner.cleanup();
|
|
1261
|
+
}
|
|
1262
|
+
catch (e) {
|
|
1263
|
+
console.error('Failed to clean up child processes on dispose:', e);
|
|
1264
|
+
}
|
|
1265
|
+
for (const [signal, handler] of this.signalHandlers) {
|
|
1266
|
+
process.off(signal, handler);
|
|
1267
|
+
}
|
|
1268
|
+
this.signalHandlers = [];
|
|
1269
|
+
this.forkedProcessTaskRunner.removeProcessEventListeners();
|
|
1236
1270
|
}
|
|
1237
1271
|
cleanUpUnneededContinuousTasks() {
|
|
1238
1272
|
const incompleteTasks = this.tasksSchedule.getIncompleteTasks();
|
|
@@ -1,9 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
export declare
|
|
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
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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
|
|
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;
|
|
@@ -1,56 +1,290 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.MessageFramingError = exports.DEFAULT_MAX_MESSAGE_SIZE = exports.MESSAGE_HEADER_PREFIX = void 0;
|
|
4
|
+
exports.getMaxMessageSize = getMaxMessageSize;
|
|
5
|
+
exports.frameHeader = frameHeader;
|
|
6
|
+
exports.writeMessage = writeMessage;
|
|
4
7
|
exports.consumeMessagesFromSocket = consumeMessagesFromSocket;
|
|
5
8
|
exports.isJsonMessage = isJsonMessage;
|
|
9
|
+
exports.describeMessage = describeMessage;
|
|
6
10
|
exports.parseMessage = parseMessage;
|
|
7
|
-
const string_decoder_1 = require("string_decoder");
|
|
8
11
|
const v8_1 = require("v8");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
exports.MESSAGE_HEADER_PREFIX = 'NX_MSG_';
|
|
13
|
+
const MESSAGE_HEADER_TERMINATOR = ':'.charCodeAt(0);
|
|
14
|
+
const MESSAGE_HEADER_PREFIX_BYTES = Buffer.from(exports.MESSAGE_HEADER_PREFIX, 'ascii');
|
|
15
|
+
// `Number.MAX_SAFE_INTEGER` is 16 digits, so a longer run of digits than that
|
|
16
|
+
// is a desynchronized stream rather than a very large message.
|
|
17
|
+
const MAX_HEADER_LENGTH = exports.MESSAGE_HEADER_PREFIX.length + 16 + 1;
|
|
18
|
+
/**
|
|
19
|
+
* Ceiling on a single message, in bytes. Payloads are buffered outside the V8
|
|
20
|
+
* heap, so `--max-old-space-size` does not bound them and a peer that declares
|
|
21
|
+
* a huge length would otherwise be allowed to stream until the machine gives
|
|
22
|
+
* out. The default is four times the ~0.5GiB string ceiling that used to cap
|
|
23
|
+
* every message, so it clears any payload that previously worked or was meant
|
|
24
|
+
* to. Set `NX_MAX_MESSAGE_SIZE` to another byte count to change it, or to 0 to
|
|
25
|
+
* remove the ceiling. The daemon reads it from the env it was spawned with —
|
|
26
|
+
* clients do not reflect it (see DAEMON_ENV_VARS_EXCLUSIONS) — so changing it
|
|
27
|
+
* needs a daemon restart (`nx reset`).
|
|
28
|
+
*/
|
|
29
|
+
exports.DEFAULT_MAX_MESSAGE_SIZE = 2 * 1024 * 1024 * 1024;
|
|
30
|
+
function getMaxMessageSize() {
|
|
31
|
+
const configured = process.env.NX_MAX_MESSAGE_SIZE;
|
|
32
|
+
if (configured === undefined || configured === '') {
|
|
33
|
+
return exports.DEFAULT_MAX_MESSAGE_SIZE;
|
|
34
|
+
}
|
|
35
|
+
const parsed = Number(configured);
|
|
36
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
37
|
+
console.warn(`NX_MAX_MESSAGE_SIZE must be a non-negative number of bytes, but was "${configured}". Using the default of ${exports.DEFAULT_MAX_MESSAGE_SIZE}.`);
|
|
38
|
+
return exports.DEFAULT_MAX_MESSAGE_SIZE;
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* `nx reset` only helps while a daemon is enabled: it and its plugin workers keep the
|
|
44
|
+
* limit they were spawned with. Every other reader re-reads the env per invocation.
|
|
45
|
+
* Required lazily because the daemon client imports this module.
|
|
46
|
+
*/
|
|
47
|
+
function daemonHoldsItsOwnLimit() {
|
|
48
|
+
try {
|
|
49
|
+
return require('../daemon/client/client').daemonClient.enabled();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const ZERO = '0'.charCodeAt(0);
|
|
56
|
+
const NINE = '9'.charCodeAt(0);
|
|
57
|
+
function frameHeader(payloadLength) {
|
|
58
|
+
return Buffer.from(`${exports.MESSAGE_HEADER_PREFIX}${payloadLength}:`, 'ascii');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Writes a length-prefixed message. The header and payload are written
|
|
62
|
+
* separately so a large payload is never copied to prepend its header.
|
|
63
|
+
*/
|
|
64
|
+
function writeMessage(socket, payload, callback) {
|
|
65
|
+
socket.write(frameHeader(payload.length));
|
|
66
|
+
socket.write(payload, callback);
|
|
67
|
+
}
|
|
68
|
+
class MessageFramingError extends Error {
|
|
69
|
+
constructor(message) {
|
|
70
|
+
super(message);
|
|
71
|
+
this.name = 'MessageFramingError';
|
|
72
|
+
Object.setPrototypeOf(this, MessageFramingError.prototype);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
exports.MessageFramingError = MessageFramingError;
|
|
76
|
+
function consumeMessagesFromSocket(callback, onError = (error) => {
|
|
77
|
+
console.error(error.message);
|
|
78
|
+
}) {
|
|
79
|
+
let chunks = [];
|
|
80
|
+
let buffered = 0;
|
|
81
|
+
let expectedPayloadLength = null;
|
|
82
|
+
let broken = false;
|
|
83
|
+
// Read once per socket so a test or a caller can change it between
|
|
84
|
+
// connections without paying the lookup on every frame.
|
|
85
|
+
const maxMessageSize = getMaxMessageSize();
|
|
86
|
+
const fail = (message) => {
|
|
87
|
+
broken = true;
|
|
88
|
+
chunks = [];
|
|
89
|
+
buffered = 0;
|
|
90
|
+
expectedPayloadLength = null;
|
|
91
|
+
onError(new MessageFramingError(message));
|
|
92
|
+
};
|
|
93
|
+
// Copies at most `length` leading bytes without collapsing the chunk list.
|
|
94
|
+
const peek = (length) => {
|
|
95
|
+
const size = Math.min(length, buffered);
|
|
96
|
+
if (chunks.length === 1) {
|
|
97
|
+
return chunks[0].subarray(0, size);
|
|
98
|
+
}
|
|
99
|
+
const out = Buffer.allocUnsafe(size);
|
|
100
|
+
let offset = 0;
|
|
101
|
+
for (const chunk of chunks) {
|
|
102
|
+
if (offset >= size)
|
|
103
|
+
break;
|
|
104
|
+
offset += chunk.copy(out, offset, 0, Math.min(chunk.length, size - offset));
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
};
|
|
108
|
+
const take = (length) => {
|
|
109
|
+
if (length === 0) {
|
|
110
|
+
return Buffer.alloc(0);
|
|
111
|
+
}
|
|
112
|
+
// A socket chunk usually carries several whole messages, so slice the
|
|
113
|
+
// leading one out in place rather than allocating and copying for each.
|
|
114
|
+
// The payload is parsed by the callback before the next read, so sharing
|
|
115
|
+
// the chunk's memory does not retain it.
|
|
116
|
+
if (chunks[0].length === length) {
|
|
117
|
+
buffered -= length;
|
|
118
|
+
return chunks.shift();
|
|
119
|
+
}
|
|
120
|
+
if (chunks[0].length > length) {
|
|
121
|
+
const out = chunks[0].subarray(0, length);
|
|
122
|
+
chunks[0] = chunks[0].subarray(length);
|
|
123
|
+
buffered -= length;
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
const out = Buffer.allocUnsafe(length);
|
|
127
|
+
let offset = 0;
|
|
128
|
+
while (offset < length) {
|
|
129
|
+
const chunk = chunks[0];
|
|
130
|
+
const needed = length - offset;
|
|
131
|
+
if (chunk.length <= needed) {
|
|
132
|
+
chunk.copy(out, offset);
|
|
133
|
+
offset += chunk.length;
|
|
134
|
+
chunks.shift();
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
chunk.copy(out, offset, 0, needed);
|
|
138
|
+
chunks[0] = chunk.subarray(needed);
|
|
139
|
+
offset = length;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
buffered -= length;
|
|
143
|
+
return out;
|
|
144
|
+
};
|
|
145
|
+
const discard = (length) => {
|
|
146
|
+
let remaining = length;
|
|
147
|
+
while (remaining > 0) {
|
|
148
|
+
const chunk = chunks[0];
|
|
149
|
+
if (chunk.length <= remaining) {
|
|
150
|
+
remaining -= chunk.length;
|
|
151
|
+
chunks.shift();
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
chunks[0] = chunk.subarray(remaining);
|
|
155
|
+
remaining = 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
buffered -= length;
|
|
159
|
+
};
|
|
160
|
+
// Returns the payload length, or null when the header is still incomplete.
|
|
161
|
+
const readHeader = () => {
|
|
162
|
+
const head = peek(MAX_HEADER_LENGTH);
|
|
163
|
+
for (let i = 0; i < MESSAGE_HEADER_PREFIX_BYTES.length; i++) {
|
|
164
|
+
if (i >= head.length)
|
|
165
|
+
return null;
|
|
166
|
+
if (head[i] !== MESSAGE_HEADER_PREFIX_BYTES[i]) {
|
|
167
|
+
fail(`Expected a message to begin with '${exports.MESSAGE_HEADER_PREFIX}' but received ` +
|
|
168
|
+
`${JSON.stringify(head.toString('utf8', 0, 32))}. The stream is out of sync.`);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
let digits = 0;
|
|
173
|
+
let value = 0;
|
|
174
|
+
for (let i = MESSAGE_HEADER_PREFIX_BYTES.length; i < head.length; i++) {
|
|
175
|
+
const byte = head[i];
|
|
176
|
+
if (byte === MESSAGE_HEADER_TERMINATOR) {
|
|
177
|
+
if (digits === 0) {
|
|
178
|
+
fail(`Message header carried no length.`);
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
if (maxMessageSize > 0 && value > maxMessageSize) {
|
|
182
|
+
fail(`Message of ${value} bytes exceeds the ${maxMessageSize} byte limit. ` +
|
|
183
|
+
`Set NX_MAX_MESSAGE_SIZE to raise it, or to 0 to remove it.` +
|
|
184
|
+
(daemonHoldsItsOwnLimit()
|
|
185
|
+
? ` Then run \`nx reset\`, since a running daemon and the plugin workers it spawns keep the limit they started with.`
|
|
186
|
+
: ''));
|
|
187
|
+
return null;
|
|
28
188
|
}
|
|
189
|
+
discard(i + 1);
|
|
190
|
+
return value;
|
|
29
191
|
}
|
|
30
|
-
|
|
192
|
+
if (byte < ZERO || byte > NINE) {
|
|
193
|
+
fail(`Message header contained a non-digit length. The stream is out of sync.`);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
value = value * 10 + (byte - ZERO);
|
|
197
|
+
digits++;
|
|
198
|
+
}
|
|
199
|
+
if (head.length >= MAX_HEADER_LENGTH) {
|
|
200
|
+
fail(`Message header exceeded ${MAX_HEADER_LENGTH} bytes without a ':'.`);
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
};
|
|
204
|
+
return (data) => {
|
|
205
|
+
if (broken) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
chunks.push(data);
|
|
209
|
+
buffered += data.length;
|
|
210
|
+
while (!broken) {
|
|
211
|
+
if (expectedPayloadLength === null) {
|
|
212
|
+
const length = readHeader();
|
|
213
|
+
if (length === null)
|
|
214
|
+
break;
|
|
215
|
+
expectedPayloadLength = length;
|
|
216
|
+
}
|
|
217
|
+
if (expectedPayloadLength === 0) {
|
|
218
|
+
fail('Message header declared a zero-length payload.');
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
if (buffered < expectedPayloadLength)
|
|
222
|
+
break;
|
|
223
|
+
const payload = take(expectedPayloadLength);
|
|
224
|
+
expectedPayloadLength = null;
|
|
225
|
+
callback(payload);
|
|
31
226
|
}
|
|
32
|
-
// If message doesn't end with MESSAGE_END_SEQ, keep accumulating chunks
|
|
33
227
|
};
|
|
34
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* v8-serialized payloads always begin with the 0xFF version header, which no
|
|
231
|
+
* JSON document can start with.
|
|
232
|
+
*/
|
|
35
233
|
function isJsonMessage(message) {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
234
|
+
return message.length === 0 || message[0] !== 0xff;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Widest slice of `window` that holds only whole utf8 characters. Cutting at an
|
|
238
|
+
* arbitrary byte leaves a partial sequence, and a partial sequence decodes to
|
|
239
|
+
* U+FFFD, which is the corruption `describeMessage` exists to avoid. A slice
|
|
240
|
+
* taken from the end can also begin mid-character, so both edges are trimmed.
|
|
241
|
+
*/
|
|
242
|
+
function trimToCharBoundary(window, from) {
|
|
243
|
+
const isContinuation = (byte) => (byte & 0xc0) === 0x80;
|
|
244
|
+
if (from === 'end') {
|
|
245
|
+
let offset = 0;
|
|
246
|
+
while (offset < window.length && isContinuation(window[offset])) {
|
|
247
|
+
offset++;
|
|
248
|
+
}
|
|
249
|
+
return window.subarray(offset);
|
|
250
|
+
}
|
|
251
|
+
let lead = window.length - 1;
|
|
252
|
+
while (lead >= 0 && isContinuation(window[lead])) {
|
|
253
|
+
lead--;
|
|
254
|
+
}
|
|
255
|
+
if (lead < 0) {
|
|
256
|
+
return window.subarray(0, 0);
|
|
257
|
+
}
|
|
258
|
+
const byte = window[lead];
|
|
259
|
+
const width = byte >= 0xf0 ? 4 : byte >= 0xe0 ? 3 : byte >= 0xc0 ? 2 : 1;
|
|
260
|
+
// Keep the trailing sequence only when the cut did not land inside it.
|
|
261
|
+
return lead + width <= window.length ? window : window.subarray(0, lead);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Render part of a message for an error message. A v8 payload is binary rather
|
|
265
|
+
* than utf8 text — its 0xFF header alone can never decode — so it is rendered
|
|
266
|
+
* as hex instead of as U+FFFD-riddled mojibake.
|
|
267
|
+
*/
|
|
268
|
+
function describeMessage(message, { maxBytes = 300, from = 'start' } = {}) {
|
|
269
|
+
const json = isJsonMessage(message);
|
|
270
|
+
const window = from === 'end'
|
|
271
|
+
? message.subarray(Math.max(0, message.length - maxBytes))
|
|
272
|
+
: message.subarray(0, maxBytes);
|
|
273
|
+
const slice = json ? trimToCharBoundary(window, from) : window;
|
|
274
|
+
const elided = message.length - slice.length;
|
|
275
|
+
return [
|
|
276
|
+
`${json ? 'json' : 'v8'}, ${message.length} bytes` +
|
|
277
|
+
(elided > 0
|
|
278
|
+
? `, ${from === 'end' ? 'last' : 'first'} ${slice.length} shown`
|
|
279
|
+
: ''),
|
|
280
|
+
json ? slice.toString('utf8') : slice.toString('hex'),
|
|
281
|
+
].join('\n');
|
|
46
282
|
}
|
|
47
283
|
/**
|
|
48
|
-
* Parse a message
|
|
49
|
-
* `daemon/socket-utils.ts`. Auto-detects JSON vs. v8-serialized payloads using
|
|
50
|
-
* `isJsonMessage()` and decodes the binary path via `v8.deserialize`.
|
|
284
|
+
* Parse a message produced by `serialize()` in `daemon/socket-utils.ts`.
|
|
51
285
|
*/
|
|
52
286
|
function parseMessage(message) {
|
|
53
287
|
return isJsonMessage(message)
|
|
54
|
-
? JSON.parse(message)
|
|
55
|
-
: (0, v8_1.deserialize)(
|
|
288
|
+
? JSON.parse(message.toString('utf8'))
|
|
289
|
+
: (0, v8_1.deserialize)(message);
|
|
56
290
|
}
|
package/dist/src/utils/params.js
CHANGED
|
@@ -443,7 +443,7 @@ function applyVerbosity(options, schema, isVerbose) {
|
|
|
443
443
|
}
|
|
444
444
|
function combineOptionsForExecutor(commandLineOpts, config, target, schema, defaultProjectName, relativeCwd, isVerbose = false) {
|
|
445
445
|
const r = convertAliases(coerceTypesInOptions(convertToCamelCase(commandLineOpts, schema), schema), schema, false);
|
|
446
|
-
let combined = target.options
|
|
446
|
+
let combined = { ...target.options };
|
|
447
447
|
if (config && target.configurations && target.configurations[config]) {
|
|
448
448
|
Object.assign(combined, target.configurations[config]);
|
|
449
449
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx",
|
|
3
|
-
"version": "22.7.
|
|
3
|
+
"version": "22.7.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
|
|
@@ -175,16 +175,16 @@
|
|
|
175
175
|
}
|
|
176
176
|
},
|
|
177
177
|
"optionalDependencies": {
|
|
178
|
-
"@nx/nx-darwin-arm64": "22.7.
|
|
179
|
-
"@nx/nx-darwin-x64": "22.7.
|
|
180
|
-
"@nx/nx-freebsd-x64": "22.7.
|
|
181
|
-
"@nx/nx-linux-arm-gnueabihf": "22.7.
|
|
182
|
-
"@nx/nx-linux-arm64-gnu": "22.7.
|
|
183
|
-
"@nx/nx-linux-arm64-musl": "22.7.
|
|
184
|
-
"@nx/nx-linux-x64-gnu": "22.7.
|
|
185
|
-
"@nx/nx-linux-x64-musl": "22.7.
|
|
186
|
-
"@nx/nx-win32-arm64-msvc": "22.7.
|
|
187
|
-
"@nx/nx-win32-x64-msvc": "22.7.
|
|
178
|
+
"@nx/nx-darwin-arm64": "22.7.12",
|
|
179
|
+
"@nx/nx-darwin-x64": "22.7.12",
|
|
180
|
+
"@nx/nx-freebsd-x64": "22.7.12",
|
|
181
|
+
"@nx/nx-linux-arm-gnueabihf": "22.7.12",
|
|
182
|
+
"@nx/nx-linux-arm64-gnu": "22.7.12",
|
|
183
|
+
"@nx/nx-linux-arm64-musl": "22.7.12",
|
|
184
|
+
"@nx/nx-linux-x64-gnu": "22.7.12",
|
|
185
|
+
"@nx/nx-linux-x64-musl": "22.7.12",
|
|
186
|
+
"@nx/nx-win32-arm64-msvc": "22.7.12",
|
|
187
|
+
"@nx/nx-win32-x64-msvc": "22.7.12"
|
|
188
188
|
},
|
|
189
189
|
"nx-migrations": {
|
|
190
190
|
"migrations": "./migrations.json",
|