mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 15:03:57 +00:00
Enforce static imports and improve error handling for Tauri API calls
- Updated the codebase to replace dynamic imports with static imports for Tauri API calls, enhancing performance and compliance with new coding standards. - Implemented try/catch blocks around Tauri API calls to handle errors gracefully in non-Tauri environments. - Refactored components to ensure consistent usage of static imports, improving code clarity and maintainability. - Adjusted the `activeTeamId` property in the User interface to be required, ensuring better type safety.
This commit is contained in:
@@ -352,6 +352,7 @@ Key updates from recent commits (cd9ebcd to current):
|
||||
## Key Patterns
|
||||
|
||||
- **Code Quality**: ESLint and Prettier enforce code standards with Husky hooks. Use type-only imports (`import type`) and consolidate imports from same modules.
|
||||
- **No dynamic imports**: All imports must be static `import` statements at the top of the file. Do not use `await import()` or `import().then()` inside functions or code blocks. Use try/catch around Tauri API calls for non-Tauri environments instead.
|
||||
- **No localStorage**: Avoid `localStorage` and `sessionStorage`; use Redux (and persist) for app state. Remove any direct usage when working on affected code.
|
||||
- **AI System Integration**: Use `src/lib/ai/` for memory management, constitution loading, entity queries, and session capture. AI providers abstracted through interface pattern.
|
||||
- **V8 Skills Runtime**: Skills execute in V8 JavaScript engine on desktop platforms. Use `SkillProvider` for GitHub sync, `SkillsGrid` for management interface, and Rust runtime commands for lifecycle management. Platform filtering ensures skills only run on supported platforms.
|
||||
@@ -377,7 +378,7 @@ Key updates from recent commits (cd9ebcd to current):
|
||||
|
||||
- **macOS deep links**: Require `.app` bundle (not `tauri dev`). Clear WebKit caches when debugging stale content: `rm -rf ~/Library/WebKit/com.alphahuman.app ~/Library/Caches/com.alphahuman.app`
|
||||
- **Cargo caching**: May serve stale frontend assets on incremental builds. Run `cargo clean --manifest-path src-tauri/Cargo.toml` if the app shows outdated UI.
|
||||
- **`window.__TAURI__`**: Not available at module load time. Use dynamic `import()` and try/catch for Tauri plugin calls.
|
||||
- **`window.__TAURI__`**: Not available at module load time. Use static imports and try/catch around Tauri API calls (not around imports).
|
||||
- **Android background services**: RuntimeService requires notification permissions (API 33+) and foreground service type specification (API 34+). Use Android logging (`android_logger`) for debug output in logcat.
|
||||
- **V8 runtime limitations**: V8 engine is desktop-only. Android skills should use lightweight alternatives or server-side execution patterns.
|
||||
- **Socket connections**: Persistent Socket.io connections via Rust backend work better than WebView-based connections on mobile platforms.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { platform } from '@tauri-apps/plugin-os';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useModelStatus } from '../hooks/useModelStatus';
|
||||
@@ -19,7 +20,6 @@ const ModelDownloadProgress = ({
|
||||
// Detect mobile platform
|
||||
const detectMobile = async () => {
|
||||
try {
|
||||
const { platform } = await import('@tauri-apps/plugin-os');
|
||||
const currentPlatform = await platform();
|
||||
setIsMobile(currentPlatform === 'android' || currentPlatform === 'ios');
|
||||
} catch {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { platform } from '@tauri-apps/plugin-os';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import GoogleIcon from '../assets/icons/GoogleIcon';
|
||||
@@ -292,7 +294,6 @@ export default function SkillsGrid() {
|
||||
// Detect mobile platform
|
||||
const detectMobile = async () => {
|
||||
try {
|
||||
const { platform } = await import('@tauri-apps/plugin-os');
|
||||
const currentPlatform = await platform();
|
||||
setIsMobile(currentPlatform === 'android' || currentPlatform === 'ios');
|
||||
} catch {
|
||||
@@ -305,7 +306,6 @@ export default function SkillsGrid() {
|
||||
// Load skills from the V8 runtime engine.
|
||||
const loadSkills = async () => {
|
||||
try {
|
||||
const { invoke } = await import('@tauri-apps/api/core');
|
||||
const manifests = await invoke<Array<Record<string, unknown>>>('runtime_discover_skills');
|
||||
|
||||
console.log('manifests', manifests);
|
||||
|
||||
@@ -27,15 +27,11 @@ const BillingPanel = () => {
|
||||
const activeTeam = teams.find(t => t.team._id === activeTeamId);
|
||||
const teamName = activeTeam?.team.name;
|
||||
|
||||
// Derive plan from active team when available, fall back to user
|
||||
const currentTier: PlanTier =
|
||||
activeTeam?.team.subscription?.plan ?? user?.subscription?.plan ?? 'FREE';
|
||||
const hasActive =
|
||||
activeTeam?.team.subscription?.hasActiveSubscription ??
|
||||
user?.subscription?.hasActiveSubscription ??
|
||||
false;
|
||||
const planExpiry = activeTeam?.team.subscription?.planExpiry ?? user?.subscription?.planExpiry;
|
||||
const usage = activeTeam?.team.usage ?? user?.usage;
|
||||
// Derive plan from active team (team is source of truth)
|
||||
const currentTier: PlanTier = activeTeam?.team.subscription?.plan ?? 'FREE';
|
||||
const hasActive = activeTeam?.team.subscription?.hasActiveSubscription ?? false;
|
||||
const planExpiry = activeTeam?.team.subscription?.planExpiry;
|
||||
const usage = activeTeam?.team.usage;
|
||||
|
||||
// Local state
|
||||
const [billingInterval, setBillingInterval] = useState<'monthly' | 'annual'>('monthly');
|
||||
|
||||
@@ -22,9 +22,7 @@ const TeamInvitesPanel = () => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTeamId) {
|
||||
dispatch(fetchInvites(activeTeamId));
|
||||
}
|
||||
if (activeTeamId) dispatch(fetchInvites(activeTeamId));
|
||||
}, [activeTeamId, dispatch]);
|
||||
|
||||
const handleGenerate = async () => {
|
||||
|
||||
@@ -24,9 +24,7 @@ const TeamMembersPanel = () => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTeamId) {
|
||||
dispatch(fetchMembers(activeTeamId));
|
||||
}
|
||||
if (activeTeamId) dispatch(fetchMembers(activeTeamId));
|
||||
}, [activeTeamId, dispatch]);
|
||||
|
||||
const handleChangeRole = async (member: TeamMember, newRole: TeamRole) => {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* and tool invocation. Dispatches status changes to Redux.
|
||||
*/
|
||||
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
import { SkillRuntime } from "./runtime";
|
||||
import type {
|
||||
SkillManifest,
|
||||
@@ -367,7 +369,6 @@ class SkillManager {
|
||||
case "data/read": {
|
||||
const filename = params.filename as string;
|
||||
try {
|
||||
const { invoke } = await import("@tauri-apps/api/core");
|
||||
const content = await invoke<string>("runtime_skill_data_read", {
|
||||
skillId,
|
||||
filename,
|
||||
@@ -382,7 +383,6 @@ class SkillManager {
|
||||
const filename = params.filename as string;
|
||||
const content = params.content as string;
|
||||
try {
|
||||
const { invoke } = await import("@tauri-apps/api/core");
|
||||
await invoke("runtime_skill_data_write", {
|
||||
skillId,
|
||||
filename,
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
* no longer needs to handle reverse RPC from the skill.
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
export type ReverseRpcHandler = (
|
||||
method: string,
|
||||
params: Record<string, unknown>
|
||||
@@ -58,7 +60,6 @@ export class SkillTransport {
|
||||
hasParams: params !== undefined,
|
||||
});
|
||||
|
||||
const { invoke } = await import("@tauri-apps/api/core");
|
||||
const result = await invoke<T>("runtime_rpc", {
|
||||
skillId: this.skillId,
|
||||
method,
|
||||
@@ -89,14 +90,12 @@ export class SkillTransport {
|
||||
});
|
||||
|
||||
// Fire and forget
|
||||
import("@tauri-apps/api/core").then(({ invoke }) => {
|
||||
invoke("runtime_rpc", {
|
||||
skillId: this.skillId,
|
||||
method,
|
||||
params: params ?? {},
|
||||
}).catch((err: unknown) => {
|
||||
console.error("[skill-transport] Notification error:", err);
|
||||
});
|
||||
invoke("runtime_rpc", {
|
||||
skillId: this.skillId,
|
||||
method,
|
||||
params: params ?? {},
|
||||
}).catch((err: unknown) => {
|
||||
console.error("[skill-transport] Notification error:", err);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +106,6 @@ export class SkillTransport {
|
||||
async kill(): Promise<void> {
|
||||
if (this.skillId && this._started) {
|
||||
try {
|
||||
const { invoke } = await import("@tauri-apps/api/core");
|
||||
await invoke("runtime_stop_skill", { skillId: this.skillId });
|
||||
} catch {
|
||||
// Skill may already be stopped
|
||||
|
||||
+4
-5
@@ -6,15 +6,14 @@ import App from './App';
|
||||
import './index.css';
|
||||
import './polyfills';
|
||||
import { initSentry } from './services/analytics';
|
||||
import { setupDesktopDeepLinkListener } from './utils/desktopDeepLinkListener';
|
||||
|
||||
// Initialize Sentry early (before React renders)
|
||||
initSentry();
|
||||
|
||||
// Deep link listener - lazy import to avoid running before Tauri IPC is ready
|
||||
import('./utils/desktopDeepLinkListener').then(m => {
|
||||
m.setupDesktopDeepLinkListener().catch(err => {
|
||||
console.error('[DeepLink] setup error:', err);
|
||||
});
|
||||
// Deep link listener — try/catch handles non-Tauri environments
|
||||
setupDesktopDeepLinkListener().catch(err => {
|
||||
console.error('[DeepLink] setup error:', err);
|
||||
});
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* The Rust V8 engine handles skill discovery and auto-start independently.
|
||||
* This provider bridges the Rust engine state with the frontend Redux store.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { type ReactNode, useEffect, useRef } from 'react';
|
||||
|
||||
import { skillManager } from '../lib/skills/manager';
|
||||
@@ -19,7 +20,6 @@ import { DEV_AUTO_LOAD_SKILL } from '../utils/config';
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function discoverSkills(): Promise<SkillManifest[]> {
|
||||
const { invoke } = await import('@tauri-apps/api/core');
|
||||
const raw = await invoke<Array<Record<string, unknown>>>('runtime_discover_skills');
|
||||
// Map the V8 manifest format to SkillManifest
|
||||
return raw.map(m => ({
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ export interface User {
|
||||
username?: string;
|
||||
languageCode?: string;
|
||||
waitlist?: string;
|
||||
activeTeamId?: string;
|
||||
activeTeamId: string;
|
||||
}
|
||||
|
||||
// Billing types
|
||||
|
||||
Reference in New Issue
Block a user