@seaverse/auth-sdk 0.3.7 → 0.3.9

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
@@ -791,6 +791,32 @@ interface BindInviteCodeResponse {
791
791
  message: string;
792
792
  };
793
793
  }
794
+ /**
795
+ * Iframe token request message sent from child to parent
796
+ */
797
+ interface IframeTokenRequestMessage {
798
+ type: 'seaverse:get_token';
799
+ requestId: string;
800
+ }
801
+ /**
802
+ * Iframe token response message sent from parent to child
803
+ */
804
+ interface IframeTokenResponseMessage {
805
+ type: 'seaverse:token';
806
+ requestId: string;
807
+ payload: {
808
+ accessToken: string;
809
+ expiresIn: number;
810
+ };
811
+ }
812
+ /**
813
+ * Iframe token error message sent from parent to child
814
+ */
815
+ interface IframeTokenErrorMessage {
816
+ type: 'seaverse:token_error';
817
+ requestId: string;
818
+ error: string;
819
+ }
794
820
 
795
821
  type models_AccountExistsErrorDetails = AccountExistsErrorDetails;
796
822
  type models_ApiError = ApiError;
@@ -815,6 +841,9 @@ type models_ForkProjectResponse = ForkProjectResponse;
815
841
  type models_HealthResponse = HealthResponse;
816
842
  type models_HubProject = HubProject;
817
843
  type models_HubProjectsListResponse = HubProjectsListResponse;
844
+ type models_IframeTokenErrorMessage = IframeTokenErrorMessage;
845
+ type models_IframeTokenRequestMessage = IframeTokenRequestMessage;
846
+ type models_IframeTokenResponseMessage = IframeTokenResponseMessage;
818
847
  type models_InviteApplication = InviteApplication;
819
848
  type models_InviteApplicationListResponse = InviteApplicationListResponse;
820
849
  type models_InviteCode = InviteCode;
@@ -855,7 +884,7 @@ type models_UserInstalledSkillsListResponse = UserInstalledSkillsListResponse;
855
884
  type models_VideoDetails = VideoDetails;
856
885
  declare namespace models {
857
886
  export { models_ErrorCode as ErrorCode };
858
- export type { models_AccountExistsErrorDetails as AccountExistsErrorDetails, models_ApiError as ApiError, models_ApiServiceTokenResponse as ApiServiceTokenResponse, models_ApplyInviteResponse as ApplyInviteResponse, models_BindInviteCodeRequest as BindInviteCodeRequest, models_BindInviteCodeResponse as BindInviteCodeResponse, models_Container as Container, models_ContainerDetailResponse as ContainerDetailResponse, models_ContainerListResponse as ContainerListResponse, models_ContainerStatsResponse as ContainerStatsResponse, models_ConversationStatus as ConversationStatus, models_CreateMarketplaceSkillRequest as CreateMarketplaceSkillRequest, models_CreateVideoShareRequest as CreateVideoShareRequest, models_CreateVideoShareResponse as CreateVideoShareResponse, models_EmailVerificationResponse as EmailVerificationResponse, models_ForgotPasswordRequest as ForgotPasswordRequest, models_ForkProjectRequest as ForkProjectRequest, models_ForkProjectResponse as ForkProjectResponse, models_HealthResponse as HealthResponse, models_HubProject as HubProject, models_HubProjectsListResponse as HubProjectsListResponse, models_InviteApplication as InviteApplication, models_InviteApplicationListResponse as InviteApplicationListResponse, models_InviteCode as InviteCode, models_InviteCodeBindRequest as InviteCodeBindRequest, models_InviteCodeDetailResponse as InviteCodeDetailResponse, models_InviteCodeGenerateResponse as InviteCodeGenerateResponse, models_InviteCodeRequiredErrorData as InviteCodeRequiredErrorData, models_InviteCodeVerifyResponse as InviteCodeVerifyResponse, models_InviteStats as InviteStats, models_InviteStatsResponse as InviteStatsResponse, models_InviteUsage as InviteUsage, models_ListInviteUsagesRequest as ListInviteUsagesRequest, models_ListInviteUsagesResponse as ListInviteUsagesResponse, models_ListInvitesRequest as ListInvitesRequest, models_ListInvitesResponse as ListInvitesResponse, models_LoginRequest as LoginRequest, models_LoginResponse as LoginResponse, models_MarketplaceSkill as MarketplaceSkill, models_MarketplaceSkillsListResponse as MarketplaceSkillsListResponse, models_OAuthAuthorizeRequest as OAuthAuthorizeRequest, models_OAuthAuthorizeResponse as OAuthAuthorizeResponse, models_PublishProjectRequest as PublishProjectRequest, models_PublishSkillRequest as PublishSkillRequest, models_RegisterContainerRequest as RegisterContainerRequest, models_RegisterContainerResponse as RegisterContainerResponse, models_RegisterRequest as RegisterRequest, models_RegisterResponse as RegisterResponse, models_ResetPasswordRequest as ResetPasswordRequest, models_SocialMediaLink as SocialMediaLink, models_SocialMediaLinksResponse as SocialMediaLinksResponse, models_SpeechTokenResponse as SpeechTokenResponse, models_SubmitInviteApplicationRequest as SubmitInviteApplicationRequest, models_SuccessResponse as SuccessResponse, models_TrackAppTypeRequest as TrackAppTypeRequest, models_User as User, models_UserInstalledSkill as UserInstalledSkill, models_UserInstalledSkillsListResponse as UserInstalledSkillsListResponse, models_VideoDetails as VideoDetails };
887
+ export type { models_AccountExistsErrorDetails as AccountExistsErrorDetails, models_ApiError as ApiError, models_ApiServiceTokenResponse as ApiServiceTokenResponse, models_ApplyInviteResponse as ApplyInviteResponse, models_BindInviteCodeRequest as BindInviteCodeRequest, models_BindInviteCodeResponse as BindInviteCodeResponse, models_Container as Container, models_ContainerDetailResponse as ContainerDetailResponse, models_ContainerListResponse as ContainerListResponse, models_ContainerStatsResponse as ContainerStatsResponse, models_ConversationStatus as ConversationStatus, models_CreateMarketplaceSkillRequest as CreateMarketplaceSkillRequest, models_CreateVideoShareRequest as CreateVideoShareRequest, models_CreateVideoShareResponse as CreateVideoShareResponse, models_EmailVerificationResponse as EmailVerificationResponse, models_ForgotPasswordRequest as ForgotPasswordRequest, models_ForkProjectRequest as ForkProjectRequest, models_ForkProjectResponse as ForkProjectResponse, models_HealthResponse as HealthResponse, models_HubProject as HubProject, models_HubProjectsListResponse as HubProjectsListResponse, models_IframeTokenErrorMessage as IframeTokenErrorMessage, models_IframeTokenRequestMessage as IframeTokenRequestMessage, models_IframeTokenResponseMessage as IframeTokenResponseMessage, models_InviteApplication as InviteApplication, models_InviteApplicationListResponse as InviteApplicationListResponse, models_InviteCode as InviteCode, models_InviteCodeBindRequest as InviteCodeBindRequest, models_InviteCodeDetailResponse as InviteCodeDetailResponse, models_InviteCodeGenerateResponse as InviteCodeGenerateResponse, models_InviteCodeRequiredErrorData as InviteCodeRequiredErrorData, models_InviteCodeVerifyResponse as InviteCodeVerifyResponse, models_InviteStats as InviteStats, models_InviteStatsResponse as InviteStatsResponse, models_InviteUsage as InviteUsage, models_ListInviteUsagesRequest as ListInviteUsagesRequest, models_ListInviteUsagesResponse as ListInviteUsagesResponse, models_ListInvitesRequest as ListInvitesRequest, models_ListInvitesResponse as ListInvitesResponse, models_LoginRequest as LoginRequest, models_LoginResponse as LoginResponse, models_MarketplaceSkill as MarketplaceSkill, models_MarketplaceSkillsListResponse as MarketplaceSkillsListResponse, models_OAuthAuthorizeRequest as OAuthAuthorizeRequest, models_OAuthAuthorizeResponse as OAuthAuthorizeResponse, models_PublishProjectRequest as PublishProjectRequest, models_PublishSkillRequest as PublishSkillRequest, models_RegisterContainerRequest as RegisterContainerRequest, models_RegisterContainerResponse as RegisterContainerResponse, models_RegisterRequest as RegisterRequest, models_RegisterResponse as RegisterResponse, models_ResetPasswordRequest as ResetPasswordRequest, models_SocialMediaLink as SocialMediaLink, models_SocialMediaLinksResponse as SocialMediaLinksResponse, models_SpeechTokenResponse as SpeechTokenResponse, models_SubmitInviteApplicationRequest as SubmitInviteApplicationRequest, models_SuccessResponse as SuccessResponse, models_TrackAppTypeRequest as TrackAppTypeRequest, models_User as User, models_UserInstalledSkill as UserInstalledSkill, models_UserInstalledSkillsListResponse as UserInstalledSkillsListResponse, models_VideoDetails as VideoDetails };
859
888
  }
860
889
 
861
890
  /**
@@ -1027,6 +1056,48 @@ declare class SeaVerseBackendAPIClient {
1027
1056
  * }
1028
1057
  */
1029
1058
  setToken(token: string): void;
1059
+ /**
1060
+ * Get token from parent window via iframe communication
1061
+ * This method is designed for scenarios where the application is embedded in an iframe
1062
+ * and needs to obtain authentication tokens from the parent page
1063
+ *
1064
+ * @param options - Configuration options
1065
+ * @param options.timeout - Timeout in milliseconds (default: 30000)
1066
+ * @returns Promise that resolves with the access token
1067
+ *
1068
+ * @example
1069
+ * // In an iframe application
1070
+ * try {
1071
+ * const token = await client.getIframeToken({ timeout: 10000 });
1072
+ * client.setToken(token);
1073
+ * localStorage.setItem('token', token);
1074
+ * console.log('Successfully obtained token from parent');
1075
+ * } catch (error) {
1076
+ * console.error('Failed to get token from parent:', error);
1077
+ * }
1078
+ *
1079
+ * @example
1080
+ * // Parent page should listen for token requests and respond:
1081
+ * window.addEventListener('message', (event) => {
1082
+ * if (event.data.type === 'seaverse:get_token') {
1083
+ * const requestId = event.data.requestId;
1084
+ * // Get your token (from localStorage, API, etc.)
1085
+ * const token = localStorage.getItem('token');
1086
+ * // Send token back to iframe
1087
+ * event.source.postMessage({
1088
+ * type: 'seaverse:token',
1089
+ * requestId: requestId,
1090
+ * payload: {
1091
+ * accessToken: token,
1092
+ * expiresIn: 3600,
1093
+ * },
1094
+ * }, '*');
1095
+ * }
1096
+ * });
1097
+ */
1098
+ getIframeToken(options?: {
1099
+ timeout?: number;
1100
+ }): Promise<string>;
1030
1101
  /**
1031
1102
  * Health check
1032
1103
  * Check if the service is healthy
@@ -1523,4 +1594,4 @@ declare class Toast {
1523
1594
  }
1524
1595
 
1525
1596
  export { AuthFactory, AuthModal, AuthProvider, BuiltInHooks, ENVIRONMENT_CONFIGS, ErrorCode, SeaVerseBackendAPIClient, Toast, createAuthModal, detectEnvironment, getEnvironmentConfig, models };
1526
- export type { AccountExistsErrorDetails, ApiError, ApiServiceTokenResponse, ApplyInviteResponse, AuthModalOptions, AuthModalResult, BindInviteCodeRequest, BindInviteCodeResponse, Container, ContainerDetailResponse, ContainerListResponse, ContainerStatsResponse, ConversationStatus, CreateMarketplaceSkillRequest, CreateVideoShareRequest, CreateVideoShareResponse, EmailVerificationResponse, Environment, EnvironmentConfig, ForgotPasswordRequest, ForkProjectRequest, ForkProjectResponse, HealthResponse, HubProject, HubProjectsListResponse, InviteApplication, InviteApplicationListResponse, InviteCode, InviteCodeBindRequest, InviteCodeDetailResponse, InviteCodeGenerateResponse, InviteCodeRequiredErrorData, InviteCodeVerifyResponse, InviteStats, InviteStatsResponse, InviteUsage, ListInviteUsagesRequest, ListInviteUsagesResponse, ListInvitesRequest, ListInvitesResponse, LoginRequest, LoginResponse, MarketplaceSkill, MarketplaceSkillsListResponse, OAuthAuthorizeRequest, OAuthAuthorizeResponse, PublishProjectRequest, PublishSkillRequest, RegisterContainerRequest, RegisterContainerResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, RetryOptions, SeaVerseBackendAPIClientOptions, SocialMediaLink, SocialMediaLinksResponse, SpeechTokenResponse, SubmitInviteApplicationRequest, SuccessResponse, ToastOptions, ToastType, TrackAppTypeRequest, User, UserInstalledSkill, UserInstalledSkillsListResponse, VideoDetails };
1597
+ export type { AccountExistsErrorDetails, ApiError, ApiServiceTokenResponse, ApplyInviteResponse, AuthModalOptions, AuthModalResult, BindInviteCodeRequest, BindInviteCodeResponse, Container, ContainerDetailResponse, ContainerListResponse, ContainerStatsResponse, ConversationStatus, CreateMarketplaceSkillRequest, CreateVideoShareRequest, CreateVideoShareResponse, EmailVerificationResponse, Environment, EnvironmentConfig, ForgotPasswordRequest, ForkProjectRequest, ForkProjectResponse, HealthResponse, HubProject, HubProjectsListResponse, IframeTokenErrorMessage, IframeTokenRequestMessage, IframeTokenResponseMessage, InviteApplication, InviteApplicationListResponse, InviteCode, InviteCodeBindRequest, InviteCodeDetailResponse, InviteCodeGenerateResponse, InviteCodeRequiredErrorData, InviteCodeVerifyResponse, InviteStats, InviteStatsResponse, InviteUsage, ListInviteUsagesRequest, ListInviteUsagesResponse, ListInvitesRequest, ListInvitesResponse, LoginRequest, LoginResponse, MarketplaceSkill, MarketplaceSkillsListResponse, OAuthAuthorizeRequest, OAuthAuthorizeResponse, PublishProjectRequest, PublishSkillRequest, RegisterContainerRequest, RegisterContainerResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, RetryOptions, SeaVerseBackendAPIClientOptions, SocialMediaLink, SocialMediaLinksResponse, SpeechTokenResponse, SubmitInviteApplicationRequest, SuccessResponse, ToastOptions, ToastType, TrackAppTypeRequest, User, UserInstalledSkill, UserInstalledSkillsListResponse, VideoDetails };
package/dist/index.js CHANGED
@@ -1262,6 +1262,103 @@ class SeaVerseBackendAPIClient {
1262
1262
  // Update the httpClient's auth
1263
1263
  this.httpClient.auth = auth;
1264
1264
  }
1265
+ /**
1266
+ * Get token from parent window via iframe communication
1267
+ * This method is designed for scenarios where the application is embedded in an iframe
1268
+ * and needs to obtain authentication tokens from the parent page
1269
+ *
1270
+ * @param options - Configuration options
1271
+ * @param options.timeout - Timeout in milliseconds (default: 30000)
1272
+ * @returns Promise that resolves with the access token
1273
+ *
1274
+ * @example
1275
+ * // In an iframe application
1276
+ * try {
1277
+ * const token = await client.getIframeToken({ timeout: 10000 });
1278
+ * client.setToken(token);
1279
+ * localStorage.setItem('token', token);
1280
+ * console.log('Successfully obtained token from parent');
1281
+ * } catch (error) {
1282
+ * console.error('Failed to get token from parent:', error);
1283
+ * }
1284
+ *
1285
+ * @example
1286
+ * // Parent page should listen for token requests and respond:
1287
+ * window.addEventListener('message', (event) => {
1288
+ * if (event.data.type === 'seaverse:get_token') {
1289
+ * const requestId = event.data.requestId;
1290
+ * // Get your token (from localStorage, API, etc.)
1291
+ * const token = localStorage.getItem('token');
1292
+ * // Send token back to iframe
1293
+ * event.source.postMessage({
1294
+ * type: 'seaverse:token',
1295
+ * requestId: requestId,
1296
+ * payload: {
1297
+ * accessToken: token,
1298
+ * expiresIn: 3600,
1299
+ * },
1300
+ * }, '*');
1301
+ * }
1302
+ * });
1303
+ */
1304
+ getIframeToken(options) {
1305
+ // Only works in browser environment
1306
+ if (typeof window === 'undefined') {
1307
+ return Promise.reject(new Error('getIframeToken() can only be used in browser environment'));
1308
+ }
1309
+ // Check if we're in an iframe
1310
+ if (window.self === window.top) {
1311
+ return Promise.reject(new Error('getIframeToken() can only be used inside an iframe'));
1312
+ }
1313
+ const timeout = options?.timeout || 30000; // Default 30 seconds
1314
+ const requestId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1315
+ return new Promise((resolve, reject) => {
1316
+ let timeoutId = null;
1317
+ let messageHandler = null;
1318
+ // Cleanup function
1319
+ const cleanup = () => {
1320
+ if (timeoutId) {
1321
+ clearTimeout(timeoutId);
1322
+ timeoutId = null;
1323
+ }
1324
+ if (messageHandler) {
1325
+ window.removeEventListener('message', messageHandler);
1326
+ messageHandler = null;
1327
+ }
1328
+ };
1329
+ // Set up timeout
1330
+ timeoutId = setTimeout(() => {
1331
+ cleanup();
1332
+ reject(new Error(`Token request timeout after ${timeout}ms`));
1333
+ }, timeout);
1334
+ // Set up message listener
1335
+ messageHandler = (event) => {
1336
+ const data = event.data;
1337
+ // Check if this is a response to our request
1338
+ if (data &&
1339
+ typeof data === 'object' &&
1340
+ data.requestId === requestId) {
1341
+ if (data.type === 'seaverse:token') {
1342
+ cleanup();
1343
+ const tokenData = data;
1344
+ resolve(tokenData.payload.accessToken);
1345
+ }
1346
+ else if (data.type === 'seaverse:token_error') {
1347
+ cleanup();
1348
+ const errorData = data;
1349
+ reject(new Error(errorData.error || 'Failed to get token from parent'));
1350
+ }
1351
+ }
1352
+ };
1353
+ window.addEventListener('message', messageHandler);
1354
+ // Send request to parent
1355
+ const requestMessage = {
1356
+ type: 'seaverse:get_token',
1357
+ requestId,
1358
+ };
1359
+ window.parent.postMessage(requestMessage, '*');
1360
+ });
1361
+ }
1265
1362
  // ============================================================================
1266
1363
  // Authentication & OAuth APIs
1267
1364
  // ============================================================================
@@ -3068,21 +3165,37 @@ class AuthModal {
3068
3165
  const container = document.createElement('div');
3069
3166
  container.id = 'inviteCodeForm';
3070
3167
  container.className = 'auth-form-view hidden';
3071
- // Icon
3168
+ // Icon - 使用星星图标
3072
3169
  const icon = document.createElement('div');
3073
- icon.className = 'forgot-password-icon';
3074
- icon.innerHTML = '<div class="icon-glow"></div><svg class="icon-lock" width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="10" rx="2" /><path d="M12 11V7a3 3 0 0 1 3-3h0a3 3 0 0 1 3 3v4" /><circle cx="12" cy="15" r="1" /></svg>';
3170
+ icon.className = 'invite-code-icon';
3171
+ const iconGlow = document.createElement('div');
3172
+ iconGlow.className = 'icon-glow';
3173
+ icon.appendChild(iconGlow);
3174
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
3175
+ svg.setAttribute('class', 'icon-star');
3176
+ svg.setAttribute('width', '56');
3177
+ svg.setAttribute('height', '56');
3178
+ svg.setAttribute('viewBox', '0 0 24 24');
3179
+ svg.setAttribute('fill', 'none');
3180
+ svg.setAttribute('stroke', 'currentColor');
3181
+ svg.setAttribute('stroke-width', '1.5');
3182
+ svg.setAttribute('stroke-linecap', 'round');
3183
+ svg.setAttribute('stroke-linejoin', 'round');
3184
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
3185
+ path.setAttribute('d', 'M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z');
3186
+ svg.appendChild(path);
3187
+ icon.appendChild(svg);
3075
3188
  container.appendChild(icon);
3076
3189
  // Header
3077
3190
  const header = document.createElement('div');
3078
3191
  header.className = 'auth-form-header';
3079
3192
  const title = document.createElement('h2');
3080
3193
  title.className = 'auth-form-title';
3081
- title.textContent = 'Activation Required';
3194
+ title.textContent = 'Bind Invitation Code';
3082
3195
  const subtitle = document.createElement('p');
3083
3196
  subtitle.className = 'auth-form-subtitle';
3084
3197
  subtitle.id = 'inviteCodeSubtitle';
3085
- subtitle.textContent = 'Enter your invitation code to activate your account';
3198
+ subtitle.textContent = 'Complete your registration by entering an invitation code';
3086
3199
  header.appendChild(title);
3087
3200
  header.appendChild(subtitle);
3088
3201
  container.appendChild(header);
@@ -3090,7 +3203,7 @@ class AuthModal {
3090
3203
  const form = document.createElement('form');
3091
3204
  form.id = 'inviteCodeFormElement';
3092
3205
  form.className = 'auth-form';
3093
- const codeGroup = this.createFormGroup('inviteCodeInput', 'Invitation Code', 'text', 'Enter invitation code');
3206
+ const codeGroup = this.createFormGroup('inviteCodeInput', 'Invitation code *', 'text', 'Enter your invitation code');
3094
3207
  form.appendChild(codeGroup);
3095
3208
  const submitBtn = document.createElement('button');
3096
3209
  submitBtn.type = 'submit';
@@ -3098,39 +3211,41 @@ class AuthModal {
3098
3211
  submitBtn.className = 'btn-auth-primary';
3099
3212
  const btnText = document.createElement('span');
3100
3213
  btnText.className = 'btn-text';
3101
- btnText.textContent = 'Activate Account';
3214
+ btnText.textContent = 'Get Started';
3102
3215
  const btnLoader = document.createElement('span');
3103
3216
  btnLoader.className = 'btn-loader hidden';
3104
- btnLoader.innerHTML = '<svg class="spinner" viewBox="0 0 24 24"><circle class="spinner-track" cx="12" cy="12" r="10"></circle><circle class="spinner-circle" cx="12" cy="12" r="10"></circle></svg>';
3217
+ const spinnerSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
3218
+ spinnerSvg.setAttribute('class', 'spinner');
3219
+ spinnerSvg.setAttribute('viewBox', '0 0 24 24');
3220
+ const track = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
3221
+ track.setAttribute('class', 'spinner-track');
3222
+ track.setAttribute('cx', '12');
3223
+ track.setAttribute('cy', '12');
3224
+ track.setAttribute('r', '10');
3225
+ const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
3226
+ circle.setAttribute('class', 'spinner-circle');
3227
+ circle.setAttribute('cx', '12');
3228
+ circle.setAttribute('cy', '12');
3229
+ circle.setAttribute('r', '10');
3230
+ spinnerSvg.appendChild(track);
3231
+ spinnerSvg.appendChild(circle);
3232
+ btnLoader.appendChild(spinnerSvg);
3105
3233
  submitBtn.appendChild(btnText);
3106
3234
  submitBtn.appendChild(btnLoader);
3107
3235
  form.appendChild(submitBtn);
3108
3236
  container.appendChild(form);
3109
- // Apply invite link
3110
- const applyInviteSection = document.createElement('div');
3111
- applyInviteSection.className = 'auth-footer-divider';
3112
- const applyInviteText = document.createElement('p');
3113
- applyInviteText.className = 'auth-footer-text';
3114
- applyInviteText.textContent = "Don't have an invitation code?";
3115
- const applyInviteLink = document.createElement('a');
3116
- applyInviteLink.href = '#';
3117
- applyInviteLink.id = 'showApplyInviteForm';
3118
- applyInviteLink.className = 'auth-link';
3119
- applyInviteLink.textContent = 'Apply for one';
3120
- applyInviteText.appendChild(document.createTextNode(' '));
3121
- applyInviteText.appendChild(applyInviteLink);
3122
- applyInviteSection.appendChild(applyInviteText);
3123
- container.appendChild(applyInviteSection);
3124
- // Footer
3125
- const footer = document.createElement('div');
3126
- footer.className = 'auth-footer forgot-footer';
3127
- const backLink = document.createElement('a');
3128
- backLink.href = '#';
3129
- backLink.id = 'backToLoginFromInvite';
3130
- backLink.className = 'back-to-login';
3131
- backLink.innerHTML = '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 12H5M12 19l-7-7 7-7"/></svg><span>Back to Sign In</span>';
3132
- footer.appendChild(backLink);
3133
- container.appendChild(footer);
3237
+ // 分隔线
3238
+ const divider = document.createElement('div');
3239
+ divider.className = 'invite-code-divider';
3240
+ divider.textContent = "DON'T HAVE CODE?";
3241
+ container.appendChild(divider);
3242
+ // Apply invite 按钮
3243
+ const applyInviteBtn = document.createElement('button');
3244
+ applyInviteBtn.type = 'button';
3245
+ applyInviteBtn.id = 'showApplyInviteForm';
3246
+ applyInviteBtn.className = 'btn-apply-invite';
3247
+ applyInviteBtn.textContent = 'Apply for access';
3248
+ container.appendChild(applyInviteBtn);
3134
3249
  return container;
3135
3250
  }
3136
3251
  createApplyInviteForm() {