@openclaw/fs-safe 0.4.1 → 0.4.2
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/CHANGELOG.md +15 -0
- package/README.md +4 -2
- package/dist/advanced.d.ts +1 -0
- package/dist/advanced.d.ts.map +1 -1
- package/dist/advanced.js +1 -0
- package/dist/archive-limits.d.ts.map +1 -1
- package/dist/archive-staging.d.ts.map +1 -1
- package/dist/async-lock.d.ts.map +1 -1
- package/dist/bounded-read.d.ts +14 -0
- package/dist/bounded-read.d.ts.map +1 -0
- package/dist/bounded-read.js +86 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/file-store.d.ts.map +1 -1
- package/dist/file-store.js +5 -2
- package/dist/json.d.ts +8 -5
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +27 -14
- package/dist/pinned-python.js +10 -10
- package/dist/pinned-write.d.ts.map +1 -1
- package/dist/pinned-write.js +12 -2
- package/dist/read-opened-file.d.ts.map +1 -1
- package/dist/read-opened-file.js +4 -4
- package/dist/regular-file.d.ts.map +1 -1
- package/dist/regular-file.js +11 -52
- package/dist/root-context.d.ts.map +1 -1
- package/dist/root-path.d.ts.map +1 -1
- package/dist/secret-file.d.ts.map +1 -1
- package/dist/secret-file.js +5 -2
- package/dist/secure-file.d.ts.map +1 -1
- package/dist/secure-file.js +6 -7
- package/dist/sidecar-lock.d.ts +5 -1
- package/dist/sidecar-lock.d.ts.map +1 -1
- package/dist/sidecar-lock.js +3 -42
- package/docs/advanced.md +20 -0
- package/docs/config.md +2 -2
- package/docs/index.md +1 -1
- package/docs/json-store.md +2 -2
- package/docs/json.md +13 -5
- package/docs/regular-file.md +26 -32
- package/docs/sidecar-lock.md +8 -24
- package/docs/writing.md +1 -1
- package/package.json +19 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.2 - 2026-07-18
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add bounded async/sync reads for already-open file descriptors and handles, plus optional byte caps for standalone JSON readers.
|
|
8
|
+
|
|
9
|
+
### Security and Correctness
|
|
10
|
+
|
|
11
|
+
- Make capped root, regular-file, secure-file, secret-file, structured JSON, and synchronous store reads incremental so a file that grows after validation cannot trigger an unbounded allocation.
|
|
12
|
+
- Disable `remove-if-unchanged` stale sidecar deletion because a pathname identity check followed by unlink can delete a replacement lock; retain the deprecated recovery inputs for compatibility while all stale locks fail closed.
|
|
13
|
+
|
|
14
|
+
### Compatibility
|
|
15
|
+
|
|
16
|
+
- Treat `EPERM` from pinned-write file and directory `fsync` calls as best effort for filesystems that permit the write but reject explicit synchronization.
|
|
17
|
+
|
|
3
18
|
## 0.4.1 - 2026-07-01
|
|
4
19
|
|
|
5
20
|
### Security and Correctness
|
package/README.md
CHANGED
|
@@ -195,7 +195,7 @@ that OpenClaw needs to compose higher-level APIs are grouped under
|
|
|
195
195
|
| `@openclaw/fs-safe/permissions` | POSIX mode and Windows ACL inspection plus remediation formatting helpers |
|
|
196
196
|
| `@openclaw/fs-safe/walk` | budget-bounded directory walking with symlink policy, filters, and truncation accounting; not root-bounded |
|
|
197
197
|
| `@openclaw/fs-safe/archive` | `extractArchive`, `resolveArchiveKind`, `ArchiveLimitError`, preflight helpers |
|
|
198
|
-
| `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, install paths, filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
|
|
198
|
+
| `@openclaw/fs-safe/advanced` | lower-level composition helpers such as path scopes, root-file open, bounded descriptor reads, install paths, filename sanitizing, temp-file targets, sibling-temp writes, local-root readers, regular-file helpers, `pathExists`, and `withTimeout`; less stable than focused public subpaths |
|
|
199
199
|
| `@openclaw/fs-safe/errors` | `FsSafeError`, `FsSafeErrorCode` |
|
|
200
200
|
| `@openclaw/fs-safe/types` | shared types: `DirEntry`, `PathStat`, … |
|
|
201
201
|
| `@openclaw/fs-safe/test-hooks` | hooks the test suite uses to inject races; only active under `NODE_ENV=test` |
|
|
@@ -283,7 +283,9 @@ the common merge-into-defaults case. Standalone helpers use options bags
|
|
|
283
283
|
because they do not carry a bound root and often need multiple authority, path,
|
|
284
284
|
and policy knobs.
|
|
285
285
|
|
|
286
|
-
Sidecar locks fail closed on stale holders
|
|
286
|
+
Sidecar locks fail closed on stale holders. The legacy `remove-if-unchanged`
|
|
287
|
+
option remains accepted for source compatibility, but it no longer unlinks a
|
|
288
|
+
third-party stale lock during acquisition; see the [file lock docs](docs/sidecar-lock.md).
|
|
287
289
|
|
|
288
290
|
Use `fileStore()` for cache/blob/media-style directories where callers
|
|
289
291
|
need safe relative paths, size limits, atomic replacement, stream writes, and
|
package/dist/advanced.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createAsyncLock } from "./async-lock.js";
|
|
2
|
+
export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
|
|
2
3
|
export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, type UnsafeDeviceReadPathMatch, type UnsafeDeviceReadPathOptions, type UnsafeDeviceReadPathReason, } from "./device-path.js";
|
|
3
4
|
export { assertAbsolutePathInput, canonicalPathFromExistingAncestor, ensureAbsoluteDirectory, findExistingAncestor, resolveAbsolutePathForRead, resolveAbsolutePathForWrite, type AbsolutePathSymlinkPolicy, type EnsureAbsoluteDirectoryOptions, type EnsureAbsoluteDirectoryResult, type ResolvedAbsolutePath, type ResolvedWritableAbsolutePath, } from "./absolute-path.js";
|
|
4
5
|
export { sameFileIdentity, type FileIdentityStat } from "./file-identity.js";
|
package/dist/advanced.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../src/advanced.ts"],"names":[],"mappings":"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"}
|
package/dist/advanced.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// public subpaths; prefer root/json/store/temp/archive unless you are building a
|
|
3
3
|
// higher-level primitive.
|
|
4
4
|
export { createAsyncLock } from "./async-lock.js";
|
|
5
|
+
export { readFileDescriptorBounded, readFileDescriptorBoundedSync, readFileHandleBounded, } from "./bounded-read.js";
|
|
5
6
|
export { assertNoUnsafeDeviceReadPath, isUnsafeDeviceReadPath, matchUnsafeDeviceReadPath, } from "./device-path.js";
|
|
6
7
|
export { assertAbsolutePathInput, canonicalPathFromExistingAncestor, ensureAbsoluteDirectory, findExistingAncestor, resolveAbsolutePathForRead, resolveAbsolutePathForWrite, } from "./absolute-path.js";
|
|
7
8
|
export { sameFileIdentity } from "./file-identity.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-limits.d.ts","sourceRoot":"","sources":["../src/archive-limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,6BAA6B,QAAoB,CAAC;AAC/D,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,eAAO,MAAM,2BAA2B,QAAoB,CAAC;AAC7D,eAAO,MAAM,uBAAuB,QAAoB,CAAC;AAEzD,eAAO,MAAM,wBAAwB
|
|
1
|
+
{"version":3,"file":"archive-limits.d.ts","sourceRoot":"","sources":["../src/archive-limits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,MAAM,oBAAoB,GAAG;IACjC;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,6BAA6B,QAAoB,CAAC;AAC/D,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAC1C,eAAO,MAAM,2BAA2B,QAAoB,CAAC;AAC7D,eAAO,MAAM,uBAAuB,QAAoB,CAAC;AAEzD,eAAO,MAAM,wBAAwB;aACnC,0BAA0B,EAAE,4BAA4B;aACxD,yBAAyB,EAAE,mCAAmC;aAC9D,kCAAkC,EAAE,4CAA4C;aAChF,4BAA4B,EAAE,sCAAsC;CAC5D,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAC/B,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,OAAO,wBAAwB,CAAC,CAAC;AAU3E,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IAErC,YAAY,IAAI,EAAE,qBAAqB,EAItC;CACF;AAED,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAAC;AAU1E,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,oBAAoB,GAC5B,4BAA4B,CAQ9B;AAED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,4BAA4B,QAKrC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,4BAA4B,GAAG;IAC7E,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAiCA;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,GAAG,SAAS,CAYZ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"archive-staging.d.ts","sourceRoot":"","sources":["../src/archive-staging.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,wBAAwB,GAChC,2BAA2B,GAC3B,qBAAqB,GACrB,+BAA+B,CAAC;AAEpC,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,IAAI,EAAE,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"archive-staging.d.ts","sourceRoot":"","sources":["../src/archive-staging.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,wBAAwB,GAChC,2BAA2B,GAC3B,qBAAqB,GACrB,+BAA+B,CAAC;AAEpC,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,IAAI,EAAE,wBAAwB,CAAC;IAE/B,YAAY,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAIlF;CACF;AAkCD,wBAAsB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BnF;AA6CD,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmChB;AAyHD,wBAAsB,4BAA4B,CAAC,CAAC,EAAE,MAAM,EAAE;IAC5D,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CACzC,GAAG,OAAO,CAAC,CAAC,CAAC,CA6Bb;AAED,wBAAsB,iCAAiC,CAAC,MAAM,EAAE;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFhB;AAED,wBAAgB,kCAAkC,CAAC,YAAY,EAAE,MAAM,GAAG,oBAAoB,CAE7F"}
|
package/dist/async-lock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"async-lock.d.ts","sourceRoot":"","sources":["../src/async-lock.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,KAEE,CAAC,
|
|
1
|
+
{"version":3,"file":"async-lock.d.ts","sourceRoot":"","sources":["../src/async-lock.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,KAEE,CAAC,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC,CAapE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FileHandle } from "node:fs/promises";
|
|
2
|
+
type ReadableFileHandle = Pick<FileHandle, "read">;
|
|
3
|
+
/**
|
|
4
|
+
* Reads from the handle's current offset without closing it. A bounded read
|
|
5
|
+
* consumes at most maxBytes + 1 bytes so growth after an earlier stat cannot
|
|
6
|
+
* force an unbounded allocation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function readFileHandleBounded(handle: ReadableFileHandle, maxBytes: number): Promise<Buffer>;
|
|
9
|
+
/** Async bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
10
|
+
export declare function readFileDescriptorBounded(fd: number, maxBytes: number): Promise<Buffer>;
|
|
11
|
+
/** Sync bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
12
|
+
export declare function readFileDescriptorBoundedSync(fd: number, maxBytes: number): Buffer;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=bounded-read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-read.d.ts","sourceRoot":"","sources":["../src/bounded-read.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,KAAK,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AA4DnD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAIjB;AAcD,oFAAoF;AACpF,wBAAsB,yBAAyB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7F;AAED,mFAAmF;AACnF,wBAAgB,6BAA6B,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAalF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { FsSafeError } from "./errors.js";
|
|
3
|
+
const READ_CHUNK_BYTES = 64 * 1024;
|
|
4
|
+
function assertMaxBytes(maxBytes) {
|
|
5
|
+
if (maxBytes === Number.POSITIVE_INFINITY) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {
|
|
9
|
+
throw new RangeError("maxBytes must be a non-negative safe integer or Infinity");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function createScratchBuffer(maxBytes) {
|
|
13
|
+
const initialReadBytes = Number.isFinite(maxBytes)
|
|
14
|
+
? Math.min(READ_CHUNK_BYTES, maxBytes + 1)
|
|
15
|
+
: READ_CHUNK_BYTES;
|
|
16
|
+
return Buffer.allocUnsafe(Math.max(1, initialReadBytes));
|
|
17
|
+
}
|
|
18
|
+
function nextReadLength(total, maxBytes, capacity) {
|
|
19
|
+
return Number.isFinite(maxBytes)
|
|
20
|
+
? Math.min(capacity, maxBytes - total + 1)
|
|
21
|
+
: capacity;
|
|
22
|
+
}
|
|
23
|
+
function appendChunk(params) {
|
|
24
|
+
const total = params.total + params.bytesRead;
|
|
25
|
+
if (total > params.maxBytes) {
|
|
26
|
+
throw new FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got at least ${total})`);
|
|
27
|
+
}
|
|
28
|
+
params.chunks.push(Buffer.from(params.scratch.subarray(0, params.bytesRead)));
|
|
29
|
+
return total;
|
|
30
|
+
}
|
|
31
|
+
async function readBoundedAsync(maxBytes, readChunk) {
|
|
32
|
+
assertMaxBytes(maxBytes);
|
|
33
|
+
const chunks = [];
|
|
34
|
+
const scratch = createScratchBuffer(maxBytes);
|
|
35
|
+
let total = 0;
|
|
36
|
+
while (true) {
|
|
37
|
+
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
38
|
+
const bytesRead = await readChunk(scratch, length);
|
|
39
|
+
if (bytesRead === 0) {
|
|
40
|
+
return Buffer.concat(chunks, total);
|
|
41
|
+
}
|
|
42
|
+
total = appendChunk({ chunks, scratch, bytesRead, total, maxBytes });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Reads from the handle's current offset without closing it. A bounded read
|
|
47
|
+
* consumes at most maxBytes + 1 bytes so growth after an earlier stat cannot
|
|
48
|
+
* force an unbounded allocation.
|
|
49
|
+
*/
|
|
50
|
+
export async function readFileHandleBounded(handle, maxBytes) {
|
|
51
|
+
return await readBoundedAsync(maxBytes, async (scratch, length) => {
|
|
52
|
+
return (await handle.read(scratch, 0, length, null)).bytesRead;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function readDescriptorChunk(fd, scratch, length) {
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
fs.read(fd, scratch, 0, length, null, (error, bytesRead) => {
|
|
58
|
+
if (error) {
|
|
59
|
+
reject(error);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
resolve(bytesRead);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/** Async bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
67
|
+
export async function readFileDescriptorBounded(fd, maxBytes) {
|
|
68
|
+
return await readBoundedAsync(maxBytes, async (scratch, length) => {
|
|
69
|
+
return await readDescriptorChunk(fd, scratch, length);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/** Sync bounded read from a numeric descriptor. The caller owns the descriptor. */
|
|
73
|
+
export function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
74
|
+
assertMaxBytes(maxBytes);
|
|
75
|
+
const chunks = [];
|
|
76
|
+
const scratch = createScratchBuffer(maxBytes);
|
|
77
|
+
let total = 0;
|
|
78
|
+
while (true) {
|
|
79
|
+
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
80
|
+
const bytesRead = fs.readSync(fd, scratch, 0, length, null);
|
|
81
|
+
if (bytesRead === 0) {
|
|
82
|
+
return Buffer.concat(chunks, total);
|
|
83
|
+
}
|
|
84
|
+
total = appendChunk({ chunks, scratch, bytesRead, total, maxBytes });
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,UAAU,GACV,eAAe,GACf,oBAAoB,GACpB,cAAc,GACd,sBAAsB,GACtB,WAAW,GACX,UAAU,GACV,WAAW,GACX,WAAW,GACX,eAAe,GACf,mBAAmB,GACnB,YAAY,GACZ,eAAe,GACf,uBAAuB,GACvB,SAAS,GACT,SAAS,GACT,WAAW,GACX,sBAAsB,CAAC;AAE3B,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,CAAC;AAU3D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,mBAAmB,CAEhF;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,aAAa,GACb,aAAa,GACb,UAAU,GACV,eAAe,GACf,oBAAoB,GACpB,cAAc,GACd,sBAAsB,GACtB,WAAW,GACX,UAAU,GACV,WAAW,GACX,WAAW,GACX,eAAe,GACf,mBAAmB,GACnB,YAAY,GACZ,eAAe,GACf,uBAAuB,GACvB,SAAS,GACT,SAAS,GACT,WAAW,GACX,sBAAsB,CAAC;AAE3B,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,aAAa,CAAC;AAU3D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,mBAAmB,CAEhF;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IAEvC,YAAY,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAO,EAKpF;CACF"}
|
package/dist/file-store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"file-store.d.ts","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":"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"}
|
package/dist/file-store.js
CHANGED
|
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import syncFs from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { readFileDescriptorBoundedSync } from "./bounded-read.js";
|
|
5
6
|
import { createSyncDirectoryGuard } from "./directory-guard.js";
|
|
6
7
|
import { FsSafeError } from "./errors.js";
|
|
7
8
|
import { pruneExpiredStoreEntries, } from "./file-store-prune.js";
|
|
@@ -411,8 +412,10 @@ export function fileStoreSync(options) {
|
|
|
411
412
|
}
|
|
412
413
|
try {
|
|
413
414
|
assertMaxBytes(opened.stat.size, readOptions?.maxBytes ?? maxBytes);
|
|
414
|
-
const
|
|
415
|
-
|
|
415
|
+
const limit = readOptions?.maxBytes ?? maxBytes;
|
|
416
|
+
const raw = limit === undefined
|
|
417
|
+
? syncFs.readFileSync(opened.fd, "utf8")
|
|
418
|
+
: readFileDescriptorBoundedSync(opened.fd, limit).toString("utf8");
|
|
416
419
|
return raw;
|
|
417
420
|
}
|
|
418
421
|
finally {
|
package/dist/json.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
2
|
import { type RootFileOpenFailure } from "./root-file.js";
|
|
3
3
|
import { type WriteTextAtomicOptions } from "./text-atomic.js";
|
|
4
|
-
export
|
|
4
|
+
export type ReadJsonOptions = {
|
|
5
|
+
maxBytes?: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function tryReadJsonSync<T = unknown>(pathname: string, options?: ReadJsonOptions): T | null;
|
|
5
8
|
export declare function writeJsonSync(pathname: string, data: unknown): void;
|
|
6
9
|
export declare class JsonFileReadError extends Error {
|
|
7
10
|
readonly filePath: string;
|
|
@@ -38,10 +41,10 @@ export type ReadRootJsonSyncOptions = Omit<ReadRootStructuredFileSyncOptions<unk
|
|
|
38
41
|
export declare function readRootStructuredFileSync<T>(options: ReadRootStructuredFileSyncOptions<T>): RootStructuredFileReadResult<T>;
|
|
39
42
|
export declare function readRootJsonSync<T = unknown>(options: ReadRootJsonSyncOptions): RootStructuredFileReadResult<T>;
|
|
40
43
|
export declare function readRootJsonObjectSync(options: ReadRootJsonSyncOptions): RootStructuredFileReadResult<Record<string, unknown>>;
|
|
41
|
-
export declare function tryReadJson<T>(filePath: string): Promise<T | null>;
|
|
42
|
-
export declare function readJson<T>(filePath: string): Promise<T>;
|
|
43
|
-
export declare function readJsonIfExists<T>(filePath: string): Promise<T | null>;
|
|
44
|
-
export declare function readJsonSync<T = unknown>(filePath: string): T;
|
|
44
|
+
export declare function tryReadJson<T>(filePath: string, options?: ReadJsonOptions): Promise<T | null>;
|
|
45
|
+
export declare function readJson<T>(filePath: string, options?: ReadJsonOptions): Promise<T>;
|
|
46
|
+
export declare function readJsonIfExists<T>(filePath: string, options?: ReadJsonOptions): Promise<T | null>;
|
|
47
|
+
export declare function readJsonSync<T = unknown>(filePath: string, options?: ReadJsonOptions): T;
|
|
45
48
|
export type WriteJsonOptions = Pick<WriteTextAtomicOptions, "dirMode" | "durable" | "mode" | "trailingNewline">;
|
|
46
49
|
export declare function writeJson(filePath: string, value: unknown, options?: WriteJsonOptions): Promise<void>;
|
|
47
50
|
//# sourceMappingURL=json.d.ts.map
|
package/dist/json.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"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"}
|
package/dist/json.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import fsSync from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { readFileDescriptorBoundedSync } from "./bounded-read.js";
|
|
4
5
|
import { FsSafeError } from "./errors.js";
|
|
5
6
|
import { stringifyJsonDocument } from "./json-stringify.js";
|
|
6
7
|
import { readRegularFile, readRegularFileSync, statRegularFile } from "./regular-file.js";
|
|
@@ -25,7 +26,7 @@ async function readRegularFileWithRetry(filePath, options = {}) {
|
|
|
25
26
|
let lastErr;
|
|
26
27
|
for (let attempt = 0; attempt < READ_RETRY_MAX_ATTEMPTS; attempt++) {
|
|
27
28
|
try {
|
|
28
|
-
return (await readRegularFile({ filePath })).buffer;
|
|
29
|
+
return (await readRegularFile({ filePath, maxBytes: options.maxBytes })).buffer;
|
|
29
30
|
}
|
|
30
31
|
catch (err) {
|
|
31
32
|
lastErr = err;
|
|
@@ -37,12 +38,15 @@ async function readRegularFileWithRetry(filePath, options = {}) {
|
|
|
37
38
|
}
|
|
38
39
|
throw lastErr;
|
|
39
40
|
}
|
|
40
|
-
async function readRegularFileIfExistsWithRetry(filePath) {
|
|
41
|
+
async function readRegularFileIfExistsWithRetry(filePath, options = {}) {
|
|
41
42
|
const initial = await statRegularFile(filePath);
|
|
42
43
|
if (initial.missing) {
|
|
43
44
|
return null;
|
|
44
45
|
}
|
|
45
|
-
return await readRegularFileWithRetry(filePath, {
|
|
46
|
+
return await readRegularFileWithRetry(filePath, {
|
|
47
|
+
maxBytes: options.maxBytes,
|
|
48
|
+
retryOpenRaceErrors: true,
|
|
49
|
+
});
|
|
46
50
|
}
|
|
47
51
|
const JSON_FILE_MODE = 0o600;
|
|
48
52
|
const JSON_DIR_MODE = 0o700;
|
|
@@ -132,9 +136,12 @@ function writeTempJsonFile(pathname, payload) {
|
|
|
132
136
|
fsSync.closeSync(fd);
|
|
133
137
|
}
|
|
134
138
|
}
|
|
135
|
-
export function tryReadJsonSync(pathname) {
|
|
139
|
+
export function tryReadJsonSync(pathname, options = {}) {
|
|
136
140
|
try {
|
|
137
|
-
const raw = readRegularFileSync({
|
|
141
|
+
const raw = readRegularFileSync({
|
|
142
|
+
filePath: pathname,
|
|
143
|
+
maxBytes: options.maxBytes,
|
|
144
|
+
}).buffer.toString("utf8");
|
|
138
145
|
return JSON.parse(raw);
|
|
139
146
|
}
|
|
140
147
|
catch {
|
|
@@ -196,7 +203,10 @@ export function readRootStructuredFileSync(options) {
|
|
|
196
203
|
return { ok: false, reason: "open", failure: opened };
|
|
197
204
|
}
|
|
198
205
|
try {
|
|
199
|
-
const
|
|
206
|
+
const raw = options.maxBytes === undefined
|
|
207
|
+
? fsSync.readFileSync(opened.fd, "utf8")
|
|
208
|
+
: readFileDescriptorBoundedSync(opened.fd, options.maxBytes).toString("utf8");
|
|
209
|
+
const parsed = options.parse(raw);
|
|
200
210
|
if (options.validate && !options.validate(parsed)) {
|
|
201
211
|
return {
|
|
202
212
|
ok: false,
|
|
@@ -237,9 +247,9 @@ export function readRootJsonObjectSync(options) {
|
|
|
237
247
|
invalidMessage: (relativePath) => `${relativePath} must contain a JSON object`,
|
|
238
248
|
});
|
|
239
249
|
}
|
|
240
|
-
export async function tryReadJson(filePath) {
|
|
250
|
+
export async function tryReadJson(filePath, options = {}) {
|
|
241
251
|
try {
|
|
242
|
-
const buffer = await readRegularFileIfExistsWithRetry(filePath);
|
|
252
|
+
const buffer = await readRegularFileIfExistsWithRetry(filePath, options);
|
|
243
253
|
if (buffer === null) {
|
|
244
254
|
return null;
|
|
245
255
|
}
|
|
@@ -250,10 +260,13 @@ export async function tryReadJson(filePath) {
|
|
|
250
260
|
return null;
|
|
251
261
|
}
|
|
252
262
|
}
|
|
253
|
-
export async function readJson(filePath) {
|
|
263
|
+
export async function readJson(filePath, options = {}) {
|
|
254
264
|
let raw;
|
|
255
265
|
try {
|
|
256
|
-
raw = (await readRegularFileWithRetry(filePath, {
|
|
266
|
+
raw = (await readRegularFileWithRetry(filePath, {
|
|
267
|
+
maxBytes: options.maxBytes,
|
|
268
|
+
retryOpenRaceErrors: true,
|
|
269
|
+
})).toString("utf8");
|
|
257
270
|
}
|
|
258
271
|
catch (err) {
|
|
259
272
|
throw new JsonFileReadError(filePath, "read", err);
|
|
@@ -265,10 +278,10 @@ export async function readJson(filePath) {
|
|
|
265
278
|
throw new JsonFileReadError(filePath, "parse", err);
|
|
266
279
|
}
|
|
267
280
|
}
|
|
268
|
-
export async function readJsonIfExists(filePath) {
|
|
281
|
+
export async function readJsonIfExists(filePath, options = {}) {
|
|
269
282
|
let raw;
|
|
270
283
|
try {
|
|
271
|
-
const buffer = await readRegularFileIfExistsWithRetry(filePath);
|
|
284
|
+
const buffer = await readRegularFileIfExistsWithRetry(filePath, options);
|
|
272
285
|
if (buffer === null) {
|
|
273
286
|
return null;
|
|
274
287
|
}
|
|
@@ -287,10 +300,10 @@ export async function readJsonIfExists(filePath) {
|
|
|
287
300
|
throw new JsonFileReadError(filePath, "parse", err);
|
|
288
301
|
}
|
|
289
302
|
}
|
|
290
|
-
export function readJsonSync(filePath) {
|
|
303
|
+
export function readJsonSync(filePath, options = {}) {
|
|
291
304
|
let raw;
|
|
292
305
|
try {
|
|
293
|
-
raw = readRegularFileSync({ filePath }).buffer.toString("utf8");
|
|
306
|
+
raw = readRegularFileSync({ filePath, maxBytes: options.maxBytes }).buffer.toString("utf8");
|
|
294
307
|
}
|
|
295
308
|
catch (err) {
|
|
296
309
|
throw new JsonFileReadError(filePath, "read", err);
|
package/dist/pinned-python.js
CHANGED
|
@@ -5,15 +5,11 @@ import { getFsSafePythonConfig } from "./pinned-python-config.js";
|
|
|
5
5
|
const PINNED_PYTHON_WORKER_SOURCE = String.raw `
|
|
6
6
|
import base64, errno, json, os, secrets, stat, sys
|
|
7
7
|
DIR_FLAGS = os.O_RDONLY
|
|
8
|
-
if hasattr(os, "O_DIRECTORY"):
|
|
9
|
-
|
|
10
|
-
if hasattr(os, "O_NOFOLLOW"):
|
|
11
|
-
DIR_FLAGS |= os.O_NOFOLLOW
|
|
8
|
+
if hasattr(os, "O_DIRECTORY"): DIR_FLAGS |= os.O_DIRECTORY
|
|
9
|
+
if hasattr(os, "O_NOFOLLOW"): DIR_FLAGS |= os.O_NOFOLLOW
|
|
12
10
|
READ_FLAGS = os.O_RDONLY
|
|
13
|
-
if hasattr(os, "O_NONBLOCK"):
|
|
14
|
-
|
|
15
|
-
if hasattr(os, "O_NOFOLLOW"):
|
|
16
|
-
READ_FLAGS |= os.O_NOFOLLOW
|
|
11
|
+
if hasattr(os, "O_NONBLOCK"): READ_FLAGS |= os.O_NONBLOCK
|
|
12
|
+
if hasattr(os, "O_NOFOLLOW"): READ_FLAGS |= os.O_NOFOLLOW
|
|
17
13
|
WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL
|
|
18
14
|
if hasattr(os, "O_NOFOLLOW"):
|
|
19
15
|
WRITE_FLAGS |= os.O_NOFOLLOW
|
|
@@ -93,6 +89,10 @@ def write_all(fd, data):
|
|
|
93
89
|
if written <= 0:
|
|
94
90
|
raise OSError(errno.EIO, "short write")
|
|
95
91
|
view = view[written:]
|
|
92
|
+
def fsync_best_effort(fd):
|
|
93
|
+
try: os.fsync(fd)
|
|
94
|
+
except OSError as error:
|
|
95
|
+
if error.errno != errno.EPERM: raise
|
|
96
96
|
def link_unsupported(exc):
|
|
97
97
|
unsupported = (errno.EPERM, errno.EOPNOTSUPP, getattr(errno, "ENOTSUP", errno.EOPNOTSUPP))
|
|
98
98
|
return getattr(exc, "errno", None) in unsupported
|
|
@@ -298,13 +298,13 @@ def write_path(root_fd, payload):
|
|
|
298
298
|
temp_name, temp_fd = create_temp_file(parent_fd, basename, mode)
|
|
299
299
|
os.fchmod(temp_fd, mode)
|
|
300
300
|
write_all(temp_fd, data)
|
|
301
|
-
|
|
301
|
+
fsync_best_effort(temp_fd)
|
|
302
302
|
temp_stat = os.fstat(temp_fd)
|
|
303
303
|
os.close(temp_fd)
|
|
304
304
|
temp_fd = None
|
|
305
305
|
result_stat = commit_temp_file(parent_fd, temp_name, basename, overwrite, mode, temp_stat)
|
|
306
306
|
temp_name = None
|
|
307
|
-
|
|
307
|
+
fsync_best_effort(parent_fd)
|
|
308
308
|
return {"dev": result_stat.st_dev, "ino": result_stat.st_ino}
|
|
309
309
|
finally:
|
|
310
310
|
if temp_fd is not None:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pinned-write.d.ts","sourceRoot":"","sources":["../src/pinned-write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAa3D,KAAK,gBAAgB,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"pinned-write.d.ts","sourceRoot":"","sources":["../src/pinned-write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAa3D,KAAK,gBAAgB,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAuFzC,KAAK,4BAA4B,GAAG,OAAO,GAAG,gBAAgB,CAAC;AAE/D,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,0BAA0B,CAAC;AAEzE,KAAK,iBAAiB,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,wBAAwB,CAAC,EAAE,4BAA4B,CAAC;CACzD,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkD/F;AAED,wBAAsB,8BAA8B,CAClD,MAAM,EAAE,iBAAiB,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC,GACA,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAED,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,gBAAgB,CAAC;IACjC,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqB5B"}
|
package/dist/pinned-write.js
CHANGED
|
@@ -31,6 +31,16 @@ function assertWithinMaxBytes(bytes, maxBytes) {
|
|
|
31
31
|
throw new FsSafeError("too-large", `file exceeds limit of ${maxBytes} bytes (got at least ${bytes})`);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
async function syncFileBestEffort(handle) {
|
|
35
|
+
try {
|
|
36
|
+
await handle.sync();
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error?.code !== "EPERM") {
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
34
44
|
async function writeStreamToHandle(stream, handle, maxBytes) {
|
|
35
45
|
let bytes = 0;
|
|
36
46
|
for await (const chunk of stream) {
|
|
@@ -192,7 +202,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
192
202
|
else {
|
|
193
203
|
await writeStreamToHandle(params.input.stream, handle, params.maxBytes);
|
|
194
204
|
}
|
|
195
|
-
await handle
|
|
205
|
+
await syncFileBestEffort(handle);
|
|
196
206
|
const stat = await handle.stat();
|
|
197
207
|
await handle.close().catch(() => undefined);
|
|
198
208
|
await syncDirectoryBestEffort(parentPath);
|
|
@@ -237,7 +247,7 @@ async function runPinnedWriteFallback(params) {
|
|
|
237
247
|
throw new FsSafeError("path-mismatch", "fallback temp path changed during write");
|
|
238
248
|
}
|
|
239
249
|
const expectedTempStat = tempStat;
|
|
240
|
-
await handle
|
|
250
|
+
await syncFileBestEffort(handle);
|
|
241
251
|
await handle.close().catch(() => undefined);
|
|
242
252
|
handle = undefined;
|
|
243
253
|
await withAsyncDirectoryGuards([parentGuard], async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-opened-file.d.ts","sourceRoot":"","sources":["../src/read-opened-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"read-opened-file.d.ts","sourceRoot":"","sources":["../src/read-opened-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,MAAM,EAAE;IACjD,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,UAAU,CAAC,CAgBtB"}
|
package/dist/read-opened-file.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { readFileHandleBounded } from "./bounded-read.js";
|
|
1
2
|
import { FsSafeError } from "./errors.js";
|
|
2
3
|
export async function readOpenedFileSafely(params) {
|
|
3
4
|
if (params.maxBytes !== undefined && params.opened.stat.size > params.maxBytes) {
|
|
4
5
|
throw new FsSafeError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
|
|
5
6
|
}
|
|
6
|
-
const buffer =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
7
|
+
const buffer = params.maxBytes === undefined
|
|
8
|
+
? await params.opened.handle.readFile()
|
|
9
|
+
: await readFileHandleBounded(params.opened.handle, params.maxBytes);
|
|
10
10
|
return {
|
|
11
11
|
buffer,
|
|
12
12
|
realPath: params.opened.realPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,MAAM,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"regular-file.d.ts","sourceRoot":"","sources":["../src/regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,MAAM,MAAM,SAAS,CAAC;AAW7B,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAExF,KAAK,8BAA8B,GAAG,IAAI,CACxC,OAAO,MAAM,CAAC,SAAS,EACvB,UAAU,GAAG,SAAS,GAAG,UAAU,CACpC,GACC,OAAO,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC;AAEvD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,8BAAiD,GAC3D,MAAM,CAQR;AAWD,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CActF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,CAc3E;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAuD3C;AA+CD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IACpF,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,KAAK,CAAC;CACb,CAwBA;AAmBD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDxF;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CA2D7E"}
|