@jigging/jig 0.1.0-alpha.15 → 0.1.0-alpha.16
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/README.md +27 -6
- package/libexec/agent/claude-agent-acp.js +34 -34
- package/libexec/installed-cli.js +3858 -1279
- package/libexec/linux-rootless-supervisor.js +12 -2
- package/libexec/preparation/bun-native-preparation-worker.js +958 -120
- package/package.json +1 -1
|
@@ -1,26 +1,896 @@
|
|
|
1
1
|
// @bun
|
|
2
|
+
// src/internal/bun-prepared-capture.ts
|
|
3
|
+
import { lstat, opendir, readFile, realpath } from "fs/promises";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
|
|
6
|
+
// src/internal/bun-execution-layout.ts
|
|
7
|
+
import { types as utilTypes3 } from "util";
|
|
8
|
+
|
|
9
|
+
// src/diagnostics.ts
|
|
10
|
+
class CheckError extends Error {
|
|
11
|
+
kind;
|
|
12
|
+
code;
|
|
13
|
+
path;
|
|
14
|
+
pointer;
|
|
15
|
+
constructor(kind, code, message, path, pointer) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "CheckError";
|
|
18
|
+
this.kind = kind;
|
|
19
|
+
this.code = code;
|
|
20
|
+
if (path !== undefined)
|
|
21
|
+
this.path = path;
|
|
22
|
+
if (pointer !== undefined)
|
|
23
|
+
this.pointer = pointer;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function invalid(code, message, path, pointer) {
|
|
27
|
+
throw new CheckError("invalid", code, message, path, pointer);
|
|
28
|
+
}
|
|
29
|
+
function unavailable(code, message, path, pointer) {
|
|
30
|
+
throw new CheckError("unavailable", code, message, path, pointer);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/package/paths.ts
|
|
34
|
+
var encoder = new TextEncoder;
|
|
35
|
+
var REQUIRED_UNICODE_VERSION = "15.1";
|
|
36
|
+
var PACKAGE_1_MAX_PATH_BYTES = 1024;
|
|
37
|
+
function isNfc15_1(value) {
|
|
38
|
+
const actual = process.versions.unicode;
|
|
39
|
+
if (actual !== REQUIRED_UNICODE_VERSION) {
|
|
40
|
+
unavailable("PACKAGE_UNICODE_UNAVAILABLE", `Package/1 requires Unicode ${REQUIRED_UNICODE_VERSION} NFC; host reports ${actual ?? "no Unicode version"}`);
|
|
41
|
+
}
|
|
42
|
+
return value === value.normalize("NFC");
|
|
43
|
+
}
|
|
44
|
+
function validateLogicalPath(path) {
|
|
45
|
+
if (path.length === 0 || path.startsWith("/") || path.includes("\\") || path.includes("\x00")) {
|
|
46
|
+
invalid("PACKAGE_PATH", `invalid logical path ${JSON.stringify(path)}`, path);
|
|
47
|
+
}
|
|
48
|
+
assertUnicodeScalarString(path);
|
|
49
|
+
if (!isNfc15_1(path)) {
|
|
50
|
+
invalid("PACKAGE_PATH_NFC", `logical path is not NFC: ${JSON.stringify(path)}`, path);
|
|
51
|
+
}
|
|
52
|
+
const segments = path.split("/");
|
|
53
|
+
if (segments.length > 64)
|
|
54
|
+
invalid("PACKAGE_PATH_LIMIT", `logical path exceeds 64 segments`, path);
|
|
55
|
+
if (encoder.encode(path).byteLength > PACKAGE_1_MAX_PATH_BYTES) {
|
|
56
|
+
invalid("PACKAGE_PATH_LIMIT", `logical path exceeds ${PACKAGE_1_MAX_PATH_BYTES} UTF-8 bytes`, path);
|
|
57
|
+
}
|
|
58
|
+
for (const segment of segments) {
|
|
59
|
+
if (segment.length === 0 || segment === "." || segment === "..") {
|
|
60
|
+
invalid("PACKAGE_PATH", `logical path has an invalid segment`, path);
|
|
61
|
+
}
|
|
62
|
+
if (encoder.encode(segment).byteLength > 255) {
|
|
63
|
+
invalid("PACKAGE_PATH_LIMIT", `logical path segment exceeds 255 UTF-8 bytes`, path);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return path;
|
|
67
|
+
}
|
|
68
|
+
function assertUnicodeScalarString(value) {
|
|
69
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
70
|
+
const code = value.charCodeAt(index);
|
|
71
|
+
if (code >= 55296 && code <= 56319) {
|
|
72
|
+
const next = value.charCodeAt(index + 1);
|
|
73
|
+
if (!(next >= 56320 && next <= 57343)) {
|
|
74
|
+
invalid("PACKAGE_PATH", "logical path contains a lone Unicode surrogate", value);
|
|
75
|
+
}
|
|
76
|
+
index += 1;
|
|
77
|
+
} else if (code >= 56320 && code <= 57343) {
|
|
78
|
+
invalid("PACKAGE_PATH", "logical path contains a lone Unicode surrogate", value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function comparePathBytes(left, right) {
|
|
83
|
+
return Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8"));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/internal/package-aliases.ts
|
|
87
|
+
import { posix } from "path";
|
|
88
|
+
import { types as utilTypes2 } from "util";
|
|
89
|
+
|
|
90
|
+
// src/internal/private-ordinary-json.ts
|
|
91
|
+
import { types as utilTypes } from "util";
|
|
92
|
+
|
|
93
|
+
// src/json.ts
|
|
94
|
+
var JSON_1_LIMITS = Object.freeze({
|
|
95
|
+
bytes: 16777216,
|
|
96
|
+
depth: 128,
|
|
97
|
+
nodes: 262144,
|
|
98
|
+
containerEntries: 65536,
|
|
99
|
+
stringBytes: 8388608,
|
|
100
|
+
memberNameBytes: 1024,
|
|
101
|
+
numberTokenBytes: 128
|
|
102
|
+
});
|
|
103
|
+
var encoder2 = new TextEncoder;
|
|
104
|
+
var decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
105
|
+
|
|
106
|
+
class Json1Error extends Error {
|
|
107
|
+
constructor(message) {
|
|
108
|
+
super(message);
|
|
109
|
+
this.name = "Json1Error";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class Parser {
|
|
114
|
+
source;
|
|
115
|
+
position = 0;
|
|
116
|
+
nodes = 0;
|
|
117
|
+
constructor(source) {
|
|
118
|
+
this.source = source;
|
|
119
|
+
}
|
|
120
|
+
parse() {
|
|
121
|
+
this.skipWhitespace();
|
|
122
|
+
const value = this.parseValue(1);
|
|
123
|
+
this.skipWhitespace();
|
|
124
|
+
if (this.position !== this.source.length)
|
|
125
|
+
this.fail("unexpected trailing characters");
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
parseValue(depth) {
|
|
129
|
+
if (depth > JSON_1_LIMITS.depth)
|
|
130
|
+
this.fail("maximum value depth exceeded");
|
|
131
|
+
this.nodes += 1;
|
|
132
|
+
if (this.nodes > JSON_1_LIMITS.nodes)
|
|
133
|
+
this.fail("maximum value nodes exceeded");
|
|
134
|
+
const char = this.source[this.position];
|
|
135
|
+
if (char === '"')
|
|
136
|
+
return this.parseString(false);
|
|
137
|
+
if (char === "{")
|
|
138
|
+
return this.parseObject(depth);
|
|
139
|
+
if (char === "[")
|
|
140
|
+
return this.parseArray(depth);
|
|
141
|
+
if (char === "t")
|
|
142
|
+
return this.parseLiteral("true", true);
|
|
143
|
+
if (char === "f")
|
|
144
|
+
return this.parseLiteral("false", false);
|
|
145
|
+
if (char === "n")
|
|
146
|
+
return this.parseLiteral("null", null);
|
|
147
|
+
if (char === "-" || char !== undefined && char >= "0" && char <= "9") {
|
|
148
|
+
return this.parseNumber();
|
|
149
|
+
}
|
|
150
|
+
return this.fail("expected a JSON value");
|
|
151
|
+
}
|
|
152
|
+
parseObject(depth) {
|
|
153
|
+
this.position += 1;
|
|
154
|
+
const result = Object.create(null);
|
|
155
|
+
const keys = new Set;
|
|
156
|
+
this.skipWhitespace();
|
|
157
|
+
if (this.consume("}"))
|
|
158
|
+
return result;
|
|
159
|
+
let members = 0;
|
|
160
|
+
while (true) {
|
|
161
|
+
if (this.source[this.position] !== '"')
|
|
162
|
+
this.fail("expected an object member name");
|
|
163
|
+
const key = this.parseString(true);
|
|
164
|
+
if (keys.has(key))
|
|
165
|
+
this.fail(`duplicate object member ${key}`);
|
|
166
|
+
keys.add(key);
|
|
167
|
+
members += 1;
|
|
168
|
+
if (members > JSON_1_LIMITS.containerEntries) {
|
|
169
|
+
this.fail("maximum object members exceeded");
|
|
170
|
+
}
|
|
171
|
+
this.skipWhitespace();
|
|
172
|
+
if (!this.consume(":"))
|
|
173
|
+
this.fail("expected ':' after member name");
|
|
174
|
+
this.skipWhitespace();
|
|
175
|
+
result[key] = this.parseValue(depth + 1);
|
|
176
|
+
this.skipWhitespace();
|
|
177
|
+
if (this.consume("}"))
|
|
178
|
+
return result;
|
|
179
|
+
if (!this.consume(","))
|
|
180
|
+
this.fail("expected ',' or '}'");
|
|
181
|
+
this.skipWhitespace();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
parseArray(depth) {
|
|
185
|
+
this.position += 1;
|
|
186
|
+
const result = [];
|
|
187
|
+
this.skipWhitespace();
|
|
188
|
+
if (this.consume("]"))
|
|
189
|
+
return result;
|
|
190
|
+
while (true) {
|
|
191
|
+
if (result.length >= JSON_1_LIMITS.containerEntries) {
|
|
192
|
+
this.fail("maximum array items exceeded");
|
|
193
|
+
}
|
|
194
|
+
result.push(this.parseValue(depth + 1));
|
|
195
|
+
this.skipWhitespace();
|
|
196
|
+
if (this.consume("]"))
|
|
197
|
+
return result;
|
|
198
|
+
if (!this.consume(","))
|
|
199
|
+
this.fail("expected ',' or ']'");
|
|
200
|
+
this.skipWhitespace();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
parseString(memberName) {
|
|
204
|
+
this.position += 1;
|
|
205
|
+
const parts = [];
|
|
206
|
+
let segmentStart = this.position;
|
|
207
|
+
while (this.position < this.source.length) {
|
|
208
|
+
const char = this.source[this.position];
|
|
209
|
+
this.position += 1;
|
|
210
|
+
if (char === '"') {
|
|
211
|
+
parts.push(this.source.slice(segmentStart, this.position - 1));
|
|
212
|
+
const value = parts.join("");
|
|
213
|
+
const limit = memberName ? JSON_1_LIMITS.memberNameBytes : JSON_1_LIMITS.stringBytes;
|
|
214
|
+
if (encoder2.encode(value).byteLength > limit)
|
|
215
|
+
this.fail("maximum string bytes exceeded");
|
|
216
|
+
return value;
|
|
217
|
+
}
|
|
218
|
+
if (char === "\\") {
|
|
219
|
+
parts.push(this.source.slice(segmentStart, this.position - 1));
|
|
220
|
+
parts.push(this.parseEscape());
|
|
221
|
+
segmentStart = this.position;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (char === undefined || char.charCodeAt(0) <= 31) {
|
|
225
|
+
this.fail("invalid character in string");
|
|
226
|
+
}
|
|
227
|
+
const code = char.charCodeAt(0);
|
|
228
|
+
if (code >= 55296 && code <= 57343) {
|
|
229
|
+
const next = this.source[this.position];
|
|
230
|
+
if (code > 56319 || next === undefined || next.charCodeAt(0) < 56320 || next.charCodeAt(0) > 57343)
|
|
231
|
+
this.fail("lone Unicode surrogate");
|
|
232
|
+
this.position += 1;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return this.fail("unterminated string");
|
|
236
|
+
}
|
|
237
|
+
parseEscape() {
|
|
238
|
+
const escape = this.source[this.position];
|
|
239
|
+
this.position += 1;
|
|
240
|
+
switch (escape) {
|
|
241
|
+
case '"':
|
|
242
|
+
case "\\":
|
|
243
|
+
case "/":
|
|
244
|
+
return escape;
|
|
245
|
+
case "b":
|
|
246
|
+
return "\b";
|
|
247
|
+
case "f":
|
|
248
|
+
return "\f";
|
|
249
|
+
case "n":
|
|
250
|
+
return `
|
|
251
|
+
`;
|
|
252
|
+
case "r":
|
|
253
|
+
return "\r";
|
|
254
|
+
case "t":
|
|
255
|
+
return "\t";
|
|
256
|
+
case "u": {
|
|
257
|
+
const first = this.parseHexCodeUnit();
|
|
258
|
+
if (first >= 55296 && first <= 56319) {
|
|
259
|
+
if (this.source.slice(this.position, this.position + 2) !== "\\u") {
|
|
260
|
+
this.fail("high surrogate without low surrogate");
|
|
261
|
+
}
|
|
262
|
+
this.position += 2;
|
|
263
|
+
const second = this.parseHexCodeUnit();
|
|
264
|
+
if (second < 56320 || second > 57343) {
|
|
265
|
+
this.fail("high surrogate without low surrogate");
|
|
266
|
+
}
|
|
267
|
+
return String.fromCharCode(first, second);
|
|
268
|
+
}
|
|
269
|
+
if (first >= 56320 && first <= 57343)
|
|
270
|
+
this.fail("lone low surrogate");
|
|
271
|
+
return String.fromCharCode(first);
|
|
272
|
+
}
|
|
273
|
+
default:
|
|
274
|
+
return this.fail("invalid string escape");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
parseHexCodeUnit() {
|
|
278
|
+
const token = this.source.slice(this.position, this.position + 4);
|
|
279
|
+
if (!/^[0-9A-Fa-f]{4}$/.test(token))
|
|
280
|
+
this.fail("invalid Unicode escape");
|
|
281
|
+
this.position += 4;
|
|
282
|
+
return Number.parseInt(token, 16);
|
|
283
|
+
}
|
|
284
|
+
parseNumber() {
|
|
285
|
+
const start = this.position;
|
|
286
|
+
this.consume("-");
|
|
287
|
+
if (this.consume("0")) {
|
|
288
|
+
const next = this.source[this.position];
|
|
289
|
+
if (next !== undefined && next >= "0" && next <= "9") {
|
|
290
|
+
this.fail("leading zero in number");
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
if (!this.consumeDigit("1", "9"))
|
|
294
|
+
this.fail("invalid number");
|
|
295
|
+
while (this.consumeDigit("0", "9")) {}
|
|
296
|
+
}
|
|
297
|
+
if (this.consume(".")) {
|
|
298
|
+
if (!this.consumeDigit("0", "9"))
|
|
299
|
+
this.fail("fraction requires a digit");
|
|
300
|
+
while (this.consumeDigit("0", "9")) {}
|
|
301
|
+
}
|
|
302
|
+
const exponent = this.source[this.position];
|
|
303
|
+
if (exponent === "e" || exponent === "E") {
|
|
304
|
+
this.position += 1;
|
|
305
|
+
const sign = this.source[this.position];
|
|
306
|
+
if (sign === "+" || sign === "-")
|
|
307
|
+
this.position += 1;
|
|
308
|
+
if (!this.consumeDigit("0", "9"))
|
|
309
|
+
this.fail("exponent requires a digit");
|
|
310
|
+
while (this.consumeDigit("0", "9")) {}
|
|
311
|
+
}
|
|
312
|
+
const token = this.source.slice(start, this.position);
|
|
313
|
+
if (token.length > JSON_1_LIMITS.numberTokenBytes) {
|
|
314
|
+
this.fail("maximum number token bytes exceeded");
|
|
315
|
+
}
|
|
316
|
+
const value = Number(token);
|
|
317
|
+
if (!Number.isFinite(value))
|
|
318
|
+
this.fail("non-finite number");
|
|
319
|
+
if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
320
|
+
this.fail("integral number outside safe range");
|
|
321
|
+
}
|
|
322
|
+
return value;
|
|
323
|
+
}
|
|
324
|
+
parseLiteral(token, value) {
|
|
325
|
+
if (this.source.slice(this.position, this.position + token.length) !== token) {
|
|
326
|
+
this.fail(`invalid literal ${token}`);
|
|
327
|
+
}
|
|
328
|
+
this.position += token.length;
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
331
|
+
consume(expected) {
|
|
332
|
+
if (this.source[this.position] !== expected)
|
|
333
|
+
return false;
|
|
334
|
+
this.position += 1;
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
consumeDigit(minimum, maximum) {
|
|
338
|
+
const char = this.source[this.position];
|
|
339
|
+
if (char === undefined || char < minimum || char > maximum)
|
|
340
|
+
return false;
|
|
341
|
+
this.position += 1;
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
skipWhitespace() {
|
|
345
|
+
while (true) {
|
|
346
|
+
const char = this.source[this.position];
|
|
347
|
+
if (char !== " " && char !== `
|
|
348
|
+
` && char !== "\r" && char !== "\t")
|
|
349
|
+
return;
|
|
350
|
+
this.position += 1;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
fail(message) {
|
|
354
|
+
throw new Json1Error(`${message} at character ${this.position}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function decodeJson1(bytes) {
|
|
358
|
+
if (bytes.byteLength === 0)
|
|
359
|
+
throw new Json1Error("empty JSON/1 document");
|
|
360
|
+
if (bytes.byteLength > JSON_1_LIMITS.bytes)
|
|
361
|
+
throw new Json1Error("maximum bytes exceeded");
|
|
362
|
+
if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
|
|
363
|
+
throw new Json1Error("UTF-8 BOM is not allowed");
|
|
364
|
+
}
|
|
365
|
+
let text;
|
|
366
|
+
try {
|
|
367
|
+
text = decoder.decode(bytes);
|
|
368
|
+
} catch {
|
|
369
|
+
throw new Json1Error("invalid UTF-8");
|
|
370
|
+
}
|
|
371
|
+
return new Parser(text).parse();
|
|
372
|
+
}
|
|
373
|
+
function validateJson1(value) {
|
|
374
|
+
visitJson(value, 1, { nodes: 0, encodedBytes: 0, active: new WeakSet }, false);
|
|
375
|
+
}
|
|
376
|
+
function visitJson(value, depth, state, memberName) {
|
|
377
|
+
if (depth > JSON_1_LIMITS.depth)
|
|
378
|
+
throw new Json1Error("maximum value depth exceeded");
|
|
379
|
+
state.nodes += 1;
|
|
380
|
+
if (state.nodes > JSON_1_LIMITS.nodes)
|
|
381
|
+
throw new Json1Error("maximum value nodes exceeded");
|
|
382
|
+
if (value === null) {
|
|
383
|
+
chargeEncodedBytes(state, 4);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
if (typeof value === "boolean") {
|
|
387
|
+
chargeEncodedBytes(state, value ? 4 : 5);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (typeof value === "number") {
|
|
391
|
+
if (!Number.isFinite(value))
|
|
392
|
+
throw new Json1Error("non-finite number");
|
|
393
|
+
if (Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
394
|
+
throw new Json1Error("integral number outside safe range");
|
|
395
|
+
}
|
|
396
|
+
chargeEncodedBytes(state, (Object.is(value, -0) ? "0" : JSON.stringify(value)).length);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
if (typeof value === "string") {
|
|
400
|
+
validateString(value, memberName ? JSON_1_LIMITS.memberNameBytes : JSON_1_LIMITS.stringBytes);
|
|
401
|
+
chargeEncodedBytes(state, encodedJsonStringBytes(value));
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (typeof value !== "object")
|
|
405
|
+
throw new Json1Error("value is not JSON/1");
|
|
406
|
+
if (state.active.has(value))
|
|
407
|
+
throw new Json1Error("cyclic value");
|
|
408
|
+
state.active.add(value);
|
|
409
|
+
try {
|
|
410
|
+
if (Array.isArray(value)) {
|
|
411
|
+
if (value.length > JSON_1_LIMITS.containerEntries) {
|
|
412
|
+
throw new Json1Error("maximum array items exceeded");
|
|
413
|
+
}
|
|
414
|
+
chargeEncodedBytes(state, 2 + Math.max(0, value.length - 1));
|
|
415
|
+
for (const child of value)
|
|
416
|
+
visitJson(child, depth + 1, state, false);
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
const object = value;
|
|
420
|
+
const keys = Object.keys(object);
|
|
421
|
+
if (keys.length > JSON_1_LIMITS.containerEntries) {
|
|
422
|
+
throw new Json1Error("maximum object members exceeded");
|
|
423
|
+
}
|
|
424
|
+
chargeEncodedBytes(state, 2 + keys.length + Math.max(0, keys.length - 1));
|
|
425
|
+
for (const key of keys) {
|
|
426
|
+
validateString(key, JSON_1_LIMITS.memberNameBytes);
|
|
427
|
+
chargeEncodedBytes(state, encodedJsonStringBytes(key));
|
|
428
|
+
visitJson(object[key], depth + 1, state, false);
|
|
429
|
+
}
|
|
430
|
+
} finally {
|
|
431
|
+
state.active.delete(value);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function chargeEncodedBytes(state, bytes) {
|
|
435
|
+
if (bytes > JSON_1_LIMITS.bytes - state.encodedBytes) {
|
|
436
|
+
throw new Json1Error("maximum encoded bytes exceeded");
|
|
437
|
+
}
|
|
438
|
+
state.encodedBytes += bytes;
|
|
439
|
+
}
|
|
440
|
+
function encodedJsonStringBytes(value) {
|
|
441
|
+
return encoder2.encode(JSON.stringify(value)).byteLength;
|
|
442
|
+
}
|
|
443
|
+
function validateString(value, byteLimit) {
|
|
444
|
+
if (encoder2.encode(value).byteLength > byteLimit) {
|
|
445
|
+
throw new Json1Error("maximum string bytes exceeded");
|
|
446
|
+
}
|
|
447
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
448
|
+
const code = value.charCodeAt(index);
|
|
449
|
+
if (code >= 55296 && code <= 56319) {
|
|
450
|
+
const next = value.charCodeAt(index + 1);
|
|
451
|
+
if (!(next >= 56320 && next <= 57343))
|
|
452
|
+
throw new Json1Error("lone Unicode surrogate");
|
|
453
|
+
index += 1;
|
|
454
|
+
} else if (code >= 56320 && code <= 57343) {
|
|
455
|
+
throw new Json1Error("lone Unicode surrogate");
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
function canonicalJson(value) {
|
|
460
|
+
validateJson1(value);
|
|
461
|
+
return encoder2.encode(canonicalText(value));
|
|
462
|
+
}
|
|
463
|
+
function canonicalText(value) {
|
|
464
|
+
if (value === null || typeof value === "boolean" || typeof value === "string") {
|
|
465
|
+
return JSON.stringify(value);
|
|
466
|
+
}
|
|
467
|
+
if (typeof value === "number")
|
|
468
|
+
return Object.is(value, -0) ? "0" : JSON.stringify(value);
|
|
469
|
+
if (Array.isArray(value))
|
|
470
|
+
return `[${value.map(canonicalText).join(",")}]`;
|
|
471
|
+
const object = value;
|
|
472
|
+
const members = Object.keys(object).sort(compareUtf16).map((key) => `${JSON.stringify(key)}:${canonicalText(object[key])}`);
|
|
473
|
+
return `{${members.join(",")}}`;
|
|
474
|
+
}
|
|
475
|
+
function compareUtf16(left, right) {
|
|
476
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// src/internal/private-ordinary-json.ts
|
|
480
|
+
function snapshotPrivateOrdinaryJson(value, label, invalid2) {
|
|
481
|
+
const ordinary = cloneOrdinaryJson(value, label, invalid2, new Set);
|
|
482
|
+
let cloned;
|
|
483
|
+
try {
|
|
484
|
+
cloned = decodeJson1(canonicalJson(ordinary));
|
|
485
|
+
} catch (error) {
|
|
486
|
+
if (error instanceof Json1Error)
|
|
487
|
+
throw invalid2(`${label} is not valid JSON/1: ${error.message}`);
|
|
488
|
+
throw error;
|
|
489
|
+
}
|
|
490
|
+
deepFreeze(cloned);
|
|
491
|
+
return cloned;
|
|
492
|
+
}
|
|
493
|
+
function cloneOrdinaryJson(value, label, invalid2, ancestors) {
|
|
494
|
+
if (value === null || typeof value === "boolean" || typeof value === "string" || typeof value === "number") {
|
|
495
|
+
return value;
|
|
496
|
+
}
|
|
497
|
+
if (typeof value !== "object" || utilTypes.isProxy(value)) {
|
|
498
|
+
throw invalid2(`${label} must be ordinary JSON/1 data`);
|
|
499
|
+
}
|
|
500
|
+
if (ancestors.has(value)) {
|
|
501
|
+
throw invalid2(`${label} must not contain a cycle`);
|
|
502
|
+
}
|
|
503
|
+
ancestors.add(value);
|
|
504
|
+
try {
|
|
505
|
+
if (Array.isArray(value)) {
|
|
506
|
+
if (Object.getPrototypeOf(value) !== Array.prototype) {
|
|
507
|
+
throw invalid2(`${label} must use ordinary arrays`);
|
|
508
|
+
}
|
|
509
|
+
const keys = Reflect.ownKeys(value);
|
|
510
|
+
if (keys.length !== value.length + 1 || keys.some((key) => typeof key !== "string" || key !== "length" && !/^(?:0|[1-9][0-9]*)$/.test(key))) {
|
|
511
|
+
throw invalid2(`${label} must not use sparse or extended arrays`);
|
|
512
|
+
}
|
|
513
|
+
const result2 = [];
|
|
514
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
515
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
516
|
+
if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) {
|
|
517
|
+
throw invalid2(`${label} must not use array accessors`);
|
|
518
|
+
}
|
|
519
|
+
result2.push(cloneOrdinaryJson(descriptor.value, `${label}[${index}]`, invalid2, ancestors));
|
|
520
|
+
}
|
|
521
|
+
return result2;
|
|
522
|
+
}
|
|
523
|
+
const prototype = Object.getPrototypeOf(value);
|
|
524
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
525
|
+
throw invalid2(`${label} must use ordinary objects`);
|
|
526
|
+
}
|
|
527
|
+
const result = Object.create(null);
|
|
528
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
529
|
+
if (typeof key !== "string") {
|
|
530
|
+
throw invalid2(`${label} must not contain symbol properties`);
|
|
531
|
+
}
|
|
532
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
533
|
+
if (descriptor === undefined || !("value" in descriptor) || !descriptor.enumerable) {
|
|
534
|
+
throw invalid2(`${label} must contain enumerable data properties`);
|
|
535
|
+
}
|
|
536
|
+
result[key] = cloneOrdinaryJson(descriptor.value, `${label}.${key}`, invalid2, ancestors);
|
|
537
|
+
}
|
|
538
|
+
return result;
|
|
539
|
+
} finally {
|
|
540
|
+
ancestors.delete(value);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function deepFreeze(value) {
|
|
544
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value))
|
|
545
|
+
return;
|
|
546
|
+
if (Array.isArray(value)) {
|
|
547
|
+
for (const child of value)
|
|
548
|
+
deepFreeze(child);
|
|
549
|
+
} else {
|
|
550
|
+
for (const child of Object.values(value))
|
|
551
|
+
deepFreeze(child);
|
|
552
|
+
}
|
|
553
|
+
Object.freeze(value);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// src/internal/package-aliases.ts
|
|
557
|
+
var PRIVATE_PACKAGE_ALIAS_LIMITS = Object.freeze({ records: 4096, bytes: 1024 * 1024 });
|
|
558
|
+
function normalizePrivatePackageAliases(value) {
|
|
559
|
+
if (utilTypes2.isProxy(value) || !Array.isArray(value) || value.length > PRIVATE_PACKAGE_ALIAS_LIMITS.records)
|
|
560
|
+
invalid2();
|
|
561
|
+
const aliases = snapshotPrivateOrdinaryJson(value, "package aliases", () => new TypeError("invalid package aliases"));
|
|
562
|
+
if (Buffer.byteLength(JSON.stringify(aliases)) > PRIVATE_PACKAGE_ALIAS_LIMITS.bytes)
|
|
563
|
+
invalid2();
|
|
564
|
+
let prior;
|
|
565
|
+
for (const alias of aliases) {
|
|
566
|
+
if (alias === null || typeof alias !== "object" || Array.isArray(alias) || Object.keys(alias).length !== 2 || typeof alias.path !== "string" || typeof alias.target !== "string")
|
|
567
|
+
invalid2();
|
|
568
|
+
validateLogicalPath(alias.path);
|
|
569
|
+
validateLogicalPath(alias.target);
|
|
570
|
+
if (prior !== undefined && comparePathBytes(prior, alias.path) >= 0)
|
|
571
|
+
invalid2();
|
|
572
|
+
prior = alias.path;
|
|
573
|
+
}
|
|
574
|
+
const paths = new Set(aliases.map(({ path }) => path));
|
|
575
|
+
for (const alias of aliases) {
|
|
576
|
+
for (const path of [posix.dirname(alias.path), alias.target]) {
|
|
577
|
+
const parts = path.split("/");
|
|
578
|
+
while (parts.length > 0) {
|
|
579
|
+
if (paths.has(parts.join("/")))
|
|
580
|
+
invalid2();
|
|
581
|
+
parts.pop();
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return aliases;
|
|
586
|
+
}
|
|
587
|
+
function assertPrivatePackageAliasFiles(aliases, files) {
|
|
588
|
+
const paths = new Set(files.map(({ path }) => path));
|
|
589
|
+
const directories = new Set([""]);
|
|
590
|
+
for (const path of paths) {
|
|
591
|
+
const parts = path.split("/");
|
|
592
|
+
while (parts.length > 1) {
|
|
593
|
+
parts.pop();
|
|
594
|
+
directories.add(parts.join("/"));
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
for (const alias of aliases) {
|
|
598
|
+
if (!directories.has(alias.target) || paths.has(alias.path) || directories.has(alias.path))
|
|
599
|
+
invalid2();
|
|
600
|
+
const parts = alias.path.split("/");
|
|
601
|
+
while (parts.length > 1) {
|
|
602
|
+
parts.pop();
|
|
603
|
+
if (paths.has(parts.join("/")))
|
|
604
|
+
invalid2();
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
function invalid2() {
|
|
609
|
+
throw new TypeError("invalid package aliases");
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/internal/bun-execution-layout.ts
|
|
613
|
+
var PRIVATE_BUN_EXECUTION_LAYOUT_LIMITS = Object.freeze({
|
|
614
|
+
members: 256,
|
|
615
|
+
aliases: PRIVATE_PACKAGE_ALIAS_LIMITS.records,
|
|
616
|
+
bytes: 1024 * 1024
|
|
617
|
+
});
|
|
618
|
+
var EMPTY_PRIVATE_BUN_EXECUTION_LAYOUT = Object.freeze({
|
|
619
|
+
flowRoot: "",
|
|
620
|
+
members: Object.freeze([]),
|
|
621
|
+
aliases: Object.freeze([])
|
|
622
|
+
});
|
|
623
|
+
function normalizePrivateBunExecutionLayout(value) {
|
|
624
|
+
const record = exact(value, ["flowRoot", "members", "aliases"]);
|
|
625
|
+
const memberValues = array(record.members, PRIVATE_BUN_EXECUTION_LAYOUT_LIMITS.members);
|
|
626
|
+
const aliases = normalizePrivatePackageAliases(record.aliases);
|
|
627
|
+
if (typeof record.flowRoot !== "string")
|
|
628
|
+
invalid3();
|
|
629
|
+
const flowRoot = record.flowRoot;
|
|
630
|
+
if (flowRoot !== "")
|
|
631
|
+
validateLogicalPath(flowRoot);
|
|
632
|
+
const members = [];
|
|
633
|
+
for (const member of memberValues) {
|
|
634
|
+
if (typeof member !== "string")
|
|
635
|
+
invalid3();
|
|
636
|
+
validateLogicalPath(member);
|
|
637
|
+
if (member.split("/").includes("node_modules") || members.some((prior) => member.startsWith(`${prior}/`)) || members.length > 0 && comparePathBytes(members.at(-1), member) >= 0)
|
|
638
|
+
invalid3();
|
|
639
|
+
members.push(member);
|
|
640
|
+
}
|
|
641
|
+
for (const alias of aliases) {
|
|
642
|
+
if (!members.includes(alias.target) || privateBunAliasPackageName(alias.path) === undefined)
|
|
643
|
+
invalid3();
|
|
644
|
+
}
|
|
645
|
+
if (flowRoot === "") {
|
|
646
|
+
if (members.length !== 0 || aliases.length !== 0)
|
|
647
|
+
invalid3();
|
|
648
|
+
} else if (!members.includes(flowRoot))
|
|
649
|
+
invalid3();
|
|
650
|
+
const layout = Object.freeze({
|
|
651
|
+
flowRoot,
|
|
652
|
+
members: Object.freeze(members),
|
|
653
|
+
aliases: Object.freeze(aliases)
|
|
654
|
+
});
|
|
655
|
+
if (Buffer.byteLength(JSON.stringify(layout)) > PRIVATE_BUN_EXECUTION_LAYOUT_LIMITS.bytes)
|
|
656
|
+
invalid3();
|
|
657
|
+
return layout;
|
|
658
|
+
}
|
|
659
|
+
function assertPrivateBunExecutionLayoutFiles(layout, files) {
|
|
660
|
+
for (const member of layout.members)
|
|
661
|
+
if (!files.some(({ path }) => path === `${member}/package.json`))
|
|
662
|
+
invalid3();
|
|
663
|
+
assertPrivatePackageAliasFiles(layout.aliases, files);
|
|
664
|
+
}
|
|
665
|
+
function privateBunAliasPackageName(path) {
|
|
666
|
+
const match = /(?:^|\/)node_modules\/((?:@[^/]+\/)?[^/]+)$/.exec(path);
|
|
667
|
+
const name = match?.[1];
|
|
668
|
+
return name === undefined || name.startsWith(".") || name.split("/").some((part) => part === ".bin") ? undefined : name;
|
|
669
|
+
}
|
|
670
|
+
function exact(value, keys) {
|
|
671
|
+
if (value === null || typeof value !== "object" || utilTypes3.isProxy(value) || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
|
|
672
|
+
invalid3();
|
|
673
|
+
const record = value;
|
|
674
|
+
const actual = Reflect.ownKeys(record);
|
|
675
|
+
if (actual.length !== keys.length || actual.some((key) => typeof key !== "string" || !keys.includes(key)))
|
|
676
|
+
invalid3();
|
|
677
|
+
const copy = Object.create(null);
|
|
678
|
+
for (const key of keys) {
|
|
679
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
680
|
+
if (!descriptor || !Object.hasOwn(descriptor, "value") || !descriptor.enumerable)
|
|
681
|
+
invalid3();
|
|
682
|
+
copy[key] = descriptor.value;
|
|
683
|
+
}
|
|
684
|
+
return copy;
|
|
685
|
+
}
|
|
686
|
+
function array(value, maximum) {
|
|
687
|
+
if (value === null || typeof value !== "object" || utilTypes3.isProxy(value) || !Array.isArray(value))
|
|
688
|
+
invalid3();
|
|
689
|
+
const length = Object.getOwnPropertyDescriptor(value, "length")?.value;
|
|
690
|
+
if (!Number.isSafeInteger(length) || length < 0 || length > maximum || Reflect.ownKeys(value).length !== length + 1)
|
|
691
|
+
invalid3();
|
|
692
|
+
const result = [];
|
|
693
|
+
for (let index = 0;index < length; index++) {
|
|
694
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
695
|
+
if (!descriptor || !Object.hasOwn(descriptor, "value") || !descriptor.enumerable)
|
|
696
|
+
invalid3();
|
|
697
|
+
result.push(descriptor.value);
|
|
698
|
+
}
|
|
699
|
+
return result;
|
|
700
|
+
}
|
|
701
|
+
function invalid3() {
|
|
702
|
+
throw new TypeError("invalid private Bun execution layout");
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// src/internal/bun-native-preparation-protocol.ts
|
|
706
|
+
var MIB = 1024 * 1024;
|
|
707
|
+
var MAX_JSON_BYTES_PER_PATH_BYTE = 6;
|
|
708
|
+
var PRIVATE_BUN_PREPARATION_LIMITS = Object.freeze({
|
|
709
|
+
sourceFiles: 4096,
|
|
710
|
+
sourceBytes: 16 * MIB,
|
|
711
|
+
preparedFiles: 4096,
|
|
712
|
+
preparedBytes: 32 * MIB
|
|
713
|
+
});
|
|
714
|
+
function maximumPrivateBunFileMessageBytes(type, maximumFiles, maximumContentBytes) {
|
|
715
|
+
requireNonnegativeInteger(maximumFiles, "file count");
|
|
716
|
+
requireNonnegativeInteger(maximumContentBytes, "content bytes");
|
|
717
|
+
const emptyMessageBytes = Buffer.byteLength(JSON.stringify({ type, files: [] }));
|
|
718
|
+
const emptyFileBytes = Buffer.byteLength(JSON.stringify({ path: "", content: "" }));
|
|
719
|
+
const pathBytes = maximumFiles * PACKAGE_1_MAX_PATH_BYTES * MAX_JSON_BYTES_PER_PATH_BYTE;
|
|
720
|
+
const contentBytes = 4 * (Math.ceil(maximumContentBytes / 3) + maximumFiles);
|
|
721
|
+
const separators = Math.max(0, maximumFiles - 1);
|
|
722
|
+
const result = emptyMessageBytes + maximumFiles * emptyFileBytes + pathBytes + contentBytes + separators;
|
|
723
|
+
if (!Number.isSafeInteger(result))
|
|
724
|
+
throw new RangeError("Bun preparation message bound is too large");
|
|
725
|
+
return result;
|
|
726
|
+
}
|
|
727
|
+
var PRIVATE_BUN_SOURCE_MESSAGE_BYTES = maximumPrivateBunFileMessageBytes("source", PRIVATE_BUN_PREPARATION_LIMITS.sourceFiles, PRIVATE_BUN_PREPARATION_LIMITS.sourceBytes);
|
|
728
|
+
var PRIVATE_BUN_PREPARED_MESSAGE_BYTES = maximumPrivateBunFileMessageBytes("prepared", PRIVATE_BUN_PREPARATION_LIMITS.preparedFiles, PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes) + PRIVATE_BUN_EXECUTION_LAYOUT_LIMITS.bytes + Buffer.byteLength(',"layout":');
|
|
729
|
+
function privateBunMessageFits(bytes, maximum) {
|
|
730
|
+
return Number.isSafeInteger(bytes) && bytes >= 0 && bytes <= maximum;
|
|
731
|
+
}
|
|
732
|
+
function encodePrivateBunMessage(value) {
|
|
733
|
+
const json = JSON.stringify(value);
|
|
734
|
+
if (json === undefined)
|
|
735
|
+
throw new TypeError("Bun preparation message is not JSON-serializable");
|
|
736
|
+
return new TextEncoder().encode(`${json}
|
|
737
|
+
`);
|
|
738
|
+
}
|
|
739
|
+
function requireNonnegativeInteger(value, label) {
|
|
740
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
741
|
+
throw new TypeError(`${label} must be a nonnegative safe integer`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// src/internal/bun-prepared-capture.ts
|
|
746
|
+
var PATH = /^(?!\/)(?!.*(?:^|\/)\.\.?(?:\/|$))(?!.*\/\/)[^\0]+$/;
|
|
747
|
+
|
|
748
|
+
class WorkerFailure extends Error {
|
|
749
|
+
code;
|
|
750
|
+
constructor(code, message) {
|
|
751
|
+
super(message);
|
|
752
|
+
this.code = code;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
async function capturePrivateBunPreparedTree(packageRoot, workspace) {
|
|
756
|
+
const files = [];
|
|
757
|
+
const aliases = [];
|
|
758
|
+
let total = 0;
|
|
759
|
+
const memberNames = new Map;
|
|
760
|
+
for (const member of workspace?.members ?? []) {
|
|
761
|
+
const manifest = JSON.parse(await readFile(join(packageRoot, member, "package.json"), "utf8"));
|
|
762
|
+
if (typeof manifest.name !== "string")
|
|
763
|
+
unsupported("workspace member name is missing");
|
|
764
|
+
memberNames.set(member, manifest.name);
|
|
765
|
+
}
|
|
766
|
+
const reserveRecord = () => {
|
|
767
|
+
if (files.length + aliases.length >= PRIVATE_BUN_PREPARATION_LIMITS.preparedFiles)
|
|
768
|
+
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree has too many records");
|
|
769
|
+
};
|
|
770
|
+
const selectedSource = (path) => workspace === undefined || workspace.selected.some((member) => path === member || path.startsWith(`${member}/`));
|
|
771
|
+
const ancestor = (path) => workspace?.selected.some((member) => member.startsWith(`${path}/`)) ?? false;
|
|
772
|
+
const visit = async (root, prefix, installed = false) => {
|
|
773
|
+
const names = [];
|
|
774
|
+
for await (const entry of await opendir(root))
|
|
775
|
+
names.push(entry.name);
|
|
776
|
+
names.sort(compare);
|
|
777
|
+
for (const name of names) {
|
|
778
|
+
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
779
|
+
if (name === ".bin" && prefix.split("/").at(-1) === "node_modules")
|
|
780
|
+
continue;
|
|
781
|
+
requirePath(path);
|
|
782
|
+
const physical = join(root, name);
|
|
783
|
+
const information = await lstat(physical);
|
|
784
|
+
const dependencyTree = installed || name === "node_modules";
|
|
785
|
+
const retained = dependencyTree || selectedSource(path) || ancestor(path) || prefix === "" && (name === "package.json" || name === "bun.lock");
|
|
786
|
+
if (!retained)
|
|
787
|
+
continue;
|
|
788
|
+
if (information.isSymbolicLink()) {
|
|
789
|
+
if (workspace === undefined || !dependencyTree)
|
|
790
|
+
unsupported("prepared source contains an unauthorized link");
|
|
791
|
+
const packageName = privateBunAliasPackageName(path);
|
|
792
|
+
const resolved = await realpath(physical);
|
|
793
|
+
const member = workspace.members.find((value) => join(packageRoot, value) === resolved);
|
|
794
|
+
if (member === undefined || packageName === undefined || memberNames.get(member) !== packageName)
|
|
795
|
+
unsupported("prepared dependencies contain an unauthorized link");
|
|
796
|
+
if (!workspace.selected.includes(member))
|
|
797
|
+
continue;
|
|
798
|
+
reserveRecord();
|
|
799
|
+
aliases.push(Object.freeze({ path, target: member }));
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
802
|
+
if (information.isDirectory()) {
|
|
803
|
+
await visit(physical, path, dependencyTree);
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (!information.isFile() || information.nlink !== 1)
|
|
807
|
+
unsupported("prepared dependencies contain a link or special file");
|
|
808
|
+
if (!dependencyTree && !selectedSource(path) && prefix !== "")
|
|
809
|
+
continue;
|
|
810
|
+
reserveRecord();
|
|
811
|
+
if (information.size > PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes - total)
|
|
812
|
+
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree is too large");
|
|
813
|
+
const bytes = await readFile(physical);
|
|
814
|
+
total += bytes.byteLength;
|
|
815
|
+
if (total > PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes)
|
|
816
|
+
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree is too large");
|
|
817
|
+
files.push(Object.freeze({ path, content: bytes.toString("base64") }));
|
|
818
|
+
}
|
|
819
|
+
};
|
|
820
|
+
await visit(packageRoot, "");
|
|
821
|
+
files.sort((left, right) => compare(left.path, right.path));
|
|
822
|
+
aliases.sort((left, right) => compare(left.path, right.path));
|
|
823
|
+
let layout = EMPTY_PRIVATE_BUN_EXECUTION_LAYOUT;
|
|
824
|
+
try {
|
|
825
|
+
if (workspace !== undefined)
|
|
826
|
+
layout = normalizePrivateBunExecutionLayout({
|
|
827
|
+
flowRoot: workspace.target,
|
|
828
|
+
members: [...workspace.selected].sort(compare),
|
|
829
|
+
aliases
|
|
830
|
+
});
|
|
831
|
+
assertPrivateBunExecutionLayoutFiles(layout, files);
|
|
832
|
+
} catch {
|
|
833
|
+
unsupported("prepared workspace layout is invalid");
|
|
834
|
+
}
|
|
835
|
+
if (total + Buffer.byteLength(JSON.stringify(layout)) > PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes)
|
|
836
|
+
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree and layout are too large");
|
|
837
|
+
return Object.freeze({ files: Object.freeze(files), layout });
|
|
838
|
+
}
|
|
839
|
+
function requirePath(path) {
|
|
840
|
+
if (!PATH.test(path) || Buffer.byteLength(path) > 1024)
|
|
841
|
+
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "preparation source path is invalid");
|
|
842
|
+
}
|
|
843
|
+
function compare(left, right) {
|
|
844
|
+
return Buffer.from(left).compare(Buffer.from(right));
|
|
845
|
+
}
|
|
846
|
+
function unsupported(message) {
|
|
847
|
+
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_UNSUPPORTED", message);
|
|
848
|
+
}
|
|
849
|
+
|
|
2
850
|
// src/internal/bun-native-preparation-worker.ts
|
|
3
851
|
import { spawn } from "child_process";
|
|
4
|
-
import { copyFile,
|
|
5
|
-
import { dirname, join } from "path";
|
|
852
|
+
import { copyFile, mkdir, readFile as readFile2, rm, writeFile } from "fs/promises";
|
|
853
|
+
import { dirname, join as join2 } from "path";
|
|
6
854
|
|
|
7
855
|
// src/internal/bun-native-lock-policy.ts
|
|
8
|
-
function requirePrivateBunResolutionManifest(value) {
|
|
856
|
+
function requirePrivateBunResolutionManifest(value, workspace) {
|
|
9
857
|
const manifest = ordinaryRecord(value);
|
|
10
|
-
if (manifest === undefined || [
|
|
858
|
+
if (manifest === undefined || [
|
|
859
|
+
...workspace === "root" ? [] : ["workspaces"],
|
|
860
|
+
"patchedDependencies",
|
|
861
|
+
"overrides",
|
|
862
|
+
"resolutions",
|
|
863
|
+
"catalog",
|
|
864
|
+
"catalogs"
|
|
865
|
+
].some((field) => manifest[field] !== undefined))
|
|
11
866
|
throw new TypeError("unsupported Bun resolution input");
|
|
12
|
-
|
|
867
|
+
if (workspace === "member" && (typeof manifest.name !== "string" || !isPackageName(manifest.name)))
|
|
868
|
+
throw new TypeError("workspace members require valid package names");
|
|
869
|
+
requireRegistryDependencyMaps(manifest, workspace !== undefined);
|
|
13
870
|
}
|
|
14
|
-
function requirePrivateBunLockPolicy(value) {
|
|
871
|
+
function requirePrivateBunLockPolicy(value, members) {
|
|
15
872
|
const lock = ordinaryRecord(value);
|
|
16
873
|
const workspaces = ordinaryRecord(lock?.workspaces);
|
|
17
874
|
const rootWorkspace = ordinaryRecord(workspaces?.[""]);
|
|
18
875
|
const packages = ordinaryRecord(lock?.packages);
|
|
19
|
-
if (lock?.lockfileVersion !== 1 || workspaces === undefined || rootWorkspace === undefined || packages === undefined || Object.keys(workspaces).length !== 1 || lock.patchedDependencies !== undefined) {
|
|
876
|
+
if (lock?.lockfileVersion !== 1 || workspaces === undefined || rootWorkspace === undefined || packages === undefined || (members === undefined ? Object.keys(workspaces).length !== 1 : Object.keys(workspaces).some((path) => path !== "" && !members.has(path))) || lock.patchedDependencies !== undefined) {
|
|
20
877
|
throw new TypeError("unsupported Bun lock source");
|
|
21
878
|
}
|
|
22
|
-
|
|
879
|
+
for (const workspace of Object.values(workspaces)) {
|
|
880
|
+
const record = ordinaryRecord(workspace);
|
|
881
|
+
if (record === undefined)
|
|
882
|
+
throw new TypeError("unsupported Bun workspace lock");
|
|
883
|
+
requireRegistryDependencyMaps(record, members !== undefined);
|
|
884
|
+
}
|
|
23
885
|
for (const resolution of Object.values(packages)) {
|
|
886
|
+
if (members !== undefined && Array.isArray(resolution) && resolution.length === 1 && typeof resolution[0] === "string") {
|
|
887
|
+
const separator = resolution[0].indexOf("@workspace:");
|
|
888
|
+
const name = resolution[0].slice(0, separator);
|
|
889
|
+
const path = resolution[0].slice(separator + "@workspace:".length);
|
|
890
|
+
if (separator > 0 && isPackageName(name) && members.has(path) && ordinaryRecord(workspaces[path])?.name === name)
|
|
891
|
+
continue;
|
|
892
|
+
throw new TypeError("unsupported Bun workspace resolution");
|
|
893
|
+
}
|
|
24
894
|
const metadata = Array.isArray(resolution) ? ordinaryRecord(resolution[2]) : undefined;
|
|
25
895
|
if (!Array.isArray(resolution) || resolution.length !== 4 || !isExactRegistryResolution(resolution[0]) || typeof resolution[1] !== "string" || resolution[1] !== "" && resolution[1] !== "https://registry.npmjs.org" && resolution[1] !== "https://registry.npmjs.org/" || metadata === undefined || !isExactIntegrity(resolution[3])) {
|
|
26
896
|
throw new TypeError("unsupported Bun lock source");
|
|
@@ -34,7 +904,7 @@ var DEPENDENCY_MAPS = Object.freeze([
|
|
|
34
904
|
"optionalDependencies",
|
|
35
905
|
"peerDependencies"
|
|
36
906
|
]);
|
|
37
|
-
function requireRegistryDependencyMaps(container) {
|
|
907
|
+
function requireRegistryDependencyMaps(container, workspace = false) {
|
|
38
908
|
for (const field of DEPENDENCY_MAPS) {
|
|
39
909
|
if (container[field] === undefined)
|
|
40
910
|
continue;
|
|
@@ -42,7 +912,7 @@ function requireRegistryDependencyMaps(container) {
|
|
|
42
912
|
if (dependencies === undefined)
|
|
43
913
|
throw new TypeError("unsupported Bun lock source");
|
|
44
914
|
for (const [name, request] of Object.entries(dependencies)) {
|
|
45
|
-
if (!isPackageName(name) || !isRegistryRequest(request)) {
|
|
915
|
+
if (!isPackageName(name) || !(isRegistryRequest(request) || workspace && typeof request === "string" && request.startsWith("workspace:") && isRegistrySelector(request.slice("workspace:".length)))) {
|
|
46
916
|
throw new TypeError("unsupported Bun lock source");
|
|
47
917
|
}
|
|
48
918
|
}
|
|
@@ -90,62 +960,10 @@ function ordinaryRecord(value) {
|
|
|
90
960
|
return value;
|
|
91
961
|
}
|
|
92
962
|
|
|
93
|
-
// src/package/paths.ts
|
|
94
|
-
var encoder = new TextEncoder;
|
|
95
|
-
var PACKAGE_1_MAX_PATH_BYTES = 1024;
|
|
96
|
-
|
|
97
|
-
// src/internal/bun-native-preparation-protocol.ts
|
|
98
|
-
var MIB = 1024 * 1024;
|
|
99
|
-
var MAX_JSON_BYTES_PER_PATH_BYTE = 6;
|
|
100
|
-
var PRIVATE_BUN_PREPARATION_LIMITS = Object.freeze({
|
|
101
|
-
sourceFiles: 4096,
|
|
102
|
-
sourceBytes: 16 * MIB,
|
|
103
|
-
preparedFiles: 4096,
|
|
104
|
-
preparedBytes: 32 * MIB
|
|
105
|
-
});
|
|
106
|
-
function maximumPrivateBunFileMessageBytes(type, maximumFiles, maximumContentBytes) {
|
|
107
|
-
requireNonnegativeInteger(maximumFiles, "file count");
|
|
108
|
-
requireNonnegativeInteger(maximumContentBytes, "content bytes");
|
|
109
|
-
const emptyMessageBytes = Buffer.byteLength(JSON.stringify({ type, files: [] }));
|
|
110
|
-
const emptyFileBytes = Buffer.byteLength(JSON.stringify({ path: "", content: "" }));
|
|
111
|
-
const pathBytes = maximumFiles * PACKAGE_1_MAX_PATH_BYTES * MAX_JSON_BYTES_PER_PATH_BYTE;
|
|
112
|
-
const contentBytes = 4 * (Math.ceil(maximumContentBytes / 3) + maximumFiles);
|
|
113
|
-
const separators = Math.max(0, maximumFiles - 1);
|
|
114
|
-
const result = emptyMessageBytes + maximumFiles * emptyFileBytes + pathBytes + contentBytes + separators;
|
|
115
|
-
if (!Number.isSafeInteger(result))
|
|
116
|
-
throw new RangeError("Bun preparation message bound is too large");
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
var PRIVATE_BUN_SOURCE_MESSAGE_BYTES = maximumPrivateBunFileMessageBytes("source", PRIVATE_BUN_PREPARATION_LIMITS.sourceFiles, PRIVATE_BUN_PREPARATION_LIMITS.sourceBytes);
|
|
120
|
-
var PRIVATE_BUN_PREPARED_MESSAGE_BYTES = maximumPrivateBunFileMessageBytes("prepared", PRIVATE_BUN_PREPARATION_LIMITS.preparedFiles, PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes);
|
|
121
|
-
function privateBunMessageFits(bytes, maximum) {
|
|
122
|
-
return Number.isSafeInteger(bytes) && bytes >= 0 && bytes <= maximum;
|
|
123
|
-
}
|
|
124
|
-
function encodePrivateBunMessage(value) {
|
|
125
|
-
const json = JSON.stringify(value);
|
|
126
|
-
if (json === undefined)
|
|
127
|
-
throw new TypeError("Bun preparation message is not JSON-serializable");
|
|
128
|
-
return new TextEncoder().encode(`${json}
|
|
129
|
-
`);
|
|
130
|
-
}
|
|
131
|
-
function requireNonnegativeInteger(value, label) {
|
|
132
|
-
if (!Number.isSafeInteger(value) || value < 0) {
|
|
133
|
-
throw new TypeError(`${label} must be a nonnegative safe integer`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
963
|
// src/internal/bun-native-preparation-worker.ts
|
|
138
964
|
var PACKAGE_ROOT = "/work/package";
|
|
139
965
|
var CACHE_ROOT = "/work/cache";
|
|
140
|
-
var
|
|
141
|
-
|
|
142
|
-
class WorkerFailure extends Error {
|
|
143
|
-
code;
|
|
144
|
-
constructor(code, message) {
|
|
145
|
-
super(message);
|
|
146
|
-
this.code = code;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
966
|
+
var workspace;
|
|
149
967
|
var outputQueue = Promise.resolve();
|
|
150
968
|
var allowResolutionNetwork = process.argv.length === 3 && process.argv[2] === "--allow-resolution-network";
|
|
151
969
|
try {
|
|
@@ -154,19 +972,25 @@ try {
|
|
|
154
972
|
if (first.done)
|
|
155
973
|
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "preparation source is missing");
|
|
156
974
|
const source = requireSource(first.value);
|
|
975
|
+
workspace = source.workspace;
|
|
157
976
|
if (!(await iterator.next()).done) {
|
|
158
977
|
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "preparation source has trailing data");
|
|
159
978
|
}
|
|
160
|
-
const
|
|
979
|
+
const inputPaths = new Set([
|
|
980
|
+
"package.json",
|
|
981
|
+
"bun.lock",
|
|
982
|
+
...workspace?.members.map((path) => `${path}/package.json`) ?? []
|
|
983
|
+
]);
|
|
984
|
+
const inputs = source.files.filter(({ path }) => inputPaths.has(path));
|
|
161
985
|
await materializeSource(inputs);
|
|
162
986
|
const resolving = !inputs.some(({ path }) => path === "bun.lock");
|
|
163
987
|
if (resolving)
|
|
164
988
|
await resolveMissingLock();
|
|
165
989
|
await requireSupportedLock(resolving);
|
|
166
990
|
await install();
|
|
167
|
-
await materializeSource(source.files.filter(({ path }) =>
|
|
991
|
+
await materializeSource(source.files.filter(({ path }) => !inputPaths.has(path)));
|
|
168
992
|
await verifySource(source.files);
|
|
169
|
-
const prepared = await
|
|
993
|
+
const prepared = await capturePrivateBunPreparedTree(PACKAGE_ROOT, workspace);
|
|
170
994
|
await sendPrepared(prepared);
|
|
171
995
|
await outputQueue;
|
|
172
996
|
} catch (error) {
|
|
@@ -183,7 +1007,7 @@ async function materializeSource(files) {
|
|
|
183
1007
|
await mkdir(PACKAGE_ROOT, { recursive: true, mode: 448 });
|
|
184
1008
|
for (const file of files) {
|
|
185
1009
|
const bytes = decodeBase64(file.content, file.path);
|
|
186
|
-
const destination =
|
|
1010
|
+
const destination = join2(PACKAGE_ROOT, ...file.path.split("/"));
|
|
187
1011
|
await mkdir(dirname(destination), { recursive: true, mode: 448 });
|
|
188
1012
|
await writeFile(destination, bytes, { mode: 384, flag: "wx" });
|
|
189
1013
|
}
|
|
@@ -191,7 +1015,7 @@ async function materializeSource(files) {
|
|
|
191
1015
|
async function verifySource(files) {
|
|
192
1016
|
for (const file of files) {
|
|
193
1017
|
const expected = decodeBase64(file.content, file.path);
|
|
194
|
-
const actual = new Uint8Array(await
|
|
1018
|
+
const actual = new Uint8Array(await readFile2(join2(PACKAGE_ROOT, ...file.path.split("/"))));
|
|
195
1019
|
if (!Buffer.from(actual).equals(Buffer.from(expected))) {
|
|
196
1020
|
throw new WorkerFailure("PACKAGE_BUN_SOURCE_CHANGED", "Bun preparation changed authored package bytes");
|
|
197
1021
|
}
|
|
@@ -199,7 +1023,7 @@ async function verifySource(files) {
|
|
|
199
1023
|
}
|
|
200
1024
|
async function requireSupportedLock(resolved) {
|
|
201
1025
|
const lockCopy = "/work/bun-lock.jsonc";
|
|
202
|
-
await copyFile(
|
|
1026
|
+
await copyFile(join2(PACKAGE_ROOT, "bun.lock"), lockCopy);
|
|
203
1027
|
let value;
|
|
204
1028
|
try {
|
|
205
1029
|
const result = await runChild([
|
|
@@ -220,19 +1044,41 @@ async function requireSupportedLock(resolved) {
|
|
|
220
1044
|
throw new WorkerFailure("PACKAGE_BUN_LOCK_INVALID", "bun.lock is not valid for the pinned Bun runtime");
|
|
221
1045
|
}
|
|
222
1046
|
try {
|
|
223
|
-
requirePrivateBunLockPolicy(value);
|
|
1047
|
+
requirePrivateBunLockPolicy(value, workspace === undefined ? undefined : new Set(workspace.members));
|
|
224
1048
|
} catch {
|
|
225
1049
|
if (resolved) {
|
|
226
1050
|
throw new WorkerFailure("PACKAGE_BUN_RESOLVED_SOURCE_UNSUPPORTED", "resolved dependencies are unsupported; resolution requests may already have occurred");
|
|
227
1051
|
}
|
|
228
1052
|
unsupportedSource();
|
|
229
1053
|
}
|
|
1054
|
+
if (workspace !== undefined) {
|
|
1055
|
+
const locked = value.workspaces;
|
|
1056
|
+
for (const path of ["", ...workspace.members]) {
|
|
1057
|
+
const manifest = JSON.parse(await readFile2(join2(PACKAGE_ROOT, path, "package.json"), "utf8"));
|
|
1058
|
+
const entry = locked[path];
|
|
1059
|
+
const dependencyFields = [
|
|
1060
|
+
"dependencies",
|
|
1061
|
+
"devDependencies",
|
|
1062
|
+
"optionalDependencies",
|
|
1063
|
+
"peerDependencies"
|
|
1064
|
+
];
|
|
1065
|
+
if (entry === undefined || ["name", "version"].some((field) => manifest[field] !== entry[field]) || dependencyFields.some((field) => canonical(manifest[field] ?? {}) !== canonical(entry[field] ?? {})))
|
|
1066
|
+
throw new WorkerFailure("PACKAGE_BUN_LOCK_STALE", "workspace manifests and bun.lock disagree; update the workspace lock explicitly");
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
function canonical(value) {
|
|
1071
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value))
|
|
1072
|
+
return JSON.stringify(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)));
|
|
1073
|
+
return JSON.stringify(value) ?? "";
|
|
230
1074
|
}
|
|
231
1075
|
async function resolveMissingLock() {
|
|
232
1076
|
if (!allowResolutionNetwork)
|
|
233
1077
|
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "resolution permission is missing");
|
|
234
1078
|
try {
|
|
235
|
-
requirePrivateBunResolutionManifest(JSON.parse(await
|
|
1079
|
+
requirePrivateBunResolutionManifest(JSON.parse(await readFile2(join2(PACKAGE_ROOT, "package.json"), "utf8")), workspace === undefined ? undefined : "root");
|
|
1080
|
+
for (const member of workspace?.members ?? [])
|
|
1081
|
+
requirePrivateBunResolutionManifest(JSON.parse(await readFile2(join2(PACKAGE_ROOT, member, "package.json"), "utf8")), "member");
|
|
236
1082
|
} catch {
|
|
237
1083
|
throw new WorkerFailure("PACKAGE_BUN_SOURCE_UNSUPPORTED", "package.json contains unsupported resolution inputs");
|
|
238
1084
|
}
|
|
@@ -248,10 +1094,15 @@ async function resolveMissingLock() {
|
|
|
248
1094
|
`--cache-dir=${CACHE_ROOT}`,
|
|
249
1095
|
"--registry=https://registry.npmjs.org",
|
|
250
1096
|
"--no-progress",
|
|
251
|
-
"--no-summary"
|
|
1097
|
+
"--no-summary",
|
|
1098
|
+
...workspaceFilter()
|
|
252
1099
|
], { cwd: PACKAGE_ROOT, env: { LD_LIBRARY_PATH: "/jig-runtime/lib" } }, 64 * 1024, 64 * 1024);
|
|
253
|
-
if (result.exit !== 0)
|
|
1100
|
+
if (result.exit !== 0) {
|
|
1101
|
+
if (/No version matching|No matching version|No matching tag/i.test(result.stderr)) {
|
|
1102
|
+
throw new WorkerFailure("PACKAGE_BUN_RESOLUTION_VERSION_UNAVAILABLE", "a dependency version or tag is unavailable; resolution requests may already have occurred");
|
|
1103
|
+
}
|
|
254
1104
|
throw new WorkerFailure("PACKAGE_BUN_RESOLUTION_FAILED", "dependency resolution failed; network requests may already have occurred");
|
|
1105
|
+
}
|
|
255
1106
|
}
|
|
256
1107
|
function unsupportedSource() {
|
|
257
1108
|
throw new WorkerFailure("PACKAGE_BUN_SOURCE_UNSUPPORTED", "bun.lock contains a dependency source unsupported by this Jig alpha; only the default npm registry is supported");
|
|
@@ -269,7 +1120,8 @@ async function install() {
|
|
|
269
1120
|
`--cache-dir=${CACHE_ROOT}`,
|
|
270
1121
|
"--registry=https://registry.npmjs.org",
|
|
271
1122
|
"--no-progress",
|
|
272
|
-
"--no-summary"
|
|
1123
|
+
"--no-summary",
|
|
1124
|
+
...workspaceFilter()
|
|
273
1125
|
], {
|
|
274
1126
|
cwd: PACKAGE_ROOT,
|
|
275
1127
|
env: {
|
|
@@ -284,43 +1136,7 @@ ${result.stderr}`;
|
|
|
284
1136
|
}
|
|
285
1137
|
throw new WorkerFailure("PACKAGE_BUN_PREPARATION_FAILED", "the locked production dependencies could not be prepared by the pinned Bun runtime");
|
|
286
1138
|
}
|
|
287
|
-
await rm(
|
|
288
|
-
}
|
|
289
|
-
async function capturePrepared() {
|
|
290
|
-
const files = [];
|
|
291
|
-
let total = 0;
|
|
292
|
-
const visit = async (root, prefix) => {
|
|
293
|
-
const directory = await opendir(root);
|
|
294
|
-
const names = [];
|
|
295
|
-
for await (const entry of directory)
|
|
296
|
-
names.push(entry.name);
|
|
297
|
-
names.sort((left, right) => Buffer.from(left).compare(Buffer.from(right)));
|
|
298
|
-
for (const name of names) {
|
|
299
|
-
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
300
|
-
requirePath(path);
|
|
301
|
-
const physical = join(root, name);
|
|
302
|
-
const information = await lstat(physical);
|
|
303
|
-
if (information.isDirectory() && !information.isSymbolicLink()) {
|
|
304
|
-
await visit(physical, path);
|
|
305
|
-
continue;
|
|
306
|
-
}
|
|
307
|
-
if (!information.isFile() || information.isSymbolicLink() || information.nlink !== 1) {
|
|
308
|
-
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_UNSUPPORTED", "prepared dependencies contain a link or special file");
|
|
309
|
-
}
|
|
310
|
-
if (files.length >= PRIVATE_BUN_PREPARATION_LIMITS.preparedFiles) {
|
|
311
|
-
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree has too many files");
|
|
312
|
-
}
|
|
313
|
-
const bytes = new Uint8Array(await readFile(physical));
|
|
314
|
-
total += bytes.byteLength;
|
|
315
|
-
if (total > PRIVATE_BUN_PREPARATION_LIMITS.preparedBytes) {
|
|
316
|
-
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree is too large");
|
|
317
|
-
}
|
|
318
|
-
files.push(Object.freeze({ path, content: Buffer.from(bytes).toString("base64") }));
|
|
319
|
-
}
|
|
320
|
-
};
|
|
321
|
-
await visit(PACKAGE_ROOT, "");
|
|
322
|
-
files.sort((left, right) => Buffer.from(left.path).compare(Buffer.from(right.path)));
|
|
323
|
-
return Object.freeze(files);
|
|
1139
|
+
await rm(join2(PACKAGE_ROOT, "node_modules", ".bin"), { recursive: true, force: true });
|
|
324
1140
|
}
|
|
325
1141
|
function requireSource(value) {
|
|
326
1142
|
const root = ordinaryRecord2(value);
|
|
@@ -350,18 +1166,40 @@ function requireSource(value) {
|
|
|
350
1166
|
if (!files.some(({ path }) => path === "package.json") || !files.some(({ path }) => path === "bun.lock") && !allowResolutionNetwork) {
|
|
351
1167
|
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "locked Bun source is incomplete");
|
|
352
1168
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
1169
|
+
let selectedWorkspace;
|
|
1170
|
+
if (root.workspace !== undefined) {
|
|
1171
|
+
const record = ordinaryRecord2(root.workspace);
|
|
1172
|
+
if (record === undefined || typeof record.target !== "string" || !Array.isArray(record.members) || !Array.isArray(record.selected) || record.members.length === 0 || record.members.length > 256 || record.selected.length > record.members.length || !record.members.includes(record.target) || !record.selected.includes(record.target))
|
|
1173
|
+
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "workspace preparation metadata is invalid");
|
|
1174
|
+
for (const member of record.members) {
|
|
1175
|
+
if (typeof member !== "string")
|
|
1176
|
+
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "workspace path is invalid");
|
|
1177
|
+
requirePath(member);
|
|
1178
|
+
if (member.split("/").includes("node_modules") || !files.some(({ path }) => path === `${member}/package.json`))
|
|
1179
|
+
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "workspace manifest is missing");
|
|
1180
|
+
}
|
|
1181
|
+
if (new Set(record.members).size !== record.members.length || new Set(record.selected).size !== record.selected.length || record.selected.some((path) => !record.members.includes(path)))
|
|
1182
|
+
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", "workspace membership is invalid");
|
|
1183
|
+
selectedWorkspace = {
|
|
1184
|
+
target: record.target,
|
|
1185
|
+
members: record.members,
|
|
1186
|
+
selected: record.selected
|
|
1187
|
+
};
|
|
358
1188
|
}
|
|
1189
|
+
return Object.freeze({
|
|
1190
|
+
files: Object.freeze(files),
|
|
1191
|
+
...selectedWorkspace === undefined ? {} : { workspace: selectedWorkspace }
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
function workspaceFilter() {
|
|
1195
|
+
return workspace === undefined ? [] : ["--filter", `./${workspace.target}`];
|
|
359
1196
|
}
|
|
360
1197
|
function decodeBase64(value, label) {
|
|
361
|
-
|
|
1198
|
+
const bytes = Buffer.from(value, "base64");
|
|
1199
|
+
if (bytes.toString("base64") !== value) {
|
|
362
1200
|
throw new WorkerFailure("PACKAGE_BUN_PROTOCOL", `${label} has invalid encoded bytes`);
|
|
363
1201
|
}
|
|
364
|
-
return new Uint8Array(
|
|
1202
|
+
return new Uint8Array(bytes);
|
|
365
1203
|
}
|
|
366
1204
|
function ordinaryRecord2(value) {
|
|
367
1205
|
if (value === null || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype)
|
|
@@ -378,8 +1216,8 @@ function enqueue(bytes) {
|
|
|
378
1216
|
});
|
|
379
1217
|
return outputQueue;
|
|
380
1218
|
}
|
|
381
|
-
function sendPrepared(
|
|
382
|
-
const bytes = encodePrivateBunMessage({ type: "prepared",
|
|
1219
|
+
function sendPrepared(prepared) {
|
|
1220
|
+
const bytes = encodePrivateBunMessage({ type: "prepared", ...prepared });
|
|
383
1221
|
if (!privateBunMessageFits(bytes.byteLength - 1, PRIVATE_BUN_PREPARED_MESSAGE_BYTES)) {
|
|
384
1222
|
throw new WorkerFailure("PACKAGE_BUN_OUTPUT_LIMIT", "prepared dependency tree is too large");
|
|
385
1223
|
}
|