feat(miniflare): add unsafeEntrypointSubdomains for localhost subdomain routing#12584
feat(miniflare): add unsafeEntrypointSubdomains for localhost subdomain routing#12584edmundhung wants to merge 1 commit intomainfrom
Conversation
🦋 Changeset detectedLatest commit: 687cf8f The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Claude finished @edmundhung's task —— View job Changeset Review
✅ All changesets look good The changeset follows all guidelines:
|
| serviceEntryBindings.push({ | ||
| name: `${CoreBindings.SERVICE_USER_ENTRYPOINT_PREFIX}${workerName}:${entry.export}`, | ||
| service: { | ||
| name: getUserServiceName(workerName), |
There was a problem hiding this comment.
🔴 Lowercased worker name in entrypoint service bindings causes mismatch with actual service names
When a worker has a mixed-case name (e.g., "MyApi"), the entrypoint service bindings reference a non-existent service, which will cause workerd to fail or the binding to be undefined at runtime.
Root Cause
In getEntrypointSubdomains() at packages/miniflare/src/index.ts:801, the worker name is lowercased when used as a key:
result[workerName.toLowerCase()] = aliasToEntry;Then in getGlobalServices() at packages/miniflare/src/plugins/core/index.ts:1056-1064, the code iterates over allEntrypointSubdomains and uses these lowercased worker names to create service bindings:
for (const [workerName, entrypoints] of Object.entries(allEntrypointSubdomains)) {
// workerName is already lowercased from getEntrypointSubdomains
service: {
name: getUserServiceName(workerName), // produces "core:user:myapi"
...
}
}However, the actual worker service is registered with the original (non-lowercased) name at packages/miniflare/src/plugins/core/index.ts:752:
const serviceName = getUserServiceName(options.name); // produces "core:user:MyApi"So for a worker named "MyApi", the entrypoint binding points to core:user:myapi while the actual service is core:user:MyApi. This mismatch means workerd will reference a non-existent service.
All tests use lowercase worker names ("api", "admin", "app", etc.), so this bug is not caught by the test suite.
Impact: Entrypoint subdomain routing will fail for any worker with uppercase characters in its name.
Prompt for agents
The fix needs to be applied in two coordinated places:
1. In packages/miniflare/src/index.ts, the getEntrypointSubdomains function (around line 801): Instead of only storing the lowercased worker name as the key, also preserve the original worker name. One approach is to change the data structure to include the original name, e.g. store a mapping from lowercased name to { originalName, aliasToEntry }.
2. In packages/miniflare/src/plugins/core/index.ts, the getGlobalServices function (around line 1056-1064): When creating service bindings, use the original (non-lowercased) worker name for getUserServiceName() calls, while keeping the lowercased name for the binding name prefix (since the entry worker looks up by lowercased hostname).
Alternatively, a simpler fix would be to not lowercase the worker name in getEntrypointSubdomains at all, and instead lowercase the hostname parts in resolveHostnameRoute (in entry.worker.ts) before looking up in the config. Since URL hostnames are already lowercased by the URL spec, and the config keys would use the original case, you would need to lowercase the config keys at lookup time in the entry worker. The cleanest approach is probably to store both the original and lowercased names.
Was this helpful? React with 👍 or 👎 to provide feedback.
create-cloudflare
@cloudflare/kv-asset-handler
miniflare
@cloudflare/pages-shared
@cloudflare/unenv-preset
@cloudflare/vite-plugin
@cloudflare/vitest-pool-workers
@cloudflare/workers-editor-shared
@cloudflare/workers-utils
wrangler
commit: |
Fixes n/a.
This adds the ability to access worker entrypoints directly via localhost subdomains during local development. In multi-worker setups, each worker and its entrypoints get their own subdomain URLs:
http://{worker}.localhost:{port}: routes to the worker's default entrypointhttp://{entrypoint}.{worker}.localhost:{port}: routes to a specific entrypointNot all systems resolve
*.localhostsubdomains. A DNS check will run on startup and warns if the system doesn't support it. Browsers (Chrome, Edge, Firefox) resolve these independently and will always work. Non-browser tools like curl might not resolve on some systems.To enable this feature, developer will need to set the
unsafeEntrypointSubdomainsoptions on each worker which is a map between export name and the alias (subdomain).A picture of a cute animal (not mandatory, but encouraged)