import { P as Part, S as S3CallOptions, M as MultipartUpload, a as S3ApiOperations, b as S3BaseStorage } from "../../packem_shared/s3-base-storage.d-nOe1N0BL.js"; import { F as File, s as MetaStorageOptions, f as BaseStorageOptions, C as ConditionalSupport, L as LocalMetaStorageOptions, M as MetaStorage, i as FileQuery, O as OperationOptions, y as UploadPostOptions, z as UploadPostPolicy, e as FileInit } from "../../packem_shared/storage.d-Cnjmzau5.js"; import { S3ClientConfig, ObjectCannedACL, S3Client } from '@aws-sdk/client-s3'; import { ResponseMetadata } from '@aws-sdk/types'; import { Readable } from 'node:stream'; import { b as HttpError } from "../../packem_shared/types.d-DFh9698o.js"; import 'lru-cache'; import 'node:crypto'; import 'node:http'; declare class S3File extends File { Parts?: Part[]; UploadId?: string; uri?: string; partsUrls?: string[]; partSize?: number; } type S3MetaStorageOptions = MetaStorageOptions & S3ClientConfig & { bucket?: string; keyFile?: string; }; type S3StorageOptions = BaseStorageOptions & S3ClientConfig & { /** * Specifying access rules for uploaded files. */ acl?: ObjectCannedACL; /** * S3 bucket name. * @default 'node-Upload' */ bucket?: string; /** * Force compatible client upload directly to S3 storage */ clientDirectUpload?: boolean; /** * Send conditional (ETag) requests and advertise them in `Files.capabilities.conditional`. * Defaults to `true` for AWS S3 and `false` when a custom `endpoint` is set, because S3-compatible * services differ in which `If-Match` / `If-None-Match` headers they honour. Set it explicitly to * override the detection: `true` enables every kind, an object only the kinds set to `true` * (`create` / `replace` send the predicate on CompleteMultipartUpload, `read` on GetObject, * `delete` on DeleteObject, `copy` on CopyObject). Always `false` with `clientDirectUpload`. * @example `{ copy: true, read: true }` for Cloudflare R2, which documents conditional headers * on GetObject, PutObject and CopyObject only. */ conditional?: boolean | Partial; /** * @deprecated Use standard auth providers */ keyFile?: string; /** * Configure metafiles storage * @example * Using local metafiles * ```ts * const storage = new S3Storage({ * bucket: 'upload', * region: 'eu-west-3', * metaStorageConfig: { directory: '/tmp/upload-metafiles' } * }) * ``` * Using a separate bucket for metafiles * ```ts * const storage = new S3Storage({ * bucket: 'upload', * region: 'eu-west-3', * metaStorageConfig: { bucket: 'upload-metafiles' } * }) * ``` */ metaStorageConfig?: LocalMetaStorageOptions | S3MetaStorageOptions; /** * The parts size that the client should use for presigned multipart unloading. * @default '16MB' */ partSize?: number | string; /** * Sign browser-form POST policies, so `Files.signedUpload` can enforce a size range * (`Files.capabilities.signedUploadPost`). Defaults to `true` for AWS S3 and `false` when a * custom `endpoint` is set: not every S3-compatible service accepts POST uploads (Cloudflare R2 * does not). Set it to `true` for one that does (MinIO, SeaweedFS, …). */ uploadPost?: boolean; }; /** * SDK V3 * A structure containing information about a service or networking error. */ interface AwsError extends Error { $fault?: "client" | "server"; $metadata: ResponseMetadata; $service?: string; Code?: string; Type?: string; } /** * SDK V2 * A structure containing information about a service or networking error. */ interface AWSErrorV2 extends Error { /** * CloudFront request ID associated with the response. */ cfId: string; /** * A unique short code representing the error that was emitted. */ code: string; /** * Second request ID associated with the response from S3. */ extendedRequestId: string; /** * Set when a networking error occurs to easily identify the endpoint of the request. */ hostname: string; /** * A longer human readable error message. */ message: string; /** * Set when a networking error occurs to easily identify the region of the request. */ region: string; /** * The unique request ID associated with the response. */ requestId: string; /** * Whether the error message is retryable. */ retryable: boolean; /** * Amount of time (in seconds) that the request waited before being resent. */ retryDelay: number; /** * In the case of a request that reached the service, this value contains the response status code. */ statusCode: number; /** * The date time object when the error occurred. */ time: Date; } declare class S3MetaStorage extends MetaStorage { config: S3MetaStorageOptions; /** * Uses `If-Match` conditional writes. An S3-compatible service that ignores the header * degrades to plain overwrites, as before. */ override readonly supportsConditionalSave: boolean; /** The bucket the records are stored in. */ readonly bucket: string; private readonly client; constructor(config: S3MetaStorageOptions); override get(id: string): Promise; override touch(id: string, file: T): Promise; override delete(id: string): Promise; override save(id: string, file: T): Promise; override saveIfVersion(id: string, file: T, version: string): Promise; private put; } type ReadableStream = globalThis.ReadableStream; /** * Adapter that wraps AWS SDK S3Client to implement S3ApiOperations interface. */ declare class S3ClientAdapter implements S3ApiOperations { private readonly client; constructor(client: S3Client, _bucket: string); createMultipartUpload(params: { ACL?: string; Bucket: string; ContentType?: string; Key: string; Metadata?: Record; StorageClass?: string; }, options?: S3CallOptions): Promise<{ UploadId: string; }>; uploadPart(params: { Body: Readable | ReadableStream | Uint8Array; Bucket: string; ContentLength?: number; ContentMD5?: string; Key: string; PartNumber: number; UploadId: string; }, options?: S3CallOptions): Promise<{ ETag: string; }>; uploadPartCopy(params: { Bucket: string; CopySource: string; CopySourceIfMatch?: string; CopySourceRange: string; Key: string; PartNumber: number; UploadId: string; }, options?: S3CallOptions): Promise<{ ETag: string; }>; completeMultipartUpload(params: { Bucket: string; IfMatch?: string; IfNoneMatch?: string; Key: string; Parts: { ETag: string; PartNumber: number; }[]; UploadId: string; }, options?: S3CallOptions): Promise<{ ETag?: string; Location: string; }>; abortMultipartUpload(params: { Bucket: string; Key: string; UploadId: string; }, options?: S3CallOptions): Promise; listMultipartUploads(params: { Bucket: string; KeyMarker?: string; UploadIdMarker?: string; }, options?: S3CallOptions): Promise<{ IsTruncated?: boolean; NextKeyMarker?: string; NextUploadIdMarker?: string; Uploads?: MultipartUpload[]; }>; listParts(params: { Bucket: string; Key: string; PartNumberMarker?: string; UploadId: string; }, options?: S3CallOptions): Promise<{ IsTruncated?: boolean; NextPartNumberMarker?: string; Parts?: Part[]; }>; getObject(params: { Bucket: string; IfMatch?: string; Key: string; Range?: string; }, options?: S3CallOptions): Promise<{ Body?: ReadableStream | Readable; ContentLength?: number; ContentType?: string; ETag?: string; Expires?: Date; LastModified?: Date; Metadata?: Record; }>; headObject(params: { Bucket: string; Key: string; }, options?: S3CallOptions): Promise<{ ContentLength?: number; ContentType?: string; ETag?: string; Expires?: Date; LastModified?: Date; Metadata?: Record; }>; deleteObject(params: { Bucket: string; IfMatch?: string; Key: string; }, options?: S3CallOptions): Promise; copyObject(params: { ACL?: string; Bucket: string; CopySource: string; CopySourceIfMatch?: string; IfMatch?: string; IfNoneMatch?: string; Key: string; StorageClass?: string; }, options?: S3CallOptions): Promise; listObjectsV2(params: { Bucket: string; ContinuationToken?: string; Delimiter?: string; MaxKeys?: number; Prefix?: string; }, options?: S3CallOptions): Promise<{ CommonPrefixes?: { Prefix?: string; }[]; Contents?: { Key?: string; LastModified?: Date; }[]; IsTruncated?: boolean; NextContinuationToken?: string; }>; getPresignedUrl(params: { Bucket: string; expiresIn: number; Key: string; PartNumber: number; UploadId: string; }): Promise; checkBucketAccess(params: { Bucket: string; }): Promise; } /** * Amazon S3 storage implementation. * @example * ```ts * const storage = new S3Storage({ * bucket: , * endpoint: , * region: , * credentials: { * accessKeyId: , * secretAccessKey: * }, * metaStorageConfig: { directory: '/tmp/upload-metafiles' } * }); * ``` * @remarks * ## Error Handling * - S3 API errors are normalized with AWS-specific context * - Errors include S3 error codes and metadata for debugging * - Batch operations handle individual failures gracefully * * ## Retry Behavior * - All S3 API calls are wrapped with configurable retry logic via `retryConfig` option * - Default retryable status codes (`retryConfig.retryableStatusCodes`): 408 (Request Timeout), 429 (Too Many Requests), * 500 (Internal Server Error), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout) * - Retries server-side faults ($fault === "server") automatically * - A custom `shouldRetry` is consulted first; returning `undefined` defers to the defaults * - Default retry configuration: maxRetries: 3, initialDelay: 1000ms, maxDelay: 30000ms, backoffMultiplier: 2 (exponential backoff) * - Retry wrapper handles transient network errors and rate limiting * * ## Multipart Uploads * - Large files are automatically split into multipart uploads * - Maximum 10,000 parts per upload (S3 limitation) * - Part size is configurable (default: 16MB, minimum: 5MB) * - Failed multipart uploads are automatically aborted * * ## Supported Operations * - ✅ create, write, delete, get, getStream, list, update, copy, move * - ✅ Batch operations: deleteBatch, copyBatch, moveBatch (inherited from BaseStorage) * - ✅ exists: Implemented (checks metadata and S3 object) * - ✅ getReadUrl / getUploadUrl: presigned GET / PUT URLs (`@aws-sdk/s3-request-presigner`) * - ✅ clientDirectUpload: presigned part URLs for direct client uploads */ declare class S3Storage extends S3BaseStorage { static override readonly name: string; override readonly storageKind: string; private s3Api; private rawClient; constructor(config: S3StorageOptions); /** * Normalizes AWS S3 errors with S3-specific context. */ override normalizeError(error: AwsError): HttpError; override update({ id }: FileQuery, metadata: Partial): Promise; override getStream({ id }: FileQuery, options?: OperationOptions & { range?: { end?: number; start: number; }; }): Promise<{ headers?: Record; size?: number; stream: Readable; }>; override get raw(): S3Client; override getReadUrl(key: string, options?: { expiresIn?: number; responseContentDisposition?: string; responseContentType?: string; }): Promise; override getUploadUrl(key: string, options?: { contentLength?: number; contentType?: string; expiresIn?: number; }): Promise; override getUploadPost(key: string, options?: UploadPostOptions): Promise; protected getS3Api(): S3ClientAdapter; protected getFileClass(): new (config: FileInit) => S3File; protected getAcl(): string | undefined; protected accessCheck(_maxWaitTime?: number): Promise; } export { type AWSErrorV2, type AwsError, S3File, S3MetaStorage, type S3MetaStorageOptions, S3Storage, type S3StorageOptions };