@seaverse/auth-sdk 0.4.3 → 0.4.4

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/dist/index.d.ts CHANGED
@@ -88,16 +88,12 @@ declare class AuthFactory {
88
88
  static fromEnv(): AuthProvider;
89
89
  /**
90
90
  * 从配置文件创建认证提供者
91
- * @deprecated This method requires Node.js fs module and should not be used in browser environments.
92
- * Use AuthFactory.create() with a config object instead.
93
91
  */
94
- static fromFile(_path: string): Promise<AuthProvider>;
92
+ static fromFile(path: string): Promise<AuthProvider>;
95
93
  /**
96
94
  * 从profile创建认证提供者
97
- * @deprecated This method requires Node.js fs module and should not be used in browser environments.
98
- * Use AuthFactory.create() with a config object instead.
99
95
  */
100
- static fromProfile(_profileName?: string): Promise<AuthProvider>;
96
+ static fromProfile(profileName?: string): Promise<AuthProvider>;
101
97
  }
102
98
 
103
99
  type HookType = 'beforeRequest' | 'afterResponse' | 'onError' | 'onRetry';
@@ -1470,6 +1466,14 @@ declare class AuthModal {
1470
1466
  private createLeftPanel;
1471
1467
  private createRightPanel;
1472
1468
  private createLoginForm;
1469
+ /**
1470
+ * Create new style login view (OAuth-first)
1471
+ */
1472
+ private createNewStyleLoginView;
1473
+ /**
1474
+ * Create old style login view (Traditional email/password form with original CSS)
1475
+ */
1476
+ private createOldStyleLoginView;
1473
1477
  private createSignupForm;
1474
1478
  private createForgotPasswordForm;
1475
1479
  private createResetPasswordForm;
@@ -1497,6 +1501,14 @@ declare class AuthModal {
1497
1501
  */
1498
1502
  private bindSocialLoginButtons;
1499
1503
  private switchView;
1504
+ /**
1505
+ * Show new style login view (OAuth-first)
1506
+ */
1507
+ private showNewStyleLogin;
1508
+ /**
1509
+ * Show old style login view (traditional email/password form)
1510
+ */
1511
+ private showOldStyleLogin;
1500
1512
  private handleLogin;
1501
1513
  private handleSignup;
1502
1514
  private handleForgotPassword;
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import axios from 'axios';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
2
5
 
3
6
  /**
4
7
  * 生成UUID的跨平台函数
@@ -745,6 +748,113 @@ class CustomAuthProvider extends AuthProvider {
745
748
  }
746
749
  }
747
750
 
751
+ /**
752
+ * 配置管理器
753
+ */
754
+ class ConfigManager {
755
+ constructor(configDir) {
756
+ this.configDir = configDir || path.join(os.homedir(), '.openapi-sdk');
757
+ this.configPath = path.join(this.configDir, 'config.json');
758
+ }
759
+ /**
760
+ * 保存认证配置
761
+ */
762
+ async saveAuth(profileName, authConfig) {
763
+ await this.ensureConfigDir();
764
+ const config = await this.loadConfig();
765
+ config.profiles[profileName] = authConfig;
766
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), 'utf-8');
767
+ }
768
+ /**
769
+ * 加载认证配置
770
+ */
771
+ async loadAuth(profileName) {
772
+ const config = await this.loadConfig();
773
+ const authConfig = config.profiles[profileName];
774
+ if (!authConfig) {
775
+ throw new Error(`Profile '${profileName}' not found`);
776
+ }
777
+ return authConfig;
778
+ }
779
+ /**
780
+ * 列出所有profile
781
+ */
782
+ async listProfiles() {
783
+ const config = await this.loadConfig();
784
+ return Object.keys(config.profiles);
785
+ }
786
+ /**
787
+ * 删除profile
788
+ */
789
+ async removeProfile(profileName) {
790
+ const config = await this.loadConfig();
791
+ delete config.profiles[profileName];
792
+ await fs.writeFile(this.configPath, JSON.stringify(config, null, 2), 'utf-8');
793
+ }
794
+ /**
795
+ * 从文件加载配置
796
+ */
797
+ async loadFromFile(filePath) {
798
+ try {
799
+ const content = await fs.readFile(filePath, 'utf-8');
800
+ return JSON.parse(content);
801
+ }
802
+ catch (error) {
803
+ throw new Error(`Failed to load config from ${filePath}: ${error}`);
804
+ }
805
+ }
806
+ /**
807
+ * 保存配置到文件
808
+ */
809
+ async saveToFile(filePath, authConfig) {
810
+ try {
811
+ await fs.writeFile(filePath, JSON.stringify(authConfig, null, 2), 'utf-8');
812
+ }
813
+ catch (error) {
814
+ throw new Error(`Failed to save config to ${filePath}: ${error}`);
815
+ }
816
+ }
817
+ /**
818
+ * 加载完整配置文件
819
+ */
820
+ async loadConfig() {
821
+ try {
822
+ const content = await fs.readFile(this.configPath, 'utf-8');
823
+ return JSON.parse(content);
824
+ }
825
+ catch (error) {
826
+ if (error.code === 'ENOENT') {
827
+ // 文件不存在,返回默认配置
828
+ return { profiles: {} };
829
+ }
830
+ throw error;
831
+ }
832
+ }
833
+ /**
834
+ * 确保配置目录存在
835
+ */
836
+ async ensureConfigDir() {
837
+ try {
838
+ await fs.mkdir(this.configDir, { recursive: true });
839
+ }
840
+ catch (error) {
841
+ // 忽略错误,可能目录已存在
842
+ }
843
+ }
844
+ /**
845
+ * 获取配置目录路径
846
+ */
847
+ getConfigDir() {
848
+ return this.configDir;
849
+ }
850
+ /**
851
+ * 获取配置文件路径
852
+ */
853
+ getConfigPath() {
854
+ return this.configPath;
855
+ }
856
+ }
857
+
748
858
  /**
749
859
  * 跨平台环境配置工具
750
860
  * 支持 Node.js 和浏览器环境
@@ -877,19 +987,19 @@ class AuthFactory {
877
987
  }
878
988
  /**
879
989
  * 从配置文件创建认证提供者
880
- * @deprecated This method requires Node.js fs module and should not be used in browser environments.
881
- * Use AuthFactory.create() with a config object instead.
882
990
  */
883
- static async fromFile(_path) {
884
- throw new Error('AuthFactory.fromFile() is not available in browser environments. Please use AuthFactory.create() instead.');
991
+ static async fromFile(path) {
992
+ const configManager = new ConfigManager();
993
+ const config = await configManager.loadFromFile(path);
994
+ return this.create(config);
885
995
  }
886
996
  /**
887
997
  * 从profile创建认证提供者
888
- * @deprecated This method requires Node.js fs module and should not be used in browser environments.
889
- * Use AuthFactory.create() with a config object instead.
890
998
  */
891
- static async fromProfile(_profileName = 'default') {
892
- throw new Error('AuthFactory.fromProfile() is not available in browser environments. Please use AuthFactory.create() instead.');
999
+ static async fromProfile(profileName = 'default') {
1000
+ const configManager = new ConfigManager();
1001
+ const config = await configManager.loadAuth(profileName);
1002
+ return this.create(config);
893
1003
  }
894
1004
  }
895
1005
 
@@ -2804,6 +2914,97 @@ class AuthModal {
2804
2914
  const container = document.createElement('div');
2805
2915
  container.id = 'loginForm';
2806
2916
  container.className = 'auth-form-view';
2917
+ // NEW STYLE VIEW (OAuth-first, shown by default)
2918
+ const newStyleView = this.createNewStyleLoginView();
2919
+ container.appendChild(newStyleView);
2920
+ // OLD STYLE VIEW (Traditional email/password, hidden by default)
2921
+ const oldStyleView = this.createOldStyleLoginView();
2922
+ container.appendChild(oldStyleView);
2923
+ return container;
2924
+ }
2925
+ /**
2926
+ * Create new style login view (OAuth-first)
2927
+ */
2928
+ createNewStyleLoginView() {
2929
+ const view = document.createElement('div');
2930
+ view.id = 'newStyleLoginView';
2931
+ view.className = 'new-style-login-view';
2932
+ // Header
2933
+ const header = document.createElement('div');
2934
+ header.className = 'auth-form-header';
2935
+ const title = document.createElement('h2');
2936
+ title.className = 'auth-form-title';
2937
+ title.textContent = 'Welcome back';
2938
+ const subtitle = document.createElement('p');
2939
+ subtitle.className = 'auth-form-subtitle';
2940
+ subtitle.textContent = 'Please choose a login method to continue';
2941
+ header.appendChild(title);
2942
+ header.appendChild(subtitle);
2943
+ view.appendChild(header);
2944
+ // Form container
2945
+ const form = document.createElement('div');
2946
+ form.className = 'auth-form';
2947
+ // OAuth buttons - only show if enabled
2948
+ const hasOAuth = this.options.enableOAuth &&
2949
+ (this.options.enableOAuth.google || this.options.enableOAuth.discord || this.options.enableOAuth.github);
2950
+ if (hasOAuth) {
2951
+ // Google button (full width, primary style)
2952
+ if (this.options.enableOAuth?.google) {
2953
+ const googleBtn = this.createSocialButton('google', 'Continue with Google', 'login', true);
2954
+ googleBtn.className = 'btn-auth-primary';
2955
+ form.appendChild(googleBtn);
2956
+ }
2957
+ // Social buttons grid (GitHub + Discord)
2958
+ const socialGrid = document.createElement('div');
2959
+ socialGrid.className = 'social-buttons-grid';
2960
+ if (this.options.enableOAuth?.github) {
2961
+ const githubBtn = this.createSocialButton('github', 'GitHub', 'login');
2962
+ socialGrid.appendChild(githubBtn);
2963
+ }
2964
+ if (this.options.enableOAuth?.discord) {
2965
+ const discordBtn = this.createSocialButton('discord', 'Discord', 'login');
2966
+ socialGrid.appendChild(discordBtn);
2967
+ }
2968
+ if (socialGrid.children.length > 0) {
2969
+ form.appendChild(socialGrid);
2970
+ }
2971
+ // Divider
2972
+ const divider = document.createElement('div');
2973
+ divider.className = 'divider';
2974
+ divider.textContent = 'or continue with';
2975
+ form.appendChild(divider);
2976
+ }
2977
+ // "Sign in with Email" button
2978
+ const emailBtn = document.createElement('button');
2979
+ emailBtn.type = 'button';
2980
+ emailBtn.id = 'showOldStyleLogin';
2981
+ emailBtn.className = 'btn-email-toggle';
2982
+ emailBtn.innerHTML = `
2983
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
2984
+ <path d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
2985
+ </svg>
2986
+ <span>Sign in with Email</span>
2987
+ `;
2988
+ form.appendChild(emailBtn);
2989
+ // Terms text
2990
+ const termsText = document.createElement('p');
2991
+ termsText.className = 'terms-text';
2992
+ termsText.innerHTML = `
2993
+ By clicking continue, you agree to our
2994
+ <a href="#" class="terms-link">Terms of Service</a> and
2995
+ <a href="#" class="terms-link">Privacy Policy</a>.
2996
+ `;
2997
+ form.appendChild(termsText);
2998
+ view.appendChild(form);
2999
+ return view;
3000
+ }
3001
+ /**
3002
+ * Create old style login view (Traditional email/password form with original CSS)
3003
+ */
3004
+ createOldStyleLoginView() {
3005
+ const view = document.createElement('div');
3006
+ view.id = 'oldStyleLoginView';
3007
+ view.className = 'old-style-login-view hidden';
2807
3008
  // Header
2808
3009
  const header = document.createElement('div');
2809
3010
  header.className = 'auth-form-header';
@@ -2821,7 +3022,7 @@ class AuthModal {
2821
3022
  subtitle.appendChild(signupLink);
2822
3023
  header.appendChild(title);
2823
3024
  header.appendChild(subtitle);
2824
- container.appendChild(header);
3025
+ view.appendChild(header);
2825
3026
  // Form
2826
3027
  const form = document.createElement('form');
2827
3028
  form.id = 'loginFormElement';
@@ -2875,28 +3076,25 @@ class AuthModal {
2875
3076
  // Social buttons grid (Google + GitHub)
2876
3077
  const socialGrid = document.createElement('div');
2877
3078
  socialGrid.className = 'social-buttons-grid';
2878
- // Google button - only if enabled
2879
3079
  if (this.options.enableOAuth?.google) {
2880
3080
  const googleBtn = this.createSocialButton('google', 'Google', 'login');
2881
3081
  socialGrid.appendChild(googleBtn);
2882
3082
  }
2883
- // GitHub button - only if configured
2884
3083
  if (this.options.enableOAuth?.github) {
2885
3084
  const githubBtn = this.createSocialButton('github', 'Github', 'login');
2886
3085
  socialGrid.appendChild(githubBtn);
2887
3086
  }
2888
- // Only add grid if it has buttons
2889
3087
  if (socialGrid.children.length > 0) {
2890
3088
  form.appendChild(socialGrid);
2891
3089
  }
2892
- // Discord button (full width) - only if configured
3090
+ // Discord button (full width)
2893
3091
  if (this.options.enableOAuth?.discord) {
2894
3092
  const discordBtn = this.createSocialButton('discord', 'Discord', 'login', true);
2895
3093
  form.appendChild(discordBtn);
2896
3094
  }
2897
3095
  }
2898
- container.appendChild(form);
2899
- return container;
3096
+ view.appendChild(form);
3097
+ return view;
2900
3098
  }
2901
3099
  createSignupForm() {
2902
3100
  const container = document.createElement('div');
@@ -3504,17 +3702,46 @@ class AuthModal {
3504
3702
  // Backdrop click to close
3505
3703
  const backdrop = this.modal.querySelector('.auth-modal-backdrop');
3506
3704
  backdrop?.addEventListener('click', () => this.hide());
3507
- // View switching
3508
- const showSignup = this.modal.querySelector('#showSignup');
3509
- showSignup?.addEventListener('click', (e) => {
3510
- e.preventDefault();
3511
- this.switchView('signup');
3705
+ // Email form toggle
3706
+ const showEmailForm = this.modal.querySelector('#showEmailForm');
3707
+ showEmailForm?.addEventListener('click', () => {
3708
+ const emailForm = this.modal.querySelector('#emailLoginForm');
3709
+ const emailBtn = this.modal.querySelector('#showEmailForm');
3710
+ emailForm?.classList.remove('hidden');
3711
+ emailBtn?.classList.add('hidden');
3712
+ // Update header
3713
+ const title = this.modal.querySelector('#loginForm .auth-form-title');
3714
+ const subtitle = this.modal.querySelector('#loginForm .auth-form-subtitle');
3715
+ if (title)
3716
+ title.textContent = 'Sign in with Email';
3717
+ if (subtitle)
3718
+ subtitle.textContent = 'Enter your details below';
3719
+ });
3720
+ const backToSocialLogin = this.modal.querySelector('#backToSocialLogin');
3721
+ backToSocialLogin?.addEventListener('click', () => {
3722
+ const emailForm = this.modal.querySelector('#emailLoginForm');
3723
+ const emailBtn = this.modal.querySelector('#showEmailForm');
3724
+ emailForm?.classList.add('hidden');
3725
+ emailBtn?.classList.remove('hidden');
3726
+ // Restore header
3727
+ const title = this.modal.querySelector('#loginForm .auth-form-title');
3728
+ const subtitle = this.modal.querySelector('#loginForm .auth-form-subtitle');
3729
+ if (title)
3730
+ title.textContent = 'Welcome back';
3731
+ if (subtitle)
3732
+ subtitle.textContent = 'Please choose a login method to continue';
3512
3733
  });
3734
+ // View switching
3513
3735
  const showLogin = this.modal.querySelector('#showLogin');
3514
3736
  showLogin?.addEventListener('click', (e) => {
3515
3737
  e.preventDefault();
3516
3738
  this.switchView('login');
3517
3739
  });
3740
+ const showSignup = this.modal.querySelector('#showSignup');
3741
+ showSignup?.addEventListener('click', (e) => {
3742
+ e.preventDefault();
3743
+ this.switchView('signup');
3744
+ });
3518
3745
  const forgotPasswordLink = this.modal.querySelector('#forgotPasswordLink');
3519
3746
  forgotPasswordLink?.addEventListener('click', (e) => {
3520
3747
  e.preventDefault();
@@ -3568,6 +3795,11 @@ class AuthModal {
3568
3795
  }
3569
3796
  });
3570
3797
  });
3798
+ // Login view style switching
3799
+ const showOldStyleLogin = this.modal.querySelector('#showOldStyleLogin');
3800
+ showOldStyleLogin?.addEventListener('click', () => {
3801
+ this.showOldStyleLogin();
3802
+ });
3571
3803
  // Form submissions
3572
3804
  const loginForm = this.modal.querySelector('#loginFormElement');
3573
3805
  loginForm?.addEventListener('submit', (e) => this.handleLogin(e));
@@ -3668,6 +3900,32 @@ class AuthModal {
3668
3900
  const targetView = this.modal.querySelector(`#${viewMap[view]}`);
3669
3901
  targetView?.classList.remove('hidden');
3670
3902
  this.currentView = view;
3903
+ // When switching to login view, reset to new style
3904
+ if (view === 'login') {
3905
+ this.showNewStyleLogin();
3906
+ }
3907
+ }
3908
+ /**
3909
+ * Show new style login view (OAuth-first)
3910
+ */
3911
+ showNewStyleLogin() {
3912
+ if (!this.modal)
3913
+ return;
3914
+ const newStyleView = this.modal.querySelector('#newStyleLoginView');
3915
+ const oldStyleView = this.modal.querySelector('#oldStyleLoginView');
3916
+ newStyleView?.classList.remove('hidden');
3917
+ oldStyleView?.classList.add('hidden');
3918
+ }
3919
+ /**
3920
+ * Show old style login view (traditional email/password form)
3921
+ */
3922
+ showOldStyleLogin() {
3923
+ if (!this.modal)
3924
+ return;
3925
+ const newStyleView = this.modal.querySelector('#newStyleLoginView');
3926
+ const oldStyleView = this.modal.querySelector('#oldStyleLoginView');
3927
+ newStyleView?.classList.add('hidden');
3928
+ oldStyleView?.classList.remove('hidden');
3671
3929
  }
3672
3930
  async handleLogin(e) {
3673
3931
  e.preventDefault();