@editframe/api 0.7.0-beta.8 → 0.8.0-beta.10

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 (59) hide show
  1. package/dist/CHUNK_SIZE_BYTES.d.ts +1 -0
  2. package/dist/CHUNK_SIZE_BYTES.js +7 -0
  3. package/dist/client.d.ts +6 -0
  4. package/dist/client.js +13 -7
  5. package/dist/client.test.d.ts +1 -0
  6. package/dist/index.d.ts +8 -0
  7. package/dist/index.js +11 -1
  8. package/dist/readableFromBuffers.d.ts +2 -0
  9. package/dist/resources/caption-file.d.ts +39 -0
  10. package/dist/resources/caption-file.js +28 -26
  11. package/dist/resources/caption-file.test.d.ts +1 -0
  12. package/dist/resources/image-file.d.ts +31 -0
  13. package/dist/resources/image-file.js +23 -27
  14. package/dist/resources/image-file.test.d.ts +1 -0
  15. package/dist/resources/isobmff-file.d.ts +19 -0
  16. package/dist/resources/isobmff-file.js +17 -23
  17. package/dist/resources/isobmff-file.test.d.ts +1 -0
  18. package/dist/resources/isobmff-track.d.ts +270 -0
  19. package/dist/resources/isobmff-track.js +18 -31
  20. package/dist/resources/isobmff-track.test.d.ts +1 -0
  21. package/dist/resources/renders.d.ts +34 -0
  22. package/dist/resources/renders.js +17 -21
  23. package/dist/resources/renders.test.d.ts +1 -0
  24. package/dist/resources/unprocessed-file.d.ts +45 -0
  25. package/dist/resources/unprocessed-file.js +133 -0
  26. package/dist/resources/unprocessed-file.test.d.ts +1 -0
  27. package/dist/resources/url-token.d.ts +5 -0
  28. package/dist/resources/url-token.js +20 -0
  29. package/dist/resources/url-token.test.d.ts +1 -0
  30. package/dist/streamChunker.d.ts +2 -0
  31. package/dist/streamChunker.js +17 -0
  32. package/dist/streamChunker.test.d.ts +1 -0
  33. package/dist/uploadChunks.d.ts +10 -0
  34. package/dist/uploadChunks.js +65 -0
  35. package/dist/uploadChunks.test.d.ts +1 -0
  36. package/package.json +11 -11
  37. package/src/resources/caption-file.test.ts +124 -0
  38. package/src/resources/caption-file.ts +50 -25
  39. package/src/resources/image-file.test.ts +138 -0
  40. package/src/resources/image-file.ts +29 -26
  41. package/src/resources/isobmff-file.test.ts +108 -0
  42. package/src/resources/isobmff-file.ts +20 -23
  43. package/src/resources/isobmff-track.test.ts +152 -0
  44. package/src/resources/isobmff-track.ts +23 -32
  45. package/src/resources/renders.test.ts +112 -0
  46. package/src/resources/renders.ts +20 -21
  47. package/src/resources/test-av-file.txt +1 -0
  48. package/src/resources/unprocessed-file.test.ts +312 -0
  49. package/src/resources/unprocessed-file.ts +189 -0
  50. package/src/resources/url-token.test.ts +46 -0
  51. package/src/resources/url-token.ts +27 -0
  52. package/dist/client.cjs +0 -29
  53. package/dist/index.cjs +0 -24
  54. package/dist/resources/caption-file.cjs +0 -56
  55. package/dist/resources/image-file.cjs +0 -52
  56. package/dist/resources/isobmff-file.cjs +0 -56
  57. package/dist/resources/isobmff-track.cjs +0 -71
  58. package/dist/resources/renders.cjs +0 -56
  59. package/src/util/nodeStreamToWebStream.ts +0 -20
@@ -0,0 +1,108 @@
1
+ import { test, expect, beforeAll, afterEach, afterAll, describe } from "vitest";
2
+ import { http, HttpResponse } from "msw";
3
+ import { setupServer } from "msw/node";
4
+
5
+ import { Client } from "../client.ts";
6
+ import { createISOBMFFFile, uploadFragmentIndex } from "./isobmff-file.ts";
7
+ import { readableFromBuffers } from "../readableFromBuffers.ts";
8
+
9
+ const server = setupServer();
10
+ const client = new Client("ef_TEST_TOKEN", "http://localhost");
11
+
12
+ describe("ISOBMFFFile", () => {
13
+ beforeAll(() => server.listen());
14
+ afterEach(() => server.resetHandlers());
15
+ afterAll(() => server.close());
16
+
17
+ describe("createISOBMFFFile", () => {
18
+ test("Throws when server returns an error", async () => {
19
+ server.use(
20
+ http.post("http://localhost/api/video2/isobmff_files", () =>
21
+ HttpResponse.text("Internal Server Error", { status: 500 }),
22
+ ),
23
+ );
24
+
25
+ await expect(
26
+ createISOBMFFFile(client, {
27
+ id: "test-id",
28
+ filename: "test",
29
+ }),
30
+ ).rejects.toThrowError(
31
+ "Failed to create isobmff file 500 Internal Server Error",
32
+ );
33
+ });
34
+
35
+ test("Returns json data from the http response", async () => {
36
+ server.use(
37
+ http.post("http://localhost/api/video2/isobmff_files", () =>
38
+ HttpResponse.json(
39
+ { id: "test-id" },
40
+ { status: 200, statusText: "OK" },
41
+ ),
42
+ ),
43
+ );
44
+
45
+ const response = await createISOBMFFFile(client, {
46
+ id: "test-id",
47
+ filename: "test",
48
+ });
49
+
50
+ expect(response).toEqual({ id: "test-id" });
51
+ });
52
+ });
53
+
54
+ describe("uploadFragmentIndex", () => {
55
+ test("Throws when file size exceeds limit", async () => {
56
+ await expect(
57
+ uploadFragmentIndex(
58
+ client,
59
+ "test-id",
60
+ readableFromBuffers(Buffer.from("test")),
61
+ 1024 * 1024 * 3,
62
+ ),
63
+ ).rejects.toThrowError("File size exceeds limit of 2097152 bytes");
64
+ });
65
+
66
+ test("Throws when server returns an error", async () => {
67
+ server.use(
68
+ http.post(
69
+ "http://localhost/api/video2/isobmff_files/test-id/index/upload",
70
+ () => HttpResponse.text("Internal Server Error", { status: 500 }),
71
+ ),
72
+ );
73
+
74
+ await expect(
75
+ uploadFragmentIndex(
76
+ client,
77
+ "test-id",
78
+ readableFromBuffers(Buffer.from("test")),
79
+ 4,
80
+ ),
81
+ ).rejects.toThrowError(
82
+ "Failed to create fragment index 500 Internal Server Error",
83
+ );
84
+ });
85
+
86
+ test("Returns json data from the http response", async () => {
87
+ server.use(
88
+ http.post(
89
+ "http://localhost/api/video2/isobmff_files/test-id/index/upload",
90
+ () =>
91
+ HttpResponse.json(
92
+ { fragment_index_complete: true },
93
+ { status: 200, statusText: "OK" },
94
+ ),
95
+ ),
96
+ );
97
+
98
+ const response = await uploadFragmentIndex(
99
+ client,
100
+ "test-id",
101
+ readableFromBuffers(Buffer.from("test")),
102
+ 4,
103
+ );
104
+
105
+ expect(response).toEqual({ fragment_index_complete: true });
106
+ });
107
+ });
108
+ });
@@ -3,9 +3,10 @@ import type { Readable } from "node:stream";
3
3
  import { z } from "zod";
4
4
  import debug from "debug";
5
5
 
6
- import type { Client } from "../client";
6
+ import type { Client } from "../client.ts";
7
7
 
8
8
  const log = debug("ef:api:isobmff-file");
9
+ const FILE_SIZE_LIMIT = 1024 * 1024 * 2; // 32MB
9
10
 
10
11
  export const CreateISOBMFFFilePayload = z.object({
11
12
  id: z.string(),
@@ -32,26 +33,26 @@ export const createISOBMFFFile = async (
32
33
 
33
34
  log("ISOBMFF file created", response);
34
35
 
35
- switch (response.status) {
36
- case 200: {
37
- return (await response.json()) as CreateISOBMFFFileResult;
38
- }
39
- default: {
40
- console.error(
41
- `Failed to create file ${response.status} ${response.statusText}`,
42
- );
43
- return;
44
- }
36
+ if (response.ok) {
37
+ return (await response.json()) as CreateISOBMFFFileResult;
45
38
  }
39
+
40
+ throw new Error(
41
+ `Failed to create isobmff file ${response.status} ${response.statusText}`,
42
+ );
46
43
  };
47
44
 
48
45
  export const uploadFragmentIndex = async (
49
46
  client: Client,
50
47
  fileId: string,
51
48
  fileStream: Readable,
49
+ fileSize: number,
52
50
  ) => {
53
51
  log("Uploading fragment index", fileId);
54
- const fileIndex = await client.authenticatedFetch(
52
+ if (fileSize > FILE_SIZE_LIMIT) {
53
+ throw new Error(`File size exceeds limit of ${FILE_SIZE_LIMIT} bytes`);
54
+ }
55
+ const response = await client.authenticatedFetch(
55
56
  `/api/video2/isobmff_files/${fileId}/index/upload`,
56
57
  {
57
58
  method: "POST",
@@ -59,16 +60,12 @@ export const uploadFragmentIndex = async (
59
60
  },
60
61
  );
61
62
 
62
- log("Fragment index uploaded", fileIndex);
63
- switch (fileIndex.status) {
64
- case 200: {
65
- return fileIndex.json();
66
- }
67
- default: {
68
- console.error(
69
- `Failed to create fragment index ${fileIndex.status} ${fileIndex.statusText}`,
70
- );
71
- return;
72
- }
63
+ log("Fragment index uploaded", response);
64
+ if (response.ok) {
65
+ return response.json();
73
66
  }
67
+
68
+ throw new Error(
69
+ `Failed to create fragment index ${response.status} ${response.statusText}`,
70
+ );
74
71
  };
@@ -0,0 +1,152 @@
1
+ import { test, expect, beforeAll, afterEach, afterAll, describe } from "vitest";
2
+ import { http, HttpResponse } from "msw";
3
+ import { setupServer } from "msw/node";
4
+ import { ZodError } from "zod";
5
+
6
+ import { Client } from "../client.ts";
7
+ import { createISOBMFFTrack, uploadISOBMFFTrack } from "./isobmff-track.ts";
8
+ import { readableFromBuffers } from "../readableFromBuffers.ts";
9
+
10
+ const server = setupServer();
11
+ const client = new Client("ef_TEST_TOKEN", "http://localhost");
12
+
13
+ describe("ISOBMFF Track", () => {
14
+ beforeAll(() => server.listen());
15
+ afterEach(() => server.resetHandlers());
16
+ afterAll(() => server.close());
17
+
18
+ describe("createISOBMFFTrack", () => {
19
+ test("Throws when track is too large", async () => {
20
+ await expect(
21
+ createISOBMFFTrack(
22
+ client,
23
+ createTestTrack({ byte_size: 1024 * 1024 * 1025 }),
24
+ ),
25
+ ).rejects.toThrowError(
26
+ new ZodError([
27
+ {
28
+ code: "too_big",
29
+ maximum: 1073741824,
30
+ type: "number",
31
+ inclusive: true,
32
+ exact: false,
33
+ message: "Number must be less than or equal to 1073741824",
34
+ path: ["byte_size"],
35
+ },
36
+ ]),
37
+ );
38
+ });
39
+
40
+ test("Throws when server returns an error", async () => {
41
+ server.use(
42
+ http.post("http://localhost/api/video2/isobmff_tracks", () =>
43
+ HttpResponse.text("Internal Server Error", { status: 500 }),
44
+ ),
45
+ );
46
+
47
+ await expect(
48
+ createISOBMFFTrack(client, createTestTrack()),
49
+ ).rejects.toThrowError(
50
+ "Failed to create isobmff track 500 Internal Server Error",
51
+ );
52
+ });
53
+
54
+ test("Returns json data from the http response", async () => {
55
+ server.use(
56
+ http.post("http://localhost/api/video2/isobmff_tracks", () =>
57
+ HttpResponse.json(
58
+ { testResponse: "test" },
59
+ { status: 200, statusText: "OK" },
60
+ ),
61
+ ),
62
+ );
63
+
64
+ const response = await createISOBMFFTrack(
65
+ client,
66
+ createTestTrack({ byte_size: 1024 * 1024 * 5 }),
67
+ );
68
+
69
+ expect(response).toEqual({ testResponse: "test" });
70
+ });
71
+ });
72
+
73
+ describe("uploadISOBMFFTrack", () => {
74
+ test("Throws when server returns an error", async () => {
75
+ server.use(
76
+ http.post(
77
+ "http://localhost/api/video2/isobmff_tracks/test-file/1/upload",
78
+ () => HttpResponse.text("Internal Server Error", { status: 500 }),
79
+ ),
80
+ );
81
+
82
+ await expect(
83
+ uploadISOBMFFTrack(
84
+ client,
85
+ "test-file",
86
+ 1,
87
+ readableFromBuffers(Buffer.from("test")),
88
+ 4,
89
+ ),
90
+ ).rejects.toThrowError(
91
+ "Failed to upload chunk 0 for /api/video2/isobmff_tracks/test-file/1/upload 500 Internal Server Error",
92
+ );
93
+ });
94
+
95
+ test("Succeeds when server returns a success", async () => {
96
+ server.use(
97
+ http.post(
98
+ "http://localhost/api/video2/isobmff_tracks/test-file/1/upload",
99
+ () => HttpResponse.json({}, { status: 201 }),
100
+ ),
101
+ );
102
+
103
+ await expect(
104
+ uploadISOBMFFTrack(
105
+ client,
106
+ "test-file",
107
+ 1,
108
+ readableFromBuffers(Buffer.from("test")),
109
+ 4,
110
+ ),
111
+ ).resolves.toBeUndefined();
112
+ });
113
+ });
114
+ });
115
+
116
+ function createTestTrack(
117
+ options: Partial<Parameters<typeof createISOBMFFTrack>[1]> = {},
118
+ ) {
119
+ return Object.assign(
120
+ {
121
+ file_id: "test-id",
122
+ track_id: 1,
123
+ type: "audio",
124
+ probe_info: {
125
+ channels: 2,
126
+ sample_rate: "44100",
127
+ duration: 1000,
128
+ duration_ts: 1000,
129
+ start_time: 0,
130
+ start_pts: 0,
131
+ r_frame_rate: "100",
132
+ channel_layout: "stereo",
133
+ codec_tag_string: "mp3",
134
+ codec_long_name: "MP3",
135
+ codec_type: "audio",
136
+ codec_tag: "0x0000",
137
+ codec_name: "aac",
138
+ bits_per_sample: 16,
139
+ index: 0,
140
+ sample_fmt: "s16",
141
+ time_base: "100",
142
+ avg_frame_rate: "100",
143
+ disposition: {},
144
+ bit_rate: "100",
145
+ },
146
+ duration_ms: 1000,
147
+ codec_name: "mp3",
148
+ byte_size: 1024 * 1024 * 5,
149
+ } as const,
150
+ options,
151
+ );
152
+ }
@@ -5,10 +5,13 @@ import debug from "debug";
5
5
 
6
6
  import { AudioStreamSchema, VideoStreamSchema } from "@editframe/assets";
7
7
 
8
- import type { Client } from "../client";
8
+ import type { Client } from "../client.ts";
9
+ import { uploadChunks } from "../uploadChunks.ts";
9
10
 
10
11
  const log = debug("ef:api:isobmff-track");
11
12
 
13
+ const MAX_TRACK_SIZE = 1024 * 1024 * 1024; // 1GB
14
+
12
15
  export const CreateISOBMFFTrackPayload = z.discriminatedUnion("type", [
13
16
  z.object({
14
17
  file_id: z.string(),
@@ -17,7 +20,7 @@ export const CreateISOBMFFTrackPayload = z.discriminatedUnion("type", [
17
20
  probe_info: AudioStreamSchema,
18
21
  duration_ms: z.number().int(),
19
22
  codec_name: z.string(),
20
- byte_size: z.number().int(),
23
+ byte_size: z.number().int().max(MAX_TRACK_SIZE),
21
24
  }),
22
25
  z.object({
23
26
  file_id: z.string(),
@@ -26,12 +29,12 @@ export const CreateISOBMFFTrackPayload = z.discriminatedUnion("type", [
26
29
  probe_info: VideoStreamSchema,
27
30
  duration_ms: z.number().int(),
28
31
  codec_name: z.string(),
29
- byte_size: z.number().int(),
32
+ byte_size: z.number().int().max(MAX_TRACK_SIZE),
30
33
  }),
31
34
  ]);
32
35
 
33
36
  export interface CreateISOBMFFTrackResult {
34
- last_received_byte: number;
37
+ next_byte: number;
35
38
  byte_size: number;
36
39
  track_id: number;
37
40
  file_id: string;
@@ -42,6 +45,7 @@ export const createISOBMFFTrack = async (
42
45
  payload: z.infer<typeof CreateISOBMFFTrackPayload>,
43
46
  ) => {
44
47
  log("Creating isobmff track", payload);
48
+ CreateISOBMFFTrackPayload.parse(payload);
45
49
  const response = await client.authenticatedFetch(
46
50
  "/api/video2/isobmff_tracks",
47
51
  {
@@ -51,16 +55,13 @@ export const createISOBMFFTrack = async (
51
55
  );
52
56
 
53
57
  log("ISOBMFF track created", response);
54
- switch (response.status) {
55
- case 200: {
56
- return (await response.json()) as CreateISOBMFFTrackResult;
57
- }
58
- default: {
59
- console.error("Failed to create track");
60
- console.error(await response.json());
61
- return;
62
- }
58
+ if (response.ok) {
59
+ return (await response.json()) as CreateISOBMFFTrackResult;
63
60
  }
61
+
62
+ throw new Error(
63
+ `Failed to create isobmff track ${response.status} ${response.statusText}`,
64
+ );
64
65
  };
65
66
 
66
67
  export const uploadISOBMFFTrack = async (
@@ -68,25 +69,15 @@ export const uploadISOBMFFTrack = async (
68
69
  fileId: string,
69
70
  trackId: number,
70
71
  fileStream: Readable,
72
+ trackSize: number,
71
73
  ) => {
72
- log("Uploading isobmff track", fileId, trackId);
73
- const trackIndex = await client.authenticatedFetch(
74
- `/api/video2/isobmff_tracks/${fileId}/${trackId}/upload`,
75
- {
76
- method: "POST",
77
- body: fileStream,
78
- },
79
- );
74
+ log("Uploading fragment track", fileId);
80
75
 
81
- log("ISOBMFF track uploaded", trackIndex);
82
- switch (trackIndex.status) {
83
- case 200: {
84
- return trackIndex.json();
85
- }
86
- default: {
87
- console.error("Failed to upload track");
88
- console.error(trackIndex.status, trackIndex.statusText);
89
- return;
90
- }
91
- }
76
+ await uploadChunks(client, {
77
+ url: `/api/video2/isobmff_tracks/${fileId}/${trackId}/upload`,
78
+ fileStream,
79
+ fileSize: trackSize,
80
+ });
81
+
82
+ log("Fragment track upload complete");
92
83
  };
@@ -0,0 +1,112 @@
1
+ import { test, expect, beforeAll, afterEach, afterAll, describe } from "vitest";
2
+ import { http, HttpResponse } from "msw";
3
+ import { setupServer } from "msw/node";
4
+
5
+ import { Client } from "../client.ts";
6
+ import { readableFromBuffers } from "../readableFromBuffers.ts";
7
+ import { createRender, uploadRender } from "./renders.ts";
8
+
9
+ const server = setupServer();
10
+ const client = new Client("ef_TEST_TOKEN", "http://localhost");
11
+
12
+ describe("Renders", () => {
13
+ beforeAll(() => server.listen());
14
+ afterEach(() => server.resetHandlers());
15
+ afterAll(() => server.close());
16
+
17
+ describe("createRender", () => {
18
+ test("throws if server returns an error", async () => {
19
+ server.use(
20
+ http.post("http://localhost/api/video2/renders", () =>
21
+ HttpResponse.text("Internal Server Error", { status: 500 }),
22
+ ),
23
+ );
24
+
25
+ await expect(
26
+ createRender(client, createTestRender()),
27
+ ).rejects.toThrowError(
28
+ "Failed to create render 500 Internal Server Error",
29
+ );
30
+ });
31
+
32
+ test("returns json data from the http response", async () => {
33
+ server.use(
34
+ http.post("http://localhost/api/video2/renders", () =>
35
+ HttpResponse.json(
36
+ { testResponse: "test" },
37
+ { status: 200, statusText: "OK" },
38
+ ),
39
+ ),
40
+ );
41
+
42
+ const response = await createRender(client, createTestRender());
43
+
44
+ expect(response).toEqual({ testResponse: "test" });
45
+ });
46
+ });
47
+
48
+ describe("uploadRender", () => {
49
+ test("throws if file size exceeds limit", async () => {
50
+ await expect(
51
+ uploadRender(
52
+ client,
53
+ "test-id",
54
+ readableFromBuffers(Buffer.from("test")),
55
+ 1024 * 1024 * 17,
56
+ ),
57
+ ).rejects.toThrowError(
58
+ new Error("File size exceeds limit of 16777216 bytes"),
59
+ );
60
+ });
61
+
62
+ test("throws if server returns an error", async () => {
63
+ server.use(
64
+ http.post("http://localhost/api/video2/renders/test-id/upload", () =>
65
+ HttpResponse.text("Internal Server Error", { status: 500 }),
66
+ ),
67
+ );
68
+
69
+ await expect(
70
+ uploadRender(
71
+ client,
72
+ "test-id",
73
+ readableFromBuffers(Buffer.from("test")),
74
+ 1024 * 1024 * 2,
75
+ ),
76
+ ).rejects.toThrowError(
77
+ "Failed to upload render 500 Internal Server Error",
78
+ );
79
+ });
80
+
81
+ test("returns json data from the http response", async () => {
82
+ server.use(
83
+ http.post("http://localhost/api/video2/renders/test-id/upload", () =>
84
+ HttpResponse.json(
85
+ { testResponse: "test" },
86
+ { status: 200, statusText: "OK" },
87
+ ),
88
+ ),
89
+ );
90
+
91
+ const response = await uploadRender(
92
+ client,
93
+ "test-id",
94
+ readableFromBuffers(Buffer.from("test")),
95
+ 1024 * 1024 * 2,
96
+ );
97
+
98
+ expect(response).toEqual({ testResponse: "test" });
99
+ });
100
+ });
101
+ });
102
+
103
+ const createTestRender = () =>
104
+ ({
105
+ id: "test-id",
106
+ fps: 30,
107
+ width: 1920,
108
+ height: 1080,
109
+ work_slice_ms: 100,
110
+ duration_ms: 1000,
111
+ strategy: "v1",
112
+ }) as const;
@@ -3,9 +3,10 @@ import type { Readable } from "node:stream";
3
3
  import { z } from "zod";
4
4
  import debug from "debug";
5
5
 
6
- import type { Client } from "../client";
6
+ import type { Client } from "../client.ts";
7
7
 
8
8
  const log = debug("ef:api:renders");
9
+ const FILE_SIZE_LIMIT = 1024 * 1024 * 16; // 16MiB
9
10
 
10
11
  export const CreateRenderPayload = z.object({
11
12
  id: z.string().uuid(),
@@ -33,25 +34,27 @@ export const createRender = async (
33
34
  });
34
35
 
35
36
  log("Render created", response);
36
- switch (response.status) {
37
- case 200: {
38
- return (await response.json()) as CreateRenderResult;
39
- }
40
- default: {
41
- console.error("Failed to create render");
42
- console.error(await response.json());
43
- return;
44
- }
37
+ if (response.ok) {
38
+ return (await response.json()) as CreateRenderResult;
45
39
  }
40
+
41
+ throw new Error(
42
+ `Failed to create render ${response.status} ${response.statusText}`,
43
+ );
46
44
  };
47
45
 
48
46
  export const uploadRender = async (
49
47
  client: Client,
50
48
  fileId: string,
51
49
  fileStream: Readable,
50
+ folderSize: number,
52
51
  ) => {
53
52
  log("Uploading render", fileId);
54
- const fileIndex = await client.authenticatedFetch(
53
+ log("Folder size", folderSize, "bytes");
54
+ if (folderSize > FILE_SIZE_LIMIT) {
55
+ throw new Error(`File size exceeds limit of ${FILE_SIZE_LIMIT} bytes`);
56
+ }
57
+ const response = await client.authenticatedFetch(
55
58
  `/api/video2/renders/${fileId}/upload`,
56
59
  {
57
60
  method: "POST",
@@ -59,15 +62,11 @@ export const uploadRender = async (
59
62
  },
60
63
  );
61
64
 
62
- log("Render uploaded", fileIndex);
63
- switch (fileIndex.status) {
64
- case 200: {
65
- return fileIndex.json();
66
- }
67
- default: {
68
- console.error("Failed to upload render");
69
- console.error(fileIndex.status, fileIndex.statusText);
70
- return;
71
- }
65
+ if (response.ok) {
66
+ return response.json();
72
67
  }
68
+
69
+ throw new Error(
70
+ `Failed to upload render ${response.status} ${response.statusText}`,
71
+ );
73
72
  };
@@ -0,0 +1 @@
1
+ test