Skip to content

fix(cloudflare): beta.61 integration bug reports — nodejs_compat default, StaticSite Config env, vite main resolution#796

Open
sam-goodwin wants to merge 2 commits into
mainfrom
claude/alchemy-cloudflare-bugs-4f2db7
Open

fix(cloudflare): beta.61 integration bug reports — nodejs_compat default, StaticSite Config env, vite main resolution#796
sam-goodwin wants to merge 2 commits into
mainfrom
claude/alchemy-cloudflare-bugs-4f2db7

Conversation

@sam-goodwin

@sam-goodwin sam-goodwin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Fixes for the beta.61 integration bug reports from create-better-t-stack (repros). Every fix was verified by deploying the corresponding repro against a real Cloudflare account.

2. Default nodejs_compat never reached plain Workers

Cloudflare.Worker("w", { main }) (no Effect impl) sets isExternal: true, and getCompatibility only added the default nodejs_compat for Effect-native Workers — so a plain Worker importing node:crypto bundled fine and then failed upload with ScriptModuleNotFound. The default now applies to all Workers, gated on compatibility.date >= 2024-09-23 so a pinned old date doesn't get the legacy v1 mode (which lacks process.getBuiltinModule and fails at script startup). An explicit no_nodejs_compat in compatibility.flags opts out of the default.

Also fixes a latent precreate bug found along the way: the placeholder upload spread ...getCompatibility(news) into metadata, producing date/flags instead of compatibilityDate/compatibilityFlags — the stub deployed with no compatibility settings at all (spreads bypass excess-property checks).

3. StaticSite passed unresolved Config into the build env

serializeEnv JSON.stringified anything that wasn't a string/Redacted, so env: { MY_URL: Config.string("MY_URL") } reached the build subprocess as {"_id":"Config"} (overriding a correct process.env value). It now mirrors the Website.Vite env path:

// strings/Redacted pass through; Config (any runnable Effect) resolves here;
// Outputs resolve at reconcile and the resolved value is serialized the same
// way (Output<object> reaches the subprocess as JSON, not [object Object]);
// null stringifies; binding Effects (WorkerLoader) are dropped
env: yield* serializeEnv(props.env)

A live regression test covers Config, Output<string>, Output<object>, and null env values reaching the build subprocess.

5/6. vite.main — relative paths + docs/API drift

  • ViteOptions.main (documented "Custom Worker Entry") is threaded through Website.Vite and now resolves relative paths against rootDir in both the live and dev providers — the rolldown plugin resolves the worker entry with no importer, so a relative main previously resolved against process.cwd() and broke monorepo deploys.
  • React Router now deploys via the documented option (verified live, SSR serving):
const web = yield* Cloudflare.Website.Vite("web", {
  main: "workers/app.ts", // wraps createRequestHandler (RR's cloudflare template ships this)
});

The plugin-side root causes of issues 4/5 (silent export default {} wrapper, no-importer resolution) are fixed in the companion PR cloudflare-tools#62.

7. memo and monorepo workspace deps

../ include globs already escape cwd end-to-end; this documents the pattern on MemoOptions, StaticSite, and Website.Vite, normalizes absolute glob matches to cwd-relative (they previously broke hashFiles and would have leaked machine paths into the hash), and adds a live test covering rebuild-on-sibling-change.

8. alchemy logs Unauthorized

workers_observability:read is already in the default OAuth scopes (including published beta.61), but tokens keep the scopes they were minted with — an older login fails the telemetry query with a bare Unauthorized. The query now dies with an actionable message pointing at re-running alchemy login.

Docs

Website.Vite JSDoc: SSR examples no longer instruct adding nodejs_compat manually (it's the default), and a React Router example was added.

Issue 1 (Vite SPA "neither assets nor server output") was already fixed on main by #795 — re-verified with the exact repro. Issue 8's poisoned alchemy@2.0.0-pipeline-v2-test npm release needs a maintainer npm deprecate.

🤖 Generated with Claude Code

…ult, StaticSite Config env, vite main resolution

Fixes from the create-better-t-stack integration reports:

- default nodejs_compat now reaches external Workers (plain `export default { fetch }`
  entrypoints set isExternal, which excluded them from the default); gated on
  compatibility date >= 2024-09-23 so pinned old dates don't get the broken v1 mode
- precreate placeholder spread getCompatibility() as date/flags — wrong metadata keys,
  so the stub uploaded with no compatibility date or flags
- StaticSite serializeEnv resolves Config/Effect env values instead of JSON.stringifying
  them into the build subprocess ({"_id":"Config"}); Outputs pass through for the
  engine to resolve
- relative vite.main resolves from rootDir (the rolldown plugin resolves the worker
  entry with no importer, so it resolved against process.cwd())
- memo include globs escaping cwd are documented + absolute matches normalized to
  cwd-relative so machine paths never leak into the hash
- alchemy logs explains the missing workers_observability:read scope on Unauthorized
  instead of surfacing the bare tag

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

alchemy-version-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Install the packages built from this commit:

alchemy

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

@alchemy.run/better-auth

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

@alchemy.run/pr-package

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

- serializeEnv: null no longer throws on the ~alchemy/Kind probe; Output
  values are serialized after resolution via Output.map so Output<object>
  reaches the build subprocess as JSON, not [object Object]
- getCompatibility: an explicit no_nodejs_compat opts out of the default
  nodejs_compat instead of sending Cloudflare a contradictory flag pair
- memo monorepo examples pair ../ include globs with lockfile: true (include
  flips the lockfile default off) and MemoOptions documents the interaction
- add a StaticSite regression test covering Config, Output<string>,
  Output<object>, and null env values reaching the build env (verified it
  fails against the previous serializer)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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