chore: initialize from frontend template 4dc033c

This commit is contained in:
DongHyeonka
2026-08-13 18:23:26 +09:00
commit 40107eec84
897 changed files with 234824 additions and 0 deletions
@@ -0,0 +1,279 @@
import type { Result } from "../../result.ts";
import type { FileByteSource } from "../browser-file-storage/file.ts";
import type {
BrowserDataFailure,
BrowserDataResult,
TransferProgress,
} from "../browser-file-storage/shared.ts";
export const RESUMABLE_UPLOAD_PROTOCOL =
"PRESIGNED_MULTIPART_V1" as const;
export type ResumableUploadProtocol =
typeof RESUMABLE_UPLOAD_PROTOCOL;
/**
* Multipart uploads use a bounded part manifest instead of a whole-file
* ArrayBuffer. The digest is SHA-256 over the canonical ordered part metadata
* and SHA-256 part digests.
*/
export type UploadFileFingerprint = Readonly<{
algorithm: "SHA-256-PARTS-V1";
digestHex: string;
byteLength: number;
partSizeBytes: number;
partCount: number;
}>;
export type UploadPartDescriptor = Readonly<{
partNumber: number;
offset: number;
byteLength: number;
checksumSha256: string;
}>;
/**
* A non-authorizing server acknowledgement. It must be opaque, contain no PII,
* URL or credential, and be accepted only with the exact descriptor binding.
*/
export type UploadPartReceipt = UploadPartDescriptor &
Readonly<{
receiptToken: string;
}>;
export interface UploadRangeReader {
readonly byteLength: number;
readRange(input: Readonly<{
offset: number;
length: number;
signal: AbortSignal;
}>): Promise<BrowserDataResult<Uint8Array>>;
}
/**
* FILE_BYTE_SOURCE supports existing FileByteSource implementations. It must
* be replayable for the fingerprint pass and transfer pass. RANGE_READER is
* preferred for concurrent uploads and OPFS/file-vault range adapters.
*/
export type ResumableUploadSource =
| Readonly<{
kind: "FILE_BYTE_SOURCE";
bytes: FileByteSource;
}>
| Readonly<{
kind: "RANGE_READER";
reader: UploadRangeReader;
}>;
export type ResumableUploadRequest = Readonly<{
/** Opaque, caller-stable operation key. It must not contain a file name. */
uploadKey: string;
/** Registry-approved backend purpose identifier, not user-provided text. */
purpose: string;
mediaType: string;
source: ResumableUploadSource;
signal: AbortSignal;
onProgress?: (progress: TransferProgress) => void;
}>;
export type QuarantinedUpload = Readonly<{
state: "QUARANTINED";
resourceId: string;
byteLength: number;
replayed: boolean;
}>;
export type UploadAbortOutcome = Readonly<{
state: "ABORTED" | "ORPHANED" | "ALREADY_COMPLETED" | "NOT_FOUND";
}>;
export interface ResumableUploadPort {
upload(
request: ResumableUploadRequest,
): Promise<BrowserDataResult<QuarantinedUpload>>;
abort(request: Readonly<{
uploadKey: string;
signal: AbortSignal;
}>): Promise<BrowserDataResult<UploadAbortOutcome>>;
}
/**
* Retry-After is transport metadata used only by the runtime. It is bounded
* before sleeping and is removed from the application-facing failure.
*/
export type UploadProviderFailure = BrowserDataFailure &
Readonly<{
retryAfterMs?: number;
}>;
export type UploadProviderResult<Value> = Result<
Value,
UploadProviderFailure
>;
export type UploadSession = Readonly<{
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
partSizeBytes: number;
partCount: number;
maxConcurrency: number;
expiresAtEpochMs: number;
}>;
export type ActiveUploadStatus = Readonly<{
state: "ACTIVE";
session: UploadSession;
acceptedParts: readonly UploadPartReceipt[];
}>;
export type UploadSessionStatus =
| ActiveUploadStatus
| Readonly<{
state: "QUARANTINED";
session: UploadSession;
resourceId: string;
}>
| Readonly<{
state: "ABORTED" | "EXPIRED" | "NOT_FOUND";
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
}>;
/**
* The capability value is intentionally generic. The presigned-transfer
* adapter owns its URL/method/header contract; this port neither duplicates
* that type nor permits it to enter a durable checkpoint.
*/
export type UploadPartCapability<Capability> = Readonly<{
capability: Capability;
uploadBindingSha256: string;
expiresAtEpochMs: number;
}>;
export interface ResumableUploadControlPlane<Capability> {
createSession(input: Readonly<{
protocol: ResumableUploadProtocol;
uploadKey: string;
purpose: string;
mediaType: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
requestedPartSizeBytes: number;
requestedMaxConcurrency: number;
idempotencyKey: string;
signal: AbortSignal;
}>): Promise<UploadProviderResult<UploadSession>>;
getStatus(input: Readonly<{
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
signal: AbortSignal;
}>): Promise<UploadProviderResult<UploadSessionStatus>>;
issuePartCapability(input: Readonly<{
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
uploadBindingSha256: string;
fingerprint: UploadFileFingerprint;
mediaType: string;
part: UploadPartDescriptor;
idempotencyKey: string;
signal: AbortSignal;
}>): Promise<UploadProviderResult<UploadPartCapability<Capability>>>;
complete(input: Readonly<{
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
orderedParts: readonly UploadPartReceipt[];
idempotencyKey: string;
signal: AbortSignal;
}>): Promise<UploadProviderResult<Readonly<{
state: "QUARANTINED";
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
resourceId: string;
}>>>;
abort(input: Readonly<{
protocol: ResumableUploadProtocol;
sessionId: string;
requestBindingSha256: string;
idempotencyKey: string;
signal: AbortSignal;
}>): Promise<UploadProviderResult<Readonly<{
state: "ABORTED" | "NOT_FOUND" | "EXPIRED" | "ALREADY_COMPLETED";
}>>>;
}
export interface UploadPartExecutor<Capability> {
uploadPart(input: Readonly<{
protocol: ResumableUploadProtocol;
capability: Capability;
sessionId: string;
requestBindingSha256: string;
uploadBindingSha256: string;
fingerprint: UploadFileFingerprint;
mediaType: string;
part: UploadPartDescriptor;
bytes: Uint8Array;
idempotencyKey: string;
signal: AbortSignal;
}>): Promise<UploadProviderResult<UploadPartReceipt>>;
}
/**
* Durable, non-secret recovery state. Implementations must reject any unknown
* property so a signed URL, authorization header or user metadata cannot be
* smuggled into persistence.
*/
export type ResumableUploadCheckpoint = Readonly<{
schemaVersion: 1;
protocol: ResumableUploadProtocol;
revision: number;
state: "ACTIVE" | "ABORT_PENDING";
uploadKey: string;
requestBindingSha256: string;
fingerprint: UploadFileFingerprint;
sessionId: string;
sessionExpiresAtEpochMs: number;
sessionMaxConcurrency: number;
acceptedParts: readonly UploadPartReceipt[];
updatedAtEpochMs: number;
}>;
export interface ResumableUploadCheckpointStore {
read(
uploadKey: string,
signal?: AbortSignal,
): Promise<BrowserDataResult<ResumableUploadCheckpoint | null>>;
compareAndSwap(input: Readonly<{
expectedRevision: number | null;
checkpoint: ResumableUploadCheckpoint;
signal?: AbortSignal;
}>): Promise<BrowserDataResult<ResumableUploadCheckpoint>>;
remove(input: Readonly<{
uploadKey: string;
expectedRevision: number;
signal?: AbortSignal;
}>): Promise<BrowserDataResult<void>>;
close(): void;
}
export interface ResumableUploadCheckpointAdmin {
/**
* Account/logout lifecycle operation for this already-bound opaque partition.
* The adapter closes its connection before deletion and bounds blocked waits.
*/
deletePartition(
signal?: AbortSignal,
): Promise<BrowserDataResult<Readonly<{ state: "DELETED" }>>>;
}