Skip to content

Upload Service ​

The Upload Service is a Cloudflare Worker that handles Storybook build uploads and tracking.

Features ​

  • Direct Upload - Upload zipped Storybook builds directly
  • Presigned URLs - Generate secure, short-lived URLs for client-side uploads
  • API Key Authentication - Secure project-scoped authentication via Firebase
  • Build Tracking - Automatically track builds in Firestore with version history
  • Auto-incrementing Build Numbers - Each project gets sequential build numbers
  • Processing handoff - Publishes a build event so the build is captured and indexed
  • Story metadata and coverage - Attach what the capture step produced to the build
  • Image uploads - Multi-part image upload with an explicit completion step
  • Cleanup - Remove a build's artifacts, guarded by a separate token
  • OpenAPI - Routes are defined with OpenAPI; Swagger UI is served at /docs
  • Multi-environment Support - Run on Node.js, Docker, or Cloudflare Workers

Architecture ​

src/
├── app.ts              # Shared Hono application logic and routes
├── entry.node.ts       # Entry point for Node.js server
├── entry.worker.ts     # Entry point for Cloudflare Worker
├── middleware/
│   └── auth.ts         # API key authentication middleware
└── services/
    ├── apikey/         # API key service abstraction
    ├── firestore/      # Firestore service for build tracking
    └── storage/        # Storage service abstraction (R2/S3)

Where a build goes next ​

Uploading is only the first half. The service writes the archive to object storage and the build record to Firestore, then publishes an event on the build-processing queue. Processing extracts the archive, captures each story, and writes the search index.

Those complete independently: the build is servable from the CDN as soon as the archive lands, while search results for it appear only once indexing finishes. A successful upload therefore does not mean a searchable build — the build record's status is what tells you where it got to.

Storage Abstraction ​

The service uses a storage abstraction layer for portability:

  • StorageService interface for file storage operations
  • R2S3StorageService implementation for R2/S3 compatible storage
  • Works with Cloudflare R2, AWS S3, or MinIO

API Endpoints ​

MethodEndpointAuthDescription
GET/healthNoHealth check
POST/upload/:project/:versionYesDirect upload
POST/presigned-url/:project/:version/:filenameYesGet presigned URL
GET/upload/:project/:versionNoGet file info

See API Reference for details.

Authentication ​

All upload endpoints require an X-API-Key header:

bash
curl -X POST \
  -H "X-API-Key: scry_proj_my-project_your-api-key-here" \
  -H "Content-Type: application/zip" \
  --data-binary @storybook.zip \
  https://upload.scrymore.com/upload/my-project/v1.0.0

See Authentication for details.

Build Tracking ​

Builds are tracked in Firebase Firestore:

projects/{projectId}/
├── builds/{buildId}
│   ├── id: string
│   ├── projectId: string
│   ├── versionId: string
│   ├── buildNumber: number   # Auto-incrementing
│   ├── zipUrl: string
│   ├── status: 'active' | 'archived'
│   ├── createdAt: Date
│   └── createdBy: string
└── counters/builds
    └── currentBuildNumber: number

Quick Start ​

Using the Hosted Service ​

bash
# Get presigned URL
curl -X POST \
  -H "X-API-Key: scry_proj_xxx" \
  -H "Content-Type: application/zip" \
  https://upload.scrymore.com/presigned-url/my-project/v1.0.0/storybook.zip

# Upload to returned URL
curl -X PUT \
  -H "Content-Type: application/zip" \
  --data-binary @storybook.zip \
  "PRESIGNED_URL_HERE"

Self-Hosting ​

See Deployment for self-hosting instructions.

Next Steps ​