chore: initialize from frontend template 4dc033c
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
declare const authorizedDownloadCapabilityBrand: unique symbol;
|
||||
declare const authorizedDownloadCapabilityReceiptBrand: unique symbol;
|
||||
|
||||
/**
|
||||
* Telemetry-safe server-issued identifier. It is not a URL, credential,
|
||||
* object-store key or authorization token.
|
||||
*/
|
||||
export type AuthorizedDownloadCapabilityReceipt = string & {
|
||||
readonly [authorizedDownloadCapabilityReceiptBrand]:
|
||||
"AuthorizedDownloadCapabilityReceipt";
|
||||
};
|
||||
|
||||
/**
|
||||
* Opaque GET-only download handle shared by the file-delivery and transfer
|
||||
* ports. The adapter owns the corresponding URL/query/header binding in an
|
||||
* identity vault, so structurally equal caller-created objects are rejected.
|
||||
*/
|
||||
export type AuthorizedDownloadCapability = Readonly<{
|
||||
capabilityReceipt: AuthorizedDownloadCapabilityReceipt;
|
||||
method: "GET";
|
||||
binding: Readonly<{
|
||||
kind: "DOWNLOAD";
|
||||
resourceId: string;
|
||||
}>;
|
||||
mediaType: string;
|
||||
byteLength: number;
|
||||
maxBytes: number;
|
||||
expectedSha256: string;
|
||||
expiresAtEpochMs: number;
|
||||
readonly [authorizedDownloadCapabilityBrand]:
|
||||
"AuthorizedDownloadCapability";
|
||||
}>;
|
||||
@@ -0,0 +1,183 @@
|
||||
import type { BrowserDataResult } from "../browser-file-storage/shared.ts";
|
||||
|
||||
declare const imageAssetReferenceBrand: unique symbol;
|
||||
declare const imagePresetReferenceBrand: unique symbol;
|
||||
|
||||
export type ImageRasterMediaType =
|
||||
| "image/avif"
|
||||
| "image/jpeg"
|
||||
| "image/png"
|
||||
| "image/webp";
|
||||
|
||||
export type ImageOutputFormat = "avif" | "jpeg" | "png" | "webp";
|
||||
export type ImageFit = "contain" | "cover" | "fill" | "inside" | "outside";
|
||||
|
||||
/**
|
||||
* Identity capability backed by an adapter-owned WeakMap. A structurally equal
|
||||
* object or a reference issued by another runtime must be rejected.
|
||||
*/
|
||||
export type ImageAssetReference = Readonly<{
|
||||
readonly [imageAssetReferenceBrand]: "ImageAssetReference";
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Composition-issued named preset reference. Presentation cannot submit
|
||||
* width, height, DPR, quality, format, URL or query overrides.
|
||||
*/
|
||||
export type ImagePresetReference = Readonly<{
|
||||
presetKey: string;
|
||||
intention: string;
|
||||
readonly [imagePresetReferenceBrand]: "ImagePresetReference";
|
||||
}>;
|
||||
|
||||
export type PublicImmutableImageAsset = Readonly<{
|
||||
kind: "ALLOWLISTED_PUBLIC";
|
||||
originKey: string;
|
||||
assetId: string;
|
||||
revision: string;
|
||||
mediaType: ImageRasterMediaType;
|
||||
contentKind: "RASTER_STATIC";
|
||||
intrinsicWidth: number;
|
||||
intrinsicHeight: number;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Server-issued descriptor for private signed delivery. It contains no URL or
|
||||
* request headers. The signature covers every immutable field and the exact
|
||||
* set of registry-owned preset binding IDs.
|
||||
*/
|
||||
export type BackendIssuedImageAsset = Readonly<{
|
||||
kind: "BACKEND_ISSUED_PRIVATE";
|
||||
issuer: string;
|
||||
originKey: string;
|
||||
assetId: string;
|
||||
revision: string;
|
||||
mediaType: ImageRasterMediaType;
|
||||
contentKind: "RASTER_STATIC";
|
||||
intrinsicWidth: number;
|
||||
intrinsicHeight: number;
|
||||
capabilityId: string;
|
||||
issuedAtEpochMs: number;
|
||||
expiresAtEpochMs: number;
|
||||
allowedPresetBindingIds: readonly string[];
|
||||
signature: Readonly<{
|
||||
algorithm: "ECDSA_P256_SHA256";
|
||||
keyId: string;
|
||||
capabilityBindingDigestHex: string;
|
||||
valueBase64Url: string;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
export type ImageCapabilityVerificationRequest = Readonly<{
|
||||
algorithm: "ECDSA_P256_SHA256";
|
||||
keyId: string;
|
||||
canonicalPayload: Uint8Array;
|
||||
signatureBase64Url: string;
|
||||
}>;
|
||||
|
||||
export interface ImageCapabilityVerifier {
|
||||
/** Exact membership check against the verifier's immutable key registry. */
|
||||
acceptsKey(keyId: string): boolean;
|
||||
verify(
|
||||
request: ImageCapabilityVerificationRequest,
|
||||
): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface ImageAssetAcceptancePort {
|
||||
acceptPublicImmutable(
|
||||
descriptor: PublicImmutableImageAsset,
|
||||
): BrowserDataResult<ImageAssetReference>;
|
||||
acceptBackendIssued(
|
||||
descriptor: BackendIssuedImageAsset,
|
||||
options?: Readonly<{ signal?: AbortSignal }>,
|
||||
): Promise<BrowserDataResult<ImageAssetReference>>;
|
||||
}
|
||||
|
||||
export type ImageDeliveryClass =
|
||||
| "PUBLIC_IMMUTABLE"
|
||||
| "PRIVATE_SIGNED";
|
||||
|
||||
export type ImageProbeRequest = Readonly<{
|
||||
absoluteUrl: string;
|
||||
expectedMediaType: ImageRasterMediaType;
|
||||
expectedWidth: number;
|
||||
expectedHeight: number;
|
||||
maxEncodedBytes: number;
|
||||
maxDecodedPixels: number;
|
||||
maxDecodedBytes: number;
|
||||
delivery: ImageDeliveryClass;
|
||||
minimumPublicMaxAgeSeconds: number;
|
||||
referrerPolicy: "no-referrer" | "strict-origin-when-cross-origin";
|
||||
signal: AbortSignal;
|
||||
}>;
|
||||
|
||||
export type ImageProbeReceipt = Readonly<{
|
||||
absoluteUrl: string;
|
||||
mediaType: ImageRasterMediaType;
|
||||
encodedBytes: number;
|
||||
decodedWidth: number;
|
||||
decodedHeight: number;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Optional browser-native seam. Implementations must bound the encoded body
|
||||
* before buffering and close the decoded ImageBitmap after inspecting it.
|
||||
*/
|
||||
export interface ImageResourceProbePort {
|
||||
probe(
|
||||
request: ImageProbeRequest,
|
||||
): Promise<BrowserDataResult<ImageProbeReceipt>>;
|
||||
}
|
||||
|
||||
export type ImagePresentationSource = Readonly<{
|
||||
type: ImageRasterMediaType;
|
||||
srcSet: string;
|
||||
}>;
|
||||
|
||||
export type ImagePresentationDescriptor = Readonly<{
|
||||
src: string;
|
||||
srcSet: string;
|
||||
sources: readonly ImagePresentationSource[];
|
||||
sizes: string;
|
||||
width: number;
|
||||
height: number;
|
||||
fallbackMediaType: ImageRasterMediaType;
|
||||
loading: "eager" | "lazy";
|
||||
decoding: "async" | "sync";
|
||||
fetchPriority: "high" | "low" | "auto";
|
||||
referrerPolicy: "no-referrer" | "strict-origin-when-cross-origin";
|
||||
crossOrigin: "anonymous";
|
||||
delivery: Readonly<{
|
||||
class: ImageDeliveryClass;
|
||||
assetVersion: string;
|
||||
browserCache: "PUBLIC_IMMUTABLE" | "NO_STORE";
|
||||
sharedCache: "PUBLIC_IMMUTABLE" | "FORBIDDEN";
|
||||
purge:
|
||||
| "REVISION_ROLLOVER"
|
||||
| "CAPABILITY_REVOCATION_OR_EXPIRY";
|
||||
expiresAtEpochMs: number | null;
|
||||
}>;
|
||||
decodeBudget: Readonly<{
|
||||
maximumCandidatePixels: number;
|
||||
maximumDecodedBytes: number;
|
||||
maximumEncodedBytes: number;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
export interface ImageCdnPresentationPort {
|
||||
resolve(request: Readonly<{
|
||||
asset: ImageAssetReference;
|
||||
preset: ImagePresetReference;
|
||||
signal?: AbortSignal;
|
||||
}>): Promise<BrowserDataResult<ImagePresentationDescriptor>>;
|
||||
}
|
||||
|
||||
export type ImageCdnRuntime = Readonly<{
|
||||
assets: ImageAssetAcceptancePort;
|
||||
presentation: ImageCdnPresentationPort;
|
||||
/**
|
||||
* Terminal and idempotent. Aborts in-flight verification/probing, revokes
|
||||
* every issued reference and makes later accept/resolve calls unavailable.
|
||||
*/
|
||||
close(): void;
|
||||
}>;
|
||||
@@ -0,0 +1,68 @@
|
||||
export type {
|
||||
AuthorizedDownloadCapability,
|
||||
AuthorizedDownloadCapabilityReceipt,
|
||||
} from "./authorized-download.ts";
|
||||
|
||||
export type {
|
||||
BackendIssuedImageAsset,
|
||||
ImageAssetAcceptancePort,
|
||||
ImageAssetReference,
|
||||
ImageCapabilityVerificationRequest,
|
||||
ImageCapabilityVerifier,
|
||||
ImageCdnPresentationPort,
|
||||
ImageCdnRuntime,
|
||||
ImageDeliveryClass,
|
||||
ImageFit,
|
||||
ImageOutputFormat,
|
||||
ImagePresentationDescriptor,
|
||||
ImagePresentationSource,
|
||||
ImagePresetReference,
|
||||
ImageProbeReceipt,
|
||||
ImageProbeRequest,
|
||||
ImageRasterMediaType,
|
||||
ImageResourceProbePort,
|
||||
PublicImmutableImageAsset,
|
||||
} from "./image-cdn.ts";
|
||||
|
||||
export type {
|
||||
PresignedDownloadByteSource,
|
||||
PresignedDownloadCapability,
|
||||
PresignedDownloadSourcePort,
|
||||
PresignedTransferBinding,
|
||||
PresignedTransferCapability,
|
||||
PresignedTransferCapabilityProvider,
|
||||
PresignedTransferCapabilityReceipt,
|
||||
PresignedTransferMethod,
|
||||
PresignedTransferReplayGuard,
|
||||
PresignedUploadPartCapability,
|
||||
PresignedUploadPartCapabilityProvider,
|
||||
PresignedUploadPartOutcome,
|
||||
PresignedUploadPartPort,
|
||||
} from "./presigned-transfer.ts";
|
||||
|
||||
export type {
|
||||
ActiveUploadStatus,
|
||||
QuarantinedUpload,
|
||||
ResumableUploadCheckpoint,
|
||||
ResumableUploadCheckpointAdmin,
|
||||
ResumableUploadCheckpointStore,
|
||||
ResumableUploadControlPlane,
|
||||
ResumableUploadPort,
|
||||
ResumableUploadRequest,
|
||||
ResumableUploadSource,
|
||||
UploadAbortOutcome,
|
||||
UploadFileFingerprint,
|
||||
UploadPartCapability,
|
||||
UploadPartDescriptor,
|
||||
UploadPartExecutor,
|
||||
UploadPartReceipt,
|
||||
UploadProviderFailure,
|
||||
UploadProviderResult,
|
||||
UploadRangeReader,
|
||||
UploadSession,
|
||||
UploadSessionStatus,
|
||||
} from "./resumable-upload.ts";
|
||||
export {
|
||||
RESUMABLE_UPLOAD_PROTOCOL,
|
||||
type ResumableUploadProtocol,
|
||||
} from "./resumable-upload.ts";
|
||||
@@ -0,0 +1,151 @@
|
||||
import type { FileByteSource } from "../browser-file-storage/file.ts";
|
||||
import type { BrowserDataResult } from "../browser-file-storage/shared.ts";
|
||||
import type {
|
||||
AuthorizedDownloadCapability,
|
||||
AuthorizedDownloadCapabilityReceipt,
|
||||
} from "./authorized-download.ts";
|
||||
import type { ResumableUploadProtocol } from "./resumable-upload.ts";
|
||||
|
||||
declare const presignedTransferCapabilityBrand: unique symbol;
|
||||
|
||||
/**
|
||||
* Server-issued, telemetry-safe identifier. It is not a URL, credential,
|
||||
* object-store key or authorization token.
|
||||
*/
|
||||
export type PresignedTransferCapabilityReceipt =
|
||||
AuthorizedDownloadCapabilityReceipt;
|
||||
|
||||
export type PresignedTransferMethod = "GET" | "PUT";
|
||||
|
||||
export type PresignedTransferBinding =
|
||||
| Readonly<{
|
||||
kind: "DOWNLOAD";
|
||||
resourceId: string;
|
||||
}>
|
||||
| Readonly<{
|
||||
kind: "UPLOAD_PART";
|
||||
protocol: ResumableUploadProtocol;
|
||||
sessionId: string;
|
||||
requestBindingSha256: string;
|
||||
/**
|
||||
* SHA-256 over the canonical session, request and whole-file fingerprint
|
||||
* binding. The raw session fields remain owned by the upload control
|
||||
* plane; they must never be smuggled into resourceId.
|
||||
*/
|
||||
uploadBindingSha256: string;
|
||||
partNumber: number;
|
||||
offset: number;
|
||||
idempotencyKey: string;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Opaque capability handle crossing the application boundary. The adapter owns
|
||||
* the corresponding URL, query values and request headers in an in-memory
|
||||
* identity vault. Implementations must reject structurally equal or fabricated
|
||||
* handles, even if every visible field matches.
|
||||
*/
|
||||
export type PresignedDownloadCapability = AuthorizedDownloadCapability;
|
||||
|
||||
export type PresignedUploadPartCapability = Readonly<{
|
||||
capabilityReceipt: PresignedTransferCapabilityReceipt;
|
||||
method: "PUT";
|
||||
binding: Extract<
|
||||
PresignedTransferBinding,
|
||||
Readonly<{ kind: "UPLOAD_PART" }>
|
||||
>;
|
||||
mediaType: string;
|
||||
byteLength: number;
|
||||
maxBytes: number;
|
||||
expectedSha256: string;
|
||||
expiresAtEpochMs: number;
|
||||
readonly [presignedTransferCapabilityBrand]:
|
||||
"PresignedTransferCapability";
|
||||
}>;
|
||||
|
||||
export type PresignedTransferCapability =
|
||||
| PresignedDownloadCapability
|
||||
| PresignedUploadPartCapability;
|
||||
|
||||
export interface PresignedTransferCapabilityProvider {
|
||||
/**
|
||||
* Calls a composition-owned backend/BFF capability endpoint. Callers choose
|
||||
* only an opaque resource ID; they cannot supply a transfer URL or headers.
|
||||
*/
|
||||
issueDownload(input: Readonly<{
|
||||
resourceId: string;
|
||||
signal: AbortSignal;
|
||||
}>): Promise<BrowserDataResult<PresignedDownloadCapability>>;
|
||||
}
|
||||
|
||||
export interface PresignedUploadPartCapabilityProvider {
|
||||
issueUploadPart(input: Readonly<{
|
||||
sessionId: string;
|
||||
requestBindingSha256: string;
|
||||
uploadBindingSha256: string;
|
||||
partNumber: number;
|
||||
offset: number;
|
||||
byteLength: number;
|
||||
checksumSha256: string;
|
||||
mediaType: string;
|
||||
idempotencyKey: string;
|
||||
signal: AbortSignal;
|
||||
}>): Promise<BrowserDataResult<PresignedUploadPartCapability>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomic local replay seam. The server/object-store capability must also
|
||||
* enforce single use or equivalent idempotency because a browser guard is not
|
||||
* an authorization boundary.
|
||||
*/
|
||||
export interface PresignedTransferReplayGuard {
|
||||
claim(
|
||||
capability: PresignedTransferCapability,
|
||||
): BrowserDataResult<true>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Successful exhaustion proves length and SHA-256 before the terminal success
|
||||
* of the closed-Result stream. Consumers must not commit a destination until
|
||||
* the iterable finishes without a failure result.
|
||||
*/
|
||||
export type PresignedDownloadByteSource = FileByteSource &
|
||||
Readonly<{
|
||||
byteLength: number;
|
||||
capability: PresignedDownloadCapability;
|
||||
integrity: "VERIFIED_ON_SUCCESSFUL_EXHAUSTION";
|
||||
}>;
|
||||
|
||||
export interface PresignedDownloadSourcePort {
|
||||
open(input: Readonly<{
|
||||
resourceId: string;
|
||||
capability: PresignedDownloadCapability;
|
||||
signal: AbortSignal;
|
||||
}>): Promise<BrowserDataResult<PresignedDownloadByteSource>>;
|
||||
}
|
||||
|
||||
export type PresignedUploadPartOutcome = Readonly<{
|
||||
bytesWritten: number;
|
||||
checksumSha256: string;
|
||||
/**
|
||||
* Non-authorizing object-store acknowledgement (for example a normalized
|
||||
* ETag). It is safe to persist only as part of the exact completed-part
|
||||
* binding and must never be reused as a transfer capability.
|
||||
*/
|
||||
receiptToken: string;
|
||||
}>;
|
||||
|
||||
export interface PresignedUploadPartPort {
|
||||
put(input: Readonly<{
|
||||
capability: PresignedUploadPartCapability;
|
||||
sessionId: string;
|
||||
requestBindingSha256: string;
|
||||
uploadBindingSha256: string;
|
||||
partNumber: number;
|
||||
offset: number;
|
||||
byteLength: number;
|
||||
checksumSha256: string;
|
||||
idempotencyKey: string;
|
||||
bytes: Uint8Array;
|
||||
signal: AbortSignal;
|
||||
}>): Promise<BrowserDataResult<PresignedUploadPartOutcome>>;
|
||||
}
|
||||
@@ -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" }>>>;
|
||||
}
|
||||
Reference in New Issue
Block a user