Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Convex adapter #929

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

sujayakar
Copy link

@sujayakar sujayakar commented Sep 3, 2024

This PR adds a Convex adapter as a sibling to Express, Fastify, etc. It was pretty straightforward to add a new adapter!

Here's what it looks like for wiring it in to a Convex app. First, call createUploadthing as always:

// convex/http.ts
import { addUploadthingRoutes, convexCtx, createUploadthing, type FileRouter } from "uploadthing/convex"
import schema from "./schema"

const f = createUploadthing({
  errorFormatter: (err) => {
    console.log("Error uploading file", err.message);
    console.log("  - Above error caused by:", err.cause);

    return { message: err.message };
  },
  schema,
});

Note that the developer can optionally pass in their Convex schema here for more type-safety within their handlers.

Then, define the router, using the convexCtx function to access the request's current ctx value. This is necessary for calling into other Convex functions, accessing auth and the database, etc. Under the hood, this uses a hack where we stash the ctx when starting a request.

export const uploadRouter = {
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    .middleware(async (args) => {
      const ctx = convexCtx(f);      
      const identity = await ctx.auth.getUserIdentity();
      ...
      return { userId: identity?.subject ?? "nothing" }
    })
    .onUploadComplete(async (args) => {      
      const ctx = convexCtx(f);
      ...      
      return { uploadedBy: args.metadata.userId };
    }),
} satisfies FileRouter;
export type OurFileRouter = typeof uploadRouter;

Finally, install the routes into Convex's HTTP router with addUploadthingRoutes:

const http = httpRouter();
addUploadthingRoutes(http, f, { router: uploadRouter })
export default http;    

Questions

  • The hack to sneak in ctx via a "global" with convexCtx is a bit ugly. Is there a better way to pass values to the middleware and completion callbacks?
  • Where should I add Convex to the docs? Would another entry next to https://docs.uploadthing.com/backend-adapters/express be the right spot?
  • Should I add my Uploadthing+Convex example app from the snippets above as a new directory under examples/? It'll require setting up a Convex account (or self hosting Convex) to actually run the demo.
  • Are there any tests, etc., that I should also be updating?

Summary by CodeRabbit

  • New Features

    • Introduced functionality for handling file uploads using the Convex framework.
    • Added new HTTP routes for file uploads at /api/uploadthing.
    • Configured an image upload route with a maximum file size of 4MB.
  • Enhancements

    • Updated package configuration to include a new export for convex and its optional peer dependency.
    • Expanded the build process to include files from the convex directory.
    • Added a dependency for convex in the backend adapter project.

Copy link

changeset-bot bot commented Sep 3, 2024

⚠️ No Changeset found

Latest commit: ecf7a83

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

Copy link

vercel bot commented Sep 3, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
docs-uploadthing ❌ Failed (Inspect) Jan 10, 2025 10:57pm
1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
legacy-docs-uploadthing ⬜️ Ignored (Inspect) Visit Preview Jan 10, 2025 10:57pm

Copy link
Contributor

coderabbitai bot commented Oct 17, 2024

Walkthrough

The pull request introduces updates to the uploadthing package, including modifications to the package.json, the addition of a new convex.ts file, and changes to the turbo.json configuration. The package.json now includes a new export for convex and a peer dependency, while the convex.ts file implements functionality for file uploads using the Convex framework. Additionally, the turbo.json file has been updated to include the convex directory in the build outputs.

Changes

File Path Change Summary
packages/uploadthing/package.json - Added export: ./convex with import and require configurations.
- Added dependency: "convex": "^1.17.4".
- Added peer dependency: "convex": "*".
- Updated peerDependenciesMeta to indicate convex is optional.
packages/uploadthing/src/convex.ts - Introduced convex.ts with functions: createUploadthing and addUploadthingRoutes for file upload handling.
- Defined types for middleware arguments and builder options.
packages/uploadthing/turbo.json - Added output path: "convex/**" to build task in turbo.json.
examples/backend-adapters/server/package.json - Added dependency: "convex": "^1.17.4".
examples/backend-adapters/server/src/convex.ts - Introduced convex.ts for HTTP routes with imageUploader, handling file uploads with user identity.

Possibly related PRs

Suggested labels

uploadthing/client, sdk


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47a9022 and d6cd436.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • examples/backend-adapters/server/package.json (1 hunks)
  • packages/uploadthing/package.json (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/backend-adapters/server/package.json
🔇 Additional comments (3)
packages/uploadthing/package.json (3)

103-112: LGTM! Export configuration follows package conventions.

The new Convex adapter export configuration follows the established pattern used for other adapters in the package, properly defining both import and require paths with their respective type definitions.


Line range hint 1-3: Version Not Updated in package.json

The version field remains at "7.4.4" and should be updated to reflect the addition of the new Convex adapter feature.


171-171: Verify Convex version compatibility

The implementation includes Convex with the following configuration:

  • Dev dependency: ^1.17.4
  • Peer dependency: *
  • Correctly marked as optional

Please verify:

  1. The minimum required Convex version for the adapter's functionality
  2. Whether we should constrain the peer dependency version range instead of using *

Run the following script to check Convex version compatibility:

Also applies to: 186-186, 201-203

✅ Verification successful

Convex version configuration is appropriate

Based on the code analysis:

  1. The implementation uses basic Convex server features from convex/server package:

    • httpRouter
    • httpActionGeneric
    • Standard HTTP routing functionality
  2. No version-specific APIs or advanced features are used that would require a minimum version constraint.

The current configuration is appropriate:

  • Dev dependency ^1.17.4: Reasonable recent version for development
  • Peer dependency *: Justified as the adapter uses stable, core HTTP routing features
  • Optional: Correctly marked as the Convex adapter is optional
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Convex version compatibility across the repository

# Check if there are any version constraints in code comments
rg -i "requires? convex" --type ts

# Check Convex version in examples
fd package.json --exec grep -l convex {} \; --exec grep -A 1 '"convex":' {}

# Check for Convex version-specific API usage
rg "from 'convex/" --type ts

Length of output: 417


Script:

#!/bin/bash
# Let's check the actual Convex adapter implementation to understand version requirements

# Find Convex adapter implementation
rg -l "convex.*adapter" --type ts

# Search for Convex imports and usage patterns
ast-grep --pattern 'import { $_ } from "convex"'

# Look for any Convex-specific types or interfaces
rg "convex" -B2 -A2 --type ts

# Check for any migration guides or breaking changes mentioned in docs
fd "MIGRATION|CHANGELOG|BREAKING" -E md -E txt -X grep -l "convex" {} \;

Length of output: 1620


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai 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

Documentation and Community

  • 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (1)
packages/uploadthing/src/convex.ts (1)

100-100: Consider using a more descriptive variable name

Using a single-letter variable name like f may reduce code readability. Consider renaming it to something more descriptive, such as uploadthing or uploadBuilder.

Apply this diff to rename the variable:

-const f = createUploadthing();
+const uploadthing = createUploadthing();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 74c94c8 and 3474924.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • packages/uploadthing/package.json (4 hunks)
  • packages/uploadthing/src/convex.ts (1 hunks)
  • packages/uploadthing/turbo.json (1 hunks)
🧰 Additional context used
🪛 GitHub Check: lint
packages/uploadthing/src/convex.ts

[failure] 107-107:
Async arrow function has no 'await' expression

🔇 Additional comments (5)
packages/uploadthing/turbo.json (1)

8-8: Addition of Convex adapter output path looks good.

The addition of "convex/**" to the outputs array in the build task aligns well with the PR objective of introducing a new Convex adapter. This change ensures that the build process includes files from the convex directory, which is essential for the new adapter's functionality.

A few points to consider:

  1. The placement of the new output path is correct, maintaining alphabetical order within the array.
  2. This change should not negatively impact existing build processes but will include the new Convex-related files in the build outputs.
  3. Ensure that the convex directory and its contents are properly structured within the packages/uploadthing directory to match this configuration.

To verify the existence and structure of the convex directory, you can run the following script:

packages/uploadthing/package.json (3)

102-111: LGTM: New export for Convex adapter added correctly.

The new export for ./convex has been added with the correct structure, including both import and require configurations. This addition aligns with the PR objective of introducing a new Convex adapter.


139-139: LGTM: Convex directory added to files array.

The convex directory has been correctly added to the files array. This ensures that the new Convex adapter will be included in the package distribution, making it available to users.


196-196: LGTM: Convex added as an optional peer dependency.

The convex package has been correctly added as a peer dependency with a wildcard version (*). It has also been marked as optional in the peerDependenciesMeta section. These changes appropriately support the new Convex adapter while keeping it optional for users who don't require it.

Also applies to: 213-215

packages/uploadthing/src/convex.ts (1)

44-94: Route setup is correctly implemented

The addUploadthingRoutes function effectively integrates the uploadthing routes into the Convex HTTP router. The handlers for GET, POST, and OPTIONS methods are appropriately defined, ensuring proper handling of file uploads and CORS preflight requests.

packages/uploadthing/package.json Show resolved Hide resolved
const identity = await event.auth.getUserIdentity();
return { userId: identity?.subject ?? "nothing" };
})
.onUploadComplete(async (args) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove unnecessary async keyword from arrow function

The arrow function passed to .onUploadComplete does not contain any await expressions, so the async keyword can be removed to simplify the code.

Apply this diff to remove the unnecessary async keyword:

-        .onUploadComplete(async (args) => {
+        .onUploadComplete((args) => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.onUploadComplete(async (args) => {
.onUploadComplete((args) => {
🧰 Tools
🪛 GitHub Check: lint

[failure] 107-107:
Async arrow function has no 'await' expression

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
examples/backend-adapters/server/src/convex.ts (3)

1-13: LGTM with a minor typo correction.

The file header and imports look good. They provide clear context and import the necessary modules. However, there's a small typo in the comment on line 7:

-// In a real app, you can wire up `cereateUploadthing` to your Convex
+// In a real app, you can wire up `createUploadthing` to your Convex

7-13: Consider using a schema in production environments.

The current implementation of createUploadthing() without a schema is suitable for this example. However, for production environments, it's recommended to use a schema for increased type safety, as demonstrated in the commented-out example.

In a production setting, consider uncommenting and adapting the schema implementation:

import schema from "./schema";
const f = createUploadthing({ schema });

This will provide better type checking and potentially catch errors earlier in the development process.


15-24: LGTM. Consider adjusting the maxFileSize for images.

The router configuration is well-structured and includes appropriate middleware for user identification. The onUploadComplete callback effectively returns the user ID, which is useful for tracking uploads.

However, the current maxFileSize of 4MB for images might be restrictive for high-resolution photos or certain image types.

Consider adjusting the maxFileSize based on your specific use case:

imageUploader: f({ image: { maxFileSize: "10MB" } })

This allows for larger image files while still maintaining a reasonable limit. Adjust the value as needed for your application's requirements.

examples/backend-adapters/server/package.json (1)

15-15: LGTM! Consider adding a development script for Convex.

The addition of the Convex dependency (version ^1.16.0) aligns well with the PR objective of introducing a new Convex adapter. This change is appropriate and necessary for implementing the new adapter.

A few suggestions to consider:

  1. Ensure that the version pinning strategy (^1.16.0) is consistent with other dependencies in the project.
  2. Verify if Convex requires any peer dependencies that need to be added to the package.json.
  3. Consider adding a development script for Convex, similar to the other adapters. For example:
    "dev:convex": "NODE_ENV=development tsx watch src/convex.ts"
    (Adjust the command as needed based on Convex's specific requirements)

Would you like me to propose a diff for adding the Convex development script?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 3474924 and 416014b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • examples/backend-adapters/server/package.json (1 hunks)
  • examples/backend-adapters/server/src/convex.ts (1 hunks)
  • packages/uploadthing/src/convex.ts (1 hunks)
🧰 Additional context used
🔇 Additional comments (6)
examples/backend-adapters/server/src/convex.ts (1)

26-28: LGTM. HTTP router setup and export are correct.

The HTTP router is properly initialized, and the UploadThing routes are correctly added. The export statement ensures that the configured router is available for use in the Convex application.

packages/uploadthing/src/convex.ts (5)

1-31: LGTM: Imports and type definitions are well-structured

The imports and type definitions in this segment are appropriate and provide good type safety for the Convex adapter implementation.


33-42: LGTM: createUploadthing function is well-implemented

The createUploadthing function is correctly implemented as a generic builder for handling uploads. It provides flexibility through generics and utilizes the internal createBuilder function appropriately.


44-55: LGTM: addUploadthingRoutes function declaration and handler creation are correct

The addUploadthingRoutes function is well-defined with appropriate type annotations. The handler creation using makeAdapterHandler is implemented correctly, passing the necessary arguments for the Convex adapter.


57-67: LGTM: GET and POST route definitions are correctly implemented

The GET and POST routes for '/api/uploadthing' are properly defined using the created handler. The implementation is consistent and appropriate for the upload functionality.


1-94: Overall, the Convex adapter implementation is well-structured and meets the PR objectives

The convex.ts file successfully introduces a new adapter for Convex, complementing existing adapters like Express and Fastify. The implementation is straightforward and allows developers to integrate the adapter into their Convex applications seamlessly.

Key points:

  1. The createUploadthing function provides a flexible way to set up the adapter with optional schema definitions.
  2. The addUploadthingRoutes function correctly sets up the necessary HTTP routes for file uploads.
  3. CORS handling is implemented for preflight requests.

The code addresses the PR objectives and provides a solid foundation for integrating uploadthing with Convex applications. The only suggestion for improvement is to consider extracting the CORS logic into a separate function for better readability and maintainability.

packages/uploadthing/src/convex.ts Show resolved Hide resolved
Copy link
Collaborator

@markflorkowski markflorkowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all looks fine, the adapter itself is super simple.

I would probably opt for a separate example that shows the actual way this is used, even if it does require a Convex account or self hosting Convex. (Our Clerk examples also require an account)

Where should I add Convex to the docs? Would another entry next to https://docs.uploadthing.com/backend-adapters/express be the right spot?

Yeah, I think that would be a reasonable place for the docs, as another section in backend-adapters

examples/backend-adapters/server/src/convex.ts Outdated Show resolved Hide resolved
// import schema from "./schema";
// const f = createUploadthing({ schema })
// ```
const f = createUploadthing();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better to have a separate example showing the "real" way as you suggested in the PR comment. without it, this example doesnt really hold much value IMO

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, I'll remove this and port it to a full example.

Co-authored-by: Mark R. Florkowski <mark@ping.gg>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/uploadthing/package.json (1)

187-187: Consider adding version constraints for the Convex peer dependency.

While using "*" is consistent with other adapter dependencies, consider adding version constraints to prevent potential compatibility issues with future breaking changes in Convex.

-    "convex": "*",
+    "convex": "^1.0.0",
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60b055a and 47a9022.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • examples/backend-adapters/server/package.json (1 hunks)
  • packages/uploadthing/package.json (4 hunks)
  • packages/uploadthing/turbo.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/backend-adapters/server/package.json
  • packages/uploadthing/turbo.json
🔇 Additional comments (3)
packages/uploadthing/package.json (3)

103-112: LGTM! Export configuration follows package conventions.

The Convex adapter export configuration is well-structured and consistent with other adapters in the package.


130-130: LGTM! Files array updated correctly.

The "convex" directory is properly included in the files array, maintaining alphabetical order and consistency with other adapters.


202-204: LGTM! Peer dependencies meta configuration is correct.

The Convex adapter is properly marked as an optional peer dependency, consistent with other adapters in the package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants