https://github.com/transloadit/convex
https://github.com/transloadit/convex
Last synced: 5 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/transloadit/convex
- Owner: transloadit
- Created: 2026-01-15T10:54:10.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-01-24T21:45:54.000Z (5 months ago)
- Last Synced: 2026-01-25T06:47:53.442Z (5 months ago)
- Language: TypeScript
- Homepage: https://convex-bay.vercel.app
- Size: 854 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# Transloadit Convex Component
A Convex component for creating Transloadit Assemblies, handling resumable uploads with tus, and persisting status/results in Convex.
## Features
- Create Assemblies with Templates or inline Steps.
- Resumable uploads via tus (client-side hook; form/XHR uploads are intentionally not supported).
- Webhook ingestion with signature verification (direct or queued).
- Persist Assembly status + results in Convex tables.
- Typed API wrappers and React hooks.
## Requirements
- Node.js 24+
- Yarn 4 (Corepack)
## Install
```bash
yarn add @transloadit/convex
```
## Setup
### 1) Register the component
```ts
// convex/convex.config.ts
import { defineApp } from "convex/server";
import transloadit from "@transloadit/convex/convex.config";
const app = defineApp();
app.use(transloadit);
export default app;
```
### 2) Set environment variables
```bash
npx convex env set TRANSLOADIT_KEY
npx convex env set TRANSLOADIT_SECRET
```
## Golden path (secure by default)
1. **Server-only create**: a Convex action creates the Assembly (auth secret stays server-side).
2. **Client upload**: use `useTransloaditUppy` for resumable uploads.
3. **Webhook ingestion**: verify the signature and `queueWebhook` for durable processing.
4. **Realtime UI**: query status/results and render the gallery.
## Backend API
```ts
// convex/transloadit.ts
import { makeTransloaditAPI } from "@transloadit/convex";
import { components } from "./_generated/api";
export const {
createAssembly,
handleWebhook,
queueWebhook,
refreshAssembly,
getAssemblyStatus,
listAssemblies,
listResults,
storeAssemblyMetadata,
} = makeTransloaditAPI(components.transloadit);
```
Note: pass `expires` in `createAssembly` when you need a custom expiry; otherwise the component defaults to 1 hour from now.
## Data model
The component stores Transloadit metadata in two tables:
```
assemblies 1 ──── * results
```
- `assemblies`: one row per Transloadit Assembly (status/ok, notify URL, uploads, raw payload, etc).
- `results`: one row per output file, keyed by `assemblyId` + `stepName`, plus normalized fields (name/size/mime/url) and the raw Transloadit output object.
Lifecycle:
1. `createAssembly` inserts the initial `assemblies` row.
2. `handleWebhook`, `queueWebhook`, or `refreshAssembly` upserts the assembly + replaces results.
3. `listResults` returns flattened step outputs for use in UIs.
## Webhook route
Transloadit sends webhooks as `multipart/form-data` with `transloadit` (JSON) and `signature` fields.
```ts
// convex/http.ts
import { httpRouter } from "convex/server";
import { handleWebhookRequest } from "@transloadit/convex";
import { api } from "./_generated/api";
import { httpAction } from "./_generated/server";
const http = httpRouter();
http.route({
path: "/transloadit/webhook",
method: "POST",
handler: httpAction((ctx, request) =>
handleWebhookRequest(request, {
mode: "queue",
runAction: (args) => ctx.runAction(api.transloadit.queueWebhook, args),
}),
),
});
export default http;
```
## Client wrapper (optional)
Most integrations should use `makeTransloaditAPI` (above). If you prefer a class-based API
(similar to other Convex components), use `Transloadit`:
```ts
import { Transloadit } from "@transloadit/convex";
import { components } from "./_generated/api";
const transloadit = new Transloadit(components.transloadit, {
authKey: process.env.TRANSLOADIT_KEY!,
authSecret: process.env.TRANSLOADIT_SECRET!,
});
```
## React usage (Uppy)
```tsx
import { useTransloaditUppy } from "@transloadit/convex/react";
import { api } from "../convex/_generated/api";
const { startUpload, status, results, stage } = useTransloaditUppy({
uppy,
createAssembly: api.wedding.createWeddingAssembly,
getStatus: api.transloadit.getAssemblyStatus,
listResults: api.transloadit.listResults,
refreshAssembly: api.transloadit.refreshAssembly,
});
await startUpload({
createAssemblyArgs: { guestName, uploadCode },
});
```
For advanced/legacy helpers (raw parsing, low-level tus uploads, polling utilities), see `docs/advanced.md`.
## Example app (Next.js + Uppy wedding gallery)
The `example/` app is a wedding gallery where guests upload photos + short videos. It uses Uppy on the client and Convex Auth (anonymous sign-in) to create assemblies securely. If you do not set `NEXT_PUBLIC_CONVEX_URL`, the example falls back to the in-process Convex test harness.
Uploads are stored via Transloadit directly into Cloudflare R2.
The client wiring uses the `useTransloaditUppy` hook from `@transloadit/convex/react` to keep Uppy + polling in sync.
Quick start (local):
```bash
# In repo root
export TRANSLOADIT_KEY=...
export TRANSLOADIT_SECRET=...
export TRANSLOADIT_R2_CREDENTIALS=...
# Get a public webhook URL (cloudflared is auto-downloaded if needed)
yarn tunnel --once
# Set TRANSLOADIT_NOTIFY_URL to the printed notifyUrl
export TRANSLOADIT_NOTIFY_URL=...
yarn example:dev
```
If you want the API routes to talk to an existing Convex deployment (bypassing Convex Auth), set:
```bash
export CONVEX_URL=...
export CONVEX_ADMIN_KEY=...
```
The example exposes `POST /transloadit/webhook` and forwards webhooks into Convex via `queueWebhook`.
Realtime “new upload” toasts use a Convex subscription on recent assemblies.
The demo also applies a simple per-user upload limit in the Convex backend (see `example/convex/wedding.ts`).
### Storage (required R2 persistence)
The example uses the `/cloudflare/store` robot to write processed files into Cloudflare R2. Configure one of these:
```bash
# Option A: Transloadit template credentials (recommended)
export TRANSLOADIT_R2_CREDENTIALS=...
# Option B: supply R2 details directly
export R2_BUCKET=...
export R2_ACCESS_KEY_ID=...
export R2_SECRET_ACCESS_KEY=...
export R2_ACCOUNT_ID=... # or R2_HOST
export R2_PUBLIC_URL=... # optional public URL prefix
```
The UI hides older items based on `NEXT_PUBLIC_GALLERY_RETENTION_HOURS` (default: 24) to discourage spam/abuse.
If you set `WEDDING_UPLOAD_CODE` on the Convex deployment, guests must enter the passcode before uploads can start.
### Deploy the example (Vercel + stable Convex)
For a public demo, deploy the `example/` app and point it at a stable Convex deployment.
1. Deploy a Convex app that includes this component (stable/prod deployment).
2. Set Vercel environment variables for the project:
- `NEXT_PUBLIC_CONVEX_URL` (point to the stable Convex deployment)
- `NEXT_PUBLIC_GALLERY_RETENTION_HOURS` (optional)
3. Set Convex environment variables on the deployment:
- `TRANSLOADIT_KEY` and `TRANSLOADIT_SECRET`
- `TRANSLOADIT_NOTIFY_URL` (set to `https://.convex.site/transloadit/webhook`)
- R2 credentials (see above)
- `WEDDING_UPLOAD_CODE` (optional passcode for uploads)
4. Trigger the Vercel deploy hook (or deploy manually).
To deploy a stable Convex backend for the demo (once per environment), run:
```bash
export CONVEX_DEPLOY_KEY=...
export TRANSLOADIT_KEY=...
export TRANSLOADIT_SECRET=...
yarn deploy:cloud
```
Once deployed, use the Vercel URL as `E2E_REMOTE_APP_URL` for `yarn verify:cloud`.
CI expects a stable Vercel production URL in the `E2E_REMOTE_APP_URL` secret on `main`.
## Verification and QA
Fast checks:
```bash
yarn check
```
This runs format, lint, typecheck, and unit tests. For a full verification run:
```bash
yarn verify
```
Additional commands:
- `yarn lint` (Biome)
- `yarn format` (Biome write)
- `yarn typecheck` (tsc)
- `yarn test` (Vitest unit tests)
- `yarn verify:local` (runs the Next.js wedding example + uploads an image + video)
- `yarn verify:cloud` (runs the browser flow against a deployed Next.js app)
- `yarn deploy:cloud` (deploys a stable Convex backend for the demo app)
- `yarn build` (tsc build + emit package json)
Notes:
- `yarn tunnel` is a support tool, not verification.
- CI should run non-mutating checks; local `yarn check` may format/fix.
- `yarn verify:local` needs `TRANSLOADIT_KEY`, `TRANSLOADIT_SECRET`, `TRANSLOADIT_NOTIFY_URL`, and R2 credentials.
- `yarn verify:cloud` needs `E2E_REMOTE_APP_URL`.
- Set `TRANSLOADIT_DEBUG=1` to enable verbose verify logs.
## Component test helpers
For `convex-test`, you can use the built-in helper:
```ts
import { createTransloaditTest } from "@transloadit/convex/test";
const t = createTransloaditTest();
```
## Generated files
`src/component/_generated` is Convex codegen output. It is checked in so tests and component consumers have stable API references. If you change component functions or schemas, regenerate with Convex codegen (for example via `npx convex dev` or `npx convex codegen`) and commit the updated files.
## Release process
Releases are automated via Changesets + GitHub Actions and published to npm using OIDC (Trusted Publisher).
1. Ensure CI is green on `main`.
2. Run local checks:
```bash
yarn check
```
3. Add a changeset describing the release:
```bash
yarn changeset
```
4. Push the changeset to `main`. The Changesets workflow will open a “Version Packages” PR.
5. Merge the “Version Packages” PR. This will publish to npm and tag the release.
Note: This package is 0.x, so breaking changes are allowed. Use changesets to document them clearly.