diff --git a/.changeset/gentle-chairs-pull.md b/.changeset/gentle-chairs-pull.md new file mode 100644 index 000000000000..8abe8d58b96e --- /dev/null +++ b/.changeset/gentle-chairs-pull.md @@ -0,0 +1,21 @@ +--- +"miniflare": minor +--- + +feature: add a `getCf` method to Miniflare instances + +add a new `getCf` method attached to instances of `Miniflare`, this `getCf` returns +the `cf` object that the Miniflare instance provides to the actual workers and it +depends of the core option of the same name + +Example: + +```ts +import { Miniflare } from "miniflare"; + +const mf = new Miniflare({ ... }); + +const cf = await mf.getCf(); + +console.log(`country = ${cf.country} ; colo = ${cf.colo}`); // logs 'country = GB ; colo = LHR' +``` diff --git a/packages/miniflare/README.md b/packages/miniflare/README.md index b23ee9ea6b7f..163fd1cae65b 100644 --- a/packages/miniflare/README.md +++ b/packages/miniflare/README.md @@ -406,7 +406,7 @@ parameter in module format Workers. await this.STORE.fetch(this.baseURL + key, { method: "DELETE" }); } } - + // env has the type { STORE: Fetcher, NAMESPACE?: string } export default function (env) { return new MiniKV(env); @@ -770,3 +770,7 @@ defined at the top-level. `Miniflare#dispatchFetch()` cannot be called. Additionally, calling this function will invalidate any values returned by the `Miniflare#get*()` methods, preventing them from being used. + +- `getCf(): Promise>` + + Returns the same object returned from incoming `Request`'s `cf` property. This object depends on the `cf` property from `SharedOptions`. diff --git a/packages/miniflare/src/index.ts b/packages/miniflare/src/index.ts index e4caa9505c31..4eaea4b778d7 100644 --- a/packages/miniflare/src/index.ts +++ b/packages/miniflare/src/index.ts @@ -615,6 +615,8 @@ export class Miniflare { #runtimeDispatcher?: Dispatcher; #proxyClient?: ProxyClient; + #cfObject?: Record = {}; + // Path to temporary directory for use as scratch space/"in-memory" Durable // Object storage. Note this may not exist, it's up to the consumers to // create this if needed. Deleted on `dispose()`. @@ -962,6 +964,7 @@ export class Miniflare { const sharedOpts = this.#sharedOpts; sharedOpts.core.cf = await setupCf(this.#log, sharedOpts.core.cf); + this.#cfObject = sharedOpts.core.cf; const durableObjectClassNames = getDurableObjectClassNames(allWorkerOpts); const wrappedBindingNames = getWrappedBindingNames( @@ -1324,6 +1327,13 @@ export class Miniflare { return this.#waitForReady(); } + async getCf(): Promise> { + this.#checkDisposed(); + await this.ready; + + return JSON.parse(JSON.stringify(this.#cfObject)); + } + async getInspectorURL(): Promise { this.#checkDisposed(); await this.ready; diff --git a/packages/miniflare/test/index.spec.ts b/packages/miniflare/test/index.spec.ts index 17d5c0f6bfdc..4d50a6fc04f7 100644 --- a/packages/miniflare/test/index.spec.ts +++ b/packages/miniflare/test/index.spec.ts @@ -733,7 +733,8 @@ test("Miniflare: python modules", async (t) => { { type: "PythonModule", path: "index", - contents: "from test_module import add; from js import Response;\ndef fetch(request):\n return Response.new(add(2,2))", + contents: + "from test_module import add; from js import Response;\ndef fetch(request):\n return Response.new(add(2,2))", }, { type: "PythonModule", @@ -741,9 +742,7 @@ test("Miniflare: python modules", async (t) => { contents: `def add(a, b):\n return a + b`, }, ], - compatibilityFlags: [ - "experimental" - ] + compatibilityFlags: ["experimental"], }); t.teardown(() => mf.dispose()); const res = await mf.dispatchFetch("http://localhost"); @@ -1736,3 +1735,29 @@ test("Miniflare: prohibits invalid wrapped bindings", async (t) => { } ); }); + +test("Miniflare: getCf() returns a standard cf object", async (t) => { + const mf = new Miniflare({ script: "", modules: true }); + t.teardown(() => mf.dispose()); + + const cf = await mf.getCf(); + t.like(cf, { + colo: "DFW", + city: "Austin", + regionCode: "TX", + }); +}); + +test("Miniflare: getCf() returns a user provided cf object", async (t) => { + const mf = new Miniflare({ + script: "", + modules: true, + cf: { + myFakeField: "test", + }, + }); + t.teardown(() => mf.dispose()); + + const cf = await mf.getCf(); + t.deepEqual(cf, { myFakeField: "test" }); +});