@0xobelisk/sui-client 1.0.6 → 1.0.8
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 +18 -1
- package/dist/index.js +338 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +345 -10
- 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/http/ws-adapter.d.ts +6 -0
- package/dist/libs/suiIndexerClient/index.d.ts +95 -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 +15 -10
- package/src/dubhe.ts +70 -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/http/ws-adapter.ts +36 -0
- package/src/libs/suiIndexerClient/index.ts +232 -0
- package/src/libs/suiIndexerClient/types.ts +0 -0
- package/src/libs/suiInteractor/defaultConfig.ts +6 -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 { WebSocketInstance } from './ws-adapter';
|
|
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<WebSocketInstance>;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ERROR: {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Http } from '../http';
|
|
2
|
+
export interface OrderDirection {
|
|
3
|
+
ASC: 'ASC';
|
|
4
|
+
DESC: 'DESC';
|
|
5
|
+
}
|
|
6
|
+
export interface OrderBy {
|
|
7
|
+
field: string;
|
|
8
|
+
direction: OrderDirection['ASC'] | OrderDirection['DESC'];
|
|
9
|
+
}
|
|
10
|
+
export interface PageInfo {
|
|
11
|
+
hasNextPage: boolean;
|
|
12
|
+
hasPreviousPage: boolean;
|
|
13
|
+
startCursor?: string;
|
|
14
|
+
endCursor?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Transaction {
|
|
17
|
+
id: number;
|
|
18
|
+
checkpoint: number;
|
|
19
|
+
digest: string;
|
|
20
|
+
created_at: 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
|
+
created_at: string;
|
|
32
|
+
updated_at: string;
|
|
33
|
+
}
|
|
34
|
+
export interface Event {
|
|
35
|
+
id: number;
|
|
36
|
+
checkpoint: string;
|
|
37
|
+
digest: string;
|
|
38
|
+
name: string;
|
|
39
|
+
value: string;
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ConnectionResponse<T> {
|
|
43
|
+
edges: Array<{
|
|
44
|
+
cursor: string;
|
|
45
|
+
node: T;
|
|
46
|
+
}>;
|
|
47
|
+
pageInfo: PageInfo;
|
|
48
|
+
}
|
|
49
|
+
export declare class SuiIndexerClient {
|
|
50
|
+
private http;
|
|
51
|
+
constructor(http: Http);
|
|
52
|
+
private fetchGraphql;
|
|
53
|
+
getTransactions(params?: {
|
|
54
|
+
first?: number;
|
|
55
|
+
after?: string;
|
|
56
|
+
last?: number;
|
|
57
|
+
before?: string;
|
|
58
|
+
checkpoint?: number;
|
|
59
|
+
orderBy?: OrderBy;
|
|
60
|
+
distinct?: boolean;
|
|
61
|
+
}): Promise<ConnectionResponse<Transaction>>;
|
|
62
|
+
getSchemas(params?: {
|
|
63
|
+
first?: number;
|
|
64
|
+
after?: string;
|
|
65
|
+
last?: number;
|
|
66
|
+
before?: string;
|
|
67
|
+
name?: string;
|
|
68
|
+
key1?: string;
|
|
69
|
+
key2?: string;
|
|
70
|
+
orderBy?: OrderBy;
|
|
71
|
+
distinct?: boolean;
|
|
72
|
+
}): Promise<ConnectionResponse<Schema>>;
|
|
73
|
+
getEvents(params?: {
|
|
74
|
+
first?: number;
|
|
75
|
+
after?: string;
|
|
76
|
+
last?: number;
|
|
77
|
+
before?: string;
|
|
78
|
+
name?: string;
|
|
79
|
+
checkpoint?: string;
|
|
80
|
+
orderBy?: OrderBy;
|
|
81
|
+
distinct?: boolean;
|
|
82
|
+
}): Promise<ConnectionResponse<Event>>;
|
|
83
|
+
getStorage({ name, key1, key2, first, after, last, before, orderBy, distinct, }: {
|
|
84
|
+
name: string;
|
|
85
|
+
key1?: string;
|
|
86
|
+
key2?: string;
|
|
87
|
+
first?: number;
|
|
88
|
+
after?: string;
|
|
89
|
+
last?: number;
|
|
90
|
+
before?: string;
|
|
91
|
+
orderBy?: OrderBy;
|
|
92
|
+
distinct?: boolean;
|
|
93
|
+
}): Promise<ConnectionResponse<Schema>>;
|
|
94
|
+
subscribe(names: string[], handleData: (data: any) => void): Promise<WebSocket>;
|
|
95
|
+
}
|
|
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.8",
|
|
4
4
|
"description": "Tookit for interacting with move eps framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sui",
|
|
@@ -37,32 +37,34 @@
|
|
|
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",
|
|
60
|
-
"
|
|
58
|
+
"ts-retry-promise": "^0.7.1",
|
|
59
|
+
"tweetnacl": "^1.0.3",
|
|
60
|
+
"valibot": "0.36.0",
|
|
61
|
+
"ws": "^8.18.0"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@commitlint/cli": "^18.0.0",
|
|
64
65
|
"@commitlint/config-conventional": "^18.0.0",
|
|
65
66
|
"@commitlint/prompt-cli": "^18.0.0",
|
|
67
|
+
"@types/jest": "^29.5.14",
|
|
66
68
|
"@types/node": "^20.8.7",
|
|
67
69
|
"@types/tmp": "^0.2.5",
|
|
68
70
|
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
|
@@ -71,13 +73,16 @@
|
|
|
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
|
+
"@types/ws": "^8.5.14"
|
|
81
86
|
},
|
|
82
87
|
"lint-staged": {
|
|
83
88
|
"**/*.ts": [
|
package/src/dubhe.ts
CHANGED
|
@@ -41,12 +41,20 @@ 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';
|
|
50
58
|
|
|
51
59
|
export function isUndefined(value?: unknown): value is undefined {
|
|
52
60
|
return value === undefined;
|
|
@@ -121,8 +129,10 @@ function createTx(
|
|
|
121
129
|
* @description This class is used to aggregate the tools that used to interact with SUI network.
|
|
122
130
|
*/
|
|
123
131
|
export class Dubhe {
|
|
132
|
+
public http: Http;
|
|
124
133
|
public accountManager: SuiAccountManager;
|
|
125
134
|
public suiInteractor: SuiInteractor;
|
|
135
|
+
public suiIndexerClient: SuiIndexerClient;
|
|
126
136
|
public contractFactory: SuiContractFactory;
|
|
127
137
|
public packageId: string | undefined;
|
|
128
138
|
public metadata: SuiMoveNormalizedModules | undefined;
|
|
@@ -237,13 +247,27 @@ export class Dubhe {
|
|
|
237
247
|
fullnodeUrls,
|
|
238
248
|
packageId,
|
|
239
249
|
metadata,
|
|
250
|
+
customFetch,
|
|
251
|
+
defaultOptions,
|
|
252
|
+
indexerUrl,
|
|
253
|
+
indexerWsUrl,
|
|
240
254
|
}: DubheParams = {}) {
|
|
255
|
+
networkType = networkType ?? 'mainnet';
|
|
256
|
+
|
|
257
|
+
const defaultParams = getDefaultURL(networkType);
|
|
258
|
+
|
|
241
259
|
// Init the account manager
|
|
242
260
|
this.accountManager = new SuiAccountManager({ mnemonics, secretKey });
|
|
243
261
|
// Init the rpc provider
|
|
244
|
-
fullnodeUrls = fullnodeUrls || [
|
|
262
|
+
fullnodeUrls = fullnodeUrls || [defaultParams.fullNode];
|
|
245
263
|
this.suiInteractor = new SuiInteractor(fullnodeUrls, networkType);
|
|
246
264
|
|
|
265
|
+
indexerUrl = indexerUrl || defaultParams.indexerUrl;
|
|
266
|
+
indexerWsUrl = indexerWsUrl || convertHttpToWebSocket(indexerUrl);
|
|
267
|
+
this.http = new Http(indexerUrl, indexerWsUrl, customFetch, defaultOptions);
|
|
268
|
+
|
|
269
|
+
this.suiIndexerClient = new SuiIndexerClient(this.http);
|
|
270
|
+
|
|
247
271
|
this.packageId = packageId ? normalizePackageId(packageId) : undefined;
|
|
248
272
|
if (metadata !== undefined) {
|
|
249
273
|
this.metadata = metadata as SuiMoveNormalizedModules;
|
|
@@ -1085,6 +1109,47 @@ export class Dubhe {
|
|
|
1085
1109
|
});
|
|
1086
1110
|
}
|
|
1087
1111
|
|
|
1112
|
+
async getStorage({
|
|
1113
|
+
name,
|
|
1114
|
+
key1,
|
|
1115
|
+
key2,
|
|
1116
|
+
first,
|
|
1117
|
+
after,
|
|
1118
|
+
last,
|
|
1119
|
+
before,
|
|
1120
|
+
orderBy,
|
|
1121
|
+
distinct,
|
|
1122
|
+
}: {
|
|
1123
|
+
name: string;
|
|
1124
|
+
key1?: string;
|
|
1125
|
+
key2?: string;
|
|
1126
|
+
first?: number;
|
|
1127
|
+
after?: string;
|
|
1128
|
+
last?: number;
|
|
1129
|
+
before?: string;
|
|
1130
|
+
orderBy?: OrderBy;
|
|
1131
|
+
distinct?: boolean;
|
|
1132
|
+
}): Promise<ConnectionResponse<Schema>> {
|
|
1133
|
+
return await this.suiIndexerClient.getStorage({
|
|
1134
|
+
name,
|
|
1135
|
+
key1,
|
|
1136
|
+
key2,
|
|
1137
|
+
first,
|
|
1138
|
+
after,
|
|
1139
|
+
last,
|
|
1140
|
+
before,
|
|
1141
|
+
orderBy,
|
|
1142
|
+
distinct,
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
async subscribe(
|
|
1147
|
+
names: string[],
|
|
1148
|
+
handleData: (data: any) => void
|
|
1149
|
+
): Promise<WebSocket> {
|
|
1150
|
+
return this.suiIndexerClient.subscribe(names, handleData);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1088
1153
|
#processKeyParameter(tx: Transaction, keyType: string, value: any) {
|
|
1089
1154
|
// Handle basic types
|
|
1090
1155
|
switch (keyType.toLowerCase()) {
|
|
@@ -1228,6 +1293,10 @@ export class Dubhe {
|
|
|
1228
1293
|
return this.suiInteractor.currentClient;
|
|
1229
1294
|
}
|
|
1230
1295
|
|
|
1296
|
+
indexerClient() {
|
|
1297
|
+
return this.suiIndexerClient;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1231
1300
|
async getObject(objectId: string) {
|
|
1232
1301
|
return this.suiInteractor.getObject(objectId);
|
|
1233
1302
|
}
|
|
@@ -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 { BaseError, HttpError, GraphQLError, ParseError } from './errors';
|
|
2
|
+
import { createWebSocketClient, WebSocketInstance } from './ws-adapter';
|
|
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
|
+
const response = await fetchFn(this.graphqlEndpoint, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Content-Type': 'application/json',
|
|
69
|
+
Accept: 'application/json',
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
query,
|
|
73
|
+
variables: {
|
|
74
|
+
...variables,
|
|
75
|
+
after: isFirstPage ? undefined : variables?.after,
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
...this.defaultOptions,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
const errorData = await response.json();
|
|
83
|
+
|
|
84
|
+
if (errorData.errors?.[0]?.message?.includes('Syntax Error')) {
|
|
85
|
+
throw new GraphQLError(
|
|
86
|
+
`GraphQL syntax error: ${errorData.errors[0].message}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (errorData.errors?.length > 0) {
|
|
91
|
+
throw new GraphQLError(
|
|
92
|
+
errorData.errors[0].message || 'Unknown GraphQL error'
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
throw new HttpError(
|
|
97
|
+
`HTTP error: ${JSON.stringify(errorData)}`,
|
|
98
|
+
response.status
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const data = await response.json();
|
|
102
|
+
|
|
103
|
+
if (data.errors) {
|
|
104
|
+
throw new GraphQLError(
|
|
105
|
+
data.errors[0]?.message || 'GraphQL query failed'
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return data.data;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof BaseError) {
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
if (error instanceof SyntaxError) {
|
|
115
|
+
throw new ParseError('Failed to parse JSON response');
|
|
116
|
+
}
|
|
117
|
+
throw new HttpError(
|
|
118
|
+
`Failed to fetch GraphQL: ${(error as Error).message}`,
|
|
119
|
+
500
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async subscribe(
|
|
125
|
+
names: string[],
|
|
126
|
+
handleData: (data: any) => void
|
|
127
|
+
): Promise<WebSocketInstance> {
|
|
128
|
+
const ws = createWebSocketClient(this.wsEndpoint);
|
|
129
|
+
|
|
130
|
+
ws.onopen = () => {
|
|
131
|
+
console.log('Connected to the WebSocket server');
|
|
132
|
+
const subscribeMessage = JSON.stringify({
|
|
133
|
+
type: 'subscribe',
|
|
134
|
+
names: names,
|
|
135
|
+
});
|
|
136
|
+
ws.send(subscribeMessage);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
ws.onmessage = (event) => {
|
|
140
|
+
handleData(JSON.parse(event.data.toString()));
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
ws.onclose = () => {
|
|
144
|
+
console.log('Disconnected from the WebSocket server');
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
ws.onerror = (error) => {
|
|
148
|
+
console.error(`WebSocket error:`, error);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return ws;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const ERROR = {};
|