3xui-api-client 3.0.1 → 3.1.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/index.d.ts CHANGED
@@ -18,13 +18,35 @@ declare module '3xui-api-client' {
18
18
  userAgent?: string;
19
19
  token?: string;
20
20
  apiToken?: string;
21
+ /**
22
+ * Panel version detection mode.
23
+ * - 'auto': Automatically detect panel version (tries modern first, falls back to legacy)
24
+ * - 'modern': Use only modern panel endpoints (/panel/api/login)
25
+ * - 'legacy': Use only legacy panel endpoints (/login)
26
+ * @default 'auto'
27
+ */
28
+ panelVersion?: 'auto' | 'modern' | 'legacy';
29
+ /**
30
+ * Maximum number of forced re-login attempts when a 401 response is received.
31
+ * @default 3
32
+ */
33
+ maxLoginRetries?: number;
34
+ /**
35
+ * Delay in milliseconds to wait before each forced re-login attempt on a 401
36
+ * response. Helps avoid triggering fail2ban or 3x-ui login-rate limits in
37
+ * serverless / multi-instance environments. Set to 0 to disable.
38
+ * @default 500
39
+ */
40
+ loginRetryBackoff?: number;
21
41
  }
22
42
 
23
43
  export interface LoginResponse {
24
44
  success: boolean;
25
45
  fromCache?: boolean;
46
+ cookie?: string | null;
26
47
  headers?: any;
27
48
  data: any;
49
+ message?: string;
28
50
  }
29
51
 
30
52
  export interface InboundConfig {
@@ -42,6 +64,218 @@ declare module '3xui-api-client' {
42
64
  settings: string;
43
65
  }
44
66
 
67
+ // ===========================================
68
+ // MODERN API INTERFACES (3X-UI >= 2.x)
69
+ // ===========================================
70
+
71
+ /** Standard envelope returned by /panel/api/* (Modern API) endpoints. */
72
+ export interface ModernApiResponse<T = any> {
73
+ success: boolean;
74
+ msg: string;
75
+ obj: T;
76
+ }
77
+
78
+ export interface ModernClient {
79
+ id?: number;
80
+ email: string;
81
+ subId?: string;
82
+ uuid?: string;
83
+ password?: string;
84
+ flow?: string;
85
+ security?: string;
86
+ limitIp?: number;
87
+ /** Data limit in gigabytes (auto-converted to bytes internally) */
88
+ totalGB?: number;
89
+ expiryTime?: number;
90
+ enable?: boolean;
91
+ tgId?: number | string;
92
+ group?: string;
93
+ comment?: string;
94
+ reset?: number;
95
+ createdAt?: number;
96
+ updatedAt?: number;
97
+ [key: string]: any;
98
+ }
99
+
100
+ export interface ModernClientDetail {
101
+ client: ModernClient;
102
+ inboundIds: number[];
103
+ }
104
+
105
+ export interface ModernClientTraffic {
106
+ id: number;
107
+ inboundId: number;
108
+ enable: boolean;
109
+ email: string;
110
+ uuid?: string;
111
+ subId?: string;
112
+ up: number;
113
+ down: number;
114
+ expiryTime: number;
115
+ total: number;
116
+ reset: number;
117
+ lastOnline: number;
118
+ }
119
+
120
+ export interface PagedClientsResult {
121
+ items: Array<ModernClient & { traffic?: ModernClientTraffic }>;
122
+ total: number;
123
+ filtered: number;
124
+ page: number;
125
+ pageSize: number;
126
+ summary?: Record<string, any>;
127
+ }
128
+
129
+ export interface AddModernClientPayload {
130
+ inboundIds: number[];
131
+ client: ModernClient;
132
+ }
133
+
134
+ export interface BulkCreateClientEntry {
135
+ inboundIds: number[];
136
+ client: ModernClient;
137
+ }
138
+
139
+ export interface BulkSkipReport {
140
+ email: string;
141
+ reason: string;
142
+ }
143
+
144
+ export interface BulkCreateResult {
145
+ created: number;
146
+ skipped?: BulkSkipReport[];
147
+ }
148
+
149
+ export interface BulkAdjustPayload {
150
+ emails: string[];
151
+ /** Days to add (or subtract, if negative) to expiryTime. Clients with unlimited expiry (0) are skipped. */
152
+ addDays?: number;
153
+ /** Bytes to add (or subtract, if negative) to totalGB. Clients with unlimited traffic (0) are skipped. */
154
+ addBytes?: number;
155
+ }
156
+
157
+ export interface BulkAdjustResult {
158
+ adjusted: number;
159
+ skipped?: BulkSkipReport[];
160
+ }
161
+
162
+ export interface BulkDeleteResult {
163
+ deleted: number;
164
+ skipped?: BulkSkipReport[];
165
+ }
166
+
167
+ export interface BulkAttachDetachResult {
168
+ attached?: string[] | null;
169
+ detached?: string[] | null;
170
+ skipped?: string[] | null;
171
+ errors?: string[];
172
+ }
173
+
174
+ export interface BulkAffectedResult {
175
+ affected: number;
176
+ }
177
+
178
+ export interface ModernGroup {
179
+ name: string;
180
+ clientCount: number;
181
+ trafficUsed: number;
182
+ }
183
+
184
+ export interface CustomGeoResource {
185
+ id: number;
186
+ type: 'geosite' | 'geoip';
187
+ alias: string;
188
+ url: string;
189
+ localPath?: string;
190
+ lastUpdatedAt?: number;
191
+ lastModified?: string;
192
+ createdAt?: number;
193
+ updatedAt?: number;
194
+ }
195
+
196
+ export interface AddCustomGeoPayload {
197
+ type: 'geosite' | 'geoip';
198
+ alias: string;
199
+ url: string;
200
+ }
201
+
202
+ export interface AddNodePayload {
203
+ name: string;
204
+ remark?: string;
205
+ /** URL scheme of the node's panel, e.g. 'http' | 'https'. */
206
+ scheme: string;
207
+ address: string;
208
+ port: number;
209
+ /** Base path of the node's panel (must end with '/'), e.g. '/abc123/'. */
210
+ basePath: string;
211
+ /** Required - the API token configured on the target node's panel. */
212
+ apiToken: string;
213
+ enable?: boolean;
214
+ /** Required to register a node at a private/internal address (e.g. self-registration). */
215
+ allowPrivateAddress?: boolean;
216
+ /** TLS certificate verification mode for connecting to the node, e.g. 'verify' | 'skip'. */
217
+ tlsVerifyMode?: string;
218
+ /** Pinned certificate SHA-256 fingerprint, used when tlsVerifyMode requires pinning. */
219
+ pinnedCertSha256?: string;
220
+ [key: string]: any;
221
+ }
222
+
223
+ export interface NodeData {
224
+ id: number;
225
+ name: string;
226
+ remark: string;
227
+ scheme: string;
228
+ address: string;
229
+ port: number;
230
+ basePath: string;
231
+ apiToken: string;
232
+ enable: boolean;
233
+ allowPrivateAddress: boolean;
234
+ tlsVerifyMode: string;
235
+ pinnedCertSha256: string;
236
+ guid: string;
237
+ status: string;
238
+ lastHeartbeat: number;
239
+ latencyMs: number;
240
+ xrayVersion: string;
241
+ panelVersion: string;
242
+ cpuPct: number;
243
+ memPct: number;
244
+ uptimeSecs: number;
245
+ lastError: string;
246
+ xrayState: string;
247
+ xrayError: string;
248
+ configDirty: boolean;
249
+ configDirtyAt: number;
250
+ inboundCount: number;
251
+ clientCount: number;
252
+ onlineCount: number;
253
+ depletedCount: number;
254
+ createdAt: number;
255
+ updatedAt: number;
256
+ [key: string]: any;
257
+ }
258
+
259
+ export interface NodeHistoryPoint {
260
+ /** Unix timestamp in seconds */
261
+ t: number;
262
+ /** Metric value at time `t` */
263
+ v: number;
264
+ }
265
+
266
+ export interface TestNodeResult {
267
+ status: 'online' | 'offline' | string;
268
+ latencyMs: number;
269
+ xrayVersion: string;
270
+ panelVersion: string;
271
+ cpuPct: number;
272
+ memPct: number;
273
+ uptimeSecs: number;
274
+ error: string;
275
+ xrayState: string;
276
+ xrayError: string;
277
+ }
278
+
45
279
  // ===========================================
46
280
  // CREDENTIAL GENERATION INTERFACES
47
281
  // ===========================================
@@ -55,6 +289,7 @@ declare module '3xui-api-client' {
55
289
  method?: string;
56
290
  username?: string;
57
291
  limitIp?: number;
292
+ /** Data limit in gigabytes (auto-converted to bytes internally) */
58
293
  totalGB?: number;
59
294
  expiryTime?: number;
60
295
  enable?: boolean;
@@ -267,66 +502,66 @@ declare module '3xui-api-client' {
267
502
  // ===========================================
268
503
 
269
504
  // --- Clients ---
270
- getClients(): Promise<any>;
505
+ getClients(): Promise<ModernApiResponse<ModernClient[]>>;
271
506
  getPagedClients(params?: {
272
507
  page?: number;
273
508
  size?: number;
274
509
  sort?: string;
275
510
  order?: 'asc' | 'desc';
276
511
  email?: string;
277
- }): Promise<any>;
278
- getClient(email: string): Promise<any>;
279
- getClientTraffic(email: string): Promise<any>;
280
- getSubLinks(subId: string): Promise<any>;
281
- getClientLinks(email: string): Promise<any>;
282
- addModernClient(data: any): Promise<any>;
283
- updateModernClient(email: string, data: any): Promise<any>;
284
- deleteModernClient(email: string): Promise<any>;
285
- attachClientToInbounds(email: string, data: any): Promise<any>;
286
- detachClientFromInbounds(email: string, data: any): Promise<any>;
287
- resetAllModernClientTraffics(): Promise<any>;
288
- deleteDepletedModernClients(): Promise<any>;
289
- bulkAdjustModernClients(data: any): Promise<any>;
290
- bulkDeleteModernClients(data: any): Promise<any>;
291
- bulkCreateModernClients(data: any): Promise<any>;
292
- bulkAttachModernClients(data: any): Promise<any>;
293
- bulkDetachModernClients(data: any): Promise<any>;
294
- bulkResetTrafficModernClients(data: any): Promise<any>;
295
- resetModernClientTrafficByEmail(email: string): Promise<any>;
296
- updateModernClientTrafficByEmail(email: string, data: any): Promise<any>;
297
- getModernClientIps(email: string): Promise<any>;
298
- clearModernClientIps(email: string): Promise<any>;
299
- getOnlines(): Promise<any>;
300
- getModernLastOnline(): Promise<any>;
512
+ }): Promise<ModernApiResponse<PagedClientsResult>>;
513
+ getClient(email: string): Promise<ModernApiResponse<ModernClientDetail>>;
514
+ getClientTraffic(email: string): Promise<ModernApiResponse<ModernClientTraffic>>;
515
+ getSubLinks(subId: string): Promise<ModernApiResponse<string[]>>;
516
+ getClientLinks(email: string): Promise<ModernApiResponse<string[]>>;
517
+ addModernClient(data: AddModernClientPayload): Promise<ModernApiResponse<null>>;
518
+ updateModernClient(email: string, data: Partial<ModernClient>): Promise<ModernApiResponse<null>>;
519
+ deleteModernClient(email: string): Promise<ModernApiResponse<null>>;
520
+ attachClientToInbounds(email: string, data: { inboundIds: number[] }): Promise<ModernApiResponse<any>>;
521
+ detachClientFromInbounds(email: string, data: { inboundIds: number[] }): Promise<ModernApiResponse<any>>;
522
+ resetAllModernClientTraffics(): Promise<ModernApiResponse<null>>;
523
+ deleteDepletedModernClients(): Promise<ModernApiResponse<{ deleted: number }>>;
524
+ bulkAdjustModernClients(data: BulkAdjustPayload): Promise<ModernApiResponse<BulkAdjustResult>>;
525
+ bulkDeleteModernClients(data: { emails: string[] }): Promise<ModernApiResponse<BulkDeleteResult>>;
526
+ bulkCreateModernClients(data: BulkCreateClientEntry[]): Promise<ModernApiResponse<BulkCreateResult>>;
527
+ bulkAttachModernClients(data: { emails: string[]; inboundIds: number[] }): Promise<ModernApiResponse<BulkAttachDetachResult>>;
528
+ bulkDetachModernClients(data: { emails: string[]; inboundIds: number[] }): Promise<ModernApiResponse<BulkAttachDetachResult>>;
529
+ bulkResetTrafficModernClients(data: { emails: string[] }): Promise<ModernApiResponse<BulkAffectedResult>>;
530
+ resetModernClientTrafficByEmail(email: string): Promise<ModernApiResponse<null>>;
531
+ updateModernClientTrafficByEmail(email: string, data: { up: number; down: number }): Promise<ModernApiResponse<null>>;
532
+ getModernClientIps(email: string): Promise<ModernApiResponse<string[] | string>>;
533
+ clearModernClientIps(email: string): Promise<ModernApiResponse<null>>;
534
+ getOnlines(): Promise<ModernApiResponse<string[]>>;
535
+ getModernLastOnline(): Promise<ModernApiResponse<Record<string, number>>>;
301
536
 
302
537
  // --- Client Groups ---
303
- getGroups(): Promise<any>;
304
- getGroupEmails(groupName: string): Promise<any>;
305
- createGroup(data: any): Promise<any>;
306
- renameGroup(data: any): Promise<any>;
307
- deleteGroup(data: any): Promise<any>;
308
- bulkAddGroups(data: any): Promise<any>;
309
- bulkRemoveGroups(data: any): Promise<any>;
538
+ getGroups(): Promise<ModernApiResponse<ModernGroup[]>>;
539
+ getGroupEmails(groupName: string): Promise<ModernApiResponse<string[]>>;
540
+ createGroup(data: { name: string }): Promise<ModernApiResponse<any>>;
541
+ renameGroup(data: { oldName: string; newName: string }): Promise<ModernApiResponse<any>>;
542
+ deleteGroup(data: { name: string }): Promise<ModernApiResponse<any>>;
543
+ bulkAddGroups(data: { emails: string[]; group: string }): Promise<ModernApiResponse<BulkAffectedResult>>;
544
+ bulkRemoveGroups(data: { emails: string[] }): Promise<ModernApiResponse<BulkAffectedResult>>;
310
545
 
311
546
  // --- Nodes ---
312
- getNodes(): Promise<any>;
313
- getNode(id: number | string): Promise<any>;
314
- getNodeHistory(id: number | string, metric: string, bucket: string): Promise<any>;
315
- addNode(data: any): Promise<any>;
316
- updateNode(id: number | string, data: any): Promise<any>;
317
- deleteNode(id: number | string): Promise<any>;
318
- setNodeEnable(id: number | string): Promise<any>;
319
- testNode(data: any): Promise<any>;
320
- probeNode(id: number | string): Promise<any>;
547
+ getNodes(): Promise<ModernApiResponse<NodeData[]>>;
548
+ getNode(id: number | string): Promise<ModernApiResponse<NodeData>>;
549
+ getNodeHistory(id: number | string, metric: string, bucket: number | string): Promise<ModernApiResponse<NodeHistoryPoint[]>>;
550
+ addNode(data: AddNodePayload): Promise<ModernApiResponse<NodeData>>;
551
+ updateNode(id: number | string, data: Partial<AddNodePayload>): Promise<ModernApiResponse<null>>;
552
+ deleteNode(id: number | string): Promise<ModernApiResponse<null>>;
553
+ setNodeEnable(id: number | string, enable?: boolean): Promise<ModernApiResponse<null>>;
554
+ testNode(data: AddNodePayload | { address: string; port: number; [key: string]: any }): Promise<ModernApiResponse<TestNodeResult>>;
555
+ probeNode(id: number | string): Promise<ModernApiResponse<TestNodeResult>>;
321
556
 
322
557
  // --- Custom Geo ---
323
- getCustomGeos(): Promise<any>;
324
- getGeoAliases(): Promise<any>;
325
- addCustomGeo(data: any): Promise<any>;
326
- updateCustomGeo(id: string | number, data: any): Promise<any>;
327
- deleteCustomGeo(id: string | number): Promise<any>;
328
- downloadCustomGeo(id: string | number): Promise<any>;
329
- updateAllCustomGeo(): Promise<any>;
558
+ getCustomGeos(): Promise<ModernApiResponse<CustomGeoResource[]>>;
559
+ getGeoAliases(): Promise<ModernApiResponse<{ geosite: string[] | null; geoip: string[] | null }>>;
560
+ addCustomGeo(data: AddCustomGeoPayload): Promise<ModernApiResponse<null>>;
561
+ updateCustomGeo(id: string | number, data: AddCustomGeoPayload): Promise<ModernApiResponse<null>>;
562
+ deleteCustomGeo(id: string | number): Promise<ModernApiResponse<any>>;
563
+ downloadCustomGeo(id: string | number): Promise<ModernApiResponse<any>>;
564
+ updateAllCustomGeo(): Promise<ModernApiResponse<{ succeeded: string[] | null; failed: string[] | null }>>;
330
565
 
331
566
  // ===========================================
332
567
  // Original API Methods
@@ -336,11 +571,16 @@ declare module '3xui-api-client' {
336
571
  addInbound(inboundConfig: InboundConfig): Promise<any>;
337
572
  deleteInbound(id: number): Promise<any>;
338
573
  updateInbound(id: number, inboundConfig: InboundConfig): Promise<any>;
574
+ importInbounds(inbounds: InboundConfig | InboundConfig[]): Promise<any[]>;
575
+ getLastOnline(): Promise<any>;
339
576
  addClient(clientConfig: ClientConfig): Promise<any>;
340
577
  deleteClient(inboundId: number, clientId: string): Promise<any>;
341
578
  updateClient(clientId: string, clientConfig: ClientConfig): Promise<any>;
579
+ /** @param trafficConfig.totalGB Data limit in gigabytes (auto-converted to bytes internally) */
580
+ updateClientTraffic(email: string, trafficConfig: { totalGB?: number; expiryTime?: number }): Promise<any>;
581
+ deleteClientByEmail(inboundId: number, email: string): Promise<any>;
342
582
  getClientTrafficsByEmail(email: string): Promise<any>;
343
- getClientTrafficsById(id: number): Promise<any>;
583
+ getClientTrafficsById(id: string): Promise<any>;
344
584
  getClientIps(email: string): Promise<any>;
345
585
  clearClientIps(email: string): Promise<any>;
346
586
  resetClientTraffic(inboundId: number, email: string): Promise<any>;
@@ -353,6 +593,83 @@ declare module '3xui-api-client' {
353
593
 
354
594
  // Server Management
355
595
  getServerStatus(): Promise<any>;
596
+ /**
597
+ * Get CPU usage history.
598
+ * @param bucket - Bucket size in seconds. Must be one of: 2, 30, 60, 120, 180, 300 (default: 60)
599
+ */
600
+ getCPUHistory(bucket?: number): Promise<any>;
601
+ getXrayVersion(): Promise<any>;
602
+ getConfigJson(): Promise<any>;
603
+ /**
604
+ * Download database.
605
+ * @returns Raw SQLite database file content as a string (starts with "SQLite format 3 ..."), not a Buffer
606
+ */
607
+ getDb(): Promise<ModernApiResponse<string>>;
608
+ stopXrayService(): Promise<any>;
609
+ restartXrayService(): Promise<any>;
610
+ /**
611
+ * Install specific Xray version.
612
+ * @param version - Version to install (e.g., "1.8.0").
613
+ * @throws {Error} If `version` is not a non-empty string or is "latest".
614
+ */
615
+ installXray(version: string): Promise<any>;
616
+ getPanelLogs(count?: number): Promise<any>;
617
+ getXrayLogs(count?: number): Promise<any>;
618
+ updateGeofile(fileName?: string): Promise<any>;
619
+ /**
620
+ * Import database.
621
+ * @param formData - FormData containing the database file
622
+ */
623
+ importDB(formData: any): Promise<any>;
624
+
625
+ // --- Panel Settings ---
626
+ getAllSettings(): Promise<any>;
627
+ /**
628
+ * Update panel settings
629
+ * NOTE: API requires ALL settings to be sent together.
630
+ * This method automatically fetches current settings, merges your updates, and sends all.
631
+ * @param updates - Partial settings object (will be merged with current settings)
632
+ * Example: updateSetting({ webPort: 7070 }) - will fetch all settings, update webPort, send all
633
+ */
634
+ updateSetting(updates: Record<string, any>): Promise<any>;
635
+ /**
636
+ * Update admin username and password
637
+ * ⚠️ CRITICAL: This endpoint changes your login credentials.
638
+ * After update, internal credentials are refreshed and session re-authenticated.
639
+ * If re-authentication fails, old credentials are restored and error is thrown.
640
+ * See test/PHASE-C-CRITICAL-FINDINGS.md for security considerations.
641
+ */
642
+ updateUser(oldUsername: string, oldPassword: string, newUsername: string, newPassword: string): Promise<any>;
643
+ restartPanel(): Promise<any>;
644
+ getDefaultSettings(): Promise<any>;
645
+ getDefaultJsonConfig(): Promise<any>;
646
+
647
+ // --- Xray Configuration ---
648
+ getXrayConfig(): Promise<any>;
649
+ /**
650
+ * Update Xray configuration.
651
+ * @param config - Xray configuration content (JSON string or object).
652
+ * @throws {Error} If `config` is an invalid JSON string or not a valid object.
653
+ */
654
+ updateXrayConfig(config: string | object): Promise<any>;
655
+ /**
656
+ * Manage WARP.
657
+ * @param action - Action to perform (data, del, config, reg, changeIp, license, interval)
658
+ * @param data - Additional data for the action
659
+ */
660
+ manageWarp(action: string, data?: Record<string, any>): Promise<any>;
661
+ getOutboundsTraffic(): Promise<any>;
662
+ resetOutboundsTraffic(): Promise<any>;
663
+ getXrayResult(): Promise<any>;
664
+
665
+ // --- Server-side credential / certificate generators ---
666
+ getNewUUID(): Promise<ModernApiResponse<{ uuid: string }>>;
667
+ getNewX25519Cert(): Promise<ModernApiResponse<{ privateKey: string; publicKey: string; password?: string }>>;
668
+ getNewmldsa65(): Promise<ModernApiResponse<{ verify: string; seed: string }>>;
669
+ getNewmlkem768(): Promise<ModernApiResponse<{ seed: string; client: string }>>;
670
+ getNewVlessEnc(): Promise<ModernApiResponse<Record<string, string>>>;
671
+ getNewEchCert(sni?: string): Promise<ModernApiResponse<{ echServerKeys: string; echConfigList: string }>>;
672
+ getWebCertFiles(): Promise<ModernApiResponse<any>>;
356
673
  }
357
674
 
358
675
  // ===========================================