@effect-vfs/core 0.4.0 → 0.6.0

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