uploadthing icon indicating copy to clipboard operation
uploadthing copied to clipboard

feat: Add Convex Adapter

Open IslamIhab opened this issue 3 months ago • 10 comments

Summary

  • This PR adds Convex adapter.
  • This repo is an example for how to implement it.
  • It was highly inspired from PR #929.
  • New Convex adapter entrypoints
    • packages/uploadthing/src/convex.ts
    • packages/uploadthing/src/convex-helpers.ts

Design decisions

  • Internal action boundary: Keep UploadThing’s core handler pure over Request/Response, and adapt at the Convex boundary using internalActionGeneric. Mirrors existing framework adapters and avoids Convex-specific leakage.
  • Request envelope: Convex internal actions require serializable args; we pass { url, method, headers, body? } and reconstruct a Request inside the action.
  • CORS handling: Uses convex-helpers corsRouter to handle cors

Developer experience

Usage sketch:

// convex/http.ts
import corsRouter from "convex-helpers/server/cors";
import { httpRouter } from "convex/server";

import { createRouteHandler } from "uploadthing/convex-helpers";

import { internal } from "./_generated/api";

const http = httpRouter();

const cors = corsRouter(http, {
  allowedOrigins: ["http://localhost:3000"],
});

createRouteHandler({
  http: cors,
  internalAction: internal.uploadthing.handler,
  path: "/api/uploadthing",
});

export default http;
// convex/uploadthing.ts
"use node";

import { createInternalAction, createUploadthing, FileRouter } from "uploadthing/convex";
import { api } from "./_generated/api";
import crypto from "node:crypto";
// globalThis.crypto is not defined in convex
globalThis.crypto = crypto as Crypto;

const f = createUploadthing();

const router = {
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    .middleware(async (opts) => {
      const identity = await opts.ctx.auth.getUserIdentity();

      return { userId: identity?.subject };
    })
    .onUploadComplete(async (opts) => {
      await opts.ctx.runMutation(api.media.add, { url: opts.file.ufsUrl });
      return { uploadedBy: opts.metadata.userId };
    }),
} satisfies FileRouter;

export type OurFileRouter = typeof router;

export const handler = createInternalAction({ router });

Required env on convex:

  • UPLOADTHING_TOKEN

Thanks for taking a look! I’m happy to iterate on naming, paths, or API surface to fit project.

Summary by CodeRabbit

  • New Features

    • Convex backend adapter: upload builders, internal action bridge, and HTTP route helper; optional Convex peer support.
  • Documentation

    • New Convex integration guide, docs page, navigation entry, and Convex logo/icon added.
  • Examples

    • Minimal Next.js + Convex example with upload routes, handlers, schema, and client wiring.
  • Chores

    • Build and publish config updated to include Convex artifacts and example assets.

IslamIhab avatar Sep 02 '25 20:09 IslamIhab

🦋 Changeset detected

Latest commit: 75f4383695af312f028b3257b3d65733cf1aebcc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
uploadthing Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

changeset-bot[bot] avatar Sep 02 '25 20:09 changeset-bot[bot]

Walkthrough

Adds a Convex backend adapter for UploadThing: new source modules (convex, convex-helpers), package exports and optional peer dependencies for convex/convex-helpers, build and declaration config updates, docs, and a minimal Convex example app wiring UploadThing through a Convex internal action and HTTP router.

Changes

Cohort / File(s) Summary
Package exports & publishing
packages/uploadthing/package.json
Adds exports entries ./convex and ./convex-helpers (ESM/CJS + types), includes convex and convex-helpers in files, and declares them as optional peerDependencies.
Build / declaration config
packages/uploadthing/tsdown.config.ts,
packages/uploadthing/turbo.json
Adds tsdown entries mapping ../convex/indexsrc/convex.ts and ../convex-helpers/indexsrc/convex-helpers.ts; adds convex/** and convex-helpers/** to turbo build outputs.
Convex integration source
packages/uploadthing/src/convex.ts,
packages/uploadthing/src/convex-helpers.ts
New Convex adapter implementation: createUploadthing builder, createInternalAction (adapts UploadThing handlers to Convex internal actions), and createRouteHandler HTTP bridge registering OPTIONS/GET/POST and forwarding requests to Convex actions.
Documentation page
docs/src/app/(docs)/backend-adapters/convex/page.mdx
New docs page describing Convex adapter setup, FileRouter example, server wiring, HTTP mounting, and client usage.
Docs UI & nav
docs/src/components/icons.tsx, docs/src/components/Libraries.tsx, docs/src/site-config.ts
Adds ConvexIcon, inserts Convex into Backend Adapters list and site navigation, and adjusts the adapters grid layout.
Changeset
.changeset/swift-beds-explain.md
Adds changeset noting a minor version bump and Convex adapter addition.
Example project metadata
examples/minimal-convex/package.json, examples/minimal-convex/next.config.js, examples/minimal-convex/tsconfig.json, examples/minimal-convex/next-env.d.ts, examples/minimal-convex/.env.example, examples/minimal-convex/.gitignore, examples/minimal-convex/README.md
New Next.js + Convex example project with scripts, env example, gitignore, README, and TS/Next config.
Example Convex backend
examples/minimal-convex/convex/*
Adds Convex schema, http router (http.ts) using createRouteHandler, media mutation, UploadThing internal action/router (uploadthing.ts), Convex tsconfig, and example README.
Example Next.js UI
examples/minimal-convex/src/app/layout.tsx, examples/minimal-convex/src/app/page.tsx, examples/minimal-convex/src/utils/uploadthing.ts
Adds RootLayout with UploadThing SSR plugin, example page demonstrating UploadButton/Dropzone and manual upload flows, and typed helper exports (UploadButton, UploadDropzone, useUploadThing) configured to Convex site URL.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User as Client
  participant Browser as Browser
  participant ConvexHTTP as Convex HTTP Router
  participant Bridge as createRouteHandler
  participant InternalAction as Convex internalAction
  participant Adapter as adapter handler (makeAdapterHandler)
  participant UT as UploadThing router

  User->>Browser: Start upload
  Browser->>ConvexHTTP: POST /api/uploadthing
  Note right of ConvexHTTP #f3f3f3: OPTIONS route returns 204 for preflight
  ConvexHTTP->>Bridge: matched route
  Bridge->>InternalAction: ctx.runAction(internalAction, { request })
  InternalAction->>Adapter: construct Request and invoke adapter handler
  Adapter->>UT: Dispatch to UploadThing router
  UT-->>Adapter: Response { status, statusText, headers, body }
  Adapter-->>InternalAction: return Response-like object
  InternalAction-->>Bridge: plain result forwarded
  Bridge-->>ConvexHTTP: respond with action-derived status, headers, body
  ConvexHTTP-->>Browser: HTTP response

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

uploadthing/client

Suggested reviewers

  • markflorkowski
  • juliusmarminge

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f840666af289fd80d4d70fd8544506281776dac5 and 75f4383695af312f028b3257b3d65733cf1aebcc.

📒 Files selected for processing (1)
  • examples/minimal-convex/convex/http.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/minimal-convex/convex/http.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Vade Review
✨ Finishing Touches
  • [ ] 📝 Generate Docstrings
🧪 Generate unit tests
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

coderabbitai[bot] avatar Sep 02 '25 20:09 coderabbitai[bot]

@IslamIhab is attempting to deploy a commit to the Ping Labs Team on Vercel.

A member of the Team first needs to authorize it.

vercel[bot] avatar Sep 02 '25 20:09 vercel[bot]

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
legacy-docs-uploadthing Ignored Ignored Sep 4, 2025 0:03am

vercel[bot] avatar Sep 02 '25 20:09 vercel[bot]

Needs docs and examples.

markflorkowski avatar Sep 02 '25 20:09 markflorkowski

@markflorkowski Added docs and example

IslamIhab avatar Sep 03 '25 00:09 IslamIhab

@markflorkowski Sorry for spamming but could I get a review? If the PR is a bit too bit I can break it down to several smaller PRs to make each part take less time

IslamIhab avatar Sep 28 '25 00:09 IslamIhab

I would love to see this getting merged soon. @IslamIhab Great work man!

eliotgevers avatar Oct 11 '25 15:10 eliotgevers

+1

frailbongat avatar Oct 15 '25 11:10 frailbongat

bump for this, really need it asap

feldrok avatar Oct 28 '25 14:10 feldrok

+1

Ale4224 avatar Nov 29 '25 16:11 Ale4224