3xui-api-client 2.0.0 → 2.1.1

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
@@ -11,6 +11,11 @@ declare module '3xui-api-client' {
11
11
  sessionManager?: SessionManager | SessionConfig;
12
12
  autoGenerateCredentials?: boolean;
13
13
  timeout?: number;
14
+ maxRequestsPerMinute?: number;
15
+ maxLoginAttemptsPerHour?: number;
16
+ isDevelopment?: boolean;
17
+ enableCSP?: boolean;
18
+ userAgent?: string;
14
19
  }
15
20
 
16
21
  export interface LoginResponse {
@@ -237,9 +242,17 @@ declare module '3xui-api-client' {
237
242
  generateRealityKeys(): RealityKeys;
238
243
  generatePort(min?: number, max?: number): number;
239
244
  validateCredentials(credentials: any, protocol: string): ValidationResult;
245
+
246
+ // Security helpers
247
+ getSecurityStats(): any;
248
+ clearBlockedIPs(): void;
249
+ validateCredentialStrength(credential: string, type: 'password' | 'uuid' | 'port'): { isValid: boolean; issues: string[]; strength: 'weak' | 'medium' | 'strong' };
250
+ generateSecureToken(): string;
251
+ setDevelopmentMode(enabled: boolean): void;
240
252
 
241
253
  // Enhanced Client Management
242
254
  addClientWithCredentials(inboundId: number, protocol: string, options?: CredentialOptions): Promise<any>;
255
+ updateClientWithCredentials(clientId: string, inboundId: number, options?: CredentialOptions): Promise<any>;
243
256
 
244
257
  // Session Management
245
258
  getSessionStats(): Promise<any>;
@@ -265,11 +278,10 @@ declare module '3xui-api-client' {
265
278
  deleteDepletedClients(inboundId: number): Promise<any>;
266
279
  getOnlineClients(): Promise<any>;
267
280
  createBackup(): Promise<any>;
281
+ backupToTgBot(): Promise<any>;
268
282
 
269
- // Static exports
270
- static CredentialGenerator: typeof CredentialGenerator;
271
- static SessionManager: typeof SessionManager;
272
- static createSessionManager: (options?: SessionConfig) => SessionManager;
283
+ // Server Management
284
+ getServerStatus(): Promise<any>;
273
285
  }
274
286
 
275
287
  // ===========================================
@@ -284,7 +296,6 @@ declare module '3xui-api-client' {
284
296
  static generateWireGuardKeys(): WireGuardKeys;
285
297
  static generateRealityKeys(): RealityKeys;
286
298
  static generateUsername(prefix?: string): string;
287
- static generateEmail(domain?: string): string;
288
299
  static getRecommendedShadowsocksCipher(): string;
289
300
  static getShadowsocksCipherMethods(): string[];
290
301
  static generatePort(min?: number, max?: number): number;
@@ -413,4 +424,13 @@ declare module '3xui-api-client' {
413
424
  shadowsocks(options?: any): BuilderConfig;
414
425
  };
415
426
  }
416
- }
427
+
428
+ // Optional: expose security helpers for advanced users
429
+ export const SecurityEnhancer: {
430
+ InputValidator: any;
431
+ SecureHeaders: any;
432
+ SecurityMonitor: any;
433
+ CredentialSecurity: any;
434
+ ErrorSecurity: any;
435
+ };
436
+ }
package/index.js CHANGED
@@ -45,6 +45,14 @@ class ThreeXUI {
45
45
 
46
46
  // Apply security validations
47
47
  this.baseURL = InputValidator.validateURL(baseURL);
48
+
49
+ // Warning for common configuration error
50
+ if (this.baseURL.endsWith('/panel') || this.baseURL.endsWith('/panel/')) {
51
+ console.warn('WARNING: baseURL should NOT end with "/panel". The library appends this automatically. Please remove it from your configuration.');
52
+ // Auto-fix for better user experience
53
+ this.baseURL = this.baseURL.replace(/\/panel\/?$/, '');
54
+ }
55
+
48
56
  this.username = InputValidator.validateUsername(username);
49
57
  this.password = InputValidator.validatePassword(password);
50
58
  this.cookie = null;
@@ -174,6 +182,7 @@ class ThreeXUI {
174
182
  return {
175
183
  success: true,
176
184
  fromCache: false,
185
+ cookie: this.cookie, // Explicitly return the cookie
177
186
  headers: response.headers,
178
187
  data: response.data
179
188
  };
@@ -206,6 +215,12 @@ class ThreeXUI {
206
215
  * Logout and clear session
207
216
  */
208
217
  async logout() {
218
+ try {
219
+ await this._request('get', '/logout');
220
+ } catch {
221
+ // Ignore server-side logout errors, proceed to clear local session
222
+ }
223
+
209
224
  this.cookie = null;
210
225
  delete this.api.defaults.headers.Cookie;
211
226
 
@@ -214,6 +229,14 @@ class ThreeXUI {
214
229
  }
215
230
  }
216
231
 
232
+ /**
233
+ * Check if Two-Factor Authentication is enabled
234
+ * @returns {Promise<Object>} 2FA status
235
+ */
236
+ getTwoFactorEnable() {
237
+ return this._request('post', '/getTwoFactorEnable');
238
+ }
239
+
217
240
  async _request(method, path, data = {}) {
218
241
  // Check session validity first with mutex protection
219
242
  if (!this.loginMutex && this.sessionManager && !await this.sessionManager.hasValidSession(this.baseURL, this.username)) {
@@ -436,7 +459,8 @@ class ThreeXUI {
436
459
  const processedOptions = {
437
460
  email: options.email || existingClients[clientIndex].email,
438
461
  limitIp: options.limitIp !== undefined ? options.limitIp : existingClients[clientIndex].limitIp,
439
- totalGB: options.totalGB ? options.totalGB * 1024 * 1024 * 1024 : existingClients[clientIndex].totalGB,
462
+ // totalGB is specified in gigabytes in 3x-ui config; do not convert to bytes
463
+ totalGB: options.totalGB !== undefined ? options.totalGB : existingClients[clientIndex].totalGB,
440
464
  expiryTime: options.expiryDays ? Date.now() + (options.expiryDays * 24 * 60 * 60 * 1000) : existingClients[clientIndex].expiryTime,
441
465
  enable: options.enable !== undefined ? options.enable : existingClients[clientIndex].enable,
442
466
  flow: options.flow || existingClients[clientIndex].flow,
@@ -466,7 +490,7 @@ class ThreeXUI {
466
490
  ...result,
467
491
  updatedOptions: processedOptions,
468
492
  conversions: {
469
- totalGB: options.totalGB ? `${options.totalGB}GB → ${processedOptions.totalGB} bytes` : 'unchanged',
493
+ totalGB: options.totalGB !== undefined ? `${options.totalGB}GB` : 'unchanged',
470
494
  expiryDays: options.expiryDays ? `${options.expiryDays} days → ${new Date(processedOptions.expiryTime).toISOString()}` : 'unchanged'
471
495
  }
472
496
  };
@@ -544,6 +568,21 @@ class ThreeXUI {
544
568
  return this._request('post', `/panel/api/inbounds/update/${id}`, validatedConfig);
545
569
  }
546
570
 
571
+ /**
572
+ * Import inbounds
573
+ * @param {Array} inbounds - Array of inbound configurations
574
+ */
575
+ importInbounds(inbounds) {
576
+ return this._request('post', '/panel/api/inbounds/import', { inbounds });
577
+ }
578
+
579
+ /**
580
+ * Get last online time for clients
581
+ */
582
+ getLastOnline() {
583
+ return this._request('post', '/panel/api/inbounds/lastOnline');
584
+ }
585
+
547
586
  // Clients
548
587
  addClient(clientConfig) {
549
588
  // Validate client configuration for security
@@ -561,6 +600,24 @@ class ThreeXUI {
561
600
  return this._request('post', `/panel/api/inbounds/updateClient/${clientId}`, validatedConfig);
562
601
  }
563
602
 
603
+ /**
604
+ * Update client traffic limit and expiry by email
605
+ * @param {string} email - Client email
606
+ * @param {Object} trafficConfig - Traffic configuration (totalGB, expiryTime)
607
+ */
608
+ updateClientTraffic(email, trafficConfig) {
609
+ return this._request('post', `/panel/api/inbounds/updateClientTraffic/${email}`, trafficConfig);
610
+ }
611
+
612
+ /**
613
+ * Delete client by email
614
+ * @param {number} inboundId - Inbound ID
615
+ * @param {string} email - Client email
616
+ */
617
+ deleteClientByEmail(inboundId, email) {
618
+ return this._request('post', `/panel/api/inbounds/${inboundId}/delClientByEmail/${email}`);
619
+ }
620
+
564
621
  getClientTrafficsByEmail(email) {
565
622
  return this._request('get', `/panel/api/inbounds/getClientTraffics/${email}`);
566
623
  }
@@ -603,6 +660,248 @@ class ThreeXUI {
603
660
  return this._request('get', '/panel/api/inbounds/createbackup');
604
661
  }
605
662
 
663
+ /**
664
+ * Trigger sending a backup to Telegram bot admins
665
+ */
666
+ backupToTgBot() {
667
+ return this._request('post', '/panel/api/backuptotgbot');
668
+ }
669
+
670
+ // ===========================================
671
+ // SERVER MANAGEMENT
672
+ // ===========================================
673
+
674
+ /**
675
+ * Get server status (CPU, RAM, etc.)
676
+ */
677
+ getServerStatus() {
678
+ return this._request('get', '/panel/api/server/status');
679
+ }
680
+
681
+ /**
682
+ * Get CPU usage history
683
+ * @param {string} bucket - Time bucket (e.g., 'min', 'hour')
684
+ */
685
+ getCPUHistory(bucket = 'min') {
686
+ return this._request('get', `/panel/api/server/cpuHistory/${bucket}`);
687
+ }
688
+
689
+ /**
690
+ * Get current Xray version
691
+ */
692
+ getXrayVersion() {
693
+ return this._request('get', '/panel/api/server/getXrayVersion');
694
+ }
695
+
696
+ /**
697
+ * Get Xray config as JSON
698
+ */
699
+ getConfigJson() {
700
+ return this._request('get', '/panel/api/server/getConfigJson');
701
+ }
702
+
703
+ /**
704
+ * Download database
705
+ */
706
+ getDb() {
707
+ return this._request('get', '/panel/api/server/getDb');
708
+ }
709
+
710
+ /**
711
+ * Stop Xray core service
712
+ */
713
+ stopXrayService() {
714
+ return this._request('post', '/panel/api/server/stopXrayService');
715
+ }
716
+
717
+ /**
718
+ * Restart Xray core service
719
+ */
720
+ restartXrayService() {
721
+ return this._request('post', '/panel/api/server/restartXrayService');
722
+ }
723
+
724
+ /**
725
+ * Install specific Xray version
726
+ * @param {string} version - Version to install
727
+ */
728
+ installXray(version) {
729
+ return this._request('post', `/panel/api/server/installXray/${version}`);
730
+ }
731
+
732
+ /**
733
+ * Get panel logs
734
+ * @param {number} count - Number of logs to retrieve
735
+ */
736
+ getPanelLogs(count = 100) {
737
+ return this._request('post', `/panel/api/server/logs/${count}`);
738
+ }
739
+
740
+ /**
741
+ * Get Xray logs
742
+ * @param {number} count - Number of logs to retrieve
743
+ */
744
+ getXrayLogs(count = 100) {
745
+ return this._request('post', `/panel/api/server/xraylogs/${count}`);
746
+ }
747
+
748
+ /**
749
+ * Update GeoIP/GeoSite files
750
+ * @param {string} [fileName] - Specific file to update (optional)
751
+ */
752
+ updateGeofile(fileName) {
753
+ const url = fileName
754
+ ? `/panel/api/server/updateGeofile/${fileName}`
755
+ : '/panel/api/server/updateGeofile';
756
+ return this._request('post', url);
757
+ }
758
+
759
+ /**
760
+ * Import database
761
+ * @param {FormData} formData - FormData containing the database file
762
+ */
763
+ async importDB(formData) {
764
+ // Ensure authenticated before direct API call
765
+ if (!this.cookie) {
766
+ await this._ensureAuthenticated();
767
+ }
768
+ // Use direct api call to handle multipart/form-data correctly
769
+ return this.api.post('/panel/api/server/importDB', formData);
770
+ }
771
+
772
+ // ===========================================
773
+ // SERVER-SIDE GENERATORS
774
+ // ===========================================
775
+
776
+ getNewUUID() {
777
+ return this._request('get', '/panel/api/server/getNewUUID');
778
+ }
779
+
780
+ getNewX25519Cert() {
781
+ return this._request('get', '/panel/api/server/getNewX25519Cert');
782
+ }
783
+
784
+ getNewmldsa65() {
785
+ return this._request('get', '/panel/api/server/getNewmldsa65');
786
+ }
787
+
788
+ getNewmlkem768() {
789
+ return this._request('get', '/panel/api/server/getNewmlkem768');
790
+ }
791
+
792
+ getNewVlessEnc() {
793
+ return this._request('get', '/panel/api/server/getNewVlessEnc');
794
+ }
795
+
796
+ getNewEchCert() {
797
+ return this._request('post', '/panel/api/server/getNewEchCert');
798
+ }
799
+
800
+ // ===========================================
801
+ // PANEL SETTINGS
802
+ // ===========================================
803
+
804
+ /**
805
+ * Get all panel settings
806
+ */
807
+ getAllSettings() {
808
+ return this._request('post', '/panel/setting/all');
809
+ }
810
+
811
+ /**
812
+ * Update panel settings
813
+ * @param {Object} settings - Settings to update
814
+ */
815
+ updateSetting(settings) {
816
+ return this._request('post', '/panel/setting/update', settings);
817
+ }
818
+
819
+ /**
820
+ * Update admin username and password
821
+ * @param {string} oldUsername - Current username
822
+ * @param {string} oldPassword - Current password
823
+ * @param {string} newUsername - New username
824
+ * @param {string} newPassword - New password
825
+ */
826
+ updateUser(oldUsername, oldPassword, newUsername, newPassword) {
827
+ return this._request('post', '/panel/setting/updateUser', {
828
+ oldUsername,
829
+ oldPassword,
830
+ newUsername,
831
+ newPassword
832
+ });
833
+ }
834
+
835
+ /**
836
+ * Restart the panel
837
+ */
838
+ restartPanel() {
839
+ return this._request('post', '/panel/setting/restartPanel');
840
+ }
841
+
842
+ /**
843
+ * Get default settings
844
+ */
845
+ getDefaultSettings() {
846
+ return this._request('post', '/panel/setting/defaultSettings');
847
+ }
848
+
849
+ /**
850
+ * Get default Xray JSON config
851
+ */
852
+ getDefaultJsonConfig() {
853
+ return this._request('get', '/panel/setting/getDefaultJsonConfig');
854
+ }
855
+
856
+ // ===========================================
857
+ // XRAY CONFIGURATION
858
+ // ===========================================
859
+
860
+ /**
861
+ * Get Xray configuration
862
+ */
863
+ getXrayConfig() {
864
+ return this._request('post', '/panel/xray/');
865
+ }
866
+
867
+ /**
868
+ * Update Xray configuration
869
+ * @param {string} config - Xray configuration content
870
+ */
871
+ updateXrayConfig(config) {
872
+ return this._request('post', '/panel/xray/update', { content: config });
873
+ }
874
+
875
+ /**
876
+ * Manage WARP
877
+ * @param {string} action - Action to perform (data, del, config, reg, license)
878
+ * @param {Object} [data] - Additional data for the action
879
+ */
880
+ manageWarp(action, data = {}) {
881
+ return this._request('post', `/panel/xray/warp/${action}`, data);
882
+ }
883
+
884
+ /**
885
+ * Get outbound traffic statistics
886
+ */
887
+ getOutboundsTraffic() {
888
+ return this._request('get', '/panel/xray/getOutboundsTraffic');
889
+ }
890
+
891
+ /**
892
+ * Reset outbound traffic statistics
893
+ */
894
+ resetOutboundsTraffic() {
895
+ return this._request('post', '/panel/xray/resetOutboundsTraffic');
896
+ }
897
+
898
+ /**
899
+ * Get Xray execution result
900
+ */
901
+ getXrayResult() {
902
+ return this._request('get', '/panel/xray/getXrayResult');
903
+ }
904
+
606
905
  // Security Methods
607
906
 
608
907
  /**
@@ -652,4 +951,63 @@ ThreeXUI.CredentialGenerator = CredentialGenerator;
652
951
  ThreeXUI.SessionManager = SessionManager;
653
952
  ThreeXUI.createSessionManager = createSessionManager;
654
953
 
655
- module.exports = ThreeXUI;
954
+ module.exports = ThreeXUI;
955
+
956
+ // Define lazy getters to avoid circular dependencies
957
+ Object.defineProperties(module.exports, {
958
+ // Web middleware helpers
959
+ createExpressMiddleware: {
960
+ enumerable: true,
961
+ get: () => require('./src/middleware/WebMiddleware').createExpressMiddleware
962
+ },
963
+ withThreeXUI: {
964
+ enumerable: true,
965
+ get: () => require('./src/middleware/WebMiddleware').withThreeXUI
966
+ },
967
+ createReactHook: {
968
+ enumerable: true,
969
+ get: () => require('./src/middleware/WebMiddleware').createReactHook
970
+ },
971
+ createNextjsRoutes: {
972
+ enumerable: true,
973
+ get: () => require('./src/middleware/WebMiddleware').createNextjsRoutes
974
+ },
975
+ SessionConfig: {
976
+ enumerable: true,
977
+ get: () => require('./src/middleware/WebMiddleware').SessionConfig
978
+ },
979
+ // Protocol builders
980
+ ProtocolBuilder: {
981
+ enumerable: true,
982
+ get: () => require('./src/builders/ProtocolBuilders').ProtocolBuilder
983
+ },
984
+ VLESSBuilder: {
985
+ enumerable: true,
986
+ get: () => require('./src/builders/ProtocolBuilders').VLESSBuilder
987
+ },
988
+ VMESSBuilder: {
989
+ enumerable: true,
990
+ get: () => require('./src/builders/ProtocolBuilders').VMESSBuilder
991
+ },
992
+ TrojanBuilder: {
993
+ enumerable: true,
994
+ get: () => require('./src/builders/ProtocolBuilders').TrojanBuilder
995
+ },
996
+ ShadowsocksBuilder: {
997
+ enumerable: true,
998
+ get: () => require('./src/builders/ProtocolBuilders').ShadowsocksBuilder
999
+ },
1000
+ WireGuardBuilder: {
1001
+ enumerable: true,
1002
+ get: () => require('./src/builders/ProtocolBuilders').WireGuardBuilder
1003
+ },
1004
+ BaseBuilder: {
1005
+ enumerable: true,
1006
+ get: () => require('./src/builders/ProtocolBuilders').BaseBuilder
1007
+ },
1008
+ // Security helpers
1009
+ SecurityEnhancer: {
1010
+ enumerable: true,
1011
+ get: () => require('./src/security/SecurityEnhancer')
1012
+ }
1013
+ });
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { createRequire } from 'module';
2
- const require = createRequire(import.meta.url);
3
- const ThreeXUI = require('./index.js');
4
-
1
+ import { createRequire } from 'module';
2
+ const require = createRequire(import.meta.url);
3
+ const ThreeXUI = require('./index.js');
4
+
5
5
  export default ThreeXUI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "3xui-api-client",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "A Node.js client library for 3x-ui panel API with built-in credential generation, session management, and web integration support",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",