@apibara/protocol 0.4.1 → 0.4.3
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/dist/client.d.ts +5 -1
- package/dist/client.js +30 -4
- package/dist/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +54 -5
package/dist/client.d.ts
CHANGED
|
@@ -55,6 +55,10 @@ export declare type StreamClientArgs = {
|
|
|
55
55
|
* Grpc client options.
|
|
56
56
|
*/
|
|
57
57
|
clientOptions?: ClientOptions;
|
|
58
|
+
/**
|
|
59
|
+
* Authorization bearer token, used to authenticate with the server.
|
|
60
|
+
*/
|
|
61
|
+
token?: string;
|
|
58
62
|
/**
|
|
59
63
|
* Callback to control reconnection after receiving an error from the stream.
|
|
60
64
|
*
|
|
@@ -90,7 +94,7 @@ export declare class StreamClient {
|
|
|
90
94
|
* }
|
|
91
95
|
* ```
|
|
92
96
|
*/
|
|
93
|
-
constructor({ url, credentials, clientOptions, onReconnect }: StreamClientArgs);
|
|
97
|
+
constructor({ url, credentials, clientOptions, token, onReconnect }: StreamClientArgs);
|
|
94
98
|
/**
|
|
95
99
|
* Async iterator over messages in the stream.
|
|
96
100
|
*/
|
package/dist/client.js
CHANGED
|
@@ -7,6 +7,8 @@ const request_1 = require("./request");
|
|
|
7
7
|
var grpc_js_2 = require("@grpc/grpc-js");
|
|
8
8
|
Object.defineProperty(exports, "ChannelCredentials", { enumerable: true, get: function () { return grpc_js_2.ChannelCredentials; } });
|
|
9
9
|
const StreamService = proto_1.v1alpha2.protoDescriptor.apibara.node.v1alpha2.Stream;
|
|
10
|
+
// Server produces an heartbeat every 30 seconds, so we use 45 seconds as a timeout.
|
|
11
|
+
const MESSAGE_TIMEOUT_MS = 45000;
|
|
10
12
|
/**
|
|
11
13
|
* A client to configure and stream data.
|
|
12
14
|
*/
|
|
@@ -30,8 +32,10 @@ class StreamClient {
|
|
|
30
32
|
* }
|
|
31
33
|
* ```
|
|
32
34
|
*/
|
|
33
|
-
constructor({ url, credentials, clientOptions, onReconnect }) {
|
|
34
|
-
|
|
35
|
+
constructor({ url, credentials, clientOptions, token, onReconnect }) {
|
|
36
|
+
const baseCredentials = credentials ?? grpc_js_1.ChannelCredentials.createSsl();
|
|
37
|
+
const credentialsWithMetadata = baseCredentials.compose(grpc_js_1.CallCredentials.createFromMetadataGenerator(createMetadataGenerator(token)));
|
|
38
|
+
this.inner = new StreamService(url, credentialsWithMetadata, {
|
|
35
39
|
'grpc.keepalive_timeout_ms': 3600000,
|
|
36
40
|
...clientOptions,
|
|
37
41
|
});
|
|
@@ -53,13 +57,22 @@ class StreamClient {
|
|
|
53
57
|
while (true) {
|
|
54
58
|
let retryCount = 1;
|
|
55
59
|
let cursor = null;
|
|
60
|
+
let clock;
|
|
56
61
|
try {
|
|
57
62
|
// this check is to make ts happy
|
|
58
63
|
if (!this.stream) {
|
|
59
64
|
throw new Error('Stream disconnected unexpectedly');
|
|
60
65
|
}
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
const streamIter = this.stream[Symbol.asyncIterator]();
|
|
67
|
+
while (true) {
|
|
68
|
+
const timeout = new Promise((_, reject) => {
|
|
69
|
+
clock = setTimeout(() => {
|
|
70
|
+
reject(new Error('Stream timed out'));
|
|
71
|
+
}, MESSAGE_TIMEOUT_MS);
|
|
72
|
+
});
|
|
73
|
+
const message = (await Promise.race([streamIter.next(), timeout]));
|
|
74
|
+
const messageTyped = message.value;
|
|
75
|
+
clearTimeout(clock);
|
|
63
76
|
// only return messages if they are with the most recently configured stream
|
|
64
77
|
if (messageTyped.streamId?.toString() == this.stream_id.toString()) {
|
|
65
78
|
// reset retry count on new message
|
|
@@ -76,6 +89,7 @@ class StreamClient {
|
|
|
76
89
|
}
|
|
77
90
|
}
|
|
78
91
|
catch (err) {
|
|
92
|
+
clearTimeout(clock);
|
|
79
93
|
const isGrpcError = err.hasOwnProperty('code') &&
|
|
80
94
|
err.hasOwnProperty('details') &&
|
|
81
95
|
err.hasOwnProperty('metadata');
|
|
@@ -167,4 +181,16 @@ async function defaultOnReconnect(err, retryCount) {
|
|
|
167
181
|
};
|
|
168
182
|
}
|
|
169
183
|
exports.defaultOnReconnect = defaultOnReconnect;
|
|
184
|
+
/*
|
|
185
|
+
* Returns a generator that adds the given `token` to request metadata.
|
|
186
|
+
*/
|
|
187
|
+
function createMetadataGenerator(token) {
|
|
188
|
+
const metadata = new grpc_js_1.Metadata();
|
|
189
|
+
if (token) {
|
|
190
|
+
metadata.add('authorization', `bearer ${token}`);
|
|
191
|
+
}
|
|
192
|
+
return (_options, cb) => {
|
|
193
|
+
cb(null, metadata);
|
|
194
|
+
};
|
|
195
|
+
}
|
|
170
196
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CallCredentials,
|
|
3
|
+
ChannelCredentials,
|
|
4
|
+
ClientDuplexStream,
|
|
5
|
+
ClientOptions,
|
|
6
|
+
Metadata,
|
|
7
|
+
StatusObject,
|
|
8
|
+
} from '@grpc/grpc-js'
|
|
9
|
+
import { CallMetadataGenerator } from '@grpc/grpc-js/build/src/call-credentials'
|
|
2
10
|
import { v1alpha2 } from './proto'
|
|
3
11
|
import { StreamDataRequest } from './request'
|
|
4
12
|
|
|
@@ -6,6 +14,9 @@ export { ChannelCredentials, StatusObject } from '@grpc/grpc-js'
|
|
|
6
14
|
|
|
7
15
|
const StreamService = v1alpha2.protoDescriptor.apibara.node.v1alpha2.Stream
|
|
8
16
|
|
|
17
|
+
// Server produces an heartbeat every 30 seconds, so we use 45 seconds as a timeout.
|
|
18
|
+
const MESSAGE_TIMEOUT_MS = 45_000
|
|
19
|
+
|
|
9
20
|
export type DataStream = ClientDuplexStream<
|
|
10
21
|
v1alpha2.IStreamDataRequest,
|
|
11
22
|
v1alpha2.IStreamDataResponse
|
|
@@ -76,6 +87,11 @@ export type StreamClientArgs = {
|
|
|
76
87
|
* Grpc client options.
|
|
77
88
|
*/
|
|
78
89
|
clientOptions?: ClientOptions
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Authorization bearer token, used to authenticate with the server.
|
|
93
|
+
*/
|
|
94
|
+
token?: string
|
|
79
95
|
/**
|
|
80
96
|
* Callback to control reconnection after receiving an error from the stream.
|
|
81
97
|
*
|
|
@@ -114,8 +130,12 @@ export class StreamClient {
|
|
|
114
130
|
* }
|
|
115
131
|
* ```
|
|
116
132
|
*/
|
|
117
|
-
constructor({ url, credentials, clientOptions, onReconnect }: StreamClientArgs) {
|
|
118
|
-
|
|
133
|
+
constructor({ url, credentials, clientOptions, token, onReconnect }: StreamClientArgs) {
|
|
134
|
+
const baseCredentials = credentials ?? ChannelCredentials.createSsl()
|
|
135
|
+
const credentialsWithMetadata = baseCredentials.compose(
|
|
136
|
+
CallCredentials.createFromMetadataGenerator(createMetadataGenerator(token))
|
|
137
|
+
)
|
|
138
|
+
this.inner = new StreamService(url, credentialsWithMetadata, {
|
|
119
139
|
'grpc.keepalive_timeout_ms': 3_600_000,
|
|
120
140
|
...clientOptions,
|
|
121
141
|
})
|
|
@@ -140,14 +160,27 @@ export class StreamClient {
|
|
|
140
160
|
while (true) {
|
|
141
161
|
let retryCount = 1
|
|
142
162
|
let cursor = null
|
|
163
|
+
let clock
|
|
143
164
|
try {
|
|
144
165
|
// this check is to make ts happy
|
|
145
166
|
if (!this.stream) {
|
|
146
167
|
throw new Error('Stream disconnected unexpectedly')
|
|
147
168
|
}
|
|
148
169
|
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
const streamIter = this.stream[Symbol.asyncIterator]()
|
|
171
|
+
while (true) {
|
|
172
|
+
const timeout = new Promise((_, reject) => {
|
|
173
|
+
clock = setTimeout(() => {
|
|
174
|
+
reject(new Error('Stream timed out'))
|
|
175
|
+
}, MESSAGE_TIMEOUT_MS)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
const message = <IteratorResult<v1alpha2.IStreamDataResponse>>(
|
|
179
|
+
await Promise.race([streamIter.next(), timeout])
|
|
180
|
+
)
|
|
181
|
+
const messageTyped = message.value as v1alpha2.IStreamDataResponse
|
|
182
|
+
|
|
183
|
+
clearTimeout(clock)
|
|
151
184
|
|
|
152
185
|
// only return messages if they are with the most recently configured stream
|
|
153
186
|
if (messageTyped.streamId?.toString() == this.stream_id.toString()) {
|
|
@@ -165,6 +198,8 @@ export class StreamClient {
|
|
|
165
198
|
}
|
|
166
199
|
}
|
|
167
200
|
} catch (err: any) {
|
|
201
|
+
clearTimeout(clock)
|
|
202
|
+
|
|
168
203
|
const isGrpcError =
|
|
169
204
|
err.hasOwnProperty('code') &&
|
|
170
205
|
err.hasOwnProperty('details') &&
|
|
@@ -269,3 +304,17 @@ export async function defaultOnReconnect(
|
|
|
269
304
|
reconnect: retryCount < 5,
|
|
270
305
|
}
|
|
271
306
|
}
|
|
307
|
+
|
|
308
|
+
/*
|
|
309
|
+
* Returns a generator that adds the given `token` to request metadata.
|
|
310
|
+
*/
|
|
311
|
+
function createMetadataGenerator(token?: string): CallMetadataGenerator {
|
|
312
|
+
const metadata = new Metadata()
|
|
313
|
+
if (token) {
|
|
314
|
+
metadata.add('authorization', `bearer ${token}`)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return (_options, cb) => {
|
|
318
|
+
cb(null, metadata)
|
|
319
|
+
}
|
|
320
|
+
}
|