Migrating a Worker off a vendored src/core/
For a Worker that keeps its framework layer in the repository as src/core/. After this migration, that directory is
gone and the same code arrives as two libraries.
What moved where
| Was | Is now |
|---|---|
src/core/system/** |
@bayudwiyansatria/core |
src/core/cloudflare/** |
@bayudwiyansatria/cloudflare |
src/core/http/** |
@bayudwiyansatria/cloudflare/middlewares |
src/core/index.ts |
the two package barrels |
Everything else — app.ts, controllers/, services/, models/, config/*Config.ts, utils/ — stays exactly where
it is.
1. Install
npm install @bayudwiyansatria/core @bayudwiyansatria/cloudflare
rm -rf src/core
2. Rewrite the imports
Every core/… specifier becomes one of three package imports. The rule is which layer the symbol came from:
// before
import { Logger } from 'core/system/observability/Logger'
import { KVService } from 'core/cloudflare/services/KVService'
import { SecurityMiddleware } from 'core/http/SecurityMiddleware'
// after
import { Logger } from '@bayudwiyansatria/core'
import { KVService } from '@bayudwiyansatria/cloudflare'
import { SecurityMiddleware } from '@bayudwiyansatria/cloudflare/middlewares'
Both packages export from a single barrel, so the deep paths collapse.
3. Register the configuration surface
This is the substantive change. resolve() used to import src/config/ directly; a package cannot reach into its
consumer, so the application now hands the surface to the kernel instead.
Add one call at the end of src/config/index.ts, after defaults and overrides are declared:
import { configure } from '@bayudwiyansatria/core'
// …existing defaults and overrides…
configure(defaults, overrides)
Then make src/app.ts depend on it, so the module graph guarantees the ordering:
import 'config' // must stay above the rest — see below
import { Hono } from 'hono'
Why the side-effect import rather than a call in src/index.ts. ES imports are hoisted and evaluated before any
statement runs, so a configure() call written in the composition root executes after app.ts has already
initialised — and app.ts reads configuration while initialising, because SecurityMiddleware.apply needs the
protected pattern and the allowed origins at the moment it registers routes. Putting the call in config/ and naming
that dependency in app.ts makes the module graph enforce the order, since a module is always fully evaluated before
its importers.
If you skip this, the Worker throws ConfigurationError on startup with a message naming both likely causes.
4. Extend CloudflareEnv
Env used to be an ambient global that src/core/ and src/types/ both declared into. A package cannot merge into a
consumer's global scope, so it is now an exported interface you extend.
Rename src/types/env.d.ts to src/types/Env.ts and change the declaration:
import type { CloudflareEnv } from '@bayudwiyansatria/cloudflare'
export interface Env extends CloudflareEnv {
LOG_LEVEL?: string
API_AUTH_TOKEN_HEADER: string
API_AUTH_TOKEN_VALUE: string
}
Env is no longer global, so every file that references it needs an import:
import type { Env } from 'types/Env'
ctx.env still offers every member, Cloudflare's and yours.
5. Switch module resolution
Both packages publish an exports map, and the ./middlewares subpath does not resolve under classic Node resolution:
// tsconfig.json
"moduleResolution": "Bundler"
Bundler is the accurate description of what happens — Rollup and Wrangler resolve these imports, not Node, and both
honour exports.
6. Drop the obsolete lint boundary
eslint.config.ts had a no-restricted-imports block guarding src/core/system/ and an exemption for
src/core/system/config/resolve.ts. Both refer to files that no longer exist; the boundary they protected is now
enforced inside the packages. Delete them, and consider a leaf-layer rule over models/, types/, utils/, and
config/ in their place.
Verify
npx tsc --noEmit
npm run lint
npm run build
Then run the Worker locally with npx wrangler dev and exercise a protected route. A 401 without the configured key
and a successful response with it confirms that the middleware still composes across the package boundary. A startup
ConfigurationError means step 3 is incomplete.
If you vendored changes into src/core/
Diff your copy against the libraries before deleting it. Contribute framework-layer changes to the corresponding library rather than re-vendoring them, or the next upgrade will silently revert them.