Files
ServerKit/backend/app/models/cloudflare_worker.py
T
Juan DenisandClaude Opus 4.8 02774f741e feat(cloudflare): Workers edge hosting (Phase 4)
Add a Workers tab to the Cloudflare Zone Settings page for deploying edge
scripts and managing Worker routes. Workers are account-scoped, so the owning
account is resolved from the zone — the whole feature reuses the existing
Cloudflare DNS connection (no new credential).

- CloudflareWorker model: records the source ServerKit uploaded per (account,
  name) so a worker can be tracked and re-deployed (created via create_all).
- CloudflareClient: zone→account lookup, list/delete scripts, and a stable
  multipart PUT /scripts/{name} module upload (the still-beta resource-oriented
  Workers API is deliberately avoided per the roadmap's fallback note), plus
  zone Worker routes list/add/delete.
- CloudflareService: list (live scripts flagged when ServerKit-managed + routes),
  deploy (validated lowercase name, records source, optional route attach),
  delete, route add/delete.
- /api/v1/cloudflare/zones/:id/workers* routes (read any user; writes admin).
- WorkersPanel component (deploy form with a starter script, worker list, routes
  list); api methods; SCSS.

Tests: multipart upload shape, name validation, deploy records source, list
managed-flagging, delete prunes the local row (5).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 20:27:36 -04:00

42 lines
1.7 KiB
Python

from datetime import datetime
from app import db
class CloudflareWorker(db.Model):
"""A Cloudflare Worker (edge script) ServerKit uploaded.
Cloudflare is the source of truth for what's deployed; this table records the
source we pushed (so it can be viewed and re-deployed) and which connection it
belongs to. Keyed by ``(account_id, name)`` — a script name is unique per
account.
"""
__tablename__ = 'cloudflare_workers'
__table_args__ = (
db.UniqueConstraint('account_id', 'name', name='uq_cf_worker_account_name'),
)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), nullable=False, index=True) # script name
account_id = db.Column(db.String(64), nullable=False)
dns_provider_config_id = db.Column(
db.Integer, db.ForeignKey('dns_provider_configs.id'), nullable=True)
source = db.Column(db.Text) # JS module we uploaded
compatibility_date = db.Column(db.String(20))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def to_dict(self, include_source=False):
d = {
'id': self.id,
'name': self.name,
'account_id': self.account_id,
'dns_provider_config_id': self.dns_provider_config_id,
'compatibility_date': self.compatibility_date,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
}
if include_source:
d['source'] = self.source
return d