@lobehub/lobehub 2.0.0-next.20 → 2.0.0-next.22
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/.github/workflows/claude-auto-testing.yml +73 -0
- package/.github/workflows/claude-translate-comments.yml +67 -0
- package/.github/workflows/release.yml +1 -1
- package/.github/workflows/test.yml +39 -2
- package/CHANGELOG.md +42 -0
- package/apps/desktop/package.json +1 -1
- package/apps/desktop/src/main/controllers/AuthCtr.ts +53 -39
- package/apps/desktop/src/main/controllers/MenuCtr.ts +5 -5
- package/apps/desktop/src/main/controllers/NotificationCtr.ts +29 -29
- package/apps/desktop/src/main/controllers/RemoteServerConfigCtr.ts +16 -16
- package/apps/desktop/src/main/controllers/ShortcutCtr.ts +2 -2
- package/apps/desktop/src/main/controllers/TrayMenuCtr.ts +18 -18
- package/apps/desktop/src/main/controllers/UpdaterCtr.ts +4 -4
- package/apps/desktop/src/main/controllers/__tests__/AuthCtr.test.ts +706 -0
- package/apps/desktop/src/main/controllers/__tests__/TrayMenuCtr.test.ts +5 -5
- package/apps/desktop/src/main/controllers/index.ts +4 -4
- package/changelog/v1.json +14 -0
- package/docs/development/database-schema.dbml +2 -1
- package/package.json +2 -2
- package/packages/database/migrations/0042_improve_agent_index.sql +1 -0
- package/packages/database/migrations/meta/0042_snapshot.json +7800 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/core/migrations.json +8 -0
- package/packages/database/src/models/agent.ts +16 -13
- package/packages/database/src/models/session.ts +20 -9
- package/packages/database/src/models/user.ts +2 -1
- package/packages/database/src/schemas/agent.ts +4 -1
- package/packages/types/src/message/ui/params.ts +1 -1
- package/packages/utils/src/apiKey.test.ts +139 -0
- package/packages/utils/src/client/clipboard.ts +2 -2
- package/packages/utils/src/client/exportFile.ts +10 -10
- package/packages/utils/src/client/parserPlaceholder.ts +18 -18
- package/packages/utils/src/client/topic.ts +10 -10
- package/packages/utils/src/client/xor-obfuscation.ts +11 -11
- package/renovate.json +20 -3
- package/src/app/[variants]/oauth/consent/[uid]/Login.tsx +10 -1
- package/src/server/routers/lambda/message.ts +0 -2
- package/src/server/routers/lambda/user.ts +8 -6
- package/src/services/chat/index.ts +3 -3
- package/src/services/mcp.test.ts +777 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
name: Claude Auto Testing Coverage
|
|
2
|
+
description: Automatically add unit tests to improve code coverage
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
schedule:
|
|
6
|
+
# Run daily at 05:30 UTC (13:30 Beijing Time)
|
|
7
|
+
- cron: '30 5 * * *'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
target_module:
|
|
11
|
+
description: 'Specific module to add tests (e.g., packages/database, src/services/user)'
|
|
12
|
+
required: false
|
|
13
|
+
type: string
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: auto-testing
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
add-tests:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
timeout-minutes: 45
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write
|
|
25
|
+
pull-requests: write
|
|
26
|
+
id-token: write
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout repository
|
|
30
|
+
uses: actions/checkout@v5
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 1
|
|
33
|
+
|
|
34
|
+
- name: Setup Bun
|
|
35
|
+
uses: oven-sh/setup-bun@v2
|
|
36
|
+
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: bun install --frozen-lockfile
|
|
39
|
+
|
|
40
|
+
- name: Configure Git
|
|
41
|
+
run: |
|
|
42
|
+
git config --global user.name "claude-bot[bot]"
|
|
43
|
+
git config --global user.email "claude-bot[bot]@users.noreply.github.com"
|
|
44
|
+
|
|
45
|
+
- name: Copy testing prompt
|
|
46
|
+
run: |
|
|
47
|
+
mkdir -p /tmp/claude-prompts
|
|
48
|
+
cp .claude/prompts/auto-testing.md /tmp/claude-prompts/
|
|
49
|
+
|
|
50
|
+
- name: Run Claude Code for Auto Testing
|
|
51
|
+
uses: anthropics/claude-code-action@main
|
|
52
|
+
with:
|
|
53
|
+
github_token: ${{ secrets.GH_TOKEN }}
|
|
54
|
+
allowed_non_write_users: "*"
|
|
55
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
56
|
+
claude_args: "--allowed-tools Bash,Read,Edit,Write,Glob,Grep"
|
|
57
|
+
prompt: |
|
|
58
|
+
Follow the auto testing guide located at:
|
|
59
|
+
```bash
|
|
60
|
+
cat /tmp/claude-prompts/auto-testing.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Task Assignment
|
|
64
|
+
|
|
65
|
+
${{ inputs.target_module && format('Process the specified module: {0}', inputs.target_module) || 'Automatically select one module from the target directories that needs test coverage' }}
|
|
66
|
+
|
|
67
|
+
## Environment Information
|
|
68
|
+
- Repository: ${{ github.repository }}
|
|
69
|
+
- Branch: ${{ github.ref_name }}
|
|
70
|
+
- Target Module: ${{ inputs.target_module || 'Auto-select' }}
|
|
71
|
+
- Run ID: ${{ github.run_id }}
|
|
72
|
+
|
|
73
|
+
**Start the auto testing process now.**
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Claude Translate Non-English Comments
|
|
2
|
+
description: Automatically detect and translate non-English comments to English in codebase
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
schedule:
|
|
6
|
+
# Run daily at 02:00 UTC (10:00 Beijing Time)
|
|
7
|
+
- cron: '0 2 * * *'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
inputs:
|
|
10
|
+
target_module:
|
|
11
|
+
description: 'Specific module to translate (e.g., packages/database, apps/desktop/src/modules/auth)'
|
|
12
|
+
required: false
|
|
13
|
+
type: string
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: translate-comments
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
translate-comments:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
timeout-minutes: 30
|
|
23
|
+
permissions:
|
|
24
|
+
contents: write
|
|
25
|
+
pull-requests: write
|
|
26
|
+
id-token: write
|
|
27
|
+
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout repository
|
|
30
|
+
uses: actions/checkout@v5
|
|
31
|
+
with:
|
|
32
|
+
fetch-depth: 1
|
|
33
|
+
|
|
34
|
+
- name: Configure Git
|
|
35
|
+
run: |
|
|
36
|
+
git config --global user.name "claude-bot[bot]"
|
|
37
|
+
git config --global user.email "claude-bot[bot]@users.noreply.github.com"
|
|
38
|
+
|
|
39
|
+
- name: Copy translation prompt
|
|
40
|
+
run: |
|
|
41
|
+
mkdir -p /tmp/claude-prompts
|
|
42
|
+
cp .claude/prompts/translate-comments.md /tmp/claude-prompts/
|
|
43
|
+
|
|
44
|
+
- name: Run Claude Code for Comment Translation
|
|
45
|
+
uses: anthropics/claude-code-action@main
|
|
46
|
+
with:
|
|
47
|
+
github_token: ${{ secrets.GH_TOKEN }}
|
|
48
|
+
allowed_non_write_users: "*"
|
|
49
|
+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
50
|
+
claude_args: "--allowed-tools Bash,Read,Edit,Glob,Grep"
|
|
51
|
+
prompt: |
|
|
52
|
+
Follow the translation guide located at:
|
|
53
|
+
```bash
|
|
54
|
+
cat /tmp/claude-prompts/translate-comments.md
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Task Assignment
|
|
58
|
+
|
|
59
|
+
${{ inputs.target_module && format('Process the specified module: {0}', inputs.target_module) || 'Automatically select one module from the target directories that has not been processed recently' }}
|
|
60
|
+
|
|
61
|
+
## Environment Information
|
|
62
|
+
- Repository: ${{ github.repository }}
|
|
63
|
+
- Branch: ${{ github.ref_name }}
|
|
64
|
+
- Target Module: ${{ inputs.target_module || 'Auto-select' }}
|
|
65
|
+
- Run ID: ${{ github.run_id }}
|
|
66
|
+
|
|
67
|
+
**Start the translation process now.**
|
|
@@ -54,7 +54,7 @@ jobs:
|
|
|
54
54
|
env:
|
|
55
55
|
DATABASE_TEST_URL: postgresql://postgres:postgres@localhost:5432/postgres
|
|
56
56
|
DATABASE_DRIVER: node
|
|
57
|
-
KEY_VAULTS_SECRET:
|
|
57
|
+
KEY_VAULTS_SECRET: Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
|
58
58
|
S3_PUBLIC_DOMAIN: https://example.com
|
|
59
59
|
APP_URL: https://home.com
|
|
60
60
|
|
|
@@ -119,6 +119,43 @@ jobs:
|
|
|
119
119
|
files: ./coverage/app/lcov.info
|
|
120
120
|
flags: app
|
|
121
121
|
|
|
122
|
+
test-desktop:
|
|
123
|
+
name: Test Desktop App
|
|
124
|
+
|
|
125
|
+
runs-on: ubuntu-latest
|
|
126
|
+
|
|
127
|
+
steps:
|
|
128
|
+
- uses: actions/checkout@v5
|
|
129
|
+
|
|
130
|
+
- name: Setup Node.js
|
|
131
|
+
uses: actions/setup-node@v6
|
|
132
|
+
with:
|
|
133
|
+
node-version: 24
|
|
134
|
+
package-manager-cache: false
|
|
135
|
+
|
|
136
|
+
- name: Setup pnpm
|
|
137
|
+
uses: pnpm/action-setup@v2
|
|
138
|
+
with:
|
|
139
|
+
version: 10
|
|
140
|
+
|
|
141
|
+
- name: Install deps
|
|
142
|
+
run: pnpm install
|
|
143
|
+
working-directory: apps/desktop
|
|
144
|
+
env:
|
|
145
|
+
NODE_OPTIONS: --max-old-space-size=6144
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
- name: Test Desktop Client
|
|
149
|
+
run: pnpm test
|
|
150
|
+
working-directory: apps/desktop
|
|
151
|
+
|
|
152
|
+
- name: Upload Desktop App Coverage to Codecov
|
|
153
|
+
uses: codecov/codecov-action@v5
|
|
154
|
+
with:
|
|
155
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
156
|
+
files: ./apps/desktop/coverage/lcov.info
|
|
157
|
+
flags: desktop
|
|
158
|
+
|
|
122
159
|
test-databsae:
|
|
123
160
|
name: Test Database
|
|
124
161
|
|
|
@@ -156,7 +193,7 @@ jobs:
|
|
|
156
193
|
- name: Test Client DB
|
|
157
194
|
run: pnpm --filter @lobechat/database test:client-db
|
|
158
195
|
env:
|
|
159
|
-
KEY_VAULTS_SECRET:
|
|
196
|
+
KEY_VAULTS_SECRET: Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
|
160
197
|
S3_PUBLIC_DOMAIN: https://example.com
|
|
161
198
|
APP_URL: https://home.com
|
|
162
199
|
|
|
@@ -165,7 +202,7 @@ jobs:
|
|
|
165
202
|
env:
|
|
166
203
|
DATABASE_TEST_URL: postgresql://postgres:postgres@localhost:5432/postgres
|
|
167
204
|
DATABASE_DRIVER: node
|
|
168
|
-
KEY_VAULTS_SECRET:
|
|
205
|
+
KEY_VAULTS_SECRET: Kix2wcUONd4CX51E/ZPAd36BqM4wzJgKjPtz2sGztqQ=
|
|
169
206
|
S3_PUBLIC_DOMAIN: https://example.com
|
|
170
207
|
APP_URL: https://home.com
|
|
171
208
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,48 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.22](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.21...v2.0.0-next.22)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-11-04**</sup>
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
<details>
|
|
12
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
13
|
+
|
|
14
|
+
</details>
|
|
15
|
+
|
|
16
|
+
<div align="right">
|
|
17
|
+
|
|
18
|
+
[](#readme-top)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
## [Version 2.0.0-next.21](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.20...v2.0.0-next.21)
|
|
23
|
+
|
|
24
|
+
<sup>Released on **2025-11-04**</sup>
|
|
25
|
+
|
|
26
|
+
#### 🐛 Bug Fixes
|
|
27
|
+
|
|
28
|
+
- **misc**: Fix oidc auth timeout issue on the desktop.
|
|
29
|
+
|
|
30
|
+
<br/>
|
|
31
|
+
|
|
32
|
+
<details>
|
|
33
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
34
|
+
|
|
35
|
+
#### What's fixed
|
|
36
|
+
|
|
37
|
+
- **misc**: Fix oidc auth timeout issue on the desktop, closes [#10025](https://github.com/lobehub/lobe-chat/issues/10025) ([20666db](https://github.com/lobehub/lobe-chat/commit/20666db))
|
|
38
|
+
|
|
39
|
+
</details>
|
|
40
|
+
|
|
41
|
+
<div align="right">
|
|
42
|
+
|
|
43
|
+
[](#readme-top)
|
|
44
|
+
|
|
45
|
+
</div>
|
|
46
|
+
|
|
5
47
|
## [Version 2.0.0-next.20](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.19...v2.0.0-next.20)
|
|
6
48
|
|
|
7
49
|
<sup>Released on **2025-11-03**</sup>
|
|
@@ -14,39 +14,38 @@ const logger = createLogger('controllers:AuthCtr');
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Authentication Controller
|
|
17
|
-
*
|
|
17
|
+
* Implements OAuth authorization flow using intermediate page + polling mechanism
|
|
18
18
|
*/
|
|
19
19
|
export default class AuthCtr extends ControllerModule {
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* Remote server configuration controller
|
|
22
22
|
*/
|
|
23
23
|
private get remoteServerConfigCtr() {
|
|
24
24
|
return this.app.getController(RemoteServerConfigCtr);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
28
|
+
* Current PKCE parameters
|
|
29
29
|
*/
|
|
30
30
|
private codeVerifier: string | null = null;
|
|
31
31
|
private authRequestState: string | null = null;
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Polling related parameters
|
|
35
35
|
*/
|
|
36
36
|
// eslint-disable-next-line no-undef
|
|
37
37
|
private pollingInterval: NodeJS.Timeout | null = null;
|
|
38
38
|
private cachedRemoteUrl: string | null = null;
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Auto-refresh timer
|
|
42
42
|
*/
|
|
43
43
|
// eslint-disable-next-line no-undef
|
|
44
44
|
private autoRefreshTimer: NodeJS.Timeout | null = null;
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @param remoteUrl
|
|
49
|
-
* @param includeHandoffId 是否包含 handoff ID(仅在授权时需要)
|
|
47
|
+
* Construct redirect_uri, ensuring the same URI is used for authorization and token exchange
|
|
48
|
+
* @param remoteUrl Remote server URL
|
|
50
49
|
*/
|
|
51
50
|
private constructRedirectUri(remoteUrl: string): string {
|
|
52
51
|
const callbackUrl = new URL('/oidc/callback/desktop', remoteUrl);
|
|
@@ -59,9 +58,12 @@ export default class AuthCtr extends ControllerModule {
|
|
|
59
58
|
*/
|
|
60
59
|
@ipcClientEvent('requestAuthorization')
|
|
61
60
|
async requestAuthorization(config: DataSyncConfig) {
|
|
61
|
+
// Clear any old authorization state
|
|
62
|
+
this.clearAuthorizationState();
|
|
63
|
+
|
|
62
64
|
const remoteUrl = await this.remoteServerConfigCtr.getRemoteServerUrl(config);
|
|
63
65
|
|
|
64
|
-
//
|
|
66
|
+
// Cache remote server URL for subsequent polling
|
|
65
67
|
this.cachedRemoteUrl = remoteUrl;
|
|
66
68
|
|
|
67
69
|
logger.info(
|
|
@@ -115,7 +117,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
/**
|
|
118
|
-
*
|
|
120
|
+
* Start polling mechanism to retrieve credentials
|
|
119
121
|
*/
|
|
120
122
|
private startPolling() {
|
|
121
123
|
if (!this.authRequestState) {
|
|
@@ -133,7 +135,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
133
135
|
// Check if polling has timed out
|
|
134
136
|
if (Date.now() - startTime > maxPollTime) {
|
|
135
137
|
logger.warn('Credential polling timed out');
|
|
136
|
-
this.
|
|
138
|
+
this.clearAuthorizationState();
|
|
137
139
|
this.broadcastAuthorizationFailed('Authorization timed out');
|
|
138
140
|
return;
|
|
139
141
|
}
|
|
@@ -167,14 +169,14 @@ export default class AuthCtr extends ControllerModule {
|
|
|
167
169
|
}
|
|
168
170
|
} catch (error) {
|
|
169
171
|
logger.error('Error during credential polling:', error);
|
|
170
|
-
this.
|
|
172
|
+
this.clearAuthorizationState();
|
|
171
173
|
this.broadcastAuthorizationFailed('Polling error: ' + error.message);
|
|
172
174
|
}
|
|
173
175
|
}, pollInterval);
|
|
174
176
|
}
|
|
175
177
|
|
|
176
178
|
/**
|
|
177
|
-
*
|
|
179
|
+
* Stop polling
|
|
178
180
|
*/
|
|
179
181
|
private stopPolling() {
|
|
180
182
|
if (this.pollingInterval) {
|
|
@@ -184,18 +186,30 @@ export default class AuthCtr extends ControllerModule {
|
|
|
184
186
|
}
|
|
185
187
|
|
|
186
188
|
/**
|
|
187
|
-
*
|
|
189
|
+
* Clear authorization state
|
|
190
|
+
* Called before starting a new authorization flow or after authorization failure/timeout
|
|
191
|
+
*/
|
|
192
|
+
private clearAuthorizationState() {
|
|
193
|
+
logger.debug('Clearing authorization state');
|
|
194
|
+
this.stopPolling();
|
|
195
|
+
this.codeVerifier = null;
|
|
196
|
+
this.authRequestState = null;
|
|
197
|
+
this.cachedRemoteUrl = null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Start auto-refresh timer
|
|
188
202
|
*/
|
|
189
203
|
private startAutoRefresh() {
|
|
190
|
-
//
|
|
204
|
+
// Stop existing timer first
|
|
191
205
|
this.stopAutoRefresh();
|
|
192
206
|
|
|
193
|
-
const checkInterval = 2 * 60 * 1000; //
|
|
207
|
+
const checkInterval = 2 * 60 * 1000; // Check every 2 minutes
|
|
194
208
|
logger.debug('Starting auto-refresh timer');
|
|
195
209
|
|
|
196
210
|
this.autoRefreshTimer = setInterval(async () => {
|
|
197
211
|
try {
|
|
198
|
-
//
|
|
212
|
+
// Check if token is expiring soon (refresh 5 minutes in advance)
|
|
199
213
|
if (this.remoteServerConfigCtr.isTokenExpiringSoon()) {
|
|
200
214
|
const expiresAt = this.remoteServerConfigCtr.getTokenExpiresAt();
|
|
201
215
|
logger.info(
|
|
@@ -208,7 +222,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
208
222
|
this.broadcastTokenRefreshed();
|
|
209
223
|
} else {
|
|
210
224
|
logger.error(`Auto-refresh failed: ${result.error}`);
|
|
211
|
-
//
|
|
225
|
+
// If auto-refresh fails, stop timer and clear token
|
|
212
226
|
this.stopAutoRefresh();
|
|
213
227
|
await this.remoteServerConfigCtr.clearTokens();
|
|
214
228
|
await this.remoteServerConfigCtr.setRemoteServerConfig({ active: false });
|
|
@@ -222,7 +236,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
222
236
|
}
|
|
223
237
|
|
|
224
238
|
/**
|
|
225
|
-
*
|
|
239
|
+
* Stop auto-refresh timer
|
|
226
240
|
*/
|
|
227
241
|
private stopAutoRefresh() {
|
|
228
242
|
if (this.autoRefreshTimer) {
|
|
@@ -233,8 +247,8 @@ export default class AuthCtr extends ControllerModule {
|
|
|
233
247
|
}
|
|
234
248
|
|
|
235
249
|
/**
|
|
236
|
-
*
|
|
237
|
-
*
|
|
250
|
+
* Poll for credentials
|
|
251
|
+
* Sends HTTP request directly to remote server
|
|
238
252
|
*/
|
|
239
253
|
private async pollForCredentials(): Promise<{ code: string; state: string } | null> {
|
|
240
254
|
if (!this.authRequestState || !this.cachedRemoteUrl) {
|
|
@@ -242,17 +256,17 @@ export default class AuthCtr extends ControllerModule {
|
|
|
242
256
|
}
|
|
243
257
|
|
|
244
258
|
try {
|
|
245
|
-
//
|
|
259
|
+
// Use cached remote server URL
|
|
246
260
|
const remoteUrl = this.cachedRemoteUrl;
|
|
247
261
|
|
|
248
|
-
//
|
|
262
|
+
// Construct request URL
|
|
249
263
|
const url = new URL('/oidc/handoff', remoteUrl);
|
|
250
264
|
url.searchParams.set('id', this.authRequestState);
|
|
251
265
|
url.searchParams.set('client', 'desktop');
|
|
252
266
|
|
|
253
267
|
logger.debug(`Polling for credentials: ${url.toString()}`);
|
|
254
268
|
|
|
255
|
-
//
|
|
269
|
+
// Send HTTP request directly
|
|
256
270
|
const response = await fetch(url.toString(), {
|
|
257
271
|
headers: {
|
|
258
272
|
'Content-Type': 'application/json',
|
|
@@ -260,9 +274,9 @@ export default class AuthCtr extends ControllerModule {
|
|
|
260
274
|
method: 'GET',
|
|
261
275
|
});
|
|
262
276
|
|
|
263
|
-
//
|
|
277
|
+
// Check response status
|
|
264
278
|
if (response.status === 404) {
|
|
265
|
-
//
|
|
279
|
+
// Credentials not ready yet, this is normal
|
|
266
280
|
return null;
|
|
267
281
|
}
|
|
268
282
|
|
|
@@ -270,7 +284,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
270
284
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
271
285
|
}
|
|
272
286
|
|
|
273
|
-
//
|
|
287
|
+
// Parse response data
|
|
274
288
|
const data = (await response.json()) as {
|
|
275
289
|
data: {
|
|
276
290
|
id: string;
|
|
@@ -511,7 +525,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
511
525
|
}
|
|
512
526
|
|
|
513
527
|
/**
|
|
514
|
-
*
|
|
528
|
+
* Initialize after app is ready
|
|
515
529
|
*/
|
|
516
530
|
afterAppReady() {
|
|
517
531
|
logger.debug('AuthCtr initialized, checking for existing tokens');
|
|
@@ -519,7 +533,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
519
533
|
}
|
|
520
534
|
|
|
521
535
|
/**
|
|
522
|
-
*
|
|
536
|
+
* Clean up all timers
|
|
523
537
|
*/
|
|
524
538
|
cleanup() {
|
|
525
539
|
logger.debug('Cleaning up AuthCtr timers');
|
|
@@ -528,14 +542,14 @@ export default class AuthCtr extends ControllerModule {
|
|
|
528
542
|
}
|
|
529
543
|
|
|
530
544
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
545
|
+
* Initialize auto-refresh functionality
|
|
546
|
+
* Checks for valid token at app startup and starts auto-refresh timer if token exists
|
|
533
547
|
*/
|
|
534
548
|
private async initializeAutoRefresh() {
|
|
535
549
|
try {
|
|
536
550
|
const config = await this.remoteServerConfigCtr.getRemoteServerConfig();
|
|
537
551
|
|
|
538
|
-
//
|
|
552
|
+
// Check if remote server is configured and active
|
|
539
553
|
if (!config.active || !config.remoteServerUrl) {
|
|
540
554
|
logger.debug(
|
|
541
555
|
'Remote server not active or configured, skipping auto-refresh initialization',
|
|
@@ -543,36 +557,36 @@ export default class AuthCtr extends ControllerModule {
|
|
|
543
557
|
return;
|
|
544
558
|
}
|
|
545
559
|
|
|
546
|
-
//
|
|
560
|
+
// Check if valid access token exists
|
|
547
561
|
const accessToken = await this.remoteServerConfigCtr.getAccessToken();
|
|
548
562
|
if (!accessToken) {
|
|
549
563
|
logger.debug('No access token found, skipping auto-refresh initialization');
|
|
550
564
|
return;
|
|
551
565
|
}
|
|
552
566
|
|
|
553
|
-
//
|
|
567
|
+
// Check if token expiration time exists
|
|
554
568
|
const expiresAt = this.remoteServerConfigCtr.getTokenExpiresAt();
|
|
555
569
|
if (!expiresAt) {
|
|
556
570
|
logger.debug('No token expiration time found, skipping auto-refresh initialization');
|
|
557
571
|
return;
|
|
558
572
|
}
|
|
559
573
|
|
|
560
|
-
//
|
|
574
|
+
// Check if token has already expired
|
|
561
575
|
const currentTime = Date.now();
|
|
562
576
|
if (currentTime >= expiresAt) {
|
|
563
577
|
logger.info('Token has expired, attempting to refresh it');
|
|
564
578
|
|
|
565
|
-
//
|
|
579
|
+
// Attempt to refresh token
|
|
566
580
|
const refreshResult = await this.remoteServerConfigCtr.refreshAccessToken();
|
|
567
581
|
if (refreshResult.success) {
|
|
568
582
|
logger.info('Token refresh successful during initialization');
|
|
569
583
|
this.broadcastTokenRefreshed();
|
|
570
|
-
//
|
|
584
|
+
// Restart auto-refresh timer
|
|
571
585
|
this.startAutoRefresh();
|
|
572
586
|
return;
|
|
573
587
|
} else {
|
|
574
588
|
logger.error(`Token refresh failed during initialization: ${refreshResult.error}`);
|
|
575
|
-
//
|
|
589
|
+
// Clear token and require re-authorization only on refresh failure
|
|
576
590
|
await this.remoteServerConfigCtr.clearTokens();
|
|
577
591
|
await this.remoteServerConfigCtr.setRemoteServerConfig({ active: false });
|
|
578
592
|
this.broadcastAuthorizationRequired();
|
|
@@ -580,7 +594,7 @@ export default class AuthCtr extends ControllerModule {
|
|
|
580
594
|
}
|
|
581
595
|
}
|
|
582
596
|
|
|
583
|
-
//
|
|
597
|
+
// Start auto-refresh timer
|
|
584
598
|
logger.info(
|
|
585
599
|
`Token is valid, starting auto-refresh timer. Token expires at: ${new Date(expiresAt).toISOString()}`,
|
|
586
600
|
);
|
|
@@ -2,16 +2,16 @@ import { ControllerModule, ipcClientEvent } from './index';
|
|
|
2
2
|
|
|
3
3
|
export default class MenuController extends ControllerModule {
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Refresh menu
|
|
6
6
|
*/
|
|
7
7
|
@ipcClientEvent('refreshAppMenu')
|
|
8
8
|
refreshAppMenu() {
|
|
9
|
-
//
|
|
9
|
+
// Note: May need to decide whether to allow renderer process to refresh all menus based on specific circumstances
|
|
10
10
|
return this.app.menuManager.refreshMenus();
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* Show context menu
|
|
15
15
|
*/
|
|
16
16
|
@ipcClientEvent('showContextMenu')
|
|
17
17
|
showContextMenu(params: { data?: any; type: string }) {
|
|
@@ -19,11 +19,11 @@ export default class MenuController extends ControllerModule {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Set development menu visibility
|
|
23
23
|
*/
|
|
24
24
|
@ipcClientEvent('setDevMenuVisibility')
|
|
25
25
|
setDevMenuVisibility(visible: boolean) {
|
|
26
|
-
//
|
|
26
|
+
// Call MenuManager method to rebuild application menu
|
|
27
27
|
return this.app.menuManager.rebuildAppMenu({ showDevItems: visible });
|
|
28
28
|
}
|
|
29
29
|
}
|