@effect-vfs/core 0.3.1 → 0.5.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.
Files changed (58) hide show
  1. package/README.md +41 -150
  2. package/dist/BytePath.d.ts +2 -1
  3. package/dist/BytePath.d.ts.map +1 -1
  4. package/dist/LiveVolume.d.ts +104 -0
  5. package/dist/LiveVolume.d.ts.map +1 -0
  6. package/dist/LiveVolume.js +73 -0
  7. package/dist/Snapshot.d.ts +4 -2
  8. package/dist/Snapshot.d.ts.map +1 -1
  9. package/dist/Snapshot.js +4 -2
  10. package/dist/VirtualFileSystem.d.ts +333 -108
  11. package/dist/VirtualFileSystem.d.ts.map +1 -1
  12. package/dist/VirtualFileSystem.js +122 -32
  13. package/dist/VirtualFileSystemError.d.ts +54 -0
  14. package/dist/VirtualFileSystemError.d.ts.map +1 -0
  15. package/dist/VirtualFileSystemError.js +49 -0
  16. package/dist/index.d.ts +14 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +14 -0
  19. package/dist/internal/errors.d.ts +12 -0
  20. package/dist/internal/errors.d.ts.map +1 -0
  21. package/dist/internal/{virtualFileSystem/errors.js → errors.js} +11 -15
  22. package/dist/internal/{virtualFileSystem/fixture.d.ts → fixture.d.ts} +11 -8
  23. package/dist/internal/fixture.d.ts.map +1 -0
  24. package/dist/internal/{virtualFileSystem/fixture.js → fixture.js} +11 -5
  25. package/dist/internal/liveImage.d.ts +286 -0
  26. package/dist/internal/liveImage.d.ts.map +1 -0
  27. package/dist/internal/liveImage.js +176 -0
  28. package/dist/internal/{virtualFileSystem/overlayContent.d.ts → overlayContent.d.ts} +2 -2
  29. package/dist/internal/overlayContent.d.ts.map +1 -0
  30. package/dist/internal/{virtualFileSystem/overlayContent.js → overlayContent.js} +2 -2
  31. package/dist/internal/{virtualFileSystem/overlayDiff.d.ts → overlayDiff.d.ts} +1 -1
  32. package/dist/internal/overlayDiff.d.ts.map +1 -0
  33. package/dist/internal/{virtualFileSystem/overlayDiff.js → overlayDiff.js} +1 -1
  34. package/dist/internal/{virtualFileSystem/path.d.ts → path.d.ts} +2 -2
  35. package/dist/internal/path.d.ts.map +1 -0
  36. package/dist/internal/{virtualFileSystem/path.js → path.js} +1 -1
  37. package/dist/internal/stagedState.d.ts +22 -0
  38. package/dist/internal/stagedState.d.ts.map +1 -0
  39. package/dist/internal/stagedState.js +62 -0
  40. package/dist/internal/{virtualFileSystem/testHooks.d.ts → testHooks.d.ts} +2 -2
  41. package/dist/internal/testHooks.d.ts.map +1 -0
  42. package/dist/internal/virtualFileSystem.d.ts +224 -16
  43. package/dist/internal/virtualFileSystem.d.ts.map +1 -1
  44. package/dist/internal/virtualFileSystem.js +1294 -159
  45. package/dist/internal/{virtualFileSystem/watchHub.d.ts → watchHub.d.ts} +3 -3
  46. package/dist/internal/watchHub.d.ts.map +1 -0
  47. package/dist/internal/watchHub.js +54 -0
  48. package/package.json +14 -6
  49. package/dist/internal/virtualFileSystem/errors.d.ts +0 -31
  50. package/dist/internal/virtualFileSystem/errors.d.ts.map +0 -1
  51. package/dist/internal/virtualFileSystem/fixture.d.ts.map +0 -1
  52. package/dist/internal/virtualFileSystem/overlayContent.d.ts.map +0 -1
  53. package/dist/internal/virtualFileSystem/overlayDiff.d.ts.map +0 -1
  54. package/dist/internal/virtualFileSystem/path.d.ts.map +0 -1
  55. package/dist/internal/virtualFileSystem/testHooks.d.ts.map +0 -1
  56. package/dist/internal/virtualFileSystem/watchHub.d.ts.map +0 -1
  57. package/dist/internal/virtualFileSystem/watchHub.js +0 -33
  58. /package/dist/internal/{virtualFileSystem/testHooks.js → testHooks.js} +0 -0
@@ -1,8 +1,10 @@
1
1
  // Virtual filesystem failure schemas and identities shared by the runtime implementation.
2
- import * as Data from "effect/Data";
3
2
  import * as Predicate from "effect/Predicate";
4
3
  import * as Result from "effect/Result";
5
4
  import * as Schema from "effect/Schema";
5
+ import { ConfigurationError, FsError } from "../VirtualFileSystemError.js";
6
+ /** @internal */
7
+ export { ConfigurationError, FsError };
6
8
  /** @internal */
7
9
  export const FsCode = Schema.Literals([
8
10
  "NotFound",
@@ -24,21 +26,15 @@ export const FsCode = Schema.Literals([
24
26
  "FileTooLarge",
25
27
  "NoData",
26
28
  "SymlinkLoop",
27
- "UnrepresentableName"
29
+ "UnrepresentableName",
30
+ // A durable provider knows the mutation was not committed.
31
+ "StorageRejected",
32
+ // A commit or publication failed after its outcome ceased to be knowable to the caller.
33
+ "OutcomeUnknown",
34
+ // The provider stopped serving operations until recovery establishes its state.
35
+ "VolumeUnavailable",
36
+ "VolumeBusy"
28
37
  ]);
29
- /** @internal */
30
- export class FsError extends Data.TaggedError("FsError") {
31
- // The path is omitted on purpose: byte paths are not printable and may carry user data.
32
- get message() {
33
- return `${this.operation} failed with ${this.code}`;
34
- }
35
- }
36
- /** @internal */
37
- export class ConfigurationError extends Data.TaggedError("ConfigurationError") {
38
- get message() {
39
- return `Invalid option: ${this.field}`;
40
- }
41
- }
42
38
  // Names the offending option so the caller learns which key it got wrong, not just that decoding failed.
43
39
  const configurationField = (issue) => {
44
40
  if (Predicate.isTagged("Pointer")(issue))
@@ -1,5 +1,5 @@
1
1
  import * as Effect from "effect/Effect";
2
- import { ImageError } from "../../Snapshot.js";
2
+ import { ImageError } from "../Snapshot.js";
3
3
  /** @internal */
4
4
  export declare const fromFixture: (fixture: {
5
5
  readonly rootMetadata?: {
@@ -13,7 +13,7 @@ export declare const fromFixture: (fixture: {
13
13
  };
14
14
  readonly entries: readonly ({
15
15
  readonly kind: "directory";
16
- readonly path: string | import("../../BytePath.js").BytePath;
16
+ readonly path: string | import("../BytePath.js").BytePath;
17
17
  readonly metadata?: {
18
18
  readonly uid?: number;
19
19
  readonly gid?: number;
@@ -25,7 +25,7 @@ export declare const fromFixture: (fixture: {
25
25
  };
26
26
  } | {
27
27
  readonly kind: "file";
28
- readonly path: string | import("../../BytePath.js").BytePath;
28
+ readonly path: string | import("../BytePath.js").BytePath;
29
29
  readonly bytes: Uint8Array<ArrayBufferLike>;
30
30
  readonly metadata?: {
31
31
  readonly uid?: number;
@@ -38,8 +38,8 @@ export declare const fromFixture: (fixture: {
38
38
  };
39
39
  } | {
40
40
  readonly kind: "symlink";
41
- readonly path: string | import("../../BytePath.js").BytePath;
42
- readonly target: string | import("../../BytePath.js").BytePath;
41
+ readonly path: string | import("../BytePath.js").BytePath;
42
+ readonly target: string | import("../BytePath.js").BytePath;
43
43
  readonly metadata?: {
44
44
  readonly uid?: number;
45
45
  readonly gid?: number;
@@ -51,13 +51,16 @@ export declare const fromFixture: (fixture: {
51
51
  };
52
52
  } | {
53
53
  readonly kind: "hardLink";
54
- readonly path: string | import("../../BytePath.js").BytePath;
55
- readonly target: string | import("../../BytePath.js").BytePath;
54
+ readonly path: string | import("../BytePath.js").BytePath;
55
+ readonly target: string | import("../BytePath.js").BytePath;
56
56
  })[];
57
57
  }, options?: {
58
+ readonly identity?: string & import("effect/Brand").Brand<"@effect-vfs/core/VolumeIdentity">;
58
59
  readonly maxEntries?: number;
60
+ readonly maxPendingOperations?: number;
61
+ readonly maxWatchEvents?: number;
59
62
  readonly maxBytes?: import("effect/ByteSize").ByteSize;
60
63
  readonly maxFileBytes?: import("effect/ByteSize").ByteSize;
61
64
  readonly maxPathBytes?: import("effect/ByteSize").ByteSize;
62
- } | undefined) => Effect.Effect<import("../../VirtualFileSystem.js").Volume, import("./errors.js").ConfigurationError | ImageError, never>;
65
+ } | undefined) => Effect.Effect<import("../VirtualFileSystem.js").Volume, import("./errors.js").ConfigurationError | ImageError | import("effect/PlatformError").PlatformError, import("effect/Crypto").Crypto>;
63
66
  //# sourceMappingURL=fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../../src/internal/fixture.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAoB3C,gBAAgB;AAChB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+MAwLvB,CAAA"}
@@ -2,12 +2,12 @@
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as Result from "effect/Result";
4
4
  import * as Schema from "effect/Schema";
5
- import { ImageError } from "../../Snapshot.js";
6
- import { CanonicalBase64 } from "../canonicalBase64.js";
7
- import * as Image from "../image.js";
8
- import { Fixture as FixtureSchema, FixtureEntry, makeVolume, VolumeOptions as VolumeOptionsSchema, VolumeSource } from "../virtualFileSystem.js";
5
+ import { ImageError } from "../Snapshot.js";
6
+ import { CanonicalBase64 } from "./canonicalBase64.js";
9
7
  import { decodeConfiguration, FsError } from "./errors.js";
8
+ import * as Image from "./image.js";
10
9
  import { inputBytes, isAttachedBytes, isDotComponent, nameBytes, preparePath } from "./path.js";
10
+ import { Fixture as FixtureSchema, FixtureEntry, makeVolume, VolumeIdentity, VolumeOptions as VolumeOptionsSchema, VolumeSource } from "./virtualFileSystem.js";
11
11
  const DEFAULT_MODE = { directory: 0o755, file: 0o644, symlink: 0o777 };
12
12
  const EPOCH_NS = 0n;
13
13
  /** @internal */
@@ -140,5 +140,11 @@ export const fromFixture = Effect.fn("VirtualFileSystem.fromFixture")(function*
140
140
  }));
141
141
  const snapshot = yield* Image.capture({ format: "effect-vfs", version: 1, root: "root", records }, undefined, true);
142
142
  const image = yield* Image.inspect(snapshot);
143
- return yield* makeVolume(VolumeSource.Snapshot({ image }), config.success);
143
+ const { identity, ...volumeOptions } = config.success;
144
+ if (identity === undefined)
145
+ return yield* makeVolume(VolumeSource.Snapshot({ image }), volumeOptions);
146
+ return yield* makeVolume(VolumeSource.Snapshot({ image }), {
147
+ ...volumeOptions,
148
+ identity: VolumeIdentity.make(identity)
149
+ });
144
150
  });
@@ -0,0 +1,286 @@
1
+ import * as ByteSize from "effect/ByteSize";
2
+ import * as Effect from "effect/Effect";
3
+ import * as Schema from "effect/Schema";
4
+ import { ImageError } from "../Snapshot.js";
5
+ /** @internal */
6
+ export declare const Record: Schema.TaggedUnion<{
7
+ readonly directory: Schema.TaggedStruct<"directory", {
8
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
9
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
10
+ readonly lineage: Schema.optionalKey<Schema.String>;
11
+ readonly metadata: Schema.Struct<{
12
+ readonly uid: Schema.Natural;
13
+ readonly gid: Schema.Natural;
14
+ readonly mode: Schema.Natural;
15
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
16
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
17
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
18
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
19
+ readonly nlink: Schema.Natural;
20
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
21
+ }>;
22
+ readonly entries: Schema.$Array<Schema.Struct<{
23
+ readonly name: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
24
+ readonly target: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
25
+ }>>;
26
+ }>;
27
+ readonly file: Schema.TaggedStruct<"file", {
28
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
29
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
30
+ readonly lineage: Schema.optionalKey<Schema.String>;
31
+ readonly metadata: Schema.Struct<{
32
+ readonly uid: Schema.Natural;
33
+ readonly gid: Schema.Natural;
34
+ readonly mode: Schema.Natural;
35
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
36
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
37
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
38
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
39
+ readonly nlink: Schema.Natural;
40
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
41
+ }>;
42
+ readonly data: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
43
+ }>;
44
+ readonly symlink: Schema.TaggedStruct<"symlink", {
45
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
46
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
47
+ readonly lineage: Schema.optionalKey<Schema.String>;
48
+ readonly metadata: Schema.Struct<{
49
+ readonly uid: Schema.Natural;
50
+ readonly gid: Schema.Natural;
51
+ readonly mode: Schema.Natural;
52
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
53
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
54
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
55
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
56
+ readonly nlink: Schema.Natural;
57
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
58
+ }>;
59
+ readonly target: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
60
+ }>;
61
+ }>;
62
+ /** @internal */
63
+ export type Record = typeof Record.Type;
64
+ /** @internal */
65
+ export declare const Document: Schema.Struct<{
66
+ readonly format: Schema.Literal<"effect-vfs-live">;
67
+ readonly version: Schema.Literal<1>;
68
+ readonly identity: Schema.String;
69
+ readonly root: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
70
+ readonly nextInode: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
71
+ readonly revisionCounter: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
72
+ readonly entries: Schema.Natural;
73
+ readonly usedBytes: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
74
+ readonly limits: Schema.Struct<{
75
+ readonly maxEntries: Schema.optionalKey<Schema.Natural>;
76
+ readonly maxBytes: Schema.optionalKey<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>>;
77
+ readonly maxFileBytes: Schema.optionalKey<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>>;
78
+ readonly maxPathBytes: Schema.optionalKey<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>>;
79
+ }>;
80
+ readonly retainedFiles: Schema.$Array<Schema.decodeTo<Schema.BigInt, Schema.String, never, never>>;
81
+ readonly records: Schema.$Array<Schema.TaggedUnion<{
82
+ readonly directory: Schema.TaggedStruct<"directory", {
83
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
84
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
85
+ readonly lineage: Schema.optionalKey<Schema.String>;
86
+ readonly metadata: Schema.Struct<{
87
+ readonly uid: Schema.Natural;
88
+ readonly gid: Schema.Natural;
89
+ readonly mode: Schema.Natural;
90
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
91
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
92
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
93
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
94
+ readonly nlink: Schema.Natural;
95
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
96
+ }>;
97
+ readonly entries: Schema.$Array<Schema.Struct<{
98
+ readonly name: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
99
+ readonly target: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
100
+ }>>;
101
+ }>;
102
+ readonly file: Schema.TaggedStruct<"file", {
103
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
104
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
105
+ readonly lineage: Schema.optionalKey<Schema.String>;
106
+ readonly metadata: Schema.Struct<{
107
+ readonly uid: Schema.Natural;
108
+ readonly gid: Schema.Natural;
109
+ readonly mode: Schema.Natural;
110
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
111
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
112
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
113
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
114
+ readonly nlink: Schema.Natural;
115
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
116
+ }>;
117
+ readonly data: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
118
+ }>;
119
+ readonly symlink: Schema.TaggedStruct<"symlink", {
120
+ readonly ino: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
121
+ readonly revision: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
122
+ readonly lineage: Schema.optionalKey<Schema.String>;
123
+ readonly metadata: Schema.Struct<{
124
+ readonly uid: Schema.Natural;
125
+ readonly gid: Schema.Natural;
126
+ readonly mode: Schema.Natural;
127
+ readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
128
+ readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
129
+ readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
130
+ readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
131
+ readonly nlink: Schema.Natural;
132
+ readonly size: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
133
+ }>;
134
+ readonly target: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
135
+ }>;
136
+ }>>;
137
+ }>;
138
+ /** @internal */
139
+ export type Document = typeof Document.Type;
140
+ /** @internal */
141
+ export declare const encode: (document: {
142
+ readonly format: "effect-vfs-live";
143
+ readonly version: 1;
144
+ readonly identity: string;
145
+ readonly root: bigint;
146
+ readonly nextInode: bigint;
147
+ readonly revisionCounter: bigint;
148
+ readonly entries: number;
149
+ readonly usedBytes: bigint;
150
+ readonly limits: {
151
+ readonly maxEntries?: number;
152
+ readonly maxBytes?: bigint;
153
+ readonly maxFileBytes?: bigint;
154
+ readonly maxPathBytes?: bigint;
155
+ };
156
+ readonly retainedFiles: readonly bigint[];
157
+ readonly records: readonly ({
158
+ readonly _tag: "directory";
159
+ readonly ino: bigint;
160
+ readonly revision: bigint;
161
+ readonly lineage?: string;
162
+ readonly metadata: {
163
+ readonly uid: number;
164
+ readonly gid: number;
165
+ readonly mode: number;
166
+ readonly atimeNs: bigint;
167
+ readonly mtimeNs: bigint;
168
+ readonly ctimeNs: bigint;
169
+ readonly birthtimeNs: bigint;
170
+ readonly nlink: number;
171
+ readonly size: bigint;
172
+ };
173
+ readonly entries: readonly {
174
+ readonly name: string & import("effect/Brand").Brand<"CanonicalBase64">;
175
+ readonly target: bigint;
176
+ }[];
177
+ } | {
178
+ readonly _tag: "file";
179
+ readonly ino: bigint;
180
+ readonly revision: bigint;
181
+ readonly lineage?: string;
182
+ readonly metadata: {
183
+ readonly uid: number;
184
+ readonly gid: number;
185
+ readonly mode: number;
186
+ readonly atimeNs: bigint;
187
+ readonly mtimeNs: bigint;
188
+ readonly ctimeNs: bigint;
189
+ readonly birthtimeNs: bigint;
190
+ readonly nlink: number;
191
+ readonly size: bigint;
192
+ };
193
+ readonly data: string & import("effect/Brand").Brand<"CanonicalBase64">;
194
+ } | {
195
+ readonly _tag: "symlink";
196
+ readonly ino: bigint;
197
+ readonly revision: bigint;
198
+ readonly lineage?: string;
199
+ readonly metadata: {
200
+ readonly uid: number;
201
+ readonly gid: number;
202
+ readonly mode: number;
203
+ readonly atimeNs: bigint;
204
+ readonly mtimeNs: bigint;
205
+ readonly ctimeNs: bigint;
206
+ readonly birthtimeNs: bigint;
207
+ readonly nlink: number;
208
+ readonly size: bigint;
209
+ };
210
+ readonly target: string & import("effect/Brand").Brand<"CanonicalBase64">;
211
+ })[];
212
+ }) => Effect.Effect<Uint8Array<ArrayBuffer>, ImageError, never>;
213
+ /** @internal */
214
+ export declare const decode: (bytes: Uint8Array<ArrayBufferLike>, maxEncodedBytes: ByteSize.ByteSize) => Effect.Effect<{
215
+ readonly format: "effect-vfs-live";
216
+ readonly version: 1;
217
+ readonly identity: string;
218
+ readonly root: bigint;
219
+ readonly nextInode: bigint;
220
+ readonly revisionCounter: bigint;
221
+ readonly entries: number;
222
+ readonly usedBytes: bigint;
223
+ readonly limits: {
224
+ readonly maxEntries?: number;
225
+ readonly maxBytes?: bigint;
226
+ readonly maxFileBytes?: bigint;
227
+ readonly maxPathBytes?: bigint;
228
+ };
229
+ readonly retainedFiles: readonly bigint[];
230
+ readonly records: readonly ({
231
+ readonly _tag: "directory";
232
+ readonly ino: bigint;
233
+ readonly revision: bigint;
234
+ readonly lineage?: string;
235
+ readonly metadata: {
236
+ readonly uid: number;
237
+ readonly gid: number;
238
+ readonly mode: number;
239
+ readonly atimeNs: bigint;
240
+ readonly mtimeNs: bigint;
241
+ readonly ctimeNs: bigint;
242
+ readonly birthtimeNs: bigint;
243
+ readonly nlink: number;
244
+ readonly size: bigint;
245
+ };
246
+ readonly entries: readonly {
247
+ readonly name: string & import("effect/Brand").Brand<"CanonicalBase64">;
248
+ readonly target: bigint;
249
+ }[];
250
+ } | {
251
+ readonly _tag: "file";
252
+ readonly ino: bigint;
253
+ readonly revision: bigint;
254
+ readonly lineage?: string;
255
+ readonly metadata: {
256
+ readonly uid: number;
257
+ readonly gid: number;
258
+ readonly mode: number;
259
+ readonly atimeNs: bigint;
260
+ readonly mtimeNs: bigint;
261
+ readonly ctimeNs: bigint;
262
+ readonly birthtimeNs: bigint;
263
+ readonly nlink: number;
264
+ readonly size: bigint;
265
+ };
266
+ readonly data: string & import("effect/Brand").Brand<"CanonicalBase64">;
267
+ } | {
268
+ readonly _tag: "symlink";
269
+ readonly ino: bigint;
270
+ readonly revision: bigint;
271
+ readonly lineage?: string;
272
+ readonly metadata: {
273
+ readonly uid: number;
274
+ readonly gid: number;
275
+ readonly mode: number;
276
+ readonly atimeNs: bigint;
277
+ readonly mtimeNs: bigint;
278
+ readonly ctimeNs: bigint;
279
+ readonly birthtimeNs: bigint;
280
+ readonly nlink: number;
281
+ readonly size: bigint;
282
+ };
283
+ readonly target: string & import("effect/Brand").Brand<"CanonicalBase64">;
284
+ })[];
285
+ }, ImageError, never>;
286
+ //# sourceMappingURL=liveImage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveImage.d.ts","sourceRoot":"","sources":["../../src/internal/liveImage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAmB3C,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOjB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC,gBAAgB;AAChB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBnB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAgI3C,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+DAMjB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuBjB,CAAA"}
@@ -0,0 +1,176 @@
1
+ // Private, versioned image for a live volume. Unlike a public snapshot, this
2
+ // retains inode numbers, revisions, allocator state, and open unlinked files.
3
+ import * as ByteSize from "effect/ByteSize";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Result from "effect/Result";
6
+ import * as Schema from "effect/Schema";
7
+ import * as SchemaTransformation from "effect/SchemaTransformation";
8
+ import { ImageError } from "../Snapshot.js";
9
+ import { CanonicalBase64 } from "./canonicalBase64.js";
10
+ import { StoredMetadata } from "./metadata.js";
11
+ const NaturalBigInt = Schema.String.check(Schema.isPattern(/^(0|[1-9][0-9]{0,127})$/)).pipe(Schema.decodeTo(Schema.BigInt, SchemaTransformation.bigintFromString));
12
+ const Common = {
13
+ ino: NaturalBigInt,
14
+ revision: NaturalBigInt,
15
+ lineage: Schema.optionalKey(Schema.String),
16
+ metadata: Schema.Struct({
17
+ ...StoredMetadata.fields,
18
+ nlink: Schema.Natural,
19
+ size: NaturalBigInt
20
+ })
21
+ };
22
+ /** @internal */
23
+ export const Record = Schema.TaggedUnion({
24
+ directory: {
25
+ ...Common,
26
+ entries: Schema.Array(Schema.Struct({ name: CanonicalBase64.Encoded, target: NaturalBigInt }))
27
+ },
28
+ file: { ...Common, data: CanonicalBase64.Encoded },
29
+ symlink: { ...Common, target: CanonicalBase64.Encoded }
30
+ });
31
+ /** @internal */
32
+ export const Document = Schema.Struct({
33
+ format: Schema.Literal("effect-vfs-live"),
34
+ version: Schema.Literal(1),
35
+ identity: Schema.String.check(Schema.isPattern(/^[0-9a-f]{32}$/)),
36
+ root: NaturalBigInt,
37
+ nextInode: NaturalBigInt,
38
+ revisionCounter: NaturalBigInt,
39
+ entries: Schema.Natural,
40
+ usedBytes: NaturalBigInt,
41
+ limits: Schema.Struct({
42
+ maxEntries: Schema.optionalKey(Schema.Natural),
43
+ maxBytes: Schema.optionalKey(NaturalBigInt),
44
+ maxFileBytes: Schema.optionalKey(NaturalBigInt),
45
+ maxPathBytes: Schema.optionalKey(NaturalBigInt)
46
+ }),
47
+ retainedFiles: Schema.Array(NaturalBigInt),
48
+ records: Schema.Array(Record)
49
+ });
50
+ const invalid = () => new ImageError({ code: "InvalidStructure", field: "liveImage" });
51
+ const validate = Effect.fnUntraced(function* (document) {
52
+ const records = new Map();
53
+ for (const record of document.records) {
54
+ if (record.ino < 1n || records.has(record.ino) || record.revision < 1n ||
55
+ record.revision > document.revisionCounter || record.ino >= document.nextInode)
56
+ return yield* invalid();
57
+ records.set(record.ino, record);
58
+ }
59
+ const root = records.get(document.root);
60
+ if (document.root !== 1n || root?._tag !== "directory" || document.revisionCounter < 1n) {
61
+ return yield* invalid();
62
+ }
63
+ const links = new Map();
64
+ const pending = [[root, 1n]];
65
+ const seenDirectories = new Set();
66
+ const reachable = new Set();
67
+ let entries = 0;
68
+ for (let index = 0; index < pending.length; index++) {
69
+ const current = pending[index];
70
+ if (current === undefined)
71
+ return yield* invalid();
72
+ const [directory, pathBytes] = current;
73
+ if (seenDirectories.has(directory.ino))
74
+ return yield* invalid();
75
+ seenDirectories.add(directory.ino);
76
+ reachable.add(directory.ino);
77
+ const names = new Set();
78
+ for (const entry of directory.entries) {
79
+ if (names.has(entry.name) || entry.target === document.root)
80
+ return yield* invalid();
81
+ names.add(entry.name);
82
+ const name = yield* CanonicalBase64.decode(entry.name);
83
+ if (name.length < 1 || name.length > 255 || name.includes(0) || name.includes(47) ||
84
+ (name.length === 1 && name[0] === 46) ||
85
+ (name.length === 2 && name[0] === 46 && name[1] === 46))
86
+ return yield* invalid();
87
+ const childPathBytes = pathBytes + BigInt(name.length) + (pathBytes === 1n ? 0n : 1n);
88
+ if (document.limits.maxPathBytes !== undefined && childPathBytes > document.limits.maxPathBytes) {
89
+ return yield* invalid();
90
+ }
91
+ const target = records.get(entry.target);
92
+ if (target === undefined)
93
+ return yield* invalid();
94
+ entries++;
95
+ links.set(target.ino, (links.get(target.ino) ?? 0) + 1);
96
+ reachable.add(target.ino);
97
+ if (Record.guards.directory(target))
98
+ pending.push([target, childPathBytes]);
99
+ }
100
+ }
101
+ if (entries !== document.entries || links.has(root.ino))
102
+ return yield* invalid();
103
+ const retained = new Set(document.retainedFiles);
104
+ if (retained.size !== document.retainedFiles.length)
105
+ return yield* invalid();
106
+ let usedBytes = 0n;
107
+ for (const record of document.records) {
108
+ const actualLinks = links.get(record.ino) ?? 0;
109
+ if (Record.guards.directory(record)) {
110
+ const childDirectories = record.entries.filter((entry) => {
111
+ const child = records.get(entry.target);
112
+ return child !== undefined && Record.guards.directory(child);
113
+ }).length;
114
+ if (!seenDirectories.has(record.ino) || (record.ino !== root.ino && actualLinks !== 1) ||
115
+ record.metadata.nlink !== 2 + childDirectories || record.metadata.size !== 0n)
116
+ return yield* invalid();
117
+ }
118
+ else {
119
+ const payload = Record.guards.file(record) ? record.data : record.target;
120
+ const length = BigInt(CanonicalBase64.decodedLength(payload));
121
+ if (record.metadata.size !== length || record.metadata.nlink !== actualLinks)
122
+ return yield* invalid();
123
+ if (Record.guards.file(record)) {
124
+ if (document.limits.maxFileBytes !== undefined && length > document.limits.maxFileBytes) {
125
+ return yield* invalid();
126
+ }
127
+ if (actualLinks === 0 && !retained.has(record.ino))
128
+ return yield* invalid();
129
+ if (actualLinks > 0 && retained.has(record.ino))
130
+ return yield* invalid();
131
+ }
132
+ else {
133
+ if (actualLinks === 0 || retained.has(record.ino) || (yield* CanonicalBase64.decode(record.target)).includes(0)) {
134
+ return yield* invalid();
135
+ }
136
+ }
137
+ usedBytes += length;
138
+ }
139
+ if (!reachable.has(record.ino) && !retained.has(record.ino))
140
+ return yield* invalid();
141
+ }
142
+ if (document.limits.maxPathBytes !== undefined && document.limits.maxPathBytes < 1n)
143
+ return yield* invalid();
144
+ if (usedBytes !== document.usedBytes ||
145
+ (document.limits.maxEntries !== undefined && entries > document.limits.maxEntries) ||
146
+ (document.limits.maxBytes !== undefined && usedBytes > document.limits.maxBytes))
147
+ return yield* invalid();
148
+ for (const ino of retained) {
149
+ if (records.get(ino)?._tag !== "file" || reachable.has(ino))
150
+ return yield* invalid();
151
+ }
152
+ return document;
153
+ });
154
+ /** @internal */
155
+ export const encode = Effect.fnUntraced(function* (document) {
156
+ const text = yield* Schema.encodeEffect(Schema.fromJsonString(Document))(yield* validate(document)).pipe(Effect.mapError(() => new ImageError({ code: "InvalidStructure", field: "liveImage" })));
157
+ return new TextEncoder().encode(text);
158
+ });
159
+ /** @internal */
160
+ export const decode = Effect.fnUntraced(function* (bytes, maxEncodedBytes) {
161
+ if (!(bytes instanceof Uint8Array) || !(bytes.buffer instanceof ArrayBuffer)) {
162
+ return yield* new ImageError({ code: "InvalidEncoding", field: "liveImage" });
163
+ }
164
+ if (ByteSize.isGreaterThan(ByteSize.bytes(bytes.byteLength), maxEncodedBytes)) {
165
+ return yield* new ImageError({ code: "LimitExceeded", field: "encodedBytes" });
166
+ }
167
+ const text = yield* Effect.try({
168
+ try: () => new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(bytes)),
169
+ catch: () => new ImageError({ code: "InvalidEncoding", field: "liveImage" })
170
+ });
171
+ const parsed = yield* Schema.decodeEffect(Schema.fromJsonString(Schema.Unknown))(text).pipe(Effect.mapError(() => new ImageError({ code: "InvalidEncoding", field: "liveImage" })));
172
+ const document = Schema.decodeUnknownResult(Document, { onExcessProperty: "error" })(parsed);
173
+ if (Result.isFailure(document))
174
+ return yield* new ImageError({ code: "InvalidStructure", field: "liveImage" });
175
+ return yield* validate(document.success);
176
+ });
@@ -1,5 +1,5 @@
1
- import type { Snapshot } from "../../Snapshot.js";
2
- import * as Image from "../image.js";
1
+ import type { Snapshot } from "../Snapshot.js";
2
+ import * as Image from "./image.js";
3
3
  /** @internal */
4
4
  export interface Content {
5
5
  readonly bytes: Uint8Array;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlayContent.d.ts","sourceRoot":"","sources":["../../src/internal/overlayContent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AAEnC,gBAAgB;AAChB,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAC3B;AAID,gBAAgB;AAChB,eAAO,MAAM,kBAAkB,aAAc,QAAQ,KAAG,OAAwC,CAAA;AAEhG,gBAAgB;AAChB,eAAO,MAAM,IAAI,UAAW,UAAU,KAAG,OAAsB,CAAA;AAE/D,gBAAgB;AAChB,eAAO,MAAM,KAAK,QAAO,OAAkC,CAAA;AAG3D,gBAAgB;AAChB,eAAO,MAAM,UAAU,aAAc,QAAQ,SAAS,KAAK,CAAC,QAAQ,KAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAiBjG,CAAA"}
@@ -1,8 +1,8 @@
1
1
  // Immutable regular-file payloads shared by overlay workspaces.
2
2
  import * as Result from "effect/Result";
3
3
  import * as Schema from "effect/Schema";
4
- import { CanonicalBase64 } from "../canonicalBase64.js";
5
- import * as Image from "../image.js";
4
+ import { CanonicalBase64 } from "./canonicalBase64.js";
5
+ import * as Image from "./image.js";
6
6
  const overlayContents = new WeakMap();
7
7
  /** @internal */
8
8
  export const hasOverlayContents = (snapshot) => overlayContents.has(snapshot);
@@ -1,4 +1,4 @@
1
- import type { StoredMetadata } from "../metadata.js";
1
+ import type { StoredMetadata } from "./metadata.js";
2
2
  /** @internal */
3
3
  export interface ObservationEntry {
4
4
  readonly path: Uint8Array;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlayDiff.d.ts","sourceRoot":"","sources":["../../src/internal/overlayDiff.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,gBAAgB;AAChB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;CAClC;AAED,gBAAgB;AAChB,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAEtH,gBAAgB;AAChB,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;CAAE,GAC9F;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;CAAE,GAChG;IACA,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC7C,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC5C,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;CACvD,GACC;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;CACvD,GACC;IACA,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;CACvD,CAAA;AA4DH,gBAAgB;AAChB,eAAO,MAAM,cAAc,SACnB,aAAa,CAAC,gBAAgB,CAAC,WAC5B,aAAa,CAAC,gBAAgB,CAAC,kCAEvC,aAAa,CAAC,gBAAgB,CAgFhC,CAAA"}
@@ -2,7 +2,7 @@ import * as Data from "effect/Data";
2
2
  import * as Encoding from "effect/Encoding";
3
3
  import * as Order from "effect/Order";
4
4
  import * as Predicate from "effect/Predicate";
5
- import { bytesOrder, sameBytes } from "../bytes.js";
5
+ import { bytesOrder, sameBytes } from "./bytes.js";
6
6
  const RawOverlayChange = Data.taggedEnum();
7
7
  const timestampFields = new Set(["atimeNs", "mtimeNs", "ctimeNs", "birthtimeNs"]);
8
8
  const differenceOrder = [
@@ -1,8 +1,8 @@
1
1
  import * as ByteSize from "effect/ByteSize";
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as Result from "effect/Result";
4
- import type { BytePath } from "../../BytePath.js";
5
- import type { PathInput } from "../../VirtualFileSystem.js";
4
+ import type { BytePath } from "../BytePath.js";
5
+ import type { PathInput } from "../VirtualFileSystem.js";
6
6
  import { FsError } from "./errors.js";
7
7
  /** @internal */
8
8
  export declare const SLASH_HEX = "2f";