@0xobelisk/sui-client 1.0.5 → 1.0.7
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/dubhe.d.ts +19 -1
- package/dist/index.js +4059 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4059 -11
- package/dist/index.mjs.map +1 -1
- package/dist/libs/http/errors.d.ts +28 -0
- package/dist/libs/http/http.d.ts +21 -0
- package/dist/libs/http/index.d.ts +4 -0
- package/dist/libs/http/types.d.ts +1 -0
- package/dist/libs/suiIndexerClient/index.d.ts +92 -0
- package/dist/libs/suiIndexerClient/types.d.ts +0 -0
- package/dist/libs/suiInteractor/defaultConfig.d.ts +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +14 -9
- package/src/dubhe.ts +71 -1
- package/src/libs/http/errors.ts +122 -0
- package/src/libs/http/http.ts +153 -0
- package/src/libs/http/index.ts +4 -0
- package/src/libs/http/types.ts +1 -0
- package/src/libs/suiIndexerClient/index.ts +225 -0
- package/src/libs/suiIndexerClient/types.ts +0 -0
- package/src/libs/suiInteractor/defaultConfig.ts +6 -0
- package/src/libs/suiInteractor/suiInteractor.ts +8 -0
- package/src/types/index.ts +5 -0
- package/src/utils/index.ts +9 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare class BaseError extends Error {
|
|
2
|
+
code: number;
|
|
3
|
+
type: string;
|
|
4
|
+
constructor(message: string, code: number, type: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class HttpError extends BaseError {
|
|
7
|
+
constructor(message: string, code: number);
|
|
8
|
+
}
|
|
9
|
+
export declare class GraphQLError extends BaseError {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class ValidationError extends BaseError {
|
|
13
|
+
constructor(message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class NotFoundError extends BaseError {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
export declare class ParseError extends BaseError {
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
21
|
+
export type ErrorType = BaseError | Error | HttpError | NotFoundError | ValidationError | ParseError | GraphQLError;
|
|
22
|
+
export declare function handleError(error: ErrorType): {
|
|
23
|
+
code: number;
|
|
24
|
+
error: {
|
|
25
|
+
message: string;
|
|
26
|
+
type: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
export type FetchOptions = RequestInit & {
|
|
3
|
+
next?: {
|
|
4
|
+
revalidate?: boolean | number;
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
export declare class Http {
|
|
8
|
+
private customFetch?;
|
|
9
|
+
private apiEndpoint;
|
|
10
|
+
private graphqlEndpoint;
|
|
11
|
+
private wsEndpoint;
|
|
12
|
+
private defaultOptions?;
|
|
13
|
+
constructor(apiEndpoint: string, wsEndpoint: string, customFetch?: typeof fetch | undefined, defaultOptions?: FetchOptions);
|
|
14
|
+
private getFetch;
|
|
15
|
+
fetch(url: string): Promise<Response>;
|
|
16
|
+
fetchGraphql<T>({ query, variables, }: {
|
|
17
|
+
query: string;
|
|
18
|
+
variables?: any;
|
|
19
|
+
}): Promise<T>;
|
|
20
|
+
subscribe(names: string[], handleData: (data: any) => void): Promise<WebSocket>;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ERROR: {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Http } from '../http';
|
|
2
|
+
import { WebSocket } from 'ws';
|
|
3
|
+
export interface OrderDirection {
|
|
4
|
+
ASC: 'ASC';
|
|
5
|
+
DESC: 'DESC';
|
|
6
|
+
}
|
|
7
|
+
export interface OrderBy {
|
|
8
|
+
field: string;
|
|
9
|
+
direction: OrderDirection['ASC'] | OrderDirection['DESC'];
|
|
10
|
+
}
|
|
11
|
+
export interface PageInfo {
|
|
12
|
+
hasNextPage: boolean;
|
|
13
|
+
hasPreviousPage: boolean;
|
|
14
|
+
startCursor?: string;
|
|
15
|
+
endCursor?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface Transaction {
|
|
18
|
+
id: number;
|
|
19
|
+
checkpoint: number;
|
|
20
|
+
digest: string;
|
|
21
|
+
}
|
|
22
|
+
export interface Schema {
|
|
23
|
+
id: number;
|
|
24
|
+
name: string;
|
|
25
|
+
key1?: string;
|
|
26
|
+
key2?: string;
|
|
27
|
+
value: string;
|
|
28
|
+
last_update_checkpoint: string;
|
|
29
|
+
last_update_digest: string;
|
|
30
|
+
is_removed: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface Event {
|
|
33
|
+
id: number;
|
|
34
|
+
checkpoint: string;
|
|
35
|
+
digest: string;
|
|
36
|
+
name: string;
|
|
37
|
+
value: string;
|
|
38
|
+
}
|
|
39
|
+
export interface ConnectionResponse<T> {
|
|
40
|
+
edges: Array<{
|
|
41
|
+
cursor: string;
|
|
42
|
+
node: T;
|
|
43
|
+
}>;
|
|
44
|
+
pageInfo: PageInfo;
|
|
45
|
+
}
|
|
46
|
+
export declare class SuiIndexerClient {
|
|
47
|
+
private http;
|
|
48
|
+
constructor(http: Http);
|
|
49
|
+
private fetchGraphql;
|
|
50
|
+
getTransactions(params?: {
|
|
51
|
+
first?: number;
|
|
52
|
+
after?: string;
|
|
53
|
+
last?: number;
|
|
54
|
+
before?: string;
|
|
55
|
+
checkpoint?: number;
|
|
56
|
+
orderBy?: OrderBy;
|
|
57
|
+
distinct?: boolean;
|
|
58
|
+
}): Promise<ConnectionResponse<Transaction>>;
|
|
59
|
+
getSchemas(params?: {
|
|
60
|
+
first?: number;
|
|
61
|
+
after?: string;
|
|
62
|
+
last?: number;
|
|
63
|
+
before?: string;
|
|
64
|
+
name?: string;
|
|
65
|
+
key1?: string;
|
|
66
|
+
key2?: string;
|
|
67
|
+
orderBy?: OrderBy;
|
|
68
|
+
distinct?: boolean;
|
|
69
|
+
}): Promise<ConnectionResponse<Schema>>;
|
|
70
|
+
getEvents(params?: {
|
|
71
|
+
first?: number;
|
|
72
|
+
after?: string;
|
|
73
|
+
last?: number;
|
|
74
|
+
before?: string;
|
|
75
|
+
name?: string;
|
|
76
|
+
checkpoint?: string;
|
|
77
|
+
orderBy?: OrderBy;
|
|
78
|
+
distinct?: boolean;
|
|
79
|
+
}): Promise<ConnectionResponse<Event>>;
|
|
80
|
+
getStorage({ name, key1, key2, first, after, last, before, orderBy, distinct, }: {
|
|
81
|
+
name: string;
|
|
82
|
+
key1?: string;
|
|
83
|
+
key2?: string;
|
|
84
|
+
first?: number;
|
|
85
|
+
after?: string;
|
|
86
|
+
last?: number;
|
|
87
|
+
before?: string;
|
|
88
|
+
orderBy?: OrderBy;
|
|
89
|
+
distinct?: boolean;
|
|
90
|
+
}): Promise<ConnectionResponse<Schema>>;
|
|
91
|
+
subscribe(names: string[], handleData: (data: any) => void): Promise<WebSocket>;
|
|
92
|
+
}
|
|
File without changes
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Transaction, TransactionObjectArgument, TransactionResult, Argumen
|
|
|
5
5
|
import type { SuiMoveNormalizedModules, DevInspectResults, SuiTransactionBlockResponse, DisplayFieldsResponse, MoveStruct, SuiMoveNormalizedEnum, SuiMoveNormalizedStruct } from '@mysten/sui/client';
|
|
6
6
|
import { SuiTx } from '../libs/suiTxBuilder';
|
|
7
7
|
import { SuiMoveMoudleFuncType } from '../libs/suiContractFactory/types';
|
|
8
|
+
import { FetchOptions } from '../libs/http';
|
|
8
9
|
export declare const ObjectContentFields: import("superstruct").Struct<Record<string, any>, null>;
|
|
9
10
|
export type ObjectContentFields = Infer<typeof ObjectContentFields>;
|
|
10
11
|
export type DubheObjectData = {
|
|
@@ -28,6 +29,10 @@ export type DubheParams = {
|
|
|
28
29
|
networkType?: NetworkType;
|
|
29
30
|
packageId?: string;
|
|
30
31
|
metadata?: SuiMoveNormalizedModules;
|
|
32
|
+
customFetch?: typeof fetch;
|
|
33
|
+
defaultOptions?: FetchOptions;
|
|
34
|
+
indexerUrl?: string;
|
|
35
|
+
indexerWsUrl?: string;
|
|
31
36
|
};
|
|
32
37
|
export type SchemaFieldType = {
|
|
33
38
|
schemas: {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export declare function capitalizeFirstLetter(input: string): string;
|
|
|
2
2
|
export declare function normalizeHexAddress(input: string): string | null;
|
|
3
3
|
export declare function numberToAddressHex(num: number): string;
|
|
4
4
|
export declare function normalizePackageId(input: string): string;
|
|
5
|
+
export declare function convertHttpToWebSocket(url: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xobelisk/sui-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Tookit for interacting with move eps framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sui",
|
|
@@ -37,47 +37,52 @@
|
|
|
37
37
|
"src"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
40
41
|
"@mysten/bcs": "^1.2.1",
|
|
41
42
|
"@mysten/sui": "^1.19.0",
|
|
43
|
+
"@mysten/zklogin": "^0.7.8",
|
|
42
44
|
"@noble/curves": "^1.4.2",
|
|
43
45
|
"@noble/hashes": "^1.4.0",
|
|
44
46
|
"@scure/bip39": "^1.3.0",
|
|
45
|
-
"@mysten/zklogin": "^0.7.8",
|
|
46
|
-
"@graphql-typed-document-node/core": "^3.2.0",
|
|
47
47
|
"@suchipi/femver": "^1.0.0",
|
|
48
48
|
"assert": "^2.1.0",
|
|
49
49
|
"bech32": "^2.0.0",
|
|
50
|
-
"superstruct": "^1.0.3",
|
|
51
|
-
"ts-retry-promise": "^0.7.1",
|
|
52
|
-
"tweetnacl": "^1.0.3",
|
|
53
50
|
"colorts": "^0.1.63",
|
|
51
|
+
"gql.tada": "^1.7.0",
|
|
52
|
+
"graphql": "^16.8.1",
|
|
54
53
|
"husky": "^8.0.3",
|
|
55
54
|
"keccak256": "^1.0.6",
|
|
56
55
|
"process": "^0.11.10",
|
|
57
|
-
"
|
|
58
|
-
"graphql": "^16.8.1",
|
|
56
|
+
"superstruct": "^1.0.3",
|
|
59
57
|
"tmp": "^0.2.1",
|
|
58
|
+
"ts-retry-promise": "^0.7.1",
|
|
59
|
+
"tweetnacl": "^1.0.3",
|
|
60
60
|
"valibot": "0.36.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@commitlint/cli": "^18.0.0",
|
|
64
64
|
"@commitlint/config-conventional": "^18.0.0",
|
|
65
65
|
"@commitlint/prompt-cli": "^18.0.0",
|
|
66
|
+
"@types/jest": "^29.5.14",
|
|
66
67
|
"@types/node": "^20.8.7",
|
|
67
68
|
"@types/tmp": "^0.2.5",
|
|
69
|
+
"@types/ws": "^8.5.14",
|
|
68
70
|
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
|
69
71
|
"@typescript-eslint/parser": "^6.8.0",
|
|
70
72
|
"dotenv": "^16.3.1",
|
|
71
73
|
"eslint": "^8.52.0",
|
|
72
74
|
"eslint-config-prettier": "^8.8.0",
|
|
73
75
|
"eslint-plugin-prettier": "^5.0.1",
|
|
76
|
+
"graphql-ws": "^6.0.2",
|
|
77
|
+
"jest": "^29.7.0",
|
|
74
78
|
"lint-staged": "^15.0.2",
|
|
75
79
|
"prettier": "^2.8.8",
|
|
76
80
|
"ts-node": "^10.9.1",
|
|
77
81
|
"tsconfig-paths": "^4.2.0",
|
|
78
82
|
"tsup": "^7.1.0",
|
|
79
83
|
"typedoc": "^0.25.2",
|
|
80
|
-
"typescript": "^5.2.2"
|
|
84
|
+
"typescript": "^5.2.2",
|
|
85
|
+
"ws": "^8.18.0"
|
|
81
86
|
},
|
|
82
87
|
"lint-staged": {
|
|
83
88
|
"**/*.ts": [
|
package/src/dubhe.ts
CHANGED
|
@@ -41,12 +41,21 @@ import {
|
|
|
41
41
|
SuiVecTxArg,
|
|
42
42
|
} from './types';
|
|
43
43
|
import {
|
|
44
|
+
convertHttpToWebSocket,
|
|
44
45
|
normalizeHexAddress,
|
|
45
46
|
normalizePackageId,
|
|
46
47
|
numberToAddressHex,
|
|
47
48
|
} from './utils';
|
|
48
49
|
import { bcs, fromHEX, toHEX } from '@mysten/bcs';
|
|
49
50
|
import { ContractDataParsingError } from './errors';
|
|
51
|
+
import {
|
|
52
|
+
ConnectionResponse,
|
|
53
|
+
OrderBy,
|
|
54
|
+
Schema,
|
|
55
|
+
SuiIndexerClient,
|
|
56
|
+
} from './libs/suiIndexerClient';
|
|
57
|
+
import { Http } from './libs/http';
|
|
58
|
+
import { WebSocket } from 'ws';
|
|
50
59
|
|
|
51
60
|
export function isUndefined(value?: unknown): value is undefined {
|
|
52
61
|
return value === undefined;
|
|
@@ -121,8 +130,10 @@ function createTx(
|
|
|
121
130
|
* @description This class is used to aggregate the tools that used to interact with SUI network.
|
|
122
131
|
*/
|
|
123
132
|
export class Dubhe {
|
|
133
|
+
public http: Http;
|
|
124
134
|
public accountManager: SuiAccountManager;
|
|
125
135
|
public suiInteractor: SuiInteractor;
|
|
136
|
+
public suiIndexerClient: SuiIndexerClient;
|
|
126
137
|
public contractFactory: SuiContractFactory;
|
|
127
138
|
public packageId: string | undefined;
|
|
128
139
|
public metadata: SuiMoveNormalizedModules | undefined;
|
|
@@ -237,13 +248,27 @@ export class Dubhe {
|
|
|
237
248
|
fullnodeUrls,
|
|
238
249
|
packageId,
|
|
239
250
|
metadata,
|
|
251
|
+
customFetch,
|
|
252
|
+
defaultOptions,
|
|
253
|
+
indexerUrl,
|
|
254
|
+
indexerWsUrl,
|
|
240
255
|
}: DubheParams = {}) {
|
|
256
|
+
networkType = networkType ?? 'mainnet';
|
|
257
|
+
|
|
258
|
+
const defaultParams = getDefaultURL(networkType);
|
|
259
|
+
|
|
241
260
|
// Init the account manager
|
|
242
261
|
this.accountManager = new SuiAccountManager({ mnemonics, secretKey });
|
|
243
262
|
// Init the rpc provider
|
|
244
|
-
fullnodeUrls = fullnodeUrls || [
|
|
263
|
+
fullnodeUrls = fullnodeUrls || [defaultParams.fullNode];
|
|
245
264
|
this.suiInteractor = new SuiInteractor(fullnodeUrls, networkType);
|
|
246
265
|
|
|
266
|
+
indexerUrl = indexerUrl || defaultParams.indexerUrl;
|
|
267
|
+
indexerWsUrl = indexerWsUrl || convertHttpToWebSocket(indexerUrl);
|
|
268
|
+
this.http = new Http(indexerUrl, indexerWsUrl, customFetch, defaultOptions);
|
|
269
|
+
|
|
270
|
+
this.suiIndexerClient = new SuiIndexerClient(this.http);
|
|
271
|
+
|
|
247
272
|
this.packageId = packageId ? normalizePackageId(packageId) : undefined;
|
|
248
273
|
if (metadata !== undefined) {
|
|
249
274
|
this.metadata = metadata as SuiMoveNormalizedModules;
|
|
@@ -1085,6 +1110,47 @@ export class Dubhe {
|
|
|
1085
1110
|
});
|
|
1086
1111
|
}
|
|
1087
1112
|
|
|
1113
|
+
async getStorage({
|
|
1114
|
+
name,
|
|
1115
|
+
key1,
|
|
1116
|
+
key2,
|
|
1117
|
+
first,
|
|
1118
|
+
after,
|
|
1119
|
+
last,
|
|
1120
|
+
before,
|
|
1121
|
+
orderBy,
|
|
1122
|
+
distinct,
|
|
1123
|
+
}: {
|
|
1124
|
+
name: string;
|
|
1125
|
+
key1?: string;
|
|
1126
|
+
key2?: string;
|
|
1127
|
+
first?: number;
|
|
1128
|
+
after?: string;
|
|
1129
|
+
last?: number;
|
|
1130
|
+
before?: string;
|
|
1131
|
+
orderBy?: OrderBy;
|
|
1132
|
+
distinct?: boolean;
|
|
1133
|
+
}): Promise<ConnectionResponse<Schema>> {
|
|
1134
|
+
return await this.suiIndexerClient.getStorage({
|
|
1135
|
+
name,
|
|
1136
|
+
key1,
|
|
1137
|
+
key2,
|
|
1138
|
+
first,
|
|
1139
|
+
after,
|
|
1140
|
+
last,
|
|
1141
|
+
before,
|
|
1142
|
+
orderBy,
|
|
1143
|
+
distinct,
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
async subscribe(
|
|
1148
|
+
names: string[],
|
|
1149
|
+
handleData: (data: any) => void
|
|
1150
|
+
): Promise<WebSocket> {
|
|
1151
|
+
return this.suiIndexerClient.subscribe(names, handleData);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1088
1154
|
#processKeyParameter(tx: Transaction, keyType: string, value: any) {
|
|
1089
1155
|
// Handle basic types
|
|
1090
1156
|
switch (keyType.toLowerCase()) {
|
|
@@ -1228,6 +1294,10 @@ export class Dubhe {
|
|
|
1228
1294
|
return this.suiInteractor.currentClient;
|
|
1229
1295
|
}
|
|
1230
1296
|
|
|
1297
|
+
indexerClient() {
|
|
1298
|
+
return this.suiIndexerClient;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1231
1301
|
async getObject(objectId: string) {
|
|
1232
1302
|
return this.suiInteractor.getObject(objectId);
|
|
1233
1303
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
export class BaseError extends Error {
|
|
2
|
+
constructor(message: string, public code: number, public type: string) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = this.constructor.name;
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class HttpError extends BaseError {
|
|
9
|
+
constructor(message: string, code: number) {
|
|
10
|
+
super(message, code, 'ERROR_HTTP');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class GraphQLError extends BaseError {
|
|
15
|
+
constructor(message: string) {
|
|
16
|
+
super(message, 400, 'ERROR_GRAPHQL');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class ValidationError extends BaseError {
|
|
21
|
+
constructor(message: string) {
|
|
22
|
+
super(message, 400, 'ERROR_VALIDATION');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class NotFoundError extends BaseError {
|
|
27
|
+
constructor(message: string) {
|
|
28
|
+
super(message, 404, 'ERROR_NOT_FOUND');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ParseError extends BaseError {
|
|
33
|
+
constructor(message: string) {
|
|
34
|
+
super(message, 500, 'ERROR_PARSE');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type ErrorType =
|
|
39
|
+
| BaseError
|
|
40
|
+
| Error
|
|
41
|
+
| HttpError
|
|
42
|
+
| NotFoundError
|
|
43
|
+
| ValidationError
|
|
44
|
+
| ParseError
|
|
45
|
+
| GraphQLError;
|
|
46
|
+
|
|
47
|
+
export function handleError(error: ErrorType) {
|
|
48
|
+
if (!(error instanceof Error)) {
|
|
49
|
+
return {
|
|
50
|
+
code: 500,
|
|
51
|
+
error: {
|
|
52
|
+
message: 'Unknown error occurred',
|
|
53
|
+
type: `ERROR_UNKNOWN`,
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
switch (true) {
|
|
59
|
+
case error instanceof HttpError:
|
|
60
|
+
return {
|
|
61
|
+
code: (error as HttpError).code,
|
|
62
|
+
error: {
|
|
63
|
+
message: error.message,
|
|
64
|
+
type: 'ERROR_HTTP',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
case error instanceof GraphQLError:
|
|
69
|
+
return {
|
|
70
|
+
code: 400,
|
|
71
|
+
error: {
|
|
72
|
+
message: error.message,
|
|
73
|
+
type: 'ERROR_GRAPHQL',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
case error instanceof ValidationError:
|
|
78
|
+
return {
|
|
79
|
+
code: 400,
|
|
80
|
+
error: {
|
|
81
|
+
message: error.message,
|
|
82
|
+
type: 'ERROR_VALIDATION',
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
case error instanceof NotFoundError:
|
|
87
|
+
return {
|
|
88
|
+
code: 404,
|
|
89
|
+
error: {
|
|
90
|
+
message: error.message,
|
|
91
|
+
type: 'ERROR_NOT_FOUND',
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
case error instanceof ParseError:
|
|
96
|
+
return {
|
|
97
|
+
code: 500,
|
|
98
|
+
error: {
|
|
99
|
+
message: error.message,
|
|
100
|
+
type: 'ERROR_PARSE',
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
case error instanceof BaseError:
|
|
105
|
+
return {
|
|
106
|
+
code: (error as BaseError).code,
|
|
107
|
+
error: {
|
|
108
|
+
message: error.message,
|
|
109
|
+
type: (error as BaseError).type,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
default:
|
|
114
|
+
return {
|
|
115
|
+
code: 500,
|
|
116
|
+
error: {
|
|
117
|
+
message: error.message || 'Internal server error',
|
|
118
|
+
type: 'ERROR_UNKNOWN',
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { WebSocket } from 'ws';
|
|
2
|
+
import { BaseError, HttpError, GraphQLError, ParseError } from './errors';
|
|
3
|
+
|
|
4
|
+
export type FetchOptions = RequestInit & {
|
|
5
|
+
next?: {
|
|
6
|
+
revalidate?: boolean | number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export class Http {
|
|
11
|
+
private apiEndpoint: string;
|
|
12
|
+
private graphqlEndpoint: string;
|
|
13
|
+
private wsEndpoint: string;
|
|
14
|
+
private defaultOptions?: FetchOptions;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
apiEndpoint: string,
|
|
18
|
+
wsEndpoint: string,
|
|
19
|
+
private customFetch?: typeof fetch,
|
|
20
|
+
defaultOptions?: FetchOptions
|
|
21
|
+
) {
|
|
22
|
+
this.apiEndpoint = apiEndpoint;
|
|
23
|
+
this.graphqlEndpoint = apiEndpoint + '/graphql';
|
|
24
|
+
this.wsEndpoint = wsEndpoint;
|
|
25
|
+
this.defaultOptions = defaultOptions;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private getFetch() {
|
|
29
|
+
return this.customFetch || fetch;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async fetch(url: string): Promise<Response> {
|
|
33
|
+
try {
|
|
34
|
+
const fetchFn = this.getFetch();
|
|
35
|
+
const response = await fetchFn(url, {
|
|
36
|
+
...this.defaultOptions,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
throw new HttpError(
|
|
41
|
+
`HTTP error! status: ${response.status}`,
|
|
42
|
+
response.status
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return response;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof HttpError) {
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
throw new HttpError(`Failed to fetch: ${(error as Error).message}`, 500);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async fetchGraphql<T>({
|
|
56
|
+
query,
|
|
57
|
+
variables,
|
|
58
|
+
}: {
|
|
59
|
+
query: string;
|
|
60
|
+
variables?: any;
|
|
61
|
+
}): Promise<T> {
|
|
62
|
+
try {
|
|
63
|
+
const isFirstPage = variables?.after === 'first';
|
|
64
|
+
const fetchFn = this.getFetch();
|
|
65
|
+
console.log(query);
|
|
66
|
+
const response = await fetchFn(this.graphqlEndpoint, {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
Accept: 'application/json',
|
|
71
|
+
},
|
|
72
|
+
body: JSON.stringify({
|
|
73
|
+
query,
|
|
74
|
+
variables: {
|
|
75
|
+
...variables,
|
|
76
|
+
after: isFirstPage ? undefined : variables?.after,
|
|
77
|
+
},
|
|
78
|
+
}),
|
|
79
|
+
...this.defaultOptions,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const errorData = await response.json();
|
|
84
|
+
|
|
85
|
+
if (errorData.errors?.[0]?.message?.includes('Syntax Error')) {
|
|
86
|
+
throw new GraphQLError(
|
|
87
|
+
`GraphQL syntax error: ${errorData.errors[0].message}`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (errorData.errors?.length > 0) {
|
|
92
|
+
throw new GraphQLError(
|
|
93
|
+
errorData.errors[0].message || 'Unknown GraphQL error'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new HttpError(
|
|
98
|
+
`HTTP error: ${JSON.stringify(errorData)}`,
|
|
99
|
+
response.status
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
const data = await response.json();
|
|
103
|
+
|
|
104
|
+
if (data.errors) {
|
|
105
|
+
throw new GraphQLError(
|
|
106
|
+
data.errors[0]?.message || 'GraphQL query failed'
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return data.data;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.log(error);
|
|
113
|
+
if (error instanceof BaseError) {
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
if (error instanceof SyntaxError) {
|
|
117
|
+
throw new ParseError('Failed to parse JSON response');
|
|
118
|
+
}
|
|
119
|
+
throw new HttpError(
|
|
120
|
+
`Failed to fetch GraphQL: ${(error as Error).message}`,
|
|
121
|
+
500
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async subscribe(names: string[], handleData: (data: any) => void): Promise<WebSocket> {
|
|
127
|
+
const ws = new WebSocket(this.wsEndpoint);
|
|
128
|
+
|
|
129
|
+
ws.on('open', () => {
|
|
130
|
+
console.log('Connected to the WebSocket server');
|
|
131
|
+
// Subscribe to specific event names
|
|
132
|
+
const subscribeMessage = JSON.stringify({
|
|
133
|
+
type: 'subscribe',
|
|
134
|
+
names: names,
|
|
135
|
+
});
|
|
136
|
+
ws.send(subscribeMessage);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
ws.on('message', (data) => {
|
|
140
|
+
handleData(JSON.parse(data.toString()));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
ws.on('close', () => {
|
|
144
|
+
console.log('Disconnected from the WebSocket server');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
ws.on('error', (error) => {
|
|
148
|
+
console.error(`WebSocket error: ${error}`);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
return ws;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ERROR = {};
|