chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
import type {
|
||||
PresignedUploadPartCapability,
|
||||
PresignedUploadPartPort,
|
||||
} from "../../../application/ports/browser-transfer/presigned-transfer.ts";
|
||||
import type {
|
||||
UploadPartExecutor,
|
||||
UploadPartReceipt,
|
||||
UploadProviderResult,
|
||||
} from "../../../application/ports/browser-transfer/resumable-upload.ts";
|
||||
import {
|
||||
browserDataFailure,
|
||||
browserDataSuccess,
|
||||
} from "../../browser-file-storage/result.ts";
|
||||
import {
|
||||
MEDIA_TYPE,
|
||||
isSafeUploadReceiptToken,
|
||||
SHA256_HEX,
|
||||
} from "./checkpoint-schema.ts";
|
||||
|
||||
export function createPresignedUploadPartExecutor(
|
||||
inputPort: PresignedUploadPartPort,
|
||||
now: () => number = Date.now,
|
||||
): UploadPartExecutor<PresignedUploadPartCapability> {
|
||||
const put = inputPort?.put;
|
||||
if (typeof put !== "function" || typeof now !== "function") {
|
||||
throw new TypeError("Presigned upload part dependency is invalid.");
|
||||
}
|
||||
const executor: UploadPartExecutor<PresignedUploadPartCapability> = {
|
||||
async uploadPart(
|
||||
input: Parameters<
|
||||
UploadPartExecutor<PresignedUploadPartCapability>["uploadPart"]
|
||||
>[0],
|
||||
): Promise<
|
||||
UploadProviderResult<UploadPartReceipt>
|
||||
> {
|
||||
const capability = input.capability;
|
||||
let nowEpochMs: number;
|
||||
try {
|
||||
nowEpochMs = now();
|
||||
} catch {
|
||||
return browserDataFailure("UNAVAILABLE", "UPLOAD_PART", {
|
||||
retryable: true,
|
||||
recovery: "RESUME",
|
||||
});
|
||||
}
|
||||
if (
|
||||
!capability ||
|
||||
capability.method !== "PUT" ||
|
||||
capability.binding.kind !== "UPLOAD_PART" ||
|
||||
capability.binding.protocol !== input.protocol ||
|
||||
capability.binding.sessionId !== input.sessionId ||
|
||||
capability.binding.requestBindingSha256 !==
|
||||
input.requestBindingSha256 ||
|
||||
capability.binding.uploadBindingSha256 !==
|
||||
input.uploadBindingSha256 ||
|
||||
capability.binding.partNumber !== input.part.partNumber ||
|
||||
capability.binding.offset !== input.part.offset ||
|
||||
capability.binding.idempotencyKey !== input.idempotencyKey ||
|
||||
capability.mediaType !== input.mediaType ||
|
||||
!MEDIA_TYPE.test(capability.mediaType) ||
|
||||
capability.byteLength !== input.part.byteLength ||
|
||||
capability.maxBytes < capability.byteLength ||
|
||||
capability.maxBytes !== input.part.byteLength ||
|
||||
capability.expectedSha256 !== input.part.checksumSha256 ||
|
||||
!SHA256_HEX.test(capability.expectedSha256) ||
|
||||
capability.expiresAtEpochMs <= nowEpochMs ||
|
||||
!(input.bytes instanceof Uint8Array) ||
|
||||
input.bytes.byteLength !== input.part.byteLength ||
|
||||
typeof capability.capabilityReceipt !== "string"
|
||||
) {
|
||||
return browserDataFailure("POLICY_REJECTED", "UPLOAD_PART");
|
||||
}
|
||||
let uploaded;
|
||||
try {
|
||||
uploaded = await put.call(inputPort, {
|
||||
capability,
|
||||
sessionId: input.sessionId,
|
||||
requestBindingSha256: input.requestBindingSha256,
|
||||
uploadBindingSha256: input.uploadBindingSha256,
|
||||
partNumber: input.part.partNumber,
|
||||
offset: input.part.offset,
|
||||
byteLength: input.part.byteLength,
|
||||
checksumSha256: input.part.checksumSha256,
|
||||
idempotencyKey: input.idempotencyKey,
|
||||
bytes: Uint8Array.from(input.bytes),
|
||||
signal: input.signal,
|
||||
});
|
||||
} catch {
|
||||
return browserDataFailure("UNAVAILABLE", "UPLOAD_PART", {
|
||||
retryable: true,
|
||||
recovery: "RESUME",
|
||||
});
|
||||
}
|
||||
if (!uploaded.ok) return uploaded;
|
||||
if (
|
||||
uploaded.value.bytesWritten !== input.part.byteLength ||
|
||||
uploaded.value.checksumSha256 !== input.part.checksumSha256 ||
|
||||
typeof uploaded.value.receiptToken !== "string" ||
|
||||
!isSafeUploadReceiptToken(uploaded.value.receiptToken)
|
||||
) {
|
||||
return browserDataFailure("INTEGRITY_FAILED", "UPLOAD_PART", {
|
||||
recovery: "RECONCILE",
|
||||
});
|
||||
}
|
||||
return browserDataSuccess(
|
||||
Object.freeze({
|
||||
...input.part,
|
||||
receiptToken: uploaded.value.receiptToken,
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
return Object.freeze(executor);
|
||||
}
|
||||
Reference in New Issue
Block a user