Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 69a4a07

Browse files
authored
Fallback to workerd compatibility date (#395)
* Remove `runtimeBinaryPath` parameter from `RuntimeConstructor` This will always be the `default` export from `workerd`, so we may as well fold it in. * Fallback to latest supported `compatibilityDate` ...if a user selects a `compatibilityDate` that isn't supported by the currently installed version of `workerd`, but not in the future.
1 parent e339731 commit 69a4a07

File tree

7 files changed

+84
-43
lines changed

7 files changed

+84
-43
lines changed

package-lock.json

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/tre/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"kleur": "^4.1.5",
4545
"stoppable": "^1.1.0",
4646
"undici": "^5.10.0",
47-
"workerd": "^1.20220926.0",
47+
"workerd": "^1.20220926.3",
4848
"zod": "^3.18.0"
4949
},
5050
"devDependencies": {

packages/tre/src/index.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { bold, green, grey } from "kleur/colors";
66
import stoppable from "stoppable";
77
import { RequestInfo, RequestInit, fetch } from "undici";
88
import { HeadersInit, Request, Response } from "undici";
9-
import workerd from "workerd";
109
import { z } from "zod";
1110
import { setupCf } from "./cf";
1211

@@ -217,11 +216,7 @@ export class Miniflare {
217216
const entryPort = await getPort({ port: this.#sharedOpts.core.port });
218217

219218
// TODO: respect entry `host` option
220-
this.#runtime = new this.#runtimeConstructor(
221-
workerd,
222-
entryPort,
223-
loopbackPort
224-
);
219+
this.#runtime = new this.#runtimeConstructor(entryPort, loopbackPort);
225220
this.#removeRuntimeExitHook = exitHook(() => void this.#runtime?.dispose());
226221

227222
this.#runtimeEntryURL = new URL(`http://127.0.0.1:${entryPort}`);

packages/tre/src/plugins/core/index.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import { readFileSync } from "fs";
22
import fs from "fs/promises";
3+
import { bold, yellow } from "kleur/colors";
34
import { Request, Response } from "undici";
45
import { z } from "zod";
5-
import { Service, Worker_Binding, Worker_Module, kVoid } from "../../runtime";
6-
import { Awaitable, JsonSchema } from "../../shared";
6+
import {
7+
Service,
8+
Worker_Binding,
9+
Worker_Module,
10+
kVoid,
11+
supportedCompatibilityDate,
12+
} from "../../runtime";
13+
import { Awaitable, JsonSchema, MiniflareCoreError } from "../../shared";
714
import { BINDING_SERVICE_LOOPBACK, Plugin } from "../shared";
815
import {
916
ModuleDefinitionSchema,
@@ -13,6 +20,8 @@ import {
1320
convertModuleDefinition,
1421
} from "./modules";
1522

23+
const numericCompare = new Intl.Collator(undefined, { numeric: true }).compare;
24+
1625
// (request: Request) => Awaitable<Response>
1726
export const ServiceFetch = z
1827
.function()
@@ -99,8 +108,46 @@ export const SCRIPT_CUSTOM_SERVICE = `addEventListener("fetch", (event) => {
99108
event.respondWith(${BINDING_SERVICE_LOOPBACK}.fetch(request));
100109
})`;
101110

111+
const now = new Date();
112+
const CURRENT_COMPATIBILITY_DATE = [
113+
now.getFullYear(),
114+
(now.getMonth() + 1).toString().padStart(2, "0"),
115+
now.getDate().toString().padStart(2, "0"),
116+
].join("-");
117+
102118
const FALLBACK_COMPATIBILITY_DATE = "2000-01-01";
103119

120+
function validateCompatibilityDate(compatibilityDate: string) {
121+
if (numericCompare(compatibilityDate, CURRENT_COMPATIBILITY_DATE) > 0) {
122+
// If this compatibility date is in the future, throw
123+
throw new MiniflareCoreError(
124+
"ERR_FUTURE_COMPATIBILITY_DATE",
125+
`Compatibility date "${compatibilityDate}" is in the future and unsupported`
126+
);
127+
} else if (
128+
numericCompare(compatibilityDate, supportedCompatibilityDate) > 0
129+
) {
130+
// If this compatibility date is greater than the maximum supported
131+
// compatibility date of the runtime, but not in the future, warn,
132+
// and use the maximum supported date instead
133+
console.warn(
134+
yellow(
135+
[
136+
"The newest compatibility date supported by the installed version of the Cloudflare Workers Runtime is ",
137+
bold(`"${supportedCompatibilityDate}"`),
138+
",\nbut you've requested ",
139+
bold(`"${compatibilityDate}"`),
140+
". Falling back to ",
141+
bold(`"${supportedCompatibilityDate}"`),
142+
"...",
143+
].join("")
144+
)
145+
);
146+
return supportedCompatibilityDate;
147+
}
148+
return compatibilityDate;
149+
}
150+
104151
export const CORE_PLUGIN: Plugin<
105152
typeof CoreOptionsSchema,
106153
typeof CoreSharedOptionsSchema
@@ -187,13 +234,15 @@ export const CORE_PLUGIN: Plugin<
187234
if (workerScript !== undefined) {
188235
const name = getUserServiceName(options.name);
189236
const classNames = durableObjectClassNames.get(name) ?? [];
237+
const compatibilityDate = validateCompatibilityDate(
238+
options.compatibilityDate ?? FALLBACK_COMPATIBILITY_DATE
239+
);
190240

191241
services.push({
192242
name,
193243
worker: {
194244
...workerScript,
195-
compatibilityDate:
196-
options.compatibilityDate ?? FALLBACK_COMPATIBILITY_DATE,
245+
compatibilityDate,
197246
compatibilityFlags: options.compatibilityFlags,
198247
bindings: workerBindings,
199248
durableObjectNamespaces: classNames.map((className) => ({

packages/tre/src/runtime/index.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import crypto from "crypto";
33
import fs from "fs";
44
import os from "os";
55
import path from "path";
6+
import workerdPath, {
7+
compatibilityDate as supportedCompatibilityDate,
8+
} from "workerd";
69
import { SERVICE_LOOPBACK, SOCKET_ENTRY } from "../plugins";
710
import { Awaitable, MiniflareCoreError } from "../shared";
811

912
export abstract class Runtime {
1013
constructor(
11-
protected readonly runtimeBinaryPath: string,
1214
protected readonly entryPort: number,
1315
protected readonly loopbackPort: number
1416
) {}
@@ -19,11 +21,7 @@ export abstract class Runtime {
1921
}
2022

2123
export interface RuntimeConstructor {
22-
new (
23-
runtimeBinaryPath: string,
24-
entryPort: number,
25-
loopbackPort: number
26-
): Runtime;
24+
new (entryPort: number, loopbackPort: number): Runtime;
2725

2826
isSupported(): boolean;
2927
supportSuggestion: string;
@@ -77,20 +75,16 @@ class NativeRuntime extends Runtime {
7775
#process?: childProcess.ChildProcess;
7876
#processExitPromise?: Promise<void>;
7977

80-
constructor(
81-
runtimeBinaryPath: string,
82-
entryPort: number,
83-
loopbackPort: number
84-
) {
85-
super(runtimeBinaryPath, entryPort, loopbackPort);
78+
constructor(entryPort: number, loopbackPort: number) {
79+
super(entryPort, loopbackPort);
8680
const [command, ...args] = this.getCommand();
8781
this.#command = command;
8882
this.#args = args;
8983
}
9084

9185
getCommand(): string[] {
9286
return [
93-
this.runtimeBinaryPath,
87+
workerdPath,
9488
...COMMON_RUNTIME_ARGS,
9589
`--socket-addr=${SOCKET_ENTRY}=127.0.0.1:${this.entryPort}`,
9690
`--external-addr=${SERVICE_LOOPBACK}=127.0.0.1:${this.loopbackPort}`,
@@ -188,7 +182,7 @@ class DockerRuntime extends Runtime {
188182
"--interactive",
189183
"--rm",
190184
`--volume=${RESTART_PATH}:/restart.sh`,
191-
`--volume=${this.runtimeBinaryPath}:/runtime`,
185+
`--volume=${workerdPath}:/runtime`,
192186
`--volume=${this.#configPath}:/miniflare-config.bin`,
193187
`--publish=127.0.0.1:${this.entryPort}:8787`,
194188
"debian:bullseye-slim",
@@ -251,3 +245,4 @@ export function getSupportedRuntime(): RuntimeConstructor {
251245
}
252246

253247
export * from "./config";
248+
export { supportedCompatibilityDate };

packages/tre/src/shared/error.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export type MiniflareCoreErrorCode =
1818
| "ERR_MODULE_STRING_SCRIPT" // Attempt to resolve module within string script
1919
| "ERR_MODULE_DYNAMIC_SPEC" // Attempted to import/require a module without a literal spec
2020
| "ERR_MODULE_RULE" // No matching module rule for file
21-
| "ERR_PERSIST_UNSUPPORTED"; // Unsupported storage persistence protocol
21+
| "ERR_PERSIST_UNSUPPORTED" // Unsupported storage persistence protocol
22+
| "ERR_FUTURE_COMPATIBILITY_DATE"; // Compatibility date in the future
2223
export class MiniflareCoreError extends MiniflareError<MiniflareCoreErrorCode> {}
2324

2425
export class HttpError extends MiniflareError<number> {

types/workerd.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
declare module "workerd" {
22
const path: string;
33
export default path;
4+
export const compatibilityDate: string;
45
}

0 commit comments

Comments
 (0)