Skip to content

Commit c24cb15

Browse files
committed
TS...
1 parent 983cbcc commit c24cb15

11 files changed

Lines changed: 855 additions & 103 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
id: ts-client
3+
title: TypeScript Client
4+
slug: /bindings/typescript/client
5+
---
6+
7+
# TypeScript Client Reference
8+
9+
## createClient
10+
11+
The primary way to create a typed RPC client. Uses JavaScript `Proxy` for method interception with full TypeScript type inference.
12+
13+
```typescript
14+
import { createClient, LocalTransport, ServiceRegistry } from '@aster-rpc/aster';
15+
import { HelloService } from './service.js';
16+
import { HelloRequest } from './types.js';
17+
18+
const registry = new ServiceRegistry();
19+
registry.register(new HelloService());
20+
const transport = new LocalTransport(registry);
21+
22+
const client = createClient(HelloService, transport);
23+
24+
// Full type inference — client.sayHello() has correct parameter and return types
25+
const result = await client.sayHello(new HelloRequest({ name: "World" }));
26+
console.log(result.message); // "Hello, World!"
27+
```
28+
29+
### Signature
30+
31+
```typescript
32+
function createClient<T extends new (...args: any[]) => any>(
33+
serviceClass: T,
34+
transport: AsterTransport,
35+
options?: ClientOptions,
36+
): AsterClient<InstanceType<T>>;
37+
```
38+
39+
### ClientOptions
40+
41+
| Option | Type | Default | Description |
42+
|--------|------|---------|-------------|
43+
| `timeout` | `number` | `undefined` | Default timeout in seconds for all calls |
44+
| `metadata` | `Record<string, string>` | `{}` | Default metadata for all calls |
45+
46+
### Per-call options
47+
48+
Every method accepts an optional `CallOptions` as the last argument:
49+
50+
```typescript
51+
const result = await client.sayHello(req, {
52+
metadata: { 'x-request-id': '123' },
53+
deadlineEpochMs: Date.now() + 30_000,
54+
});
55+
```
56+
57+
| Option | Type | Description |
58+
|--------|------|-------------|
59+
| `metadata` | `Record<string, string>` | Per-call metadata (merged with defaults) |
60+
| `deadlineEpochMs` | `number` | Absolute deadline as epoch milliseconds |
61+
| `serializationMode` | `number` | Override serialization mode |
62+
| `contractId` | `string` | Contract identity for verification |
63+
| `callId` | `string` | Correlation ID (auto-generated if omitted) |
64+
65+
## Streaming
66+
67+
### Server streaming
68+
69+
```typescript
70+
// Returns AsyncIterable — use for-await-of
71+
for await (const item of client.watchItems(req)) {
72+
console.log(item);
73+
}
74+
```
75+
76+
### Client streaming
77+
78+
```typescript
79+
// Pass an async generator as the request
80+
const result = await client.uploadBatch(async function*() {
81+
yield new Item({ name: "one" });
82+
yield new Item({ name: "two" });
83+
}());
84+
```
85+
86+
### Bidirectional streaming
87+
88+
```typescript
89+
const channel = client.chat();
90+
await channel.send(new Message({ text: "hello" }));
91+
await channel.send(new Message({ text: "world" }));
92+
await channel.close();
93+
94+
for await (const reply of channel) {
95+
console.log(reply);
96+
}
97+
```
98+
99+
## AsterClientWrapper
100+
101+
The high-level client wrapper for production use:
102+
103+
```typescript
104+
import { AsterClientWrapper } from '@aster-rpc/aster';
105+
106+
const client = new AsterClientWrapper({
107+
transport: myTransport,
108+
config: { logFormat: 'json' },
109+
});
110+
111+
const echo = client.service(HelloService);
112+
const result = await echo.sayHello(new HelloRequest({ name: "World" }));
113+
114+
await client.close();
115+
```
116+
117+
## Transport implementations
118+
119+
| Transport | Use case | Package |
120+
|-----------|----------|---------|
121+
| `LocalTransport` | Testing (in-process, no network) | `@aster-rpc/aster` |
122+
| `IrohTransport` | Production (QUIC over Iroh P2P) | `@aster-rpc/aster` |
123+
124+
```typescript
125+
// Local (testing)
126+
import { LocalTransport, ServiceRegistry } from '@aster-rpc/aster';
127+
const transport = new LocalTransport(registry);
128+
129+
// Remote (production) — requires NAPI native addon
130+
import { IrohTransport } from '@aster-rpc/aster';
131+
const transport = new IrohTransport(connection, codec);
132+
```

docs/bindings/javascript/index.mdx

Lines changed: 92 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,124 @@
11
---
22
id: index
3-
title: JavaScript
4-
slug: /bindings/javascript
3+
title: TypeScript
4+
slug: /bindings/typescript
55
---
66

77
import BindingBadge from '@site/src/components/BindingBadge';
88

9-
<BindingBadge label="JavaScript binding" tone="planned" />
9+
<BindingBadge label="TypeScript binding" tone="alpha" />
1010

1111
## Status
1212

13-
Planned. Development will begin after the Python binding stabilizes.
13+
Alpha. The TypeScript binding mirrors the Python binding's feature set using NAPI-RS for the transport layer and pure TypeScript for the RPC framework.
1414

15-
## Timeline
15+
**Packages:**
16+
- `@aster-rpc/transport` — NAPI-RS native addon (Iroh P2P transport)
17+
- `@aster-rpc/aster` — Pure TypeScript RPC framework
1618

17-
The JavaScript binding is expected to follow the core systems-language bindings (Rust, JVM, .NET, Go) in priority.
19+
**Runtime support:** Node.js 20+, Bun 1.0+, Deno (via Node compat)
1820

19-
## Architecture
20-
21-
Two approaches are under consideration:
21+
## Install
2222

23-
### Option A: WASM
23+
```bash
24+
# bun (recommended)
25+
bun add @aster-rpc/aster
2426

25-
Compile the `core` crate to WebAssembly for use in browsers and edge runtimes (Deno, Cloudflare Workers).
27+
# npm
28+
npm install @aster-rpc/aster
2629

27-
```
28-
JavaScript / TypeScript application code
29-
|
30-
v
31-
@aster/client npm package Idiomatic JS API: decorators (TC39),
32-
AsyncIterator for streaming, AbortSignal for cancellation
33-
|
34-
| wasm-bindgen
35-
v
36-
core.wasm Core crate compiled to WASM
37-
|
38-
v
39-
iroh crates (WASM-compatible subset)
30+
# pnpm
31+
pnpm add @aster-rpc/aster
4032
```
4133

42-
WASM provides the broadest reach (browsers, edge, Node.js) but may have limitations around direct UDP access. Browser-based consumers would connect via WebSocket-to-QUIC relay bridges.
43-
44-
### Option B: N-API (Node.js native addon)
34+
The `@aster-rpc/transport` native addon is included as a dependency and auto-selects the correct binary for your platform.
35+
36+
## Quick example
37+
38+
```typescript
39+
import { Service, Rpc, WireType, AsterServer, createClient, LocalTransport, ServiceRegistry } from '@aster-rpc/aster';
40+
41+
// Define wire types
42+
@WireType("hello/HelloRequest")
43+
class HelloRequest {
44+
name = "";
45+
constructor(init?: Partial<HelloRequest>) { if (init) Object.assign(this, init); }
46+
}
47+
48+
@WireType("hello/HelloResponse")
49+
class HelloResponse {
50+
message = "";
51+
constructor(init?: Partial<HelloResponse>) { if (init) Object.assign(this, init); }
52+
}
53+
54+
// Define service
55+
@Service({ name: "Hello", version: 1 })
56+
class HelloService {
57+
@Rpc()
58+
async sayHello(req: HelloRequest): Promise<HelloResponse> {
59+
return new HelloResponse({ message: `Hello, ${req.name}!` });
60+
}
61+
}
62+
63+
// Create and call
64+
const registry = new ServiceRegistry();
65+
registry.register(new HelloService());
66+
const transport = new LocalTransport(registry);
67+
68+
const client = createClient(HelloService, transport);
69+
const result = await client.sayHello(new HelloRequest({ name: "TypeScript" }));
70+
console.log(result.message); // "Hello, TypeScript!"
71+
```
4572

46-
Use N-API to expose the `core` crate as a native Node.js addon, similar to the Python PyO3 approach.
73+
## Architecture
4774

4875
```
49-
JavaScript / TypeScript application code (Node.js)
76+
@aster-rpc/aster Pure TypeScript — decorators, client, server,
77+
interceptors, framing, protocol types
5078
|
51-
v
52-
@aster/client npm package Idiomatic JS API
79+
@aster-rpc/transport NAPI-RS native addon — IrohNode, QUIC streams,
80+
| blobs, docs, gossip
5381
|
54-
| N-API
55-
v
56-
aster.node Native addon built from core crate
82+
aster_transport_core Shared Rust crate (same as Python binding)
5783
|
58-
v
59-
iroh crates (full functionality)
84+
iroh crates QUIC, blobs, docs, gossip
6085
```
6186

62-
N-API provides full access to the networking stack (including direct UDP) but is limited to Node.js and compatible runtimes.
87+
The TypeScript binding uses the same Rust core as the Python binding. Wire-level compatibility is guaranteed — a Python server can serve TypeScript clients and vice versa.
88+
89+
## Key design decisions
90+
91+
- **TC39 Stage 3 decorators** (`@Service`, `@Rpc`, `@ServerStream`, etc.) — compiles to standard JS, no runtime decorator support needed.
92+
- **Proxy-based client stubs**`createClient(ServiceClass, transport)` returns a typed client with full IDE autocompletion.
93+
- **AsyncIterator/AsyncGenerator** for all streaming patterns.
94+
- **Fory XLANG** (`@apache-fory/core`) for cross-language wire compatibility with Python.
95+
- **NAPI-RS** for the native transport layer — same pattern as SWC, Prisma, Turbo.
96+
97+
## Features
6398

64-
### Key design decisions
99+
All features from the Python binding are available:
65100

66-
- **TypeScript-first** with full type definitions.
67-
- **TC39 decorators** (Stage 3) for service definitions where available; plain class registration as a fallback.
68-
- **AsyncIterator** for streaming patterns.
69-
- **AbortSignal** for cancellation and deadline propagation.
70-
- **Apache Fory JavaScript** will handle XLANG serialization for wire compatibility.
101+
| Feature | Status |
102+
|---------|--------|
103+
| All 4 streaming patterns (unary, server, client, bidi) | Done |
104+
| TC39 decorators (@Service, @Rpc, @ServerStream, etc.) | Done |
105+
| Proxy-based typed client stubs | Done |
106+
| 9 interceptors (deadline, retry, metrics, rate-limit, etc.) | Done |
107+
| Contract identity (BLAKE3 hashing) | Done |
108+
| Session-scoped services (CALL/CANCEL multiplexing) | Done |
109+
| Structured logging (JSON/text, correlation, masking) | Done |
110+
| Health endpoints (/healthz, /readyz, /metrics) | Done |
111+
| Configuration (env vars, TOML) | Done |
112+
| IrohTransport (QUIC) | Done |
113+
| LocalTransport (in-process testing) | Done |
71114

72-
### Requirements
115+
## WASM (future)
73116

74-
- Node.js 18+ (for N-API) or any modern browser/edge runtime (for WASM).
75-
- The native addon or WASM module for the target platform.
117+
Iroh supports WASM compilation (since v0.33) with all connections routed through relay servers. The `AsterTransport` interface is designed to support a future `IrohWasmTransport` for browser and edge runtimes. Connections remain end-to-end encrypted even via relay.
76118

77119
## Further reading
78120

79-
- [Cross-Language Interop](/docs/examples/cross-language) for how wire types enable multi-language deployments
121+
- [TypeScript Quickstart](/docs/quickstart/typescript) — step-by-step guide
122+
- [TypeScript Server Reference](/docs/bindings/typescript/server) — AsterServer API
123+
- [TypeScript Client Reference](/docs/bindings/typescript/client) — createClient API
124+
- [Cross-Language Interop](/docs/examples/cross-language) — Python ↔ TypeScript

0 commit comments

Comments
 (0)