@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.
- package/README.md +97 -8
- package/dist/BytePath.d.ts +34 -0
- package/dist/BytePath.d.ts.map +1 -0
- package/dist/BytePath.js +16 -0
- package/dist/Snapshot.d.ts +5 -5
- package/dist/Snapshot.d.ts.map +1 -1
- package/dist/Snapshot.js +5 -6
- package/dist/SnapshotDelta.d.ts +193 -0
- package/dist/SnapshotDelta.d.ts.map +1 -0
- package/dist/SnapshotDelta.js +139 -0
- package/dist/VirtualFileSystem.d.ts +193 -342
- package/dist/VirtualFileSystem.d.ts.map +1 -1
- package/dist/VirtualFileSystem.js +104 -1774
- package/dist/internal/bytePath.d.ts +10 -0
- package/dist/internal/bytePath.d.ts.map +1 -0
- package/dist/internal/bytePath.js +46 -0
- package/dist/internal/canonicalBase64.d.ts +7 -0
- package/dist/internal/canonicalBase64.d.ts.map +1 -0
- package/dist/internal/canonicalBase64.js +11 -0
- package/dist/internal/image.d.ts +28 -31
- package/dist/internal/image.d.ts.map +1 -1
- package/dist/internal/image.js +14 -23
- package/dist/internal/snapshotDelta.d.ts +87 -0
- package/dist/internal/snapshotDelta.d.ts.map +1 -0
- package/dist/internal/snapshotDelta.js +576 -0
- package/dist/internal/snapshotDeltaModel.d.ts +10 -0
- package/dist/internal/snapshotDeltaModel.d.ts.map +1 -0
- package/dist/internal/snapshotDeltaModel.js +13 -0
- package/dist/internal/virtualFileSystem/errors.d.ts +26 -0
- package/dist/internal/virtualFileSystem/errors.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem/errors.js +32 -0
- package/dist/internal/virtualFileSystem/fixture.d.ts +63 -0
- package/dist/internal/virtualFileSystem/fixture.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem/fixture.js +144 -0
- package/dist/internal/{content.d.ts → virtualFileSystem/overlayContent.d.ts} +4 -14
- package/dist/internal/virtualFileSystem/overlayContent.d.ts.map +1 -0
- package/dist/internal/{content.js → virtualFileSystem/overlayContent.js} +3 -7
- package/dist/internal/{overlayChanges.d.ts → virtualFileSystem/overlayDiff.d.ts} +1 -1
- package/dist/internal/virtualFileSystem/overlayDiff.d.ts.map +1 -0
- package/dist/internal/{overlayChanges.js → virtualFileSystem/overlayDiff.js} +4 -15
- package/dist/internal/virtualFileSystem/path.d.ts +43 -0
- package/dist/internal/virtualFileSystem/path.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem/path.js +124 -0
- package/dist/internal/virtualFileSystem/testHooks.d.ts +20 -0
- package/dist/internal/virtualFileSystem/testHooks.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem/testHooks.js +23 -0
- package/dist/internal/virtualFileSystem/watchHub.d.ts +16 -0
- package/dist/internal/virtualFileSystem/watchHub.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem/watchHub.js +33 -0
- package/dist/internal/virtualFileSystem.d.ts +290 -0
- package/dist/internal/virtualFileSystem.d.ts.map +1 -0
- package/dist/internal/virtualFileSystem.js +1677 -0
- package/package.json +5 -4
- package/dist/internal/content.d.ts.map +0 -1
- package/dist/internal/overlayChanges.d.ts.map +0 -1
- package/dist/internal/overlayTesting.d.ts +0 -12
- package/dist/internal/overlayTesting.d.ts.map +0 -1
- 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"));
|
package/dist/internal/image.d.ts
CHANGED
|
@@ -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.
|
|
12
|
-
readonly gid: Schema.
|
|
13
|
-
readonly mode: Schema.
|
|
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.
|
|
27
|
-
readonly gid: Schema.
|
|
28
|
-
readonly mode: Schema.
|
|
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.
|
|
43
|
-
readonly gid: Schema.
|
|
44
|
-
readonly mode: Schema.
|
|
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.
|
|
56
|
-
readonly gid: Schema.
|
|
57
|
-
readonly mode: Schema.
|
|
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.
|
|
77
|
-
readonly gid: Schema.
|
|
78
|
-
readonly mode: Schema.
|
|
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.
|
|
93
|
-
readonly gid: Schema.
|
|
94
|
-
readonly mode: Schema.
|
|
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.
|
|
106
|
-
readonly gid: Schema.
|
|
107
|
-
readonly mode: Schema.
|
|
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:
|
|
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:
|
|
125
|
+
readonly maxEncodedBytes: ByteSize.ByteSize;
|
|
129
126
|
readonly maxRecords: number;
|
|
130
127
|
readonly maxEntries: number;
|
|
131
|
-
readonly maxDecodedBytes:
|
|
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:
|
|
134
|
+
readonly maxEncodedBytes: ByteSize.ByteSize;
|
|
138
135
|
readonly maxRecords: number;
|
|
139
136
|
readonly maxEntries: number;
|
|
140
|
-
readonly maxDecodedBytes:
|
|
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":"
|
|
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"}
|
package/dist/internal/image.js
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
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
|
-
|
|
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:
|
|
19
|
-
gid:
|
|
20
|
-
mode:
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 (!
|
|
94
|
+
if (!CanonicalBase64.isCanonical(value))
|
|
105
95
|
return yield* error("InvalidEncoding", record.id);
|
|
106
|
-
payload
|
|
107
|
-
if (
|
|
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
|
|
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"}
|