Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/dependabot-update-15633.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"miniflare": patch
"wrangler": patch
---

Update dependencies of "miniflare", "wrangler"

The following dependency versions have been updated:

| Dependency | From | To |
| ------------------------- | ------------- | ------------- |
| @cloudflare/workers-types | ^5.20260911.1 | ^5.20260914.1 |
| workerd | 1.20260911.1 | 1.20260914.1 |
9 changes: 9 additions & 0 deletions .changeset/warm-runners-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@cloudflare/vite-plugin": patch
"@cloudflare/vitest-plugin": patch
"miniflare": minor
---

Fix `cloudflare:node` HTTP server dispatch in Vite and Vitest

Vite and Vitest evaluate user modules inside pinned runner Durable Objects but invoke exported handlers from another context. Their internal singleton runners now expose that actor's Node.js server port registrations to the isolate, allowing handlers created with `httpServerHandler()` to find servers started during module evaluation without changing port isolation for other actors.
10 changes: 10 additions & 0 deletions fixtures/vitest-plugin-examples/misc/src/cloudflare-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import http from "node:http";
import { httpServerHandler } from "cloudflare:node";

const server = http.createServer((_, response) => {
response.end("Hello from an httpServerHandler");
});

server.listen(8080);

export default httpServerHandler({ port: 8080 });
8 changes: 8 additions & 0 deletions fixtures/vitest-plugin-examples/misc/src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.workerd.json",
"compilerOptions": {
"skipLibCheck": true,
"types": ["@cloudflare/workers-types/experimental", "@types/node"]
},
"include": ["./**/*.ts"]
}
9 changes: 9 additions & 0 deletions fixtures/vitest-plugin-examples/misc/test/nodejs.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SELF } from "cloudflare:test";
import { it } from "vitest";

it("runs in Node.js compatibility mode", ({ expect }) => {
Expand All @@ -6,3 +7,11 @@ it("runs in Node.js compatibility mode", ({ expect }) => {
expect(process.versions.node).toBeDefined();
expect(typeof Buffer).toBe("function");
});

it("dispatches to an HTTP server registered with `cloudflare:node`", async ({
expect,
}) => {
const response = await SELF.fetch("https://example.com");

expect(await response.text()).toBe("Hello from an httpServerHandler");
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"$schema": "../node_modules/wrangler/config-schema.json",
"main": "src/cloudflare-node.ts",
// Pin a compatibility date from before `nodejs_compat` became enabled by
// default, so that this fixture keeps covering the explicit-flag path.
// Specifying the flag on a later date is a workerd validation error.
Expand Down
3 changes: 3 additions & 0 deletions packages/miniflare/src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,18 +349,21 @@ const MiniflareBindingSchema = z.unknown().transform((value, ctx) => {
* Extends live DO exports with miniflare-internal fields:
* - `unsafeUniqueKey` — custom unique key for DO namespace identity
* - `unsafePreventEviction` — prevents the DO from being evicted
* - `unsafeUseIsolateNodePortScopeForActor` — shares one actor's Node.js server ports across the isolate
* - `container` — container config for container-attached DOs
*/
export const MiniflareDurableObjectExportSchema =
DurableObjectCreatedExportSchema.extend({
unsafeUniqueKey: z.custom<UnsafeUniqueKey>().optional(),
unsafePreventEviction: z.boolean().optional(),
unsafeUseIsolateNodePortScopeForActor: z.string().optional(),
container: z.custom<DOContainerOptions>().optional(),
});
export const MiniflareDurableObjectExpectingTransferExportSchema =
DurableObjectExpectingTransferExportSchema.extend({
unsafeUniqueKey: z.custom<UnsafeUniqueKey>().optional(),
unsafePreventEviction: z.boolean().optional(),
unsafeUseIsolateNodePortScopeForActor: z.string().optional(),
container: z.custom<DOContainerOptions>().optional(),
});

Expand Down
2 changes: 2 additions & 0 deletions packages/miniflare/src/config/v4-convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ function addDurableObjectExport(
storage: object.useSQLite ? "sqlite" : "legacy-kv",
unsafeUniqueKey: object.unsafeUniqueKey,
unsafePreventEviction: object.unsafePreventEviction,
unsafeUseIsolateNodePortScopeForActor:
object.unsafeUseIsolateNodePortScopeForActor,
container: object.container,
};
exports[object.className] = exported as Exports[string];
Expand Down
2 changes: 2 additions & 0 deletions packages/miniflare/src/config/v4-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ const V4DurableObjectSchema = z.object({
])
.optional(),
unsafePreventEviction: z.boolean().optional(),
unsafeUseIsolateNodePortScopeForActor: z.string().optional(),
remoteProxyConnectionString: RemoteProxyConnectionStringSchema.optional(),
container: z.object({ imageName: z.string() }).optional(),
});
Expand Down Expand Up @@ -743,6 +744,7 @@ export type V4DurableObject = {
useSQLite?: boolean;
unsafeUniqueKey?: string | symbol;
unsafePreventEviction?: boolean;
unsafeUseIsolateNodePortScopeForActor?: string;
remoteProxyConnectionString?: RemoteProxyConnectionString;
container?: { imageName: string };
};
Expand Down
2 changes: 2 additions & 0 deletions packages/miniflare/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ function getDurableObjectClassNames(
enableSql: exported.storage === "sqlite",
unsafeUniqueKey: exported.unsafeUniqueKey,
unsafePreventEviction: exported.unsafePreventEviction,
unsafeUseIsolateNodePortScopeForActor:
exported.unsafeUseIsolateNodePortScopeForActor,
container: exported.container,
});
}
Expand Down
3 changes: 3 additions & 0 deletions packages/miniflare/src/plugins/do/namespaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export function getDurableObjectNamespaces(
enableSql,
unsafeUniqueKey,
unsafePreventEviction: preventEviction,
unsafeUseIsolateNodePortScopeForActor,
container,
},
]) => {
Expand All @@ -70,13 +71,15 @@ export function getDurableObjectNamespaces(
enableSql,
ephemeralLocal: kVoid,
preventEviction,
unsafeUseIsolateNodePortScopeForActor,
container: containerOptions,
}
: {
className,
enableSql,
uniqueKey,
preventEviction,
unsafeUseIsolateNodePortScopeForActor,
container: containerOptions,
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/miniflare/src/plugins/shared/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export type DurableObjectClassNames = Map<
enableSql?: boolean;
unsafeUniqueKey?: UnsafeUniqueKey;
unsafePreventEviction?: boolean;
unsafeUseIsolateNodePortScopeForActor?: string;
container?: DOContainerOptions;
}
>
Expand Down
96 changes: 94 additions & 2 deletions packages/miniflare/src/runtime/config/generated/workerd.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions packages/miniflare/src/runtime/config/workerd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,19 @@ export type Worker_DurableObjectNamespace = {
className?: string;
preventEviction?: boolean;
enableSql?: boolean;
unsafeUseIsolateNodePortScopeForActor?: string;
container?: Worker_DurableObjectNamespace_ContainerOptions;
} & ({ uniqueKey?: string } | { ephemeralLocal?: Void });

export interface Worker_DurableObjectNamespace_ContainerOptions {
imageName?: string;
privileges?: Worker_DurableObjectNamespace_ContainerOptions_ContainerPrivileges;
images?: Worker_DurableObjectNamespace_ContainerOptions_NamedImage[];
}

export interface Worker_DurableObjectNamespace_ContainerOptions_NamedImage {
name?: string;
image?: string;
}

export interface Worker_DurableObjectNamespace_ContainerOptions_ContainerPrivileges {
Expand Down
17 changes: 17 additions & 0 deletions packages/miniflare/test/config/v4-convert.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from "node:path";
import { describe, test } from "vitest";
import { convertV4MiniflareOptions } from "../../src/config/v4-convert";
import { kUnsafeEphemeralUniqueKey } from "../../src/plugins/shared/unsafe-unique-key";
import type { RemoteProxyConnectionString } from "../../src/plugins/shared";

describe("convertV4MiniflareOptions", () => {
Expand All @@ -16,7 +17,12 @@ describe("convertV4MiniflareOptions", () => {
className: "LocalObject",
useSQLite: true,
unsafeUniqueKey: "local-key",
},
RUNNER: {
className: "RunnerObject",
unsafeUniqueKey: kUnsafeEphemeralUniqueKey,
unsafePreventEviction: true,
unsafeUseIsolateNodePortScopeForActor: "singleton",
},
SELF_EXPLICIT: {
className: "SelfExplicitObject",
Expand All @@ -38,6 +44,11 @@ describe("convertV4MiniflareOptions", () => {
worker: "worker",
exportName: "LocalObject",
},
RUNNER: {
type: "durable-object",
worker: "worker",
exportName: "RunnerObject",
},
EXTERNAL: {
type: "durable-object",
worker: "external-worker",
Expand All @@ -54,7 +65,13 @@ describe("convertV4MiniflareOptions", () => {
type: "durable-object",
storage: "sqlite",
unsafeUniqueKey: "local-key",
},
RunnerObject: {
type: "durable-object",
storage: "legacy-kv",
unsafeUniqueKey: kUnsafeEphemeralUniqueKey,
unsafePreventEviction: true,
unsafeUseIsolateNodePortScopeForActor: "singleton",
},
SelfExplicitObject: {
type: "durable-object",
Expand Down
Loading
Loading