3xui-api-client 2.1.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
@@ -16,13 +16,37 @@ declare module '3xui-api-client' {
16
16
  isDevelopment?: boolean;
17
17
  enableCSP?: boolean;
18
18
  userAgent?: string;
19
+ token?: string;
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;
19
41
  }
20
42
 
21
43
  export interface LoginResponse {
22
44
  success: boolean;
23
45
  fromCache?: boolean;
46
+ cookie?: string | null;
24
47
  headers?: any;
25
48
  data: any;
49
+ message?: string;
26
50
  }
27
51
 
28
52
  export interface InboundConfig {
@@ -40,6 +64,218 @@ declare module '3xui-api-client' {
40
64
  settings: string;
41
65
  }
42
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
+
43
279
  // ===========================================
44
280
  // CREDENTIAL GENERATION INTERFACES
45
281
  // ===========================================
@@ -53,6 +289,7 @@ declare module '3xui-api-client' {
53
289
  method?: string;
54
290
  username?: string;
55
291
  limitIp?: number;
292
+ /** Data limit in gigabytes (auto-converted to bytes internally) */
56
293
  totalGB?: number;
57
294
  expiryTime?: number;
58
295
  enable?: boolean;
@@ -226,6 +463,7 @@ declare module '3xui-api-client' {
226
463
 
227
464
  export default class ThreeXUI {
228
465
  constructor(baseURL: string, username: string, password: string, options?: ThreeXUIOptions);
466
+ constructor(baseURL: string, options: ThreeXUIOptions);
229
467
 
230
468
  // Authentication
231
469
  login(forceRefresh?: boolean): Promise<LoginResponse>;
@@ -252,24 +490,97 @@ declare module '3xui-api-client' {
252
490
 
253
491
  // Enhanced Client Management
254
492
  addClientWithCredentials(inboundId: number, protocol: string, options?: CredentialOptions): Promise<any>;
255
- updateClientWithCredentials(clientId: string, inboundId: number, options?: CredentialOptions): Promise<any>;
493
+ updateClientWithCredentials(clientId: string, inboundId: number, options?: CredentialOptions): Promise<any>;
256
494
 
257
495
  // Session Management
258
496
  getSessionStats(): Promise<any>;
259
497
  clearAllSessions(): Promise<void>;
260
498
  isSessionValid(): Promise<boolean>;
261
499
 
500
+ // ===========================================
501
+ // Modern API Methods (3X-UI >= 2.x)
502
+ // ===========================================
503
+
504
+ // --- Clients ---
505
+ getClients(): Promise<ModernApiResponse<ModernClient[]>>;
506
+ getPagedClients(params?: {
507
+ page?: number;
508
+ size?: number;
509
+ sort?: string;
510
+ order?: 'asc' | 'desc';
511
+ email?: string;
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>>>;
536
+
537
+ // --- Client Groups ---
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>>;
545
+
546
+ // --- Nodes ---
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>>;
556
+
557
+ // --- Custom Geo ---
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 }>>;
565
+
566
+ // ===========================================
262
567
  // Original API Methods
568
+ // ===========================================
263
569
  getInbounds(): Promise<any>;
264
570
  getInbound(id: number): Promise<any>;
265
571
  addInbound(inboundConfig: InboundConfig): Promise<any>;
266
572
  deleteInbound(id: number): Promise<any>;
267
573
  updateInbound(id: number, inboundConfig: InboundConfig): Promise<any>;
574
+ importInbounds(inbounds: InboundConfig | InboundConfig[]): Promise<any[]>;
575
+ getLastOnline(): Promise<any>;
268
576
  addClient(clientConfig: ClientConfig): Promise<any>;
269
577
  deleteClient(inboundId: number, clientId: string): Promise<any>;
270
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>;
271
582
  getClientTrafficsByEmail(email: string): Promise<any>;
272
- getClientTrafficsById(id: number): Promise<any>;
583
+ getClientTrafficsById(id: string): Promise<any>;
273
584
  getClientIps(email: string): Promise<any>;
274
585
  clearClientIps(email: string): Promise<any>;
275
586
  resetClientTraffic(inboundId: number, email: string): Promise<any>;
@@ -282,6 +593,83 @@ declare module '3xui-api-client' {
282
593
 
283
594
  // Server Management
284
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>>;
285
673
  }
286
674
 
287
675
  // ===========================================