x3ui-api 1.0.2 → 1.0.4
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 +306 -1
- package/package.json +2 -2
- package/src/core/ClientBuilder.d.ts +37 -0
- package/src/core/ClientBuilder.js +57 -0
- package/src/core/IndoundBuilder.d.ts +1 -0
- package/src/core/X3UIClient.d.ts +31 -0
- package/src/core/X3UIClient.js +147 -0
- package/src/index.d.ts +12 -148
- package/src/index.d.ts~ +185 -0
- package/src/index.js +2 -455
- package/src/protocols/vless/RealityBuilder.d.ts +69 -0
- package/src/protocols/vless/RealityBuilder.js +223 -0
- package/src/protocols/vless/RealityClientBuilder.d.ts +11 -0
- package/src/protocols/vless/RealityClientBuilder.js +25 -0
- package/src/protocols/vless/index.d.ts +9 -0
- package/src/protocols/vless/index.js +4 -0
- package/src/protocols/vmess/VmessBuilder.d.ts +77 -0
- package/src/protocols/vmess/VmessBuilder.js +189 -0
- package/src/protocols/vmess/VmessClientBuilder.d.ts +13 -0
- package/src/protocols/vmess/VmessClientBuilder.js +92 -0
- package/src/protocols/vmess/index.d.ts +9 -0
- package/src/protocols/vmess/index.js +4 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# x3ui-api
|
|
2
2
|
|
|
3
|
-
A Node.js client for interacting with the x3ui panel API.
|
|
3
|
+
A Node.js client for interacting with the x3ui panel API. This library provides a simple interface to manage X-UI inbounds, clients, and system statistics.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -8,6 +8,311 @@ A Node.js client for interacting with the x3ui panel API.
|
|
|
8
8
|
npm install x3ui-api
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Authentication with x3ui panel
|
|
14
|
+
- Get system statistics (CPU, memory, network, etc.)
|
|
15
|
+
- Manage inbounds (list, add, update, delete)
|
|
16
|
+
- Protocol-specific builders with fluent API:
|
|
17
|
+
- VLESS with Reality support
|
|
18
|
+
- VMess with HTTP Upgrade support
|
|
19
|
+
- Client management with fluent API
|
|
20
|
+
- TypeScript support
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### Basic Usage
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const X3UIClient = require('x3ui-api');
|
|
28
|
+
|
|
29
|
+
// Initialize client
|
|
30
|
+
const client = new X3UIClient({
|
|
31
|
+
baseURL: 'http://your-x3ui-panel.com:54321',
|
|
32
|
+
parseJSONSettings: true // Default: true - automatically parse JSON settings
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Login to panel
|
|
36
|
+
async function main() {
|
|
37
|
+
try {
|
|
38
|
+
const loginResult = await client.login('admin', 'password');
|
|
39
|
+
console.log('Login successful:', loginResult.success);
|
|
40
|
+
|
|
41
|
+
// Get system stats
|
|
42
|
+
const stats = await client.getSystemStats();
|
|
43
|
+
console.log('CPU Usage:', stats.cpu + '%');
|
|
44
|
+
console.log('Memory:', Math.round(stats.mem.current / stats.mem.total * 100) + '%');
|
|
45
|
+
|
|
46
|
+
// List all inbounds
|
|
47
|
+
const inbounds = await client.getInbounds();
|
|
48
|
+
console.log('Inbounds:', inbounds.length);
|
|
49
|
+
|
|
50
|
+
// First inbound details
|
|
51
|
+
if (inbounds.length > 0) {
|
|
52
|
+
console.log('First inbound:', inbounds[0].remark);
|
|
53
|
+
console.log('Protocol:', inbounds[0].protocol);
|
|
54
|
+
console.log('Port:', inbounds[0].port);
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error:', error.message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
main();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Creating a VMess Inbound
|
|
65
|
+
|
|
66
|
+
The library provides a convenient builder pattern for creating VMess inbounds with HTTP Upgrade:
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
const X3UIClient = require('x3ui-api');
|
|
70
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
71
|
+
|
|
72
|
+
const client = new X3UIClient({
|
|
73
|
+
baseURL: 'http://your-x3ui-panel.com:54321'
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
async function createVmessInbound() {
|
|
77
|
+
try {
|
|
78
|
+
await client.login('admin', 'password');
|
|
79
|
+
|
|
80
|
+
// Create a VMess inbound builder
|
|
81
|
+
let builder = new vmess.VmessBuilder(client)
|
|
82
|
+
.setRemark('My VMess Inbound')
|
|
83
|
+
.setPort(8443) // Optional, will auto-generate if not provided
|
|
84
|
+
.setHttpUpgradeHost('your-domain.com');
|
|
85
|
+
|
|
86
|
+
// Add a client
|
|
87
|
+
builder.addClient()
|
|
88
|
+
.setEmail('user@example.com')
|
|
89
|
+
.setTotalGB(100) // 100 GB traffic limit
|
|
90
|
+
.setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
91
|
+
|
|
92
|
+
// Build and add the inbound
|
|
93
|
+
const inbound = await builder.build();
|
|
94
|
+
const createdInbound = await client.addInbound(inbound);
|
|
95
|
+
|
|
96
|
+
// Update the builder with the server-returned inbound to get all metrics and IDs
|
|
97
|
+
builder = new vmess.VmessBuilder(client, createdInbound);
|
|
98
|
+
|
|
99
|
+
console.log('Inbound created:', createdInbound);
|
|
100
|
+
|
|
101
|
+
// Get connection link for the client (now with accurate server-assigned values)
|
|
102
|
+
const link = builder.getClientLink(0, 'your-server-ip.com');
|
|
103
|
+
console.log('Client connection link:', link);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Error creating inbound:', error.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
createVmessInbound();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Creating a VLESS Reality Inbound
|
|
113
|
+
|
|
114
|
+
The library provides a convenient builder pattern for creating Reality inbounds:
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const X3UIClient = require('x3ui-api');
|
|
118
|
+
const vless = require('x3ui-api/src/protocols/vless');
|
|
119
|
+
|
|
120
|
+
const client = new X3UIClient({
|
|
121
|
+
baseURL: 'http://your-x3ui-panel.com:54321'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
async function createRealityInbound() {
|
|
125
|
+
try {
|
|
126
|
+
await client.login('admin', 'password');
|
|
127
|
+
|
|
128
|
+
// Create a Reality inbound builder
|
|
129
|
+
let builder = new vless.RealityBuilder(client, {
|
|
130
|
+
remark: 'My Reality Inbound',
|
|
131
|
+
port: 8443 // Optional, will auto-generate if not provided
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Configure Reality settings
|
|
135
|
+
builder
|
|
136
|
+
.setDest('yahoo.com:443')
|
|
137
|
+
.setServerNames(['yahoo.com', 'www.yahoo.com'])
|
|
138
|
+
.setFingerprint('chrome');
|
|
139
|
+
|
|
140
|
+
// Add a client
|
|
141
|
+
builder.addClient()
|
|
142
|
+
.setEmail('user@example.com')
|
|
143
|
+
.setTotalGB(100) // 100 GB traffic limit
|
|
144
|
+
.setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
145
|
+
|
|
146
|
+
// Build and add the inbound
|
|
147
|
+
const inbound = await builder.build();
|
|
148
|
+
const createdInbound = await client.addInbound(inbound);
|
|
149
|
+
|
|
150
|
+
// Update the builder with the server-returned inbound to get all metrics and IDs
|
|
151
|
+
builder = new vless.RealityBuilder(client, createdInbound);
|
|
152
|
+
|
|
153
|
+
console.log('Inbound created:', createdInbound);
|
|
154
|
+
|
|
155
|
+
// Get connection link for the client (now with accurate server-assigned values)
|
|
156
|
+
const link = builder.getClientLink(0, 'your-server-ip.com');
|
|
157
|
+
console.log('Client connection link:', link);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error('Error creating inbound:', error.message);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Real-World Example
|
|
165
|
+
|
|
166
|
+
Here's a complete example showing how to create a VMess inbound and get the client link:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
const X3UIClient = require('x3ui-api');
|
|
170
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
171
|
+
|
|
172
|
+
const client = new X3UIClient({
|
|
173
|
+
baseURL: 'https://your-panel-url.com/path/',
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
(async () => {
|
|
177
|
+
await client.login('username', 'password');
|
|
178
|
+
|
|
179
|
+
// Create VMess builder with HTTP Upgrade
|
|
180
|
+
let vmessBuilder = new vmess.VmessBuilder(client)
|
|
181
|
+
.setRemark("My VMess Inbound")
|
|
182
|
+
.setHttpUpgradeHost("your-domain.com");
|
|
183
|
+
|
|
184
|
+
// Add the inbound to the server
|
|
185
|
+
const vmessInbound = await client.addInbound(await vmessBuilder.build());
|
|
186
|
+
|
|
187
|
+
// Create a new builder with the server-returned inbound to get accurate client links
|
|
188
|
+
vmessBuilder = new vmess.VmessBuilder(client, vmessInbound);
|
|
189
|
+
|
|
190
|
+
// Generate and output the client connection link
|
|
191
|
+
console.log(vmessBuilder.getClientLink(0, "your-domain.com"));
|
|
192
|
+
})();
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Managing Existing Inbounds
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
async function manageInbounds() {
|
|
199
|
+
try {
|
|
200
|
+
// Get all inbounds
|
|
201
|
+
const inbounds = await client.getInbounds();
|
|
202
|
+
|
|
203
|
+
if (inbounds.length > 0) {
|
|
204
|
+
// Get the first inbound
|
|
205
|
+
const inbound = inbounds[0];
|
|
206
|
+
const inboundId = inbound.id;
|
|
207
|
+
|
|
208
|
+
// IMPORTANT: When updating an inbound, always start with the complete inbound object
|
|
209
|
+
// to avoid losing data, then modify only what you need to change
|
|
210
|
+
|
|
211
|
+
// Example 1: Update the remark and enable status
|
|
212
|
+
inbound.remark = 'Updated Inbound Name';
|
|
213
|
+
inbound.enable = true;
|
|
214
|
+
|
|
215
|
+
// Send the complete updated inbound back to the server
|
|
216
|
+
await client.updateInbound(inboundId, inbound);
|
|
217
|
+
|
|
218
|
+
// Example 2: Add a new client to an existing inbound
|
|
219
|
+
if (inbound.protocol === 'vmess') {
|
|
220
|
+
// Create a builder with the existing inbound
|
|
221
|
+
const builder = new vmess.VmessBuilder(client, inbound);
|
|
222
|
+
|
|
223
|
+
// Add a new client
|
|
224
|
+
builder.addClient()
|
|
225
|
+
.setEmail('newuser@example.com')
|
|
226
|
+
.setTotalGB(50);
|
|
227
|
+
|
|
228
|
+
// Build the updated inbound and send it to the server
|
|
229
|
+
const updatedInbound = await builder.build();
|
|
230
|
+
await client.updateInbound(inboundId, updatedInbound);
|
|
231
|
+
|
|
232
|
+
// Get the link for the new client
|
|
233
|
+
const link = builder.getClientLink(builder.clients.length - 1, 'your-server-ip.com');
|
|
234
|
+
console.log('New client link:', link);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Example 3: Delete an inbound
|
|
238
|
+
await client.deleteInbound(inboundId);
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
console.error('Error managing inbounds:', error.message);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## API Reference
|
|
247
|
+
|
|
248
|
+
### X3UIClient
|
|
249
|
+
|
|
250
|
+
#### Constructor
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
new X3UIClient({
|
|
254
|
+
baseURL: string, // Required: URL to your x3ui panel
|
|
255
|
+
token?: string, // Optional: Authentication token (if already logged in)
|
|
256
|
+
parseJSONSettings?: boolean // Optional: Auto-parse JSON settings (default: true)
|
|
257
|
+
})
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Methods
|
|
261
|
+
|
|
262
|
+
- `login(username: string, password: string)` - Authenticate with the panel
|
|
263
|
+
- `getSystemStats()` - Get system statistics
|
|
264
|
+
- `getInbounds()` - Get all configured inbounds
|
|
265
|
+
- `addInbound(config)` - Add a new inbound and returns the created inbound with server-assigned values
|
|
266
|
+
- `updateInbound(id, config)` - Update an existing inbound with the complete inbound configuration
|
|
267
|
+
- `deleteInbound(id)` - Delete an inbound
|
|
268
|
+
- `getNewX25519Cert()` - Generate a new X25519 certificate
|
|
269
|
+
|
|
270
|
+
### Protocol Builders
|
|
271
|
+
|
|
272
|
+
The library provides protocol-specific builders for creating different types of inbounds:
|
|
273
|
+
|
|
274
|
+
#### VMess Builder
|
|
275
|
+
|
|
276
|
+
```javascript
|
|
277
|
+
const vmess = require('x3ui-api/src/protocols/vmess');
|
|
278
|
+
const builder = new vmess.VmessBuilder(client, options);
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Methods:
|
|
282
|
+
- `setPort(port)` - Set the port for the inbound
|
|
283
|
+
- `setRemark(remark)` - Set the name/remark for the inbound
|
|
284
|
+
- `setNetwork(network)` - Set the network type (default: 'httpupgrade')
|
|
285
|
+
- `setSecurity(security)` - Set the security type (default: 'none')
|
|
286
|
+
- `setHttpUpgradePath(path)` - Set the HTTP upgrade path
|
|
287
|
+
- `setHttpUpgradeHost(host)` - Set the HTTP upgrade host
|
|
288
|
+
- `setSniffing(enabled, destOverride, metadataOnly, routeOnly)` - Configure sniffing
|
|
289
|
+
- `setListenIP(ip)` - Set listen IP address
|
|
290
|
+
- `setExpiryTime(timestamp)` - Set inbound expiry time
|
|
291
|
+
- `addClient(options)` - Add a new client to the inbound
|
|
292
|
+
- `getClientLink(clientIndex, host, port)` - Get connection link for a client
|
|
293
|
+
- `build()` - Build the final inbound config
|
|
294
|
+
|
|
295
|
+
#### VLESS Reality Builder
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
const vless = require('x3ui-api/src/protocols/vless');
|
|
299
|
+
const builder = new vless.RealityBuilder(client, options);
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Methods:
|
|
303
|
+
- `setPort(port)` - Set the port for the inbound
|
|
304
|
+
- `setRemark(remark)` - Set the name/remark for the inbound
|
|
305
|
+
- `setDest(dest)` - Set the destination address (e.g., "yahoo.com:443")
|
|
306
|
+
- `setServerNames(names)` - Set server names for SNI
|
|
307
|
+
- `setKeyPair(privateKey, publicKey)` - Set Reality keypair
|
|
308
|
+
- `setShortIds(ids)` - Set short IDs for Reality
|
|
309
|
+
- `setFingerprint(fingerprint)` - Set browser fingerprint
|
|
310
|
+
- `setListenIP(ip)` - Set listen IP address
|
|
311
|
+
- `setExpiryTime(timestamp)` - Set inbound expiry time
|
|
312
|
+
- `addClient(options)` - Add a new client to the inbound
|
|
313
|
+
- `getClientLink(clientIndex, host)` - Get connection link for a client
|
|
314
|
+
- `build()` - Build the final inbound config
|
|
315
|
+
|
|
11
316
|
## License
|
|
12
317
|
|
|
13
318
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x3ui-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "API client for x3ui panel",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"author": "",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"axios": "^1.
|
|
14
|
+
"axios": "^1.8.2",
|
|
15
15
|
"form-data": "^4.0.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {ClientSettings, InboundConfig} from "../index";
|
|
2
|
+
import InboundBuilder from "./IndoundBuilder";
|
|
3
|
+
|
|
4
|
+
export default class ClientBuilder {
|
|
5
|
+
|
|
6
|
+
constructor(parent: InboundBuilder | InboundConfig);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Set client UUID. If not provided, will be auto-generated
|
|
10
|
+
*/
|
|
11
|
+
setId(id: string): this;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Set client email
|
|
15
|
+
*/
|
|
16
|
+
setEmail(email: string): this;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Set total traffic limit in GB
|
|
20
|
+
*/
|
|
21
|
+
setTotalGB(gb: number): this;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Set expiry time in unix timestamp
|
|
25
|
+
*/
|
|
26
|
+
setExpiryTime(timestamp: number): this;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Set Telegram ID
|
|
30
|
+
*/
|
|
31
|
+
setTgId(id: string): this;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build the client configuration
|
|
35
|
+
*/
|
|
36
|
+
build(): ClientSettings;
|
|
37
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const crypto = require("crypto");
|
|
2
|
+
|
|
3
|
+
module.exports = class ClientBuilder {
|
|
4
|
+
constructor(parent) {
|
|
5
|
+
this.parent = parent;
|
|
6
|
+
this.id = '';
|
|
7
|
+
this.flow = '';
|
|
8
|
+
this.email = '';
|
|
9
|
+
this.limitIp = 0;
|
|
10
|
+
this.totalGB = 0;
|
|
11
|
+
this.expiryTime = 0;
|
|
12
|
+
this.enable = true;
|
|
13
|
+
this.tgId = '';
|
|
14
|
+
this.subId = '';
|
|
15
|
+
this.reset = 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setId(id) {
|
|
19
|
+
this.id = id;
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setEmail(email) {
|
|
24
|
+
this.email = email;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
setTotalGB(gb) {
|
|
29
|
+
this.totalGB = gb;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setExpiryTime(timestamp) {
|
|
34
|
+
this.expiryTime = timestamp;
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setTgId(id) {
|
|
39
|
+
this.tgId = id;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
build() {
|
|
44
|
+
return {
|
|
45
|
+
id: this.id || crypto.randomUUID(),
|
|
46
|
+
flow: this.flow,
|
|
47
|
+
email: this.email || Math.random().toString(36).substring(2, 10),
|
|
48
|
+
limitIp: this.limitIp,
|
|
49
|
+
totalGB: this.totalGB,
|
|
50
|
+
expiryTime: this.expiryTime,
|
|
51
|
+
enable: this.enable,
|
|
52
|
+
tgId: this.tgId,
|
|
53
|
+
subId: this.subId || Math.random().toString(36).substring(2, 18),
|
|
54
|
+
reset: this.reset
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class InboundBuilder {}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {AxiosInstance} from "axios";
|
|
2
|
+
import {
|
|
3
|
+
InboundConfig,
|
|
4
|
+
LoginResponse,
|
|
5
|
+
SystemStats,
|
|
6
|
+
X3UIConfig
|
|
7
|
+
} from "../index";
|
|
8
|
+
|
|
9
|
+
export default class X3UIClient {
|
|
10
|
+
private client: AxiosInstance;
|
|
11
|
+
|
|
12
|
+
constructor(config: X3UIConfig);
|
|
13
|
+
|
|
14
|
+
login(username: string, password: string): Promise<LoginResponse>;
|
|
15
|
+
|
|
16
|
+
getSystemStats(): Promise<SystemStats>;
|
|
17
|
+
|
|
18
|
+
getInbounds(): Promise<InboundConfig[]>;
|
|
19
|
+
|
|
20
|
+
addInbound(config: Omit<InboundConfig, 'id'>): Promise<InboundConfig>;
|
|
21
|
+
|
|
22
|
+
updateInbound(id: number, config: Partial<InboundConfig>): Promise<void>;
|
|
23
|
+
|
|
24
|
+
deleteInbound(id: number): Promise<void>;
|
|
25
|
+
|
|
26
|
+
getInboundTraffic(id: number): Promise<{ up: number; down: number }>;
|
|
27
|
+
|
|
28
|
+
resetInboundTraffic(id: number): Promise<void>;
|
|
29
|
+
|
|
30
|
+
getNewX25519Cert(): Promise<{ privateKey: string; publicKey: string }>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const axios = require("axios");
|
|
2
|
+
|
|
3
|
+
module.exports = class X3UIClient {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.parseJSONSettings = config.parseJSONSettings || true;
|
|
6
|
+
this.client = axios.create({
|
|
7
|
+
baseURL: config.baseURL,
|
|
8
|
+
headers: config.token ? {
|
|
9
|
+
'Cookie': `lang=en-US; 3x-ui=${config.token}`,
|
|
10
|
+
} : {
|
|
11
|
+
'Cookie': 'lang=en-US'
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Login to the x3ui panel
|
|
18
|
+
* @param {string} username Panel username
|
|
19
|
+
* @param {string} password Panel password
|
|
20
|
+
* @returns {Promise<{success: boolean, msg: string, obj: any}>} Login response with success status and token
|
|
21
|
+
*/
|
|
22
|
+
async login(username, password) {
|
|
23
|
+
const formData = new URLSearchParams();
|
|
24
|
+
formData.append('username', username);
|
|
25
|
+
formData.append('password', password);
|
|
26
|
+
|
|
27
|
+
const response = await this.client.post('/login', formData, {
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (response.data.success) {
|
|
34
|
+
this.client.defaults.headers.Cookie = `lang=en-US; ${response.headers.get("set-cookie")[0].split(";")[0]}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getSystemStats() {
|
|
41
|
+
const response = await this.client.post('/server/status');
|
|
42
|
+
return response.data.obj;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get all inbounds
|
|
47
|
+
* @returns {Promise<Array<{
|
|
48
|
+
* id?: number,
|
|
49
|
+
* up: number,
|
|
50
|
+
* down: number,
|
|
51
|
+
* total: number,
|
|
52
|
+
* remark: string,
|
|
53
|
+
* enable: boolean,
|
|
54
|
+
* expiryTime: number | null,
|
|
55
|
+
* listen: string,
|
|
56
|
+
* port: number,
|
|
57
|
+
* protocol: string,
|
|
58
|
+
* settings: any,
|
|
59
|
+
* streamSettings: any,
|
|
60
|
+
* sniffing: any
|
|
61
|
+
* }>>}
|
|
62
|
+
*/
|
|
63
|
+
async getInbounds() {
|
|
64
|
+
const response = await this.client.get('/panel/api/inbounds/list');
|
|
65
|
+
let inbounds = response.data.obj;
|
|
66
|
+
if (this.parseJSONSettings) {
|
|
67
|
+
inbounds = inbounds.map(inbound => this.parseInbound(inbound));
|
|
68
|
+
}
|
|
69
|
+
return inbounds;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
parseInbound(inbound) {
|
|
73
|
+
if (this.parseJSONSettings) {
|
|
74
|
+
inbound.settings = inbound.settings && inbound.settings.length > 0 ? JSON.parse(inbound.settings) : {};
|
|
75
|
+
inbound.streamSettings = inbound.streamSettings && inbound.streamSettings.length > 0 ? JSON.parse(inbound.streamSettings) : {};
|
|
76
|
+
inbound.sniffing = inbound.sniffing && inbound.sniffing.length > 0 ? JSON.parse(inbound.sniffing) : {};
|
|
77
|
+
inbound.allocate = inbound.allocate && inbound.allocate.length > 0 ? JSON.parse(inbound.allocate) : {};
|
|
78
|
+
}
|
|
79
|
+
return inbound;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
stringifyInbound(inbound) {
|
|
83
|
+
inbound.settings = JSON.stringify(inbound.settings);
|
|
84
|
+
inbound.streamSettings = JSON.stringify(inbound.streamSettings);
|
|
85
|
+
inbound.sniffing = JSON.stringify(inbound.sniffing);
|
|
86
|
+
inbound.allocate = JSON.stringify(inbound.allocate);
|
|
87
|
+
return inbound;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Add new inbound
|
|
92
|
+
* @param {Object} config Inbound configuration
|
|
93
|
+
* @param {number} config.up Upload traffic in bytes
|
|
94
|
+
* @param {number} config.down Download traffic in bytes
|
|
95
|
+
* @param {number} config.total Total traffic limit in bytes
|
|
96
|
+
* @param {string} config.remark Inbound remark/name
|
|
97
|
+
* @param {boolean} config.enable Enable status
|
|
98
|
+
* @param {number|null} config.expiryTime Expiry timestamp
|
|
99
|
+
* @param {string} config.listen Listen address
|
|
100
|
+
* @param {number} config.port Port number
|
|
101
|
+
* @param {string} config.protocol Protocol type
|
|
102
|
+
* @param {Object} config.settings Protocol settings
|
|
103
|
+
* @param {Object} config.streamSettings Stream settings
|
|
104
|
+
* @param {Object} config.sniffing Sniffing settings
|
|
105
|
+
* @param {Object} config.allocate Allocation settings
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
async addInbound(config) {
|
|
109
|
+
config = this.stringifyInbound(config);
|
|
110
|
+
const response = await this.client.post('/panel/api/inbounds/add', config);
|
|
111
|
+
if(!response.data.success)
|
|
112
|
+
throw new Error(response.data.msg);
|
|
113
|
+
return this.parseInbound(response.data.obj);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Update existing inbound
|
|
118
|
+
* @param {number} id Inbound ID
|
|
119
|
+
* @param {Object} config Partial inbound configuration
|
|
120
|
+
* @returns {Promise<void>}
|
|
121
|
+
*/
|
|
122
|
+
async updateInbound(id, config) {
|
|
123
|
+
config = this.stringifyInbound(config);
|
|
124
|
+
const response = await this.client.post(`/panel/api/inbounds/update/${id}`, config);
|
|
125
|
+
if(!response.data.success)
|
|
126
|
+
throw new Error(response.data.msg);
|
|
127
|
+
return this.parseInbound(response.data.obj);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Delete inbound
|
|
132
|
+
* @param {number} id Inbound ID
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async deleteInbound(id) {
|
|
136
|
+
await this.client.post(`/panel/api/inbounds/del/${id}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get new X25519 certificate
|
|
141
|
+
* @returns {Promise<{privateKey: string, publicKey: string}>} New X25519 key pair
|
|
142
|
+
*/
|
|
143
|
+
async getNewX25519Cert() {
|
|
144
|
+
const response = await this.client.post('/server/getNewX25519Cert');
|
|
145
|
+
return response.data.obj;
|
|
146
|
+
}
|
|
147
|
+
}
|