diff --git a/src/extension/__tests__/rpc.test.ts b/src/extension/__tests__/rpc.test.ts index 36d468577..2aa8b89c0 100644 --- a/src/extension/__tests__/rpc.test.ts +++ b/src/extension/__tests__/rpc.test.ts @@ -1,11 +1,6 @@ import { MessageAdapter } from "../messageAdapters"; import { ApolloClientDevtoolsRPCMessage, MessageType } from "../messages"; -import { - RPCMessage, - createRPCBridge, - createRpcClient, - createRpcHandler, -} from "../rpc"; +import { createRPCBridge, createRpcClient, createRpcHandler } from "../rpc"; interface TestAdapter extends MessageAdapter< @@ -67,7 +62,9 @@ function createBridge(adapter1: TestAdapter, adapter2: TestAdapter) { } test("can send and receive rpc messages", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; // Since these are sent over separate instances in the real world, we want to // simulate that as best as we can with separate adapters const handlerAdapter = createTestAdapter(); @@ -85,7 +82,9 @@ test("can send and receive rpc messages", async () => { }); test("resolves async handlers", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; // Since these are sent over separate instances in the real world, we want to // simulate that as best as we can with separate adapters const handlerAdapter = createTestAdapter(); @@ -109,7 +108,9 @@ test("resolves async handlers", async () => { }); test("does not mistakenly handle messages from different rpc calls", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const clientAdapter = createTestAdapter(); const client = createRpcClient(clientAdapter); @@ -132,7 +133,9 @@ test("does not mistakenly handle messages from different rpc calls", async () => }); test("rejects when handler throws error", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; // Since these are sent over separate instances in the real world, we want to // simulate that as best as we can with separate adapters const handlerAdapter = createTestAdapter(); @@ -152,7 +155,9 @@ test("rejects when handler throws error", async () => { }); test("rejects when async handler rejects", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; // Since these are sent over separate instances in the real world, we want to // simulate that as best as we can with separate adapters const handlerAdapter = createTestAdapter(); @@ -170,9 +175,12 @@ test("rejects when async handler rejects", async () => { }); test("can handle multiple rpc messages", async () => { - type Message = - | RPCMessage<"add", { x: number; y: number }, number> - | RPCMessage<"shout", { text: string }, string>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + // while we're at it, let's have this one return a Promise in the definition + // it should not matter for the implementation + shout({ text }: { text: string }): Promise; + }; const handlerAdapter = createTestAdapter(); const clientAdapter = createTestAdapter(); @@ -192,7 +200,9 @@ test("can handle multiple rpc messages", async () => { }); test("only allows one handler per type", async () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const handle = createRpcHandler(createTestAdapter()); @@ -204,7 +214,9 @@ test("only allows one handler per type", async () => { }); test("ignores messages that don't originate from devtools", () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -221,7 +233,9 @@ test("ignores messages that don't originate from devtools", () => { // actor message type collides with an rpc message type, we want to ignore the // actor message type. test("ignores messages that aren't rpc messages", () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -239,7 +253,9 @@ test("ignores messages that aren't rpc messages", () => { }); test("does not add listener to adapter until first subscribed handler", () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -252,10 +268,11 @@ test("does not add listener to adapter until first subscribed handler", () => { }); test("adds a single listener regardless of active handlers", () => { - type Message = - | RPCMessage<"add", { x: number; y: number }, number> - | RPCMessage<"subtract", { x: number; y: number }, number> - | RPCMessage<"shout", { text: string }, string>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + subtract({ x, y }: { x: number; y: number }): number; + shout({ text }: { text: string }): string; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -270,7 +287,9 @@ test("adds a single listener regardless of active handlers", () => { }); test("can unsubscribe from a handler by calling the returned function", () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -297,9 +316,10 @@ test("can unsubscribe from a handler by calling the returned function", () => { }); test("removes listener on adapter when unsubscribing from last handler", () => { - type Message = - | RPCMessage<"add", { x: number; y: number }, number> - | RPCMessage<"shout", { text: string }, string>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + shout({ text }: { text: string }): string; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -315,7 +335,9 @@ test("removes listener on adapter when unsubscribing from last handler", () => { }); test("re-adds listener on adapter when subscribing after unsubscribing", () => { - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const handle = createRpcHandler(adapter); @@ -332,7 +354,9 @@ test("re-adds listener on adapter when subscribing after unsubscribing", () => { test("times out if no message received within default timeout", async () => { jest.useFakeTimers(); - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const client = createRpcClient(adapter); @@ -350,7 +374,9 @@ test("times out if no message received within default timeout", async () => { test("times out if no message received within configured timeout", async () => { jest.useFakeTimers(); - type Message = RPCMessage<"add", { x: number; y: number }, number>; + type Message = { + add({ x, y }: { x: number; y: number }): number; + }; const adapter = createTestAdapter(); const client = createRpcClient(adapter); diff --git a/src/extension/devtools/devtools.ts b/src/extension/devtools/devtools.ts index 6de0aed01..4a1563bc0 100755 --- a/src/extension/devtools/devtools.ts +++ b/src/extension/devtools/devtools.ts @@ -84,7 +84,7 @@ function startRequestInterval(ms = 500) { let id: NodeJS.Timeout; async function getClientData() { - const payload = await rpcClient.request("getClientOperations", {}); + const payload = await rpcClient.request("getClientOperations", undefined); if (panelWindow) { panelWindow.send({ type: "update", payload }); diff --git a/src/extension/messages.ts b/src/extension/messages.ts index b9ead50b2..9ea6be5dc 100644 --- a/src/extension/messages.ts +++ b/src/extension/messages.ts @@ -1,7 +1,6 @@ import { ExplorerResponse } from "../types"; import { GetStates, GetContext } from "../application/stateMachine"; import { DevtoolsMachine } from "../application/machines"; -import { RPCMessage } from "./rpc"; export interface MessageFormat { type: string; @@ -76,11 +75,9 @@ export type PanelMessage = | { type: "devtoolsStateChanged"; state: GetStates } | { type: "update"; payload: GetContext["clientContext"] }; -export type DevtoolsRPCMessage = RPCMessage< - "getClientOperations", - Record, - GetContext["clientContext"] ->; +export type DevtoolsRPCMessage = { + getClientOperations(): GetContext["clientContext"]; +}; export function isApolloClientDevtoolsMessage< Message extends Record, diff --git a/src/extension/rpc.ts b/src/extension/rpc.ts index f7ded5140..cd62e7b13 100644 --- a/src/extension/rpc.ts +++ b/src/extension/rpc.ts @@ -17,32 +17,20 @@ type RPCResponseMessageFormat = | { sourceId: number; result: unknown } | { sourceId: number; error: unknown }; -export type RPCMessage< - Name extends string, - Params extends RPCParams, - ReturnType, -> = { - __name: Name; - __params: Params; - __returnType: ReturnType; -}; +type MessageCollection = Record SafeAny>; -export interface RpcClient< - Messages extends RPCMessage, -> { - request: ( +export interface RpcClient { + request: ( name: TName, - params: Extract["__params"], + params: Parameters[0], options?: { timeoutMs?: number } - ) => Promise["__returnType"]>; + ) => Promise>>; } let nextMessageId = 0; const DEFAULT_TIMEOUT = 30_000; -export function createRpcClient< - Messages extends RPCMessage, ->( +export function createRpcClient( adapter: MessageAdapter< ApolloClientDevtoolsRPCMessage > @@ -50,13 +38,13 @@ export function createRpcClient< return { request: (name, params, options) => { return Promise.race([ - new Promise((_, reject) => { + new Promise((_, reject) => { setTimeout( () => reject(new Error("Timeout waiting for message")), options?.timeoutMs ?? DEFAULT_TIMEOUT ); }), - new Promise((resolve, reject) => { + new Promise((resolve, reject) => { const id = ++nextMessageId; const removeListener = adapter.addListener((message) => { @@ -87,9 +75,7 @@ export function createRpcClient< }; } -export function createRpcHandler< - Messages extends RPCMessage, ->( +export function createRpcHandler( adapter: MessageAdapter< ApolloClientDevtoolsRPCMessage > @@ -119,14 +105,13 @@ export function createRpcHandler< } } - return function < - TName extends Messages["__name"], - TReturnType = Extract["__returnType"], - >( + return function ( name: TName, execute: ( - params: Extract["__params"] - ) => NoInfer | Promise> + params: Parameters[0] + ) => + | NoInfer>> + | Promise>>> ) { if (listeners.has(name)) { throw new Error("Only one rpc handler can be registered per type");