import { ObjectCannedACL, StorageClass } from "@aws-sdk/client-s3"; //#region src/server/types/standard-schema.d.ts /** The Standard Schema interface. */ interface StandardSchemaV1 { /** The Standard Schema properties. */ readonly '~standard': StandardSchemaV1.Props; } declare namespace StandardSchemaV1 { /** The Standard Schema properties interface. */ interface Props { /** The version number of the standard. */ readonly version: 1; /** The vendor name of the schema library. */ readonly vendor: string; /** Validates unknown input values. */ readonly validate: (value: unknown) => Result | Promise>; /** Inferred types associated with the schema. */ readonly types?: Types | undefined; } /** The result interface of the validate function. */ type Result = SuccessResult | FailureResult; /** The result interface if validation succeeds. */ interface SuccessResult { /** The typed output value. */ readonly value: Output; /** The non-existent issues. */ readonly issues?: undefined; } /** The result interface if validation fails. */ interface FailureResult { /** The issues of failed validation. */ readonly issues: ReadonlyArray; } /** The issue interface of the failure output. */ interface Issue { /** The error message of the issue. */ readonly message: string; /** The path of the issue, if any. */ readonly path?: ReadonlyArray | undefined; } /** The path segment interface of the issue. */ interface PathSegment { /** The key representing a path segment. */ readonly key: PropertyKey; } /** The Standard Schema types interface. */ interface Types { /** The input type of the schema. */ readonly input: Input; /** The output type of the schema. */ readonly output: Output; } /** Infers the input type of a Standard Schema. */ type InferInput = NonNullable['input']; /** Infers the output type of a Standard Schema. */ type InferOutput = NonNullable['output']; } //#endregion //#region src/server/types/internal.d.ts type UnknownMetadata = Record; type ObjectMetadata = Record; type ClientMetadata = T extends StandardSchemaV1 ? StandardSchemaV1.InferOutput : unknown; type FileInfo = { /** * The name of the file. */ name: string; /** * File size in bytes. */ size: number; /** * The MIME type of the file. */ type: string; /** * The object key where the file will be uploaded to. */ objectKey: string; }; type RouteConfig = { /** * Maximum file size in bytes. * * @default 1024 * 1024 * 5 // 5MB * * @example * * ```ts * maxFileSize: 1024 * 1024 * 10 // 10MB * ``` */ maxFileSize?: number; /** * Allowed file types. * * @default [] // All file types are allowed * * @example * * ```ts * fileTypes: ['image/png', 'image/jpeg'] // Only PNG and JPEG files are allowed * ``` * * @example * * ```ts * fileTypes: ['image/*'] // All image files are allowed * ``` */ fileTypes?: string[]; /** * The number of seconds the upload signed URL is valid for. * * This is not used for multipart uploads. * * @default 120 * * @example * * ```ts * signedUrlExpiresIn: 300 // 5 minutes * ``` */ signedUrlExpiresIn?: number; /** * Schema for validating metadata sent from the client. You can use any validation library that is compatible with `standard-schema`. * * @example * * ```ts * clientMetadataSchema: z.object({ * title: z.string(), * }) * ``` */ clientMetadataSchema?: ClientMetadataSchema; /** * Use this callback to run custom logic before uploading a file, such as auth and rate-limiting. You can also return `objectInfo` to customize the S3 object (`generateObjectInfo` for multiple files). This runs only once regardless of the number of files uploaded. * * Metadata sent from the client is also available. * * Throw `RejectUpload` to reject the file upload. This will also send the error message to the client. */ onBeforeUpload?: (data: { /** * The incoming request. */ req: Request; /** * Metadata sent from the client. */ clientMetadata: ClientMetadata; } & (Multiple extends false ? { /** * Information about the file to be uploaded. */ file: Omit; } : { /** * Information about the files to be uploaded. */ files: Omit[]; })) => BeforeUploadCallbackResult | void | Promise | void>; /** * Use this callback to run custom logic after creating the signed URL, such as saving data to a database. This runs only once regardless of the number of files uploaded. * * Metadata sent from `onBeforeUpload` is available as `metadata`. Metadata sent from the client is available as `clientMetadata`. * * You can return additional metadata to be sent back to the client, needs to be JSON serializable. */ onAfterSignedUrl?: (data: { /** * The incoming request. */ req: Request; /** * Metadata returned by `onBeforeUpload`. */ metadata: InterMetadata; /** * Metadata sent from the client. */ clientMetadata: ClientMetadata; } & (Multiple extends false ? { /** * Information about the uploaded file, including the object key. */ file: FileInfo; } : { /** * Information about the uploaded files, including the object keys. */ files: FileInfo[]; })) => AfterSignedUrlCallbackResult | void | Promise; } & (Multiple extends true ? { /** * Allow more than one file to be uploaded. * * @default false */ multipleFiles: Multiple; /** * The maximum number of files that can be uploaded. * * @default 3 */ maxFiles?: number; } : { /** * Allow more than one file to be uploaded. * * @default false */ multipleFiles?: Multiple; }) & (Multipart extends true ? { /** * Use multipart upload for large files. * * **Use this for files larger than 5GB.** * * @default false */ multipart?: Multipart; /** * The size of each part in bytes. * * @default 1024 * 1024 * 50 // 50MB */ partSize?: number; /** * The number of seconds the upload part pre-signed URL is valid for. * * @default 1500 // 25 minutes */ partSignedUrlExpiresIn?: number; /** * The number of seconds the complete multipart upload pre-signed URL is valid for. * * @default 1800 // 30 minutes */ completeSignedUrlExpiresIn?: number; } : { /** * Use multipart upload for large files. * * **Use this for files larger than 5GB.** * * @default false */ multipart?: Multipart; }); type BeforeUploadCallbackObjectInfo = { /** * The S3 object key to upload to. */ key?: string; /** * Custom S3 object metadata. * * **All keys will be lower cased.** * * **WARNING:** All values here will be exposed to the client. Do not use this for sensitive data. */ metadata?: ObjectMetadata; /** * ACL (access control list) to apply to the S3 object. */ acl?: ObjectCannedACL; /** * Storage class to apply to the S3 object. */ storageClass?: StorageClass; /** * Cache-Control header to apply to the S3 object. * * **WARNING:** If not set, the client is able to set it to any value (does not apply to multipart uploads). */ cacheControl?: string; }; type BeforeUploadCallbackResult = { /** * Metadata sent to `onAfterSignedUrl`. */ metadata?: InterMetadata; /** * The bucket name to upload to. * * If you wish to upload to a different bucket than the one specified in the router. */ bucketName?: string; } & (Multiple extends false ? { /** * Use this to specify properties for the S3 object that will be uploaded. * * Options: * - `key`: The S3 object key to upload to. * - `metadata`: Custom S3 object metadata. * - `acl`: ACL to apply to the S3 object. * - `storageClass`: Storage class to apply to the S3 object. */ objectInfo?: BeforeUploadCallbackObjectInfo; } : { /** * Use this to specify properties for the S3 objects that will be uploaded. Will be called for each file, in parallel. * * Options: * - `key`: The S3 object key to upload to. * - `metadata`: Custom S3 object metadata. * - `acl`: ACL to apply to the S3 object. * - `storageClass`: Storage class to apply to the S3 object. */ generateObjectInfo?: (data: { /** * Information about the file to be uploaded. */ file: Omit; }) => BeforeUploadCallbackObjectInfo | Promise; }); type AfterSignedUrlCallbackResult = { /** * Metadata sent back to the client. * * Needs to be JSON serializable. */ metadata?: UnknownMetadata; }; type Route = { maxFileSize?: number; fileTypes?: string[]; signedUrlExpiresIn?: number; clientMetadataSchema?: StandardSchemaV1; maxFiles?: number; multipart?: { partSize?: number; partSignedUrlExpiresIn?: number; completeSignedUrlExpiresIn?: number; }; onBeforeUpload?: (data: { req: Request; clientMetadata: unknown; files: Omit[]; }) => Promise<{ metadata?: UnknownMetadata; bucketName?: string; generateObjectInfo?: (data: { file: Omit; }) => BeforeUploadCallbackObjectInfo | Promise; } | void>; onAfterSignedUrl?: (data: { req: Request; metadata: UnknownMetadata; clientMetadata: unknown; files: FileInfo[]; }) => Promise<{ metadata?: UnknownMetadata; } | void>; }; type ExecRoute = () => Route; //#endregion export { BeforeUploadCallbackObjectInfo, ExecRoute, FileInfo, ObjectMetadata, Route, RouteConfig, StandardSchemaV1, UnknownMetadata };