diff --git a/.changeset/spotty-flowers-flow.md b/.changeset/spotty-flowers-flow.md
new file mode 100644
index 0000000000..9a8f1f7ef0
--- /dev/null
+++ b/.changeset/spotty-flowers-flow.md
@@ -0,0 +1,7 @@
+---
+"@uploadthing/shared": patch
+"@uploadthing/react": patch
+"@uploadthing/expo": patch
+---
+
+fix vite monorepos sometimes complaining about `$RefreshSig$ is not a function`
diff --git a/examples/minimal-tanstack-start/.env.example b/examples/minimal-tanstack-start/.env.example
new file mode 100644
index 0000000000..87877a7ff0
--- /dev/null
+++ b/examples/minimal-tanstack-start/.env.example
@@ -0,0 +1,2 @@
+# Go to https://uploadthing.com/dashboard to get your token
+UPLOADTHING_TOKEN='...'
\ No newline at end of file
diff --git a/examples/minimal-tanstack-start/app.config.ts b/examples/minimal-tanstack-start/app.config.ts
new file mode 100644
index 0000000000..e00f8dbef6
--- /dev/null
+++ b/examples/minimal-tanstack-start/app.config.ts
@@ -0,0 +1,3 @@
+import { defineConfig } from "@tanstack/start/config";
+
+export default defineConfig({});
diff --git a/examples/minimal-tanstack-start/app/api.ts b/examples/minimal-tanstack-start/app/api.ts
new file mode 100644
index 0000000000..f1324764dd
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/api.ts
@@ -0,0 +1,6 @@
+import {
+ createStartAPIHandler,
+ defaultAPIFileRouteHandler,
+} from "@tanstack/start/api";
+
+export default createStartAPIHandler(defaultAPIFileRouteHandler);
diff --git a/examples/minimal-tanstack-start/app/client.tsx b/examples/minimal-tanstack-start/app/client.tsx
new file mode 100644
index 0000000000..f7f49c6d38
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/client.tsx
@@ -0,0 +1,8 @@
+import { StartClient } from "@tanstack/start";
+import { hydrateRoot } from "react-dom/client";
+
+import { createRouter } from "./router";
+
+const router = createRouter();
+
+hydrateRoot(document.getElementById("root")!, );
diff --git a/examples/minimal-tanstack-start/app/routeTree.gen.ts b/examples/minimal-tanstack-start/app/routeTree.gen.ts
new file mode 100644
index 0000000000..8f205ff90a
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/routeTree.gen.ts
@@ -0,0 +1,89 @@
+/* prettier-ignore-start */
+
+/* eslint-disable */
+
+// @ts-nocheck
+
+// noinspection JSUnusedGlobalSymbols
+
+// This file is auto-generated by TanStack Router
+
+// Import Routes
+
+import { Route as rootRoute } from "./routes/__root";
+import { Route as IndexImport } from "./routes/index";
+
+// Create/Update Routes
+
+const IndexRoute = IndexImport.update({
+ path: "/",
+ getParentRoute: () => rootRoute,
+} as any);
+
+// Populate the FileRoutesByPath interface
+
+declare module "@tanstack/react-router" {
+ interface FileRoutesByPath {
+ "/": {
+ id: "/";
+ path: "/";
+ fullPath: "/";
+ preLoaderRoute: typeof IndexImport;
+ parentRoute: typeof rootRoute;
+ };
+ }
+}
+
+// Create and export the route tree
+
+export interface FileRoutesByFullPath {
+ "/": typeof IndexRoute;
+}
+
+export interface FileRoutesByTo {
+ "/": typeof IndexRoute;
+}
+
+export interface FileRoutesById {
+ __root__: typeof rootRoute;
+ "/": typeof IndexRoute;
+}
+
+export interface FileRouteTypes {
+ fileRoutesByFullPath: FileRoutesByFullPath;
+ fullPaths: "/";
+ fileRoutesByTo: FileRoutesByTo;
+ to: "/";
+ id: "__root__" | "/";
+ fileRoutesById: FileRoutesById;
+}
+
+export interface RootRouteChildren {
+ IndexRoute: typeof IndexRoute;
+}
+
+const rootRouteChildren: RootRouteChildren = {
+ IndexRoute: IndexRoute,
+};
+
+export const routeTree = rootRoute
+ ._addFileChildren(rootRouteChildren)
+ ._addFileTypes();
+
+/* prettier-ignore-end */
+
+/* ROUTE_MANIFEST_START
+{
+ "routes": {
+ "__root__": {
+ "filePath": "__root.tsx",
+ "children": [
+ "/"
+ ]
+ },
+ "/": {
+ "filePath": "index.tsx"
+ }
+ }
+}
+ROUTE_MANIFEST_END */
diff --git a/examples/minimal-tanstack-start/app/router.tsx b/examples/minimal-tanstack-start/app/router.tsx
new file mode 100644
index 0000000000..4552d1ca39
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/router.tsx
@@ -0,0 +1,17 @@
+import { createRouter as createTanStackRouter } from "@tanstack/react-router";
+
+import { routeTree } from "./routeTree.gen";
+
+export function createRouter() {
+ const router = createTanStackRouter({
+ routeTree,
+ });
+
+ return router;
+}
+
+declare module "@tanstack/react-router" {
+ interface Register {
+ router: ReturnType;
+ }
+}
diff --git a/examples/minimal-tanstack-start/app/routes/__root.tsx b/examples/minimal-tanstack-start/app/routes/__root.tsx
new file mode 100644
index 0000000000..ae4d5d2f1b
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/routes/__root.tsx
@@ -0,0 +1,38 @@
+import * as React from "react";
+import {
+ createRootRoute,
+ Outlet,
+ ScrollRestoration,
+} from "@tanstack/react-router";
+import { Body, Head, Html, Meta, Scripts } from "@tanstack/start";
+
+// @ts-expect-error
+import uploadthingCss from "@uploadthing/react/styles.css?url";
+
+export const Route = createRootRoute({
+ component: RootComponent,
+ links: () => [{ rel: "stylesheet", href: uploadthingCss }],
+});
+
+function RootComponent() {
+ return (
+
+
+
+ );
+}
+
+function RootDocument({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/examples/minimal-tanstack-start/app/routes/api/uploadthing.ts b/examples/minimal-tanstack-start/app/routes/api/uploadthing.ts
new file mode 100644
index 0000000000..68c07c1a65
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/routes/api/uploadthing.ts
@@ -0,0 +1,11 @@
+import { createAPIFileRoute } from "@tanstack/start/api";
+
+import { createRouteHandler } from "uploadthing/server";
+
+import { uploadRouter } from "../../server/uploadthing";
+
+const handlers = createRouteHandler({ router: uploadRouter });
+export const Route = createAPIFileRoute("/api/uploadthing")({
+ GET: handlers,
+ POST: handlers,
+});
diff --git a/examples/minimal-tanstack-start/app/routes/index.tsx b/examples/minimal-tanstack-start/app/routes/index.tsx
new file mode 100644
index 0000000000..71dfbe11ce
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/routes/index.tsx
@@ -0,0 +1,79 @@
+import { createFileRoute } from "@tanstack/react-router";
+
+import {
+ UploadButton,
+ UploadDropzone,
+ useUploadThing,
+} from "../utils/uploadthing";
+
+export const Route = createFileRoute("/")({
+ component: Home,
+});
+
+function Home() {
+ const { startUpload } = useUploadThing("videoAndImage", {
+ /**
+ * @see https://docs.uploadthing.com/api-reference/react#useuploadthing
+ */
+ onBeforeUploadBegin: (files) => {
+ console.log("Uploading", files.length, "files");
+ return files;
+ },
+ onUploadBegin: (name) => {
+ console.log("Beginning upload of", name);
+ },
+ onClientUploadComplete: (res) => {
+ console.log("Upload Completed.", res.length, "files uploaded");
+ },
+ onUploadProgress(p) {
+ console.log("onUploadProgress", p);
+ },
+ });
+
+ return (
+
+ {
+ console.log(`onClientUploadComplete`, res);
+ alert("Upload Completed");
+ }}
+ onUploadBegin={() => {
+ console.log("upload begin");
+ }}
+ config={{ appendOnPaste: true, mode: "manual" }}
+ />
+ {
+ alert("Upload Aborted");
+ }}
+ onClientUploadComplete={(res) => {
+ console.log(`onClientUploadComplete`, res);
+ alert("Upload Completed");
+ }}
+ onUploadBegin={() => {
+ console.log("upload begin");
+ }}
+ />
+ {
+ const files = Array.from(e.target.files ?? []);
+
+ // Do something with files
+
+ // Then start the upload
+ await startUpload(files);
+ }}
+ />
+
+ );
+}
diff --git a/examples/minimal-tanstack-start/app/server/uploadthing.ts b/examples/minimal-tanstack-start/app/server/uploadthing.ts
new file mode 100644
index 0000000000..b664e6c096
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/server/uploadthing.ts
@@ -0,0 +1,61 @@
+import { createUploadthing, UTFiles } from "uploadthing/next";
+import type { FileRouter } from "uploadthing/next";
+
+const f = createUploadthing({
+ /**
+ * Log out more information about the error, but don't return it to the client
+ * @see https://docs.uploadthing.com/errors#error-formatting
+ */
+ errorFormatter: (err) => {
+ console.log("Error uploading file", err.message);
+ console.log(" - Above error caused by:", err.cause);
+
+ return { message: err.message };
+ },
+});
+
+/**
+ * This is your Uploadthing file router. For more information:
+ * @see https://docs.uploadthing.com/api-reference/server#file-routes
+ */
+export const uploadRouter = {
+ videoAndImage: f({
+ image: {
+ maxFileSize: "32MB",
+ maxFileCount: 4,
+ acl: "public-read",
+ },
+ video: {
+ maxFileSize: "16MB",
+ },
+ blob: {
+ maxFileSize: "8GB",
+ },
+ })
+ .middleware(({ req, files }) => {
+ // Check some condition based on the incoming requrest
+ console.log("Request", req);
+ //^?
+ // if (!req.headers.get("x-some-header")) {
+ // throw new Error("x-some-header is required");
+ // }
+
+ // (Optional) Label your files with a custom identifier
+ const filesWithMyIds = files.map((file, idx) => ({
+ ...file,
+ customId: `${idx}-HELLO`,
+ }));
+
+ // Return some metadata to be stored with the file
+ return { foo: "bar" as const, [UTFiles]: filesWithMyIds };
+ })
+ .onUploadComplete(({ file, metadata }) => {
+ metadata;
+ // ^?
+ file.customId;
+ // ^?
+ console.log("upload completed", file);
+ }),
+} satisfies FileRouter;
+
+export type OurFileRouter = typeof uploadRouter;
diff --git a/examples/minimal-tanstack-start/app/ssr.tsx b/examples/minimal-tanstack-start/app/ssr.tsx
new file mode 100644
index 0000000000..b271444181
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/ssr.tsx
@@ -0,0 +1,12 @@
+import { getRouterManifest } from "@tanstack/start/router-manifest";
+import {
+ createStartHandler,
+ defaultStreamHandler,
+} from "@tanstack/start/server";
+
+import { createRouter } from "./router";
+
+export default createStartHandler({
+ createRouter,
+ getRouterManifest,
+})(defaultStreamHandler);
diff --git a/examples/minimal-tanstack-start/app/utils/uploadthing.ts b/examples/minimal-tanstack-start/app/utils/uploadthing.ts
new file mode 100644
index 0000000000..b77a7e14ff
--- /dev/null
+++ b/examples/minimal-tanstack-start/app/utils/uploadthing.ts
@@ -0,0 +1,12 @@
+import {
+ generateReactHelpers,
+ generateUploadButton,
+ generateUploadDropzone,
+} from "@uploadthing/react";
+
+import type { OurFileRouter } from "../server/uploadthing";
+
+export const UploadButton = generateUploadButton();
+export const UploadDropzone = generateUploadDropzone();
+
+export const { useUploadThing } = generateReactHelpers();
diff --git a/examples/minimal-tanstack-start/package.json b/examples/minimal-tanstack-start/package.json
new file mode 100644
index 0000000000..1962d4524e
--- /dev/null
+++ b/examples/minimal-tanstack-start/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "@example/minimal-tanstack-start",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vinxi dev",
+ "build": "vinxi build",
+ "start": "vinxi start"
+ },
+ "dependencies": {
+ "@tanstack/react-router": "^1.58.7",
+ "@tanstack/start": "^1.58.7",
+ "@uploadthing/react": "7.0.2",
+ "react": "18.3.1",
+ "react-dom": "18.3.1",
+ "uploadthing": "7.0.2",
+ "vinxi": "^0.4.3"
+ },
+ "devDependencies": {
+ "@types/react": "18.3.3",
+ "@types/react-dom": "18.3.0",
+ "@vitejs/plugin-react": "^4.3.1",
+ "typescript": "^5.5.2"
+ }
+}
diff --git a/examples/minimal-tanstack-start/tsconfig.json b/examples/minimal-tanstack-start/tsconfig.json
new file mode 100644
index 0000000000..6003c08318
--- /dev/null
+++ b/examples/minimal-tanstack-start/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "jsx": "react-jsx",
+ "moduleResolution": "Bundler",
+ "module": "ESNext",
+ "target": "ES2022",
+ "skipLibCheck": true
+ }
+}
diff --git a/packages/expo/src/document-picker.ts b/packages/expo/src/document-picker.ts
index 3d8ef2b5fd..99d61df5cf 100644
--- a/packages/expo/src/document-picker.ts
+++ b/packages/expo/src/document-picker.ts
@@ -2,7 +2,7 @@ import { useMemo } from "react";
import * as DocumentPicker from "expo-document-picker";
import type { UseUploadthingProps } from "@uploadthing/react";
-import { INTERNAL_uploadthingHookGen } from "@uploadthing/react/native";
+import { __useUploadThingInternal } from "@uploadthing/react/native";
import { generatePermittedFileTypes } from "@uploadthing/shared";
import type { ExpandedRouteConfig, ExtendObjectIf } from "@uploadthing/shared";
import type { FileRouter } from "uploadthing/server";
@@ -34,15 +34,12 @@ export const GENERATE_useDocumentUploader = <
>(initOpts: {
url: URL;
}) => {
- const useUploadThing = INTERNAL_uploadthingHookGen({
- url: initOpts.url,
- });
-
const useDocumentUploader = (
endpoint: TEndpoint,
opts?: UseUploadthingProps,
) => {
- const { routeConfig, startUpload, isUploading } = useUploadThing(
+ const { routeConfig, startUpload, isUploading } = __useUploadThingInternal(
+ initOpts.url,
endpoint,
opts,
);
diff --git a/packages/expo/src/image-picker.ts b/packages/expo/src/image-picker.ts
index 4f81fa46a1..33475bf15e 100644
--- a/packages/expo/src/image-picker.ts
+++ b/packages/expo/src/image-picker.ts
@@ -2,7 +2,7 @@ import { useMemo } from "react";
import * as ImagePicker from "expo-image-picker";
import type { UseUploadthingProps } from "@uploadthing/react";
-import { INTERNAL_uploadthingHookGen } from "@uploadthing/react/native";
+import { __useUploadThingInternal } from "@uploadthing/react/native";
import { generatePermittedFileTypes } from "@uploadthing/shared";
import type { ExpandedRouteConfig, ExtendObjectIf } from "@uploadthing/shared";
import type { FileRouter } from "uploadthing/server";
@@ -26,15 +26,12 @@ export const GENERATE_useImageUploader = <
>(initOpts: {
url: URL;
}) => {
- const useUploadThing = INTERNAL_uploadthingHookGen({
- url: initOpts.url,
- });
-
const useImageUploader = (
endpoint: TEndpoint,
opts?: UseUploadthingProps,
) => {
- const { routeConfig, startUpload, isUploading } = useUploadThing(
+ const { routeConfig, startUpload, isUploading } = __useUploadThingInternal(
+ initOpts.url,
endpoint,
opts,
);
diff --git a/packages/expo/src/index.ts b/packages/expo/src/index.ts
index bd338c68f8..dd3fa1aa1d 100644
--- a/packages/expo/src/index.ts
+++ b/packages/expo/src/index.ts
@@ -1,9 +1,11 @@
import Constants from "expo-constants";
import { generateReactHelpers } from "@uploadthing/react/native";
-import type * as _TS_FIND_ME_1 from "@uploadthing/shared";
+import { warnIfInvalidPeerDependency } from "@uploadthing/shared";
+import { version as uploadthingClientVersion } from "uploadthing/client";
import type { FileRouter } from "uploadthing/internal/types";
+import { peerDependencies } from "../package.json";
import { GENERATE_useDocumentUploader } from "./document-picker";
import { GENERATE_useImageUploader } from "./image-picker";
@@ -23,6 +25,12 @@ export interface GenerateTypedHelpersOptions {
export const generateReactNativeHelpers = (
initOpts?: GenerateTypedHelpersOptions,
) => {
+ warnIfInvalidPeerDependency(
+ "@uploadthing/expo",
+ peerDependencies.uploadthing,
+ uploadthingClientVersion,
+ );
+
const debuggerHost = Constants.expoConfig?.hostUri;
let url = new URL("http://localhost:8081/api/uploadthing");
try {
diff --git a/packages/react/src/components/button.tsx b/packages/react/src/components/button.tsx
index 9d0e3e0b2f..0b53de2a88 100644
--- a/packages/react/src/components/button.tsx
+++ b/packages/react/src/components/button.tsx
@@ -22,7 +22,7 @@ import type {
import type { FileRouter } from "uploadthing/types";
import type { UploadthingComponentProps } from "../types";
-import { INTERNAL_uploadthingHookGen } from "../useUploadThing";
+import { __useUploadThingInternal } from "../useUploadThing";
import { usePaste } from "../utils/usePaste";
import { Cancel, progressWidths, Spinner } from "./shared";
@@ -102,10 +102,6 @@ export function UploadButton<
} = $props.config ?? {};
const acRef = useRef(new AbortController());
- const useUploadThing = INTERNAL_uploadthingHookGen({
- url: resolveMaybeUrlArg($props.url),
- });
-
const fileInputRef = useRef(null);
const labelRef = useRef(null);
const [uploadProgress, setUploadProgress] = useState(
@@ -113,7 +109,8 @@ export function UploadButton<
);
const [files, setFiles] = useState([]);
- const { startUpload, isUploading, routeConfig } = useUploadThing(
+ const { startUpload, isUploading, routeConfig } = __useUploadThingInternal(
+ resolveMaybeUrlArg($props.url),
$props.endpoint,
{
signal: acRef.current.signal,
diff --git a/packages/react/src/components/dropzone.tsx b/packages/react/src/components/dropzone.tsx
index 93cf4ef78b..4f1255c936 100644
--- a/packages/react/src/components/dropzone.tsx
+++ b/packages/react/src/components/dropzone.tsx
@@ -49,7 +49,7 @@ import type {
import type { FileRouter } from "uploadthing/types";
import type { UploadthingComponentProps } from "../types";
-import { INTERNAL_uploadthingHookGen } from "../useUploadThing";
+import { __useUploadThingInternal } from "../useUploadThing";
import { Cancel, progressWidths, Spinner } from "./shared";
type DropzoneStyleFieldCallbackArgs = {
@@ -137,10 +137,6 @@ export function UploadDropzone<
} = $props.config ?? {};
const acRef = useRef(new AbortController());
- const useUploadThing = INTERNAL_uploadthingHookGen({
- url: resolveMaybeUrlArg($props.url),
- });
-
const [files, setFiles] = useState([]);
const [uploadProgressState, setUploadProgress] = useState(
@@ -148,7 +144,8 @@ export function UploadDropzone<
);
const uploadProgress =
$props.__internal_upload_progress ?? uploadProgressState;
- const { startUpload, isUploading, routeConfig } = useUploadThing(
+ const { startUpload, isUploading, routeConfig } = __useUploadThingInternal(
+ resolveMaybeUrlArg($props.url),
$props.endpoint,
{
signal: acRef.current.signal,
diff --git a/packages/react/src/components/index.tsx b/packages/react/src/components/index.tsx
index 4d1d1948c9..77c78f4735 100644
--- a/packages/react/src/components/index.tsx
+++ b/packages/react/src/components/index.tsx
@@ -1,6 +1,11 @@
-import { resolveMaybeUrlArg } from "@uploadthing/shared";
+import {
+ resolveMaybeUrlArg,
+ warnIfInvalidPeerDependency,
+} from "@uploadthing/shared";
+import { version as uploadthingClientVersion } from "uploadthing/client";
import type { FileRouter } from "uploadthing/types";
+import { peerDependencies } from "../../package.json";
import type {
GenerateTypedHelpersOptions,
UploadthingComponentProps,
@@ -16,6 +21,12 @@ export { UploadButton, UploadDropzone, Uploader };
export const generateUploadButton = (
opts?: GenerateTypedHelpersOptions,
) => {
+ warnIfInvalidPeerDependency(
+ "@uploadthing/react",
+ peerDependencies.uploadthing,
+ uploadthingClientVersion,
+ );
+
const url = resolveMaybeUrlArg(opts?.url);
const TypedButton = (
@@ -30,6 +41,12 @@ export const generateUploadButton = (
export const generateUploadDropzone = (
opts?: GenerateTypedHelpersOptions,
) => {
+ warnIfInvalidPeerDependency(
+ "@uploadthing/react",
+ peerDependencies.uploadthing,
+ uploadthingClientVersion,
+ );
+
const url = resolveMaybeUrlArg(opts?.url);
const TypedDropzone = (
@@ -44,6 +61,12 @@ export const generateUploadDropzone = (
export const generateUploader = (
opts?: GenerateTypedHelpersOptions,
) => {
+ warnIfInvalidPeerDependency(
+ "@uploadthing/react",
+ peerDependencies.uploadthing,
+ uploadthingClientVersion,
+ );
+
const url = resolveMaybeUrlArg(opts?.url);
const TypedUploader = (
diff --git a/packages/react/src/native.ts b/packages/react/src/native.ts
index 82ff98ce5e..4c27653640 100644
--- a/packages/react/src/native.ts
+++ b/packages/react/src/native.ts
@@ -4,7 +4,7 @@ export {
*/
generateReactHelpers,
/**
- * @internal - if you're using @uploadthing/react, import this from the main entrypoint instead
+ * @deprecated - This is an internal function.
*/
- INTERNAL_uploadthingHookGen,
+ __useUploadThingInternal,
} from "./useUploadThing";
diff --git a/packages/react/src/useUploadThing.ts b/packages/react/src/useUploadThing.ts
index abc77779db..7b7b799751 100644
--- a/packages/react/src/useUploadThing.ts
+++ b/packages/react/src/useUploadThing.ts
@@ -7,9 +7,9 @@ import type {
import {
INTERNAL_DO_NOT_USE__fatalClientError,
resolveMaybeUrlArg,
- semverLite,
UploadAbortedError,
UploadThingError,
+ warnIfInvalidPeerDependency,
} from "@uploadthing/shared";
import {
genUploader,
@@ -42,119 +42,123 @@ const useRouteConfig = (
return (maybeServerData ?? data)?.find((x) => x.slug === endpoint)?.config;
};
-export const INTERNAL_uploadthingHookGen = <
+/**
+ * @internal - This is an internal function. Use `generateReactHelpers` instead.
+ * The actual hook we export for public usage is generated from `generateReactHelpers`
+ * which has the URL and FileRouter generic pre-bound.
+ */
+export function __useUploadThingInternal<
TRouter extends FileRouter,
->(initOpts: {
- /**
- * URL to the UploadThing API endpoint
- * @example URL { http://localhost:3000/api/uploadthing }
- * @example URL { https://www.example.com/api/uploadthing }
- */
- url: URL;
-}) => {
- if (!semverLite(peerDependencies.uploadthing, uploadthingClientVersion)) {
- console.error(
- `!!!WARNING::: @uploadthing/react requires "uploadthing@${peerDependencies.uploadthing}", but version "${uploadthingClientVersion}" is installed`,
- );
- }
+ TEndpoint extends keyof TRouter,
+>(
+ url: URL,
+ endpoint: TEndpoint,
+ opts?: UseUploadthingProps,
+) {
const { uploadFiles } = genUploader({
- url: initOpts.url,
+ url,
package: "@uploadthing/react",
});
- const useUploadThing = (
- endpoint: TEndpoint,
- opts?: UseUploadthingProps,
- ) => {
- const [isUploading, setUploading] = useState(false);
- const uploadProgress = useRef(0);
- const fileProgress = useRef