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 aPromise
that resolves to an array of activeDurableObjectId
s for theTEST_OBJECT
namespace. Closes issue #384, thanks @DaniFoldi for the PR.
Fixes
- Strip quotes from R2
onlyIf
header values. Closes issue #402, thanks @vincentbernat and @CraigglesO for the PR. - Disable
r2Persist
option 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/r2
dependency to@miniflare/shared-test-environment
package. Thanks @askoufis for the PR. - Return correct
Content-Length
fromCache#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
workerd
compatibility date, but not in the future, log a warning, and fallback to the latest supported date instead. - Resolve
Miniflare#ready
'sPromise
with theURL
ofworkerd
'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.log
ging 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 dev
has additional features such as automatic bundling and TypeScript support. For now, usewrangler dev --experimental-local
.
Miniflare
API Changes
-
kvNamespaces
now 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,
r2Buckets
now 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 + }, });
-
workerd
requires all modules to be known ahead of time, so Miniflare will parse your JavaScript to search for module dependencies when settingmodules
totrue
. This has some limitations:- Dynamic
import()
with non-literal arguments is unsupported. - Any call to a function named
require
in a CommonJS module will be searched, even if it's not actually the globalrequire
function, 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
-
mounts
has been removed and replaced with theworkers
option.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#readyState
andWebSocket.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_MODE
environment variables based on Node's. -
💵 Add support for
Range
,If-Modified-Since
andIf-None-Match
headers onRequest
s toCache#match
. Closes issue #246.
Fixes
- Don't wait for
waitUntil
Promise
s to resolve before opening WebSocket connections - Allow WebSockets to be
close()
d on receiving aclose
event. 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
WebSocket
error
events - Ensure only scheduled Durable Object alarms are flushed. Previously, flushing all alarms would attempt to execute the
alarm
handler of every constructed Durable Object instance, even if that instance hadn't scheduled an alarm, or didn't have analarm
handler. - 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
/Response
properties with the Workers runtime. Specifically, throw unimplemented errors when attempting to accessRequest#{context,mode,credentials,integrity,cache}
andResponse#{type,useFinalUrl}
. - Discard
Content-Length: NaN
headers 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
TypeError
when callingFetcher#fetch
with 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
Response
s with immutable headers fromcache.match
s. Closes issue #365, thanks @AlCalzone. - Ensure
request.cf.clientAcceptEncoding
is always astring
. Closes issue #362, thanks @GregBrimble.
v2.8.1
Fixes
- Add missing
@miniflare/queues
dependencies. 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 returneddescribe
function instead of the regulardescribe
/suite
functions imported fromvitest
. See ⚡️ Vitest Environment for more details. - 🌐 Populate Workers Sites
__STATIC_CONTENT_MANIFEST
with 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 andExecutionContext
class to the Jest and Vitest testing environments. This can be used toawait
the results ofwaitUntil
edPromise
s 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
IdentityTransformStream
class. - Add support for the
streams_enable_constructors
compatibility flag.ReadableStream
andWritableStream
constructors will throw unless this flag is enabled.ReadableByteStreamController
,ReadableStreamBYOBRequest
,ReadableStreamDefaultController
andWritableStreamDefaultController
will only be included in the sandbox if this flag is enabled. - Add support for the
transformstream_enable_standard_constructor
compatibility flag.TransformStream
will behave likeIdentityTransformStream
if this isn't enabled, ignoring custom transformers. Iftransformstream_enable_standard_constructor
is set, butstreams_enable_constructors
isn't, theTransformStream
constructor will throw.TransformStreamDefaultController
will only be included in the sandbox if both flags are enabled. - Add support for BYOB reads to the non-standard
FixedLengthStream
class.
- Add support for the non-standard
- 🇬🇧 Add support for Queues. Docs coming soon™... 👀
- 🙉 Allow calls to
addEventListener
,removeEventListener
anddispatchEvent
in modules mode. Please note, callingaddEventListener
with a special event type (e.g.fetch
,scheduled
) will log a warning prompting you to use theexport default
syntax. 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
/inaccurateCpu
option. Closes issue #161. Thanks @alexandernst and @y21. - 🦄 Automatically enable watch mode when
live_reload = true
is set inwrangler.toml
.
Fixes
- Return
Response
s with immutable headers fromfetch
es to Durable Objects and service bindings. Closes issue #346, thanks @Cherry. - Fix
CryptoKey#algorithm.name
property ofNODE-ED25519
keys. Closes issue panva/jose#446, thanks @ItalyPaleAle. - Disable automatic insertion of
Sec-WebSocket-Protocol
header. Closes issue #179, thanks @aboodman and @grgbkr. - Return
Content-Length
header is customContent-Encoding
is specified. Closes issue #313, thanks @vlovich. - Require
"automatic"
instead of"auto"
for theencodeBody
option when constructingRequest
s. Closes issue #357, thanks @GregBrimble for the PR. - Remove
request.cf.cacheTtl
/request.cf.cacheTtlByStatus
support 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
DurableObjectTransaction
operations 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
fetch
requests. 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
routes
property. Closes issue #254, thanks @jrencz for the PR. -
⚠️ Upgradeundici
to5.9.1
. Thanks @yusukebe and @cameron-robey for the PRs.
Fixes
- Return custom
Content-Encoding
s, 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-time
flag. Closes issue #314, thanks @WalshyDev and @AggressivelyMeows. - Preserve full path in
File#name
field. Thanks @yusefnapora for the PR. - Change underlying glob matching implementation to
picomatch
. Closes issue #244, thanks @jed and @cometkim for the PR. - Fix
NotSupportedError
when using theNODE-ED25519
algorithm in recent versions of Node.js. Closes issue #310, thanks @yusefnapora for the PR.