@agent-teams/engineering-foundation 0.13.0 → 0.13.1

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 (55) hide show
  1. package/dist/repository-mutation/adapters/node/node-absent-file-publication.d.ts +31 -0
  2. package/dist/repository-mutation/adapters/node/node-absent-file-publication.d.ts.map +1 -0
  3. package/dist/repository-mutation/adapters/node/node-absent-file-publication.js +272 -0
  4. package/dist/repository-mutation/adapters/node/node-absent-file-publication.js.map +1 -0
  5. package/dist/repository-mutation/adapters/node/node-bounded-regular-file.d.ts +20 -0
  6. package/dist/repository-mutation/adapters/node/node-bounded-regular-file.d.ts.map +1 -0
  7. package/dist/repository-mutation/adapters/node/node-bounded-regular-file.js +123 -0
  8. package/dist/repository-mutation/adapters/node/node-bounded-regular-file.js.map +1 -0
  9. package/dist/repository-mutation/adapters/node/node-directory-durability.d.ts +12 -0
  10. package/dist/repository-mutation/adapters/node/node-directory-durability.d.ts.map +1 -0
  11. package/dist/repository-mutation/adapters/node/node-directory-durability.js +32 -0
  12. package/dist/repository-mutation/adapters/node/node-directory-durability.js.map +1 -0
  13. package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.d.ts +13 -0
  14. package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.d.ts.map +1 -0
  15. package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.js +67 -0
  16. package/dist/repository-mutation/adapters/node/node-existing-repository-ancestors.js.map +1 -0
  17. package/dist/repository-mutation/adapters/node/node-repository-path.d.ts +2 -0
  18. package/dist/repository-mutation/adapters/node/node-repository-path.d.ts.map +1 -0
  19. package/dist/repository-mutation/adapters/node/node-repository-path.js +7 -0
  20. package/dist/repository-mutation/adapters/node/node-repository-path.js.map +1 -0
  21. package/dist/repository-mutation/application/model/exact-postimage.d.ts +17 -0
  22. package/dist/repository-mutation/application/model/exact-postimage.d.ts.map +1 -0
  23. package/dist/repository-mutation/application/model/exact-postimage.js +11 -0
  24. package/dist/repository-mutation/application/model/exact-postimage.js.map +1 -0
  25. package/dist/repository-mutation/application/model/path-identity.d.ts +7 -0
  26. package/dist/repository-mutation/application/model/path-identity.d.ts.map +1 -0
  27. package/dist/repository-mutation/application/model/path-identity.js +2 -0
  28. package/dist/repository-mutation/application/model/path-identity.js.map +1 -0
  29. package/dist/repository-mutation/application/model/repository-path.d.ts +8 -0
  30. package/dist/repository-mutation/application/model/repository-path.d.ts.map +1 -0
  31. package/dist/repository-mutation/application/model/repository-path.js +74 -0
  32. package/dist/repository-mutation/application/model/repository-path.js.map +1 -0
  33. package/dist/scaffolding/adapters/node/filesystem-file-identity.d.ts +3 -23
  34. package/dist/scaffolding/adapters/node/filesystem-file-identity.d.ts.map +1 -1
  35. package/dist/scaffolding/adapters/node/filesystem-file-identity.js +1 -122
  36. package/dist/scaffolding/adapters/node/filesystem-file-identity.js.map +1 -1
  37. package/dist/scaffolding/adapters/node/filesystem-operation-state.d.ts +2 -1
  38. package/dist/scaffolding/adapters/node/filesystem-operation-state.d.ts.map +1 -1
  39. package/dist/scaffolding/adapters/node/filesystem-operation-state.js +73 -122
  40. package/dist/scaffolding/adapters/node/filesystem-operation-state.js.map +1 -1
  41. package/dist/scaffolding/adapters/node/filesystem-path-guard.d.ts.map +1 -1
  42. package/dist/scaffolding/adapters/node/filesystem-path-guard.js +27 -68
  43. package/dist/scaffolding/adapters/node/filesystem-path-guard.js.map +1 -1
  44. package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.d.ts +4 -0
  45. package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.d.ts.map +1 -0
  46. package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.js +48 -0
  47. package/dist/scaffolding/application/policies/legacy-scaffolding-repository-path.js.map +1 -0
  48. package/dist/transaction-coordination/adapters/node/installed-foundation-build-identity.js +1 -1
  49. package/dist/transaction-coordination/adapters/node/installed-foundation-build-identity.js.map +1 -1
  50. package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.d.ts.map +1 -1
  51. package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.js +1 -1
  52. package/dist/transaction-coordination/adapters/node/node-foundation-operation-lock.js.map +1 -1
  53. package/dist/transaction-coordination/adapters/node/node-foundation-transaction-slot.js +1 -1
  54. package/dist/transaction-coordination/adapters/node/node-foundation-transaction-slot.js.map +1 -1
  55. package/package.json +1 -1
@@ -0,0 +1,31 @@
1
+ import { link, type FileHandle } from "node:fs/promises";
2
+ import { type AbsentFilePublicationOutcome, type ExactFilePostimage, type ExactFilePostimageState } from "../../application/model/exact-postimage.js";
3
+ import { readBoundedRegularFile } from "./node-bounded-regular-file.js";
4
+ import { syncDirectoryDurably } from "./node-directory-durability.js";
5
+ export interface AbsentFilePublicationFaultPoint {
6
+ readonly phase: "after-hard-link" | "after-temporary-synced" | "after-temporary-written";
7
+ }
8
+ export type AbsentFilePublicationFaultInjector = (point: AbsentFilePublicationFaultPoint) => Promise<void> | void;
9
+ interface AbsentFilePublicationOperations {
10
+ readonly link: typeof link;
11
+ readonly open: (path: string, flags: "wx", mode: number) => Promise<FileHandle>;
12
+ readonly readBoundedRegularFile: typeof readBoundedRegularFile;
13
+ readonly rm: (path: string) => Promise<void>;
14
+ readonly syncDirectory: typeof syncDirectoryDurably;
15
+ }
16
+ export declare function classifyExactFilePostimage(destinationPath: string, postimage: ExactFilePostimage): Promise<ExactFilePostimageState>;
17
+ export declare function assertTemporaryPathsAbsent(entries: readonly {
18
+ readonly displayPath: string;
19
+ readonly temporaryPath: string;
20
+ }[]): Promise<void>;
21
+ export declare function publishAbsentFile(options: {
22
+ readonly allowUnsupportedDirectoryDurability?: boolean;
23
+ readonly destinationPath: string;
24
+ readonly displayPath: string;
25
+ readonly faultInjector?: AbsentFilePublicationFaultInjector;
26
+ readonly operations?: Partial<AbsentFilePublicationOperations>;
27
+ readonly postimage: ExactFilePostimage;
28
+ readonly temporaryPath: string;
29
+ }): Promise<AbsentFilePublicationOutcome>;
30
+ export {};
31
+ //# sourceMappingURL=node-absent-file-publication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-absent-file-publication.d.ts","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-absent-file-publication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAmB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG1E,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC7B,MAAM,4CAA4C,CAAC;AAGpD,OAAO,EAGL,sBAAsB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAEtE,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,KAAK,EACV,iBAAiB,GACjB,wBAAwB,GACxB,yBAAyB,CAAC;CAC/B;AAED,MAAM,MAAM,kCAAkC,GAAG,CAC/C,KAAK,EAAE,+BAA+B,KACnC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE1B,UAAU,+BAA+B;IACvC,QAAQ,CAAC,IAAI,EAAE,OAAO,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,CACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,IAAI,EACX,IAAI,EAAE,MAAM,KACT,OAAO,CAAC,UAAU,CAAC,CAAC;IACzB,QAAQ,CAAC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IAC/D,QAAQ,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,aAAa,EAAE,OAAO,oBAAoB,CAAC;CACrD;AAwMD,wBAAsB,0BAA0B,CAC9C,eAAe,EAAE,MAAM,EACvB,SAAS,EAAE,kBAAkB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CAMlC;AAED,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,SAAS;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAAE,GACnF,OAAO,CAAC,IAAI,CAAC,CAef;AA0MD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,QAAQ,CAAC,mCAAmC,CAAC,EAAE,OAAO,CAAC;IACvD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,CAAC,EAAE,kCAAkC,CAAC;IAC5D,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAC;IAC/D,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAmCxC"}
@@ -0,0 +1,272 @@
1
+ import { createHash } from "node:crypto";
2
+ import { link, lstat, open, rm } from "node:fs/promises";
3
+ import { dirname, resolve } from "node:path";
4
+ import { AbsentFilePublicationError } from "../../application/model/exact-postimage.js";
5
+ import { portableRepositoryPathIdentity } from "../../application/model/repository-path.js";
6
+ import { captureFileHandleIdentity, pathMatchesRegularFileIdentity, readBoundedRegularFile } from "./node-bounded-regular-file.js";
7
+ import { syncDirectoryDurably } from "./node-directory-durability.js";
8
+ const nodeOperations = {
9
+ link,
10
+ open,
11
+ readBoundedRegularFile,
12
+ rm,
13
+ syncDirectory: syncDirectoryDurably
14
+ };
15
+ function errorCode(error) {
16
+ return error instanceof Error && "code" in error
17
+ ? error.code
18
+ : undefined;
19
+ }
20
+ function isMissing(error) {
21
+ return errorCode(error) === "ENOENT";
22
+ }
23
+ function isUnsupportedLink(error) {
24
+ return ["ENOSYS", "ENOTSUP", "EOPNOTSUPP", "EPERM", "EXDEV"].includes(errorCode(error) ?? "");
25
+ }
26
+ function sha256(bytes) {
27
+ return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
28
+ }
29
+ function sameIdentity(left, right) {
30
+ return (left.dev === right.dev &&
31
+ left.ino === right.ino &&
32
+ left.birthtimeNs === right.birthtimeNs);
33
+ }
34
+ function exactReadMatchesPostimage(result, postimage) {
35
+ return (result.outcome === "read" &&
36
+ result.bytes.byteLength === postimage.size &&
37
+ sha256(result.bytes) === postimage.digest &&
38
+ (process.platform === "win32" ||
39
+ (result.mode & 0o777) === postimage.mode));
40
+ }
41
+ async function verifyTemporaryForPublication(temporaryPath, postimage, expectedIdentity, displayPath) {
42
+ const stableTemporary = await readBoundedRegularFile(temporaryPath, postimage.size);
43
+ if (exactReadMatchesPostimage(stableTemporary, postimage) &&
44
+ sameIdentity(stableTemporary.identity, expectedIdentity)) {
45
+ return;
46
+ }
47
+ throw new AbsentFilePublicationError("TEMPORARY_REPLACED", `Temporary path was replaced or modified concurrently: ${displayPath}.`);
48
+ }
49
+ async function verifyPublishedFile(destinationPath, postimage, expectedIdentity, displayPath) {
50
+ const publishedFile = await readBoundedRegularFile(destinationPath, postimage.size);
51
+ if (exactReadMatchesPostimage(publishedFile, postimage) &&
52
+ sameIdentity(publishedFile.identity, expectedIdentity)) {
53
+ return;
54
+ }
55
+ throw new AbsentFilePublicationError("VERIFICATION_FAILED", `Published file failed identity or content verification: ${displayPath}.`);
56
+ }
57
+ function assertValidPostimage(postimage) {
58
+ if (!Number.isSafeInteger(postimage.size) ||
59
+ postimage.size < 0 ||
60
+ postimage.bytes.byteLength !== postimage.size ||
61
+ sha256(postimage.bytes) !== postimage.digest ||
62
+ !Number.isSafeInteger(postimage.mode) ||
63
+ postimage.mode < 0 ||
64
+ postimage.mode > 0o777) {
65
+ throw new AbsentFilePublicationError("INVALID_POSTIMAGE", "Exact file postimage metadata does not match its bytes.");
66
+ }
67
+ }
68
+ function snapshotPostimage(postimage) {
69
+ const snapshot = {
70
+ bytes: Buffer.from(postimage.bytes),
71
+ digest: postimage.digest,
72
+ mode: postimage.mode,
73
+ size: postimage.size
74
+ };
75
+ assertValidPostimage(snapshot);
76
+ return snapshot;
77
+ }
78
+ function assertValidPublicationPaths(temporaryPath, destinationPath, displayPath) {
79
+ const resolvedTemporary = resolve(temporaryPath);
80
+ const resolvedDestination = resolve(destinationPath);
81
+ if (portableRepositoryPathIdentity(resolvedTemporary) ===
82
+ portableRepositoryPathIdentity(resolvedDestination) ||
83
+ dirname(resolvedTemporary) !== dirname(resolvedDestination)) {
84
+ throw new AbsentFilePublicationError("PUBLICATION_INVALID", `Publication paths are not distinct siblings: ${displayPath}.`);
85
+ }
86
+ }
87
+ // Covers the one-shot ctime change when a concurrent publisher unlinks its hard-link temporary.
88
+ const maximumUnstableReadRetries = 2;
89
+ async function classifyExactFilePostimageWith(readFile, destinationPath, postimage) {
90
+ for (let attempt = 0;; attempt += 1) {
91
+ try {
92
+ const result = await readFile(destinationPath, postimage.size);
93
+ if (result.outcome === "changed" &&
94
+ attempt < maximumUnstableReadRetries) {
95
+ continue;
96
+ }
97
+ if (result.outcome !== "read") {
98
+ return "conflict";
99
+ }
100
+ const modeMatches = process.platform === "win32" ||
101
+ (result.mode & 0o777) === postimage.mode;
102
+ return result.bytes.byteLength === postimage.size &&
103
+ sha256(result.bytes) === postimage.digest &&
104
+ modeMatches
105
+ ? "exact"
106
+ : "conflict";
107
+ }
108
+ catch (error) {
109
+ if (isMissing(error)) {
110
+ return "absent";
111
+ }
112
+ throw error;
113
+ }
114
+ }
115
+ }
116
+ export async function classifyExactFilePostimage(destinationPath, postimage) {
117
+ return classifyExactFilePostimageWith(readBoundedRegularFile, destinationPath, snapshotPostimage(postimage));
118
+ }
119
+ export async function assertTemporaryPathsAbsent(entries) {
120
+ for (const entry of entries) {
121
+ try {
122
+ await lstat(entry.temporaryPath);
123
+ }
124
+ catch (error) {
125
+ if (isMissing(error)) {
126
+ continue;
127
+ }
128
+ throw error;
129
+ }
130
+ throw new AbsentFilePublicationError("TEMPORARY_EXISTS", `Temporary path already exists: ${entry.displayPath}.`);
131
+ }
132
+ }
133
+ async function syncPublicationParent(context) {
134
+ const durability = await context.operations.syncDirectory(context.parent);
135
+ if (durability === "unsupported" &&
136
+ !context.allowUnsupportedDirectoryDurability) {
137
+ throw new AbsentFilePublicationError("PUBLICATION_UNSUPPORTED", `Directory durability is unsupported: ${context.displayPath}.`);
138
+ }
139
+ }
140
+ async function createPublicationTemporary(context, state) {
141
+ const handle = await context.operations
142
+ .open(context.temporaryPath, "wx", 0o600)
143
+ .catch((error) => {
144
+ if (errorCode(error) === "EEXIST") {
145
+ throw new AbsentFilePublicationError("TEMPORARY_EXISTS", `Temporary path already exists: ${context.displayPath}.`, { cause: error });
146
+ }
147
+ throw error;
148
+ });
149
+ try {
150
+ state.temporaryIdentity = await captureFileHandleIdentity(handle);
151
+ await handle.writeFile(context.postimage.bytes);
152
+ await context.faultInjector?.({ phase: "after-temporary-written" });
153
+ await handle.chmod(context.postimage.mode);
154
+ await handle.sync();
155
+ }
156
+ finally {
157
+ await handle.close();
158
+ }
159
+ }
160
+ async function linkPublicationDestination(context) {
161
+ try {
162
+ await context.operations.link(context.temporaryPath, context.destinationPath);
163
+ return false;
164
+ }
165
+ catch (error) {
166
+ if (errorCode(error) === "EEXIST") {
167
+ const state = await classifyExactFilePostimageWith(context.operations.readBoundedRegularFile, context.destinationPath, context.postimage);
168
+ if (state === "exact") {
169
+ return true;
170
+ }
171
+ throw new AbsentFilePublicationError("CONFLICT", `Destination changed concurrently: ${context.displayPath}.`, { cause: error });
172
+ }
173
+ if (isUnsupportedLink(error)) {
174
+ throw new AbsentFilePublicationError("PUBLICATION_UNSUPPORTED", `Atomic absent-only publication is unsupported: ${context.displayPath}.`, { cause: error });
175
+ }
176
+ throw error;
177
+ }
178
+ }
179
+ async function runPublicationPhase(context) {
180
+ const state = {
181
+ concurrentSatisfied: false,
182
+ published: false
183
+ };
184
+ try {
185
+ await createPublicationTemporary(context, state);
186
+ const temporaryIdentity = state.temporaryIdentity;
187
+ if (temporaryIdentity === undefined) {
188
+ throw new AbsentFilePublicationError("PUBLICATION_INCOMPLETE", `Publication temporary identity was not captured: ${context.displayPath}.`);
189
+ }
190
+ await context.faultInjector?.({ phase: "after-temporary-synced" });
191
+ await verifyTemporaryForPublication(context.temporaryPath, context.postimage, temporaryIdentity, context.displayPath);
192
+ state.concurrentSatisfied = await linkPublicationDestination(context);
193
+ if (!state.concurrentSatisfied) {
194
+ state.published = true;
195
+ await context.faultInjector?.({ phase: "after-hard-link" });
196
+ await verifyPublishedFile(context.destinationPath, context.postimage, temporaryIdentity, context.displayPath);
197
+ await syncPublicationParent(context);
198
+ }
199
+ }
200
+ catch (error) {
201
+ state.error = error;
202
+ }
203
+ return state;
204
+ }
205
+ async function cleanupPublicationTemporary(context, state) {
206
+ try {
207
+ const ownership = state.temporaryIdentity === undefined
208
+ ? "missing"
209
+ : await pathMatchesRegularFileIdentity(context.temporaryPath, state.temporaryIdentity);
210
+ if (ownership === "match") {
211
+ await context.operations.rm(context.temporaryPath);
212
+ await syncPublicationParent(context);
213
+ }
214
+ else if (ownership === "different") {
215
+ throw new AbsentFilePublicationError("TEMPORARY_REPLACED", `Temporary path was replaced concurrently: ${context.displayPath}.`, state.error === undefined ? undefined : { cause: state.error });
216
+ }
217
+ }
218
+ catch (cleanupError) {
219
+ if (cleanupError instanceof AbsentFilePublicationError &&
220
+ cleanupError.code === "TEMPORARY_REPLACED") {
221
+ throw cleanupError;
222
+ }
223
+ throw new AbsentFilePublicationError("CLEANUP_FAILED", `Publication temporary cleanup failed: ${context.displayPath}.`, {
224
+ cause: state.error ?? cleanupError,
225
+ cleanupError
226
+ });
227
+ }
228
+ }
229
+ async function publicationOutcome(context, state) {
230
+ if (state.error !== undefined) {
231
+ if (!(state.error instanceof Error)) {
232
+ throw new AbsentFilePublicationError("INVALID_ERROR", `Publication failed with an invalid error value: ${context.displayPath}.`);
233
+ }
234
+ throw state.error;
235
+ }
236
+ if (state.concurrentSatisfied) {
237
+ if ((await classifyExactFilePostimageWith(context.operations.readBoundedRegularFile, context.destinationPath, context.postimage)) !== "exact") {
238
+ throw new AbsentFilePublicationError("CONFLICT", `Destination changed concurrently: ${context.displayPath}.`);
239
+ }
240
+ return "already-satisfied";
241
+ }
242
+ if (!state.published || state.temporaryIdentity === undefined) {
243
+ throw new AbsentFilePublicationError("PUBLICATION_INCOMPLETE", `Publication did not reach a terminal state: ${context.displayPath}.`);
244
+ }
245
+ await verifyPublishedFile(context.destinationPath, context.postimage, state.temporaryIdentity, context.displayPath);
246
+ return "published";
247
+ }
248
+ export async function publishAbsentFile(options) {
249
+ const postimage = snapshotPostimage(options.postimage);
250
+ const context = {
251
+ allowUnsupportedDirectoryDurability: options.allowUnsupportedDirectoryDurability === true,
252
+ destinationPath: options.destinationPath,
253
+ displayPath: options.displayPath,
254
+ faultInjector: options.faultInjector,
255
+ operations: { ...nodeOperations, ...options.operations },
256
+ parent: dirname(resolve(options.destinationPath)),
257
+ postimage,
258
+ temporaryPath: options.temporaryPath
259
+ };
260
+ assertValidPublicationPaths(context.temporaryPath, context.destinationPath, context.displayPath);
261
+ const initial = await classifyExactFilePostimageWith(context.operations.readBoundedRegularFile, context.destinationPath, context.postimage);
262
+ if (initial === "exact") {
263
+ return "already-satisfied";
264
+ }
265
+ if (initial === "conflict") {
266
+ throw new AbsentFilePublicationError("CONFLICT", `Destination changed concurrently: ${context.displayPath}.`);
267
+ }
268
+ const state = await runPublicationPhase(context);
269
+ await cleanupPublicationTemporary(context, state);
270
+ return publicationOutcome(context, state);
271
+ }
272
+ //# sourceMappingURL=node-absent-file-publication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-absent-file-publication.js","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-absent-file-publication.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAmB,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EACL,0BAA0B,EAI3B,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,8BAA8B,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EACL,yBAAyB,EACzB,8BAA8B,EAC9B,sBAAsB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AA2CtE,MAAM,cAAc,GAAoC;IACtD,IAAI;IACJ,IAAI;IACJ,sBAAsB;IACtB,EAAE;IACF,aAAa,EAAE,oBAAoB;CACpC,CAAC;AAEF,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK;QAC9C,CAAC,CAAE,KAA+B,CAAC,IAAI;QACvC,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC;AACvC,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CACnE,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CACvB,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,KAAiB;IAC/B,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,SAAS,YAAY,CACnB,IAA0B,EAC1B,KAA2B;IAE3B,OAAO,CACL,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG;QACtB,IAAI,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG;QACtB,IAAI,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW,CACvC,CAAC;AACJ,CAAC;AAED,SAAS,yBAAyB,CAChC,MAA0D,EAC1D,SAA6B;IAE7B,OAAO,CACL,MAAM,CAAC,OAAO,KAAK,MAAM;QACzB,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;QAC1C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,MAAM;QACzC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC3B,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC,CAC5C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,6BAA6B,CAC1C,aAAqB,EACrB,SAA6B,EAC7B,gBAAsC,EACtC,WAAmB;IAEnB,MAAM,eAAe,GAAG,MAAM,sBAAsB,CAClD,aAAa,EACb,SAAS,CAAC,IAAI,CACf,CAAC;IACF,IACE,yBAAyB,CAAC,eAAe,EAAE,SAAS,CAAC;QACrD,YAAY,CAAC,eAAe,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EACxD,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,0BAA0B,CAClC,oBAAoB,EACpB,yDAAyD,WAAW,GAAG,CACxE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,eAAuB,EACvB,SAA6B,EAC7B,gBAAsC,EACtC,WAAmB;IAEnB,MAAM,aAAa,GAAG,MAAM,sBAAsB,CAChD,eAAe,EACf,SAAS,CAAC,IAAI,CACf,CAAC;IACF,IACE,yBAAyB,CAAC,aAAa,EAAE,SAAS,CAAC;QACnD,YAAY,CAAC,aAAa,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EACtD,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,0BAA0B,CAClC,qBAAqB,EACrB,2DAA2D,WAAW,GAAG,CAC1E,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAA6B;IACzD,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC;QACrC,SAAS,CAAC,IAAI,GAAG,CAAC;QAClB,SAAS,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;QAC7C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,MAAM;QAC5C,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC;QACrC,SAAS,CAAC,IAAI,GAAG,CAAC;QAClB,SAAS,CAAC,IAAI,GAAG,KAAK,EACtB,CAAC;QACD,MAAM,IAAI,0BAA0B,CAClC,mBAAmB,EACnB,yDAAyD,CAC1D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,SAA6B;IACtD,MAAM,QAAQ,GAAG;QACf,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QACnC,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,IAAI,EAAE,SAAS,CAAC,IAAI;QACpB,IAAI,EAAE,SAAS,CAAC,IAAI;KACrB,CAAC;IACF,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,2BAA2B,CAClC,aAAqB,EACrB,eAAuB,EACvB,WAAmB;IAEnB,MAAM,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,MAAM,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACrD,IACE,8BAA8B,CAAC,iBAAiB,CAAC;QAC/C,8BAA8B,CAAC,mBAAmB,CAAC;QACrD,OAAO,CAAC,iBAAiB,CAAC,KAAK,OAAO,CAAC,mBAAmB,CAAC,EAC3D,CAAC;QACD,MAAM,IAAI,0BAA0B,CAClC,qBAAqB,EACrB,gDAAgD,WAAW,GAAG,CAC/D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,0BAA0B,GAAG,CAAC,CAAC;AAErC,KAAK,UAAU,8BAA8B,CAC3C,QAAuC,EACvC,eAAuB,EACvB,SAA6B;IAE7B,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;YAC/D,IACE,MAAM,CAAC,OAAO,KAAK,SAAS;gBAC5B,OAAO,GAAG,0BAA0B,EACpC,CAAC;gBACD,SAAS;YACX,CAAC;YACD,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;gBAC9B,OAAO,UAAU,CAAC;YACpB,CAAC;YACD,MAAM,WAAW,GACf,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC5B,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,SAAS,CAAC,IAAI,CAAC;YAC3C,OAAO,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI;gBAC/C,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,MAAM;gBACzC,WAAW;gBACX,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,UAAU,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrB,OAAO,QAAQ,CAAC;YAClB,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,eAAuB,EACvB,SAA6B;IAE7B,OAAO,8BAA8B,CACnC,sBAAsB,EACtB,eAAe,EACf,iBAAiB,CAAC,SAAS,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAoF;IAEpF,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,0BAA0B,CAClC,kBAAkB,EAClB,kCAAkC,KAAK,CAAC,WAAW,GAAG,CACvD,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,OAA2B;IAC9D,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1E,IACE,UAAU,KAAK,aAAa;QAC5B,CAAC,OAAO,CAAC,mCAAmC,EAC5C,CAAC;QACD,MAAM,IAAI,0BAA0B,CAClC,yBAAyB,EACzB,wCAAwC,OAAO,CAAC,WAAW,GAAG,CAC/D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,0BAA0B,CACvC,OAA2B,EAC3B,KAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU;SACpC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC;SACxC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,IAAI,0BAA0B,CAClC,kBAAkB,EAClB,kCAAkC,OAAO,CAAC,WAAW,GAAG,EACxD,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACL,IAAI,CAAC;QACH,KAAK,CAAC,iBAAiB,GAAG,MAAM,yBAAyB,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACpE,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,0BAA0B,CACvC,OAA2B;IAE3B,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAC3B,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,eAAe,CACxB,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,MAAM,8BAA8B,CAChD,OAAO,CAAC,UAAU,CAAC,sBAAsB,EACzC,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,SAAS,CAClB,CAAC;YACF,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,IAAI,0BAA0B,CAClC,UAAU,EACV,qCAAqC,OAAO,CAAC,WAAW,GAAG,EAC3D,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;QACD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,0BAA0B,CAClC,yBAAyB,EACzB,kDAAkD,OAAO,CAAC,WAAW,GAAG,EACxE,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,OAA2B;IAE3B,MAAM,KAAK,GAAqB;QAC9B,mBAAmB,EAAE,KAAK;QAC1B,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,IAAI,CAAC;QACH,MAAM,0BAA0B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;QAClD,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,IAAI,0BAA0B,CAClC,wBAAwB,EACxB,oDAAoD,OAAO,CAAC,WAAW,GAAG,CAC3E,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC,CAAC;QACnE,MAAM,6BAA6B,CACjC,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,SAAS,EACjB,iBAAiB,EACjB,OAAO,CAAC,WAAW,CACpB,CAAC;QACF,KAAK,CAAC,mBAAmB,GAAG,MAAM,0BAA0B,CAAC,OAAO,CAAC,CAAC;QACtE,IAAI,CAAC,KAAK,CAAC,mBAAmB,EAAE,CAAC;YAC/B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;YACvB,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;YAC5D,MAAM,mBAAmB,CACvB,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,SAAS,EACjB,iBAAiB,EACjB,OAAO,CAAC,WAAW,CACpB,CAAC;YACF,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,2BAA2B,CACxC,OAA2B,EAC3B,KAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,SAAS,GACb,KAAK,CAAC,iBAAiB,KAAK,SAAS;YACnC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,MAAM,8BAA8B,CAClC,OAAO,CAAC,aAAa,EACrB,KAAK,CAAC,iBAAiB,CACxB,CAAC;QACR,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;YACnD,MAAM,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,0BAA0B,CAClC,oBAAoB,EACpB,6CAA6C,OAAO,CAAC,WAAW,GAAG,EACnE,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,OAAO,YAAY,EAAE,CAAC;QACtB,IACE,YAAY,YAAY,0BAA0B;YAClD,YAAY,CAAC,IAAI,KAAK,oBAAoB,EAC1C,CAAC;YACD,MAAM,YAAY,CAAC;QACrB,CAAC;QACD,MAAM,IAAI,0BAA0B,CAClC,gBAAgB,EAChB,yCAAyC,OAAO,CAAC,WAAW,GAAG,EAC/D;YACE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,YAAY;YAClC,YAAY;SACb,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,OAA2B,EAC3B,KAAuB;IAEvB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,0BAA0B,CAClC,eAAe,EACf,mDAAmD,OAAO,CAAC,WAAW,GAAG,CAC1E,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC,KAAK,CAAC;IACpB,CAAC;IACD,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;QAC9B,IACE,CAAC,MAAM,8BAA8B,CACnC,OAAO,CAAC,UAAU,CAAC,sBAAsB,EACzC,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,SAAS,CAClB,CAAC,KAAK,OAAO,EACd,CAAC;YACD,MAAM,IAAI,0BAA0B,CAClC,UAAU,EACV,qCAAqC,OAAO,CAAC,WAAW,GAAG,CAC5D,CAAC;QACJ,CAAC;QACD,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC9D,MAAM,IAAI,0BAA0B,CAClC,wBAAwB,EACxB,+CAA+C,OAAO,CAAC,WAAW,GAAG,CACtE,CAAC;IACJ,CAAC;IACD,MAAM,mBAAmB,CACvB,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,SAAS,EACjB,KAAK,CAAC,iBAAiB,EACvB,OAAO,CAAC,WAAW,CACpB,CAAC;IACF,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAQvC;IACC,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,OAAO,GAAuB;QAClC,mCAAmC,EACjC,OAAO,CAAC,mCAAmC,KAAK,IAAI;QACtD,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,UAAU,EAAE,EAAE,GAAG,cAAc,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE;QACxD,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACjD,SAAS;QACT,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC;IACF,2BAA2B,CACzB,OAAO,CAAC,aAAa,EACrB,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,WAAW,CACpB,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,8BAA8B,CAClD,OAAO,CAAC,UAAU,CAAC,sBAAsB,EACzC,OAAO,CAAC,eAAe,EACvB,OAAO,CAAC,SAAS,CAClB,CAAC;IACF,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IACD,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;QAC3B,MAAM,IAAI,0BAA0B,CAClC,UAAU,EACV,qCAAqC,OAAO,CAAC,WAAW,GAAG,CAC5D,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,2BAA2B,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAClD,OAAO,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type FileHandle } from "node:fs/promises";
2
+ import type { PathIdentityMatch, PortablePathIdentity } from "../../application/model/path-identity.js";
3
+ export type BoundedRegularFileRead = {
4
+ readonly outcome: "read";
5
+ readonly bytes: Buffer;
6
+ readonly identity: PortablePathIdentity;
7
+ readonly mode: number;
8
+ } | {
9
+ readonly outcome: "changed";
10
+ } | {
11
+ readonly outcome: "invalid";
12
+ };
13
+ export type BoundedRegularFileReadFaultInjector = (point: {
14
+ readonly phase: "before-stability-check";
15
+ readonly path: string;
16
+ }) => Promise<void> | void;
17
+ export declare function readBoundedRegularFile(path: string, maximumBytes: number, faultInjector?: BoundedRegularFileReadFaultInjector): Promise<BoundedRegularFileRead>;
18
+ export declare function captureFileHandleIdentity(handle: FileHandle): Promise<PortablePathIdentity>;
19
+ export declare function pathMatchesRegularFileIdentity(path: string, expected: PortablePathIdentity): Promise<PathIdentityMatch>;
20
+ //# sourceMappingURL=node-bounded-regular-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-bounded-regular-file.d.ts","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-bounded-regular-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3E,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,0CAA0C,CAAC;AAElD,MAAM,MAAM,sBAAsB,GAC9B;IACE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GACD;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAAE,GAC/B;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;CAAE,CAAC;AAEpC,MAAM,MAAM,mCAAmC,GAAG,CAAC,KAAK,EAAE;IACxD,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAiF3B,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,aAAa,CAAC,EAAE,mCAAmC,GAClD,OAAO,CAAC,sBAAsB,CAAC,CAkDjC;AAED,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,oBAAoB,CAAC,CAE/B;AAED,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,oBAAoB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAkB5B"}
@@ -0,0 +1,123 @@
1
+ import { constants, lstat, open } from "node:fs/promises";
2
+ function identityFromStat(metadata) {
3
+ return {
4
+ birthtimeNs: metadata.birthtimeNs,
5
+ dev: metadata.dev,
6
+ ino: metadata.ino
7
+ };
8
+ }
9
+ function isMissing(error) {
10
+ return (error instanceof Error &&
11
+ "code" in error &&
12
+ error.code === "ENOENT");
13
+ }
14
+ function hasErrorCode(error, code) {
15
+ return (error instanceof Error &&
16
+ "code" in error &&
17
+ error.code === code);
18
+ }
19
+ async function isExistingNonRegularPath(path) {
20
+ try {
21
+ const metadata = await lstat(path);
22
+ return metadata.isSymbolicLink() || !metadata.isFile();
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ }
28
+ function sameFileObservation(left, right) {
29
+ return (left.dev === right.dev &&
30
+ left.ino === right.ino &&
31
+ left.birthtimeNs === right.birthtimeNs &&
32
+ left.ctimeNs === right.ctimeNs &&
33
+ left.mtimeNs === right.mtimeNs &&
34
+ left.size === right.size);
35
+ }
36
+ async function readAtMost(handle, maximumBytes) {
37
+ const chunks = [];
38
+ let total = 0;
39
+ while (total <= maximumBytes) {
40
+ const remaining = maximumBytes + 1 - total;
41
+ const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, remaining));
42
+ const { bytesRead } = await handle.read(buffer, 0, buffer.byteLength, null);
43
+ if (bytesRead === 0) {
44
+ return Buffer.concat(chunks, total);
45
+ }
46
+ chunks.push(buffer.subarray(0, bytesRead));
47
+ total += bytesRead;
48
+ }
49
+ return undefined;
50
+ }
51
+ export async function readBoundedRegularFile(path, maximumBytes, faultInjector) {
52
+ if (!Number.isSafeInteger(maximumBytes) || maximumBytes < 0) {
53
+ throw new TypeError("maximumBytes must be a non-negative safe integer.");
54
+ }
55
+ if (await isExistingNonRegularPath(path)) {
56
+ return { outcome: "invalid" };
57
+ }
58
+ const noFollow = process.platform === "win32" ? 0 : constants.O_NOFOLLOW;
59
+ const nonBlocking = process.platform === "win32" ? 0 : constants.O_NONBLOCK;
60
+ let handle;
61
+ try {
62
+ handle = await open(path, constants.O_RDONLY | noFollow | nonBlocking);
63
+ }
64
+ catch (error) {
65
+ if (hasErrorCode(error, "ELOOP") ||
66
+ (await isExistingNonRegularPath(path))) {
67
+ return { outcome: "invalid" };
68
+ }
69
+ throw error;
70
+ }
71
+ try {
72
+ const before = await handle.stat({ bigint: true });
73
+ if (!before.isFile() || before.size > BigInt(maximumBytes)) {
74
+ return { outcome: "invalid" };
75
+ }
76
+ const identity = identityFromStat(before);
77
+ const bytes = await readAtMost(handle, maximumBytes);
78
+ if (bytes === undefined) {
79
+ return { outcome: "invalid" };
80
+ }
81
+ await faultInjector?.({ phase: "before-stability-check", path });
82
+ const after = await handle.stat({ bigint: true });
83
+ if (!after.isFile() ||
84
+ !sameFileObservation(before, after) ||
85
+ after.size !== BigInt(bytes.byteLength) ||
86
+ (await pathMatchesRegularFileIdentity(path, identity)) !== "match") {
87
+ return { outcome: "changed" };
88
+ }
89
+ return {
90
+ outcome: "read",
91
+ bytes,
92
+ identity,
93
+ mode: Number(after.mode)
94
+ };
95
+ }
96
+ finally {
97
+ await handle.close();
98
+ }
99
+ }
100
+ export async function captureFileHandleIdentity(handle) {
101
+ return identityFromStat(await handle.stat({ bigint: true }));
102
+ }
103
+ export async function pathMatchesRegularFileIdentity(path, expected) {
104
+ try {
105
+ const metadata = await lstat(path, { bigint: true });
106
+ if (metadata.isSymbolicLink() || !metadata.isFile()) {
107
+ return "different";
108
+ }
109
+ const observed = identityFromStat(metadata);
110
+ return observed.dev === expected.dev &&
111
+ observed.ino === expected.ino &&
112
+ observed.birthtimeNs === expected.birthtimeNs
113
+ ? "match"
114
+ : "different";
115
+ }
116
+ catch (error) {
117
+ if (isMissing(error)) {
118
+ return "missing";
119
+ }
120
+ throw error;
121
+ }
122
+ }
123
+ //# sourceMappingURL=node-bounded-regular-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-bounded-regular-file.js","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-bounded-regular-file.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export type DirectoryDurability = "durable" | "unsupported";
2
+ interface DirectorySyncHandle {
3
+ close(): Promise<void>;
4
+ sync(): Promise<void>;
5
+ }
6
+ interface DirectoryDurabilityOperations {
7
+ readonly open: (path: string) => Promise<DirectorySyncHandle>;
8
+ readonly platform: NodeJS.Platform;
9
+ }
10
+ export declare function syncDirectoryDurably(path: string, operations?: DirectoryDurabilityOperations): Promise<DirectoryDurability>;
11
+ export {};
12
+ //# sourceMappingURL=node-directory-durability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-directory-durability.d.ts","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-directory-durability.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,aAAa,CAAC;AAE5D,UAAU,mBAAmB;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,UAAU,6BAA6B;IACrC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC9D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;CACpC;AAeD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,6BAAiE,GAC5E,OAAO,CAAC,mBAAmB,CAAC,CAkB9B"}
@@ -0,0 +1,32 @@
1
+ import { open } from "node:fs/promises";
2
+ const nodeDirectoryDurabilityOperations = {
3
+ async open(path) {
4
+ return open(path, "r");
5
+ },
6
+ platform: process.platform
7
+ };
8
+ function errorCode(error) {
9
+ return error instanceof Error && "code" in error
10
+ ? error.code
11
+ : undefined;
12
+ }
13
+ export async function syncDirectoryDurably(path, operations = nodeDirectoryDurabilityOperations) {
14
+ try {
15
+ const handle = await operations.open(path);
16
+ try {
17
+ await handle.sync();
18
+ }
19
+ finally {
20
+ await handle.close();
21
+ }
22
+ return "durable";
23
+ }
24
+ catch (error) {
25
+ if (operations.platform === "win32" &&
26
+ ["EACCES", "EINVAL", "EISDIR", "EPERM"].includes(errorCode(error) ?? "")) {
27
+ return "unsupported";
28
+ }
29
+ throw error;
30
+ }
31
+ }
32
+ //# sourceMappingURL=node-directory-durability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-directory-durability.js","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-directory-durability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAcxC,MAAM,iCAAiC,GAAkC;IACvE,KAAK,CAAC,IAAI,CAAC,IAAI;QACb,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,QAAQ,EAAE,OAAO,CAAC,QAAQ;CAC3B,CAAC;AAEF,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK;QAC9C,CAAC,CAAE,KAA+B,CAAC,IAAI;QACvC,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAY,EACZ,UAAU,GAAkC,iCAAiC;IAE7E,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IACE,UAAU,CAAC,QAAQ,KAAK,OAAO;YAC/B,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EACxE,CAAC;YACD,OAAO,aAAa,CAAC;QACvB,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ export type ExistingRepositoryAncestorProblem = "name-collision" | "not-directory" | "outside-root";
2
+ export declare class ExistingRepositoryAncestorError extends Error {
3
+ readonly problem: ExistingRepositoryAncestorProblem;
4
+ readonly existingName: string | undefined;
5
+ readonly requestedName: string | undefined;
6
+ constructor(problem: ExistingRepositoryAncestorProblem, options?: {
7
+ readonly existingName?: string;
8
+ readonly requestedName?: string;
9
+ });
10
+ }
11
+ export declare function assertNoPortableNameCollision(parent: string, requestedName: string, pathIdentity?: (path: string) => string, ordering?: "binary" | "filesystem", readEntries?: (path: string) => Promise<string[]>): Promise<void>;
12
+ export declare function assertSafeExistingRepositoryAncestors(root: string, repositoryPath: string, pathIdentity?: (path: string) => string, ordering?: "binary" | "filesystem"): Promise<void>;
13
+ //# sourceMappingURL=node-existing-repository-ancestors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-existing-repository-ancestors.d.ts","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-existing-repository-ancestors.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iCAAiC,GACzC,gBAAgB,GAChB,eAAe,GACf,cAAc,CAAC;AAEnB,qBAAa,+BAAgC,SAAQ,KAAK;IACxD,QAAQ,CAAC,OAAO,EAAE,iCAAiC,CAAC;IACpD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3C,YACE,OAAO,EAAE,iCAAiC,EAC1C,OAAO,GAAE;QAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAO,EAOlF;CACF;AAUD,wBAAsB,6BAA6B,CACjD,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,YAAY,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAuC,EACvE,QAAQ,GAAE,QAAQ,GAAG,YAAuB,EAC5C,WAAW,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAW,GACzD,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,qCAAqC,CACzD,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,YAAY,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAuC,EACvE,QAAQ,GAAE,QAAQ,GAAG,YAAuB,GAC3C,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
@@ -0,0 +1,67 @@
1
+ import { lstat, readdir, realpath } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { portableRepositoryPathIdentity } from "../../application/model/repository-path.js";
4
+ import { isLexicallyContainedPath } from "./node-repository-path.js";
5
+ export class ExistingRepositoryAncestorError extends Error {
6
+ problem;
7
+ existingName;
8
+ requestedName;
9
+ constructor(problem, options = {}) {
10
+ super(`Existing repository ancestor is unsafe: ${problem}.`);
11
+ this.name = "ExistingRepositoryAncestorError";
12
+ this.problem = problem;
13
+ this.existingName = options.existingName;
14
+ this.requestedName = options.requestedName;
15
+ }
16
+ }
17
+ function isMissing(error) {
18
+ return (error instanceof Error &&
19
+ "code" in error &&
20
+ error.code === "ENOENT");
21
+ }
22
+ export async function assertNoPortableNameCollision(parent, requestedName, pathIdentity = portableRepositoryPathIdentity, ordering = "binary", readEntries = readdir) {
23
+ const observedEntries = await readEntries(parent).catch((error) => {
24
+ if (isMissing(error)) {
25
+ return [];
26
+ }
27
+ throw error;
28
+ });
29
+ const entries = ordering === "binary"
30
+ ? observedEntries.toSorted((left, right) => Buffer.compare(Buffer.from(left), Buffer.from(right)))
31
+ : observedEntries;
32
+ const requestedIdentity = pathIdentity(requestedName);
33
+ const collision = entries.find((entry) => entry !== requestedName && pathIdentity(entry) === requestedIdentity);
34
+ if (collision !== undefined) {
35
+ throw new ExistingRepositoryAncestorError("name-collision", {
36
+ existingName: collision,
37
+ requestedName
38
+ });
39
+ }
40
+ }
41
+ export async function assertSafeExistingRepositoryAncestors(root, repositoryPath, pathIdentity = portableRepositoryPathIdentity, ordering = "binary") {
42
+ const segments = repositoryPath.split("/");
43
+ let current = root;
44
+ for (const segment of segments.slice(0, -1)) {
45
+ await assertNoPortableNameCollision(current, segment, pathIdentity, ordering);
46
+ const next = join(current, segment);
47
+ const metadata = await lstat(next).catch((error) => {
48
+ if (isMissing(error)) {
49
+ return null;
50
+ }
51
+ throw error;
52
+ });
53
+ if (metadata === null) {
54
+ return;
55
+ }
56
+ if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
57
+ throw new ExistingRepositoryAncestorError("not-directory");
58
+ }
59
+ const canonical = await realpath(next);
60
+ if (!isLexicallyContainedPath(root, canonical)) {
61
+ throw new ExistingRepositoryAncestorError("outside-root");
62
+ }
63
+ current = canonical;
64
+ }
65
+ await assertNoPortableNameCollision(current, segments.at(-1) ?? "", pathIdentity, ordering);
66
+ }
67
+ //# sourceMappingURL=node-existing-repository-ancestors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-existing-repository-ancestors.js","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-existing-repository-ancestors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function isLexicallyContainedPath(root: string, candidate: string): boolean;
2
+ //# sourceMappingURL=node-repository-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-repository-path.d.ts","sourceRoot":"","sources":["../../../../src/repository-mutation/adapters/node/node-repository-path.ts"],"names":[],"mappings":"AAEA,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAMjF"}