@effect-vfs/core 0.5.0 → 0.7.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 +29 -21
  2. package/dist/BytePath.d.ts +115 -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 +13 -20
  15. package/dist/LiveVolume.d.ts.map +1 -1
  16. package/dist/LiveVolume.js +19 -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 +32 -53
  21. package/dist/Snapshot.d.ts.map +1 -1
  22. package/dist/Snapshot.js +27 -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 +132 -0
  30. package/dist/Testing.d.ts.map +1 -0
  31. package/dist/Testing.js +100 -0
  32. package/dist/VfsError.d.ts +200 -0
  33. package/dist/VfsError.d.ts.map +1 -0
  34. package/dist/VfsError.js +165 -0
  35. package/dist/VirtualFileSystem.d.ts +676 -353
  36. package/dist/VirtualFileSystem.d.ts.map +1 -1
  37. package/dist/VirtualFileSystem.js +487 -121
  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 +4 -15
  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 +605 -503
  98. package/dist/internal/snapshotDeltaModel.d.ts.map +1 -1
  99. package/dist/internal/snapshotDeltaModel.js +0 -1
  100. package/dist/internal/testSeams.d.ts +17 -0
  101. package/dist/internal/testSeams.d.ts.map +1 -0
  102. package/dist/internal/testSeams.js +20 -0
  103. package/dist/internal/tree.d.ts +225 -0
  104. package/dist/internal/tree.d.ts.map +1 -0
  105. package/dist/internal/tree.js +385 -0
  106. package/dist/internal/turnstile.d.ts +8 -0
  107. package/dist/internal/turnstile.d.ts.map +1 -0
  108. package/dist/internal/turnstile.js +43 -0
  109. package/dist/internal/virtualFileSystem.d.ts +44 -488
  110. package/dist/internal/virtualFileSystem.d.ts.map +1 -1
  111. package/dist/internal/virtualFileSystem.js +2111 -2466
  112. package/dist/internal/volumeState.d.ts +111 -0
  113. package/dist/internal/volumeState.d.ts.map +1 -0
  114. package/dist/internal/volumeState.js +202 -0
  115. package/dist/internal/watchHub.d.ts +15 -6
  116. package/dist/internal/watchHub.d.ts.map +1 -1
  117. package/dist/internal/watchHub.js +56 -42
  118. package/package.json +54 -10
  119. package/dist/VirtualFileSystemError.d.ts +0 -54
  120. package/dist/VirtualFileSystemError.d.ts.map +0 -1
  121. package/dist/VirtualFileSystemError.js +0 -49
  122. package/dist/internal/overlayContent.d.ts +0 -15
  123. package/dist/internal/overlayContent.d.ts.map +0 -1
  124. package/dist/internal/overlayContent.js +0 -29
  125. package/dist/internal/stagedState.d.ts +0 -22
  126. package/dist/internal/stagedState.d.ts.map +0 -1
  127. package/dist/internal/stagedState.js +0 -62
  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
@@ -1,31 +1,25 @@
1
- // Fixture image construction.
2
1
  import * as Effect from "effect/Effect";
3
2
  import * as Result from "effect/Result";
4
3
  import * as Schema from "effect/Schema";
5
- import { ImageError } from "../Snapshot.js";
6
- import { CanonicalBase64 } from "./canonicalBase64.js";
7
- import { decodeConfiguration, FsError } from "./errors.js";
8
- import * as Image from "./image.js";
9
- import { inputBytes, isAttachedBytes, isDotComponent, nameBytes, preparePath } from "./path.js";
10
- import { Fixture as FixtureSchema, FixtureEntry, makeVolume, VolumeIdentity, VolumeOptions as VolumeOptionsSchema, VolumeSource } from "./virtualFileSystem.js";
4
+ import { Fixture as FixtureSchema, FixtureEntry } from "../Fixture.js";
5
+ import { VolumeIdentity, VolumeOptions as VolumeOptionsSchema } from "../Volume.js";
6
+ import { decodeConfiguration, imageFailure, OpContext, VfsError } from "./errors.js";
7
+ import { inputBytes, isAttachedBytes, isDotComponent, preparePath } from "./path.js";
8
+ import { makeVolume, VolumeSource } from "./virtualFileSystem.js";
9
+ import { assemble, Ino, ROOT_INO } from "./volumeState.js";
11
10
  const DEFAULT_MODE = { directory: 0o755, file: 0o644, symlink: 0o777 };
12
11
  const EPOCH_NS = 0n;
13
12
  /** @internal */
14
13
  export const fromFixture = Effect.fn("VirtualFileSystem.fromFixture")(function* (fixture, options) {
15
- const config = decodeConfiguration(VolumeOptionsSchema, options ?? {});
16
- if (Result.isFailure(config))
17
- return yield* config.failure;
18
- const decoded = Schema.decodeResult(FixtureSchema, { onExcessProperty: "error" })(fixture);
19
- if (Result.isFailure(decoded))
20
- return yield* new ImageError({ code: "InvalidStructure", field: "fixture" });
21
- const source = decoded.success;
14
+ const config = yield* Effect.fromResult(decodeConfiguration(VolumeOptionsSchema, options ?? {}, "fromFixture"));
15
+ const source = yield* Schema.decodeEffect(FixtureSchema, { onExcessProperty: "error" })(fixture).pipe(Effect.mapError((cause) => imageFailure("fromFixture", "InvalidStructure", { field: "fixture", cause })));
22
16
  if (source.entries.some((entry) => FixtureEntry.match(entry, {
23
17
  directory: () => false,
24
18
  file: ({ bytes }) => !isAttachedBytes(bytes),
25
19
  symlink: () => false,
26
20
  hardLink: () => false
27
21
  }))) {
28
- return yield* new ImageError({ code: "InvalidEncoding", field: "bytes" });
22
+ return yield* imageFailure("fromFixture", "InvalidEncoding", { field: "bytes" });
29
23
  }
30
24
  const metadata = (kind, overrides) => ({
31
25
  uid: overrides?.uid ?? 0,
@@ -36,70 +30,53 @@ export const fromFixture = Effect.fn("VirtualFileSystem.fromFixture")(function*
36
30
  ctimeNs: overrides?.ctimeNs ?? EPOCH_NS,
37
31
  birthtimeNs: overrides?.birthtimeNs ?? EPOCH_NS
38
32
  });
33
+ // Assign inode numbers in declaration order, before resolving hard links.
39
34
  const declarations = new Map();
40
35
  const aliases = new Map();
41
36
  const paths = new Map();
42
- const root = Image.Record.cases.directory.make({
43
- id: "root",
44
- metadata: metadata("directory", source.rootMetadata),
45
- entries: []
46
- });
47
- declarations.set("", root);
48
- const fixturePath = (input) => preparePath(input, "fixture", config.success.maxPathBytes).pipe(Result.flatMap((path) => !path.absolute || path.components.length === 0 ||
37
+ let nextInode = ROOT_INO;
38
+ const declare = (declared) => {
39
+ nextInode = Ino(nextInode + 1);
40
+ return { ...declared, ino: nextInode };
41
+ };
42
+ declarations.set("", { kind: "directory", ino: ROOT_INO, metadata: metadata("directory", source.rootMetadata) });
43
+ const op = OpContext.make("fixture");
44
+ const fixturePath = (input) => preparePath(input, op.operation, config.maxPathBytes).pipe(Result.flatMap((path) => !path.absolute || path.components.length === 0 ||
49
45
  path.components.some(isDotComponent)
50
- ? Result.fail(new FsError({ code: "InvalidArgument", operation: "fixture", path: input })) :
46
+ ? Result.fail(op.at(input).fail("InvalidArgument")) :
51
47
  Result.succeed(path.components)));
52
- // Encode caller-owned byte buffers now: nothing below yields until Image.capture, so a caller
53
- // cannot mutate them first.
48
+ // Copy caller-owned bytes before storing them.
54
49
  for (const entry of source.entries) {
55
- const parsed = fixturePath(entry.path);
56
- if (Result.isFailure(parsed)) {
57
- return yield* new ImageError({ code: "InvalidStructure", field: "path" });
58
- }
59
- const components = parsed.success;
50
+ const components = yield* Effect.fromResult(fixturePath(entry.path)).pipe(Effect.mapError((cause) => imageFailure("fromFixture", "InvalidStructure", { field: "path", cause })));
60
51
  const key = components.join("/");
61
52
  if (paths.has(key))
62
- return yield* new ImageError({ code: "InvalidStructure", field: "duplicate" });
53
+ return yield* imageFailure("fromFixture", "InvalidStructure", { field: "duplicate" });
63
54
  paths.set(key, components);
64
55
  const error = FixtureEntry.match(entry, {
65
56
  hardLink: ({ target }) => {
66
57
  const parsedTarget = fixturePath(target);
67
- if (Result.isFailure(parsedTarget))
68
- return new ImageError({ code: "InvalidStructure", field: "target" });
58
+ if (Result.isFailure(parsedTarget)) {
59
+ return imageFailure("fromFixture", "InvalidStructure", { field: "target", cause: parsedTarget.failure });
60
+ }
69
61
  aliases.set(key, parsedTarget.success.join("/"));
70
62
  },
71
63
  directory: (entry) => {
72
- declarations.set(key, Image.Record.cases.directory.make({
73
- id: String(paths.size),
74
- metadata: metadata("directory", entry.metadata),
75
- entries: []
76
- }));
64
+ declarations.set(key, declare({ kind: "directory", metadata: metadata("directory", entry.metadata) }));
77
65
  },
78
66
  file: (entry) => {
79
- declarations.set(key, Image.Record.cases.file.make({
80
- id: String(paths.size),
81
- metadata: metadata("file", entry.metadata),
82
- data: CanonicalBase64.encode(entry.bytes)
83
- }));
67
+ declarations.set(key, declare({ kind: "file", metadata: metadata("file", entry.metadata), payload: entry.bytes.slice() }));
84
68
  },
85
69
  symlink: ({ metadata: overrides, target: input }) => {
86
70
  const target = inputBytes(input);
87
71
  if (Result.isFailure(target)) {
88
- return new ImageError({
89
- code: target.failure === "InvalidPathEncoding" ? "InvalidEncoding" : "InvalidStructure",
90
- field: "target"
91
- });
72
+ return imageFailure("fromFixture", target.failure === "InvalidPathEncoding" ? "InvalidEncoding" : "InvalidStructure", { field: "target" });
92
73
  }
93
74
  if (target.success.includes(0))
94
- return new ImageError({ code: "InvalidStructure", field: "target" });
95
- declarations.set(key, Image.Record.cases.symlink.make({
96
- id: String(paths.size),
97
- metadata: metadata("symlink", overrides),
98
- target: CanonicalBase64.encode(target.success)
99
- }));
75
+ return imageFailure("fromFixture", "InvalidStructure", { field: "target" });
76
+ declarations.set(key, declare({ kind: "symlink", metadata: metadata("symlink", overrides), payload: target.success.slice() }));
100
77
  }
101
78
  });
102
- if (error instanceof ImageError)
79
+ if (Schema.is(VfsError)(error))
103
80
  return yield* error;
104
81
  }
105
82
  for (const [key] of aliases) {
@@ -107,44 +84,50 @@ export const fromFixture = Effect.fn("VirtualFileSystem.fromFixture")(function*
107
84
  const seen = new Set();
108
85
  while (!declarations.has(target)) {
109
86
  if (seen.has(target))
110
- return yield* new ImageError({ code: "InvalidStructure", field: "hardLink" });
87
+ return yield* imageFailure("fromFixture", "InvalidStructure", { field: "hardLink" });
111
88
  seen.add(target);
112
89
  const next = aliases.get(target);
113
90
  if (next === undefined)
114
- return yield* new ImageError({ code: "InvalidStructure", field: "hardLink" });
91
+ return yield* imageFailure("fromFixture", "InvalidStructure", { field: "hardLink" });
115
92
  target = next;
116
93
  }
117
94
  const node = declarations.get(target);
118
- if (node === undefined || Image.Record.guards.directory(node)) {
119
- return yield* new ImageError({ code: "InvalidStructure", field: "hardLink" });
95
+ if (node === undefined || node.kind === "directory") {
96
+ return yield* imageFailure("fromFixture", "InvalidStructure", { field: "hardLink" });
120
97
  }
121
98
  for (const alias of seen)
122
99
  declarations.set(alias, node);
123
100
  }
124
- const children = new Map();
101
+ const names = new Map();
125
102
  for (const [key, components] of paths) {
126
103
  const parent = declarations.get(components.slice(0, -1).join("/"));
127
104
  const child = declarations.get(key);
128
105
  const name = components.at(-1);
129
- if (parent?._tag !== "directory" || child === undefined || name === undefined) {
130
- return yield* new ImageError({ code: "InvalidStructure", field: "parent" });
106
+ if (parent?.kind !== "directory" || child === undefined || name === undefined) {
107
+ return yield* imageFailure("fromFixture", "InvalidStructure", { field: "parent" });
131
108
  }
132
- const entries = children.get(parent.id) ?? [];
133
- entries.push({ name: CanonicalBase64.encode(nameBytes(name)), target: child.id });
134
- children.set(parent.id, entries);
109
+ names.set(child, [...(names.get(child) ?? []), { parent: parent.ino, name }]);
135
110
  }
136
- const records = [...new Set(declarations.values())].map((record) => Image.Record.match(record, {
137
- directory: (record) => ({ ...record, entries: children.get(record.id) ?? [] }),
138
- file: (record) => record,
139
- symlink: (record) => record
140
- }));
141
- const snapshot = yield* Image.capture({ format: "effect-vfs", version: 1, root: "root", records }, undefined, true);
142
- const image = yield* Image.inspect(snapshot);
143
- const { identity, ...volumeOptions } = config.success;
111
+ const specs = [...new Set(declarations.values())].map((declared) => {
112
+ const links = names.get(declared) ?? [];
113
+ const common = { ino: declared.ino, metadata: declared.metadata, revision: 1n };
114
+ if (declared.kind === "directory") {
115
+ // The root has no path; directories cannot have hard links.
116
+ const [link = { parent: ROOT_INO, name: "" }] = links;
117
+ return { ...common, kind: "directory", parent: link.parent, name: link.name };
118
+ }
119
+ const payload = declared.payload ?? new Uint8Array();
120
+ return declared.kind === "file"
121
+ ? { ...common, kind: "file", links, data: payload }
122
+ : { ...common, kind: "symlink", links, target: payload };
123
+ });
124
+ const restored = VolumeSource.Restored({ value: assemble(specs) });
125
+ const { identity, ...volumeOptions } = config;
144
126
  if (identity === undefined)
145
- return yield* makeVolume(VolumeSource.Snapshot({ image }), volumeOptions);
146
- return yield* makeVolume(VolumeSource.Snapshot({ image }), {
127
+ return (yield* makeVolume(restored, volumeOptions)).volume;
128
+ const { volume } = yield* makeVolume(restored, {
147
129
  ...volumeOptions,
148
130
  identity: VolumeIdentity.make(identity)
149
131
  });
132
+ return volume;
150
133
  });
@@ -0,0 +1,12 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** @internal */
3
+ export declare const Hex128: Schema.String;
4
+ /** @internal */
5
+ export declare const VolumeEpoch: Schema.brand<Schema.String, "@effect-vfs/core/VolumeEpoch">;
6
+ /** @internal */
7
+ export type VolumeEpoch = typeof VolumeEpoch.Type;
8
+ /** @internal */
9
+ export declare const KeySecret: Schema.brand<Schema.String, "@effect-vfs/core/KeySecret">;
10
+ /** @internal */
11
+ export type KeySecret = typeof KeySecret.Type;
12
+ //# sourceMappingURL=hex128.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hex128.d.ts","sourceRoot":"","sources":["../../src/internal/hex128.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,gBAAgB;AAChB,eAAO,MAAM,MAAM,eAA0D,CAAA;AAE7E,gBAAgB;AAChB,eAAO,MAAM,WAAW,6DAA4D,CAAA;AAEpF,gBAAgB;AAChB,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAEjD,gBAAgB;AAChB,eAAO,MAAM,SAAS,2DAA0D,CAAA;AAEhF,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,IAAI,CAAA"}
@@ -0,0 +1,7 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** @internal */
3
+ export const Hex128 = Schema.String.check(Schema.isPattern(/^[0-9a-f]{32}$/));
4
+ /** @internal */
5
+ export const VolumeEpoch = Hex128.pipe(Schema.brand("@effect-vfs/core/VolumeEpoch"));
6
+ /** @internal */
7
+ export const KeySecret = Hex128.pipe(Schema.brand("@effect-vfs/core/KeySecret"));
@@ -0,0 +1,5 @@
1
+ /** @internal */
2
+ export declare const hmacSha256: (key: Uint8Array, message: Uint8Array) => Uint8Array;
3
+ /** @internal */
4
+ export declare const sameTag: (left: Uint8Array, right: Uint8Array) => boolean;
5
+ //# sourceMappingURL=hmac.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hmac.d.ts","sourceRoot":"","sources":["../../src/internal/hmac.ts"],"names":[],"mappings":"AAqJA,gBAAgB;AAChB,eAAO,MAAM,UAAU,QAAS,UAAU,WAAW,UAAU,KAAG,UAOjE,CAAA;AAGD,gBAAgB;AAChB,eAAO,MAAM,OAAO,SAAU,UAAU,SAAS,UAAU,KAAG,OAQ7D,CAAA"}
@@ -0,0 +1,150 @@
1
+ // Synchronous HMAC keeps reference-key methods free of Crypto service requirements.
2
+ const BLOCK_BYTES = 64;
3
+ const ROUND_CONSTANTS = new Uint32Array([
4
+ 0x428a2f98,
5
+ 0x71374491,
6
+ 0xb5c0fbcf,
7
+ 0xe9b5dba5,
8
+ 0x3956c25b,
9
+ 0x59f111f1,
10
+ 0x923f82a4,
11
+ 0xab1c5ed5,
12
+ 0xd807aa98,
13
+ 0x12835b01,
14
+ 0x243185be,
15
+ 0x550c7dc3,
16
+ 0x72be5d74,
17
+ 0x80deb1fe,
18
+ 0x9bdc06a7,
19
+ 0xc19bf174,
20
+ 0xe49b69c1,
21
+ 0xefbe4786,
22
+ 0x0fc19dc6,
23
+ 0x240ca1cc,
24
+ 0x2de92c6f,
25
+ 0x4a7484aa,
26
+ 0x5cb0a9dc,
27
+ 0x76f988da,
28
+ 0x983e5152,
29
+ 0xa831c66d,
30
+ 0xb00327c8,
31
+ 0xbf597fc7,
32
+ 0xc6e00bf3,
33
+ 0xd5a79147,
34
+ 0x06ca6351,
35
+ 0x14292967,
36
+ 0x27b70a85,
37
+ 0x2e1b2138,
38
+ 0x4d2c6dfc,
39
+ 0x53380d13,
40
+ 0x650a7354,
41
+ 0x766a0abb,
42
+ 0x81c2c92e,
43
+ 0x92722c85,
44
+ 0xa2bfe8a1,
45
+ 0xa81a664b,
46
+ 0xc24b8b70,
47
+ 0xc76c51a3,
48
+ 0xd192e819,
49
+ 0xd6990624,
50
+ 0xf40e3585,
51
+ 0x106aa070,
52
+ 0x19a4c116,
53
+ 0x1e376c08,
54
+ 0x2748774c,
55
+ 0x34b0bcb5,
56
+ 0x391c0cb3,
57
+ 0x4ed8aa4a,
58
+ 0x5b9cca4f,
59
+ 0x682e6ff3,
60
+ 0x748f82ee,
61
+ 0x78a5636f,
62
+ 0x84c87814,
63
+ 0x8cc70208,
64
+ 0x90befffa,
65
+ 0xa4506ceb,
66
+ 0xbef9a3f7,
67
+ 0xc67178f2
68
+ ]);
69
+ const INITIAL_STATE = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];
70
+ const rotr = (value, bits) => (value >>> bits) | (value << (32 - bits));
71
+ const sha256 = (message) => {
72
+ const padded = new Uint8Array(Math.ceil((message.length + 9) / BLOCK_BYTES) * BLOCK_BYTES);
73
+ padded.set(message);
74
+ padded[message.length] = 0x80;
75
+ const view = new DataView(padded.buffer);
76
+ view.setBigUint64(padded.length - 8, BigInt(message.length) * 8n);
77
+ const state = Int32Array.from(INITIAL_STATE);
78
+ const schedule = new Uint32Array(64);
79
+ for (let block = 0; block < padded.length; block += BLOCK_BYTES) {
80
+ for (let t = 0; t < 16; t++)
81
+ schedule[t] = view.getUint32(block + t * 4);
82
+ for (let t = 16; t < 64; t++) {
83
+ const w15 = schedule[t - 15];
84
+ const w2 = schedule[t - 2];
85
+ const s0 = rotr(w15, 7) ^ rotr(w15, 18) ^ (w15 >>> 3);
86
+ const s1 = rotr(w2, 17) ^ rotr(w2, 19) ^ (w2 >>> 10);
87
+ schedule[t] = (schedule[t - 16] + s0 + schedule[t - 7] + s1) | 0;
88
+ }
89
+ let a = state[0];
90
+ let b = state[1];
91
+ let c = state[2];
92
+ let d = state[3];
93
+ let e = state[4];
94
+ let f = state[5];
95
+ let g = state[6];
96
+ let h = state[7];
97
+ for (let t = 0; t < 64; t++) {
98
+ const t1 = (h + (rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25)) + ((e & f) ^ (~e & g)) + ROUND_CONSTANTS[t]
99
+ + schedule[t]) | 0;
100
+ const t2 = ((rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22)) + ((a & b) ^ (a & c) ^ (b & c))) | 0;
101
+ h = g;
102
+ g = f;
103
+ f = e;
104
+ e = (d + t1) | 0;
105
+ d = c;
106
+ c = b;
107
+ b = a;
108
+ a = (t1 + t2) | 0;
109
+ }
110
+ state.set([
111
+ state[0] + a,
112
+ state[1] + b,
113
+ state[2] + c,
114
+ state[3] + d,
115
+ state[4] + e,
116
+ state[5] + f,
117
+ state[6] + g,
118
+ state[7] + h
119
+ ]);
120
+ }
121
+ const digest = new Uint8Array(32);
122
+ const out = new DataView(digest.buffer);
123
+ for (let word = 0; word < 8; word++)
124
+ out.setUint32(word * 4, state[word]);
125
+ return digest;
126
+ };
127
+ const concat = (left, right) => {
128
+ const joined = new Uint8Array(left.length + right.length);
129
+ joined.set(left);
130
+ joined.set(right, left.length);
131
+ return joined;
132
+ };
133
+ /** @internal */
134
+ export const hmacSha256 = (key, message) => {
135
+ const block = new Uint8Array(BLOCK_BYTES);
136
+ block.set(key.length > BLOCK_BYTES ? sha256(key) : key);
137
+ const inner = block.map((byte) => byte ^ 0x36);
138
+ const outer = block.map((byte) => byte ^ 0x5c);
139
+ return sha256(concat(outer, sha256(concat(inner, message))));
140
+ };
141
+ // Compare every byte regardless of the first difference to avoid leaking a matching prefix.
142
+ /** @internal */
143
+ export const sameTag = (left, right) => {
144
+ if (left.length !== right.length)
145
+ return false;
146
+ let difference = 0;
147
+ for (let index = 0; index < left.length; index++)
148
+ difference |= left[index] ^ right[index];
149
+ return difference === 0;
150
+ };
@@ -1,125 +1,22 @@
1
- import * as ByteSize from "effect/ByteSize";
2
1
  import * as Effect from "effect/Effect";
3
- import * as Schema from "effect/Schema";
4
- import { ImageError, type Snapshot } from "../Snapshot.js";
5
- import { StoredMetadata } from "./metadata.js";
2
+ import type * as Sink from "effect/Sink";
3
+ import * as Stream from "effect/Stream";
4
+ import type { FixtureEntry } from "../Fixture.js";
5
+ import { type Snapshot } from "../Snapshot.js";
6
+ import type { FsFailure, ImageFailure } from "../VfsError.js";
7
+ import type { PathInput } from "../VirtualFileSystem.js";
8
+ import type { Budget } from "./budget.js";
9
+ import { type VolumeState } from "./volumeState.js";
6
10
  /** @internal */
7
- export { StoredMetadata };
11
+ export declare const make: (value: VolumeState) => Snapshot;
8
12
  /** @internal */
9
- export declare const Record: Schema.TaggedUnion<{
10
- readonly directory: Schema.TaggedStruct<"directory", {
11
- readonly id: Schema.String;
12
- readonly metadata: Schema.Struct<{
13
- readonly uid: Schema.Natural;
14
- readonly gid: Schema.Natural;
15
- readonly mode: Schema.Natural;
16
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
17
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
18
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
19
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
20
- }>;
21
- readonly entries: Schema.$Array<Schema.Struct<{
22
- readonly name: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
23
- readonly target: Schema.String;
24
- }>>;
25
- }>;
26
- readonly file: Schema.TaggedStruct<"file", {
27
- readonly id: Schema.String;
28
- readonly metadata: Schema.Struct<{
29
- readonly uid: Schema.Natural;
30
- readonly gid: Schema.Natural;
31
- readonly mode: Schema.Natural;
32
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
33
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
34
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
35
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
36
- }>;
37
- readonly data: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
38
- }>;
39
- readonly symlink: Schema.TaggedStruct<"symlink", {
40
- readonly id: Schema.String;
41
- readonly metadata: Schema.Struct<{
42
- readonly uid: Schema.Natural;
43
- readonly gid: Schema.Natural;
44
- readonly mode: Schema.Natural;
45
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
46
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
47
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
48
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
49
- }>;
50
- readonly target: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
51
- }>;
52
- }>;
13
+ export declare const valueOf: (snapshot: Snapshot) => Effect.Effect<VolumeState, ImageFailure>;
53
14
  /** @internal */
54
- export type Record = typeof Record.Type;
15
+ export declare const encodeSnapshotStream: (snapshot: Snapshot, budget?: Budget) => Stream.Stream<Uint8Array, ImageFailure>;
55
16
  /** @internal */
56
- export declare const Document: Schema.Struct<{
57
- readonly format: Schema.Literal<"effect-vfs">;
58
- readonly version: Schema.Literal<1>;
59
- readonly root: Schema.String;
60
- readonly records: Schema.$Array<Schema.TaggedUnion<{
61
- readonly directory: Schema.TaggedStruct<"directory", {
62
- readonly id: Schema.String;
63
- readonly metadata: Schema.Struct<{
64
- readonly uid: Schema.Natural;
65
- readonly gid: Schema.Natural;
66
- readonly mode: Schema.Natural;
67
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
68
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
69
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
70
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
71
- }>;
72
- readonly entries: Schema.$Array<Schema.Struct<{
73
- readonly name: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
74
- readonly target: Schema.String;
75
- }>>;
76
- }>;
77
- readonly file: Schema.TaggedStruct<"file", {
78
- readonly id: Schema.String;
79
- readonly metadata: Schema.Struct<{
80
- readonly uid: Schema.Natural;
81
- readonly gid: Schema.Natural;
82
- readonly mode: Schema.Natural;
83
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
84
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
85
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
86
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
87
- }>;
88
- readonly data: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
89
- }>;
90
- readonly symlink: Schema.TaggedStruct<"symlink", {
91
- readonly id: Schema.String;
92
- readonly metadata: Schema.Struct<{
93
- readonly uid: Schema.Natural;
94
- readonly gid: Schema.Natural;
95
- readonly mode: Schema.Natural;
96
- readonly atimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
97
- readonly mtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
98
- readonly ctimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
99
- readonly birthtimeNs: Schema.decodeTo<Schema.BigInt, Schema.String, never, never>;
100
- }>;
101
- readonly target: Schema.brand<Schema.refine<string, Schema.String>, "CanonicalBase64">;
102
- }>;
103
- }>>;
104
- }>;
17
+ export declare const encodeSnapshot: (snapshot: Snapshot, budget?: Budget) => Effect.Effect<Uint8Array, ImageFailure>;
105
18
  /** @internal */
106
- export type Document = typeof Document.Type;
19
+ export declare const decodeSnapshotSink: (budget: Budget) => Sink.Sink<Snapshot, Uint8Array, never, ImageFailure>;
107
20
  /** @internal */
108
- export declare const inspect: (snapshot: Snapshot) => Effect.Effect<Document, ImageError>;
109
- /** @internal */
110
- export declare const capture: (input: unknown, limits?: {
111
- readonly maxEncodedBytes: ByteSize.ByteSize;
112
- readonly maxRecords: number;
113
- readonly maxEntries: number;
114
- readonly maxDecodedBytes: ByteSize.ByteSize;
115
- } | undefined, trusted?: any) => Effect.Effect<Snapshot, ImageError, never>;
116
- /** @internal */
117
- export declare const encodeSnapshot: (snapshot: Snapshot) => Effect.Effect<Uint8Array<ArrayBuffer>, ImageError, never>;
118
- /** @internal */
119
- export declare const decodeSnapshot: (input: Uint8Array<ArrayBufferLike>, limits: {
120
- readonly maxEncodedBytes: ByteSize.ByteSize;
121
- readonly maxRecords: number;
122
- readonly maxEntries: number;
123
- readonly maxDecodedBytes: ByteSize.ByteSize;
124
- }) => Effect.Effect<Snapshot, ImageError, never>;
21
+ export declare const snapshotEntries: (snapshot: Snapshot, root: PathInput) => Stream.Stream<FixtureEntry, FsFailure | ImageFailure>;
125
22
  //# sourceMappingURL=image.d.ts.map
@@ -1 +1 @@
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;AAExF,OAAO,EAAE,cAAc,EAAsB,MAAM,eAAe,CAAA;AAMlE,gBAAgB;AAChB,OAAO,EAAE,cAAc,EAAE,CAAA;AAIzB,gBAAgB;AAChB,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQjB,CAAA;AAEF,gBAAgB;AAChB,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC,IAAI,CAAA;AAEvC,gBAAgB;AAChB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAKnB,CAAA;AAwBF,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAI3C,gBAAgB;AAChB,eAAO,MAAM,OAAO,aAAc,QAAQ,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAO3E,CAAA;AAEJ,gBAAgB;AAChB,eAAO,MAAM,OAAO;;;;;2EAiJlB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc,mFAMzB,CAAA;AAEF,gBAAgB;AAChB,eAAO,MAAM,cAAc;;;;;gDA+B1B,CAAA"}
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/internal/image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAKvC,OAAO,KAAK,KAAK,IAAI,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,KAAK,QAAQ,EAAkB,MAAM,gBAAgB,CAAA;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAezC,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAA;AAgBzB,gBAAgB;AAChB,eAAO,MAAM,IAAI,UAAW,WAAW,KAAG,QAAkD,CAAA;AAE5F,gBAAgB;AAChB,eAAO,MAAM,OAAO,aAAc,QAAQ,KAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,YAAY,CAOhF,CAAA;AAOJ,gBAAgB;AAChB,eAAO,MAAM,oBAAoB,aACrB,QAAQ,WACT,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,CAapC,CAAA;AAEL,gBAAgB;AAChB,eAAO,MAAM,cAAc,aAAc,QAAQ,WAAW,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,YAAY,CACpD,CAAA;AAEvD,gBAAgB;AAChB,eAAO,MAAM,kBAAkB,WAAY,MAAM,KAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,CAYtG,CAAA;AA0GD,gBAAgB;AAChB,eAAO,MAAM,eAAe,aAChB,QAAQ,QACZ,SAAS,KACd,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,GAAG,YAAY,CAOlD,CAAA"}