@mathrunet/masamune_cloudflare_storage
v3.2.1
Published
Server-side package for handling Cloudflare R2.
Maintainers
Readme
[GitHub] | [YouTube] | [Packages] | [X] | [LinkedIn] | [mathru.net]
Just load the package in index.ts and pass the predefined data to the methods to implement the server side.
Also, masamune_functions_cloudflare can be used to execute server-side functions from methods defined on the client side, allowing for safe implementation.
Installation
Install the following packages
npm install @mathrunet/masamune_cloudflare_storageImplementation
Pass the return value of the deploy function to export default. It is defined by passing various Workers to the deploy function.
import * as m from "@mathrunet/masamune_cloudflare_storage";
// Define [m.Functions.xxxx] for the functions to be added to Workers.
export default m.deploy(
[
m.Functions.storageCloudflare(),
],
{
rules: {
version: "1",
rules: {
storage: {
"public/**": {
read: "allow",
write: "authenticated",
},
"images/{uid}/**": {
read: { type: "path", param: "uid" },
write: { type: "path", param: "uid", server: true },
},
},
},
},
},
);Bind an R2 bucket as R2_BUCKET. Public URLs are served by the Cloudflare R2
public domain or custom domain. Limited download URLs are generated by the
Worker and require STORAGE_DOWNLOAD_URL_SECRET.
The public base URL used to build publicUri is resolved in the following
order: the publicBaseUrl option passed to storageCloudflare() takes
precedence; if it is not specified (or empty), the STORAGE_PUBLIC_BASE_URL
variable defined in wrangler.jsonc vars is used. This allows a single
edge.ts to serve different public URLs per environment
(e.g. https://storage-dev.example.com for dev and
https://storage.example.com for prod). If neither is configured,
publicUri is omitted from the response and only the limited download URL is
returned. A trailing slash is trimmed automatically.
{
"env": {
"dev": { "vars": { "STORAGE_PUBLIC_BASE_URL": "https://storage-dev.example.com" } },
"prod": { "vars": { "STORAGE_PUBLIC_BASE_URL": "https://storage.example.com" } }
}
}R2 Backup
R2 event notifications can be consumed through Cloudflare Queues to copy the latest source object to another R2 bucket.
import * as m from "@mathrunet/masamune_cloudflare_storage";
export default m.deploy([
m.Functions.storageCloudflare(),
m.Functions.storageCloudflareBackup({
sourceBucketBindingName: "R2_BUCKET",
backupBucketBindingName: "R2_BACKUP_BUCKET",
sourceBucketName: "my-app-bucket",
}),
]);Bind both buckets and configure the Queue consumer in wrangler.jsonc.
max_concurrency is fixed to 1 when generated by Katana so an older event
cannot overwrite a newer backup concurrently.
{
"r2_buckets": [
{
"binding": "R2_BUCKET",
"bucket_name": "my-app-bucket"
},
{
"binding": "R2_BACKUP_BUCKET",
"bucket_name": "my-app-bucket-backup"
}
],
"queues": {
"consumers": [
{
"queue": "my-app-storage-backup",
"max_batch_size": 10,
"max_batch_timeout": 5,
"max_retries": 3,
"max_concurrency": 1,
"dead_letter_queue": "my-app-storage-backup-dlq"
}
]
}
}Create an object-create event notification for the source bucket:
wrangler queues create my-app-storage-backup
wrangler queues create my-app-storage-backup-dlq
wrangler r2 bucket notification create my-app-bucket \
--event-type object-create \
--queue my-app-storage-backupThe Worker streams the object body without buffering the whole file, and keeps HTTP/custom metadata. Each successful message is acknowledged individually; temporary R2 failures are retried. Delete events are intentionally ignored, and if the source object has already been deleted, an existing backup is retained.
This feature maintains a latest-state replica. It is not object versioning: overwrites also overwrite the backup object at the same key.
Katana configuration
katana apply can register the backup Worker, both R2 bindings, the Queue
consumer, Queue/DLQ resources, and the source bucket notification.
cloudflare:
workers:
enable: true
storage:
enable: true
binding: R2_BUCKET
bucket_name: my-app-bucket
public_base_url: https://assets.example.com
backup:
enable: true
binding: R2_BACKUP_BUCKET
bucket_name: my-app-bucket-backup
preview_bucket_name: my-app-bucket-backup-preview
queue_name: my-app-storage-backup
max_batch_size: 10
max_batch_timeout: 5
max_retries: 3
dead_letter_queue: my-app-storage-backup-dlqCreate the source and backup R2 buckets before running katana apply.
Wrangler must already be authenticated. Existing overlapping R2 notification
rules must be removed or adjusted before Katana can create the backup rule.
GitHub Sponsors
Sponsors are always welcome. Thank you for your support!
