#3175·emdash

Node adapter build fails on unresolved "cloudflare:sockets" import in registry artifact-fetch (0.36.0+)

Author: SailingGregCreated Sep 17, 2026Updated Sep 17, 2026
Labelsarea/corebot:bugbot:needs-attention

Description

Since 0.36.0, any site on the Node adapter fails to build because Rollup cannot resolve the cloudflare:sockets specifier in the registry artifact transport:

[vite]: Rollup failed to resolve import "cloudflare:sockets" from
"node_modules/emdash/dist/artifact-fetch-P2JXVwOq.mjs".

The runtime behaviour is already correct — createRuntimeRegistryArtifactTransport() in packages/core/src/registry/artifact-fetch.ts wraps the dynamic import in a try/catch and falls back to createNodeRegistryArtifactTransport():

typescript
async function createRuntimeRegistryArtifactTransport(): Promise<RegistryArtifactTransport> {
	try {
		// @ts-ignore - virtual module
		const sockets: unknown = await import("cloudflare:sockets");
		const connect = objectProperty(sockets, "connect");
		if (!isWorkerSocketConnect(connect)) throw new TypeError("Workers socket binding is invalid");
		return createWorkersRegistryArtifactTransport(connect);
	} catch {
		return createNodeRegistryArtifactTransport();
	}
}

So this is purely a build-time failure: the specifier is a static string literal, so Rollup tries to resolve it during the consumer's Astro build and errors before the guard ever runs. Node-adapter sites cannot build at all past 0.35.0 without a workaround.

This also looks inconsistent with how the rest of core treats Workers built-ins. cloudflare:workers is deliberately kept out of core and routed through a virtual module instead — packages/core/src/astro/integration/virtual-modules.ts emits export { env } from "cloudflare:workers"; only under the Cloudflare adapter, with the comment:

core stays adapter-agnostic, with no direct cloudflare:workers import

artifact-fetch.ts is the one place that imports a cloudflare: built-in directly.

Suggested fix

Two options, both inside emdash rather than in every consumer's config:

  1. Externalize the scheme on the non-Cloudflare path. packages/core/src/astro/integration/vite-config.ts already maintains a Node-only external list for exactly this class of problem:

    typescript
    const NODE_NATIVE_EXTERNALS = ["@libsql/kysely-libsql", "pg"];

    Modules that contain native Node.js addons or Node-only code. These must be external in SSR to avoid bundling failures on Node. On Cloudflare, the adapter handles its own externalization […]

    Adding /^cloudflare:/ there (and to build.rollupOptions.external, since the failure is in the Rollup build rather than SSR resolution) would fix every Node-adapter consumer without them knowing this exists.

  2. Route it through the existing virtual-module pattern, as cloudflare:workers already is, so the specifier is only ever emitted under @astrojs/cloudflare. This is more consistent with the stated adapter-agnostic design of core.

Steps to reproduce

  1. Create an EmDash site on the Node adapter (@astrojs/node in standalone mode, output: "server").
  2. Install [email protected] or later (reproduced on 0.36.0, 0.37.0 and 0.38.0).
  3. Run astro build.

The build fails during "Building server entrypoints…". Pinning to [email protected] builds clean — packages/core/src/registry/artifact-fetch.ts does not exist before 0.36.0.

Workaround — externalizing the scheme in the site's own astro.config.mjs builds and runs correctly, with the Node transport selected at runtime as intended:

javascript
export default defineConfig({
  // …
  vite: {
    build: {
      rollupOptions: {
        external: [/^cloudflare:/],
      },
    },
  },
});

artifact-fetch.ts was introduced in 0.36.0, which git tag --contains puts at commit e3ad0823 ("feat(registry): hide unapproved listings in EmDash", #2647).

Environment

  • emdash 0.38.0 (also reproduced on 0.36.0 and 0.37.0; 0.35.0 unaffected)
  • astro 6.1.3
  • @astrojs/node 10.0.4 (mode: "standalone")
  • @astrojs/react 5.0.2
  • Node.js 22.22.2
  • pnpm 10.33.0
  • Database: SQLite via better-sqlite3 12.8.0
  • OS: Debian (arm64)

Screenshots

Not applicable — this is a build-time failure, error output below.

Logs / error output

[build] Building server entrypoints...
[ERROR] [vite] ✗ Build failed in 2.62s
[vite]: Rollup failed to resolve import "cloudflare:sockets" from
"/home/pi/emdash-cms/node_modules/.pnpm/[email protected]_.../node_modules/emdash/dist/artifact-fetch-P2JXVwOq.mjs".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rollupOptions.external`
  Stack trace:
    at viteLog (.../vite/dist/node/chunks/config.js:33635:57)
    at onwarn (.../@vitejs/plugin-react/dist/index.js:76:7)
    at onRollupLog (.../vite/dist/node/chunks/config.js:33664:63)
    at .../rollup/dist/es/shared/node-entry.js:21369:32
    at ModuleLoader.handleInvalidResolvedId (.../rollup/dist/es/shared/node-entry.js:22108:26)
 ELIFECYCLE  Command failed with exit code 1.