@milaboratories/pl-client 2.16.26 → 2.16.28
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/README.md +2 -1
- package/dist/core/PromiseTracker.cjs +1 -3
- package/dist/core/PromiseTracker.cjs.map +1 -1
- package/dist/core/PromiseTracker.d.ts.map +1 -1
- package/dist/core/PromiseTracker.js +1 -3
- package/dist/core/PromiseTracker.js.map +1 -1
- package/dist/core/StatefulPromise.cjs +4 -4
- package/dist/core/StatefulPromise.cjs.map +1 -1
- package/dist/core/StatefulPromise.d.ts +1 -1
- package/dist/core/StatefulPromise.d.ts.map +1 -1
- package/dist/core/StatefulPromise.js +4 -4
- package/dist/core/StatefulPromise.js.map +1 -1
- package/dist/core/advisory_locks.cjs +1 -1
- package/dist/core/advisory_locks.cjs.map +1 -1
- package/dist/core/advisory_locks.js +1 -1
- package/dist/core/advisory_locks.js.map +1 -1
- package/dist/core/auth.cjs.map +1 -1
- package/dist/core/auth.d.ts +1 -1
- package/dist/core/auth.js.map +1 -1
- package/dist/core/cache.d.ts +1 -1
- package/dist/core/client.cjs +14 -14
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.d.ts +11 -11
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +14 -14
- package/dist/core/client.js.map +1 -1
- package/dist/core/config.cjs +39 -39
- package/dist/core/config.cjs.map +1 -1
- package/dist/core/config.d.ts +5 -5
- package/dist/core/config.js +39 -39
- package/dist/core/config.js.map +1 -1
- package/dist/core/default_client.cjs +23 -23
- package/dist/core/default_client.cjs.map +1 -1
- package/dist/core/default_client.d.ts +3 -3
- package/dist/core/default_client.js +23 -23
- package/dist/core/default_client.js.map +1 -1
- package/dist/core/driver.cjs +1 -1
- package/dist/core/driver.cjs.map +1 -1
- package/dist/core/driver.d.ts +5 -5
- package/dist/core/driver.js +1 -1
- package/dist/core/driver.js.map +1 -1
- package/dist/core/error_resource.cjs +2 -2
- package/dist/core/error_resource.cjs.map +1 -1
- package/dist/core/error_resource.d.ts +1 -1
- package/dist/core/error_resource.js +2 -2
- package/dist/core/error_resource.js.map +1 -1
- package/dist/core/errors.cjs +24 -24
- package/dist/core/errors.cjs.map +1 -1
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +24 -24
- package/dist/core/errors.js.map +1 -1
- package/dist/core/final.cjs +43 -43
- package/dist/core/final.cjs.map +1 -1
- package/dist/core/final.d.ts +3 -3
- package/dist/core/final.d.ts.map +1 -1
- package/dist/core/final.js +43 -43
- package/dist/core/final.js.map +1 -1
- package/dist/core/ll_client.cjs +50 -43
- package/dist/core/ll_client.cjs.map +1 -1
- package/dist/core/ll_client.d.ts +9 -9
- package/dist/core/ll_client.d.ts.map +1 -1
- package/dist/core/ll_client.js +50 -43
- package/dist/core/ll_client.js.map +1 -1
- package/dist/core/ll_transaction.cjs +9 -9
- package/dist/core/ll_transaction.cjs.map +1 -1
- package/dist/core/ll_transaction.d.ts +7 -7
- package/dist/core/ll_transaction.d.ts.map +1 -1
- package/dist/core/ll_transaction.js +9 -9
- package/dist/core/ll_transaction.js.map +1 -1
- package/dist/core/stat.cjs.map +1 -1
- package/dist/core/stat.d.ts +1 -1
- package/dist/core/stat.js.map +1 -1
- package/dist/core/transaction.cjs +46 -46
- package/dist/core/transaction.cjs.map +1 -1
- package/dist/core/transaction.d.ts +7 -7
- package/dist/core/transaction.d.ts.map +1 -1
- package/dist/core/transaction.js +46 -46
- package/dist/core/transaction.js.map +1 -1
- package/dist/core/type_conversion.cjs +22 -22
- package/dist/core/type_conversion.cjs.map +1 -1
- package/dist/core/type_conversion.d.ts +3 -3
- package/dist/core/type_conversion.d.ts.map +1 -1
- package/dist/core/type_conversion.js +22 -22
- package/dist/core/type_conversion.js.map +1 -1
- package/dist/core/types.cjs +25 -25
- package/dist/core/types.cjs.map +1 -1
- package/dist/core/types.d.ts +7 -7
- package/dist/core/types.js +25 -25
- package/dist/core/types.js.map +1 -1
- package/dist/core/unauth_client.cjs +6 -4
- package/dist/core/unauth_client.cjs.map +1 -1
- package/dist/core/unauth_client.d.ts +4 -4
- package/dist/core/unauth_client.d.ts.map +1 -1
- package/dist/core/unauth_client.js +6 -4
- package/dist/core/unauth_client.js.map +1 -1
- package/dist/core/websocket_stream.cjs +22 -20
- package/dist/core/websocket_stream.cjs.map +1 -1
- package/dist/core/websocket_stream.d.ts +3 -3
- package/dist/core/websocket_stream.d.ts.map +1 -1
- package/dist/core/websocket_stream.js +22 -20
- package/dist/core/websocket_stream.js.map +1 -1
- package/dist/core/wire.d.ts +6 -6
- package/dist/core/wire.d.ts.map +1 -1
- package/dist/helpers/pl.cjs +19 -19
- package/dist/helpers/pl.cjs.map +1 -1
- package/dist/helpers/pl.d.ts +2 -2
- package/dist/helpers/pl.js +19 -19
- package/dist/helpers/pl.js.map +1 -1
- package/dist/helpers/poll.cjs +6 -6
- package/dist/helpers/poll.cjs.map +1 -1
- package/dist/helpers/poll.d.ts +4 -4
- package/dist/helpers/poll.d.ts.map +1 -1
- package/dist/helpers/poll.js +6 -6
- package/dist/helpers/poll.js.map +1 -1
- package/dist/helpers/retry_strategy.cjs +1 -1
- package/dist/helpers/retry_strategy.cjs.map +1 -1
- package/dist/helpers/retry_strategy.d.ts.map +1 -1
- package/dist/helpers/retry_strategy.js +1 -1
- package/dist/helpers/retry_strategy.js.map +1 -1
- package/dist/helpers/state_helpers.d.ts +2 -2
- package/dist/helpers/tx_helpers.cjs +2 -2
- package/dist/helpers/tx_helpers.cjs.map +1 -1
- package/dist/helpers/tx_helpers.d.ts +2 -2
- package/dist/helpers/tx_helpers.d.ts.map +1 -1
- package/dist/helpers/tx_helpers.js +2 -2
- package/dist/helpers/tx_helpers.js.map +1 -1
- package/dist/index.d.ts +16 -16
- package/dist/proto-grpc/google/protobuf/struct.d.ts +1 -1
- package/dist/proto-grpc/google/protobuf/struct.d.ts.map +1 -1
- package/dist/proto-rest/index.cjs +4 -5
- package/dist/proto-rest/index.cjs.map +1 -1
- package/dist/proto-rest/index.d.ts +4 -4
- package/dist/proto-rest/index.d.ts.map +1 -1
- package/dist/proto-rest/index.js +4 -5
- package/dist/proto-rest/index.js.map +1 -1
- package/dist/proto-rest/plapi.d.ts.map +1 -1
- package/dist/test/tcp-proxy.cjs +11 -10
- package/dist/test/tcp-proxy.cjs.map +1 -1
- package/dist/test/tcp-proxy.d.ts +1 -1
- package/dist/test/tcp-proxy.d.ts.map +1 -1
- package/dist/test/tcp-proxy.js +11 -10
- package/dist/test/tcp-proxy.js.map +1 -1
- package/dist/test/test_config.cjs +21 -17
- package/dist/test/test_config.cjs.map +1 -1
- package/dist/test/test_config.d.ts +6 -6
- package/dist/test/test_config.d.ts.map +1 -1
- package/dist/test/test_config.js +21 -17
- package/dist/test/test_config.js.map +1 -1
- package/dist/util/pl.cjs +1 -1
- package/dist/util/pl.cjs.map +1 -1
- package/dist/util/pl.js +1 -1
- package/dist/util/pl.js.map +1 -1
- package/dist/util/util.cjs +1 -1
- package/dist/util/util.cjs.map +1 -1
- package/dist/util/util.js +1 -1
- package/dist/util/util.js.map +1 -1
- package/package.json +23 -23
- package/src/core/PromiseTracker.ts +3 -4
- package/src/core/StatefulPromise.ts +17 -8
- package/src/core/abstract_stream.ts +3 -4
- package/src/core/advisory_locks.ts +1 -1
- package/src/core/auth.ts +2 -2
- package/src/core/cache.ts +1 -1
- package/src/core/client.test.ts +25 -21
- package/src/core/client.ts +54 -45
- package/src/core/config.test.ts +44 -44
- package/src/core/config.ts +49 -49
- package/src/core/connectivity.test.ts +69 -63
- package/src/core/default_client.ts +46 -46
- package/src/core/driver.ts +6 -6
- package/src/core/error.test.ts +5 -5
- package/src/core/error_resource.ts +3 -3
- package/src/core/errors.ts +39 -31
- package/src/core/final.ts +48 -55
- package/src/core/ll_client.test.ts +53 -36
- package/src/core/ll_client.ts +125 -81
- package/src/core/ll_transaction.test.ts +75 -49
- package/src/core/ll_transaction.ts +37 -35
- package/src/core/stat.ts +1 -1
- package/src/core/transaction.test.ts +65 -65
- package/src/core/transaction.ts +91 -84
- package/src/core/type_conversion.ts +30 -31
- package/src/core/types.test.ts +6 -6
- package/src/core/types.ts +35 -35
- package/src/core/unauth_client.test.ts +18 -14
- package/src/core/unauth_client.ts +14 -12
- package/src/core/websocket_stream.test.ts +52 -52
- package/src/core/websocket_stream.ts +41 -37
- package/src/core/wire.ts +10 -8
- package/src/helpers/pl.ts +22 -22
- package/src/helpers/poll.ts +13 -27
- package/src/helpers/retry_strategy.ts +2 -4
- package/src/helpers/rich_resource_types.test.ts +2 -2
- package/src/helpers/state_helpers.ts +3 -3
- package/src/helpers/tx_helpers.ts +9 -7
- package/src/index.ts +16 -16
- package/src/proto-grpc/google/protobuf/struct.ts +1 -1
- package/src/proto-rest/index.ts +17 -18
- package/src/proto-rest/plapi.ts +1472 -1472
- package/src/test/tcp-proxy.ts +55 -54
- package/src/test/test_config.test.ts +3 -3
- package/src/test/test_config.ts +51 -46
- package/src/util/pl.ts +1 -1
- package/src/util/util.test.ts +5 -5
- package/src/util/util.ts +1 -1
- package/dist/helpers/rich_resource_types.d.ts +0 -2
- package/dist/helpers/rich_resource_types.d.ts.map +0 -1
- package/dist/helpers/smart_accessors.d.ts +0 -2
- package/dist/helpers/smart_accessors.d.ts.map +0 -1
- package/src/helpers/rich_resource_types.ts +0 -84
- package/src/helpers/smart_accessors.ts +0 -146
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from
|
|
2
|
-
import type { BiDiStream } from
|
|
3
|
-
import Denque from
|
|
4
|
-
import type { RetryConfig } from
|
|
5
|
-
import { RetryStrategy } from
|
|
6
|
-
import { DisconnectedError } from
|
|
1
|
+
import { WebSocket, type WebSocketInit, type Dispatcher, ErrorEvent } from "undici";
|
|
2
|
+
import type { BiDiStream } from "./abstract_stream";
|
|
3
|
+
import Denque from "denque";
|
|
4
|
+
import type { RetryConfig } from "../helpers/retry_strategy";
|
|
5
|
+
import { RetryStrategy } from "../helpers/retry_strategy";
|
|
6
|
+
import { DisconnectedError } from "./errors";
|
|
7
7
|
|
|
8
8
|
interface QueuedMessage<InType extends object> {
|
|
9
9
|
message: InType;
|
|
@@ -38,7 +38,10 @@ export type WSStreamOptions<ClientMsg extends object, ServerMsg extends object>
|
|
|
38
38
|
* WebSocket-based bidirectional stream implementation for LLTransaction.
|
|
39
39
|
* Implements BiDiStream interface which is compatible with DuplexStreamingCall.
|
|
40
40
|
*/
|
|
41
|
-
export class WebSocketBiDiStream<
|
|
41
|
+
export class WebSocketBiDiStream<
|
|
42
|
+
ClientMsg extends object,
|
|
43
|
+
ServerMsg extends object,
|
|
44
|
+
> implements BiDiStream<ClientMsg, ServerMsg> {
|
|
42
45
|
// Connection
|
|
43
46
|
private ws: WebSocket | null = null;
|
|
44
47
|
private connectionState: ConnectionState = ConnectionState.NEW;
|
|
@@ -47,7 +50,9 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
47
50
|
// Send management
|
|
48
51
|
private readonly sendQueue = new Denque<QueuedMessage<ClientMsg>>();
|
|
49
52
|
private sendCompleted = false;
|
|
50
|
-
private readonly onComplete: (
|
|
53
|
+
private readonly onComplete: (
|
|
54
|
+
stream: WebSocketBiDiStream<ClientMsg, ServerMsg>,
|
|
55
|
+
) => void | Promise<void>;
|
|
51
56
|
|
|
52
57
|
// Response management
|
|
53
58
|
private readonly responseQueue = new Denque<ServerMsg>();
|
|
@@ -69,7 +74,7 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
69
74
|
await this.drainSendQueue(); // ensure we sent all already queued messages before closing the stream
|
|
70
75
|
try {
|
|
71
76
|
await this.onComplete(this); // custom onComplete may send additional messages
|
|
72
|
-
} catch
|
|
77
|
+
} catch {
|
|
73
78
|
// When 'complete' gets called concurrently with connection break or over a broken
|
|
74
79
|
// transaction stream (server decided it should drop transaction), server would close
|
|
75
80
|
// connection anyway on its end. We can safely ignore error here and just continue working.
|
|
@@ -106,7 +111,9 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
106
111
|
|
|
107
112
|
const retryConfig = this.options.retryConfig ?? {};
|
|
108
113
|
this.reconnection = new RetryStrategy(retryConfig, {
|
|
109
|
-
onRetry: () => {
|
|
114
|
+
onRetry: () => {
|
|
115
|
+
void this.connect();
|
|
116
|
+
},
|
|
110
117
|
onMaxAttemptsReached: (error) => this.handleError(error),
|
|
111
118
|
});
|
|
112
119
|
|
|
@@ -115,7 +122,7 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
115
122
|
return;
|
|
116
123
|
}
|
|
117
124
|
|
|
118
|
-
this.options.abortSignal?.addEventListener(
|
|
125
|
+
this.options.abortSignal?.addEventListener("abort", () => this.close());
|
|
119
126
|
this.connect();
|
|
120
127
|
}
|
|
121
128
|
|
|
@@ -130,10 +137,10 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
130
137
|
try {
|
|
131
138
|
this.ws = this.createWebSocket();
|
|
132
139
|
|
|
133
|
-
this.ws.addEventListener(
|
|
134
|
-
this.ws.addEventListener(
|
|
135
|
-
this.ws.addEventListener(
|
|
136
|
-
this.ws.addEventListener(
|
|
140
|
+
this.ws.addEventListener("open", () => this.onOpen());
|
|
141
|
+
this.ws.addEventListener("message", (event) => this.onMessage(event.data));
|
|
142
|
+
this.ws.addEventListener("error", (error) => this.onError(error));
|
|
143
|
+
this.ws.addEventListener("close", () => this.onClose());
|
|
137
144
|
} catch (error) {
|
|
138
145
|
this.lastError = this.toError(error);
|
|
139
146
|
this.reconnection.schedule();
|
|
@@ -143,11 +150,12 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
143
150
|
private createWebSocket(): WebSocket {
|
|
144
151
|
const options: WebSocketInit = {};
|
|
145
152
|
|
|
146
|
-
if (this.options.jwtToken)
|
|
153
|
+
if (this.options.jwtToken)
|
|
154
|
+
options.headers = { authorization: `Bearer ${this.options.jwtToken}` };
|
|
147
155
|
if (this.options.dispatcher) options.dispatcher = this.options.dispatcher;
|
|
148
156
|
|
|
149
157
|
const ws = new WebSocket(this.url, options);
|
|
150
|
-
ws.binaryType =
|
|
158
|
+
ws.binaryType = "arraybuffer";
|
|
151
159
|
return ws;
|
|
152
160
|
}
|
|
153
161
|
|
|
@@ -208,11 +216,11 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
208
216
|
|
|
209
217
|
private enqueueSend(message: ClientMsg): Promise<void> {
|
|
210
218
|
if (this.sendCompleted) {
|
|
211
|
-
throw new Error(
|
|
219
|
+
throw new Error("Cannot send: stream already completed");
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
if (this.options.abortSignal?.aborted) {
|
|
215
|
-
throw new Error(
|
|
223
|
+
throw new Error("Cannot send: stream aborted");
|
|
216
224
|
}
|
|
217
225
|
|
|
218
226
|
return new Promise<void>((resolve, reject) => {
|
|
@@ -238,7 +246,7 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
238
246
|
try {
|
|
239
247
|
const ws = this.ws;
|
|
240
248
|
if (!ws) {
|
|
241
|
-
throw new Error(
|
|
249
|
+
throw new Error("WebSocket is not connected");
|
|
242
250
|
}
|
|
243
251
|
|
|
244
252
|
// Check if WebSocket is in a valid state for sending
|
|
@@ -258,33 +266,27 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
258
266
|
const POLL_INTERVAL_MS = 5;
|
|
259
267
|
|
|
260
268
|
while (this.sendQueue.length > 0) {
|
|
261
|
-
await this.waitForCondition(
|
|
262
|
-
() => this.sendQueue.length === 0,
|
|
263
|
-
POLL_INTERVAL_MS,
|
|
264
|
-
);
|
|
269
|
+
await this.waitForCondition(() => this.sendQueue.length === 0, POLL_INTERVAL_MS);
|
|
265
270
|
}
|
|
266
271
|
}
|
|
267
272
|
|
|
268
|
-
private waitForCondition(
|
|
269
|
-
condition: () => boolean,
|
|
270
|
-
intervalMs: number,
|
|
271
|
-
): Promise<void> {
|
|
273
|
+
private waitForCondition(condition: () => boolean, intervalMs: number): Promise<void> {
|
|
272
274
|
return new Promise<void>((resolve, reject) => {
|
|
273
275
|
if (this.options.abortSignal?.aborted) {
|
|
274
|
-
return reject(this.toError(this.options.abortSignal.reason) ?? new Error(
|
|
276
|
+
return reject(this.toError(this.options.abortSignal.reason) ?? new Error("Stream aborted"));
|
|
275
277
|
}
|
|
276
278
|
|
|
277
279
|
let timeoutId: ReturnType<typeof setTimeout>;
|
|
278
280
|
const onAbort = () => {
|
|
279
281
|
clearTimeout(timeoutId);
|
|
280
|
-
reject(this.toError(this.options.abortSignal?.reason) ?? new Error(
|
|
282
|
+
reject(this.toError(this.options.abortSignal?.reason) ?? new Error("Stream aborted"));
|
|
281
283
|
};
|
|
282
284
|
|
|
283
|
-
this.options.abortSignal?.addEventListener(
|
|
285
|
+
this.options.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
284
286
|
|
|
285
287
|
const check = () => {
|
|
286
288
|
if (condition() || this.isStreamEnded()) {
|
|
287
|
-
this.options.abortSignal?.removeEventListener(
|
|
289
|
+
this.options.abortSignal?.removeEventListener("abort", onAbort);
|
|
288
290
|
resolve();
|
|
289
291
|
} else {
|
|
290
292
|
timeoutId = setTimeout(check, intervalMs);
|
|
@@ -379,16 +381,18 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
379
381
|
if (reason instanceof Error) {
|
|
380
382
|
return reason;
|
|
381
383
|
}
|
|
382
|
-
return new Error(
|
|
384
|
+
return new Error("Stream aborted", { cause: reason });
|
|
383
385
|
}
|
|
384
386
|
|
|
385
|
-
return new Error(
|
|
387
|
+
return new Error("Stream closed");
|
|
386
388
|
}
|
|
387
389
|
|
|
388
390
|
// === Helpers ===
|
|
389
391
|
|
|
390
392
|
private isStreamEnded(): boolean {
|
|
391
|
-
return
|
|
393
|
+
return (
|
|
394
|
+
this.connectionState === ConnectionState.CLOSED || this.options.abortSignal?.aborted || false
|
|
395
|
+
);
|
|
392
396
|
}
|
|
393
397
|
|
|
394
398
|
private toError(error: unknown): Error {
|
|
@@ -398,9 +402,9 @@ export class WebSocketBiDiStream<ClientMsg extends object, ServerMsg extends obj
|
|
|
398
402
|
// undici WebSocket throws TypeError with empty message on socket close
|
|
399
403
|
// (e.g., when connection is lost or server disconnects)
|
|
400
404
|
if (err instanceof TypeError && !err.message) {
|
|
401
|
-
return new DisconnectedError(
|
|
405
|
+
return new DisconnectedError("WebSocket connection closed unexpectedly");
|
|
402
406
|
}
|
|
403
|
-
return err instanceof Error ? err : new Error(
|
|
407
|
+
return err instanceof Error ? err : new Error("WebSocket error", { cause: error });
|
|
404
408
|
}
|
|
405
409
|
return new Error(String(error));
|
|
406
410
|
}
|
package/src/core/wire.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type { GrpcTransport } from
|
|
2
|
-
import type { Dispatcher } from
|
|
3
|
-
import type { PlClientConfig, wireProtocol } from
|
|
4
|
-
import type { Middleware } from
|
|
1
|
+
import type { GrpcTransport } from "@protobuf-ts/grpc-transport";
|
|
2
|
+
import type { Dispatcher } from "undici";
|
|
3
|
+
import type { PlClientConfig, wireProtocol } from "./config";
|
|
4
|
+
import type { Middleware } from "openapi-fetch";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Options for the HTTP client to properly reach the PL server API when
|
|
8
8
|
* it works in WebSocket + REST mode.
|
|
9
9
|
*/
|
|
10
10
|
export type RestConnection = {
|
|
11
|
-
type:
|
|
11
|
+
type: "rest";
|
|
12
12
|
Config: PlClientConfig;
|
|
13
13
|
Dispatcher: Dispatcher;
|
|
14
14
|
Middlewares: Middleware[];
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export type GrpcConnection = {
|
|
18
|
-
type:
|
|
18
|
+
type: "grpc";
|
|
19
19
|
Transport: GrpcTransport;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export type WireConnection = RestConnection | GrpcConnection;
|
|
23
23
|
// type compatibility check: types used in WireConnection should match known wire protocols.
|
|
24
|
-
const _ct: Extract<WireConnection, { type: string }>[
|
|
24
|
+
const _ct: Extract<WireConnection, { type: string }>["type"] = "rest" as wireProtocol;
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* A provider for a wire (gRPC, HTTP, etc.) client.
|
|
@@ -36,5 +36,7 @@ export interface WireClientProvider<Client> {
|
|
|
36
36
|
* A factory for wire client providers.
|
|
37
37
|
*/
|
|
38
38
|
export interface WireClientProviderFactory {
|
|
39
|
-
createWireClientProvider<Client>(
|
|
39
|
+
createWireClientProvider<Client>(
|
|
40
|
+
clientConstructor: (transport: WireConnection) => Client,
|
|
41
|
+
): WireClientProvider<Client>;
|
|
40
42
|
}
|
package/src/helpers/pl.ts
CHANGED
|
@@ -7,31 +7,31 @@
|
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { FutureFieldType, ResourceType } from
|
|
11
|
-
import type { AnyRef, FieldRef, PlTransaction, ResourceRef } from
|
|
12
|
-
import { field } from
|
|
10
|
+
import type { FutureFieldType, ResourceType } from "../core/types";
|
|
11
|
+
import type { AnyRef, FieldRef, PlTransaction, ResourceRef } from "../core/transaction";
|
|
12
|
+
import { field } from "../core/transaction";
|
|
13
13
|
|
|
14
14
|
function rt(name: string, version: string): ResourceType {
|
|
15
15
|
return { name, version };
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export const ClientRoot = rt(
|
|
18
|
+
export const ClientRoot = rt("ClientRoot", "1");
|
|
19
19
|
|
|
20
|
-
export const StructTestResource = rt(
|
|
21
|
-
export const ValueTestResource = rt(
|
|
20
|
+
export const StructTestResource = rt("StructTest", "1");
|
|
21
|
+
export const ValueTestResource = rt("ValueTest", "1");
|
|
22
22
|
|
|
23
|
-
export const JsonString = rt(
|
|
24
|
-
export const JsonBool = rt(
|
|
25
|
-
export const JsonObject = rt(
|
|
26
|
-
export const JsonGzObject = rt(
|
|
27
|
-
export const JsonArray = rt(
|
|
28
|
-
export const JsonNumber = rt(
|
|
29
|
-
export const JsonNull = rt(
|
|
23
|
+
export const JsonString = rt("json/string", "1");
|
|
24
|
+
export const JsonBool = rt("json/bool", "1");
|
|
25
|
+
export const JsonObject = rt("json/object", "1");
|
|
26
|
+
export const JsonGzObject = rt("json-gz/object", "1");
|
|
27
|
+
export const JsonArray = rt("json/array", "1");
|
|
28
|
+
export const JsonNumber = rt("json/number", "1");
|
|
29
|
+
export const JsonNull = rt("json/null", "1");
|
|
30
30
|
|
|
31
|
-
export const RNull = rt(
|
|
31
|
+
export const RNull = rt("Null", "1");
|
|
32
32
|
|
|
33
|
-
export const EphStdMap: ResourceType = rt(
|
|
34
|
-
export const StdMap: ResourceType = rt(
|
|
33
|
+
export const EphStdMap: ResourceType = rt("EphStdMap", "1");
|
|
34
|
+
export const StdMap: ResourceType = rt("StdMap", "1");
|
|
35
35
|
|
|
36
36
|
//
|
|
37
37
|
// Standard value resources
|
|
@@ -96,7 +96,7 @@ export function createPlMap(
|
|
|
96
96
|
const rId = ephemeral ? tx.createEphemeral(actualType) : tx.createStruct(actualType);
|
|
97
97
|
|
|
98
98
|
for (const [name, value] of Array.isArray(entries) ? entries : plEntries(entries))
|
|
99
|
-
tx.createField(field(rId, name),
|
|
99
|
+
tx.createField(field(rId, name), "Input", value);
|
|
100
100
|
|
|
101
101
|
tx.lock(rId);
|
|
102
102
|
|
|
@@ -108,7 +108,7 @@ export function futureRecord<Key extends string>(
|
|
|
108
108
|
rId: AnyRef,
|
|
109
109
|
keys: Key[],
|
|
110
110
|
fieldType: FutureFieldType,
|
|
111
|
-
prefix: string =
|
|
111
|
+
prefix: string = "",
|
|
112
112
|
): PlRecord<Key, FieldRef> {
|
|
113
113
|
return Object.fromEntries(
|
|
114
114
|
keys.map((k) => plEntry(k, tx.getFutureFieldValue(rId, `${prefix}${k}`, fieldType))),
|
|
@@ -122,12 +122,12 @@ export function futureRecord<Key extends string>(
|
|
|
122
122
|
/** Name of the field in block holder, that references the actual block-pack. */
|
|
123
123
|
export const Holder = StdMap;
|
|
124
124
|
export const EphHolder = EphStdMap;
|
|
125
|
-
export const HolderRefField =
|
|
125
|
+
export const HolderRefField = "ref";
|
|
126
126
|
|
|
127
127
|
export function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {
|
|
128
128
|
const holder = tx.createStruct(Holder);
|
|
129
129
|
const mainHolderField = field(holder, HolderRefField);
|
|
130
|
-
tx.createField(mainHolderField,
|
|
130
|
+
tx.createField(mainHolderField, "Input", ref);
|
|
131
131
|
tx.lock(holder);
|
|
132
132
|
return holder;
|
|
133
133
|
}
|
|
@@ -135,11 +135,11 @@ export function wrapInHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {
|
|
|
135
135
|
export function wrapInEphHolder(tx: PlTransaction, ref: AnyRef): ResourceRef {
|
|
136
136
|
const holder = tx.createEphemeral(EphHolder);
|
|
137
137
|
const mainHolderField = field(holder, HolderRefField);
|
|
138
|
-
tx.createField(mainHolderField,
|
|
138
|
+
tx.createField(mainHolderField, "Input", ref);
|
|
139
139
|
tx.lock(holder);
|
|
140
140
|
return holder;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
export function unwrapHolder(tx: PlTransaction, ref: AnyRef): FieldRef {
|
|
144
|
-
return tx.getFutureFieldValue(ref, HolderRefField,
|
|
144
|
+
return tx.getFutureFieldValue(ref, HolderRefField, "Input");
|
|
145
145
|
}
|
package/src/helpers/poll.ts
CHANGED
|
@@ -1,28 +1,14 @@
|
|
|
1
|
-
import type { PlClient } from
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
} from
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
notEmpty,
|
|
9
|
-
} from '@milaboratories/ts-helpers';
|
|
10
|
-
import type {
|
|
11
|
-
FieldData,
|
|
12
|
-
FieldType,
|
|
13
|
-
ResourceData,
|
|
14
|
-
ResourceId } from '../core/types';
|
|
15
|
-
import {
|
|
16
|
-
isNotNullResourceId,
|
|
17
|
-
isNullResourceId,
|
|
18
|
-
resourceIdToString,
|
|
19
|
-
} from '../core/types';
|
|
20
|
-
import type { PlTransaction } from '../core/transaction';
|
|
21
|
-
import * as tp from 'node:timers/promises';
|
|
1
|
+
import type { PlClient } from "../core/client";
|
|
2
|
+
import type { RetryOptions } from "@milaboratories/ts-helpers";
|
|
3
|
+
import { createRetryState, nextRetryStateOrError, notEmpty } from "@milaboratories/ts-helpers";
|
|
4
|
+
import type { FieldData, FieldType, ResourceData, ResourceId } from "../core/types";
|
|
5
|
+
import { isNotNullResourceId, isNullResourceId, resourceIdToString } from "../core/types";
|
|
6
|
+
import type { PlTransaction } from "../core/transaction";
|
|
7
|
+
import * as tp from "node:timers/promises";
|
|
22
8
|
|
|
23
9
|
/** This error tells state assertion mechanism that required state is not yet ready */
|
|
24
10
|
export class ContinuePolling extends Error {
|
|
25
|
-
name =
|
|
11
|
+
name = "ContinuePolling";
|
|
26
12
|
}
|
|
27
13
|
|
|
28
14
|
export type PollFieldTraverseOps = {
|
|
@@ -68,8 +54,8 @@ export class PollResourceAccessor {
|
|
|
68
54
|
}
|
|
69
55
|
|
|
70
56
|
if (
|
|
71
|
-
((expectedType ===
|
|
72
|
-
|
|
57
|
+
((expectedType === "Input" || expectedType === "Service") && this.data.inputsLocked) ||
|
|
58
|
+
(expectedType === "Output" && this.data.outputsLocked)
|
|
73
59
|
)
|
|
74
60
|
throw new Error(
|
|
75
61
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string, @typescript-eslint/restrict-template-expressions
|
|
@@ -150,12 +136,12 @@ export class PollTxAccessor {
|
|
|
150
136
|
async throwError(error: ResourceId, path: string[] = []): Promise<never> {
|
|
151
137
|
const errorRes = await this.get(error);
|
|
152
138
|
const errorText = Buffer.from(notEmpty(errorRes.data.data)).toString();
|
|
153
|
-
throw new Error(`${path.join(
|
|
139
|
+
throw new Error(`${path.join(" -> ")} = ${errorText}`);
|
|
154
140
|
}
|
|
155
141
|
}
|
|
156
142
|
|
|
157
143
|
export const DefaultPollingRetryOptions: RetryOptions = {
|
|
158
|
-
type:
|
|
144
|
+
type: "linearBackoff",
|
|
159
145
|
jitter: 0,
|
|
160
146
|
maxAttempts: 100,
|
|
161
147
|
backoffStep: 10,
|
|
@@ -166,7 +152,7 @@ export async function poll<T>(
|
|
|
166
152
|
cl: PlClient,
|
|
167
153
|
cb: (tx: PollTxAccessor) => Promise<T>,
|
|
168
154
|
retryOptions: RetryOptions = DefaultPollingRetryOptions,
|
|
169
|
-
txName: string =
|
|
155
|
+
txName: string = "polling",
|
|
170
156
|
): Promise<T> {
|
|
171
157
|
let retryState = createRetryState(retryOptions);
|
|
172
158
|
while (true) {
|
|
@@ -64,9 +64,7 @@ export class RetryStrategy {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
private notifyMaxAttemptsReached(): void {
|
|
67
|
-
const error = new Error(
|
|
68
|
-
`Max retry attempts (${this.config.maxAttempts}) reached`,
|
|
69
|
-
);
|
|
67
|
+
const error = new Error(`Max retry attempts (${this.config.maxAttempts}) reached`);
|
|
70
68
|
this.callbacks.onMaxAttemptsReached(error);
|
|
71
69
|
}
|
|
72
70
|
}
|
|
@@ -117,7 +115,7 @@ class ExponentialBackoff {
|
|
|
117
115
|
if (delay === 0 || this.jitter === 0) {
|
|
118
116
|
return delay;
|
|
119
117
|
}
|
|
120
|
-
const delayFactor = 1 -
|
|
118
|
+
const delayFactor = 1 - this.jitter / 2 + Math.random() * this.jitter;
|
|
121
119
|
return delay * delayFactor;
|
|
122
120
|
}
|
|
123
121
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { test } from
|
|
1
|
+
import { test } from "vitest";
|
|
2
2
|
|
|
3
3
|
// type TestType1 = string;
|
|
4
4
|
// type TestType2 = string | number | { a: number };
|
|
@@ -17,7 +17,7 @@ import { test } from 'vitest';
|
|
|
17
17
|
// return t2;
|
|
18
18
|
// }
|
|
19
19
|
|
|
20
|
-
test(
|
|
20
|
+
test("simple test", () => {
|
|
21
21
|
// const t2 = '';
|
|
22
22
|
// const t2a = withRichType(t2, RichType1);
|
|
23
23
|
// const t2c = something(t2a);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { FieldData } from
|
|
2
|
-
import { isNotNullResourceId } from
|
|
1
|
+
import type { FieldData } from "../core/types";
|
|
2
|
+
import { isNotNullResourceId } from "../core/types";
|
|
3
3
|
|
|
4
|
-
export function fieldResolved(data: Pick<FieldData,
|
|
4
|
+
export function fieldResolved(data: Pick<FieldData, "value" | "error">) {
|
|
5
5
|
return isNotNullResourceId(data.error) || isNotNullResourceId(data.value);
|
|
6
6
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { PlTransaction } from
|
|
2
|
-
import type { FieldData, OptionalResourceId } from
|
|
3
|
-
import { isNotNullResourceId } from
|
|
4
|
-
import { cachedDeserialize, notEmpty } from
|
|
1
|
+
import type { PlTransaction } from "../core/transaction";
|
|
2
|
+
import type { FieldData, OptionalResourceId } from "../core/types";
|
|
3
|
+
import { isNotNullResourceId } from "../core/types";
|
|
4
|
+
import { cachedDeserialize, notEmpty } from "@milaboratories/ts-helpers";
|
|
5
5
|
|
|
6
6
|
export interface ValErr {
|
|
7
7
|
valueId: OptionalResourceId;
|
|
@@ -13,15 +13,17 @@ export async function valErr(tx: PlTransaction, f: FieldData): Promise<ValErr> {
|
|
|
13
13
|
const result = {
|
|
14
14
|
valueId: f.value,
|
|
15
15
|
errorId: f.error,
|
|
16
|
-
error:
|
|
16
|
+
error: "",
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
if (isNotNullResourceId(f.error)) {
|
|
20
20
|
const e = await tx.getResourceData(f.error, true);
|
|
21
21
|
const deserializationResult = cachedDeserialize(notEmpty(e.data));
|
|
22
|
-
if (typeof deserializationResult !==
|
|
22
|
+
if (typeof deserializationResult !== "string") {
|
|
23
23
|
const dataStr = notEmpty(e.data).toString();
|
|
24
|
-
throw new Error(
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Unexpected error structure: ${dataStr.substring(0, Math.min(dataStr.length, 100))}...`,
|
|
26
|
+
);
|
|
25
27
|
}
|
|
26
28
|
result.error = deserializationResult;
|
|
27
29
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * as Pl from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
1
|
+
export * from "./core/types";
|
|
2
|
+
export * as Pl from "./helpers/pl";
|
|
3
|
+
export * from "./core/config";
|
|
4
|
+
export * from "./core/client";
|
|
5
|
+
export * from "./core/driver";
|
|
6
|
+
export * from "./core/transaction";
|
|
7
|
+
export * from "./core/errors";
|
|
8
|
+
export * from "./core/default_client";
|
|
9
|
+
export * from "./core/unauth_client";
|
|
10
|
+
export * from "./core/auth";
|
|
11
|
+
export * from "./core/final";
|
|
12
|
+
export * from "./core/wire";
|
|
13
|
+
export * from "./helpers/tx_helpers";
|
|
14
|
+
export * from "./helpers/poll";
|
|
15
15
|
|
|
16
|
-
export * as TestHelpers from
|
|
16
|
+
export * as TestHelpers from "./test/test_config";
|
|
17
17
|
|
|
18
|
-
export * as RestAPI from
|
|
18
|
+
export * as RestAPI from "./proto-rest";
|
|
@@ -178,7 +178,7 @@ class Struct$Type extends MessageType<Struct> {
|
|
|
178
178
|
/**
|
|
179
179
|
* Encode `Struct` to JSON object.
|
|
180
180
|
*/
|
|
181
|
-
internalJsonWrite(message: Struct,
|
|
181
|
+
internalJsonWrite(message: Struct, _options: JsonWriteOptions): JsonValue {
|
|
182
182
|
let json: JsonObject = {};
|
|
183
183
|
for (let [k, v] of Object.entries(message.fields)) {
|
|
184
184
|
json[k] = Value.toJson(v);
|
package/src/proto-rest/index.ts
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
// After generating new clients from openapi specifications, add client types here.
|
|
5
5
|
//
|
|
6
6
|
|
|
7
|
-
import type { paths as PlApiPaths } from
|
|
8
|
-
import { default as createOpenApiClient, type Middleware, type Client } from
|
|
9
|
-
import { Dispatcher, fetch as undiciFetch } from
|
|
10
|
-
import { RESTError, rethrowMeaningfulError } from
|
|
11
|
-
import { Code } from
|
|
7
|
+
import type { paths as PlApiPaths } from "./plapi";
|
|
8
|
+
import { default as createOpenApiClient, type Middleware, type Client } from "openapi-fetch";
|
|
9
|
+
import { Dispatcher, fetch as undiciFetch } from "undici";
|
|
10
|
+
import { RESTError, rethrowMeaningfulError } from "../core/errors";
|
|
11
|
+
import { Code } from "../proto-grpc/google/rpc/code";
|
|
12
12
|
|
|
13
13
|
export { PlApiPaths };
|
|
14
14
|
export type PlRestClientType = Client<PlApiPaths>;
|
|
@@ -18,10 +18,10 @@ export type RestClientConfig = {
|
|
|
18
18
|
ssl: boolean;
|
|
19
19
|
dispatcher: Dispatcher;
|
|
20
20
|
middlewares: Middleware[];
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
|
|
23
23
|
export function createClient<Paths extends {}>(opts: RestClientConfig): Client<Paths> {
|
|
24
|
-
const scheme = opts.ssl ?
|
|
24
|
+
const scheme = opts.ssl ? "https://" : "http://";
|
|
25
25
|
const client = createOpenApiClient<Paths>({
|
|
26
26
|
baseUrl: `${scheme}${opts.hostAndPort}`,
|
|
27
27
|
fetch: (input: Request): Promise<Response> => {
|
|
@@ -51,14 +51,14 @@ export function createClient<Paths extends {}>(opts: RestClientConfig): Client<P
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export type ErrorResponse = {
|
|
54
|
-
code: Code
|
|
55
|
-
message: string
|
|
56
|
-
details: any[]
|
|
57
|
-
}
|
|
54
|
+
code: Code;
|
|
55
|
+
message: string;
|
|
56
|
+
details: any[];
|
|
57
|
+
};
|
|
58
58
|
export async function parseResponseError(response: Response): Promise<{
|
|
59
|
-
error?: ErrorResponse | string
|
|
60
|
-
origBody?: string
|
|
61
|
-
}>{
|
|
59
|
+
error?: ErrorResponse | string;
|
|
60
|
+
origBody?: string;
|
|
61
|
+
}> {
|
|
62
62
|
if (response.status < 400) {
|
|
63
63
|
return {};
|
|
64
64
|
}
|
|
@@ -67,11 +67,10 @@ export async function parseResponseError(response: Response): Promise<{
|
|
|
67
67
|
const origBody = error;
|
|
68
68
|
try {
|
|
69
69
|
error = JSON.parse(error) as ErrorResponse;
|
|
70
|
-
} catch {
|
|
71
|
-
}
|
|
70
|
+
} catch {}
|
|
72
71
|
return {
|
|
73
72
|
error: error,
|
|
74
|
-
origBody
|
|
73
|
+
origBody,
|
|
75
74
|
};
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -88,7 +87,7 @@ function errorHandlerMiddleware(): Middleware {
|
|
|
88
87
|
return new Response(body, { ...resOptions, status: response.status });
|
|
89
88
|
}
|
|
90
89
|
|
|
91
|
-
if (typeof respErr.error ===
|
|
90
|
+
if (typeof respErr.error === "string") {
|
|
92
91
|
throw new Error(respErr.error);
|
|
93
92
|
}
|
|
94
93
|
|