chore(node-sdk): audit plugins shared
Add plugins/common.ts for the helpers and size limits copied across plugin files; managed-transaction compares snapshots in one place; guard template imported directly. Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
This commit is contained in:
1 parent
07f32a48d7
commit
b7f14ba34b
9 files changed
+55
-87
No files matched your search
@@ -2,14 +2,13 @@ import { randomUUID } from 'node:crypto';
|
||||
import fsp from 'node:fs/promises';
|
||||
import type { FileHandle } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { asError, errorMessage, hasCode, MAX_SOURCE_BYTES } from './common.js';
|
||||
import {
|
||||
inspectPhysicalDirectory,
|
||||
readPhysicalFile,
|
||||
type FileSnapshot,
|
||||
} from './managed-files.js';
|
||||
|
||||
const MAX_SOURCE_BYTES = 2 * 1024 * 1024;
|
||||
|
||||
export interface ManagedChangeSpec {
|
||||
readonly filePath: string;
|
||||
readonly label: string;
|
||||
@@ -60,18 +59,6 @@ interface StagedChange {
|
||||
|
||||
export type RenameFile = (source: string, destination: string) => Promise<void>;
|
||||
|
||||
function asError(error: unknown): Error {
|
||||
return error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
||||
function hasCode(error: unknown, code: string): boolean {
|
||||
return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
|
||||
}
|
||||
|
||||
function targetKey(filePath: string): string {
|
||||
const resolved = path.resolve(filePath);
|
||||
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
||||
@@ -113,16 +100,20 @@ export async function prepareManagedFileChange(
|
||||
};
|
||||
}
|
||||
|
||||
async function assertUnchanged(change: ManagedFileChange, operationName: string): Promise<void> {
|
||||
const current = await readPhysicalFile(change.filePath, change.label, change.maximumBytes);
|
||||
if ((!current && change.original)
|
||||
|| (current && !change.original)
|
||||
|| (current && change.original && (
|
||||
current.contents !== change.original.contents
|
||||
|| current.device !== change.original.device
|
||||
|| current.inode !== change.original.inode
|
||||
))) {
|
||||
throw new Error(`${change.label} changed during ${operationName}: ${change.filePath}`);
|
||||
function sameSnapshot(current: FileSnapshot | undefined, original: FileSnapshot | undefined): boolean {
|
||||
if (!current || !original) return !current && !original;
|
||||
return current.contents === original.contents
|
||||
&& current.device === original.device
|
||||
&& current.inode === original.inode;
|
||||
}
|
||||
|
||||
async function assertUnchanged(
|
||||
target: ManagedFilePrecondition,
|
||||
operationName: string,
|
||||
): Promise<void> {
|
||||
const current = await readPhysicalFile(target.filePath, target.label, target.maximumBytes);
|
||||
if (!sameSnapshot(current, target.original)) {
|
||||
throw new Error(`${target.label} changed during ${operationName}: ${target.filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,20 +122,7 @@ async function assertPreconditions(
|
||||
operationName: string,
|
||||
): Promise<void> {
|
||||
for (const condition of transaction.preconditions ?? []) {
|
||||
const current = await readPhysicalFile(
|
||||
condition.filePath,
|
||||
condition.label,
|
||||
condition.maximumBytes,
|
||||
);
|
||||
if ((!current && condition.original)
|
||||
|| (current && !condition.original)
|
||||
|| (current && condition.original && (
|
||||
current.contents !== condition.original.contents
|
||||
|| current.device !== condition.original.device
|
||||
|| current.inode !== condition.original.inode
|
||||
))) {
|
||||
throw new Error(`${condition.label} changed during ${operationName}: ${condition.filePath}`);
|
||||
}
|
||||
await assertUnchanged(condition, operationName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,11 +263,7 @@ async function assertCommittedUnchanged(staged: StagedChange): Promise<void> {
|
||||
}
|
||||
return;
|
||||
}
|
||||
const committed = staged.committedSnapshot;
|
||||
if (!current || !committed
|
||||
|| current.contents !== committed.contents
|
||||
|| current.device !== committed.device
|
||||
|| current.inode !== committed.inode) {
|
||||
if (!current || !sameSnapshot(current, staged.committedSnapshot)) {
|
||||
throw new Error(
|
||||
`${staged.change.label} changed during transaction recovery: ${staged.change.filePath}`,
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user