Skip to content

Commit

Permalink
fix: allow getPlatformProxy to handle RPC calls returning objects
Browse files Browse the repository at this point in the history
  • Loading branch information
dario-piotrowicz committed Jul 20, 2024
1 parent 5462ead commit d258ac1
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 2 deletions.
9 changes: 9 additions & 0 deletions .changeset/polite-dodos-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"miniflare": patch
---

fix: fix the magic proxy no longer disposing of the `dispose` and `asyncDispose` symbol properties of `RpcProperty`s

Fix the fact that from https://github.com/cloudflare/workers-sdk/pull/5670 the magic proxy no longer disposes the
`dispose` and `asyncDispose` properties found on `RpcProperty` objects causing serialization issues when trying
to proxy plain objects
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,15 @@ describe("getPlatformProxy - env", () => {
rpc = env.MY_RPC as unknown as EntrypointService;
return dispose;
});
it("can call RPC methods directly", async () => {
it("can call RPC methods returning a string", async () => {
expect(await rpc.sum([1, 2, 3])).toMatchInlineSnapshot(`6`);
});
it("can call RPC methods returning an object", async () => {
expect(await rpc.sumObj([1, 2, 3, 5])).toEqual({
isObject: true,
value: 11,
});
});
it("can call RPC methods returning a Response", async () => {
const resp = await rpc.asJsonResponse([1, 2, 3]);
expect(resp.status).toMatchInlineSnapshot(`200`);
Expand Down
8 changes: 8 additions & 0 deletions fixtures/get-platform-proxy/workers/rpc-worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export class NamedEntrypoint extends WorkerEntrypoint {
sum(args: number[]): number {
return args.reduce((a, b) => a + b);
}

sumObj(args: number[]): { isObject: true; value: number } {
return {
isObject: true,
value: args.reduce((a, b) => a + b),
};
}

asJsonResponse(args: unknown): {
status: number;
text: () => Promise<string>;
Expand Down
17 changes: 16 additions & 1 deletion packages/miniflare/src/workers/core/proxy.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,22 @@ export class ProxyServer implements DurableObject {
}
assert(Array.isArray(args));
try {
if (["RpcProperty", "RpcStub"].includes(func.constructor.name)) {
if (func.constructor.name === "RpcProperty") {
result = func(...args);
// Wrap RpcPromise instances with a standard promise to support serialisation
result = new Promise((resolve, reject) =>
(result as Promise<any>)
.then((v) => {
// Drop `Symbol.dispose` and `Symbol.asyncDispose` so that the resulting value can be serialised.
if (v.hasOwnProperty(Symbol.dispose)) delete v[Symbol.dispose];
if (v.hasOwnProperty(Symbol.asyncDispose))
delete v[Symbol.asyncDispose];

resolve(v);
})
.catch(reject)
);
} else if (func.constructor.name === "RpcStub") {
// let's resolve RpcPromise instances right away (to support serialization)
result = await func(...args);
} else {
Expand Down
47 changes: 47 additions & 0 deletions packages/miniflare/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,53 @@ test("Miniflare: service binding to named entrypoint", async (t) => {
});
});

test("Miniflare: service binding to named entrypoint that implement a method returning a plain object", async (t) => {
const mf = new Miniflare({
workers: [
{
name: "a",
serviceBindings: {
RPC_SERVICE: { name: "b", entrypoint: "RpcEntrypoint" },
},
compatibilityFlags: ["rpc"],
modules: true,
script: `
export default {
async fetch(request, env) {
const obj = await env.RPC_SERVICE.getObject();
return Response.json({ obj });
}
}
`,
},
{
name: "b",
modules: true,
script: `
import { WorkerEntrypoint } from "cloudflare:workers";
export class RpcEntrypoint extends WorkerEntrypoint {
getObject() {
return {
isPlainObject: true,
value: 123,
}
}
}
`,
},
],
});
t.teardown(() => mf.dispose());

const bindings = await mf.getBindings<{ RPC_SERVICE: any }>();
const obj = await bindings.RPC_SERVICE.getObject();
t.deepEqual(obj, {
isPlainObject: true,
value: 123,
});
});

test("Miniflare: custom outbound service", async (t) => {
const mf = new Miniflare({
workers: [
Expand Down

0 comments on commit d258ac1

Please sign in to comment.