mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 08:47:00 +00:00
fix(setup): preserve the selected destination during configuration publication
Replace configuration-specific write-file-atomic delegation with a verified input snapshot, exclusive private staging, and an explicit canonical-parent destination. Existing files publish by rename; first-run files use an exclusive link so a newly created destination is retained. Both consumers read back the publication owner's selected path. Retain descriptor and staging cleanup capabilities through recovery and host retry. Preserve mode and ownership, remove temporary permission handoffs, and use positional restoration writes. Keep UTF-8 diagnostics with failed cleanup. Validation: 284 focused tests passed, one skipped across 14 files; check:fast, format:check, docs:check (including five consistency tests), two source reviews, and 12 completed isolated public CLI setup/uninstall cost controls passed. Native Windows/Linux, real editor concurrency, and providers were not verified. Final-check/publication races and same-inode concurrent writers remain unexcluded. Fixes #4904
This commit is contained in:
1 parent
2fb5e204a3
commit
d0253c99d6
12 files changed
+771
-215
No files matched your search
@@ -188,25 +188,36 @@ export const readRegularFileText = (
|
||||
path: string,
|
||||
options: RegularFileReadOptions = {},
|
||||
): Promise<string> =>
|
||||
readRegularFileContent(path, (bytes) => decodeFileText(path, bytes), options);
|
||||
|
||||
/** Retain the read owner's verified file state together with its decoded text. */
|
||||
export const readRegularFileTextSnapshot = (
|
||||
path: string,
|
||||
options: RegularFileReadOptions = {},
|
||||
): Promise<{ readonly text: string; readonly state: Stats }> =>
|
||||
readRegularFileContent(
|
||||
path,
|
||||
(bytes) => {
|
||||
try {
|
||||
return new TextDecoder("utf-8", {
|
||||
fatal: true,
|
||||
ignoreBOM: true,
|
||||
}).decode(bytes);
|
||||
} catch (cause: unknown) {
|
||||
if (!(cause instanceof TypeError)) throw cause;
|
||||
throw new InvalidUtf8FileError(path, cause);
|
||||
}
|
||||
},
|
||||
(bytes, state) => ({
|
||||
text: decodeFileText(path, bytes),
|
||||
state,
|
||||
}),
|
||||
options,
|
||||
);
|
||||
|
||||
const decodeFileText = (path: string, bytes: Buffer): string => {
|
||||
try {
|
||||
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(
|
||||
bytes,
|
||||
);
|
||||
} catch (cause: unknown) {
|
||||
if (!(cause instanceof TypeError)) throw cause;
|
||||
throw new InvalidUtf8FileError(path, cause);
|
||||
}
|
||||
};
|
||||
|
||||
const readRegularFileContent = <Value>(
|
||||
path: string,
|
||||
decode: (bytes: Buffer) => Value,
|
||||
decode: (bytes: Buffer, state: Stats) => Value,
|
||||
options: RegularFileReadOptions,
|
||||
): Promise<Value> =>
|
||||
withRegularFile(
|
||||
@@ -219,7 +230,7 @@ const readRegularFileContent = <Value>(
|
||||
);
|
||||
if (bytes === undefined || bytes.length !== stats.size)
|
||||
throw new RegularFileChangedError(path);
|
||||
return decode(bytes);
|
||||
return decode(bytes, stats);
|
||||
},
|
||||
options,
|
||||
);
|
||||
Reference in new issue
Block a user