Skip to content

Migrate from v0.1.0 to v0.2.0

v0.2.0 keeps the stable Transport<RPCMessage> architecture but changes where advanced features live. The default kkrpc entry is now a slim core for ordinary request/response RPC. Async iterable streaming and request/response remote references moved to explicit subpath entries.

This guide is for code written against v0.1.0 behavior where streaming or remote references were available from the default kkrpc entry.

Featurev0.1.0v0.2.0
Ordinary RPC callskkrpckkrpc
Property get/set, constructorskkrpckkrpc
Top-level progress callbackskkrpckkrpc, fire-and-forget only
Callback return values / thrown callback errorsdefault remote refskkrpc/remote-refs with proxy(callback)
Explicit object handlesproxy(value) from default entryproxy(value) from kkrpc/remote-refs
Nested function leavesautomatic in remote-ref coreexplicit proxy(fn) only in kkrpc/remote-refs; unmarked functions are rejected
Async iterable arguments/resultsdefault corekkrpc/streaming
HTTP with callbacks/streams/refsunsupportedclearly rejected before unsupported traffic starts
  1. Leave ordinary request/response code on kkrpc.
  2. Move async iterable APIs to kkrpc/streaming on both endpoints.
  3. Move callback-return or object-handle APIs to kkrpc/remote-refs on both endpoints.
  4. Wrap by-reference callbacks, returned functions, and object handles with proxy().
  5. Replace assumptions about automatic nested function refs with explicit proxy(fn) markers.
  6. Keep HTTP value-only. Move callback, streaming, or remote-handle boundaries to WebSocket, Worker, stdio, iframe, Electron, Tauri, Socket.IO, or a point-to-point message-bus transport.
  7. Update tests to import the feature entry that matches the behavior under test.

Use kkrpc for small, value-oriented RPC.

import { expose, wrap } from "kkrpc"
const controller = expose(api, transport)
const remote = wrap<RemoteAPI>(transport)

Default callback arguments are still useful for progress notifications:

await remote.processFile("input.dat", (percent) => {
console.log(percent)
})

Do not rely on the callback return value in the default entry. The callback is invoked through a compact t: "cb" message and is fire-and-forget.

If a method returns or accepts AsyncIterable, import wrap, expose, or RPCChannel from kkrpc/streaming on both sides of the boundary.

v0.1.0
import { expose, wrap } from "kkrpc"
v0.2.0
import { expose, wrap } from "kkrpc/streaming"

The API shape can stay the same:

type LogAPI = {
tail(service: string): AsyncIterable<string>
}
for await (const line of remote.tail("api")) {
console.log(line)
}

kkrpc/streaming uses pull credit internally, so it avoids one round trip per chunk while still bounding buffered values.

If a callback return value matters, or if a value should cross the RPC boundary by reference, use kkrpc/remote-refs.

v0.1.0
import { expose, wrap } from "kkrpc"
v0.2.0
import { expose, proxy, releaseProxy, wrap } from "kkrpc/remote-refs"

Mark callback functions explicitly:

v0.2.0 callback return value
const result = await remote.useCallback(
proxy(async (value) => {
if (value === "bad") throw new Error("callback rejected")
return `callback:${value}`
})
)

Mark returned object handles explicitly:

v0.2.0 returned handle
class CounterHandle {
value = 0
increment(amount: number) {
this.value += amount
return this.value
}
}
const api = {
createCounter() {
return proxy(new CounterHandle())
}
}

Release long-lived remote proxies when their application lifetime ends:

const counter = await remote.createCounter()
console.log(await counter.increment(5))
await releaseProxy(counter)

v0.2.0’s remote-reference entry does not automatically proxy every unmarked nested function. Mark the specific function leaf that should remain callable remotely. Unmarked function values are rejected instead of being passed by raw identity across same-process object transports.

v0.1.0 style
return {
message,
hide: async () => `hidden:${message}`
}
v0.2.0
return {
message,
hide: proxy(async () => `hidden:${message}`)
}

This makes the by-reference boundary visible and keeps plain data as by-value data.

HTTP remains unary request/response. It cannot support features that require later bidirectional traffic.

Unsupported over kkrpc/http:

  • callback arguments
  • async iterable streaming
  • kkrpc/remote-refs handles
  • raw function values
  • server-initiated calls

If v0.1.0 code tried to use those patterns over HTTP, split the API:

  • keep value-only calls on HTTP
  • move progress, subscriptions, streams, or remote handles to WebSocket, Worker, stdio, iframe, Electron, Tauri, Socket.IO, or a point-to-point message-bus transport

Update tests to import the entry that matches the behavior:

Streaming tests
import { RPCChannel } from "kkrpc/streaming"
Remote-reference tests
import { RPCChannel, proxy, releaseProxy } from "kkrpc/remote-refs"

Keep default-core tests focused on ordinary calls, property access, transfer descriptors, plugins, and fire-and-forget top-level callbacks.

SymptomLikely causeFix
RPC result is not async iterableClient used default kkrpc for a streaming methodImport from kkrpc/streaming on both sides
Callback result is undefinedDefault callback arguments are fire-and-forgetUse kkrpc/remote-refs and pass proxy(callback)
Nested returned function is not callable remotelyFunction was not explicitly markedWrap the function leaf with proxy(fn)
RPC channel does not support remote referencesRemote refs entry used with a transport or channel that does not advertise supportUse a bidirectional object-mode transport and kkrpc/remote-refs on both endpoints
Remote proxy belongs to a different RPC channelA remote proxy decoded from one channel was passed through another channelDo not treat remote proxies as portable; expose an explicit bridge method instead
HTTP rejects callbacks, streams, or refsHTTP is unaryMove that boundary to a bidirectional transport

The default bundle had grown as streaming and remote-reference state machines were added directly to core. v0.2.0 moves those costs behind explicit entries.

Measured after the split:

BundleRaw minifiedGzipBrotli
kkrpc core6.37 KB2.41 KB2.17 KB
kkrpc/streaming14.78 KB4.28 KB3.81 KB
kkrpc/remote-refs16.85 KB4.79 KB4.24 KB

Use the smallest entry that matches the behavior you need.