Skip to content

Commit 0abe15b

Browse files
alexyakuninclaude
andcommitted
refactor(ts): RpcPeerRefBuilder -> RpcRefBuilder (TS side of the RpcRef rename)
TS refs stay plain strings - there's no RpcRoute counterpart. Also updates the .NET-comparison comments to describe the RpcRef + RpcRoute model. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PLbC1QXTLkBj3G2CBgkXdC
1 parent 3e1dcf5 commit 0abe15b

10 files changed

Lines changed: 59 additions & 21 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ _ReSharper*/
1616
*.sln.docstates
1717
*.userprefs
1818
**/Properties/launchSettings.json
19+
!samples/TodoApp/AspireHost/Properties/launchSettings.json
1920

2021
# Build artifacts
2122
[Aa]rtifacts/

docs/PartR-CallRouting.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Starting from v14.1, `RpcPeerRef` is replaced by the `RpcRef` + `RpcRoute` pair:
5252
| `RpcPeerRef` | `RpcRef` (stable; one instance per logical target) |
5353
| `RpcRouteState` | `RpcRoute` (one instance per route generation) |
5454
| `RpcPeerRef.RouteState` | `RpcRef.Route` (re-minted via `CreateRoute()` on change) |
55+
| `RpcPeerRefBuilder` (TS, `@actuallab/rpc`) | `RpcRefBuilder` (TS refs stay plain strings; no route concept) |
5556
| `RpcRouteStateExt` | Merged into `RpcRoute` (`IsChanged`, `RerouteIfChanged`, etc.) |
5657
| `RpcPeer.Ref.RouteState` | `RpcPeer.Route` (the generation the peer is bound to) |
5758

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
/*
5+
"https": {
6+
"commandName": "Project",
7+
"dotnetRunMessages": true,
8+
"launchBrowser": true,
9+
"applicationUrl": "https://localhost:17120;http://localhost:15185",
10+
"environmentVariables": {
11+
"ASPNETCORE_ENVIRONMENT": "Development",
12+
"DOTNET_ENVIRONMENT": "Development",
13+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21151",
14+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22136"
15+
}
16+
},
17+
*/
18+
"http": {
19+
"commandName": "Project",
20+
"dotnetRunMessages": true,
21+
"launchBrowser": true,
22+
"applicationUrl": "http://localhost:15185",
23+
"environmentVariables": {
24+
"ASPNETCORE_ENVIRONMENT": "Development",
25+
"DOTNET_ENVIRONMENT": "Development",
26+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19070",
27+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20130",
28+
"ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true",
29+
"DOTNET_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS": "true"
30+
}
31+
}
32+
}
33+
}

samples/TodoApp/Host/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ void ConfigureApp()
332332

333333
// Fusion endpoints
334334
app.MapRpcWebSocketServer();
335-
app.MapFusionAuthEndpoints();
335+
if (hostKind != HostKind.BackendServer)
336+
app.MapFusionAuthEndpoints();
336337
app.MapFusionRenderModeEndpoints();
337338
}

ts/e2e/ts-dotnet-e2e.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import WebSocket from 'ws';
1313
import {
1414
RpcClientPeer,
1515
RpcError,
16-
RpcPeerRefBuilder,
16+
RpcRefBuilder,
1717
RpcType,
1818
defineRpcService,
1919
type RpcConnectionState,
@@ -155,7 +155,7 @@ async function run(): Promise<void> {
155155
const hub = new FusionHub();
156156
// Bake the serialization format into the URL via ?f=... so the peer ctor
157157
// picks it up. Pass `mustStart=false` — we need to set webSocketFactory first.
158-
const peer = new RpcClientPeer(hub, RpcPeerRefBuilder.forClient(serverUrl, rpcFormat), false);
158+
const peer = new RpcClientPeer(hub, RpcRefBuilder.forClient(serverUrl, rpcFormat), false);
159159

160160
// wsFactory: create ws WebSocket (Node.js)
161161
peer.webSocketFactory = (url: string) => new WebSocket(url) as unknown as WebSocketLike;

ts/packages/rpc/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export type {
8888
} from './rpc-peer.js';
8989
export { RpcHub } from './rpc-hub.js';
9090
export type { RpcPeerFactory } from './rpc-hub.js';
91-
export { RpcPeerRefBuilder } from './rpc-peer-ref-builder.js';
91+
export { RpcRefBuilder } from './rpc-ref-builder.js';
9292
export { RpcServiceHost } from './rpc-service-host.js';
9393
export type { RpcServiceImpl, RpcDispatchContext } from './rpc-service-host.js';
9494
export { createRpcClient } from './rpc-client.js';

ts/packages/rpc/src/rpc-hub.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// DI-resolved configuration (RpcRegistryOptions, PeerOptions, InboundCallOptions,
44
// OutboundCallOptions, DiagnosticsOptions), SerializationFormats, Middlewares,
55
// ClientPeerReconnectDelayer, Limits, SystemClock.
6-
// Manages peers via ConcurrentDictionary<RpcPeerRef, RpcPeer> with GetPeer()
6+
// Manages peers via ConcurrentDictionary<RpcRoute, RpcPeer> with GetPeer()
77
// that lazily creates + starts peers. Also has GetClient<T>() / GetServer<T>()
88
// that look up services in ServiceRegistry.
99
//
@@ -15,14 +15,15 @@
1515
// addService() / addClient() calls.
1616
// - GetClient<T>() / GetServer<T>() — .NET resolves typed client/server proxies
1717
// via the ServiceRegistry + DI. TS uses addClient<T>(peer, def).
18-
// - RpcPeerRef-keyed peer dictionary — .NET peers are keyed by RpcPeerRef (rich
19-
// value object encoding route, version, serialization format). TS uses string
20-
// refs (URL for clients, "server://{uuid}" for servers).
18+
// - RpcRoute-keyed peer dictionary — .NET peers are keyed by RpcRoute (one
19+
// route generation of a stable RpcRef, which encodes client/server, versions,
20+
// serialization format). TS uses string refs (URL for clients,
21+
// "server://{uuid}" for servers).
2122
// - Lazy peer creation + Start() — .NET's GetPeer auto-creates and starts a
2223
// peer's reconnection loop. TS requires explicit addPeer() + run().
2324
// - DisposeAsync — .NET disposes all peers on hub shutdown. TS has close().
24-
// - Route change detection (RouteState.WhenChanged → Dispose peer) — .NET
25-
// watches for load-balancer route changes and auto-disposes stale peers.
25+
// - Route change detection (RpcRoute.WhenChanged → Dispose peer) — .NET
26+
// watches for topology changes and auto-disposes stale-route peers.
2627
// TS has no routing layer.
2728
// - Middlewares (IRpcMiddleware[]) — ordered middleware pipeline for inbound
2829
// calls. TS dispatches directly to service implementations.
@@ -52,7 +53,7 @@ import { RpcSystemCalls } from './rpc-message.js';
5253
const { warnLog } = getLogs('RpcHub');
5354

5455
/** Factory signature shared by all peer lookup/creation methods. Serialization
55-
* format is encoded in the URL via `?f=...` (see {@link RpcPeerRefBuilder}),
56+
* format is encoded in the URL via `?f=...` (see {@link RpcRefBuilder}),
5657
* so the factory doesn't need an extra parameter for it. `getClientPeer` /
5758
* `getServerPeer` cast the result, so the factory returns RpcPeer. */
5859
export type RpcPeerFactory = (hub: RpcHub, ref: string) => RpcPeer;

ts/packages/rpc/src/rpc-peer.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@
5656
// - ProcessMessage() — creates RpcInboundContext per message, dispatches via
5757
// MethodDef.InboundCallInvoker. TS dispatches via _handleMessage →
5858
// handleSystemCall or RpcServiceHost.dispatch.
59-
// - RpcPeerRef / routing — .NET peers are keyed by RpcPeerRef (which encodes
60-
// client/server, route state, versions, serialization format). TS peers are
61-
// keyed by string ref (URL for clients, "server://{uuid}" for servers).
59+
// - RpcRef / RpcRoute / routing — .NET peers are bound to an RpcRoute (one route
60+
// generation of a stable RpcRef, which encodes client/server, versions,
61+
// serialization format). TS peers are keyed by string ref (URL for clients,
62+
// "server://{uuid}" for servers).
6263
// - StopMode / ComputeAutoStopMode — controls behavior of inbound calls when
6364
// peer stops (cancel vs keep-incomplete). TS has no stop mode.
6465
// - ConnectionKind detector (Remote/Loopback/Local/None) — .NET detects if peer
@@ -792,7 +793,7 @@ export class RpcClientPeer extends RpcPeer {
792793
* @param url Full WebSocket URL — the serialization format is taken from
793794
* the `f=` query parameter (e.g. `wss://host/rpc/ws?f=msgpack6`);
794795
* falls back to the resolver's default when absent. Use
795-
* {@link RpcPeerRefBuilder.forClient} to compose URLs with a format.
796+
* {@link RpcRefBuilder.forClient} to compose URLs with a format.
796797
* @param mustStart Kick off the reconnect loop automatically at the end of
797798
* construction (default `true`). Pass `false` if you need to
798799
* tweak `reconnectDelayer`, `handshakeTimeoutMs`, or similar

ts/packages/rpc/src/rpc-peer-ref-builder.ts renamed to ts/packages/rpc/src/rpc-ref-builder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
// `RpcServerPeer`'s ref is `server://{id}`.
66
//
77
// Typical use:
8-
// rpcHub.defaultPeerUrl = RpcPeerRefBuilder.forClient('wss://host/rpc/ws', 'msgpack6');
9-
// const serverRef = RpcPeerRefBuilder.forServer(crypto.randomUUID());
8+
// rpcHub.defaultPeerUrl = RpcRefBuilder.forClient('wss://host/rpc/ws', 'msgpack6');
9+
// const serverRef = RpcRefBuilder.forServer(crypto.randomUUID());
1010

11-
export class RpcPeerRefBuilder {
11+
export class RpcRefBuilder {
1212
/** Build a client peer ref from a WebSocket URL, optionally baking in the
1313
* serialization format as a `f=` query parameter.
1414
* @param url Base WebSocket URL, e.g. `wss://host/rpc/ws`.

ts/packages/rpc/tests/rpc-reconnection.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,18 +187,18 @@ describe('RPC Reconnection', () => {
187187
const r1 = await calc.add(1, 2);
188188
expect(r1).toBe(3);
189189

190-
const peerRef = conn.clientPeer.ref;
190+
const rpcRef = conn.clientPeer.ref;
191191
const peerIdBefore = conn.clientPeer.id;
192192
expect(conn.clientPeer.connection).toBeDefined();
193-
expect(clientHub.peers.get(peerRef)).toBe(conn.clientPeer);
193+
expect(clientHub.peers.get(rpcRef)).toBe(conn.clientPeer);
194194

195195
// Call the public disconnect() — closes WS without disposing peer.
196196
conn.clientPeer.disconnect();
197197
await delay(5);
198198

199199
// Connection is cleared, peer instance survives with same identity.
200200
expect(conn.clientPeer.connection).toBeUndefined();
201-
expect(clientHub.peers.get(peerRef)).toBe(conn.clientPeer);
201+
expect(clientHub.peers.get(rpcRef)).toBe(conn.clientPeer);
202202
expect(conn.clientPeer.id).toBe(peerIdBefore);
203203

204204
// Re-attach a fresh connection — the same peer instance is reused.

0 commit comments

Comments
 (0)