@lvce-editor/chat-view 7.11.0 → 7.14.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.
@@ -1290,9 +1290,6 @@ const {
1290
1290
  const openExternal = async url => {
1291
1291
  return invoke$1('Open.openExternal', url);
1292
1292
  };
1293
- const openUrl = async (url, platform) => {
1294
- return invoke$1('Open.openUrl', url, platform);
1295
- };
1296
1293
 
1297
1294
  const {
1298
1295
  invoke,
@@ -2368,6 +2365,7 @@ const createDefaultState = () => {
2368
2365
  authAccessToken: '',
2369
2366
  authEnabled: false,
2370
2367
  authErrorMessage: '',
2368
+ authUseRedirect: false,
2371
2369
  backendUrl: '',
2372
2370
  chatFocusContentMaxWidth: 700,
2373
2371
  chatHistoryEnabled: true,
@@ -4365,6 +4363,7 @@ const getBackendAuthUrl = (backendUrl, path) => {
4365
4363
  return `${trimTrailingSlashes(backendUrl)}${path}`;
4366
4364
  };
4367
4365
 
4366
+ const PlatformTypeElectron$1 = 2;
4368
4367
  const getCurrentHref = async () => {
4369
4368
  try {
4370
4369
  return await invoke('Layout.getHref');
@@ -4376,13 +4375,25 @@ const getCurrentHref = async () => {
4376
4375
  }
4377
4376
  return globalThis.location.href;
4378
4377
  };
4379
- const getBackendLoginUrl = async backendUrl => {
4380
- const loginUrl = new URL(getBackendAuthUrl(backendUrl, '/login'));
4381
- const redirectUri = await getCurrentHref();
4378
+ const getEffectiveRedirectUri = async (platform, uid, redirectUri) => {
4382
4379
  if (redirectUri) {
4383
- loginUrl.searchParams.set('redirect_uri', redirectUri);
4380
+ return redirectUri;
4381
+ }
4382
+ if (platform === PlatformTypeElectron$1) {
4383
+ return `http://localhost:${await invoke('OAuthServer.create', String(uid))}`;
4384
+ }
4385
+ return getCurrentHref();
4386
+ };
4387
+ const getBackendLoginRequest = async (backendUrl, platform = 0, uid = 0, redirectUri = '') => {
4388
+ const loginUrl = new URL(getBackendAuthUrl(backendUrl, '/login'));
4389
+ const effectiveRedirectUri = await getEffectiveRedirectUri(platform, uid, redirectUri);
4390
+ if (effectiveRedirectUri) {
4391
+ loginUrl.searchParams.set('redirect_uri', effectiveRedirectUri);
4384
4392
  }
4385
- return loginUrl.toString();
4393
+ return {
4394
+ loginUrl: loginUrl.toString(),
4395
+ redirectUri: effectiveRedirectUri
4396
+ };
4386
4397
  };
4387
4398
 
4388
4399
  const getLoggedOutBackendAuthState = (authErrorMessage = '') => {
@@ -4545,6 +4556,39 @@ const delay = async ms => {
4545
4556
  await new Promise(resolve => setTimeout(resolve, ms));
4546
4557
  };
4547
4558
 
4559
+ const getBackendNativeExchangeUrl = backendUrl => {
4560
+ return getBackendAuthUrl(backendUrl, '/auth/native/exchange');
4561
+ };
4562
+
4563
+ const getExchangeErrorMessage = async response => {
4564
+ try {
4565
+ const payload = await response.json();
4566
+ if (payload && typeof payload === 'object' && typeof payload.error === 'string' && payload.error) {
4567
+ return payload.error;
4568
+ }
4569
+ } catch {
4570
+ // ignore
4571
+ }
4572
+ return 'Backend authentication failed.';
4573
+ };
4574
+ const exchangeElectronAuthorizationCode = async (backendUrl, code, redirectUri) => {
4575
+ const response = await fetch(getBackendNativeExchangeUrl(backendUrl), {
4576
+ body: JSON.stringify({
4577
+ code,
4578
+ redirectUri
4579
+ }),
4580
+ credentials: 'include',
4581
+ headers: {
4582
+ Accept: 'application/json',
4583
+ 'Content-Type': 'application/json'
4584
+ },
4585
+ method: 'POST'
4586
+ });
4587
+ if (!response.ok) {
4588
+ throw new Error(await getExchangeErrorMessage(response));
4589
+ }
4590
+ };
4591
+
4548
4592
  const waitForBackendLogin = async (backendUrl, timeoutMs = 30_000, pollIntervalMs = 1000) => {
4549
4593
  const deadline = Date.now() + timeoutMs;
4550
4594
  let lastErrorMessage = '';
@@ -4561,6 +4605,26 @@ const waitForBackendLogin = async (backendUrl, timeoutMs = 30_000, pollIntervalM
4561
4605
  return getLoggedOutBackendAuthState(lastErrorMessage);
4562
4606
  };
4563
4607
 
4608
+ const hasAuthorizationCode = value => {
4609
+ return typeof value === 'string' && value.length > 0;
4610
+ };
4611
+ const waitForElectronBackendLogin = async (backendUrl, uid, redirectUri, timeoutMs = 30_000, pollIntervalMs = 1000) => {
4612
+ const started = Date.now();
4613
+ const deadline = started + timeoutMs;
4614
+ while (Date.now() < deadline) {
4615
+ const authorizationCode = await invoke('OAuthServer.getCode', String(uid));
4616
+ if (hasAuthorizationCode(authorizationCode)) {
4617
+ const elapsed = Date.now() - started;
4618
+ const remainingTime = Math.max(0, timeoutMs - elapsed);
4619
+ await exchangeElectronAuthorizationCode(backendUrl, authorizationCode, redirectUri);
4620
+ return waitForBackendLogin(backendUrl, remainingTime, pollIntervalMs);
4621
+ }
4622
+ await delay(pollIntervalMs);
4623
+ }
4624
+ return getLoggedOutBackendAuthState('Timed out waiting for backend login.');
4625
+ };
4626
+
4627
+ const PlatformTypeElectron = 2;
4564
4628
  const isLoginResponse = value => {
4565
4629
  if (!value || typeof value !== 'object') {
4566
4630
  return false;
@@ -4568,19 +4632,30 @@ const isLoginResponse = value => {
4568
4632
  return true;
4569
4633
  };
4570
4634
  const getLoggedInState = (state, response) => {
4635
+ const {
4636
+ userName,
4637
+ userSubscriptionPlan,
4638
+ userUsedTokens
4639
+ } = state;
4571
4640
  const accessToken = typeof response.accessToken === 'string' ? response.accessToken : '';
4572
4641
  return {
4573
4642
  ...state,
4574
4643
  authAccessToken: accessToken,
4575
4644
  authErrorMessage: '',
4576
- userName: typeof response.userName === 'string' ? response.userName : state.userName,
4645
+ userName: typeof response.userName === 'string' ? response.userName : userName,
4577
4646
  userState: accessToken ? 'loggedIn' : 'loggedOut',
4578
- userSubscriptionPlan: typeof response.subscriptionPlan === 'string' ? response.subscriptionPlan : state.userSubscriptionPlan,
4579
- userUsedTokens: typeof response.usedTokens === 'number' ? response.usedTokens : state.userUsedTokens
4647
+ userSubscriptionPlan: typeof response.subscriptionPlan === 'string' ? response.subscriptionPlan : userSubscriptionPlan,
4648
+ userUsedTokens: typeof response.usedTokens === 'number' ? response.usedTokens : userUsedTokens
4580
4649
  };
4581
4650
  };
4582
4651
  const handleClickLogin = async state => {
4583
- if (!state.backendUrl) {
4652
+ const {
4653
+ authUseRedirect,
4654
+ backendUrl,
4655
+ platform,
4656
+ uid
4657
+ } = state;
4658
+ if (!backendUrl) {
4584
4659
  return {
4585
4660
  ...state,
4586
4661
  authErrorMessage: 'Backend URL is missing.',
@@ -4592,8 +4667,8 @@ const handleClickLogin = async state => {
4592
4667
  authErrorMessage: '',
4593
4668
  userState: 'loggingIn'
4594
4669
  };
4595
- if (state.uid) {
4596
- set(state.uid, state, signingInState);
4670
+ if (uid) {
4671
+ set(uid, state, signingInState);
4597
4672
  await invoke('Chat.rerender');
4598
4673
  }
4599
4674
  try {
@@ -4615,9 +4690,12 @@ const handleClickLogin = async state => {
4615
4690
  }
4616
4691
  return getLoggedInState(signingInState, response);
4617
4692
  }
4618
- const url = await getBackendLoginUrl(state.backendUrl);
4619
- await openUrl(url, state.platform);
4620
- const authState = await waitForBackendLogin(state.backendUrl);
4693
+ const {
4694
+ loginUrl,
4695
+ redirectUri
4696
+ } = await getBackendLoginRequest(backendUrl, platform, uid);
4697
+ await invoke$1('Open.openUrl', loginUrl, platform, authUseRedirect);
4698
+ const authState = platform === PlatformTypeElectron ? await waitForElectronBackendLogin(backendUrl, uid, redirectUri) : await waitForBackendLogin(backendUrl);
4621
4699
  return {
4622
4700
  ...signingInState,
4623
4701
  ...authState
@@ -10604,6 +10682,15 @@ const loadAuthEnabled = async () => {
10604
10682
  }
10605
10683
  };
10606
10684
 
10685
+ const loadAuthUseRedirect = async () => {
10686
+ try {
10687
+ const savedAuthUseRedirect = await get('chat.authUseRedirect');
10688
+ return typeof savedAuthUseRedirect === 'boolean' ? savedAuthUseRedirect : false;
10689
+ } catch {
10690
+ return false;
10691
+ }
10692
+ };
10693
+
10607
10694
  const loadBackendUrl = async () => {
10608
10695
  try {
10609
10696
  const savedBackendUrl = await get('chat.backendUrl');
@@ -10784,10 +10871,11 @@ const loadVoiceDictationEnabled = async () => {
10784
10871
  };
10785
10872
 
10786
10873
  const loadPreferences = async () => {
10787
- const [aiSessionTitleGenerationEnabled, authEnabled, backendUrl, chatHistoryEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, reasoningPickerEnabled, scrollDownButtonEnabled, searchEnabled, streamingEnabled, todoListToolEnabled, toolEnablement, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, useOwnBackend, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadAuthEnabled(), loadBackendUrl(), loadChatHistoryEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadReasoningPickerEnabled(), loadScrollDownButtonEnabled(), loadSearchEnabled(), loadStreamingEnabled(), loadTodoListToolEnabled(), loadToolEnablement(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadUseOwnBackend(), loadVoiceDictationEnabled()]);
10874
+ const [aiSessionTitleGenerationEnabled, authEnabled, authUseRedirect, backendUrl, chatHistoryEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, reasoningPickerEnabled, scrollDownButtonEnabled, searchEnabled, streamingEnabled, todoListToolEnabled, toolEnablement, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, useOwnBackend, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadAuthEnabled(), loadAuthUseRedirect(), loadBackendUrl(), loadChatHistoryEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadReasoningPickerEnabled(), loadScrollDownButtonEnabled(), loadSearchEnabled(), loadStreamingEnabled(), loadTodoListToolEnabled(), loadToolEnablement(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadUseOwnBackend(), loadVoiceDictationEnabled()]);
10788
10875
  return {
10789
10876
  aiSessionTitleGenerationEnabled,
10790
10877
  authEnabled,
10878
+ authUseRedirect,
10791
10879
  backendUrl,
10792
10880
  chatHistoryEnabled,
10793
10881
  composerDropEnabled,
@@ -10860,6 +10948,7 @@ const loadContent = async (state, savedState) => {
10860
10948
  const {
10861
10949
  aiSessionTitleGenerationEnabled,
10862
10950
  authEnabled,
10951
+ authUseRedirect,
10863
10952
  backendUrl,
10864
10953
  chatHistoryEnabled,
10865
10954
  composerDropEnabled,
@@ -10940,6 +11029,7 @@ const loadContent = async (state, savedState) => {
10940
11029
  authAccessToken: authState.authAccessToken,
10941
11030
  authEnabled,
10942
11031
  authErrorMessage: authState.authErrorMessage,
11032
+ authUseRedirect,
10943
11033
  backendUrl,
10944
11034
  chatHistoryEnabled,
10945
11035
  chatListScrollTop,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "7.11.0",
3
+ "version": "7.14.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",