Skip to content

feat(cloudflare): credential-free alchemy dev - #1066

Open
sam-goodwin wants to merge 2 commits into
mainfrom
claude/credential-free-dev
Open

feat(cloudflare): credential-free alchemy dev#1066
sam-goodwin wants to merge 2 commits into
mainfrom
claude/credential-free-dev

Conversation

@sam-goodwin

Copy link
Copy Markdown
Contributor

alchemy dev now runs with zero Cloudflare configuration when every resource resolves to a local provider — no profile, no env vars, no login. Credentials are demanded lazily, exactly once, and only when the plan actually needs the real cloud.

# fresh machine, nothing configured
bun alchemy dev   # plans, applies, serves — entirely local

:::caution
Cloudflare.state() now resolves to a local file store (.alchemy/state) whenever alchemy dev runs. Dev and deploy states become disjoint for Cloudflare.state() users: a deploy after dev creates fresh resources instead of mode-replacing dev rows (which only ever described machine-local emulator instances). This matches what Alchemy.localState() users already have.
:::

Plan-time credential demand

After plan resolution, the dev path scans for genuine cloud needs — live-mode nodes (Alchemy.remote()), bindings opted out via dev: { remote: true }, and deletes of live-stamped rows. Only then does it run the existing profile setup flow, interactively, with the reason spelled out:

This dev session requires Cloudflare credentials:
  - LiveKV (runs against the real cloud via Alchemy.remote())

Non-interactive runs fail with a typed CredentialsRequired naming the resources and pointing at alchemy login. The RPC sidecar never prompts — it reads the credentials the exec process persisted.

Local providers no longer force accountId

Seven capability *Local layers deferred (they only needed the account for an HTTP branch never taken for dev: ids), and local providers now stamp accountId opportunistically through a non-forcing probe. The replace-on-account-drift rule fires only when both old and new accounts are known — so resources created credential-free are not replaced (and their data not destroyed) on the first run after login.

Proof

examples/cloudflare-dev/test/credential-free.test.ts runs the real CLI with a scrubbed HOME, no CLOUDFLARE_* env, and no profile: dev boots, the worker serves, rows land in the local store. Plus 22 new engine tests (demand detector matrix, drift rule, dev-state selection) and the existing local/live suites re-verified green.

Also fixes a latent Test.make bug: the dev context override was applied inside the state layer, so Test.make({ dev: true, state: Cloudflare.state() }) built state seeing dev: false.

🤖 Generated with Claude Code

sam-goodwin and others added 2 commits August 3, 2026 18:17
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alchemy dev now runs with no Cloudflare profile configured when every
resource resolves to a local provider. Credentials are demanded lazily,
exactly once, in the tty-owning process, only when the plan needs the
cloud — and Cloudflare.state() resolves to a local file store in dev.

- plan-time demand seam: collectCredentialDemands scans the plan for
  live-mode nodes, devRemote bindings, and live-stamped deletes; the
  demand runs loadOrConfigure interactively (with a reason naming the
  resources) or fails typed (CredentialsRequired) non-interactively with
  alchemy login guidance. The RPC sidecar never prompts — it reads
  credentials persisted by the exec process.
- accountId is lazy everywhere local: 7 capability *Local layers defer
  resolution to the never-taken-for-dev HTTP branch; local providers
  stamp accountId opportunistically via a non-forcing probe and replace
  on account drift only when BOTH sides are defined (a credential-free
  session's resources survive the first post-login run); the local
  worker injects ALCHEMY_CLOUDFLARE_ACCOUNT_ID only when known.
- Cloudflare.state() under dev always uses the local file store
  (.alchemy/state, telemetry id cloudflare-dev-local), skipping the
  cloud init entirely; dev and deploy states are disjoint for
  Cloudflare.state() users (documented).
- Test.make now applies the dev context override OUTSIDE the state
  layer, matching the CLI (it previously built state seeing dev: false).
- e2e proof: examples/cloudflare-dev/test/credential-free.test.ts runs
  the real CLI with a scrubbed HOME, no CLOUDFLARE_* env, and no
  profile — dev boots, the worker serves, state goes local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@alchemy-version-bot

Copy link
Copy Markdown
Contributor

Install the packages built from this commit:

alchemy

bun add alchemy@https://pkg.ing/alchemy/e5cb2c2

@alchemy.run/better-auth

bun add @alchemy.run/better-auth@https://pkg.ing/@alchemy.run/better-auth/e5cb2c2

@alchemy.run/pr-package

bun add @alchemy.run/pr-package@https://pkg.ing/@alchemy.run/pr-package/e5cb2c2

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.

1 participant