@effect-vfs/core 0.5.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 +34 -31
- 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 +11 -21
- package/dist/LiveVolume.d.ts.map +1 -1
- package/dist/LiveVolume.js +17 -14
- 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 +448 -115
- 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 +47 -5
- package/dist/internal/errors.d.ts.map +1 -1
- package/dist/internal/errors.js +80 -36
- package/dist/internal/fixture.d.ts +2 -2
- package/dist/internal/fixture.d.ts.map +1 -1
- package/dist/internal/fixture.js +57 -74
- 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/overlayDiff.d.ts +2 -2
- package/dist/internal/overlayDiff.d.ts.map +1 -1
- package/dist/internal/overlayDiff.js +0 -3
- package/dist/internal/path.d.ts +17 -5
- package/dist/internal/path.d.ts.map +1 -1
- package/dist/internal/path.js +38 -24
- 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 +11 -15
- package/dist/internal/stagedState.d.ts.map +1 -1
- package/dist/internal/stagedState.js +15 -59
- 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 +39 -489
- package/dist/internal/virtualFileSystem.d.ts.map +1 -1
- package/dist/internal/virtualFileSystem.js +2112 -2465
- 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 +15 -6
- package/dist/internal/watchHub.d.ts.map +1 -1
- package/dist/internal/watchHub.js +56 -42
- package/package.json +48 -4
- package/dist/VirtualFileSystemError.d.ts +0 -54
- package/dist/VirtualFileSystemError.d.ts.map +0 -1
- package/dist/VirtualFileSystemError.js +0 -49
- package/dist/internal/overlayContent.d.ts +0 -15
- package/dist/internal/overlayContent.d.ts.map +0 -1
- package/dist/internal/overlayContent.js +0 -29
- package/dist/internal/testHooks.d.ts +0 -20
- package/dist/internal/testHooks.d.ts.map +0 -1
- package/dist/internal/testHooks.js +0 -23
|
@@ -12,24 +12,33 @@ import type * as ByteSize from "effect/ByteSize";
|
|
|
12
12
|
import * as Context from "effect/Context";
|
|
13
13
|
import type * as Crypto from "effect/Crypto";
|
|
14
14
|
import * as Effect from "effect/Effect";
|
|
15
|
+
import * as Layer from "effect/Layer";
|
|
15
16
|
import type * as Order from "effect/Order";
|
|
16
17
|
import type * as PlatformError from "effect/PlatformError";
|
|
17
18
|
import * as Schema from "effect/Schema";
|
|
18
19
|
import type * as Scope from "effect/Scope";
|
|
19
|
-
import
|
|
20
|
+
import * as Sink from "effect/Sink";
|
|
21
|
+
import * as Stream from "effect/Stream";
|
|
20
22
|
import type { BytePath } from "./BytePath.js";
|
|
21
|
-
import type {
|
|
23
|
+
import type { CallerId, ObjectReferenceId } from "./Caller.js";
|
|
24
|
+
import * as CallerModule from "./Caller.js";
|
|
25
|
+
import type { DirectoryHandleId, FileHandleId } from "./FileHandle.js";
|
|
26
|
+
import * as FileHandleModule from "./FileHandle.js";
|
|
27
|
+
import * as FixtureModule from "./Fixture.js";
|
|
28
|
+
import * as MetadataModule from "./Metadata.js";
|
|
29
|
+
import type { Entry, EntryInput, Target, TargetInput } from "./Target.js";
|
|
30
|
+
import type { ArgumentFailure, FsFailure, ImageFailure, VfsError } from "./VfsError.js";
|
|
31
|
+
import * as VfsErrorModule from "./VfsError.js";
|
|
32
|
+
import type { VolumeId } from "./Volume.js";
|
|
33
|
+
import * as VolumeModule from "./Volume.js";
|
|
34
|
+
import * as WatchModule from "./Watch.js";
|
|
35
|
+
export { Entry, type EntryInput, isEntry, isTarget, Name, type NameInput, type PathTarget, Target, type TargetInput } from "./Target.js";
|
|
22
36
|
export { BytePath } from "./BytePath.js";
|
|
23
|
-
import type { DecodeLimits,
|
|
24
|
-
export { DecodeLimits,
|
|
25
|
-
import
|
|
37
|
+
import type { DecodeLimits, Snapshot } from "./Snapshot.js";
|
|
38
|
+
export { DecodeLimits, type Snapshot, SnapshotTypeId } from "./Snapshot.js";
|
|
39
|
+
import { type LiveImageStore, type Options as LiveVolumeOptions } from "./LiveVolume.js";
|
|
26
40
|
import * as SnapshotDeltaModel from "./SnapshotDelta.js";
|
|
27
|
-
export { SnapshotChange, SnapshotChangesOptions, type SnapshotDelta,
|
|
28
|
-
declare const VolumeId: typeof VfsModel.VolumeId;
|
|
29
|
-
declare const CallerId: typeof VfsModel.CallerId;
|
|
30
|
-
declare const FileHandleId: typeof VfsModel.FileHandleId;
|
|
31
|
-
declare const DirectoryHandleId: typeof VfsModel.DirectoryHandleId;
|
|
32
|
-
declare const ObjectReferenceId: typeof VfsModel.ObjectReferenceId;
|
|
41
|
+
export { SnapshotChange, SnapshotChangesOptions, type SnapshotDelta, SnapshotDeltaLimits, SnapshotDeltaTypeId, SnapshotDifference, SnapshotNodeKind } from "./SnapshotDelta.js";
|
|
33
42
|
/**
|
|
34
43
|
* A UTF-8 string path or an opaque byte-preserving path.
|
|
35
44
|
*
|
|
@@ -73,7 +82,7 @@ export type PathInput = string | BytePath;
|
|
|
73
82
|
* @category schemas
|
|
74
83
|
* @since 0.1.0
|
|
75
84
|
*/
|
|
76
|
-
export declare const FsCode: typeof
|
|
85
|
+
export declare const FsCode: typeof VfsErrorModule.FsCode;
|
|
77
86
|
/**
|
|
78
87
|
* A portable virtual filesystem error code.
|
|
79
88
|
*
|
|
@@ -91,7 +100,6 @@ export type FsCode = typeof FsCode.Type;
|
|
|
91
100
|
* @example
|
|
92
101
|
* ```ts
|
|
93
102
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
94
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
95
103
|
* import { Effect } from "effect"
|
|
96
104
|
*
|
|
97
105
|
* const program = Effect.gen(function*() {
|
|
@@ -100,28 +108,26 @@ export type FsCode = typeof FsCode.Type;
|
|
|
100
108
|
* // Every filesystem operation fails with this one tagged error; `code`
|
|
101
109
|
* // distinguishes the cases, so match on it rather than on the tag alone.
|
|
102
110
|
* return yield* caller.readFile("/missing").pipe(
|
|
103
|
-
* Effect.catchTag("
|
|
111
|
+
* Effect.catchTag("VfsError", (error) =>
|
|
104
112
|
* error.code === "NotFound"
|
|
105
113
|
* ? Effect.succeed(new Uint8Array())
|
|
106
114
|
* : Effect.fail(error))
|
|
107
115
|
* )
|
|
108
116
|
* })
|
|
109
117
|
*
|
|
110
|
-
* Effect.runPromise(program
|
|
118
|
+
* Effect.runPromise(program).then(console.log)
|
|
111
119
|
* // Uint8Array(0) []
|
|
112
120
|
* ```
|
|
113
121
|
*
|
|
114
122
|
* @category errors
|
|
115
123
|
* @since 0.1.0
|
|
116
124
|
*/
|
|
117
|
-
export { FsError } from "./VirtualFileSystemError.js";
|
|
118
125
|
/**
|
|
119
126
|
* Describes an invalid volume or caller option and names the rejected field.
|
|
120
127
|
*
|
|
121
128
|
* @example
|
|
122
129
|
* ```ts
|
|
123
130
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
124
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
125
131
|
* import { Effect } from "effect"
|
|
126
132
|
*
|
|
127
133
|
* // `field` names the rejected option, so the caller learns which key was wrong.
|
|
@@ -131,25 +137,25 @@ export { FsError } from "./VirtualFileSystemError.js";
|
|
|
131
137
|
*
|
|
132
138
|
* return yield* Vfs.make(options).pipe(
|
|
133
139
|
* Effect.as("ok"),
|
|
134
|
-
* Effect.catchTag("
|
|
140
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed(`rejected ${error.field}`))
|
|
135
141
|
* )
|
|
136
142
|
* })
|
|
137
143
|
*
|
|
138
|
-
* Effect.runPromise(program
|
|
144
|
+
* Effect.runPromise(program).then(console.log)
|
|
139
145
|
* // rejected maxEntries
|
|
140
146
|
* ```
|
|
141
147
|
*
|
|
142
148
|
* @category errors
|
|
143
149
|
* @since 0.1.0
|
|
144
150
|
*/
|
|
145
|
-
export {
|
|
151
|
+
export { type ArgumentFailure, DeltaCode, type FsFailure, ImageCode, type ImageFailure, StoreCode, type StoreFailure, VfsCode, VfsError } from "./VfsError.js";
|
|
146
152
|
/**
|
|
147
153
|
* Schema for a caller's numeric identity, supplementary groups, and explicit privilege.
|
|
148
154
|
*
|
|
149
155
|
* @category schemas
|
|
150
156
|
* @since 0.1.0
|
|
151
157
|
*/
|
|
152
|
-
export declare const Identity: typeof
|
|
158
|
+
export declare const Identity: typeof CallerModule.Identity;
|
|
153
159
|
/**
|
|
154
160
|
* A caller identity used for permission checks.
|
|
155
161
|
*
|
|
@@ -163,7 +169,6 @@ export type Identity = typeof Identity.Type;
|
|
|
163
169
|
* @example
|
|
164
170
|
* ```ts
|
|
165
171
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
166
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
167
172
|
* import { Effect } from "effect"
|
|
168
173
|
*
|
|
169
174
|
* const program = Effect.gen(function*() {
|
|
@@ -184,14 +189,14 @@ export type Identity = typeof Identity.Type;
|
|
|
184
189
|
* return ((yield* user.stat("/home/user")).mode & 0o777).toString(8)
|
|
185
190
|
* })
|
|
186
191
|
*
|
|
187
|
-
* Effect.runPromise(program
|
|
192
|
+
* Effect.runPromise(program).then(console.log)
|
|
188
193
|
* // 755
|
|
189
194
|
* ```
|
|
190
195
|
*
|
|
191
196
|
* @category schemas
|
|
192
197
|
* @since 0.1.0
|
|
193
198
|
*/
|
|
194
|
-
export declare const RootCallerOptions: typeof
|
|
199
|
+
export declare const RootCallerOptions: typeof CallerModule.RootCallerOptions;
|
|
195
200
|
/**
|
|
196
201
|
* Options for creating a root caller on a volume.
|
|
197
202
|
*
|
|
@@ -205,7 +210,7 @@ export type RootCallerOptions = typeof RootCallerOptions.Type;
|
|
|
205
210
|
* @category schemas
|
|
206
211
|
* @since 0.1.0
|
|
207
212
|
*/
|
|
208
|
-
export declare const VolumeDurability: typeof
|
|
213
|
+
export declare const VolumeDurability: typeof VolumeModule.VolumeDurability;
|
|
209
214
|
/**
|
|
210
215
|
* The failure boundary survived by an acknowledged volume write.
|
|
211
216
|
*
|
|
@@ -233,7 +238,7 @@ export declare const isVolumeDurabilityAtLeast: (actual: VolumeDurability, requi
|
|
|
233
238
|
* @category schemas
|
|
234
239
|
* @since 0.1.0
|
|
235
240
|
*/
|
|
236
|
-
export declare const VolumeIdentity: typeof
|
|
241
|
+
export declare const VolumeIdentity: typeof VolumeModule.VolumeIdentity;
|
|
237
242
|
/**
|
|
238
243
|
* Stable logical identity of a volume as a branded 128-bit lowercase hexadecimal string.
|
|
239
244
|
*
|
|
@@ -247,7 +252,7 @@ export type VolumeIdentity = typeof VolumeIdentity.Type;
|
|
|
247
252
|
* @category schemas
|
|
248
253
|
* @since 0.1.0
|
|
249
254
|
*/
|
|
250
|
-
export declare const VolumeIncarnation: typeof
|
|
255
|
+
export declare const VolumeIncarnation: typeof VolumeModule.VolumeIncarnation;
|
|
251
256
|
/**
|
|
252
257
|
* One uninterrupted storage lifetime as a branded 128-bit lowercase hexadecimal string.
|
|
253
258
|
*
|
|
@@ -255,13 +260,52 @@ export declare const VolumeIncarnation: typeof VfsModel.VolumeIncarnation;
|
|
|
255
260
|
* @since 0.1.0
|
|
256
261
|
*/
|
|
257
262
|
export type VolumeIncarnation = typeof VolumeIncarnation.Type;
|
|
263
|
+
/**
|
|
264
|
+
* Schema for the serialisable name of one object in one volume: the volume's
|
|
265
|
+
* identity, the epoch of its inode numbers, the object's inode number, and a
|
|
266
|
+
* tag only the volume can compute, so a key cannot be guessed from another.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* ```ts
|
|
270
|
+
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
271
|
+
* import { Effect, Schema } from "effect"
|
|
272
|
+
*
|
|
273
|
+
* const Json = Schema.fromJsonString(Vfs.ReferenceKey)
|
|
274
|
+
*
|
|
275
|
+
* const program = Effect.gen(function*() {
|
|
276
|
+
* const volume = yield* Vfs.make()
|
|
277
|
+
* const caller = yield* volume.caller()
|
|
278
|
+
* yield* caller.writeFile("/f", new Uint8Array([1]), { access: "write", create: "exclusive" })
|
|
279
|
+
*
|
|
280
|
+
* // The key survives a wire; resolving it returns the same reference.
|
|
281
|
+
* const reference = yield* caller.lookup("/f")
|
|
282
|
+
* const text = yield* Schema.encodeEffect(Json)(yield* volume.referenceKey(reference))
|
|
283
|
+
* const key = yield* Schema.decodeEffect(Json)(text)
|
|
284
|
+
*
|
|
285
|
+
* return (yield* volume.resolveReferenceKey(key)) === reference
|
|
286
|
+
* })
|
|
287
|
+
*
|
|
288
|
+
* Effect.runPromise(program).then(console.log)
|
|
289
|
+
* // true
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @category schemas
|
|
293
|
+
* @since 0.6.0
|
|
294
|
+
*/
|
|
295
|
+
export declare const ReferenceKey: typeof VolumeModule.ReferenceKey;
|
|
296
|
+
/**
|
|
297
|
+
* The serialisable name of one object in one volume.
|
|
298
|
+
*
|
|
299
|
+
* @category models
|
|
300
|
+
* @since 0.6.0
|
|
301
|
+
*/
|
|
302
|
+
export type ReferenceKey = typeof ReferenceKey.Type;
|
|
258
303
|
/**
|
|
259
304
|
* Schema for optional volume capacity and path limits.
|
|
260
305
|
*
|
|
261
306
|
* @example
|
|
262
307
|
* ```ts
|
|
263
308
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
264
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
265
309
|
* import { ByteSize, Effect } from "effect"
|
|
266
310
|
*
|
|
267
311
|
* // Every limit is optional, and each one is enforced once set.
|
|
@@ -274,18 +318,18 @@ export type VolumeIncarnation = typeof VolumeIncarnation.Type;
|
|
|
274
318
|
* create: "exclusive"
|
|
275
319
|
* }).pipe(
|
|
276
320
|
* Effect.as("written"),
|
|
277
|
-
* Effect.catchTag("
|
|
321
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed(error.code))
|
|
278
322
|
* )
|
|
279
323
|
* })
|
|
280
324
|
*
|
|
281
|
-
* Effect.runPromise(program
|
|
325
|
+
* Effect.runPromise(program).then(console.log)
|
|
282
326
|
* // FileTooLarge
|
|
283
327
|
* ```
|
|
284
328
|
*
|
|
285
329
|
* @category schemas
|
|
286
330
|
* @since 0.1.0
|
|
287
331
|
*/
|
|
288
|
-
export declare const VolumeOptions: typeof
|
|
332
|
+
export declare const VolumeOptions: typeof VolumeModule.VolumeOptions;
|
|
289
333
|
/**
|
|
290
334
|
* Capacity, admission, watch retention, and path limits for a volume.
|
|
291
335
|
* `maxPendingOperations` defaults to 64 and `maxWatchEvents` defaults to 256.
|
|
@@ -328,7 +372,6 @@ export interface VolumeUsage {
|
|
|
328
372
|
* @example
|
|
329
373
|
* ```ts
|
|
330
374
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
331
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
332
375
|
* import { Effect } from "effect"
|
|
333
376
|
*
|
|
334
377
|
* // Sizes and inode numbers are bigint; times are nanosecond timestamps.
|
|
@@ -345,14 +388,14 @@ export interface VolumeUsage {
|
|
|
345
388
|
* return [metadata.kind, metadata.size, metadata.nlink]
|
|
346
389
|
* })
|
|
347
390
|
*
|
|
348
|
-
* Effect.runPromise(program
|
|
391
|
+
* Effect.runPromise(program).then(console.log)
|
|
349
392
|
* // [ 'file', 3n, 1 ]
|
|
350
393
|
* ```
|
|
351
394
|
*
|
|
352
395
|
* @category schemas
|
|
353
396
|
* @since 0.1.0
|
|
354
397
|
*/
|
|
355
|
-
export declare const Metadata: typeof
|
|
398
|
+
export declare const Metadata: typeof MetadataModule.Metadata;
|
|
356
399
|
/**
|
|
357
400
|
* Metadata for a directory, regular file, or symbolic link.
|
|
358
401
|
*
|
|
@@ -375,7 +418,6 @@ export interface ObjectReference {
|
|
|
375
418
|
* @example
|
|
376
419
|
* ```ts
|
|
377
420
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
378
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
379
421
|
* import { Effect } from "effect"
|
|
380
422
|
*
|
|
381
423
|
* // References survive renames, and each observation carries the revision it
|
|
@@ -385,20 +427,20 @@ export interface ObjectReference {
|
|
|
385
427
|
*
|
|
386
428
|
* yield* caller.mkdir("/work")
|
|
387
429
|
*
|
|
388
|
-
* const root = yield* caller.
|
|
389
|
-
* const work = yield* caller.
|
|
430
|
+
* const root = yield* caller.root
|
|
431
|
+
* const work = yield* caller.lookup(Vfs.Entry(root, "work"))
|
|
390
432
|
*
|
|
391
|
-
* const before = yield* caller.
|
|
433
|
+
* const before = yield* caller.stat(work)
|
|
392
434
|
*
|
|
393
435
|
* yield* caller.rename("/work", "/moved")
|
|
394
436
|
*
|
|
395
|
-
* const after = yield* caller.
|
|
437
|
+
* const after = yield* caller.stat(work)
|
|
396
438
|
*
|
|
397
|
-
* return [before.
|
|
439
|
+
* return [before.kind, after.kind, after.revision > before.revision]
|
|
398
440
|
* })
|
|
399
441
|
*
|
|
400
|
-
* Effect.runPromise(program
|
|
401
|
-
* // [ 'directory', 'directory' ]
|
|
442
|
+
* Effect.runPromise(program).then(console.log)
|
|
443
|
+
* // [ 'directory', 'directory', true ]
|
|
402
444
|
* ```
|
|
403
445
|
*
|
|
404
446
|
* @category models
|
|
@@ -418,13 +460,60 @@ export interface DirectoryEntry {
|
|
|
418
460
|
readonly name: Uint8Array;
|
|
419
461
|
readonly reference: ObjectReference;
|
|
420
462
|
}
|
|
463
|
+
/**
|
|
464
|
+
* One entry a walk reached: its path below the walk's root, its name, the
|
|
465
|
+
* object it names and the directory it was listed in, its kind, and its depth.
|
|
466
|
+
*
|
|
467
|
+
* **Details**
|
|
468
|
+
*
|
|
469
|
+
* `path` is relative to the walk's root, with no leading slash (`a/b` for
|
|
470
|
+
* `b` in the root's child `a`), so it reads the same whichever way the root
|
|
471
|
+
* was addressed; the root itself is not an entry. `depth` is 1 for a child of
|
|
472
|
+
* the root. A symbolic link is reported as a link and never followed.
|
|
473
|
+
*
|
|
474
|
+
* @category models
|
|
475
|
+
* @since 0.6.0
|
|
476
|
+
*/
|
|
477
|
+
export interface WalkEntry {
|
|
478
|
+
readonly path: BytePath;
|
|
479
|
+
readonly name: Uint8Array;
|
|
480
|
+
readonly reference: ObjectReference;
|
|
481
|
+
readonly directory: ObjectReference;
|
|
482
|
+
readonly kind: Metadata["kind"];
|
|
483
|
+
readonly depth: number;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* What a walk fails with: a failure of the directory it lists, or
|
|
487
|
+
* `LimitExceeded` when it would pass one of its bounds, which `field` names.
|
|
488
|
+
*
|
|
489
|
+
* @category models
|
|
490
|
+
* @since 0.6.0
|
|
491
|
+
*/
|
|
492
|
+
export type WalkFailure = FsFailure | (VfsError & {
|
|
493
|
+
readonly code: "LimitExceeded";
|
|
494
|
+
});
|
|
495
|
+
/**
|
|
496
|
+
* Settings for walking a directory tree: the order and the optional depth,
|
|
497
|
+
* entry, and byte bounds.
|
|
498
|
+
*
|
|
499
|
+
* @category schemas
|
|
500
|
+
* @since 0.6.0
|
|
501
|
+
*/
|
|
502
|
+
export declare const WalkOptions: typeof CallerModule.WalkOptions;
|
|
503
|
+
/**
|
|
504
|
+
* Settings for walking a directory tree.
|
|
505
|
+
*
|
|
506
|
+
* @category models
|
|
507
|
+
* @since 0.6.0
|
|
508
|
+
*/
|
|
509
|
+
export type WalkOptions = typeof WalkOptions.Type;
|
|
421
510
|
/**
|
|
422
511
|
* A directory revision transition captured inside one coordinated operation.
|
|
423
512
|
*
|
|
424
513
|
* @category schemas
|
|
425
514
|
* @since 0.4.0
|
|
426
515
|
*/
|
|
427
|
-
export declare const DirectoryChange: typeof
|
|
516
|
+
export declare const DirectoryChange: typeof CallerModule.DirectoryChange;
|
|
428
517
|
/**
|
|
429
518
|
* A directory revision transition captured inside one coordinated operation.
|
|
430
519
|
*
|
|
@@ -448,7 +537,7 @@ export interface ReferenceEntryResult {
|
|
|
448
537
|
* @category schemas
|
|
449
538
|
* @since 0.4.0
|
|
450
539
|
*/
|
|
451
|
-
export declare const RenameReferenceResult: typeof
|
|
540
|
+
export declare const RenameReferenceResult: typeof CallerModule.RenameReferenceResult;
|
|
452
541
|
/**
|
|
453
542
|
* The directory transitions produced by a same-directory or cross-directory rename.
|
|
454
543
|
*
|
|
@@ -456,64 +545,13 @@ export declare const RenameReferenceResult: typeof VfsModel.RenameReferenceResul
|
|
|
456
545
|
* @since 0.4.0
|
|
457
546
|
*/
|
|
458
547
|
export type RenameReferenceResult = typeof RenameReferenceResult.Type;
|
|
459
|
-
/**
|
|
460
|
-
* Resolves a relative path from a live directory handle instead of the caller's directory.
|
|
461
|
-
*
|
|
462
|
-
* @category models
|
|
463
|
-
* @since 0.1.0
|
|
464
|
-
*/
|
|
465
|
-
export interface RelativeOptions {
|
|
466
|
-
/** Resolve relative paths from this live, same-volume handle instead of the caller's current directory. */
|
|
467
|
-
readonly relativeTo?: DirectoryHandle;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Controls the base directory and whether metadata operations follow the final symbolic link.
|
|
471
|
-
*
|
|
472
|
-
* @example
|
|
473
|
-
* ```ts
|
|
474
|
-
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
475
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
476
|
-
* import { Effect } from "effect"
|
|
477
|
-
*
|
|
478
|
-
* const program = Effect.gen(function*() {
|
|
479
|
-
* const caller = yield* (yield* Vfs.make()).caller()
|
|
480
|
-
*
|
|
481
|
-
* yield* caller.writeFile("/target", new Uint8Array([1]), {
|
|
482
|
-
* access: "write",
|
|
483
|
-
* create: "exclusive",
|
|
484
|
-
* mode: 0o644
|
|
485
|
-
* })
|
|
486
|
-
* yield* caller.symlink("/target", "/link")
|
|
487
|
-
*
|
|
488
|
-
* // Metadata operations follow the final link by default, so this reaches the
|
|
489
|
-
* // target; opting out changes the link itself and leaves the target alone.
|
|
490
|
-
* yield* caller.chmod("/link", 0o600)
|
|
491
|
-
* const followed = (yield* caller.stat("/target")).mode & 0o777
|
|
492
|
-
*
|
|
493
|
-
* yield* caller.chmod("/link", 0o777, { followFinalSymlink: false })
|
|
494
|
-
* const unchanged = (yield* caller.stat("/target")).mode & 0o777
|
|
495
|
-
*
|
|
496
|
-
* return [followed.toString(8), unchanged.toString(8)]
|
|
497
|
-
* })
|
|
498
|
-
*
|
|
499
|
-
* Effect.runPromise(program.pipe(Effect.provide(NodeCrypto.layer))).then(console.log)
|
|
500
|
-
* // [ '600', '600' ]
|
|
501
|
-
* ```
|
|
502
|
-
*
|
|
503
|
-
* @category models
|
|
504
|
-
* @since 0.1.0
|
|
505
|
-
*/
|
|
506
|
-
export interface MetadataOptions extends RelativeOptions {
|
|
507
|
-
/** Follow the final symbolic link. Defaults to `true`. */
|
|
508
|
-
readonly followFinalSymlink?: boolean;
|
|
509
|
-
}
|
|
510
548
|
/**
|
|
511
549
|
* Schema for an owner update. Omitted fields retain their existing values.
|
|
512
550
|
*
|
|
513
551
|
* @category schemas
|
|
514
552
|
* @since 0.1.0
|
|
515
553
|
*/
|
|
516
|
-
export declare const OwnerUpdate: typeof
|
|
554
|
+
export declare const OwnerUpdate: typeof MetadataModule.OwnerUpdate;
|
|
517
555
|
/**
|
|
518
556
|
* An owner update for `chown` operations.
|
|
519
557
|
*
|
|
@@ -527,14 +565,13 @@ export type OwnerUpdate = typeof OwnerUpdate.Type;
|
|
|
527
565
|
* @category schemas
|
|
528
566
|
* @since 0.1.0
|
|
529
567
|
*/
|
|
530
|
-
export declare const TimeUpdate: typeof
|
|
568
|
+
export declare const TimeUpdate: typeof MetadataModule.TimeUpdate;
|
|
531
569
|
/**
|
|
532
570
|
* Schema for independent access and modification time updates.
|
|
533
571
|
*
|
|
534
572
|
* @example
|
|
535
573
|
* ```ts
|
|
536
574
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
537
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
538
575
|
* import { Effect } from "effect"
|
|
539
576
|
*
|
|
540
577
|
* const program = Effect.gen(function*() {
|
|
@@ -556,14 +593,14 @@ export declare const TimeUpdate: typeof VfsModel.TimeUpdate;
|
|
|
556
593
|
* return [metadata.atimeNs, metadata.mtimeNs === 1_000n]
|
|
557
594
|
* })
|
|
558
595
|
*
|
|
559
|
-
* Effect.runPromise(program
|
|
596
|
+
* Effect.runPromise(program).then(console.log)
|
|
560
597
|
* // [ 1000n, false ]
|
|
561
598
|
* ```
|
|
562
599
|
*
|
|
563
600
|
* @category schemas
|
|
564
601
|
* @since 0.1.0
|
|
565
602
|
*/
|
|
566
|
-
export declare const Times: typeof
|
|
603
|
+
export declare const Times: typeof MetadataModule.Times;
|
|
567
604
|
/**
|
|
568
605
|
* Access and modification time updates for `utimes` operations.
|
|
569
606
|
*
|
|
@@ -577,7 +614,6 @@ export type Times = typeof Times.Type;
|
|
|
577
614
|
* @example
|
|
578
615
|
* ```ts
|
|
579
616
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
580
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
581
617
|
* import { Effect } from "effect"
|
|
582
618
|
*
|
|
583
619
|
* // The handle anchors relative paths to the directory itself, so a rename in
|
|
@@ -590,16 +626,15 @@ export type Times = typeof Times.Type;
|
|
|
590
626
|
* const directory = yield* caller.openDirectory("/project")
|
|
591
627
|
*
|
|
592
628
|
* yield* caller.rename("/project", "/renamed")
|
|
593
|
-
* yield* caller.writeFile("notes.txt", new TextEncoder().encode("kept"), {
|
|
629
|
+
* yield* caller.writeFile(Vfs.Target.Path({ path: "notes.txt", relativeTo: directory }), new TextEncoder().encode("kept"), {
|
|
594
630
|
* access: "write",
|
|
595
|
-
* create: "exclusive"
|
|
596
|
-
* relativeTo: directory
|
|
631
|
+
* create: "exclusive"
|
|
597
632
|
* })
|
|
598
633
|
*
|
|
599
|
-
* return yield* caller.readDirectory("/renamed")
|
|
634
|
+
* return (yield* caller.readDirectory("/renamed")).value.map((entry) => new TextDecoder().decode(entry.name))
|
|
600
635
|
* }).pipe(Effect.scoped)
|
|
601
636
|
*
|
|
602
|
-
* Effect.runPromise(program
|
|
637
|
+
* Effect.runPromise(program).then(console.log)
|
|
603
638
|
* // [ 'notes.txt' ]
|
|
604
639
|
* ```
|
|
605
640
|
*
|
|
@@ -608,8 +643,8 @@ export type Times = typeof Times.Type;
|
|
|
608
643
|
*/
|
|
609
644
|
export interface DirectoryHandle {
|
|
610
645
|
readonly [DirectoryHandleId]: true;
|
|
611
|
-
readonly stat: Effect.Effect<Metadata,
|
|
612
|
-
readonly close: Effect.Effect<void,
|
|
646
|
+
readonly stat: Effect.Effect<Metadata, FsFailure>;
|
|
647
|
+
readonly close: Effect.Effect<void, FsFailure>;
|
|
613
648
|
}
|
|
614
649
|
/**
|
|
615
650
|
* Schema for file seek origins, including dense-file data and hole queries.
|
|
@@ -617,7 +652,7 @@ export interface DirectoryHandle {
|
|
|
617
652
|
* @category schemas
|
|
618
653
|
* @since 0.1.0
|
|
619
654
|
*/
|
|
620
|
-
export declare const SeekMode: typeof
|
|
655
|
+
export declare const SeekMode: typeof FileHandleModule.SeekMode;
|
|
621
656
|
/**
|
|
622
657
|
* The origin used by a file handle seek operation.
|
|
623
658
|
*
|
|
@@ -631,7 +666,6 @@ export type SeekMode = typeof SeekMode.Type;
|
|
|
631
666
|
* @example
|
|
632
667
|
* ```ts
|
|
633
668
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
634
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
635
669
|
* import { Effect } from "effect"
|
|
636
670
|
*
|
|
637
671
|
* // `access` is required; `create` decides whether a missing file is an error.
|
|
@@ -649,65 +683,86 @@ export type SeekMode = typeof SeekMode.Type;
|
|
|
649
683
|
* return (yield* handle.stat).size
|
|
650
684
|
* }).pipe(Effect.scoped)
|
|
651
685
|
*
|
|
652
|
-
* Effect.runPromise(program
|
|
686
|
+
* Effect.runPromise(program).then(console.log)
|
|
653
687
|
* // 2n
|
|
654
688
|
* ```
|
|
655
689
|
*
|
|
656
690
|
* @category schemas
|
|
657
691
|
* @since 0.1.0
|
|
658
692
|
*/
|
|
659
|
-
export declare const
|
|
693
|
+
export declare const OpenOptions: typeof CallerModule.OpenOptions;
|
|
660
694
|
/**
|
|
661
|
-
* Options
|
|
695
|
+
* Options of `open` on a target.
|
|
662
696
|
*
|
|
663
697
|
* @category models
|
|
664
698
|
* @since 0.1.0
|
|
665
699
|
*/
|
|
666
|
-
export type OpenOptions = typeof
|
|
700
|
+
export type OpenOptions = typeof OpenOptions.Type;
|
|
667
701
|
/**
|
|
668
702
|
* Settings for creating a directory through a parent object reference.
|
|
669
703
|
* `exactMode` skips the caller's umask for an explicit creation mode; permission policy still applies.
|
|
704
|
+
* `recursive` creates every missing directory on a path in one change, as `mkdir -p` does.
|
|
670
705
|
*
|
|
671
706
|
* @category schemas
|
|
672
707
|
* @since 0.4.0
|
|
673
708
|
*/
|
|
674
|
-
export declare const
|
|
709
|
+
export declare const MkdirOptions: typeof CallerModule.MkdirOptions;
|
|
675
710
|
/**
|
|
676
711
|
* Settings for creating a directory through a parent object reference.
|
|
677
712
|
* `exactMode` skips the caller's umask for an explicit creation mode; permission policy still applies.
|
|
713
|
+
* `recursive` creates every missing directory on a path in one change, as `mkdir -p` does.
|
|
678
714
|
*
|
|
679
715
|
* @category models
|
|
680
716
|
* @since 0.4.0
|
|
681
717
|
*/
|
|
682
|
-
export type
|
|
718
|
+
export type MkdirOptions = typeof MkdirOptions.Type;
|
|
719
|
+
/**
|
|
720
|
+
* Settings for removing an entry: whether a directory goes with everything
|
|
721
|
+
* under it, and whether a missing target is success.
|
|
722
|
+
*
|
|
723
|
+
* @category schemas
|
|
724
|
+
* @since 0.6.0
|
|
725
|
+
*/
|
|
726
|
+
export declare const RemoveOptions: typeof CallerModule.RemoveOptions;
|
|
727
|
+
/**
|
|
728
|
+
* Settings for removing an entry.
|
|
729
|
+
*
|
|
730
|
+
* @category models
|
|
731
|
+
* @since 0.6.0
|
|
732
|
+
*/
|
|
733
|
+
export type RemoveOptions = typeof RemoveOptions.Type;
|
|
683
734
|
/**
|
|
684
735
|
* Settings for creating a symbolic link through a parent object reference.
|
|
685
736
|
*
|
|
686
737
|
* @category schemas
|
|
687
738
|
* @since 0.4.0
|
|
688
739
|
*/
|
|
689
|
-
export declare const
|
|
740
|
+
export declare const SymlinkOptions: typeof CallerModule.SymlinkOptions;
|
|
690
741
|
/**
|
|
691
742
|
* Settings for creating a symbolic link through a parent object reference.
|
|
692
743
|
*
|
|
693
744
|
* @category models
|
|
694
745
|
* @since 0.4.0
|
|
695
746
|
*/
|
|
696
|
-
export type
|
|
747
|
+
export type SymlinkOptions = typeof SymlinkOptions.Type;
|
|
697
748
|
/**
|
|
698
|
-
*
|
|
749
|
+
* The attributes `setattr` changes together: a regular file's size, the
|
|
750
|
+
* permission mode, the owner, and the access and modification times. An
|
|
751
|
+
* omitted attribute keeps its current value. `expected` pins the revision the
|
|
752
|
+
* caller last observed and fails as `StaleReference` naming `expected` when
|
|
753
|
+
* the target has moved on.
|
|
699
754
|
*
|
|
700
755
|
* @category schemas
|
|
701
|
-
* @since 0.
|
|
756
|
+
* @since 0.6.0
|
|
702
757
|
*/
|
|
703
|
-
export declare const
|
|
758
|
+
export declare const SetattrOptions: typeof CallerModule.SetattrOptions;
|
|
704
759
|
/**
|
|
705
|
-
*
|
|
760
|
+
* The attributes `setattr` changes together.
|
|
706
761
|
*
|
|
707
762
|
* @category models
|
|
708
|
-
* @since 0.
|
|
763
|
+
* @since 0.6.0
|
|
709
764
|
*/
|
|
710
|
-
export type
|
|
765
|
+
export type SetattrOptions = typeof SetattrOptions.Type;
|
|
711
766
|
/**
|
|
712
767
|
* Settings for atomically looking up or creating and opening one referenced child.
|
|
713
768
|
* `exactMode` skips the caller's umask for an explicit creation mode; permission policy still applies.
|
|
@@ -715,7 +770,7 @@ export type OpenReferenceSettings = typeof OpenReferenceSettings.Type;
|
|
|
715
770
|
* @category schemas
|
|
716
771
|
* @since 0.4.0
|
|
717
772
|
*/
|
|
718
|
-
export declare const
|
|
773
|
+
export declare const OpenEntryOptions: typeof CallerModule.OpenEntryOptions;
|
|
719
774
|
/**
|
|
720
775
|
* Settings for atomically looking up or creating and opening one referenced child.
|
|
721
776
|
* `exactMode` skips the caller's umask for an explicit creation mode; permission policy still applies.
|
|
@@ -728,14 +783,14 @@ export declare const OpenChildReferenceSettings: typeof VfsModel.OpenChildRefere
|
|
|
728
783
|
* @category models
|
|
729
784
|
* @since 0.4.0
|
|
730
785
|
*/
|
|
731
|
-
export type
|
|
786
|
+
export type OpenEntryOptions = typeof OpenEntryOptions.Type;
|
|
732
787
|
/**
|
|
733
788
|
* A scoped child-open result captured inside one coordinated operation.
|
|
734
789
|
*
|
|
735
790
|
* @category models
|
|
736
791
|
* @since 0.4.0
|
|
737
792
|
*/
|
|
738
|
-
export interface
|
|
793
|
+
export interface OpenEntryResult {
|
|
739
794
|
readonly handle: FileHandle;
|
|
740
795
|
readonly reference: ObjectReference;
|
|
741
796
|
readonly created: boolean;
|
|
@@ -747,7 +802,6 @@ export interface OpenChildReferenceResult {
|
|
|
747
802
|
* @example
|
|
748
803
|
* ```ts
|
|
749
804
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
750
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
751
805
|
* import { Effect } from "effect"
|
|
752
806
|
*
|
|
753
807
|
* const program = Effect.gen(function*() {
|
|
@@ -767,7 +821,7 @@ export interface OpenChildReferenceResult {
|
|
|
767
821
|
* create: "exclusive"
|
|
768
822
|
* }).pipe(
|
|
769
823
|
* Effect.as("replaced"),
|
|
770
|
-
* Effect.catchTag("
|
|
824
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed(error.code))
|
|
771
825
|
* )
|
|
772
826
|
*
|
|
773
827
|
* yield* caller.writeFile("/app.conf", bytes, { access: "write", truncate: true })
|
|
@@ -775,21 +829,37 @@ export interface OpenChildReferenceResult {
|
|
|
775
829
|
* return [refused, new TextDecoder().decode(yield* caller.readFile("/app.conf"))]
|
|
776
830
|
* })
|
|
777
831
|
*
|
|
778
|
-
* Effect.runPromise(program
|
|
832
|
+
* Effect.runPromise(program).then(console.log)
|
|
779
833
|
* // [ 'AlreadyExists', 'v2' ]
|
|
780
834
|
* ```
|
|
781
835
|
*
|
|
782
836
|
* @category models
|
|
783
837
|
* @since 0.1.0
|
|
784
838
|
*/
|
|
785
|
-
export
|
|
839
|
+
export declare const WriteFileOptions: typeof CallerModule.WriteFileOptions;
|
|
840
|
+
/**
|
|
841
|
+
* Options of `writeFile`.
|
|
842
|
+
*
|
|
843
|
+
* @category models
|
|
844
|
+
* @since 0.1.0
|
|
845
|
+
*/
|
|
846
|
+
export type WriteFileOptions = typeof WriteFileOptions.Type;
|
|
847
|
+
/**
|
|
848
|
+
* The bytes a positional read returned and whether they reach the end of the file.
|
|
849
|
+
*
|
|
850
|
+
* @category models
|
|
851
|
+
* @since 0.6.0
|
|
852
|
+
*/
|
|
853
|
+
export interface ReadResult {
|
|
854
|
+
readonly bytes: Uint8Array;
|
|
855
|
+
readonly eof: boolean;
|
|
856
|
+
}
|
|
786
857
|
/**
|
|
787
858
|
* A scoped regular-file capability with an independent bigint cursor.
|
|
788
859
|
*
|
|
789
860
|
* @example
|
|
790
861
|
* ```ts
|
|
791
862
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
792
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
793
863
|
* import { Effect } from "effect"
|
|
794
864
|
*
|
|
795
865
|
* const program = Effect.gen(function*() {
|
|
@@ -805,11 +875,11 @@ export type WriteFileOptions = VfsModel.WriteFileOptions;
|
|
|
805
875
|
* // `pread` reads at an offset and leaves the cursor where writing left it.
|
|
806
876
|
* const slice = yield* handle.pread(2, 1n)
|
|
807
877
|
*
|
|
808
|
-
* return [slice, yield* handle.seek(0n, "current")]
|
|
878
|
+
* return [slice.bytes, slice.eof, yield* handle.seek(0n, "current")]
|
|
809
879
|
* }).pipe(Effect.scoped)
|
|
810
880
|
*
|
|
811
|
-
* Effect.runPromise(program
|
|
812
|
-
* // [ Uint8Array(2) [ 2, 3 ], 4n ]
|
|
881
|
+
* Effect.runPromise(program).then(console.log)
|
|
882
|
+
* // [ Uint8Array(2) [ 2, 3 ], false, 4n ]
|
|
813
883
|
* ```
|
|
814
884
|
*
|
|
815
885
|
* @category models
|
|
@@ -818,23 +888,23 @@ export type WriteFileOptions = VfsModel.WriteFileOptions;
|
|
|
818
888
|
export interface FileHandle {
|
|
819
889
|
readonly [FileHandleId]: true;
|
|
820
890
|
/** Reads up to `maximumBytes` from the cursor and advances it by the returned length. */
|
|
821
|
-
readonly read: (maximumBytes: number) => Effect.Effect<Uint8Array,
|
|
891
|
+
readonly read: (maximumBytes: number) => Effect.Effect<Uint8Array, FsFailure>;
|
|
822
892
|
/** Reads at `offset` without changing the cursor. */
|
|
823
|
-
readonly pread: (maximumBytes: number, offset: bigint) => Effect.Effect<
|
|
893
|
+
readonly pread: (maximumBytes: number, offset: bigint) => Effect.Effect<ReadResult, FsFailure>;
|
|
824
894
|
/** Writes at the cursor and advances it, or writes at end of file when opened for append. */
|
|
825
|
-
readonly write: (bytes: Uint8Array) => Effect.Effect<number,
|
|
895
|
+
readonly write: (bytes: Uint8Array) => Effect.Effect<number, FsFailure>;
|
|
826
896
|
/** Writes at `offset` without changing the cursor. Append mode does not affect positional writes. */
|
|
827
|
-
readonly pwrite: (bytes: Uint8Array, offset: bigint) => Effect.Effect<number,
|
|
897
|
+
readonly pwrite: (bytes: Uint8Array, offset: bigint) => Effect.Effect<number, FsFailure>;
|
|
828
898
|
/** Moves the cursor and returns its new offset. `data` finds content and `hole` finds end of file. */
|
|
829
|
-
readonly seek: (offset: bigint, mode: SeekMode) => Effect.Effect<bigint,
|
|
899
|
+
readonly seek: (offset: bigint, mode: SeekMode) => Effect.Effect<bigint, FsFailure>;
|
|
830
900
|
/** Sets the file length without changing the cursor. */
|
|
831
|
-
readonly truncate: (length: bigint) => Effect.Effect<void,
|
|
901
|
+
readonly truncate: (length: bigint) => Effect.Effect<void, FsFailure>;
|
|
832
902
|
/** Reads metadata for the open file. */
|
|
833
|
-
readonly stat: Effect.Effect<Metadata,
|
|
903
|
+
readonly stat: Effect.Effect<Metadata, FsFailure>;
|
|
834
904
|
/** Checks handle and provider health. Durable mutations have already committed; memory volumes have nothing to flush. */
|
|
835
|
-
readonly sync: Effect.Effect<void,
|
|
905
|
+
readonly sync: Effect.Effect<void, FsFailure>;
|
|
836
906
|
/** Closes the handle. A repeated explicit close fails; scope cleanup remains safe. */
|
|
837
|
-
readonly close: Effect.Effect<void,
|
|
907
|
+
readonly close: Effect.Effect<void, FsFailure>;
|
|
838
908
|
}
|
|
839
909
|
/**
|
|
840
910
|
* A filesystem caller with its own identity, creation mask, and current directory.
|
|
@@ -842,7 +912,6 @@ export interface FileHandle {
|
|
|
842
912
|
* @example
|
|
843
913
|
* ```ts
|
|
844
914
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
845
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
846
915
|
* import { Effect } from "effect"
|
|
847
916
|
*
|
|
848
917
|
* // Whole-file reads and writes need no scope. `writeFile` always takes an
|
|
@@ -857,17 +926,16 @@ export interface FileHandle {
|
|
|
857
926
|
* create: "exclusive"
|
|
858
927
|
* })
|
|
859
928
|
*
|
|
860
|
-
* return yield* caller.readDirectory("/work")
|
|
929
|
+
* return (yield* caller.readDirectory("/work")).value.map((entry) => new TextDecoder().decode(entry.name))
|
|
861
930
|
* })
|
|
862
931
|
*
|
|
863
|
-
* Effect.runPromise(program
|
|
932
|
+
* Effect.runPromise(program).then(console.log)
|
|
864
933
|
* // [ 'notes.txt' ]
|
|
865
934
|
* ```
|
|
866
935
|
*
|
|
867
936
|
* @example
|
|
868
937
|
* ```ts
|
|
869
938
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
870
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
871
939
|
* import { Effect } from "effect"
|
|
872
940
|
*
|
|
873
941
|
* // Reach for a handle when a whole-file write will not do. A handle carries a
|
|
@@ -887,14 +955,13 @@ export interface FileHandle {
|
|
|
887
955
|
* return new TextDecoder().decode(yield* handle.read(64))
|
|
888
956
|
* }).pipe(Effect.scoped)
|
|
889
957
|
*
|
|
890
|
-
* Effect.runPromise(program
|
|
958
|
+
* Effect.runPromise(program).then(console.log)
|
|
891
959
|
* // first second
|
|
892
960
|
* ```
|
|
893
961
|
*
|
|
894
962
|
* @example
|
|
895
963
|
* ```ts
|
|
896
964
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
897
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
898
965
|
* import { Effect } from "effect"
|
|
899
966
|
*
|
|
900
967
|
* // A derived caller holds the directory's identity, not its path, so renaming
|
|
@@ -912,10 +979,10 @@ export interface FileHandle {
|
|
|
912
979
|
* create: "exclusive"
|
|
913
980
|
* })
|
|
914
981
|
*
|
|
915
|
-
* return yield* caller.readDirectory("/dist")
|
|
982
|
+
* return (yield* caller.readDirectory("/dist")).value.map((entry) => new TextDecoder().decode(entry.name))
|
|
916
983
|
* }).pipe(Effect.scoped)
|
|
917
984
|
*
|
|
918
|
-
* Effect.runPromise(program
|
|
985
|
+
* Effect.runPromise(program).then(console.log)
|
|
919
986
|
* // [ 'out.txt' ]
|
|
920
987
|
* ```
|
|
921
988
|
*
|
|
@@ -925,109 +992,99 @@ export interface FileHandle {
|
|
|
925
992
|
*/
|
|
926
993
|
export interface Caller {
|
|
927
994
|
readonly [CallerId]: true;
|
|
928
|
-
/**
|
|
929
|
-
readonly
|
|
930
|
-
/**
|
|
931
|
-
readonly
|
|
932
|
-
/**
|
|
933
|
-
readonly
|
|
934
|
-
/**
|
|
935
|
-
readonly
|
|
936
|
-
/**
|
|
937
|
-
readonly
|
|
938
|
-
/**
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
readonly
|
|
948
|
-
/**
|
|
949
|
-
readonly
|
|
950
|
-
/**
|
|
951
|
-
readonly
|
|
952
|
-
/**
|
|
953
|
-
readonly
|
|
954
|
-
/**
|
|
955
|
-
readonly
|
|
956
|
-
/**
|
|
957
|
-
readonly
|
|
958
|
-
/**
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
/**
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
readonly truncate: (path: PathInput, length: bigint, options?: RelativeOptions) => Effect.Effect<void, FsError>;
|
|
983
|
-
/** Changes permission bits, following the final symbolic link by default. */
|
|
984
|
-
readonly chmod: (path: PathInput, mode: number, options?: MetadataOptions) => Effect.Effect<void, FsError>;
|
|
985
|
-
/** Changes uid, gid, or both, following the final symbolic link by default. */
|
|
986
|
-
readonly chown: (path: PathInput, owner: OwnerUpdate, options?: MetadataOptions) => Effect.Effect<void, FsError>;
|
|
987
|
-
/** Updates access and modification times, following the final symbolic link by default. */
|
|
988
|
-
readonly utimes: (path: PathInput, times: Times, options?: MetadataOptions) => Effect.Effect<void, FsError>;
|
|
989
|
-
/** Changes permission bits through a live, same-volume handle. */
|
|
990
|
-
readonly chmodHandle: (handle: FileHandle | DirectoryHandle, mode: number) => Effect.Effect<void, FsError>;
|
|
991
|
-
/** Changes uid, gid, or both through a live, same-volume handle. */
|
|
992
|
-
readonly chownHandle: (handle: FileHandle | DirectoryHandle, owner: OwnerUpdate) => Effect.Effect<void, FsError>;
|
|
993
|
-
/** Updates access and modification times through a live, same-volume handle. */
|
|
994
|
-
readonly utimesHandle: (handle: FileHandle | DirectoryHandle, times: Times) => Effect.Effect<void, FsError>;
|
|
995
|
-
/** Reads metadata without following the final symbolic link. */
|
|
996
|
-
readonly lstat: (path: PathInput, options?: RelativeOptions) => Effect.Effect<Metadata, FsError>;
|
|
997
|
-
/** Creates a hard link to an existing non-directory entry. */
|
|
998
|
-
readonly link: (source: PathInput, destination: PathInput, options?: {
|
|
999
|
-
readonly sourceRelativeTo?: DirectoryHandle;
|
|
1000
|
-
readonly destinationRelativeTo?: DirectoryHandle;
|
|
1001
|
-
readonly followSourceSymlink?: boolean;
|
|
1002
|
-
}) => Effect.Effect<void, FsError>;
|
|
1003
|
-
/** Creates a symbolic link. The target bytes are stored without resolving them. */
|
|
1004
|
-
readonly symlink: (target: PathInput, path: PathInput, options?: RelativeOptions) => Effect.Effect<void, FsError>;
|
|
1005
|
-
/** Reads a symbolic-link target as UTF-8, failing `UnrepresentableName` for other bytes. See `readLinkBytes`. */
|
|
1006
|
-
readonly readLink: (path: PathInput, options?: RelativeOptions) => Effect.Effect<string, FsError>;
|
|
1007
|
-
/** Reads a symbolic-link target as owned bytes. */
|
|
1008
|
-
readonly readLinkBytes: (path: PathInput, options?: RelativeOptions) => Effect.Effect<Uint8Array, FsError>;
|
|
1009
|
-
/** Reads directory names as UTF-8, failing `UnrepresentableName` for other bytes. See `readDirectoryBytes`. */
|
|
1010
|
-
readonly readDirectory: (path: PathInput, options?: RelativeOptions) => Effect.Effect<ReadonlyArray<string>, FsError>;
|
|
1011
|
-
/** Reads directory names as owned byte arrays. */
|
|
1012
|
-
readonly readDirectoryBytes: (path: PathInput, options?: RelativeOptions) => Effect.Effect<ReadonlyArray<Uint8Array>, FsError>;
|
|
1013
|
-
/** Resolves links and normalizes a path as UTF-8, failing `UnrepresentableName` for other bytes. See `realPathBytes`. */
|
|
1014
|
-
readonly realPath: (path: PathInput, options?: RelativeOptions) => Effect.Effect<string, FsError>;
|
|
1015
|
-
/** Resolves links and normalizes a path without requiring UTF-8 names. */
|
|
1016
|
-
readonly realPathBytes: (path: PathInput, options?: RelativeOptions) => Effect.Effect<BytePath, FsError>;
|
|
1017
|
-
/** Opens a scoped regular-file handle. The surrounding scope closes it automatically. */
|
|
1018
|
-
readonly open: (path: PathInput, options: OpenOptions) => Effect.Effect<FileHandle, FsError, Scope.Scope>;
|
|
1019
|
-
/** Removes a non-directory entry. Open handles remain usable until closed. */
|
|
1020
|
-
readonly unlink: (path: PathInput, options?: RelativeOptions) => Effect.Effect<void, FsError>;
|
|
995
|
+
/** The reference of the volume's root directory. */
|
|
996
|
+
readonly root: Effect.Effect<ObjectReference, FsFailure>;
|
|
997
|
+
/** The reference of a child of a directory, without following it. */
|
|
998
|
+
readonly lookup: (entry: EntryInput) => Effect.Effect<ObjectReference, FsFailure>;
|
|
999
|
+
/** The reference of a directory's parent; the root is its own parent. */
|
|
1000
|
+
readonly parent: (directory: TargetInput) => Effect.Effect<ObjectReference, FsFailure>;
|
|
1001
|
+
/** Metadata and revision of a target. A path follows a final symbolic link unless its target says otherwise. */
|
|
1002
|
+
readonly stat: (target: TargetInput) => Effect.Effect<Metadata, FsFailure>;
|
|
1003
|
+
/** The entries of a directory with their references, and the directory's revision. */
|
|
1004
|
+
readonly readDirectory: (directory: TargetInput) => Effect.Effect<ObjectObservation<ReadonlyArray<DirectoryEntry>>, FsFailure>;
|
|
1005
|
+
/**
|
|
1006
|
+
* Every entry below a directory, as a stream that reads one directory at a time and holds no handle. Entries
|
|
1007
|
+
* arrive depth first, each directory's entries in the byte order of their names; symbolic links are reported,
|
|
1008
|
+
* never followed. Each directory is read in one observation, so the walk sees each listing whole but no
|
|
1009
|
+
* snapshot of the tree, and it refreshes no access time. Each directory below the root is reached by name, as a
|
|
1010
|
+
* path lookup reaches it, so it needs search permission on every directory above it, and one that goes away or
|
|
1011
|
+
* is renamed out of the tree before the walk reads it is skipped. A failure below the root names the entry's
|
|
1012
|
+
* path under the path the root was given by, or under the root when it was given by reference or handle.
|
|
1013
|
+
*/
|
|
1014
|
+
readonly walk: (directory: TargetInput, options?: WalkOptions) => Stream.Stream<WalkEntry, WalkFailure>;
|
|
1015
|
+
/** The bytes a symbolic link points at. A path never follows the final link. */
|
|
1016
|
+
readonly readLink: (target: TargetInput) => Effect.Effect<Uint8Array, FsFailure>;
|
|
1017
|
+
/** The canonical absolute path of a target. */
|
|
1018
|
+
readonly realPath: (target: TargetInput) => Effect.Effect<BytePath, FsFailure>;
|
|
1019
|
+
/** The bits of `bits` the caller may exercise on the target: READ, WRITE, EXECUTE as 4, 2, 1. */
|
|
1020
|
+
readonly access: (target: TargetInput, bits?: number) => Effect.Effect<number, FsFailure>;
|
|
1021
|
+
/** The whole content of a regular file. */
|
|
1022
|
+
readonly readFile: (target: TargetInput) => Effect.Effect<Uint8Array, FsFailure>;
|
|
1023
|
+
/** Writes a whole file in one operation, creating or replacing it as the options say. */
|
|
1024
|
+
readonly writeFile: (entry: EntryInput, bytes: Uint8Array, options: WriteFileOptions) => Effect.Effect<void, FsFailure>;
|
|
1025
|
+
/**
|
|
1026
|
+
* Opens a file. On a target, the file must exist and `create` is rejected. On an entry, the name is looked up
|
|
1027
|
+
* and created in one gate hold, and the result reports whether it was created.
|
|
1028
|
+
*/
|
|
1029
|
+
readonly open: {
|
|
1030
|
+
(target: Target | PathInput | ObjectReference | FileHandle, options: OpenOptions): Effect.Effect<FileHandle, FsFailure, Scope.Scope>;
|
|
1031
|
+
(entry: Entry, options: OpenEntryOptions): Effect.Effect<OpenEntryResult, FsFailure, Scope.Scope>;
|
|
1032
|
+
};
|
|
1033
|
+
/**
|
|
1034
|
+
* Creates a directory. With `recursive`, every missing directory on a path is created in one change, so a
|
|
1035
|
+
* failure creates none and a watcher sees them all at once; symbolic links on the way are followed, dot names
|
|
1036
|
+
* are walked, and a final name that is already a directory (or a link to one) succeeds without a change. The
|
|
1037
|
+
* result names the directory the path ends on, with its parent's revision before and after the call, so a path
|
|
1038
|
+
* that leaves a directory it created, such as `new/..`, still reports the change. A name on the way that is not
|
|
1039
|
+
* a directory fails with `NotDirectory`, a final one with `AlreadyExists`, and only names the caller wrote are
|
|
1040
|
+
* created, so a dangling link fails with `NotFound`.
|
|
1041
|
+
*/
|
|
1042
|
+
readonly mkdir: (entry: EntryInput, options?: MkdirOptions) => Effect.Effect<ReferenceEntryResult, FsFailure>;
|
|
1043
|
+
/** Creates a symbolic link to `target`, stored as given. */
|
|
1044
|
+
readonly symlink: (target: PathInput, entry: EntryInput, options?: SymlinkOptions) => Effect.Effect<ReferenceEntryResult, FsFailure>;
|
|
1045
|
+
/** Adds a name for an existing file or symbolic link. A path source follows a final symbolic link only when its target says so. */
|
|
1046
|
+
readonly link: (source: TargetInput, entry: EntryInput) => Effect.Effect<ReferenceEntryResult, FsFailure>;
|
|
1047
|
+
/** Removes a file or symbolic link. */
|
|
1048
|
+
readonly unlink: (entry: EntryInput) => Effect.Effect<DirectoryChange, FsFailure>;
|
|
1021
1049
|
/** Removes an empty directory. */
|
|
1022
|
-
readonly rmdir: (
|
|
1023
|
-
/**
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1050
|
+
readonly rmdir: (entry: EntryInput) => Effect.Effect<DirectoryChange, FsFailure>;
|
|
1051
|
+
/**
|
|
1052
|
+
* Removes a file, a symbolic link, or an empty directory. With `recursive`, a directory that has entries is
|
|
1053
|
+
* emptied first, entries before their directories, each removal its own change; it stops at the first failure,
|
|
1054
|
+
* whose path names the entry it stopped at, and leaves what it has not reached. Each entry is removed by its name
|
|
1055
|
+
* in a directory reached by name, so a subtree renamed out of the target is left alone. A directory with entries
|
|
1056
|
+
* must be readable, and no permission is changed to make it so. With `force`, a missing target is success and the
|
|
1057
|
+
* result is `undefined`; a failure below the target is still a failure.
|
|
1058
|
+
*/
|
|
1059
|
+
readonly remove: {
|
|
1060
|
+
(entry: EntryInput, options?: RemoveOptions & {
|
|
1061
|
+
readonly force?: false;
|
|
1062
|
+
}): Effect.Effect<DirectoryChange, FsFailure>;
|
|
1063
|
+
(entry: EntryInput, options: RemoveOptions): Effect.Effect<DirectoryChange | undefined, FsFailure>;
|
|
1064
|
+
};
|
|
1065
|
+
/** Moves an entry, replacing a compatible destination. */
|
|
1066
|
+
readonly rename: (from: EntryInput, to: EntryInput) => Effect.Effect<RenameReferenceResult, FsFailure>;
|
|
1067
|
+
/** Sets the permission bits of a target. */
|
|
1068
|
+
readonly chmod: (target: TargetInput, mode: number) => Effect.Effect<void, FsFailure>;
|
|
1069
|
+
/** Changes the owner or group of a target. */
|
|
1070
|
+
readonly chown: (target: TargetInput, owner: OwnerUpdate) => Effect.Effect<void, FsFailure>;
|
|
1071
|
+
/** Sets the access and modification times of a target. */
|
|
1072
|
+
readonly utimes: (target: TargetInput, times: Times) => Effect.Effect<void, FsFailure>;
|
|
1073
|
+
/** Sets the size of a regular file. */
|
|
1074
|
+
readonly truncate: (target: TargetInput, length: bigint) => Effect.Effect<void, FsFailure>;
|
|
1075
|
+
/**
|
|
1076
|
+
* Changes a target's size, owner, mode and times as one change. Every check passes before any attribute
|
|
1077
|
+
* applies, so a failure changes nothing. The attributes apply as size, owner, mode, then times, the POSIX
|
|
1078
|
+
* composition of chown then chmod, so a requested mode wins over the set-ID clearing an owner change or a
|
|
1079
|
+
* resize triggers. A protocol adapter that sanitises the requested mode, as NFS does after Linux knfsd,
|
|
1080
|
+
* does so before it calls setattr, and passes the revision it read as `expected` so the change refuses a
|
|
1081
|
+
* target another change has moved.
|
|
1082
|
+
*/
|
|
1083
|
+
readonly setattr: (target: TargetInput, attributes: SetattrOptions) => Effect.Effect<void, FsFailure>;
|
|
1084
|
+
/** A caller whose working directory is the target, released with the scope. */
|
|
1085
|
+
readonly withDirectory: (directory: TargetInput) => Effect.Effect<Caller, FsFailure, Scope.Scope>;
|
|
1086
|
+
/** A handle on a directory, released with the scope. */
|
|
1087
|
+
readonly openDirectory: (directory: TargetInput) => Effect.Effect<DirectoryHandle, FsFailure, Scope.Scope>;
|
|
1031
1088
|
}
|
|
1032
1089
|
/**
|
|
1033
1090
|
* A committed namespace or content change emitted by a volume watch stream.
|
|
@@ -1035,14 +1092,13 @@ export interface Caller {
|
|
|
1035
1092
|
* @example
|
|
1036
1093
|
* ```ts
|
|
1037
1094
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1038
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1039
1095
|
* import { Effect, Fiber, Stream } from "effect"
|
|
1040
1096
|
*
|
|
1041
1097
|
* const program = Effect.gen(function*() {
|
|
1042
1098
|
* const volume = yield* Vfs.make()
|
|
1043
1099
|
* const caller = yield* volume.caller()
|
|
1044
1100
|
*
|
|
1045
|
-
* const watcher = yield* volume.watch.pipe(
|
|
1101
|
+
* const watcher = yield* volume.watch().pipe(
|
|
1046
1102
|
* Effect.flatMap((stream) => Stream.runCollect(Stream.take(stream, 2))),
|
|
1047
1103
|
* Effect.forkChild({ startImmediately: true })
|
|
1048
1104
|
* )
|
|
@@ -1060,26 +1116,80 @@ export interface Caller {
|
|
|
1060
1116
|
* ))
|
|
1061
1117
|
* }).pipe(Effect.scoped)
|
|
1062
1118
|
*
|
|
1063
|
-
* Effect.runPromise(program
|
|
1119
|
+
* Effect.runPromise(program).then(console.log)
|
|
1064
1120
|
* // [ 'Create /logs', 'Remove /logs' ]
|
|
1065
1121
|
* ```
|
|
1066
1122
|
*
|
|
1123
|
+
* @category schemas
|
|
1124
|
+
* @since 0.1.0
|
|
1125
|
+
*/
|
|
1126
|
+
export declare const Change: typeof WatchModule.Change;
|
|
1127
|
+
/**
|
|
1128
|
+
* One committed change observed through a watch subscription. `Rescan` means
|
|
1129
|
+
* the subscriber lost events; it names `/` for a volume-wide watch and the
|
|
1130
|
+
* scope's current path for a scoped one.
|
|
1131
|
+
*
|
|
1067
1132
|
* @category models
|
|
1068
1133
|
* @since 0.1.0
|
|
1069
1134
|
*/
|
|
1070
|
-
export
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1135
|
+
export type Change = typeof Change.Type;
|
|
1136
|
+
/**
|
|
1137
|
+
* Schema for the options of `Volume.watch`: an object reference to narrow the
|
|
1138
|
+
* watch to, and whether its whole subtree is reported.
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* ```ts
|
|
1142
|
+
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1143
|
+
* import { Effect, Fiber, Stream } from "effect"
|
|
1144
|
+
*
|
|
1145
|
+
* const program = Effect.gen(function*() {
|
|
1146
|
+
* const volume = yield* Vfs.make()
|
|
1147
|
+
* const caller = yield* volume.caller()
|
|
1148
|
+
* yield* caller.mkdir("/work")
|
|
1149
|
+
* const work = yield* caller.lookup("/work")
|
|
1150
|
+
*
|
|
1151
|
+
* const watcher = yield* volume.watch({ scope: work }).pipe(
|
|
1152
|
+
* Effect.flatMap((stream) => Stream.runCollect(Stream.take(stream, 3))),
|
|
1153
|
+
* Effect.forkChild({ startImmediately: true })
|
|
1154
|
+
* )
|
|
1155
|
+
*
|
|
1156
|
+
* // Outside the scope, so not reported.
|
|
1157
|
+
* yield* caller.mkdir("/elsewhere")
|
|
1158
|
+
* // The scope is the directory, not its path: the rename is reported and the watch goes on.
|
|
1159
|
+
* yield* caller.rename("/work", "/renamed")
|
|
1160
|
+
* yield* caller.mkdir("/renamed/out")
|
|
1161
|
+
*
|
|
1162
|
+
* const events = yield* Fiber.join(watcher)
|
|
1163
|
+
*
|
|
1164
|
+
* return yield* Effect.forEach(events, (change) =>
|
|
1165
|
+
* Effect.map(
|
|
1166
|
+
* Vfs.pathToBytes(change.path),
|
|
1167
|
+
* (bytes) => `${change._tag} ${new TextDecoder().decode(bytes)}`
|
|
1168
|
+
* ))
|
|
1169
|
+
* }).pipe(Effect.scoped)
|
|
1170
|
+
*
|
|
1171
|
+
* Effect.runPromise(program).then(console.log)
|
|
1172
|
+
* // [ 'Remove /work', 'Create /renamed', 'Create /renamed/out' ]
|
|
1173
|
+
* ```
|
|
1174
|
+
*
|
|
1175
|
+
* @category schemas
|
|
1176
|
+
* @since 0.6.0
|
|
1177
|
+
*/
|
|
1178
|
+
export declare const WatchOptions: typeof WatchModule.WatchOptions;
|
|
1179
|
+
/**
|
|
1180
|
+
* Options of `Volume.watch`.
|
|
1181
|
+
*
|
|
1182
|
+
* @category models
|
|
1183
|
+
* @since 0.6.0
|
|
1184
|
+
*/
|
|
1185
|
+
export type WatchOptions = typeof WatchOptions.Type;
|
|
1076
1186
|
/**
|
|
1077
1187
|
* Schema for the filesystem entry kinds reported by overlay summaries.
|
|
1078
1188
|
*
|
|
1079
1189
|
* @category schemas
|
|
1080
1190
|
* @since 0.1.0
|
|
1081
1191
|
*/
|
|
1082
|
-
export declare const OverlayNodeKind: typeof
|
|
1192
|
+
export declare const OverlayNodeKind: typeof VolumeModule.OverlayNodeKind;
|
|
1083
1193
|
/**
|
|
1084
1194
|
* A filesystem entry kind reported by an overlay summary.
|
|
1085
1195
|
*
|
|
@@ -1093,7 +1203,7 @@ export type OverlayNodeKind = typeof OverlayNodeKind.Type;
|
|
|
1093
1203
|
* @category schemas
|
|
1094
1204
|
* @since 0.1.0
|
|
1095
1205
|
*/
|
|
1096
|
-
export declare const OverlayDifference: typeof
|
|
1206
|
+
export declare const OverlayDifference: typeof VolumeModule.OverlayDifference;
|
|
1097
1207
|
/**
|
|
1098
1208
|
* A content, ownership, permission, or timestamp field that differs from the overlay base.
|
|
1099
1209
|
*
|
|
@@ -1112,7 +1222,7 @@ export type OverlayDifference = typeof OverlayDifference.Type;
|
|
|
1112
1222
|
* @category schemas
|
|
1113
1223
|
* @since 0.1.0
|
|
1114
1224
|
*/
|
|
1115
|
-
export declare const OverlayChange: typeof
|
|
1225
|
+
export declare const OverlayChange: typeof VolumeModule.OverlayChange;
|
|
1116
1226
|
/**
|
|
1117
1227
|
* A path-oriented final-state difference from an overlay's immutable base.
|
|
1118
1228
|
*
|
|
@@ -1126,7 +1236,6 @@ export type OverlayChange = typeof OverlayChange.Type;
|
|
|
1126
1236
|
* @example
|
|
1127
1237
|
* ```ts
|
|
1128
1238
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1129
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1130
1239
|
* import { Effect } from "effect"
|
|
1131
1240
|
*
|
|
1132
1241
|
* const program = Effect.gen(function*() {
|
|
@@ -1142,14 +1251,14 @@ export type OverlayChange = typeof OverlayChange.Type;
|
|
|
1142
1251
|
* return [plain.length, timed.length]
|
|
1143
1252
|
* })
|
|
1144
1253
|
*
|
|
1145
|
-
* Effect.runPromise(program
|
|
1254
|
+
* Effect.runPromise(program).then(console.log)
|
|
1146
1255
|
* // [ 1, 2 ]
|
|
1147
1256
|
* ```
|
|
1148
1257
|
*
|
|
1149
1258
|
* @category schemas
|
|
1150
1259
|
* @since 0.1.0
|
|
1151
1260
|
*/
|
|
1152
|
-
export declare const OverlayChangesOptions: typeof
|
|
1261
|
+
export declare const OverlayChangesOptions: typeof VolumeModule.OverlayChangesOptions;
|
|
1153
1262
|
/**
|
|
1154
1263
|
* Filtering options for an overlay final-difference summary.
|
|
1155
1264
|
*
|
|
@@ -1163,7 +1272,6 @@ export type OverlayChangesOptions = typeof OverlayChangesOptions.Type;
|
|
|
1163
1272
|
* @example
|
|
1164
1273
|
* ```ts
|
|
1165
1274
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1166
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1167
1275
|
* import { Effect } from "effect"
|
|
1168
1276
|
*
|
|
1169
1277
|
* const program = Effect.gen(function*() {
|
|
@@ -1187,7 +1295,7 @@ export type OverlayChangesOptions = typeof OverlayChangesOptions.Type;
|
|
|
1187
1295
|
* ]
|
|
1188
1296
|
* })
|
|
1189
1297
|
*
|
|
1190
|
-
* Effect.runPromise(program
|
|
1298
|
+
* Effect.runPromise(program).then(console.log)
|
|
1191
1299
|
* // [ [ 'Added' ], 'built' ]
|
|
1192
1300
|
* ```
|
|
1193
1301
|
*
|
|
@@ -1206,7 +1314,6 @@ export interface OverlayCapture {
|
|
|
1206
1314
|
* @example
|
|
1207
1315
|
* ```ts
|
|
1208
1316
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1209
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1210
1317
|
* import { Effect, Fiber, Option, Stream } from "effect"
|
|
1211
1318
|
*
|
|
1212
1319
|
* const program = Effect.gen(function*() {
|
|
@@ -1214,7 +1321,7 @@ export interface OverlayCapture {
|
|
|
1214
1321
|
* const caller = yield* volume.caller()
|
|
1215
1322
|
*
|
|
1216
1323
|
* // `watch` reports future changes only; nothing is replayed.
|
|
1217
|
-
* const watcher = yield* volume.watch.pipe(
|
|
1324
|
+
* const watcher = yield* volume.watch().pipe(
|
|
1218
1325
|
* Effect.flatMap(Stream.runHead),
|
|
1219
1326
|
* Effect.forkChild({ startImmediately: true })
|
|
1220
1327
|
* )
|
|
@@ -1226,7 +1333,7 @@ export interface OverlayCapture {
|
|
|
1226
1333
|
* return Option.getOrElse(Option.map(change, (event) => event._tag), () => "none")
|
|
1227
1334
|
* }).pipe(Effect.scoped)
|
|
1228
1335
|
*
|
|
1229
|
-
* Effect.runPromise(program
|
|
1336
|
+
* Effect.runPromise(program).then(console.log)
|
|
1230
1337
|
* // Create
|
|
1231
1338
|
* ```
|
|
1232
1339
|
*
|
|
@@ -1243,14 +1350,31 @@ export interface Volume {
|
|
|
1243
1350
|
/** Effective static limits, where `undefined` means unlimited. */
|
|
1244
1351
|
readonly limits: VolumeLimits;
|
|
1245
1352
|
/** Samples content bytes and directory entries together from the current committed state. */
|
|
1246
|
-
readonly usage: Effect.Effect<VolumeUsage,
|
|
1247
|
-
/**
|
|
1248
|
-
|
|
1353
|
+
readonly usage: Effect.Effect<VolumeUsage, FsFailure>;
|
|
1354
|
+
/**
|
|
1355
|
+
* Opens a scoped stream of future changes, registered before it returns; events are not replayed. Without a
|
|
1356
|
+
* scope it covers the volume and `Rescan` at `/` requires a full rescan; with one it covers that object (and its
|
|
1357
|
+
* subtree unless `recursive` is `false`), `Rescan` names the object's current path, and the stream ends after
|
|
1358
|
+
* `Remove` for the object once its last name is gone.
|
|
1359
|
+
*/
|
|
1360
|
+
readonly watch: (options?: WatchOptions) => Effect.Effect<Stream.Stream<Change>, FsFailure, Scope.Scope>;
|
|
1249
1361
|
/** Captures an isolated snapshot of the reachable namespace and metadata. */
|
|
1250
|
-
readonly snapshot: Effect.Effect<Snapshot,
|
|
1362
|
+
readonly snapshot: Effect.Effect<Snapshot, VfsError>;
|
|
1363
|
+
/**
|
|
1364
|
+
* The serialisable key of an object this volume issued. Fails with `InvalidReference` for a value that is not a
|
|
1365
|
+
* reference, `ForeignReference` for another volume's, and `StaleReference` once the object is gone.
|
|
1366
|
+
*/
|
|
1367
|
+
readonly referenceKey: (reference: ObjectReference) => Effect.Effect<ReferenceKey, FsFailure>;
|
|
1368
|
+
/**
|
|
1369
|
+
* The object a key names, as the same reference traversal returns. Fails with `InvalidReference` for a malformed
|
|
1370
|
+
* key or one whose tag this volume did not compute, `ForeignReference` for a key another volume or another epoch
|
|
1371
|
+
* of this one minted, and `StaleReference` once the object is gone. It checks no permission: holding the volume
|
|
1372
|
+
* already grants every caller, and the tag keeps a key holder from reaching an object no key was issued for.
|
|
1373
|
+
*/
|
|
1374
|
+
readonly resolveReferenceKey: (key: ReferenceKey) => Effect.Effect<ObjectReference, FsFailure>;
|
|
1251
1375
|
readonly [VolumeId]: true;
|
|
1252
1376
|
/** Creates a caller rooted at `/` with independent credentials, umask, and current directory. */
|
|
1253
|
-
readonly caller: (options?: RootCallerOptions) => Effect.Effect<Caller,
|
|
1377
|
+
readonly caller: (options?: RootCallerOptions) => Effect.Effect<Caller, VfsError>;
|
|
1254
1378
|
}
|
|
1255
1379
|
/**
|
|
1256
1380
|
* An ordinary volume with final-state inspection relative to one immutable snapshot base.
|
|
@@ -1258,7 +1382,6 @@ export interface Volume {
|
|
|
1258
1382
|
* @example
|
|
1259
1383
|
* ```ts
|
|
1260
1384
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1261
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1262
1385
|
* import { Effect } from "effect"
|
|
1263
1386
|
*
|
|
1264
1387
|
* const program = Effect.gen(function*() {
|
|
@@ -1276,7 +1399,7 @@ export interface Volume {
|
|
|
1276
1399
|
* return captured.changes.map((change) => change._tag)
|
|
1277
1400
|
* })
|
|
1278
1401
|
*
|
|
1279
|
-
* Effect.runPromise(program
|
|
1402
|
+
* Effect.runPromise(program).then(console.log)
|
|
1280
1403
|
* // [ 'Added' ]
|
|
1281
1404
|
* ```
|
|
1282
1405
|
*
|
|
@@ -1285,62 +1408,118 @@ export interface Volume {
|
|
|
1285
1408
|
*/
|
|
1286
1409
|
export interface OverlayVolume extends Volume {
|
|
1287
1410
|
/** Computes final differences from the immutable base when this reusable effect executes. */
|
|
1288
|
-
readonly changes: (options?: OverlayChangesOptions) => Effect.Effect<ReadonlyArray<OverlayChange>,
|
|
1411
|
+
readonly changes: (options?: OverlayChangesOptions) => Effect.Effect<ReadonlyArray<OverlayChange>, VfsError>;
|
|
1289
1412
|
/** Captures one committed state when this reusable effect executes. */
|
|
1290
|
-
readonly capture: (options?: OverlayChangesOptions) => Effect.Effect<OverlayCapture,
|
|
1413
|
+
readonly capture: (options?: OverlayChangesOptions) => Effect.Effect<OverlayCapture, VfsError>;
|
|
1291
1414
|
}
|
|
1292
1415
|
/**
|
|
1293
|
-
*
|
|
1416
|
+
* The volume an application runs against, as an Effect service. The static
|
|
1417
|
+
* layers wrap the explicit constructors; each call builds a fresh layer, so
|
|
1418
|
+
* share one layer value to share one volume.
|
|
1294
1419
|
*
|
|
1295
1420
|
* @example
|
|
1296
1421
|
* ```ts
|
|
1297
1422
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1298
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1299
1423
|
* import { Effect } from "effect"
|
|
1300
1424
|
*
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1425
|
+
* const program = Effect.gen(function*() {
|
|
1426
|
+
* const fs = yield* Vfs.Caller
|
|
1427
|
+
* yield* fs.mkdir("/work")
|
|
1304
1428
|
*
|
|
1305
|
-
* return yield*
|
|
1429
|
+
* return (yield* fs.readDirectory("/")).value.map((entry) => new TextDecoder().decode(entry.name))
|
|
1306
1430
|
* })
|
|
1307
1431
|
*
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
*
|
|
1432
|
+
* Effect.runPromise(program.pipe(Effect.provide(Vfs.Caller.layer()), Effect.provide(Vfs.Volume.layer())))
|
|
1433
|
+
* .then(console.log)
|
|
1434
|
+
* // [ 'work' ]
|
|
1435
|
+
* ```
|
|
1311
1436
|
*
|
|
1312
|
-
*
|
|
1313
|
-
*
|
|
1314
|
-
|
|
1437
|
+
* @category services
|
|
1438
|
+
* @since 0.6.0
|
|
1439
|
+
*/
|
|
1440
|
+
export declare const Volume: Context.Service<Volume, Volume> & {
|
|
1441
|
+
/** A fresh empty volume. */
|
|
1442
|
+
readonly layer: (options?: VolumeOptions) => Layer.Layer<Volume, VfsError>;
|
|
1443
|
+
/** A fresh volume restored from a snapshot. */
|
|
1444
|
+
readonly layerFromSnapshot: (snapshot: Snapshot, options?: VolumeOptions) => Layer.Layer<Volume, VfsError>;
|
|
1445
|
+
/** A fresh volume built from a fixture. */
|
|
1446
|
+
readonly layerFromFixture: (fixture: Fixture, options?: VolumeOptions) => Layer.Layer<Volume, VfsError>;
|
|
1447
|
+
/** A writable overlay over a snapshot base. */
|
|
1448
|
+
readonly layerOverlay: (base: Snapshot, options?: VolumeOptions) => Layer.Layer<Volume, VfsError>;
|
|
1449
|
+
/** A durable volume opened through the `LiveImageStore` in context; it shuts down with the layer's scope. */
|
|
1450
|
+
readonly layerLive: (options: LiveVolumeOptions) => Layer.Layer<Volume, VfsError, LiveImageStore>;
|
|
1451
|
+
};
|
|
1452
|
+
/**
|
|
1453
|
+
* The caller an application operates through, as an Effect service. A caller
|
|
1454
|
+
* supplied through the service keeps its own volume, credentials, umask and
|
|
1455
|
+
* working directory; `layer` makes a root caller on the `Volume` in context.
|
|
1456
|
+
*
|
|
1457
|
+
* @category services
|
|
1458
|
+
* @since 0.6.0
|
|
1459
|
+
*/
|
|
1460
|
+
export declare const Caller: Context.Service<Caller, Caller> & {
|
|
1461
|
+
/** A root caller on the volume in context; root callers need no scope. */
|
|
1462
|
+
readonly layer: (options?: RootCallerOptions) => Layer.Layer<Caller, VfsError, Volume>;
|
|
1463
|
+
};
|
|
1464
|
+
/**
|
|
1465
|
+
* Streams a snapshot's version 1 encoding as owned UTF-8 chunks: a header line,
|
|
1466
|
+
* then one line per node, each ending in a newline.
|
|
1467
|
+
*
|
|
1468
|
+
* **Details**
|
|
1469
|
+
*
|
|
1470
|
+
* The encoding is newline-delimited JSON. The first line names the format and
|
|
1471
|
+
* version; each later line is one node in inode order, with names and payloads
|
|
1472
|
+
* as canonical base64. Nodes are encoded as the stream is pulled, so writing a
|
|
1473
|
+
* large snapshot to a file or a socket never holds its whole encoding. A chunk
|
|
1474
|
+
* holds at most 128 lines and 64 KiB, so a pull holds at most that and the next
|
|
1475
|
+
* line; a line longer than 64 KiB is a chunk of its own.
|
|
1476
|
+
*
|
|
1477
|
+
* Given `limits`, the stream fails with `LimitExceeded` at the first line that
|
|
1478
|
+
* `decodeSnapshot` would refuse under the same limits, naming the same field,
|
|
1479
|
+
* so bytes it completes are known to decode without decoding them.
|
|
1480
|
+
*
|
|
1481
|
+
* @example
|
|
1482
|
+
* ```ts
|
|
1483
|
+
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1484
|
+
* import { Effect, Stream } from "effect"
|
|
1485
|
+
*
|
|
1486
|
+
* const program = Effect.gen(function*() {
|
|
1487
|
+
* const volume = yield* Vfs.fromFixture({
|
|
1488
|
+
* entries: [{ kind: "file", path: "/f", bytes: new Uint8Array([1]) }]
|
|
1315
1489
|
* })
|
|
1316
1490
|
*
|
|
1317
|
-
*
|
|
1491
|
+
* const text = yield* Vfs.encodeSnapshotStream(yield* volume.snapshot).pipe(
|
|
1492
|
+
* Stream.decodeText,
|
|
1493
|
+
* Stream.mkString
|
|
1494
|
+
* )
|
|
1495
|
+
*
|
|
1496
|
+
* // A header line, then the root and the file, each line ending in a newline.
|
|
1497
|
+
* return text.split("\n").map((line) => (line === "" ? "end" : JSON.parse(line)._tag ?? "header"))
|
|
1318
1498
|
* })
|
|
1319
1499
|
*
|
|
1320
|
-
* Effect.runPromise(program
|
|
1321
|
-
* //
|
|
1500
|
+
* Effect.runPromise(program).then(console.log)
|
|
1501
|
+
* // [ 'header', 'directory', 'file', 'end' ]
|
|
1322
1502
|
* ```
|
|
1323
1503
|
*
|
|
1324
|
-
* @see
|
|
1325
|
-
* @
|
|
1326
|
-
* @
|
|
1504
|
+
* @see {@link encodeSnapshot} for the same bytes collected into one array.
|
|
1505
|
+
* @see {@link decodeSnapshotSink} for reading a stream back under limits.
|
|
1506
|
+
* @category serialization
|
|
1507
|
+
* @since 0.6.0
|
|
1327
1508
|
*/
|
|
1328
|
-
export declare const
|
|
1509
|
+
export declare const encodeSnapshotStream: (snapshot: Snapshot, limits?: DecodeLimits) => Stream.Stream<Uint8Array, ImageFailure | ArgumentFailure>;
|
|
1329
1510
|
/**
|
|
1330
|
-
*
|
|
1511
|
+
* Encodes a snapshot as owned UTF-8 bytes in the version 1 snapshot format.
|
|
1331
1512
|
*
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
* Encodes a snapshot as owned UTF-8 JSON bytes using the version 1 snapshot format.
|
|
1513
|
+
* **Details**
|
|
1514
|
+
*
|
|
1515
|
+
* The bytes are the chunks of {@link encodeSnapshotStream} collected into one
|
|
1516
|
+
* array: newline-delimited JSON, a header line and then one line per node.
|
|
1517
|
+
* Given `limits`, encoding fails with `LimitExceeded` wherever `decodeSnapshot`
|
|
1518
|
+
* would refuse the bytes under the same limits.
|
|
1339
1519
|
*
|
|
1340
1520
|
* @example
|
|
1341
1521
|
* ```ts
|
|
1342
1522
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1343
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1344
1523
|
* import { Effect } from "effect"
|
|
1345
1524
|
*
|
|
1346
1525
|
* // Bytes are portable: store or transmit them, then decode under explicit limits.
|
|
@@ -1355,11 +1534,11 @@ export interface CurrentFileSystem extends Caller {
|
|
|
1355
1534
|
*
|
|
1356
1535
|
* const bytes = yield* Vfs.encodeSnapshot(yield* volume.snapshot)
|
|
1357
1536
|
*
|
|
1358
|
-
* // The
|
|
1359
|
-
* return JSON.parse(new TextDecoder().decode(bytes)).version
|
|
1537
|
+
* // The first line is the header carrying the version 1 snapshot format.
|
|
1538
|
+
* return JSON.parse(new TextDecoder().decode(bytes).split("\n")[0]!).version
|
|
1360
1539
|
* })
|
|
1361
1540
|
*
|
|
1362
|
-
* Effect.runPromise(program
|
|
1541
|
+
* Effect.runPromise(program).then(console.log)
|
|
1363
1542
|
* // 1
|
|
1364
1543
|
* ```
|
|
1365
1544
|
*
|
|
@@ -1367,17 +1546,75 @@ export interface CurrentFileSystem extends Caller {
|
|
|
1367
1546
|
* @category serialization
|
|
1368
1547
|
* @since 0.1.0
|
|
1369
1548
|
*/
|
|
1370
|
-
export declare const encodeSnapshot: (snapshot: Snapshot) => Effect.Effect<Uint8Array,
|
|
1549
|
+
export declare const encodeSnapshot: (snapshot: Snapshot, limits?: DecodeLimits) => Effect.Effect<Uint8Array, ImageFailure | ArgumentFailure>;
|
|
1550
|
+
/**
|
|
1551
|
+
* A sink that decodes a stream of version 1 snapshot chunks while enforcing
|
|
1552
|
+
* explicit input and payload limits.
|
|
1553
|
+
*
|
|
1554
|
+
* **Details**
|
|
1555
|
+
*
|
|
1556
|
+
* Chunks may split lines, and UTF-8 sequences, anywhere. Each line is checked
|
|
1557
|
+
* as it ends, so input that breaks a limit or a rule is refused before the
|
|
1558
|
+
* sink holds more than one line of it: `maxLineBytes` bounds that line, and
|
|
1559
|
+
* the other limits bound what the accepted lines add up to. A line is
|
|
1560
|
+
* refused at the byte where it first crosses `maxLineBytes` or
|
|
1561
|
+
* `maxEncodedBytes`, so the field a refusal names does not depend on how the
|
|
1562
|
+
* input is chunked. Every line must end in a newline, the last included; a
|
|
1563
|
+
* carriage return, an empty line, a byte-order mark and malformed UTF-8 are
|
|
1564
|
+
* refused as `InvalidEncoding`.
|
|
1565
|
+
*
|
|
1566
|
+
* @example
|
|
1567
|
+
* ```ts
|
|
1568
|
+
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1569
|
+
* import { ByteSize, Effect, Stream } from "effect"
|
|
1570
|
+
*
|
|
1571
|
+
* const limits: Vfs.DecodeLimits = {
|
|
1572
|
+
* maxEncodedBytes: ByteSize.megabytes(4),
|
|
1573
|
+
* maxRecords: 10_000,
|
|
1574
|
+
* maxEntries: 10_000,
|
|
1575
|
+
* maxDecodedBytes: ByteSize.megabytes(16),
|
|
1576
|
+
* maxLineBytes: ByteSize.megabytes(1)
|
|
1577
|
+
* }
|
|
1578
|
+
*
|
|
1579
|
+
* const program = Effect.gen(function*() {
|
|
1580
|
+
* const volume = yield* Vfs.fromFixture({
|
|
1581
|
+
* entries: [{ kind: "file", path: "/f", bytes: new Uint8Array([1, 2, 3]) }]
|
|
1582
|
+
* })
|
|
1583
|
+
*
|
|
1584
|
+
* // Rechunked to single bytes: the sink joins lines across chunks.
|
|
1585
|
+
* const snapshot = yield* Vfs.encodeSnapshotStream(yield* volume.snapshot).pipe(
|
|
1586
|
+
* Stream.flattenIterable,
|
|
1587
|
+
* Stream.rechunk(1),
|
|
1588
|
+
* Stream.map((byte) => new Uint8Array([byte])),
|
|
1589
|
+
* Stream.run(Vfs.decodeSnapshotSink(limits))
|
|
1590
|
+
* )
|
|
1591
|
+
*
|
|
1592
|
+
* return yield* (yield* (yield* Vfs.fromSnapshot(snapshot)).caller()).readFile("/f")
|
|
1593
|
+
* })
|
|
1594
|
+
*
|
|
1595
|
+
* Effect.runPromise(program).then(console.log)
|
|
1596
|
+
* // Uint8Array(3) [ 1, 2, 3 ]
|
|
1597
|
+
* ```
|
|
1598
|
+
*
|
|
1599
|
+
* @see {@link DecodeLimits} for what each bound protects.
|
|
1600
|
+
* @see {@link decodeSnapshot} for decoding bytes already in memory.
|
|
1601
|
+
* @category serialization
|
|
1602
|
+
* @since 0.6.0
|
|
1603
|
+
*/
|
|
1604
|
+
export declare const decodeSnapshotSink: (limits: DecodeLimits) => Sink.Sink<Snapshot, Uint8Array, never, ImageFailure | ArgumentFailure>;
|
|
1371
1605
|
/**
|
|
1372
1606
|
* Decodes version 1 snapshot bytes while enforcing explicit input and payload limits.
|
|
1373
1607
|
*
|
|
1608
|
+
* **Details**
|
|
1609
|
+
*
|
|
1610
|
+
* The same decoder as {@link decodeSnapshotSink}, run over one chunk.
|
|
1611
|
+
*
|
|
1374
1612
|
* @example
|
|
1375
1613
|
* ```ts
|
|
1376
1614
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1377
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1378
1615
|
* import { ByteSize, Effect } from "effect"
|
|
1379
1616
|
*
|
|
1380
|
-
* // Limits are mandatory: decoding is the boundary where
|
|
1617
|
+
* // Limits are mandatory: decoding is the boundary where outside input arrives.
|
|
1381
1618
|
* const program = Effect.gen(function*() {
|
|
1382
1619
|
* const volume = yield* Vfs.make()
|
|
1383
1620
|
* const bytes = yield* Vfs.encodeSnapshot(yield* volume.snapshot)
|
|
@@ -1389,11 +1626,11 @@ export declare const encodeSnapshot: (snapshot: Snapshot) => Effect.Effect<Uint8
|
|
|
1389
1626
|
* maxDecodedBytes: ByteSize.megabytes(16)
|
|
1390
1627
|
* }).pipe(
|
|
1391
1628
|
* Effect.as("accepted"),
|
|
1392
|
-
* Effect.catchTag("
|
|
1629
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed([error.code, error.field]))
|
|
1393
1630
|
* )
|
|
1394
1631
|
* })
|
|
1395
1632
|
*
|
|
1396
|
-
* Effect.runPromise(program
|
|
1633
|
+
* Effect.runPromise(program).then(console.log)
|
|
1397
1634
|
* // [ 'LimitExceeded', 'encodedBytes' ]
|
|
1398
1635
|
* ```
|
|
1399
1636
|
*
|
|
@@ -1401,7 +1638,7 @@ export declare const encodeSnapshot: (snapshot: Snapshot) => Effect.Effect<Uint8
|
|
|
1401
1638
|
* @category serialization
|
|
1402
1639
|
* @since 0.1.0
|
|
1403
1640
|
*/
|
|
1404
|
-
export declare const decodeSnapshot: (input: Uint8Array, limits: DecodeLimits) => Effect.Effect<Snapshot,
|
|
1641
|
+
export declare const decodeSnapshot: (input: Uint8Array, limits: DecodeLimits) => Effect.Effect<Snapshot, ImageFailure | ArgumentFailure>;
|
|
1405
1642
|
/**
|
|
1406
1643
|
* Computes an exact portable delta between two immutable snapshots.
|
|
1407
1644
|
* Requires the platform-neutral `Crypto.Crypto` service for base identity. Provide
|
|
@@ -1439,7 +1676,7 @@ export declare const decodeSnapshot: (input: Uint8Array, limits: DecodeLimits) =
|
|
|
1439
1676
|
* @category snapshots
|
|
1440
1677
|
* @since 0.1.0
|
|
1441
1678
|
*/
|
|
1442
|
-
export declare const diffSnapshots: (base: Snapshot, target: Snapshot, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<SnapshotDeltaModel.SnapshotDelta,
|
|
1679
|
+
export declare const diffSnapshots: (base: Snapshot, target: Snapshot, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<SnapshotDeltaModel.SnapshotDelta, VfsError | PlatformError.PlatformError, Crypto.Crypto>;
|
|
1443
1680
|
/**
|
|
1444
1681
|
* Verifies an exact snapshot delta against its base and derives an owned path-oriented summary.
|
|
1445
1682
|
* Requires the platform-neutral `Crypto.Crypto` service for base identity. Provide
|
|
@@ -1474,7 +1711,7 @@ export declare const diffSnapshots: (base: Snapshot, target: Snapshot, limits?:
|
|
|
1474
1711
|
* @category snapshots
|
|
1475
1712
|
* @since 0.1.0
|
|
1476
1713
|
*/
|
|
1477
|
-
export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDeltaModel.SnapshotDelta, options?: SnapshotDeltaModel.SnapshotChangesOptions, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<ReadonlyArray<SnapshotDeltaModel.SnapshotChange>,
|
|
1714
|
+
export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDeltaModel.SnapshotDelta, options?: SnapshotDeltaModel.SnapshotChangesOptions, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<ReadonlyArray<SnapshotDeltaModel.SnapshotChange>, VfsError | PlatformError.PlatformError, Crypto.Crypto>;
|
|
1478
1715
|
/**
|
|
1479
1716
|
* Applies an exact delta to its semantically matching base and returns a new snapshot.
|
|
1480
1717
|
* Requires the platform-neutral `Crypto.Crypto` service for base identity. Provide
|
|
@@ -1514,7 +1751,7 @@ export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDelta
|
|
|
1514
1751
|
* @category snapshots
|
|
1515
1752
|
* @since 0.1.0
|
|
1516
1753
|
*/
|
|
1517
|
-
export declare const applySnapshotDelta: (base: Snapshot, delta: SnapshotDeltaModel.SnapshotDelta, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<Snapshot,
|
|
1754
|
+
export declare const applySnapshotDelta: (base: Snapshot, delta: SnapshotDeltaModel.SnapshotDelta, limits?: SnapshotDeltaModel.SnapshotDeltaLimits) => Effect.Effect<Snapshot, VfsError | PlatformError.PlatformError, Crypto.Crypto>;
|
|
1518
1755
|
/**
|
|
1519
1756
|
* Creates an Effect Schema codec between owned bytes and opaque snapshot deltas.
|
|
1520
1757
|
* Omission uses `SnapshotDeltaLimits.default`.
|
|
@@ -1570,7 +1807,7 @@ export declare const SnapshotDeltaFromBytes: (limits?: SnapshotDeltaModel.Snapsh
|
|
|
1570
1807
|
*
|
|
1571
1808
|
* const rejected = yield* Vfs.pathFromBytes(new Uint8Array([47, 0])).pipe(
|
|
1572
1809
|
* Effect.as("accepted"),
|
|
1573
|
-
* Effect.catchTag("
|
|
1810
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed(error.code))
|
|
1574
1811
|
* )
|
|
1575
1812
|
*
|
|
1576
1813
|
* return [yield* Vfs.pathToBytes(path), rejected]
|
|
@@ -1583,14 +1820,14 @@ export declare const SnapshotDeltaFromBytes: (limits?: SnapshotDeltaModel.Snapsh
|
|
|
1583
1820
|
* @category constructors
|
|
1584
1821
|
* @since 0.1.0
|
|
1585
1822
|
*/
|
|
1586
|
-
export declare const pathFromBytes: (bytes: Uint8Array) => Effect.Effect<BytePath,
|
|
1823
|
+
export declare const pathFromBytes: (bytes: Uint8Array) => Effect.Effect<BytePath, FsFailure>;
|
|
1587
1824
|
/**
|
|
1588
1825
|
* Copies the bytes held by an opaque byte path.
|
|
1589
1826
|
*
|
|
1590
1827
|
* @category getters
|
|
1591
1828
|
* @since 0.1.0
|
|
1592
1829
|
*/
|
|
1593
|
-
export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array,
|
|
1830
|
+
export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array, FsFailure>;
|
|
1594
1831
|
/**
|
|
1595
1832
|
* Schema for a complete fixture namespace with optional metadata and forward hard links.
|
|
1596
1833
|
*
|
|
@@ -1601,7 +1838,6 @@ export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array,
|
|
|
1601
1838
|
* @example
|
|
1602
1839
|
* ```ts
|
|
1603
1840
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1604
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1605
1841
|
* import { Effect, Schema } from "effect"
|
|
1606
1842
|
*
|
|
1607
1843
|
* // Fixtures must list every parent directory before its children.
|
|
@@ -1612,17 +1848,17 @@ export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array,
|
|
|
1612
1848
|
* }).pipe(
|
|
1613
1849
|
* Effect.flatMap(Vfs.fromFixture),
|
|
1614
1850
|
* Effect.as("built"),
|
|
1615
|
-
* Effect.catchTag("
|
|
1851
|
+
* Effect.catchTag("VfsError", (error) => Effect.succeed(`rejected: ${error.code}`))
|
|
1616
1852
|
* )
|
|
1617
1853
|
*
|
|
1618
|
-
* Effect.runPromise(program
|
|
1854
|
+
* Effect.runPromise(program).then(console.log)
|
|
1619
1855
|
* // rejected: InvalidStructure
|
|
1620
1856
|
* ```
|
|
1621
1857
|
*
|
|
1622
1858
|
* @category schemas
|
|
1623
1859
|
* @since 0.1.0
|
|
1624
1860
|
*/
|
|
1625
|
-
export declare const Fixture: typeof
|
|
1861
|
+
export declare const Fixture: typeof FixtureModule.Fixture;
|
|
1626
1862
|
/**
|
|
1627
1863
|
* A complete filesystem fixture accepted by `fromFixture`.
|
|
1628
1864
|
*
|
|
@@ -1641,7 +1877,6 @@ export type Fixture = typeof Fixture.Type;
|
|
|
1641
1877
|
* @example
|
|
1642
1878
|
* ```ts
|
|
1643
1879
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1644
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1645
1880
|
* import { Effect } from "effect"
|
|
1646
1881
|
*
|
|
1647
1882
|
* const program = Effect.gen(function*() {
|
|
@@ -1654,7 +1889,7 @@ export type Fixture = typeof Fixture.Type;
|
|
|
1654
1889
|
* return yield* caller.readFile("/work/notes.txt")
|
|
1655
1890
|
* })
|
|
1656
1891
|
*
|
|
1657
|
-
* Effect.runPromise(program
|
|
1892
|
+
* Effect.runPromise(program).then(console.log)
|
|
1658
1893
|
* // Uint8Array(2) [ 104, 105 ]
|
|
1659
1894
|
* ```
|
|
1660
1895
|
*
|
|
@@ -1662,14 +1897,59 @@ export type Fixture = typeof Fixture.Type;
|
|
|
1662
1897
|
* @category constructors
|
|
1663
1898
|
* @since 0.1.0
|
|
1664
1899
|
*/
|
|
1665
|
-
export declare const make: (options?: VolumeOptions) => Effect.Effect<Volume,
|
|
1900
|
+
export declare const make: (options?: VolumeOptions) => Effect.Effect<Volume, VfsError>;
|
|
1901
|
+
/**
|
|
1902
|
+
* Streams the tree at `root` in a snapshot as fixture entries, read from the
|
|
1903
|
+
* snapshot itself without restoring a volume.
|
|
1904
|
+
*
|
|
1905
|
+
* **Details**
|
|
1906
|
+
*
|
|
1907
|
+
* `root` resolves as a privileged caller at `/` of a volume restored from the
|
|
1908
|
+
* snapshot with default options would resolve it, following intermediate
|
|
1909
|
+
* symbolic links but not a final one and applying no path byte limit. Entries come in sorted
|
|
1910
|
+
* pre-order, children in the byte order of their names, with paths rooted at
|
|
1911
|
+
* `root`, so the root entry's path is `/`. A path stays a string while every
|
|
1912
|
+
* name on it is UTF-8 and is a `BytePath` otherwise. A file or symbolic link
|
|
1913
|
+
* that more than one name reaches is an entry at its first path and a
|
|
1914
|
+
* `hardLink` to that path at the others. Each file's bytes are an owned copy,
|
|
1915
|
+
* made when the stream pulls its entry. Every entry after the root's is a
|
|
1916
|
+
* fixture entry for a volume holding the same tree.
|
|
1917
|
+
*
|
|
1918
|
+
* @example
|
|
1919
|
+
* ```ts
|
|
1920
|
+
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1921
|
+
* import { Effect, Stream } from "effect"
|
|
1922
|
+
*
|
|
1923
|
+
* const program = Effect.gen(function*() {
|
|
1924
|
+
* const volume = yield* Vfs.fromFixture({
|
|
1925
|
+
* entries: [
|
|
1926
|
+
* { kind: "directory", path: "/src" },
|
|
1927
|
+
* { kind: "file", path: "/src/b.txt", bytes: new Uint8Array([2]) },
|
|
1928
|
+
* { kind: "file", path: "/src/a.txt", bytes: new Uint8Array([1]) },
|
|
1929
|
+
* { kind: "hardLink", path: "/src/c.txt", target: "/src/a.txt" }
|
|
1930
|
+
* ]
|
|
1931
|
+
* })
|
|
1932
|
+
*
|
|
1933
|
+
* const entries = yield* Stream.runCollect(Vfs.snapshotEntries(yield* volume.snapshot, "/src"))
|
|
1934
|
+
*
|
|
1935
|
+
* return entries.map((entry) => `${entry.kind} ${String(entry.path)}`)
|
|
1936
|
+
* })
|
|
1937
|
+
*
|
|
1938
|
+
* Effect.runPromise(program).then(console.log)
|
|
1939
|
+
* // [ 'directory /', 'file /a.txt', 'file /b.txt', 'hardLink /c.txt' ]
|
|
1940
|
+
* ```
|
|
1941
|
+
*
|
|
1942
|
+
* @see {@link fromFixture} for building a volume from the entries.
|
|
1943
|
+
* @category snapshots
|
|
1944
|
+
* @since 0.6.0
|
|
1945
|
+
*/
|
|
1946
|
+
export declare const snapshotEntries: (snapshot: Snapshot, root: PathInput) => Stream.Stream<Fixture["entries"][number], FsFailure | ImageFailure>;
|
|
1666
1947
|
/**
|
|
1667
1948
|
* Restores a fresh volume from an opaque snapshot under the supplied destination limits.
|
|
1668
1949
|
*
|
|
1669
1950
|
* @example
|
|
1670
1951
|
* ```ts
|
|
1671
1952
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1672
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1673
1953
|
* import { Effect } from "effect"
|
|
1674
1954
|
*
|
|
1675
1955
|
* const program = Effect.gen(function*() {
|
|
@@ -1696,7 +1976,7 @@ export declare const make: (options?: VolumeOptions) => Effect.Effect<Volume, Co
|
|
|
1696
1976
|
* ]
|
|
1697
1977
|
* })
|
|
1698
1978
|
*
|
|
1699
|
-
* Effect.runPromise(program
|
|
1979
|
+
* Effect.runPromise(program).then(console.log)
|
|
1700
1980
|
* // [ 'one', 'two' ]
|
|
1701
1981
|
* ```
|
|
1702
1982
|
*
|
|
@@ -1704,7 +1984,7 @@ export declare const make: (options?: VolumeOptions) => Effect.Effect<Volume, Co
|
|
|
1704
1984
|
* @category constructors
|
|
1705
1985
|
* @since 0.1.0
|
|
1706
1986
|
*/
|
|
1707
|
-
export declare const fromSnapshot: (snapshot: Snapshot, options?: VolumeOptions) => Effect.Effect<Volume,
|
|
1987
|
+
export declare const fromSnapshot: (snapshot: Snapshot, options?: VolumeOptions) => Effect.Effect<Volume, VfsError>;
|
|
1708
1988
|
/**
|
|
1709
1989
|
* Creates an isolated writable volume relative to one immutable snapshot base.
|
|
1710
1990
|
*
|
|
@@ -1715,13 +1995,12 @@ export declare const fromSnapshot: (snapshot: Snapshot, options?: VolumeOptions)
|
|
|
1715
1995
|
* storage. Metadata, namespace state, coordination, handles, and watches are
|
|
1716
1996
|
* always private to the new workspace.
|
|
1717
1997
|
*
|
|
1718
|
-
* Invalid base snapshots
|
|
1719
|
-
*
|
|
1998
|
+
* Invalid base snapshots and invalid volume limits fail with `VfsError`. Each
|
|
1999
|
+
* execution creates a fresh workspace.
|
|
1720
2000
|
*
|
|
1721
2001
|
* @example
|
|
1722
2002
|
* ```ts
|
|
1723
2003
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1724
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1725
2004
|
* import { Effect } from "effect"
|
|
1726
2005
|
*
|
|
1727
2006
|
* const program = Effect.gen(function*() {
|
|
@@ -1747,7 +2026,7 @@ export declare const fromSnapshot: (snapshot: Snapshot, options?: VolumeOptions)
|
|
|
1747
2026
|
* ]
|
|
1748
2027
|
* })
|
|
1749
2028
|
*
|
|
1750
|
-
* Effect.runPromise(program
|
|
2029
|
+
* Effect.runPromise(program).then(console.log)
|
|
1751
2030
|
* // [ '{}', [ 'Updated' ] ]
|
|
1752
2031
|
* ```
|
|
1753
2032
|
*
|
|
@@ -1755,20 +2034,19 @@ export declare const fromSnapshot: (snapshot: Snapshot, options?: VolumeOptions)
|
|
|
1755
2034
|
* @category constructors
|
|
1756
2035
|
* @since 0.1.0
|
|
1757
2036
|
*/
|
|
1758
|
-
export declare const makeOverlay: (base: Snapshot, options?: VolumeOptions) => Effect.Effect<OverlayVolume,
|
|
2037
|
+
export declare const makeOverlay: (base: Snapshot, options?: VolumeOptions) => Effect.Effect<OverlayVolume, VfsError>;
|
|
1759
2038
|
/**
|
|
1760
2039
|
* Builds a fresh volume from a validated final-state fixture.
|
|
1761
2040
|
*
|
|
1762
2041
|
* @example
|
|
1763
2042
|
* ```ts
|
|
1764
2043
|
* import { VirtualFileSystem as Vfs } from "@effect-vfs/core"
|
|
1765
|
-
* import * as NodeCrypto from "@effect/platform-node-shared/NodeCrypto"
|
|
1766
2044
|
* import { Effect } from "effect"
|
|
1767
2045
|
*
|
|
1768
2046
|
* const encoder = new TextEncoder()
|
|
1769
2047
|
*
|
|
1770
2048
|
* const program = Effect.gen(function*() {
|
|
1771
|
-
* // Parent directories must be listed explicitly,
|
|
2049
|
+
* // Parent directories must be listed explicitly, in any order.
|
|
1772
2050
|
* const volume = yield* Vfs.fromFixture({
|
|
1773
2051
|
* entries: [
|
|
1774
2052
|
* { kind: "directory", path: "/project" },
|
|
@@ -1781,16 +2059,19 @@ export declare const makeOverlay: (base: Snapshot, options?: VolumeOptions) => E
|
|
|
1781
2059
|
* ]
|
|
1782
2060
|
* })
|
|
1783
2061
|
*
|
|
1784
|
-
*
|
|
2062
|
+
* // A fixture's directories list their entries in the byte order of their names.
|
|
2063
|
+
* const listing = yield* (yield* volume.caller()).readDirectory("/project")
|
|
2064
|
+
*
|
|
2065
|
+
* return listing.value.map((entry) => new TextDecoder().decode(entry.name))
|
|
1785
2066
|
* })
|
|
1786
2067
|
*
|
|
1787
|
-
* Effect.runPromise(program
|
|
1788
|
-
* // [ '
|
|
2068
|
+
* Effect.runPromise(program).then(console.log)
|
|
2069
|
+
* // [ 'latest', 'package.json' ]
|
|
1789
2070
|
* ```
|
|
1790
2071
|
*
|
|
1791
2072
|
* @see The fixtures guide at `/guides/fixtures-and-snapshots`.
|
|
1792
2073
|
* @category constructors
|
|
1793
2074
|
* @since 0.1.0
|
|
1794
2075
|
*/
|
|
1795
|
-
export declare const fromFixture: (fixture: Fixture, options?: VolumeOptions) => Effect.Effect<Volume,
|
|
2076
|
+
export declare const fromFixture: (fixture: Fixture, options?: VolumeOptions) => Effect.Effect<Volume, VfsError>;
|
|
1796
2077
|
//# sourceMappingURL=VirtualFileSystem.d.ts.map
|