3xui-api-client 1.0.0
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/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +448 -0
- package/SECURITY.md +150 -0
- package/index.d.ts +109 -0
- package/index.js +215 -0
- package/index.mjs +5 -0
- package/package.json +98 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-06-20
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Complete API client library for 3x-ui panel management
|
|
12
|
+
- Authentication with automatic session management
|
|
13
|
+
- Inbound management (5 methods): getInbounds, getInbound, addInbound, updateInbound, deleteInbound
|
|
14
|
+
- Client management (7 methods): addClient, updateClient, deleteClient, getClientTrafficsByEmail, getClientTrafficsById, getClientIps, clearClientIps
|
|
15
|
+
- Traffic management (4 methods): resetClientTraffic, resetAllTraffics, resetAllClientTraffics, deleteDepletedClients
|
|
16
|
+
- System operations (2 methods): getOnlineClients, createBackup
|
|
17
|
+
- Comprehensive error handling and automatic re-authentication
|
|
18
|
+
- TypeScript definitions for better developer experience
|
|
19
|
+
- ESM module support alongside CommonJS
|
|
20
|
+
- Complete documentation and wiki guides
|
|
21
|
+
- Interactive testing suite with 19 test files
|
|
22
|
+
- Security best practices implementation
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
- ๐ Secure session-based authentication
|
|
26
|
+
- ๐ Automatic login retry on session expiry
|
|
27
|
+
- ๐ Complete API coverage (19 routes tested and working)
|
|
28
|
+
- ๐ก๏ธ Server-side only design for security
|
|
29
|
+
- ๐ Comprehensive documentation with real-world examples
|
|
30
|
+
- ๐งช Extensive testing suite with actual API responses
|
|
31
|
+
- ๐ TypeScript support for better DX
|
|
32
|
+
- ๐ Both CommonJS and ESM module support
|
|
33
|
+
|
|
34
|
+
### Security
|
|
35
|
+
- No vulnerabilities in dependencies
|
|
36
|
+
- Secure session cookie handling
|
|
37
|
+
- Server-side only architecture
|
|
38
|
+
- Input validation and error handling
|
|
39
|
+
- Automatic timeout and retry mechanisms
|
|
40
|
+
|
|
41
|
+
## [Unreleased]
|
|
42
|
+
|
|
43
|
+
### Planned
|
|
44
|
+
- GitHub Actions CI/CD pipeline
|
|
45
|
+
- Automated semantic releases
|
|
46
|
+
- Unit test coverage with Jest
|
|
47
|
+
- ESLint configuration
|
|
48
|
+
- Contribution guidelines
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Helitha Guruge
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
# 3xui-api-client
|
|
2
|
+
|
|
3
|
+
A Node.js client library for 3x-ui panel API that provides easy-to-use methods for managing your 3x-ui server.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/3xui-api-client)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- โ
**Authentication** - Secure login with automatic session management
|
|
11
|
+
- โ
**Inbound Management** - Get, add, update, and delete inbounds
|
|
12
|
+
- โ
**Client Management** - Add, update, delete clients and monitor traffic
|
|
13
|
+
- โ
**Traffic Management** - Monitor, reset, and manage traffic limits
|
|
14
|
+
- โ
**System Operations** - Backup creation and online client monitoring
|
|
15
|
+
- โ
**Complete API Coverage** - All 19 API routes fully tested and working
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install 3xui-api-client
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const ThreeXUI = require('3xui-api-client');
|
|
27
|
+
|
|
28
|
+
const client = new ThreeXUI('https://your-3xui-server.com', 'username', 'password');
|
|
29
|
+
|
|
30
|
+
// Get all inbounds
|
|
31
|
+
client.getInbounds()
|
|
32
|
+
.then(inbounds => {
|
|
33
|
+
console.log('Inbounds:', inbounds);
|
|
34
|
+
})
|
|
35
|
+
.catch(error => {
|
|
36
|
+
console.error('Error:', error.message);
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Authentication & Security
|
|
41
|
+
|
|
42
|
+
### Automatic Login
|
|
43
|
+
The client automatically handles authentication. When you make your first API call, it will:
|
|
44
|
+
1. Login with your credentials
|
|
45
|
+
2. Store the session cookie
|
|
46
|
+
3. Use the cookie for subsequent requests
|
|
47
|
+
4. Automatically re-login if the session expires
|
|
48
|
+
|
|
49
|
+
### Server-Side Cookie Storage (Recommended)
|
|
50
|
+
For production applications, store the session cookie securely on your server:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const ThreeXUI = require('3xui-api-client');
|
|
54
|
+
|
|
55
|
+
class SecureThreeXUIManager {
|
|
56
|
+
constructor(baseURL, username, password) {
|
|
57
|
+
this.client = new ThreeXUI(baseURL, username, password);
|
|
58
|
+
this.sessionCookie = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async ensureAuthenticated() {
|
|
62
|
+
if (!this.sessionCookie) {
|
|
63
|
+
const loginResult = await this.client.login();
|
|
64
|
+
this.sessionCookie = this.client.cookie;
|
|
65
|
+
|
|
66
|
+
// Store in secure session storage (Redis, database, etc.)
|
|
67
|
+
await this.storeSessionSecurely(this.sessionCookie);
|
|
68
|
+
} else {
|
|
69
|
+
// Restore from secure storage
|
|
70
|
+
this.client.cookie = this.sessionCookie;
|
|
71
|
+
this.client.api.defaults.headers.Cookie = this.sessionCookie;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async storeSessionSecurely(cookie) {
|
|
76
|
+
// Example: Store in Redis with expiration
|
|
77
|
+
// await redis.setex('3xui_session', 3600, cookie);
|
|
78
|
+
|
|
79
|
+
// Example: Store in database
|
|
80
|
+
// await db.sessions.upsert({ service: '3xui', cookie, expires_at: new Date(Date.now() + 3600000) });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async getInbounds() {
|
|
84
|
+
await this.ensureAuthenticated();
|
|
85
|
+
return this.client.getInbounds();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## API Reference
|
|
91
|
+
|
|
92
|
+
### Constructor
|
|
93
|
+
```javascript
|
|
94
|
+
new ThreeXUI(baseURL, username, password)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- `baseURL` (string): Your 3x-ui server URL (e.g., 'https://your-server.com')
|
|
98
|
+
- `username` (string): Admin username
|
|
99
|
+
- `password` (string): Admin password
|
|
100
|
+
|
|
101
|
+
### Inbound Management (โ
Tested & Working)
|
|
102
|
+
|
|
103
|
+
#### Get All Inbounds
|
|
104
|
+
```javascript
|
|
105
|
+
const inbounds = await client.getInbounds();
|
|
106
|
+
console.log(inbounds);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Get Specific Inbound
|
|
110
|
+
```javascript
|
|
111
|
+
const inbound = await client.getInbound(inboundId);
|
|
112
|
+
console.log(inbound);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Add New Inbound
|
|
116
|
+
```javascript
|
|
117
|
+
const inboundConfig = {
|
|
118
|
+
remark: "My VPN Server",
|
|
119
|
+
port: 443,
|
|
120
|
+
protocol: "vless",
|
|
121
|
+
settings: {
|
|
122
|
+
// Your inbound settings
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = await client.addInbound(inboundConfig);
|
|
127
|
+
console.log('Inbound added:', result);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Update Inbound
|
|
131
|
+
```javascript
|
|
132
|
+
const updatedConfig = {
|
|
133
|
+
remark: "Updated VPN Server",
|
|
134
|
+
// Other updated settings
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const result = await client.updateInbound(inboundId, updatedConfig);
|
|
138
|
+
console.log('Inbound updated:', result);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Delete Inbound
|
|
142
|
+
```javascript
|
|
143
|
+
const result = await client.deleteInbound(inboundId);
|
|
144
|
+
console.log('Inbound deleted:', result);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Client Management (โ
Tested & Working)
|
|
148
|
+
|
|
149
|
+
#### Add Client to Inbound
|
|
150
|
+
```javascript
|
|
151
|
+
const clientConfig = {
|
|
152
|
+
id: inboundId,
|
|
153
|
+
settings: JSON.stringify({
|
|
154
|
+
clients: [{
|
|
155
|
+
id: "client-uuid-here",
|
|
156
|
+
email: "user@example.com",
|
|
157
|
+
limitIp: 0,
|
|
158
|
+
totalGB: 0,
|
|
159
|
+
expiryTime: 0,
|
|
160
|
+
enable: true
|
|
161
|
+
}]
|
|
162
|
+
})
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const result = await client.addClient(clientConfig);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
#### Update Client
|
|
169
|
+
```javascript
|
|
170
|
+
const updateConfig = {
|
|
171
|
+
id: inboundId,
|
|
172
|
+
settings: JSON.stringify({
|
|
173
|
+
clients: [/* updated client settings */]
|
|
174
|
+
})
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const result = await client.updateClient(clientUUID, updateConfig);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### Delete Client
|
|
181
|
+
```javascript
|
|
182
|
+
const result = await client.deleteClient(inboundId, clientUUID);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### Get Client Traffic by Email
|
|
186
|
+
```javascript
|
|
187
|
+
const traffic = await client.getClientTrafficsByEmail("user@example.com");
|
|
188
|
+
console.log('Client traffic:', traffic);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### Get Client Traffic by UUID
|
|
192
|
+
```javascript
|
|
193
|
+
const traffic = await client.getClientTrafficsById("client-uuid");
|
|
194
|
+
console.log('Client traffic:', traffic);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Manage Client IPs
|
|
198
|
+
```javascript
|
|
199
|
+
// Get client IPs
|
|
200
|
+
const ips = await client.getClientIps("user@example.com");
|
|
201
|
+
|
|
202
|
+
// Clear client IPs
|
|
203
|
+
const result = await client.clearClientIps("user@example.com");
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Traffic Management (โ
Tested & Working)
|
|
207
|
+
|
|
208
|
+
#### Reset Individual Client Traffic
|
|
209
|
+
```javascript
|
|
210
|
+
const result = await client.resetClientTraffic(inboundId, "user@example.com");
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### Reset All Traffic (Global)
|
|
214
|
+
```javascript
|
|
215
|
+
const result = await client.resetAllTraffics();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
#### Reset All Client Traffic in Inbound
|
|
219
|
+
```javascript
|
|
220
|
+
const result = await client.resetAllClientTraffics(inboundId);
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
#### Delete Depleted Clients
|
|
224
|
+
```javascript
|
|
225
|
+
const result = await client.deleteDepletedClients(inboundId);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### System Operations (โ
Tested & Working)
|
|
229
|
+
|
|
230
|
+
#### Get Online Clients
|
|
231
|
+
```javascript
|
|
232
|
+
const onlineClients = await client.getOnlineClients();
|
|
233
|
+
console.log('Currently online:', onlineClients);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### Create System Backup
|
|
237
|
+
```javascript
|
|
238
|
+
const result = await client.createBackup();
|
|
239
|
+
console.log('Backup created:', result);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Use Cases
|
|
243
|
+
|
|
244
|
+
### VPN Service Provider
|
|
245
|
+
```javascript
|
|
246
|
+
const ThreeXUI = require('3xui-api-client');
|
|
247
|
+
|
|
248
|
+
class VPNServiceManager {
|
|
249
|
+
constructor() {
|
|
250
|
+
this.client = new ThreeXUI(process.env.XUI_URL, process.env.XUI_USER, process.env.XUI_PASS);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Create new customer account
|
|
254
|
+
async createCustomerAccount(email, dataLimitGB = 50) {
|
|
255
|
+
// 1. Get available inbound
|
|
256
|
+
const inbounds = await this.client.getInbounds();
|
|
257
|
+
const activeInbound = inbounds.obj.find(i => i.enable);
|
|
258
|
+
|
|
259
|
+
// 2. Add client to inbound
|
|
260
|
+
const clientConfig = {
|
|
261
|
+
id: activeInbound.id,
|
|
262
|
+
settings: JSON.stringify({
|
|
263
|
+
clients: [{
|
|
264
|
+
id: this.generateUUID(),
|
|
265
|
+
email: email,
|
|
266
|
+
limitIp: 2,
|
|
267
|
+
totalGB: dataLimitGB,
|
|
268
|
+
expiryTime: Date.now() + (30 * 24 * 60 * 60 * 1000), // 30 days
|
|
269
|
+
enable: true
|
|
270
|
+
}]
|
|
271
|
+
})
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
return await this.client.addClient(clientConfig);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Monthly billing cycle
|
|
278
|
+
async processBillingCycle() {
|
|
279
|
+
const inbounds = await this.client.getInbounds();
|
|
280
|
+
|
|
281
|
+
for (const inbound of inbounds.obj) {
|
|
282
|
+
if (inbound.clientStats) {
|
|
283
|
+
for (const client of inbound.clientStats) {
|
|
284
|
+
// Reset traffic for active subscriptions
|
|
285
|
+
await this.client.resetClientTraffic(inbound.id, client.email);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Monitor usage and send alerts
|
|
292
|
+
async monitorUsage() {
|
|
293
|
+
const onlineClients = await this.client.getOnlineClients();
|
|
294
|
+
|
|
295
|
+
for (const client of onlineClients.obj || []) {
|
|
296
|
+
const traffic = await this.client.getClientTrafficsByEmail(client.email);
|
|
297
|
+
|
|
298
|
+
if (traffic.obj && traffic.obj.total > (40 * 1024 * 1024 * 1024)) { // 40GB
|
|
299
|
+
console.log(`โ ๏ธ Client ${client.email} approaching data limit`);
|
|
300
|
+
// Send notification to customer
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Server Administration
|
|
308
|
+
```javascript
|
|
309
|
+
class ServerAdmin {
|
|
310
|
+
constructor() {
|
|
311
|
+
this.client = new ThreeXUI(process.env.XUI_URL, process.env.XUI_USER, process.env.XUI_PASS);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Daily maintenance
|
|
315
|
+
async dailyMaintenance() {
|
|
316
|
+
// 1. Create backup
|
|
317
|
+
await this.client.createBackup();
|
|
318
|
+
|
|
319
|
+
// 2. Clean up depleted clients
|
|
320
|
+
const inbounds = await this.client.getInbounds();
|
|
321
|
+
for (const inbound of inbounds.obj) {
|
|
322
|
+
await this.client.deleteDepletedClients(inbound.id);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// 3. Generate usage report
|
|
326
|
+
const report = await this.generateUsageReport();
|
|
327
|
+
console.log('Daily Report:', report);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Setup new VPN server
|
|
331
|
+
async setupNewServer(port, protocol = 'vless') {
|
|
332
|
+
const serverConfig = {
|
|
333
|
+
remark: `VPN-Server-${port}`,
|
|
334
|
+
port: port,
|
|
335
|
+
protocol: protocol,
|
|
336
|
+
settings: {
|
|
337
|
+
clients: [],
|
|
338
|
+
decryption: "none",
|
|
339
|
+
fallbacks: []
|
|
340
|
+
},
|
|
341
|
+
streamSettings: {
|
|
342
|
+
network: "tcp",
|
|
343
|
+
security: "reality",
|
|
344
|
+
realitySettings: {
|
|
345
|
+
dest: "google.com:443",
|
|
346
|
+
serverNames: ["google.com"]
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
return await this.client.addInbound(serverConfig);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Real-Time Monitoring Dashboard
|
|
357
|
+
```javascript
|
|
358
|
+
class MonitoringDashboard {
|
|
359
|
+
constructor() {
|
|
360
|
+
this.client = new ThreeXUI(process.env.XUI_URL, process.env.XUI_USER, process.env.XUI_PASS);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async getDashboardData() {
|
|
364
|
+
const [inbounds, onlineClients] = await Promise.all([
|
|
365
|
+
this.client.getInbounds(),
|
|
366
|
+
this.client.getOnlineClients()
|
|
367
|
+
]);
|
|
368
|
+
|
|
369
|
+
return {
|
|
370
|
+
totalInbounds: inbounds.obj.length,
|
|
371
|
+
activeInbounds: inbounds.obj.filter(i => i.enable).length,
|
|
372
|
+
totalClients: inbounds.obj.reduce((sum, i) => sum + (i.clientStats?.length || 0), 0),
|
|
373
|
+
onlineClients: onlineClients.obj?.length || 0,
|
|
374
|
+
totalTraffic: inbounds.obj.reduce((sum, i) => sum + i.total, 0)
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// WebSocket endpoint for real-time updates
|
|
379
|
+
async startRealTimeUpdates(ws) {
|
|
380
|
+
setInterval(async () => {
|
|
381
|
+
const data = await this.getDashboardData();
|
|
382
|
+
ws.send(JSON.stringify(data));
|
|
383
|
+
}, 30000); // Update every 30 seconds
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Error Handling
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
try {
|
|
392
|
+
const inbounds = await client.getInbounds();
|
|
393
|
+
console.log(inbounds);
|
|
394
|
+
} catch (error) {
|
|
395
|
+
if (error.message.includes('Login failed')) {
|
|
396
|
+
console.error('Authentication error:', error.message);
|
|
397
|
+
} else if (error.response?.status === 401) {
|
|
398
|
+
console.error('Unauthorized - check your credentials');
|
|
399
|
+
} else {
|
|
400
|
+
console.error('API error:', error.message);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Requirements
|
|
406
|
+
|
|
407
|
+
- Node.js >= 14.0.0
|
|
408
|
+
- 3x-ui panel with API access enabled
|
|
409
|
+
|
|
410
|
+
## Contributing
|
|
411
|
+
|
|
412
|
+
1. Fork the repository
|
|
413
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
414
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
415
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
416
|
+
5. Open a Pull Request
|
|
417
|
+
|
|
418
|
+
## Testing
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
# Run login test
|
|
422
|
+
npm run test:login
|
|
423
|
+
|
|
424
|
+
# Run all tests
|
|
425
|
+
npm test
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Documentation
|
|
429
|
+
|
|
430
|
+
For detailed guides and examples, visit our [Wiki](https://github.com/iamhelitha/3xui-api-client/wiki).
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
435
|
+
|
|
436
|
+
## Support
|
|
437
|
+
|
|
438
|
+
- ๐ [Wiki & Documentation](https://github.com/iamhelitha/3xui-api-client/wiki)
|
|
439
|
+
- ๐ [Report Issues](https://github.com/iamhelitha/3xui-api-client/issues)
|
|
440
|
+
- ๐ฌ [Discussions](https://github.com/iamhelitha/3xui-api-client/discussions)
|
|
441
|
+
|
|
442
|
+
## Author
|
|
443
|
+
|
|
444
|
+
**Helitha Guruge** - [@iamhelitha](https://github.com/iamhelitha)
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
โ ๏ธ **Security Notice**: Always store credentials and session cookies securely. Never expose them in client-side code or commit them to version control.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
We take security seriously and actively maintain the following versions:
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
| ------- | ------------------ |
|
|
9
|
+
| 1.0.x | :white_check_mark: |
|
|
10
|
+
| < 1.0 | :x: |
|
|
11
|
+
|
|
12
|
+
## Security Best Practices
|
|
13
|
+
|
|
14
|
+
### For Users
|
|
15
|
+
|
|
16
|
+
**๐ Server-Side Only Usage**
|
|
17
|
+
- This package is designed for **server-side use only**
|
|
18
|
+
- Never use this package in browser/client-side applications
|
|
19
|
+
- Session cookies contain sensitive authentication data
|
|
20
|
+
|
|
21
|
+
**๐ก๏ธ Credential Security**
|
|
22
|
+
- Store credentials in environment variables, not in code
|
|
23
|
+
- Use secure session storage (Redis, Database) for production
|
|
24
|
+
- Implement proper access controls for your server
|
|
25
|
+
|
|
26
|
+
**๐ Session Management**
|
|
27
|
+
- Sessions expire after 1 hour and are automatically renewed
|
|
28
|
+
- Monitor for unusual authentication patterns
|
|
29
|
+
- Implement rate limiting on your server
|
|
30
|
+
|
|
31
|
+
**๐ Example Secure Implementation:**
|
|
32
|
+
```javascript
|
|
33
|
+
const ThreeXUI = require('3xui-api-client');
|
|
34
|
+
|
|
35
|
+
// โ
Good: Use environment variables
|
|
36
|
+
const client = new ThreeXUI(
|
|
37
|
+
process.env.XUI_URL,
|
|
38
|
+
process.env.XUI_USERNAME,
|
|
39
|
+
process.env.XUI_PASSWORD
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
// โ
Good: Store sessions securely
|
|
43
|
+
class SecureXUIManager {
|
|
44
|
+
constructor(database) {
|
|
45
|
+
this.client = client;
|
|
46
|
+
this.db = database;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async ensureAuthenticated() {
|
|
50
|
+
const session = await this.db.getValidSession();
|
|
51
|
+
if (!session) {
|
|
52
|
+
await this.client.login();
|
|
53
|
+
await this.db.storeSession(this.client.cookie);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Reporting a Vulnerability
|
|
60
|
+
|
|
61
|
+
We appreciate responsible disclosure of security vulnerabilities.
|
|
62
|
+
|
|
63
|
+
### How to Report
|
|
64
|
+
|
|
65
|
+
1. **Do NOT** create a public GitHub issue for security vulnerabilities
|
|
66
|
+
2. Email security reports to: [your-security-email@example.com]
|
|
67
|
+
3. Include detailed information about the vulnerability
|
|
68
|
+
4. Allow up to 48 hours for initial response
|
|
69
|
+
|
|
70
|
+
### What to Include
|
|
71
|
+
|
|
72
|
+
- **Description**: Clear description of the vulnerability
|
|
73
|
+
- **Impact**: Potential security impact and affected versions
|
|
74
|
+
- **Reproduction**: Steps to reproduce the issue
|
|
75
|
+
- **Fix Suggestion**: If you have ideas for fixes
|
|
76
|
+
|
|
77
|
+
### Our Response Process
|
|
78
|
+
|
|
79
|
+
1. **Acknowledgment**: We'll confirm receipt within 48 hours
|
|
80
|
+
2. **Investigation**: We'll investigate and assess the impact
|
|
81
|
+
3. **Fix Development**: We'll develop and test a fix
|
|
82
|
+
4. **Release**: We'll release a security update
|
|
83
|
+
5. **Disclosure**: We'll publicly disclose after users have time to update
|
|
84
|
+
|
|
85
|
+
### Security Update Process
|
|
86
|
+
|
|
87
|
+
- Security fixes are released as patch versions (e.g., 1.0.1)
|
|
88
|
+
- We'll publish security advisories on GitHub
|
|
89
|
+
- Critical vulnerabilities may trigger emergency releases
|
|
90
|
+
- We'll notify users through multiple channels
|
|
91
|
+
|
|
92
|
+
## Security Features
|
|
93
|
+
|
|
94
|
+
### Built-in Security
|
|
95
|
+
|
|
96
|
+
โ
**Automatic Session Management**
|
|
97
|
+
- Sessions expire after 1 hour
|
|
98
|
+
- Automatic re-authentication on expiry
|
|
99
|
+
- Secure cookie handling
|
|
100
|
+
|
|
101
|
+
โ
**Input Validation**
|
|
102
|
+
- Required parameter validation
|
|
103
|
+
- URL sanitization
|
|
104
|
+
- Error message sanitization
|
|
105
|
+
|
|
106
|
+
โ
**HTTP Security**
|
|
107
|
+
- 30-second request timeouts
|
|
108
|
+
- Connection validation
|
|
109
|
+
- Redirect limits (max 5)
|
|
110
|
+
- Security headers
|
|
111
|
+
|
|
112
|
+
โ
**Error Handling**
|
|
113
|
+
- No sensitive data in error messages
|
|
114
|
+
- Proper exception handling
|
|
115
|
+
- Network error management
|
|
116
|
+
|
|
117
|
+
### Dependencies Security
|
|
118
|
+
|
|
119
|
+
- All dependencies are regularly audited
|
|
120
|
+
- No known vulnerabilities in current dependencies
|
|
121
|
+
- Minimal dependency footprint (only axios)
|
|
122
|
+
|
|
123
|
+
## Security Considerations
|
|
124
|
+
|
|
125
|
+
### Network Security
|
|
126
|
+
- Always use HTTPS for production deployments
|
|
127
|
+
- Implement proper firewall rules
|
|
128
|
+
- Use VPN or private networks when possible
|
|
129
|
+
|
|
130
|
+
### Access Control
|
|
131
|
+
- Limit access to 3x-ui admin accounts
|
|
132
|
+
- Use strong, unique passwords
|
|
133
|
+
- Implement IP whitelisting where possible
|
|
134
|
+
- Monitor access logs regularly
|
|
135
|
+
|
|
136
|
+
### Data Protection
|
|
137
|
+
- Never log credentials or session cookies
|
|
138
|
+
- Implement proper data retention policies
|
|
139
|
+
- Use encryption for stored session data
|
|
140
|
+
- Regular security audits of your implementation
|
|
141
|
+
|
|
142
|
+
## Contact
|
|
143
|
+
|
|
144
|
+
For security-related questions or concerns:
|
|
145
|
+
- GitHub Issues: For non-security bugs only
|
|
146
|
+
- Documentation: Check our [Wiki](https://github.com/iamhelitha/3xui-api-client/wiki) for security guides
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
**Note**: This security policy applies to the 3xui-api-client library itself. Security of your 3x-ui server and infrastructure remains your responsibility.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
declare module '3xui-api-client' {
|
|
2
|
+
export interface ThreeXUIResponse<T = any> {
|
|
3
|
+
success: boolean;
|
|
4
|
+
msg: string;
|
|
5
|
+
obj: T | null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface InboundConfig {
|
|
9
|
+
remark: string;
|
|
10
|
+
port: number;
|
|
11
|
+
protocol: string;
|
|
12
|
+
settings: any;
|
|
13
|
+
streamSettings?: any;
|
|
14
|
+
sniffing?: any;
|
|
15
|
+
allocate?: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ClientConfig {
|
|
19
|
+
id: number;
|
|
20
|
+
settings: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ClientData {
|
|
24
|
+
id: string;
|
|
25
|
+
email: string;
|
|
26
|
+
limitIp?: number;
|
|
27
|
+
totalGB?: number;
|
|
28
|
+
expiryTime?: number;
|
|
29
|
+
enable?: boolean;
|
|
30
|
+
tgId?: string;
|
|
31
|
+
subId?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface InboundData {
|
|
35
|
+
id: number;
|
|
36
|
+
up: number;
|
|
37
|
+
down: number;
|
|
38
|
+
total: number;
|
|
39
|
+
remark: string;
|
|
40
|
+
enable: boolean;
|
|
41
|
+
expiryTime: number;
|
|
42
|
+
clientStats: ClientTrafficData[] | null;
|
|
43
|
+
listen: string;
|
|
44
|
+
port: number;
|
|
45
|
+
protocol: string;
|
|
46
|
+
settings: string;
|
|
47
|
+
streamSettings: string;
|
|
48
|
+
tag: string;
|
|
49
|
+
sniffing: string;
|
|
50
|
+
allocate: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ClientTrafficData {
|
|
54
|
+
id: number;
|
|
55
|
+
inboundId: number;
|
|
56
|
+
enable: boolean;
|
|
57
|
+
email: string;
|
|
58
|
+
up: number;
|
|
59
|
+
down: number;
|
|
60
|
+
expiryTime: number;
|
|
61
|
+
total: number;
|
|
62
|
+
reset: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface OnlineClientData {
|
|
66
|
+
email: string;
|
|
67
|
+
ip: string;
|
|
68
|
+
connectedAt: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface LoginResponse {
|
|
72
|
+
success: boolean;
|
|
73
|
+
headers: any;
|
|
74
|
+
data: any;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default class ThreeXUI {
|
|
78
|
+
constructor(baseURL: string, username: string, password: string);
|
|
79
|
+
|
|
80
|
+
// Authentication
|
|
81
|
+
login(): Promise<LoginResponse>;
|
|
82
|
+
|
|
83
|
+
// Inbound Management
|
|
84
|
+
getInbounds(): Promise<ThreeXUIResponse<InboundData[]>>;
|
|
85
|
+
getInbound(id: number): Promise<ThreeXUIResponse<InboundData>>;
|
|
86
|
+
addInbound(inboundConfig: InboundConfig): Promise<ThreeXUIResponse<any>>;
|
|
87
|
+
updateInbound(id: number, inboundConfig: Partial<InboundConfig>): Promise<ThreeXUIResponse<any>>;
|
|
88
|
+
deleteInbound(id: number): Promise<ThreeXUIResponse<number>>;
|
|
89
|
+
|
|
90
|
+
// Client Management
|
|
91
|
+
addClient(clientConfig: ClientConfig): Promise<ThreeXUIResponse<null>>;
|
|
92
|
+
updateClient(clientId: string, clientConfig: ClientConfig): Promise<ThreeXUIResponse<null>>;
|
|
93
|
+
deleteClient(inboundId: number, clientId: string): Promise<ThreeXUIResponse<null>>;
|
|
94
|
+
getClientTrafficsByEmail(email: string): Promise<ThreeXUIResponse<ClientTrafficData>>;
|
|
95
|
+
getClientTrafficsById(id: string): Promise<ThreeXUIResponse<ClientTrafficData[]>>;
|
|
96
|
+
getClientIps(email: string): Promise<ThreeXUIResponse<string>>;
|
|
97
|
+
clearClientIps(email: string): Promise<ThreeXUIResponse<null>>;
|
|
98
|
+
|
|
99
|
+
// Traffic Management
|
|
100
|
+
resetClientTraffic(inboundId: number, email: string): Promise<ThreeXUIResponse<null>>;
|
|
101
|
+
resetAllTraffics(): Promise<ThreeXUIResponse<null>>;
|
|
102
|
+
resetAllClientTraffics(inboundId: number): Promise<ThreeXUIResponse<null>>;
|
|
103
|
+
deleteDepletedClients(inboundId: number): Promise<ThreeXUIResponse<null>>;
|
|
104
|
+
|
|
105
|
+
// System Operations
|
|
106
|
+
getOnlineClients(): Promise<ThreeXUIResponse<OnlineClientData[]>>;
|
|
107
|
+
createBackup(): Promise<ThreeXUIResponse<string>>;
|
|
108
|
+
}
|
|
109
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 3X-UI API Client Library
|
|
5
|
+
*
|
|
6
|
+
* A Node.js client for managing 3x-ui panel APIs with automatic session management.
|
|
7
|
+
* This library is designed for server-side use only due to security requirements.
|
|
8
|
+
*
|
|
9
|
+
* @class ThreeXUI
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
* @author Helitha Guruge
|
|
12
|
+
*/
|
|
13
|
+
class ThreeXUI {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new ThreeXUI client instance
|
|
16
|
+
*
|
|
17
|
+
* @param {string} baseURL - The base URL of your 3x-ui server (e.g., 'https://your-server.com')
|
|
18
|
+
* @param {string} username - Admin username for authentication
|
|
19
|
+
* @param {string} password - Admin password for authentication
|
|
20
|
+
* @throws {Error} If baseURL, username, or password is missing
|
|
21
|
+
*/
|
|
22
|
+
constructor(baseURL, username, password) {
|
|
23
|
+
if (!baseURL) {
|
|
24
|
+
throw new Error('baseURL is required');
|
|
25
|
+
}
|
|
26
|
+
if (!username) {
|
|
27
|
+
throw new Error('username is required');
|
|
28
|
+
}
|
|
29
|
+
if (!password) {
|
|
30
|
+
throw new Error('password is required');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.baseURL = baseURL.replace(/\/$/, ''); // Remove trailing slash
|
|
34
|
+
this.username = username;
|
|
35
|
+
this.password = password;
|
|
36
|
+
this.cookie = null;
|
|
37
|
+
|
|
38
|
+
// Create axios instance with security best practices
|
|
39
|
+
this.api = axios.create({
|
|
40
|
+
baseURL: this.baseURL,
|
|
41
|
+
timeout: 30000, // 30 second timeout
|
|
42
|
+
maxRedirects: 5,
|
|
43
|
+
validateStatus: (status) => status >= 200 && status < 300,
|
|
44
|
+
headers: {
|
|
45
|
+
'User-Agent': '3xui-api-client/1.0.0',
|
|
46
|
+
'Accept': 'application/json',
|
|
47
|
+
'Connection': 'keep-alive'
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Add request interceptor for security headers
|
|
52
|
+
this.api.interceptors.request.use((config) => {
|
|
53
|
+
// Add security headers
|
|
54
|
+
config.headers['X-Requested-With'] = 'XMLHttpRequest';
|
|
55
|
+
return config;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Add response interceptor for error handling
|
|
59
|
+
this.api.interceptors.response.use(
|
|
60
|
+
(response) => response,
|
|
61
|
+
(error) => {
|
|
62
|
+
if (error.code === 'ECONNABORTED') {
|
|
63
|
+
throw new Error('Request timeout - server took too long to respond');
|
|
64
|
+
}
|
|
65
|
+
if (error.code === 'ENOTFOUND') {
|
|
66
|
+
throw new Error(`Cannot connect to server: ${this.baseURL}`);
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async login() {
|
|
74
|
+
try {
|
|
75
|
+
const params = new URLSearchParams();
|
|
76
|
+
params.append('username', this.username);
|
|
77
|
+
params.append('password', this.password);
|
|
78
|
+
|
|
79
|
+
const response = await this.api.post('/login', params, {
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (response.data.success) {
|
|
86
|
+
const cookies = response.headers['set-cookie'];
|
|
87
|
+
if (cookies && cookies.length > 0) {
|
|
88
|
+
this.cookie = cookies[0].split(';')[0];
|
|
89
|
+
this.api.defaults.headers.Cookie = this.cookie;
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error('Login failed: No session cookie received.');
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
success: true,
|
|
95
|
+
headers: response.headers,
|
|
96
|
+
data: response.data
|
|
97
|
+
};
|
|
98
|
+
} else {
|
|
99
|
+
throw new Error(`Login failed: ${response.data.msg}`);
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
let errorMessage = `Login failed: ${error.message}`;
|
|
103
|
+
if (error.response) {
|
|
104
|
+
errorMessage = `Login failed with status ${error.response.status}: ${JSON.stringify(error.response.data)}`;
|
|
105
|
+
}
|
|
106
|
+
throw new Error(errorMessage);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async _request(method, path, data = {}) {
|
|
111
|
+
if (!this.cookie) {
|
|
112
|
+
await this.login();
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const response = await this.api.request({
|
|
116
|
+
method,
|
|
117
|
+
url: path,
|
|
118
|
+
data,
|
|
119
|
+
...(method.toLowerCase() === 'post' ? { headers: { 'Content-Type': 'application/json' } } : {})
|
|
120
|
+
});
|
|
121
|
+
return response.data;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error.response && error.response.status === 401) {
|
|
124
|
+
// Cookie might have expired, try to login again
|
|
125
|
+
await this.login();
|
|
126
|
+
const response = await this.api.request({
|
|
127
|
+
method,
|
|
128
|
+
url: path,
|
|
129
|
+
data,
|
|
130
|
+
...(method.toLowerCase() === 'post' ? { headers: { 'Content-Type': 'application/json' } } : {})
|
|
131
|
+
});
|
|
132
|
+
return response.data;
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Inbounds
|
|
139
|
+
getInbounds() {
|
|
140
|
+
return this._request('get', '/panel/api/inbounds/list');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
getInbound(id) {
|
|
144
|
+
return this._request('get', `/panel/api/inbounds/get/${id}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
addInbound(inboundConfig) {
|
|
148
|
+
return this._request('post', '/panel/api/inbounds/add', inboundConfig);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
deleteInbound(id) {
|
|
152
|
+
return this._request('post', `/panel/api/inbounds/del/${id}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
updateInbound(id, inboundConfig) {
|
|
156
|
+
return this._request('post', `/panel/api/inbounds/update/${id}`, inboundConfig);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Clients
|
|
160
|
+
addClient(clientConfig) {
|
|
161
|
+
return this._request('post', '/panel/api/inbounds/addClient', clientConfig);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
deleteClient(inboundId, clientId) {
|
|
165
|
+
return this._request('post', `/panel/api/inbounds/${inboundId}/delClient/${clientId}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
updateClient(clientId, clientConfig) {
|
|
169
|
+
return this._request('post', `/panel/api/inbounds/updateClient/${clientId}`, clientConfig);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getClientTrafficsByEmail(email) {
|
|
173
|
+
return this._request('get', `/panel/api/inbounds/getClientTraffics/${email}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
getClientTrafficsById(id) {
|
|
177
|
+
return this._request('get', `/panel/api/inbounds/getClientTrafficsById/${id}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
getClientIps(email) {
|
|
181
|
+
return this._request('post', `/panel/api/inbounds/clientIps/${email}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
clearClientIps(email) {
|
|
185
|
+
return this._request('post', `/panel/api/inbounds/clearClientIps/${email}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Traffic
|
|
189
|
+
resetClientTraffic(inboundId, email) {
|
|
190
|
+
return this._request('post', `/panel/api/inbounds/${inboundId}/resetClientTraffic/${email}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
resetAllTraffics() {
|
|
194
|
+
return this._request('post', '/panel/api/inbounds/resetAllTraffics');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
resetAllClientTraffics(inboundId) {
|
|
198
|
+
return this._request('post', `/panel/api/inbounds/resetAllClientTraffics/${inboundId}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
deleteDepletedClients(inboundId) {
|
|
202
|
+
return this._request('post', `/panel/api/inbounds/delDepletedClients/${inboundId}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// System
|
|
206
|
+
getOnlineClients() {
|
|
207
|
+
return this._request('post', '/panel/api/inbounds/onlines');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
createBackup() {
|
|
211
|
+
return this._request('get', '/panel/api/inbounds/createbackup');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = ThreeXUI;
|
package/index.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "3xui-api-client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Node.js client library for 3x-ui panel API that provides easy-to-use methods for managing your 3x-ui server",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"require": "./index.js",
|
|
11
|
+
"import": "./index.mjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"test:manual": "node test/main-test.js",
|
|
17
|
+
"test:main": "node test/main-test.js",
|
|
18
|
+
"test:login": "node test/login-test.js",
|
|
19
|
+
"test:inbounds": "node test/inbounds-test.js",
|
|
20
|
+
"test:create": "node test/create-inbound-test.js",
|
|
21
|
+
"lint": "eslint index.js",
|
|
22
|
+
"prepublishOnly": "npm test"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"3x-ui",
|
|
26
|
+
"3xui",
|
|
27
|
+
"api",
|
|
28
|
+
"client",
|
|
29
|
+
"vpn",
|
|
30
|
+
"proxy",
|
|
31
|
+
"panel",
|
|
32
|
+
"xray",
|
|
33
|
+
"v2ray",
|
|
34
|
+
"server-management",
|
|
35
|
+
"api-client",
|
|
36
|
+
"network-management"
|
|
37
|
+
],
|
|
38
|
+
"author": {
|
|
39
|
+
"name": "Helitha Guruge",
|
|
40
|
+
"email": "helithalochana@gmail.com",
|
|
41
|
+
"url": "https://github.com/iamhelitha"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"type": "commonjs",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/iamhelitha/3xui-api-client.git"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/iamhelitha/3xui-api-client/issues"
|
|
51
|
+
},
|
|
52
|
+
"homepage": "https://github.com/iamhelitha/3xui-api-client#readme",
|
|
53
|
+
"funding": {
|
|
54
|
+
"type": "github",
|
|
55
|
+
"url": "https://github.com/sponsors/iamhelitha"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=16.0.0",
|
|
59
|
+
"npm": ">=7.0.0"
|
|
60
|
+
},
|
|
61
|
+
"os": [
|
|
62
|
+
"linux",
|
|
63
|
+
"darwin",
|
|
64
|
+
"win32"
|
|
65
|
+
],
|
|
66
|
+
"files": [
|
|
67
|
+
"index.js",
|
|
68
|
+
"index.mjs",
|
|
69
|
+
"index.d.ts",
|
|
70
|
+
"README.md",
|
|
71
|
+
"LICENSE",
|
|
72
|
+
"CHANGELOG.md",
|
|
73
|
+
"SECURITY.md"
|
|
74
|
+
],
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"axios": "^1.10.0"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"dotenv": "^16.5.0",
|
|
80
|
+
"jest": "^29.7.0",
|
|
81
|
+
"eslint": "^9.0.0",
|
|
82
|
+
"@eslint/js": "^9.0.0"
|
|
83
|
+
},
|
|
84
|
+
"jest": {
|
|
85
|
+
"testEnvironment": "node",
|
|
86
|
+
"collectCoverageFrom": [
|
|
87
|
+
"index.js"
|
|
88
|
+
],
|
|
89
|
+
"coverageDirectory": "coverage",
|
|
90
|
+
"testMatch": [
|
|
91
|
+
"**/tests/**/*.test.js"
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
"publishConfig": {
|
|
95
|
+
"access": "public",
|
|
96
|
+
"registry": "https://registry.npmjs.org/"
|
|
97
|
+
}
|
|
98
|
+
}
|