@effect-vfs/core 0.4.0 → 0.6.0
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 +39 -32
- package/dist/BytePath.d.ts +114 -4
- package/dist/BytePath.d.ts.map +1 -1
- package/dist/BytePath.js +155 -0
- package/dist/Caller.d.ts +391 -0
- package/dist/Caller.d.ts.map +1 -0
- package/dist/Caller.js +199 -0
- package/dist/FileHandle.d.ts +50 -0
- package/dist/FileHandle.d.ts.map +1 -0
- package/dist/FileHandle.js +28 -0
- package/dist/Fixture.d.ts +155 -0
- package/dist/Fixture.d.ts.map +1 -0
- package/dist/Fixture.js +65 -0
- package/dist/LiveVolume.d.ts +15 -22
- package/dist/LiveVolume.d.ts.map +1 -1
- package/dist/LiveVolume.js +19 -15
- package/dist/Metadata.d.ts +186 -0
- package/dist/Metadata.d.ts.map +1 -0
- package/dist/Metadata.js +125 -0
- package/dist/Snapshot.d.ts +31 -53
- package/dist/Snapshot.d.ts.map +1 -1
- package/dist/Snapshot.js +26 -49
- package/dist/SnapshotDelta.d.ts +24 -39
- package/dist/SnapshotDelta.d.ts.map +1 -1
- package/dist/SnapshotDelta.js +14 -35
- package/dist/Target.d.ts +225 -0
- package/dist/Target.d.ts.map +1 -0
- package/dist/Target.js +92 -0
- package/dist/Testing.d.ts +128 -0
- package/dist/Testing.d.ts.map +1 -0
- package/dist/Testing.js +111 -0
- package/dist/VfsError.d.ts +199 -0
- package/dist/VfsError.d.ts.map +1 -0
- package/dist/VfsError.js +164 -0
- package/dist/VirtualFileSystem.d.ts +628 -347
- package/dist/VirtualFileSystem.d.ts.map +1 -1
- package/dist/VirtualFileSystem.js +450 -117
- package/dist/Volume.d.ts +211 -0
- package/dist/Volume.d.ts.map +1 -0
- package/dist/Volume.js +172 -0
- package/dist/Watch.d.ts +68 -0
- package/dist/Watch.d.ts.map +1 -0
- package/dist/Watch.js +46 -0
- package/dist/index.d.ts +56 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -1
- package/dist/internal/budget.d.ts +90 -0
- package/dist/internal/budget.d.ts.map +1 -0
- package/dist/internal/budget.js +70 -0
- package/dist/internal/bytePath.d.ts +2 -0
- package/dist/internal/bytePath.d.ts.map +1 -1
- package/dist/internal/bytePath.js +3 -2
- package/dist/internal/bytes.d.ts +3 -0
- package/dist/internal/bytes.d.ts.map +1 -1
- package/dist/internal/bytes.js +4 -2
- package/dist/internal/canonicalBase64.d.ts +1 -4
- package/dist/internal/canonicalBase64.d.ts.map +1 -1
- package/dist/internal/canonicalBase64.js +9 -13
- package/dist/internal/errors.d.ts +54 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +91 -0
- package/dist/internal/{virtualFileSystem/fixture.d.ts → fixture.d.ts} +8 -8
- package/dist/internal/fixture.d.ts.map +1 -0
- package/dist/internal/fixture.js +133 -0
- package/dist/internal/hex128.d.ts +12 -0
- package/dist/internal/hex128.d.ts.map +1 -0
- package/dist/internal/hex128.js +7 -0
- package/dist/internal/hmac.d.ts +5 -0
- package/dist/internal/hmac.d.ts.map +1 -0
- package/dist/internal/hmac.js +150 -0
- package/dist/internal/image.d.ts +14 -117
- package/dist/internal/image.d.ts.map +1 -1
- package/dist/internal/image.js +137 -167
- package/dist/internal/inodeTable.d.ts +20 -0
- package/dist/internal/inodeTable.d.ts.map +1 -0
- package/dist/internal/inodeTable.js +48 -0
- package/dist/internal/lines.d.ts +36 -0
- package/dist/internal/lines.d.ts.map +1 -0
- package/dist/internal/lines.js +115 -0
- package/dist/internal/liveImage.d.ts +19 -278
- package/dist/internal/liveImage.d.ts.map +1 -1
- package/dist/internal/liveImage.js +75 -166
- package/dist/internal/merkle.d.ts +45 -0
- package/dist/internal/merkle.d.ts.map +1 -0
- package/dist/internal/merkle.js +179 -0
- package/dist/internal/metadata.d.ts +2 -13
- package/dist/internal/metadata.d.ts.map +1 -1
- package/dist/internal/metadata.js +5 -15
- package/dist/internal/{virtualFileSystem/overlayDiff.d.ts → overlayDiff.d.ts} +3 -3
- package/dist/internal/overlayDiff.d.ts.map +1 -0
- package/dist/internal/{virtualFileSystem/overlayDiff.js → overlayDiff.js} +1 -4
- package/dist/internal/{virtualFileSystem/path.d.ts → path.d.ts} +19 -7
- package/dist/internal/path.d.ts.map +1 -0
- package/dist/internal/{virtualFileSystem/path.js → path.js} +39 -25
- package/dist/internal/snapshotDelta.d.ts +61 -60
- package/dist/internal/snapshotDelta.d.ts.map +1 -1
- package/dist/internal/snapshotDelta.js +612 -504
- package/dist/internal/snapshotDeltaModel.d.ts.map +1 -1
- package/dist/internal/snapshotDeltaModel.js +0 -1
- package/dist/internal/stagedState.d.ts +18 -0
- package/dist/internal/stagedState.d.ts.map +1 -0
- package/dist/internal/stagedState.js +18 -0
- package/dist/internal/testSeams.d.ts +17 -0
- package/dist/internal/testSeams.d.ts.map +1 -0
- package/dist/internal/testSeams.js +20 -0
- package/dist/internal/tree.d.ts +225 -0
- package/dist/internal/tree.d.ts.map +1 -0
- package/dist/internal/tree.js +385 -0
- package/dist/internal/turnstile.d.ts +8 -0
- package/dist/internal/turnstile.d.ts.map +1 -0
- package/dist/internal/turnstile.js +43 -0
- package/dist/internal/virtualFileSystem.d.ts +41 -491
- package/dist/internal/virtualFileSystem.d.ts.map +1 -1
- package/dist/internal/virtualFileSystem.js +2118 -2471
- package/dist/internal/volumeState.d.ts +110 -0
- package/dist/internal/volumeState.d.ts.map +1 -0
- package/dist/internal/volumeState.js +204 -0
- package/dist/internal/watchHub.d.ts +25 -0
- package/dist/internal/watchHub.d.ts.map +1 -0
- package/dist/internal/watchHub.js +68 -0
- package/package.json +53 -9
- package/dist/VirtualFileSystemError.d.ts +0 -54
- package/dist/VirtualFileSystemError.d.ts.map +0 -1
- package/dist/VirtualFileSystemError.js +0 -49
- package/dist/internal/virtualFileSystem/errors.d.ts +0 -12
- package/dist/internal/virtualFileSystem/errors.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/errors.js +0 -47
- package/dist/internal/virtualFileSystem/fixture.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/fixture.js +0 -150
- package/dist/internal/virtualFileSystem/overlayContent.d.ts +0 -15
- package/dist/internal/virtualFileSystem/overlayContent.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/overlayContent.js +0 -29
- package/dist/internal/virtualFileSystem/overlayDiff.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/path.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/stagedState.d.ts +0 -22
- package/dist/internal/virtualFileSystem/stagedState.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/stagedState.js +0 -62
- package/dist/internal/virtualFileSystem/testHooks.d.ts +0 -20
- package/dist/internal/virtualFileSystem/testHooks.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/testHooks.js +0 -23
- package/dist/internal/virtualFileSystem/watchHub.d.ts +0 -16
- package/dist/internal/virtualFileSystem/watchHub.d.ts.map +0 -1
- package/dist/internal/virtualFileSystem/watchHub.js +0 -54
package/dist/Metadata.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata schemas for virtual filesystem objects: timestamps, permission modes,
|
|
3
|
+
* the metadata record every observation returns, and the owner and time updates
|
|
4
|
+
* that mutations accept.
|
|
5
|
+
*
|
|
6
|
+
* @since 0.6.0
|
|
7
|
+
*/
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
9
|
+
const MAX_TIMESTAMP = 10n ** 128n - 1n;
|
|
10
|
+
/**
|
|
11
|
+
* Schema for a timestamp in nanoseconds since the Unix epoch. Values stay
|
|
12
|
+
* within 128 decimal digits so they round-trip through snapshot encodings.
|
|
13
|
+
*
|
|
14
|
+
* @category schemas
|
|
15
|
+
* @since 0.6.0
|
|
16
|
+
*/
|
|
17
|
+
export const Timestamp = Schema.BigInt.check(Schema.isGreaterThanOrEqualToBigInt(-MAX_TIMESTAMP), Schema.isLessThanOrEqualToBigInt(MAX_TIMESTAMP));
|
|
18
|
+
/**
|
|
19
|
+
* Schema for a POSIX permission mode: the permission, setuid, setgid and sticky
|
|
20
|
+
* bits without any file-type bits.
|
|
21
|
+
*
|
|
22
|
+
* @category schemas
|
|
23
|
+
* @since 0.6.0
|
|
24
|
+
*/
|
|
25
|
+
export const Mode = Schema.Natural.check(Schema.isLessThanOrEqualTo(0o7777));
|
|
26
|
+
/**
|
|
27
|
+
* Schema for the metadata of a filesystem object.
|
|
28
|
+
*
|
|
29
|
+
* @category schemas
|
|
30
|
+
* @since 0.6.0
|
|
31
|
+
*/
|
|
32
|
+
export const Metadata = Schema.Struct({
|
|
33
|
+
kind: Schema.Literals(["directory", "file", "symlink"]),
|
|
34
|
+
ino: Schema.BigInt,
|
|
35
|
+
nlink: Schema.Natural,
|
|
36
|
+
size: Schema.BigInt,
|
|
37
|
+
uid: Schema.Natural,
|
|
38
|
+
gid: Schema.Natural,
|
|
39
|
+
mode: Mode,
|
|
40
|
+
atimeNs: Timestamp,
|
|
41
|
+
mtimeNs: Timestamp,
|
|
42
|
+
ctimeNs: Timestamp,
|
|
43
|
+
birthtimeNs: Timestamp,
|
|
44
|
+
/** The object's revision, advanced by every committed change to it. */
|
|
45
|
+
revision: Schema.BigInt
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* Mask of the file-type bits in a POSIX `st_mode`.
|
|
49
|
+
*
|
|
50
|
+
* @category constants
|
|
51
|
+
* @since 0.6.0
|
|
52
|
+
*/
|
|
53
|
+
export const S_IFMT = 0o170000;
|
|
54
|
+
/**
|
|
55
|
+
* File-type bits of a regular file in a POSIX `st_mode`.
|
|
56
|
+
*
|
|
57
|
+
* @category constants
|
|
58
|
+
* @since 0.6.0
|
|
59
|
+
*/
|
|
60
|
+
export const S_IFREG = 0o100000;
|
|
61
|
+
/**
|
|
62
|
+
* File-type bits of a directory in a POSIX `st_mode`.
|
|
63
|
+
*
|
|
64
|
+
* @category constants
|
|
65
|
+
* @since 0.6.0
|
|
66
|
+
*/
|
|
67
|
+
export const S_IFDIR = 0o040000;
|
|
68
|
+
/**
|
|
69
|
+
* File-type bits of a symbolic link in a POSIX `st_mode`.
|
|
70
|
+
*
|
|
71
|
+
* @category constants
|
|
72
|
+
* @since 0.6.0
|
|
73
|
+
*/
|
|
74
|
+
export const S_IFLNK = 0o120000;
|
|
75
|
+
const FILE_TYPE_BITS = { directory: S_IFDIR, file: S_IFREG, symlink: S_IFLNK };
|
|
76
|
+
/**
|
|
77
|
+
* The POSIX `st_mode` of an object: the file-type bits of its `kind` joined
|
|
78
|
+
* with its permission `mode`. `mode` itself never carries type bits, so the
|
|
79
|
+
* kind has a single source.
|
|
80
|
+
*
|
|
81
|
+
* A volume has no device nodes, so a `stat` built from metadata reports `dev`
|
|
82
|
+
* and `rdev` as 0, and `(dev, ino)` identifies an object only within one volume.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { S_IFDIR, S_IFMT, typedMode } from "@effect-vfs/core/Metadata"
|
|
87
|
+
*
|
|
88
|
+
* const stMode = typedMode({ kind: "directory", mode: 0o755 })
|
|
89
|
+
*
|
|
90
|
+
* console.log(stMode.toString(8)) // "40755"
|
|
91
|
+
* console.log((stMode & S_IFMT) === S_IFDIR) // true
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @category getters
|
|
95
|
+
* @since 0.6.0
|
|
96
|
+
*/
|
|
97
|
+
export const typedMode = (metadata) => FILE_TYPE_BITS[metadata.kind] | metadata.mode;
|
|
98
|
+
/**
|
|
99
|
+
* Schema for an ownership update; an omitted field keeps its current value.
|
|
100
|
+
*
|
|
101
|
+
* @category schemas
|
|
102
|
+
* @since 0.6.0
|
|
103
|
+
*/
|
|
104
|
+
export const OwnerUpdate = Schema.Struct({
|
|
105
|
+
uid: Schema.optionalKey(Schema.Natural),
|
|
106
|
+
gid: Schema.optionalKey(Schema.Natural)
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* Schema for one timestamp update: the current time, no change, or an explicit value.
|
|
110
|
+
*
|
|
111
|
+
* @category schemas
|
|
112
|
+
* @since 0.6.0
|
|
113
|
+
*/
|
|
114
|
+
export const TimeUpdate = Schema.Union([
|
|
115
|
+
Schema.Struct({ kind: Schema.Literal("now") }),
|
|
116
|
+
Schema.Struct({ kind: Schema.Literal("omit") }),
|
|
117
|
+
Schema.Struct({ kind: Schema.Literal("value"), nanoseconds: Timestamp })
|
|
118
|
+
]);
|
|
119
|
+
/**
|
|
120
|
+
* Schema for the access and modification time updates a mutation applies together.
|
|
121
|
+
*
|
|
122
|
+
* @category schemas
|
|
123
|
+
* @since 0.6.0
|
|
124
|
+
*/
|
|
125
|
+
export const Times = Schema.Struct({ access: TimeUpdate, modification: TimeUpdate });
|
package/dist/Snapshot.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opaque virtual filesystem snapshots and their decoding limits.
|
|
3
|
+
*
|
|
4
|
+
* A snapshot is the immutable value of a volume at one committed state, so
|
|
5
|
+
* capturing one copies nothing. It holds the reachable namespace and metadata,
|
|
6
|
+
* but excludes callers, open handles, watch subscriptions, and unlinked
|
|
7
|
+
* content. Use the encoding, decoding, and restoration functions in
|
|
8
|
+
* `VirtualFileSystem`.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.1.0
|
|
11
|
+
*/
|
|
1
12
|
import * as Schema from "effect/Schema";
|
|
2
13
|
/**
|
|
3
14
|
* Type identifier for opaque filesystem snapshots.
|
|
@@ -22,68 +33,30 @@ export type SnapshotTypeId = typeof SnapshotTypeId;
|
|
|
22
33
|
export interface Snapshot {
|
|
23
34
|
readonly [SnapshotTypeId]: SnapshotTypeId;
|
|
24
35
|
}
|
|
25
|
-
declare const ImageError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
26
|
-
readonly _tag: "ImageError";
|
|
27
|
-
} & Readonly<A>;
|
|
28
36
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
34
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
35
|
-
* import { ByteSize, Effect } from "effect"
|
|
36
|
-
*
|
|
37
|
-
* // Decoding is a trust boundary. `code` says what went wrong and `field` says
|
|
38
|
-
* // which input or limit it was, so a caller can decline just the bad payload.
|
|
39
|
-
* const program = Effect.gen(function*() {
|
|
40
|
-
* const volume = yield* Vfs.make()
|
|
41
|
-
* const bytes = yield* Vfs.encodeSnapshot(yield* volume.snapshot)
|
|
42
|
-
*
|
|
43
|
-
* return yield* Vfs.decodeSnapshot(bytes, {
|
|
44
|
-
* maxEncodedBytes: ByteSize.bytes(16),
|
|
45
|
-
* maxRecords: 10_000,
|
|
46
|
-
* maxEntries: 10_000,
|
|
47
|
-
* maxDecodedBytes: ByteSize.megabytes(16)
|
|
48
|
-
* }).pipe(
|
|
49
|
-
* Effect.as("accepted"),
|
|
50
|
-
* Effect.catchTag("ImageError", (error) =>
|
|
51
|
-
* error.code === "LimitExceeded"
|
|
52
|
-
* ? Effect.succeed(`declined at ${error.field}`)
|
|
53
|
-
* : Effect.fail(error))
|
|
54
|
-
* )
|
|
55
|
-
* })
|
|
37
|
+
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
56
38
|
*
|
|
57
|
-
*
|
|
58
|
-
* // declined at encodedBytes
|
|
59
|
-
* ```
|
|
39
|
+
* **Details**
|
|
60
40
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
/** Machine-readable encoding, version, structure, or limit failure. */
|
|
66
|
-
readonly code: "InvalidEncoding" | "UnsupportedVersion" | "InvalidStructure" | "LimitExceeded";
|
|
67
|
-
/** Input area or configured limit associated with the failure, when available. */
|
|
68
|
-
readonly field?: string;
|
|
69
|
-
}> {
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
41
|
+
* A snapshot is encoded one line per node, and a decoder checks each line as
|
|
42
|
+
* it ends, so input that breaks a limit is refused before the decoder holds
|
|
43
|
+
* more than one line of it. `maxLineBytes` bounds that line; the other limits
|
|
44
|
+
* bound what the accepted lines add up to.
|
|
73
45
|
*
|
|
74
46
|
* @example
|
|
75
47
|
* ```ts
|
|
76
48
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
77
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
78
49
|
* import { ByteSize, Effect } from "effect"
|
|
79
50
|
*
|
|
80
|
-
* //
|
|
51
|
+
* // The four counts are required: each bounds a different resource. `maxEncodedBytes`
|
|
81
52
|
* // caps the wire payload before parsing; `maxDecodedBytes` caps memory after it.
|
|
53
|
+
* // `maxLineBytes` is optional and caps one line, which holds at most one file.
|
|
82
54
|
* const limits: Vfs.DecodeLimits = {
|
|
83
55
|
* maxEncodedBytes: ByteSize.megabytes(4),
|
|
84
56
|
* maxRecords: 10_000,
|
|
85
57
|
* maxEntries: 10_000,
|
|
86
|
-
* maxDecodedBytes: ByteSize.megabytes(16)
|
|
58
|
+
* maxDecodedBytes: ByteSize.megabytes(16),
|
|
59
|
+
* maxLineBytes: ByteSize.megabytes(4)
|
|
87
60
|
* }
|
|
88
61
|
*
|
|
89
62
|
* const program = Effect.gen(function*() {
|
|
@@ -95,7 +68,7 @@ export declare class ImageError extends ImageError_base<{
|
|
|
95
68
|
* return "accepted"
|
|
96
69
|
* })
|
|
97
70
|
*
|
|
98
|
-
* Effect.runPromise(program
|
|
71
|
+
* Effect.runPromise(program).then(console.log)
|
|
99
72
|
* // accepted
|
|
100
73
|
* ```
|
|
101
74
|
*
|
|
@@ -105,12 +78,18 @@ export declare class ImageError extends ImageError_base<{
|
|
|
105
78
|
export declare const DecodeLimits: Schema.Struct<{
|
|
106
79
|
/** Maximum accepted encoded input length in bytes. */
|
|
107
80
|
readonly maxEncodedBytes: Schema.ByteSize;
|
|
108
|
-
/** Maximum number of stored
|
|
81
|
+
/** Maximum number of stored objects, one node each, the root included. */
|
|
109
82
|
readonly maxRecords: Schema.Natural;
|
|
110
|
-
/** Maximum number of namespace entries. */
|
|
83
|
+
/** Maximum number of namespace entries, counting every name of a hard-linked file. */
|
|
111
84
|
readonly maxEntries: Schema.Natural;
|
|
112
|
-
/** Maximum combined decoded
|
|
85
|
+
/** Maximum combined decoded bytes of names, file contents and symbolic-link targets. */
|
|
113
86
|
readonly maxDecodedBytes: Schema.ByteSize;
|
|
87
|
+
/**
|
|
88
|
+
* Maximum bytes of one line of the encoding, without its newline: the most a decoder holds before it can check
|
|
89
|
+
* what the line says. A file's line holds its whole content, so this also bounds the largest file. Defaults to
|
|
90
|
+
* `maxEncodedBytes`.
|
|
91
|
+
*/
|
|
92
|
+
readonly maxLineBytes: Schema.optionalKey<Schema.ByteSize>;
|
|
114
93
|
}>;
|
|
115
94
|
/**
|
|
116
95
|
* Resource limits applied while decoding a snapshot.
|
|
@@ -119,5 +98,4 @@ export declare const DecodeLimits: Schema.Struct<{
|
|
|
119
98
|
* @since 0.1.0
|
|
120
99
|
*/
|
|
121
100
|
export type DecodeLimits = typeof DecodeLimits.Type;
|
|
122
|
-
export {};
|
|
123
101
|
//# sourceMappingURL=Snapshot.d.ts.map
|
package/dist/Snapshot.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Snapshot.d.ts","sourceRoot":"","sources":["../src/Snapshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Snapshot.d.ts","sourceRoot":"","sources":["../src/Snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAG,2BAAoC,CAAA;AAElE;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAA;AAElD;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,YAAY;IACvB,sDAAsD;;IAEtD,0EAA0E;;IAE1E,sFAAsF;;IAEtF,wFAAwF;;IAExF;;;;OAIG;;EAEH,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA"}
|
package/dist/Snapshot.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Opaque virtual filesystem snapshots and their decoding limits.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* A snapshot is the immutable value of a volume at one committed state, so
|
|
5
|
+
* capturing one copies nothing. It holds the reachable namespace and metadata,
|
|
6
|
+
* but excludes callers, open handles, watch subscriptions, and unlinked
|
|
7
|
+
* content. Use the encoding, decoding, and restoration functions in
|
|
8
|
+
* `VirtualFileSystem`.
|
|
7
9
|
*
|
|
8
10
|
* @since 0.1.0
|
|
9
11
|
*/
|
|
10
|
-
import * as Data from "effect/Data";
|
|
11
12
|
import * as Schema from "effect/Schema";
|
|
12
13
|
/**
|
|
13
14
|
* Type identifier for opaque filesystem snapshots.
|
|
@@ -17,59 +18,29 @@ import * as Schema from "effect/Schema";
|
|
|
17
18
|
*/
|
|
18
19
|
export const SnapshotTypeId = "@effect-vfs/core/Snapshot";
|
|
19
20
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
25
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
26
|
-
* import { ByteSize, Effect } from "effect"
|
|
27
|
-
*
|
|
28
|
-
* // Decoding is a trust boundary. `code` says what went wrong and `field` says
|
|
29
|
-
* // which input or limit it was, so a caller can decline just the bad payload.
|
|
30
|
-
* const program = Effect.gen(function*() {
|
|
31
|
-
* const volume = yield* Vfs.make()
|
|
32
|
-
* const bytes = yield* Vfs.encodeSnapshot(yield* volume.snapshot)
|
|
33
|
-
*
|
|
34
|
-
* return yield* Vfs.decodeSnapshot(bytes, {
|
|
35
|
-
* maxEncodedBytes: ByteSize.bytes(16),
|
|
36
|
-
* maxRecords: 10_000,
|
|
37
|
-
* maxEntries: 10_000,
|
|
38
|
-
* maxDecodedBytes: ByteSize.megabytes(16)
|
|
39
|
-
* }).pipe(
|
|
40
|
-
* Effect.as("accepted"),
|
|
41
|
-
* Effect.catchTag("ImageError", (error) =>
|
|
42
|
-
* error.code === "LimitExceeded"
|
|
43
|
-
* ? Effect.succeed(`declined at ${error.field}`)
|
|
44
|
-
* : Effect.fail(error))
|
|
45
|
-
* )
|
|
46
|
-
* })
|
|
21
|
+
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
47
22
|
*
|
|
48
|
-
*
|
|
49
|
-
* // declined at encodedBytes
|
|
50
|
-
* ```
|
|
23
|
+
* **Details**
|
|
51
24
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
25
|
+
* A snapshot is encoded one line per node, and a decoder checks each line as
|
|
26
|
+
* it ends, so input that breaks a limit is refused before the decoder holds
|
|
27
|
+
* more than one line of it. `maxLineBytes` bounds that line; the other limits
|
|
28
|
+
* bound what the accepted lines add up to.
|
|
59
29
|
*
|
|
60
30
|
* @example
|
|
61
31
|
* ```ts
|
|
62
32
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
63
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
64
33
|
* import { ByteSize, Effect } from "effect"
|
|
65
34
|
*
|
|
66
|
-
* //
|
|
35
|
+
* // The four counts are required: each bounds a different resource. `maxEncodedBytes`
|
|
67
36
|
* // caps the wire payload before parsing; `maxDecodedBytes` caps memory after it.
|
|
37
|
+
* // `maxLineBytes` is optional and caps one line, which holds at most one file.
|
|
68
38
|
* const limits: Vfs.DecodeLimits = {
|
|
69
39
|
* maxEncodedBytes: ByteSize.megabytes(4),
|
|
70
40
|
* maxRecords: 10_000,
|
|
71
41
|
* maxEntries: 10_000,
|
|
72
|
-
* maxDecodedBytes: ByteSize.megabytes(16)
|
|
42
|
+
* maxDecodedBytes: ByteSize.megabytes(16),
|
|
43
|
+
* maxLineBytes: ByteSize.megabytes(4)
|
|
73
44
|
* }
|
|
74
45
|
*
|
|
75
46
|
* const program = Effect.gen(function*() {
|
|
@@ -81,7 +52,7 @@ export class ImageError extends Data.TaggedError("ImageError") {
|
|
|
81
52
|
* return "accepted"
|
|
82
53
|
* })
|
|
83
54
|
*
|
|
84
|
-
* Effect.runPromise(program
|
|
55
|
+
* Effect.runPromise(program).then(console.log)
|
|
85
56
|
* // accepted
|
|
86
57
|
* ```
|
|
87
58
|
*
|
|
@@ -91,10 +62,16 @@ export class ImageError extends Data.TaggedError("ImageError") {
|
|
|
91
62
|
export const DecodeLimits = Schema.Struct({
|
|
92
63
|
/** Maximum accepted encoded input length in bytes. */
|
|
93
64
|
maxEncodedBytes: Schema.ByteSize,
|
|
94
|
-
/** Maximum number of stored
|
|
65
|
+
/** Maximum number of stored objects, one node each, the root included. */
|
|
95
66
|
maxRecords: Schema.Natural,
|
|
96
|
-
/** Maximum number of namespace entries. */
|
|
67
|
+
/** Maximum number of namespace entries, counting every name of a hard-linked file. */
|
|
97
68
|
maxEntries: Schema.Natural,
|
|
98
|
-
/** Maximum combined decoded
|
|
99
|
-
maxDecodedBytes: Schema.ByteSize
|
|
69
|
+
/** Maximum combined decoded bytes of names, file contents and symbolic-link targets. */
|
|
70
|
+
maxDecodedBytes: Schema.ByteSize,
|
|
71
|
+
/**
|
|
72
|
+
* Maximum bytes of one line of the encoding, without its newline: the most a decoder holds before it can check
|
|
73
|
+
* what the line says. A file's line holds its whole content, so this also bounds the largest file. Defaults to
|
|
74
|
+
* `maxEncodedBytes`.
|
|
75
|
+
*/
|
|
76
|
+
maxLineBytes: Schema.optionalKey(Schema.ByteSize)
|
|
100
77
|
});
|
package/dist/SnapshotDelta.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Opaque portable snapshot deltas and their public inspection models.
|
|
3
3
|
*
|
|
4
|
+
* A delta names its base and target snapshots by their semantic identities and
|
|
5
|
+
* holds one change per path that differs, each carrying only the node it
|
|
6
|
+
* leaves behind, so its size follows what changed rather than the tree.
|
|
7
|
+
*
|
|
4
8
|
* @since 0.1.0
|
|
5
9
|
*/
|
|
6
10
|
import * as ByteSize from "effect/ByteSize";
|
|
@@ -168,55 +172,26 @@ export declare const SnapshotChangesOptions: Schema.Struct<{
|
|
|
168
172
|
* @since 0.1.0
|
|
169
173
|
*/
|
|
170
174
|
export type SnapshotChangesOptions = typeof SnapshotChangesOptions.Type;
|
|
171
|
-
declare const SnapshotDeltaError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
172
|
-
readonly _tag: "SnapshotDeltaError";
|
|
173
|
-
} & Readonly<A>;
|
|
174
|
-
/**
|
|
175
|
-
* A valid snapshot delta was inspected or applied against a valid but semantically different base.
|
|
176
|
-
*
|
|
177
|
-
* @example
|
|
178
|
-
* ```ts
|
|
179
|
-
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
180
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
181
|
-
* import { Effect } from "effect"
|
|
182
|
-
*
|
|
183
|
-
* const program = Effect.gen(function*() {
|
|
184
|
-
* const volume = yield* Vfs.make()
|
|
185
|
-
* const caller = yield* volume.caller()
|
|
186
|
-
* const base = yield* volume.snapshot
|
|
187
|
-
*
|
|
188
|
-
* yield* caller.mkdir("/work")
|
|
189
|
-
*
|
|
190
|
-
* // Omitting limits uses `default`; `constrained` suits memory-sensitive hosts.
|
|
191
|
-
* const tight = { ...Vfs.SnapshotDeltaLimits.constrained, maxOutputRecords: 0 }
|
|
192
|
-
*
|
|
193
|
-
* return yield* Vfs.diffSnapshots(base, yield* volume.snapshot, tight).pipe(
|
|
194
|
-
* Effect.as("diffed"),
|
|
195
|
-
* Effect.catchTag("ImageError", (error) => Effect.succeed(`${error.code} at ${error.field}`))
|
|
196
|
-
* )
|
|
197
|
-
* }).pipe(Effect.provide(NodeCrypto.layer))
|
|
198
|
-
*
|
|
199
|
-
* Effect.runPromise(program).then(console.log)
|
|
200
|
-
* // LimitExceeded at outputRecords
|
|
201
|
-
* ```
|
|
202
|
-
*
|
|
203
|
-
* @category errors
|
|
204
|
-
* @since 0.1.0
|
|
205
|
-
*/
|
|
206
|
-
export declare class SnapshotDeltaError extends SnapshotDeltaError_base<{
|
|
207
|
-
readonly code: "BaseMismatch";
|
|
208
|
-
}> {
|
|
209
|
-
}
|
|
210
175
|
declare const SnapshotDeltaLimitsSchema: Schema.Struct<{
|
|
176
|
+
/** Maximum encoded delta length in bytes. */
|
|
211
177
|
readonly maxEncodedBytes: Schema.ByteSize;
|
|
178
|
+
/** Maximum bytes hashed for one snapshot's identity. */
|
|
212
179
|
readonly maxIdentityBytes: Schema.ByteSize;
|
|
180
|
+
/** Maximum number of changes a delta holds. */
|
|
213
181
|
readonly maxDeltaRecords: Schema.Natural;
|
|
182
|
+
/** Maximum decoded bytes of a delta's digests, paths and payloads. */
|
|
214
183
|
readonly maxDecodedDeltaBytes: Schema.ByteSize;
|
|
184
|
+
/** Maximum number of nodes in the base snapshot. */
|
|
215
185
|
readonly maxBaseRecords: Schema.Natural;
|
|
186
|
+
/** Maximum number of nodes in the target snapshot. */
|
|
216
187
|
readonly maxTargetRecords: Schema.Natural;
|
|
188
|
+
/** Maximum number of names in either snapshot, and of names a delta writes. */
|
|
217
189
|
readonly maxEntries: Schema.Natural;
|
|
190
|
+
/** Maximum number of nodes an applied delta produces. */
|
|
218
191
|
readonly maxOutputRecords: Schema.Natural;
|
|
192
|
+
/** Maximum payload bytes of the target, and of the payloads a delta carries. */
|
|
219
193
|
readonly maxOutputBytes: Schema.ByteSize;
|
|
194
|
+
/** Maximum number of target nodes carried over from the base rather than written by the delta. */
|
|
220
195
|
readonly maxInheritedRecords: Schema.Natural;
|
|
221
196
|
}>;
|
|
222
197
|
/**
|
|
@@ -263,15 +238,25 @@ export declare const makeSnapshotDeltaLimits: (limits: SnapshotDeltaLimits) => S
|
|
|
263
238
|
* @since 0.1.0
|
|
264
239
|
*/
|
|
265
240
|
export declare const SnapshotDeltaLimits: Schema.Struct<{
|
|
241
|
+
/** Maximum encoded delta length in bytes. */
|
|
266
242
|
readonly maxEncodedBytes: Schema.ByteSize;
|
|
243
|
+
/** Maximum bytes hashed for one snapshot's identity. */
|
|
267
244
|
readonly maxIdentityBytes: Schema.ByteSize;
|
|
245
|
+
/** Maximum number of changes a delta holds. */
|
|
268
246
|
readonly maxDeltaRecords: Schema.Natural;
|
|
247
|
+
/** Maximum decoded bytes of a delta's digests, paths and payloads. */
|
|
269
248
|
readonly maxDecodedDeltaBytes: Schema.ByteSize;
|
|
249
|
+
/** Maximum number of nodes in the base snapshot. */
|
|
270
250
|
readonly maxBaseRecords: Schema.Natural;
|
|
251
|
+
/** Maximum number of nodes in the target snapshot. */
|
|
271
252
|
readonly maxTargetRecords: Schema.Natural;
|
|
253
|
+
/** Maximum number of names in either snapshot, and of names a delta writes. */
|
|
272
254
|
readonly maxEntries: Schema.Natural;
|
|
255
|
+
/** Maximum number of nodes an applied delta produces. */
|
|
273
256
|
readonly maxOutputRecords: Schema.Natural;
|
|
257
|
+
/** Maximum payload bytes of the target, and of the payloads a delta carries. */
|
|
274
258
|
readonly maxOutputBytes: Schema.ByteSize;
|
|
259
|
+
/** Maximum number of target nodes carried over from the base rather than written by the delta. */
|
|
275
260
|
readonly maxInheritedRecords: Schema.Natural;
|
|
276
261
|
}> & {
|
|
277
262
|
constrained: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapshotDelta.d.ts","sourceRoot":"","sources":["../src/SnapshotDelta.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"SnapshotDelta.d.ts","sourceRoot":"","sources":["../src/SnapshotDelta.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAGxC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,gCAA+D,CAAA;AAEjG;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA;AAE5D;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,mBAAmB,CAAA;CACpD;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,8CAA0D,CAAA;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,4DAAoD,CAAA;AAEjF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAC,IAAI,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,4IAY7B,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,kBAAkB,CAAC,IAAI,CAAA;AAI/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;IASzB,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,sBAAsB;IACjC,6FAA6F;;EAE7F,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,OAAO,sBAAsB,CAAC,IAAI,CAAA;AAEvE,QAAA,MAAM,yBAAyB;IAC7B,6CAA6C;;IAE7C,wDAAwD;;IAExD,+CAA+C;;IAE/C,sEAAsE;;IAEtE,oDAAoD;;IAEpD,sDAAsD;;IAEtD,+EAA+E;;IAE/E,yDAAyD;;IAEzD,gFAAgF;;IAEhF,kGAAkG;;EAElG,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,yBAAyB,CAAC,IAAI,CAAA;AAEvE;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,WAAY,mBAAmB,KAAG,mBACxC,CAAA;AA4B9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,mBAAmB;IA9F9B,6CAA6C;;IAE7C,wDAAwD;;IAExD,+CAA+C;;IAE/C,sEAAsE;;IAEtE,oDAAoD;;IAEpD,sDAAsD;;IAEtD,+EAA+E;;IAE/E,yDAAyD;;IAEzD,gFAAgF;;IAEhF,kGAAkG;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+ElG,CAAA"}
|
package/dist/SnapshotDelta.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Opaque portable snapshot deltas and their public inspection models.
|
|
3
3
|
*
|
|
4
|
+
* A delta names its base and target snapshots by their semantic identities and
|
|
5
|
+
* holds one change per path that differs, each carrying only the node it
|
|
6
|
+
* leaves behind, so its size follows what changed rather than the tree.
|
|
7
|
+
*
|
|
4
8
|
* @since 0.1.0
|
|
5
9
|
*/
|
|
6
10
|
import * as ByteSize from "effect/ByteSize";
|
|
7
|
-
import * as Data from "effect/Data";
|
|
8
11
|
import * as Schema from "effect/Schema";
|
|
9
12
|
import { BytePath } from "./BytePath.js";
|
|
10
13
|
import * as Internal from "./internal/snapshotDeltaModel.js";
|
|
@@ -137,50 +140,26 @@ export const SnapshotChangesOptions = Schema.Struct({
|
|
|
137
140
|
/** Include access, modification, change, and birth-time differences. Defaults to `false`. */
|
|
138
141
|
includeTimestamps: Schema.optionalKey(Schema.Boolean)
|
|
139
142
|
});
|
|
140
|
-
/**
|
|
141
|
-
* A valid snapshot delta was inspected or applied against a valid but semantically different base.
|
|
142
|
-
*
|
|
143
|
-
* @example
|
|
144
|
-
* ```ts
|
|
145
|
-
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
146
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
147
|
-
* import { Effect } from "effect"
|
|
148
|
-
*
|
|
149
|
-
* const program = Effect.gen(function*() {
|
|
150
|
-
* const volume = yield* Vfs.make()
|
|
151
|
-
* const caller = yield* volume.caller()
|
|
152
|
-
* const base = yield* volume.snapshot
|
|
153
|
-
*
|
|
154
|
-
* yield* caller.mkdir("/work")
|
|
155
|
-
*
|
|
156
|
-
* // Omitting limits uses `default`; `constrained` suits memory-sensitive hosts.
|
|
157
|
-
* const tight = { ...Vfs.SnapshotDeltaLimits.constrained, maxOutputRecords: 0 }
|
|
158
|
-
*
|
|
159
|
-
* return yield* Vfs.diffSnapshots(base, yield* volume.snapshot, tight).pipe(
|
|
160
|
-
* Effect.as("diffed"),
|
|
161
|
-
* Effect.catchTag("ImageError", (error) => Effect.succeed(`${error.code} at ${error.field}`))
|
|
162
|
-
* )
|
|
163
|
-
* }).pipe(Effect.provide(NodeCrypto.layer))
|
|
164
|
-
*
|
|
165
|
-
* Effect.runPromise(program).then(console.log)
|
|
166
|
-
* // LimitExceeded at outputRecords
|
|
167
|
-
* ```
|
|
168
|
-
*
|
|
169
|
-
* @category errors
|
|
170
|
-
* @since 0.1.0
|
|
171
|
-
*/
|
|
172
|
-
export class SnapshotDeltaError extends Data.TaggedError("SnapshotDeltaError") {
|
|
173
|
-
}
|
|
174
143
|
const SnapshotDeltaLimitsSchema = Schema.Struct({
|
|
144
|
+
/** Maximum encoded delta length in bytes. */
|
|
175
145
|
maxEncodedBytes: Schema.ByteSize,
|
|
146
|
+
/** Maximum bytes hashed for one snapshot's identity. */
|
|
176
147
|
maxIdentityBytes: Schema.ByteSize,
|
|
148
|
+
/** Maximum number of changes a delta holds. */
|
|
177
149
|
maxDeltaRecords: Schema.Natural,
|
|
150
|
+
/** Maximum decoded bytes of a delta's digests, paths and payloads. */
|
|
178
151
|
maxDecodedDeltaBytes: Schema.ByteSize,
|
|
152
|
+
/** Maximum number of nodes in the base snapshot. */
|
|
179
153
|
maxBaseRecords: Schema.Natural,
|
|
154
|
+
/** Maximum number of nodes in the target snapshot. */
|
|
180
155
|
maxTargetRecords: Schema.Natural,
|
|
156
|
+
/** Maximum number of names in either snapshot, and of names a delta writes. */
|
|
181
157
|
maxEntries: Schema.Natural,
|
|
158
|
+
/** Maximum number of nodes an applied delta produces. */
|
|
182
159
|
maxOutputRecords: Schema.Natural,
|
|
160
|
+
/** Maximum payload bytes of the target, and of the payloads a delta carries. */
|
|
183
161
|
maxOutputBytes: Schema.ByteSize,
|
|
162
|
+
/** Maximum number of target nodes carried over from the base rather than written by the delta. */
|
|
184
163
|
maxInheritedRecords: Schema.Natural
|
|
185
164
|
});
|
|
186
165
|
/**
|