starpc 0.25.2 → 0.25.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ import { OpenStreamFunc, PacketStream } from '../srpc/stream.js';
5
5
  export type RpcStreamCaller = (request: AsyncIterable<RpcStreamPacket>) => AsyncIterable<RpcStreamPacket>;
6
6
  export declare function openRpcStream(componentId: string, caller: RpcStreamCaller, waitAck?: boolean): Promise<PacketStream>;
7
7
  export declare function buildRpcStreamOpenStream(componentId: string, caller: RpcStreamCaller): OpenStreamFunc;
8
- export type RpcStreamHandler = (stream: PacketStream) => void;
8
+ export type RpcStreamHandler = (stream: PacketStream) => Promise<void>;
9
9
  export type RpcStreamGetter = (componentId: string) => Promise<RpcStreamHandler | null>;
10
10
  export declare function handleRpcStream(packetRx: AsyncIterator<RpcStreamPacket>, getter: RpcStreamGetter): AsyncIterable<RpcStreamPacket>;
11
11
  export declare class RpcStream implements PacketStream {
@@ -86,7 +86,9 @@ export async function* handleRpcStream(packetRx, getter) {
86
86
  const packetTx = pushable({ objectMode: true });
87
87
  // start the handler
88
88
  const rpcStream = new RpcStream(packetTx, packetRx);
89
- handler(rpcStream);
89
+ handler(rpcStream)
90
+ .catch((err) => packetTx.end(err))
91
+ .then(() => packetTx.end());
90
92
  // process packets
91
93
  for await (const packet of packetTx) {
92
94
  yield* [packet];
@@ -6,6 +6,7 @@ import { ERR_STREAM_IDLE } from './errors.js';
6
6
  // NOTE: there is no way to tell if a BroadcastChannel or MessagePort is closed.
7
7
  // This implementation sends a "closed" message when close() is called.
8
8
  // However: if the remote is removed w/o closing cleanly, the stream will be left open!
9
+ // Enable keepAliveMs and idleTimeoutMs to mitigate this issue with keep-alive messages.
9
10
  export class ChannelStream {
10
11
  // isAcked checks if the stream is acknowledged by the remote.
11
12
  get isAcked() {
@@ -28,7 +28,8 @@ export class Client {
28
28
  // clientStreamingRequest starts a client side streaming request.
29
29
  async clientStreamingRequest(service, method, data, abortSignal) {
30
30
  const call = await this.startRpc(service, method, null, abortSignal);
31
- call.writeCallDataFromSource(data);
31
+ call.writeCallDataFromSource(data)
32
+ .catch(err => call.close(err));
32
33
  for await (const data of call.rpcDataSource) {
33
34
  call.close();
34
35
  return data;
@@ -43,7 +44,8 @@ export class Client {
43
44
  this.startRpc(service, method, data, abortSignal)
44
45
  .then(async (call) => {
45
46
  const result = writeToPushable(call.rpcDataSource, serverData);
46
- result.finally(() => call.close());
47
+ result.catch((err) => call.close(err));
48
+ result.then(() => call.close());
47
49
  return result;
48
50
  })
49
51
  .catch((err) => serverData.end(err));
@@ -54,7 +56,11 @@ export class Client {
54
56
  const serverData = pushable({ objectMode: true });
55
57
  this.startRpc(service, method, null, abortSignal)
56
58
  .then(async (call) => {
57
- call.writeCallDataFromSource(data).catch((err) => call.close(err));
59
+ const handleErr = (err) => {
60
+ serverData.end(err);
61
+ call.close(err);
62
+ };
63
+ call.writeCallDataFromSource(data).catch(handleErr);
58
64
  try {
59
65
  for await (const message of call.rpcDataSource) {
60
66
  serverData.push(message);
@@ -63,8 +69,7 @@ export class Client {
63
69
  call.close();
64
70
  }
65
71
  catch (err) {
66
- call.close(err);
67
- throw err;
72
+ handleErr(err);
68
73
  }
69
74
  })
70
75
  .catch((err) => serverData.end(err));
@@ -85,8 +90,8 @@ export class Client {
85
90
  call.close(new Error(ERR_RPC_ABORT));
86
91
  });
87
92
  pipe(stream, decodePacketSource, call, encodePacketSource, stream)
88
- .then(() => call.close())
89
- .catch((err) => call.close(err));
93
+ .catch((err) => call.close(err))
94
+ .then(() => call.close());
90
95
  await call.writeCallStart(data || undefined);
91
96
  return call;
92
97
  }
@@ -9,7 +9,12 @@ export class Server {
9
9
  // rpcStreamHandler implements the RpcStreamHandler interface.
10
10
  // uses handlePacketDuplex (expects 1 buf = 1 Packet)
11
11
  get rpcStreamHandler() {
12
- return this.handlePacketStream.bind(this);
12
+ return async (stream) => {
13
+ const rpc = this.startRpc();
14
+ return pipe(stream, decodePacketSource, rpc, encodePacketSource, stream)
15
+ .catch((err) => rpc.close(err))
16
+ .then(() => rpc.close());
17
+ };
13
18
  }
14
19
  // startRpc starts a new server-side RPC.
15
20
  // the returned RPC handles incoming Packets.
@@ -10,7 +10,9 @@ export class WebSocketConn extends StreamConn {
10
10
  const socketDuplex = duplex(socket);
11
11
  pipe(socketDuplex, this,
12
12
  // it-ws only supports sending Uint8Array.
13
- combineUint8ArrayListTransform(), socketDuplex);
13
+ combineUint8ArrayListTransform(), socketDuplex)
14
+ .catch((err) => this.close(err))
15
+ .then(() => this.close());
14
16
  }
15
17
  // getSocket returns the websocket.
16
18
  getSocket() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starpc",
3
- "version": "0.25.2",
3
+ "version": "0.25.4",
4
4
  "description": "Streaming protobuf RPC service protocol over any two-way channel.",
5
5
  "license": "MIT",
6
6
  "author": {
package/srpc/channel.ts CHANGED
@@ -42,6 +42,7 @@ export interface ChannelStreamOpts {
42
42
  // NOTE: there is no way to tell if a BroadcastChannel or MessagePort is closed.
43
43
  // This implementation sends a "closed" message when close() is called.
44
44
  // However: if the remote is removed w/o closing cleanly, the stream will be left open!
45
+ // Enable keepAliveMs and idleTimeoutMs to mitigate this issue with keep-alive messages.
45
46
  export class ChannelStream<T = Uint8Array>
46
47
  implements Duplex<AsyncGenerator<T>, Source<T>, Promise<void>>
47
48
  {
package/srpc/client.ts CHANGED
@@ -49,6 +49,7 @@ export class Client implements TsProtoRpc {
49
49
  ): Promise<Uint8Array> {
50
50
  const call = await this.startRpc(service, method, null, abortSignal)
51
51
  call.writeCallDataFromSource(data)
52
+ .catch(err => call.close(err))
52
53
  for await (const data of call.rpcDataSource) {
53
54
  call.close()
54
55
  return data
@@ -69,7 +70,8 @@ export class Client implements TsProtoRpc {
69
70
  this.startRpc(service, method, data, abortSignal)
70
71
  .then(async (call) => {
71
72
  const result = writeToPushable(call.rpcDataSource, serverData)
72
- result.finally(() => call.close())
73
+ result.catch((err) => call.close(err))
74
+ result.then(() => call.close())
73
75
  return result
74
76
  })
75
77
  .catch((err) => serverData.end(err))
@@ -86,7 +88,11 @@ export class Client implements TsProtoRpc {
86
88
  const serverData: Pushable<Uint8Array> = pushable({ objectMode: true })
87
89
  this.startRpc(service, method, null, abortSignal)
88
90
  .then(async (call) => {
89
- call.writeCallDataFromSource(data).catch((err) => call.close(err))
91
+ const handleErr = (err: Error) => {
92
+ serverData.end(err)
93
+ call.close(err)
94
+ }
95
+ call.writeCallDataFromSource(data).catch(handleErr)
90
96
  try {
91
97
  for await (const message of call.rpcDataSource) {
92
98
  serverData.push(message)
@@ -94,8 +100,7 @@ export class Client implements TsProtoRpc {
94
100
  serverData.end()
95
101
  call.close()
96
102
  } catch (err) {
97
- call.close(err as Error)
98
- throw err
103
+ handleErr(err as Error)
99
104
  }
100
105
  })
101
106
  .catch((err) => serverData.end(err))
@@ -122,8 +127,8 @@ export class Client implements TsProtoRpc {
122
127
  call.close(new Error(ERR_RPC_ABORT))
123
128
  })
124
129
  pipe(stream, decodePacketSource, call, encodePacketSource, stream)
125
- .then(() => call.close())
126
130
  .catch((err) => call.close(err))
131
+ .then(() => call.close())
127
132
  await call.writeCallStart(data || undefined)
128
133
  return call
129
134
  }
package/srpc/server.ts CHANGED
@@ -19,7 +19,12 @@ export class Server implements StreamHandler {
19
19
  // rpcStreamHandler implements the RpcStreamHandler interface.
20
20
  // uses handlePacketDuplex (expects 1 buf = 1 Packet)
21
21
  public get rpcStreamHandler(): RpcStreamHandler {
22
- return this.handlePacketStream.bind(this)
22
+ return async (stream: PacketStream) => {
23
+ const rpc = this.startRpc()
24
+ return pipe(stream, decodePacketSource, rpc, encodePacketSource, stream)
25
+ .catch((err: Error) => rpc.close(err))
26
+ .then(() => rpc.close())
27
+ }
23
28
  }
24
29
 
25
30
  // startRpc starts a new server-side RPC.
package/srpc/websocket.ts CHANGED
@@ -24,6 +24,8 @@ export class WebSocketConn extends StreamConn {
24
24
  combineUint8ArrayListTransform(),
25
25
  socketDuplex,
26
26
  )
27
+ .catch((err) => this.close(err))
28
+ .then(() => this.close())
27
29
  }
28
30
 
29
31
  // getSocket returns the websocket.