@remnawave/xtls-sdk 0.0.2 → 0.0.3
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 +164 -53
- package/build/tests/stats.spec.d.ts +2 -0
- package/build/tests/stats.spec.d.ts.map +1 -0
- package/build/tests/stats.spec.js +86 -0
- package/package.json +43 -4
package/README.md
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
-
# XTLS
|
|
1
|
+
# XTLS SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
4
5
|
|
|
5
|
-
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+

|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
A TypeScript SDK for interacting with XRAY (XTLS) Core via gRPC API. This package provides a type-safe interface for managing and monitoring your XRAY server, including statistics, user management, and connection information.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- 🔒 Type-safe API interactions
|
|
22
|
+
- 📊 Comprehensive statistics monitoring
|
|
23
|
+
- 👥 User management capabilities
|
|
24
|
+
- 🔄 Connection monitoring
|
|
25
|
+
- ⚡ Async/Promise-based API
|
|
26
|
+
- 📝 Detailed error handling
|
|
6
27
|
|
|
7
28
|
## Installation
|
|
8
29
|
|
|
@@ -10,95 +31,185 @@ This package provides a simple and type-safe way to retrieve various statistics
|
|
|
10
31
|
npm install @remnawave/xtls-sdk
|
|
11
32
|
# or
|
|
12
33
|
yarn add @remnawave/xtls-sdk
|
|
34
|
+
# or
|
|
35
|
+
pnpm add @remnawave/xtls-sdk
|
|
13
36
|
```
|
|
14
37
|
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
### Basic Setup
|
|
38
|
+
## Quick Start
|
|
18
39
|
|
|
19
40
|
```typescript
|
|
20
41
|
import { XtlsApi } from '@remnawave/xtls-sdk';
|
|
21
42
|
|
|
22
|
-
//
|
|
23
|
-
const
|
|
43
|
+
// Initialize the API client
|
|
44
|
+
const api = new XtlsApi('127.0.0.1', '10085');
|
|
45
|
+
|
|
46
|
+
// Example: Get system statistics
|
|
47
|
+
const stats = await api.stats.getSysStats();
|
|
48
|
+
if (stats.isOk) {
|
|
49
|
+
console.log('System Stats:', stats.data);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Core Features
|
|
54
|
+
|
|
55
|
+
### Statistics Management
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// System Statistics
|
|
59
|
+
const sysStats = await api.stats.getSysStats();
|
|
60
|
+
|
|
61
|
+
// User Statistics
|
|
62
|
+
const userStats = await api.stats.getUserStats('username');
|
|
63
|
+
const allUsers = await api.stats.getAllUsersStats();
|
|
64
|
+
const isOnline = await api.stats.getUserOnlineStatus('username');
|
|
65
|
+
|
|
66
|
+
// Traffic Statistics
|
|
67
|
+
const inbounds = await api.stats.getAllInboundsStats();
|
|
68
|
+
const outbounds = await api.stats.getAllOutboundsStats();
|
|
24
69
|
```
|
|
25
70
|
|
|
26
|
-
###
|
|
71
|
+
### Response Handling
|
|
27
72
|
|
|
28
|
-
|
|
73
|
+
All API methods return a standardized response format:
|
|
29
74
|
|
|
30
75
|
```typescript
|
|
31
|
-
|
|
76
|
+
interface ISdkResponse<T> {
|
|
77
|
+
isOk: boolean;
|
|
78
|
+
data?: T;
|
|
79
|
+
message?: string;
|
|
80
|
+
code?: string;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Example usage:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
const response = await api.stats.getSysStats();
|
|
32
88
|
|
|
33
89
|
if (response.isOk) {
|
|
34
|
-
|
|
90
|
+
// Success case
|
|
91
|
+
console.log('Stats:', response.data);
|
|
35
92
|
} else {
|
|
36
|
-
|
|
93
|
+
// Error case
|
|
94
|
+
console.error(`Error ${response.code}: ${response.message}`);
|
|
37
95
|
}
|
|
38
96
|
```
|
|
39
97
|
|
|
40
|
-
|
|
98
|
+
### Reset Options
|
|
99
|
+
|
|
100
|
+
Many methods support statistics reset functionality:
|
|
41
101
|
|
|
42
102
|
```typescript
|
|
43
|
-
// Get stats
|
|
44
|
-
const
|
|
103
|
+
// Get stats and reset counters
|
|
104
|
+
const stats = await api.stats.getUserStats('username', true);
|
|
105
|
+
```
|
|
45
106
|
|
|
46
|
-
|
|
47
|
-
const userStats = await xtlsApi.stats.getUserStats('username123');
|
|
107
|
+
## API Reference
|
|
48
108
|
|
|
49
|
-
|
|
50
|
-
const onlineStatus = await xtlsApi.stats.getUserOnlineStatus('username123');
|
|
51
|
-
```
|
|
109
|
+
### XtlsApi
|
|
52
110
|
|
|
53
|
-
|
|
111
|
+
Main client class for interacting with the XRAY server.
|
|
54
112
|
|
|
55
113
|
```typescript
|
|
56
|
-
|
|
57
|
-
|
|
114
|
+
const api = new XtlsApi(ip: string, port: string);
|
|
115
|
+
```
|
|
58
116
|
|
|
59
|
-
|
|
60
|
-
const inbound = await xtlsApi.stats.getInboundStats('http_in');
|
|
117
|
+
### HandlerService
|
|
61
118
|
|
|
62
|
-
|
|
63
|
-
const outbounds = await xtlsApi.stats.getAllOutboundsStats();
|
|
119
|
+
Service for managing inbound handlers and their users.
|
|
64
120
|
|
|
65
|
-
|
|
66
|
-
const outbound = await xtlsApi.stats.getOutboundStats('http_out');
|
|
67
|
-
```
|
|
121
|
+
#### User Management Methods
|
|
68
122
|
|
|
69
|
-
|
|
123
|
+
| Method | Description | Parameters |
|
|
124
|
+
| ------------------------------------------- | -------------------------------- | -------------------------------------------------------- |
|
|
125
|
+
| `getInboundUsers(tag: string)` | Get all users from an inbound | `tag`: Inbound handler tag |
|
|
126
|
+
| `getInboundUsersCount(tag: string)` | Get count of users in an inbound | `tag`: Inbound handler tag |
|
|
127
|
+
| `removeUser(tag: string, username: string)` | Remove a user from an inbound | `tag`: Inbound handler tag<br>`username`: User to remove |
|
|
70
128
|
|
|
71
|
-
|
|
129
|
+
#### Add User Methods
|
|
130
|
+
|
|
131
|
+
| Method | Description | Parameters |
|
|
132
|
+
| ------------------------------------------------------- | ------------------------- | ---------------------------------------------------------------- |
|
|
133
|
+
| `addTrojanUser(data: IAddTrojanUser)` | Add Trojan user | `data`: { tag, username, password, level } |
|
|
134
|
+
| `addVlessUser(data: IAddVlessUser)` | Add VLESS user | `data`: { tag, username, uuid, flow, level } |
|
|
135
|
+
| `addShadowsocksUser(data: IAddShadowsocksUser)` | Add Shadowsocks user | `data`: { tag, username, password, cipherType, ivCheck, level } |
|
|
136
|
+
| `addShadowsocks2022User(data: IAddShadowsocks2022User)` | Add Shadowsocks 2022 user | `data`: { tag, username, key, level } |
|
|
137
|
+
| `addSocksUser(data: IAddSocksUser)` | Add SOCKS user | `data`: { tag, username, socks_username, socks_password, level } |
|
|
138
|
+
| `addHttpUser(data: IAddHttpUser)` | Add HTTP user | `data`: { tag, username, http_username, http_password, level } |
|
|
139
|
+
|
|
140
|
+
Example usage:
|
|
72
141
|
|
|
73
142
|
```typescript
|
|
74
|
-
// Get
|
|
75
|
-
const
|
|
143
|
+
// Get all users in an inbound
|
|
144
|
+
const users = await api.handler.getInboundUsers('main-inbound');
|
|
145
|
+
if (users.isOk) {
|
|
146
|
+
console.log('Users:', users.data.users);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Add a new Trojan user
|
|
150
|
+
const newUser = await api.handler.addTrojanUser({
|
|
151
|
+
tag: 'main-inbound',
|
|
152
|
+
username: 'user@example.com',
|
|
153
|
+
password: 'secure-password',
|
|
154
|
+
level: 0,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Remove a user
|
|
158
|
+
const removed = await api.handler.removeUser('main-inbound', 'user@example.com');
|
|
159
|
+
|
|
160
|
+
// Get user count
|
|
161
|
+
const count = await api.handler.getInboundUsersCount('main-inbound');
|
|
162
|
+
if (count.isOk) {
|
|
163
|
+
console.log('Total users:', count.data);
|
|
164
|
+
}
|
|
76
165
|
```
|
|
77
166
|
|
|
78
|
-
|
|
167
|
+
### StatsService
|
|
79
168
|
|
|
80
|
-
|
|
169
|
+
Statistics management service.
|
|
81
170
|
|
|
82
|
-
|
|
171
|
+
| Method | Description | Parameters |
|
|
172
|
+
| ----------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------- |
|
|
173
|
+
| `getSysStats()` | Get system statistics | None |
|
|
174
|
+
| `getAllUsersStats(reset?: boolean)` | Get all users' statistics | `reset`: Reset stats after retrieval |
|
|
175
|
+
| `getUserStats(username: string, reset?: boolean)` | Get specific user statistics | `username`: Target user<br>`reset`: Reset stats after retrieval |
|
|
176
|
+
| `getUserOnlineStatus(username: string)` | Check user online status | `username`: Target user |
|
|
177
|
+
| `getAllInboundsStats(reset?: boolean)` | Get all inbound statistics | `reset`: Reset stats after retrieval |
|
|
178
|
+
| `getInboundStats(inbound: string, reset?: boolean)` | Get specific inbound statistics | `inbound`: Inbound tag<br>`reset`: Reset stats after retrieval |
|
|
179
|
+
| `getAllOutboundsStats(reset?: boolean)` | Get all outbound statistics | `reset`: Reset stats after retrieval |
|
|
180
|
+
| `getOutboundStats(outbound: string, reset?: boolean)` | Get specific outbound statistics | `outbound`: Outbound tag<br>`reset`: Reset stats after retrieval |
|
|
83
181
|
|
|
84
|
-
|
|
182
|
+
## Error Handling
|
|
183
|
+
|
|
184
|
+
The SDK provides detailed error information through the response object:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
try {
|
|
188
|
+
const response = await api.stats.getUserStats('username');
|
|
189
|
+
if (!response.isOk) {
|
|
190
|
+
console.error(`Operation failed: ${response.message}`);
|
|
191
|
+
console.error(`Error code: ${response.code}`);
|
|
192
|
+
}
|
|
193
|
+
} catch (error) {
|
|
194
|
+
console.error('Unexpected error:', error);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
# Contributors
|
|
85
199
|
|
|
86
|
-
|
|
87
|
-
- `getAllUsersStats(reset?: boolean)`: Get statistics for all users
|
|
88
|
-
- `getUserStats(username: string, reset?: boolean)`: Get statistics for a specific user
|
|
89
|
-
- `getUserOnlineStatus(username: string)`: Check if a user is currently online
|
|
90
|
-
- `getAllInboundsStats(reset?: boolean)`: Get statistics for all inbound connections
|
|
91
|
-
- `getInboundStats(inbound: string, reset?: boolean)`: Get statistics for a specific inbound connection
|
|
92
|
-
- `getAllOutboundsStats(reset?: boolean)`: Get statistics for all outbound connections
|
|
93
|
-
- `getOutboundStats(outbound: string, reset?: boolean)`: Get statistics for a specific outbound connection
|
|
200
|
+
We ❤️🔥 contributors! If you'd like to contribute, please check out our [Contributing Guidelines](CONTRIBUTING.md) and feel free to submit a pull request or open an issue.
|
|
94
201
|
|
|
95
|
-
|
|
202
|
+
Check [open issues](https://github.com/remnawave/xtls-sdk/issues) to help the progress of this project.
|
|
96
203
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
204
|
+
<p align="center">
|
|
205
|
+
Thanks to the all contributors who have helped improve XTLS SDK:
|
|
206
|
+
</p>
|
|
207
|
+
<p align="center">
|
|
208
|
+
<a href="https://github.com/remnawave/xtls-sdk/graphs/contributors">
|
|
209
|
+
<img src="https://contrib.rocks/image?repo=remnawave/xtls-sdk" />
|
|
210
|
+
</a>
|
|
211
|
+
</p>
|
|
101
212
|
|
|
102
213
|
## License
|
|
103
214
|
|
|
104
|
-
MIT
|
|
215
|
+
MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.spec.d.ts","sourceRoot":"","sources":["../../tests/stats.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../index");
|
|
4
|
+
describe('StatsService', () => {
|
|
5
|
+
const validIp = '127.0.0.1';
|
|
6
|
+
const validPort = '8080';
|
|
7
|
+
let api;
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
api = new index_1.XtlsApi(validIp, validPort);
|
|
10
|
+
});
|
|
11
|
+
describe('System Stats', () => {
|
|
12
|
+
it('should get system stats', async () => {
|
|
13
|
+
const response = await api.stats.getSysStats();
|
|
14
|
+
expect(response.isOk).toBe(true);
|
|
15
|
+
if (response.isOk) {
|
|
16
|
+
expect(response.data).toBeDefined();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('User Stats', () => {
|
|
21
|
+
const testUsername = 'testUser';
|
|
22
|
+
it('should get all users stats', async () => {
|
|
23
|
+
const response = await api.stats.getAllUsersStats();
|
|
24
|
+
expect(response.isOk).toBe(true);
|
|
25
|
+
if (response.isOk) {
|
|
26
|
+
expect(Array.isArray(response.data?.users)).toBe(true);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
it('should get all users stats with reset', async () => {
|
|
30
|
+
const response = await api.stats.getAllUsersStats(true);
|
|
31
|
+
expect(response.isOk).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
it('should get specific user stats', async () => {
|
|
34
|
+
const response = await api.stats.getUserStats(testUsername);
|
|
35
|
+
expect(response.isOk).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('should get user online status', async () => {
|
|
38
|
+
const response = await api.stats.getUserOnlineStatus(testUsername);
|
|
39
|
+
expect(response.isOk).toBe(true);
|
|
40
|
+
if (response.isOk) {
|
|
41
|
+
expect(typeof response.data?.online).toBe('boolean');
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('Inbound Stats', () => {
|
|
46
|
+
const testInbound = 'testInbound';
|
|
47
|
+
it('should get all inbounds stats', async () => {
|
|
48
|
+
const response = await api.stats.getAllInboundsStats();
|
|
49
|
+
expect(response.isOk).toBe(true);
|
|
50
|
+
if (response.isOk) {
|
|
51
|
+
expect(Array.isArray(response.data?.inbounds)).toBe(true);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it('should get specific inbound stats', async () => {
|
|
55
|
+
const response = await api.stats.getInboundStats(testInbound);
|
|
56
|
+
expect(response.isOk).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
it('should get all inbounds stats with reset', async () => {
|
|
59
|
+
const response = await api.stats.getAllInboundsStats(true);
|
|
60
|
+
expect(response.isOk).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
describe('Outbound Stats', () => {
|
|
64
|
+
const testOutbound = 'testOutbound';
|
|
65
|
+
it('should get all outbounds stats', async () => {
|
|
66
|
+
const response = await api.stats.getAllOutboundsStats();
|
|
67
|
+
expect(response.isOk).toBe(true);
|
|
68
|
+
if (response.isOk) {
|
|
69
|
+
expect(Array.isArray(response.data?.outbounds)).toBe(true);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
it('should get specific outbound stats', async () => {
|
|
73
|
+
const response = await api.stats.getOutboundStats(testOutbound);
|
|
74
|
+
expect(response.isOk).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
it('should get all outbounds stats with reset', async () => {
|
|
77
|
+
const response = await api.stats.getAllOutboundsStats(true);
|
|
78
|
+
expect(response.isOk).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
afterEach(async () => {
|
|
82
|
+
if (api?.channel) {
|
|
83
|
+
await api.channel.close();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnawave/xtls-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "A Typescript SDK for XRAY (XTLS) Core GRPC Api",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -9,11 +9,29 @@
|
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prepublish": "rm -rf build && tsc",
|
|
12
|
-
"build": "tsc"
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"test": "jest",
|
|
14
|
+
"test:watch": "jest --watch"
|
|
13
15
|
},
|
|
14
16
|
"author": "Remnawave",
|
|
15
17
|
"license": "MIT",
|
|
16
|
-
"keywords": [
|
|
18
|
+
"keywords": [
|
|
19
|
+
"xtls",
|
|
20
|
+
"grpc",
|
|
21
|
+
"sdk",
|
|
22
|
+
"xray core api",
|
|
23
|
+
"typescript",
|
|
24
|
+
"xray",
|
|
25
|
+
"xray-core",
|
|
26
|
+
"api",
|
|
27
|
+
"client",
|
|
28
|
+
"network",
|
|
29
|
+
"proxy",
|
|
30
|
+
"protocol",
|
|
31
|
+
"trojan",
|
|
32
|
+
"vless",
|
|
33
|
+
"vmess"
|
|
34
|
+
],
|
|
17
35
|
"dependencies": {
|
|
18
36
|
"long": "^5.2.3",
|
|
19
37
|
"nice-grpc": "^2.1.10",
|
|
@@ -21,8 +39,29 @@
|
|
|
21
39
|
"tar": "^7.4.3"
|
|
22
40
|
},
|
|
23
41
|
"devDependencies": {
|
|
42
|
+
"@types/jest": "^29.5.2",
|
|
24
43
|
"@types/node": "^22.9.0",
|
|
25
44
|
"grpc-tools": "^1.12.4",
|
|
26
|
-
"ts-
|
|
45
|
+
"ts-jest": "^29.1.0",
|
|
46
|
+
"jest": "^29.5.0",
|
|
47
|
+
"ts-proto": "^2.2.7",
|
|
48
|
+
"typescript": "^5.6.3"
|
|
49
|
+
},
|
|
50
|
+
"jest": {
|
|
51
|
+
"moduleFileExtensions": [
|
|
52
|
+
"js",
|
|
53
|
+
"json",
|
|
54
|
+
"ts"
|
|
55
|
+
],
|
|
56
|
+
"rootDir": ".",
|
|
57
|
+
"testRegex": ".*\\.spec\\.ts$",
|
|
58
|
+
"transform": {
|
|
59
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
60
|
+
},
|
|
61
|
+
"collectCoverageFrom": [
|
|
62
|
+
"**/*.(t|j)s"
|
|
63
|
+
],
|
|
64
|
+
"coverageDirectory": "./coverage",
|
|
65
|
+
"testEnvironment": "node"
|
|
27
66
|
}
|
|
28
67
|
}
|