-
Notifications
You must be signed in to change notification settings - Fork 71
Open
Description
I tried ngrok but it was super laggy and is added complexity for my team.
I think in dev, blob uploadStart should automatically handle calling the api endpoint again on completion or provide some documentation to do so.
E.g.
// client side
export const useVercelBlob: UseVercelBlob = () => {
const userId = useUserId();
return async (file, data, onComplete) => {
const clientPayload = Schema.encodeSync(
Schema.parseJson(VercelBlobClientToken),
)(data);
const response = await upload(file.name, file, {
clientPayload,
access: "public",
handleUploadUrl: "/api/vercel-blob",
});
if (env.NEXT_PUBLIC_VERCEL_ENV === "development") {
// must be a string so it gets double stringified
const tokenPayload: string = Schema.encodeSync(
Schema.parseJson(VercelBlobPayloadToken),
)({
body: data.body,
userId,
});
// fake the api request that the webhook should have sent
const body = {
type: "blob.upload-completed",
payload: {
tokenPayload,
blob: response,
},
};
await fetch("/api/vercel-blob", {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
});
}
onComplete(response);
};
};
// in api endpoint
const body = (await request.json()) as HandleUploadBody;
const signature =
env.VERCEL_ENV === "development" && body.type === "blob.upload-completed"
? await signPayload(
JSON.stringify(body),
// biome-ignore lint/style/noNonNullAssertion: <explanation>
process.env.BLOB_READ_WRITE_TOKEN!,
)
: null;
//...
handleUpload({
//...
// pass in the faked signature
request:
env.VERCEL_ENV === "development"
? ({
headers: {
"x-vercel-signature": signature,
},
} as unknown as IncomingMessage)
: request,
})
// helper functions taken from blob sourcecode
function importKey(token: string): Promise<webcrypto.CryptoKey> {
return globalThis.crypto.subtle.importKey(
"raw",
new TextEncoder().encode(token),
{ name: "HMAC", hash: "SHA-256" },
false,
["sign", "verify"],
);
}
async function signPayload(
payload: string,
token: string,
): Promise<string | undefined> {
const signature = await globalThis.crypto.subtle.sign(
"HMAC",
await importKey(token),
new TextEncoder().encode(payload),
);
return Buffer.from(new Uint8Array(signature)).toString("hex");
}
Thoughts?
Metadata
Metadata
Assignees
Labels
No labels