Bad blob webhook dev experience
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 595
- Forks
- 101
- Avg merge
- 2h 24m
- Merged PRs (30d)
- 1
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?
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No repository files are named. Start by tracing the TypeScript blob uploadStart and blob.upload-completed webhook handling, then review the related local-development documentation. Done should mean the intended development flow is clearly defined and either works without ngrok or documents the required completion request.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend, devtools
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100