@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.
Files changed (130) hide show
  1. package/README.md +34 -31
  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 +11 -21
  15. package/dist/LiveVolume.d.ts.map +1 -1
  16. package/dist/LiveVolume.js +17 -14
  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 +448 -115
  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 +47 -5
  60. package/dist/internal/errors.d.ts.map +1 -1
  61. package/dist/internal/errors.js +80 -36
  62. package/dist/internal/fixture.d.ts +2 -2
  63. package/dist/internal/fixture.d.ts.map +1 -1
  64. package/dist/internal/fixture.js +57 -74
  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/overlayDiff.d.ts +2 -2
  90. package/dist/internal/overlayDiff.d.ts.map +1 -1
  91. package/dist/internal/overlayDiff.js +0 -3
  92. package/dist/internal/path.d.ts +17 -5
  93. package/dist/internal/path.d.ts.map +1 -1
  94. package/dist/internal/path.js +38 -24
  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 +11 -15
  101. package/dist/internal/stagedState.d.ts.map +1 -1
  102. package/dist/internal/stagedState.js +15 -59
  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 +39 -489
  113. package/dist/internal/virtualFileSystem.d.ts.map +1 -1
  114. package/dist/internal/virtualFileSystem.js +2112 -2465
  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 +15 -6
  119. package/dist/internal/watchHub.d.ts.map +1 -1
  120. package/dist/internal/watchHub.js +56 -42
  121. package/package.json +48 -4
  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/overlayContent.d.ts +0 -15
  126. package/dist/internal/overlayContent.d.ts.map +0 -1
  127. package/dist/internal/overlayContent.js +0 -29
  128. package/dist/internal/testHooks.d.ts +0 -20
  129. package/dist/internal/testHooks.d.ts.map +0 -1
  130. package/dist/internal/testHooks.js +0 -23
@@ -0,0 +1,179 @@
1
+ // This versioned digest covers namespace content and hard-link groups, independent of inode numbers. Framing,
2
+ // byte order, and domain prefix are part of the persisted delta contract.
3
+ import * as ByteSize from "effect/ByteSize";
4
+ import * as Crypto from "effect/Crypto";
5
+ import * as Effect from "effect/Effect";
6
+ import { bytesOrder } from "./bytes.js";
7
+ import { imageFailure } from "./errors.js";
8
+ import { joinPath, nameBytes, ROOT_PATH } from "./path.js";
9
+ import { byEntryName, getNode, payloadOf, ROOT_INO } from "./volumeState.js";
10
+ const ALGORITHM = "effect-vfs-semantic-sha256-v1";
11
+ /** @internal */
12
+ export const DIGEST_BYTES = 32;
13
+ const U64_BYTES = 8;
14
+ const encoder = new TextEncoder();
15
+ const IDENTITY_PREFIX = encoder.encode(`${ALGORITHM}\0`);
16
+ const KIND_BYTE = { directory: 0, file: 1, symlink: 2 };
17
+ const u64 = (out, offset, n) => {
18
+ new DataView(out.buffer, out.byteOffset).setBigUint64(offset, BigInt(n), false);
19
+ return offset + U64_BYTES;
20
+ };
21
+ const frame = (out, offset, bytes) => {
22
+ const at = u64(out, offset, bytes.length);
23
+ out.set(bytes, at);
24
+ return at + bytes.length;
25
+ };
26
+ const stamps = (node) => [node.metadata.atimeNs, node.metadata.mtimeNs, node.metadata.ctimeNs, node.metadata.birthtimeNs].map((value) => encoder.encode(String(value)));
27
+ const layout = (node) => {
28
+ const times = stamps(node);
29
+ const entries = node.kind === "directory"
30
+ ? [...node.entries].sort(byEntryName).map(([name, ino]) => [nameBytes(name), ino])
31
+ : [];
32
+ const body = payloadOf(node);
33
+ const length = 1 + 3 * U64_BYTES + times.reduce((sum, stamp) => sum + U64_BYTES + stamp.length, 0) +
34
+ (body === undefined
35
+ ? U64_BYTES + entries.reduce((sum, [name]) => sum + U64_BYTES + name.length + DIGEST_BYTES, 0)
36
+ : U64_BYTES + body.length);
37
+ return { times, entries, body, length };
38
+ };
39
+ /** @internal */
40
+ export const nodeBytes = (node) => layout(node).length;
41
+ const preimage = (node, { body, entries, length, times }, childDigest) => {
42
+ const out = new Uint8Array(length);
43
+ out[0] = KIND_BYTE[node.kind];
44
+ let offset = u64(out, 1, node.metadata.uid);
45
+ offset = u64(out, offset, node.metadata.gid);
46
+ offset = u64(out, offset, node.metadata.mode);
47
+ for (const stamp of times)
48
+ offset = frame(out, offset, stamp);
49
+ if (body !== undefined)
50
+ frame(out, offset, body);
51
+ else {
52
+ offset = u64(out, offset, entries.length);
53
+ for (const [name, ino] of entries) {
54
+ offset = frame(out, offset, name);
55
+ out.set(childDigest(ino), offset);
56
+ offset += DIGEST_BYTES;
57
+ }
58
+ }
59
+ return out;
60
+ };
61
+ /** @internal */
62
+ export const meter = (budget) => {
63
+ let hashed = 0;
64
+ return {
65
+ charge: (bytes) => Effect.suspend(() => {
66
+ hashed += bytes;
67
+ return ByteSize.isGreaterThan(ByteSize.bytes(hashed), budget.identityBytes)
68
+ ? Effect.fail(imageFailure(budget.operation, "LimitExceeded", { field: "identityBytes" }))
69
+ : Effect.void;
70
+ }),
71
+ spent: () => hashed
72
+ };
73
+ };
74
+ /** @internal */
75
+ export const nodeDigest = Effect.fnUntraced(function* (node, childDigest, meter) {
76
+ const crypto = yield* Crypto.Crypto;
77
+ const planned = layout(node);
78
+ // Reject oversized nodes before allocating their preimage.
79
+ yield* meter.charge(planned.length);
80
+ return yield* crypto.digest("SHA-256", preimage(node, planned, childDigest));
81
+ });
82
+ /** @internal */
83
+ export const identityDigest = Effect.fnUntraced(function* (root, groups, meter) {
84
+ const crypto = yield* Crypto.Crypto;
85
+ const sorted = [...groups].sort((a, b) => bytesOrder(a[0], b[0]));
86
+ const length = IDENTITY_PREFIX.length + DIGEST_BYTES + U64_BYTES +
87
+ sorted.reduce((sum, group) => group.reduce((inner, path) => inner + U64_BYTES + path.length, sum + U64_BYTES), 0);
88
+ yield* meter.charge(length);
89
+ const out = new Uint8Array(length);
90
+ out.set(IDENTITY_PREFIX);
91
+ out.set(root, IDENTITY_PREFIX.length);
92
+ let offset = u64(out, IDENTITY_PREFIX.length + DIGEST_BYTES, sorted.length);
93
+ for (const group of sorted) {
94
+ offset = u64(out, offset, group.length);
95
+ for (const path of group)
96
+ offset = frame(out, offset, path);
97
+ }
98
+ return yield* crypto.digest("SHA-256", out);
99
+ });
100
+ // Digest leaves first and directories in reverse walk order so every child digest exists before its parent.
101
+ /** @internal */
102
+ export const identify = Effect.fnUntraced(function* (state, budget) {
103
+ const root = getNode(state, ROOT_INO);
104
+ if (root?.kind !== "directory") {
105
+ return yield* imageFailure(budget.operation, "InvalidStructure", { field: "root" });
106
+ }
107
+ const order = [root];
108
+ // The root is a record too, so a limit of zero refuses even an empty snapshot.
109
+ if (order.length > budget.records) {
110
+ return yield* imageFailure(budget.operation, "LimitExceeded", { field: budget.recordsField });
111
+ }
112
+ const seen = new Set([ROOT_INO]);
113
+ const directoryPaths = new Map([[ROOT_INO, ROOT_PATH]]);
114
+ const named = new Map();
115
+ let entries = 0;
116
+ for (let index = 0; index < order.length; index++) {
117
+ const node = order[index];
118
+ if (node.kind !== "directory")
119
+ continue;
120
+ const path = directoryPaths.get(node.ino);
121
+ for (const [name, ino] of node.entries) {
122
+ if (++entries > budget.entries) {
123
+ return yield* imageFailure(budget.operation, "LimitExceeded", { field: "entries" });
124
+ }
125
+ const child = getNode(state, ino);
126
+ if (child === undefined)
127
+ continue;
128
+ if (child.kind === "directory")
129
+ directoryPaths.set(ino, joinPath(path, nameBytes(name)));
130
+ else if (child.links.length > 1) {
131
+ const paths = named.get(ino);
132
+ const childPath = joinPath(path, nameBytes(name));
133
+ if (paths === undefined)
134
+ named.set(ino, [childPath]);
135
+ else
136
+ paths.push(childPath);
137
+ }
138
+ if (seen.has(ino))
139
+ continue;
140
+ seen.add(ino);
141
+ order.push(child);
142
+ if (order.length > budget.records) {
143
+ return yield* imageFailure(budget.operation, "LimitExceeded", { field: budget.recordsField });
144
+ }
145
+ }
146
+ }
147
+ const digests = new Map();
148
+ const measure = meter(budget);
149
+ const lookup = (ino) => digests.get(ino);
150
+ let payloadBytes = 0;
151
+ const leavesFirst = [
152
+ ...order.filter((node) => node.kind !== "directory"),
153
+ ...order.filter((node) => node.kind === "directory").reverse()
154
+ ];
155
+ for (const node of leavesFirst) {
156
+ const body = payloadOf(node);
157
+ if (body !== undefined) {
158
+ payloadBytes += body.length;
159
+ if (budget.payloadBytes !== undefined &&
160
+ ByteSize.isGreaterThan(ByteSize.bytes(payloadBytes), budget.payloadBytes.limit)) {
161
+ return yield* imageFailure(budget.operation, "LimitExceeded", { field: budget.payloadBytes.field });
162
+ }
163
+ }
164
+ digests.set(node.ino, yield* nodeDigest(node, lookup, measure));
165
+ }
166
+ const groups = new Map();
167
+ for (const [ino, paths] of named)
168
+ if (paths.length > 1)
169
+ groups.set(ino, paths.sort(bytesOrder));
170
+ const nodeBytes = measure.spent();
171
+ return {
172
+ digest: yield* identityDigest(digests.get(ROOT_INO), groups.values(), measure),
173
+ digests,
174
+ groups,
175
+ records: order.length,
176
+ payloadBytes,
177
+ nodeBytes
178
+ };
179
+ });
@@ -1,18 +1,7 @@
1
1
  import * as Schema from "effect/Schema";
2
+ import { Timestamp } from "../Metadata.js";
2
3
  /** @internal */
3
- export declare const Timestamp: Schema.BigInt;
4
- /** @internal */
5
- export declare const TimestampFromString: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
6
- /** @internal */
7
- export declare const WireStoredMetadata: Schema.Struct<{
8
- readonly uid: Schema.Natural;
9
- readonly gid: Schema.Natural;
10
- readonly mode: Schema.Natural;
11
- readonly atimeNs: Schema.String;
12
- readonly mtimeNs: Schema.String;
13
- readonly ctimeNs: Schema.String;
14
- readonly birthtimeNs: Schema.String;
15
- }>;
4
+ export { Timestamp };
16
5
  /** @internal */
17
6
  export declare const StoredMetadata: Schema.Struct<{
18
7
  readonly uid: Schema.Natural;
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/internal/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAKvC,gBAAgB;AAChB,eAAO,MAAM,SAAS,eAGrB,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,mBAAmB,6DAE0C,CAAA;AAE1E,gBAAgB;AAChB,eAAO,MAAM,kBAAkB;;;;;;;;EAQ7B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA"}
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/internal/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAG1C,gBAAgB;AAChB,OAAO,EAAE,SAAS,EAAE,CAAA;AAMpB,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA"}
@@ -1,23 +1,13 @@
1
1
  import * as Schema from "effect/Schema";
2
2
  import * as SchemaTransformation from "effect/SchemaTransformation";
3
- const MAX_TIMESTAMP = 10n ** 128n - 1n;
3
+ import { Timestamp } from "../Metadata.js";
4
+ import { ENCODING_CHECK } from "./errors.js";
4
5
  /** @internal */
5
- export const Timestamp = Schema.BigInt.check(Schema.isGreaterThanOrEqualToBigInt(-MAX_TIMESTAMP), Schema.isLessThanOrEqualToBigInt(MAX_TIMESTAMP));
6
- /** @internal */
7
- export const TimestampFromString = Schema.String
8
- .check(Schema.isPattern(/^-?[0-9]{1,128}$/))
6
+ export { Timestamp };
7
+ const TimestampFromString = Schema.String
8
+ .check(Schema.isPattern(/^-?[0-9]{1,128}$/, { [ENCODING_CHECK]: true }))
9
9
  .pipe(Schema.decodeTo(Timestamp, SchemaTransformation.bigintFromString));
10
10
  /** @internal */
11
- export const WireStoredMetadata = Schema.Struct({
12
- uid: Schema.Natural,
13
- gid: Schema.Natural,
14
- mode: Schema.Natural.check(Schema.isLessThanOrEqualTo(0o7777)),
15
- atimeNs: Schema.String,
16
- mtimeNs: Schema.String,
17
- ctimeNs: Schema.String,
18
- birthtimeNs: Schema.String
19
- });
20
- /** @internal */
21
11
  export const StoredMetadata = Schema.Struct({
22
12
  uid: Schema.Natural,
23
13
  gid: Schema.Natural,
@@ -7,8 +7,7 @@ export interface ObservationEntry {
7
7
  readonly content: Uint8Array | undefined;
8
8
  readonly metadata: StoredMetadata;
9
9
  }
10
- /** @internal */
11
- export type OverlayDifference = "content" | "mode" | "uid" | "gid" | "atimeNs" | "mtimeNs" | "ctimeNs" | "birthtimeNs";
10
+ type OverlayDifference = "content" | "mode" | "uid" | "gid" | "atimeNs" | "mtimeNs" | "ctimeNs" | "birthtimeNs";
12
11
  /** @internal */
13
12
  export type RawOverlayChange = {
14
13
  readonly _tag: "Added";
@@ -38,4 +37,5 @@ export type RawOverlayChange = {
38
37
  };
39
38
  /** @internal */
40
39
  export declare const compareOverlay: (base: ReadonlyArray<ObservationEntry>, current: ReadonlyArray<ObservationEntry>, includeTimestamps?: boolean) => ReadonlyArray<RawOverlayChange>;
40
+ export {};
41
41
  //# sourceMappingURL=overlayDiff.d.ts.map
@@ -1 +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"}
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,KAAK,iBAAiB,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;AAE/G,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;AA2DH,gBAAgB;AAChB,eAAO,MAAM,cAAc,SACnB,aAAa,CAAC,gBAAgB,CAAC,WAC5B,aAAa,CAAC,gBAAgB,CAAC,kCAEvC,aAAa,CAAC,gBAAgB,CA8EhC,CAAA"}
@@ -23,7 +23,6 @@ const tagOrder = {
23
23
  Updated: 4
24
24
  };
25
25
  const key = Encoding.encodeHex;
26
- // Output order: source path bytewise (a rename sorts by its `from`), then Added, Removed, Replaced, Renamed, Updated.
27
26
  const sourcePath = (change) => Predicate.isTagged("Renamed")(change) ? change.from : change.path;
28
27
  const changeOrder = Order.combine(Order.mapInput(bytesOrder, sourcePath), Order.mapInput(Order.Number, (change) => tagOrder[change._tag]));
29
28
  const differences = (before, after, includeTimestamps) => Object.freeze(differenceOrder.filter((field) => {
@@ -88,7 +87,6 @@ export const compareOverlay = (base, current, includeTimestamps = false) => {
88
87
  if (renameSources.has(pathKey))
89
88
  continue;
90
89
  const after = currentPaths.get(pathKey);
91
- // Gone, or the path's current occupant arrived by rename: the base entry was removed either way.
92
90
  if (after === undefined || renameTargets.has(pathKey)) {
93
91
  changes.push(RawOverlayChange.Removed({ path: before.path.slice(), kind: before.kind }));
94
92
  continue;
@@ -109,7 +107,6 @@ export const compareOverlay = (base, current, includeTimestamps = false) => {
109
107
  }
110
108
  for (const after of current) {
111
109
  const pathKey = key(after.path);
112
- // A new path, or one whose base occupant was renamed away; rename targets were already reported.
113
110
  if (!renameTargets.has(pathKey) && (!basePaths.has(pathKey) || renameSources.has(pathKey))) {
114
111
  changes.push(RawOverlayChange.Added({ path: after.path.slice(), kind: after.kind }));
115
112
  }
@@ -2,8 +2,8 @@ import * as ByteSize from "effect/ByteSize";
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as Result from "effect/Result";
4
4
  import type { BytePath } from "../BytePath.js";
5
+ import type { FsFailure } from "../VfsError.js";
5
6
  import type { PathInput } from "../VirtualFileSystem.js";
6
- import { FsError } from "./errors.js";
7
7
  /** @internal */
8
8
  export declare const SLASH_HEX = "2f";
9
9
  /** @internal */
@@ -13,21 +13,31 @@ export declare const DOT_DOT_HEX = "2e2e";
13
13
  /** @internal */
14
14
  export declare const SLASH_BYTE = 47;
15
15
  /** @internal */
16
+ export declare const NUL_BYTE = 0;
17
+ /** @internal */
18
+ export declare const MAX_SYMLINK_TRAVERSALS = 40;
19
+ /** @internal */
16
20
  export declare const MAX_NAME_BYTES = 255;
17
21
  /** @internal */
22
+ export declare const isNameBytes: (name: Uint8Array) => boolean;
23
+ /** @internal */
24
+ export declare const ROOT_PATH: Uint8Array<ArrayBuffer>;
25
+ /** @internal */
26
+ export declare const joinPath: (prefix: Uint8Array, name: Uint8Array) => Uint8Array;
27
+ /** @internal */
18
28
  export declare const isDotComponent: (name: string | undefined) => name is undefined | typeof DOT_HEX | typeof DOT_DOT_HEX;
19
29
  /** @internal */
20
30
  export declare const ownedPath: (bytes: Uint8Array) => BytePath;
21
31
  /** @internal */
22
- export declare const strictString: (bytes: Uint8Array, operation: string) => Effect.Effect<string, FsError, never>;
32
+ export declare const strictString: (bytes: Uint8Array, operation: string) => Effect.Effect<string, FsFailure, never>;
23
33
  /** @internal */
24
34
  export declare const nameBytes: (name: string) => Uint8Array;
25
35
  /** @internal */
26
36
  export declare const isAttachedBytes: (bytes: Uint8Array) => boolean;
27
37
  /** @internal */
28
- export declare const pathFromBytes: (bytes: Uint8Array<ArrayBufferLike>) => Effect.Effect<BytePath, FsError, never>;
38
+ export declare const pathFromBytes: (bytes: Uint8Array<ArrayBufferLike>) => Effect.Effect<BytePath, FsFailure, never>;
29
39
  /** @internal */
30
- export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array<ArrayBuffer>, FsError, never>;
40
+ export declare const pathToBytes: (path: BytePath) => Effect.Effect<Uint8Array<ArrayBuffer>, FsFailure, never>;
31
41
  /** @internal */
32
42
  export interface PreparedPath {
33
43
  readonly input: PathInput;
@@ -38,7 +48,9 @@ export interface PreparedPath {
38
48
  readonly components: ReadonlyArray<string>;
39
49
  }
40
50
  /** @internal */
51
+ export declare const isWellFormed: (value: string) => boolean;
52
+ /** @internal */
41
53
  export declare const inputBytes: (input: PathInput) => Result.Result<Uint8Array, "InvalidPathEncoding" | "InvalidArgument">;
42
54
  /** @internal */
43
- export declare const preparePath: (input: PathInput, operation: string, maxPathBytes: ByteSize.ByteSize | undefined) => Result.Result<PreparedPath, FsError>;
55
+ export declare const preparePath: (input: PathInput, operation: string, maxPathBytes: ByteSize.ByteSize | undefined) => Result.Result<PreparedPath, FsFailure>;
44
56
  //# sourceMappingURL=path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/internal/path.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAGrC,gBAAgB;AAChB,eAAO,MAAM,SAAS,OAAO,CAAA;AAE7B,gBAAgB;AAChB,eAAO,MAAM,OAAO,OAAO,CAAA;AAE3B,gBAAgB;AAChB,eAAO,MAAM,WAAW,SAAS,CAAA;AAEjC,gBAAgB;AAChB,eAAO,MAAM,UAAU,KAAK,CAAA;AAG5B,gBAAgB;AAChB,eAAO,MAAM,cAAc,MAAM,CAAA;AAKjC,gBAAgB;AAChB,eAAO,MAAM,cAAc,SAAU,MAAM,GAAG,SAAS,KAAG,IAAI,IAAI,SAAS,GAAG,OAAO,OAAO,GAAG,OAAO,WACtC,CAAA;AAEhE,gBAAgB;AAChB,eAAO,MAAM,SAAS,UAAW,UAAU,KAAG,QAA+B,CAAA;AAE7E,gBAAgB;AAChB,eAAO,MAAM,YAAY,UAAW,UAAU,aAAa,MAAM,0CAI7D,CAAA;AAEJ,gBAAgB;AAChB,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,UAAyD,CAAA;AAgBlG,gBAAgB;AAChB,eAAO,MAAM,eAAe,UAAW,UAAU,KAAG,OAC2C,CAAA;AAE/F,gBAAgB;AAChB,eAAO,MAAM,aAAa,iFASxB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,WAAW,4EAMtB,CAAA;AAEF,gBAAgB;AAChB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAC5C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAC3C;AAoBD,gBAAgB;AAChB,eAAO,MAAM,UAAU,UAAW,SAAS,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,GAAG,iBAAiB,CAG5B,CAAA;AAErF,gBAAgB;AAChB,eAAO,MAAM,WAAW,UACf,SAAS,aACL,MAAM,gBACH,QAAQ,CAAC,QAAQ,GAAG,SAAS,KAC1C,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAgDrC,CAAA"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/internal/path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAIxD,gBAAgB;AAChB,eAAO,MAAM,SAAS,OAAO,CAAA;AAC7B,gBAAgB;AAChB,eAAO,MAAM,OAAO,OAAO,CAAA;AAC3B,gBAAgB;AAChB,eAAO,MAAM,WAAW,SAAS,CAAA;AACjC,gBAAgB;AAChB,eAAO,MAAM,UAAU,KAAK,CAAA;AAE5B,gBAAgB;AAChB,eAAO,MAAM,QAAQ,IAAI,CAAA;AACzB,gBAAgB;AAChB,eAAO,MAAM,sBAAsB,KAAK,CAAA;AACxC,gBAAgB;AAChB,eAAO,MAAM,cAAc,MAAM,CAAA;AAEjC,gBAAgB;AAChB,eAAO,MAAM,WAAW,SAAU,UAAU,KAAG,OAEuE,CAAA;AAEtH,gBAAgB;AAChB,eAAO,MAAM,SAAS,yBAA+B,CAAA;AAErD,gBAAgB;AAChB,eAAO,MAAM,QAAQ,WAAY,UAAU,QAAQ,UAAU,KAAG,UAS/D,CAAA;AAGD,gBAAgB;AAChB,eAAO,MAAM,cAAc,SAAU,MAAM,GAAG,SAAS,KAAG,IAAI,IAAI,SAAS,GAAG,OAAO,OAAO,GAAG,OAAO,WACtC,CAAA;AAEhE,gBAAgB;AAChB,eAAO,MAAM,SAAS,UAAW,UAAU,KAAG,QAA+B,CAAA;AAE7E,gBAAgB;AAChB,eAAO,MAAM,YAAY,UAAW,UAAU,aAAa,MAAM,4CAI7D,CAAA;AAEJ,gBAAgB;AAChB,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,UAAyD,CAAA;AAelG,gBAAgB;AAChB,eAAO,MAAM,eAAe,UAAW,UAAU,KAAG,OAC2C,CAAA;AAE/F,gBAAgB;AAChB,eAAO,MAAM,aAAa,mFASxB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,WAAW,8EAMtB,CAAA;AAEF,gBAAgB;AAChB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAC5C,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAC3C;AAGD,gBAAgB;AAChB,eAAO,MAAM,YAAY,UAAW,MAAM,KAAG,OAY5C,CAAA;AAID,gBAAgB;AAChB,eAAO,MAAM,UAAU,UAAW,SAAS,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,qBAAqB,GAAG,iBAAiB,CAG5B,CAAA;AAErF,gBAAgB;AAChB,eAAO,MAAM,WAAW,UACf,SAAS,aACL,MAAM,gBACH,QAAQ,CAAC,QAAQ,GAAG,SAAS,KAC1C,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAgDvC,CAAA"}
@@ -1,12 +1,10 @@
1
- // Byte-preserving path validation and conversion.
2
1
  import * as ByteSize from "effect/ByteSize";
3
2
  import * as Effect from "effect/Effect";
4
3
  import * as Encoding from "effect/Encoding";
5
4
  import * as Predicate from "effect/Predicate";
6
5
  import * as Result from "effect/Result";
7
6
  import { getBytes as getBytePathBytes, make as makeBytePath } from "./bytePath.js";
8
- import { FsError } from "./errors.js";
9
- // Components are hex-encoded bytes so names compare as bytes, not text: 2f is "/", 2e is ".", 2e2e is "..".
7
+ import { fsFailure } from "./errors.js";
10
8
  /** @internal */
11
9
  export const SLASH_HEX = "2f";
12
10
  /** @internal */
@@ -15,12 +13,29 @@ export const DOT_HEX = "2e";
15
13
  export const DOT_DOT_HEX = "2e2e";
16
14
  /** @internal */
17
15
  export const SLASH_BYTE = 47;
18
- // POSIX NAME_MAX: the longest single path component.
16
+ const DOT_BYTE = 46;
17
+ /** @internal */
18
+ export const NUL_BYTE = 0;
19
+ /** @internal */
20
+ export const MAX_SYMLINK_TRAVERSALS = 40;
19
21
  /** @internal */
20
22
  export const MAX_NAME_BYTES = 255;
21
- // A missing final component is rejected wherever "." and ".." are, so it counts as a dot component.
22
- // Callers pass the code POSIX gives their operation, so the codes differ on purpose: EEXIST for
23
- // create (link, symlink, mkdir), EISDIR for open and unlink, EINVAL for rename and rmdir.
23
+ /** @internal */
24
+ export const isNameBytes = (name) => name.length >= 1 && name.length <= MAX_NAME_BYTES && !name.includes(NUL_BYTE) && !name.includes(SLASH_BYTE) &&
25
+ !(name.length === 1 && name[0] === DOT_BYTE) && !(name.length === 2 && name[0] === DOT_BYTE && name[1] === DOT_BYTE);
26
+ /** @internal */
27
+ export const ROOT_PATH = new Uint8Array([SLASH_BYTE]);
28
+ /** @internal */
29
+ export const joinPath = (prefix, name) => {
30
+ const separator = prefix.length === 0 || prefix[prefix.length - 1] === SLASH_BYTE ? 0 : 1;
31
+ const joined = new Uint8Array(prefix.length + separator + name.length);
32
+ joined.set(prefix);
33
+ if (separator === 1)
34
+ joined[prefix.length] = SLASH_BYTE;
35
+ joined.set(name, prefix.length + separator);
36
+ return joined;
37
+ };
38
+ // A missing final component follows the same rejection path as "." and ".."; callers choose the POSIX error code.
24
39
  /** @internal */
25
40
  export const isDotComponent = (name) => name === undefined || name === DOT_HEX || name === DOT_DOT_HEX;
26
41
  /** @internal */
@@ -28,11 +43,11 @@ export const ownedPath = (bytes) => makeBytePath(bytes);
28
43
  /** @internal */
29
44
  export const strictString = (bytes, operation) => Effect.try({
30
45
  try: () => new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes),
31
- catch: () => new FsError({ code: "UnrepresentableName", operation })
46
+ catch: () => fsFailure("UnrepresentableName", operation)
32
47
  });
33
48
  /** @internal */
34
49
  export const nameBytes = (name) => Result.getOrThrow(Encoding.decodeHex(name));
35
- // A zero-length view distinguishes a detached buffer from a valid empty buffer.
50
+ // Constructing a view detects detached buffers, including empty ones.
36
51
  const attachedBuffer = (bytes) => {
37
52
  try {
38
53
  const probe = new Uint8Array(bytes.buffer, bytes.byteOffset, 0);
@@ -44,17 +59,16 @@ const attachedBuffer = (bytes) => {
44
59
  throw error;
45
60
  }
46
61
  };
47
- // Accepts any Uint8Array, subclasses such as Node's Buffer included; rejects views over a
48
- // SharedArrayBuffer or a detached buffer before the bytes are copied or trusted.
62
+ // Reject shared or detached buffers before copying; Buffer subclasses remain valid.
49
63
  /** @internal */
50
64
  export const isAttachedBytes = (bytes) => Predicate.isUint8Array(bytes) && bytes.buffer instanceof ArrayBuffer && attachedBuffer(bytes);
51
65
  /** @internal */
52
66
  export const pathFromBytes = Effect.fn("VirtualFileSystem.pathFromBytes")(function* (bytes) {
53
67
  if (!isAttachedBytes(bytes))
54
- return yield* new FsError({ code: "InvalidArgument", operation: "pathFromBytes" });
68
+ return yield* fsFailure("InvalidArgument", "pathFromBytes");
55
69
  const owned = new Uint8Array(bytes);
56
70
  if (owned.length === 0 || owned.includes(0)) {
57
- return yield* new FsError({ code: "InvalidArgument", operation: "pathFromBytes" });
71
+ return yield* fsFailure("InvalidArgument", "pathFromBytes");
58
72
  }
59
73
  return makeBytePath(owned);
60
74
  });
@@ -62,11 +76,12 @@ export const pathFromBytes = Effect.fn("VirtualFileSystem.pathFromBytes")(functi
62
76
  export const pathToBytes = Effect.fn("VirtualFileSystem.pathToBytes")(function* (path) {
63
77
  const bytes = getBytePathBytes(path);
64
78
  if (bytes === undefined)
65
- return yield* new FsError({ code: "InvalidArgument", operation: "pathToBytes" });
79
+ return yield* fsFailure("InvalidArgument", "pathToBytes");
66
80
  return new Uint8Array(bytes);
67
81
  });
68
- // Hand-rolled because String.prototype.isWellFormed is ES2024 and the package targets ES2023.
69
- const wellFormed = (value) => {
82
+ // String.prototype.isWellFormed requires ES2024; this package targets ES2023.
83
+ /** @internal */
84
+ export const isWellFormed = (value) => {
70
85
  for (let index = 0; index < value.length; index++) {
71
86
  const code = value.charCodeAt(index);
72
87
  if (code >= 0xd800 && code <= 0xdbff) {
@@ -80,26 +95,25 @@ const wellFormed = (value) => {
80
95
  return true;
81
96
  };
82
97
  const UTF8_ENCODER = new TextEncoder();
83
- // Strings must be well-formed UTF-16 before encoding; BytePaths must belong to this package.
84
98
  /** @internal */
85
99
  export const inputBytes = (input) => Predicate.isString(input)
86
- ? wellFormed(input) ? Result.succeed(UTF8_ENCODER.encode(input)) : Result.fail("InvalidPathEncoding")
100
+ ? isWellFormed(input) ? Result.succeed(UTF8_ENCODER.encode(input)) : Result.fail("InvalidPathEncoding")
87
101
  : Result.fromNullishOr(getBytePathBytes(input), () => "InvalidArgument");
88
102
  /** @internal */
89
103
  export const preparePath = (input, operation, maxPathBytes) => {
90
104
  const encoded = inputBytes(input);
91
105
  if (Result.isFailure(encoded)) {
92
106
  return Result.fail(encoded.failure === "InvalidPathEncoding"
93
- ? new FsError({ code: "InvalidPathEncoding", operation, path: input })
94
- : new FsError({ code: "InvalidArgument", operation }));
107
+ ? fsFailure("InvalidPathEncoding", operation, { path: input })
108
+ : fsFailure("InvalidArgument", operation));
95
109
  }
96
110
  const bytes = encoded.success;
97
111
  if (bytes.length === 0)
98
- return Result.fail(new FsError({ code: "NotFound", operation, path: input }));
112
+ return Result.fail(fsFailure("NotFound", operation, { path: input }));
99
113
  if (bytes.includes(0))
100
- return Result.fail(new FsError({ code: "InvalidArgument", operation, path: input }));
114
+ return Result.fail(fsFailure("InvalidArgument", operation, { path: input }));
101
115
  if (maxPathBytes !== undefined && ByteSize.isGreaterThan(ByteSize.bytes(bytes.length), maxPathBytes)) {
102
- return Result.fail(new FsError({ code: "PathTooLong", operation, path: input }));
116
+ return Result.fail(fsFailure("PathTooLong", operation, { path: input }));
103
117
  }
104
118
  const components = [];
105
119
  const suffixes = [];
@@ -109,7 +123,7 @@ export const preparePath = (input, operation, maxPathBytes) => {
109
123
  continue;
110
124
  if (index > start) {
111
125
  if (index - start > MAX_NAME_BYTES) {
112
- return Result.fail(new FsError({ code: "PathTooLong", operation, path: input }));
126
+ return Result.fail(fsFailure("PathTooLong", operation, { path: input }));
113
127
  }
114
128
  components.push(Encoding.encodeHex(bytes.subarray(start, index)));
115
129
  suffixes.push(bytes.subarray(index));
@@ -1,35 +1,36 @@
1
1
  import * as ByteSize from "effect/ByteSize";
2
- import * as Crypto from "effect/Crypto";
3
2
  import * as Effect from "effect/Effect";
4
- import { ImageError, type Snapshot } from "../Snapshot.js";
5
- import { type SnapshotDelta, SnapshotDeltaError } from "../SnapshotDelta.js";
3
+ import type { Snapshot } from "../Snapshot.js";
4
+ import { type SnapshotDelta } from "../SnapshotDelta.js";
5
+ import type { ImageFailure } from "../VfsError.js";
6
+ import { VfsError } from "./errors.js";
6
7
  /** @internal */
7
8
  export declare const diffSnapshots: (base: Snapshot, target: Snapshot, limits: {
8
- readonly maxEncodedBytes: ByteSize.ByteSize;
9
- readonly maxIdentityBytes: ByteSize.ByteSize;
10
- readonly maxDeltaRecords: number;
11
- readonly maxDecodedDeltaBytes: ByteSize.ByteSize;
12
- readonly maxBaseRecords: number;
13
- readonly maxTargetRecords: number;
14
- readonly maxEntries: number;
15
- readonly maxOutputRecords: number;
16
- readonly maxOutputBytes: ByteSize.ByteSize;
17
- readonly maxInheritedRecords: number;
18
- }) => Effect.Effect<SnapshotDelta, ImageError | import("effect/PlatformError").PlatformError, Crypto.Crypto>;
9
+ readonly encodedBytes: ByteSize.ByteSize;
10
+ readonly records: number;
11
+ readonly entries: number;
12
+ readonly decodedBytes: ByteSize.ByteSize;
13
+ readonly identityBytes: ByteSize.ByteSize;
14
+ readonly baseRecords: number;
15
+ readonly targetRecords: number;
16
+ readonly outputRecords: number;
17
+ readonly outputBytes: ByteSize.ByteSize;
18
+ readonly inheritedRecords: number;
19
+ }) => Effect.Effect<SnapshotDelta, import("effect/PlatformError").PlatformError | ImageFailure, import("effect/Crypto").Crypto>;
19
20
  /** @internal */
20
21
  export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDelta, options: {
21
22
  readonly includeTimestamps?: boolean;
22
23
  }, limits: {
23
- readonly maxEncodedBytes: ByteSize.ByteSize;
24
- readonly maxIdentityBytes: ByteSize.ByteSize;
25
- readonly maxDeltaRecords: number;
26
- readonly maxDecodedDeltaBytes: ByteSize.ByteSize;
27
- readonly maxBaseRecords: number;
28
- readonly maxTargetRecords: number;
29
- readonly maxEntries: number;
30
- readonly maxOutputRecords: number;
31
- readonly maxOutputBytes: ByteSize.ByteSize;
32
- readonly maxInheritedRecords: number;
24
+ readonly encodedBytes: ByteSize.ByteSize;
25
+ readonly records: number;
26
+ readonly entries: number;
27
+ readonly decodedBytes: ByteSize.ByteSize;
28
+ readonly identityBytes: ByteSize.ByteSize;
29
+ readonly baseRecords: number;
30
+ readonly targetRecords: number;
31
+ readonly outputRecords: number;
32
+ readonly outputBytes: ByteSize.ByteSize;
33
+ readonly inheritedRecords: number;
33
34
  }) => Effect.Effect<readonly ({
34
35
  readonly _tag: "Added";
35
36
  readonly path: import("../BytePath.js").BytePath;
@@ -44,44 +45,44 @@ export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDelta
44
45
  readonly beforeKind: "directory" | "file" | "symlink";
45
46
  readonly afterKind: "directory" | "file" | "symlink";
46
47
  readonly differences: readonly ("atimeNs" | "birthtimeNs" | "content" | "ctimeNs" | "gid" | "hardLinks" | "kind" | "mode" | "mtimeNs" | "target" | "uid")[];
47
- })[], ImageError | import("effect/PlatformError").PlatformError | SnapshotDeltaError, Crypto.Crypto>;
48
+ })[], import("effect/PlatformError").PlatformError | VfsError, import("effect/Crypto").Crypto>;
49
+ /** @internal */
50
+ export declare const applySnapshotDelta: (base: Snapshot, delta: SnapshotDelta, limits: {
51
+ readonly encodedBytes: ByteSize.ByteSize;
52
+ readonly records: number;
53
+ readonly entries: number;
54
+ readonly decodedBytes: ByteSize.ByteSize;
55
+ readonly identityBytes: ByteSize.ByteSize;
56
+ readonly baseRecords: number;
57
+ readonly targetRecords: number;
58
+ readonly outputRecords: number;
59
+ readonly outputBytes: ByteSize.ByteSize;
60
+ readonly inheritedRecords: number;
61
+ }) => Effect.Effect<Snapshot, import("effect/PlatformError").PlatformError | VfsError, import("effect/Crypto").Crypto>;
48
62
  /** @internal */
49
63
  export declare const encodeSnapshotDelta: (delta: SnapshotDelta, limits: {
50
- readonly maxEncodedBytes: ByteSize.ByteSize;
51
- readonly maxIdentityBytes: ByteSize.ByteSize;
52
- readonly maxDeltaRecords: number;
53
- readonly maxDecodedDeltaBytes: ByteSize.ByteSize;
54
- readonly maxBaseRecords: number;
55
- readonly maxTargetRecords: number;
56
- readonly maxEntries: number;
57
- readonly maxOutputRecords: number;
58
- readonly maxOutputBytes: ByteSize.ByteSize;
59
- readonly maxInheritedRecords: number;
60
- }) => Effect.Effect<Uint8Array<ArrayBuffer>, ImageError, never>;
64
+ readonly encodedBytes: ByteSize.ByteSize;
65
+ readonly records: number;
66
+ readonly entries: number;
67
+ readonly decodedBytes: ByteSize.ByteSize;
68
+ readonly identityBytes: ByteSize.ByteSize;
69
+ readonly baseRecords: number;
70
+ readonly targetRecords: number;
71
+ readonly outputRecords: number;
72
+ readonly outputBytes: ByteSize.ByteSize;
73
+ readonly inheritedRecords: number;
74
+ }) => Effect.Effect<Uint8Array<ArrayBuffer>, ImageFailure, never>;
61
75
  /** @internal */
62
76
  export declare const decodeSnapshotDelta: (input: Uint8Array<ArrayBufferLike>, limits: {
63
- readonly maxEncodedBytes: ByteSize.ByteSize;
64
- readonly maxIdentityBytes: ByteSize.ByteSize;
65
- readonly maxDeltaRecords: number;
66
- readonly maxDecodedDeltaBytes: ByteSize.ByteSize;
67
- readonly maxBaseRecords: number;
68
- readonly maxTargetRecords: number;
69
- readonly maxEntries: number;
70
- readonly maxOutputRecords: number;
71
- readonly maxOutputBytes: ByteSize.ByteSize;
72
- readonly maxInheritedRecords: number;
73
- }) => Effect.Effect<SnapshotDelta, ImageError, never>;
74
- /** @internal */
75
- export declare const applySnapshotDelta: (base: Snapshot, delta: SnapshotDelta, limits: {
76
- readonly maxEncodedBytes: ByteSize.ByteSize;
77
- readonly maxIdentityBytes: ByteSize.ByteSize;
78
- readonly maxDeltaRecords: number;
79
- readonly maxDecodedDeltaBytes: ByteSize.ByteSize;
80
- readonly maxBaseRecords: number;
81
- readonly maxTargetRecords: number;
82
- readonly maxEntries: number;
83
- readonly maxOutputRecords: number;
84
- readonly maxOutputBytes: ByteSize.ByteSize;
85
- readonly maxInheritedRecords: number;
86
- }) => Effect.Effect<Snapshot, ImageError | import("effect/PlatformError").PlatformError | SnapshotDeltaError, Crypto.Crypto>;
77
+ readonly encodedBytes: ByteSize.ByteSize;
78
+ readonly records: number;
79
+ readonly entries: number;
80
+ readonly decodedBytes: ByteSize.ByteSize;
81
+ readonly identityBytes: ByteSize.ByteSize;
82
+ readonly baseRecords: number;
83
+ readonly targetRecords: number;
84
+ readonly outputRecords: number;
85
+ readonly outputBytes: ByteSize.ByteSize;
86
+ readonly inheritedRecords: number;
87
+ }) => Effect.Effect<SnapshotDelta, ImageFailure, never>;
87
88
  //# sourceMappingURL=snapshotDelta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotDelta.d.ts","sourceRoot":"","sources":["../../src/internal/snapshotDelta.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAOvC,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAGL,KAAK,aAAa,EAClB,kBAAkB,EAInB,MAAM,qBAAqB,CAAA;AAmuB5B,gBAAgB;AAChB,eAAO,MAAM,aAAa;;;;;;;;;;;4GAgDzB,CAAA;AAyBD,gBAAgB;AAChB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;oGAoBhC,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;+DAe9B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;qDAkC9B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,kBAAkB;;;;;;;;;;;4HAI9B,CAAA"}
1
+ {"version":3,"file":"snapshotDelta.d.ts","sourceRoot":"","sources":["../../src/internal/snapshotDelta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAGL,KAAK,aAAa,EAGnB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAKlD,OAAO,EAA4C,QAAQ,EAAE,MAAM,aAAa,CAAA;AA01BhF,gBAAgB;AAChB,eAAO,MAAM,aAAa;;;;;;;;;;;+HA2BxB,CAAA;AA2BF,gBAAgB;AAChB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;8FAchC,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,kBAAkB;;;;;;;;;;;sHAI9B,CAAA;AAID,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;iEAe9B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;uDAyB9B,CAAA"}