@subsquid/portal-client 0.0.1-portal-api.4494d2

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 ADDED
@@ -0,0 +1,3 @@
1
+ # @subsquid/portal-client
2
+
3
+ API for SQD Portal.
@@ -0,0 +1,35 @@
1
+ import { HttpClient } from '@subsquid/http-client';
2
+ import type { Logger } from '@subsquid/logger';
3
+ export interface PortalQuery {
4
+ fromBlock: number;
5
+ toBlock?: number;
6
+ }
7
+ export interface Block {
8
+ header: {
9
+ number: number;
10
+ hash: string;
11
+ };
12
+ }
13
+ export interface Metadata {
14
+ isRealTime: boolean;
15
+ }
16
+ export interface PortalClientOptions {
17
+ url: string;
18
+ http?: HttpClient;
19
+ log?: Logger;
20
+ queryTimeout?: number;
21
+ bufferThreshold?: number;
22
+ }
23
+ export declare class PortalClient {
24
+ private url;
25
+ private http;
26
+ private queryTimeout;
27
+ private bufferThreshold;
28
+ constructor(options: PortalClientOptions);
29
+ private getDatasetUrl;
30
+ getHeight(): Promise<number>;
31
+ getMetadata(): Promise<Metadata>;
32
+ query<B extends Block = Block, Q extends PortalQuery = PortalQuery>(query: Q): Promise<B[]>;
33
+ stream<B extends Block = Block, Q extends PortalQuery = PortalQuery>(query: Q): AsyncIterable<B[]>;
34
+ }
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAC,MAAM,uBAAuB,CAAA;AAChD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AAM5C,MAAM,WAAW,WAAW;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AAGD,MAAM,WAAW,KAAK;IAClB,MAAM,EAAE;QACJ,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;KACf,CAAA;CACJ;AAGD,MAAM,WAAW,QAAQ;IACrB,UAAU,EAAE,OAAO,CAAA;CACtB;AAGD,MAAM,WAAW,mBAAmB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,eAAe,CAAC,EAAE,MAAM,CAAA;CAC3B;AAGD,qBAAa,YAAY;IACrB,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,IAAI,CAAY;IACxB,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,eAAe,CAAQ;gBAEnB,OAAO,EAAE,mBAAmB;IAOxC,OAAO,CAAC,aAAa;IAUf,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAU5B,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;IAUtC,KAAK,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,EAAE,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAuBpF,MAAM,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,EAAE,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,KAAK,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,EAAE,CAAC;CAuE5G"}
package/lib/client.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PortalClient = void 0;
7
+ const http_client_1 = require("@subsquid/http-client");
8
+ const util_internal_1 = require("@subsquid/util-internal");
9
+ const util_internal_archive_layout_1 = require("@subsquid/util-internal-archive-layout");
10
+ const assert_1 = __importDefault(require("assert"));
11
+ class PortalClient {
12
+ constructor(options) {
13
+ this.url = new URL(options.url);
14
+ this.http = options.http || new http_client_1.HttpClient({ log: options.log });
15
+ this.queryTimeout = options.queryTimeout ?? 180000;
16
+ this.bufferThreshold = options.bufferThreshold ?? 10 * 1024 * 1024;
17
+ }
18
+ getDatasetUrl(path) {
19
+ let u = new URL(this.url);
20
+ if (this.url.pathname.endsWith('/')) {
21
+ u.pathname += path;
22
+ }
23
+ else {
24
+ u.pathname += '/' + path;
25
+ }
26
+ return u.toString();
27
+ }
28
+ async getHeight() {
29
+ let res = await this.http.get(this.getDatasetUrl('height'), {
30
+ retryAttempts: 3,
31
+ httpTimeout: 10000,
32
+ });
33
+ let height = parseInt(res);
34
+ (0, assert_1.default)(Number.isSafeInteger(height));
35
+ return height;
36
+ }
37
+ async getMetadata() {
38
+ let res = await this.http.get(this.getDatasetUrl('metadata'), {
39
+ retryAttempts: 3,
40
+ httpTimeout: 10000,
41
+ });
42
+ return {
43
+ isRealTime: !!res.real_time
44
+ };
45
+ }
46
+ query(query) {
47
+ return this.http
48
+ .request('POST', this.getDatasetUrl(`stream`), {
49
+ json: query,
50
+ retryAttempts: 3,
51
+ httpTimeout: this.queryTimeout,
52
+ })
53
+ .catch((0, util_internal_1.withErrorContext)({
54
+ archiveQuery: query,
55
+ }))
56
+ .then((res) => {
57
+ // TODO: move the conversion to the server
58
+ let blocks = res.body
59
+ .toString('utf8')
60
+ .trimEnd()
61
+ .split('\n')
62
+ .map((line) => JSON.parse(line));
63
+ return blocks;
64
+ });
65
+ }
66
+ async *stream(query) {
67
+ let queue = new util_internal_1.AsyncQueue(1);
68
+ const ingest = async () => {
69
+ let bufferSize = 0;
70
+ let fromBlock = query.fromBlock;
71
+ let toBlock = query.toBlock ?? Infinity;
72
+ while (fromBlock <= toBlock) {
73
+ let archiveQuery = { ...query, fromBlock };
74
+ let res = await this.http
75
+ .request('POST', this.getDatasetUrl(`stream`), {
76
+ json: archiveQuery,
77
+ retryAttempts: 3,
78
+ httpTimeout: this.queryTimeout,
79
+ stream: true,
80
+ })
81
+ .catch((0, util_internal_1.withErrorContext)({
82
+ archiveQuery,
83
+ }));
84
+ for await (let lines of (0, util_internal_archive_layout_1.splitLines)(res.body)) {
85
+ let batch = queue.peek();
86
+ if (batch instanceof Error)
87
+ return;
88
+ if (!batch) {
89
+ bufferSize = 0;
90
+ }
91
+ let blocks = lines.map((line) => {
92
+ bufferSize += line.length;
93
+ return JSON.parse(line);
94
+ });
95
+ if (batch) {
96
+ // FIXME: won't it overflow stack?
97
+ batch.push(...blocks);
98
+ if (bufferSize > this.bufferThreshold) {
99
+ await queue.wait();
100
+ }
101
+ }
102
+ else {
103
+ await queue.put(blocks);
104
+ }
105
+ fromBlock = (0, util_internal_1.last)(blocks).header.number + 1;
106
+ }
107
+ // no blocks left
108
+ if (res.status == 204) {
109
+ await (0, util_internal_1.wait)(1000);
110
+ }
111
+ }
112
+ };
113
+ ingest().then(() => queue.close(), (err) => {
114
+ if (!queue.isClosed()) {
115
+ queue.forcePut((0, util_internal_1.ensureError)(err));
116
+ }
117
+ });
118
+ for await (let valueOrError of queue.iterate()) {
119
+ if (valueOrError instanceof Error)
120
+ throw valueOrError;
121
+ yield valueOrError;
122
+ }
123
+ }
124
+ }
125
+ exports.PortalClient = PortalClient;
126
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@subsquid/portal-client",
3
+ "version": "0.0.1-portal-api.4494d2",
4
+ "description": "SQD Portal API",
5
+ "license": "GPL-3.0-or-later",
6
+ "repository": "git@github.com:subsquid/squid.git",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "main": "lib/client.js",
11
+ "files": [
12
+ "lib",
13
+ "src"
14
+ ],
15
+ "dependencies": {
16
+ "@subsquid/util-internal": "3.3.0-portal-api.4494d2",
17
+ "@subsquid/util-internal-range": "^0.3.0",
18
+ "@subsquid/util-internal-archive-layout": "1.1.0-portal-api.4494d2"
19
+ },
20
+ "peerDependencies": {
21
+ "@subsquid/http-client": "^1.5.0",
22
+ "@subsquid/logger": "^1.3.3"
23
+ },
24
+ "peerDependenciesMeta": {
25
+ "@subsquid/logger": {
26
+ "optional": true
27
+ }
28
+ },
29
+ "devDependencies": {
30
+ "@subsquid/http-client": "^1.5.0",
31
+ "@subsquid/logger": "^1.3.3",
32
+ "@types/node": "^18.18.14",
33
+ "typescript": "~5.3.2"
34
+ },
35
+ "scripts": {
36
+ "build": "rm -rf lib && tsc"
37
+ }
38
+ }
package/src/client.ts ADDED
@@ -0,0 +1,173 @@
1
+ import {HttpClient} from '@subsquid/http-client'
2
+ import type {Logger} from '@subsquid/logger'
3
+ import {AsyncQueue, ensureError, last, wait, withErrorContext} from '@subsquid/util-internal'
4
+ import {splitLines} from '@subsquid/util-internal-archive-layout'
5
+ import assert from 'assert'
6
+
7
+
8
+ export interface PortalQuery {
9
+ fromBlock: number
10
+ toBlock?: number
11
+ }
12
+
13
+
14
+ export interface Block {
15
+ header: {
16
+ number: number
17
+ hash: string
18
+ }
19
+ }
20
+
21
+
22
+ export interface Metadata {
23
+ isRealTime: boolean
24
+ }
25
+
26
+
27
+ export interface PortalClientOptions {
28
+ url: string
29
+ http?: HttpClient
30
+ log?: Logger
31
+ queryTimeout?: number
32
+ bufferThreshold?: number
33
+ }
34
+
35
+
36
+ export class PortalClient {
37
+ private url: URL
38
+ private http: HttpClient
39
+ private queryTimeout: number
40
+ private bufferThreshold: number
41
+
42
+ constructor(options: PortalClientOptions) {
43
+ this.url = new URL(options.url)
44
+ this.http = options.http || new HttpClient({log: options.log})
45
+ this.queryTimeout = options.queryTimeout ?? 180_000
46
+ this.bufferThreshold = options.bufferThreshold ?? 10 * 1024 * 1024
47
+ }
48
+
49
+ private getDatasetUrl(path: string): string {
50
+ let u = new URL(this.url)
51
+ if (this.url.pathname.endsWith('/')) {
52
+ u.pathname += path
53
+ } else {
54
+ u.pathname += '/' + path
55
+ }
56
+ return u.toString()
57
+ }
58
+
59
+ async getHeight(): Promise<number> {
60
+ let res: string = await this.http.get(this.getDatasetUrl('height'), {
61
+ retryAttempts: 3,
62
+ httpTimeout: 10_000,
63
+ })
64
+ let height = parseInt(res)
65
+ assert(Number.isSafeInteger(height))
66
+ return height
67
+ }
68
+
69
+ async getMetadata(): Promise<Metadata> {
70
+ let res: {real_time: boolean} = await this.http.get(this.getDatasetUrl('metadata'), {
71
+ retryAttempts: 3,
72
+ httpTimeout: 10_000,
73
+ })
74
+ return {
75
+ isRealTime: !!res.real_time
76
+ }
77
+ }
78
+
79
+ query<B extends Block = Block, Q extends PortalQuery = PortalQuery>(query: Q): Promise<B[]> {
80
+ return this.http
81
+ .request<Buffer>('POST', this.getDatasetUrl(`stream`), {
82
+ json: query,
83
+ retryAttempts: 3,
84
+ httpTimeout: this.queryTimeout,
85
+ })
86
+ .catch(
87
+ withErrorContext({
88
+ archiveQuery: query,
89
+ })
90
+ )
91
+ .then((res) => {
92
+ // TODO: move the conversion to the server
93
+ let blocks = res.body
94
+ .toString('utf8')
95
+ .trimEnd()
96
+ .split('\n')
97
+ .map((line) => JSON.parse(line))
98
+ return blocks
99
+ })
100
+ }
101
+
102
+ async *stream<B extends Block = Block, Q extends PortalQuery = PortalQuery>(query: Q): AsyncIterable<B[]> {
103
+ let queue = new AsyncQueue<B[] | Error>(1)
104
+
105
+ const ingest = async () => {
106
+ let bufferSize = 0
107
+ let fromBlock = query.fromBlock
108
+ let toBlock = query.toBlock ?? Infinity
109
+
110
+ while (fromBlock <= toBlock) {
111
+ let archiveQuery = {...query, fromBlock}
112
+
113
+ let res = await this.http
114
+ .request<NodeJS.ReadableStream>('POST', this.getDatasetUrl(`stream`), {
115
+ json: archiveQuery,
116
+ retryAttempts: 3,
117
+ httpTimeout: this.queryTimeout,
118
+ stream: true,
119
+ })
120
+ .catch(
121
+ withErrorContext({
122
+ archiveQuery,
123
+ })
124
+ )
125
+
126
+ for await (let lines of splitLines(res.body as AsyncIterable<Buffer>)) {
127
+ let batch = queue.peek()
128
+ if (batch instanceof Error) return
129
+
130
+ if (!batch) {
131
+ bufferSize = 0
132
+ }
133
+
134
+ let blocks = lines.map((line) => {
135
+ bufferSize += line.length
136
+ return JSON.parse(line) as B
137
+ })
138
+
139
+ if (batch) {
140
+ // FIXME: won't it overflow stack?
141
+ batch.push(...blocks)
142
+ if (bufferSize > this.bufferThreshold) {
143
+ await queue.wait()
144
+ }
145
+ } else {
146
+ await queue.put(blocks)
147
+ }
148
+
149
+ fromBlock = last(blocks).header.number + 1
150
+ }
151
+
152
+ // no blocks left
153
+ if (res.status == 204) {
154
+ await wait(1000)
155
+ }
156
+ }
157
+ }
158
+
159
+ ingest().then(
160
+ () => queue.close(),
161
+ (err) => {
162
+ if (!queue.isClosed()) {
163
+ queue.forcePut(ensureError(err))
164
+ }
165
+ }
166
+ )
167
+
168
+ for await (let valueOrError of queue.iterate()) {
169
+ if (valueOrError instanceof Error) throw valueOrError
170
+ yield valueOrError
171
+ }
172
+ }
173
+ }