@metamask/json-rpc-engine
Version:
A tool for processing JSON-RPC messages
1 lines • 4.46 kB
Source Map (JSON)
{"version":3,"file":"createAsyncMiddleware.mjs","sourceRoot":"","sources":["../src/createAsyncMiddleware.ts"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,qBAAqB,CAInC,eAAuD;IAEvD,kEAAkE;IAClE,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC5C,+CAA+C;QAC/C,qDAAqD;QACrD,kBAAkB;QAClB,IAAI,kBAA8B,CAAC;QACnC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAChD,kBAAkB,GAAG,OAAO,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,IAAI,qBAAqB,GAAY,IAAI,CAAC;QAC1C,IAAI,aAAa,GAAG,KAAK,CAAC;QAE1B,0DAA0D;QAC1D,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;YAC3B,aAAa,GAAG,IAAI,CAAC;YAErB,uEAAuE;YACvE,yDAAyD;YACzD,IAAI,CAAC,CAAC,yBAAyB,EAAE,EAAE;gBACjC,4DAA4D;gBAC5D,qBAAqB,GAAG,yBAAyB,CAAC;gBAClD,kBAAkB,EAAE,CAAC;YACvB,CAAC,CAAC,CAAC;YACH,OAAO,WAAW,CAAC;QACrB,CAAC,CAAC;QAEF,IAAI;YACF,MAAM,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;YAEpD,IAAI,aAAa,EAAE;gBACjB,MAAM,WAAW,CAAC,CAAC,kDAAkD;gBACpE,qBAA+C,CAAC,IAAI,CAAC,CAAC;aACxD;iBAAM;gBACL,GAAG,CAAC,IAAI,CAAC,CAAC;aACX;SACF;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,qBAAqB,EAAE;gBACxB,qBAA+C,CAAC,KAAK,CAAC,CAAC;aACzD;iBAAM;gBACL,GAAG,CAAC,KAAK,CAAC,CAAC;aACZ;SACF;IACH,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n Json,\n JsonRpcParams,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\n\nimport type {\n JsonRpcEngineReturnHandler,\n JsonRpcMiddleware,\n} from './JsonRpcEngine';\n\nexport type AsyncJsonRpcEngineNextCallback = () => Promise<void>;\n\nexport type AsyncJsonrpcMiddleware<\n Params extends JsonRpcParams,\n Result extends Json,\n> = (\n request: JsonRpcRequest<Params>,\n response: PendingJsonRpcResponse<Result>,\n next: AsyncJsonRpcEngineNextCallback,\n) => Promise<void>;\n\ntype ReturnHandlerCallback = Parameters<JsonRpcEngineReturnHandler>[0];\n\n/**\n * JsonRpcEngine only accepts callback-based middleware directly.\n * createAsyncMiddleware exists to enable consumers to pass in async middleware\n * functions.\n *\n * Async middleware have no \"end\" function. Instead, they \"end\" if they return\n * without calling \"next\". Rather than passing in explicit return handlers,\n * async middleware can simply await \"next\", and perform operations on the\n * response object when execution resumes.\n *\n * To accomplish this, createAsyncMiddleware passes the async middleware a\n * wrapped \"next\" function. That function calls the internal JsonRpcEngine\n * \"next\" function with a return handler that resolves a promise when called.\n *\n * The return handler will always be called. Its resolution of the promise\n * enables the control flow described above.\n *\n * @param asyncMiddleware - The asynchronous middleware function to wrap.\n * @returns The wrapped asynchronous middleware function, ready to be consumed\n * by JsonRpcEngine.\n */\nexport function createAsyncMiddleware<\n Params extends JsonRpcParams,\n Result extends Json,\n>(\n asyncMiddleware: AsyncJsonrpcMiddleware<Params, Result>,\n): JsonRpcMiddleware<Params, Result> {\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return async (request, response, next, end) => {\n // nextPromise is the key to the implementation\n // it is resolved by the return handler passed to the\n // \"next\" function\n let resolveNextPromise: () => void;\n const nextPromise = new Promise<void>((resolve) => {\n resolveNextPromise = resolve;\n });\n\n let returnHandlerCallback: unknown = null;\n let nextWasCalled = false;\n\n // This will be called by the consumer's async middleware.\n const asyncNext = async () => {\n nextWasCalled = true;\n\n // We pass a return handler to next(). When it is called by the engine,\n // the consumer's async middleware will resume executing.\n next((runReturnHandlersCallback) => {\n // This callback comes from JsonRpcEngine._runReturnHandlers\n returnHandlerCallback = runReturnHandlersCallback;\n resolveNextPromise();\n });\n return nextPromise;\n };\n\n try {\n await asyncMiddleware(request, response, asyncNext);\n\n if (nextWasCalled) {\n await nextPromise; // we must wait until the return handler is called\n (returnHandlerCallback as ReturnHandlerCallback)(null);\n } else {\n end(null);\n }\n } catch (error) {\n if (returnHandlerCallback) {\n (returnHandlerCallback as ReturnHandlerCallback)(error);\n } else {\n end(error);\n }\n }\n };\n}\n"]}