starpc 0.50.0 → 0.51.0

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.
Files changed (81) hide show
  1. package/dist/integration/cross-language/ts-client.js +5 -79
  2. package/dist/integration/cross-language/ts-server.js +4 -100
  3. package/dist/srpc/client.d.ts +1 -3
  4. package/dist/srpc/client.js +2 -22
  5. package/dist/srpc/common-rpc.d.ts +1 -9
  6. package/dist/srpc/common-rpc.js +4 -62
  7. package/dist/srpc/handler.d.ts +1 -2
  8. package/dist/srpc/index.d.ts +0 -4
  9. package/dist/srpc/index.js +0 -3
  10. package/dist/srpc/invoker.d.ts +1 -2
  11. package/dist/srpc/rpcproto.pb.d.ts +0 -44
  12. package/dist/srpc/rpcproto.pb.js +0 -53
  13. package/dist/srpc/server-rpc.js +1 -3
  14. package/dist/srpc/server.test.js +35 -1
  15. package/echo/echo.go +8 -8
  16. package/echo/echo.pb.go +12 -36
  17. package/echo/echo_srpc.pb.cpp +1 -1
  18. package/echo/echo_srpc.pb.go +1 -1
  19. package/echo/echo_srpc.pb.hpp +1 -1
  20. package/echo/echo_srpc.pb.rs +1 -1
  21. package/echo/server.go +1 -1
  22. package/go.mod +1 -1
  23. package/go.sum +2 -0
  24. package/integration/cross-language/go-client/main.go +4 -142
  25. package/integration/cross-language/go-server/main.go +2 -170
  26. package/integration/cross-language/run.bash +5 -105
  27. package/integration/cross-language/ts-client.ts +5 -90
  28. package/integration/cross-language/ts-server.ts +4 -112
  29. package/mock/mock.go +1 -1
  30. package/mock/mock.pb.go +12 -36
  31. package/mock/mock_srpc.pb.cpp +1 -1
  32. package/mock/mock_srpc.pb.go +1 -1
  33. package/mock/mock_srpc.pb.hpp +1 -1
  34. package/mock/mock_srpc.pb.rs +1 -1
  35. package/package.json +1 -1
  36. package/srpc/client-prefix.go +1 -1
  37. package/srpc/client-set.go +1 -1
  38. package/srpc/client.go +1 -1
  39. package/srpc/client.ts +4 -31
  40. package/srpc/common-rpc.go +15 -69
  41. package/srpc/common-rpc.ts +4 -77
  42. package/srpc/common-rpc_test.go +81 -0
  43. package/srpc/errors.go +26 -1
  44. package/srpc/handler.ts +1 -2
  45. package/srpc/index.ts +0 -4
  46. package/srpc/invoker-prefix.go +1 -1
  47. package/srpc/invoker.go +2 -2
  48. package/srpc/invoker.ts +5 -9
  49. package/srpc/message.go +1 -1
  50. package/srpc/msg-stream.go +1 -9
  51. package/srpc/mux-verbose.go +1 -1
  52. package/srpc/mux.go +1 -1
  53. package/srpc/rpcproto.pb.cc +4 -15
  54. package/srpc/rpcproto.pb.go +102 -419
  55. package/srpc/rpcproto.pb.h +0 -59
  56. package/srpc/rpcproto.pb.rs +0 -45
  57. package/srpc/rpcproto.pb.ts +0 -62
  58. package/srpc/rpcproto.proto +0 -16
  59. package/srpc/server-rpc.go +1 -1
  60. package/srpc/server-rpc.ts +1 -6
  61. package/srpc/server.test.ts +49 -1
  62. package/srpc/stream-pipe.go +1 -1
  63. package/srpc/stream-rwc.go +1 -1
  64. package/srpc/stream.go +0 -20
  65. package/dist/rpcstream/receipt.test.d.ts +0 -1
  66. package/dist/rpcstream/receipt.test.js +0 -41
  67. package/dist/srpc/call-receipt.d.ts +0 -17
  68. package/dist/srpc/call-receipt.js +0 -106
  69. package/dist/srpc/call-receipt.test.d.ts +0 -1
  70. package/dist/srpc/call-receipt.test.js +0 -375
  71. package/dist/srpc/server-invocation.d.ts +0 -17
  72. package/dist/srpc/server-invocation.js +0 -37
  73. package/integration/cross-language/go-server/fixture-owner_test.go +0 -127
  74. package/srpc/call-receipt-e2e_test.go +0 -111
  75. package/srpc/call-receipt.go +0 -112
  76. package/srpc/call-receipt.test.ts +0 -441
  77. package/srpc/call-receipt.ts +0 -131
  78. package/srpc/call-receipt_test.go +0 -536
  79. package/srpc/schema-ownership_test.go +0 -115
  80. package/srpc/server-invocation.go +0 -40
  81. package/srpc/server-invocation.ts +0 -76
@@ -1,25 +1,10 @@
1
1
  import net from 'net';
2
- import { closeSync, openSync, writeSync } from 'node:fs';
3
2
  import { pipe } from 'it-pipe';
4
3
  import { pushable } from 'it-pushable';
5
4
  import { Client } from '../../srpc/client.js';
6
5
  import { parseLengthPrefixTransform, prependLengthPrefixTransform, } from '../../srpc/packet.js';
7
6
  import { combineUint8ArrayListTransform } from '../../srpc/array-list.js';
8
- import { EchoMsg, runClientTest } from '../../echo/index.js';
9
- function emitReceiptEvent(line) {
10
- console.log(line);
11
- const fifo = process.env.RECEIPT_EVENT_FIFO;
12
- if (!fifo) {
13
- return;
14
- }
15
- const fd = openSync(fifo, 'w');
16
- try {
17
- writeSync(fd, `${line}\n`);
18
- }
19
- finally {
20
- closeSync(fd);
21
- }
22
- }
7
+ import { runClientTest } from '../../echo/index.js';
23
8
  // tcpSocketToPacketStream wraps a Node.js TCP socket into a PacketStream.
24
9
  function tcpSocketToPacketStream(socket) {
25
10
  const socketSource = async function* () {
@@ -51,85 +36,26 @@ function tcpSocketToPacketStream(socket) {
51
36
  };
52
37
  }
53
38
  async function main() {
54
- const receiptMode = process.argv[2] === 'receipt';
55
- const receiptCase = receiptMode ? process.argv[3] : undefined;
56
- const addr = receiptMode ? process.argv[4] : process.argv[2];
39
+ const addr = process.argv[2];
57
40
  if (!addr) {
58
- console.error('usage: ts-client [receipt <case>] <host:port>');
41
+ console.error('usage: ts-client <host:port>');
59
42
  process.exit(1);
60
43
  }
61
- if (receiptMode &&
62
- !['commit', 'abort', 'loss', 'bare-close'].includes(receiptCase ?? '')) {
63
- throw new Error(`unknown receipt case: ${receiptCase}`);
64
- }
65
44
  const [host, portStr] = addr.split(':');
66
45
  const port = parseInt(portStr, 10);
67
- let activeSocket;
68
46
  const openStream = async () => {
69
47
  const { promise, resolve, reject } = Promise.withResolvers();
70
48
  const socket = net.connect(port, host, () => {
71
- activeSocket = socket;
72
49
  resolve(tcpSocketToPacketStream(socket));
73
50
  });
74
51
  socket.on('error', reject);
75
52
  return promise;
76
53
  };
77
54
  const client = new Client(openStream);
78
- if (receiptMode) {
79
- console.log(`Running held receipt test via TCP (${receiptCase})...`);
80
- const request = EchoMsg.create({ body: 'held receipt' });
81
- const held = await client.requestWithReceipt('echo.Echoer', 'Echo', EchoMsg.toBinary(request));
82
- const result = EchoMsg.fromBinary(held.response);
83
- if (result.body !== request.body) {
84
- throw new Error(`expected ${request.body}, got ${result.body}`);
85
- }
86
- switch (receiptCase) {
87
- case 'commit':
88
- await held.receipt.commit();
89
- break;
90
- case 'abort':
91
- await held.receipt.abort();
92
- break;
93
- case 'loss':
94
- activeSocket?.resetAndDestroy();
95
- await expectReceiptFailure(held.receipt);
96
- break;
97
- case 'bare-close':
98
- activeSocket?.end();
99
- await expectReceiptFailure(held.receipt);
100
- break;
101
- }
102
- emitReceiptEvent(`CLIENT_RECEIPT_RESOLVED ${receiptTerminalName(receiptCase ?? '')}`);
103
- }
104
- else {
105
- console.log('Running client test via TCP...');
106
- await runClientTest(client);
107
- }
55
+ console.log('Running client test via TCP...');
56
+ await runClientTest(client);
108
57
  console.log('All tests passed.');
109
58
  }
110
- function receiptTerminalName(receiptCase) {
111
- switch (receiptCase) {
112
- case 'commit':
113
- return 'committed';
114
- case 'abort':
115
- return 'canceled';
116
- case 'loss':
117
- return 'transportLost';
118
- case 'bare-close':
119
- return 'closed';
120
- default:
121
- return 'unknown';
122
- }
123
- }
124
- async function expectReceiptFailure(receipt) {
125
- try {
126
- await receipt.commit();
127
- }
128
- catch {
129
- return;
130
- }
131
- throw new Error('receipt commit unexpectedly succeeded');
132
- }
133
59
  process.on('unhandledRejection', (ev) => {
134
60
  console.error('Unhandled rejection', ev);
135
61
  process.exit(1);
@@ -1,27 +1,11 @@
1
1
  import net from 'net';
2
- import { closeSync, openSync, writeSync } from 'node:fs';
3
2
  import { pipe } from 'it-pipe';
4
3
  import { pushable } from 'it-pushable';
5
4
  import { createMux, createHandler, Server } from '../../srpc/index.js';
6
5
  import { parseLengthPrefixTransform, prependLengthPrefixTransform, } from '../../srpc/packet.js';
7
6
  import { combineUint8ArrayListTransform } from '../../srpc/array-list.js';
8
- import { EchoerServer, EchoMsg } from '../../echo/index.js';
7
+ import { EchoerServer } from '../../echo/index.js';
9
8
  import { EchoerDefinition } from '../../echo/echo_srpc.pb.js';
10
- import { Packet, TerminalKind } from '../../srpc/rpcproto.pb.js';
11
- function emitReceiptEvent(line) {
12
- console.log(line);
13
- const fifo = process.env.RECEIPT_EVENT_FIFO;
14
- if (!fifo) {
15
- return;
16
- }
17
- const fd = openSync(fifo, 'w');
18
- try {
19
- writeSync(fd, `${line}\n`);
20
- }
21
- finally {
22
- closeSync(fd);
23
- }
24
- }
25
9
  // tcpSocketToPacketStream wraps a Node.js TCP socket into a PacketStream.
26
10
  // Each Uint8Array in source/sink is one packet (no length prefix).
27
11
  function tcpSocketToPacketStream(socket) {
@@ -41,15 +25,7 @@ function tcpSocketToPacketStream(socket) {
41
25
  sink: async (source) => {
42
26
  for await (const chunk of pipe(source, prependLengthPrefixTransform())) {
43
27
  const data = chunk instanceof Uint8Array ? chunk : chunk.subarray();
44
- const packet = Packet.fromBinary(data.subarray(4));
45
- const receiptCompletion = receiptMode &&
46
- packet.body?.case === 'callData' &&
47
- packet.body.value.complete &&
48
- !packet.body.value.error;
49
- if (receiptCompletion) {
50
- emitReceiptEvent('SERVER_RECEIPT_ACK_WRITE committed');
51
- }
52
- const writeDone = new Promise((resolve, reject) => {
28
+ await new Promise((resolve, reject) => {
53
29
  socket.write(data, (err) => {
54
30
  if (err)
55
31
  reject(err);
@@ -57,82 +33,15 @@ function tcpSocketToPacketStream(socket) {
57
33
  resolve();
58
34
  });
59
35
  });
60
- await writeDone;
61
- if (receiptCompletion) {
62
- finishReceiptServer();
63
- }
64
36
  }
65
37
  socket.end();
66
38
  },
67
39
  };
68
40
  }
69
41
  const mux = createMux();
70
- const receiptMode = process.argv[2] === 'receipt';
71
- const receiptCase = receiptMode ? process.argv[3] : undefined;
72
- if (receiptMode &&
73
- !['commit', 'abort', 'loss', 'bare-close'].includes(receiptCase ?? '')) {
74
- console.error(`unknown receipt case: ${receiptCase}`);
75
- process.exit(1);
76
- }
77
- const receiptServerDone = Promise.withResolvers();
78
- let receiptServerFinished = false;
79
- function finishReceiptServer() {
80
- if (!receiptServerFinished) {
81
- receiptServerFinished = true;
82
- receiptServerDone.resolve();
83
- }
84
- }
85
- if (receiptMode) {
86
- mux.registerLookupMethod(async (serviceID, methodID) => {
87
- if (serviceID !== 'echo.Echoer' || methodID !== 'Echo') {
88
- return null;
89
- }
90
- return async (dataSource, dataSink, invocation) => {
91
- let requestData;
92
- for await (const data of dataSource) {
93
- requestData = data;
94
- break;
95
- }
96
- if (!requestData) {
97
- throw new Error('receipt request was empty');
98
- }
99
- const requestMsg = EchoMsg.fromBinary(requestData);
100
- await dataSink((async function* () {
101
- yield EchoMsg.toBinary(requestMsg);
102
- if (!invocation) {
103
- throw new Error('receipt invocation was missing');
104
- }
105
- emitReceiptEvent('SERVER_RECEIPT_WAITING');
106
- const terminal = await invocation.waitTerminal(new AbortController().signal);
107
- emitReceiptEvent(`SERVER_RECEIPT_TERMINAL ${terminalName(terminal)}`);
108
- if (terminal !== TerminalKind.COMMITTED) {
109
- finishReceiptServer();
110
- }
111
- })());
112
- };
113
- });
114
- }
115
- function terminalName(terminal) {
116
- switch (terminal) {
117
- case TerminalKind.COMMITTED:
118
- return 'committed';
119
- case TerminalKind.CANCELED:
120
- return 'canceled';
121
- case TerminalKind.TRANSPORT_LOST:
122
- return 'transportLost';
123
- case TerminalKind.CLOSED:
124
- return 'closed';
125
- case TerminalKind.ABANDONED:
126
- return 'abandoned';
127
- default:
128
- return 'unknown';
129
- }
130
- }
131
42
  const server = new Server(mux.lookupMethod);
132
- if (!receiptMode) {
133
- const echoer = new EchoerServer(server);
134
- mux.register(createHandler(EchoerDefinition, echoer));
135
- }
43
+ const echoer = new EchoerServer(server);
44
+ mux.register(createHandler(EchoerDefinition, echoer));
136
45
  const tcpServer = net.createServer((socket) => {
137
46
  const stream = tcpSocketToPacketStream(socket);
138
47
  server.handlePacketStream(stream);
@@ -141,11 +50,6 @@ tcpServer.listen(0, '127.0.0.1', () => {
141
50
  const addr = tcpServer.address();
142
51
  console.log(`LISTENING ${addr.address}:${addr.port}`);
143
52
  });
144
- if (receiptMode) {
145
- void receiptServerDone.promise.then(() => {
146
- tcpServer.close();
147
- });
148
- }
149
53
  process.on('SIGINT', () => {
150
54
  tcpServer.close();
151
55
  process.exit(0);
@@ -1,12 +1,10 @@
1
1
  import type { ProtoRpc } from './proto-rpc.js';
2
2
  import type { OpenStreamFunc } from './stream.js';
3
- import type { HeldCall, ReceiptRpc } from './call-receipt.js';
4
- export declare class Client implements ProtoRpc, ReceiptRpc {
3
+ export declare class Client implements ProtoRpc {
5
4
  private openStreamCtr;
6
5
  constructor(openStreamFn?: OpenStreamFunc);
7
6
  setOpenStreamFn(openStreamFn?: OpenStreamFunc): void;
8
7
  request(service: string, method: string, data: Uint8Array, abortSignal?: AbortSignal): Promise<Uint8Array>;
9
- requestWithReceipt(service: string, method: string, data: Uint8Array, abortSignal?: AbortSignal): Promise<HeldCall>;
10
8
  clientStreamingRequest(service: string, method: string, data: AsyncIterable<Uint8Array>, abortSignal?: AbortSignal): Promise<Uint8Array>;
11
9
  serverStreamingRequest(service: string, method: string, data: Uint8Array, abortSignal?: AbortSignal): AsyncIterable<Uint8Array>;
12
10
  bidirectionalStreamingRequest(service: string, method: string, data: AsyncIterable<Uint8Array>, abortSignal?: AbortSignal): AsyncIterable<Uint8Array>;
@@ -5,7 +5,6 @@ import { ClientRPC } from './client-rpc.js';
5
5
  import { writeToPushable } from './pushable.js';
6
6
  import { decodePacketSource, encodePacketSource } from './packet.js';
7
7
  import { OpenStreamCtr } from './open-stream-ctr.js';
8
- import { CallReceipt } from './call-receipt.js';
9
8
  // Client implements the ts-proto Rpc interface with the drpcproto protocol.
10
9
  export class Client {
11
10
  // openStreamCtr contains the OpenStreamFunc.
@@ -28,25 +27,6 @@ export class Client {
28
27
  call.close(err);
29
28
  throw err;
30
29
  }
31
- // requestWithReceipt reads one response and retains the call terminal.
32
- async requestWithReceipt(service, method, data, abortSignal) {
33
- const call = await this.startRpc(service, method, data, abortSignal);
34
- const iterator = call.rpcDataSource[Symbol.asyncIterator]();
35
- try {
36
- const result = await iterator.next();
37
- if (result.done) {
38
- throw new Error('empty response');
39
- }
40
- return {
41
- response: result.value,
42
- receipt: new CallReceipt(call, iterator),
43
- };
44
- }
45
- catch (err) {
46
- await call.close(err instanceof Error ? err : new Error('receipt read failed'));
47
- throw err;
48
- }
49
- }
50
30
  // clientStreamingRequest starts a client side streaming request.
51
31
  async clientStreamingRequest(service, method, data, abortSignal) {
52
32
  const call = await this.startRpc(service, method, null, abortSignal);
@@ -102,8 +82,8 @@ export class Client {
102
82
  const stream = await openStreamFn();
103
83
  const call = new ClientRPC(rpcService, rpcMethod);
104
84
  const onAbort = () => {
105
- call.writeCallCancel();
106
- call.close(new Error(ERR_RPC_ABORT));
85
+ void call.writeCallCancel().catch(() => undefined);
86
+ void call.close(new Error(ERR_RPC_ABORT)).catch(() => undefined);
107
87
  };
108
88
  abortSignal?.addEventListener('abort', onAbort, { once: true });
109
89
  pipe(stream, decodePacketSource, call, encodePacketSource, stream)
@@ -1,5 +1,5 @@
1
1
  import type { Sink, Source } from 'it-stream-types';
2
- import { Packet, TerminalKind, type CallData, type CallStart } from './rpcproto.pb.js';
2
+ import { Packet, type CallData, type CallStart } from './rpcproto.pb.js';
3
3
  export declare class CommonRPC {
4
4
  readonly sink: Sink<Source<Packet>>;
5
5
  readonly source: AsyncIterable<Packet>;
@@ -9,20 +9,12 @@ export declare class CommonRPC {
9
9
  protected service?: string;
10
10
  protected method?: string;
11
11
  private closed?;
12
- private remoteCompleted;
13
12
  private remoteError?;
14
- private remoteSourceClosed;
15
- private remoteTerminal?;
16
13
  private readonly invocationController;
17
- private readonly terminalPromise;
18
- private resolveTerminal;
19
14
  private readonly writeDrainAbort;
20
15
  constructor();
21
16
  get isClosed(): boolean | Error;
22
17
  protected get invocationSignal(): AbortSignal;
23
- protected waitTerminal(ownerSignal: AbortSignal): Promise<TerminalKind>;
24
- getTerminalKind(): TerminalKind | undefined;
25
- private recordRemoteTerminal;
26
18
  writeCallData(data?: Uint8Array, complete?: boolean, error?: string): Promise<void>;
27
19
  private writeCallDataPacket;
28
20
  writeCallCancel(waitForDrain?: boolean): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import { pushable } from 'it-pushable';
2
- import { Packet, TerminalKind, } from './rpcproto.pb.js';
2
+ import { Packet } from './rpcproto.pb.js';
3
3
  import { ERR_RPC_ABORT, RemoteRPCError } from './errors.js';
4
4
  const maxBufferedOutgoingPackets = 1;
5
5
  // CommonRPC is common logic between server and client RPCs.
@@ -24,25 +24,13 @@ export class CommonRPC {
24
24
  method;
25
25
  // closed indicates this rpc has been closed already.
26
26
  closed;
27
- // remoteCompleted is set only by an explicit remote CallData completion.
28
- remoteCompleted = false;
29
27
  // remoteError records a remote error or transport failure.
30
28
  remoteError;
31
- // remoteSourceClosed records an incoming source ending without a packet error.
32
- remoteSourceClosed = false;
33
- // remoteTerminal is the first valid remote terminal.
34
- remoteTerminal;
35
- // invocationController cancels the server invocation on a remote terminal.
29
+ // invocationController cancels the server invocation when the RPC closes.
36
30
  invocationController = new AbortController();
37
- // terminalPromise resolves when a remote terminal is recorded.
38
- terminalPromise;
39
- resolveTerminal;
40
31
  // writeDrainAbort wakes writers waiting for outbound stream drain on close.
41
32
  writeDrainAbort = new AbortController();
42
33
  constructor() {
43
- const { promise, resolve } = Promise.withResolvers();
44
- this.terminalPromise = promise;
45
- this.resolveTerminal = resolve;
46
34
  this.sink = this._createSink();
47
35
  this.source = this._source;
48
36
  this.rpcDataSource = this._rpcDataSource;
@@ -51,49 +39,10 @@ export class CommonRPC {
51
39
  get isClosed() {
52
40
  return this.closed ?? false;
53
41
  }
54
- // invocationSignal is canceled when the RPC reaches a terminal.
42
+ // invocationSignal is canceled when the RPC closes.
55
43
  get invocationSignal() {
56
44
  return this.invocationController.signal;
57
45
  }
58
- // waitTerminal waits for the remote terminal or external owner cancellation.
59
- async waitTerminal(ownerSignal) {
60
- const { promise: ownerDone, resolve: resolveOwnerDone } = Promise.withResolvers();
61
- const onAbort = () => resolveOwnerDone();
62
- ownerSignal.addEventListener('abort', onAbort, { once: true });
63
- let ownerAborted = ownerSignal.aborted;
64
- try {
65
- for (;;) {
66
- const terminal = this.getTerminalKind();
67
- if (terminal !== undefined) {
68
- if (terminal === TerminalKind.CLOSED &&
69
- this.remoteSourceClosed &&
70
- !this.closed) {
71
- await this.close();
72
- }
73
- return terminal;
74
- }
75
- if (ownerAborted) {
76
- return TerminalKind.ABANDONED;
77
- }
78
- await Promise.race([this.terminalPromise, ownerDone]);
79
- ownerAborted = ownerSignal.aborted;
80
- }
81
- }
82
- finally {
83
- ownerSignal.removeEventListener('abort', onAbort);
84
- }
85
- }
86
- // getTerminalKind returns the observed remote terminal, if any.
87
- getTerminalKind() {
88
- return this.remoteTerminal;
89
- }
90
- recordRemoteTerminal(kind) {
91
- if (this.remoteTerminal !== undefined) {
92
- return;
93
- }
94
- this.remoteTerminal = kind;
95
- this.resolveTerminal();
96
- }
97
46
  // writeCallData writes the call data packet.
98
47
  async writeCallData(data, complete, error) {
99
48
  await this.writeCallDataPacket(data, complete, error);
@@ -221,20 +170,16 @@ export class CommonRPC {
221
170
  if (remoteError) {
222
171
  this.remoteError ??= remoteError;
223
172
  this.invocationController.abort();
224
- this.recordRemoteTerminal(TerminalKind.TRANSPORT_LOST);
225
173
  }
226
174
  if (packet.complete && !remoteError) {
227
- this.remoteCompleted = true;
228
- this.recordRemoteTerminal(TerminalKind.COMMITTED);
229
175
  this._rpcDataSource.end(remoteError);
230
176
  }
231
177
  else if (remoteError) {
232
178
  this._rpcDataSource.end(remoteError);
233
179
  }
234
180
  }
235
- // handleCallCancel handles a CallCancel packet.
181
+ // handleCallCancel aborts the invocation and closes the call.
236
182
  async handleCallCancel() {
237
- this.recordRemoteTerminal(TerminalKind.CANCELED);
238
183
  await this.close(new Error(ERR_RPC_ABORT));
239
184
  }
240
185
  // close closes the call, optionally with an error.
@@ -246,7 +191,6 @@ export class CommonRPC {
246
191
  if (!this.remoteError && err) {
247
192
  this.remoteError = err;
248
193
  }
249
- this.recordRemoteTerminal(err ? TerminalKind.TRANSPORT_LOST : TerminalKind.CLOSED);
250
194
  this.invocationController.abort();
251
195
  // note: this does nothing if _source is already ended.
252
196
  if (err && err.message) {
@@ -272,8 +216,6 @@ export class CommonRPC {
272
216
  await this.handlePacket(msg);
273
217
  }
274
218
  }
275
- this.remoteSourceClosed = true;
276
- this.recordRemoteTerminal(TerminalKind.CLOSED);
277
219
  }
278
220
  catch (err) {
279
221
  this.close(err);
@@ -1,7 +1,6 @@
1
1
  import type { Sink, Source } from 'it-stream-types';
2
2
  import { ServiceDefinition, ServiceMethodDefinitions } from './definition.js';
3
- import type { ServerInvocation } from './server-invocation.js';
4
- export type InvokeFn = (dataSource: Source<Uint8Array>, dataSink: Sink<Source<Uint8Array>>, invocation?: ServerInvocation) => Promise<void>;
3
+ export type InvokeFn = (dataSource: Source<Uint8Array>, dataSink: Sink<Source<Uint8Array>>, invocation?: AbortSignal) => Promise<void>;
5
4
  export interface Handler {
6
5
  getServiceID(): string;
7
6
  getMethodIDs(): string[];
@@ -1,9 +1,5 @@
1
1
  export { ERR_RPC_ABORT, isAbortError, ERR_STREAM_IDLE, isStreamIdleError, castToError, } from './errors.js';
2
2
  export { Client } from './client.js';
3
- export { CallReceipt } from './call-receipt.js';
4
- export type { HeldCall, ReceiptRpc } from './call-receipt.js';
5
- export { ServerInvocation } from './server-invocation.js';
6
- export { TerminalKind } from './rpcproto.pb.js';
7
3
  export { Server } from './server.js';
8
4
  export { StreamConn } from './conn.js';
9
5
  export type { StreamConnParams, StreamHandler } from './conn.js';
@@ -1,8 +1,5 @@
1
1
  export { ERR_RPC_ABORT, isAbortError, ERR_STREAM_IDLE, isStreamIdleError, castToError, } from './errors.js';
2
2
  export { Client } from './client.js';
3
- export { CallReceipt } from './call-receipt.js';
4
- export { ServerInvocation } from './server-invocation.js';
5
- export { TerminalKind } from './rpcproto.pb.js';
6
3
  export { Server } from './server.js';
7
4
  export { StreamConn } from './conn.js';
8
5
  export { WebSocketConn } from './websocket.js';
@@ -2,6 +2,5 @@ import type { MethodDefinition } from './definition.js';
2
2
  import { InvokeFn } from './handler.js';
3
3
  import type { MessageType, Message } from '@aptre/protobuf-es-lite';
4
4
  import { MethodIdempotency, MethodKind } from '@aptre/protobuf-es-lite';
5
- import type { ServerInvocation } from './server-invocation.js';
6
- export type MethodProto<R extends Message<R>, O extends Message<O>> = ((request: R, invocation?: ServerInvocation) => Promise<O>) | ((request: R, invocation?: ServerInvocation) => AsyncIterable<O>) | ((request: AsyncIterable<R>, invocation?: ServerInvocation) => Promise<O>) | ((request: AsyncIterable<R>, invocation?: ServerInvocation) => AsyncIterable<O>);
5
+ export type MethodProto<R extends Message<R>, O extends Message<O>> = ((request: R, invocation?: AbortSignal) => Promise<O>) | ((request: R, invocation?: AbortSignal) => AsyncIterable<O>) | ((request: AsyncIterable<R>, invocation?: AbortSignal) => Promise<O>) | ((request: AsyncIterable<R>, invocation?: AbortSignal) => AsyncIterable<O>);
7
6
  export declare function createInvokeFn<R extends Message<R>, O extends Message<O>>(methodInfo: MethodDefinition<MessageType<R>, MessageType<O>, MethodKind, MethodIdempotency | undefined>, methodProto: MethodProto<R, O>): InvokeFn;
@@ -1,49 +1,5 @@
1
1
  import type { MessageType } from '@aptre/protobuf-es-lite/message';
2
2
  export declare const protobufPackage = "srpc";
3
- /**
4
- * TerminalKind is the terminal state of a held unary invocation.
5
- *
6
- * @generated from enum srpc.TerminalKind
7
- */
8
- export declare enum TerminalKind {
9
- /**
10
- * TERMINAL_KIND_UNSPECIFIED is not a valid terminal state.
11
- *
12
- * @generated from enum value: TERMINAL_KIND_UNSPECIFIED = 0;
13
- */
14
- UNSPECIFIED = 0,
15
- /**
16
- * TERMINAL_KIND_COMMITTED identifies an explicit remote CallData completion.
17
- *
18
- * @generated from enum value: TERMINAL_KIND_COMMITTED = 1;
19
- */
20
- COMMITTED = 1,
21
- /**
22
- * TERMINAL_KIND_CANCELED identifies a remote CallCancel packet.
23
- *
24
- * @generated from enum value: TERMINAL_KIND_CANCELED = 2;
25
- */
26
- CANCELED = 2,
27
- /**
28
- * TERMINAL_KIND_TRANSPORT_LOST identifies a remote error or transport failure.
29
- *
30
- * @generated from enum value: TERMINAL_KIND_TRANSPORT_LOST = 3;
31
- */
32
- TRANSPORT_LOST = 3,
33
- /**
34
- * TERMINAL_KIND_CLOSED identifies a bare remote close without completion.
35
- *
36
- * @generated from enum value: TERMINAL_KIND_CLOSED = 4;
37
- */
38
- CLOSED = 4,
39
- /**
40
- * TERMINAL_KIND_ABANDONED identifies owner-context expiry without a remote terminal.
41
- *
42
- * @generated from enum value: TERMINAL_KIND_ABANDONED = 5;
43
- */
44
- ABANDONED = 5
45
- }
46
- export declare const TerminalKind_Enum: import("@aptre/protobuf-es-lite/enum").EnumType;
47
3
  /**
48
4
  * CallStart requests starting a new RPC call.
49
5
  *
@@ -1,62 +1,9 @@
1
1
  // @generated by protoc-gen-es-lite unknown with parameter "target=ts,ts_nocheck=false"
2
2
  // @generated from file github.com/aperturerobotics/starpc/srpc/rpcproto.proto (package srpc, syntax proto3)
3
3
  /* eslint-disable */
4
- import { createEnumType } from '@aptre/protobuf-es-lite/enum';
5
4
  import { createMessageType } from '@aptre/protobuf-es-lite/message';
6
5
  import { ScalarType } from '@aptre/protobuf-es-lite/scalar';
7
6
  export const protobufPackage = 'srpc';
8
- /**
9
- * TerminalKind is the terminal state of a held unary invocation.
10
- *
11
- * @generated from enum srpc.TerminalKind
12
- */
13
- export var TerminalKind;
14
- (function (TerminalKind) {
15
- /**
16
- * TERMINAL_KIND_UNSPECIFIED is not a valid terminal state.
17
- *
18
- * @generated from enum value: TERMINAL_KIND_UNSPECIFIED = 0;
19
- */
20
- TerminalKind[TerminalKind["UNSPECIFIED"] = 0] = "UNSPECIFIED";
21
- /**
22
- * TERMINAL_KIND_COMMITTED identifies an explicit remote CallData completion.
23
- *
24
- * @generated from enum value: TERMINAL_KIND_COMMITTED = 1;
25
- */
26
- TerminalKind[TerminalKind["COMMITTED"] = 1] = "COMMITTED";
27
- /**
28
- * TERMINAL_KIND_CANCELED identifies a remote CallCancel packet.
29
- *
30
- * @generated from enum value: TERMINAL_KIND_CANCELED = 2;
31
- */
32
- TerminalKind[TerminalKind["CANCELED"] = 2] = "CANCELED";
33
- /**
34
- * TERMINAL_KIND_TRANSPORT_LOST identifies a remote error or transport failure.
35
- *
36
- * @generated from enum value: TERMINAL_KIND_TRANSPORT_LOST = 3;
37
- */
38
- TerminalKind[TerminalKind["TRANSPORT_LOST"] = 3] = "TRANSPORT_LOST";
39
- /**
40
- * TERMINAL_KIND_CLOSED identifies a bare remote close without completion.
41
- *
42
- * @generated from enum value: TERMINAL_KIND_CLOSED = 4;
43
- */
44
- TerminalKind[TerminalKind["CLOSED"] = 4] = "CLOSED";
45
- /**
46
- * TERMINAL_KIND_ABANDONED identifies owner-context expiry without a remote terminal.
47
- *
48
- * @generated from enum value: TERMINAL_KIND_ABANDONED = 5;
49
- */
50
- TerminalKind[TerminalKind["ABANDONED"] = 5] = "ABANDONED";
51
- })(TerminalKind || (TerminalKind = {}));
52
- export const TerminalKind_Enum = /* @__PURE__ */ createEnumType('srpc.TerminalKind', [
53
- [0, 'TERMINAL_KIND_UNSPECIFIED'],
54
- [1, 'TERMINAL_KIND_COMMITTED'],
55
- [2, 'TERMINAL_KIND_CANCELED'],
56
- [3, 'TERMINAL_KIND_TRANSPORT_LOST'],
57
- [4, 'TERMINAL_KIND_CLOSED'],
58
- [5, 'TERMINAL_KIND_ABANDONED'],
59
- ]);
60
7
  export const CallStart =
61
8
  /* @__PURE__ */ createMessageType({
62
9
  typeName: 'srpc.CallStart',
@@ -1,5 +1,4 @@
1
1
  import { CommonRPC } from './common-rpc.js';
2
- import { ServerInvocation } from './server-invocation.js';
3
2
  // ServerRPC is an ongoing RPC from the server side.
4
3
  export class ServerRPC extends CommonRPC {
5
4
  // lookupMethod looks up the incoming RPC methods.
@@ -38,9 +37,8 @@ export class ServerRPC extends CommonRPC {
38
37
  // invokeRPC starts invoking the RPC handler.
39
38
  async invokeRPC(invokeFn) {
40
39
  const dataSink = this._createDataSink();
41
- const invocation = new ServerInvocation(this.invocationSignal, (ownerSignal) => this.waitTerminal(ownerSignal));
42
40
  try {
43
- await invokeFn(this.rpcDataSource, dataSink, invocation);
41
+ await invokeFn(this.rpcDataSource, dataSink, this.invocationSignal);
44
42
  }
45
43
  catch (err) {
46
44
  this.close(err);