Last active
March 20, 2024 11:05
-
-
Save AndrewIngram/c9631759445fb10680f4ae6eee890070 to your computer and use it in GitHub Desktop.
Read/write from Cloudflare R2 in a Vercel edge function w/default
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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