refactor: retire lib/effect-cloudflare - #760
Merged
Merged
Conversation
The package was a hand-vendored subset of alchemy-effect's
Cloudflare/Workers/* runtime modules, carried while that package was
unpublished — nearly every file said so in a provenance header. The repo now
runs alchemy@2.0.0-beta.74, which ships that design as first-party source.
Two things drove the shape of this change:
- ~1600 of the package's 2520 lines had no production consumer at all: the
DO / Workflow / RPC / KV / fetcher / websocket / http / scheduled-events
cluster. apps/api's own Workflows and its ChatSession DO extend
cloudflare:workers directly and bypassed the library entirely. Deleted,
along with the one test that exercised the dead rpc.ts.
- The ~250 lines that do have consumers move to packages/infra behind
runtime-only subpaths (/worker-runtime, /workers-cache, /r2,
/config-helpers), kept out of the ./cloudflare barrel so a worker bundle
never reaches the deploy graph.
Alchemy's runtime services turned out not to be importable from a
hand-written Worker entry, so the env/config tag stays local. Its exports map
has no entry finer than a directory (./Cloudflare/* -> */index.ts), and the
Cloudflare/Workers barrel re-exports Source.ts / WorkerProvider.ts /
LocalWorkerProvider.ts next to the two runtime services: bundling it pulls
fdir, rolldown glue and node:module — 426 KB minified against 14 KB for the
tag alone, and node:module does not exist in workerd. R2/KV/service-binding
clients are blocked twice over, since makeBucketBinding wants the deploy-side
resource value and the Worker service. So worker-env.ts defines the service
under alchemy's exact key ("Cloudflare.Workers.WorkerEnvironment") — Effect
resolves by string, so it is the same service, and the whole surface becomes
importable the day api/alerting move to the class-form Cloudflare.Worker.
Call sites are otherwise unchanged: 48 imports repointed and
WorkerEnvironment.layer renamed to workerEnvironmentLayer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`packages/infra` now holds the `import("cloudflare:workers")` that
lib/effect-cloudflare used to, so it needs that workspace's
`ignoreDependencies: ["cloudflare"]` — the module is a Workers runtime
module, not a package.
The other two knip reports were latent and only surface now that the run
reaches these workspaces: `wrangler` no longer needs an apps/api ignore, and
`BucketAxis` in apps/web has had no consumer since it was introduced
(`makeBucketAxis` is what the charts import).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🍁 Maple PR previewWarning Preview cleanup could not be confirmed. The Alchemy teardown outcome was Final commit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
lib/effect-cloudflarewas a hand-vendored subset ofalchemy-effect'sCloudflare/Workers/*runtime modules, copied in while that package was unpublished — nearly every file carried a provenance header saying exactly that, and promising a mechanical find-and-replace once upstream shipped. The repo now runsalchemy@2.0.0-beta.74, which ships that design as first-party source. This deletes the package.What changed
Deleted ~1600 LOC with zero production consumers. The DO / Workflow / RPC / KV / fetcher / websocket / http / scheduled-events cluster was imported by nothing outside the library itself — apps/api's two Workflows and its
ChatSessionDO extendcloudflare:workersdirectly and bypassed it entirely. The only importer waseffect-cloudflare-rpc.test.ts, a test for the deadrpc.ts; it goes too. Every exported symbol was grepped repo-wide first (the apparent hits fornamespaceOf,WorkflowEvent,DurableObjectState,HttpEffectare all false positives — a local helper inpackages/ui, and CF's / Effect's own types of the same name).Moved the ~250 LOC that does have consumers into
packages/infra, behind runtime-only subpaths so a worker bundle never reaches the deploy graph through the existing./cloudflarebarrel:@maple/infra/worker-runtimerunScheduledEffect,withRequestRuntime, thedrainSchedulerspan-flush fix) plus the env/config surface@maple/infra/workers-cache@maple/infra/r2bindOptionalfor self-hosted installs with no R2@maple/infra/config-helpersConfighelpers48 import sites repointed;
WorkerEnvironment.layerrenamed toworkerEnvironmentLayer. No other call-site changes.What a reviewer should know
Alchemy's runtime services are not importable from a hand-written Worker entry, which is why the env/config tag is still defined in-repo rather than re-exported. Its exports map has no entry finer than a directory (
./Cloudflare/*→*/index.ts), and theCloudflare/Workersbarrel re-exportsSource.ts/WorkerProvider.ts/LocalWorkerProvider.tsnext to the two runtime services. Bundling it pullsfdir, rolldown glue and Node builtins — 426 KB minified for an entry importing justWorkerEnvironment, against 14 KB with the tag defined locally — andnode:moduledoes not exist in workerd. R2/KV/service-binding clients are blocked twice over:makeBucketBindingyields theWorkerservice and indexesenv[bucket.LogicalId], so it needs the deploy-side resource value, andapps/api/src/worker.tsimportsalchemy.run.tstype-only.So
packages/infra/src/cloudflare/worker-env.tsdefines the service under alchemy's exact key ("Cloudflare.Workers.WorkerEnvironment"). Effect resolves services by that string, so this and alchemy's are the same service in both directions — the whole runtime surface becomes free the day api/alerting move to the class-formCloudflare.Workerand let alchemy's bundler generate the entry. That migration is deliberately out of scope here; it's the only wayworker-runtime.tsitself could go. All of this is written up under Alchemy v1 → v2 notes indocs/infra.md.The one behavioural difference: alchemy's
WorkerConfigProvideralso reifies the{"_tag":"Redacted"}markers its deploy-timeConfiginterceptor writes into the env. Maple binds plain vars and secrets, and the vendored copy never reified either, so nothing changes — noted in the file.Verification
tsc --noEmitclean forapps/api,apps/alerting,apps/electric-sync,packages/infra, andtsconfig.alchemy.jsonoxlintclean over the touched workspacespackages/infra(57 tests) and 9 targetedapps/apisuites — ReplayBlobStore, pg-connection-scope, DatabasePgLive, both rate limiters, both queues, slack-integration, internal chat (71 tests) — all passNot yet run locally: the full test suite,
knip, anapps/apialchemy build, and abun devcheck that a request still produces a root server span with children (thedrainSchedulercontract — parentless spans would mean the flush regressed). Worth eyeballing thestgdeploy for the R2 / Cache / config paths before prd.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.