Files
ipal-kit/dist/modules/storage/buildR2Storage.js
T

72 lines
3.2 KiB
JavaScript

import { s3Storage } from '@payloadcms/storage-s3';
/**
* Cloudflare R2 media storage — configured from environment variables (agency
* infrastructure, not per-project panel data). R2 is S3-compatible, so we use
* @payloadcms/storage-s3 pointed at the R2 endpoint.
*
* Storage is infrastructure (like the database or PAYLOAD_SECRET): it binds at
* boot, and its credentials are agency-owned — so it lives in .env, not the
* panel. See docs/storage.md for the required variables.
*
* Returns the storage plugin when all R2 vars are present; otherwise returns a
* no-op passthrough so the project falls back to Payload's default local disk
* storage (useful in dev without R2). This mirrors how mailAdapter degrades
* gracefully when a transport isn't configured.
*
* @param collections - slugs of upload collections to offload to R2 (e.g. ['media'])
*/ export const buildR2Storage = (collections = [
'media'
])=>{
const bucket = process.env.R2_BUCKET;
const endpoint = process.env.R2_ENDPOINT;
const accessKeyId = process.env.R2_ACCESS_KEY_ID;
const secretAccessKey = process.env.R2_SECRET_ACCESS_KEY;
// Any missing → skip R2, fall back to local disk. Warn so it's not silent.
if (!bucket || !endpoint || !accessKeyId || !secretAccessKey) {
return (config)=>{
// Only warn when SOME vars are set (partial config = likely a mistake).
if (bucket || endpoint || accessKeyId || secretAccessKey) {
console.warn('[ipal] R2 storage: incomplete env (need R2_BUCKET, R2_ENDPOINT, ' + 'R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY). Falling back to local disk.');
}
return config;
};
}
// Public URL for served media. R2 is private by default; its S3 endpoint only
// accepts uploads and won't serve files (403). With a custom domain
// (media.klient.pl → bucket) set R2_PUBLIC_URL so Payload generates URLs
// pointing there. Without it, uploads work but images don't display publicly.
// See docs/storage.md.
const publicUrl = process.env.R2_PUBLIC_URL?.replace(/\/$/, '') // strip trailing slash
;
// generateFileURL is a PER-COLLECTION option in @payloadcms/storage-s3 (not a
// top-level one) — R2 needs it to point served URLs at the custom domain
// instead of the private S3 endpoint. Each collection gets either `true`
// (plain offload) or an object carrying generateFileURL when a public URL is set.
const generateFileURL = publicUrl ? ({ filename, prefix })=>[
publicUrl,
prefix,
filename
].filter(Boolean).join('/') : undefined;
const collectionsConfig = {};
for (const slug of collections){
collectionsConfig[slug] = generateFileURL ? {
generateFileURL
} : true;
}
return s3Storage({
bucket,
collections: collectionsConfig,
config: {
credentials: {
accessKeyId,
secretAccessKey
},
endpoint,
region: 'auto',
// R2 requires path-style addressing for S3 compatibility.
forcePathStyle: true
}
});
};
//# sourceMappingURL=buildR2Storage.js.map