- Create `docs/storage-tab-design.md` covering StorageService architecture - Update `docs/storage-r2.md` to reflect the new provider pattern - Expand Kind 22242 details in `docs/nostr-event-schemas.md`
4.5 KiB
Cloudflare R2 integration (r2Service)
Purpose and scope
js/services/r2Service.js is the specialized provider handler for Cloudflare R2 uploads. While the new Storage Tab (powered by StorageService) manages the secure storage of credentials, r2Service is responsible for:
- Uploading the selected video/HLS asset via multipart S3 uploads.
- Verifying public access via the configured Public Bucket URL.
- Publishing the resulting public URL into the video note payload.
Architecture Note: For the high-level design of credential storage, encryption, and the provider adapter pattern, please refer to
docs/storage-tab-design.md.
Assets stored in R2
R2 is used as the URL-first playback source. The upload path supports a single file per upload, but file types include:
- Video files (MP4/WebM/MOV/MKV/MPG/MPEG).
- HLS/DASH assets (manifest
.m3u8/.mpdand segment files like.ts/.m4s). - Related static media if the operator chooses to upload them separately (images, subtitles such as
.vtt/.srt), which benefit from cache-friendly headers set in the upload flow.
The object key format is generated by buildR2Key() in js/r2.js and looks like:
u/<npub>/<YYYY>/<MM>/<slug>.<ext>, which keeps uploads scoped by user and month.
Setup Guide: Getting your Cloudflare Credentials
To enable R2 uploads, you must provide Cloudflare S3-compatible credentials and configure your bucket for public access and CORS.
Step 1: Create Bucket & Enable Public Access
- Log in to the Cloudflare Dashboard.
- Navigate to R2 -> Create Bucket.
- In the bucket settings, enable Public Access (R2.dev subdomain) or connect a custom domain.
- Copy the Public Bucket URL (e.g.,
https://pub-xxxxxx.r2.dev).
Step 2: Configure CORS
Manually add a CORS policy in the bucket settings to allow uploads from your app's origin (or *).
(See content/upload-content.md for the recommended JSON configuration).
Step 3: Create S3 Credentials
- In the R2 dashboard, click Manage R2 API Tokens.
- Click Create API Token.
- Select Object Read & Write permissions (Minimal).
- Copy the Account ID, Access Key ID, and Secret Access Key.
Step 4: Configure the App
- Open the Storage Tab (in Profile or Upload modal).
- Add a new connection and select Cloudflare R2.
- Enter the Account ID, Access Key ID, Secret Access Key, and Public Bucket URL.
- Click Verify & Save.
The app will attempt to upload a small test file to verify the credentials and public access configuration.
Upload lifecycle
-
Credential Retrieval:
- When an upload starts,
UploadModalretrieves the decrypted credentials fromStorageService. StorageServicehandles the NIP-44/04 decryption of the Master Key and subsequent decryption of the R2 connection payload.
- When an upload starts,
-
Upload Execution:
r2Service.multipartUpload()uses the standard AWS SDK commands (CreateMultipartUpload,UploadPart, etc.) via the genericmakeR2Clientadapter.- The adapter automatically constructs the R2 endpoint (
https://<accountId>.r2.cloudflarestorage.com) using the storedaccountId.
-
Publish:
- On success,
publishVideoNote()is called with the hosted URL, enabling URL-first playback.
- On success,
Configuration keys
R2 credentials are no longer stored in plain bitvidSettings. They are encapsulated within the StorageService data model.
R2 Connection Profile (Encrypted):
provider:cloudflare_r2accountId: Cloudflare account ID.accessKeyId: S3 access key ID.secretAccessKey: S3 secret access key.bucket: The target bucket name.
Metadata (Plaintext):
baseDomain: The Public Bucket URL (e.g.,https://pub-xxxx.r2.dev).defaultForUploads: Boolean flag indicating if this is the active upload target.
Environment / global flags
globalThis.__BITVID_DISABLE_NETWORK_IMPORTS__: disables the AWS SDK network import used by the R2 S3 client loader (js/storage/r2-s3.js). When true, uploads will fail with a load error until the SDK is bundled or otherwise provided.
Security considerations
- Encrypted Storage: All sensitive keys (
accessKeyId,secretAccessKey) are encrypted at rest using the user's Nostr signer. - Session Security: Decrypted keys exist in memory only during the active session.
- Public Exposure: The generated playback URLs are public. Ensure your bucket permissions match your intent.
- Least Privilege: Always use "Object Read & Write" tokens rather than Admin tokens.