fix(desktop): guard invoke calls with isTauriRuntime check
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

Step 5 (embedding config) and Step 5b (summary driver) in App.tsx
bootstrap called invoke() without checking if Tauri IPC is available.
When accessing http://localhost:1420/ in a regular browser, this caused
"Cannot read properties of undefined (reading 'transformCallback')".

Also added __TAURI_INTERNALS__ guard in saasStore kernel config sync.
This commit is contained in:
iven
2026-04-03 12:46:14 +08:00
parent 65b73c547f
commit 564c7ca28f
2 changed files with 53 additions and 51 deletions

View File

@@ -261,63 +261,65 @@ function App() {
// Non-critical, continue without heartbeat
}
// Step 5: Restore embedding config to Rust backend
try {
// Migrate plaintext embedding apiKey to secure storage if present
// Step 5: Restore embedding config to Rust backend (Tauri-only)
if (isTauriRuntime()) {
try {
const embStored = localStorage.getItem('zclaw-embedding-config');
if (embStored) {
const embParsed = JSON.parse(embStored);
if (embParsed.apiKey && embParsed.apiKey.trim()) {
const { saveEmbeddingApiKey } = await import('./lib/embedding-client');
const { secureStorage } = await import('./lib/secure-storage');
// Only migrate if not already in secure storage
const existing = await secureStorage.get('zclaw-secure-embedding-apikey');
if (!existing) {
await saveEmbeddingApiKey(embParsed.apiKey);
// Migrate plaintext embedding apiKey to secure storage if present
try {
const embStored = localStorage.getItem('zclaw-embedding-config');
if (embStored) {
const embParsed = JSON.parse(embStored);
if (embParsed.apiKey && embParsed.apiKey.trim()) {
const { saveEmbeddingApiKey } = await import('./lib/embedding-client');
const { secureStorage } = await import('./lib/secure-storage');
// Only migrate if not already in secure storage
const existing = await secureStorage.get('zclaw-secure-embedding-apikey');
if (!existing) {
await saveEmbeddingApiKey(embParsed.apiKey);
}
// Strip apiKey from localStorage
const { apiKey: _, ...stripped } = embParsed;
localStorage.setItem('zclaw-embedding-config', JSON.stringify(stripped));
}
// Strip apiKey from localStorage
const { apiKey: _, ...stripped } = embParsed;
localStorage.setItem('zclaw-embedding-config', JSON.stringify(stripped));
}
} catch { /* migration failure is non-critical */ }
const embConfig = loadEmbeddingConfig();
const embApiKey = await loadEmbeddingApiKey();
if (embConfig.enabled && embConfig.provider !== 'local' && embApiKey) {
setBootstrapStatus('Restoring embedding configuration...');
await invoke('viking_configure_embedding', {
provider: embConfig.provider,
apiKey: embApiKey,
model: embConfig.model || undefined,
endpoint: embConfig.endpoint || undefined,
});
log.debug('Embedding configuration restored to backend');
}
} catch { /* migration failure is non-critical */ }
const embConfig = loadEmbeddingConfig();
const embApiKey = await loadEmbeddingApiKey();
if (embConfig.enabled && embConfig.provider !== 'local' && embApiKey) {
setBootstrapStatus('Restoring embedding configuration...');
await invoke('viking_configure_embedding', {
provider: embConfig.provider,
apiKey: embApiKey,
model: embConfig.model || undefined,
endpoint: embConfig.endpoint || undefined,
});
log.debug('Embedding configuration restored to backend');
} catch (embErr) {
log.warn('Failed to restore embedding config:', embErr);
// Non-critical, semantic search will fall back to TF-IDF
}
} catch (embErr) {
log.warn('Failed to restore embedding config:', embErr);
// Non-critical, semantic search will fall back to TF-IDF
}
// Step 5b: Configure summary driver using active LLM (for L0/L1 generation)
try {
const { getDefaultModelConfigAsync, migrateModelApiKeysToSecureStorage } = await import('./store/connectionStore');
// Migrate any plaintext API keys to secure storage (idempotent)
await migrateModelApiKeysToSecureStorage();
const modelConfig = await getDefaultModelConfigAsync();
if (modelConfig && modelConfig.apiKey && modelConfig.baseUrl) {
setBootstrapStatus('Configuring summary driver...');
await invoke('viking_configure_summary_driver', {
endpoint: modelConfig.baseUrl,
apiKey: modelConfig.apiKey,
model: modelConfig.model || undefined,
});
log.debug('Summary driver configured with active LLM');
// Step 5b: Configure summary driver using active LLM (for L0/L1 generation)
try {
const { getDefaultModelConfigAsync, migrateModelApiKeysToSecureStorage } = await import('./store/connectionStore');
// Migrate any plaintext API keys to secure storage (idempotent)
await migrateModelApiKeysToSecureStorage();
const modelConfig = await getDefaultModelConfigAsync();
if (modelConfig && modelConfig.apiKey && modelConfig.baseUrl) {
setBootstrapStatus('Configuring summary driver...');
await invoke('viking_configure_summary_driver', {
endpoint: modelConfig.baseUrl,
apiKey: modelConfig.apiKey,
model: modelConfig.model || undefined,
});
log.debug('Summary driver configured with active LLM');
}
} catch (sumErr) {
log.warn('Failed to configure summary driver:', sumErr);
// Non-critical, summaries won't be auto-generated
}
} catch (sumErr) {
log.warn('Failed to configure summary driver:', sumErr);
// Non-critical, summaries won't be auto-generated
}
// Step 6: Bootstrap complete

View File

@@ -542,7 +542,7 @@ export const useSaaSStore = create<SaaSStore>((set, get) => {
const kernelConfigs = result.configs.filter(
(c) => kernelCategories.includes(c.category) && c.value !== null
);
if (kernelConfigs.length > 0) {
if (kernelConfigs.length > 0 && typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window) {
try {
const { invoke } = await import('@tauri-apps/api/core');
await invoke('kernel_apply_saas_config', {