@subsquid/portal-client 0.3.2 → 0.4.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 (131) hide show
  1. package/lib/client.d.ts +40 -18
  2. package/lib/client.d.ts.map +1 -1
  3. package/lib/client.js +166 -188
  4. package/lib/client.js.map +1 -1
  5. package/lib/query/common/data.d.ts +21 -0
  6. package/lib/query/common/data.d.ts.map +1 -0
  7. package/lib/query/common/data.js +3 -0
  8. package/lib/query/common/data.js.map +1 -0
  9. package/lib/query/common/query.d.ts +7 -0
  10. package/lib/query/common/query.d.ts.map +1 -0
  11. package/lib/query/common/query.js +3 -0
  12. package/lib/query/common/query.js.map +1 -0
  13. package/lib/query/evm/data.d.ts +159 -0
  14. package/lib/query/evm/data.d.ts.map +1 -0
  15. package/lib/query/evm/data.js +3 -0
  16. package/lib/query/evm/data.js.map +1 -0
  17. package/lib/query/evm/fields.d.ts +50 -0
  18. package/lib/query/evm/fields.d.ts.map +1 -0
  19. package/lib/query/evm/fields.js +3 -0
  20. package/lib/query/evm/fields.js.map +1 -0
  21. package/lib/query/evm/index.d.ts +4 -0
  22. package/lib/query/evm/index.d.ts.map +1 -0
  23. package/lib/query/evm/index.js +7 -0
  24. package/lib/query/evm/index.js.map +1 -0
  25. package/lib/query/evm/query.d.ts +54 -0
  26. package/lib/query/evm/query.d.ts.map +1 -0
  27. package/lib/query/evm/query.js +3 -0
  28. package/lib/query/evm/query.js.map +1 -0
  29. package/lib/query/evm/schema.d.ts +322 -0
  30. package/lib/query/evm/schema.d.ts.map +1 -0
  31. package/lib/query/evm/schema.js +224 -0
  32. package/lib/query/evm/schema.js.map +1 -0
  33. package/lib/query/index.d.ts +576 -8
  34. package/lib/query/index.d.ts.map +1 -1
  35. package/lib/query/index.js +15 -24
  36. package/lib/query/index.js.map +1 -1
  37. package/lib/query/solana/data.d.ts +115 -0
  38. package/lib/query/solana/data.d.ts.map +1 -0
  39. package/lib/query/solana/data.js +3 -0
  40. package/lib/query/solana/data.js.map +1 -0
  41. package/lib/query/solana/fields.d.ts +31 -0
  42. package/lib/query/solana/fields.d.ts.map +1 -0
  43. package/lib/query/solana/fields.js +3 -0
  44. package/lib/query/solana/fields.js.map +1 -0
  45. package/lib/query/solana/index.d.ts +4 -0
  46. package/lib/query/solana/index.d.ts.map +1 -0
  47. package/lib/query/solana/index.js +7 -0
  48. package/lib/query/solana/index.js.map +1 -0
  49. package/lib/query/solana/query.d.ts +74 -0
  50. package/lib/query/solana/query.d.ts.map +1 -0
  51. package/lib/query/solana/query.js +3 -0
  52. package/lib/query/solana/query.js.map +1 -0
  53. package/lib/query/solana/schema.d.ts +160 -0
  54. package/lib/query/solana/schema.d.ts.map +1 -0
  55. package/lib/query/solana/schema.js +130 -0
  56. package/lib/query/solana/schema.js.map +1 -0
  57. package/lib/query/substrate/data.d.ts +98 -0
  58. package/lib/query/substrate/data.d.ts.map +1 -0
  59. package/lib/query/substrate/data.js +3 -0
  60. package/lib/query/substrate/data.js.map +1 -0
  61. package/lib/query/substrate/fields.d.ts +22 -0
  62. package/lib/query/substrate/fields.d.ts.map +1 -0
  63. package/lib/query/substrate/fields.js +3 -0
  64. package/lib/query/substrate/fields.js.map +1 -0
  65. package/lib/query/substrate/index.d.ts +4 -0
  66. package/lib/query/substrate/index.d.ts.map +1 -0
  67. package/lib/query/substrate/index.js +7 -0
  68. package/lib/query/substrate/index.js.map +1 -0
  69. package/lib/query/substrate/query.d.ts +50 -0
  70. package/lib/query/substrate/query.d.ts.map +1 -0
  71. package/lib/query/substrate/query.js +3 -0
  72. package/lib/query/substrate/query.js.map +1 -0
  73. package/lib/query/substrate/schema.d.ts +102 -0
  74. package/lib/query/substrate/schema.d.ts.map +1 -0
  75. package/lib/query/substrate/schema.js +88 -0
  76. package/lib/query/substrate/schema.js.map +1 -0
  77. package/lib/query/type-util.d.ts +13 -0
  78. package/lib/query/type-util.d.ts.map +1 -0
  79. package/lib/query/type-util.js +3 -0
  80. package/lib/query/type-util.js.map +1 -0
  81. package/lib/query/util.d.ts +5 -0
  82. package/lib/query/util.d.ts.map +1 -0
  83. package/lib/query/util.js +23 -0
  84. package/lib/query/util.js.map +1 -0
  85. package/lib/util.d.ts +19 -0
  86. package/lib/util.d.ts.map +1 -0
  87. package/lib/util.js +57 -0
  88. package/lib/util.js.map +1 -0
  89. package/package.json +3 -3
  90. package/src/client.ts +231 -247
  91. package/src/query/common/data.ts +24 -0
  92. package/src/query/common/query.ts +6 -0
  93. package/src/query/evm/data.ts +182 -0
  94. package/src/query/evm/fields.ts +105 -0
  95. package/src/query/evm/index.ts +3 -0
  96. package/src/query/evm/query.ts +59 -0
  97. package/src/query/evm/schema.ts +277 -0
  98. package/src/query/index.ts +19 -36
  99. package/src/query/solana/data.ts +132 -0
  100. package/src/query/solana/fields.ts +42 -0
  101. package/src/query/solana/index.ts +3 -0
  102. package/src/query/solana/query.ts +89 -0
  103. package/src/query/solana/schema.ts +164 -0
  104. package/src/query/substrate/data.ts +101 -0
  105. package/src/query/substrate/fields.ts +30 -0
  106. package/src/query/substrate/index.ts +3 -0
  107. package/src/query/substrate/query.ts +60 -0
  108. package/src/query/substrate/schema.ts +114 -0
  109. package/src/query/type-util.ts +25 -0
  110. package/src/query/util.ts +23 -0
  111. package/src/util.ts +56 -0
  112. package/lib/query/common.d.ts +0 -56
  113. package/lib/query/common.d.ts.map +0 -1
  114. package/lib/query/common.js +0 -16
  115. package/lib/query/common.js.map +0 -1
  116. package/lib/query/evm.d.ts +0 -267
  117. package/lib/query/evm.d.ts.map +0 -1
  118. package/lib/query/evm.js +0 -245
  119. package/lib/query/evm.js.map +0 -1
  120. package/lib/query/solana.d.ts +0 -224
  121. package/lib/query/solana.d.ts.map +0 -1
  122. package/lib/query/solana.js +0 -121
  123. package/lib/query/solana.js.map +0 -1
  124. package/lib/query/substrate.d.ts +0 -173
  125. package/lib/query/substrate.d.ts.map +0 -1
  126. package/lib/query/substrate.js +0 -71
  127. package/lib/query/substrate.js.map +0 -1
  128. package/src/query/common.ts +0 -83
  129. package/src/query/evm.ts +0 -677
  130. package/src/query/solana.ts +0 -438
  131. package/src/query/substrate.ts +0 -288
package/lib/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HttpClient, HttpClientOptions } from '@subsquid/http-client';
2
- import { GetBlock, evm, PortalBlock, PortalQuery, Query, solana, substrate } from './query';
2
+ import { type AnyQuery, type GetQueryBlock } from './query';
3
3
  export * from './query';
4
4
  export interface PortalClientOptions {
5
5
  /**
@@ -12,17 +12,17 @@ export interface PortalClientOptions {
12
12
  http?: HttpClient | HttpClientOptions;
13
13
  /**
14
14
  * Minimum number of bytes to return.
15
- * @default 10_485_760 (10MB)
15
+ * @deprecated not used
16
16
  */
17
17
  minBytes?: number;
18
18
  /**
19
19
  * Maximum number of bytes to return.
20
- * @default minBytes
20
+ * @default 52_428_800 (50MB)
21
21
  */
22
22
  maxBytes?: number;
23
23
  /**
24
24
  * Maximum time between stream data in milliseconds for return.
25
- * @default 300
25
+ * @default 500
26
26
  */
27
27
  maxIdleTime?: number;
28
28
  /**
@@ -46,16 +46,34 @@ export interface PortalRequestOptions {
46
46
  }
47
47
  export interface PortalStreamOptions {
48
48
  request?: Omit<PortalRequestOptions, 'abort'>;
49
- minBytes?: number;
50
49
  maxBytes?: number;
51
50
  maxIdleTime?: number;
52
51
  maxWaitTime?: number;
53
52
  headPollInterval?: number;
54
53
  }
54
+ export interface PortalStreamBaseResponse {
55
+ headNumber?: number;
56
+ finalizedHeadNumber?: number;
57
+ finalizedHeadHash?: string;
58
+ }
59
+ export interface PortalStreamDataResponse extends PortalStreamBaseResponse {
60
+ type: 'data';
61
+ data: AsyncIterable<Uint8Array> | null;
62
+ }
63
+ export interface PortalStreamNoDataResponse extends PortalStreamBaseResponse {
64
+ type: 'no-data';
65
+ }
66
+ export interface PortalStreamForkResponse extends PortalStreamBaseResponse {
67
+ type: 'fork';
68
+ previousBlocks: BlockRef[];
69
+ }
70
+ export type PortalStreamResponse = PortalStreamDataResponse | PortalStreamNoDataResponse | PortalStreamForkResponse;
55
71
  export type PortalStreamData<B> = {
56
72
  blocks: B[];
57
- finalizedHead?: BlockRef;
58
73
  meta: {
74
+ finalizedHeadNumber?: number;
75
+ finalizedHeadHash?: string;
76
+ headNumber?: number;
59
77
  bytes: number;
60
78
  };
61
79
  };
@@ -69,31 +87,35 @@ export declare class PortalClient {
69
87
  private url;
70
88
  private client;
71
89
  private headPollInterval;
72
- private minBytes;
73
90
  private maxBytes;
74
91
  private maxIdleTime;
75
92
  private maxWaitTime;
76
93
  constructor(options: PortalClientOptions);
77
94
  private getDatasetUrl;
78
- getHead(options?: PortalRequestOptions): Promise<BlockRef | undefined>;
95
+ getHead(options?: PortalRequestOptions, finalized?: boolean): Promise<BlockRef | undefined>;
79
96
  getFinalizedHead(options?: PortalRequestOptions): Promise<BlockRef | undefined>;
80
97
  /**
81
- * @deprecated
98
+ * Waits until the finalized head reaches or exceeds the specified block number.
99
+ * @param blockNumber - The block number to wait for finalization
100
+ * @param options - Request options including abort signal and poll interval
101
+ * @returns The finalized head once it reaches the target block number
82
102
  */
83
- getFinalizedHeight(options?: PortalRequestOptions): Promise<number>;
84
- getFinalizedQuery<Q extends Query>(query: Q, options?: PortalRequestOptions): Promise<GetBlock<Q>[]>;
85
- getQuery<Q extends PortalQuery = PortalQuery, R extends PortalBlock = PortalBlock>(query: Q, options?: PortalRequestOptions): Promise<R[]>;
86
- getFinalizedStream<Q extends evm.Query | solana.Query | substrate.Query>(query: Q, options?: PortalStreamOptions): PortalStream<GetBlock<Q>>;
87
- getStream<Q extends evm.Query | solana.Query | substrate.Query>(query: Q, options?: PortalStreamOptions): PortalStream<GetBlock<Q>>;
103
+ waitForFinalization(blockNumber: number, options?: PortalRequestOptions & {
104
+ pollInterval?: number;
105
+ }): Promise<BlockRef>;
106
+ getStream<Q extends AnyQuery>(query: Q, options?: PortalStreamOptions, finalized?: boolean): PortalStream<GetQueryBlock<Q>>;
107
+ getFinalizedStream<Q extends AnyQuery>(query: Q, options?: PortalStreamOptions): PortalStream<GetQueryBlock<Q>>;
88
108
  private getStreamOptions;
89
109
  private getStreamRequest;
90
110
  private request;
91
111
  }
92
112
  export declare class ForkException extends Error {
93
- readonly previousBlocks: BlockRef[];
94
- readonly head: BlockRef;
95
- readonly name = "ForkError";
96
- constructor(previousBlocks: BlockRef[], head: BlockRef);
113
+ blockNumber: number;
114
+ parentBlockHash: string;
115
+ previousBlocks: BlockRef[];
116
+ constructor(blockNumber: number, parentBlockHash: string, previousBlocks: BlockRef[]);
117
+ get name(): string;
118
+ get isSubsquidForkException(): true;
97
119
  }
98
120
  export declare function isForkException(err: unknown): err is ForkException;
99
121
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/lib/client.js CHANGED
@@ -18,8 +18,9 @@ exports.ForkException = exports.PortalClient = void 0;
18
18
  exports.isForkException = isForkException;
19
19
  const http_client_1 = require("@subsquid/http-client");
20
20
  const util_internal_1 = require("@subsquid/util-internal");
21
- const query_1 = require("./query");
22
21
  const util_internal_validation_1 = require("@subsquid/util-internal-validation");
22
+ const util_1 = require("./util");
23
+ const query_1 = require("./query");
23
24
  __exportStar(require("./query"), exports);
24
25
  const USER_AGENT = `@subsquid/portal-client (https://sqd.ai)`;
25
26
  class PortalClient {
@@ -27,9 +28,8 @@ class PortalClient {
27
28
  this.url = new URL(options.url);
28
29
  this.client = options.http instanceof http_client_1.HttpClient ? options.http : new http_client_1.HttpClient(options.http);
29
30
  this.headPollInterval = options.headPollInterval ?? 0;
30
- this.minBytes = options.minBytes ?? 10 * 1024 * 1024;
31
- this.maxBytes = options.maxBytes ?? this.minBytes;
32
- this.maxIdleTime = options.maxIdleTime ?? 300;
31
+ this.maxBytes = options.maxBytes ?? 50 * 1024 * 1024;
32
+ this.maxIdleTime = options.maxIdleTime ?? 500;
33
33
  this.maxWaitTime = options.maxWaitTime ?? 5000;
34
34
  }
35
35
  getDatasetUrl(path) {
@@ -42,69 +42,40 @@ class PortalClient {
42
42
  }
43
43
  return u.toString();
44
44
  }
45
- async getHead(options) {
46
- const res = await this.request('GET', this.getDatasetUrl('head'), options);
45
+ async getHead(options, finalized) {
46
+ const res = await this.request('GET', this.getDatasetUrl(!finalized ? 'head' : 'finalized-head'), options);
47
47
  return res.body ?? undefined;
48
48
  }
49
- async getFinalizedHead(options) {
50
- const res = await this.request('GET', this.getDatasetUrl('finalized-head'), options);
51
- return res.body ?? undefined;
49
+ getFinalizedHead(options) {
50
+ return this.getHead(options, true);
52
51
  }
53
52
  /**
54
- * @deprecated
53
+ * Waits until the finalized head reaches or exceeds the specified block number.
54
+ * @param blockNumber - The block number to wait for finalization
55
+ * @param options - Request options including abort signal and poll interval
56
+ * @returns The finalized head once it reaches the target block number
55
57
  */
56
- async getFinalizedHeight(options) {
57
- let { body } = await this.request('GET', this.getDatasetUrl('finalized-stream/height'), options);
58
- let height = parseInt(body);
59
- return height;
60
- }
61
- getFinalizedQuery(query, options) {
62
- // FIXME: is it needed or it is better to always use stream?
63
- return this.request('POST', this.getDatasetUrl(`finalized-stream`), {
64
- ...options,
65
- json: query,
66
- })
67
- .catch((0, util_internal_1.withErrorContext)({
68
- archiveQuery: query,
69
- }))
70
- .then((res) => {
71
- let blocks = res.body
72
- .toString('utf8')
73
- .trimEnd()
74
- .split('\n')
75
- .map((line) => JSON.parse(line));
76
- return blocks;
77
- });
58
+ async waitForFinalization(blockNumber, options) {
59
+ let { pollInterval = this.headPollInterval || 1000, ...requestOptions } = options ?? {};
60
+ while (true) {
61
+ options?.abort?.throwIfAborted();
62
+ let head = await this.getFinalizedHead(requestOptions);
63
+ if (head && head.number >= blockNumber) {
64
+ return head;
65
+ }
66
+ await (0, util_internal_1.wait)(pollInterval, options?.abort);
67
+ }
78
68
  }
79
- getQuery(query, options) {
80
- // FIXME: is it needed or it is better to always use stream?
81
- return this.request('POST', this.getDatasetUrl(`stream`), {
82
- ...options,
83
- json: query,
84
- })
85
- .catch((0, util_internal_1.withErrorContext)({
86
- archiveQuery: query,
87
- }))
88
- .then((res) => {
89
- let blocks = res.body
90
- .toString('utf8')
91
- .trimEnd()
92
- .split('\n')
93
- .map((line) => JSON.parse(line));
94
- return blocks;
95
- });
69
+ getStream(query, options, finalized) {
70
+ return createPortalStream(query, this.getStreamOptions(options), async (q, o) => this.getStreamRequest(!finalized ? 'stream' : 'finalized-stream', q, o));
96
71
  }
97
72
  getFinalizedStream(query, options) {
98
- return createPortalStream(query, this.getStreamOptions(options), async (q, o) => this.getStreamRequest('finalized-stream', q, o));
99
- }
100
- getStream(query, options) {
101
- return createPortalStream(query, this.getStreamOptions(options), async (q, o) => this.getStreamRequest('stream', q, o));
73
+ return this.getStream(query, options, true);
102
74
  }
103
75
  getStreamOptions(options) {
104
- let { headPollInterval = this.headPollInterval, minBytes = this.minBytes, maxBytes = this.maxBytes, maxIdleTime = this.maxIdleTime, maxWaitTime = this.maxWaitTime, request = {}, } = options ?? {};
76
+ let { headPollInterval = this.headPollInterval, maxBytes = this.maxBytes, maxIdleTime = this.maxIdleTime, maxWaitTime = this.maxWaitTime, request = {}, } = options ?? {};
105
77
  return {
106
78
  headPollInterval,
107
- minBytes,
108
79
  maxBytes,
109
80
  maxIdleTime,
110
81
  maxWaitTime,
@@ -120,28 +91,29 @@ class PortalClient {
120
91
  }).catch((0, util_internal_1.withErrorContext)({
121
92
  query: query,
122
93
  }));
94
+ let headers = getPortalStreamHeaders(res.headers);
123
95
  switch (res.status) {
124
96
  case 200:
125
- let finalizedHead = getFinalizedHeadHeader(res.headers);
126
- let stream = res.body ? splitLines(res.body) : undefined;
127
97
  return {
128
- finalizedHead,
129
- stream,
98
+ ...headers,
99
+ type: 'data',
100
+ data: res.body ?? null,
130
101
  };
131
102
  case 204:
132
103
  return {
133
- finalizedHead: getFinalizedHeadHeader(res.headers),
104
+ ...headers,
105
+ type: 'no-data',
134
106
  };
135
107
  default:
136
108
  throw (0, util_internal_1.unexpectedCase)(res.status);
137
109
  }
138
110
  }
139
111
  catch (e) {
140
- if (isForkHttpError(e) && query.fromBlock != null && query.parentBlockHash != null) {
141
- e = new ForkException(e.response.body.previousBlocks, {
142
- number: query.fromBlock - 1,
143
- hash: query.parentBlockHash,
144
- });
112
+ if (isForkHttpError(e)) {
113
+ return {
114
+ type: 'fork',
115
+ previousBlocks: e.response.body.previousBlocks,
116
+ };
145
117
  }
146
118
  throw (0, util_internal_1.addErrorContext)(e, {
147
119
  query,
@@ -171,35 +143,35 @@ function isForkHttpError(err) {
171
143
  function createPortalStream(query, options, requestStream) {
172
144
  let { headPollInterval, request, ...bufferOptions } = options;
173
145
  let buffer = new PortalStreamBuffer(bufferOptions);
174
- let schema = (0, query_1.getBlockSchema)(query);
175
- let { fromBlock = 0, toBlock, parentBlockHash } = query;
146
+ let [normalizedQuery, schema] = (0, query_1.getQuery)(query);
147
+ let { fromBlock = 0, toBlock, parentBlockHash } = normalizedQuery;
176
148
  const ingest = async () => {
177
149
  while (!buffer.signal.aborted) {
178
150
  if (toBlock != null && fromBlock > toBlock)
179
151
  break;
180
152
  let res = await requestStream({
181
- ...query,
153
+ ...normalizedQuery,
182
154
  fromBlock,
183
155
  parentBlockHash,
184
156
  }, {
185
157
  ...request,
186
158
  abort: buffer.signal,
187
159
  });
188
- const finalizedHead = res.finalizedHead;
189
- // we are on head
190
- if (!('stream' in res)) {
191
- await buffer.put({ blocks: [], meta: { bytes: 0 }, finalizedHead });
160
+ if (res.type === 'fork') {
161
+ throw new ForkException(fromBlock, parentBlockHash, res.previousBlocks);
162
+ }
163
+ buffer.updateHead(res);
164
+ if (res.type === 'no-data') {
192
165
  buffer.flush();
193
166
  if (headPollInterval > 0) {
194
167
  await (0, util_internal_1.wait)(headPollInterval, buffer.signal);
195
168
  }
196
169
  continue;
197
170
  }
198
- // no data left on this range
199
- if (res.stream == null)
171
+ if (!res.data)
200
172
  break;
201
173
  try {
202
- for await (let data of res.stream) {
174
+ for await (let data of splitLines(res.data)) {
203
175
  buffer.signal.throwIfAborted();
204
176
  let blocks = [];
205
177
  let bytes = 0;
@@ -210,8 +182,9 @@ function createPortalStream(query, options, requestStream) {
210
182
  fromBlock = block.header.number + 1;
211
183
  parentBlockHash = block.header.hash;
212
184
  }
213
- await buffer.put({ blocks, finalizedHead, meta: { bytes } });
185
+ await buffer.put(blocks, bytes);
214
186
  }
187
+ buffer.flush();
215
188
  }
216
189
  catch (err) {
217
190
  if (buffer.signal.aborted)
@@ -221,141 +194,139 @@ function createPortalStream(query, options, requestStream) {
221
194
  }
222
195
  }
223
196
  }
197
+ buffer.flush();
224
198
  };
225
199
  ingest().then(() => buffer.close(), (err) => buffer.fail(err));
226
- return buffer.iterate();
200
+ return buffer;
227
201
  }
228
202
  class PortalStreamBuffer {
229
203
  get signal() {
230
204
  return this.abortController.signal;
231
205
  }
232
206
  constructor(options) {
233
- this.state = 'pending';
234
- this.readyFuture = (0, util_internal_1.createFuture)();
235
- this.takeFuture = (0, util_internal_1.createFuture)();
236
- this.putFuture = (0, util_internal_1.createFuture)();
207
+ this.blocks = [];
208
+ this.bytes = 0;
209
+ this.headUpdated = false;
210
+ this.state = 'open';
211
+ this.waitTimeouted = false;
212
+ this.putMutex = new util_1.Semaphore(false);
213
+ this.takeMutex = new util_1.Semaphore(true);
237
214
  this.abortController = new AbortController();
238
- this.maxWaitTime = options.maxWaitTime;
239
- this.minBytes = options.minBytes;
240
- this.maxBytes = Math.max(options.maxBytes, options.minBytes);
241
- this.maxIdleTime = options.maxIdleTime;
215
+ this.maxBytes = options.maxBytes;
216
+ this.idleTimer = new util_1.Timer(options.maxIdleTime, () => this.flush());
217
+ this.waitTimer = new util_1.Timer(options.maxWaitTime, () => (this.waitTimeouted = true));
242
218
  }
243
219
  async take() {
244
- if (this.state === 'pending') {
245
- this.waitTimeout = setTimeout(() => this._ready('wait'), this.maxWaitTime);
246
- }
247
- await Promise.all([this.readyFuture.promise(), this.putFuture.promise()]);
248
- if (this.state === 'failed') {
249
- throw this.error;
250
- }
251
- let result = this.buffer;
252
- this.buffer = undefined;
253
- if (this.state === 'closed') {
254
- return result;
255
- }
256
- if (result == null) {
257
- throw new Error('Buffer is empty');
220
+ if (this.isTerminated()) {
221
+ return this.collect();
258
222
  }
259
- this.takeFuture.resolve();
260
- this.readyFuture = (0, util_internal_1.createFuture)();
261
- this.putFuture = (0, util_internal_1.createFuture)();
262
- this.takeFuture = (0, util_internal_1.createFuture)();
263
- this.state = 'pending';
223
+ this.waitTimer.start();
224
+ await this.putMutex.wait();
225
+ this.waitTimer.stop();
226
+ let result = this.collect();
227
+ this.putMutex.unready();
228
+ this.takeMutex.ready();
229
+ this.waitTimeouted = false;
264
230
  return result;
265
231
  }
266
- async put(data) {
267
- if (this.state === 'closed' || this.state === 'failed') {
232
+ updateHead(head) {
233
+ this.headNumber = head.headNumber;
234
+ this.finalizedHeadNumber = head.finalizedHeadNumber;
235
+ this.finalizedHeadHash = head.finalizedHeadHash;
236
+ this.headUpdated = true;
237
+ }
238
+ async put(blocks, bytes) {
239
+ if (this.isTerminated()) {
268
240
  throw new Error('Buffer is closed');
269
241
  }
270
- if (this.idleTimeout != null) {
271
- clearTimeout(this.idleTimeout);
272
- this.idleTimeout = undefined;
273
- }
274
- if (this.buffer == null) {
275
- this.buffer = { blocks: [], meta: { bytes: 0 } };
276
- }
277
- this.buffer.blocks.push(...data.blocks);
278
- this.buffer.finalizedHead = data.finalizedHead;
279
- this.buffer.meta.bytes += data.meta.bytes;
280
- this.putFuture.resolve();
281
- if (this.buffer.meta.bytes >= this.minBytes) {
282
- this._ready('minBytes');
242
+ this.idleTimer.stop();
243
+ this.blocks.push(...blocks);
244
+ this.bytes += bytes;
245
+ if (this.waitTimeouted || this.bytes >= this.maxBytes) {
246
+ this.flush();
283
247
  }
284
- if (this.buffer.meta.bytes >= this.maxBytes) {
285
- await this.takeFuture.promise();
286
- }
287
- if (this.state === 'pending') {
288
- this.idleTimeout = setTimeout(() => this._ready('idle'), this.maxIdleTime);
248
+ if (this.bytes >= this.maxBytes) {
249
+ this.takeMutex.unready();
250
+ await this.takeMutex.wait();
289
251
  }
252
+ this.idleTimer.start();
290
253
  }
291
254
  flush() {
292
- if (this.buffer == null)
255
+ if (!this.hasData())
293
256
  return;
294
- this._ready('flush');
257
+ this.stopTimers();
258
+ this.putMutex.ready();
295
259
  }
296
260
  close() {
297
- if (this.state === 'closed' || this.state === 'failed')
261
+ if (this.isTerminated())
298
262
  return;
299
263
  this.state = 'closed';
300
- this._cleanup();
264
+ this.stopTimers();
265
+ this.putMutex.ready();
266
+ this.takeMutex.reject(new Error('Buffer closed'));
267
+ this.abortController.abort();
301
268
  }
302
269
  fail(err) {
303
- if (this.state === 'closed' || this.state === 'failed')
270
+ if (this.isTerminated())
304
271
  return;
305
272
  this.state = 'failed';
306
273
  this.error = err;
307
- this._cleanup();
274
+ this.stopTimers();
275
+ this.putMutex.ready();
276
+ this.takeMutex.reject(new Error('Buffer closed'));
277
+ this.abortController.abort();
308
278
  }
309
- iterate() {
279
+ [Symbol.asyncIterator]() {
310
280
  return {
311
- [Symbol.asyncIterator]: () => {
312
- return {
313
- next: async () => {
314
- const value = await this.take();
315
- if (value == null) {
316
- return { done: true, value: undefined };
317
- }
318
- return { done: false, value };
319
- },
320
- return: async () => {
321
- this.close();
322
- return { done: true, value: undefined };
323
- },
324
- throw: async (error) => {
325
- this.fail(error);
326
- throw error;
327
- },
328
- };
281
+ next: async () => {
282
+ let value = await this.take();
283
+ if (value == null) {
284
+ return { done: true, value: undefined };
285
+ }
286
+ return { done: false, value };
287
+ },
288
+ return: async () => {
289
+ this.close();
290
+ return { done: true, value: undefined };
291
+ },
292
+ throw: async (error) => {
293
+ this.fail(error);
294
+ throw error;
329
295
  },
330
296
  };
331
297
  }
332
- _ready(reason) {
333
- if (this.state === 'pending') {
334
- this.state = 'ready';
335
- this.readyFuture.resolve();
336
- }
337
- if (this.idleTimeout != null) {
338
- clearTimeout(this.idleTimeout);
339
- this.idleTimeout = undefined;
340
- }
341
- if (this.waitTimeout != null) {
342
- clearTimeout(this.waitTimeout);
343
- this.waitTimeout = undefined;
344
- }
298
+ hasData() {
299
+ return this.blocks.length > 0 || this.headUpdated;
345
300
  }
346
- _cleanup() {
347
- if (this.idleTimeout != null) {
348
- clearTimeout(this.idleTimeout);
349
- this.idleTimeout = undefined;
350
- }
351
- if (this.waitTimeout != null) {
352
- clearTimeout(this.waitTimeout);
353
- this.waitTimeout = undefined;
301
+ isTerminated() {
302
+ return this.state !== 'open';
303
+ }
304
+ isFailed() {
305
+ return this.state === 'failed';
306
+ }
307
+ collect() {
308
+ if (!this.hasData()) {
309
+ if (this.isFailed())
310
+ throw this.error;
311
+ return undefined;
354
312
  }
355
- this.readyFuture.resolve();
356
- this.putFuture.resolve();
357
- this.takeFuture.resolve();
358
- this.abortController.abort();
313
+ let result = {
314
+ blocks: this.blocks,
315
+ meta: {
316
+ bytes: this.bytes,
317
+ headNumber: this.headNumber,
318
+ finalizedHeadNumber: this.finalizedHeadNumber,
319
+ finalizedHeadHash: this.finalizedHeadHash,
320
+ },
321
+ };
322
+ this.blocks = [];
323
+ this.bytes = 0;
324
+ this.headUpdated = false;
325
+ return result;
326
+ }
327
+ stopTimers() {
328
+ this.idleTimer.stop();
329
+ this.waitTimer.stop();
359
330
  }
360
331
  }
361
332
  async function* splitLines(chunks) {
@@ -402,12 +373,19 @@ class LineSplitter {
402
373
  }
403
374
  }
404
375
  class ForkException extends Error {
405
- constructor(previousBlocks, head) {
406
- let parent = (0, util_internal_1.last)(previousBlocks);
407
- super(`expected ${head.number + 1} to have parent ${parent.number}#${parent.hash}, but got ${head.number}#${head.hash}`);
376
+ constructor(blockNumber, parentBlockHash, previousBlocks) {
377
+ let base = (0, util_internal_1.last)(previousBlocks);
378
+ super(`expected block ${blockNumber} to have parent ${base.number}#${parentBlockHash}, ` +
379
+ `but got ${base.number}#${base.hash} as a parent instead`);
380
+ this.blockNumber = blockNumber;
381
+ this.parentBlockHash = parentBlockHash;
408
382
  this.previousBlocks = previousBlocks;
409
- this.head = head;
410
- this.name = 'ForkError';
383
+ }
384
+ get name() {
385
+ return 'ForkException';
386
+ }
387
+ get isSubsquidForkException() {
388
+ return true;
411
389
  }
412
390
  }
413
391
  exports.ForkException = ForkException;
@@ -418,15 +396,15 @@ function isForkException(err) {
418
396
  return true;
419
397
  return false;
420
398
  }
421
- function getFinalizedHeadHeader(headers) {
422
- let finalizedHeadHash = headers.get('X-Sqd-Finalized-Head-Hash');
423
- let finalizedHeadNumber = headers.get('X-Sqd-Finalized-Head-Number');
424
- return finalizedHeadHash != null && finalizedHeadNumber != null
425
- ? {
426
- hash: finalizedHeadHash,
427
- number: parseInt(finalizedHeadNumber),
428
- }
429
- : undefined;
399
+ function getPortalStreamHeaders(headers) {
400
+ let finalizedHeadHash = headers.get('x-sqd-finalized-head-hash');
401
+ let finalizedHeadNumber = headers.get('x-sqd-finalized-head-number');
402
+ let headNumber = headers.get('x-sqd-head-number');
403
+ return {
404
+ headNumber: headNumber ? parseInt(headNumber) : undefined,
405
+ finalizedHeadNumber: finalizedHeadNumber ? parseInt(finalizedHeadNumber) : undefined,
406
+ finalizedHeadHash: finalizedHeadHash ?? undefined,
407
+ };
430
408
  }
431
409
  function isStreamAbortedError(err) {
432
410
  if (!(err instanceof Error))