Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/config-export-binding-schemas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/config": minor
---

Export `BrowserBindingSchema`, `DurableObjectCreatedExportSchema`, `DurableObjectDeletedExportSchema`, `DurableObjectRenamedExportSchema`, `DurableObjectTransferredExportSchema`, `DurableObjectExpectingTransferExportSchema`, and `WorkerEntrypointExportSchema`
5 changes: 5 additions & 0 deletions .changeset/config-export-binding-union-schemas.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/config": minor
---

Export `KnownBindingSchema`, `BindingSchema`, `ExportSchema`, `UnsafeBindingSchema`, and `WorkerBindingSchema`
7 changes: 7 additions & 0 deletions .changeset/drop-service-worker-sourcemaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"miniflare": major
---

Drop source map resolution for service-worker scripts

Stack traces from service-worker scripts (provided via `legacy.serviceWorkerScript`) are no longer source-mapped. Service-worker scripts have no associated module path, so their `//# sourceMappingURL=` comments can no longer be resolved to a source map. Module workers continue to be source-mapped via `sourcemap`-type manifest modules.
35 changes: 35 additions & 0 deletions .changeset/miniflare-new-config-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
"miniflare": major
---

Adopt the `@cloudflare/config` worker configuration format

Workers are now configured with a `workers` array of `{ config, legacy, dev }` entries, where `config` follows the shared `@cloudflare/config` output schema (including inline module `manifest`s) rather than the previous flat per-worker options. Service bindings, tail consumers, assets, and source maps are all driven from this format:

- Service bindings support the `external`, `network`, and `disk` designators alongside worker/fetcher/node-handler bindings.
- Tail consumers accept `entrypoint` and `props`.
- Assets expose a `hasUserWorker` flag to control router behaviour.
- Source maps are provided inline as `sourcemap`-type manifest modules.

```js
new Miniflare({
workers: [
{
config: {
type: "worker",
name: "my-worker",
compatibilityDate: "2025-05-01",
manifest: {
mainModule: "index.mjs",
modules: {
"index.mjs": {
type: "esm",
contents: "export default { fetch() {} }",
},
},
},
},
},
],
});
```
13 changes: 13 additions & 0 deletions packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,24 @@ export {
writeRootOutputConfig,
} from "./build-output";
export {
AssetsSchema,
BindingSchema,
BrowserBindingSchema,
ConfigExportsSchema,
DurableObjectCreatedExportSchema,
DurableObjectDeletedExportSchema,
DurableObjectExpectingTransferExportSchema,
DurableObjectRenamedExportSchema,
DurableObjectTransferredExportSchema,
ExportSchema,
InputWorkerSchema,
KnownBindingSchema,
OutputWorkerSchema,
ModuleTypeSchema,
SettingsSchema,
UnsafeBindingSchema,
WorkerBindingSchema,
WorkerEntrypointExportSchema,
} from "./schema";
export { generateTypes } from "./generate";
export { convertToWranglerConfig } from "./convert";
Expand Down
106 changes: 61 additions & 45 deletions packages/config/src/schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as z from "zod";
import type { SettingsConfig, WorkerConfig } from "./types";

const AssetsSchema = z.strictObject({
export const AssetsSchema = z.strictObject({
htmlHandling: z
.enum([
"auto-trailing-slash",
Expand All @@ -16,7 +16,20 @@ const AssetsSchema = z.strictObject({
runWorkerFirst: z.union([z.array(z.string()), z.boolean()]).optional(),
});

const KnownBindingSchema = z.discriminatedUnion("type", [
export const BrowserBindingSchema = z.strictObject({
type: z.literal("browser"),
remote: z.boolean().optional(),
});

export const WorkerBindingSchema = z.strictObject({
type: z.literal("worker"),
workerName: z.string(),
exportName: z.string().optional(),
props: z.record(z.string(), z.unknown()).optional(),
remote: z.boolean().optional(),
});

export const KnownBindingSchema = z.discriminatedUnion("type", [
z.strictObject({
type: z.literal("agent-memory"),
namespace: z.string(),
Expand All @@ -43,10 +56,7 @@ const KnownBindingSchema = z.discriminatedUnion("type", [
remote: z.boolean().optional(),
}),
z.strictObject({ type: z.literal("assets") }),
z.strictObject({
type: z.literal("browser"),
remote: z.boolean().optional(),
}),
BrowserBindingSchema,
z.strictObject({
type: z.literal("d1"),
name: z.string().optional(),
Expand Down Expand Up @@ -178,13 +188,7 @@ const KnownBindingSchema = z.discriminatedUnion("type", [
type: z.literal("web-search"),
remote: z.boolean().optional(),
}),
z.strictObject({
type: z.literal("worker"),
workerName: z.string(),
exportName: z.string().optional(),
props: z.record(z.string(), z.unknown()).optional(),
remote: z.boolean().optional(),
}),
WorkerBindingSchema,
z.strictObject({ type: z.literal("worker-loader") }),
// TODO: support Workflows
// z.strictObject({
Expand All @@ -195,7 +199,7 @@ const KnownBindingSchema = z.discriminatedUnion("type", [
// }),
]);

const UnsafeBindingSchema = z.looseObject({
export const UnsafeBindingSchema = z.looseObject({
type: z.templateLiteral(["unsafe:", z.string().min(1)]),
dev: z
.strictObject({
Expand All @@ -215,7 +219,7 @@ type BindingOutput =
| z.output<typeof KnownBindingSchema>
| z.output<typeof UnsafeBindingSchema>;

const BindingSchema = z.unknown().transform((value, ctx) => {
export const BindingSchema = z.unknown().transform((value, ctx) => {
const isUnsafe =
typeof value === "object" &&
value !== null &&
Expand Down Expand Up @@ -291,36 +295,48 @@ const EnvSchema = z
// `state` defaults to `"created"` (live) when omitted. Tombstones use one of
// `"deleted"`, `"renamed"`, `"transferred"`; `"expecting-transfer"` is a live
// entry awaiting incoming data via the two-phase cross-script transfer flow.
const ExportSchema = z.union([
z.strictObject({
type: z.literal("durable-object"),
state: z.literal("created").optional(),
storage: z.enum(["sqlite", "legacy-kv"]),
}),
z.strictObject({
type: z.literal("durable-object"),
state: z.literal("deleted"),
}),
z.strictObject({
type: z.literal("durable-object"),
state: z.literal("renamed"),
renamedTo: z.string(),
}),
z.strictObject({
type: z.literal("durable-object"),
state: z.literal("transferred"),
transferredTo: z.string(),
}),
z.strictObject({
type: z.literal("durable-object"),
state: z.literal("expecting-transfer"),
storage: z.enum(["sqlite", "legacy-kv"]),
transferFrom: z.string(),
}),
z.strictObject({
type: z.literal("worker"),
cache: z.strictObject({ enabled: z.boolean() }).optional(),
}),
export const DurableObjectCreatedExportSchema = z.strictObject({
type: z.literal("durable-object"),
state: z.literal("created").optional(),
storage: z.enum(["sqlite", "legacy-kv"]),
});

export const DurableObjectDeletedExportSchema = z.strictObject({
type: z.literal("durable-object"),
state: z.literal("deleted"),
});

export const DurableObjectRenamedExportSchema = z.strictObject({
type: z.literal("durable-object"),
state: z.literal("renamed"),
renamedTo: z.string(),
});

export const DurableObjectTransferredExportSchema = z.strictObject({
type: z.literal("durable-object"),
state: z.literal("transferred"),
transferredTo: z.string(),
});

export const DurableObjectExpectingTransferExportSchema = z.strictObject({
type: z.literal("durable-object"),
state: z.literal("expecting-transfer"),
storage: z.enum(["sqlite", "legacy-kv"]),
transferFrom: z.string(),
});

export const WorkerEntrypointExportSchema = z.strictObject({
type: z.literal("worker"),
cache: z.strictObject({ enabled: z.boolean() }).optional(),
});

export const ExportSchema = z.union([
DurableObjectCreatedExportSchema,
DurableObjectDeletedExportSchema,
DurableObjectRenamedExportSchema,
DurableObjectTransferredExportSchema,
DurableObjectExpectingTransferExportSchema,
WorkerEntrypointExportSchema,
// TODO: support Workflows
// z.strictObject({
// type: z.literal("workflow"),
Expand Down
12 changes: 6 additions & 6 deletions packages/config/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ import type {
WebSearchBinding,
WorkerBinding,
WorkerLoaderBinding,
// TODO: re-enable when workflow bindings return.
// WorkflowBinding,
WorkflowBinding,
} from "./bindings";
import type {
DurableObjectDeletedExport,
Expand All @@ -53,6 +52,7 @@ import type {
DurableObjectRenamedExport,
DurableObjectTransferredExport,
WorkerEntrypointExport,
WorkflowExport,
} from "./exports";
import type { WorkerModule } from "./inference";
import type {
Expand Down Expand Up @@ -101,9 +101,8 @@ type Binding =
| VpcServiceBinding
| WebSearchBinding
| WorkerBinding
| WorkerLoaderBinding;
// TODO: re-enable when workflow bindings return.
// | WorkflowBinding;
| WorkerLoaderBinding
| WorkflowBinding;

/**
* Union of all trigger definitions accepted in `triggers`.
Expand All @@ -125,7 +124,8 @@ type Export =
| DurableObjectRenamedExport
| DurableObjectTransferredExport
| DurableObjectExpectingTransferExport
| WorkerEntrypointExport;
| WorkerEntrypointExport
| WorkflowExport;
// TODO: support Workflows

/**
Expand Down
1 change: 1 addition & 0 deletions packages/miniflare/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
},
"devDependencies": {
"@cloudflare/cli-shared-helpers": "workspace:*",
"@cloudflare/config": "workspace:*",
"@cloudflare/containers-shared": "workspace:*",
"@cloudflare/kv-asset-handler": "workspace:*",
"@cloudflare/local-explorer-ui": "workspace:*",
Expand Down
6 changes: 6 additions & 0 deletions packages/miniflare/scripts/types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ const extractorCfgObject = {
extractorMessageReporting: {
default: { logLevel: "warning" },
"ae-missing-release-tag": { logLevel: "none" },
// Our public config types transitively reference `@cloudflare/workers-shared`
// (via `@cloudflare/config` -> `@cloudflare/workers-utils`), which has no
// `exports`/`types` map, so bare imports resolve to its `.ts` source rather
// than a `.d.ts`. API Extractor never surfaces those types in the rollup, so
// this is a false positive we can safely ignore.
"ae-wrong-input-file-type": { logLevel: "none" },
},
},
};
Expand Down
6 changes: 3 additions & 3 deletions packages/miniflare/src/cf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
import path from "node:path";
import { dim } from "kleur/colors";
import { fetch } from "undici";
import type { Plugins } from "./plugins";
import type { Log, OptionalZodTypeOf } from "./shared";
import type { ParsedInstanceOptions } from "./config/schema";
import type { Log } from "./shared";
import type { IncomingRequestCfProperties } from "@cloudflare/workers-types/experimental";

/**
Expand Down Expand Up @@ -111,7 +111,7 @@ export const DAY = 86400000;
// Max age in days of cf.json
export const CF_DAYS = 30;

type CoreOptions = OptionalZodTypeOf<Plugins["core"]["sharedOptions"]>;
type CoreOptions = ParsedInstanceOptions;

/**
* Check if cf fetching is disabled via environment variable.
Expand Down
Loading
Loading