perf(skills): store repository packages outside Postgres

Convert legacy packages automatically, restore exact commits on cache misses, and expire unused recoverable packages while keeping warm turn checks metadata-only.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-28 17:15:19 -05:00
1 parent 65fa1cd617
commit 0bb36b2c6b
53 files changed
+13120 -203

No files matched your search

+2 -2
View File
@@ -48,7 +48,7 @@ export function createLocalDiskStorageProvider(baseDir: string): StorageProvider
const tempPath = `${targetPath}.tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
try {
await fs.writeFile(tempPath, input.body);
await fs.writeFile(tempPath, input.body, { signal: input.signal });
await fs.rename(tempPath, targetPath);
} finally { await fs.rm(tempPath, { force: true }); }
},
@@ -66,7 +66,7 @@ export function createLocalDiskStorageProvider(baseDir: string): StorageProvider
? input.range.end - input.range.start + 1
: stat.size;
return {
stream: createReadStream(filePath, streamOptions),
stream: createReadStream(filePath, { ...streamOptions, signal: input.signal }),
contentLength,
lastModified: stat.mtime,
};
+3 -3
View File
@@ -13,7 +13,7 @@ export async function putS3Multipart(client: S3Client, bucket: string, key: stri
// Scale part sizes to the S3 part-count limit while retaining stream backpressure.
const partSize = Math.max(8 * 1024 * 1024, Math.ceil(input.contentLength / 10_000));
try {
uploadId = (await withS3FailureDiagnostics("create_multipart_upload", () => client.send(new CreateMultipartUploadCommand({ Bucket: bucket, Key: key, ContentType: input.contentType })))).UploadId;
uploadId = (await withS3FailureDiagnostics("create_multipart_upload", () => client.send(new CreateMultipartUploadCommand({ Bucket: bucket, Key: key, ContentType: input.contentType }), { abortSignal: input.signal }))).UploadId;
if (!uploadId) throw new Error("S3 did not return a multipart upload id");
const parts: { ETag: string; PartNumber: number }[] = [];
for (let offset = 0; offset < input.contentLength;) {
@@ -35,14 +35,14 @@ export async function putS3Multipart(client: S3Client, bucket: string, key: stri
}
})());
try {
const result = await withS3FailureDiagnostics("upload_part", () => client.send(new UploadPartCommand({ Bucket: bucket, Key: key, UploadId: uploadId, PartNumber: parts.length + 1, Body: body, ContentLength: length })));
const result = await withS3FailureDiagnostics("upload_part", () => client.send(new UploadPartCommand({ Bucket: bucket, Key: key, UploadId: uploadId, PartNumber: parts.length + 1, Body: body, ContentLength: length }), { abortSignal: input.signal }));
if (remaining || !result.ETag) throw new Error("S3 upload part is incomplete");
parts.push({ ETag: result.ETag, PartNumber: parts.length + 1 });
} finally { body.destroy(); }
offset += length;
}
if (pending.length || !(await iterator.next()).done) throw new Error("S3 upload source exceeds its declared size");
await withS3FailureDiagnostics("complete_multipart_upload", () => client.send(new CompleteMultipartUploadCommand({ Bucket: bucket, Key: key, UploadId: uploadId, MultipartUpload: { Parts: parts } })));
await withS3FailureDiagnostics("complete_multipart_upload", () => client.send(new CompleteMultipartUploadCommand({ Bucket: bucket, Key: key, UploadId: uploadId, MultipartUpload: { Parts: parts } }), { abortSignal: input.signal }));
} catch (error) {
if (uploadId) await client.send(new AbortMultipartUploadCommand({ Bucket: bucket, Key: key, UploadId: uploadId })).catch(() => {});
throw error;
+1
View File
@@ -95,6 +95,7 @@ export function createS3StorageProvider(config: S3ProviderConfig): StorageProvid
ContentType: input.contentType,
ContentLength: input.contentLength,
}),
{ abortSignal: input.signal },
));
},
+2 -1
View File
@@ -107,6 +107,7 @@ export function createStorageService(provider: StorageProvider): StorageService
body: input.body,
contentType,
contentLength: byteSize,
signal: input.signal,
});
} catch (error) {
await provider.deleteObject({ objectKey }).catch(() => {});
@@ -127,7 +128,7 @@ export function createStorageService(provider: StorageProvider): StorageService
async getObject(companyId: string, objectKey: string, options) {
ensureCompanyPrefix(companyId, objectKey);
return provider.getObject({ objectKey, range: options?.range });
return provider.getObject({ objectKey, range: options?.range, signal: options?.signal });
},
async headObject(companyId: string, objectKey: string) {
+3 -1
View File
@@ -3,6 +3,7 @@ import type { Readable } from "node:stream";
export interface PutObjectInput {
objectKey: string;
signal?: AbortSignal;
// Readable bodies stream straight to the backend (contentLength must be the
// exact byte size); Buffer stays supported for small payloads.
body: Buffer | Readable;
@@ -45,6 +46,7 @@ export interface StorageProvider {
}
export type PutFileInput = {
signal?: AbortSignal;
/** Server-allocated, company-prefixed key for durable idempotent uploads. Never accept from client input. */
objectKey?: string;
companyId: string;
@@ -65,7 +67,7 @@ export interface PutFileResult {
export interface StorageService {
provider: StorageProviderId;
putFile(input: PutFileInput): Promise<PutFileResult>;
getObject(companyId: string, objectKey: string, options?: Pick<GetObjectInput, "range">): Promise<GetObjectResult>;
getObject(companyId: string, objectKey: string, options?: Pick<GetObjectInput, "range" | "signal">): Promise<GetObjectResult>;
headObject(companyId: string, objectKey: string): Promise<HeadObjectResult>;
deleteObject(companyId: string, objectKey: string): Promise<void>;
}