@metamask/json-rpc-engine
Version:
A tool for processing JSON-RPC messages
1 lines • 29.1 kB
Source Map (JSON)
{"version":3,"file":"JsonRpcEngine.mjs","sourceRoot":"","sources":["../src/JsonRpcEngine.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,6BAA6B;AAChF,OAAO,gBAAgB,qCAAqC;AAU5D,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,gBAAgB,EACjB,wBAAwB;AA2BzB,MAAM,uBAAuB,GAC3B,qDAAqD,CAAC;AAmBxD;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,gBAAgB;IAYjD;;;;;;;;;;OAUG;IACH,YAAY,EAAE,mBAAmB,KAAwB,EAAE;QACzD,KAAK,EAAE,CAAC;;QAvBV;;WAEG;QACH,qCAAe,KAAK,EAAC;QAErB,4CAAsD;QAE7C,qDAEK;QAeZ,uBAAA,IAAI,6BAAe,EAAE,MAAA,CAAC;QACtB,uBAAA,IAAI,sCAAwB,mBAAmB,MAAA,CAAC;IAClD,CAAC;IAWD;;;;OAIG;IACH,OAAO;QACL,uBAAA,IAAI,iCAAY,CAAC,OAAO,CACtB,CAAC,UAAkD,EAAE,EAAE;YACrD;YACE,gEAAgE;YAChE,iBAAiB;YACjB,SAAS,IAAI,UAAU;gBACvB,OAAO,UAAU,CAAC,OAAO,KAAK,UAAU,EACxC;gBACA,mEAAmE;gBACnE,UAAU,CAAC,OAAO,EAAE,CAAC;aACtB;QACH,CAAC,CACF,CAAC;QACF,uBAAA,IAAI,6BAAe,EAAE,MAAA,CAAC;QACtB,uBAAA,IAAI,8BAAgB,IAAI,MAAA,CAAC;IAC3B,CAAC;IAED;;;;OAIG;IACH,IAAI,CACF,UAA6C;QAE7C,uBAAA,IAAI,qEAAsB,MAA1B,IAAI,CAAwB,CAAC;QAC7B,uBAAA,IAAI,iCAAY,CAAC,IAAI,CAAC,UAAoD,CAAC,CAAC;IAC9E,CAAC;IAmED,MAAM,CACJ,GAGuB,EACvB,QAAoD;QAEpD,uBAAA,IAAI,qEAAsB,MAA1B,IAAI,CAAwB,CAAC;QAE7B,IAAI,QAAQ,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE;YAC9C,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;SAC/D;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACtB,IAAI,QAAQ,EAAE;gBACZ,OAAO,uBAAA,IAAI,4DAAa,MAAjB,IAAI,EACT,GAAG;gBACH,oHAAoH;gBACpH,iIAAiI;gBACjI,QAAmE,CACpE,CAAC;aACH;YACD,OAAO,uBAAA,IAAI,4DAAa,MAAjB,IAAI,EAAc,GAAG,CAAC,CAAC;SAC/B;QAED,IAAI,QAAQ,EAAE;YACZ,OAAO,uBAAA,IAAI,uDAAQ,MAAZ,IAAI,EACT,GAAG,EACH,QAAgE,CACjE,CAAC;SACH;QACD,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACH,YAAY;QACV,uBAAA,IAAI,qEAAsB,MAA1B,IAAI,CAAwB,CAAC;QAE7B,kEAAkE;QAClE,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YACnC,IAAI;gBACF,MAAM,CAAC,eAAe,EAAE,UAAU,EAAE,cAAc,CAAC,GACjD,MAAM,uBAAA,EAAa,2CAAkB,MAA/B,EAAa,EAAmB,GAAG,EAAE,GAAG,EAAE,uBAAA,IAAI,iCAAY,CAAC,CAAC;gBAEpE,IAAI,UAAU,EAAE;oBACd,MAAM,uBAAA,EAAa,4CAAmB,MAAhC,EAAa,EAAoB,cAAc,CAAC,CAAC;oBACvD,OAAO,GAAG,CAAC,eAAe,CAAC,CAAC;iBAC7B;gBAED,kEAAkE;gBAClE,OAAO,IAAI,CAAC,KAAK,EAAE,eAAe,EAAE,EAAE;oBACpC,IAAI;wBACF,MAAM,uBAAA,EAAa,4CAAmB,MAAhC,EAAa,EAAoB,cAAc,CAAC,CAAC;qBACxD;oBAAC,OAAO,KAAK,EAAE;wBACd,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;qBAC/B;oBACD,OAAO,eAAe,EAAE,CAAC;gBAC3B,CAAC,CAAC,CAAC;aACJ;YAAC,OAAO,KAAK,EAAE;gBACd,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;aACnB;QACH,CAAC,CAAC;IACJ,CAAC;IA2ED;;;;;OAKG;IACH,2EAA2E;IAC3E,eAAe;IACf,gDAAgD;IACxC,KAAK,CAAC,cAAc,CAC1B,OAA6C;QAE7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,uBAAA,IAAI,uDAAQ,MAAZ,IAAI,EAAS,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;gBACnC,sEAAsE;gBACtE,8DAA8D;gBAC9D,IAAI,KAAK,IAAI,GAAG,KAAK,SAAS,EAAE;oBAC9B,MAAM,CAAC,KAAK,CAAC,CAAC;iBACf;qBAAM;oBACL,wEAAwE;oBACxE,uDAAuD;oBACvD,OAAO,CAAC,GAAG,CAAC,CAAC;iBACd;YACH,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;CAgRF;;IAhiBG,IAAI,uBAAA,IAAI,kCAAa,EAAE;QACrB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;KAC1C;AACH,CAAC;AA0LD;;;;;;;GAOG;AACH,KAAK,qCACH,QAAkD,EAClD,QAAkE;IAElE,8BAA8B;IAC9B,IAAI;QACF,kFAAkF;QAClF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;YACzB,MAAM,QAAQ,GAAsB;gBAClC;oBACE,EAAE,EAAE,IAAI;oBACR,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,IAAI,YAAY,CACrB,UAAU,CAAC,GAAG,CAAC,cAAc,EAC7B,mEAAmE,CACpE;iBACF;aACF,CAAC;YACF,IAAI,QAAQ,EAAE;gBACZ,OAAO,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;aACjC;YACD,OAAO,QAAQ,CAAC;SACjB;QAED,qEAAqE;QACrE,QAAQ;QACR,MAAM,SAAS,GAAG,CAChB,MAAM,OAAO,CAAC,GAAG;QACf,wDAAwD;QACxD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAC7C,CACF,CAAC,MAAM;QACN,yCAAyC;QACzC,CAAC,QAAQ,EAA+B,EAAE,CAAC,QAAQ,KAAK,SAAS,CAClE,CAAC;QAEF,2BAA2B;QAC3B,IAAI,QAAQ,EAAE;YACZ,OAAO,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;SAClC;QACD,OAAO,SAAS,CAAC;KAClB;IAAC,OAAO,KAAK,EAAE;QACd,IAAI,QAAQ,EAAE;YACZ,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxB;QAED,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AA6BD;;;;;;;;;GASG;AACH,KAAK,gCACH,SAA+C,EAC/C,QAA8D;IAE9D,IACE,CAAC,SAAS;QACV,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QACxB,OAAO,SAAS,KAAK,QAAQ,EAC7B;QACA,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,UAAU,CAAC,GAAG,CAAC,cAAc,EAC7B,6CAA6C,OAAO,SAAS,EAAE,EAC/D,EAAE,OAAO,EAAE,SAAS,EAAE,CACvB,CAAC;QACF,OAAO,QAAQ,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;KAC7D;IAED,IAAI,OAAO,SAAS,CAAC,MAAM,KAAK,QAAQ,EAAE;QACxC,MAAM,KAAK,GAAG,IAAI,YAAY,CAC5B,UAAU,CAAC,GAAG,CAAC,cAAc,EAC7B,2CAA2C,OAAO,SAAS,CAAC,MAAM,EAAE,EACpE,EAAE,OAAO,EAAE,SAAS,EAAE,CACvB,CAAC;QAEF,IAAI,uBAAA,IAAI,0CAAqB,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE;YAC7D,6DAA6D;YAC7D,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;SACvB;QAED,OAAO,QAAQ,CAAC,KAAK,EAAE;YACrB,oEAAoE;YACpE,iCAAiC;YACjC,EAAE,EAAG,SAA4B,CAAC,EAAE,IAAI,IAAI;YAC5C,OAAO,EAAE,KAAK;YACd,KAAK;SACN,CAAC,CAAC;KACJ;SAAM,IACL,uBAAA,IAAI,0CAAqB;QACzB,qBAAqB,CAAC,SAAS,CAAC;QAChC,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAC5B;QACA,IAAI;YACF,MAAM,uBAAA,IAAI,0CAAqB,MAAzB,IAAI,EAAsB,SAAS,CAAC,CAAC;SAC5C;QAAC,OAAO,KAAK,EAAE;YACd,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;SACxB;QACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;KACvB;IACD,IAAI,KAAK,GAAG,IAAI,CAAC;IAEjB,mBAAmB;IACnB,6DAA6D;IAC7D,MAAM,GAAG,GAAG,EAAE,GAAI,SAA4B,EAAE,CAAC;IACjD,MAAM,GAAG,GAA2B;QAClC,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,OAAO;KACrB,CAAC;IAEF,IAAI;QACF,MAAM,uBAAA,EAAa,yCAAgB,MAA7B,EAAa,EAAiB,GAAG,EAAE,GAAG,EAAE,uBAAA,IAAI,iCAAY,CAAC,CAAC;KACjE;IAAC,OAAO,MAAM,EAAE;QACf,sEAAsE;QACtE,cAAc;QACd,KAAK,GAAG,MAAM,CAAC;KAChB;IAED,IAAI,KAAK,EAAE;QACT,qDAAqD;QACrD,OAAO,GAAG,CAAC,MAAM,CAAC;QAClB,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;YACd,GAAG,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;SACnC;KACF;IAED,OAAO,QAAQ,CAAC,KAAK,EAAE,GAAsB,CAAC,CAAC;AACjD,CAAC,kCAWM,KAAK,wCACV,GAAmB,EACnB,GAA2B,EAC3B,WAAqD;IAErD,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,GACvC,MAAM,uBAAA,EAAa,2CAAkB,MAA/B,EAAa,EAAmB,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;IAE/D,yEAAyE;IACzE,gBAAgB;IAChB,uBAAA,EAAa,6CAAoB,MAAjC,EAAa,EAAqB,GAAG,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;IAExD,yEAAyE;IACzE,yBAAyB;IACzB,MAAM,uBAAA,EAAa,4CAAmB,MAAhC,EAAa,EAAoB,cAAc,CAAC,CAAC;IAEvD,uEAAuE;IACvE,6BAA6B;IAC7B,IAAI,KAAK,EAAE;QACT,+DAA+D;QAC/D,MAAM,KAAK,CAAC;KACb;AACH,CAAC,oCAYM,KAAK,0CACV,GAAmB,EACnB,GAA2B,EAC3B,WAAqD;IAQrD,MAAM,cAAc,GAAiC,EAAE,CAAC;IACxD,IAAI,KAAK,GAAG,IAAI,CAAC;IACjB,IAAI,UAAU,GAAG,KAAK,CAAC;IAEvB,wEAAwE;IACxE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;QACpC,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,MAAM,uBAAA,EAAa,wCAAe,MAA5B,EAAa,EACvC,GAAG,EACH,GAAG,EACH,UAAU,EACV,cAAc,CACf,CAAC;QAEF,IAAI,UAAU,EAAE;YACd,MAAM;SACP;KACF;IACD,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC;AACvD,CAAC,iCAYM,KAAK,uCACV,OAAuB,EACvB,QAAgC,EAChC,UAAkD,EAClD,cAA4C;IAE5C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAA6B,CAAC,KAAK,EAAE,EAAE;YAC9C,MAAM,WAAW,GAAG,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC;YAC5C,IAAI,WAAW,EAAE;gBACf,QAAQ,CAAC,KAAK,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;aAC9C;YACD,6CAA6C;YAC7C,OAAO,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,MAAM,IAAI,GAA8B,CACtC,aAA0C,EAC1C,EAAE;YACF,IAAI,QAAQ,CAAC,KAAK,EAAE;gBAClB,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aACrB;iBAAM;gBACL,IAAI,aAAa,EAAE;oBACjB,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE;wBACvC,GAAG,CACD,IAAI,YAAY,CACd,UAAU,CAAC,GAAG,CAAC,QAAQ,EACvB,2DAA2D;4BACzD,aAAa,OAAO,aAAa,mBAAmB,OAAO,CACzD,OAAO,CACR,EAAE,EACL,EAAE,OAAO,EAAE,CACZ,CACF,CAAC;qBACH;oBACD,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;iBACpC;gBAED,kDAAkD;gBAClD,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;aACxB;QACH,CAAC,CAAC;QAEF,IAAI;YACF,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;SAC1C;QAAC,OAAO,KAAK,EAAE;YACd,GAAG,CAAC,KAAK,CAAC,CAAC;SACZ;IACH,CAAC,CAAC,CAAC;AACL,CAAC,qCAQM,KAAK,2CACV,QAAsC;IAEtC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;QAC9B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;KACJ;AACH,CAAC,iFAYC,OAAuB,EACvB,QAAgC,EAChC,UAAmB;IAEnB,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;QACvE,MAAM,IAAI,YAAY,CACpB,UAAU,CAAC,GAAG,CAAC,QAAQ,EACvB,gEAAgE,OAAO,CACrE,OAAO,CACR,EAAE,EACH,EAAE,OAAO,EAAE,CACZ,CAAC;KACH;IAED,IAAI,CAAC,UAAU,EAAE;QACf,MAAM,IAAI,YAAY,CACpB,UAAU,CAAC,GAAG,CAAC,QAAQ,EACvB,0CAA0C,OAAO,CAAC,OAAO,CAAC,EAAE,EAC5D,EAAE,OAAO,EAAE,CACZ,CAAC;KACH;AACH,CAAC;AAGH;;;;;GAKG;AACH,SAAS,OAAO,CAAC,OAAuB;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { errorCodes, JsonRpcError, serializeError } from '@metamask/rpc-errors';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type {\n JsonRpcError as SerializedJsonRpcError,\n JsonRpcRequest,\n JsonRpcResponse,\n JsonRpcNotification,\n Json,\n JsonRpcParams,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport {\n hasProperty,\n isJsonRpcNotification,\n isJsonRpcRequest,\n} from '@metamask/utils';\n\nexport type JsonRpcEngineCallbackError = Error | SerializedJsonRpcError | null;\n\nexport type JsonRpcEngineReturnHandler = (\n done: (error?: unknown) => void,\n) => void;\n\nexport type JsonRpcEngineNextCallback = (\n returnHandlerCallback?: JsonRpcEngineReturnHandler,\n) => void;\n\nexport type JsonRpcEngineEndCallback = (error?: unknown) => void;\n\nexport type JsonRpcMiddleware<\n Params extends JsonRpcParams,\n Result extends Json,\n> = {\n (\n req: JsonRpcRequest<Params>,\n res: PendingJsonRpcResponse<Result>,\n next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n ): void;\n destroy?: () => void | Promise<void>;\n};\n\nconst DESTROYED_ERROR_MESSAGE =\n 'This engine is destroyed and can no longer be used.';\n\nexport type JsonRpcNotificationHandler<Params extends JsonRpcParams> = (\n notification: JsonRpcNotification<Params>,\n) => void | Promise<void>;\n\ntype JsonRpcEngineArgs = {\n /**\n * A function for handling JSON-RPC notifications. A JSON-RPC notification is\n * defined as a JSON-RPC request without an `id` property. If this option is\n * _not_ provided, notifications will be treated the same as requests. If this\n * option _is_ provided, notifications will be passed to the handler\n * function without touching the engine's middleware stack.\n *\n * This function should not throw or reject.\n */\n notificationHandler?: JsonRpcNotificationHandler<JsonRpcParams>;\n};\n\n/**\n * A JSON-RPC request and response processor.\n * Give it a stack of middleware, pass it requests, and get back responses.\n */\nexport class JsonRpcEngine extends SafeEventEmitter {\n /**\n * Indicating whether this engine is destroyed or not.\n */\n #isDestroyed = false;\n\n #middleware: JsonRpcMiddleware<JsonRpcParams, Json>[];\n\n readonly #notificationHandler?:\n | JsonRpcNotificationHandler<JsonRpcParams>\n | undefined;\n\n /**\n * Constructs a {@link JsonRpcEngine} instance.\n *\n * @param options - Options bag.\n * @param options.notificationHandler - A function for handling JSON-RPC\n * notifications. A JSON-RPC notification is defined as a JSON-RPC request\n * without an `id` property. If this option is _not_ provided, notifications\n * will be treated the same as requests. If this option _is_ provided,\n * notifications will be passed to the handler function without touching\n * the engine's middleware stack. This function should not throw or reject.\n */\n constructor({ notificationHandler }: JsonRpcEngineArgs = {}) {\n super();\n this.#middleware = [];\n this.#notificationHandler = notificationHandler;\n }\n\n /**\n * Throws an error if this engine is destroyed.\n */\n #assertIsNotDestroyed() {\n if (this.#isDestroyed) {\n throw new Error(DESTROYED_ERROR_MESSAGE);\n }\n }\n\n /**\n * Calls the `destroy()` function of any middleware with that property, clears\n * the middleware array, and marks this engine as destroyed. A destroyed\n * engine cannot be used.\n */\n destroy(): void {\n this.#middleware.forEach(\n (middleware: JsonRpcMiddleware<JsonRpcParams, Json>) => {\n if (\n // `in` walks the prototype chain, which is probably the desired\n // behavior here.\n 'destroy' in middleware &&\n typeof middleware.destroy === 'function'\n ) {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n middleware.destroy();\n }\n },\n );\n this.#middleware = [];\n this.#isDestroyed = true;\n }\n\n /**\n * Add a middleware function to the engine's middleware stack.\n *\n * @param middleware - The middleware function to add.\n */\n push<Params extends JsonRpcParams, Result extends Json>(\n middleware: JsonRpcMiddleware<Params, Result>,\n ): void {\n this.#assertIsNotDestroyed();\n this.#middleware.push(middleware as JsonRpcMiddleware<JsonRpcParams, Json>);\n }\n\n /**\n * Handle a JSON-RPC request, and return a response.\n *\n * @param request - The request to handle.\n * @param callback - An error-first callback that will receive the response.\n */\n handle<Params extends JsonRpcParams, Result extends Json>(\n request: JsonRpcRequest<Params>,\n callback: (error: unknown, response: JsonRpcResponse<Result>) => void,\n ): void;\n\n /**\n * Handle a JSON-RPC notification.\n *\n * @param notification - The notification to handle.\n * @param callback - An error-first callback that will receive a `void` response.\n */\n handle<Params extends JsonRpcParams>(\n notification: JsonRpcNotification<Params>,\n callback: (error: unknown, response: void) => void,\n ): void;\n\n /**\n * Handle an array of JSON-RPC requests and/or notifications, and return an\n * array of responses to any included requests.\n *\n * @param request - The requests to handle.\n * @param callback - An error-first callback that will receive the array of\n * responses.\n */\n handle<Params extends JsonRpcParams, Result extends Json>(\n requests: (JsonRpcRequest<Params> | JsonRpcNotification<Params>)[],\n callback: (error: unknown, responses: JsonRpcResponse<Result>[]) => void,\n ): void;\n\n /**\n * Handle a JSON-RPC request, and return a response.\n *\n * @param request - The JSON-RPC request to handle.\n * @returns The JSON-RPC response.\n */\n handle<Params extends JsonRpcParams, Result extends Json>(\n request: JsonRpcRequest<Params>,\n ): Promise<JsonRpcResponse<Result>>;\n\n /**\n * Handle a JSON-RPC notification.\n *\n * @param notification - The notification to handle.\n */\n handle<Params extends JsonRpcParams>(\n notification: JsonRpcNotification<Params>,\n ): Promise<void>;\n\n /**\n * Handle an array of JSON-RPC requests and/or notifications, and return an\n * array of responses to any included requests.\n *\n * @param request - The JSON-RPC requests to handle.\n * @returns An array of JSON-RPC responses.\n */\n handle<Params extends JsonRpcParams, Result extends Json>(\n requests: (JsonRpcRequest<Params> | JsonRpcNotification<Params>)[],\n ): Promise<JsonRpcResponse<Result>[]>;\n\n handle(\n req:\n | (JsonRpcRequest | JsonRpcNotification)[]\n | JsonRpcRequest\n | JsonRpcNotification,\n callback?: (error: unknown, response: never) => void,\n ) {\n this.#assertIsNotDestroyed();\n\n if (callback && typeof callback !== 'function') {\n throw new Error('\"callback\" must be a function if provided.');\n }\n\n if (Array.isArray(req)) {\n if (callback) {\n return this.#handleBatch(\n req,\n // This assertion is safe because of the runtime checks validating that `req` is an array and `callback` is defined.\n // There is only one overload signature that satisfies both conditions, and its `callback` type is the one that's being asserted.\n callback as (error: unknown, responses?: JsonRpcResponse[]) => void,\n );\n }\n return this.#handleBatch(req);\n }\n\n if (callback) {\n return this.#handle(\n req,\n callback as (error: unknown, response?: JsonRpcResponse) => void,\n );\n }\n return this._promiseHandle(req);\n }\n\n /**\n * Returns this engine as a middleware function that can be pushed to other\n * engines.\n *\n * @returns This engine as a middleware function.\n */\n asMiddleware(): JsonRpcMiddleware<JsonRpcParams, Json> {\n this.#assertIsNotDestroyed();\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return async (req, res, next, end) => {\n try {\n const [middlewareError, isComplete, returnHandlers] =\n await JsonRpcEngine.#runAllMiddleware(req, res, this.#middleware);\n\n if (isComplete) {\n await JsonRpcEngine.#runReturnHandlers(returnHandlers);\n return end(middlewareError);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n return next(async (handlerCallback) => {\n try {\n await JsonRpcEngine.#runReturnHandlers(returnHandlers);\n } catch (error) {\n return handlerCallback(error);\n }\n return handlerCallback();\n });\n } catch (error) {\n return end(error);\n }\n };\n }\n\n /**\n * Like _handle, but for batch requests.\n */\n #handleBatch(\n reqs: (JsonRpcRequest | JsonRpcNotification)[],\n ): Promise<JsonRpcResponse[]>;\n\n /**\n * Like _handle, but for batch requests.\n */\n #handleBatch(\n reqs: (JsonRpcRequest | JsonRpcNotification)[],\n callback: (error: unknown, responses?: JsonRpcResponse[]) => void,\n ): Promise<void>;\n\n /**\n * Handles a batch of JSON-RPC requests, either in `async` or callback\n * fashion.\n *\n * @param requests - The request objects to process.\n * @param callback - The completion callback.\n * @returns The array of responses, or nothing if a callback was specified.\n */\n async #handleBatch(\n requests: (JsonRpcRequest | JsonRpcNotification)[],\n callback?: (error: unknown, responses?: JsonRpcResponse[]) => void,\n ): Promise<JsonRpcResponse[] | void> {\n // The order here is important\n try {\n // If the batch is an empty array, the response array must contain a single object\n if (requests.length === 0) {\n const response: JsonRpcResponse[] = [\n {\n id: null,\n jsonrpc: '2.0',\n error: new JsonRpcError(\n errorCodes.rpc.invalidRequest,\n 'Request batch must contain plain objects. Received an empty array',\n ),\n },\n ];\n if (callback) {\n return callback(null, response);\n }\n return response;\n }\n\n // 2. Wait for all requests to finish, or throw on some kind of fatal\n // error\n const responses = (\n await Promise.all(\n // 1. Begin executing each request in the order received\n requests.map(this._promiseHandle.bind(this)),\n )\n ).filter(\n // Filter out any notification responses.\n (response): response is JsonRpcResponse => response !== undefined,\n );\n\n // 3. Return batch response\n if (callback) {\n return callback(null, responses);\n }\n return responses;\n } catch (error) {\n if (callback) {\n return callback(error);\n }\n\n throw error;\n }\n }\n\n /**\n * A promise-wrapped _handle.\n *\n * @param request - The JSON-RPC request.\n * @returns The JSON-RPC response.\n */\n // This function is used in tests, so we cannot easily change it to use the\n // hash syntax.\n // eslint-disable-next-line no-restricted-syntax\n private async _promiseHandle(\n request: JsonRpcRequest | JsonRpcNotification,\n ): Promise<JsonRpcResponse | void> {\n return new Promise((resolve, reject) => {\n this.#handle(request, (error, res) => {\n // For notifications, the response will be `undefined`, and any caught\n // errors are unexpected and should be surfaced to the caller.\n if (error && res === undefined) {\n reject(error);\n } else {\n // Excepting notifications, there will always be a response, and it will\n // always have any error that is caught and propagated.\n resolve(res);\n }\n }).catch(reject);\n });\n }\n\n /**\n * Ensures that the request / notification object is valid, processes it, and\n * passes any error and response object to the given callback.\n *\n * Does not reject.\n *\n * @param callerReq - The request object from the caller.\n * @param callback - The callback function.\n * @returns Nothing.\n */\n async #handle(\n callerReq: JsonRpcRequest | JsonRpcNotification,\n callback: (error: unknown, response?: JsonRpcResponse) => void,\n ): Promise<void> {\n if (\n !callerReq ||\n Array.isArray(callerReq) ||\n typeof callerReq !== 'object'\n ) {\n const error = new JsonRpcError(\n errorCodes.rpc.invalidRequest,\n `Requests must be plain objects. Received: ${typeof callerReq}`,\n { request: callerReq },\n );\n return callback(error, { id: null, jsonrpc: '2.0', error });\n }\n\n if (typeof callerReq.method !== 'string') {\n const error = new JsonRpcError(\n errorCodes.rpc.invalidRequest,\n `Must specify a string method. Received: ${typeof callerReq.method}`,\n { request: callerReq },\n );\n\n if (this.#notificationHandler && !isJsonRpcRequest(callerReq)) {\n // Do not reply to notifications, even if they are malformed.\n return callback(null);\n }\n\n return callback(error, {\n // Typecast: This could be a notification, but we want to access the\n // `id` even if it doesn't exist.\n id: (callerReq as JsonRpcRequest).id ?? null,\n jsonrpc: '2.0',\n error,\n });\n } else if (\n this.#notificationHandler &&\n isJsonRpcNotification(callerReq) &&\n !isJsonRpcRequest(callerReq)\n ) {\n try {\n await this.#notificationHandler(callerReq);\n } catch (error) {\n return callback(error);\n }\n return callback(null);\n }\n let error = null;\n\n // Handle requests.\n // Typecast: Permit missing id's for backwards compatibility.\n const req = { ...(callerReq as JsonRpcRequest) };\n const res: PendingJsonRpcResponse = {\n id: req.id,\n jsonrpc: req.jsonrpc,\n };\n\n try {\n await JsonRpcEngine.#processRequest(req, res, this.#middleware);\n } catch (_error) {\n // A request handler error, a re-thrown middleware error, or something\n // unexpected.\n error = _error;\n }\n\n if (error) {\n // Ensure no result is present on an errored response\n delete res.result;\n if (!res.error) {\n res.error = serializeError(error);\n }\n }\n\n return callback(error, res as JsonRpcResponse);\n }\n\n /**\n * For the given request and response, runs all middleware and their return\n * handlers, if any, and ensures that internal request processing semantics\n * are satisfied.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param middlewares - The stack of middleware functions.\n */\n static async #processRequest(\n req: JsonRpcRequest,\n res: PendingJsonRpcResponse,\n middlewares: JsonRpcMiddleware<JsonRpcParams, Json>[],\n ): Promise<void> {\n const [error, isComplete, returnHandlers] =\n await JsonRpcEngine.#runAllMiddleware(req, res, middlewares);\n\n // Throw if \"end\" was not called, or if the response has neither a result\n // nor an error.\n JsonRpcEngine.#checkForCompletion(req, res, isComplete);\n\n // The return handlers should run even if an error was encountered during\n // middleware processing.\n await JsonRpcEngine.#runReturnHandlers(returnHandlers);\n\n // Now we re-throw the middleware processing error, if any, to catch it\n // further up the call chain.\n if (error) {\n // eslint-disable-next-line @typescript-eslint/only-throw-error\n throw error;\n }\n }\n\n /**\n * Serially executes the given stack of middleware.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param middlewares - The stack of middleware functions to execute.\n * @returns An array of any error encountered during middleware execution,\n * a boolean indicating whether the request was completed, and an array of\n * middleware-defined return handlers.\n */\n static async #runAllMiddleware(\n req: JsonRpcRequest,\n res: PendingJsonRpcResponse,\n middlewares: JsonRpcMiddleware<JsonRpcParams, Json>[],\n ): Promise<\n [\n unknown, // error\n boolean, // isComplete\n JsonRpcEngineReturnHandler[],\n ]\n > {\n const returnHandlers: JsonRpcEngineReturnHandler[] = [];\n let error = null;\n let isComplete = false;\n\n // Go down stack of middleware, call and collect optional returnHandlers\n for (const middleware of middlewares) {\n [error, isComplete] = await JsonRpcEngine.#runMiddleware(\n req,\n res,\n middleware,\n returnHandlers,\n );\n\n if (isComplete) {\n break;\n }\n }\n return [error, isComplete, returnHandlers.reverse()];\n }\n\n /**\n * Runs an individual middleware function.\n *\n * @param request - The request object.\n * @param response - The response object.\n * @param middleware - The middleware function to execute.\n * @param returnHandlers - The return handlers array for the current request.\n * @returns An array of any error encountered during middleware execution,\n * and a boolean indicating whether the request should end.\n */\n static async #runMiddleware(\n request: JsonRpcRequest,\n response: PendingJsonRpcResponse,\n middleware: JsonRpcMiddleware<JsonRpcParams, Json>,\n returnHandlers: JsonRpcEngineReturnHandler[],\n ): Promise<[unknown, boolean]> {\n return new Promise((resolve) => {\n const end: JsonRpcEngineEndCallback = (error) => {\n const parsedError = error || response.error;\n if (parsedError) {\n response.error = serializeError(parsedError);\n }\n // True indicates that the request should end\n resolve([parsedError, true]);\n };\n\n const next: JsonRpcEngineNextCallback = (\n returnHandler?: JsonRpcEngineReturnHandler,\n ) => {\n if (response.error) {\n end(response.error);\n } else {\n if (returnHandler) {\n if (typeof returnHandler !== 'function') {\n end(\n new JsonRpcError(\n errorCodes.rpc.internal,\n `JsonRpcEngine: \"next\" return handlers must be functions. ` +\n `Received \"${typeof returnHandler}\" for request:\\n${jsonify(\n request,\n )}`,\n { request },\n ),\n );\n }\n returnHandlers.push(returnHandler);\n }\n\n // False indicates that the request should not end\n resolve([null, false]);\n }\n };\n\n try {\n middleware(request, response, next, end);\n } catch (error) {\n end(error);\n }\n });\n }\n\n /**\n * Serially executes array of return handlers. The request and response are\n * assumed to be in their scope.\n *\n * @param handlers - The return handlers to execute.\n */\n static async #runReturnHandlers(\n handlers: JsonRpcEngineReturnHandler[],\n ): Promise<void> {\n for (const handler of handlers) {\n await new Promise<void>((resolve, reject) => {\n handler((error) => (error ? reject(error) : resolve()));\n });\n }\n }\n\n /**\n * Throws an error if the response has neither a result nor an error, or if\n * the \"isComplete\" flag is falsy.\n *\n * @param request - The request object.\n * @param response - The response object.\n * @param isComplete - Boolean from {@link JsonRpcEngine.#runAllMiddleware}\n * indicating whether a middleware ended the request.\n */\n static #checkForCompletion(\n request: JsonRpcRequest,\n response: PendingJsonRpcResponse,\n isComplete: boolean,\n ): void {\n if (!hasProperty(response, 'result') && !hasProperty(response, 'error')) {\n throw new JsonRpcError(\n errorCodes.rpc.internal,\n `JsonRpcEngine: Response has no error or result for request:\\n${jsonify(\n request,\n )}`,\n { request },\n );\n }\n\n if (!isComplete) {\n throw new JsonRpcError(\n errorCodes.rpc.internal,\n `JsonRpcEngine: Nothing ended request:\\n${jsonify(request)}`,\n { request },\n );\n }\n }\n}\n\n/**\n * JSON-stringifies a request object.\n *\n * @param request - The request object to JSON-stringify.\n * @returns The JSON-stringified request object.\n */\nfunction jsonify(request: JsonRpcRequest): string {\n return JSON.stringify(request, null, 2);\n}\n"]}