Files
zeekayandHanzo Dev d7054fa778 rename(cms): Payload → CMS across all 44 packages (identifiers, slugs, env, i18n, brand)
Complete de-brand of the fork the org owns (unpublished, empty DB — so no external
consumers and no data migration). 1308 files. Applied Payload→CMS / payload→cms /
PAYLOAD→CMS to: type/identifier names (PayloadRequest→CMSRequest, getPayload→getCMS,
BasePayload→BaseCMS, the request property req.payload→req.cms, PayloadComponent→
CMSComponent, usePayloadAPI→useCMSAPI, …); collection/DB slugs (payload-jobs→cms-jobs,
payload-kv, payload-migrations, payload-preferences, payload-locked-documents);
env vars (PAYLOAD_*→CMS_*); i18n key + values (payloadSettings→cmsSettings, 'Payload
Settings'→'CMS Settings' across 44 languages); CSS @layer/classes; comments/docs/UI.

PRESERVED (deliberate — renaming breaks resolution or law):
- MIT LICENSE + 'Copyright (c) 2018-2025 Payload CMS, Inc.' (legal attribution)
- every import/require/export specifier + path literal; on-disk filenames
  (payload.config.ts, payload-types.ts) + the packages/payload dir; @payload-config alias
- package.json "name" fields (already @hanzo/cms*)
- URLs (payloadcms.com); Redux action.payload (a different, unrelated field)

CONSISTENCY VERIFIED repo-wide: req.payload=0, from 'payload'=0, payloadSettings=0
(all now cms*), Redux action.payload intact, license intact. Individual files
transpile clean.

NOT YET VERIFIED: full type-compilation — requires a 44-package monorepo build
(node_modules absent). Green build is the gate before publish; not claimed here.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-12 17:41:01 -07:00

154 lines
4.3 KiB
TypeScript

import type { CollectionConfig, CMSRequest } from '@hanzo/cms'
import {
getFilePrefix as getDocPrefix,
getFileKey,
} from '@hanzo/cms-plugin-cloud-storage/utilities'
import { getRangeRequestInfo } from '@hanzo/cms/internal'
import type { R2Bucket } from './types.js'
interface GetFileArgs {
bucket: R2Bucket
clientUploadContext?: unknown
collection: CollectionConfig
filename: string
incomingHeaders?: Headers
prefix: string
prefixQueryParam?: string
req: CMSRequest
useCompositePrefixes?: boolean
}
const isMiniflare = process.env.NODE_ENV === 'development'
export async function getFile({
bucket,
clientUploadContext,
collection,
filename,
incomingHeaders,
prefix = '',
prefixQueryParam,
req,
useCompositePrefixes = false,
}: GetFileArgs): Promise<Response> {
try {
const docPrefix = await getDocPrefix({
clientUploadContext,
collection,
filename,
prefixQueryParam,
req,
})
const { fileKey } = getFileKey({
collectionPrefix: prefix,
docPrefix,
filename,
useCompositePrefixes,
})
// Get file size for range validation
const headObj = await bucket?.head(fileKey)
if (!headObj) {
return new Response(null, { status: 404, statusText: 'Not Found' })
}
const fileSize = headObj.size
// Don't return large file uploads back to the client, or the Worker will run out of memory
if (fileSize > 50 * 1024 * 1024 && clientUploadContext) {
return new Response(null, { status: 200 })
}
// Handle range request
const rangeHeader = req.headers.get('range')
const rangeResult = getRangeRequestInfo({ fileSize, rangeHeader })
if (rangeResult.type === 'invalid') {
return new Response(null, {
headers: new Headers(rangeResult.headers),
status: rangeResult.status,
})
}
// Get object with range if needed
// Due to https://github.com/cloudflare/workers-sdk/issues/6047
// We cannot send a Headers instance to Miniflare
const obj =
rangeResult.type === 'partial' && !isMiniflare
? await bucket?.get(fileKey, {
range: {
length: rangeResult.rangeEnd - rangeResult.rangeStart + 1,
offset: rangeResult.rangeStart,
},
})
: await bucket?.get(fileKey)
if (!obj || obj.body == undefined) {
return new Response(null, { status: 404, statusText: 'Not Found' })
}
let headers = new Headers(incomingHeaders)
// Add range-related headers from the result
for (const [headerKey, value] of Object.entries(rangeResult.headers)) {
headers.append(headerKey, value)
}
// Add R2-specific headers
if (isMiniflare) {
// In development with Miniflare, manually set headers from httpMetadata
const metadata = obj.httpMetadata
if (metadata?.cacheControl) {
headers.set('Cache-Control', metadata.cacheControl)
}
if (metadata?.contentDisposition) {
headers.set('Content-Disposition', metadata.contentDisposition)
}
if (metadata?.contentEncoding) {
headers.set('Content-Encoding', metadata.contentEncoding)
}
if (metadata?.contentLanguage) {
headers.set('Content-Language', metadata.contentLanguage)
}
if (metadata?.contentType) {
headers.set('Content-Type', metadata.contentType)
}
} else {
obj.writeHttpMetadata(headers)
}
// Add Content-Security-Policy header for SVG files to prevent executable code
const contentType = headers.get('Content-Type')
if (contentType === 'image/svg+xml') {
headers.set('Content-Security-Policy', "script-src 'none'")
}
const etagFromHeaders = req.headers.get('etag') || req.headers.get('if-none-match')
if (
collection.upload &&
typeof collection.upload === 'object' &&
typeof collection.upload.modifyResponseHeaders === 'function'
) {
headers = collection.upload.modifyResponseHeaders({ headers }) || headers
}
if (etagFromHeaders && etagFromHeaders === obj.etag) {
return new Response(null, {
headers,
status: 304,
})
}
return new Response(obj.body, {
headers,
status: rangeResult.status,
})
} catch (_err: unknown) {
return new Response('Internal Server Error', { status: 500 })
}
}