Skip to content

feat: full-stack deployments — deploy/promote/rollback/logs for Workers-based apps#559

Open
netanelgilad wants to merge 5 commits into
mainfrom
claude/session-m669xy
Open

feat: full-stack deployments — deploy/promote/rollback/logs for Workers-based apps#559
netanelgilad wants to merge 5 commits into
mainfrom
claude/session-m669xy

Conversation

@netanelgilad

@netanelgilad netanelgilad commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Note

Description

This PR adds first-class support for full-stack deployments — hosting framework builds (React Router 7, TanStack Start, Astro 6, vinext, anything built with @cloudflare/vite-plugin) as Cloudflare Workers on Base44. It introduces a new src/core/deployments/ module that detects the wrangler artifact, hashes and uploads static assets, collects Worker modules, and drives the create → upload → finalize API flow. The base44 deploy command now automatically prefers this Workers path over the legacy site tar.gz upload when an artifact is present, and new deployments, promote, rollback, and domains commands round out the lifecycle. It also adds custom domain management (base44 domains add/list/remove) and extends base44 logs to stream deployment logs.

Related Issue

None

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Other (please describe):

Changes Made

Full-stack deployments (src/core/deployments/)

  • wrangler-config.ts — detects the deploy artifact via .wrangler/deploy/config.json redirect, root wrangler.json(c), or errors on unsupported wrangler.toml; validates no_bundle: true and rejects unsupported bindings while passing vars through. Handles Astro 6 quirks (empty compatibility_flags, extra redirect-file fields).
  • manifest.ts — walks the assets directory, applies .assetsignore, and hashes files as sha256(app_id || bytes) (app-id-salted to prevent cross-tenant cache poisoning), with 25 MiB per-file and 100k file caps.
  • modules.ts — collects Worker modules per the wrangler rules globs, including source maps, capped at 40 MB.
  • upload.ts — uploads asset buckets directly to the signed upload_url (base64 multipart, bearer JWT, concurrency 3 with retries/backoff).
  • api.ts / deploy.ts / schema.ts — the create → bucket upload → finalize flow, plus list/get/promote/rollback/logs API calls with Zod schemas.

CLI commands

  • Extended base44 deploy with --prod, --build, and --prebuilt flags; builds when configured and routes to the full-stack path when an artifact exists (legacy behavior unchanged otherwise).
  • Added base44 deployments list / get <id>, base44 promote <id>, and base44 rollback [-y].
  • Added base44 domains add/list/remove (src/core/domains/) with live status polling for connecting custom domains.
  • Extended base44 logs with --deployment <id|production> and live --follow streaming.
  • Wired all new commands into program.ts; added error classes in core/errors.ts.

Docs & tests

  • New docs/deployments.md topic guide; updated docs/AGENTS.md, docs/resources.md, docs/testing.md.
  • Extended TestAPIServer testkit with deployment/asset-upload/finalize/promote/rollback/logs mocks and a fullstack-project fixture.
  • Added CLI integration specs (deployments, domains, fullstack_deploy, logs_deployment) and core unit specs (manifest, modules, wrangler-config).

Testing

  • I have tested these changes locally
  • I have added/updated tests as needed
  • All tests pass (npm test)

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (if applicable)
  • My changes generate no new warnings
  • I have updated docs/ (AGENTS.md) if I made architectural changes

Additional Notes

Full-stack support is limited to no_bundle: true outputs with no non-vars bindings; wrangler.toml and bundled outputs fail fast with clear errors. The legacy site tar.gz deploy path is preserved unchanged for apps without a full-stack artifact. A follow-up commit greens CI (knip dead exports, Windows fixture line-endings, Bun binary charset).


🤖 Generated by Claude | 2026-07-06 14:37 UTC | 1712ae1

…rs-based apps

Add first-class full-stack (Cloudflare Workers) deployments to the CLI,
targeting the new app-scoped deployments API:

- core/deployments/: wrangler config resolution (.wrangler/deploy/config.json
  redirect + root wrangler.jsonc fallback, toml rejected, no_bundle required,
  binding policing), app-id-salted asset manifest hashing (sha256, 32 hex
  chars, .assetsignore support, 25 MiB/100k caps), module collection from
  rules globs (sourcemaps, 40 MB cap), direct bucket uploads (concurrency 3,
  retry with backoff, 401 session-expired handling), and the create/finalize/
  list/get/promote/rollback/logs API surface with Zod-validated responses.
- deploy command: detects a full-stack artifact after the resource pushes and
  routes it through the deployments API instead of the legacy site tar.gz;
  --prod/--build/--prebuilt flags; wrangler-style progress; --json emits
  {deploymentId, target, urls}. Legacy behavior unchanged otherwise.
- new commands: deployments list/get, promote <id>, rollback [-y].
- logs --deployment <id|production> with all existing filters + --follow.
- testkit mocks (create/asset-upload/finalize/list/get/promote/rollback/logs)
  with request capture, fullstack-project fixture, 25 unit + 25 CLI tests.
- docs/deployments.md topic guide, linked from AGENTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvhQfqxACcq25XAQRpoSh9
@netanelgilad netanelgilad self-assigned this Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/cli@0.1.1-pr.559.d9cc6f9

Prefer not to change any import paths? Install using npm alias so your code still imports base44:

npm i "base44@npm:@base44-preview/cli@0.1.1-pr.559.d9cc6f9"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "base44": "npm:@base44-preview/cli@0.1.1-pr.559.d9cc6f9"
  }
}

Preview published to npm registry — try new features instantly!

claude added 2 commits July 6, 2026 10:44
…, prerender redirect field)

Two corrections from live testing against real framework output:

- Warn when the resolved wrangler config lacks the nodejs_compat
  compatibility flag (Astro 6 can generate an empty compatibility_flags);
  the flag is not injected since the fix belongs in the framework's
  adapter settings. Surfaced via a new onWarning progress callback.
- Document + pin with a test that extra redirect-file fields
  (auxiliaryWorkers, Astro 6's prerenderWorkerConfigPath) are ignored
  (the redirect schema is a looseObject).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvhQfqxACcq25XAQRpoSh9
Add a `base44 domains` command family for connecting custom domains to
deployed full-stack apps (Cloudflare-for-SaaS custom hostnames), part of
the full-stack hosting POC.

core/domains:
- addDomain / listDomains / removeDomain via the app client with Zod
  snake→camel transforms and ApiError.fromHttpError.
- waitForDomainActive: polls listDomains until the hostname + SSL are
  active; TimeoutError (new UserError) when it never activates.

cli/commands/domains:
- `domains add <hostname>` prints the exact DNS record (CNAME <hostname>
  → <cname-target>) and current status; `--wait` polls until the domain
  and its TLS cert are active with a spinner.
- `domains list` (padded table), `domains remove <hostname>` (confirm,
  -y in non-interactive). All honor the global --json contract.

Registered getDomainsCommand() in program.ts. Added testkit mocks
(mockDomainAdd/List/Remove + error variants) and domains.spec.ts in the
Given/When/Then style.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvhQfqxACcq25XAQRpoSh9
claude added 2 commits July 6, 2026 14:36
… binary charset

- Drop unused exports flagged by knip (WaitForDomainOptions, DomainVerification,
  mockDomainListError).
- Pin test fixtures to LF via .gitattributes: the deploy tests hash fixture
  bytes, and autocrlf checkout on Windows changed the bytes so the manifest
  hashes never matched the mocked upload buckets.
- Accept the charset suffix Bun's compiled binary adds to multipart part
  content types (text/html;charset=utf-8).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvhQfqxACcq25XAQRpoSh9
Add a `base44 slug` command family for the app's URL slug — its public
subdomain (`<slug>.base44.app`), which the production URL follows.

core/slug:
- getSlug reads the slug from the app document (GET api/apps/{id});
  updateSlug PATCHes api/apps/{id}/metadata/slug ({slug} or {slug: null}
  to reset to the auto-generated slug), both Zod-validated.
- When a requested slug is already in use, the API's 400 body includes
  alternative suggestions — surfaced as a hint on the thrown ApiError.

cli/commands/slug:
- `slug` (default action) shows the current slug + app URL (via the
  existing published-url endpoint); `slug set <slug>` prints old → new
  slug and the resulting production URL; `slug reset` prints the newly
  auto-generated slug. All honor the global --json contract.
- allowExcessArguments(false) so a mistyped subcommand errors instead
  of silently showing the current slug.

Registered getSlugCommand() in program.ts. Added testkit support for
PATCH routes plus mockAppGet/mockSlugUpdate(+Error) mocks, and
slug.spec.ts in the Given/When/Then style (show/set/reset, invalid
format 400, taken slug with suggestions, server error).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DvhQfqxACcq25XAQRpoSh9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants