Skip to content

Commit

Permalink
[miniflare] fix: make the magic proxy able to serialize objects conta…
Browse files Browse the repository at this point in the history
…ining functions
  • Loading branch information
dario-piotrowicz authored and RamIdeas committed May 8, 2024
1 parent c0b057b commit ca631ee
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/wet-taxis-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"miniflare": patch
---

fix: make the magic proxy able to serialize objects containing functions
25 changes: 25 additions & 0 deletions packages/miniflare/src/workers/core/proxy.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,37 @@ function isPlainObject(value: unknown) {
if(value?.constructor?.name === 'RpcStub') {
return false;
}
if(isObject(value)) {
const valueAsRecord = value as Record<string, unknown>;
if (objectContainsFunctions(valueAsRecord)){
return false;
}
}
return (
proto === Object.prototype ||
proto === null ||
Object.getOwnPropertyNames(proto).sort().join("\0") === objectProtoNames
);
}
function objectContainsFunctions(obj: Record<string, unknown>): boolean {
for(const [, entry] of Object.entries(obj)) {
if(typeof entry === 'function') {
return true;
}
if(isObject(entry)) {
if(objectContainsFunctions(entry as Record<string, unknown>)) {
return false;
}
}
}

return false;
}

function isObject(value: unknown) {
return value && typeof value === 'object';
}

function getType(value: unknown) {
return Object.prototype.toString.call(value).slice(8, -1); // `[object <type>]`
}
Expand Down
92 changes: 92 additions & 0 deletions packages/miniflare/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,98 @@ test("Miniflare: getBindings() returns wrapped bindings", async (t) => {

t.is(helloWorld, 'Hello World');
});
test("Miniflare: getBindings() handles wrapped bindings returning objects containing functions", async (t) => {
const mf = new Miniflare({
workers: [
{
wrappedBindings: {
Greeter: {
scriptName: "greeter-obj-implementation",
},
},
modules: true,
script: "",
},
{
modules: true,
name: "greeter-obj-implementation",
script: `
export default function (env) {
const objWithFunction = {
sayHello: (name) => {
return "Hello " + name;
}
};
return objWithFunction;
}
`,
},
],
});
t.teardown(() => mf.dispose());

interface Env {
Greeter: {
sayHello: (str: string) => string,
},
};
const { Greeter } = await mf.getBindings<Env>();

const helloWorld = Greeter.sayHello('World');

t.is(helloWorld, 'Hello World');
});
test("Miniflare: getBindings() handles wrapped bindings returning objects containing nested functions", async (t) => {
const mf = new Miniflare({
workers: [
{
wrappedBindings: {
Greeter: {
scriptName: "greeter-obj-implementation",
},
},
modules: true,
script: "",
},
{
modules: true,
name: "greeter-obj-implementation",
script: `
export default function (env) {
const objWithFunction = {
obj: {
obj1: {
obj2: {
sayHello: (name) => "Hello " + name + " from a nested function"
}
}
}
};
return objWithFunction;
}
`,
},
],
});
t.teardown(() => mf.dispose());

interface Env {
Greeter: {
obj: {
obj1: {
obj2: {
sayHello: (str: string) => string,
}
}
}
},
};
const { Greeter } = await mf.getBindings<Env>();

const helloWorld = Greeter.obj.obj1.obj2.sayHello('World');

t.is(helloWorld, 'Hello World from a nested function');
});
test("Miniflare: getWorker() allows dispatching events directly", async (t) => {
const mf = new Miniflare({
modules: true,
Expand Down

0 comments on commit ca631ee

Please sign in to comment.