Deep under the waves and storms there lies a vault...
- Multi-version API Support (v1, v2, v3)
- Slack Bot Integration
- Upload up to 10 files per message
- Automatic file sanitization
- file organization
- Secure API Endpoints
- Cost-Effective Storage (87-98% cost reduction vs. Vercel CDN)
- Prevent File Deduplication
- Organized Storage Structure
- Create a new Slack App at api.slack.com
- Add the following Bot Token Scopes:
channels:history
channels:read
chat:write
files:read
files:write
groups:history
reactions:write
- Enable Event Subscriptions:
- Set Request URL to
https://your-domain.com/slack/events
- Subscribe to
file_shared
event
- Set Request URL to
- Install the app to your workspace
This CDN supports any S3-compatible storage service. Here's how to set it up using Cloudflare R2 as an example:
-
Create R2 Bucket
- Go to Cloudflare Dashboard > R2
- Click "Create Bucket"
- Name your bucket
- Enable public access
-
Generate API Credentials
- Go to R2
- Click "Manage API tokens" in API
- Click "Create API Token"
- Permissions: "Object Read & Write"
- Save both Access Key ID and Secret Access Key (S3)
-
Get Your URL
- Go to R2
- Click "Use R2 with APIs" in API
- Select S3 Compatible API
- The URL is your Endpoint
-
Configure Custom Domain (Optional)
- Go to R2 > Bucket Settings > Custom Domains
- Add your domain (e.g., cdn.beans.com)
- Follow DNS configuration steps
Create a .env
file with:
# Slack
SLACK_BOT_TOKEN=xoxb- # From OAuth & Permissions
SLACK_SIGNING_SECRET= # From Basic Information
SLACK_CHANNEL_ID=channel-id # Channel where bot operates
# S3 Config CF in this example
AWS_ACCESS_KEY_ID=1234567890abcdef
AWS_SECRET_ACCESS_KEY=abcdef1234567890
AWS_BUCKET_NAME=my-cdn-bucket
AWS_REGION=auto
AWS_ENDPOINT=https://<accountid>.r2.cloudflarestorage.com
AWS_CDN_URL=https://cdn.beans.com
# API
API_TOKEN=beans # Set a secure random string
PORT=3000
Make sure you have Bun installed, then run:
bun install
You can start the application using any of the following methods:
# Using Node.js
node index.js
# Using Bun
bun index.js
# Using Bun with script
bun run start
For auto-starting the application, you can use PM2:
pm2 start bun --name "HC-CDN1" -- run start
# Optionally, save the process list
pm2 save
# Optionally, generate startup script
pm2 startup
- All API endpoints require authentication via
Authorization: Bearer api-token
header - This includes all versions (v1, v2, v3) - no exceptions!
- Use the API_TOKEN from your environment configuration
- Failure to include a valid token will result in 401 Unauthorized responses
Endpoint: POST https://e2.example.hackclub.app/api/v3/new
Headers:
Authorization: Bearer api-token
Content-Type: application/json
Request Example:
curl --location 'https://e2.example.hackclub.app/api/v3/new' \
--header 'Authorization: Bearer beans' \
--header 'Content-Type: application/json' \
--data '[
"https://assets.hackclub.com/flag-standalone.svg",
"https://assets.hackclub.com/flag-orpheus-left.png",
"https://assets.hackclub.com/icon-progress-marker.svg"
]'
Response:
{
"files": [
{
"deployedUrl": "https://cdn.example.dev/s/v3/3e48b91a4599a3841c028e9a683ef5ce58cea372_flag-standalone.svg",
"file": "0_16361167e11b0d172a47e726b40d70e9873c792b_upload_1736985095691",
"sha": "16361167e11b0d172a47e726b40d70e9873c792b",
"size": 90173
},
{
"deployedUrl": "https://cdn.example.dev/s/v3/4e48b91a4599a3841c028e9a683ef5ce58cea372_flag-orpheus-left.png",
"file": "1_16361167e11b0d172a47e726b40d70e9873c792b_upload_1736985095692",
"sha": "16361167e11b0d172a47e726b40d70e9873c792b",
"size": 80234
},
{
"deployedUrl": "https://cdn.example.dev/s/v3/5e48b91a4599a3841c028e9a683ef5ce58cea372_icon-progress-marker.svg",
"file": "2_16361167e11b0d172a47e726b40d70e9873c792b_upload_1736985095693",
"sha": "16361167e11b0d172a47e726b40d70e9873c792b",
"size": 70345
},
{
"deployedUrl": "https://cdn.example.dev/s/v3/6e48b91a4599a3841c028e9a683ef5ce58cea372_flag-orpheus-right.png",
"file": "3_16361167e11b0d172a47e726b40d70e9873c792b_upload_1736985095694",
"sha": "16361167e11b0d172a47e726b40d70e9873c792b",
"size": 60456
}
],
"cdnBase": "https://cdn.example.dev"
}
V2 API
Endpoint: POST https://e2.example.hackclub.app/api/v2/new
Headers:
Authorization: Bearer api-token
Content-Type: application/json
Request Example:
[
"https://assets.hackclub.com/flag-standalone.svg",
"https://assets.hackclub.com/flag-orpheus-left.png",
"https://assets.hackclub.com/icon-progress-marker.svg"
]
Response:
{
"flag-standalone.svg": "https://cdn.example.dev/s/v2/flag-standalone.svg",
"flag-orpheus-left.png": "https://cdn.example.dev/s/v2/flag-orpheus-left.png",
"icon-progress-marker.svg": "https://cdn.example.dev/s/v2/icon-progress-marker.svg"
}
V1 API
Endpoint: POST https://e2.example.hackclub.app/api/v1/new
Headers:
Authorization: Bearer api-token
Content-Type: application/json
Request Example:
[
"https://assets.hackclub.com/flag-standalone.svg",
"https://assets.hackclub.com/flag-orpheus-left.png",
"https://assets.hackclub.com/icon-progress-marker.svg"
]
Response:
[
"https://cdn.example.dev/s/v1/0_flag-standalone.svg",
"https://cdn.example.dev/s/v1/1_flag-orpheus-left.png",
"https://cdn.example.dev/s/v1/2_icon-progress-marker.svg"
]
- Multi-file Upload: Upload up to 10 files in a single message no more than 3 messages at a time!
- File Organization: Files are stored as
/s/{slackUserId}/{timestamp}_{sanitizedFilename}
- Error Handling: Error Handeling
- File Sanitization: Automatic filename cleaning
- Size Limits: Enforces files to be under 2GB
- V1 and V2 APIs are maintained for backwards compatibility
- All versions now require authentication via Bearer token
- We recommend using V3 API for new implementations
- Storage Structure:
/s/v3/{HASH}_{filename}
- File Naming:
/s/{slackUserId}/{unix}_{sanitizedFilename}
- Cost Efficiency: Uses object storage for significant cost savings
- Security: Token-based authentication for API access
- Reacts to file uploads with status emojis:
- β³ Processing
- β Success
- β Error
- Supports up to 10 files per message
- Max 3 messages concurrently!
- Maximum file size: 2GB per file
- Uses Object storage
- 87-98% cost reduction compared to Vercel CDN