@effect-vfs/core 0.0.1
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/LICENSE +21 -0
- package/README.md +283 -0
- package/dist/Snapshot.d.ts +65 -0
- package/dist/Snapshot.d.ts.map +1 -0
- package/dist/Snapshot.js +43 -0
- package/dist/VirtualFileSystem.d.ts +674 -0
- package/dist/VirtualFileSystem.d.ts.map +1 -0
- package/dist/VirtualFileSystem.js +1768 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/internal/image.d.ts +142 -0
- package/dist/internal/image.d.ts.map +1 -0
- package/dist/internal/image.js +187 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lloyd Richards
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# @effect-vfs/core
|
|
2
|
+
|
|
3
|
+
`@effect-vfs/core` is a runtime-neutral virtual filesystem engine for Effect. It gives you isolated in-memory volumes,
|
|
4
|
+
byte-preserving paths, POSIX-inspired permissions, logical quotas, change streams, deterministic fixtures, and portable
|
|
5
|
+
encoded snapshots without reading from or writing to the host filesystem.
|
|
6
|
+
|
|
7
|
+
Use it when filesystem state is part of your domain: sandboxing a tool, modeling several users against one namespace,
|
|
8
|
+
testing permission behavior, building repeatable fixtures, or saving and restoring an in-memory workspace. If you need
|
|
9
|
+
Effect's standard `FileSystem` service, use [`@effect-vfs/memory`](https://www.npmjs.com/package/@effect-vfs/memory),
|
|
10
|
+
which adapts this package to that interface.
|
|
11
|
+
|
|
12
|
+
The package implements a documented subset of POSIX behavior. It does not claim full POSIX conformance. See the
|
|
13
|
+
[implemented profile](https://github.com/lloydrichards/effect-virtual-fs/blob/main/.docs/context/implemented-profile.md)
|
|
14
|
+
for the exact permission, path, timestamp, quota, and atomicity rules.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npm install @effect-vfs/core effect@4.0.0-rc.112
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Version `0.1.0` targets the exact peer version `effect@4.0.0-rc.112`.
|
|
23
|
+
|
|
24
|
+
## The mental model
|
|
25
|
+
|
|
26
|
+
The API has three levels:
|
|
27
|
+
|
|
28
|
+
- A `Volume` owns one isolated namespace and its file contents.
|
|
29
|
+
- A `Caller` accesses that volume with its own identity, umask, and current directory.
|
|
30
|
+
- File and directory handles are scoped capabilities. Effect closes them when their scope ends.
|
|
31
|
+
|
|
32
|
+
Callers created from the same volume see the same files. A new volume starts with independent state. This separation
|
|
33
|
+
lets you model access by several users without reaching for process globals or the host filesystem.
|
|
34
|
+
|
|
35
|
+
## Create an isolated workspace
|
|
36
|
+
|
|
37
|
+
This example creates a bounded workspace, gives an unprivileged caller access to one directory, and uses a scoped file
|
|
38
|
+
handle to read the result. It demonstrates the main benefit of the core API: storage, credentials, limits, and resource
|
|
39
|
+
lifetime are explicit values that can be composed in one Effect program.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
43
|
+
import { Effect } from "effect"
|
|
44
|
+
|
|
45
|
+
const utf8 = new TextEncoder()
|
|
46
|
+
|
|
47
|
+
const program = Effect.scoped(Effect.gen(function*() {
|
|
48
|
+
const volume = yield* Vfs.make({
|
|
49
|
+
maxEntries: 100,
|
|
50
|
+
maxBytes: 1_000_000,
|
|
51
|
+
maxFileBytes: 100_000
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const admin = yield* volume.caller()
|
|
55
|
+
yield* admin.mkdir("/workspace", { mode: 0o770 })
|
|
56
|
+
yield* admin.chown("/workspace", { uid: 1000, gid: 1000 })
|
|
57
|
+
|
|
58
|
+
const developer = yield* volume.caller({
|
|
59
|
+
identity: { uid: 1000, gid: 1000, groups: [], privileged: false },
|
|
60
|
+
umask: 0o027
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
yield* developer.writeFile(
|
|
64
|
+
"/workspace/config.json",
|
|
65
|
+
utf8.encode(JSON.stringify({ feature: "preview" })),
|
|
66
|
+
{ access: "write", create: "exclusive", mode: 0o666 }
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
const file = yield* developer.open("/workspace/config.json", { access: "read" })
|
|
70
|
+
const contents = yield* file.read(100_000)
|
|
71
|
+
const metadata = yield* file.stat
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
config: JSON.parse(new TextDecoder().decode(contents)),
|
|
75
|
+
mode: metadata.mode.toString(8)
|
|
76
|
+
}
|
|
77
|
+
}))
|
|
78
|
+
|
|
79
|
+
const result = await Effect.runPromise(program)
|
|
80
|
+
console.log(result) // { config: { feature: "preview" }, mode: "640" }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The root caller is privileged by default. Privilege is explicit: setting `uid` to `0` does not grant it. New root
|
|
84
|
+
callers default to umask `0o022`; the developer's `0o027` mask turns the requested file mode `0o666` into `0o640`.
|
|
85
|
+
|
|
86
|
+
The root package exports `VirtualFileSystem` as a namespace. The equivalent direct module import is
|
|
87
|
+
`import * as Vfs from "@effect-vfs/core/VirtualFileSystem"`.
|
|
88
|
+
|
|
89
|
+
## Preserve path bytes exactly
|
|
90
|
+
|
|
91
|
+
JavaScript strings cannot represent every filename allowed by a byte-oriented filesystem. `BytePath` keeps arbitrary
|
|
92
|
+
non-NUL path bytes intact. This matters when reproducing archives, protocol fixtures, or Unix directory trees that
|
|
93
|
+
contain names which are not valid UTF-8.
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
97
|
+
import { Effect } from "effect"
|
|
98
|
+
|
|
99
|
+
const program = Effect.gen(function*() {
|
|
100
|
+
const volume = yield* Vfs.make()
|
|
101
|
+
const fs = yield* volume.caller()
|
|
102
|
+
|
|
103
|
+
// Absolute path whose final component is the single byte 0xff.
|
|
104
|
+
const opaquePath = yield* Vfs.pathFromBytes(new Uint8Array([0x2f, 0xff]))
|
|
105
|
+
yield* fs.writeFile(opaquePath, new Uint8Array([1, 2, 3]), {
|
|
106
|
+
access: "write",
|
|
107
|
+
create: "exclusive"
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const names = yield* fs.readDirectoryBytes("/")
|
|
111
|
+
const roundTrip = yield* Vfs.pathToBytes(opaquePath)
|
|
112
|
+
return { names: names.map((name) => Array.from(name)), roundTrip: Array.from(roundTrip) }
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
console.log(await Effect.runPromise(program))
|
|
116
|
+
// { names: [[255]], roundTrip: [47, 255] }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The constructors and byte-returning operations copy their buffers, so later mutation cannot change stored paths.
|
|
120
|
+
String-returning operations fail with `FsError` code `UnrepresentableName` when a name is not valid UTF-8. Use the byte
|
|
121
|
+
variants of directory enumeration, symbolic-link targets, and resolved paths when exact bytes matter.
|
|
122
|
+
|
|
123
|
+
## Build fixtures and restore snapshots
|
|
124
|
+
|
|
125
|
+
Fixtures make tests deterministic without a setup sequence. Snapshots let you capture that prepared state, serialize
|
|
126
|
+
it, and create independent workspaces from the same image. This is useful for test isolation, preview environments, and
|
|
127
|
+
resettable sandboxes.
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
131
|
+
import { Effect } from "effect"
|
|
132
|
+
|
|
133
|
+
const decodeLimits = {
|
|
134
|
+
maxEncodedBytes: 1_000_000,
|
|
135
|
+
maxRecords: 1_000,
|
|
136
|
+
maxEntries: 1_000,
|
|
137
|
+
maxDecodedBytes: 1_000_000
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const program = Effect.gen(function*() {
|
|
141
|
+
const template = yield* Vfs.fromFixture({
|
|
142
|
+
entries: [
|
|
143
|
+
{ kind: "directory", path: "/project" },
|
|
144
|
+
{
|
|
145
|
+
kind: "file",
|
|
146
|
+
path: "/project/settings.json",
|
|
147
|
+
bytes: new TextEncoder().encode("{\"theme\":\"dark\"}")
|
|
148
|
+
}
|
|
149
|
+
]
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
const encoded = yield* Vfs.encodeSnapshot(yield* template.snapshot)
|
|
153
|
+
const snapshot = yield* Vfs.decodeSnapshot(encoded, decodeLimits)
|
|
154
|
+
const workspaceA = yield* Vfs.fromSnapshot(snapshot)
|
|
155
|
+
const workspaceB = yield* Vfs.fromSnapshot(snapshot)
|
|
156
|
+
const a = yield* workspaceA.caller()
|
|
157
|
+
const b = yield* workspaceB.caller()
|
|
158
|
+
|
|
159
|
+
yield* a.writeFile("/project/settings.json", new TextEncoder().encode("{\"theme\":\"light\"}"), {
|
|
160
|
+
access: "write",
|
|
161
|
+
truncate: true
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
return new TextDecoder().decode(yield* b.readFile("/project/settings.json"))
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
console.log(await Effect.runPromise(program)) // {"theme":"dark"}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Fixture paths must be absolute and unique, and parent directories must be listed explicitly. Fixtures can also contain
|
|
171
|
+
symbolic links, metadata, and forward hard links.
|
|
172
|
+
|
|
173
|
+
Snapshot decoding requires explicit work limits because encoded bytes may come from an untrusted source. A snapshot
|
|
174
|
+
contains the reachable namespace and metadata. It excludes callers, open handles, cursor positions, watch
|
|
175
|
+
subscriptions, and unlinked content. Each restored volume is independent.
|
|
176
|
+
|
|
177
|
+
## Use scoped handles for incremental I/O
|
|
178
|
+
|
|
179
|
+
Whole-file operations are convenient, but handles give each open file an independent `bigint` cursor and support
|
|
180
|
+
incremental reads, positional I/O, seeking, and truncation. `Effect.scoped` guarantees cleanup on success, failure, or
|
|
181
|
+
interruption.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
185
|
+
import { Effect } from "effect"
|
|
186
|
+
|
|
187
|
+
const program = Effect.scoped(Effect.gen(function*() {
|
|
188
|
+
const fs = yield* (yield* Vfs.make()).caller()
|
|
189
|
+
yield* fs.writeFile("/events.log", new TextEncoder().encode("one\ntwo\n"), {
|
|
190
|
+
access: "write",
|
|
191
|
+
create: "exclusive"
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const file = yield* fs.open("/events.log", { access: "read" })
|
|
195
|
+
const first = yield* file.read(4) // Advances this handle's cursor.
|
|
196
|
+
const second = yield* file.read(4)
|
|
197
|
+
const preview = yield* file.pread(3, 0n) // Does not move the cursor.
|
|
198
|
+
|
|
199
|
+
return [first, second, preview].map((bytes) => new TextDecoder().decode(bytes))
|
|
200
|
+
}))
|
|
201
|
+
|
|
202
|
+
console.log(await Effect.runPromise(program)) // ["one\n", "two\n", "one"]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Handles also expose an explicit `close` effect when early release matters. Calling explicit close twice fails, while
|
|
206
|
+
scope cleanup remains safe after an explicit close.
|
|
207
|
+
|
|
208
|
+
## Handle expected failures as data
|
|
209
|
+
|
|
210
|
+
Filesystem failures are typed `FsError` values with a stable `code`, `operation`, and optional `path`. Configuration
|
|
211
|
+
and snapshot failures use `ConfigurationError` and `ImageError`. Interruption and defects remain separate from these
|
|
212
|
+
expected failures.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
216
|
+
import { Effect } from "effect"
|
|
217
|
+
|
|
218
|
+
const program = Effect.gen(function*() {
|
|
219
|
+
const fs = yield* (yield* Vfs.make()).caller()
|
|
220
|
+
|
|
221
|
+
return yield* fs.readFile("/optional.json").pipe(
|
|
222
|
+
Effect.catchTag("FsError", (error) =>
|
|
223
|
+
error.code === "NotFound"
|
|
224
|
+
? Effect.succeed(new TextEncoder().encode("{}"))
|
|
225
|
+
: Effect.fail(error))
|
|
226
|
+
)
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
const bytes = await Effect.runPromise(program)
|
|
230
|
+
console.log(new TextDecoder().decode(bytes)) // {}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Provide a caller as an Effect service
|
|
234
|
+
|
|
235
|
+
`CurrentFileSystem` is an optional service for application code that should receive an existing caller through its
|
|
236
|
+
Effect environment. The service owns no storage; the provided caller keeps its original volume, identity, umask, and
|
|
237
|
+
current directory.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
241
|
+
import { Effect } from "effect"
|
|
242
|
+
|
|
243
|
+
const loadConfig = Effect.gen(function*() {
|
|
244
|
+
const fs = yield* Vfs.CurrentFileSystem
|
|
245
|
+
return yield* fs.readFile("/app/config.json")
|
|
246
|
+
})
|
|
247
|
+
|
|
248
|
+
const program = Effect.gen(function*() {
|
|
249
|
+
const fs = yield* (yield* Vfs.make()).caller()
|
|
250
|
+
yield* fs.mkdir("/app")
|
|
251
|
+
yield* fs.writeFile("/app/config.json", new TextEncoder().encode("{}"), {
|
|
252
|
+
access: "write",
|
|
253
|
+
create: "exclusive"
|
|
254
|
+
})
|
|
255
|
+
return yield* loadConfig.pipe(Effect.provideService(Vfs.CurrentFileSystem, fs))
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
const bytes = await Effect.runPromise(program)
|
|
259
|
+
console.log(new TextDecoder().decode(bytes)) // {}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## When to use core or memory
|
|
263
|
+
|
|
264
|
+
Choose `@effect-vfs/core` when you need direct access to volumes, callers, credentials, byte paths, quotas, watches,
|
|
265
|
+
fixtures, or snapshots. Choose `@effect-vfs/memory` when existing code expects Effect's `FileSystem` service and you
|
|
266
|
+
want an in-memory implementation. The memory adapter is built on this core, so you can create a core volume and bind
|
|
267
|
+
the adapter to it when you need both interfaces.
|
|
268
|
+
|
|
269
|
+
## Compatibility and behavioral limits
|
|
270
|
+
|
|
271
|
+
This package is experimental. Its public API may change between minor releases while Effect v4 remains a release
|
|
272
|
+
candidate.
|
|
273
|
+
|
|
274
|
+
- Components are limited to 255 bytes. Symbolic-link traversal is limited to 40 links.
|
|
275
|
+
- Omitted logical quotas are unbounded by configuration, apart from fixed file and component bounds.
|
|
276
|
+
- Absolute paths ignore a supplied directory base. Relative paths can use a live, same-volume directory handle.
|
|
277
|
+
- Operations coordinate through one permit per volume. Interruption while waiting makes no change; interruption after
|
|
278
|
+
a commit does not roll it back.
|
|
279
|
+
- Watch streams contain byte paths and report future committed creates, updates, and removals without replay.
|
|
280
|
+
- `sync` checks handle liveness. An in-memory volume provides no host or crash durability.
|
|
281
|
+
|
|
282
|
+
For the complete contract, read the
|
|
283
|
+
[implemented profile](https://github.com/lloydrichards/effect-virtual-fs/blob/main/.docs/context/implemented-profile.md).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
/**
|
|
3
|
+
* Type identifier for opaque filesystem snapshots.
|
|
4
|
+
*
|
|
5
|
+
* @category type ids
|
|
6
|
+
* @since 0.1.0
|
|
7
|
+
*/
|
|
8
|
+
export declare const SnapshotTypeId: unique symbol;
|
|
9
|
+
/**
|
|
10
|
+
* Type identifier for opaque filesystem snapshots.
|
|
11
|
+
*
|
|
12
|
+
* @category type ids
|
|
13
|
+
* @since 0.1.0
|
|
14
|
+
*/
|
|
15
|
+
export type SnapshotTypeId = typeof SnapshotTypeId;
|
|
16
|
+
/**
|
|
17
|
+
* An immutable, opaque capture of a virtual filesystem volume.
|
|
18
|
+
*
|
|
19
|
+
* @category models
|
|
20
|
+
* @since 0.1.0
|
|
21
|
+
*/
|
|
22
|
+
export interface Snapshot {
|
|
23
|
+
readonly [SnapshotTypeId]: SnapshotTypeId;
|
|
24
|
+
}
|
|
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
|
+
/**
|
|
29
|
+
* Describes a snapshot encoding, decoding, structure, or resource-limit failure.
|
|
30
|
+
*
|
|
31
|
+
* @category errors
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export declare class ImageError extends ImageError_base<{
|
|
35
|
+
/** Machine-readable encoding, version, structure, or limit failure. */
|
|
36
|
+
readonly code: "InvalidEncoding" | "UnsupportedVersion" | "InvalidStructure" | "LimitExceeded";
|
|
37
|
+
/** Input area or configured limit associated with the failure, when available. */
|
|
38
|
+
readonly field?: string;
|
|
39
|
+
}> {
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
43
|
+
*
|
|
44
|
+
* @category schemas
|
|
45
|
+
* @since 0.1.0
|
|
46
|
+
*/
|
|
47
|
+
export declare const DecodeLimits: Schema.Struct<{
|
|
48
|
+
/** Maximum accepted encoded input length in bytes. */
|
|
49
|
+
readonly maxEncodedBytes: Schema.Finite;
|
|
50
|
+
/** Maximum number of stored metadata and content records. */
|
|
51
|
+
readonly maxRecords: Schema.Finite;
|
|
52
|
+
/** Maximum number of namespace entries. */
|
|
53
|
+
readonly maxEntries: Schema.Finite;
|
|
54
|
+
/** Maximum combined decoded byte content. */
|
|
55
|
+
readonly maxDecodedBytes: Schema.Finite;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Resource limits applied while decoding a snapshot.
|
|
59
|
+
*
|
|
60
|
+
* @category models
|
|
61
|
+
* @since 0.1.0
|
|
62
|
+
*/
|
|
63
|
+
export type DecodeLimits = typeof DecodeLimits.Type;
|
|
64
|
+
export {};
|
|
65
|
+
//# sourceMappingURL=Snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Snapshot.d.ts","sourceRoot":"","sources":["../src/Snapshot.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAQvC;;;;;GAKG;AACH,eAAO,MAAM,cAAc,eAAsC,CAAA;AAEjE;;;;;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;;;;;GAKG;AACH,qBAAa,UAAW,SAAQ,gBAA+B;IAC7D,uEAAuE;IACvE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,kBAAkB,GAAG,eAAe,CAAA;IAC9F,kFAAkF;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB,CAAC;CAAG;AAEL;;;;;GAKG;AACH,eAAO,MAAM,YAAY;IACvB,sDAAsD;;IAEtD,6DAA6D;;IAE7D,2CAA2C;;IAE3C,6CAA6C;;EAE7C,CAAA;AAEF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA"}
|
package/dist/Snapshot.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opaque virtual filesystem snapshots and their decoding limits.
|
|
3
|
+
*
|
|
4
|
+
* Snapshots contain a volume's reachable namespace and metadata, but exclude
|
|
5
|
+
* callers, open handles, watch subscriptions, and unlinked content. Use the
|
|
6
|
+
* encoding, decoding, and restoration functions in `VirtualFileSystem`.
|
|
7
|
+
*
|
|
8
|
+
* @since 0.1.0
|
|
9
|
+
*/
|
|
10
|
+
import * as Data from "effect/Data";
|
|
11
|
+
import * as Schema from "effect/Schema";
|
|
12
|
+
const Natural = Schema.Finite.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER));
|
|
13
|
+
/**
|
|
14
|
+
* Type identifier for opaque filesystem snapshots.
|
|
15
|
+
*
|
|
16
|
+
* @category type ids
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
*/
|
|
19
|
+
export const SnapshotTypeId = Symbol("@effect-vfs/core/Snapshot");
|
|
20
|
+
/**
|
|
21
|
+
* Describes a snapshot encoding, decoding, structure, or resource-limit failure.
|
|
22
|
+
*
|
|
23
|
+
* @category errors
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
export class ImageError extends Data.TaggedError("ImageError") {
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Schema for the mandatory resource limits applied while decoding a snapshot.
|
|
30
|
+
*
|
|
31
|
+
* @category schemas
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export const DecodeLimits = Schema.Struct({
|
|
35
|
+
/** Maximum accepted encoded input length in bytes. */
|
|
36
|
+
maxEncodedBytes: Natural,
|
|
37
|
+
/** Maximum number of stored metadata and content records. */
|
|
38
|
+
maxRecords: Natural,
|
|
39
|
+
/** Maximum number of namespace entries. */
|
|
40
|
+
maxEntries: Natural,
|
|
41
|
+
/** Maximum combined decoded byte content. */
|
|
42
|
+
maxDecodedBytes: Natural
|
|
43
|
+
});
|