@0xobelisk/client 0.4.7 → 1.2.0-pre.92
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 +550 -2
- package/dist/browser/obelisk-client.js +102 -0
- package/dist/browser/obelisk-client.js.LICENSE.txt +16 -0
- package/dist/browser/obelisk-client.js.map +1 -0
- package/dist/browser/obelisk-client.min.js +101 -0
- package/dist/browser/obelisk-client.min.js.map +1 -0
- package/dist/index.d.ts +27 -9
- package/dist/sui/client.d.ts +59 -0
- package/dist/sui/index.d.mts +150 -0
- package/dist/sui/index.d.ts +19 -0
- package/dist/sui/index.js +92 -0
- package/dist/sui/index.js.map +1 -0
- package/dist/sui/index.mjs +87 -0
- package/dist/sui/index.mjs.map +1 -0
- package/dist/sui/types.d.ts +84 -0
- package/package.json +60 -121
- package/src/index.ts +31 -9
- package/src/sui/client.test.ts +277 -0
- package/src/sui/client.ts +156 -0
- package/src/sui/index.ts +30 -0
- package/src/sui/types.ts +87 -0
- package/LICENSE +0 -92
- package/dist/index.js +0 -1287
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -1268
- package/dist/index.mjs.map +0 -1
- package/dist/libs/suiAccountManager/crypto.d.ts +0 -1
- package/dist/libs/suiAccountManager/index.d.ts +0 -35
- package/dist/libs/suiAccountManager/keypair.d.ts +0 -21
- package/dist/libs/suiAccountManager/util.d.ts +0 -29
- package/dist/libs/suiContractFactory/index.d.ts +0 -20
- package/dist/libs/suiContractFactory/types.d.ts +0 -49
- package/dist/libs/suiInteractor/defaultConfig.d.ts +0 -10
- package/dist/libs/suiInteractor/index.d.ts +0 -2
- package/dist/libs/suiInteractor/suiInteractor.d.ts +0 -205
- package/dist/libs/suiInteractor/util.d.ts +0 -1
- package/dist/libs/suiModel/index.d.ts +0 -2
- package/dist/libs/suiModel/suiOwnedObject.d.ts +0 -24
- package/dist/libs/suiModel/suiSharedObject.d.ts +0 -12
- package/dist/libs/suiTxBuilder/index.d.ts +0 -544
- package/dist/libs/suiTxBuilder/util.d.ts +0 -76
- package/dist/metadata/index.d.ts +0 -34
- package/dist/obelisk.d.ts +0 -2566
- package/dist/types/index.d.ts +0 -141
- package/dist/utils/index.d.ts +0 -3
- package/src/libs/suiAccountManager/crypto.ts +0 -7
- package/src/libs/suiAccountManager/index.ts +0 -72
- package/src/libs/suiAccountManager/keypair.ts +0 -38
- package/src/libs/suiAccountManager/util.ts +0 -70
- package/src/libs/suiContractFactory/index.ts +0 -120
- package/src/libs/suiContractFactory/types.ts +0 -54
- package/src/libs/suiInteractor/defaultConfig.ts +0 -32
- package/src/libs/suiInteractor/index.ts +0 -2
- package/src/libs/suiInteractor/suiInteractor.ts +0 -319
- package/src/libs/suiInteractor/util.ts +0 -2
- package/src/libs/suiModel/index.ts +0 -2
- package/src/libs/suiModel/suiOwnedObject.ts +0 -62
- package/src/libs/suiModel/suiSharedObject.ts +0 -33
- package/src/libs/suiTxBuilder/index.ts +0 -245
- package/src/libs/suiTxBuilder/util.ts +0 -84
- package/src/metadata/index.ts +0 -22
- package/src/obelisk.ts +0 -600
- package/src/types/index.ts +0 -205
- package/src/utils/index.ts +0 -23
package/package.json
CHANGED
|
@@ -1,149 +1,88 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@0xobelisk/client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0-pre.92",
|
|
4
|
+
"description": "Unified client creation layer for Dubhe framework with multi-chain support",
|
|
5
5
|
"keywords": [
|
|
6
|
+
"dubhe",
|
|
7
|
+
"client",
|
|
8
|
+
"blockchain",
|
|
6
9
|
"sui",
|
|
7
|
-
"
|
|
8
|
-
"move",
|
|
9
|
-
"blockchain"
|
|
10
|
+
"web3"
|
|
10
11
|
],
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"bugs": "https://github.com/0xobelisk/obelisk-engine/issues",
|
|
12
|
+
"homepage": "https://github.com/0xobelisk/dubhe/tree/main/packages/client#readme",
|
|
13
|
+
"bugs": "https://github.com/0xobelisk/dubhe/issues",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/0xobelisk/
|
|
16
|
+
"url": "https://github.com/0xobelisk/dubhe.git"
|
|
17
17
|
},
|
|
18
18
|
"license": "Apache-2.0",
|
|
19
|
-
"
|
|
20
|
-
"access": "public"
|
|
21
|
-
},
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=18"
|
|
24
|
-
},
|
|
25
|
-
"main": "./dist/index.js",
|
|
26
|
-
"module": "./dist/index.mjs",
|
|
27
|
-
"types": "./dist/index.d.ts",
|
|
19
|
+
"author": "team@obelisk.build",
|
|
28
20
|
"exports": {
|
|
29
|
-
"
|
|
30
|
-
"source": "./src/index.ts",
|
|
31
|
-
"import": "./dist/index.mjs",
|
|
32
|
-
"require": "./dist/index.js"
|
|
21
|
+
"./sui": {
|
|
22
|
+
"source": "./src/sui/index.ts",
|
|
23
|
+
"import": "./dist/sui/index.mjs",
|
|
24
|
+
"require": "./dist/sui/index.js",
|
|
25
|
+
"types": "./dist/sui/index.d.ts"
|
|
33
26
|
}
|
|
34
27
|
},
|
|
28
|
+
"browser": "./dist/browser/obelisk-client.min.js",
|
|
35
29
|
"files": [
|
|
36
30
|
"dist",
|
|
37
31
|
"src"
|
|
38
32
|
],
|
|
39
33
|
"dependencies": {
|
|
40
|
-
"
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"husky": "^8.0.3",
|
|
46
|
-
"keccak256": "^1.0.6",
|
|
47
|
-
"process": "^0.11.10",
|
|
48
|
-
"superstruct": "^1.0.3",
|
|
49
|
-
"tmp": "^0.2.1",
|
|
50
|
-
"ts-retry-promise": "^0.7.0"
|
|
51
|
-
},
|
|
52
|
-
"peerDependencies": {
|
|
53
|
-
"@mysten/sui.js": "^0.41.0"
|
|
34
|
+
"dotenv": "^17.2.3",
|
|
35
|
+
"@0xobelisk/ecs": "1.2.0-pre.92",
|
|
36
|
+
"@0xobelisk/graphql-client": "1.2.0-pre.92",
|
|
37
|
+
"@0xobelisk/grpc-client": "1.2.0-pre.92",
|
|
38
|
+
"@0xobelisk/sui-client": "1.2.0-pre.92"
|
|
54
39
|
},
|
|
55
40
|
"devDependencies": {
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"@
|
|
59
|
-
"@
|
|
60
|
-
"@
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"lint-staged": "^13.2.3",
|
|
68
|
-
"prettier": "^2.8.8",
|
|
69
|
-
"ts-node": "^10.9.1",
|
|
70
|
-
"tsconfig-paths": "^4.2.0",
|
|
41
|
+
"@types/node": "^20.8.7",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^6.8.0",
|
|
43
|
+
"@typescript-eslint/parser": "^6.8.0",
|
|
44
|
+
"@vitest/coverage-v8": "^1.0.4",
|
|
45
|
+
"@vitest/ui": "^1.0.4",
|
|
46
|
+
"eslint": "^9.0.0",
|
|
47
|
+
"eslint-config-prettier": "^9.1.0",
|
|
48
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
49
|
+
"prettier": "3.3.3",
|
|
50
|
+
"terser-webpack-plugin": "^5.3.10",
|
|
51
|
+
"ts-loader": "^9.5.1",
|
|
71
52
|
"tsup": "^7.1.0",
|
|
72
|
-
"
|
|
73
|
-
"typescript": "^5.
|
|
53
|
+
"tsx": "^4.20.6",
|
|
54
|
+
"typescript": "^5.2.2",
|
|
55
|
+
"vitest": "^1.0.4",
|
|
56
|
+
"webpack": "^5.94.0",
|
|
57
|
+
"webpack-cli": "^5.1.4"
|
|
74
58
|
},
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"pnpm run format:fix",
|
|
78
|
-
"pnpm run lint:fix"
|
|
79
|
-
],
|
|
80
|
-
"**/*.json|md": [
|
|
81
|
-
"pnpm run format:fix"
|
|
82
|
-
]
|
|
83
|
-
},
|
|
84
|
-
"commitlint": {
|
|
85
|
-
"extends": [
|
|
86
|
-
"@commitlint/config-conventional"
|
|
87
|
-
]
|
|
88
|
-
},
|
|
89
|
-
"prettier": {
|
|
90
|
-
"trailingComma": "es5",
|
|
91
|
-
"tabWidth": 2,
|
|
92
|
-
"semi": true,
|
|
93
|
-
"singleQuote": true,
|
|
94
|
-
"useTabs": false,
|
|
95
|
-
"quoteProps": "as-needed",
|
|
96
|
-
"bracketSpacing": true,
|
|
97
|
-
"arrowParens": "always",
|
|
98
|
-
"endOfLine": "lf"
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
99
61
|
},
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"env": {
|
|
103
|
-
"browser": true,
|
|
104
|
-
"node": true,
|
|
105
|
-
"es2022": true
|
|
106
|
-
},
|
|
107
|
-
"extends": [
|
|
108
|
-
"eslint:recommended",
|
|
109
|
-
"plugin:@typescript-eslint/eslint-recommended",
|
|
110
|
-
"plugin:prettier/recommended"
|
|
111
|
-
],
|
|
112
|
-
"plugins": [
|
|
113
|
-
"@typescript-eslint",
|
|
114
|
-
"prettier"
|
|
115
|
-
],
|
|
116
|
-
"parser": "@typescript-eslint/parser",
|
|
117
|
-
"rules": {
|
|
118
|
-
"prettier/prettier": "warn",
|
|
119
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
120
|
-
"no-unused-vars": "off",
|
|
121
|
-
"@typescript-eslint/no-unused-vars": [
|
|
122
|
-
"error",
|
|
123
|
-
{
|
|
124
|
-
"argsIgnorePattern": "^_",
|
|
125
|
-
"varsIgnorePattern": "^_",
|
|
126
|
-
"caughtErrorsIgnorePattern": "^_"
|
|
127
|
-
}
|
|
128
|
-
]
|
|
129
|
-
}
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public"
|
|
130
64
|
},
|
|
131
65
|
"scripts": {
|
|
132
|
-
"
|
|
133
|
-
"build": "
|
|
134
|
-
"build:
|
|
66
|
+
"build": "npm run build:types && npm run build:tsup && npm run build:browser",
|
|
67
|
+
"build:browser": "webpack --mode production",
|
|
68
|
+
"build:browser:dev": "webpack --mode development",
|
|
69
|
+
"build:tsup": "tsup",
|
|
135
70
|
"build:types": "tsc --build",
|
|
136
|
-
"
|
|
137
|
-
"
|
|
71
|
+
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
|
72
|
+
"format": "prettier --write .",
|
|
73
|
+
"format:check": "prettier --check .",
|
|
74
|
+
"format:fix": "prettier --write '**/*.{ts,json,md}'",
|
|
75
|
+
"lint": "eslint . --ext .ts",
|
|
76
|
+
"serve": "python3 -m http.server 8080",
|
|
77
|
+
"test": "vitest run",
|
|
78
|
+
"test:coverage": "vitest run --coverage",
|
|
79
|
+
"test:typecheck": "tsc --noEmit",
|
|
80
|
+
"test:ui": "vitest --ui",
|
|
81
|
+
"test:watch": "vitest watch",
|
|
82
|
+
"type-check": "tsc --noEmit",
|
|
83
|
+
"validate": "pnpm format:check && pnpm type-check && pnpm test",
|
|
138
84
|
"watch": "pnpm run clean & pnpm run watch:types & pnpm run watch:tsup",
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"format:fix": "prettier --ignore-path 'dist/* docs/*' --write '**/*.{ts,json,md}'",
|
|
142
|
-
"lint:fix": "eslint . --ignore-pattern dist --ext .ts --fix",
|
|
143
|
-
"commit": "commit",
|
|
144
|
-
"doc": "typedoc --out docs src/index.ts",
|
|
145
|
-
"chalk": "^5.0.1",
|
|
146
|
-
"prettier": "^2.8.4",
|
|
147
|
-
"prettier-plugin-rust": "^0.1.9"
|
|
85
|
+
"watch:tsup": "tsup --watch",
|
|
86
|
+
"watch:types": "tsc --watch"
|
|
148
87
|
}
|
|
149
88
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @0xobelisk/client - Unified Client Creation Layer for Dubhe Framework
|
|
3
|
+
*
|
|
4
|
+
* This package provides a unified interface for creating blockchain clients
|
|
5
|
+
* across different chains. Currently supports Sui, with more chains coming soon.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* - For Sui: import from '@0xobelisk/client/sui'
|
|
9
|
+
* - For Aptos: import from '@0xobelisk/client/aptos' (coming soon)
|
|
10
|
+
* - For Initia: import from '@0xobelisk/client/initia' (coming soon)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createClient } from '@0xobelisk/client/sui';
|
|
15
|
+
*
|
|
16
|
+
* const client = createClient({
|
|
17
|
+
* network: 'devnet',
|
|
18
|
+
* packageId: '0x123...',
|
|
19
|
+
* metadata: contractMetadata,
|
|
20
|
+
* credentials: { secretKey: '...' }
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Main entry point - currently redirects to Sui
|
|
26
|
+
// In the future, this could export a chain-agnostic interface
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Note: Import chain-specific clients from their subpaths:
|
|
30
|
+
* - '@0xobelisk/client/sui'
|
|
31
|
+
*/
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { createClient, isNetworkType, validateClientConfig } from './client';
|
|
3
|
+
import type { ClientConfig } from './types';
|
|
4
|
+
|
|
5
|
+
// Mock all dependencies
|
|
6
|
+
vi.mock('@0xobelisk/sui-client', () => ({
|
|
7
|
+
Dubhe: vi.fn(function (this: any, config) {
|
|
8
|
+
this.networkType = config.networkType;
|
|
9
|
+
this.packageId = config.packageId;
|
|
10
|
+
this.tx = {};
|
|
11
|
+
this.query = {};
|
|
12
|
+
this.getAddress = () => '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
|
|
13
|
+
return this;
|
|
14
|
+
})
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
vi.mock('@0xobelisk/graphql-client', () => ({
|
|
18
|
+
createDubheGraphqlClient: vi.fn((config) => ({
|
|
19
|
+
endpoint: config.endpoint,
|
|
20
|
+
query: vi.fn(),
|
|
21
|
+
subscribe: vi.fn()
|
|
22
|
+
}))
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
vi.mock('@0xobelisk/grpc-client', () => ({
|
|
26
|
+
DubheGrpcClient: vi.fn(function (this: any, config) {
|
|
27
|
+
this.baseUrl = config.baseUrl;
|
|
28
|
+
this.getEntities = vi.fn();
|
|
29
|
+
this.getEntity = vi.fn();
|
|
30
|
+
return this;
|
|
31
|
+
})
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
vi.mock('@0xobelisk/ecs', () => ({
|
|
35
|
+
createECSWorld: vi.fn(() => ({
|
|
36
|
+
getEntities: vi.fn(() => []),
|
|
37
|
+
getEntity: vi.fn(),
|
|
38
|
+
subscribe: vi.fn()
|
|
39
|
+
}))
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
describe('createClient', () => {
|
|
43
|
+
const mockMetadata = {
|
|
44
|
+
name: 'test-package',
|
|
45
|
+
version: '1.0.0',
|
|
46
|
+
schemas: {}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const validConfig: ClientConfig = {
|
|
50
|
+
network: 'devnet',
|
|
51
|
+
packageId: '0x123',
|
|
52
|
+
metadata: mockMetadata
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
vi.clearAllMocks();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterEach(() => {
|
|
60
|
+
vi.resetAllMocks();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('Basic functionality', () => {
|
|
64
|
+
it('should create client with minimal valid config', () => {
|
|
65
|
+
const client = createClient(validConfig);
|
|
66
|
+
|
|
67
|
+
expect(client).toBeDefined();
|
|
68
|
+
expect(client.contract).toBeDefined();
|
|
69
|
+
expect(client.graphqlClient).toBeDefined();
|
|
70
|
+
expect(client.grpcClient).toBeDefined();
|
|
71
|
+
expect(client.ecsWorld).toBeDefined();
|
|
72
|
+
expect(client.metadata).toBe(mockMetadata);
|
|
73
|
+
expect(client.network).toBe('devnet');
|
|
74
|
+
expect(client.packageId).toBe('0x123');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should create client with full config', () => {
|
|
78
|
+
const fullConfig: ClientConfig = {
|
|
79
|
+
...validConfig,
|
|
80
|
+
credentials: {
|
|
81
|
+
secretKey: 'test-secret-key',
|
|
82
|
+
mnemonics: 'test mnemonics'
|
|
83
|
+
},
|
|
84
|
+
endpoints: {
|
|
85
|
+
fullnodeUrls: ['https://fullnode.devnet.sui.io'],
|
|
86
|
+
graphql: 'http://localhost:4000/graphql',
|
|
87
|
+
websocket: 'ws://localhost:4000/graphql',
|
|
88
|
+
grpc: 'http://localhost:8080'
|
|
89
|
+
},
|
|
90
|
+
dubheMetadata: {
|
|
91
|
+
schemas: ['Counter'],
|
|
92
|
+
systems: ['counter_system']
|
|
93
|
+
},
|
|
94
|
+
dubheSchemaId: '0x456',
|
|
95
|
+
options: {
|
|
96
|
+
enableBatchOptimization: true,
|
|
97
|
+
cacheTimeout: 10000,
|
|
98
|
+
debounceMs: 200,
|
|
99
|
+
reconnectOnError: true
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const client = createClient(fullConfig);
|
|
104
|
+
|
|
105
|
+
expect(client).toBeDefined();
|
|
106
|
+
expect(client.dubheSchemaId).toBe('0x456');
|
|
107
|
+
expect(client.options?.enableBatchOptimization).toBe(true);
|
|
108
|
+
expect(client.options?.cacheTimeout).toBe(10000);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should use default endpoints when not provided', () => {
|
|
112
|
+
const client = createClient(validConfig);
|
|
113
|
+
|
|
114
|
+
// The GraphQL and gRPC clients should be created with default endpoints
|
|
115
|
+
expect(client.graphqlClient).toBeDefined();
|
|
116
|
+
expect(client.grpcClient).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should return address from contract', () => {
|
|
120
|
+
const client = createClient(validConfig);
|
|
121
|
+
|
|
122
|
+
expect(client.address).toBe(
|
|
123
|
+
'0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef'
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('Configuration validation', () => {
|
|
129
|
+
it('should throw error when network is missing', () => {
|
|
130
|
+
const invalidConfig = {
|
|
131
|
+
packageId: '0x123',
|
|
132
|
+
metadata: mockMetadata
|
|
133
|
+
} as ClientConfig;
|
|
134
|
+
|
|
135
|
+
expect(() => createClient(invalidConfig)).toThrow('ClientConfig: network is required');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should throw error when packageId is missing', () => {
|
|
139
|
+
const invalidConfig = {
|
|
140
|
+
network: 'devnet',
|
|
141
|
+
metadata: mockMetadata
|
|
142
|
+
} as ClientConfig;
|
|
143
|
+
|
|
144
|
+
expect(() => createClient(invalidConfig)).toThrow('ClientConfig: packageId is required');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should throw error when metadata is missing', () => {
|
|
148
|
+
const invalidConfig = {
|
|
149
|
+
network: 'devnet',
|
|
150
|
+
packageId: '0x123'
|
|
151
|
+
} as ClientConfig;
|
|
152
|
+
|
|
153
|
+
expect(() => createClient(invalidConfig)).toThrow('ClientConfig: metadata is required');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('Options handling', () => {
|
|
158
|
+
it('should use default options when not provided', () => {
|
|
159
|
+
const client = createClient(validConfig);
|
|
160
|
+
|
|
161
|
+
// Default options should be applied in the ecsWorld creation
|
|
162
|
+
expect(client.ecsWorld).toBeDefined();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('should respect custom options', () => {
|
|
166
|
+
const configWithOptions: ClientConfig = {
|
|
167
|
+
...validConfig,
|
|
168
|
+
options: {
|
|
169
|
+
enableBatchOptimization: false,
|
|
170
|
+
cacheTimeout: 15000,
|
|
171
|
+
debounceMs: 500,
|
|
172
|
+
reconnectOnError: false
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const client = createClient(configWithOptions);
|
|
177
|
+
|
|
178
|
+
expect(client.options).toEqual({
|
|
179
|
+
enableBatchOptimization: false,
|
|
180
|
+
cacheTimeout: 15000,
|
|
181
|
+
debounceMs: 500,
|
|
182
|
+
reconnectOnError: false
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
describe('isNetworkType', () => {
|
|
189
|
+
it('should return true for valid network types', () => {
|
|
190
|
+
expect(isNetworkType('mainnet')).toBe(true);
|
|
191
|
+
expect(isNetworkType('testnet')).toBe(true);
|
|
192
|
+
expect(isNetworkType('devnet')).toBe(true);
|
|
193
|
+
expect(isNetworkType('localnet')).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should return false for invalid network types', () => {
|
|
197
|
+
expect(isNetworkType('invalid')).toBe(false);
|
|
198
|
+
expect(isNetworkType('production')).toBe(false);
|
|
199
|
+
expect(isNetworkType('')).toBe(false);
|
|
200
|
+
expect(isNetworkType('MAINNET')).toBe(false); // Case sensitive
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe('validateClientConfig', () => {
|
|
205
|
+
const mockMetadata = {
|
|
206
|
+
name: 'test-package',
|
|
207
|
+
version: '1.0.0',
|
|
208
|
+
schemas: {}
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
it('should validate correct config without throwing', () => {
|
|
212
|
+
const validConfig: Partial<ClientConfig> = {
|
|
213
|
+
network: 'devnet',
|
|
214
|
+
packageId: '0x123',
|
|
215
|
+
metadata: mockMetadata
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
expect(() => validateClientConfig(validConfig)).not.toThrow();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should throw when network is missing', () => {
|
|
222
|
+
const config = {
|
|
223
|
+
packageId: '0x123',
|
|
224
|
+
metadata: mockMetadata
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
expect(() => validateClientConfig(config)).toThrow(
|
|
228
|
+
'ClientConfig validation failed: network is required'
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should throw when network type is invalid', () => {
|
|
233
|
+
const config = {
|
|
234
|
+
network: 'invalid-network' as ClientConfig['network'],
|
|
235
|
+
packageId: '0x123',
|
|
236
|
+
metadata: mockMetadata
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
expect(() => validateClientConfig(config)).toThrow(
|
|
240
|
+
'ClientConfig validation failed: invalid network type'
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should throw when packageId is missing', () => {
|
|
245
|
+
const config: Partial<ClientConfig> = {
|
|
246
|
+
network: 'devnet',
|
|
247
|
+
metadata: mockMetadata
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
expect(() => validateClientConfig(config)).toThrow(
|
|
251
|
+
'ClientConfig validation failed: packageId is required'
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should throw when packageId is empty string', () => {
|
|
256
|
+
const config: Partial<ClientConfig> = {
|
|
257
|
+
network: 'devnet',
|
|
258
|
+
packageId: ' ',
|
|
259
|
+
metadata: mockMetadata
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
expect(() => validateClientConfig(config)).toThrow(
|
|
263
|
+
'ClientConfig validation failed: packageId must be a non-empty string'
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should throw when metadata is missing', () => {
|
|
268
|
+
const config: Partial<ClientConfig> = {
|
|
269
|
+
network: 'devnet',
|
|
270
|
+
packageId: '0x123'
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
expect(() => validateClientConfig(config)).toThrow(
|
|
274
|
+
'ClientConfig validation failed: metadata is required'
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Dubhe } from '@0xobelisk/sui-client';
|
|
2
|
+
import { createDubheGraphqlClient } from '@0xobelisk/graphql-client';
|
|
3
|
+
import { createECSWorld } from '@0xobelisk/ecs';
|
|
4
|
+
import { DubheGrpcClient } from '@0xobelisk/grpc-client';
|
|
5
|
+
import type { ClientConfig, DubheClientBundle } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create a Dubhe client bundle with all necessary instances
|
|
9
|
+
*
|
|
10
|
+
* This factory function creates and initializes:
|
|
11
|
+
* - Dubhe contract client for on-chain interactions
|
|
12
|
+
* - GraphQL client for querying indexed data
|
|
13
|
+
* - gRPC client for high-performance queries
|
|
14
|
+
* - ECS World for entity-component-system queries
|
|
15
|
+
*
|
|
16
|
+
* @param config - Client configuration matching @0xobelisk/react interface
|
|
17
|
+
* @returns DubheClientBundle with all initialized client instances
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { createClient } from '@0xobelisk/client/sui';
|
|
22
|
+
* import metadata from './metadata.json';
|
|
23
|
+
*
|
|
24
|
+
* const client = createClient({
|
|
25
|
+
* network: 'devnet',
|
|
26
|
+
* packageId: '0x123...',
|
|
27
|
+
* metadata,
|
|
28
|
+
* credentials: {
|
|
29
|
+
* secretKey: process.env.PRIVATE_KEY
|
|
30
|
+
* }
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Use the contract client
|
|
34
|
+
* const tx = new Transaction();
|
|
35
|
+
* await client.contract.tx.counter_system.inc({ tx });
|
|
36
|
+
*
|
|
37
|
+
* // Use GraphQL client
|
|
38
|
+
* const data = await client.graphqlClient.query(...);
|
|
39
|
+
*
|
|
40
|
+
* // Use ECS World
|
|
41
|
+
* const entities = client.ecsWorld.getEntities();
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function createClient(config: ClientConfig): DubheClientBundle {
|
|
45
|
+
// Validate required fields
|
|
46
|
+
if (!config.network) {
|
|
47
|
+
throw new Error('ClientConfig: network is required');
|
|
48
|
+
}
|
|
49
|
+
if (!config.packageId) {
|
|
50
|
+
throw new Error('ClientConfig: packageId is required');
|
|
51
|
+
}
|
|
52
|
+
if (!config.metadata) {
|
|
53
|
+
throw new Error('ClientConfig: metadata is required');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Initialize Dubhe contract client
|
|
57
|
+
const contract = new Dubhe({
|
|
58
|
+
networkType: config.network,
|
|
59
|
+
packageId: config.packageId,
|
|
60
|
+
metadata: config.metadata,
|
|
61
|
+
secretKey: config.credentials?.secretKey,
|
|
62
|
+
mnemonics: config.credentials?.mnemonics,
|
|
63
|
+
fullnodeUrls: config.endpoints?.fullnodeUrls
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Initialize GraphQL client with default localhost endpoint if not provided
|
|
67
|
+
const graphqlClient = createDubheGraphqlClient({
|
|
68
|
+
endpoint: config.endpoints?.graphql || 'http://localhost:4000/graphql',
|
|
69
|
+
subscriptionEndpoint: config.endpoints?.websocket || 'ws://localhost:4000/graphql',
|
|
70
|
+
dubheMetadata: config.dubheMetadata
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Initialize gRPC client with default localhost endpoint if not provided
|
|
74
|
+
const grpcClient = new DubheGrpcClient({
|
|
75
|
+
baseUrl: config.endpoints?.grpc || 'http://localhost:8080'
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Initialize ECS World (depends on GraphQL client)
|
|
79
|
+
const ecsWorld = createECSWorld(graphqlClient, {
|
|
80
|
+
dubheMetadata: config.dubheMetadata,
|
|
81
|
+
queryConfig: {
|
|
82
|
+
enableBatchOptimization: config.options?.enableBatchOptimization ?? true,
|
|
83
|
+
defaultCacheTimeout: config.options?.cacheTimeout ?? 5000
|
|
84
|
+
},
|
|
85
|
+
subscriptionConfig: {
|
|
86
|
+
defaultDebounceMs: config.options?.debounceMs ?? 100,
|
|
87
|
+
reconnectOnError: config.options?.reconnectOnError ?? true
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Get user address from contract
|
|
92
|
+
const address = contract.getAddress();
|
|
93
|
+
|
|
94
|
+
// Return complete client bundle
|
|
95
|
+
return {
|
|
96
|
+
contract,
|
|
97
|
+
graphqlClient,
|
|
98
|
+
grpcClient,
|
|
99
|
+
ecsWorld,
|
|
100
|
+
metadata: config.metadata,
|
|
101
|
+
network: config.network,
|
|
102
|
+
packageId: config.packageId,
|
|
103
|
+
dubheSchemaId: config.dubheSchemaId,
|
|
104
|
+
address,
|
|
105
|
+
options: config.options
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Type guard to check if a value is a valid NetworkType
|
|
111
|
+
*/
|
|
112
|
+
export function isNetworkType(value: string): value is ClientConfig['network'] {
|
|
113
|
+
return ['mainnet', 'testnet', 'devnet', 'localnet'].includes(value);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Helper function to validate client configuration
|
|
118
|
+
* Throws descriptive errors for invalid configurations
|
|
119
|
+
*/
|
|
120
|
+
export function validateClientConfig(
|
|
121
|
+
config: Partial<ClientConfig>
|
|
122
|
+
): asserts config is ClientConfig {
|
|
123
|
+
if (!config.network) {
|
|
124
|
+
throw new Error('ClientConfig validation failed: network is required');
|
|
125
|
+
}
|
|
126
|
+
if (!isNetworkType(config.network)) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`ClientConfig validation failed: invalid network type "${config.network}". ` +
|
|
129
|
+
'Must be one of: mainnet, testnet, devnet, localnet'
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
if (!config.packageId) {
|
|
133
|
+
throw new Error('ClientConfig validation failed: packageId is required');
|
|
134
|
+
}
|
|
135
|
+
if (typeof config.packageId !== 'string' || config.packageId.trim() === '') {
|
|
136
|
+
throw new Error('ClientConfig validation failed: packageId must be a non-empty string');
|
|
137
|
+
}
|
|
138
|
+
if (!config.metadata) {
|
|
139
|
+
throw new Error('ClientConfig validation failed: metadata is required');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create client with configuration validation
|
|
145
|
+
* Useful when working with external configuration sources
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const config = loadConfigFromFile(); // May be incomplete
|
|
150
|
+
* const client = createClientWithValidation(config); // Throws if invalid
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export function createClientWithValidation(config: Partial<ClientConfig>): DubheClientBundle {
|
|
154
|
+
validateClientConfig(config);
|
|
155
|
+
return createClient(config);
|
|
156
|
+
}
|