Skip to content

Commit e14fee2

Browse files
authored
refactor: use @uppy/transloadit (#22)
* refactor example to use @uppy/transloadit * fix qa app template for assembly options * fix assembly options count and doc migration * add changeset for uppy refactor * stabilize cloud e2e status wait
1 parent cd20593 commit e14fee2

File tree

24 files changed

+1105
-2180
lines changed

24 files changed

+1105
-2180
lines changed

.changeset/uppy-official.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@transloadit/convex": minor
3+
---
4+
5+
- switch the example and docs to Uppy + @uppy/transloadit and remove the React/tus helpers
6+
- add signed assemblyOptions helpers and ensure expected upload counts are included in params
7+
- update docs for the new Uppy-first integration path

README.md

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Transloadit Convex Component
22

3-
A Convex component for creating Transloadit Assemblies, handling resumable uploads with tus, and persisting status/results in Convex.
3+
A Convex component for creating Transloadit Assemblies, signing Uppy uploads, and persisting status/results in Convex.
44

55
## Features
66

77
- Create Assemblies with Templates or inline Steps.
8-
- Resumable uploads via tus (client-side hook; form/XHR uploads are intentionally not supported).
8+
- Signed upload options for Uppy + `@uppy/transloadit`.
99
- Webhook ingestion with signature verification (direct or queued).
1010
- Persist Assembly status + results in Convex tables.
11-
- Typed API wrappers and React hooks.
11+
- Typed API wrappers and helpers.
1212

1313
## Requirements
1414

@@ -45,8 +45,8 @@ npx convex env set TRANSLOADIT_SECRET <your_auth_secret>
4545

4646
## Golden path (secure by default)
4747

48-
1. **Server-only create**: a Convex action creates the Assembly (auth secret stays server-side).
49-
2. **Client upload**: use `useTransloaditUppy` for resumable uploads.
48+
1. **Server-only create**: a Convex action creates signed `assemblyOptions` (auth secret stays server-side).
49+
2. **Client upload**: use Uppy + `@uppy/transloadit` with `assemblyOptions()`.
5050
3. **Webhook ingestion**: verify the signature and `queueWebhook` for durable processing.
5151
4. **Realtime UI**: query status/results and render the gallery.
5252

@@ -59,6 +59,7 @@ import { components } from "./_generated/api";
5959

6060
export const {
6161
createAssembly,
62+
createAssemblyOptions,
6263
handleWebhook,
6364
queueWebhook,
6465
refreshAssembly,
@@ -129,25 +130,33 @@ const transloadit = new Transloadit(components.transloadit, {
129130
});
130131
```
131132

132-
## React usage (Uppy)
133+
## Uppy client (React example)
133134

134135
```tsx
135-
import { useTransloaditUppy } from "@transloadit/convex/react";
136+
import Uppy from "@uppy/core";
137+
import Transloadit from "@uppy/transloadit";
136138
import { api } from "../convex/_generated/api";
137139

138-
const { startUpload, status, results, stage } = useTransloaditUppy({
139-
uppy,
140-
createAssembly: api.wedding.createWeddingAssembly,
141-
getStatus: api.transloadit.getAssemblyStatus,
142-
listResults: api.transloadit.listResults,
143-
refreshAssembly: api.transloadit.refreshAssembly,
140+
const uppy = new Uppy().use(Transloadit, {
141+
waitForEncoding: true,
142+
assemblyOptions: async () => {
143+
const { assemblyOptions } = await runAction(
144+
api.wedding.createWeddingAssemblyOptions,
145+
{ fileCount, guestName, uploadCode },
146+
);
147+
return assemblyOptions;
148+
},
144149
});
145150

146-
await startUpload({
147-
createAssemblyArgs: { guestName, uploadCode },
148-
});
151+
await uppy.upload();
149152
```
150-
For advanced/legacy helpers (raw parsing, low-level tus uploads, polling utilities), see `docs/advanced.md`.
153+
Note: `assemblyOptions()` is called once per batch, so pass per-file metadata via Uppy file meta
154+
(e.g. `uppy.setFileMeta(fileId, {...})`) and use `fields` for shared values.
155+
156+
Migration note: the `@transloadit/convex/react` entrypoint has been removed; use Uppy +
157+
`@uppy/transloadit` directly.
158+
159+
For status parsing and polling helpers, see `docs/advanced.md`.
151160

152161
## Example app (Next.js + Uppy wedding gallery)
153162

docs/advanced.md

Lines changed: 12 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,6 @@
11
# Advanced usage
22

3-
This page collects low-level helpers and optional maintenance tools. These are intentionally
4-
kept out of the main README so new users can follow a single, Uppy-first path.
5-
6-
## Low-level tus helpers (advanced)
7-
8-
If you need a custom uploader (no Uppy), the legacy tus helpers are still available:
9-
10-
```tsx
11-
import {
12-
uploadWithTransloaditTus,
13-
useTransloaditTusUpload,
14-
uploadFilesWithTransloaditTus,
15-
} from "@transloadit/convex/react";
16-
import { api } from "../convex/_generated/api";
17-
18-
function TusUpload() {
19-
const { upload, isUploading, progress } = useTransloaditTusUpload(
20-
api.transloadit.createAssembly,
21-
);
22-
23-
const handleUpload = async (file: File) => {
24-
await upload(file, {
25-
templateId: "template_id_here",
26-
onAssemblyCreated: (assembly) => console.log(assembly.assemblyId),
27-
});
28-
};
29-
30-
return (
31-
<div>
32-
<input type="file" onChange={(e) => handleUpload(e.target.files![0])} />
33-
{isUploading && <p>Uploading: {progress}%</p>}
34-
</div>
35-
);
36-
}
37-
```
38-
39-
Imperative helper (e.g. non-React):
40-
41-
```ts
42-
import { useAction } from "convex/react";
43-
44-
const createAssembly = useAction(api.transloadit.createAssembly);
45-
46-
await uploadWithTransloaditTus(
47-
createAssembly,
48-
file,
49-
{ templateId: "template_id_here" },
50-
{ onStateChange: (state) => console.log(state) },
51-
);
52-
```
53-
54-
Multi-file uploads with concurrency + cancellation:
55-
56-
```ts
57-
import { uploadFilesWithTransloaditTus } from "@transloadit/convex/react";
58-
59-
const controller = uploadFilesWithTransloaditTus(createAssembly, files, {
60-
concurrency: 3,
61-
onFileProgress: (file, progress) => console.log(file.name, progress),
62-
onOverallProgress: (progress) => console.log("overall", progress),
63-
});
64-
65-
// Optional: cancel in-flight uploads
66-
// controller.cancel();
67-
68-
const result = await controller.promise;
69-
console.log(result.files);
70-
```
71-
72-
## Reactive status/results helpers
73-
74-
```tsx
75-
import { useAssemblyStatus, useTransloaditFiles } from "@transloadit/convex/react";
76-
import { api } from "../convex/_generated/api";
77-
78-
function AssemblyStatus({ assemblyId }: { assemblyId: string }) {
79-
const status = useAssemblyStatus(api.transloadit.getAssemblyStatus, assemblyId);
80-
const results = useTransloaditFiles(api.transloadit.listResults, {
81-
assemblyId,
82-
});
83-
84-
if (!status) return null;
85-
return (
86-
<div>
87-
<p>Status: {status.ok}</p>
88-
<p>Results: {results?.length ?? 0}</p>
89-
</div>
90-
);
91-
}
92-
```
93-
94-
Polling fallback (no webhooks):
95-
96-
```tsx
97-
import { useAssemblyStatusWithPolling } from "@transloadit/convex/react";
98-
import { api } from "../convex/_generated/api";
99-
100-
const status = useAssemblyStatusWithPolling(
101-
api.transloadit.getAssemblyStatus,
102-
api.transloadit.refreshAssembly,
103-
assemblyId,
104-
{ pollIntervalMs: 5000, stopOnTerminal: true },
105-
);
106-
```
3+
This page collects optional helpers that build on the Uppy-first integration path.
1074

1085
## Typed helpers (raw payload parsing)
1096

@@ -145,14 +42,20 @@ type ResizeResult = ResultForRobot<"/image/resize">;
14542
type EncodeResult = ResultForRobot<"/video/encode">;
14643
```
14744

148-
Uppy/Tus wiring:
45+
Polling fallback (no webhooks):
14946

15047
```ts
151-
import { buildTusUploadConfig } from "@transloadit/convex";
152-
153-
const { endpoint, metadata } = buildTusUploadConfig(assembly.data, file, {
154-
fieldName: "file",
48+
import { pollAssembly, isAssemblyTerminal } from "@transloadit/convex";
49+
50+
const controller = pollAssembly({
51+
intervalMs: 5000,
52+
refresh: async () => {
53+
await refreshAssembly({ assemblyId });
54+
},
55+
isTerminal: () => isAssemblyTerminal(status),
15556
});
57+
58+
// controller.stop();
15659
```
15760

15861
## Optional demo template tooling

0 commit comments

Comments
 (0)