feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,226 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { randomBytes } from 'crypto';
import {
assertCompletionReceiptId,
InvalidCompletionReceiptError,
MAX_COMPLETION_RECEIPT_BYTES,
parseCompletionReceipt,
serializeCompletionReceipt,
type CompletionReceipt,
} from '../../domain/completionReceipt';
import type { CompletionReceiptStore } from '../../ports/completionReceiptStore';
export class CompletionReceiptAlreadyExistsError extends Error {
constructor(readonly attemptId: string) {
super(`Completion receipt already exists for Attempt ${attemptId}`);
this.name = 'CompletionReceiptAlreadyExistsError';
}
}
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
/**
* A bounded local journal. It does not scan directories or own a lifecycle;
* callers must discover active Attempts from the database.
*/
export class CompletionReceiptFileStore implements CompletionReceiptStore {
constructor(private readonly root: string) {
if (!path.isAbsolute(root)) {
throw new RangeError('Completion receipt root must be absolute');
}
}
async publish(receipt: CompletionReceipt): Promise<void> {
const serialized = serializeCompletionReceipt(receipt);
const directory = this.directory(receipt.attemptId);
const target = this.target(receipt.attemptId);
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
const temporary = path.join(
directory,
`.${receipt.attemptId}.${randomBytes(16).toString('hex')}.tmp`,
);
let handle: fs.FileHandle | undefined;
try {
handle = await fs.open(temporary, 'wx', 0o600);
await handle.writeFile(serialized, 'utf8');
await handle.sync();
await handle.close();
handle = undefined;
// A hard link publishes the fully written inode atomically and, unlike
// plain rename(), never replaces an existing completion fact.
try {
await fs.link(temporary, target);
} catch (error) {
if (isCode(error, 'EEXIST')) {
throw new CompletionReceiptAlreadyExistsError(receipt.attemptId);
}
throw error;
}
await this.bestEffortUnlink(temporary);
await this.bestEffortSyncDirectory(directory);
} catch (error) {
await handle?.close().catch(() => undefined);
await this.bestEffortUnlink(temporary);
throw error;
}
}
async read(attemptId: string): Promise<CompletionReceipt | undefined> {
const target = this.target(attemptId);
let handle: fs.FileHandle;
try {
handle = await fs.open(
target,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
} catch (error) {
if (isCode(error, 'ENOENT')) return undefined;
if (isCode(error, 'ELOOP')) {
throw new InvalidCompletionReceiptError(
'Completion receipt must not be a symbolic link',
);
}
throw error;
}
try {
const stat = await handle.stat();
if (!stat.isFile()) {
throw new InvalidCompletionReceiptError(
'Completion receipt must be a regular file',
);
}
const bytes = Buffer.allocUnsafe(MAX_COMPLETION_RECEIPT_BYTES + 1);
const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
if (bytesRead > MAX_COMPLETION_RECEIPT_BYTES) {
throw new InvalidCompletionReceiptError(
'Completion receipt exceeds the byte limit',
);
}
const receipt = parseCompletionReceipt(bytes.subarray(0, bytesRead));
if (receipt.attemptId !== attemptId) {
throw new InvalidCompletionReceiptError(
'Completion receipt path and Attempt do not match',
);
}
return receipt;
} finally {
await handle.close();
}
}
async remove(attemptId: string): Promise<boolean> {
const target = this.target(attemptId);
try {
await fs.unlink(target);
await this.bestEffortSyncDirectory(path.dirname(target));
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
throw error;
}
}
async quarantine(attemptId: string): Promise<string | undefined> {
const target = this.target(attemptId);
const reference = this.quarantineReference(attemptId);
const relativeDirectory = path.dirname(reference);
const directory = path.join(this.root, relativeDirectory);
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
await fs.chmod(directory, 0o700);
const quarantined = path.join(this.root, reference);
try {
await fs.link(target, quarantined);
} catch (error) {
if (isCode(error, 'ENOENT')) {
return (await this.pathExists(quarantined)) ? reference : undefined;
}
if (!isCode(error, 'EEXIST')) throw error;
}
await this.unlinkIfPresent(target);
await this.bestEffortSyncDirectory(path.dirname(target));
await this.bestEffortSyncDirectory(directory);
return reference;
}
quarantineReference(attemptId: string): string {
assertCompletionReceiptId(attemptId, 'attemptId');
return path.posix.join(
'.quarantine',
attemptId.slice(0, 2),
`${attemptId}.json`,
);
}
async purgeQuarantine(attemptId: string): Promise<boolean> {
const target = path.join(this.root, this.quarantineReference(attemptId));
try {
await fs.unlink(target);
await this.bestEffortSyncDirectory(path.dirname(target));
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
throw error;
}
}
private directory(attemptId: string): string {
assertCompletionReceiptId(attemptId, 'attemptId');
return path.join(this.root, attemptId.slice(0, 2));
}
private target(attemptId: string): string {
return path.join(this.directory(attemptId), `${attemptId}.json`);
}
private async bestEffortUnlink(value: string): Promise<void> {
try {
await fs.unlink(value);
} catch (error) {
if (!isCode(error, 'ENOENT')) {
// Temp cleanup is diagnostic-only; the immutable final fact wins.
}
}
}
private async unlinkIfPresent(value: string): Promise<void> {
try {
await fs.unlink(value);
} catch (error) {
if (!isCode(error, 'ENOENT')) throw error;
}
}
private async pathExists(value: string): Promise<boolean> {
try {
await fs.lstat(value);
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
throw error;
}
}
private async bestEffortSyncDirectory(directory: string): Promise<void> {
try {
const handle = await fs.open(directory, constants.O_RDONLY);
try {
await handle.sync();
} finally {
await handle.close();
}
} catch {
// Some supported filesystems cannot fsync directories. The receipt
// remains restart-safe, while power-loss durability is best effort.
}
}
}
@@ -0,0 +1,302 @@
import { createHash } from 'crypto';
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { assertCompletionReceiptId } from '../../domain/completionReceipt';
import type {
CompletionReceiptDirectoryEntry,
CompletionReceiptDirectoryEntryKind,
CompletionReceiptOrphanDirectory,
CompletionReceiptOrphanQuarantineResult,
CompletionReceiptShardSnapshot,
} from '../../ports/completionReceiptOrphanMaintenance';
const SHARD_PATTERN = /^[0-9a-f]{2}$/;
const TEMPORARY_PATTERN = /^\.([0-9a-f-]{36})\.[0-9a-f]{32}\.tmp$/;
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
function receiptAttemptId(name: string): string | undefined {
if (!name.endsWith('.json')) return undefined;
const attemptId = name.slice(0, -'.json'.length);
try {
assertCompletionReceiptId(attemptId, 'attemptId');
return attemptId;
} catch {
return undefined;
}
}
function temporaryAttemptId(name: string): string | undefined {
const match = TEMPORARY_PATTERN.exec(name);
if (!match) return undefined;
try {
assertCompletionReceiptId(match[1], 'attemptId');
return match[1];
} catch {
return undefined;
}
}
function entryKind(
shard: string,
name: string,
regularFile: boolean,
): { kind: CompletionReceiptDirectoryEntryKind; attemptId?: string } {
if (!regularFile) return { kind: 'unsafe' };
const finalAttemptId = receiptAttemptId(name);
if (finalAttemptId && finalAttemptId.startsWith(shard)) {
return { kind: 'receipt', attemptId: finalAttemptId };
}
const tempAttemptId = temporaryAttemptId(name);
if (tempAttemptId && tempAttemptId.startsWith(shard)) {
return { kind: 'temporary', attemptId: tempAttemptId };
}
return { kind: 'unknown' };
}
function filesystemIdentity(
stat: Awaited<ReturnType<typeof fs.lstat>>,
): string {
return [stat.dev, stat.ino, stat.size, stat.mtimeMs].join(':');
}
export class CompletionReceiptOrphanFileDirectory
implements CompletionReceiptOrphanDirectory
{
constructor(private readonly root: string) {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new RangeError(
'Completion receipt orphan root must be an absolute path containing no NUL',
);
}
if (path.resolve(root) === path.parse(path.resolve(root)).root) {
throw new RangeError(
'Completion receipt orphan root must not be a filesystem root',
);
}
}
async inspectShard(
shard: string,
maxEntries: number,
): Promise<CompletionReceiptShardSnapshot> {
if (!SHARD_PATTERN.test(shard)) {
throw new RangeError(
'Completion receipt shard must be two lowercase hex digits',
);
}
if (
!Number.isSafeInteger(maxEntries) ||
maxEntries < 1 ||
maxEntries > 64
) {
throw new RangeError('maxEntries must be between 1 and 64');
}
const directoryPath = await this.resolveShardDirectory(shard);
if (!directoryPath) return { shard, entries: [], overflow: false };
const directory = await fs.opendir(directoryPath, { bufferSize: 1 });
const entries: CompletionReceiptDirectoryEntry[] = [];
let overflow = false;
try {
for await (const dirent of directory) {
if (entries.length === maxEntries) {
overflow = true;
break;
}
const entryPath = path.join(directoryPath, dirent.name);
let stat: Awaited<ReturnType<typeof fs.lstat>>;
try {
stat = await fs.lstat(entryPath);
} catch (error) {
if (isCode(error, 'ENOENT')) continue;
throw error;
}
const classified = entryKind(shard, dirent.name, stat.isFile());
entries.push({
shard,
name: dirent.name,
kind: classified.kind,
modifiedAtMs: Math.max(0, Math.trunc(stat.mtimeMs)),
sizeBytes: stat.size,
filesystemIdentity: filesystemIdentity(stat),
...(classified.attemptId ? { attemptId: classified.attemptId } : {}),
});
}
} finally {
await directory.close().catch((error) => {
if (!isCode(error, 'ERR_DIR_CLOSED')) throw error;
});
}
return { shard, entries, overflow };
}
async quarantine(
entry: CompletionReceiptDirectoryEntry,
): Promise<CompletionReceiptOrphanQuarantineResult> {
if (
!SHARD_PATTERN.test(entry.shard) ||
path.basename(entry.name) !== entry.name
) {
throw new RangeError('Completion receipt orphan entry path is invalid');
}
if (entry.kind === 'unsafe') return { status: 'changed' };
const shardDirectory = await this.resolveShardDirectory(entry.shard);
if (!shardDirectory) return { status: 'changed' };
const source = path.join(shardDirectory, entry.name);
let current: Awaited<ReturnType<typeof fs.lstat>>;
try {
current = await fs.lstat(source);
} catch (error) {
if (isCode(error, 'ENOENT')) return { status: 'changed' };
throw error;
}
if (
!current.isFile() ||
filesystemIdentity(current) !== entry.filesystemIdentity
) {
return { status: 'changed' };
}
const digest = createHash('sha256')
.update(`${entry.shard}/${entry.name}\0${entry.filesystemIdentity}`)
.digest('hex');
const reference = path.posix.join(
'.orphan-quarantine',
entry.shard,
`${digest}.entry`,
);
const canonicalRoot = path.dirname(shardDirectory);
const directory = await this.ensureQuarantineDirectory(
canonicalRoot,
entry.shard,
);
const target = path.join(directory, `${digest}.entry`);
let linkedByThisCall = false;
try {
await fs.link(source, target);
linkedByThisCall = true;
} catch (error) {
if (!isCode(error, 'EEXIST')) {
if (isCode(error, 'ENOENT')) return { status: 'changed' };
throw error;
}
const targetStat = await fs.lstat(target);
const sourceStat = await fs.lstat(source).catch(() => undefined);
if (
!sourceStat ||
targetStat.dev !== sourceStat.dev ||
targetStat.ino !== sourceStat.ino
) {
return { status: 'changed' };
}
}
let verifiedShardDirectory: string | undefined;
try {
verifiedShardDirectory = await this.resolveShardDirectory(entry.shard);
} catch (error) {
if (linkedByThisCall) await fs.unlink(target).catch(() => undefined);
throw error;
}
const verifiedSource = await fs.lstat(source).catch(() => undefined);
if (
verifiedShardDirectory !== shardDirectory ||
!verifiedSource ||
filesystemIdentity(verifiedSource) !== entry.filesystemIdentity
) {
if (linkedByThisCall) await fs.unlink(target).catch(() => undefined);
return { status: 'changed' };
}
await fs.unlink(source);
await this.bestEffortSync(path.dirname(source));
await this.bestEffortSync(directory);
return { status: 'quarantined', reference };
}
private async resolveShardDirectory(
shard: string,
): Promise<string | undefined> {
let canonicalRoot: string;
try {
canonicalRoot = await fs.realpath(this.root);
} catch (error) {
if (isCode(error, 'ENOENT')) return undefined;
throw error;
}
const candidate = path.join(canonicalRoot, shard);
let stat: Awaited<ReturnType<typeof fs.lstat>>;
try {
stat = await fs.lstat(candidate);
} catch (error) {
if (isCode(error, 'ENOENT')) return undefined;
throw error;
}
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new Error(
`Completion receipt shard ${shard} is not a safe directory`,
);
}
const canonicalDirectory = await fs.realpath(candidate);
if (
path.dirname(canonicalDirectory) !== canonicalRoot ||
path.basename(canonicalDirectory) !== shard
) {
throw new Error(`Completion receipt shard ${shard} escapes its root`);
}
return canonicalDirectory;
}
private async ensureQuarantineDirectory(
canonicalRoot: string,
shard: string,
): Promise<string> {
const quarantineRoot = path.join(canonicalRoot, '.orphan-quarantine');
await this.ensurePrivateDirectory(quarantineRoot, canonicalRoot);
const directory = path.join(quarantineRoot, shard);
await this.ensurePrivateDirectory(directory, quarantineRoot);
return directory;
}
private async ensurePrivateDirectory(
directory: string,
expectedParent: string,
): Promise<void> {
try {
await fs.mkdir(directory, { mode: 0o700 });
} catch (error) {
if (!isCode(error, 'EEXIST')) throw error;
}
const stat = await fs.lstat(directory);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new Error(
'Completion receipt quarantine path is not a safe directory',
);
}
const canonicalDirectory = await fs.realpath(directory);
if (path.dirname(canonicalDirectory) !== expectedParent) {
throw new Error('Completion receipt quarantine path escapes its root');
}
await fs.chmod(directory, 0o700);
}
private async bestEffortSync(directory: string): Promise<void> {
try {
const handle = await fs.open(directory, constants.O_RDONLY);
try {
await handle.sync();
} finally {
await handle.close();
}
} catch {
// Directory fsync is unavailable on some supported filesystems.
}
}
}
@@ -0,0 +1,122 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { normalizeLocalArtifactReadRange } from '../../domain/artifactRead';
import { assertLocalExecutionArtifactId } from '../../domain/localExecutionArtifact';
import type {
AvailableLocalArtifactByteRange,
LocalArtifactByteRangeReadResult,
LocalArtifactByteRangeReader as LocalArtifactByteRangeReaderPort,
} from '../../ports/localArtifactByteRangeReader';
export class UnsafeLocalArtifactReadTargetError extends Error {
constructor() {
super('Local Artifact read target is unsafe');
this.name = 'UnsafeLocalArtifactReadTargetError';
}
}
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
export class LocalArtifactByteRangeReader
implements LocalArtifactByteRangeReaderPort
{
private readonly root: string;
constructor(root: string) {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new TypeError('Local Artifact read root must be absolute');
}
this.root = path.resolve(root);
}
async read(
logArtifactId: string,
requestedRange: Parameters<LocalArtifactByteRangeReaderPort['read']>[1],
): Promise<LocalArtifactByteRangeReadResult> {
assertLocalExecutionArtifactId(logArtifactId);
const range = normalizeLocalArtifactReadRange(requestedRange);
const directory = path.join(this.root, logArtifactId.slice(6, 8));
await this.assertDirectory(this.root);
if (!(await this.optionalDirectory(directory)))
return { status: 'missing' };
const target = path.join(directory, `${logArtifactId}.log`);
let handle;
try {
handle = await fs.open(
target,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
} catch (error) {
if (isCode(error, 'ENOENT')) return { status: 'missing' };
throw new UnsafeLocalArtifactReadTargetError();
}
try {
const stat = await handle.stat();
if (!stat.isFile() || !Number.isSafeInteger(stat.size) || stat.size < 0) {
throw new UnsafeLocalArtifactReadTargetError();
}
const start = Math.min(range.offset, stat.size);
const expected = Math.min(range.length, stat.size - start);
const content = Buffer.allocUnsafe(expected);
let read = 0;
while (read < expected) {
const result = await handle.read(
content,
read,
expected - read,
start + read,
);
if (result.bytesRead < 1) {
throw new UnsafeLocalArtifactReadTargetError();
}
read += result.bytesRead;
}
const endExclusive = start + expected;
const result: AvailableLocalArtifactByteRange = {
status: 'available',
content,
start,
endExclusive,
totalBytes: stat.size,
...(endExclusive < stat.size ? { nextOffset: endExclusive } : {}),
};
return Object.freeze(result);
} finally {
await handle.close();
}
}
private async assertDirectory(value: string): Promise<void> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactReadTargetError();
}
} catch (error) {
if (error instanceof UnsafeLocalArtifactReadTargetError) throw error;
throw new UnsafeLocalArtifactReadTargetError();
}
}
private async optionalDirectory(value: string): Promise<boolean> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactReadTargetError();
}
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
if (error instanceof UnsafeLocalArtifactReadTargetError) throw error;
throw new UnsafeLocalArtifactReadTargetError();
}
}
}
@@ -0,0 +1,179 @@
import { constants, type Stats } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { MAX_LOCAL_ARTIFACT_TRUNCATION_FACT_BYTES } from '../../domain/localArtifactTruncation';
import { assertLocalExecutionArtifactId } from '../../domain/localExecutionArtifact';
import type {
LocalArtifactFileRetirementResult,
LocalArtifactFileRetirementStore as LocalArtifactFileRetirementStorePort,
} from '../../ports/localArtifactFileRetirementStore';
import { localArtifactTruncationFactFileName } from './localArtifactTruncationFactStore';
export class UnsafeLocalArtifactRetirementError extends Error {
constructor() {
super('Local Artifact retirement target is unsafe');
this.name = 'UnsafeLocalArtifactRetirementError';
}
}
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
export class LocalArtifactFileRetirementStore
implements LocalArtifactFileRetirementStorePort
{
private readonly root: string;
constructor(root: string) {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new TypeError('Local Artifact retirement root must be absolute');
}
this.root = path.resolve(root);
}
async retire(
logArtifactId: string,
): Promise<LocalArtifactFileRetirementResult> {
assertLocalExecutionArtifactId(logArtifactId);
const directory = path.join(this.root, logArtifactId.slice(6, 8));
await this.assertDirectory(this.root);
if (!(await this.optionalDirectory(directory))) {
return Object.freeze({
disposition: 'already_absent',
bytesReclaimed: 0,
});
}
const target = path.join(directory, `${logArtifactId}.log`);
const fifo = path.join(directory, `.${logArtifactId}.log.fifo`);
const truncation = path.join(
directory,
localArtifactTruncationFactFileName(logArtifactId),
);
const truncationTemporary = path.join(
directory,
`.${logArtifactId}.log.truncated.tmp`,
);
const [targetStat, fifoStat, truncationStat, truncationTemporaryStat] =
await Promise.all([
this.lstat(target),
this.lstat(fifo),
this.lstat(truncation),
this.lstat(truncationTemporary),
]);
if (targetStat && (!targetStat.isFile() || targetStat.isSymbolicLink())) {
throw new UnsafeLocalArtifactRetirementError();
}
if (
targetStat &&
(!Number.isSafeInteger(targetStat.size) || targetStat.size < 0)
) {
throw new UnsafeLocalArtifactRetirementError();
}
if (fifoStat && (!fifoStat.isFIFO() || fifoStat.isSymbolicLink())) {
throw new UnsafeLocalArtifactRetirementError();
}
for (const stat of [truncationStat, truncationTemporaryStat]) {
if (
stat &&
(!stat.isFile() ||
stat.isSymbolicLink() ||
!Number.isSafeInteger(stat.size) ||
stat.size < 0 ||
stat.size > MAX_LOCAL_ARTIFACT_TRUNCATION_FACT_BYTES)
) {
throw new UnsafeLocalArtifactRetirementError();
}
}
let targetDeleted = false;
let bytesReclaimed = 0;
if (targetStat) {
try {
await fs.unlink(target);
targetDeleted = true;
bytesReclaimed = targetStat.size;
} catch (error) {
if (!isCode(error, 'ENOENT')) throw error;
}
}
let auxiliaryRemoved = false;
for (const [auxiliary, stat] of [
[fifo, fifoStat],
[truncation, truncationStat],
[truncationTemporary, truncationTemporaryStat],
] as const) {
if (!stat) continue;
try {
await fs.unlink(auxiliary);
auxiliaryRemoved = true;
} catch (error) {
if (!isCode(error, 'ENOENT')) throw error;
}
}
if (targetDeleted || auxiliaryRemoved) {
await this.syncDirectory(directory);
}
if (!targetDeleted) {
return Object.freeze({
disposition: 'already_absent',
bytesReclaimed: 0,
});
}
return Object.freeze({
disposition: 'deleted',
bytesReclaimed,
});
}
private async assertDirectory(value: string): Promise<void> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactRetirementError();
}
} catch (error) {
if (error instanceof UnsafeLocalArtifactRetirementError) throw error;
throw new UnsafeLocalArtifactRetirementError();
}
}
private async optionalDirectory(value: string): Promise<boolean> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactRetirementError();
}
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
if (error instanceof UnsafeLocalArtifactRetirementError) throw error;
throw new UnsafeLocalArtifactRetirementError();
}
}
private async lstat(value: string): Promise<Stats | null> {
try {
return await fs.lstat(value);
} catch (error) {
if (isCode(error, 'ENOENT')) return null;
throw error;
}
}
private async syncDirectory(directory: string): Promise<void> {
const handle = await fs.open(
directory,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
try {
await handle.sync();
} finally {
await handle.close();
}
}
}
@@ -0,0 +1,113 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import {
decodeLocalArtifactTruncationFact,
MAX_LOCAL_ARTIFACT_TRUNCATION_FACT_BYTES,
type LocalArtifactTruncationFact,
} from '../../domain/localArtifactTruncation';
import { assertLocalExecutionArtifactId } from '../../domain/localExecutionArtifact';
import type { LocalArtifactTruncationFactStore as LocalArtifactTruncationFactStorePort } from '../../ports/localArtifactTruncationFactStore';
export function localArtifactTruncationFactFileName(
logArtifactId: string,
): string {
assertLocalExecutionArtifactId(logArtifactId);
return `.${logArtifactId}.log.truncated.json`;
}
export class UnsafeLocalArtifactTruncationFactError extends Error {
constructor() {
super('Local Artifact truncation fact target is unsafe');
this.name = 'UnsafeLocalArtifactTruncationFactError';
}
}
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
export class LocalArtifactTruncationFactStore
implements LocalArtifactTruncationFactStorePort
{
private readonly root: string;
constructor(root: string) {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new TypeError('Local Artifact truncation root must be absolute');
}
this.root = path.resolve(root);
}
async read(
logArtifactId: string,
): Promise<Readonly<LocalArtifactTruncationFact> | null> {
assertLocalExecutionArtifactId(logArtifactId);
const directory = path.join(this.root, logArtifactId.slice(6, 8));
await this.assertDirectory(this.root);
if (!(await this.optionalDirectory(directory))) return null;
const target = path.join(
directory,
localArtifactTruncationFactFileName(logArtifactId),
);
let handle;
try {
handle = await fs.open(
target,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
} catch (error) {
if (isCode(error, 'ENOENT')) return null;
throw new UnsafeLocalArtifactTruncationFactError();
}
try {
const stat = await handle.stat();
if (
!stat.isFile() ||
!Number.isSafeInteger(stat.size) ||
stat.size < 1 ||
stat.size > MAX_LOCAL_ARTIFACT_TRUNCATION_FACT_BYTES
) {
throw new UnsafeLocalArtifactTruncationFactError();
}
const fact = decodeLocalArtifactTruncationFact(await handle.readFile());
if (fact.logArtifactId !== logArtifactId) {
throw new UnsafeLocalArtifactTruncationFactError();
}
return fact;
} finally {
await handle.close();
}
}
private async assertDirectory(value: string): Promise<void> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactTruncationFactError();
}
} catch (error) {
if (error instanceof UnsafeLocalArtifactTruncationFactError) throw error;
throw new UnsafeLocalArtifactTruncationFactError();
}
}
private async optionalDirectory(value: string): Promise<boolean> {
try {
const stat = await fs.lstat(value);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new UnsafeLocalArtifactTruncationFactError();
}
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
if (error instanceof UnsafeLocalArtifactTruncationFactError) throw error;
throw new UnsafeLocalArtifactTruncationFactError();
}
}
}
@@ -0,0 +1,175 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import type {
ExecutionOutputChunk,
ExecutionOutputSink,
} from '../../domain/execution';
import {
LocalArtifactCapacityUnavailableError,
LocalArtifactQuotaExceededError,
normalizeLocalArtifactCapacityPolicy,
type LocalArtifactCapacityPolicy,
} from '../../domain/localArtifactCapacity';
import {
localExecutionArtifactId,
assertLocalExecutionArtifactId,
} from '../../domain/localExecutionArtifact';
import type { RunDispatchCandidate } from '../../domain/runDispatchCandidate';
import type {
LocalExecutionArtifactAllocator,
PreparedLocalExecutionArtifact,
} from '../../ports/localExecutionArtifactAllocator';
import type { LocalArtifactCapacityProbe } from '../../ports/localArtifactCapacityProbe';
import { LocalFileSystemCapacityProbe } from './localFileSystemCapacityProbe';
import { enableDurableLocalProcessOutput } from '../local-process/durableLocalProcessOutput';
async function privateDirectory(directory: string): Promise<void> {
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
const stat = await fs.lstat(directory);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new TypeError('Local execution artifact directory is unsafe');
}
await fs.chmod(directory, 0o700);
}
class LocalFileExecutionOutput implements ExecutionOutputSink {
private pending: Promise<unknown> = Promise.resolve();
private closed = false;
private remainingBytes: number;
constructor(
private readonly file: fs.FileHandle,
maximumBytes: number,
existingBytes: number,
) {
this.remainingBytes = maximumBytes - existingBytes;
}
write(output: ExecutionOutputChunk): Promise<void> {
if (this.closed) {
return Promise.reject(new Error('Local execution artifact is closed'));
}
const chunk = Buffer.from(output.chunk);
const operation = this.pending.then(async () => {
if (this.remainingBytes <= 0) {
throw new LocalArtifactQuotaExceededError();
}
const accepted = chunk.subarray(
0,
Math.min(chunk.length, this.remainingBytes),
);
let written = 0;
while (written < accepted.length) {
const result = await this.file.write(accepted.subarray(written));
if (result.bytesWritten < 1) {
throw new Error('Local execution artifact write made no progress');
}
written += result.bytesWritten;
this.remainingBytes -= result.bytesWritten;
}
if (accepted.length !== chunk.length) {
throw new LocalArtifactQuotaExceededError();
}
});
this.pending = operation.catch(() => undefined);
return operation;
}
async close(): Promise<void> {
if (this.closed) return;
this.closed = true;
await this.pending.catch(() => undefined);
await this.file.close();
}
}
export class LocalFileExecutionArtifactAllocator
implements LocalExecutionArtifactAllocator
{
private readonly artifactRoot: string;
private readonly completionReceiptRoot: string;
private readonly policy: Readonly<LocalArtifactCapacityPolicy>;
private readonly capacity: LocalArtifactCapacityProbe;
constructor(
artifactRoot: string,
completionReceiptRoot: string,
policy: LocalArtifactCapacityPolicy,
capacity: LocalArtifactCapacityProbe = new LocalFileSystemCapacityProbe(),
) {
if (
!path.isAbsolute(artifactRoot) ||
artifactRoot.includes('\0') ||
!path.isAbsolute(completionReceiptRoot) ||
completionReceiptRoot.includes('\0')
) {
throw new TypeError('Local execution artifact roots must be absolute');
}
this.artifactRoot = path.resolve(artifactRoot);
this.completionReceiptRoot = path.resolve(completionReceiptRoot);
this.policy = normalizeLocalArtifactCapacityPolicy(policy);
this.capacity = capacity;
}
async prepare(
candidate: Readonly<RunDispatchCandidate>,
): Promise<PreparedLocalExecutionArtifact> {
const logArtifactId = localExecutionArtifactId(candidate);
assertLocalExecutionArtifactId(logArtifactId);
const shard = logArtifactId.slice('local-'.length, 'local-'.length + 2);
const directory = path.join(this.artifactRoot, shard);
await privateDirectory(this.artifactRoot);
const capacity = await this.capacity.inspect(this.artifactRoot);
const requiredBytes =
BigInt(this.policy.minimumFreeBytes) +
BigInt(this.policy.maximumAttemptBytes);
if (capacity.availableBytes < requiredBytes) {
throw new LocalArtifactCapacityUnavailableError();
}
await privateDirectory(directory);
await privateDirectory(this.completionReceiptRoot);
const outputFilePath = path.join(directory, `${logArtifactId}.log`);
const file = await fs.open(
outputFilePath,
constants.O_WRONLY |
constants.O_CREAT |
constants.O_APPEND |
(constants.O_NOFOLLOW ?? 0),
0o600,
);
try {
const stat = await file.stat();
if (!stat.isFile()) {
throw new TypeError('Local execution artifact target is unsafe');
}
if (
!Number.isSafeInteger(stat.size) ||
stat.size < 0 ||
stat.size > this.policy.maximumAttemptBytes
) {
throw new LocalArtifactQuotaExceededError();
}
await file.chmod(0o600);
const output = new LocalFileExecutionOutput(
file,
this.policy.maximumAttemptBytes,
stat.size,
);
return {
logArtifactId,
output: enableDurableLocalProcessOutput(output, {
outputFilePath,
completionReceiptRoot: this.completionReceiptRoot,
maximumBytes: this.policy.maximumAttemptBytes,
logArtifactId,
}),
dispose: () => output.close(),
};
} catch (error) {
await file.close().catch(() => undefined);
throw error;
}
}
}
@@ -0,0 +1,68 @@
import fs from 'fs/promises';
import path from 'path';
import { LocalArtifactCapacityUnavailableError } from '../../domain/localArtifactCapacity';
import type {
LocalArtifactCapacityProbe,
LocalArtifactCapacitySnapshot,
LocalArtifactCapacitySource,
} from '../../ports/localArtifactCapacityProbe';
interface BigIntStatFs {
bavail: bigint;
blocks: bigint;
bsize: bigint;
}
export class RootedLocalFileSystemCapacitySource
implements LocalArtifactCapacitySource
{
private readonly root: string;
constructor(
root: string,
private readonly probe: LocalArtifactCapacityProbe = new LocalFileSystemCapacityProbe(),
) {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new TypeError('Local Artifact capacity root must be absolute');
}
this.root = path.resolve(root);
}
inspect(): Promise<LocalArtifactCapacitySnapshot> {
return this.probe.inspect(this.root);
}
}
interface StatFsPromises {
statfs(value: string, options: { bigint: true }): Promise<BigIntStatFs>;
}
export class LocalFileSystemCapacityProbe
implements LocalArtifactCapacityProbe
{
async inspect(root: string): Promise<LocalArtifactCapacitySnapshot> {
if (!path.isAbsolute(root) || root.includes('\0')) {
throw new LocalArtifactCapacityUnavailableError();
}
try {
const statfs = (fs as unknown as StatFsPromises).statfs;
if (typeof statfs !== 'function') {
throw new LocalArtifactCapacityUnavailableError();
}
const stat = await statfs.call(fs, root, { bigint: true });
const availableBytes = stat.bavail * stat.bsize;
const totalBytes = stat.blocks * stat.bsize;
if (
availableBytes < BigInt(0) ||
totalBytes < BigInt(1) ||
availableBytes > totalBytes
) {
throw new LocalArtifactCapacityUnavailableError();
}
return Object.freeze({ availableBytes, totalBytes });
} catch (error) {
if (error instanceof LocalArtifactCapacityUnavailableError) throw error;
throw new LocalArtifactCapacityUnavailableError();
}
}
}
@@ -0,0 +1,160 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import {
LocalSecretUnavailableError,
assertLocalSecretKeyId,
} from '../../domain/localSecret';
import type {
LocalSecretKeyMaterial,
LocalSecretKeyProvider,
} from '../../ports/localSecretKeyProvider';
const MAX_KEYRING_BYTES = 16 * 1024;
const MAX_KEY_COUNT = 16;
const BASE64URL_PATTERN = /^[A-Za-z0-9_-]+$/;
interface LocalSecretKeyringManifest {
version: 1;
activeKeyId: string;
keys: Record<string, string>;
}
function exactKeys(value: object, expected: readonly string[]): boolean {
const actual = Object.keys(value).sort();
return (
actual.length === expected.length &&
actual.every((key, index) => key === expected[index])
);
}
function parseManifest(value: Buffer): LocalSecretKeyringManifest {
let parsed: unknown;
try {
parsed = JSON.parse(value.toString('utf8'));
} catch {
throw new LocalSecretUnavailableError();
}
if (
!parsed ||
typeof parsed !== 'object' ||
Array.isArray(parsed) ||
!exactKeys(parsed, ['activeKeyId', 'keys', 'version'])
) {
throw new LocalSecretUnavailableError();
}
const record = parsed as Record<string, unknown>;
if (
record.version !== 1 ||
!record.keys ||
typeof record.keys !== 'object' ||
Array.isArray(record.keys)
) {
throw new LocalSecretUnavailableError();
}
assertLocalSecretKeyId(record.activeKeyId as string);
const entries = Object.entries(record.keys as Record<string, unknown>);
if (entries.length < 1 || entries.length > MAX_KEY_COUNT) {
throw new LocalSecretUnavailableError();
}
const keys: Record<string, string> = Object.create(null);
for (const [keyId, encoded] of entries) {
assertLocalSecretKeyId(keyId);
const decoded =
typeof encoded === 'string'
? Buffer.from(encoded, 'base64url')
: Buffer.alloc(0);
if (
typeof encoded !== 'string' ||
!BASE64URL_PATTERN.test(encoded) ||
decoded.length !== 32 ||
decoded.toString('base64url') !== encoded
) {
decoded.fill(0);
throw new LocalSecretUnavailableError();
}
decoded.fill(0);
keys[keyId] = encoded;
}
if (!keys[record.activeKeyId as string]) {
throw new LocalSecretUnavailableError();
}
return {
version: 1,
activeKeyId: record.activeKeyId as string,
keys,
};
}
export class LocalSecretKeyringFileProvider implements LocalSecretKeyProvider {
private readonly filePath: string;
constructor(filePath: string) {
if (!path.isAbsolute(filePath) || filePath.includes('\0')) {
throw new TypeError('Local Secret keyring path must be absolute');
}
this.filePath = path.resolve(filePath);
}
async active(): Promise<LocalSecretKeyMaterial> {
const manifest = await this.read();
return this.material(
manifest,
manifest.activeKeyId,
) as LocalSecretKeyMaterial;
}
async resolve(keyId: string): Promise<LocalSecretKeyMaterial | null> {
try {
assertLocalSecretKeyId(keyId);
} catch {
throw new LocalSecretUnavailableError();
}
const manifest = await this.read();
return this.material(manifest, keyId);
}
private material(
manifest: LocalSecretKeyringManifest,
keyId: string,
): LocalSecretKeyMaterial | null {
const encoded = manifest.keys[keyId];
return encoded
? Object.freeze({
keyId,
key: Uint8Array.from(Buffer.from(encoded, 'base64url')),
})
: null;
}
private async read(): Promise<LocalSecretKeyringManifest> {
let file: fs.FileHandle | undefined;
let contents: Buffer | undefined;
try {
file = await fs.open(
this.filePath,
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
const stat = await file.stat();
if (
!stat.isFile() ||
stat.isSymbolicLink() ||
(stat.mode & 0o077) !== 0 ||
stat.size < 1 ||
stat.size > MAX_KEYRING_BYTES
) {
throw new LocalSecretUnavailableError();
}
contents = await file.readFile();
if (contents.length !== stat.size) {
throw new LocalSecretUnavailableError();
}
return parseManifest(contents);
} catch {
throw new LocalSecretUnavailableError();
} finally {
contents?.fill(0);
await file?.close().catch(() => undefined);
}
}
}
@@ -0,0 +1,106 @@
import { createHash } from 'crypto';
import fs from 'fs/promises';
import path from 'path';
import {
defaultOffRuntimeRolloutPolicy,
parseRuntimeRolloutManifest,
} from '../../domain/runtimeRolloutManifest';
import type {
RuntimeRolloutLoadAudit,
RuntimeRolloutLoadResult,
} from '../../ports/runtimeRolloutLoader';
export type {
RuntimeRolloutLoadAudit,
RuntimeRolloutLoadResult,
RuntimeRolloutLoadStatus,
} from '../../ports/runtimeRolloutLoader';
export const MAX_RUNTIME_ROLLOUT_MANIFEST_BYTES = 64 * 1024;
export interface RuntimeRolloutManifestLoaderOptions {
clock?: { now(): number };
maxBytes?: number;
}
function rejected(
audit: RuntimeRolloutLoadAudit,
reasonCode: NonNullable<RuntimeRolloutLoadAudit['reasonCode']>,
): RuntimeRolloutLoadResult {
return {
status: 'rejected',
policy: defaultOffRuntimeRolloutPolicy(),
audit: { ...audit, status: 'rejected', reasonCode },
};
}
export async function loadRuntimeRolloutManifest(
sourcePath: string,
options: RuntimeRolloutManifestLoaderOptions = {},
): Promise<RuntimeRolloutLoadResult> {
if (!path.isAbsolute(sourcePath)) {
throw new TypeError('Runtime rollout manifest path must be absolute');
}
const evaluatedAtMs = (options.clock ?? { now: Date.now }).now();
if (!Number.isSafeInteger(evaluatedAtMs) || evaluatedAtMs < 0) {
throw new TypeError('Runtime rollout clock returned an invalid timestamp');
}
const maxBytes = options.maxBytes ?? MAX_RUNTIME_ROLLOUT_MANIFEST_BYTES;
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
throw new TypeError('Runtime rollout maxBytes must be a positive integer');
}
const baseAudit: RuntimeRolloutLoadAudit = {
event: 'runtime.rollout_config_evaluated',
evaluatedAtMs,
sourcePath,
status: 'rejected',
};
let bytes: Buffer;
try {
bytes = await fs.readFile(sourcePath);
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return {
status: 'missing',
policy: defaultOffRuntimeRolloutPolicy(),
audit: {
...baseAudit,
status: 'missing',
reasonCode: 'FILE_MISSING',
},
};
}
return rejected(baseAudit, 'FILE_READ_FAILED');
}
const sourceSha256 = createHash('sha256').update(bytes).digest('hex');
const hashedAudit = { ...baseAudit, sourceSha256 };
if (bytes.byteLength > maxBytes) {
return rejected(hashedAudit, 'FILE_TOO_LARGE');
}
let value: unknown;
try {
value = JSON.parse(bytes.toString('utf8'));
} catch {
return rejected(hashedAudit, 'INVALID_JSON');
}
try {
const decision = parseRuntimeRolloutManifest(value, evaluatedAtMs);
const status = decision.manifest.enabled ? 'accepted' : 'disabled';
return {
status,
policy: decision.policy,
manifest: decision.manifest,
audit: {
...hashedAudit,
status,
revision: decision.manifest.revision,
},
};
} catch {
return rejected(hashedAudit, 'INVALID_MANIFEST');
}
}
@@ -0,0 +1,534 @@
import { constants } from 'fs';
import fs from 'fs/promises';
import path from 'path';
import { randomBytes } from 'crypto';
import { lock } from 'proper-lockfile';
import {
MAX_WORKER_EXECUTION_OFFER_JOURNAL_ENTRIES,
MAX_WORKER_EXECUTION_OFFER_JOURNAL_PAGE_SIZE,
MAX_WORKER_EXECUTION_OFFER_RECORD_BYTES,
cloneWorkerExecutionOfferJournalRecord,
parseWorkerExecutionOfferJournalRecord,
serializeWorkerExecutionOfferJournalRecord,
type WorkerExecutionOfferJournalRecord,
} from '../../domain/workerExecutionOffer';
import { assertRunDispatchOfferId } from '../../domain/runDispatchOffer';
import type {
WorkerExecutionOfferJournal,
WorkerExecutionOfferJournalCreateResult,
WorkerExecutionOfferJournalPage,
} from '../../ports/workerExecutionOfferJournal';
import type {
WorkerExecutionOfferJournalOwnership,
WorkerExecutionOfferJournalOwnershipState,
} from '../../ports/workerExecutionOfferJournalOwnership';
const JOURNAL_FILE_PATTERN = /^([0-9a-f]{64})\.json$/;
export const MIN_WORKER_OFFER_JOURNAL_LOCK_STALE_MS = 5_000;
export const MAX_WORKER_OFFER_JOURNAL_LOCK_STALE_MS = 5 * 60_000;
export interface WorkerExecutionOfferLockProvider {
acquire(options: {
root: string;
lockfilePath: string;
staleMs: number;
updateMs: number;
onCompromised(error: Error): void;
}): Promise<() => Promise<void>>;
}
const properLockProvider: WorkerExecutionOfferLockProvider = {
acquire(options) {
return lock(options.root, {
stale: options.staleMs,
update: options.updateMs,
retries: 0,
realpath: true,
lockfilePath: options.lockfilePath,
onCompromised: options.onCompromised,
});
},
};
export class WorkerExecutionOfferJournalCapacityError extends Error {
constructor(readonly maximumEntries: number) {
super(`Worker execution offer journal reached ${maximumEntries} entries`);
this.name = 'WorkerExecutionOfferJournalCapacityError';
}
}
export class WorkerExecutionOfferJournalRevisionError extends Error {
constructor(readonly offerId: string) {
super(`Worker execution offer journal revision changed for ${offerId}`);
this.name = 'WorkerExecutionOfferJournalRevisionError';
}
}
export class WorkerExecutionOfferJournalNotFoundError extends Error {
constructor(readonly offerId: string) {
super(`Worker execution offer journal entry ${offerId} was not found`);
this.name = 'WorkerExecutionOfferJournalNotFoundError';
}
}
export class WorkerExecutionOfferJournalOwnershipError extends Error {
constructor(
readonly reason: 'already_owned' | 'not_owned' | 'compromised',
readonly cause?: unknown,
) {
super(`Worker execution offer journal ownership failed: ${reason}`);
this.name = 'WorkerExecutionOfferJournalOwnershipError';
}
}
function isCode(error: unknown, code: string): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
(error as { code?: string }).code === code
);
}
function assertIntegerBetween(
name: string,
value: number,
minimum: number,
maximum: number,
): void {
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
throw new RangeError(`${name} must be between ${minimum} and ${maximum}`);
}
}
/**
* Worker-local restart journal. One bounded file per offer avoids a database or
* sidecar on edge devices. The Worker runtime must exclusively own this root.
*/
export class WorkerExecutionOfferFileJournal
implements WorkerExecutionOfferJournal, WorkerExecutionOfferJournalOwnership
{
private readonly maximumEntries: number;
private readonly ownershipStaleMs: number;
private readonly lockProvider: WorkerExecutionOfferLockProvider;
private readonly onOwnershipCompromised?: (error: Error) => void;
private ownerState: WorkerExecutionOfferJournalOwnershipState = 'unowned';
private releaseOwner?: () => Promise<void>;
private ownershipError?: Error;
private mutationTail: Promise<void> = Promise.resolve();
constructor(
private readonly root: string,
options: {
maximumEntries?: number;
ownershipStaleMs?: number;
lockProvider?: WorkerExecutionOfferLockProvider;
onOwnershipCompromised?: (error: Error) => void;
} = {},
) {
if (!path.isAbsolute(root)) {
throw new RangeError(
'Worker execution offer journal root must be absolute',
);
}
this.maximumEntries = options.maximumEntries ?? 64;
assertIntegerBetween(
'maximumEntries',
this.maximumEntries,
1,
MAX_WORKER_EXECUTION_OFFER_JOURNAL_ENTRIES,
);
this.ownershipStaleMs = options.ownershipStaleMs ?? 30_000;
assertIntegerBetween(
'ownershipStaleMs',
this.ownershipStaleMs,
MIN_WORKER_OFFER_JOURNAL_LOCK_STALE_MS,
MAX_WORKER_OFFER_JOURNAL_LOCK_STALE_MS,
);
this.lockProvider = options.lockProvider ?? properLockProvider;
this.onOwnershipCompromised = options.onOwnershipCompromised;
}
ownershipState(): WorkerExecutionOfferJournalOwnershipState {
return this.ownerState;
}
async acquireOwnership(): Promise<'acquired' | 'already_owned'> {
if (this.ownerState === 'owned') return 'already_owned';
if (this.ownerState === 'releasing') {
throw new WorkerExecutionOfferJournalOwnershipError('not_owned');
}
if (this.ownerState === 'compromised') {
throw new WorkerExecutionOfferJournalOwnershipError(
'compromised',
this.ownershipError,
);
}
await this.ensureRoot();
try {
const release = await this.lockProvider.acquire({
root: this.root,
lockfilePath: path.join(this.root, '.owner.lock'),
staleMs: this.ownershipStaleMs,
updateMs: Math.max(1_000, Math.floor(this.ownershipStaleMs / 2)),
onCompromised: (error) => this.compromiseOwnership(error),
});
this.releaseOwner = release;
this.ownerState = 'owned';
return 'acquired';
} catch (error) {
if (isCode(error, 'ELOCKED')) {
throw new WorkerExecutionOfferJournalOwnershipError(
'already_owned',
error,
);
}
throw error;
}
}
async releaseOwnership(): Promise<'released' | 'not_owned' | 'compromised'> {
if (this.ownerState === 'unowned') return 'not_owned';
if (this.ownerState === 'compromised') return 'compromised';
if (this.ownerState === 'releasing') return 'not_owned';
while (true) {
const pending = this.mutationTail;
await pending;
if (pending === this.mutationTail) break;
}
const ownerStateAfterMutations = this.ownershipState();
if (ownerStateAfterMutations === 'compromised') return 'compromised';
if (ownerStateAfterMutations !== 'owned') return 'not_owned';
const release = this.releaseOwner;
if (!release) {
this.compromiseOwnership(
new Error('Worker offer journal owner release capability is missing'),
);
return 'compromised';
}
this.ownerState = 'releasing';
try {
await release();
this.releaseOwner = undefined;
this.ownerState = 'unowned';
return 'released';
} catch (error) {
const compromised =
error instanceof Error
? error
: new Error('Worker offer journal owner release failed');
this.compromiseOwnership(compromised);
throw new WorkerExecutionOfferJournalOwnershipError('compromised', error);
}
}
async create(
record: WorkerExecutionOfferJournalRecord,
): Promise<WorkerExecutionOfferJournalCreateResult> {
this.assertOwned();
const candidate = cloneWorkerExecutionOfferJournalRecord(record);
if (candidate.revision !== 0 || candidate.state !== 'accepted') {
throw new TypeError(
'A new Worker offer journal entry must be accepted at revision zero',
);
}
return this.serializeMutation(async () => {
const target = this.target(candidate.offer.offerId);
if (await this.exists(target)) return 'exists';
const names = await this.entryNames();
if (names.length >= this.maximumEntries) {
throw new WorkerExecutionOfferJournalCapacityError(this.maximumEntries);
}
const temporary = this.temporary(candidate.offer.offerId);
try {
await this.writeTemporary(temporary, candidate);
this.assertOwned();
await fs.link(temporary, target);
await this.bestEffortSyncDirectory();
return 'created';
} catch (error) {
if (isCode(error, 'EEXIST')) return 'exists';
throw error;
} finally {
await this.bestEffortUnlink(temporary);
}
});
}
async read(
offerId: string,
): Promise<WorkerExecutionOfferJournalRecord | undefined> {
this.assertOwned();
assertRunDispatchOfferId(offerId);
let handle: fs.FileHandle;
try {
handle = await fs.open(
this.target(offerId),
constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),
);
} catch (error) {
if (isCode(error, 'ENOENT')) return undefined;
throw error;
}
try {
const stat = await handle.stat();
if (!stat.isFile()) {
throw new TypeError(
'Worker execution offer journal entry must be a regular file',
);
}
const bytes = Buffer.allocUnsafe(
MAX_WORKER_EXECUTION_OFFER_RECORD_BYTES + 1,
);
const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
if (bytesRead > MAX_WORKER_EXECUTION_OFFER_RECORD_BYTES) {
throw new TypeError(
'Worker execution offer journal entry exceeds the byte limit',
);
}
const record = parseWorkerExecutionOfferJournalRecord(
bytes.subarray(0, bytesRead),
);
if (record.offer.offerId !== offerId) {
throw new TypeError(
'Worker offer journal path and payload do not match',
);
}
return record;
} finally {
await handle.close();
}
}
async replace(
record: WorkerExecutionOfferJournalRecord,
expectedRevision: number,
): Promise<void> {
this.assertOwned();
const candidate = cloneWorkerExecutionOfferJournalRecord(record);
assertIntegerBetween(
'expectedRevision',
expectedRevision,
0,
Number.MAX_SAFE_INTEGER - 1,
);
if (candidate.revision !== expectedRevision + 1) {
throw new TypeError('Replacement journal revision must increment by one');
}
await this.serializeMutation(async () => {
const current = await this.read(candidate.offer.offerId);
if (!current) {
throw new WorkerExecutionOfferJournalNotFoundError(
candidate.offer.offerId,
);
}
if (current.revision !== expectedRevision) {
throw new WorkerExecutionOfferJournalRevisionError(
candidate.offer.offerId,
);
}
const temporary = this.temporary(candidate.offer.offerId);
try {
await this.writeTemporary(temporary, candidate);
this.assertOwned();
await fs.rename(temporary, this.target(candidate.offer.offerId));
await this.bestEffortSyncDirectory();
} finally {
await this.bestEffortUnlink(temporary);
}
});
}
async remove(offerId: string, expectedRevision?: number): Promise<boolean> {
this.assertOwned();
assertRunDispatchOfferId(offerId);
if (expectedRevision !== undefined) {
assertIntegerBetween(
'expectedRevision',
expectedRevision,
0,
Number.MAX_SAFE_INTEGER,
);
}
return this.serializeMutation(async () => {
if (expectedRevision !== undefined) {
const current = await this.read(offerId);
if (!current) return false;
if (current.revision !== expectedRevision) {
throw new WorkerExecutionOfferJournalRevisionError(offerId);
}
}
try {
this.assertOwned();
await fs.unlink(this.target(offerId));
await this.bestEffortSyncDirectory();
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
throw error;
}
});
}
async list(
options: { afterOfferId?: string; limit?: number } = {},
): Promise<WorkerExecutionOfferJournalPage> {
this.assertOwned();
if (options.afterOfferId !== undefined) {
assertRunDispatchOfferId(options.afterOfferId);
}
const limit = options.limit ?? 32;
assertIntegerBetween(
'limit',
limit,
1,
MAX_WORKER_EXECUTION_OFFER_JOURNAL_PAGE_SIZE,
);
const names = await this.entryNames();
const offerIds = names
.map((name) => JOURNAL_FILE_PATTERN.exec(name)?.[1])
.filter((value): value is string => value !== undefined)
.filter(
(offerId) =>
options.afterOfferId === undefined || offerId > options.afterOfferId,
)
.sort();
const selected = offerIds.slice(0, limit + 1);
const hasMore = selected.length > limit;
const pageIds = selected.slice(0, limit);
const records: WorkerExecutionOfferJournalRecord[] = [];
for (const offerId of pageIds) {
const record = await this.read(offerId);
if (!record) {
throw new WorkerExecutionOfferJournalRevisionError(offerId);
}
records.push(record);
}
return {
records,
...(hasMore && pageIds.length
? { nextAfterOfferId: pageIds[pageIds.length - 1] }
: {}),
};
}
private target(offerId: string): string {
assertRunDispatchOfferId(offerId);
return path.join(this.root, `${offerId}.json`);
}
private temporary(offerId: string): string {
return path.join(
this.root,
`.${offerId}.${randomBytes(16).toString('hex')}.tmp`,
);
}
private async ensureRoot(): Promise<void> {
await fs.mkdir(this.root, { recursive: true, mode: 0o700 });
const stat = await fs.lstat(this.root);
if (!stat.isDirectory() || stat.isSymbolicLink()) {
throw new TypeError(
'Worker execution offer journal root must be a real directory',
);
}
await fs.chmod(this.root, 0o700);
}
private assertOwned(): void {
if (this.ownerState === 'owned') return;
throw new WorkerExecutionOfferJournalOwnershipError(
this.ownerState === 'compromised' ? 'compromised' : 'not_owned',
this.ownershipError,
);
}
private compromiseOwnership(error: Error): void {
this.ownershipError = error;
this.releaseOwner = undefined;
this.ownerState = 'compromised';
try {
this.onOwnershipCompromised?.(error);
} catch {
// Ownership loss must remain visible even if diagnostics fail.
}
}
private async entryNames(): Promise<string[]> {
let names: string[];
try {
names = await fs.readdir(this.root);
} catch (error) {
if (isCode(error, 'ENOENT')) return [];
throw error;
}
const entries = names.filter((name) => JOURNAL_FILE_PATTERN.test(name));
if (entries.length > this.maximumEntries) {
throw new WorkerExecutionOfferJournalCapacityError(this.maximumEntries);
}
return entries;
}
private async writeTemporary(
temporary: string,
record: WorkerExecutionOfferJournalRecord,
): Promise<void> {
const serialized = serializeWorkerExecutionOfferJournalRecord(record);
let handle: fs.FileHandle | undefined;
try {
handle = await fs.open(temporary, 'wx', 0o600);
await handle.writeFile(serialized, 'utf8');
await handle.sync();
} finally {
await handle?.close().catch(() => undefined);
}
}
private async exists(target: string): Promise<boolean> {
try {
const stat = await fs.lstat(target);
if (!stat.isFile()) {
throw new TypeError(
'Worker execution offer journal target must be a regular file',
);
}
return true;
} catch (error) {
if (isCode(error, 'ENOENT')) return false;
throw error;
}
}
private async bestEffortUnlink(target: string): Promise<void> {
try {
await fs.unlink(target);
} catch (error) {
if (!isCode(error, 'ENOENT')) {
// Temp cleanup is diagnostic-only; the atomically published record wins.
}
}
}
private async bestEffortSyncDirectory(): Promise<void> {
try {
const handle = await fs.open(this.root, constants.O_RDONLY);
try {
await handle.sync();
} finally {
await handle.close();
}
} catch {
// Some supported filesystems cannot fsync directories.
}
}
private serializeMutation<T>(operation: () => Promise<T>): Promise<T> {
const result = this.mutationTail.then(operation, operation);
this.mutationTail = result.then(
() => undefined,
() => undefined,
);
return result;
}
}