Skip to main content

TypeScript Client Reference

AsterClientWrapper

The primary way to connect to an Aster server over QUIC. Handles consumer admission, service discovery, and the proxy/typed-client surface.

import { AsterClientWrapper } from '@aster-rpc/aster';

const client = new AsterClientWrapper({
address: "aster1...",
});
await client.connect();

// Dynamic proxy: speaks JSON, no local types needed
const hello = client.proxy("Hello");
const reply = await hello.sayHello({ name: "World" });
console.log(reply.message);

await client.close();

Options

OptionTypeDefaultDescription
addressstringundefinedaster1... ticket of the producer to connect to
transportAsterTransportundefinedPre-built transport (for tests). Mutually exclusive with address.
configPartial<AsterConfig>{}Override config values
identitystringundefinedPath to a .aster-identity TOML file
peerstringundefinedPeer name to load from the identity file
enrollmentCredentialFilestringundefinedPath to a .cred enrollment credential for trusted-mode servers

Methods

MethodReturnsDescription
connect()Promise<void>Run consumer admission against the producer and discover services
proxy(name)ProxyClientDynamic proxy for a service. Speaks JSON; no codegen needed.
client(ServiceClass)Promise<typed client>Typed client built from a generated client class
session(name)Promise<SessionProxyClient>Open a multiplexed session against a session-scoped service
close()Promise<void>Close the underlying QUIC connections

Properties

PropertyTypeDescription
connectedbooleanWhether connect() has succeeded
servicesServiceSummary[]Services discovered during admission

Lower-level: createClient

For tests and advanced use, createClient builds a typed stub over an existing transport. This is what AsterClientWrapper.client() uses internally.

import { createClient } from '@aster-rpc/aster';

const client = createClient(HelloService, transport);
const result = await client.sayHello(new HelloRequest({ name: "World" }));

Signature

function createClient<T extends new (...args: any[]) => any>(
serviceClass: T,
transport: AsterTransport,
options?: ClientOptions,
): AsterClient<InstanceType<T>>;

ClientOptions

OptionTypeDefaultDescription
timeoutnumberundefinedDefault timeout in seconds for all calls
metadataRecord<string, string>{}Default metadata for all calls

Per-call options

Every method accepts an optional CallOptions as the last argument:

const result = await client.sayHello(req, {
metadata: { 'x-request-id': '123' },
deadlineEpochMs: Date.now() + 30_000,
});
OptionTypeDescription
metadataRecord<string, string>Per-call metadata (merged with defaults)
deadlineEpochMsnumberAbsolute deadline as epoch milliseconds
serializationModenumberOverride serialization mode
contractIdstringContract identity for verification
callIdstringCorrelation ID (auto-generated if omitted)

Streaming

Server streaming

// Returns AsyncIterable — use for-await-of
for await (const item of client.watchItems(req)) {
console.log(item);
}

Client streaming

// Pass an async generator as the request
const result = await client.uploadBatch(async function*() {
yield new Item({ name: "one" });
yield new Item({ name: "two" });
}());

Bidirectional streaming

const channel = client.chat();
await channel.send(new Message({ text: "hello" }));
await channel.send(new Message({ text: "world" }));
await channel.close();

for await (const reply of channel) {
console.log(reply);
}

Transport implementations

TransportUse casePackage
LocalTransportTesting (in-process, no network)@aster-rpc/aster
IrohTransportProduction (QUIC over Iroh P2P)@aster-rpc/aster
// Local (testing)
import { LocalTransport, ServiceRegistry } from '@aster-rpc/aster';
const transport = new LocalTransport(registry);

// Remote (production) — requires NAPI native addon
import { IrohTransport } from '@aster-rpc/aster';
const transport = new IrohTransport(connection, codec);