5.8 KiB
TypeSRPC
TypeSRPC is a lightweight, type-safe RPC (Remote Procedure Call) framework for TypeScript that enables seamless communication between client and server with full type inference and deep nested method support.
✨ Features
- Full TypeScript Support: Automatic type inference.
- Deep Nested API: Supports arbitrarily nested method structures (e.g.,
api.math.utils.absolute()). - Promise-Based: All remote calls return promises—no callback hell.
- Pluggable Transport Layer: Easily swap underlying socket implementations (default: Socket.IO).
- Access Control: Built-in access key authentication for secure connections.
- Lightweight & Zero Boilerplate: Define your provider once—no need to manually declare RPC interfaces.
- Bidirectional Communication: Both client and server can expose and consume APIs.
📦 Installation
npm install @tonecn/typesrpc
# or
yarn add @tonecn/typesrpc
# or
pnpm add @tonecn/typesrpc
🚀 Quick Start
1. Define Your Providers
// Server-side provider
type ServerProvider = {
add: (a: number, b: number) => number;
math: {
multiply: (a: number, b: number) => number;
utils: {
absolute: (num: number) => number;
};
};
};
const serverProvider = {
add(a: number, b: number) { return a + b; },
math: {
multiply(a: number, b: number) { return a * b; },
utils: {
absolute(num: number) { return Math.abs(num); }
}
}
};
// Client-side provider (optional, for bidirectional RPC)
type ClientProvider = {
getName: () => string;
sub: {
getName: () => string;
};
};
const clientProvider = {
name: 'Client1',
getName() { return this.name; },
sub: {
name: 'SubClient',
getName() { return this.name; }
}
};
2. Set Up Server & Client
import { RPCHandler } from '@tonecn/typesrpc';
// Server
const server = new RPCHandler();
server.setProvider(serverProvider);
await server.listen({ port: 3000 });
// Client
const client = new RPCHandler();
client.setProvider(clientProvider);
const session = await client.connect({ url: 'http://localhost:3000' });
// Get typed API proxies
const serverAPI = session.getAPI<ServerProvider>();
const clientAPI = session.getAPI<ClientProvider>(); // if server also consumes client API
3. Make Remote Calls
// All methods return Promises
const sum = await serverAPI.add(2, 3); // 5
const product = await serverAPI.math.multiply(4, 5); // 20
const abs = await serverAPI.math.utils.absolute(-10); // 10
const name = await clientAPI.getName(); // 'Client1'
💡 Note: The
ToDeepPromise<T>utility (exported internally) automatically converts all synchronous methods in your provider to async (Promise<T>), so you canawaitthem on the client side.
🔐 Access Key Authentication
Secure your RPC endpoints with access keys:
Server (require access key)
const server = new RPCHandler();
server.setAccessKey('my-secret-key');
await server.listen({ port: 3001 });
Client (provide access key)
const client = new RPCHandler();
await client.connect({
url: 'http://localhost:3001',
accessKey: 'my-secret-key' // required!
});
Connections without a valid access key will be rejected.
⚙️ Custom Socket Implementation
TypeSRPC supports pluggable transport layers. By default, it uses Socket.IO, but you can replace it with any real-time communication library (e.g., WebSocket, SignalR, etc.).
How to Inject a Custom Implementation
-
Implement the required interfaces:
SocketClientSocketServerSocketConnection
-
Inject your implementations:
// my-socket-impl/index.ts
import { injectSocketClient, injectSocketServer } from '@tonecn/typesrpc';
import { MySocketClient } from './MySocketClient';
import { MySocketServer } from './MySocketServer';
export function injectMySocketImpl() {
injectSocketClient(MySocketClient);
injectSocketServer(MySocketServer);
}
- Call the injector before creating any
RPCHandlerinstances:
import { injectMySocketImpl } from './my-socket-impl';
injectMySocketImpl(); // Must be called once at app startup
const handler = new RPCHandler(); // Now uses your custom socket layer
✅ The built-in Socket.IO implementation is injected automatically when you import typesrpc. To override it, call your custom injector before creating any RPCHandler instances (but after importing typesrpc).
📁 Project Structure
src/
├── core/ # Core RPC logic (transport-agnostic)
├── implements/ # Transport implementations
│ └── socket.io/ # Default: Socket.IO adapter
├── utils/ # Utilities (e.g., ToDeepPromise, EventEmitter)
└── index.ts # Public API exports + default Socket.IO injection
🧪 Testing
The project includes comprehensive tests:
- Unit:
npm run test:unit - Integration:
npm run test:integration - E2E:
npm run test:e2e - Coverage:
npm run test:coverage
Run all tests with:
npm test
📄 API Reference
RPCHandler
Main entry point for both client and server.
.setProvider(provider: T)– Register local methods..setAccessKey(key: string)– Set access key (server-side)..listen(options?)– Start server..connect(options?)– Connect to server; returnsPromise<RPCSession>.
RPCSession
Represents an active RPC connection.
.getAPI<T>()– Get a typed proxy to the remote provider.
📜 License
MIT License © tonecn
Note
: This library is designed for development and internal tooling. For production use in public-facing services, ensure proper authentication, rate limiting, and input validation are implemented on top of the access key mechanism.