Skip to content

Commit

Permalink
fix: uploadFiles wrong runtime return type (#247)
Browse files Browse the repository at this point in the history
Co-authored-by: Miguel Velasquez <[email protected]>
  • Loading branch information
juliusmarminge and miguelvelasquezdev committed Aug 7, 2023
1 parent c887146 commit 84a7b7d
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/little-dogs-exercise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"uploadthing": patch
---

fix: runtime return type of `utapi.uploadFiles`
35 changes: 20 additions & 15 deletions packages/uploadthing/src/sdk/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import type { Json } from "@uploadthing/shared";
import { UploadThingError, generateUploadThingURL } from "@uploadthing/shared";
import { generateUploadThingURL, UploadThingError } from "@uploadthing/shared";

import { UPLOADTHING_VERSION } from "../constants";
import type { FileEsque } from "./utils";
import type { FileEsque, UploadData, UploadError } from "./utils";
import { uploadFilesInternal } from "./utils";

function guardServerOnly() {
if (typeof window !== "undefined") {
throw new UploadThingError({
code: "INTERNAL_SERVER_ERROR",
message: "The `utapi` can only be used on the server.",
})
});
}
}

Expand All @@ -19,13 +19,14 @@ function getApiKeyOrThrow() {
throw new UploadThingError({
code: "MISSING_ENV",
message: "Missing `UPLOADTHING_SECRET` env variable.",
})
});
}
return process.env.UPLOADTHING_SECRET;
}

// File is just a Blob with a name property
type UploadFileResponse = Awaited<ReturnType<typeof uploadFilesInternal>>[0];
type UploadFileResponse =
| { data: UploadData; error: null }
| { data: null; error: UploadError };

/**
* @param {FileEsque | FileEsque[]} files The file(s) to upload
Expand All @@ -43,9 +44,7 @@ type UploadFileResponse = Awaited<ReturnType<typeof uploadFilesInternal>>[0];
export const uploadFiles = async <T extends FileEsque | FileEsque[]>(
files: T,
metadata: Json = {},
): Promise<
T extends FileEsque[] ? UploadFileResponse[] : UploadFileResponse
> => {
) => {
guardServerOnly();

const filesToUpload: FileEsque[] = Array.isArray(files) ? files : [files];
Expand All @@ -61,8 +60,11 @@ export const uploadFiles = async <T extends FileEsque | FileEsque[]>(
},
);

// @ts-expect-error - ehh? type is tested in sdk.test.ts
return uploads;
const uploadFileResponse = Array.isArray(files) ? uploads : uploads[0];

return uploadFileResponse as T extends FileEsque[]
? UploadFileResponse[]
: UploadFileResponse;
};

/**
Expand All @@ -82,7 +84,7 @@ type Url = string | URL;
export const uploadFilesFromUrl = async <T extends Url | Url[]>(
urls: T,
metadata: Json = {},
): Promise<T extends Url[] ? UploadFileResponse[] : UploadFileResponse> => {
) => {
guardServerOnly();

const fileUrls: Url[] = Array.isArray(urls) ? urls : [urls];
Expand All @@ -102,7 +104,7 @@ export const uploadFilesFromUrl = async <T extends Url | Url[]>(
code: "BAD_REQUEST",
message: "Failed to download requested file.",
cause: fileResponse,
})
});
}
const blob = await fileResponse.blob();
return Object.assign(blob, { name: filename });
Expand All @@ -120,8 +122,11 @@ export const uploadFilesFromUrl = async <T extends Url | Url[]>(
},
);

// @ts-expect-error - ehh? type is tested in sdk.test.ts
return Array.isArray(urls) ? uploads : uploads[0];
const uploadFileResponse = Array.isArray(urls) ? uploads : uploads[0];

return uploadFileResponse as T extends Url[]
? UploadFileResponse[]
: UploadFileResponse;
};

/**
Expand Down
14 changes: 5 additions & 9 deletions packages/uploadthing/src/sdk/sdk.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { describe, expectTypeOf, test } from "vitest";

import * as utapi from ".";
import type { UploadError } from "./utils";

type SerializedUploadthingError = {
code: string;
message: string;
data: any;
};

async function ignoreErrors<T>(fn: () => T | Promise<T>) {
try {
Expand All @@ -23,7 +19,7 @@ describe("uploadFiles", () => {
expectTypeOf<
(
| { data: { key: string; url: string }; error: null }
| { data: null; error: SerializedUploadthingError }
| { data: null; error: UploadError }
)[]
>(result);
});
Expand All @@ -34,7 +30,7 @@ describe("uploadFiles", () => {
const result = await utapi.uploadFiles({} as File);
expectTypeOf<
| { data: { key: string; url: string }; error: null }
| { data: null; error: SerializedUploadthingError }
| { data: null; error: UploadError }
>(result);
});
});
Expand All @@ -47,7 +43,7 @@ describe("uploadFilesFromUrl", () => {
expectTypeOf<
(
| { data: { key: string; url: string }; error: null }
| { data: null; error: SerializedUploadthingError }
| { data: null; error: UploadError }
)[]
>(result);
});
Expand All @@ -58,7 +54,7 @@ describe("uploadFilesFromUrl", () => {
const result = await utapi.uploadFilesFromUrl("foo");
expectTypeOf<
| { data: { key: string; url: string }; error: null }
| { data: null; error: SerializedUploadthingError }
| { data: null; error: UploadError }
>(result);
});
});
Expand Down
22 changes: 17 additions & 5 deletions packages/uploadthing/src/sdk/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import {

export type FileEsque = Blob & { name: string };

export type UploadData = {
key: string;
url: string;
};

export type UploadError = {
code: string;
message: string;
data: any;
};

export const uploadFilesInternal = async (
data: {
files: FileEsque[];
Expand Down Expand Up @@ -100,11 +111,12 @@ export const uploadFilesInternal = async (

return uploads.map((upload) => {
if (upload.status === "fulfilled") {
return { data: upload.value, error: null };
const data = upload.value satisfies UploadData;
return { data, error: null };
}
return {
data: null,
error: UploadThingError.toObject(upload.reason as UploadThingError),
};
// We only throw UploadThingErrors, so this is safe
const reason = upload.reason as UploadThingError;
const error = UploadThingError.toObject(reason) satisfies UploadError;
return { data: null, error };
});
};

1 comment on commit 84a7b7d

@vercel
Copy link

@vercel vercel bot commented on 84a7b7d Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.