Skip to content

Commit bf15fb9

Browse files
committed
fix: harden desktop transport bootstrap
1 parent 50a9774 commit bf15fb9

3 files changed

Lines changed: 70 additions & 10 deletions

File tree

scripts/prepare-resources/desktop-bridge-checks.test.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ test('getDesktopBridgeExpectations returns stable expectation metadata', () => {
1616
assert.ok(expectations.length > 0);
1717
assert.ok(expectations.some((expectation) => expectation.required === true));
1818
assert.ok(expectations.some((expectation) => expectation.required === false));
19+
assert.ok(expectations.some((expectation) => expectation.label === 'chat transport preference read'));
20+
assert.ok(expectations.some((expectation) => expectation.label === 'chat transport preference write'));
21+
assert.ok(
22+
expectations.some((expectation) => expectation.label === 'standalone chat transport preference read'),
23+
);
1924

2025
for (const expectation of expectations) {
2126
assert.equal(Array.isArray(expectation.filePath), true);

scripts/prepare-resources/desktop-bridge-expectations.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2+
3+
const CHAT_TRANSPORT_MODE_STORAGE_KEY = 'chat.transportMode';
4+
const CHAT_TRANSPORT_MODE_WEBSOCKET = 'websocket';
5+
6+
const CHAT_TRANSPORT_STORAGE_KEY_PATTERN = escapeRegex(CHAT_TRANSPORT_MODE_STORAGE_KEY);
7+
const CHAT_TRANSPORT_WEBSOCKET_PATTERN = escapeRegex(CHAT_TRANSPORT_MODE_WEBSOCKET);
8+
19
const DESKTOP_BRIDGE_PATTERNS = {
210
trayRestartGuard: /if\s*\(\s*!desktopBridge\s*\?\.\s*onTrayRestartBackend\s*\)\s*\{/,
311
trayRestartPromptInvoke:
@@ -10,6 +18,12 @@ const DESKTOP_BRIDGE_PATTERNS = {
1018
/const\s+runtimeInfo\s*=\s*await\s+getDesktopRuntimeInfo\s*\(\s*\)\s*;?[\s\S]*?isDesktopReleaseMode\.value\s*=\s*runtimeInfo\.isDesktopRuntime/,
1119
desktopReleaseModeFlag: /\bisDesktopReleaseMode\b/,
1220
desktopRuntimeProbeWarn: /console\.warn\([\s\S]*desktop runtime/i,
21+
chatTransportPreferenceRead: new RegExp(
22+
`localStorage\\.getItem\\(["']${CHAT_TRANSPORT_STORAGE_KEY_PATTERN}["']\\)[\\s\\S]*?["']${CHAT_TRANSPORT_WEBSOCKET_PATTERN}["']`,
23+
),
24+
chatTransportPreferenceWrite: new RegExp(
25+
`localStorage\\.setItem\\(["']${CHAT_TRANSPORT_STORAGE_KEY_PATTERN}["']\\s*,`,
26+
),
1327
};
1428

1529
const DESKTOP_BRIDGE_EXPECTATIONS = [
@@ -62,6 +76,29 @@ const DESKTOP_BRIDGE_EXPECTATIONS = [
6276
hint: 'Expected warning log when desktop runtime detection fails.',
6377
required: false,
6478
},
79+
{
80+
filePath: ['src', 'components', 'chat', 'Chat.vue'],
81+
pattern: DESKTOP_BRIDGE_PATTERNS.chatTransportPreferenceRead,
82+
label: 'chat transport preference read',
83+
hint:
84+
'Expected chat UI to read localStorage["chat.transportMode"] and recognize "websocket".',
85+
required: true,
86+
},
87+
{
88+
filePath: ['src', 'components', 'chat', 'Chat.vue'],
89+
pattern: DESKTOP_BRIDGE_PATTERNS.chatTransportPreferenceWrite,
90+
label: 'chat transport preference write',
91+
hint: 'Expected chat UI to persist transport mode via localStorage.setItem("chat.transportMode", ...).',
92+
required: true,
93+
},
94+
{
95+
filePath: ['src', 'components', 'chat', 'StandaloneChat.vue'],
96+
pattern: DESKTOP_BRIDGE_PATTERNS.chatTransportPreferenceRead,
97+
label: 'standalone chat transport preference read',
98+
hint:
99+
'Expected standalone chat UI to read localStorage["chat.transportMode"] and recognize "websocket".',
100+
required: true,
101+
},
65102
];
66103

67104
export const getDesktopBridgeExpectations = () => [...DESKTOP_BRIDGE_EXPECTATIONS];

src-tauri/src/bridge_bootstrap.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,12 @@
148148

149149
const TOKEN_STORAGE_KEY = 'token';
150150
const SHELL_LOCALE_STORAGE_KEY = 'astrbot-locale';
151-
const CHAT_TRANSPORT_MODE_STORAGE_KEY = 'chat.transportMode';
152-
const CHAT_TRANSPORT_MODE_WEBSOCKET = 'websocket';
151+
// Mirror AstrBot dashboard transport persistence. Resource preparation verifies
152+
// the upstream ChatUI still recognizes this storage contract before packaging.
153+
const CHAT_TRANSPORT = Object.freeze({
154+
STORAGE_KEY: 'chat.transportMode',
155+
WEBSOCKET: 'websocket',
156+
});
153157
const STORAGE_SYNC_PATCHED_FLAG = '__astrbotDesktopStorageSyncPatched';
154158
const LEGACY_TOKEN_SYNC_PATCHED_FLAG = '__astrbotDesktopTokenSyncPatched';
155159

@@ -203,6 +207,12 @@
203207
error,
204208
});
205209
};
210+
const warnDefaultChatTransportModeError = (phase, error) => {
211+
devWarn('[astrbotDesktop] failed to seed default chat transport mode', {
212+
phase,
213+
error,
214+
});
215+
};
206216

207217
const normalizeExternalHttpUrl = (rawUrl) => {
208218
if (rawUrl instanceof URL) {
@@ -700,15 +710,23 @@
700710
};
701711

702712
const ensureDefaultChatTransportMode = () => {
713+
const storage = window.localStorage;
714+
if (!storage) return;
715+
716+
let existingTransportMode;
703717
try {
704-
const storage = window.localStorage;
705-
if (!storage) return;
706-
if (storage.getItem(CHAT_TRANSPORT_MODE_STORAGE_KEY) !== null) return;
707-
storage.setItem(
708-
CHAT_TRANSPORT_MODE_STORAGE_KEY,
709-
CHAT_TRANSPORT_MODE_WEBSOCKET,
710-
);
711-
} catch {}
718+
existingTransportMode = storage.getItem(CHAT_TRANSPORT.STORAGE_KEY);
719+
} catch (error) {
720+
warnDefaultChatTransportModeError('read', error);
721+
return;
722+
}
723+
if (existingTransportMode !== null) return;
724+
725+
try {
726+
storage.setItem(CHAT_TRANSPORT.STORAGE_KEY, CHAT_TRANSPORT.WEBSOCKET);
727+
} catch (error) {
728+
warnDefaultChatTransportModeError('write', error);
729+
}
712730
};
713731

714732
window.astrbotDesktop = {

0 commit comments

Comments
 (0)