R2 storage (generateFileURL per-collection) + filename normalization
This commit is contained in:
@@ -38,32 +38,30 @@ export const buildR2Storage = (collections: string[] = ['media']): Plugin => {
|
||||
}
|
||||
}
|
||||
|
||||
// s3Storage wants Record<string, true> (the literal true, per collection),
|
||||
// not Record<string, boolean>. Object.fromEntries widens true → boolean, so
|
||||
// build the map with an explicitly-typed accumulator to keep the literal.
|
||||
const collectionsConfig: Record<string, true> = {}
|
||||
for (const slug of collections) {
|
||||
collectionsConfig[slug] = true
|
||||
}
|
||||
|
||||
// Public URL for served media. R2 is private by default; with a custom domain
|
||||
// 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 instead of the private S3 endpoint (which 403s on the front).
|
||||
// Without it, uploads work but images don't display publicly. See docs/storage.md.
|
||||
// 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 }: { filename: string; prefix?: string }) =>
|
||||
[publicUrl, prefix, filename].filter(Boolean).join('/')
|
||||
: undefined
|
||||
|
||||
const collectionsConfig: Record<string, { generateFileURL: typeof generateFileURL } | true> = {}
|
||||
for (const slug of collections) {
|
||||
collectionsConfig[slug] = generateFileURL ? { generateFileURL } : true
|
||||
}
|
||||
|
||||
return s3Storage({
|
||||
bucket,
|
||||
collections: collectionsConfig,
|
||||
...(publicUrl
|
||||
? {
|
||||
// generateFileURL overrides the stored/returned URL to the CDN domain.
|
||||
// Params come from Payload's storage plugin; type them explicitly since
|
||||
// the callback shape isn't inferred here (would be implicit any).
|
||||
generateFileURL: ({ filename, prefix }: { filename: string; prefix?: string }) =>
|
||||
[publicUrl, prefix, filename].filter(Boolean).join('/'),
|
||||
}
|
||||
: {}),
|
||||
config: {
|
||||
credentials: { accessKeyId, secretAccessKey },
|
||||
endpoint,
|
||||
|
||||
Reference in New Issue
Block a user