@effect-vfs/core 0.1.0 → 0.3.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 +97 -8
  2. package/dist/BytePath.d.ts +34 -0
  3. package/dist/BytePath.d.ts.map +1 -0
  4. package/dist/BytePath.js +16 -0
  5. package/dist/Snapshot.d.ts +5 -5
  6. package/dist/Snapshot.d.ts.map +1 -1
  7. package/dist/Snapshot.js +5 -6
  8. package/dist/SnapshotDelta.d.ts +193 -0
  9. package/dist/SnapshotDelta.d.ts.map +1 -0
  10. package/dist/SnapshotDelta.js +139 -0
  11. package/dist/VirtualFileSystem.d.ts +193 -342
  12. package/dist/VirtualFileSystem.d.ts.map +1 -1
  13. package/dist/VirtualFileSystem.js +104 -1774
  14. package/dist/internal/bytePath.d.ts +10 -0
  15. package/dist/internal/bytePath.d.ts.map +1 -0
  16. package/dist/internal/bytePath.js +46 -0
  17. package/dist/internal/canonicalBase64.d.ts +7 -0
  18. package/dist/internal/canonicalBase64.d.ts.map +1 -0
  19. package/dist/internal/canonicalBase64.js +11 -0
  20. package/dist/internal/image.d.ts +28 -31
  21. package/dist/internal/image.d.ts.map +1 -1
  22. package/dist/internal/image.js +14 -23
  23. package/dist/internal/snapshotDelta.d.ts +87 -0
  24. package/dist/internal/snapshotDelta.d.ts.map +1 -0
  25. package/dist/internal/snapshotDelta.js +576 -0
  26. package/dist/internal/snapshotDeltaModel.d.ts +10 -0
  27. package/dist/internal/snapshotDeltaModel.d.ts.map +1 -0
  28. package/dist/internal/snapshotDeltaModel.js +13 -0
  29. package/dist/internal/virtualFileSystem/errors.d.ts +26 -0
  30. package/dist/internal/virtualFileSystem/errors.d.ts.map +1 -0
  31. package/dist/internal/virtualFileSystem/errors.js +32 -0
  32. package/dist/internal/virtualFileSystem/fixture.d.ts +63 -0
  33. package/dist/internal/virtualFileSystem/fixture.d.ts.map +1 -0
  34. package/dist/internal/virtualFileSystem/fixture.js +144 -0
  35. package/dist/internal/{content.d.ts → virtualFileSystem/overlayContent.d.ts} +4 -14
  36. package/dist/internal/virtualFileSystem/overlayContent.d.ts.map +1 -0
  37. package/dist/internal/{content.js → virtualFileSystem/overlayContent.js} +3 -7
  38. package/dist/internal/{overlayChanges.d.ts → virtualFileSystem/overlayDiff.d.ts} +1 -1
  39. package/dist/internal/virtualFileSystem/overlayDiff.d.ts.map +1 -0
  40. package/dist/internal/{overlayChanges.js → virtualFileSystem/overlayDiff.js} +4 -15
  41. package/dist/internal/virtualFileSystem/path.d.ts +43 -0
  42. package/dist/internal/virtualFileSystem/path.d.ts.map +1 -0
  43. package/dist/internal/virtualFileSystem/path.js +124 -0
  44. package/dist/internal/virtualFileSystem/testHooks.d.ts +20 -0
  45. package/dist/internal/virtualFileSystem/testHooks.d.ts.map +1 -0
  46. package/dist/internal/virtualFileSystem/testHooks.js +23 -0
  47. package/dist/internal/virtualFileSystem/watchHub.d.ts +16 -0
  48. package/dist/internal/virtualFileSystem/watchHub.d.ts.map +1 -0
  49. package/dist/internal/virtualFileSystem/watchHub.js +33 -0
  50. package/dist/internal/virtualFileSystem.d.ts +290 -0
  51. package/dist/internal/virtualFileSystem.d.ts.map +1 -0
  52. package/dist/internal/virtualFileSystem.js +1677 -0
  53. package/package.json +5 -4
  54. package/dist/internal/content.d.ts.map +0 -1
  55. package/dist/internal/overlayChanges.d.ts.map +0 -1
  56. package/dist/internal/overlayTesting.d.ts +0 -12
  57. package/dist/internal/overlayTesting.d.ts.map +0 -1
  58. package/dist/internal/overlayTesting.js +0 -12
@@ -0,0 +1,10 @@
1
+ import type { BytePath } from "../BytePath.js";
2
+ /** @internal */
3
+ export declare const BytePathId: "@effect-vfs/core/BytePath";
4
+ /** @internal */
5
+ export declare const isBytePath: (value: unknown) => value is BytePath;
6
+ /** @internal */
7
+ export declare const make: (bytes: Uint8Array) => BytePath;
8
+ /** @internal */
9
+ export declare const getBytes: (path: BytePath) => Uint8Array | undefined;
10
+ //# sourceMappingURL=bytePath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytePath.d.ts","sourceRoot":"","sources":["../../src/internal/bytePath.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE9C,gBAAgB;AAChB,eAAO,MAAM,UAAU,EAAG,2BAAoC,CAAA;AAgC9D,gBAAgB;AAChB,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,KAAK,IAAI,QAC4B,CAAA;AAEjF,gBAAgB;AAChB,eAAO,MAAM,IAAI,UAAW,UAAU,KAAG,QAIxC,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,QAAQ,SAAU,QAAQ,KAAG,UAAU,GAAG,SAAgC,CAAA"}
@@ -0,0 +1,46 @@
1
+ // Opaque byte path representation and value protocols.
2
+ import * as Equal from "effect/Equal";
3
+ import * as Hash from "effect/Hash";
4
+ import { pipeArguments } from "effect/Pipeable";
5
+ /** @internal */
6
+ export const BytePathId = "@effect-vfs/core/BytePath";
7
+ const bytePaths = new WeakMap();
8
+ const hashBytes = (bytes) => {
9
+ let hash = Hash.string("@effect-vfs/core/BytePath");
10
+ for (const byte of bytes) {
11
+ hash = Hash.combine(Hash.number(byte))(hash);
12
+ }
13
+ return Hash.combine(Hash.number(bytes.length))(hash);
14
+ };
15
+ const BytePathProto = {
16
+ [BytePathId]: BytePathId,
17
+ [Equal.symbol](that) {
18
+ if (!isBytePath(that))
19
+ return false;
20
+ const selfBytes = bytePaths.get(this);
21
+ const thatBytes = bytePaths.get(that);
22
+ if (selfBytes.length !== thatBytes.length)
23
+ return false;
24
+ for (let index = 0; index < selfBytes.length; index++) {
25
+ if (selfBytes[index] !== thatBytes[index])
26
+ return false;
27
+ }
28
+ return true;
29
+ },
30
+ [Hash.symbol]() {
31
+ return hashBytes(bytePaths.get(this));
32
+ },
33
+ pipe() {
34
+ return pipeArguments(this, arguments);
35
+ }
36
+ };
37
+ /** @internal */
38
+ export const isBytePath = (value) => typeof value === "object" && value !== null && bytePaths.has(value);
39
+ /** @internal */
40
+ export const make = (bytes) => {
41
+ const path = Object.create(BytePathProto);
42
+ bytePaths.set(path, bytes);
43
+ return Object.freeze(path);
44
+ };
45
+ /** @internal */
46
+ export const getBytes = (path) => bytePaths.get(path);
@@ -0,0 +1,7 @@
1
+ /** @internal */
2
+ export declare const isCanonical: (value: string) => boolean;
3
+ /** @internal */
4
+ export declare const decodedLength: (value: string) => number;
5
+ /** @internal */
6
+ export declare const decodeTrusted: (value: string) => Uint8Array;
7
+ //# sourceMappingURL=canonicalBase64.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalBase64.d.ts","sourceRoot":"","sources":["../../src/internal/canonicalBase64.ts"],"names":[],"mappings":"AAKA,gBAAgB;AAChB,eAAO,MAAM,WAAW,UAAW,MAAM,KAAG,OAGP,CAAA;AAErC,gBAAgB;AAChB,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,MACmC,CAAA;AAEjF,gBAAgB;AAChB,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,UAC4D,CAAA"}
@@ -0,0 +1,11 @@
1
+ import * as Encoding from "effect/Encoding";
2
+ import * as Result from "effect/Result";
3
+ const canonicalTail = /^(?:[A-Za-z0-9+/]{4}|[A-Za-z0-9+/][AQgw]==|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=)?(?![\s\S])/;
4
+ /** @internal */
5
+ export const isCanonical = (value) => value.length % 4 === 0 &&
6
+ !/[^A-Za-z0-9+/]/.test(value.slice(0, -4)) &&
7
+ canonicalTail.test(value.slice(-4));
8
+ /** @internal */
9
+ export const decodedLength = (value) => value.length / 4 * 3 - (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
10
+ /** @internal */
11
+ export const decodeTrusted = (value) => Result.getOrThrowWith(Encoding.decodeBase64(value), () => new Error("Invalid trusted canonical base64"));
@@ -1,16 +1,13 @@
1
- /**
2
- * Snapshot validation and serialization used by `VirtualFileSystem`.
3
- *
4
- * @internal
5
- */
1
+ import * as ByteSize from "effect/ByteSize";
6
2
  import * as Effect from "effect/Effect";
7
3
  import * as Schema from "effect/Schema";
8
4
  import { ImageError, type Snapshot } from "../Snapshot.js";
5
+ import * as CanonicalBase64 from "./canonicalBase64.js";
9
6
  /** @internal */
10
7
  export declare const StoredMetadata: Schema.Struct<{
11
- readonly uid: Schema.Finite;
12
- readonly gid: Schema.Finite;
13
- readonly mode: Schema.Finite;
8
+ readonly uid: Schema.Natural;
9
+ readonly gid: Schema.Natural;
10
+ readonly mode: Schema.Natural;
14
11
  readonly atimeNs: Schema.String;
15
12
  readonly mtimeNs: Schema.String;
16
13
  readonly ctimeNs: Schema.String;
@@ -23,9 +20,9 @@ export declare const Record: Schema.Union<readonly [Schema.Struct<{
23
20
  readonly id: Schema.String;
24
21
  readonly kind: Schema.Literal<"directory">;
25
22
  readonly metadata: Schema.Struct<{
26
- readonly uid: Schema.Finite;
27
- readonly gid: Schema.Finite;
28
- readonly mode: Schema.Finite;
23
+ readonly uid: Schema.Natural;
24
+ readonly gid: Schema.Natural;
25
+ readonly mode: Schema.Natural;
29
26
  readonly atimeNs: Schema.String;
30
27
  readonly mtimeNs: Schema.String;
31
28
  readonly ctimeNs: Schema.String;
@@ -39,9 +36,9 @@ export declare const Record: Schema.Union<readonly [Schema.Struct<{
39
36
  readonly id: Schema.String;
40
37
  readonly kind: Schema.Literal<"file">;
41
38
  readonly metadata: Schema.Struct<{
42
- readonly uid: Schema.Finite;
43
- readonly gid: Schema.Finite;
44
- readonly mode: Schema.Finite;
39
+ readonly uid: Schema.Natural;
40
+ readonly gid: Schema.Natural;
41
+ readonly mode: Schema.Natural;
45
42
  readonly atimeNs: Schema.String;
46
43
  readonly mtimeNs: Schema.String;
47
44
  readonly ctimeNs: Schema.String;
@@ -52,9 +49,9 @@ export declare const Record: Schema.Union<readonly [Schema.Struct<{
52
49
  readonly id: Schema.String;
53
50
  readonly kind: Schema.Literal<"symlink">;
54
51
  readonly metadata: Schema.Struct<{
55
- readonly uid: Schema.Finite;
56
- readonly gid: Schema.Finite;
57
- readonly mode: Schema.Finite;
52
+ readonly uid: Schema.Natural;
53
+ readonly gid: Schema.Natural;
54
+ readonly mode: Schema.Natural;
58
55
  readonly atimeNs: Schema.String;
59
56
  readonly mtimeNs: Schema.String;
60
57
  readonly ctimeNs: Schema.String;
@@ -73,9 +70,9 @@ export declare const Document: Schema.Struct<{
73
70
  readonly id: Schema.String;
74
71
  readonly kind: Schema.Literal<"directory">;
75
72
  readonly metadata: Schema.Struct<{
76
- readonly uid: Schema.Finite;
77
- readonly gid: Schema.Finite;
78
- readonly mode: Schema.Finite;
73
+ readonly uid: Schema.Natural;
74
+ readonly gid: Schema.Natural;
75
+ readonly mode: Schema.Natural;
79
76
  readonly atimeNs: Schema.String;
80
77
  readonly mtimeNs: Schema.String;
81
78
  readonly ctimeNs: Schema.String;
@@ -89,9 +86,9 @@ export declare const Document: Schema.Struct<{
89
86
  readonly id: Schema.String;
90
87
  readonly kind: Schema.Literal<"file">;
91
88
  readonly metadata: Schema.Struct<{
92
- readonly uid: Schema.Finite;
93
- readonly gid: Schema.Finite;
94
- readonly mode: Schema.Finite;
89
+ readonly uid: Schema.Natural;
90
+ readonly gid: Schema.Natural;
91
+ readonly mode: Schema.Natural;
95
92
  readonly atimeNs: Schema.String;
96
93
  readonly mtimeNs: Schema.String;
97
94
  readonly ctimeNs: Schema.String;
@@ -102,9 +99,9 @@ export declare const Document: Schema.Struct<{
102
99
  readonly id: Schema.String;
103
100
  readonly kind: Schema.Literal<"symlink">;
104
101
  readonly metadata: Schema.Struct<{
105
- readonly uid: Schema.Finite;
106
- readonly gid: Schema.Finite;
107
- readonly mode: Schema.Finite;
102
+ readonly uid: Schema.Natural;
103
+ readonly gid: Schema.Natural;
104
+ readonly mode: Schema.Natural;
108
105
  readonly atimeNs: Schema.String;
109
106
  readonly mtimeNs: Schema.String;
110
107
  readonly ctimeNs: Schema.String;
@@ -116,7 +113,7 @@ export declare const Document: Schema.Struct<{
116
113
  /** @internal */
117
114
  export type Document = typeof Document.Type;
118
115
  /** @internal */
119
- export declare const decodedLength: (value: string) => number;
116
+ export declare const decodedLength: typeof CanonicalBase64.decodedLength;
120
117
  /** @internal */
121
118
  export declare const base64: (input: Uint8Array) => string;
122
119
  /** @internal */
@@ -125,18 +122,18 @@ export declare const bytes: (value: string) => Uint8Array;
125
122
  export declare const inspect: (snapshot: Snapshot) => Effect.Effect<Document, ImageError>;
126
123
  /** @internal */
127
124
  export declare const capture: (input: unknown, limits?: {
128
- readonly maxEncodedBytes: number;
125
+ readonly maxEncodedBytes: ByteSize.ByteSize;
129
126
  readonly maxRecords: number;
130
127
  readonly maxEntries: number;
131
- readonly maxDecodedBytes: number;
128
+ readonly maxDecodedBytes: ByteSize.ByteSize;
132
129
  } | undefined) => Effect.Effect<Snapshot, ImageError, never>;
133
130
  /** @internal */
134
131
  export declare const encodeSnapshot: (snapshot: Snapshot) => Effect.Effect<Uint8Array<ArrayBuffer>, ImageError, never>;
135
132
  /** @internal */
136
133
  export declare const decodeSnapshot: (input: Uint8Array<ArrayBufferLike>, limits: {
137
- readonly maxEncodedBytes: number;
134
+ readonly maxEncodedBytes: ByteSize.ByteSize;
138
135
  readonly maxRecords: number;
139
136
  readonly maxEntries: number;
140
- readonly maxDecodedBytes: number;
137
+ readonly maxDecodedBytes: ByteSize.ByteSize;
141
138
  }) => Effect.Effect<Snapshot, ImageError, never>;
142
139
  //# sourceMappingURL=image.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/internal/image.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAGvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAgB,UAAU,EAAE,KAAK,QAAQ,EAAkB,MAAM,gBAAgB,CAAA;AAaxF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAA;AACF,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IASjB,CAAA;AACF,gBAAgB;AAChB,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AACvC,gBAAgB;AAChB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKnB,CAAA;AACF,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAO3C,gBAAgB;AAChB,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,MACmC,CAAA;AACjF,gBAAgB;AAChB,eAAO,MAAM,MAAM,UAAW,UAAU,KAAG,MAU1C,CAAA;AAGD,gBAAgB;AAChB,eAAO,MAAM,KAAK,UAAW,MAAM,KAAG,UAIrC,CAAA;AACD,gBAAgB;AAChB,eAAO,MAAM,OAAO,aAAc,QAAQ,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAI3E,CAAA;AAEJ,gBAAgB;AAChB,eAAO,MAAM,OAAO;;;;;4DAwElB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc,mFAKzB,CAAA;AACF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;gDAmB1B,CAAA"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/internal/image.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,EAAgB,UAAU,EAAE,KAAK,QAAQ,EAAkB,MAAM,gBAAgB,CAAA;AACxF,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAA;AAQvD,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;;;;EAQzB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAIvD,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IASjB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC,gBAAgB;AAChB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKnB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAI3C,gBAAgB;AAChB,eAAO,MAAM,aAAa,sCAAgC,CAAA;AAE1D,gBAAgB;AAChB,eAAO,MAAM,MAAM,UAAW,UAAU,KAAG,MAU1C,CAAA;AAKD,gBAAgB;AAChB,eAAO,MAAM,KAAK,UAAW,MAAM,KAAG,UAErC,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,OAAO,aAAc,QAAQ,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAI3E,CAAA;AAEJ,gBAAgB;AAChB,eAAO,MAAM,OAAO;;;;;4DAwElB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc,mFAKzB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;gDAqB1B,CAAA"}
@@ -1,23 +1,20 @@
1
- /**
2
- * Snapshot validation and serialization used by `VirtualFileSystem`.
3
- *
4
- * @internal
5
- */
1
+ // Snapshot validation and serialization used by VirtualFileSystem.
2
+ import * as ByteSize from "effect/ByteSize";
6
3
  import * as Effect from "effect/Effect";
7
4
  import * as Encoding from "effect/Encoding";
8
5
  import * as Result from "effect/Result";
9
6
  import * as Schema from "effect/Schema";
10
7
  import { DecodeLimits, ImageError, SnapshotTypeId } from "../Snapshot.js";
11
- const natural = Schema.Finite.check(Schema.isInt(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(Number.MAX_SAFE_INTEGER));
8
+ import * as CanonicalBase64 from "./canonicalBase64.js";
12
9
  class SnapshotImpl {
13
10
  [SnapshotTypeId] = SnapshotTypeId;
14
11
  }
15
12
  const integer = Schema.String.check(Schema.isPattern(/^(?:0|-?[1-9][0-9]{0,127})(?![\s\S])/));
16
13
  /** @internal */
17
14
  export const StoredMetadata = Schema.Struct({
18
- uid: natural,
19
- gid: natural,
20
- mode: natural.check(Schema.isLessThanOrEqualTo(0o7777)),
15
+ uid: Schema.Natural,
16
+ gid: Schema.Natural,
17
+ mode: Schema.Natural.check(Schema.isLessThanOrEqualTo(0o7777)),
21
18
  atimeNs: integer,
22
19
  mtimeNs: integer,
23
20
  ctimeNs: integer,
@@ -43,12 +40,8 @@ export const Document = Schema.Struct({
43
40
  records: Schema.Array(Record)
44
41
  });
45
42
  const snapshots = new WeakMap();
46
- const canonicalBase64Tail = /^(?:[A-Za-z0-9+/]{4}|[A-Za-z0-9+/][AQgw]==|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=)?(?![\s\S])/;
47
- // Only the final quartet can contain padding. Scanning the alphabet separately avoids
48
- // the regexp stack growth caused by repeating a four-character group over large files.
49
- const canonicalBase64 = (value) => value.length % 4 === 0 && !/[^A-Za-z0-9+/]/.test(value.slice(0, -4)) && canonicalBase64Tail.test(value.slice(-4));
50
43
  /** @internal */
51
- export const decodedLength = (value) => value.length / 4 * 3 - (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
44
+ export const decodedLength = CanonicalBase64.decodedLength;
52
45
  /** @internal */
53
46
  export const base64 = (input) => {
54
47
  // Effect's encoder concatenates individual characters. Join bounded chunks so snapshots
@@ -64,10 +57,7 @@ export const base64 = (input) => {
64
57
  const error = (code, field) => new ImageError({ code, ...(field === undefined ? {} : { field }) });
65
58
  /** @internal */
66
59
  export const bytes = (value) => {
67
- const result = Encoding.decodeBase64(value);
68
- if (Result.isFailure(result))
69
- throw new Error("Invalid trusted snapshot base64");
70
- return result.success;
60
+ return CanonicalBase64.decodeTrusted(value);
71
61
  };
72
62
  /** @internal */
73
63
  export const inspect = (snapshot) => Effect.suspend(() => {
@@ -82,7 +72,7 @@ export const capture = Effect.fnUntraced(function* (input, limits) {
82
72
  const document = decoded.success;
83
73
  const records = new Map();
84
74
  let entries = 0;
85
- let payload = 0;
75
+ let payload = ByteSize.zero;
86
76
  if (limits !== undefined && document.records.length > limits.maxRecords) {
87
77
  return yield* error("LimitExceeded", "records");
88
78
  }
@@ -101,10 +91,10 @@ export const capture = Effect.fnUntraced(function* (input, limits) {
101
91
  ? record.entries.map((entry) => entry.name)
102
92
  : [record.kind === "file" ? record.data : record.target];
103
93
  for (const value of values) {
104
- if (!canonicalBase64(value))
94
+ if (!CanonicalBase64.isCanonical(value))
105
95
  return yield* error("InvalidEncoding", record.id);
106
- payload += decodedLength(value);
107
- if (!Number.isSafeInteger(payload) || (limits !== undefined && payload > limits.maxDecodedBytes)) {
96
+ payload = ByteSize.sum(payload, ByteSize.bytes(decodedLength(value)));
97
+ if (limits !== undefined && ByteSize.isGreaterThan(payload, limits.maxDecodedBytes)) {
108
98
  return yield* error("LimitExceeded", "bytes");
109
99
  }
110
100
  }
@@ -173,8 +163,9 @@ export const decodeSnapshot = Effect.fn("VirtualFileSystem.decodeSnapshot")(func
173
163
  return yield* error("InvalidStructure", "limits");
174
164
  if (!(input instanceof Uint8Array) || !(input.buffer instanceof ArrayBuffer))
175
165
  return yield* error("InvalidEncoding");
176
- if (input.byteLength > checked.success.maxEncodedBytes)
166
+ if (ByteSize.isGreaterThan(ByteSize.bytes(input.byteLength), checked.success.maxEncodedBytes)) {
177
167
  return yield* error("LimitExceeded", "encodedBytes");
168
+ }
178
169
  const text = yield* Effect.try({
179
170
  try: () => new TextDecoder("utf-8", { fatal: true }).decode(new Uint8Array(input)),
180
171
  catch: () => error("InvalidEncoding")
@@ -0,0 +1,87 @@
1
+ import * as ByteSize from "effect/ByteSize";
2
+ import * as Crypto from "effect/Crypto";
3
+ import * as Effect from "effect/Effect";
4
+ import { ImageError, type Snapshot } from "../Snapshot.js";
5
+ import { type SnapshotDelta, SnapshotDeltaError } from "../SnapshotDelta.js";
6
+ /** @internal */
7
+ 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>;
19
+ /** @internal */
20
+ export declare const inspectSnapshotDelta: (base: Snapshot, delta: SnapshotDelta, options: {
21
+ readonly includeTimestamps?: boolean;
22
+ }, 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;
33
+ }) => Effect.Effect<readonly ({
34
+ readonly _tag: "Added";
35
+ readonly path: import("../BytePath.js").BytePath;
36
+ readonly kind: "directory" | "file" | "symlink";
37
+ } | {
38
+ readonly _tag: "Removed";
39
+ readonly path: import("../BytePath.js").BytePath;
40
+ readonly kind: "directory" | "file" | "symlink";
41
+ } | {
42
+ readonly _tag: "Updated";
43
+ readonly path: import("../BytePath.js").BytePath;
44
+ readonly beforeKind: "directory" | "file" | "symlink";
45
+ readonly afterKind: "directory" | "file" | "symlink";
46
+ readonly differences: readonly ("atimeNs" | "birthtimeNs" | "content" | "ctimeNs" | "gid" | "hardLinks" | "kind" | "mode" | "mtimeNs" | "target" | "uid")[];
47
+ })[], ImageError | import("effect/PlatformError").PlatformError | SnapshotDeltaError, Crypto.Crypto>;
48
+ /** @internal */
49
+ 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>;
61
+ /** @internal */
62
+ 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>;
87
+ //# sourceMappingURL=snapshotDelta.d.ts.map
@@ -0,0 +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;AAKvC,OAAO,EAAE,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAGL,KAAK,aAAa,EAClB,kBAAkB,EAInB,MAAM,qBAAqB,CAAA;AA6e5B,gBAAgB;AAChB,eAAO,MAAM,aAAa;;;;;;;;;;;4GAgDzB,CAAA;AAyBD,gBAAgB;AAChB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;oGAgBhC,CAAA;AAED,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;+DAS9B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,mBAAmB;;;;;;;;;;;qDAkB9B,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,kBAAkB;;;;;;;;;;;4HAI9B,CAAA"}