Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@linear-webdev/shared

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@linear-webdev/shared - npm Package Compare versions

Comparing version
1.0.2
to
1.0.3
+6
-0
dist/index.cjs

@@ -594,2 +594,8 @@ //#region rolldown:runtime

const baseMimeType = mimeType.replace(/\/.*$/, "");
console.log({
acceptedFilesArray,
fileName,
mimeType,
baseMimeType
});
return acceptedFilesArray.some((type) => {

@@ -596,0 +602,0 @@ const validType = type.trim().toLowerCase();

@@ -564,2 +564,8 @@ import * as Micro from "effect/Micro";

const baseMimeType = mimeType.replace(/\/.*$/, "");
console.log({
acceptedFilesArray,
fileName,
mimeType,
baseMimeType
});
return acceptedFilesArray.some((type) => {

@@ -566,0 +572,0 @@ const validType = type.trim().toLowerCase();

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","names":["newConfig: ExpandedRouteConfig","type","text","opts: UploadThingErrorOptions<TShape>","defaultClassListMerger: ClassListMerger","temp: string","j: number"],"sources":["../src/types.ts","../src/tagged-errors.ts","../src/utils.ts","../src/file-types.ts","../src/error.ts","../src/effect.ts","../src/component-utils.ts","../src/crypto.ts","../src/dropzone-utils.ts"],"sourcesContent":["import type { MimeType } from \"@linear-webdev/mime-types\";\n\nimport type { AllowedFileType } from \"./file-types\";\n\nexport type JsonValue = string | number | boolean | null | undefined;\nexport type JsonObject = { [key: string]: JsonValue | JsonObject | JsonArray };\nexport type JsonArray = (JsonValue | JsonObject)[];\nexport type Json = JsonValue | JsonObject | JsonArray;\n\nexport type Overwrite<T, U> = Omit<T, keyof U> & U;\nexport type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;\nexport type ErrorMessage<TError extends string> = TError;\nexport type Simplify<TType> = { [TKey in keyof TType]: TType[TKey] } & {};\nexport type MaybePromise<TType> = TType | Promise<TType>;\nexport type Either<TData, TError> =\n | { data: TData; error: null }\n | { data: null; error: TError };\nexport type ExtendObjectIf<Predicate, ToAdd> = undefined extends Predicate\n ? {}\n : ToAdd;\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>;\n }\n : T;\n\nexport interface FileProperties {\n name: string;\n size: number;\n type: string;\n lastModified?: number | undefined;\n}\n\nexport type ExtractHashPartsFn = (\n file: FileProperties,\n) => (string | number | undefined | null | boolean)[];\n\n/**\n * A subset of the standard RequestInit properties needed by UploadThing internally.\n * @see RequestInit from lib.dom.d.ts\n */\nexport interface RequestInitEsque {\n /**\n * Sets the request's body.\n */\n body?: FormData | ReadableStream | string | null;\n\n /**\n * Sets the request's associated headers.\n */\n headers?: [string, string][] | Record<string, string>;\n\n /**\n * The request's HTTP-style method.\n */\n method?: string;\n}\n\n/**\n * A subset of the standard Response properties needed by UploadThing internally.\n * @see Response from lib.dom.d.ts\n */\nexport interface ResponseEsque {\n status: number;\n statusText: string;\n ok: boolean;\n /**\n * @remarks\n * The built-in Response::json() method returns Promise<any>, but\n * that's not as type-safe as unknown. We use unknown because we're\n * more type-safe. You do want more type safety, right? 😉\n */\n json: <T = unknown>() => Promise<T>;\n text: () => Promise<string>;\n blob: () => Promise<Blob>;\n body: ReadableStream | null;\n\n headers: Headers;\n\n clone: () => ResponseEsque;\n}\n\nexport type MaybeUrl = string | URL;\n\n/**\n * A subset of the standard fetch function type needed by UploadThing internally.\n * @see fetch from lib.dom.d.ts\n */\nexport type FetchEsque = (\n input: RequestInfo | MaybeUrl,\n init?: RequestInit | RequestInitEsque,\n) => Promise<ResponseEsque>;\n\ntype PowOf2 = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024;\nexport type SizeUnit = \"B\" | \"KB\" | \"MB\" | \"GB\";\nexport type FileSize = `${PowOf2}${SizeUnit}`;\n\nexport type TimeShort = \"s\" | \"m\" | \"h\" | \"d\";\nexport type TimeLong = \"second\" | \"minute\" | \"hour\" | \"day\";\ntype SuggestedNumbers = 2 | 3 | 4 | 5 | 6 | 7 | 10 | 15 | 30 | 60;\ntype AutoCompleteableNumber = SuggestedNumbers | (number & {});\nexport type Time =\n | number\n | `1${TimeShort}`\n | `${AutoCompleteableNumber}${TimeShort}`\n | `1 ${TimeLong}`\n | `${AutoCompleteableNumber} ${TimeLong}s`;\n\nexport const ValidContentDispositions = [\"inline\", \"attachment\"] as const;\nexport type ContentDisposition = (typeof ValidContentDispositions)[number];\n\nexport const ValidACLs = [\"public-read\", \"private\"] as const;\nexport type ACL = (typeof ValidACLs)[number];\n\ntype ImageProperties = {\n /** Specify the width of the image. */\n width?: number;\n /** Specify the height of the image. */\n height?: number;\n /**\n * Specify the aspect ratio of the image.\n * @remarks If both width and height are specified, this will be ignored.\n */\n aspectRatio?: number;\n};\n\ntype AdditionalProperties<T> = Record<string, unknown> & T;\n\nexport type RouteConfig<TAdditionalProperties extends Record<string, unknown>> =\n {\n /**\n * Human-readable file size limit\n * @example \"1MB\"\n * @default https://docs.uploadthing.com/api-reference/server#defaults\n */\n maxFileSize: FileSize;\n /**\n * Maximum number of files allowed to be uploaded of this type\n * @example 10\n * @default https://docs.uploadthing.com/api-reference/server#defaults\n */\n maxFileCount: number;\n /**\n * Minimum number of files allowed to be uploaded of this type\n * @remarks Must be <= maxFileCount\n * @example 2\n * @default 1\n */\n minFileCount: number;\n /**\n * Specify the [content disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) of the uploaded file\n * @example \"attachment\"\n * @default \"inline\"\n */\n contentDisposition: ContentDisposition;\n /**\n * Specify the [access control list](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) of the uploaded file\n * @remarks This must be enabled for your app. See https://docs.uploadthing.com/regions-and-acl#access-controls.\n * @example \"private\"\n * @default \"public-read\"\n */\n acl?: ACL;\n /**\n * Additional properties to be passed to the client-side `useRouteConfig` hook\n * @remarks These properties are not validated on the server on upload\n */\n additionalProperties?: AdditionalProperties<TAdditionalProperties>;\n };\n\n/**\n * Shared config options for an entire route not bound to any specific file type\n * @example\n * ```ts\n * f(\n * { image: {} },\n * { awaitServerData: true },\n * )\n * ```\n */\nexport type RouteOptions = {\n /**\n * Set this to `false` to run the client-side `onClientUploadComplete`\n * immediately after file has been uploaded without waiting for the\n * server to return the `onUploadComplete` data.\n * @default true\n */\n awaitServerData?: boolean;\n /**\n * TTL for the presigned URLs generated for the upload\n * @default `1h`\n */\n presignedURLTTL?: Time;\n /**\n * Function that pulls out the properties of the uploaded file\n * that you want to be included as part of the presigned URL generation.\n * By default, we include all properties as well as a timestamp to make\n * each URL unique. You can for example override this to always return\n * the same hash for the same file, no matter when it was uploaded.\n * @default (file) => [file.name, file.size, file.type, file.lastModified, Date.now()]\n */\n getFileHashParts?: ExtractHashPartsFn;\n};\n\nexport type FileRouterInputKey = AllowedFileType | MimeType;\n\nexport type ExpandedRouteConfig = {\n [key in FileRouterInputKey]?: key extends `image${string}`\n ? RouteConfig<ImageProperties>\n : RouteConfig<Record<string, unknown>>;\n};\n\nexport type EndpointMetadata = {\n slug: string;\n config: ExpandedRouteConfig;\n}[];\n\nexport type FileRouterInputConfig =\n | FileRouterInputKey[]\n | DeepPartial<ExpandedRouteConfig>;\n","import * as Micro from \"effect/Micro\";\nimport * as Predicate from \"effect/Predicate\";\n\nexport class InvalidRouteConfigError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidRouteConfig\")<{\n reason: string;\n }>\n{\n constructor(type: string, field?: string) {\n const reason = field\n ? `Expected route config to have a ${field} for key ${type} but none was found.`\n : `Encountered an invalid route config during backfilling. ${type} was not found.`;\n super({ reason });\n }\n}\n\nexport class UnknownFileTypeError\n extends /** #__PURE__ */ Micro.TaggedError(\"UnknownFileType\")<{\n reason: string;\n }>\n{\n constructor(fileName: string) {\n const reason = `Could not determine type for ${fileName}`;\n super({ reason });\n }\n}\n\nexport class InvalidFileTypeError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidFileType\")<{\n reason: string;\n }>\n{\n constructor(fileType: string, fileName: string) {\n const reason = `File type ${fileType} not allowed for ${fileName}`;\n super({ reason });\n }\n}\n\nexport class InvalidFileSizeError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidFileSize\")<{\n reason: string;\n }>\n{\n constructor(fileSize: string) {\n const reason = `Invalid file size: ${fileSize}`;\n super({ reason });\n }\n}\n\nexport class InvalidURLError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidURL\")<{\n reason: string;\n }>\n{\n constructor(attemptedUrl: string) {\n super({ reason: `Failed to parse '${attemptedUrl}' as a URL.` });\n }\n}\n\nexport class RetryError\n extends /** #__PURE__ */ Micro.TaggedError(\"RetryError\") {}\n\nexport class FetchError\n extends /** #__PURE__ */ Micro.TaggedError(\"FetchError\")<{\n readonly input: {\n url: string;\n method: string | undefined;\n body: unknown;\n headers: Record<string, string>;\n };\n readonly error: unknown;\n }> {}\n\nexport class InvalidJsonError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidJson\")<{\n readonly input: unknown;\n readonly error: unknown;\n }> {}\n\nexport class BadRequestError<T = unknown>\n extends /** #__PURE__ */ Micro.TaggedError(\"BadRequestError\")<{\n readonly message: string;\n readonly status: number;\n readonly json: T;\n }>\n{\n getMessage() {\n if (Predicate.isRecord(this.json)) {\n if (typeof this.json.message === \"string\") return this.json.message;\n }\n return this.message;\n }\n}\n\nexport class UploadPausedError\n extends /** #__PURE__ */ Micro.TaggedError(\"UploadAborted\") {}\n\nexport class UploadAbortedError\n extends /** #__PURE__ */ Micro.TaggedError(\"UploadAborted\") {}\n","import * as Micro from \"effect/Micro\";\n\nimport { lookup } from \"@linear-webdev/mime-types\";\n\nimport type { AllowedFileType } from \"./file-types\";\nimport {\n InvalidFileSizeError,\n InvalidFileTypeError,\n InvalidRouteConfigError,\n InvalidURLError,\n UnknownFileTypeError,\n} from \"./tagged-errors\";\nimport type {\n ExpandedRouteConfig,\n FileProperties,\n FileRouterInputConfig,\n FileRouterInputKey,\n FileSize,\n Json,\n ResponseEsque,\n RouteConfig,\n Time,\n TimeShort,\n} from \"./types\";\n\nexport function isRouteArray(\n routeConfig: FileRouterInputConfig,\n): routeConfig is FileRouterInputKey[] {\n return Array.isArray(routeConfig);\n}\n\nexport function getDefaultSizeForType(fileType: FileRouterInputKey): FileSize {\n if (fileType === \"image\") return \"4MB\";\n if (fileType === \"video\") return \"16MB\";\n if (fileType === \"audio\") return \"8MB\";\n if (fileType === \"blob\") return \"8MB\";\n if (fileType === \"pdf\") return \"4MB\";\n if (fileType === \"text\") return \"64KB\";\n\n return \"4MB\";\n}\n\nexport function getDefaultRouteConfigValues(\n type: FileRouterInputKey,\n): RouteConfig<Record<string, never>> {\n return {\n maxFileSize: getDefaultSizeForType(type),\n maxFileCount: 1,\n minFileCount: 1,\n contentDisposition: \"inline\" as const,\n };\n}\n\n/**\n * This function takes in the user's input and \"upscales\" it to a full config\n * Additionally, it replaces numbers with \"safe\" equivalents\n *\n * Example:\n * ```ts\n * [\"image\"] => { image: { maxFileSize: \"4MB\", limit: 1 } }\n * ```\n */\n\nexport const fillInputRouteConfig = (\n routeConfig: FileRouterInputConfig,\n): Micro.Micro<ExpandedRouteConfig, InvalidRouteConfigError> => {\n // If array, apply defaults\n if (isRouteArray(routeConfig)) {\n return Micro.succeed(\n routeConfig.reduce<ExpandedRouteConfig>((acc, fileType) => {\n acc[fileType] = getDefaultRouteConfigValues(fileType);\n return acc;\n }, {}),\n );\n }\n\n // Backfill defaults onto config\n const newConfig: ExpandedRouteConfig = {};\n for (const key of objectKeys(routeConfig)) {\n const value = routeConfig[key];\n if (!value) return Micro.fail(new InvalidRouteConfigError(key));\n newConfig[key] = { ...getDefaultRouteConfigValues(key), ...value };\n }\n\n // we know that the config is valid, so we can stringify it and parse it back\n // this allows us to replace numbers with \"safe\" equivalents\n return Micro.succeed(\n JSON.parse(\n JSON.stringify(newConfig, safeNumberReplacer),\n ) as ExpandedRouteConfig,\n );\n};\n\n/**\n * Match the file's type for a given allow list e.g. `image/png => image`\n * Prefers the file's type, then falls back to a extension-based lookup\n */\nexport const matchFileType = (\n file: FileProperties,\n allowedTypes: FileRouterInputKey[],\n): Micro.Micro<\n FileRouterInputKey,\n UnknownFileTypeError | InvalidFileTypeError\n> => {\n // Type might be \"\" if the browser doesn't recognize the mime type\n const mimeType = file.type || lookup(file.name);\n if (!mimeType) {\n if (allowedTypes.includes(\"blob\")) return Micro.succeed(\"blob\");\n return Micro.fail(new UnknownFileTypeError(file.name));\n }\n\n // If the user has specified a specific mime type, use that\n if (allowedTypes.some((type) => type.includes(\"/\"))) {\n if (allowedTypes.includes(mimeType as FileRouterInputKey)) {\n return Micro.succeed(mimeType as FileRouterInputKey);\n }\n }\n\n // Otherwise, we have a \"magic\" type eg. \"image\" or \"video\"\n const type = (\n mimeType.toLowerCase() === \"application/pdf\"\n ? \"pdf\"\n : mimeType.split(\"/\")[0]\n ) as AllowedFileType;\n\n if (!allowedTypes.includes(type)) {\n // Blob is a catch-all for any file type not explicitly supported\n if (allowedTypes.includes(\"blob\")) {\n return Micro.succeed(\"blob\");\n } else {\n return Micro.fail(new InvalidFileTypeError(type, file.name));\n }\n }\n\n return Micro.succeed(type);\n};\n\nexport const FILESIZE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"] as const;\nexport type FileSizeUnit = (typeof FILESIZE_UNITS)[number];\nexport const fileSizeToBytes = (\n fileSize: FileSize,\n): Micro.Micro<number, InvalidFileSizeError> => {\n const regex = new RegExp(\n `^(\\\\d+)(\\\\.\\\\d+)?\\\\s*(${FILESIZE_UNITS.join(\"|\")})$`,\n \"i\",\n );\n\n // make sure the string is in the format of 123KB\n const match = regex.exec(fileSize);\n if (!match?.[1] || !match[3]) {\n return Micro.fail(new InvalidFileSizeError(fileSize));\n }\n\n const sizeValue = parseFloat(match[1]);\n const sizeUnit = match[3].toUpperCase() as FileSizeUnit;\n const bytes = sizeValue * Math.pow(1024, FILESIZE_UNITS.indexOf(sizeUnit));\n return Micro.succeed(Math.floor(bytes));\n};\n\nexport const bytesToFileSize = (bytes: number) => {\n if (bytes === 0 || bytes === -1) {\n return \"0B\";\n }\n\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n return `${(bytes / Math.pow(1024, i)).toFixed(2)}${FILESIZE_UNITS[i]}`;\n};\n\nexport async function safeParseJSON<T>(\n input: ResponseEsque,\n): Promise<T | Error> {\n const text = await input.text();\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Error parsing JSON, got '${text}'`, err);\n return new Error(`Error parsing JSON, got '${text}'`);\n }\n}\n\n/** typesafe Object.keys */\nexport function objectKeys<T extends Record<string, unknown>>(\n obj: T,\n): (keyof T)[] {\n return Object.keys(obj) as (keyof T)[];\n}\n\nexport function filterDefinedObjectValues<T>(\n obj: Record<string, T | null | undefined>,\n): Record<string, T> {\n return Object.fromEntries(\n Object.entries(obj).filter((pair): pair is [string, T] => pair[1] != null),\n );\n}\n\nexport function semverLite(required: string, toCheck: string) {\n // Pull out numbers from strings like `6.0.0`, `^6.4`, `~6.4.0`\n const semverRegex = /(\\d+)\\.?(\\d+)?\\.?(\\d+)?/;\n const requiredMatch = semverRegex.exec(required);\n if (!requiredMatch?.[0]) {\n throw new Error(`Invalid semver requirement: ${required}`);\n }\n const toCheckMatch = semverRegex.exec(toCheck);\n if (!toCheckMatch?.[0]) {\n throw new Error(`Invalid semver to check: ${toCheck}`);\n }\n\n const [_1, rMajor, rMinor, rPatch] = requiredMatch;\n const [_2, cMajor, cMinor, cPatch] = toCheckMatch;\n\n if (required.startsWith(\"^\")) {\n // Major must be equal, minor must be greater or equal\n if (rMajor !== cMajor) return false;\n if (rMinor && cMinor && rMinor > cMinor) return false;\n return true;\n }\n\n if (required.startsWith(\"~\")) {\n // Major must be equal, minor must be equal\n if (rMajor !== cMajor) return false;\n if (rMinor !== cMinor) return false;\n return true;\n }\n\n // Exact match\n return rMajor === cMajor && rMinor === cMinor && rPatch === cPatch;\n}\n\nexport function warnIfInvalidPeerDependency(\n pkg: string,\n required: string,\n toCheck: string,\n) {\n if (!semverLite(required, toCheck)) {\n // eslint-disable-next-line no-console\n console.warn(\n `!!!WARNING::: ${pkg} requires \"uploadthing@${required}\", but version \"${toCheck}\" is installed`,\n );\n }\n}\n\nexport const getRequestUrl = (req: Request) =>\n Micro.gen(function* () {\n const host = req.headers.get(\"x-forwarded-host\") ?? req.headers.get(\"host\");\n const proto = req.headers.get(\"x-forwarded-proto\") ?? \"https\";\n const protocol = proto.endsWith(\":\") ? proto : `${proto}:`;\n const url = yield* Micro.try({\n try: () => new URL(req.url, `${protocol}//${host}`),\n catch: () => new InvalidURLError(req.url),\n });\n url.search = \"\";\n return url;\n });\n\nexport const getFullApiUrl = (\n maybeUrl?: string,\n): Micro.Micro<URL, InvalidURLError> =>\n Micro.gen(function* () {\n const base = (() => {\n if (typeof window !== \"undefined\") return window.location.origin;\n if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;\n return \"http://localhost:3000\";\n })();\n\n const url = yield* Micro.try({\n try: () => new URL(maybeUrl ?? \"/api/uploadthing\", base),\n catch: () => new InvalidURLError(maybeUrl ?? \"/api/uploadthing\"),\n });\n\n if (url.pathname === \"/\") {\n url.pathname = \"/api/uploadthing\";\n }\n return url;\n });\n\n/*\n * Returns a full URL to the dev's uploadthing endpoint\n * Can take either an origin, or a pathname, or a full URL\n * and will return the \"closest\" url matching the default\n * `<VERCEL_URL || localhost>/api/uploadthing`\n */\nexport const resolveMaybeUrlArg = (maybeUrl: string | URL | undefined): URL => {\n return maybeUrl instanceof URL\n ? maybeUrl\n : Micro.runSync(getFullApiUrl(maybeUrl));\n};\n\nexport function parseTimeToSeconds(time: Time) {\n if (typeof time === \"number\") return time;\n\n const match = time.split(/(\\d+)/).filter(Boolean);\n const num = Number(match[0]);\n const unit = (match[1] ?? \"s\").trim().slice(0, 1) as TimeShort;\n\n const multiplier = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n }[unit];\n\n return num * multiplier;\n}\n\n/**\n * Replacer for JSON.stringify that will replace numbers that cannot be\n * serialized to JSON with \"reasonable equivalents\".\n *\n * Infinity and -Infinity are replaced by MAX_SAFE_INTEGER and MIN_SAFE_INTEGER\n * NaN is replaced by 0\n *\n */\nexport const safeNumberReplacer = (_: string, value: unknown) => {\n if (typeof value !== \"number\") return value;\n if (\n Number.isSafeInteger(value) ||\n (value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER)\n ) {\n return value;\n }\n if (value === Infinity) return Number.MAX_SAFE_INTEGER;\n if (value === -Infinity) return Number.MIN_SAFE_INTEGER;\n if (Number.isNaN(value)) return 0;\n};\n\nexport function noop() {\n // noop\n}\n\nexport function createIdentityProxy<TObj extends Record<string, unknown>>() {\n return new Proxy(noop, {\n get: (_, prop) => prop,\n }) as unknown as TObj;\n}\n\nexport function unwrap<T extends Json | PropertyKey, Param extends unknown[]>(\n x: T | ((...args: Param) => T),\n ...args: Param\n) {\n return typeof x === \"function\" ? x(...args) : x;\n}\n","export const ALLOWED_FILE_TYPES = [\n \"image\",\n \"video\",\n \"audio\",\n \"pdf\",\n \"text\",\n \"blob\",\n] as const;\n\nexport type AllowedFileType = (typeof ALLOWED_FILE_TYPES)[number];\n","import * as Micro from \"effect/Micro\";\nimport * as Predicate from \"effect/Predicate\";\n\nimport type { Json } from \"./types\";\n\nconst ERROR_CODES = {\n // Generic\n BAD_REQUEST: 400,\n NOT_FOUND: 404,\n FORBIDDEN: 403,\n INTERNAL_SERVER_ERROR: 500,\n INTERNAL_CLIENT_ERROR: 500,\n\n // S3 specific\n TOO_LARGE: 413,\n TOO_SMALL: 400,\n TOO_MANY_FILES: 400,\n KEY_TOO_LONG: 400,\n\n // UploadThing specific\n URL_GENERATION_FAILED: 500,\n UPLOAD_FAILED: 500,\n MISSING_ENV: 500,\n INVALID_SERVER_CONFIG: 500,\n FILE_LIMIT_EXCEEDED: 500,\n} as const;\n\ntype ErrorCode = keyof typeof ERROR_CODES;\ntype UploadThingErrorOptions<T> = {\n code: keyof typeof ERROR_CODES;\n message?: string | undefined;\n cause?: unknown;\n data?: T;\n};\n\nfunction messageFromUnknown(cause: unknown, fallback?: string) {\n if (typeof cause === \"string\") {\n return cause;\n }\n if (cause instanceof Error) {\n return cause.message;\n }\n if (\n cause &&\n typeof cause === \"object\" &&\n \"message\" in cause &&\n typeof cause.message === \"string\"\n ) {\n return cause.message;\n }\n return fallback ?? \"An unknown error occurred\";\n}\n\nexport interface SerializedUploadThingError {\n code: ErrorCode;\n message: string;\n data?: Json;\n}\n\nexport class UploadThingError<\n TShape extends Json = { message: string },\n> extends Micro.Error<{ message: string }> {\n readonly _tag = \"UploadThingError\";\n readonly name = \"UploadThingError\";\n\n public readonly cause?: unknown;\n public readonly code: ErrorCode;\n public readonly data: TShape | undefined;\n\n constructor(initOpts: UploadThingErrorOptions<TShape> | string) {\n const opts: UploadThingErrorOptions<TShape> =\n typeof initOpts === \"string\"\n ? { code: \"INTERNAL_SERVER_ERROR\", message: initOpts }\n : initOpts;\n const message = opts.message ?? messageFromUnknown(opts.cause, opts.code);\n\n super({ message });\n this.code = opts.code;\n this.data = opts.data;\n\n if (opts.cause instanceof Error) {\n this.cause = opts.cause;\n } else if (\n Predicate.isRecord(opts.cause) &&\n Predicate.isNumber(opts.cause.status) &&\n Predicate.isString(opts.cause.statusText)\n ) {\n this.cause = new Error(\n `Response ${opts.cause.status} ${opts.cause.statusText}`,\n );\n } else if (Predicate.isString(opts.cause)) {\n this.cause = new Error(opts.cause);\n } else {\n this.cause = opts.cause;\n }\n }\n\n public static toObject(error: UploadThingError): SerializedUploadThingError {\n return {\n code: error.code,\n message: error.message,\n data: error.data,\n };\n }\n\n public static serialize(error: UploadThingError) {\n return JSON.stringify(UploadThingError.toObject(error));\n }\n}\n\nexport function getErrorTypeFromStatusCode(statusCode: number): ErrorCode {\n for (const [code, status] of Object.entries(ERROR_CODES)) {\n if (status === statusCode) {\n return code as ErrorCode;\n }\n }\n return \"INTERNAL_SERVER_ERROR\";\n}\n\nexport function getStatusCodeFromError(error: UploadThingError<any>) {\n return ERROR_CODES[error.code];\n}\n\nexport const INTERNAL_DO_NOT_USE__fatalClientError = (e: Error) =>\n new UploadThingError({\n code: \"INTERNAL_CLIENT_ERROR\",\n message: \"Something went wrong. Please report this to UploadThing.\",\n cause: e,\n });\n","import * as Context from \"effect/Context\";\nimport * as Micro from \"effect/Micro\";\n\nimport { BadRequestError, FetchError, InvalidJsonError } from \"./tagged-errors\";\nimport type { FetchEsque, ResponseEsque } from \"./types\";\n\nexport class FetchContext\n extends /** #__PURE__ */ Context.Tag(\"uploadthing/Fetch\")<\n FetchContext,\n FetchEsque\n >() {}\n\ninterface ResponseWithURL extends ResponseEsque {\n requestUrl: string;\n}\n\n// Temporary Effect wrappers below.\n// Only for use in the browser.\n// On the server, use `@effect/platform.HttpClient` instead.\nexport const fetchEff = (\n input: string | URL,\n init?: RequestInit,\n): Micro.Micro<ResponseWithURL, FetchError, FetchContext> =>\n Micro.flatMap(Micro.service(FetchContext), (fetch) => {\n const headers = new Headers(init?.headers ?? []);\n\n const reqInfo = {\n url: input.toString(),\n method: init?.method,\n body: init?.body,\n headers: Object.fromEntries(headers),\n };\n\n return Micro.tryPromise({\n try: (signal) => fetch(input, { ...init, headers, signal }),\n catch: (error) =>\n new FetchError({\n error:\n error instanceof Error\n ? {\n ...error,\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n input: reqInfo,\n }),\n }).pipe(\n // eslint-disable-next-line no-console\n Micro.tapError((e) => Micro.sync(() => console.error(e.input))),\n Micro.map((res) => Object.assign(res, { requestUrl: reqInfo.url })),\n Micro.withTrace(\"fetch\"),\n );\n });\n\nexport const parseResponseJson = (\n res: ResponseWithURL,\n): Micro.Micro<unknown, InvalidJsonError | BadRequestError> =>\n Micro.tryPromise({\n try: async () => {\n const json = await res.json();\n return { json, ok: res.ok, status: res.status };\n },\n catch: (error) => new InvalidJsonError({ error, input: res.requestUrl }),\n }).pipe(\n Micro.filterOrFail(\n ({ ok }) => ok,\n ({ json, status }) =>\n new BadRequestError({\n status,\n message: `Request to ${res.requestUrl} failed with status ${status}`,\n json,\n }),\n ),\n Micro.map(({ json }) => json),\n Micro.withTrace(\"parseJson\"),\n );\n","import type { CSSProperties, ReactNode } from \"react\";\nimport type { JSX } from \"solid-js/jsx-runtime\";\nimport type { RenderFunction, StyleValue } from \"vue\";\n\n/**\n * Use granular imports to better tree-shake\n * We don't need all the types, and `/application`\n * entrypoint is ~7k gzip which we can shave off\n */\nimport { audio } from \"@linear-webdev/mime-types/audio\";\nimport { image } from \"@linear-webdev/mime-types/image\";\nimport { text } from \"@linear-webdev/mime-types/text\";\nimport { video } from \"@linear-webdev/mime-types/video\";\n\nimport type { ExpandedRouteConfig } from \"./types\";\nimport { objectKeys } from \"./utils\";\n\nexport type ProgressGranularity = \"all\" | \"fine\" | \"coarse\";\nexport const roundProgress = (\n progress: number,\n granularity: ProgressGranularity,\n) => {\n if (granularity === \"all\") return progress;\n if (granularity === \"fine\") return Math.round(progress);\n return Math.floor(progress / 10) * 10;\n};\n\nexport const generateMimeTypes = (\n typesOrRouteConfig: string[] | ExpandedRouteConfig,\n) => {\n const fileTypes = Array.isArray(typesOrRouteConfig)\n ? typesOrRouteConfig\n : objectKeys(typesOrRouteConfig);\n if (fileTypes.includes(\"blob\")) return [];\n\n return fileTypes.map((type) => {\n if (type === \"pdf\") return \"application/pdf\";\n if (type.includes(\"/\")) return type;\n\n // Add wildcard to support all subtypes, e.g. image => \"image/*\"\n // But some browsers/OSes don't support it, so we'll also dump all the mime types\n // we know that starts with the type, e.g. image => \"image/png, image/jpeg, ...\"\n if (type === \"audio\") return [\"audio/*\", ...objectKeys(audio)].join(\", \");\n if (type === \"image\") return [\"image/*\", ...objectKeys(image)].join(\", \");\n if (type === \"text\") return [\"text/*\", ...objectKeys(text)].join(\", \");\n if (type === \"video\") return [\"video/*\", ...objectKeys(video)].join(\", \");\n\n return `${type}/*`;\n });\n};\n\nexport const generateClientDropzoneAccept = (fileTypes: string[]) => {\n const mimeTypes = generateMimeTypes(fileTypes);\n return Object.fromEntries(mimeTypes.map((type) => [type, []]));\n};\n\nexport function getFilesFromClipboardEvent(event: ClipboardEvent) {\n const dataTransferItems = event.clipboardData?.items;\n if (!dataTransferItems) return;\n\n const files = Array.from(dataTransferItems).reduce<File[]>((acc, curr) => {\n const f = curr.getAsFile();\n return f ? [...acc, f] : acc;\n }, []);\n\n return files;\n}\n\n/**\n * Shared helpers for our premade components that's reusable by multiple frameworks\n */\n\nexport const generatePermittedFileTypes = (config?: ExpandedRouteConfig) => {\n const fileTypes = config ? objectKeys(config) : [];\n\n const maxFileCount = config\n ? Object.values(config).map((v) => v.maxFileCount)\n : [];\n\n return { fileTypes, multiple: maxFileCount.some((v) => v && v > 1) };\n};\n\nexport const capitalizeStart = (str: string) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n};\n\nexport const INTERNAL_doFormatting = (config?: ExpandedRouteConfig): string => {\n if (!config) return \"\";\n\n const allowedTypes = objectKeys(config);\n\n const formattedTypes = allowedTypes.map((f) => (f === \"blob\" ? \"file\" : f));\n\n // Format multi-type uploader label as \"Supports videos, images and files\";\n if (formattedTypes.length > 1) {\n const lastType = formattedTypes.pop();\n return `${formattedTypes.join(\"s, \")} and ${lastType}s`;\n }\n\n // Single type uploader label\n const key = allowedTypes[0];\n const formattedKey = formattedTypes[0];\n if (!key || !formattedKey) return \"\";\n\n const { maxFileSize, maxFileCount, minFileCount } = config[key]!;\n\n if (maxFileCount && maxFileCount > 1) {\n if (minFileCount > 1) {\n return `${minFileCount} - ${maxFileCount} ${formattedKey}s up to ${maxFileSize}`;\n } else {\n return `${formattedKey}s up to ${maxFileSize}, max ${maxFileCount}`;\n }\n } else {\n return `${formattedKey} (${maxFileSize})`;\n }\n};\n\nexport const allowedContentTextLabelGenerator = (\n config?: ExpandedRouteConfig,\n): string => {\n return capitalizeStart(INTERNAL_doFormatting(config));\n};\n\ntype AnyRuntime = \"react\" | \"solid\" | \"svelte\" | \"vue\";\ntype MinCallbackArg = { __runtime: AnyRuntime };\ntype inferRuntime<T extends MinCallbackArg> = T[\"__runtime\"] extends \"react\"\n ? \"react\"\n : T[\"__runtime\"] extends \"solid\"\n ? \"solid\"\n : T[\"__runtime\"] extends \"svelte\"\n ? \"svelte\"\n : T[\"__runtime\"] extends \"vue\"\n ? \"vue\"\n : never;\n\ntype ElementEsque<TRuntime extends AnyRuntime> = TRuntime extends \"react\"\n ? ReactNode\n : TRuntime extends \"solid\"\n ? JSX.Element\n : ReturnType<RenderFunction>;\ntype CSSPropertiesEsque<TRuntime extends AnyRuntime> = TRuntime extends \"react\"\n ? CSSProperties\n : TRuntime extends \"solid\"\n ? JSX.CSSProperties\n : TRuntime extends \"svelte\"\n ? string\n : TRuntime extends \"vue\"\n ? StyleValue\n : never;\n\nexport type StyleField<\n CallbackArg extends MinCallbackArg,\n TRuntime extends AnyRuntime = inferRuntime<CallbackArg>,\n> =\n | string\n | CSSPropertiesEsque<TRuntime>\n | ((\n arg: Omit<CallbackArg, \"__runtime\">,\n ) => string | CSSPropertiesEsque<TRuntime>);\n\nexport type ContentField<\n CallbackArg extends MinCallbackArg,\n TRuntime extends AnyRuntime = inferRuntime<CallbackArg>,\n> =\n | ElementEsque<TRuntime>\n | ((arg: Omit<CallbackArg, \"__runtime\">) => ElementEsque<TRuntime>);\n\nexport const styleFieldToClassName = <T extends MinCallbackArg>(\n styleField: StyleField<T> | undefined,\n args: T,\n) => {\n if (typeof styleField === \"string\") return styleField;\n if (typeof styleField === \"function\") {\n const result = styleField(args);\n\n if (typeof result === \"string\") return result;\n }\n\n return \"\";\n};\n\nexport const styleFieldToCssObject = <T extends MinCallbackArg>(\n styleField: StyleField<T> | undefined,\n args: T,\n) => {\n if (typeof styleField === \"object\") return styleField;\n if (typeof styleField === \"function\") {\n const result = styleField(args);\n\n if (typeof result === \"object\") return result;\n }\n\n return {};\n};\n\nexport const contentFieldToContent = <T extends MinCallbackArg>(\n contentField: ContentField<T> | undefined,\n arg: T,\n) => {\n if (!contentField) return null;\n if (typeof contentField !== \"function\") return contentField;\n if (typeof contentField === \"function\") {\n const result = contentField(arg);\n\n return result;\n }\n};\n\nexport type ClassListMerger = (\n ...classes: (string | null | undefined | false)[]\n) => string;\nexport const defaultClassListMerger: ClassListMerger = (...classes) => {\n return classes.filter(Boolean).join(\" \");\n};\n","import * as Encoding from \"effect/Encoding\";\nimport * as Hash from \"effect/Hash\";\nimport * as Micro from \"effect/Micro\";\nimport * as Redacted from \"effect/Redacted\";\nimport SQIds, { defaultOptions } from \"sqids\";\n\nimport { UploadThingError } from \"./error\";\nimport type { ExtractHashPartsFn, FileProperties, Time } from \"./types\";\nimport { parseTimeToSeconds } from \"./utils\";\n\nconst signaturePrefix = \"hmac-sha256=\";\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\nconst encoder = new TextEncoder();\n\nfunction shuffle(str: string, seed: string) {\n const chars = str.split(\"\");\n const seedNum = Hash.string(seed);\n\n let temp: string;\n let j: number;\n for (let i = 0; i < chars.length; i++) {\n j = ((seedNum % (i + 1)) + i) % chars.length;\n temp = chars[i]!;\n chars[i] = chars[j]!;\n chars[j] = temp;\n }\n\n return chars.join(\"\");\n}\n\nexport const signPayload = (\n payload: string,\n secret: Redacted.Redacted<string>,\n) =>\n Micro.gen(function* () {\n const signingKey = yield* Micro.tryPromise({\n try: () =>\n crypto.subtle.importKey(\n \"raw\",\n encoder.encode(Redacted.value(secret)),\n algorithm,\n false,\n [\"sign\"],\n ),\n catch: (e) =>\n new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"Invalid signing secret\",\n cause: e,\n }),\n });\n\n const signature = yield* Micro.map(\n Micro.tryPromise({\n try: () =>\n crypto.subtle.sign(algorithm, signingKey, encoder.encode(payload)),\n catch: (e) => new UploadThingError({ code: \"BAD_REQUEST\", cause: e }),\n }),\n (arrayBuffer) => Encoding.encodeHex(new Uint8Array(arrayBuffer)),\n );\n\n return `${signaturePrefix}${signature}`;\n }).pipe(Micro.withTrace(\"signPayload\"));\n\nexport const verifySignature = (\n payload: string,\n signature: string | null,\n secret: Redacted.Redacted<string>,\n) =>\n Micro.gen(function* () {\n const sig = signature?.slice(signaturePrefix.length);\n if (!sig) return false;\n\n const secretBytes = encoder.encode(Redacted.value(secret));\n const signingKey = yield* Micro.promise(() =>\n crypto.subtle.importKey(\"raw\", secretBytes, algorithm, false, [\"verify\"]),\n );\n\n const sigBytes = yield* Micro.fromEither(Encoding.decodeHex(sig));\n const payloadBytes = encoder.encode(payload);\n return yield* Micro.promise(() =>\n crypto.subtle.verify(algorithm, signingKey, sigBytes, payloadBytes),\n );\n }).pipe(\n Micro.withTrace(\"verifySignature\"),\n Micro.orElseSucceed(() => false),\n );\n\nexport const generateKey = (\n file: FileProperties,\n appId: string,\n getHashParts?: ExtractHashPartsFn,\n) =>\n Micro.sync(() => {\n // Get the parts of which we should hash to constuct the key\n // This allows the user to customize the hashing algorithm\n // If they for example want to generate the same key for the\n // same file whenever it was uploaded\n const hashParts = JSON.stringify(\n getHashParts?.(file) ?? [\n file.name,\n file.size,\n file.type,\n file.lastModified,\n Date.now(),\n ],\n );\n\n // Hash and Encode the parts and appId as sqids\n const alphabet = shuffle(defaultOptions.alphabet, appId);\n const encodedFileSeed = new SQIds({ alphabet, minLength: 36 }).encode([\n Math.abs(Hash.string(hashParts)),\n ]);\n const encodedAppId = new SQIds({ alphabet, minLength: 12 }).encode([\n Math.abs(Hash.string(appId)),\n ]);\n\n // Concatenate them\n return encodedAppId + encodedFileSeed;\n }).pipe(Micro.withTrace(\"generateKey\"));\n\n// Verify that the key was generated with the same appId\nexport const verifyKey = (key: string, appId: string) =>\n Micro.sync(() => {\n const alphabet = shuffle(defaultOptions.alphabet, appId);\n const expectedPrefix = new SQIds({ alphabet, minLength: 12 }).encode([\n Math.abs(Hash.string(appId)),\n ]);\n\n return key.startsWith(expectedPrefix);\n }).pipe(\n Micro.withTrace(\"verifyKey\"),\n Micro.orElseSucceed(() => false),\n );\n\nexport const generateSignedURL = (\n url: string | URL,\n secretKey: Redacted.Redacted<string>,\n opts: {\n ttlInSeconds?: Time | undefined;\n data?: Record<string, string | number | boolean | null | undefined>;\n },\n) =>\n Micro.gen(function* () {\n const parsedURL = new URL(url);\n\n const ttl = opts.ttlInSeconds\n ? parseTimeToSeconds(opts.ttlInSeconds)\n : 60 * 60;\n\n const expirationTime = Date.now() + ttl * 1000;\n parsedURL.searchParams.append(\"expires\", expirationTime.toString());\n\n if (opts.data) {\n Object.entries(opts.data).forEach(([key, value]) => {\n if (value == null) return;\n const encoded = encodeURIComponent(value);\n parsedURL.searchParams.append(key, encoded);\n });\n }\n\n const signature = yield* signPayload(parsedURL.toString(), secretKey);\n parsedURL.searchParams.append(\"signature\", signature);\n\n return parsedURL.href;\n }).pipe(Micro.withTrace(\"generateSignedURL\"));\n","export type AcceptProp = Record<string, string[]>;\n\nexport type DropzoneOptions = {\n multiple?: boolean;\n accept?: AcceptProp | undefined;\n minSize?: number;\n maxSize?: number;\n maxFiles?: number;\n disabled?: boolean | undefined;\n onDrop: <T extends File>(acceptedFiles: T[]) => void;\n};\n\nexport type DropzoneState = {\n isFocused: boolean;\n isDragActive: boolean;\n isDragAccept: boolean;\n isDragReject: boolean;\n isFileDialogActive: boolean;\n acceptedFiles: File[];\n};\n\n/**\n * Copyright (c) (MIT License) 2015 Andrey Okonetchnikov\n * https://github.com/react-dropzone/attr-accept/blob/master/src/index.js\n */\nfunction accepts(file: File, acceptedFiles: string | string[]): boolean {\n if (acceptedFiles) {\n const acceptedFilesArray = Array.isArray(acceptedFiles)\n ? acceptedFiles\n : acceptedFiles.split(\",\");\n const fileName = file.name;\n const mimeType = file.type.toLowerCase();\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\");\n\n return acceptedFilesArray.some((type) => {\n const validType = type.trim().toLowerCase();\n if (validType.startsWith(\".\")) {\n return fileName.toLowerCase().endsWith(validType);\n } else if (validType.endsWith(\"/*\")) {\n // This is something like a image/* mime type\n return baseMimeType === validType.replace(/\\/.*$/, \"\");\n }\n return mimeType === validType;\n });\n }\n return true;\n}\n\nexport const isPropagationStopped = (\n event: Event & { isPropagationStopped?: () => boolean },\n) => {\n if (typeof event.isPropagationStopped === \"function\") {\n return event.isPropagationStopped();\n }\n if (typeof event.cancelBubble !== \"undefined\") {\n return event.cancelBubble;\n }\n return false;\n};\n\n// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with\n// that MIME type will always be accepted\nexport function isFileAccepted(file: File, accept: string | string[]) {\n return file.type === \"application/x-moz-file\" || accepts(file, accept);\n}\n\nexport function isEnterOrSpace(event: { key?: string; keyCode?: number }) {\n return (\n (\"key\" in event && (event.key === \" \" || event.key === \"Enter\")) ||\n (\"keyCode\" in event && (event.keyCode === 32 || event.keyCode === 13))\n );\n}\n\nconst isDefined = <T>(v: T | null | undefined): v is T => v != null;\nexport function isValidSize(file: File, minSize: number, maxSize: number) {\n if (!isDefined(file.size)) return true;\n if (isDefined(minSize) && isDefined(maxSize)) {\n return file.size >= minSize && file.size <= maxSize;\n }\n if (isDefined(minSize) && file.size < minSize) return false;\n if (isDefined(maxSize) && file.size > maxSize) return false;\n return true;\n}\n\nexport function isValidQuantity(\n files: File[],\n multiple: boolean,\n maxFiles: number,\n) {\n if (!multiple && files.length > 1) return false;\n if (multiple && maxFiles >= 1 && files.length > maxFiles) return false;\n return true;\n}\n\nexport function allFilesAccepted({\n files,\n accept,\n minSize,\n maxSize,\n multiple,\n maxFiles,\n}: {\n files: File[];\n accept: string | string[];\n minSize: number;\n maxSize: number;\n multiple: boolean;\n maxFiles: number;\n}) {\n if (!isValidQuantity(files, multiple, maxFiles)) return false;\n\n return files.every(\n (file) =>\n isFileAccepted(file, accept) && isValidSize(file, minSize, maxSize),\n );\n}\n\nexport function isEventWithFiles(event: Partial<Event>) {\n if (!(\"dataTransfer\" in event && event.dataTransfer !== null)) {\n return !!event.target && \"files\" in event.target && !!event.target.files;\n }\n // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types\n // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file\n return Array.prototype.some.call(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n (event.dataTransfer as any)?.types,\n (type) => type === \"Files\" || type === \"application/x-moz-file\",\n );\n}\n\nexport function isIeOrEdge(ua = window.navigator.userAgent) {\n return (\n ua.includes(\"MSIE \") || ua.includes(\"Trident/\") || ua.includes(\"Edge/\")\n );\n}\n\nfunction isMIMEType(v: string) {\n return (\n v === \"audio/*\" ||\n v === \"video/*\" ||\n v === \"image/*\" ||\n v === \"text/*\" ||\n /\\w+\\/[-+.\\w]+/g.test(v)\n );\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v);\n}\n\n/**\n * Convert the `{accept}` dropzone prop to an array of MIME types/extensions.\n */\nexport function acceptPropAsAcceptAttr(accept?: AcceptProp) {\n if (isDefined(accept)) {\n return (\n Object.entries(accept)\n .reduce<string[]>((a, [mimeType, ext]) => [...a, mimeType, ...ext], [])\n // Silently discard invalid entries as pickerOptionsFromAccept warns about these\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n );\n }\n\n return undefined;\n}\n\n/**\n * ================================================\n * Reducer\n * ================================================\n */\ntype Payload<T extends keyof DropzoneState> = Pick<DropzoneState, T>;\n\ntype Focus = { type: \"focus\" };\ntype Blur = { type: \"blur\" };\ntype OpenDialog = { type: \"openDialog\" };\ntype CloseDialog = { type: \"closeDialog\" };\ntype SetDraggedFiles = {\n type: \"setDraggedFiles\";\n payload: Payload<\"isDragActive\" | \"isDragAccept\" | \"isDragReject\">;\n};\ntype SetFiles = { type: \"setFiles\"; payload: Payload<\"acceptedFiles\"> };\ntype Reset = { type: \"reset\" };\ntype DropzoneActions =\n | Focus\n | Blur\n | OpenDialog\n | CloseDialog\n | SetDraggedFiles\n | SetFiles\n | Reset;\n\nexport const initialState = {\n isFocused: false,\n isFileDialogActive: false,\n isDragActive: false,\n isDragAccept: false,\n isDragReject: false,\n acceptedFiles: [] as File[],\n};\n\nexport function reducer(\n state: DropzoneState,\n action: DropzoneActions,\n): DropzoneState {\n switch (action.type) {\n case \"focus\":\n return {\n ...state,\n isFocused: true,\n };\n case \"blur\":\n return {\n ...state,\n isFocused: false,\n };\n case \"openDialog\":\n return {\n ...initialState,\n isFileDialogActive: true,\n };\n case \"closeDialog\":\n return {\n ...state,\n isFileDialogActive: false,\n };\n case \"setDraggedFiles\":\n return {\n ...state,\n ...action.payload,\n };\n case \"setFiles\":\n return {\n ...state,\n ...action.payload,\n };\n case \"reset\":\n return initialState;\n default:\n return state;\n }\n}\n"],"mappings":"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"}
{"version":3,"file":"index.js","names":["newConfig: ExpandedRouteConfig","type","text","opts: UploadThingErrorOptions<TShape>","defaultClassListMerger: ClassListMerger","temp: string","j: number"],"sources":["../src/types.ts","../src/tagged-errors.ts","../src/utils.ts","../src/file-types.ts","../src/error.ts","../src/effect.ts","../src/component-utils.ts","../src/crypto.ts","../src/dropzone-utils.ts"],"sourcesContent":["import type { MimeType } from \"@linear-webdev/mime-types\";\n\nimport type { AllowedFileType } from \"./file-types\";\n\nexport type JsonValue = string | number | boolean | null | undefined;\nexport type JsonObject = { [key: string]: JsonValue | JsonObject | JsonArray };\nexport type JsonArray = (JsonValue | JsonObject)[];\nexport type Json = JsonValue | JsonObject | JsonArray;\n\nexport type Overwrite<T, U> = Omit<T, keyof U> & U;\nexport type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;\nexport type ErrorMessage<TError extends string> = TError;\nexport type Simplify<TType> = { [TKey in keyof TType]: TType[TKey] } & {};\nexport type MaybePromise<TType> = TType | Promise<TType>;\nexport type Either<TData, TError> =\n | { data: TData; error: null }\n | { data: null; error: TError };\nexport type ExtendObjectIf<Predicate, ToAdd> = undefined extends Predicate\n ? {}\n : ToAdd;\nexport type DeepPartial<T> = T extends object\n ? {\n [P in keyof T]?: DeepPartial<T[P]>;\n }\n : T;\n\nexport interface FileProperties {\n name: string;\n size: number;\n type: string;\n lastModified?: number | undefined;\n}\n\nexport type ExtractHashPartsFn = (\n file: FileProperties,\n) => (string | number | undefined | null | boolean)[];\n\n/**\n * A subset of the standard RequestInit properties needed by UploadThing internally.\n * @see RequestInit from lib.dom.d.ts\n */\nexport interface RequestInitEsque {\n /**\n * Sets the request's body.\n */\n body?: FormData | ReadableStream | string | null;\n\n /**\n * Sets the request's associated headers.\n */\n headers?: [string, string][] | Record<string, string>;\n\n /**\n * The request's HTTP-style method.\n */\n method?: string;\n}\n\n/**\n * A subset of the standard Response properties needed by UploadThing internally.\n * @see Response from lib.dom.d.ts\n */\nexport interface ResponseEsque {\n status: number;\n statusText: string;\n ok: boolean;\n /**\n * @remarks\n * The built-in Response::json() method returns Promise<any>, but\n * that's not as type-safe as unknown. We use unknown because we're\n * more type-safe. You do want more type safety, right? 😉\n */\n json: <T = unknown>() => Promise<T>;\n text: () => Promise<string>;\n blob: () => Promise<Blob>;\n body: ReadableStream | null;\n\n headers: Headers;\n\n clone: () => ResponseEsque;\n}\n\nexport type MaybeUrl = string | URL;\n\n/**\n * A subset of the standard fetch function type needed by UploadThing internally.\n * @see fetch from lib.dom.d.ts\n */\nexport type FetchEsque = (\n input: RequestInfo | MaybeUrl,\n init?: RequestInit | RequestInitEsque,\n) => Promise<ResponseEsque>;\n\ntype PowOf2 = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024;\nexport type SizeUnit = \"B\" | \"KB\" | \"MB\" | \"GB\";\nexport type FileSize = `${PowOf2}${SizeUnit}`;\n\nexport type TimeShort = \"s\" | \"m\" | \"h\" | \"d\";\nexport type TimeLong = \"second\" | \"minute\" | \"hour\" | \"day\";\ntype SuggestedNumbers = 2 | 3 | 4 | 5 | 6 | 7 | 10 | 15 | 30 | 60;\ntype AutoCompleteableNumber = SuggestedNumbers | (number & {});\nexport type Time =\n | number\n | `1${TimeShort}`\n | `${AutoCompleteableNumber}${TimeShort}`\n | `1 ${TimeLong}`\n | `${AutoCompleteableNumber} ${TimeLong}s`;\n\nexport const ValidContentDispositions = [\"inline\", \"attachment\"] as const;\nexport type ContentDisposition = (typeof ValidContentDispositions)[number];\n\nexport const ValidACLs = [\"public-read\", \"private\"] as const;\nexport type ACL = (typeof ValidACLs)[number];\n\ntype ImageProperties = {\n /** Specify the width of the image. */\n width?: number;\n /** Specify the height of the image. */\n height?: number;\n /**\n * Specify the aspect ratio of the image.\n * @remarks If both width and height are specified, this will be ignored.\n */\n aspectRatio?: number;\n};\n\ntype AdditionalProperties<T> = Record<string, unknown> & T;\n\nexport type RouteConfig<TAdditionalProperties extends Record<string, unknown>> =\n {\n /**\n * Human-readable file size limit\n * @example \"1MB\"\n * @default https://docs.uploadthing.com/api-reference/server#defaults\n */\n maxFileSize: FileSize;\n /**\n * Maximum number of files allowed to be uploaded of this type\n * @example 10\n * @default https://docs.uploadthing.com/api-reference/server#defaults\n */\n maxFileCount: number;\n /**\n * Minimum number of files allowed to be uploaded of this type\n * @remarks Must be <= maxFileCount\n * @example 2\n * @default 1\n */\n minFileCount: number;\n /**\n * Specify the [content disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) of the uploaded file\n * @example \"attachment\"\n * @default \"inline\"\n */\n contentDisposition: ContentDisposition;\n /**\n * Specify the [access control list](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin) of the uploaded file\n * @remarks This must be enabled for your app. See https://docs.uploadthing.com/regions-and-acl#access-controls.\n * @example \"private\"\n * @default \"public-read\"\n */\n acl?: ACL;\n /**\n * Additional properties to be passed to the client-side `useRouteConfig` hook\n * @remarks These properties are not validated on the server on upload\n */\n additionalProperties?: AdditionalProperties<TAdditionalProperties>;\n };\n\n/**\n * Shared config options for an entire route not bound to any specific file type\n * @example\n * ```ts\n * f(\n * { image: {} },\n * { awaitServerData: true },\n * )\n * ```\n */\nexport type RouteOptions = {\n /**\n * Set this to `false` to run the client-side `onClientUploadComplete`\n * immediately after file has been uploaded without waiting for the\n * server to return the `onUploadComplete` data.\n * @default true\n */\n awaitServerData?: boolean;\n /**\n * TTL for the presigned URLs generated for the upload\n * @default `1h`\n */\n presignedURLTTL?: Time;\n /**\n * Function that pulls out the properties of the uploaded file\n * that you want to be included as part of the presigned URL generation.\n * By default, we include all properties as well as a timestamp to make\n * each URL unique. You can for example override this to always return\n * the same hash for the same file, no matter when it was uploaded.\n * @default (file) => [file.name, file.size, file.type, file.lastModified, Date.now()]\n */\n getFileHashParts?: ExtractHashPartsFn;\n};\n\nexport type FileRouterInputKey = AllowedFileType | MimeType;\n\nexport type ExpandedRouteConfig = {\n [key in FileRouterInputKey]?: key extends `image${string}`\n ? RouteConfig<ImageProperties>\n : RouteConfig<Record<string, unknown>>;\n};\n\nexport type EndpointMetadata = {\n slug: string;\n config: ExpandedRouteConfig;\n}[];\n\nexport type FileRouterInputConfig =\n | FileRouterInputKey[]\n | DeepPartial<ExpandedRouteConfig>;\n","import * as Micro from \"effect/Micro\";\nimport * as Predicate from \"effect/Predicate\";\n\nexport class InvalidRouteConfigError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidRouteConfig\")<{\n reason: string;\n }>\n{\n constructor(type: string, field?: string) {\n const reason = field\n ? `Expected route config to have a ${field} for key ${type} but none was found.`\n : `Encountered an invalid route config during backfilling. ${type} was not found.`;\n super({ reason });\n }\n}\n\nexport class UnknownFileTypeError\n extends /** #__PURE__ */ Micro.TaggedError(\"UnknownFileType\")<{\n reason: string;\n }>\n{\n constructor(fileName: string) {\n const reason = `Could not determine type for ${fileName}`;\n super({ reason });\n }\n}\n\nexport class InvalidFileTypeError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidFileType\")<{\n reason: string;\n }>\n{\n constructor(fileType: string, fileName: string) {\n const reason = `File type ${fileType} not allowed for ${fileName}`;\n super({ reason });\n }\n}\n\nexport class InvalidFileSizeError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidFileSize\")<{\n reason: string;\n }>\n{\n constructor(fileSize: string) {\n const reason = `Invalid file size: ${fileSize}`;\n super({ reason });\n }\n}\n\nexport class InvalidURLError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidURL\")<{\n reason: string;\n }>\n{\n constructor(attemptedUrl: string) {\n super({ reason: `Failed to parse '${attemptedUrl}' as a URL.` });\n }\n}\n\nexport class RetryError\n extends /** #__PURE__ */ Micro.TaggedError(\"RetryError\") {}\n\nexport class FetchError\n extends /** #__PURE__ */ Micro.TaggedError(\"FetchError\")<{\n readonly input: {\n url: string;\n method: string | undefined;\n body: unknown;\n headers: Record<string, string>;\n };\n readonly error: unknown;\n }> {}\n\nexport class InvalidJsonError\n extends /** #__PURE__ */ Micro.TaggedError(\"InvalidJson\")<{\n readonly input: unknown;\n readonly error: unknown;\n }> {}\n\nexport class BadRequestError<T = unknown>\n extends /** #__PURE__ */ Micro.TaggedError(\"BadRequestError\")<{\n readonly message: string;\n readonly status: number;\n readonly json: T;\n }>\n{\n getMessage() {\n if (Predicate.isRecord(this.json)) {\n if (typeof this.json.message === \"string\") return this.json.message;\n }\n return this.message;\n }\n}\n\nexport class UploadPausedError\n extends /** #__PURE__ */ Micro.TaggedError(\"UploadAborted\") {}\n\nexport class UploadAbortedError\n extends /** #__PURE__ */ Micro.TaggedError(\"UploadAborted\") {}\n","import * as Micro from \"effect/Micro\";\n\nimport { lookup } from \"@linear-webdev/mime-types\";\n\nimport type { AllowedFileType } from \"./file-types\";\nimport {\n InvalidFileSizeError,\n InvalidFileTypeError,\n InvalidRouteConfigError,\n InvalidURLError,\n UnknownFileTypeError,\n} from \"./tagged-errors\";\nimport type {\n ExpandedRouteConfig,\n FileProperties,\n FileRouterInputConfig,\n FileRouterInputKey,\n FileSize,\n Json,\n ResponseEsque,\n RouteConfig,\n Time,\n TimeShort,\n} from \"./types\";\n\nexport function isRouteArray(\n routeConfig: FileRouterInputConfig,\n): routeConfig is FileRouterInputKey[] {\n return Array.isArray(routeConfig);\n}\n\nexport function getDefaultSizeForType(fileType: FileRouterInputKey): FileSize {\n if (fileType === \"image\") return \"4MB\";\n if (fileType === \"video\") return \"16MB\";\n if (fileType === \"audio\") return \"8MB\";\n if (fileType === \"blob\") return \"8MB\";\n if (fileType === \"pdf\") return \"4MB\";\n if (fileType === \"text\") return \"64KB\";\n\n return \"4MB\";\n}\n\nexport function getDefaultRouteConfigValues(\n type: FileRouterInputKey,\n): RouteConfig<Record<string, never>> {\n return {\n maxFileSize: getDefaultSizeForType(type),\n maxFileCount: 1,\n minFileCount: 1,\n contentDisposition: \"inline\" as const,\n };\n}\n\n/**\n * This function takes in the user's input and \"upscales\" it to a full config\n * Additionally, it replaces numbers with \"safe\" equivalents\n *\n * Example:\n * ```ts\n * [\"image\"] => { image: { maxFileSize: \"4MB\", limit: 1 } }\n * ```\n */\n\nexport const fillInputRouteConfig = (\n routeConfig: FileRouterInputConfig,\n): Micro.Micro<ExpandedRouteConfig, InvalidRouteConfigError> => {\n // If array, apply defaults\n if (isRouteArray(routeConfig)) {\n return Micro.succeed(\n routeConfig.reduce<ExpandedRouteConfig>((acc, fileType) => {\n acc[fileType] = getDefaultRouteConfigValues(fileType);\n return acc;\n }, {}),\n );\n }\n\n // Backfill defaults onto config\n const newConfig: ExpandedRouteConfig = {};\n for (const key of objectKeys(routeConfig)) {\n const value = routeConfig[key];\n if (!value) return Micro.fail(new InvalidRouteConfigError(key));\n newConfig[key] = { ...getDefaultRouteConfigValues(key), ...value };\n }\n\n // we know that the config is valid, so we can stringify it and parse it back\n // this allows us to replace numbers with \"safe\" equivalents\n return Micro.succeed(\n JSON.parse(\n JSON.stringify(newConfig, safeNumberReplacer),\n ) as ExpandedRouteConfig,\n );\n};\n\n/**\n * Match the file's type for a given allow list e.g. `image/png => image`\n * Prefers the file's type, then falls back to a extension-based lookup\n */\nexport const matchFileType = (\n file: FileProperties,\n allowedTypes: FileRouterInputKey[],\n): Micro.Micro<\n FileRouterInputKey,\n UnknownFileTypeError | InvalidFileTypeError\n> => {\n // Type might be \"\" if the browser doesn't recognize the mime type\n const mimeType = file.type || lookup(file.name);\n if (!mimeType) {\n if (allowedTypes.includes(\"blob\")) return Micro.succeed(\"blob\");\n return Micro.fail(new UnknownFileTypeError(file.name));\n }\n\n // If the user has specified a specific mime type, use that\n if (allowedTypes.some((type) => type.includes(\"/\"))) {\n if (allowedTypes.includes(mimeType as FileRouterInputKey)) {\n return Micro.succeed(mimeType as FileRouterInputKey);\n }\n }\n\n // Otherwise, we have a \"magic\" type eg. \"image\" or \"video\"\n const type = (\n mimeType.toLowerCase() === \"application/pdf\"\n ? \"pdf\"\n : mimeType.split(\"/\")[0]\n ) as AllowedFileType;\n\n if (!allowedTypes.includes(type)) {\n // Blob is a catch-all for any file type not explicitly supported\n if (allowedTypes.includes(\"blob\")) {\n return Micro.succeed(\"blob\");\n } else {\n return Micro.fail(new InvalidFileTypeError(type, file.name));\n }\n }\n\n return Micro.succeed(type);\n};\n\nexport const FILESIZE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"] as const;\nexport type FileSizeUnit = (typeof FILESIZE_UNITS)[number];\nexport const fileSizeToBytes = (\n fileSize: FileSize,\n): Micro.Micro<number, InvalidFileSizeError> => {\n const regex = new RegExp(\n `^(\\\\d+)(\\\\.\\\\d+)?\\\\s*(${FILESIZE_UNITS.join(\"|\")})$`,\n \"i\",\n );\n\n // make sure the string is in the format of 123KB\n const match = regex.exec(fileSize);\n if (!match?.[1] || !match[3]) {\n return Micro.fail(new InvalidFileSizeError(fileSize));\n }\n\n const sizeValue = parseFloat(match[1]);\n const sizeUnit = match[3].toUpperCase() as FileSizeUnit;\n const bytes = sizeValue * Math.pow(1024, FILESIZE_UNITS.indexOf(sizeUnit));\n return Micro.succeed(Math.floor(bytes));\n};\n\nexport const bytesToFileSize = (bytes: number) => {\n if (bytes === 0 || bytes === -1) {\n return \"0B\";\n }\n\n const i = Math.floor(Math.log(bytes) / Math.log(1024));\n return `${(bytes / Math.pow(1024, i)).toFixed(2)}${FILESIZE_UNITS[i]}`;\n};\n\nexport async function safeParseJSON<T>(\n input: ResponseEsque,\n): Promise<T | Error> {\n const text = await input.text();\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(`Error parsing JSON, got '${text}'`, err);\n return new Error(`Error parsing JSON, got '${text}'`);\n }\n}\n\n/** typesafe Object.keys */\nexport function objectKeys<T extends Record<string, unknown>>(\n obj: T,\n): (keyof T)[] {\n return Object.keys(obj) as (keyof T)[];\n}\n\nexport function filterDefinedObjectValues<T>(\n obj: Record<string, T | null | undefined>,\n): Record<string, T> {\n return Object.fromEntries(\n Object.entries(obj).filter((pair): pair is [string, T] => pair[1] != null),\n );\n}\n\nexport function semverLite(required: string, toCheck: string) {\n // Pull out numbers from strings like `6.0.0`, `^6.4`, `~6.4.0`\n const semverRegex = /(\\d+)\\.?(\\d+)?\\.?(\\d+)?/;\n const requiredMatch = semverRegex.exec(required);\n if (!requiredMatch?.[0]) {\n throw new Error(`Invalid semver requirement: ${required}`);\n }\n const toCheckMatch = semverRegex.exec(toCheck);\n if (!toCheckMatch?.[0]) {\n throw new Error(`Invalid semver to check: ${toCheck}`);\n }\n\n const [_1, rMajor, rMinor, rPatch] = requiredMatch;\n const [_2, cMajor, cMinor, cPatch] = toCheckMatch;\n\n if (required.startsWith(\"^\")) {\n // Major must be equal, minor must be greater or equal\n if (rMajor !== cMajor) return false;\n if (rMinor && cMinor && rMinor > cMinor) return false;\n return true;\n }\n\n if (required.startsWith(\"~\")) {\n // Major must be equal, minor must be equal\n if (rMajor !== cMajor) return false;\n if (rMinor !== cMinor) return false;\n return true;\n }\n\n // Exact match\n return rMajor === cMajor && rMinor === cMinor && rPatch === cPatch;\n}\n\nexport function warnIfInvalidPeerDependency(\n pkg: string,\n required: string,\n toCheck: string,\n) {\n if (!semverLite(required, toCheck)) {\n // eslint-disable-next-line no-console\n console.warn(\n `!!!WARNING::: ${pkg} requires \"uploadthing@${required}\", but version \"${toCheck}\" is installed`,\n );\n }\n}\n\nexport const getRequestUrl = (req: Request) =>\n Micro.gen(function* () {\n const host = req.headers.get(\"x-forwarded-host\") ?? req.headers.get(\"host\");\n const proto = req.headers.get(\"x-forwarded-proto\") ?? \"https\";\n const protocol = proto.endsWith(\":\") ? proto : `${proto}:`;\n const url = yield* Micro.try({\n try: () => new URL(req.url, `${protocol}//${host}`),\n catch: () => new InvalidURLError(req.url),\n });\n url.search = \"\";\n return url;\n });\n\nexport const getFullApiUrl = (\n maybeUrl?: string,\n): Micro.Micro<URL, InvalidURLError> =>\n Micro.gen(function* () {\n const base = (() => {\n if (typeof window !== \"undefined\") return window.location.origin;\n if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;\n return \"http://localhost:3000\";\n })();\n\n const url = yield* Micro.try({\n try: () => new URL(maybeUrl ?? \"/api/uploadthing\", base),\n catch: () => new InvalidURLError(maybeUrl ?? \"/api/uploadthing\"),\n });\n\n if (url.pathname === \"/\") {\n url.pathname = \"/api/uploadthing\";\n }\n return url;\n });\n\n/*\n * Returns a full URL to the dev's uploadthing endpoint\n * Can take either an origin, or a pathname, or a full URL\n * and will return the \"closest\" url matching the default\n * `<VERCEL_URL || localhost>/api/uploadthing`\n */\nexport const resolveMaybeUrlArg = (maybeUrl: string | URL | undefined): URL => {\n return maybeUrl instanceof URL\n ? maybeUrl\n : Micro.runSync(getFullApiUrl(maybeUrl));\n};\n\nexport function parseTimeToSeconds(time: Time) {\n if (typeof time === \"number\") return time;\n\n const match = time.split(/(\\d+)/).filter(Boolean);\n const num = Number(match[0]);\n const unit = (match[1] ?? \"s\").trim().slice(0, 1) as TimeShort;\n\n const multiplier = {\n s: 1,\n m: 60,\n h: 3600,\n d: 86400,\n }[unit];\n\n return num * multiplier;\n}\n\n/**\n * Replacer for JSON.stringify that will replace numbers that cannot be\n * serialized to JSON with \"reasonable equivalents\".\n *\n * Infinity and -Infinity are replaced by MAX_SAFE_INTEGER and MIN_SAFE_INTEGER\n * NaN is replaced by 0\n *\n */\nexport const safeNumberReplacer = (_: string, value: unknown) => {\n if (typeof value !== \"number\") return value;\n if (\n Number.isSafeInteger(value) ||\n (value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER)\n ) {\n return value;\n }\n if (value === Infinity) return Number.MAX_SAFE_INTEGER;\n if (value === -Infinity) return Number.MIN_SAFE_INTEGER;\n if (Number.isNaN(value)) return 0;\n};\n\nexport function noop() {\n // noop\n}\n\nexport function createIdentityProxy<TObj extends Record<string, unknown>>() {\n return new Proxy(noop, {\n get: (_, prop) => prop,\n }) as unknown as TObj;\n}\n\nexport function unwrap<T extends Json | PropertyKey, Param extends unknown[]>(\n x: T | ((...args: Param) => T),\n ...args: Param\n) {\n return typeof x === \"function\" ? x(...args) : x;\n}\n","export const ALLOWED_FILE_TYPES = [\n \"image\",\n \"video\",\n \"audio\",\n \"pdf\",\n \"text\",\n \"blob\",\n] as const;\n\nexport type AllowedFileType = (typeof ALLOWED_FILE_TYPES)[number];\n","import * as Micro from \"effect/Micro\";\nimport * as Predicate from \"effect/Predicate\";\n\nimport type { Json } from \"./types\";\n\nconst ERROR_CODES = {\n // Generic\n BAD_REQUEST: 400,\n NOT_FOUND: 404,\n FORBIDDEN: 403,\n INTERNAL_SERVER_ERROR: 500,\n INTERNAL_CLIENT_ERROR: 500,\n\n // S3 specific\n TOO_LARGE: 413,\n TOO_SMALL: 400,\n TOO_MANY_FILES: 400,\n KEY_TOO_LONG: 400,\n\n // UploadThing specific\n URL_GENERATION_FAILED: 500,\n UPLOAD_FAILED: 500,\n MISSING_ENV: 500,\n INVALID_SERVER_CONFIG: 500,\n FILE_LIMIT_EXCEEDED: 500,\n} as const;\n\ntype ErrorCode = keyof typeof ERROR_CODES;\ntype UploadThingErrorOptions<T> = {\n code: keyof typeof ERROR_CODES;\n message?: string | undefined;\n cause?: unknown;\n data?: T;\n};\n\nfunction messageFromUnknown(cause: unknown, fallback?: string) {\n if (typeof cause === \"string\") {\n return cause;\n }\n if (cause instanceof Error) {\n return cause.message;\n }\n if (\n cause &&\n typeof cause === \"object\" &&\n \"message\" in cause &&\n typeof cause.message === \"string\"\n ) {\n return cause.message;\n }\n return fallback ?? \"An unknown error occurred\";\n}\n\nexport interface SerializedUploadThingError {\n code: ErrorCode;\n message: string;\n data?: Json;\n}\n\nexport class UploadThingError<\n TShape extends Json = { message: string },\n> extends Micro.Error<{ message: string }> {\n readonly _tag = \"UploadThingError\";\n readonly name = \"UploadThingError\";\n\n public readonly cause?: unknown;\n public readonly code: ErrorCode;\n public readonly data: TShape | undefined;\n\n constructor(initOpts: UploadThingErrorOptions<TShape> | string) {\n const opts: UploadThingErrorOptions<TShape> =\n typeof initOpts === \"string\"\n ? { code: \"INTERNAL_SERVER_ERROR\", message: initOpts }\n : initOpts;\n const message = opts.message ?? messageFromUnknown(opts.cause, opts.code);\n\n super({ message });\n this.code = opts.code;\n this.data = opts.data;\n\n if (opts.cause instanceof Error) {\n this.cause = opts.cause;\n } else if (\n Predicate.isRecord(opts.cause) &&\n Predicate.isNumber(opts.cause.status) &&\n Predicate.isString(opts.cause.statusText)\n ) {\n this.cause = new Error(\n `Response ${opts.cause.status} ${opts.cause.statusText}`,\n );\n } else if (Predicate.isString(opts.cause)) {\n this.cause = new Error(opts.cause);\n } else {\n this.cause = opts.cause;\n }\n }\n\n public static toObject(error: UploadThingError): SerializedUploadThingError {\n return {\n code: error.code,\n message: error.message,\n data: error.data,\n };\n }\n\n public static serialize(error: UploadThingError) {\n return JSON.stringify(UploadThingError.toObject(error));\n }\n}\n\nexport function getErrorTypeFromStatusCode(statusCode: number): ErrorCode {\n for (const [code, status] of Object.entries(ERROR_CODES)) {\n if (status === statusCode) {\n return code as ErrorCode;\n }\n }\n return \"INTERNAL_SERVER_ERROR\";\n}\n\nexport function getStatusCodeFromError(error: UploadThingError<any>) {\n return ERROR_CODES[error.code];\n}\n\nexport const INTERNAL_DO_NOT_USE__fatalClientError = (e: Error) =>\n new UploadThingError({\n code: \"INTERNAL_CLIENT_ERROR\",\n message: \"Something went wrong. Please report this to UploadThing.\",\n cause: e,\n });\n","import * as Context from \"effect/Context\";\nimport * as Micro from \"effect/Micro\";\n\nimport { BadRequestError, FetchError, InvalidJsonError } from \"./tagged-errors\";\nimport type { FetchEsque, ResponseEsque } from \"./types\";\n\nexport class FetchContext\n extends /** #__PURE__ */ Context.Tag(\"uploadthing/Fetch\")<\n FetchContext,\n FetchEsque\n >() {}\n\ninterface ResponseWithURL extends ResponseEsque {\n requestUrl: string;\n}\n\n// Temporary Effect wrappers below.\n// Only for use in the browser.\n// On the server, use `@effect/platform.HttpClient` instead.\nexport const fetchEff = (\n input: string | URL,\n init?: RequestInit,\n): Micro.Micro<ResponseWithURL, FetchError, FetchContext> =>\n Micro.flatMap(Micro.service(FetchContext), (fetch) => {\n const headers = new Headers(init?.headers ?? []);\n\n const reqInfo = {\n url: input.toString(),\n method: init?.method,\n body: init?.body,\n headers: Object.fromEntries(headers),\n };\n\n return Micro.tryPromise({\n try: (signal) => fetch(input, { ...init, headers, signal }),\n catch: (error) =>\n new FetchError({\n error:\n error instanceof Error\n ? {\n ...error,\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n input: reqInfo,\n }),\n }).pipe(\n // eslint-disable-next-line no-console\n Micro.tapError((e) => Micro.sync(() => console.error(e.input))),\n Micro.map((res) => Object.assign(res, { requestUrl: reqInfo.url })),\n Micro.withTrace(\"fetch\"),\n );\n });\n\nexport const parseResponseJson = (\n res: ResponseWithURL,\n): Micro.Micro<unknown, InvalidJsonError | BadRequestError> =>\n Micro.tryPromise({\n try: async () => {\n const json = await res.json();\n return { json, ok: res.ok, status: res.status };\n },\n catch: (error) => new InvalidJsonError({ error, input: res.requestUrl }),\n }).pipe(\n Micro.filterOrFail(\n ({ ok }) => ok,\n ({ json, status }) =>\n new BadRequestError({\n status,\n message: `Request to ${res.requestUrl} failed with status ${status}`,\n json,\n }),\n ),\n Micro.map(({ json }) => json),\n Micro.withTrace(\"parseJson\"),\n );\n","import type { CSSProperties, ReactNode } from \"react\";\nimport type { JSX } from \"solid-js/jsx-runtime\";\nimport type { RenderFunction, StyleValue } from \"vue\";\n\n/**\n * Use granular imports to better tree-shake\n * We don't need all the types, and `/application`\n * entrypoint is ~7k gzip which we can shave off\n */\nimport { audio } from \"@linear-webdev/mime-types/audio\";\nimport { image } from \"@linear-webdev/mime-types/image\";\nimport { text } from \"@linear-webdev/mime-types/text\";\nimport { video } from \"@linear-webdev/mime-types/video\";\n\nimport type { ExpandedRouteConfig } from \"./types\";\nimport { objectKeys } from \"./utils\";\n\nexport type ProgressGranularity = \"all\" | \"fine\" | \"coarse\";\nexport const roundProgress = (\n progress: number,\n granularity: ProgressGranularity,\n) => {\n if (granularity === \"all\") return progress;\n if (granularity === \"fine\") return Math.round(progress);\n return Math.floor(progress / 10) * 10;\n};\n\nexport const generateMimeTypes = (\n typesOrRouteConfig: string[] | ExpandedRouteConfig,\n) => {\n const fileTypes = Array.isArray(typesOrRouteConfig)\n ? typesOrRouteConfig\n : objectKeys(typesOrRouteConfig);\n if (fileTypes.includes(\"blob\")) return [];\n\n return fileTypes.map((type) => {\n if (type === \"pdf\") return \"application/pdf\";\n if (type.includes(\"/\")) return type;\n\n // Add wildcard to support all subtypes, e.g. image => \"image/*\"\n // But some browsers/OSes don't support it, so we'll also dump all the mime types\n // we know that starts with the type, e.g. image => \"image/png, image/jpeg, ...\"\n if (type === \"audio\") return [\"audio/*\", ...objectKeys(audio)].join(\", \");\n if (type === \"image\") return [\"image/*\", ...objectKeys(image)].join(\", \");\n if (type === \"text\") return [\"text/*\", ...objectKeys(text)].join(\", \");\n if (type === \"video\") return [\"video/*\", ...objectKeys(video)].join(\", \");\n\n return `${type}/*`;\n });\n};\n\nexport const generateClientDropzoneAccept = (fileTypes: string[]) => {\n const mimeTypes = generateMimeTypes(fileTypes);\n return Object.fromEntries(mimeTypes.map((type) => [type, []]));\n};\n\nexport function getFilesFromClipboardEvent(event: ClipboardEvent) {\n const dataTransferItems = event.clipboardData?.items;\n if (!dataTransferItems) return;\n\n const files = Array.from(dataTransferItems).reduce<File[]>((acc, curr) => {\n const f = curr.getAsFile();\n return f ? [...acc, f] : acc;\n }, []);\n\n return files;\n}\n\n/**\n * Shared helpers for our premade components that's reusable by multiple frameworks\n */\n\nexport const generatePermittedFileTypes = (config?: ExpandedRouteConfig) => {\n const fileTypes = config ? objectKeys(config) : [];\n\n const maxFileCount = config\n ? Object.values(config).map((v) => v.maxFileCount)\n : [];\n\n return { fileTypes, multiple: maxFileCount.some((v) => v && v > 1) };\n};\n\nexport const capitalizeStart = (str: string) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n};\n\nexport const INTERNAL_doFormatting = (config?: ExpandedRouteConfig): string => {\n if (!config) return \"\";\n\n const allowedTypes = objectKeys(config);\n\n const formattedTypes = allowedTypes.map((f) => (f === \"blob\" ? \"file\" : f));\n\n // Format multi-type uploader label as \"Supports videos, images and files\";\n if (formattedTypes.length > 1) {\n const lastType = formattedTypes.pop();\n return `${formattedTypes.join(\"s, \")} and ${lastType}s`;\n }\n\n // Single type uploader label\n const key = allowedTypes[0];\n const formattedKey = formattedTypes[0];\n if (!key || !formattedKey) return \"\";\n\n const { maxFileSize, maxFileCount, minFileCount } = config[key]!;\n\n if (maxFileCount && maxFileCount > 1) {\n if (minFileCount > 1) {\n return `${minFileCount} - ${maxFileCount} ${formattedKey}s up to ${maxFileSize}`;\n } else {\n return `${formattedKey}s up to ${maxFileSize}, max ${maxFileCount}`;\n }\n } else {\n return `${formattedKey} (${maxFileSize})`;\n }\n};\n\nexport const allowedContentTextLabelGenerator = (\n config?: ExpandedRouteConfig,\n): string => {\n return capitalizeStart(INTERNAL_doFormatting(config));\n};\n\ntype AnyRuntime = \"react\" | \"solid\" | \"svelte\" | \"vue\";\ntype MinCallbackArg = { __runtime: AnyRuntime };\ntype inferRuntime<T extends MinCallbackArg> = T[\"__runtime\"] extends \"react\"\n ? \"react\"\n : T[\"__runtime\"] extends \"solid\"\n ? \"solid\"\n : T[\"__runtime\"] extends \"svelte\"\n ? \"svelte\"\n : T[\"__runtime\"] extends \"vue\"\n ? \"vue\"\n : never;\n\ntype ElementEsque<TRuntime extends AnyRuntime> = TRuntime extends \"react\"\n ? ReactNode\n : TRuntime extends \"solid\"\n ? JSX.Element\n : ReturnType<RenderFunction>;\ntype CSSPropertiesEsque<TRuntime extends AnyRuntime> = TRuntime extends \"react\"\n ? CSSProperties\n : TRuntime extends \"solid\"\n ? JSX.CSSProperties\n : TRuntime extends \"svelte\"\n ? string\n : TRuntime extends \"vue\"\n ? StyleValue\n : never;\n\nexport type StyleField<\n CallbackArg extends MinCallbackArg,\n TRuntime extends AnyRuntime = inferRuntime<CallbackArg>,\n> =\n | string\n | CSSPropertiesEsque<TRuntime>\n | ((\n arg: Omit<CallbackArg, \"__runtime\">,\n ) => string | CSSPropertiesEsque<TRuntime>);\n\nexport type ContentField<\n CallbackArg extends MinCallbackArg,\n TRuntime extends AnyRuntime = inferRuntime<CallbackArg>,\n> =\n | ElementEsque<TRuntime>\n | ((arg: Omit<CallbackArg, \"__runtime\">) => ElementEsque<TRuntime>);\n\nexport const styleFieldToClassName = <T extends MinCallbackArg>(\n styleField: StyleField<T> | undefined,\n args: T,\n) => {\n if (typeof styleField === \"string\") return styleField;\n if (typeof styleField === \"function\") {\n const result = styleField(args);\n\n if (typeof result === \"string\") return result;\n }\n\n return \"\";\n};\n\nexport const styleFieldToCssObject = <T extends MinCallbackArg>(\n styleField: StyleField<T> | undefined,\n args: T,\n) => {\n if (typeof styleField === \"object\") return styleField;\n if (typeof styleField === \"function\") {\n const result = styleField(args);\n\n if (typeof result === \"object\") return result;\n }\n\n return {};\n};\n\nexport const contentFieldToContent = <T extends MinCallbackArg>(\n contentField: ContentField<T> | undefined,\n arg: T,\n) => {\n if (!contentField) return null;\n if (typeof contentField !== \"function\") return contentField;\n if (typeof contentField === \"function\") {\n const result = contentField(arg);\n\n return result;\n }\n};\n\nexport type ClassListMerger = (\n ...classes: (string | null | undefined | false)[]\n) => string;\nexport const defaultClassListMerger: ClassListMerger = (...classes) => {\n return classes.filter(Boolean).join(\" \");\n};\n","import * as Encoding from \"effect/Encoding\";\nimport * as Hash from \"effect/Hash\";\nimport * as Micro from \"effect/Micro\";\nimport * as Redacted from \"effect/Redacted\";\nimport SQIds, { defaultOptions } from \"sqids\";\n\nimport { UploadThingError } from \"./error\";\nimport type { ExtractHashPartsFn, FileProperties, Time } from \"./types\";\nimport { parseTimeToSeconds } from \"./utils\";\n\nconst signaturePrefix = \"hmac-sha256=\";\nconst algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\nconst encoder = new TextEncoder();\n\nfunction shuffle(str: string, seed: string) {\n const chars = str.split(\"\");\n const seedNum = Hash.string(seed);\n\n let temp: string;\n let j: number;\n for (let i = 0; i < chars.length; i++) {\n j = ((seedNum % (i + 1)) + i) % chars.length;\n temp = chars[i]!;\n chars[i] = chars[j]!;\n chars[j] = temp;\n }\n\n return chars.join(\"\");\n}\n\nexport const signPayload = (\n payload: string,\n secret: Redacted.Redacted<string>,\n) =>\n Micro.gen(function* () {\n const signingKey = yield* Micro.tryPromise({\n try: () =>\n crypto.subtle.importKey(\n \"raw\",\n encoder.encode(Redacted.value(secret)),\n algorithm,\n false,\n [\"sign\"],\n ),\n catch: (e) =>\n new UploadThingError({\n code: \"BAD_REQUEST\",\n message: \"Invalid signing secret\",\n cause: e,\n }),\n });\n\n const signature = yield* Micro.map(\n Micro.tryPromise({\n try: () =>\n crypto.subtle.sign(algorithm, signingKey, encoder.encode(payload)),\n catch: (e) => new UploadThingError({ code: \"BAD_REQUEST\", cause: e }),\n }),\n (arrayBuffer) => Encoding.encodeHex(new Uint8Array(arrayBuffer)),\n );\n\n return `${signaturePrefix}${signature}`;\n }).pipe(Micro.withTrace(\"signPayload\"));\n\nexport const verifySignature = (\n payload: string,\n signature: string | null,\n secret: Redacted.Redacted<string>,\n) =>\n Micro.gen(function* () {\n const sig = signature?.slice(signaturePrefix.length);\n if (!sig) return false;\n\n const secretBytes = encoder.encode(Redacted.value(secret));\n const signingKey = yield* Micro.promise(() =>\n crypto.subtle.importKey(\"raw\", secretBytes, algorithm, false, [\"verify\"]),\n );\n\n const sigBytes = yield* Micro.fromEither(Encoding.decodeHex(sig));\n const payloadBytes = encoder.encode(payload);\n return yield* Micro.promise(() =>\n crypto.subtle.verify(algorithm, signingKey, sigBytes, payloadBytes),\n );\n }).pipe(\n Micro.withTrace(\"verifySignature\"),\n Micro.orElseSucceed(() => false),\n );\n\nexport const generateKey = (\n file: FileProperties,\n appId: string,\n getHashParts?: ExtractHashPartsFn,\n) =>\n Micro.sync(() => {\n // Get the parts of which we should hash to constuct the key\n // This allows the user to customize the hashing algorithm\n // If they for example want to generate the same key for the\n // same file whenever it was uploaded\n const hashParts = JSON.stringify(\n getHashParts?.(file) ?? [\n file.name,\n file.size,\n file.type,\n file.lastModified,\n Date.now(),\n ],\n );\n\n // Hash and Encode the parts and appId as sqids\n const alphabet = shuffle(defaultOptions.alphabet, appId);\n const encodedFileSeed = new SQIds({ alphabet, minLength: 36 }).encode([\n Math.abs(Hash.string(hashParts)),\n ]);\n const encodedAppId = new SQIds({ alphabet, minLength: 12 }).encode([\n Math.abs(Hash.string(appId)),\n ]);\n\n // Concatenate them\n return encodedAppId + encodedFileSeed;\n }).pipe(Micro.withTrace(\"generateKey\"));\n\n// Verify that the key was generated with the same appId\nexport const verifyKey = (key: string, appId: string) =>\n Micro.sync(() => {\n const alphabet = shuffle(defaultOptions.alphabet, appId);\n const expectedPrefix = new SQIds({ alphabet, minLength: 12 }).encode([\n Math.abs(Hash.string(appId)),\n ]);\n\n return key.startsWith(expectedPrefix);\n }).pipe(\n Micro.withTrace(\"verifyKey\"),\n Micro.orElseSucceed(() => false),\n );\n\nexport const generateSignedURL = (\n url: string | URL,\n secretKey: Redacted.Redacted<string>,\n opts: {\n ttlInSeconds?: Time | undefined;\n data?: Record<string, string | number | boolean | null | undefined>;\n },\n) =>\n Micro.gen(function* () {\n const parsedURL = new URL(url);\n\n const ttl = opts.ttlInSeconds\n ? parseTimeToSeconds(opts.ttlInSeconds)\n : 60 * 60;\n\n const expirationTime = Date.now() + ttl * 1000;\n parsedURL.searchParams.append(\"expires\", expirationTime.toString());\n\n if (opts.data) {\n Object.entries(opts.data).forEach(([key, value]) => {\n if (value == null) return;\n const encoded = encodeURIComponent(value);\n parsedURL.searchParams.append(key, encoded);\n });\n }\n\n const signature = yield* signPayload(parsedURL.toString(), secretKey);\n parsedURL.searchParams.append(\"signature\", signature);\n\n return parsedURL.href;\n }).pipe(Micro.withTrace(\"generateSignedURL\"));\n","export type AcceptProp = Record<string, string[]>;\n\nexport type DropzoneOptions = {\n multiple?: boolean;\n accept?: AcceptProp | undefined;\n minSize?: number;\n maxSize?: number;\n maxFiles?: number;\n disabled?: boolean | undefined;\n onDrop: <T extends File>(acceptedFiles: T[]) => void;\n};\n\nexport type DropzoneState = {\n isFocused: boolean;\n isDragActive: boolean;\n isDragAccept: boolean;\n isDragReject: boolean;\n isFileDialogActive: boolean;\n acceptedFiles: File[];\n};\n\n/**\n * Copyright (c) (MIT License) 2015 Andrey Okonetchnikov\n * https://github.com/react-dropzone/attr-accept/blob/master/src/index.js\n */\nfunction accepts(file: File, acceptedFiles: string | string[]): boolean {\n if (acceptedFiles) {\n const acceptedFilesArray = Array.isArray(acceptedFiles)\n ? acceptedFiles\n : acceptedFiles.split(\",\");\n const fileName = file.name;\n const mimeType = file.type.toLowerCase();\n const baseMimeType = mimeType.replace(/\\/.*$/, \"\");\n console.log({ acceptedFilesArray, fileName, mimeType, baseMimeType });\n return acceptedFilesArray.some((type) => {\n const validType = type.trim().toLowerCase();\n if (validType.startsWith(\".\")) {\n return fileName.toLowerCase().endsWith(validType);\n } else if (validType.endsWith(\"/*\")) {\n // This is something like a image/* mime type\n return baseMimeType === validType.replace(/\\/.*$/, \"\");\n }\n return mimeType === validType;\n });\n }\n return true;\n}\n\nexport const isPropagationStopped = (\n event: Event & { isPropagationStopped?: () => boolean },\n) => {\n if (typeof event.isPropagationStopped === \"function\") {\n return event.isPropagationStopped();\n }\n if (typeof event.cancelBubble !== \"undefined\") {\n return event.cancelBubble;\n }\n return false;\n};\n\n// Firefox versions prior to 53 return a bogus MIME type for every file drag, so dragovers with\n// that MIME type will always be accepted\nexport function isFileAccepted(file: File, accept: string | string[]) {\n return file.type === \"application/x-moz-file\" || accepts(file, accept);\n}\n\nexport function isEnterOrSpace(event: { key?: string; keyCode?: number }) {\n return (\n (\"key\" in event && (event.key === \" \" || event.key === \"Enter\")) ||\n (\"keyCode\" in event && (event.keyCode === 32 || event.keyCode === 13))\n );\n}\n\nconst isDefined = <T>(v: T | null | undefined): v is T => v != null;\nexport function isValidSize(file: File, minSize: number, maxSize: number) {\n if (!isDefined(file.size)) return true;\n if (isDefined(minSize) && isDefined(maxSize)) {\n return file.size >= minSize && file.size <= maxSize;\n }\n if (isDefined(minSize) && file.size < minSize) return false;\n if (isDefined(maxSize) && file.size > maxSize) return false;\n return true;\n}\n\nexport function isValidQuantity(\n files: File[],\n multiple: boolean,\n maxFiles: number,\n) {\n if (!multiple && files.length > 1) return false;\n if (multiple && maxFiles >= 1 && files.length > maxFiles) return false;\n return true;\n}\n\nexport function allFilesAccepted({\n files,\n accept,\n minSize,\n maxSize,\n multiple,\n maxFiles,\n}: {\n files: File[];\n accept: string | string[];\n minSize: number;\n maxSize: number;\n multiple: boolean;\n maxFiles: number;\n}) {\n if (!isValidQuantity(files, multiple, maxFiles)) return false;\n\n return files.every(\n (file) =>\n isFileAccepted(file, accept) && isValidSize(file, minSize, maxSize),\n );\n}\n\nexport function isEventWithFiles(event: Partial<Event>) {\n if (!(\"dataTransfer\" in event && event.dataTransfer !== null)) {\n return !!event.target && \"files\" in event.target && !!event.target.files;\n }\n // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/types\n // https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file\n return Array.prototype.some.call(\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n (event.dataTransfer as any)?.types,\n (type) => type === \"Files\" || type === \"application/x-moz-file\",\n );\n}\n\nexport function isIeOrEdge(ua = window.navigator.userAgent) {\n return (\n ua.includes(\"MSIE \") || ua.includes(\"Trident/\") || ua.includes(\"Edge/\")\n );\n}\n\nfunction isMIMEType(v: string) {\n return (\n v === \"audio/*\" ||\n v === \"video/*\" ||\n v === \"image/*\" ||\n v === \"text/*\" ||\n /\\w+\\/[-+.\\w]+/g.test(v)\n );\n}\n\nfunction isExt(v: string) {\n return /^.*\\.[\\w]+$/.test(v);\n}\n\n/**\n * Convert the `{accept}` dropzone prop to an array of MIME types/extensions.\n */\nexport function acceptPropAsAcceptAttr(accept?: AcceptProp) {\n if (isDefined(accept)) {\n return (\n Object.entries(accept)\n .reduce<string[]>((a, [mimeType, ext]) => [...a, mimeType, ...ext], [])\n // Silently discard invalid entries as pickerOptionsFromAccept warns about these\n .filter((v) => isMIMEType(v) || isExt(v))\n .join(\",\")\n );\n }\n\n return undefined;\n}\n\n/**\n * ================================================\n * Reducer\n * ================================================\n */\ntype Payload<T extends keyof DropzoneState> = Pick<DropzoneState, T>;\n\ntype Focus = { type: \"focus\" };\ntype Blur = { type: \"blur\" };\ntype OpenDialog = { type: \"openDialog\" };\ntype CloseDialog = { type: \"closeDialog\" };\ntype SetDraggedFiles = {\n type: \"setDraggedFiles\";\n payload: Payload<\"isDragActive\" | \"isDragAccept\" | \"isDragReject\">;\n};\ntype SetFiles = { type: \"setFiles\"; payload: Payload<\"acceptedFiles\"> };\ntype Reset = { type: \"reset\" };\ntype DropzoneActions =\n | Focus\n | Blur\n | OpenDialog\n | CloseDialog\n | SetDraggedFiles\n | SetFiles\n | Reset;\n\nexport const initialState = {\n isFocused: false,\n isFileDialogActive: false,\n isDragActive: false,\n isDragAccept: false,\n isDragReject: false,\n acceptedFiles: [] as File[],\n};\n\nexport function reducer(\n state: DropzoneState,\n action: DropzoneActions,\n): DropzoneState {\n switch (action.type) {\n case \"focus\":\n return {\n ...state,\n isFocused: true,\n };\n case \"blur\":\n return {\n ...state,\n isFocused: false,\n };\n case \"openDialog\":\n return {\n ...initialState,\n isFileDialogActive: true,\n };\n case \"closeDialog\":\n return {\n ...state,\n isFileDialogActive: false,\n };\n case \"setDraggedFiles\":\n return {\n ...state,\n ...action.payload,\n };\n case \"setFiles\":\n return {\n ...state,\n ...action.payload,\n };\n case \"reset\":\n return initialState;\n default:\n return state;\n }\n}\n"],"mappings":"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"}
{
"name": "@linear-webdev/shared",
"version": "1.0.2",
"version": "1.0.3",
"type": "module",

@@ -35,3 +35,3 @@ "repository": {

"dependencies": {
"@linear-webdev/mime-types": "1.0.5",
"@linear-webdev/mime-types": "1.0.6",
"effect": "3.17.7",

@@ -38,0 +38,0 @@ "sqids": "^0.3.0"