{"id":38106237,"url":"https://github.com/transloadit/convex","last_synced_at":"2026-01-27T17:13:17.911Z","repository":{"id":332776888,"uuid":"1134890371","full_name":"transloadit/convex","owner":"transloadit","description":null,"archived":false,"fork":false,"pushed_at":"2026-01-24T21:45:54.000Z","size":874,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-25T06:47:53.442Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://convex-bay.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/transloadit.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-15T10:54:10.000Z","updated_at":"2026-01-24T21:45:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/transloadit/convex","commit_stats":null,"previous_names":["transloadit/convex"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/transloadit/convex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transloadit%2Fconvex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transloadit%2Fconvex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transloadit%2Fconvex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transloadit%2Fconvex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transloadit","download_url":"https://codeload.github.com/transloadit/convex/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transloadit%2Fconvex/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28816618,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T12:25:15.069Z","status":"ssl_error","status_checked_at":"2026-01-27T12:25:05.297Z","response_time":168,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-16T21:37:55.035Z","updated_at":"2026-01-27T17:13:17.905Z","avatar_url":"https://github.com/transloadit.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Transloadit Convex Component\n\nA Convex component for creating Transloadit Assemblies, handling resumable uploads with tus, and persisting status/results in Convex.\n\n## Features\n\n- Create Assemblies with Templates or inline Steps.\n- Resumable uploads via tus (client-side hook; form/XHR uploads are intentionally not supported).\n- Webhook ingestion with signature verification (direct or queued).\n- Persist Assembly status + results in Convex tables.\n- Typed API wrappers and React hooks.\n\n## Requirements\n\n- Node.js 24+\n- Yarn 4 (Corepack)\n\n## Install\n\n```bash\nyarn add @transloadit/convex\n```\n\n## Setup\n\n### 1) Register the component\n\n```ts\n// convex/convex.config.ts\nimport { defineApp } from \"convex/server\";\nimport transloadit from \"@transloadit/convex/convex.config\";\n\nconst app = defineApp();\napp.use(transloadit);\n\nexport default app;\n```\n\n### 2) Set environment variables\n\n```bash\nnpx convex env set TRANSLOADIT_KEY \u003cyour_auth_key\u003e\nnpx convex env set TRANSLOADIT_SECRET \u003cyour_auth_secret\u003e\n```\n\n## Golden path (secure by default)\n\n1. **Server-only create**: a Convex action creates the Assembly (auth secret stays server-side).\n2. **Client upload**: use `useTransloaditUppy` for resumable uploads.\n3. **Webhook ingestion**: verify the signature and `queueWebhook` for durable processing.\n4. **Realtime UI**: query status/results and render the gallery.\n\n## Backend API\n\n```ts\n// convex/transloadit.ts\nimport { makeTransloaditAPI } from \"@transloadit/convex\";\nimport { components } from \"./_generated/api\";\n\nexport const {\n  createAssembly,\n  handleWebhook,\n  queueWebhook,\n  refreshAssembly,\n  getAssemblyStatus,\n  listAssemblies,\n  listResults,\n  storeAssemblyMetadata,\n} = makeTransloaditAPI(components.transloadit);\n```\n\nNote: pass `expires` in `createAssembly` when you need a custom expiry; otherwise the component defaults to 1 hour from now.\n\n## Data model\n\nThe component stores Transloadit metadata in two tables:\n\n```\nassemblies 1 ──── * results\n```\n\n- `assemblies`: one row per Transloadit Assembly (status/ok, notify URL, uploads, raw payload, etc).\n- `results`: one row per output file, keyed by `assemblyId` + `stepName`, plus normalized fields (name/size/mime/url) and the raw Transloadit output object.\n\nLifecycle:\n1. `createAssembly` inserts the initial `assemblies` row.\n2. `handleWebhook`, `queueWebhook`, or `refreshAssembly` upserts the assembly + replaces results.\n3. `listResults` returns flattened step outputs for use in UIs.\n\n## Webhook route\n\nTransloadit sends webhooks as `multipart/form-data` with `transloadit` (JSON) and `signature` fields.\n\n```ts\n// convex/http.ts\nimport { httpRouter } from \"convex/server\";\nimport { handleWebhookRequest } from \"@transloadit/convex\";\nimport { api } from \"./_generated/api\";\nimport { httpAction } from \"./_generated/server\";\n\nconst http = httpRouter();\n\nhttp.route({\n  path: \"/transloadit/webhook\",\n  method: \"POST\",\n  handler: httpAction((ctx, request) =\u003e\n    handleWebhookRequest(request, {\n      mode: \"queue\",\n      runAction: (args) =\u003e ctx.runAction(api.transloadit.queueWebhook, args),\n    }),\n  ),\n});\n\nexport default http;\n```\n\n## Client wrapper (optional)\n\nMost integrations should use `makeTransloaditAPI` (above). If you prefer a class-based API\n(similar to other Convex components), use `Transloadit`:\n\n```ts\nimport { Transloadit } from \"@transloadit/convex\";\nimport { components } from \"./_generated/api\";\n\nconst transloadit = new Transloadit(components.transloadit, {\n  authKey: process.env.TRANSLOADIT_KEY!,\n  authSecret: process.env.TRANSLOADIT_SECRET!,\n});\n```\n\n## React usage (Uppy)\n\n```tsx\nimport { useTransloaditUppy } from \"@transloadit/convex/react\";\nimport { api } from \"../convex/_generated/api\";\n\nconst { startUpload, status, results, stage } = useTransloaditUppy({\n  uppy,\n  createAssembly: api.wedding.createWeddingAssembly,\n  getStatus: api.transloadit.getAssemblyStatus,\n  listResults: api.transloadit.listResults,\n  refreshAssembly: api.transloadit.refreshAssembly,\n});\n\nawait startUpload({\n  createAssemblyArgs: { guestName, uploadCode },\n});\n```\nFor advanced/legacy helpers (raw parsing, low-level tus uploads, polling utilities), see `docs/advanced.md`.\n\n## Example app (Next.js + Uppy wedding gallery)\n\nThe `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.\nUploads are stored via Transloadit directly into Cloudflare R2.\nThe client wiring uses the `useTransloaditUppy` hook from `@transloadit/convex/react` to keep Uppy + polling in sync.\n\nQuick start (local):\n\n```bash\n# In repo root\nexport TRANSLOADIT_KEY=...\nexport TRANSLOADIT_SECRET=...\nexport TRANSLOADIT_R2_CREDENTIALS=...\n\n# Get a public webhook URL (cloudflared is auto-downloaded if needed)\nyarn tunnel --once\n# Set TRANSLOADIT_NOTIFY_URL to the printed notifyUrl\nexport TRANSLOADIT_NOTIFY_URL=...\n\nyarn example:dev\n```\n\nIf you want the API routes to talk to an existing Convex deployment (bypassing Convex Auth), set:\n\n```bash\nexport CONVEX_URL=...\nexport CONVEX_ADMIN_KEY=...\n```\n\nThe example exposes `POST /transloadit/webhook` and forwards webhooks into Convex via `queueWebhook`.\nRealtime “new upload” toasts use a Convex subscription on recent assemblies.\nThe demo also applies a simple per-user upload limit in the Convex backend (see `example/convex/wedding.ts`).\n\n### Storage (required R2 persistence)\n\nThe example uses the `/cloudflare/store` robot to write processed files into Cloudflare R2. Configure one of these:\n\n```bash\n# Option A: Transloadit template credentials (recommended)\nexport TRANSLOADIT_R2_CREDENTIALS=...\n\n# Option B: supply R2 details directly\nexport R2_BUCKET=...\nexport R2_ACCESS_KEY_ID=...\nexport R2_SECRET_ACCESS_KEY=...\nexport R2_ACCOUNT_ID=...   # or R2_HOST\nexport R2_PUBLIC_URL=...   # optional public URL prefix\n```\n\nThe UI hides older items based on `NEXT_PUBLIC_GALLERY_RETENTION_HOURS` (default: 24) to discourage spam/abuse.\nIf you set `WEDDING_UPLOAD_CODE` on the Convex deployment, guests must enter the passcode before uploads can start.\n\n### Deploy the example (Vercel + stable Convex)\n\nFor a public demo, deploy the `example/` app and point it at a stable Convex deployment.\n\n1. Deploy a Convex app that includes this component (stable/prod deployment).\n2. Set Vercel environment variables for the project:\n   - `NEXT_PUBLIC_CONVEX_URL` (point to the stable Convex deployment)\n   - `NEXT_PUBLIC_GALLERY_RETENTION_HOURS` (optional)\n3. Set Convex environment variables on the deployment:\n   - `TRANSLOADIT_KEY` and `TRANSLOADIT_SECRET`\n   - `TRANSLOADIT_NOTIFY_URL` (set to `https://\u003cdeployment\u003e.convex.site/transloadit/webhook`)\n   - R2 credentials (see above)\n   - `WEDDING_UPLOAD_CODE` (optional passcode for uploads)\n4. Trigger the Vercel deploy hook (or deploy manually).\n\nTo deploy a stable Convex backend for the demo (once per environment), run:\n\n```bash\nexport CONVEX_DEPLOY_KEY=...\nexport TRANSLOADIT_KEY=...\nexport TRANSLOADIT_SECRET=...\n\nyarn deploy:cloud\n```\n\nOnce deployed, use the Vercel URL as `E2E_REMOTE_APP_URL` for `yarn verify:cloud`.\nCI expects a stable Vercel production URL in the `E2E_REMOTE_APP_URL` secret on `main`.\n\n## Verification and QA\n\nFast checks:\n\n```bash\nyarn check\n```\n\nThis runs format, lint, typecheck, and unit tests. For a full verification run:\n\n```bash\nyarn verify\n```\n\nAdditional commands:\n\n- `yarn lint` (Biome)\n- `yarn format` (Biome write)\n- `yarn typecheck` (tsc)\n- `yarn test` (Vitest unit tests)\n- `yarn verify:local` (runs the Next.js wedding example + uploads an image + video)\n- `yarn verify:cloud` (runs the browser flow against a deployed Next.js app)\n- `yarn deploy:cloud` (deploys a stable Convex backend for the demo app)\n- `yarn build` (tsc build + emit package json)\n\nNotes:\n- `yarn tunnel` is a support tool, not verification.\n- CI should run non-mutating checks; local `yarn check` may format/fix.\n- `yarn verify:local` needs `TRANSLOADIT_KEY`, `TRANSLOADIT_SECRET`, `TRANSLOADIT_NOTIFY_URL`, and R2 credentials.\n- `yarn verify:cloud` needs `E2E_REMOTE_APP_URL`.\n- Set `TRANSLOADIT_DEBUG=1` to enable verbose verify logs.\n\n## Component test helpers\n\nFor `convex-test`, you can use the built-in helper:\n\n```ts\nimport { createTransloaditTest } from \"@transloadit/convex/test\";\n\nconst t = createTransloaditTest();\n```\n\n## Generated files\n\n`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.\n\n## Release process\n\nReleases are automated via Changesets + GitHub Actions and published to npm using OIDC (Trusted Publisher).\n\n1. Ensure CI is green on `main`.\n2. Run local checks:\n\n```bash\nyarn check\n```\n\n3. Add a changeset describing the release:\n\n```bash\nyarn changeset\n```\n\n4. Push the changeset to `main`. The Changesets workflow will open a “Version Packages” PR.\n5. Merge the “Version Packages” PR. This will publish to npm and tag the release.\n\nNote: This package is 0.x, so breaking changes are allowed. Use changesets to document them clearly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransloadit%2Fconvex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransloadit%2Fconvex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransloadit%2Fconvex/lists"}