Warning
Deprecated project. divine-cdn-worker has been replaced by divine-blossom and is no longer the active media relay implementation.
Use divine-blossom for current development and production changes.
Experimental Cloudflare Worker implementation using blossom-server-sdk.
This worker implements the Blossom protocol for blob storage using:
- blossom-server-sdk - Core Blossom protocol abstractions
- Cloudflare R2 - Blob storage backend
- Cloudflare KV - Metadata storage backend
blossom-sdk-worker/
├── src/
│ ├── index.mjs # Main worker entry point
│ └── storage/
│ ├── r2-blob-storage.mjs # R2 storage adapter
│ └── kv-metadata-store.mjs # KV metadata adapter
├── package.json
├── wrangler.toml
└── README.md
- Uses SDK abstractions - Implements
IBlobStorageandIBlobMetadataStoreinterfaces - Cleaner separation - Storage logic is separated from request handling
- Experimental - Testing how well the SDK works with Cloudflare Workers
cd blossom-sdk-worker
npm installnpm test50+ tests covering all endpoints, authentication, and upload strategies.
./test-live.shAutomated test script that validates all endpoints against staging.
See TESTING.md for comprehensive testing guide.
npm run dev# Production
npm run deployProduction: https://blossom.divine.video
Test it:
# Homepage with API docs
curl https://blossom.divine.video/
# List blobs
curl https://blossom.divine.video/list/0000000000000000000000000000000000000000000000000000000000000000
# Upload (requires signed Nostr event, kind 24242)
# See BLOSSOM_CLIENT_SPEC.md for complete authentication detailsFor client implementation details, see BLOSSOM_CLIENT_SPEC.md.
GET /<sha256>- Retrieve blobHEAD /<sha256>- Check blob existencePUT /uploadorPOST /upload- Upload blob (requires Nostr authentication)GET /list/<pubkey>- List user's blobsDELETE /<sha256>- Delete blob (requires owner authentication)GET /video-status/<sha256>- Check video processing statusPOST /webhooks/bunny- BunnyStream encoding webhooks
See BLOSSOM_CLIENT_SPEC.md for complete API documentation.
Implements IBlobStorage interface for Cloudflare R2:
hasBlob(sha256)- Check if blob existsreadBlob(sha256)- Read blob datawriteBlob(sha256, stream, mimeType)- Write blobremoveBlob(sha256)- Delete blob
Implements IBlobMetadataStore interface for Cloudflare KV:
hasBlob(sha256)- Check if metadata existsgetBlob(sha256)- Get blob metadataaddBlob(blob)- Add blob metadataremoveBlob(sha256)- Delete blob metadataaddBlobOwner(sha256, pubkey)- Associate ownergetBlobsForPubkey(pubkey)- List user's blobs
For legacy video thumbnail support, the worker needs to fetch thumbnails from Cloudflare Stream.
IMPORTANT: The Stream customer subdomain is NOT based on your account ID. You must configure STREAM_CUSTOMER_DOMAIN explicitly in wrangler.toml:
[vars]
STREAM_CUSTOMER_DOMAIN = "customer-4c3uhd5qzuhwz9hu.cloudflarestream.com"To find your Stream customer domain:
- Go to Cloudflare Dashboard → Stream
- Click on any video
- Look at the video URL, it will be in the format:
https://customer-XXXXXXXXXX.cloudflarestream.com/VIDEO_ID/... - Use the full subdomain (e.g.,
customer-XXXXXXXXXX.cloudflarestream.com)
Common mistake: Trying to construct the domain from the account ID (e.g., customer-${ACCOUNT_ID}.cloudflarestream.com) will result in 404 errors for thumbnail requests.
All authenticated endpoints require proper Nostr event signatures (kind 24242):
- Production: Full signature verification enabled using @noble/curves
- Development: Can bypass with
DEV_AUTH_MODE=trueand simple pubkey auth
See SECURITY_FIX_SUMMARY.md for security audit details.
- ✅ Full NIP-01 signature verification (Schnorr/BIP-340)
- ✅ Event ID validation
- ✅ SHA-256 hash verification for uploads
- ✅ Content moderation integration
- ✅ ProofMode support for verified media
- ✅ Secure by default (DEV_AUTH_MODE=false in production)
CHANGELOG.md- Version history and release notesBLOSSOM_CLIENT_SPEC.md- Complete API specification for client developersSECURITY_FIX_SUMMARY.md- Security audit and fix documentation
- Performance comparison vs main worker
- Evaluate SDK benefits vs custom implementation
- Add rate limiting
- Add metrics/observability