Skip to content

Instantly share code, notes, and snippets.

@AndrewIngram
Last active March 20, 2024 11:05
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save AndrewIngram/c9631759445fb10680f4ae6eee890070 to your computer and use it in GitHub Desktop.
Save AndrewIngram/c9631759445fb10680f4ae6eee890070 to your computer and use it in GitHub Desktop.
Read/write from Cloudflare R2 in a Vercel edge function w/default
import { AwsClient } from "aws4fetch";
import { deflate } from "pako";
const R2_ACCOUNT_ID = "SOMETHING"
const R2_ACCESS_KEY_ID = "SOMETHING"
const R2_SECRET_ACCESS_KEY ="SOMETHING"
const R2_BUCKET = "SOMETHING"
const R2_URL = `https://${R2_BUCKET}.${R2_ACCOUNT_ID}.r2.cloudflarestorage.com`;
const getR2Client = () => {
return new AwsClient({
accessKeyId: R2_ACCESS_KEY_ID,
secretAccessKey: R2_SECRET_ACCESS_KEY,
});
});
export default class FileStorage {
static head(key: string) {
return getR2Client().fetch(`${R2_URL}/${key}`, {
method: "HEAD",
});
}
static async exists(key: string): Promise<boolean> {
const response = await this.head(key);
return response.status !== 404;
}
static list() {
return getR2Client().fetch(`${R2_URL}`, {
method: "GET",
});
}
static async get(key: string) {
const url = new URL(R2_URL);
// preserve the original path
url.pathname = key;
// Specify a custom expiry for the presigned URL, in seconds
// 3600 is almost certainly overkill
url.searchParams.set("X-Amz-Expires", "3600");
const signed = await getR2Client().sign(
new Request(url, {
method: "GET",
headers: {
"Accept-Encoding": "deflate",
},
}),
{
aws: { signQuery: true },
},
);
return fetch(signed.url, {
method: "GET",
headers: {
"Accept-Encoding": "deflate",
},
});
}
static async put(key: string, data: Buffer | Uint8Array | string) {
const url = new URL(R2_URL);
url.pathname = key;
// Specify a custom expiry for the presigned URL, in seconds
// 3600 is almost certainly overkill
url.searchParams.set("X-Amz-Expires", "3600");
const signed = await getR2Client().sign(
new Request(url, {
method: "PUT",
headers: {},
}),
{
aws: { signQuery: true },
},
);
let body;
if (typeof data === "string") {
const enc = new TextEncoder();
body = deflate(enc.encode(data));
} else if (data instanceof Uint8Array) {
body = deflate(data);
} else {
body = data;
}
return fetch(signed.url, {
method: "PUT",
body,
headers: {
"Content-Encoding": "deflate",
},
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment