import {z} from 'zod' export type AccountId = string; export type FolderPath = string; export type UnspecifiedFieldValue = {set: false}; export type FolderDescription = string; export type SpecifiedFieldValueEmptiableFolderDescription = {set: true, value?: FolderDescription | undefined}; export type PatchFolderDescription = UnspecifiedFieldValue | SpecifiedFieldValueEmptiableFolderDescription; export type TransformationUrlSlugPattern = string; export type FileDownloadGrantsArray = Array; export type PublicPermissionsGrantsFiles = {downloadFile: FileDownloadGrantsArray}; export type PublicPermissionsGrants = {file: PublicPermissionsGrantsFiles}; export type PathPermissionScope = 'Children' | 'Grandchildren+' | 'This'; export type PublicPermissions = {permissions: PublicPermissionsGrants, scope: PathPermissionScope}; export type SpecifiedFieldValueEmptiablePublicPermissionsArray = {set: true, value?: Array | undefined}; export type PatchFolderPublicPermissions = UnspecifiedFieldValue | SpecifiedFieldValueEmptiablePublicPermissionsArray; export type InternalStorageV2 = {mount?: FolderPath | undefined, type: 'InternalStorageV2'}; export type QueryStringNoPrefix = string; export type HttpUrl = string; export type QueryStringParamNameEncoded = string; export type WebStorageQueryStringParam = {name: QueryStringParamNameEncoded}; export type WebStorageQueryStringForwarding = {parameters: Array, type: 'Whitelist' | 'Blacklist'}; export type WebStorage = {appendQueryString?: QueryStringNoPrefix | undefined, baseUrl?: HttpUrl | undefined, queryStringForwarding?: WebStorageQueryStringForwarding | undefined, type: 'Web'}; export type AzureStorageContainerName = string; export type AzureStorageBlobNamePrefix = string; export type AzureStorageAccountName = string; export type AzureReadOnlyStorage = {azureStorage: {containerName: AzureStorageContainerName, blobNamePrefix: AzureStorageBlobNamePrefix, accountName: AzureStorageAccountName}, credentials: {sasToken: QueryStringNoPrefix}, type: 'AzureReadOnly', useAbsolutePaths: boolean}; export type S3ObjectKey = string; export type AwsRegion = 'us-east-2' | 'us-east-1' | 'us-west-1' | 'us-west-2' | 'af-south-1' | 'ap-east-1' | 'ap-south-2' | 'ap-southeast-3' | 'ap-southeast-4' | 'ap-south-1' | 'ap-northeast-3' | 'ap-northeast-2' | 'ap-southeast-1' | 'ap-southeast-2' | 'ap-northeast-1' | 'ca-central-1' | 'ca-west-1' | 'eu-central-1' | 'eu-west-1' | 'eu-west-2' | 'eu-south-1' | 'eu-west-3' | 'eu-south-2' | 'eu-north-1' | 'eu-central-2' | 'il-central-1' | 'me-south-1' | 'me-central-1' | 'sa-east-1'; export type S3BucketName = string; export type AwsSecretKey = string; export type AwsAccessKey = string; export type S3Storage = {bucket: {objectKeyPrefix: S3ObjectKey, bucketRegion: AwsRegion, bucketName: S3BucketName}, credentials: {awsSecretKey: AwsSecretKey, awsAccessKey: AwsAccessKey}, type: 'S3', useAbsolutePaths: boolean, useTransferAcceleration: boolean}; export type S3OperationName = 'DeleteObjects'; export type GenericS3Region = string; export type GenericS3Storage = {bucket: {unsupportedOperations: Array, objectKeyPrefix: S3ObjectKey, forcePathStyle: boolean, bucketRegion: GenericS3Region, bucketName: S3BucketName, bucketEndpoint: HttpUrl}, credentials: {secretKey: AwsSecretKey, accessKey: AwsAccessKey}, type: 'GenericS3', useAbsolutePaths: boolean}; export type DigitalOceanRegion = string; export type DigitalOceanStorage = {bucket: {objectKeyPrefix: S3ObjectKey, bucketRegion: DigitalOceanRegion, bucketName: S3BucketName}, credentials: {spacesSecretKey: AwsSecretKey, spacesAccessKey: AwsAccessKey}, type: 'DigitalOceanSpace', useAbsolutePaths: boolean}; export type CloudflareAccountId = string; export type R2Storage = {bucket: {objectKeyPrefix: S3ObjectKey, bucketName: S3BucketName}, cloudflareAccountId: CloudflareAccountId, credentials: {r2SecretKey: AwsSecretKey, r2AccessKey: AwsAccessKey}, type: 'R2', useAbsolutePaths: boolean}; export type GoogleBucketName = string; export type GoogleStorage = {bucket: {objectKeyPrefix: S3ObjectKey, bucketName: GoogleBucketName}, credentials: {googleSecretKey: AwsSecretKey, googleAccessKey: AwsAccessKey}, type: 'GoogleStorage', useAbsolutePaths: boolean}; export type StorageLayerUpdate = InternalStorageV2 | WebStorage | AzureReadOnlyStorage | S3Storage | GenericS3Storage | DigitalOceanStorage | R2Storage | GoogleStorage; export type SpecifiedFieldValueEmptiableStorageLayerUpdate = {set: true, value?: StorageLayerUpdate | undefined}; export type PatchFolderStorageLayer = UnspecifiedFieldValue | SpecifiedFieldValueEmptiableStorageLayerUpdate; export type PatchFolderSettings = {description?: PatchFolderDescription | undefined, publicPermissions?: PatchFolderPublicPermissions | undefined, storageLayer?: PatchFolderStorageLayer | undefined}; export type PutFolderRequest = {allowUnnamedFolder?: boolean | undefined, folderPath: FolderPath, folderSettings?: PatchFolderSettings | undefined}; export type UpdateApiV2AccountsAccountIdFoldersArgs = {accountId: AccountId, body: PutFolderRequest}; export type UpdateApiV2AccountsAccountIdFoldersOptions = {baseUrl?: string | undefined, authorizationHeader?: string | undefined, fetch?: typeof fetch | undefined}; export const folderPath = z.string().min(1).max(512); export const folderDescription = z.string().min(1).max(100); export const transformationUrlSlugPattern = z.string().min(1).max(100); export const fileDownloadGrantsArray = z.array(transformationUrlSlugPattern); export const publicPermissionsGrantsFiles = z.object({downloadFile: fileDownloadGrantsArray}); export const publicPermissionsGrants = z.object({file: publicPermissionsGrantsFiles}); export const pathPermissionScope = z.enum(["Children", "Grandchildren+", "This"]); export const publicPermissions = z.object({permissions: publicPermissionsGrants, scope: pathPermissionScope}); export const internalStorageV1 = z.object({type: z.literal("InternalStorageV1")}); export const internalStorageV2 = z.object({mount: folderPath.optional(), type: z.literal("InternalStorageV2")}); export const queryStringNoPrefix = z.string().max(1000); export const httpUrl = z.string().min(1).max(255); export const queryStringParamNameEncoded = z.string().min(1).max(50); export const webStorageQueryStringParam = z.object({name: queryStringParamNameEncoded}); export const webStorageQueryStringForwarding = z.object({parameters: z.array(webStorageQueryStringParam), type: z.enum(["Whitelist", "Blacklist"])}); export const webStorage = z.object({appendQueryString: queryStringNoPrefix.optional(), baseUrl: httpUrl.optional(), queryStringForwarding: webStorageQueryStringForwarding.optional(), type: z.literal("Web")}); export const azureStorageContainerName = z.string().min(3).max(63); export const azureStorageBlobNamePrefix = z.string().max(1024); export const azureStorageAccountName = z.string().min(3).max(24); export const pickAzureReadOnlyStorageExcludeKeyofAzureReadOnlyStorageCredentials = z.object({type: z.literal("AzureReadOnly"), azureStorage: z.object({containerName: azureStorageContainerName, blobNamePrefix: azureStorageBlobNamePrefix, accountName: azureStorageAccountName}), useAbsolutePaths: z.boolean()}); export const azureReadOnlyStorageWithoutCredentials = pickAzureReadOnlyStorageExcludeKeyofAzureReadOnlyStorageCredentials; export const s3ObjectKey = z.string().max(1024); export const awsRegion = z.enum(["us-east-2", "us-east-1", "us-west-1", "us-west-2", "af-south-1", "ap-east-1", "ap-south-2", "ap-southeast-3", "ap-southeast-4", "ap-south-1", "ap-northeast-3", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1", "ca-central-1", "ca-west-1", "eu-central-1", "eu-west-1", "eu-west-2", "eu-south-1", "eu-west-3", "eu-south-2", "eu-north-1", "eu-central-2", "il-central-1", "me-south-1", "me-central-1", "sa-east-1"]).min(1).max(20); export const s3BucketName = z.string().min(1).max(61); export const pickS3StorageExcludeKeyofS3StorageCredentials = z.object({type: z.literal("S3"), useAbsolutePaths: z.boolean(), bucket: z.object({objectKeyPrefix: s3ObjectKey, bucketRegion: awsRegion, bucketName: s3BucketName}), useTransferAcceleration: z.boolean()}); export const s3StorageWithoutCredentials = pickS3StorageExcludeKeyofS3StorageCredentials; export const s3OperationName = z.literal("DeleteObjects"); export const genericS3Region = z.string().min(1).max(50); export const pickGenericS3StorageExcludeKeyofGenericS3StorageCredentials = z.object({type: z.literal("GenericS3"), useAbsolutePaths: z.boolean(), bucket: z.object({unsupportedOperations: z.array(s3OperationName), objectKeyPrefix: s3ObjectKey, forcePathStyle: z.boolean(), bucketRegion: genericS3Region, bucketName: s3BucketName, bucketEndpoint: httpUrl})}); export const genericS3StorageWithoutCredentials = pickGenericS3StorageExcludeKeyofGenericS3StorageCredentials; export const digitalOceanRegion = z.string().min(4).max(4); export const pickDigitalOceanStorageExcludeKeyofDigitalOceanStorageCredentials = z.object({type: z.literal("DigitalOceanSpace"), useAbsolutePaths: z.boolean(), bucket: z.object({objectKeyPrefix: s3ObjectKey, bucketRegion: digitalOceanRegion, bucketName: s3BucketName})}); export const digitalOceanStorageWithoutCredentials = pickDigitalOceanStorageExcludeKeyofDigitalOceanStorageCredentials; export const cloudflareAccountId = z.string().min(1).max(64); export const pickR2StorageExcludeKeyofR2StorageCredentials = z.object({type: z.literal("R2"), useAbsolutePaths: z.boolean(), bucket: z.object({objectKeyPrefix: s3ObjectKey, bucketName: s3BucketName}), cloudflareAccountId: cloudflareAccountId}); export const r2StorageWithoutCredentials = pickR2StorageExcludeKeyofR2StorageCredentials; export const googleBucketName = z.string().min(1).max(61); export const pickGoogleStorageExcludeKeyofGoogleStorageCredentials = z.object({type: z.literal("GoogleStorage"), useAbsolutePaths: z.boolean(), bucket: z.object({objectKeyPrefix: s3ObjectKey, bucketName: googleBucketName})}); export const googleStorageWithoutCredentials = pickGoogleStorageExcludeKeyofGoogleStorageCredentials; export const storageLayerSummary = z.union([internalStorageV1, internalStorageV2, webStorage, azureReadOnlyStorageWithoutCredentials, s3StorageWithoutCredentials, genericS3StorageWithoutCredentials, digitalOceanStorageWithoutCredentials, r2StorageWithoutCredentials, googleStorageWithoutCredentials]); export const folderSettings = z.object({description: folderDescription.optional(), publicPermissions: z.array(publicPermissions).optional(), storageLayer: storageLayerSummary.optional()}); export const publicPermissionsInherited = z.object({folderPath: folderPath, value: z.array(publicPermissions)}); export const storageLayerInherited = z.object({folderPath: folderPath, value: storageLayerSummary}); export const folderSettingsInherited = z.object({publicPermissions: publicPermissionsInherited.optional(), storageLayer: storageLayerInherited.optional()}); export const folderDetails = z.object({folderPath: folderPath, settings: folderSettings, type: z.literal("Folder"), virtual: z.boolean(), settingsInherited: folderSettingsInherited}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Creates or updates the folder specified by the `folderPath`. * * If the folder's ancestors do not exist, they will be created automatically (with empty FolderSettings). * * Note: you don't need to create folders before uploading files to them. * * Requires a `secret_*` API key. Alternatively, you can use a `public_*` API key and JWT-based auth. * * PUT /v2/accounts/{accountId}/folders */ export const updateApiV2AccountsAccountIdFolders = async (args: UpdateApiV2AccountsAccountIdFoldersArgs, options?: UpdateApiV2AccountsAccountIdFoldersOptions) => { const {baseUrl = "https://api.bytescale.com", fetch: fetchFn = fetch, authorizationHeader} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (authorizationHeader !== undefined) headers.set("Authorization", authorizationHeader) const url = `${baseUrl.replace(/\/+$/, '')}/v2/accounts/${encodeURIComponent(String(args.accountId))}/folders${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "PUT", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(folderDetails, await res.json()) };