x3ui-api 1.0.1 → 1.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 +158 -1
- package/package.json +2 -2
- package/src/index.d.ts +17 -2
- package/src/index.js +45 -4
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,163 @@ 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
|
+
- Convenient Reality inbound builder
|
|
17
|
+
- Client management with fluent API
|
|
18
|
+
- TypeScript support
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Usage
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
const X3UIClient = require('x3ui-api');
|
|
26
|
+
|
|
27
|
+
// Initialize client
|
|
28
|
+
const client = new X3UIClient({
|
|
29
|
+
baseURL: 'http://your-x3ui-panel.com:54321',
|
|
30
|
+
parseJSONSettings: true // Default: true - automatically parse JSON settings
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Login to panel
|
|
34
|
+
async function main() {
|
|
35
|
+
try {
|
|
36
|
+
const loginResult = await client.login('admin', 'password');
|
|
37
|
+
console.log('Login successful:', loginResult.success);
|
|
38
|
+
|
|
39
|
+
// Get system stats
|
|
40
|
+
const stats = await client.getSystemStats();
|
|
41
|
+
console.log('CPU Usage:', stats.cpu + '%');
|
|
42
|
+
console.log('Memory:', Math.round(stats.mem.current / stats.mem.total * 100) + '%');
|
|
43
|
+
|
|
44
|
+
// List all inbounds
|
|
45
|
+
const inbounds = await client.getInbounds();
|
|
46
|
+
console.log('Inbounds:', inbounds.length);
|
|
47
|
+
|
|
48
|
+
// First inbound details
|
|
49
|
+
if (inbounds.length > 0) {
|
|
50
|
+
console.log('First inbound:', inbounds[0].remark);
|
|
51
|
+
console.log('Protocol:', inbounds[0].protocol);
|
|
52
|
+
console.log('Port:', inbounds[0].port);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error:', error.message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
main();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Creating a Reality Inbound
|
|
63
|
+
|
|
64
|
+
The library provides a convenient builder pattern for creating Reality inbounds:
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
async function createRealityInbound() {
|
|
68
|
+
try {
|
|
69
|
+
// Create a Reality inbound builder
|
|
70
|
+
const builder = client.createRealityBuilder({
|
|
71
|
+
remark: 'My Reality Inbound',
|
|
72
|
+
port: 8443 // Optional, will auto-generate if not provided
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Configure Reality settings
|
|
76
|
+
builder
|
|
77
|
+
.setDest('yahoo.com:443')
|
|
78
|
+
.setServerNames(['yahoo.com', 'www.yahoo.com'])
|
|
79
|
+
.setFingerprint('chrome');
|
|
80
|
+
|
|
81
|
+
// Add a client
|
|
82
|
+
const clientBuilder = builder.addClient()
|
|
83
|
+
.setEmail('user@example.com')
|
|
84
|
+
.setTotalGB(100) // 100 GB traffic limit
|
|
85
|
+
.setExpiryTime(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
86
|
+
|
|
87
|
+
// Build and add the inbound
|
|
88
|
+
const inbound = await builder.build();
|
|
89
|
+
const result = await client.addInbound(inbound);
|
|
90
|
+
|
|
91
|
+
console.log('Inbound created:', result);
|
|
92
|
+
|
|
93
|
+
// Get connection link for the client
|
|
94
|
+
const link = builder.getClientLink(0, 'your-server-ip.com');
|
|
95
|
+
console.log('Client connection link:', link);
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error('Error creating inbound:', error.message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Managing Existing Inbounds
|
|
103
|
+
|
|
104
|
+
```javascript
|
|
105
|
+
async function manageInbounds() {
|
|
106
|
+
// Get all inbounds
|
|
107
|
+
const inbounds = await client.getInbounds();
|
|
108
|
+
|
|
109
|
+
if (inbounds.length > 0) {
|
|
110
|
+
const inboundId = inbounds[0].id;
|
|
111
|
+
|
|
112
|
+
// Update an inbound
|
|
113
|
+
await client.updateInbound(inboundId, {
|
|
114
|
+
remark: 'Updated Inbound Name',
|
|
115
|
+
enable: true
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Delete an inbound
|
|
119
|
+
await client.deleteInbound(inboundId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## API Reference
|
|
125
|
+
|
|
126
|
+
### X3UIClient
|
|
127
|
+
|
|
128
|
+
#### Constructor
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
new X3UIClient({
|
|
132
|
+
baseURL: string, // Required: URL to your x3ui panel
|
|
133
|
+
token?: string, // Optional: Authentication token (if already logged in)
|
|
134
|
+
parseJSONSettings?: boolean // Optional: Auto-parse JSON settings (default: true)
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Methods
|
|
139
|
+
|
|
140
|
+
- `login(username: string, password: string)` - Authenticate with the panel
|
|
141
|
+
- `getSystemStats()` - Get system statistics
|
|
142
|
+
- `getInbounds()` - Get all configured inbounds
|
|
143
|
+
- `addInbound(config)` - Add a new inbound
|
|
144
|
+
- `updateInbound(id, config)` - Update an existing inbound
|
|
145
|
+
- `deleteInbound(id)` - Delete an inbound
|
|
146
|
+
- `getNewX25519Cert()` - Generate a new X25519 certificate
|
|
147
|
+
- `createRealityBuilder(options)` - Create a Reality inbound builder
|
|
148
|
+
|
|
149
|
+
### RealityBuilder
|
|
150
|
+
|
|
151
|
+
Builder class for creating Reality inbounds with a fluent API.
|
|
152
|
+
|
|
153
|
+
#### Methods
|
|
154
|
+
|
|
155
|
+
- `setPort(port)` - Set the port for the inbound
|
|
156
|
+
- `setRemark(remark)` - Set the name/remark for the inbound
|
|
157
|
+
- `setDest(dest)` - Set the destination address (e.g., "yahoo.com:443")
|
|
158
|
+
- `setServerNames(names)` - Set server names for SNI
|
|
159
|
+
- `setKeyPair(privateKey, publicKey)` - Set Reality keypair
|
|
160
|
+
- `setShortIds(ids)` - Set short IDs for Reality
|
|
161
|
+
- `setFingerprint(fingerprint)` - Set browser fingerprint
|
|
162
|
+
- `setListenIP(ip)` - Set listen IP address
|
|
163
|
+
- `setExpiryTime(timestamp)` - Set inbound expiry time
|
|
164
|
+
- `addClient(options)` - Add a new client to the inbound
|
|
165
|
+
- `getClientLink(clientIndex, host)` - Get connection link for a client
|
|
166
|
+
- `build()` - Build the final inbound config
|
|
167
|
+
|
|
11
168
|
## License
|
|
12
169
|
|
|
13
170
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x3ui-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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": {
|
package/src/index.d.ts
CHANGED
|
@@ -201,9 +201,17 @@ export interface ClientBuilder {
|
|
|
201
201
|
setTgId(id: string): this;
|
|
202
202
|
|
|
203
203
|
/**
|
|
204
|
-
* Build client configuration
|
|
204
|
+
* Build the client configuration
|
|
205
205
|
*/
|
|
206
|
-
build():
|
|
206
|
+
build(): ClientSettings;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Generate connection link for this client
|
|
210
|
+
* @param host Host address
|
|
211
|
+
* @param port Optional port number, defaults to parent's port
|
|
212
|
+
* @param protocol Optional protocol, defaults to parent's protocol or 'vless'
|
|
213
|
+
*/
|
|
214
|
+
getLink(host: string, port?: number, protocol?: string): string;
|
|
207
215
|
}
|
|
208
216
|
|
|
209
217
|
export interface RealityBuilder {
|
|
@@ -257,6 +265,13 @@ export interface RealityBuilder {
|
|
|
257
265
|
*/
|
|
258
266
|
addClient(options?: Partial<ClientSettings>): ClientBuilder;
|
|
259
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Get connection link for a client
|
|
270
|
+
* @param clientIndex Index of the client (defaults to 0)
|
|
271
|
+
* @param host Optional host address (defaults to listenIP or 'localhost')
|
|
272
|
+
*/
|
|
273
|
+
getClientLink(clientIndex?: number, host?: string): string;
|
|
274
|
+
|
|
260
275
|
/**
|
|
261
276
|
* Build the final inbound config
|
|
262
277
|
*/
|
package/src/index.js
CHANGED
|
@@ -72,9 +72,9 @@ module.exports = class X3UIClient {
|
|
|
72
72
|
|
|
73
73
|
parseInbound(inbound) {
|
|
74
74
|
if (this.parseJSONSettings) {
|
|
75
|
-
inbound.settings = JSON.parse(inbound.settings);
|
|
76
|
-
inbound.streamSettings = JSON.parse(inbound.streamSettings);
|
|
77
|
-
inbound.sniffing = JSON.parse(inbound.sniffing);
|
|
75
|
+
inbound.settings = inbound.settings && inbound.settings.length > 0 ? JSON.parse(inbound.settings) : {};
|
|
76
|
+
inbound.streamSettings = inbound.streamSettings && inbound.streamSettings.length > 0 ? JSON.parse(inbound.streamSettings) : {};
|
|
77
|
+
inbound.sniffing = inbound.sniffing && inbound.sniffing.length > 0 ? JSON.parse(inbound.sniffing) : {};
|
|
78
78
|
inbound.allocate = inbound.allocate && inbound.allocate.length > 0 ? JSON.parse(inbound.allocate) : {};
|
|
79
79
|
}
|
|
80
80
|
return inbound;
|
|
@@ -196,7 +196,7 @@ class ClientBuilder {
|
|
|
196
196
|
return this;
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
|
|
199
|
+
build() {
|
|
200
200
|
return {
|
|
201
201
|
id: this.id || crypto.randomUUID(),
|
|
202
202
|
flow: this.flow,
|
|
@@ -210,6 +210,28 @@ class ClientBuilder {
|
|
|
210
210
|
reset: this.reset
|
|
211
211
|
};
|
|
212
212
|
}
|
|
213
|
+
|
|
214
|
+
getLink(host, port, protocol) {
|
|
215
|
+
const id = this.id || crypto.randomUUID();
|
|
216
|
+
const settings = this.parent.streamSettings?.realitySettings;
|
|
217
|
+
if (!settings) throw new Error('Reality settings not found');
|
|
218
|
+
|
|
219
|
+
port = port || this.parent.port;
|
|
220
|
+
protocol = protocol || this.parent.protocol || 'vless';
|
|
221
|
+
|
|
222
|
+
const params = new URLSearchParams({
|
|
223
|
+
security: this.parent.streamSettings?.security || 'reality',
|
|
224
|
+
sni: settings.serverNames[0],
|
|
225
|
+
fp: settings.settings.fingerprint,
|
|
226
|
+
pbk: settings.settings.publicKey,
|
|
227
|
+
sid: settings.shortIds[0],
|
|
228
|
+
spx: settings.settings.spiderX || '/',
|
|
229
|
+
type: this.parent.streamSettings?.network || 'tcp',
|
|
230
|
+
encryption: this.parent.settings?.decryption || 'none'
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return `${protocol}://${id}@${host}:${port}?${params.toString()}#${encodeURIComponent(this.email || 'default')}`;
|
|
234
|
+
}
|
|
213
235
|
}
|
|
214
236
|
|
|
215
237
|
class RealityBuilder {
|
|
@@ -303,10 +325,29 @@ class RealityBuilder {
|
|
|
303
325
|
if (options.totalGB) builder.setTotalGB(options.totalGB);
|
|
304
326
|
if (options.expiryTime) builder.setExpiryTime(options.expiryTime);
|
|
305
327
|
if (options.tgId) builder.setTgId(options.tgId);
|
|
328
|
+
builder.parent.streamSettings = {
|
|
329
|
+
realitySettings: {
|
|
330
|
+
serverNames: this.serverNames,
|
|
331
|
+
settings: {
|
|
332
|
+
fingerprint: this.fingerprint,
|
|
333
|
+
publicKey: this.publicKey,
|
|
334
|
+
spiderX: '/'
|
|
335
|
+
},
|
|
336
|
+
shortIds: this.shortIds
|
|
337
|
+
}
|
|
338
|
+
};
|
|
306
339
|
this.clients.push(builder);
|
|
307
340
|
return builder;
|
|
308
341
|
}
|
|
309
342
|
|
|
343
|
+
getClientLink(clientIndex = 0, host) {
|
|
344
|
+
if (clientIndex < 0 || clientIndex >= this.clients.length) {
|
|
345
|
+
throw new Error('Invalid client index');
|
|
346
|
+
}
|
|
347
|
+
const client = this.clients[clientIndex];
|
|
348
|
+
return client.getLink(host || this.listenIP || 'localhost', this.port);
|
|
349
|
+
}
|
|
350
|
+
|
|
310
351
|
generateRandomPort() {
|
|
311
352
|
return Math.floor(Math.random() * (65535 - 1024) + 1024);
|
|
312
353
|
}
|