@procedures/client 0.48.2 → 0.49.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.
- package/CHANGELOG.md +18 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/server/body.d.ts.map +1 -1
- package/dist/adapters/http/server/body.js +13 -2
- package/dist/adapters/http/server/body.js.map +1 -1
- package/dist/adapters/websocket/client/transport.d.ts +6 -0
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +53 -6
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/client/types.d.ts +2 -0
- package/dist/adapters/websocket/client/types.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +2 -1
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/server/types.d.ts +2 -0
- package/dist/adapters/websocket/server/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/adapters/http/server/body.ts +11 -2
- package/src/adapters/websocket/client/transport.ts +52 -7
- package/src/adapters/websocket/client/types.ts +3 -0
- package/src/adapters/websocket/server/transport.ts +2 -1
- package/src/adapters/websocket/server/types.ts +3 -0
|
@@ -133,6 +133,12 @@ function detach(ws: WebSocket): void {
|
|
|
133
133
|
ws.onerror = ignoreError;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/** A call longer than this length waits for the `hello` of the server. The `hello` tells the limit of the server (roadmap CLI-108). */
|
|
137
|
+
const HELLO_WAIT_FROM_CHARS = 64 * 1024;
|
|
138
|
+
|
|
139
|
+
/** The longest wait for the `hello` of the server. An older server answers the `hello` with an error, which also ends the wait. */
|
|
140
|
+
const HELLO_WAIT_MS = 2_000;
|
|
141
|
+
|
|
136
142
|
/** The close code of a message above the limit of the other side (RFC 6455, 1009). */
|
|
137
143
|
const MESSAGE_TOO_BIG = 1009;
|
|
138
144
|
|
|
@@ -146,6 +152,13 @@ function tooLarge(id: string): ClientError {
|
|
|
146
152
|
return new ClientError({ type: "error", code: "PAYLOAD_TOO_LARGE", message, retryable: false }, id);
|
|
147
153
|
}
|
|
148
154
|
|
|
155
|
+
/** This function tells if the UTF-8 form of a text has more bytes than a limit. It encodes the text only when its length does not decide. */
|
|
156
|
+
function byteLengthAbove(text: string, limit: number): boolean {
|
|
157
|
+
if (text.length > limit) return true;
|
|
158
|
+
if (text.length * 3 <= limit) return false;
|
|
159
|
+
return new TextEncoder().encode(text).length > limit;
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
function errorItem<TRes>(id: string, code: string, message: string, retryable: boolean): ResponseItem<TRes> {
|
|
150
163
|
return { id, status: { type: "error", code, message, retryable }, payload: null as TRes, metadata: {} };
|
|
151
164
|
}
|
|
@@ -263,6 +276,12 @@ export class WebSocketTransport implements Transport {
|
|
|
263
276
|
private readonly transitionHandler: ((transition: MachineTransition) => void) | undefined;
|
|
264
277
|
/** The protocol version of the server, from its hello, or undefined (an older server) (R25) */
|
|
265
278
|
private serverProtocol: number | undefined;
|
|
279
|
+
/** The largest message in bytes that the server takes, from its `hello` (roadmap CLI-108). */
|
|
280
|
+
private serverMaxPayload: number | undefined;
|
|
281
|
+
/** The wait for the `hello` of the server on this connection. It ends at the answer, or after `HELLO_WAIT_MS`. */
|
|
282
|
+
private helloWait: Promise<void> = Promise.resolve();
|
|
283
|
+
/** The end of `helloWait`. */
|
|
284
|
+
private helloSettle: () => void = () => undefined;
|
|
266
285
|
/** The calls that the server sends on the current socket, served by `serve` (roadmap R24) */
|
|
267
286
|
private incoming: IncomingCalls | undefined;
|
|
268
287
|
/** The time limit of the handshake of the socket that opens now */
|
|
@@ -359,6 +378,16 @@ export class WebSocketTransport implements Transport {
|
|
|
359
378
|
// The protocol version of this client (roadmap R25). An older server answers with an
|
|
360
379
|
// error frame, which the client ignores.
|
|
361
380
|
this.serverProtocol = undefined;
|
|
381
|
+
this.serverMaxPayload = undefined;
|
|
382
|
+
this.helloSettle();
|
|
383
|
+
let cancelWait: () => void = () => undefined;
|
|
384
|
+
this.helloWait = new Promise<void>((resolve) => {
|
|
385
|
+
this.helloSettle = () => {
|
|
386
|
+
cancelWait();
|
|
387
|
+
resolve();
|
|
388
|
+
};
|
|
389
|
+
});
|
|
390
|
+
cancelWait = this.clock.after(HELLO_WAIT_MS, () => this.helloSettle());
|
|
362
391
|
ws.send(JSON.stringify({ id: "hello", type: "hello", protocol: PROTOCOL_VERSION }));
|
|
363
392
|
this.setState(WebSocketState.CONNECTED, "open");
|
|
364
393
|
console.error(`[${this.name}] Connected to ${this.options.url}`);
|
|
@@ -566,8 +595,11 @@ export class WebSocketTransport implements Transport {
|
|
|
566
595
|
private handleMessage(message: WebSocketMessage): void {
|
|
567
596
|
// The hello of the server, or the error of an older server that does not know it (R25)
|
|
568
597
|
if (message.id === "hello" && (message.type === "hello" || message.type === "error")) {
|
|
569
|
-
if (message.type === "hello")
|
|
570
|
-
|
|
598
|
+
if (message.type === "hello") {
|
|
599
|
+
this.serverProtocol = protocolVersionOf(message.protocol);
|
|
600
|
+
this.serverMaxPayload = typeof message.maxPayload === "number" && message.maxPayload > 0 ? message.maxPayload : undefined;
|
|
601
|
+
} else if (message.error?.code === "PROTOCOL_VERSION") this.options.onError?.(new Error(message.error.message));
|
|
602
|
+
this.helloSettle();
|
|
571
603
|
return;
|
|
572
604
|
}
|
|
573
605
|
// A call of the server, its cancel or its credit (roadmap R24)
|
|
@@ -757,11 +789,24 @@ export class WebSocketTransport implements Transport {
|
|
|
757
789
|
message.signal?.addEventListener("abort", onAbort, { once: true });
|
|
758
790
|
|
|
759
791
|
try {
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
792
|
+
const text = JSON.stringify(wsMessage);
|
|
793
|
+
// A large call waits for the hello of the server, which tells its limit (roadmap CLI-108)
|
|
794
|
+
if (text.length > HELLO_WAIT_FROM_CHARS) await this.helloWait;
|
|
795
|
+
if (this.pendingRequests.get(wireId) !== pending) {
|
|
796
|
+
// The connection closed, the call timed out or the reader aborted in the wait: the queue has the end of the call
|
|
797
|
+
} else if (this.serverMaxPayload !== undefined && byteLengthAbove(text, this.serverMaxPayload)) {
|
|
798
|
+
// The server closes the connection on a larger message, and each pending call fails with it.
|
|
799
|
+
// So this call fails alone, before the send (roadmap CLI-108)
|
|
800
|
+
this.pendingRequests.delete(wireId);
|
|
801
|
+
queue.push(errorItem(message.id, "PAYLOAD_TOO_LARGE", `The call is larger than the limit of the server (${this.serverMaxPayload} bytes)`, false));
|
|
802
|
+
queue.end();
|
|
803
|
+
} else {
|
|
804
|
+
try {
|
|
805
|
+
this.ws!.send(text);
|
|
806
|
+
} catch (error) {
|
|
807
|
+
console.error(`[${this.name}] Send error:`, error);
|
|
808
|
+
throw error;
|
|
809
|
+
}
|
|
765
810
|
}
|
|
766
811
|
let taken = 0;
|
|
767
812
|
for await (const item of queue) {
|
|
@@ -224,6 +224,9 @@ export interface WebSocketMessage<T = unknown> {
|
|
|
224
224
|
/** The protocol version of a `hello` frame (roadmap R25). */
|
|
225
225
|
protocol?: number;
|
|
226
226
|
|
|
227
|
+
/** The largest message in bytes that the server takes, in the `hello` frame of the server (roadmap CLI-108). */
|
|
228
|
+
maxPayload?: number;
|
|
229
|
+
|
|
227
230
|
/** RPC method (for requests) */
|
|
228
231
|
method?: {
|
|
229
232
|
service: string;
|
|
@@ -558,7 +558,8 @@ export class WebSocketServerTransport implements ServerTransport {
|
|
|
558
558
|
ws.close(1002, "protocol version");
|
|
559
559
|
return;
|
|
560
560
|
}
|
|
561
|
-
|
|
561
|
+
// The limit of the server: a client refuses a larger call alone, before the server closes the connection (roadmap CLI-108)
|
|
562
|
+
this.send(ws, { id: message.id || "hello", type: "hello", protocol: PROTOCOL_VERSION, maxPayload: this.options.maxPayload });
|
|
562
563
|
return;
|
|
563
564
|
}
|
|
564
565
|
|
|
@@ -120,6 +120,9 @@ export interface WebSocketMessage<TReq = unknown> {
|
|
|
120
120
|
/** The protocol version of a `hello` frame (roadmap R25). */
|
|
121
121
|
protocol?: number;
|
|
122
122
|
|
|
123
|
+
/** The largest message in bytes that the server takes, in the `hello` frame of the server (roadmap CLI-108). */
|
|
124
|
+
maxPayload?: number;
|
|
125
|
+
|
|
123
126
|
/** RPC method (for requests) */
|
|
124
127
|
method?: {
|
|
125
128
|
service: string;
|