s3mini
Version:
👶 Tiny & fast S3 client for node and edge computing platforms
259 lines (224 loc) • 7.71 kB
text/typescript
export interface S3Config {
accessKeyId: string;
secretAccessKey: string;
endpoint: string;
region?: string;
requestSizeInBytes?: number;
requestAbortTimeout?: number;
logger?: Logger;
fetch?: typeof fetch;
minPartSize?: number;
}
export type PartData = Uint8Array | Blob | ArrayBuffer;
export interface SSECHeaders {
'x-amz-server-side-encryption-customer-algorithm': string;
'x-amz-server-side-encryption-customer-key': string;
'x-amz-server-side-encryption-customer-key-md5': string;
}
export interface AWSHeaders {
[k: `x-amz-${string}`]: string;
}
export interface Logger {
info: (message: string, ...args: unknown[]) => void;
warn: (message: string, ...args: unknown[]) => void;
error: (message: string, ...args: unknown[]) => void;
}
export interface UploadPart {
partNumber: number;
etag: string;
}
export interface ListObject {
Key: string;
Size: number;
LastModified: Date;
ETag: string;
StorageClass: string;
/** Present when listing with `{ versions: true }` or via `listObjectVersions`. */
VersionId?: string;
/** Present when listing versions; true if this is the current version of the key. */
IsLatest?: boolean;
/** True when the entry is a delete marker from ListObjectVersions. */
IsDeleteMarker?: boolean;
}
/**
* Object identity for delete APIs. Use instead of a bare key string when
* targeting a specific version on a versioned bucket.
*/
export interface DeleteObject {
key: string;
versionId?: string;
}
export interface CompleteMultipartUploadResult {
location: string;
bucket: string;
key: string;
etag: string;
eTag: string; // for backward compatibility
ETag: string; // for backward compatibility
}
interface ListBucketResult {
keyCount: string;
contents?: Array<Record<string, unknown>>;
}
export interface ListBucketError {
error: {
code: string;
message: string;
};
}
export type ListBucketResponse = { listBucketResult: ListBucketResult } | ListBucketError;
export interface ListMultipartUploadSuccess {
listMultipartUploadsResult: {
bucket: string;
key: string;
uploadId: string;
size?: number;
mtime?: Date;
etag?: string;
eTag?: string; // for backward compatibility
parts: UploadPart[];
isTruncated: boolean;
uploads: UploadPart[];
};
}
export interface MultipartUploadError {
error: {
code: string;
message: string;
};
}
export interface ErrorWithCode {
code?: string;
cause?: { code?: string };
}
export type ListMultipartUploadResponse = ListMultipartUploadSuccess | MultipartUploadError;
export type HttpMethod = 'POST' | 'GET' | 'HEAD' | 'PUT' | 'DELETE';
// false - Not found (404)
// true - Found (200)
// null - ETag mismatch (412)
export type ExistResponseCode = false | true | null;
export type XmlValue = string | XmlMap | boolean | number | null;
export interface XmlMap {
[key: string]: XmlValue | XmlValue[]; // one or many children
[key: number]: XmlValue | XmlValue[]; // allow numeric keys
}
export interface CopyObjectOptions {
/**
* Source object version to copy. Appended as `?versionId=` on `x-amz-copy-source`.
* Useful for restoring an older version (copy version onto the same key).
*/
versionId?: string;
/**
* Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request.
* Valid values: 'COPY' | 'REPLACE'
* Default: 'COPY'
*/
metadataDirective?: 'COPY' | 'REPLACE';
/**
* Metadata to be set on the destination object when metadataDirective is 'REPLACE'.
* Keys can be provided with or without 'x-amz-meta-' prefix.
*/
metadata?: Record<string, string>;
contentType?: string;
/**
* Storage class for the destination object.
* Valid values: 'STANDARD' | 'REDUCED_REDUNDANCY' | 'STANDARD_IA' | 'ONEZONE_IA' | 'INTELLIGENT_TIERING' | 'GLACIER' | 'DEEP_ARCHIVE' | 'GLACIER_IR'
*/
storageClass?: string;
/**
* Specifies whether the object tag-set is copied from the source object or replaced with tag-set provided in the request.
* Valid values: 'COPY' | 'REPLACE'
*/
taggingDirective?: 'COPY' | 'REPLACE';
/**
* If the bucket is configured as a website, redirects requests for this object to another object or URL.
*/
websiteRedirectLocation?: string;
/**
* Server-Side Encryption with Customer-Provided Keys headers for the source object.
* Should include:
* - x-amz-copy-source-server-side-encryption-customer-algorithm
* - x-amz-copy-source-server-side-encryption-customer-key
* - x-amz-copy-source-server-side-encryption-customer-key-MD5
*/
sourceSSECHeaders?: Record<string, string | number>;
destinationSSECHeaders?: SSECHeaders;
additionalHeaders?: Record<string, string | number>;
}
export interface CopyObjectResult {
etag: string;
lastModified?: Date;
/** Version id of the newly created destination object (versioned buckets). */
versionId?: string;
}
/**
* Detailed delete outcome for a single target. Returned by `deleteObject` /
* `deleteObjects` when called with `{ versionInfo: true }`.
*/
export interface DeleteObjectResult {
key: string;
deleted: boolean;
/** Version id of the object version permanently deleted (when a `versionId` was targeted). */
versionId?: string;
/** True if S3 created a delete marker rather than permanently deleting. */
deleteMarker?: boolean;
/** Version id of the delete marker created (versioned bucket, no `versionId` targeted). */
deleteMarkerVersionId?: string;
}
type BinaryData = ArrayBuffer | Uint8Array;
type MaybeBuffer = typeof globalThis extends { Buffer?: infer B }
? B extends new (...a: unknown[]) => unknown
? InstanceType<B> | BinaryData
: BinaryData
: BinaryData;
export type DataInput = string | MaybeBuffer | ReadableStream | File | Blob;
// Bun-native S3 interfaces (zero-cost in non-Bun runtimes)
export interface NativeS3Stat {
size: number;
etag: string;
lastModified: Date;
type: string;
}
export interface NativeS3File {
text(): Promise<string>;
json(): Promise<unknown>;
arrayBuffer(): Promise<ArrayBuffer>;
bytes(): Promise<Uint8Array>;
stream(): ReadableStream;
slice(start?: number, end?: number): NativeS3File;
write(data: string | ArrayBuffer | Uint8Array | Blob | ReadableStream, opts?: { type?: string }): Promise<number>;
writer(opts?: { type?: string }): { write(data: unknown): void; flush(): Promise<void>; end(): Promise<void> };
delete(): Promise<void>;
unlink(): Promise<void>;
exists(): Promise<boolean>;
stat(): Promise<NativeS3Stat>;
presign(opts?: { method?: string; expiresIn?: number; acl?: string; type?: string }): string;
}
export interface NativeS3ListObject {
key: string;
lastModified: Date | string;
size: number;
/** Bun spells it `eTag` and leaves the XML entities (`"`) unresolved. */
eTag?: string;
storageClass?: string;
}
export interface NativeS3ListResult {
contents?: NativeS3ListObject[];
commonPrefixes?: { prefix: string }[];
isTruncated: boolean;
nextContinuationToken?: string;
}
export interface NativeS3Client {
file(key: string): NativeS3File;
write(
key: string,
data: string | ArrayBuffer | Uint8Array | Blob | ReadableStream,
opts?: Record<string, unknown>,
): Promise<number>;
delete(key: string): Promise<void>;
exists(key: string): Promise<boolean>;
size(key: string): Promise<number>;
stat(key: string): Promise<NativeS3Stat>;
presign(key: string, opts?: { method?: string; expiresIn?: number; acl?: string; type?: string }): string;
list(opts?: Record<string, unknown> | null, credentials?: Record<string, unknown>): Promise<NativeS3ListResult>;
}