Releases: cloudflare/miniflare
v2.11.0
Features
- Add support for dead-letter queues. Thanks @jbw1991 for the PR.
- Add
getMiniflareDurableObjectIds()global function to Miniflare's Jest/Vitest environments for listing active Durable Objects. CallinggetMiniflareDurableObjectIds("TEST_OBJECT")will return aPromisethat resolves to an array of activeDurableObjectIds for theTEST_OBJECTnamespace. Closes issue #384, thanks @DaniFoldi for the PR.
Fixes
- Strip quotes from R2
onlyIfheader values. Closes issue #402, thanks @vincentbernat and @CraigglesO for the PR. - Disable
r2Persistoption in Miniflare's Jest/Vitest environments. Thanks @hanford for the PR.
v2.10.0
Features
- Add support for
TextEncoderStream/TextDecoderStream. Closes issue #389, thanks @vlovich.
Fixes
- Fix reporting of server port when using
--port=0. Closes issue #381, thanks @GregBrimble for the PR. - Return Durable Object
get()s in lexicographic order. Closes issue #393, thanks @vlovich. - Add missing
@miniflare/r2dependency to@miniflare/shared-test-environmentpackage. Thanks @askoufis for the PR. - Return correct
Content-LengthfromCache#match()partial responses. Closes issue #406. Thanks @notorca for the PR. - Fix links in Vitest test environment docs. Thanks @eadmundo for the PR.
v3.0.0-next.2
Fixes
- If the specified compatibility date is after the latest supported
workerdcompatibility date, but not in the future, log a warning, and fallback to the latest supported date instead. - Resolve
Miniflare#ready'sPromisewith theURLofworkerd's HTTP server.
v3.0.0-next.1
Miniflare now uses Cloudflare's open-source Workers runtime, workerd, to run your code! 🎉 This is a massive change, and should mean your code runs locally almost-exactly as in production. Most Workers features are supported, including Web Standards, KV, R2, but there are a few things that aren't just yet:
- Durable Objects are in-memory only and cannot be persisted between reloads
- The Cache API is not yet implemented
- Scheduled Events are not yet implemented
console.logging an object will not show all its properties
Breaking Changes
- Miniflare's CLI has been removed. We're still discussing whether it makes sense to keep this, given
wrangler devhas additional features such as automatic bundling and TypeScript support. For now, usewrangler dev --experimental-local.
Miniflare API Changes
-
kvNamespacesnow accepts an object mapping binding names to namespace IDs, instead of an array of binding names. This means multiple workers can bind the same namespace under different names.const mf = new Miniflare({ - kvNamespaces: ["NAMESPACE_1", "NAMESPACE_2"], + kvNamespaces: { + NAMESPACE_1: "NAMESPACE_1", // Miniflare <= 2 behaviour + NAMESPACE_2: "ns2", // Custom namespace ID + }, }); -
Similarly,
r2Bucketsnow accepts an object mapping binding names to bucket IDs, instead of an array of binding names.const mf = new Miniflare({ - r2Buckets: ["BUCKET_1", "BUCKET_2"], + r2Buckets: { + BUCKET_1: "BUCKET_1", // Miniflare <= 2 behaviour + BUCKET_2: "bucket2", // Custom namespace ID + }, }); -
workerdrequires all modules to be known ahead of time, so Miniflare will parse your JavaScript to search for module dependencies when settingmodulestotrue. This has some limitations:- Dynamic
import()with non-literal arguments is unsupported. - Any call to a function named
requirein a CommonJS module will be searched, even if it's not actually the globalrequirefunction, and just a user-defined function with the same name.
Because of these limitations, Miniflare allows you to define all your modules manually.
import { Miniflare } from "@miniflare/tre"; const mf = new Miniflare({ modules: [ // The first module must be your entrypoint. `type` must be one of // "ESModule", "CommonJS", "Text", "Data" or "CompiledWasm". If `path` // isn't relative, it will be converted to a relative path before being // passed to `workerd`. { type: "ESModule", path: "src/index.mjs" }, // Optionally, a `contents` `string` or `Uint8Array` can be defined. // If omitted, `contents` is loaded from `path`. { type: "Text", path: "src/message.txt", contents: "Hello!" }, ], });
- Dynamic
-
mountshas been removed and replaced with theworkersoption.import { Miniflare } from "@miniflare/tre"; const message = "The count is "; const mf = new Miniflare({ // Options shared between workers such as HTTP and persistence configuration // should always be defined at the top level. host: "0.0.0.0", port: 8787, kvPersist: true, workers: [ { name: "worker", kvNamespaces: { COUNTS: "counts" }, serviceBindings: { INCREMENTER: "incrementer", // Service bindings can also be defined as custom functions, with access // to anything defined outside Miniflare. async CUSTOM(request) { // `request` is the incoming `Request` object. return new Response(message); }, }, modules: true, script: `export default { async fetch(request, env, ctx) { // Get the message defined outside const response = await env.CUSTOM.fetch("http://host/"); const message = await response.text(); // Increment the count 3 times await env.INCREMENTER.fetch("http://host/"); await env.INCREMENTER.fetch("http://host/"); await env.INCREMENTER.fetch("http://host/"); const count = await env.COUNTS.get("count"); return new Response(message + count); } }`, }, { name: "incrementer", // Note we're using the same `COUNTS` namespace as before, but binding it // to `NUMBERS` instead. kvNamespaces: { NUMBERS: "counts" }, // Worker formats can be mixed-and-matched script: `addEventListener("fetch", (event) => { event.respondWith(handleRequest()); }) async function handleRequest() { const count = parseInt((await NUMBERS.get("count")) ?? "0") + 1; await NUMBERS.put("count", count.toString()); return new Response(count.toString()); }`, }, ], }); const res = await mf.dispatchFetch("http://localhost"); console.log(await res.text()); // "The count is 3"
v2.9.0
Features
-
💾 Add support for D1. Closes issue #277, thanks @geelen for the PR. Docs coming soon™... 👀
-
🚪 Add
getMiniflareDurableObjectState()andrunWithMiniflareDurableObjectGates()functions to the Jest/Vitest environments. This allows you to construct and call instance methods of Durable Objects directly, without having to fetch through a stub. Closes issue #157, thanks @jorroll.// Durable Object class, would probably come from an import class Counter { constructor(state) { this.storage = state.storage; } async fetch() { const count = ((await this.storage.get("count")) ?? 0) + 1; void this.storage.put("count", count); return new Response(String(count)); } } const env = getMiniflareBindings(); // Use standard Durable Object bindings to generate IDs const id = env.COUNTER.newUniqueId(); // Get DurableObjectState, and seed data const state = await getMiniflareDurableObjectState(id); await state.storage.put("count", 3); // Construct object directly const object = new Counter(state, env); // Call instance method directly, closing input gate, // and waiting for output gate to open const res = await runWithMiniflareDurableObjectGates(state, () => object.fetch(new Request("http://localhost/")) ); expect(await res.text()).toBe("4");
-
🥷 Don't construct corresponding Durable Object instance when calling
Miniflare#getDurableObjectStorage(). This allows you to seed data before your Durable Object's constructor is invoked. Closes issue #300, thanks @spigaz. -
☑️ Add support for
WebSocket#readyStateandWebSocket.READY_STATE_{CONNECTING,OPEN,CLOSING,CLOSED}constants. Note these constant names intentionally deviate from the spec to match the Workers runtime. -
📜 Add persistent history to the REPL. This respects the
MINIFLARE_REPL_HISTORY,MINIFLARE_REPL_HISTORY_SIZE, andMINIFLARE_REPL_MODEenvironment variables based on Node's. -
💵 Add support for
Range,If-Modified-SinceandIf-None-Matchheaders onRequests toCache#match. Closes issue #246.
Fixes
- Don't wait for
waitUntilPromises to resolve before opening WebSocket connections - Allow WebSockets to be
close()d on receiving acloseevent. Closes issue #331, thanks @awthwathje. - Ensure calling
WebSocket#close()before returning a WebSocket response sends the correct close code and reason. - Fix delivery of incoming
WebSocketerrorevents - Ensure only scheduled Durable Object alarms are flushed. Previously, flushing all alarms would attempt to execute the
alarmhandler of every constructed Durable Object instance, even if that instance hadn't scheduled an alarm, or didn't have analarmhandler. - Delay scheduled missed alarms. Previously, if Durable Object persistence was enabled, and an alarm should've executed when Miniflare wasn't running, Miniflare may have crashed on startup. Closes issue #359, thanks @AlCalzone.
- Allow empty-chunk writes to
IdentityTransformStream. Closes issue #374, thanks @cdloh. - Don't hang when fetching from Durable Objects with fake-timers installed. Closes issue #190, thanks @vlovich.
- Match unimplemented
Request/Responseproperties with the Workers runtime. Specifically, throw unimplemented errors when attempting to accessRequest#{context,mode,credentials,integrity,cache}andResponse#{type,useFinalUrl}. - Discard
Content-Length: NaNheaders as a temporary workaround until cloudflare/kv-asset-handler#295 is released. Closes honojs/hono#520, thanks @Cherry. - Return byte streams when
tee()ing byte streams to match the behaviour of the Workers runtime. Closes issues #317 and #375. - Throw
TypeErrorwhen callingFetcher#fetchwith an illegal this to match the behaviour of the Workers runtime.
v2.8.2
Fixes
- Allow WebSocket client connection errors to be caught. Closes issue #229, thanks @viorel-d.
- Return
Responses with immutable headers fromcache.matchs. Closes issue #365, thanks @AlCalzone. - Ensure
request.cf.clientAcceptEncodingis always astring. Closes issue #362, thanks @GregBrimble.
v2.8.1
Fixes
- Add missing
@miniflare/queuesdependencies. Closes issue #360, thanks @AlCalzone for the PR. - Fix support for queues in Jest/Vitest testing environments
v2.8.0
Features
- ⚡️ Add custom Vitest testing environment. This behaves almost identically to the Jest environment. However, isolated storage must be installed manually in each test file. Call the
setupMiniflareIsolatedStorage()global function and use the returneddescribefunction instead of the regulardescribe/suitefunctions imported fromvitest. See ⚡️ Vitest Environment for more details. - 🌐 Populate Workers Sites
__STATIC_CONTENT_MANIFESTwith site files instead of an empty object. Miniflare will still disable caching of Workers Sites files to ensure the most up-to-date files are always returned. Closes issues #233, #326 and cloudflare/wrangler2#1632. Thanks @ItalyPaleAle, @Skye-31, @CraigglesO, @Hexstream and @PolariTOON. - ⏱ Add global
getMiniflareWaitUntil()method andExecutionContextclass to the Jest and Vitest testing environments. This can be used toawaitthe results ofwaitUntiledPromises in tests. See 🤹️ Jest Environment and ⚡️ Vitest Environment for more details. Closes issue #202, thanks @jamesarosen and @CraigglesO for the PR. - ⏳ Match Web Streams implementations with Workers runtime, closes issue #168, thanks @leviwolfe:
- Add support for the non-standard
IdentityTransformStreamclass. - Add support for the
streams_enable_constructorscompatibility flag.ReadableStreamandWritableStreamconstructors will throw unless this flag is enabled.ReadableByteStreamController,ReadableStreamBYOBRequest,ReadableStreamDefaultControllerandWritableStreamDefaultControllerwill only be included in the sandbox if this flag is enabled. - Add support for the
transformstream_enable_standard_constructorcompatibility flag.TransformStreamwill behave likeIdentityTransformStreamif this isn't enabled, ignoring custom transformers. Iftransformstream_enable_standard_constructoris set, butstreams_enable_constructorsisn't, theTransformStreamconstructor will throw.TransformStreamDefaultControllerwill only be included in the sandbox if both flags are enabled. - Add support for BYOB reads to the non-standard
FixedLengthStreamclass.
- Add support for the non-standard
- 🇬🇧 Add support for Queues. Docs coming soon™... 👀
- 🙉 Allow calls to
addEventListener,removeEventListeneranddispatchEventin modules mode. Please note, callingaddEventListenerwith a special event type (e.g.fetch,scheduled) will log a warning prompting you to use theexport defaultsyntax. Closes issue #207, thanks @Electroid. - 🍟 Add experimental and highly-inaccurate request CPU time measurements. These are not representative of deployed worker performance, should only be used for relative comparisons, and may be removed in the future. Enable measurements with the
--inaccurate-cpu/[miniflare] inaccurate_cpu/inaccurateCpuoption. Closes issue #161. Thanks @alexandernst and @y21. - 🦄 Automatically enable watch mode when
live_reload = trueis set inwrangler.toml.
Fixes
- Return
Responses with immutable headers fromfetches to Durable Objects and service bindings. Closes issue #346, thanks @Cherry. - Fix
CryptoKey#algorithm.nameproperty ofNODE-ED25519keys. Closes issue panva/jose#446, thanks @ItalyPaleAle. - Disable automatic insertion of
Sec-WebSocket-Protocolheader. Closes issue #179, thanks @aboodman and @grgbkr. - Return
Content-Lengthheader is customContent-Encodingis specified. Closes issue #313, thanks @vlovich. - Require
"automatic"instead of"auto"for theencodeBodyoption when constructingRequests. Closes issue #357, thanks @GregBrimble for the PR. - Remove
request.cf.cacheTtl/request.cf.cacheTtlByStatussupport from the Cache API to match the behaviour of the Workers runtime, which only supportsrequest.cf.cacheKey.
v2.7.1
Fixes
- Ensure initialisation is complete before tear down in
Miniflare#dispose(). Closes issue #341, thanks @vlovich. - Ensure
DurableObjectTransactionoperations are executed in program order. Closes issue #344, thanks @vlovich.
v2.7.0
⚠️ Miniflare's minimum supported Node.js version is now16.13.0. This was the first LTS release of Node.js 16.We recommend you use the latest Node.js version if possible, as Cloudflare Workers use a very up-to-date version of V8. Consider using a Node.js version manager such as https://volta.sh/ or https://github.com/nvm-sh/nvm.
Features
-
🎉 Add support for easily mocking outbound
fetchrequests. See 🕸 Web Standards for more details. Closes issue #162, thanks @william1616 for the PR.test("mocks fetch", async () => { // Get correctly set up `MockAgent` const fetchMock = getMiniflareFetchMock(); // Throw when no matching mocked request is found fetchMock.disableNetConnect(); // Mock request to https://example.com/thing const origin = fetchMock.get("https://example.com"); origin.intercept({ method: "GET", path: "/thing" }).reply(200, "Mocked response!"); const res = await fetch("https://example.com/thing"); const text = await res.text(); expect(text).toBe("Mocked response!"); });
-
🚽 Add support to immediately invoke ("flush") scheduled Durable Object alarms in the 🤹 Jest Environment. Closes issue #322, thanks @robertcepa and @CraigglesO for the PR.
test("flushes alarms", async () => { // Get Durable Object stub const env = getMiniflareBindings(); const id = env.TEST_OBJECT.newUniqueId(); const stub = env.TEST_OBJECT.get(id); // Schedule Durable Object alarm await stub.fetch("http://localhost/"); // Flush all alarms... await flushMiniflareDurableObjectAlarms(); // ...or specify an array of `DurableObjectId`s to flush await flushMiniflareDurableObjectAlarms([id]); });
-
🪣 Add support for R2 bucket bindings to the 🤹 Jest Environment. Closes issue #305, thanks @Cerberus for the PR.
-
2️⃣ Add support for Wrangler 2's
routesproperty. Closes issue #254, thanks @jrencz for the PR. -
⚠️ Upgradeundicito5.9.1. Thanks @yusukebe and @cameron-robey for the PRs.
Fixes
- Return custom
Content-Encodings, closes issue #312, thanks @vlovich. - Fix reading symlinked files from Miniflare's file-system storage. Closes issue #318, thanks @CraigglesO for the PR.
- Display all accessible addresses when listening on host
0.0.0.0. Closes issue cloudflare/wrangler2#1652, thanks @Skye-31 for the PR. - Fix unbounded recursion when calling
Date.now()/new Date()without--actual-timeflag. Closes issue #314, thanks @WalshyDev and @AggressivelyMeows. - Preserve full path in
File#namefield. Thanks @yusefnapora for the PR. - Change underlying glob matching implementation to
picomatch. Closes issue #244, thanks @jed and @cometkim for the PR. - Fix
NotSupportedErrorwhen using theNODE-ED25519algorithm in recent versions of Node.js. Closes issue #310, thanks @yusefnapora for the PR.