Edge CDN + Security Gateway for R2/S3 storage, deployable as Cloudflare Workers or Pages.
- CDN Caching — Edge caching via Cloudflare Cache API with
Cache-Control,ETag,stale-while-revalidate - Security Layer — Signed URLs (HMAC-SHA256), Referer/Origin whitelisting, Hotlink protection
- Dual Runtime — Deploy as Workers (via
wrangler.jsonc) or Pages (via Dashboard + Functions) - Storage Driver Abstraction — Currently R2 binding, future support for S3-compatible (B2, AWS, MinIO)
- Modular Monorepo — Turborepo-powered with shared
@ceefex/flared-object-core,@ceefex/flared-object-ui, and@ceefex/flared-object-client
pnpm install
pnpm dev:worker # Start Worker dev server
pnpm dev:pages # Start Pages dev serverConfigure via SECURITY_MODE environment variable:
| Mode | Description |
|---|---|
none |
Open access (default) |
signed-url |
HMAC-SHA256 signed URL required |
referer |
Referer/Origin whitelist |
signed-url+referer |
Both required |
Generate a strong random secret (32 bytes / 256 bits) with OpenSSL:
openssl rand -hex 32Copy the output and store it as a secret, not as a plain environment variable or in source control. For a Cloudflare Worker, run this from the repository root and paste the generated value when prompted:
pnpm --filter @ceefex/flared-object-worker exec wrangler secret put HMAC_SECRETFor the named Worker preview environment, set its secret separately:
pnpm --filter @ceefex/flared-object-worker exec wrangler secret put HMAC_SECRET --env previewFor Cloudflare Pages, add HMAC_SECRET as a secret in the Pages project's environment settings. Configure it separately for Production and Preview as needed. Use the same secret for URL generation and validation in each environment, and never expose it to browsers or include it in a URL.
URL format: /path/to/file.jpg?token=<hmac>&expires=<unix_ts>
expires is a Unix timestamp in seconds: the number of seconds since 1970-01-01 UTC at which the URL expires. When generateSignedUrl creates a URL, it calculates this as the current system time plus the requested lifetime (ttlSeconds). The URL generator includes both expires and an HMAC signature of the path and expiry time; the Worker or Pages Function checks the timestamp against its current time and recomputes the signature using HMAC_SECRET on each request.
This is stateless: no issuance or expiry record is stored in a database. The expiry timestamp travels in the URL, and the signature prevents changing it without the secret. A valid URL can be reused until it expires; to revoke URLs earlier, rotate the secret (which invalidates URLs signed with the old secret). Ensure the system generating URLs and the Cloudflare runtime have reasonably accurate clocks.
Set the runtime variable ALLOWED_REFERERS as a JSON array in the Cloudflare Worker or Pages project settings:
["example.com", "*.example.com"]This project supports two Cloudflare runtime targets: Standalone Worker and Cloudflare Pages. Both can be deployed automatically via Git or manually via CLI.
The Cloudflare Workers Builds CI/CD pipeline separates build and deploy into two distinct steps:
- Build Step (
pnpm build:worker): Executesscripts/build/index.ts, generatingapps/worker/wrangler.deploy.jsoncfrom build-time environment variables. - Deploy Step (
pnpm deploy:worker): Runswrangler deploy --config wrangler.deploy.jsoncto deploy the Worker.
- Root directory:
/ - Build command:
pnpm build:worker - Deploy command:
pnpm deploy:worker - Preview / Version command:
pnpm deploy:worker:preview
Configured under Settings → Build variables:
| Variable | Purpose |
|---|---|
DEPLOY_WORKER_NAME |
Production Worker name (e.g. flared-object-media) |
DEPLOY_WORKER_PREVIEW_NAME |
Named preview Worker name (e.g. flared-object-media-preview) |
DEPLOY_R2_BUCKET_NAME |
Production R2 bucket name |
DEPLOY_R2_PREVIEW_BUCKET_NAME |
Named preview environment R2 bucket |
DEPLOY_R2_BUILDS_PREVIEW_BUCKET_NAME |
Workers Builds Preview R2 bucket |
Configured under Settings → Variables and secrets:
| Setting | Type | Purpose |
|---|---|---|
SECURITY_MODE |
Variable | none, signed-url, referer, or signed-url+referer |
ALLOWED_REFERERS |
Variable | JSON array of allowed referer hostnames, for example ["example.com", "*.example.com"] |
HMAC_SECRET |
Secret | HMAC secret key required for signed URL modes |
Cloudflare Pages serves static assets from apps/pages/public/ and executes Edge Functions from apps/pages/functions/.
- Framework preset:
None - Root directory:
apps/pages - Build command:
pnpm build(runswrangler pages functions build functionsto validate the TypeScript functions bundle) - Build output directory:
public
Note: If Root Directory is set to
/(repository root), use Build Command:pnpm build:pagesand Output Directory:apps/pages/public.
Configured under Settings → Functions → Compatibility flags & Settings → Bindings:
- R2 Bucket Binding:
- Binding name:
MEDIA_BUCKET(select the R2 bucket for Production and Preview).
- Binding name:
- Environment Variables & Secrets:
SECURITY_MODE:none,signed-url,referer, orsigned-url+refererALLOWED_REFERERS: JSON array of allowed referer hostnamesHMAC_SECRET: Secret key for HMAC signed URL validation
To deploy directly from your local machine:
# Worker
pnpm build:worker # Generate wrangler.deploy.jsonc
pnpm deploy:worker # Deploy production Worker
pnpm deploy:worker:preview # Deploy preview Worker
# Pages
pnpm build:pages # Validate Pages functions bundle
pnpm deploy:pages # Deploy production Pages
pnpm deploy:pages:preview # Deploy Pages preview branchpackages/core/ — Shared logic (drivers, security, cache, pipeline)
packages/ui/ — Error pages & branding (from komikhq/media)
apps/worker/ — Cloudflare Worker runtime
apps/pages/ — Cloudflare Pages Functions runtime