{"id":15967,"library":"async-call-rpc","title":"async-call-rpc JSON RPC Client & Server","description":"async-call-rpc is a lightweight, zero-dependency JSON RPC server and client library written in TypeScript, designed for any ECMAScript 2018+ environment. The current stable version is 6.4.2, and the package sees active development with frequent patch and minor releases addressing bug fixes and introducing new features like the `encoder` option. Key differentiators include its full TypeScript support, custom encoder capabilities for complex data types, and experimental support for async generators. It works in both Node.js and browser environments and is published on both npm and JSR, offering flexibility in module consumption. It explicitly does not support ES5 environments or JSON RPC 1.0.","status":"active","version":"6.4.2","language":"javascript","source_language":"en","source_url":"https://github.com/Jack-Works/async-call-rpc","tags":["javascript","jsonrpc","typescript"],"install":[{"cmd":"npm install async-call-rpc","lang":"bash","label":"npm"},{"cmd":"yarn add async-call-rpc","lang":"bash","label":"yarn"},{"cmd":"pnpm add async-call-rpc","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"Use named import for ESM. CommonJS `require` is not officially supported and may lead to issues or require specific bundler configurations. For Deno/Bun via JSR, import from '@works/json-rpc'.","wrong":"const AsyncCall = require('async-call-rpc');","symbol":"AsyncCall","correct":"import { AsyncCall } from 'async-call-rpc';"},{"note":"AsyncGeneratorCall is part of the 'full' entry point, not the default base entry point. Ensure your environment supports async generators.","wrong":"import { AsyncGeneratorCall } from 'async-call-rpc';","symbol":"AsyncGeneratorCall","correct":"import { AsyncGeneratorCall } from 'async-call-rpc/full';"},{"note":"When using `Encoder` as a type for type annotations, `import type` is preferred to avoid bundling unused runtime code if not implemented as an actual class.","wrong":"import { Encoder } from 'async-call-rpc';","symbol":"Encoder","correct":"import type { Encoder } from 'async-call-rpc';"}],"quickstart":{"code":"import { AsyncCall } from 'async-call-rpc';\n\n// Define a simple in-memory channel for demonstration\nclass InMemoryChannel {\n    private clientSend?: (data: string) => void;\n    private serverSend?: (data: string) => void;\n\n    // Simulate client sending to server\n    clientChannel = {\n        send: (data: string) => {\n            if (this.serverSend) {\n                this.serverSend(data);\n            }\n        },\n        on: (cb: (data: string) => void) => {\n            this.clientSend = cb;\n        }\n    };\n\n    // Simulate server sending to client\n    serverChannel = {\n        send: (data: string) => {\n            if (this.clientSend) {\n                this.clientSend(data);\n            }\n        },\n        on: (cb: (data: string) => void) => {\n            this.serverSend = cb;\n        }\n    };\n}\n\nconst channel = new InMemoryChannel();\n\n// Define the server API interface\ninterface MyServerAPI {\n    add(a: number, b: number): Promise<number>;\n    greet(name: string): Promise<string>;\n}\n\n// Server implementation\nconst serverImpl: MyServerAPI = {\n    async add(a, b) {\n        console.log(`Server received: add(${a}, ${b})`);\n        return a + b;\n    },\n    async greet(name) {\n        console.log(`Server received: greet('${name}')`);\n        return `Hello, ${name}!`;\n    }\n};\n\n// Create the RPC server instance\nconst server = new AsyncCall(serverImpl, { channel: channel.serverChannel });\n\n// Create the RPC client instance (null for `thisSideImplementation` means it's purely a client)\nconst client = new AsyncCall<MyServerAPI>(null, { channel: channel.clientChannel });\n\n// Use the client to call server methods\nasync function runClient() {\n    console.log('Client calling add(5, 3)');\n    const resultAdd = await client.add(5, 3);\n    console.log('Result of add(5, 3):', resultAdd); // Expected: 8\n\n    console.log('Client calling greet(\"World\")');\n    const resultGreet = await client.greet('World');\n    console.log('Result of greet(\"World\"):', resultGreet); // Expected: \"Hello, World!\"\n\n    // Clean up server (optional, for explicit shutdown)\n    server.stop();\n}\n\nrunClient().catch(console.error);\n","lang":"typescript","description":"This quickstart demonstrates how to set up a basic in-memory JSON RPC client and server using `async-call-rpc`, define a simple API, and make remote procedure calls."},"warnings":[{"fix":"Migrate your `serializer` option to the new `encoder` option. The `serialization(data)` and `deserialization(data)` methods should be renamed to `encode(data)` and `decode(data)` respectively.","message":"The `serializer` option in AsyncCall constructor has been deprecated and replaced by the `encoder` option. Custom serialization logic needs to be migrated.","severity":"breaking","affected_versions":">=6.4.0"},{"fix":"Exercise caution when using async generators, especially in long-running server processes. Monitor memory usage and implement proper resource management and cleanup for async generator streams.","message":"Async generator support in `async-call-rpc` can lead to memory leaks on the server side if not handled carefully.","severity":"gotcha","affected_versions":"All versions supporting async generators"},{"fix":"Ensure your runtime environment supports ES2018 or newer. If targeting older browsers, transpile your code with a tool like Babel. Avoid using JSON RPC 1.0.","message":"This package ships with ECMAScript 2018 syntax (`async function`) and does not support ES5 environments or JSON RPC 1.0.","severity":"breaking","affected_versions":"All"},{"fix":"Adjust your import statements based on your package manager: `import { AsyncCall } from 'async-call-rpc'` for npm/yarn/pnpm, and `import { AsyncCall } from '@works/json-rpc'` for jsr users.","message":"When installing via JSR (e.g., Deno, Bun), the import path for `async-call-rpc` changes from `'async-call-rpc'` to `'@works/json-rpc'`. Additionally, the `utils/` entrypoint is not published on JSR.","severity":"gotcha","affected_versions":">=6.4.1"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Use a named ESM import: `import { AsyncCall } from 'async-call-rpc';`. If in a browser UMD context, access via `const { AsyncCall } = globalThis.AsyncCall;`.","cause":"Attempting to use `require` or incorrect default import syntax for a package primarily designed for ES Modules, or incorrect access in a UMD context.","error":"TypeError: AsyncCall is not a constructor"},{"fix":"Refactor your code to use the `encoder` option instead. Replace `serializer.serialization` with `encoder.encode` and `serializer.deserialization` with `encoder.decode`.","cause":"Using the deprecated `serializer` option in the `AsyncCall` constructor.","error":"Property 'serializer' is deprecated and will be removed in a future major release."},{"fix":"Import `AsyncGeneratorCall` specifically from the full entry point: `import { AsyncGeneratorCall } from 'async-call-rpc/full';`. Ensure your JavaScript environment targets ES2018 or higher.","cause":"Attempting to import `AsyncGeneratorCall` from the default 'async-call-rpc' entry point, or the runtime environment lacks async generator support.","error":"Cannot find name 'AsyncGeneratorCall' or 'AsyncGeneratorCall' is not defined."}],"ecosystem":"npm"}