@transloadit/convex 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +184 -121
  2. package/dist/client/index.d.ts +100 -60
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +69 -31
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/component/_generated/api.d.ts +2 -2
  7. package/dist/component/_generated/component.d.ts +35 -15
  8. package/dist/component/_generated/component.d.ts.map +1 -1
  9. package/dist/component/_generated/dataModel.d.ts +1 -1
  10. package/dist/component/_generated/server.d.ts +1 -1
  11. package/dist/component/apiUtils.d.ts +36 -7
  12. package/dist/component/apiUtils.d.ts.map +1 -1
  13. package/dist/component/apiUtils.js +60 -40
  14. package/dist/component/apiUtils.js.map +1 -1
  15. package/dist/component/lib.d.ts +71 -49
  16. package/dist/component/lib.d.ts.map +1 -1
  17. package/dist/component/lib.js +206 -73
  18. package/dist/component/lib.js.map +1 -1
  19. package/dist/component/schema.d.ts +11 -13
  20. package/dist/component/schema.d.ts.map +1 -1
  21. package/dist/component/schema.js +3 -10
  22. package/dist/component/schema.js.map +1 -1
  23. package/dist/debug/index.d.ts +19 -0
  24. package/dist/debug/index.d.ts.map +1 -0
  25. package/dist/debug/index.js +49 -0
  26. package/dist/debug/index.js.map +1 -0
  27. package/dist/react/index.d.ts +213 -17
  28. package/dist/react/index.d.ts.map +1 -1
  29. package/dist/react/index.js +726 -105
  30. package/dist/react/index.js.map +1 -1
  31. package/dist/shared/assemblyUrls.d.ts +10 -0
  32. package/dist/shared/assemblyUrls.d.ts.map +1 -0
  33. package/dist/shared/assemblyUrls.js +26 -0
  34. package/dist/shared/assemblyUrls.js.map +1 -0
  35. package/dist/shared/errors.d.ts +7 -0
  36. package/dist/shared/errors.d.ts.map +1 -0
  37. package/dist/shared/errors.js +10 -0
  38. package/dist/shared/errors.js.map +1 -0
  39. package/dist/shared/pollAssembly.d.ts +12 -0
  40. package/dist/shared/pollAssembly.d.ts.map +1 -0
  41. package/dist/shared/pollAssembly.js +50 -0
  42. package/dist/shared/pollAssembly.js.map +1 -0
  43. package/dist/shared/resultTypes.d.ts +37 -0
  44. package/dist/shared/resultTypes.d.ts.map +1 -0
  45. package/dist/shared/resultTypes.js +2 -0
  46. package/dist/shared/resultTypes.js.map +1 -0
  47. package/dist/shared/resultUtils.d.ts +4 -0
  48. package/dist/shared/resultUtils.d.ts.map +1 -0
  49. package/dist/shared/resultUtils.js +69 -0
  50. package/dist/shared/resultUtils.js.map +1 -0
  51. package/dist/shared/tusUpload.d.ts +13 -0
  52. package/dist/shared/tusUpload.d.ts.map +1 -0
  53. package/dist/shared/tusUpload.js +32 -0
  54. package/dist/shared/tusUpload.js.map +1 -0
  55. package/dist/test/index.d.ts +65 -0
  56. package/dist/test/index.d.ts.map +1 -0
  57. package/dist/test/index.js +8 -0
  58. package/dist/test/index.js.map +1 -0
  59. package/dist/test/nodeModules.d.ts +2 -0
  60. package/dist/test/nodeModules.d.ts.map +1 -0
  61. package/dist/test/nodeModules.js +19 -0
  62. package/dist/test/nodeModules.js.map +1 -0
  63. package/package.json +53 -15
  64. package/src/client/index.ts +141 -38
  65. package/src/component/_generated/api.ts +2 -2
  66. package/src/component/_generated/component.ts +44 -13
  67. package/src/component/_generated/dataModel.ts +1 -1
  68. package/src/component/_generated/server.ts +1 -1
  69. package/src/component/apiUtils.test.ts +195 -2
  70. package/src/component/apiUtils.ts +124 -66
  71. package/src/component/lib.test.ts +243 -7
  72. package/src/component/lib.ts +302 -90
  73. package/src/component/schema.ts +3 -13
  74. package/src/debug/index.ts +84 -0
  75. package/src/react/index.test.tsx +340 -0
  76. package/src/react/index.tsx +1105 -152
  77. package/src/react/uploadWithTus.test.tsx +192 -0
  78. package/src/shared/assemblyUrls.test.ts +71 -0
  79. package/src/shared/assemblyUrls.ts +59 -0
  80. package/src/shared/errors.ts +23 -0
  81. package/src/shared/pollAssembly.ts +65 -0
  82. package/src/shared/resultTypes.ts +44 -0
  83. package/src/shared/resultUtils.test.ts +29 -0
  84. package/src/shared/resultUtils.ts +71 -0
  85. package/src/shared/tusUpload.ts +59 -0
  86. package/src/test/index.ts +10 -0
  87. package/src/test/nodeModules.ts +19 -0
@@ -2,13 +2,13 @@
2
2
 
3
3
  import { createHmac } from "node:crypto";
4
4
  import { convexTest } from "convex-test";
5
- import { describe, expect, test } from "vitest";
6
- import { api } from "./_generated/api.js";
7
- import schema from "./schema.js";
8
- import { modules } from "./setup.test.js";
5
+ import { describe, expect, test, vi } from "vitest";
6
+ import { api } from "./_generated/api.ts";
7
+ import schema from "./schema.ts";
8
+ import { modules } from "./setup.test.ts";
9
9
 
10
- process.env.TRANSLOADIT_AUTH_KEY = "test-key";
11
- process.env.TRANSLOADIT_AUTH_SECRET = "test-secret";
10
+ process.env.TRANSLOADIT_KEY = "test-key";
11
+ process.env.TRANSLOADIT_SECRET = "test-secret";
12
12
 
13
13
  describe("Transloadit component lib", () => {
14
14
  test("handleWebhook stores assembly and results", async () => {
@@ -40,7 +40,6 @@ describe("Transloadit component lib", () => {
40
40
  payload,
41
41
  rawBody,
42
42
  signature: `sha1:${signature}`,
43
- verifySignature: true,
44
43
  });
45
44
 
46
45
  expect(result.assemblyId).toBe("asm_123");
@@ -60,4 +59,241 @@ describe("Transloadit component lib", () => {
60
59
  expect(results).toHaveLength(1);
61
60
  expect(results[0]?.stepName).toBe("resized");
62
61
  });
62
+
63
+ test("handleWebhook stores url when ssl_url missing", async () => {
64
+ const t = convexTest(schema, modules);
65
+
66
+ const payload = {
67
+ assembly_id: "asm_url",
68
+ ok: "ASSEMBLY_COMPLETED",
69
+ results: {
70
+ stored: [
71
+ {
72
+ id: "file_3",
73
+ url: "https://example.com/file-3.jpg",
74
+ name: "file-3.jpg",
75
+ size: 42,
76
+ mime: "image/jpeg",
77
+ },
78
+ ],
79
+ },
80
+ };
81
+
82
+ const rawBody = JSON.stringify(payload);
83
+ const signature = createHmac("sha1", "test-secret")
84
+ .update(rawBody)
85
+ .digest("hex");
86
+
87
+ await t.action(api.lib.handleWebhook, {
88
+ payload,
89
+ rawBody,
90
+ signature: `sha1:${signature}`,
91
+ });
92
+
93
+ const results = await t.query(api.lib.listResults, {
94
+ assemblyId: "asm_url",
95
+ });
96
+
97
+ expect(results).toHaveLength(1);
98
+ expect(results[0]?.sslUrl).toBe("https://example.com/file-3.jpg");
99
+ });
100
+
101
+ test("listResults exposes expected fields for common robot outputs", async () => {
102
+ const t = convexTest(schema, modules);
103
+
104
+ const payload = {
105
+ assembly_id: "asm_schema",
106
+ ok: "ASSEMBLY_COMPLETED",
107
+ results: {
108
+ images_resized: [
109
+ {
110
+ id: "img_1",
111
+ ssl_url: "https://example.com/img.jpg",
112
+ name: "img.jpg",
113
+ mime: "image/jpeg",
114
+ width: 1600,
115
+ height: 1200,
116
+ },
117
+ ],
118
+ videos_encoded: [
119
+ {
120
+ id: "vid_1",
121
+ ssl_url: "https://example.com/vid.mp4",
122
+ name: "vid.mp4",
123
+ mime: "video/mp4",
124
+ duration: 12.5,
125
+ },
126
+ ],
127
+ videos_thumbs_output: [
128
+ {
129
+ id: "thumb_1",
130
+ ssl_url: "https://example.com/thumb.jpg",
131
+ name: "thumb.jpg",
132
+ mime: "image/jpeg",
133
+ original_id: "vid_1",
134
+ },
135
+ ],
136
+ },
137
+ };
138
+
139
+ const rawBody = JSON.stringify(payload);
140
+ const signature = createHmac("sha1", "test-secret")
141
+ .update(rawBody)
142
+ .digest("hex");
143
+
144
+ await t.action(api.lib.handleWebhook, {
145
+ payload,
146
+ rawBody,
147
+ signature: `sha1:${signature}`,
148
+ });
149
+
150
+ const results = await t.query(api.lib.listResults, {
151
+ assemblyId: "asm_schema",
152
+ });
153
+
154
+ expect(results).toHaveLength(3);
155
+
156
+ const byStep = new Map(results.map((result) => [result.stepName, result]));
157
+ const image = byStep.get("images_resized");
158
+ const video = byStep.get("videos_encoded");
159
+ const thumb = byStep.get("videos_thumbs_output");
160
+
161
+ expect(image?.sslUrl).toBe("https://example.com/img.jpg");
162
+ expect(image?.mime).toBe("image/jpeg");
163
+ expect(image?.raw?.width).toBe(1600);
164
+ expect(image?.raw?.height).toBe(1200);
165
+
166
+ expect(video?.sslUrl).toBe("https://example.com/vid.mp4");
167
+ expect(video?.mime).toBe("video/mp4");
168
+ expect(video?.raw?.duration).toBe(12.5);
169
+
170
+ expect(thumb?.sslUrl).toBe("https://example.com/thumb.jpg");
171
+ expect(thumb?.raw?.original_id).toBe("vid_1");
172
+ });
173
+
174
+ test("handleWebhook requires rawBody when verifying signature", async () => {
175
+ const t = convexTest(schema, modules);
176
+ const payload = { assembly_id: "asm_missing" };
177
+ const signature = createHmac("sha1", "test-secret")
178
+ .update(JSON.stringify(payload))
179
+ .digest("hex");
180
+
181
+ await expect(
182
+ t.action(api.lib.handleWebhook, {
183
+ payload,
184
+ signature: `sha1:${signature}`,
185
+ }),
186
+ ).rejects.toThrow("Missing rawBody for webhook verification");
187
+ });
188
+
189
+ test("handleWebhook can skip verification when configured", async () => {
190
+ const t = convexTest(schema, modules);
191
+ const payload = {
192
+ assembly_id: "asm_skip",
193
+ ok: "ASSEMBLY_COMPLETED",
194
+ results: {
195
+ resized: [
196
+ {
197
+ id: "file_skip",
198
+ ssl_url: "https://example.com/skip.jpg",
199
+ name: "skip.jpg",
200
+ size: 123,
201
+ mime: "image/jpeg",
202
+ },
203
+ ],
204
+ },
205
+ };
206
+
207
+ const result = await t.action(api.lib.handleWebhook, {
208
+ payload,
209
+ verifySignature: false,
210
+ });
211
+
212
+ expect(result.assemblyId).toBe("asm_skip");
213
+ expect(result.resultCount).toBe(1);
214
+ });
215
+
216
+ test("queueWebhook rejects invalid signature", async () => {
217
+ const t = convexTest(schema, modules);
218
+ const payload = { assembly_id: "asm_bad" };
219
+ const rawBody = JSON.stringify(payload);
220
+
221
+ await expect(
222
+ t.action(api.lib.queueWebhook, {
223
+ payload,
224
+ rawBody,
225
+ signature: "sha1:bad",
226
+ }),
227
+ ).rejects.toThrow("Invalid Transloadit webhook signature");
228
+ });
229
+
230
+ test("refreshAssembly fetches status and stores results", async () => {
231
+ const t = convexTest(schema, modules);
232
+
233
+ const payload = {
234
+ assembly_id: "asm_456",
235
+ ok: "ASSEMBLY_COMPLETED",
236
+ message: "Assembly complete",
237
+ results: {
238
+ resized: [
239
+ {
240
+ id: "file_2",
241
+ ssl_url: "https://example.com/file-2.jpg",
242
+ name: "file-2.jpg",
243
+ size: 54321,
244
+ mime: "image/jpeg",
245
+ },
246
+ ],
247
+ },
248
+ };
249
+
250
+ const fetchMock = vi.fn<typeof fetch>(async () => {
251
+ return new Response(JSON.stringify(payload), {
252
+ status: 200,
253
+ headers: { "content-type": "application/json" },
254
+ });
255
+ });
256
+
257
+ vi.stubGlobal("fetch", fetchMock);
258
+
259
+ try {
260
+ const result = await t.action(api.lib.refreshAssembly, {
261
+ assemblyId: "asm_456",
262
+ config: { authKey: "test-key", authSecret: "test-secret" },
263
+ });
264
+
265
+ expect(result.assemblyId).toBe("asm_456");
266
+ expect(result.ok).toBe("ASSEMBLY_COMPLETED");
267
+
268
+ const requestInfo = fetchMock.mock.calls[0]?.[0];
269
+ const requestUrl =
270
+ typeof requestInfo === "string"
271
+ ? requestInfo
272
+ : requestInfo instanceof URL
273
+ ? requestInfo.toString()
274
+ : requestInfo instanceof Request
275
+ ? requestInfo.url
276
+ : "";
277
+ if (!requestUrl) {
278
+ throw new Error("Expected fetch to be called with a URL string");
279
+ }
280
+ const url = new URL(requestUrl);
281
+ expect(url.origin).toBe("https://api2.transloadit.com");
282
+ expect(url.searchParams.get("signature")).toBeTruthy();
283
+ expect(url.searchParams.get("params")).toBeTruthy();
284
+
285
+ const assembly = await t.query(api.lib.getAssemblyStatus, {
286
+ assemblyId: "asm_456",
287
+ });
288
+ expect(assembly?.ok).toBe("ASSEMBLY_COMPLETED");
289
+
290
+ const results = await t.query(api.lib.listResults, {
291
+ assemblyId: "asm_456",
292
+ });
293
+ expect(results).toHaveLength(1);
294
+ expect(results[0]?.stepName).toBe("resized");
295
+ } finally {
296
+ vi.unstubAllGlobals();
297
+ }
298
+ });
63
299
  });