Strip every comment from the source (parsed with the TypeScript compiler so strings, template literals, regex literals and JSX are never touched), and drop internal/working artifacts that do not belong in the public repository (design mockups, internal analysis docs, a stray backup file and an old log). No functional change: build is green, the full test suite passes.
151 lines
4.0 KiB
TypeScript
151 lines
4.0 KiB
TypeScript
import { ALLOCATION_UNIT_SIZE } from "./constants";
|
|
|
|
export type DownloadCompletionSource =
|
|
| "content-range"
|
|
| "content-length"
|
|
| "provider-metadata"
|
|
| "stream-end";
|
|
|
|
export type DownloadCompletionPlan = {
|
|
expectedTotal: number | null;
|
|
source: DownloadCompletionSource;
|
|
canFinishEarly: boolean;
|
|
};
|
|
|
|
export function planDownloadCompletion(args: {
|
|
existingBytes: number;
|
|
responseStatus: number;
|
|
contentLength: number;
|
|
totalFromRange: number | null;
|
|
knownTotal: number | null;
|
|
correctedTotal: number | null;
|
|
}): DownloadCompletionPlan {
|
|
const existingBytes = Math.max(0, Math.floor(Number(args.existingBytes) || 0));
|
|
const responseStatus = Math.floor(Number(args.responseStatus) || 0);
|
|
const contentLength = Math.max(0, Math.floor(Number(args.contentLength) || 0));
|
|
const totalFromRange = Number.isFinite(args.totalFromRange || NaN)
|
|
? Math.max(0, Math.floor(args.totalFromRange || 0))
|
|
: 0;
|
|
const correctedTotal = Number.isFinite(args.correctedTotal || NaN)
|
|
? Math.max(0, Math.floor(args.correctedTotal || 0))
|
|
: 0;
|
|
const knownTotal = Number.isFinite(args.knownTotal || NaN)
|
|
? Math.max(0, Math.floor(args.knownTotal || 0))
|
|
: 0;
|
|
|
|
if (correctedTotal > 0) {
|
|
return {
|
|
expectedTotal: correctedTotal,
|
|
source: totalFromRange > 0 ? "content-range" : "content-length",
|
|
canFinishEarly: true
|
|
};
|
|
}
|
|
|
|
if (totalFromRange > 0) {
|
|
return {
|
|
expectedTotal: totalFromRange,
|
|
source: "content-range",
|
|
canFinishEarly: true
|
|
};
|
|
}
|
|
|
|
if (contentLength > 0) {
|
|
return {
|
|
expectedTotal: responseStatus === 206 ? existingBytes + contentLength : contentLength,
|
|
source: "content-length",
|
|
canFinishEarly: true
|
|
};
|
|
}
|
|
|
|
if (knownTotal > 0) {
|
|
return {
|
|
expectedTotal: knownTotal,
|
|
source: "provider-metadata",
|
|
canFinishEarly: false
|
|
};
|
|
}
|
|
|
|
return {
|
|
expectedTotal: null,
|
|
source: "stream-end",
|
|
canFinishEarly: false
|
|
};
|
|
}
|
|
|
|
export function validateDownloadedFileCompletion(args: {
|
|
actualBytes: number;
|
|
plan: DownloadCompletionPlan;
|
|
toleranceBytes?: number;
|
|
}): {
|
|
ok: boolean;
|
|
totalBytes: number;
|
|
acceptedMetadataMismatch: boolean;
|
|
error?: string;
|
|
} {
|
|
const actualBytes = Math.max(0, Math.floor(Number(args.actualBytes) || 0));
|
|
const expectedTotal = Number.isFinite(args.plan.expectedTotal || NaN)
|
|
? Math.max(0, Math.floor(args.plan.expectedTotal || 0))
|
|
: 0;
|
|
const toleranceBytes = Math.max(0, Math.floor(Number(args.toleranceBytes ?? ALLOCATION_UNIT_SIZE) || 0));
|
|
|
|
if (
|
|
expectedTotal > 0 &&
|
|
(args.plan.source === "content-range" || args.plan.source === "content-length") &&
|
|
actualBytes + toleranceBytes < expectedTotal
|
|
) {
|
|
return {
|
|
ok: false,
|
|
totalBytes: expectedTotal,
|
|
acceptedMetadataMismatch: false,
|
|
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
|
};
|
|
}
|
|
|
|
if (actualBytes <= 0 && expectedTotal > 0) {
|
|
return {
|
|
ok: false,
|
|
totalBytes: expectedTotal,
|
|
acceptedMetadataMismatch: false,
|
|
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
|
};
|
|
}
|
|
|
|
if (args.plan.source === "provider-metadata") {
|
|
if (expectedTotal > 0 && actualBytes + toleranceBytes < expectedTotal) {
|
|
return {
|
|
ok: false,
|
|
totalBytes: expectedTotal,
|
|
acceptedMetadataMismatch: false,
|
|
error: `download_underflow:${actualBytes}/${expectedTotal}`
|
|
};
|
|
}
|
|
return {
|
|
ok: true,
|
|
totalBytes: actualBytes,
|
|
acceptedMetadataMismatch: expectedTotal > 0 && Math.abs(actualBytes - expectedTotal) > toleranceBytes
|
|
};
|
|
}
|
|
|
|
if (args.plan.source === "stream-end") {
|
|
if (actualBytes <= 0) {
|
|
return {
|
|
ok: false,
|
|
totalBytes: 0,
|
|
acceptedMetadataMismatch: false,
|
|
error: "download_underflow:0/0"
|
|
};
|
|
}
|
|
return {
|
|
ok: true,
|
|
totalBytes: actualBytes,
|
|
acceptedMetadataMismatch: false
|
|
};
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
totalBytes: Math.max(actualBytes, expectedTotal),
|
|
acceptedMetadataMismatch: false
|
|
};
|
|
}
|