@orkestrel/test 0.0.11 → 0.0.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/README.md +20 -8
- package/dist/src/browser/index.d.ts +483 -237
- package/dist/src/browser/index.js +357 -69
- package/dist/src/browser/index.js.map +1 -1
- package/dist/src/core/index.cjs +189 -21
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +270 -21
- package/dist/src/core/index.d.ts +270 -21
- package/dist/src/core/index.js +183 -22
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +67 -48
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +70 -32
- package/dist/src/server/index.d.ts +70 -32
- package/dist/src/server/index.js +66 -50
- package/dist/src/server/index.js.map +1 -1
- package/package.json +14 -11
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Server } from 'node:net';
|
|
2
2
|
import { Socket } from 'node:net';
|
|
3
|
+
import { Stats } from 'node:fs';
|
|
3
4
|
import { WaitOptions } from '@orkestrel/test';
|
|
4
5
|
|
|
5
|
-
/**
|
|
6
|
+
/** Holds a name-keyed cookie store a test drives one origin with, filled from real responses. */
|
|
6
7
|
export declare interface CookieJarInterface {
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* Reports the `Cookie` request header naming every stored cookie, or `undefined` while the jar
|
|
10
|
+
* holds none.
|
|
9
11
|
*/
|
|
10
12
|
readonly header: string | undefined;
|
|
11
13
|
/**
|
|
@@ -100,13 +102,14 @@ export declare function createScratch(options?: ScratchOptions): ScratchInterfac
|
|
|
100
102
|
*/
|
|
101
103
|
export declare function destroyScratch(scratch: ScratchInterface, options?: WaitOptions): Promise<void>;
|
|
102
104
|
|
|
103
|
-
/**
|
|
105
|
+
/** Configures a source inventory read. */
|
|
104
106
|
export declare interface InventoryOptions {
|
|
105
|
-
/**
|
|
107
|
+
/** Lists the file extensions to include, each written with its leading dot. */
|
|
106
108
|
readonly extensions?: readonly string[];
|
|
107
109
|
/**
|
|
108
|
-
*
|
|
109
|
-
* on whole segments, so `excluded` drops `excluded/file.ts` and keeps
|
|
110
|
+
* Lists the root-relative path keys to exclude. A key excludes itself and every key below it,
|
|
111
|
+
* matched on whole segments, so `excluded` drops `excluded/file.ts` and keeps
|
|
112
|
+
* `excluded-other/file.ts`.
|
|
110
113
|
*/
|
|
111
114
|
readonly exclude?: readonly string[];
|
|
112
115
|
}
|
|
@@ -116,7 +119,7 @@ export declare interface InventoryOptions {
|
|
|
116
119
|
*
|
|
117
120
|
* @param key - The root-relative key to test.
|
|
118
121
|
* @param exclusions - The normalized root-relative exclusion keys.
|
|
119
|
-
* @returns
|
|
122
|
+
* @returns True if an exclusion names the key or one of its ancestors; false otherwise.
|
|
120
123
|
*/
|
|
121
124
|
export declare function isExcluded(key: string, exclusions: readonly string[]): boolean;
|
|
122
125
|
|
|
@@ -139,14 +142,14 @@ export declare function isExcluded(key: string, exclusions: readonly string[]):
|
|
|
139
142
|
*/
|
|
140
143
|
export declare function isRunning(pid: number): boolean;
|
|
141
144
|
|
|
142
|
-
/**
|
|
145
|
+
/** Holds a server a test owns, listening on an ephemeral loopback port until the test releases it. */
|
|
143
146
|
export declare interface LoopbackInterface {
|
|
144
147
|
/**
|
|
145
|
-
*
|
|
146
|
-
* same port under `https`.
|
|
148
|
+
* Names the `http` origin for the assigned port, without a trailing slash. A TLS server answers
|
|
149
|
+
* on the same port under `https`.
|
|
147
150
|
*/
|
|
148
151
|
readonly url: string;
|
|
149
|
-
/**
|
|
152
|
+
/** Holds the ephemeral port the host assigned. */
|
|
150
153
|
readonly port: number;
|
|
151
154
|
/**
|
|
152
155
|
* Drops every live connection on a server that carries `closeAllConnections`, stops listening, and
|
|
@@ -162,13 +165,33 @@ export declare interface LoopbackInterface {
|
|
|
162
165
|
*
|
|
163
166
|
* @param current - The identity read from the path now.
|
|
164
167
|
* @param allocation - The identity recorded when the directory was allocated.
|
|
165
|
-
* @returns
|
|
168
|
+
* @returns True if the device, the index node, and the creation time all match; false otherwise.
|
|
166
169
|
* @remarks All three fields are compared because none of them alone identifies an allocation. A
|
|
167
170
|
* device is shared by every directory on one filesystem, an index node is reused once its directory
|
|
168
171
|
* is removed, and a creation time repeats within the host's timestamp resolution.
|
|
169
172
|
*/
|
|
170
173
|
export declare function matchesIdentity(current: ScratchIdentity, allocation: ScratchIdentity): boolean;
|
|
171
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Reads the `code` an unknown thrown value carries.
|
|
177
|
+
*
|
|
178
|
+
* @param error - The thrown value to read.
|
|
179
|
+
* @returns The string `code` the value carries, or `undefined` when it carries none.
|
|
180
|
+
* @remarks The read is contained on its own terms: a value that is not an object, one carrying no
|
|
181
|
+
* `code`, and one carrying a `code` that is not a string all answer `undefined`. A null-prototype
|
|
182
|
+
* object is read the same way, because the key is tested with `in` rather than through
|
|
183
|
+
* `hasOwnProperty`.
|
|
184
|
+
*/
|
|
185
|
+
export declare function readErrorCode(error: unknown): string | undefined;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Reads the identity of one allocated directory off a host status.
|
|
189
|
+
*
|
|
190
|
+
* @param status - The status read from the directory's path.
|
|
191
|
+
* @returns The device, index node, and creation time that together name the allocation.
|
|
192
|
+
*/
|
|
193
|
+
export declare function readIdentity(status: Stats): ScratchIdentity;
|
|
194
|
+
|
|
172
195
|
/**
|
|
173
196
|
* Reads files from selected targets below a root directory.
|
|
174
197
|
*
|
|
@@ -185,17 +208,17 @@ export declare function matchesIdentity(current: ScratchIdentity, allocation: Sc
|
|
|
185
208
|
export declare function readInventory(root: URL | string, targets: readonly string[], options?: InventoryOptions): Readonly<Record<string, string>>;
|
|
186
209
|
|
|
187
210
|
/**
|
|
188
|
-
*
|
|
211
|
+
* Caps the attempts `removeTree` makes before rethrowing a retryable removal error.
|
|
189
212
|
*/
|
|
190
213
|
export declare const REMOVE_TREE_MAX_ATTEMPTS = 10;
|
|
191
214
|
|
|
192
215
|
/**
|
|
193
|
-
*
|
|
216
|
+
* Names the synchronous delay, in milliseconds, `removeTree` waits between attempts.
|
|
194
217
|
*/
|
|
195
218
|
export declare const REMOVE_TREE_RETRY_DELAY_MS = 100;
|
|
196
219
|
|
|
197
220
|
/**
|
|
198
|
-
*
|
|
221
|
+
* Names the error codes `removeTree` retries; every other code rethrows immediately.
|
|
199
222
|
*/
|
|
200
223
|
export declare const REMOVE_TREE_RETRYABLE_CODES: readonly string[];
|
|
201
224
|
|
|
@@ -248,6 +271,20 @@ export declare function removeTree(path: string): void;
|
|
|
248
271
|
*/
|
|
249
272
|
export declare function requestUpgrade(port: number, options?: UpgradeOptions): Promise<UpgradeResult>;
|
|
250
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Resolves a target that stays below a root directory, refusing an escape.
|
|
276
|
+
*
|
|
277
|
+
* @param root - The absolute root directory.
|
|
278
|
+
* @param target - The relative or absolute target to resolve.
|
|
279
|
+
* @returns The absolute target below the root.
|
|
280
|
+
* @throws An `Error` reading `Path outside scratch directory: <target>` when the target escapes the
|
|
281
|
+
* root.
|
|
282
|
+
* @remarks This is {@link resolveContained} with the refusal every contained scratch operation makes
|
|
283
|
+
* of an escape, so the check and its one message are stated once. Read `resolveContained` where an
|
|
284
|
+
* escape is an answer rather than a refusal.
|
|
285
|
+
*/
|
|
286
|
+
export declare function requireContained(root: string, target: string): string;
|
|
287
|
+
|
|
251
288
|
/**
|
|
252
289
|
* Resolves a target that stays below a root directory.
|
|
253
290
|
*
|
|
@@ -257,19 +294,19 @@ export declare function requestUpgrade(port: number, options?: UpgradeOptions):
|
|
|
257
294
|
*/
|
|
258
295
|
export declare function resolveContained(root: string, target: string): string | undefined;
|
|
259
296
|
|
|
260
|
-
/**
|
|
297
|
+
/** Represents the fields that together identify one allocated directory on its host. */
|
|
261
298
|
export declare interface ScratchIdentity {
|
|
262
|
-
/**
|
|
299
|
+
/** Holds the identifier of the device holding the directory. */
|
|
263
300
|
readonly device: number;
|
|
264
|
-
/**
|
|
301
|
+
/** Holds the number of the directory's index node on that device. */
|
|
265
302
|
readonly inode: number;
|
|
266
|
-
/**
|
|
303
|
+
/** Holds the directory's creation time in milliseconds. */
|
|
267
304
|
readonly birth: number;
|
|
268
305
|
}
|
|
269
306
|
|
|
270
|
-
/**
|
|
307
|
+
/** Holds a temporary directory a test owns, writes into, reads back, and removes when it is done. */
|
|
271
308
|
export declare interface ScratchInterface {
|
|
272
|
-
/**
|
|
309
|
+
/** Holds the absolute path of the allocated directory. */
|
|
273
310
|
readonly path: string;
|
|
274
311
|
/**
|
|
275
312
|
* Writes a file, creating each parent directory that does not exist.
|
|
@@ -296,7 +333,8 @@ export declare interface ScratchInterface {
|
|
|
296
333
|
* Reports whether a path exists without following its final symbolic link.
|
|
297
334
|
*
|
|
298
335
|
* @param target - A relative or absolute path contained by the scratch directory.
|
|
299
|
-
* @returns True
|
|
336
|
+
* @returns True if the entry exists, including a symbolic link whose target is
|
|
337
|
+
* missing; false otherwise.
|
|
300
338
|
* @throws When the path escapes the scratch directory or its root is a symbolic link or file.
|
|
301
339
|
*/
|
|
302
340
|
has(target: string): boolean;
|
|
@@ -353,23 +391,23 @@ export declare interface ScratchInterface {
|
|
|
353
391
|
destroy(): void;
|
|
354
392
|
}
|
|
355
393
|
|
|
356
|
-
/**
|
|
394
|
+
/** Configures a scratch directory allocation. */
|
|
357
395
|
export declare interface ScratchOptions {
|
|
358
396
|
/**
|
|
359
|
-
*
|
|
397
|
+
* Names the existing directory in which to create the allocation. Defaults to the host temporary
|
|
360
398
|
* directory. Allocation throws when this path is missing, a symbolic link, or not a directory.
|
|
361
399
|
*/
|
|
362
400
|
readonly parent?: string;
|
|
363
401
|
/**
|
|
364
|
-
*
|
|
365
|
-
* contains `/` or `\`. Both are refused on every host, so the rule does not vary by host. A
|
|
402
|
+
* Holds the name fragment that starts the generated directory name. Allocation throws when this
|
|
403
|
+
* value contains `/` or `\`. Both are refused on every host, so the rule does not vary by host. A
|
|
366
404
|
* fragment carrying no separator is one path segment and cannot steer the allocation, so
|
|
367
405
|
* `release-0..2-` allocates.
|
|
368
406
|
*/
|
|
369
407
|
readonly prefix?: string;
|
|
370
408
|
/**
|
|
371
|
-
*
|
|
372
|
-
* directory and rethrows when a key escapes or the host refuses a write.
|
|
409
|
+
* Holds the files to write on allocation, keyed by path below the scratch directory. Allocation
|
|
410
|
+
* removes its directory and rethrows when a key escapes or the host refuses a write.
|
|
373
411
|
*/
|
|
374
412
|
readonly files?: Readonly<Record<string, string>>;
|
|
375
413
|
}
|
|
@@ -449,23 +487,23 @@ export declare function supportsFileLinks(): boolean;
|
|
|
449
487
|
export declare function supportsMode(): boolean;
|
|
450
488
|
|
|
451
489
|
/**
|
|
452
|
-
*
|
|
490
|
+
* Configures a client upgrade request.
|
|
453
491
|
*
|
|
454
492
|
* @remarks The time bounds and abort signal bound the wait for the server's answer, so a server
|
|
455
493
|
* that accepts the connection and never answers ends the call rather than parking it.
|
|
456
494
|
*/
|
|
457
495
|
export declare interface UpgradeOptions extends WaitOptions {
|
|
458
|
-
/**
|
|
496
|
+
/** Names the request path, written with its leading slash. Defaults to `/`. */
|
|
459
497
|
readonly path?: string;
|
|
460
498
|
/**
|
|
461
|
-
*
|
|
499
|
+
* Lists the subprotocol tokens the request offers. They are sent as one comma-separated
|
|
462
500
|
* `Sec-WebSocket-Protocol` field, and an empty or omitted list sends no field at all.
|
|
463
501
|
*/
|
|
464
502
|
readonly protocols?: readonly string[];
|
|
465
503
|
}
|
|
466
504
|
|
|
467
505
|
/**
|
|
468
|
-
*
|
|
506
|
+
* Represents what one server did with a client upgrade request.
|
|
469
507
|
*
|
|
470
508
|
* @remarks `claimed` is the discriminant. The claimed arm carries `protocol`, the subprotocol the
|
|
471
509
|
* server selected, which is `undefined` when it selected none; a claimed upgrade produced no plain
|
package/dist/src/server/index.js
CHANGED
|
@@ -4,19 +4,19 @@ import { request } from "node:http";
|
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { waitForDelay } from "../core/index.js";
|
|
7
|
+
import { checkBounds, waitForDelay } from "../core/index.js";
|
|
8
8
|
import { once } from "node:events";
|
|
9
9
|
//#region src/server/constants.ts
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Caps the attempts `removeTree` makes before rethrowing a retryable removal error.
|
|
12
12
|
*/
|
|
13
13
|
var REMOVE_TREE_MAX_ATTEMPTS = 10;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* Names the synchronous delay, in milliseconds, `removeTree` waits between attempts.
|
|
16
16
|
*/
|
|
17
17
|
var REMOVE_TREE_RETRY_DELAY_MS = 100;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Names the error codes `removeTree` retries; every other code rethrows immediately.
|
|
20
20
|
*/
|
|
21
21
|
var REMOVE_TREE_RETRYABLE_CODES = Object.freeze([
|
|
22
22
|
"EBUSY",
|
|
@@ -39,11 +39,54 @@ function resolveContained(root, target) {
|
|
|
39
39
|
return candidate;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
+
* Resolves a target that stays below a root directory, refusing an escape.
|
|
43
|
+
*
|
|
44
|
+
* @param root - The absolute root directory.
|
|
45
|
+
* @param target - The relative or absolute target to resolve.
|
|
46
|
+
* @returns The absolute target below the root.
|
|
47
|
+
* @throws An `Error` reading `Path outside scratch directory: <target>` when the target escapes the
|
|
48
|
+
* root.
|
|
49
|
+
* @remarks This is {@link resolveContained} with the refusal every contained scratch operation makes
|
|
50
|
+
* of an escape, so the check and its one message are stated once. Read `resolveContained` where an
|
|
51
|
+
* escape is an answer rather than a refusal.
|
|
52
|
+
*/
|
|
53
|
+
function requireContained(root, target) {
|
|
54
|
+
const candidate = resolveContained(root, target);
|
|
55
|
+
if (candidate === void 0) throw new Error(`Path outside scratch directory: ${target}`);
|
|
56
|
+
return candidate;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads the identity of one allocated directory off a host status.
|
|
60
|
+
*
|
|
61
|
+
* @param status - The status read from the directory's path.
|
|
62
|
+
* @returns The device, index node, and creation time that together name the allocation.
|
|
63
|
+
*/
|
|
64
|
+
function readIdentity(status) {
|
|
65
|
+
return {
|
|
66
|
+
birth: status.birthtimeMs,
|
|
67
|
+
device: status.dev,
|
|
68
|
+
inode: status.ino
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reads the `code` an unknown thrown value carries.
|
|
73
|
+
*
|
|
74
|
+
* @param error - The thrown value to read.
|
|
75
|
+
* @returns The string `code` the value carries, or `undefined` when it carries none.
|
|
76
|
+
* @remarks The read is contained on its own terms: a value that is not an object, one carrying no
|
|
77
|
+
* `code`, and one carrying a `code` that is not a string all answer `undefined`. A null-prototype
|
|
78
|
+
* object is read the same way, because the key is tested with `in` rather than through
|
|
79
|
+
* `hasOwnProperty`.
|
|
80
|
+
*/
|
|
81
|
+
function readErrorCode(error) {
|
|
82
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
42
85
|
* Reports whether two directory identities name the same allocation.
|
|
43
86
|
*
|
|
44
87
|
* @param current - The identity read from the path now.
|
|
45
88
|
* @param allocation - The identity recorded when the directory was allocated.
|
|
46
|
-
* @returns
|
|
89
|
+
* @returns True if the device, the index node, and the creation time all match; false otherwise.
|
|
47
90
|
* @remarks All three fields are compared because none of them alone identifies an allocation. A
|
|
48
91
|
* device is shared by every directory on one filesystem, an index node is reused once its directory
|
|
49
92
|
* is removed, and a creation time repeats within the host's timestamp resolution.
|
|
@@ -56,7 +99,7 @@ function matchesIdentity(current, allocation) {
|
|
|
56
99
|
*
|
|
57
100
|
* @param key - The root-relative key to test.
|
|
58
101
|
* @param exclusions - The normalized root-relative exclusion keys.
|
|
59
|
-
* @returns
|
|
102
|
+
* @returns True if an exclusion names the key or one of its ancestors; false otherwise.
|
|
60
103
|
*/
|
|
61
104
|
function isExcluded(key, exclusions) {
|
|
62
105
|
return exclusions.some((rule) => rule === "" || key === rule || key.startsWith(`${rule}/`));
|
|
@@ -78,7 +121,7 @@ function createLink(path, source) {
|
|
|
78
121
|
try {
|
|
79
122
|
symlinkSync(source, path);
|
|
80
123
|
} catch (error) {
|
|
81
|
-
if ((
|
|
124
|
+
if (readErrorCode(error) !== "EPERM") throw error;
|
|
82
125
|
const resolved = resolve(dirname(path), source);
|
|
83
126
|
const status = statSync(resolved, { throwIfNoEntry: false });
|
|
84
127
|
if (status !== void 0 && !status.isDirectory()) throw error;
|
|
@@ -107,7 +150,7 @@ function removeTree(path) {
|
|
|
107
150
|
});
|
|
108
151
|
return;
|
|
109
152
|
} catch (error) {
|
|
110
|
-
const code =
|
|
153
|
+
const code = readErrorCode(error);
|
|
111
154
|
if (code === void 0 || !REMOVE_TREE_RETRYABLE_CODES.includes(code) || attempt >= 10) throw error;
|
|
112
155
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100);
|
|
113
156
|
}
|
|
@@ -230,8 +273,7 @@ function isRunning(pid) {
|
|
|
230
273
|
async function waitForSocketClose(socket, options) {
|
|
231
274
|
const budget = options?.budget ?? 1e3;
|
|
232
275
|
const interval = options?.interval ?? 10;
|
|
233
|
-
|
|
234
|
-
if (!Number.isFinite(interval) || interval < 0) throw new Error("Socket interval must be finite and non-negative");
|
|
276
|
+
checkBounds("Socket", budget, interval);
|
|
235
277
|
const signal = options?.signal;
|
|
236
278
|
signal?.throwIfAborted();
|
|
237
279
|
if (socket.closed) return;
|
|
@@ -298,8 +340,7 @@ async function waitForSocketClose(socket, options) {
|
|
|
298
340
|
async function destroyScratch(scratch, options) {
|
|
299
341
|
const budget = options?.budget ?? 1e4;
|
|
300
342
|
const interval = options?.interval ?? 25;
|
|
301
|
-
|
|
302
|
-
if (!Number.isFinite(interval) || interval < 0) throw new Error("Scratch interval must be finite and non-negative");
|
|
343
|
+
checkBounds("Scratch", budget, interval);
|
|
303
344
|
const start = performance.now();
|
|
304
345
|
let refusal;
|
|
305
346
|
while (true) {
|
|
@@ -348,8 +389,7 @@ async function destroyScratch(scratch, options) {
|
|
|
348
389
|
async function requestUpgrade(port, options) {
|
|
349
390
|
const budget = options?.budget ?? 1e3;
|
|
350
391
|
const interval = options?.interval ?? 10;
|
|
351
|
-
|
|
352
|
-
if (!Number.isFinite(interval) || interval < 0) throw new Error("Upgrade interval must be finite and non-negative");
|
|
392
|
+
checkBounds("Upgrade", budget, interval);
|
|
353
393
|
const signal = options?.signal;
|
|
354
394
|
signal?.throwIfAborted();
|
|
355
395
|
const path = options?.path ?? "/";
|
|
@@ -568,18 +608,11 @@ function createScratch(options) {
|
|
|
568
608
|
const prefix = options?.prefix ?? "orkestrel-test-";
|
|
569
609
|
if (prefix.includes("/") || prefix.includes("\\")) throw new Error("Scratch prefix must be a name fragment");
|
|
570
610
|
const path = mkdtempSync(`${parent}${sep}${prefix}`);
|
|
571
|
-
const
|
|
572
|
-
const allocation = {
|
|
573
|
-
birth: allocated.birthtimeMs,
|
|
574
|
-
device: allocated.dev,
|
|
575
|
-
inode: allocated.ino
|
|
576
|
-
};
|
|
577
|
-
const outside = "Path outside scratch directory";
|
|
611
|
+
const allocation = readIdentity(statSync(path));
|
|
578
612
|
const unremovable = "Scratch directory is not a removable target";
|
|
579
613
|
try {
|
|
580
614
|
for (const [target, text] of Object.entries(options?.files ?? {})) {
|
|
581
|
-
const candidate =
|
|
582
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
615
|
+
const candidate = requireContained(path, target);
|
|
583
616
|
mkdirSync(dirname(candidate), { recursive: true });
|
|
584
617
|
writeFileSync(candidate, text);
|
|
585
618
|
}
|
|
@@ -590,16 +623,14 @@ function createScratch(options) {
|
|
|
590
623
|
const scratch = {
|
|
591
624
|
path,
|
|
592
625
|
write(target, text) {
|
|
593
|
-
const candidate =
|
|
594
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
626
|
+
const candidate = requireContained(path, target);
|
|
595
627
|
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
596
628
|
mkdirSync(dirname(candidate), { recursive: true });
|
|
597
629
|
writeFileSync(candidate, text);
|
|
598
630
|
return candidate;
|
|
599
631
|
},
|
|
600
632
|
read(target) {
|
|
601
|
-
const candidate =
|
|
602
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
633
|
+
const candidate = requireContained(path, target);
|
|
603
634
|
if (!scratch.has(target)) return void 0;
|
|
604
635
|
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
605
636
|
if (status === void 0) return void 0;
|
|
@@ -607,8 +638,7 @@ function createScratch(options) {
|
|
|
607
638
|
return readFileSync(candidate, "utf8");
|
|
608
639
|
},
|
|
609
640
|
has(target) {
|
|
610
|
-
const candidate =
|
|
611
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
641
|
+
const candidate = requireContained(path, target);
|
|
612
642
|
const rootStatus = lstatSync(path, { throwIfNoEntry: false });
|
|
613
643
|
if (rootStatus === void 0) return false;
|
|
614
644
|
if (rootStatus.isSymbolicLink()) throw new Error("Scratch directory is a symbolic link");
|
|
@@ -616,8 +646,7 @@ function createScratch(options) {
|
|
|
616
646
|
return lstatSync(candidate, { throwIfNoEntry: false }) !== void 0;
|
|
617
647
|
},
|
|
618
648
|
names(target = ".") {
|
|
619
|
-
const candidate =
|
|
620
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
649
|
+
const candidate = requireContained(path, target);
|
|
621
650
|
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
622
651
|
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
623
652
|
if (status === void 0) throw new Error(`Scratch path does not exist: ${target}`);
|
|
@@ -625,8 +654,7 @@ function createScratch(options) {
|
|
|
625
654
|
return readdirSync(candidate).sort();
|
|
626
655
|
},
|
|
627
656
|
ensure(target) {
|
|
628
|
-
const candidate =
|
|
629
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
657
|
+
const candidate = requireContained(path, target);
|
|
630
658
|
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
631
659
|
const status = statSync(candidate, { throwIfNoEntry: false });
|
|
632
660
|
if (status !== void 0 && !status.isDirectory()) throw new Error(`Scratch path is not a directory: ${target}`);
|
|
@@ -634,36 +662,24 @@ function createScratch(options) {
|
|
|
634
662
|
return candidate;
|
|
635
663
|
},
|
|
636
664
|
link(target, source) {
|
|
637
|
-
const candidate =
|
|
638
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
665
|
+
const candidate = requireContained(path, target);
|
|
639
666
|
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
640
667
|
mkdirSync(dirname(candidate), { recursive: true });
|
|
641
668
|
createLink(candidate, source);
|
|
642
669
|
return candidate;
|
|
643
670
|
},
|
|
644
671
|
remove(target) {
|
|
645
|
-
const candidate =
|
|
646
|
-
if (candidate === void 0) throw new Error(`${outside}: ${target}`);
|
|
672
|
+
const candidate = requireContained(path, target);
|
|
647
673
|
if (candidate === path) throw new Error(`${unremovable}: ${target}`);
|
|
648
674
|
if (!scratch.has(".")) throw new Error("Scratch directory does not exist");
|
|
649
675
|
const status = lstatSync(candidate, { throwIfNoEntry: false });
|
|
650
|
-
if (status !== void 0) {
|
|
651
|
-
if (matchesIdentity({
|
|
652
|
-
birth: status.birthtimeMs,
|
|
653
|
-
device: status.dev,
|
|
654
|
-
inode: status.ino
|
|
655
|
-
}, allocation)) throw new Error(`${unremovable}: ${target}`);
|
|
656
|
-
}
|
|
676
|
+
if (status !== void 0 && matchesIdentity(readIdentity(status), allocation)) throw new Error(`${unremovable}: ${target}`);
|
|
657
677
|
removeTree(candidate);
|
|
658
678
|
},
|
|
659
679
|
destroy() {
|
|
660
680
|
const status = lstatSync(path, { throwIfNoEntry: false });
|
|
661
681
|
if (status === void 0) return;
|
|
662
|
-
if (!matchesIdentity(
|
|
663
|
-
birth: status.birthtimeMs,
|
|
664
|
-
device: status.dev,
|
|
665
|
-
inode: status.ino
|
|
666
|
-
}, allocation)) return;
|
|
682
|
+
if (!matchesIdentity(readIdentity(status), allocation)) return;
|
|
667
683
|
removeTree(path);
|
|
668
684
|
}
|
|
669
685
|
};
|
|
@@ -732,6 +748,6 @@ function createCookieJar() {
|
|
|
732
748
|
};
|
|
733
749
|
}
|
|
734
750
|
//#endregion
|
|
735
|
-
export { REMOVE_TREE_MAX_ATTEMPTS, REMOVE_TREE_RETRYABLE_CODES, REMOVE_TREE_RETRY_DELAY_MS, createCookieJar, createLink, createLoopback, createScratch, destroyScratch, isExcluded, isRunning, matchesIdentity, readInventory, removeTree, requestUpgrade, resolveContained, supportsBytes, supportsCase, supportsDirectoryLinks, supportsFileLinks, supportsMode, waitForSocketClose };
|
|
751
|
+
export { REMOVE_TREE_MAX_ATTEMPTS, REMOVE_TREE_RETRYABLE_CODES, REMOVE_TREE_RETRY_DELAY_MS, createCookieJar, createLink, createLoopback, createScratch, destroyScratch, isExcluded, isRunning, matchesIdentity, readErrorCode, readIdentity, readInventory, removeTree, requestUpgrade, requireContained, resolveContained, supportsBytes, supportsCase, supportsDirectoryLinks, supportsFileLinks, supportsMode, waitForSocketClose };
|
|
736
752
|
|
|
737
753
|
//# sourceMappingURL=index.js.map
|