|
| 1 | +# 2026-01-26 Refactoring Proposal: Align with Uppy + Shared SDKs |
| 2 | + |
| 3 | +This proposal responds to Merlijn's review and issue #20 (type duplication). It focuses on: |
| 4 | + |
| 5 | +- Removing custom Uppy + React hooks in favor of official Uppy patterns. |
| 6 | +- Reusing existing Transloadit SDKs where it makes sense. |
| 7 | +- Reducing type duplication by leaning on Zod schemas and convex-helpers. |
| 8 | +- Keeping the current component stable while introducing a cleaner, long-term path. |
| 9 | + |
| 10 | +## Context (today) |
| 11 | + |
| 12 | +- We ship custom React hooks (`useTransloaditUppy`, `useTransloaditUpload`) and a bespoke tus uploader. |
| 13 | +- We already use `@transloadit/utils` for signature verification and `@transloadit/zod/v3` for types. |
| 14 | +- The example app uses Uppy Dashboard but not `@uppy/transloadit`. |
| 15 | +- Some types and validators are duplicated between Convex validators (`v.*`) and Zod schemas. |
| 16 | + |
| 17 | +## Research highlights |
| 18 | + |
| 19 | +- Uppy 5.0 ships official React hooks and recommends using them via `UppyContextProvider`. |
| 20 | +- `@uppy/transloadit` is the canonical plugin; it uses Tus internally and supports |
| 21 | + `assemblyOptions` as a function that can call a backend for signatures. |
| 22 | +- Convex allows marking external packages for Node actions, so a heavier SDK like `transloadit` |
| 23 | + can be used server-side without client bundle impact. |
| 24 | +- `convex-helpers` provides Zod-based function argument validation and optional `zodToConvex` |
| 25 | + helpers for schema definitions, with caveats. |
| 26 | + |
| 27 | +## Feasibility assessment |
| 28 | + |
| 29 | +### 1) Replace custom hooks with Uppy + @uppy/transloadit |
| 30 | + |
| 31 | +Feasible and recommended. |
| 32 | + |
| 33 | +We can: |
| 34 | +- Add a Convex action that returns `assemblyOptions` (params + signature + fields). |
| 35 | +- Use `@uppy/transloadit` in the example and docs. |
| 36 | +- Let Uppy manage Tus uploads and its own upload lifecycle. |
| 37 | +- Keep Convex as the source of truth for webhooks, results, and auth. |
| 38 | + |
| 39 | +This lets us remove: |
| 40 | +- `tus-js-client` usage in React |
| 41 | +- `useTransloaditUppy` |
| 42 | +- `uploadWithTus` and related helpers |
| 43 | + |
| 44 | +We can keep a small helper that wires `assemblyOptions()` to a Convex HTTP endpoint or action. |
| 45 | + |
| 46 | +### 2) Reuse the `transloadit` Node SDK server-side |
| 47 | + |
| 48 | +Likely feasible, but optional. |
| 49 | + |
| 50 | +Convex Node actions can import external packages. That means we could: |
| 51 | +- Use the `transloadit` SDK inside `createAssembly` and `refreshAssembly` actions. |
| 52 | +- Avoid re-implementing API logic and edge-case handling. |
| 53 | + |
| 54 | +Tradeoffs: |
| 55 | +- Adds dependency weight. |
| 56 | +- Need to verify ESM/CJS interop. |
| 57 | +- Might require a Convex `convex.json` config change or explicit guidance for adopters. |
| 58 | + |
| 59 | +Alternative: keep the lightweight `fetch` + `@transloadit/utils` approach to avoid dependency risk. |
| 60 | + |
| 61 | +### 3) Type duplication (issue #20) |
| 62 | + |
| 63 | +We can reduce duplication without fully replacing Convex validators: |
| 64 | + |
| 65 | +- Keep table schemas in `convex/values` (Convex requires these). |
| 66 | +- Use `convex-helpers` Zod wrappers for function args, so we only define args once and |
| 67 | + share types with `@transloadit/zod/v3`. |
| 68 | +- Export Zod-based types from `@transloadit/convex` (already done) and avoid re-defining |
| 69 | + assembly and results types in multiple files. |
| 70 | + |
| 71 | +This aligns with Convex guidance: Zod is great for args; use `zodToConvex` for DB schemas only |
| 72 | +when the tradeoffs are acceptable. |
| 73 | + |
| 74 | +## Proposed direction (phased) |
| 75 | + |
| 76 | +### Phase 0: Remove custom hooks + expose the official path (short) |
| 77 | + |
| 78 | +- Remove `useTransloaditUppy`, `useTransloaditUpload`, and tus helpers from exports and docs. |
| 79 | +- Add an explicit “Recommended path” that uses Uppy + `@uppy/transloadit`. |
| 80 | +- Add a minimal helper: `createAssemblyOptions` action + `getAssemblyOptions()` client helper. |
| 81 | + |
| 82 | +### Phase 1: Example app refactor (short) |
| 83 | + |
| 84 | +- Switch example app to `@uppy/transloadit`. |
| 85 | +- Use Uppy React hooks (`@uppy/react`) and `UppyContextProvider`. |
| 86 | +- Keep webhooks/results via Convex. |
| 87 | +- Remove `tus-js-client` dependency from React path. |
| 88 | + |
| 89 | +### Phase 2: API surface reduction (medium) |
| 90 | + |
| 91 | +- Remove remaining Uppy-specific helpers from `@transloadit/convex/react`. |
| 92 | +- Keep only status/results helpers (or remove the React entry entirely if unnecessary). |
| 93 | + |
| 94 | +### Phase 3: Optional server SDK adoption (medium) |
| 95 | + |
| 96 | +Likely **not** needed. Keep `fetch` + `@transloadit/utils` unless we can demonstrate: |
| 97 | +- clear edge-case improvements over the current implementation, or |
| 98 | +- significant DX improvements without extra complexity. |
| 99 | + |
| 100 | +### Phase 4: Type cleanup (medium) |
| 101 | + |
| 102 | +- Use convex-helpers Zod wrappers for function args. |
| 103 | +- Consider replacing some hand-written validators (where safe). |
| 104 | +- Add explicit mapping from Zod types -> Convex validators only where we benefit. |
| 105 | + |
| 106 | +## Why we might *not* take some suggestions (yet) |
| 107 | + |
| 108 | +- Rewriting the entire component around Uppy + SDKs in one shot risks regressions and |
| 109 | + would delay iteration. Phased adoption is safer. |
| 110 | +- The `transloadit` SDK brings benefits, but also increases dependency complexity. |
| 111 | + If the current `fetch` + `@transloadit/utils` approach already works well, we may |
| 112 | + choose to keep it until a clear edge-case benefit is demonstrated. |
| 113 | + |
| 114 | +## Open questions |
| 115 | + |
| 116 | +1. Should `@transloadit/convex/react` remain as a small status/results hook library, |
| 117 | + or be removed entirely in favor of Uppy React hooks? |
| 118 | +2. `createAssemblyOptions` should support both templates and inline steps. |
| 119 | +3. Avoid requiring `convex.json` changes unless we adopt the `transloadit` SDK for |
| 120 | + clear edge-case wins. |
| 121 | + |
| 122 | +## Success criteria |
| 123 | + |
| 124 | +- Uppy integration follows official hooks + plugin usage. |
| 125 | +- Reduced duplication (fewer custom helpers + better type reuse). |
| 126 | +- Smaller surface area in `@transloadit/convex/react`. |
| 127 | +- No regressions in webhook handling or results storage. |
0 commit comments