builtin-extensions/serverkit-cloudflare-ops + the tracked frontend live
copy removed; FLAGSHIP_SLUGS is now empty (machinery kept);
plugins-manifest.json empties; the bundled registry entry flips to
bundled:false with the local zip's sha256. cloudflare_ops_bridge resolves
the copy-installed package FIRST so a registry install works without the
builtin registration path.
Tests: new conftest.mount_sibling_extension mirrors a real install from
the sibling checkout (the _wp_support.ensure_plugin analogue) and a
cf_extension fixture forces a private app; the zone-settings and round2
suites mount it autouse (74/74 green), the extraction suite pins the
lean-panel shape, and the flagship-era onboarding tests prove the
machinery with a fabricated member instead.
OPERATOR: publish jhd3197/serverkit-cloudflare-ops, sign,
sync-registry-index.sh.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Moves the Cloudflare per-zone control panel (zone settings, cache purge, WAF,
Workers, Tunnels, R2/KV/D1 storage) out of core into the bundled, default-installed
`serverkit-cloudflare-ops` extension (#36). Much cleaner than WordPress:
- Backend: only 2 files move — `api/cloudflare.py` + `cloudflare_service.py` →
`builtin-extensions/serverkit-cloudflare-ops/backend/` (blueprint keeps
/api/v1/cloudflare, D9; the one intra-extension import made relative). ZERO core
callers (the service's only importer was its own blueprint), so no bridge
accessors are needed for core — `cloudflare_ops_bridge.py` exists only so the
moved test can reach the service by a dash-safe importlib path.
- No duplicate Cloudflare client (the hard constraint): the moved CloudflareService
still borrows the single core CloudflareClient via DNSZoneService._resolve_credential.
The whole DNS layer (dns/cloudflare.py, dns_zone_service, dns_provider_service,
DNSProviderConfig) and the CloudflareWorker/CloudflareTunnel models (FK into
dns_provider_configs) STAY core.
- Flagship (default-installed, uninstallable): added to FLAGSHIP_SLUGS — zero nav
footprint, and the core Domains "Open in Cloudflare" button depends on the route.
- Frontend: a single plain route `cloudflare/zones/:zoneId` contributed via the
manifest + a re-export shim; the page/panels/api-client/SCSS stay in core
(Pattern A). Core App.jsx import + route removed.
- Retired the core blueprint registration; the plugin status guard is the gate.
Verified: 80 tests green (new tests/test_cloudflare_extraction.py + the moved
test_cloudflare_zone_settings.py + the 4 DNS-layer tests that stay core and still
exercise the shared client); npm run lint + build clean; the backend serves the
`cloudflare/zones/:zoneId` route contribution from the seeded flagship row.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>