diff --git a/apps/cli/src/output.rs b/apps/cli/src/output.rs index 495c6cda04..6772f56855 100644 --- a/apps/cli/src/output.rs +++ b/apps/cli/src/output.rs @@ -46,10 +46,14 @@ async fn ensure_parent_dirs(path: &Path) -> CliResult<()> { Ok(()) } -async fn write_bytes_to(output: Option<&Path>, bytes: Vec) -> CliResult<()> { +async fn write_bytes_to(output: Option<&Path>, bytes: Vec, add_newline: bool) -> CliResult<()> { if let Some(path) = output { ensure_parent_dirs(path).await?; - tokio::fs::write(path, bytes) + let mut data = bytes; + if add_newline { + data.push(b'\n'); + } + tokio::fs::write(path, data) .await .map_err(|e| CliError::operation_failed("write output", e.to_string()))?; return Ok(()); @@ -58,14 +62,17 @@ async fn write_bytes_to(output: Option<&Path>, bytes: Vec) -> CliResult<()> std::io::stdout() .write_all(&bytes) .map_err(|e| CliError::operation_failed("write output", e.to_string()))?; - std::io::stdout() - .write_all(b"\n") - .map_err(|e| CliError::operation_failed("write output", e.to_string()))?; + if add_newline { + std::io::stdout() + .write_all(b"\n") + .map_err(|e| CliError::operation_failed("write output", e.to_string()))?; + } Ok(()) } pub async fn write_text(output: Option<&Path>, text: String) -> CliResult<()> { - write_bytes_to(output, (text + "\n").into_bytes()).await + // Text content; add single trailing newline for POSIX compliance + write_bytes_to(output, text.into_bytes(), true).await } pub async fn write_json(output: Option<&Path>, value: &impl serde::Serialize) -> CliResult<()> { @@ -76,7 +83,8 @@ pub async fn write_json(output: Option<&Path>, value: &impl serde::Serialize) -> } .map_err(|e| CliError::operation_failed("serialize response", e.to_string()))?; - write_bytes_to(output, bytes).await + // JSON output needs trailing newline for POSIX compliance + write_bytes_to(output, bytes, true).await } pub fn create_progress_bar( diff --git a/apps/desktop/src/auth/context.tsx b/apps/desktop/src/auth/context.tsx index 88f3519083..baf888a686 100644 --- a/apps/desktop/src/auth/context.tsx +++ b/apps/desktop/src/auth/context.tsx @@ -65,6 +65,28 @@ export type AuthContextType = AuthState & const AuthContext = createContext(null); +const MOCK_SESSION: Session = { + access_token: "mock-access-token", + refresh_token: "mock-refresh-token", + token_type: "bearer", + expires_in: 3600, + expires_at: Math.floor(Date.now() / 1000) + 3600 * 24 * 365, + user: { + id: "00000000-0000-0000-0000-000000000000", + aud: "authenticated", + role: "authenticated", + email: "local@localhost", + email_confirmed_at: new Date().toISOString(), + phone: "", + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + app_metadata: {}, + user_metadata: {}, + identities: [], + factors: [], + }, +}; + export function useAuth() { const context = useContext(AuthContext); @@ -197,6 +219,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { useEffect(() => { if (!supabase) { + console.log("[auth] Supabase not configured, using mock session"); + setSession(MOCK_SESSION); return; } diff --git a/apps/desktop/src/onboarding/index.tsx b/apps/desktop/src/onboarding/index.tsx index 1650ae2f05..991066a895 100644 --- a/apps/desktop/src/onboarding/index.tsx +++ b/apps/desktop/src/onboarding/index.tsx @@ -4,7 +4,7 @@ import { Volume2Icon, VolumeXIcon } from "lucide-react"; import { useCallback, useEffect, useRef, useState } from "react"; import { commands as analyticsCommands } from "@hypr/plugin-analytics"; -import { commands as sfxCommands } from "@hypr/plugin-sfx"; +// import { commands as sfxCommands } from "@hypr/plugin-sfx"; import { LoginSection } from "./account"; import { CalendarSection } from "./calendar"; @@ -90,19 +90,21 @@ export function TabContentOnboarding({ }); }, [currentStep]); - useEffect(() => { - sfxCommands - .play("BGM") - .then(() => sfxCommands.setVolume("BGM", 0.2)) - .catch(console.error); - return () => { - sfxCommands.stop("BGM").catch(console.error); - }; - }, []); - - useEffect(() => { - sfxCommands.setVolume("BGM", isMuted ? 0 : 0.2).catch(console.error); - }, [isMuted]); + // Disabled: Background music during onboarding + // useEffect(() => { + // sfxCommands + // .play("BGM") + // .then(() => sfxCommands.setVolume("BGM", 0.2)) + // .catch(console.error); + // return () => { + // sfxCommands.stop("BGM").catch(console.error); + // }; + // }, []); + + // Disabled: Volume control for background music + // useEffect(() => { + // sfxCommands.setVolume("BGM", isMuted ? 0 : 0.2).catch(console.error); + // }, [isMuted]); useEffect(() => { if (onboardingVideoRef.current) { diff --git a/apps/desktop/src/routes/app/main/_layout.tsx b/apps/desktop/src/routes/app/main/_layout.tsx index 82c31bc1d5..1bf08ca516 100644 --- a/apps/desktop/src/routes/app/main/_layout.tsx +++ b/apps/desktop/src/routes/app/main/_layout.tsx @@ -30,7 +30,7 @@ import { restoreRecentlyOpenedToStore, useTabs, } from "~/store/zustand/tabs"; -import { commands } from "~/types/tauri.gen"; +// import { commands } from "~/types/tauri.gen"; export const Route = createFileRoute("/app/main/_layout")({ component: Component, @@ -76,12 +76,8 @@ function Component() { }); const currentTabs = useTabs.getState().tabs; if (currentTabs.length === 0) { - const result = await commands.getOnboardingNeeded(); - if (result.status === "ok" && result.data) { - openNew({ type: "onboarding" }); - } else { - openDefaultEmptyTab(); - } + // Skip onboarding - always open default empty tab + openDefaultEmptyTab(); } } }; diff --git a/crates/audio-device/src/macos.rs b/crates/audio-device/src/macos.rs index 445ebb4945..af014c82ed 100644 --- a/crates/audio-device/src/macos.rs +++ b/crates/audio-device/src/macos.rs @@ -59,7 +59,7 @@ impl MacOSBackend { .unwrap_or(TransportType::Unknown); let is_default = default_device_id - .map(|id| device.0.0 == id) + .map(|id| device.0 .0 == id) .unwrap_or(false); let mut audio_device = AudioDevice { @@ -102,7 +102,11 @@ impl MacOSBackend { }) }); - if detected { Some(true) } else { None } + if detected { + Some(true) + } else { + None + } } fn is_external_from_device(device: Option) -> bool { @@ -120,8 +124,8 @@ impl AudioDeviceBackend for MacOSBackend { let ca_devices = ca::System::devices().map_err(|e| Error::EnumerationFailed(format!("{:?}", e)))?; - let default_input_id = ca::System::default_input_device().ok().map(|d| d.0.0); - let default_output_id = ca::System::default_output_device().ok().map(|d| d.0.0); + let default_input_id = ca::System::default_input_device().ok().map(|d| d.0 .0); + let default_output_id = ca::System::default_output_device().ok().map(|d| d.0 .0); let mut devices = Vec::new(); @@ -161,7 +165,7 @@ impl AudioDeviceBackend for MacOSBackend { Ok(Self::create_audio_device( &ca_device, AudioDirection::Input, - Some(ca_device.0.0), + Some(ca_device.0 .0), )) } @@ -178,7 +182,7 @@ impl AudioDeviceBackend for MacOSBackend { Ok(Self::create_audio_device( &ca_device, AudioDirection::Output, - Some(ca_device.0.0), + Some(ca_device.0 .0), )) } diff --git a/crates/audio-device/src/windows.rs b/crates/audio-device/src/windows.rs index 3d7b95fc08..74b6416b22 100644 --- a/crates/audio-device/src/windows.rs +++ b/crates/audio-device/src/windows.rs @@ -1,17 +1,17 @@ use crate::{AudioDevice, AudioDeviceBackend, AudioDirection, DeviceId, Error, TransportType}; use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; +use windows::core::{Interface, GUID, PCWSTR, PWSTR}; use windows::Win32::Devices::FunctionDiscovery::PKEY_Device_FriendlyName; use windows::Win32::Media::Audio::Endpoints::IAudioEndpointVolume; use windows::Win32::Media::Audio::{ - DEVICE_STATE_ACTIVE, IMMDevice, IMMDeviceEnumerator, MMDeviceEnumerator, eAll, eCapture, - eConsole, eRender, + eAll, eCapture, eConsole, eRender, IMMDevice, IMMDeviceEnumerator, MMDeviceEnumerator, + DEVICE_STATE_ACTIVE, }; use windows::Win32::System::Com::{ - CLSCTX_ALL, COINIT_MULTITHREADED, CoCreateInstance, CoInitializeEx, CoUninitialize, STGM_READ, + CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_MULTITHREADED, STGM_READ, }; use windows::Win32::UI::Shell::PropertiesSystem::IPropertyStore; -use windows::core::{GUID, Interface, PCWSTR, PWSTR}; pub struct WindowsBackend; diff --git a/crates/owhisper-client/src/adapter/openai/live.rs b/crates/owhisper-client/src/adapter/openai/live.rs index 924c823450..06d5fea616 100644 --- a/crates/owhisper-client/src/adapter/openai/live.rs +++ b/crates/owhisper-client/src/adapter/openai/live.rs @@ -29,8 +29,18 @@ impl RealtimeSttAdapter for OpenAIAdapter { false } - fn build_ws_url(&self, api_base: &str, _params: &ListenParams, _channels: u8) -> url::Url { - let (mut url, existing_params) = Self::build_ws_url_from_base(api_base); + fn build_ws_url(&self, api_base: &str, params: &ListenParams, _channels: u8) -> url::Url { + // Detect Azure from the base URL and store flag for initial_message + if let Ok(parsed) = api_base.parse::() { + if let Some(host) = parsed.host_str() { + if Self::is_azure_host(host) { + self.set_azure(true); + } + } + } + + let model = params.model.as_deref(); + let (mut url, existing_params) = Self::build_ws_url_from_base_with_model(api_base, model); if !existing_params.is_empty() { let mut query_pairs = url.query_pairs_mut(); @@ -78,6 +88,11 @@ impl RealtimeSttAdapter for OpenAIAdapter { None => default, }; + // Use the Azure flag set during build_ws_url (detected from api_base URL) + if self.is_azure() { + return self.build_azure_initial_message(model, language); + } + let session_config = SessionUpdateEvent { event_type: "session.update".to_string(), session: SessionConfig { @@ -227,6 +242,76 @@ impl RealtimeSttAdapter for OpenAIAdapter { } } +impl OpenAIAdapter { + /// Build Azure OpenAI-specific initial message + /// Azure uses a different session update format: transcription_session.update + fn build_azure_initial_message( + &self, + model: &str, + language: Option, + ) -> Option { + let session_update = AzureTranscriptionSessionUpdate { + event_type: "transcription_session.update".to_string(), + session: AzureSessionConfig { + input_audio_format: "pcm16".to_string(), + input_audio_transcription: AzureTranscriptionConfig { + model: model.to_string(), + prompt: None, + language, + }, + turn_detection: Some(AzureTurnDetection { + detection_type: VAD_DETECTION_TYPE.to_string(), + threshold: Some(VAD_THRESHOLD), + prefix_padding_ms: Some(VAD_PREFIX_PADDING_MS), + silence_duration_ms: Some(VAD_SILENCE_DURATION_MS), + }), + }, + }; + + let json = serde_json::to_string(&session_update).ok()?; + tracing::debug!(payload = %json, "azure_openai_session_update_payload"); + Some(Message::Text(json.into())) + } +} + +// Azure OpenAI specific session message types + +#[derive(Debug, Serialize)] +struct AzureTranscriptionSessionUpdate { + #[serde(rename = "type")] + event_type: String, + session: AzureSessionConfig, +} + +#[derive(Debug, Serialize)] +struct AzureSessionConfig { + input_audio_format: String, + input_audio_transcription: AzureTranscriptionConfig, + #[serde(skip_serializing_if = "Option::is_none")] + turn_detection: Option, +} + +#[derive(Debug, Serialize)] +struct AzureTranscriptionConfig { + model: String, + #[serde(skip_serializing_if = "Option::is_none")] + prompt: Option, + #[serde(skip_serializing_if = "Option::is_none")] + language: Option, +} + +#[derive(Debug, Serialize)] +struct AzureTurnDetection { + #[serde(rename = "type")] + detection_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + threshold: Option, + #[serde(skip_serializing_if = "Option::is_none")] + prefix_padding_ms: Option, + #[serde(skip_serializing_if = "Option::is_none")] + silence_duration_ms: Option, +} + #[derive(Debug, Serialize)] struct SessionUpdateEvent { #[serde(rename = "type")] diff --git a/crates/owhisper-client/src/adapter/openai/mod.rs b/crates/owhisper-client/src/adapter/openai/mod.rs index 7dd67158f1..bc078806fd 100644 --- a/crates/owhisper-client/src/adapter/openai/mod.rs +++ b/crates/owhisper-client/src/adapter/openai/mod.rs @@ -5,8 +5,33 @@ use crate::providers::Provider; use super::{LanguageQuality, LanguageSupport}; -#[derive(Clone, Default)] -pub struct OpenAIAdapter; +const AZURE_API_VERSION: &str = "2025-04-01-preview"; + +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; + +#[derive(Clone)] +pub struct OpenAIAdapter { + is_azure: Arc, +} + +impl Default for OpenAIAdapter { + fn default() -> Self { + Self { + is_azure: Arc::new(AtomicBool::new(false)), + } + } +} + +impl OpenAIAdapter { + pub fn set_azure(&self, value: bool) { + self.is_azure.store(value, Ordering::SeqCst); + } + + pub fn is_azure(&self) -> bool { + self.is_azure.load(Ordering::SeqCst) + } +} impl OpenAIAdapter { pub fn language_support_live(_languages: &[hypr_language::Language]) -> LanguageSupport { @@ -27,7 +52,18 @@ impl OpenAIAdapter { Self::language_support_batch(languages).is_supported() } + pub fn is_azure_host(host: &str) -> bool { + host.ends_with(".openai.azure.com") + } + pub(crate) fn build_ws_url_from_base(api_base: &str) -> (url::Url, Vec<(String, String)>) { + Self::build_ws_url_from_base_with_model(api_base, None) + } + + pub(crate) fn build_ws_url_from_base_with_model( + api_base: &str, + model: Option<&str>, + ) -> (url::Url, Vec<(String, String)>) { if api_base.is_empty() { return ( Provider::OpenAI @@ -43,15 +79,20 @@ impl OpenAIAdapter { } let parsed: url::Url = api_base.parse().expect("invalid_api_base"); + let host = parsed + .host_str() + .unwrap_or(Provider::OpenAI.default_ws_host()); + + if Self::is_azure_host(host) { + return Self::build_azure_ws_url(&parsed, host, model); + } + let mut existing_params = super::extract_query_params(&parsed); if !existing_params.iter().any(|(k, _)| k == "intent") { existing_params.push(("intent".to_string(), "transcription".to_string())); } - let host = parsed - .host_str() - .unwrap_or(Provider::OpenAI.default_ws_host()); let mut url: url::Url = format!("wss://{}{}", host, Provider::OpenAI.ws_path()) .parse() .expect("invalid_ws_url"); @@ -60,6 +101,28 @@ impl OpenAIAdapter { (url, existing_params) } + + fn build_azure_ws_url( + parsed: &url::Url, + host: &str, + _model: Option<&str>, + ) -> (url::Url, Vec<(String, String)>) { + // For Azure transcription Realtime API: + // - deployment/model should NOT be in URL (causes 400 error) + // - deployment must be sent in transcription_session.update message + // - Only api-version and intent go in the URL + + let url: url::Url = format!("wss://{}/openai/realtime", host) + .parse() + .expect("invalid_azure_ws_url"); + + let params = vec![ + ("api-version".to_string(), AZURE_API_VERSION.to_string()), + ("intent".to_string(), "transcription".to_string()), + ]; + + (url, params) + } } #[cfg(test)] @@ -98,4 +161,65 @@ mod tests { assert!(Provider::OpenAI.is_host("openai.com")); assert!(!Provider::OpenAI.is_host("api.deepgram.com")); } + + #[test] + fn test_is_azure_host() { + assert!(OpenAIAdapter::is_azure_host("my-resource.openai.azure.com")); + assert!(OpenAIAdapter::is_azure_host("eastus.openai.azure.com")); + assert!(!OpenAIAdapter::is_azure_host("api.openai.com")); + assert!(!OpenAIAdapter::is_azure_host("openai.com")); + assert!(!OpenAIAdapter::is_azure_host("azure.com")); + } + + #[test] + fn test_build_ws_url_azure() { + // Azure transcription: deployment should NOT be in URL + // Only api-version and intent should be in params + let (url, params) = OpenAIAdapter::build_ws_url_from_base_with_model( + "https://my-resource.openai.azure.com", + Some("gpt-4o-realtime-preview"), + ); + assert_eq!( + url.as_str(), + "wss://my-resource.openai.azure.com/openai/realtime" + ); + assert!( + params + .iter() + .any(|(k, v)| k == "api-version" && v == "2025-04-01-preview") + ); + assert!( + params + .iter() + .any(|(k, v)| k == "intent" && v == "transcription") + ); + // deployment should NOT be in URL params + assert!(!params.iter().any(|(k, _)| k == "deployment")); + } + + #[test] + fn test_build_ws_url_azure_deployment_not_in_url() { + // Even if deployment is in input URL, it should not appear in output params + // (deployment goes in session message, not URL) + let (url, params) = OpenAIAdapter::build_ws_url_from_base_with_model( + "https://my-resource.openai.azure.com?deployment=my-deployment", + None, + ); + assert_eq!( + url.as_str(), + "wss://my-resource.openai.azure.com/openai/realtime" + ); + // deployment should NOT be in URL params + assert!(!params.iter().any(|(k, _)| k == "deployment")); + assert!( + params + .iter() + .any(|(k, v)| k == "api-version" && v == "2025-04-01-preview") + ); + assert!( + params + .iter() + .any(|(k, v)| k == "intent" && v == "transcription") + ); + } } diff --git a/crates/owhisper-client/src/lib.rs b/crates/owhisper-client/src/lib.rs index 06ff619213..93dfebcade 100644 --- a/crates/owhisper-client/src/lib.rs +++ b/crates/owhisper-client/src/lib.rs @@ -15,8 +15,6 @@ pub use providers::{Auth, Provider, is_meta_model}; use std::marker::PhantomData; -#[cfg(feature = "argmax")] -pub use adapter::StreamingBatchConfig; pub use adapter::deepgram::DeepgramModel; pub use adapter::{ AdapterKind, ArgmaxAdapter, AssemblyAIAdapter, BatchSttAdapter, CactusAdapter, CallbackResult, @@ -26,7 +24,15 @@ pub use adapter::{ documented_language_codes_batch, documented_language_codes_live, is_hyprnote_proxy, is_local_host, normalize_languages, }; -pub use adapter::{StreamingBatchEvent, StreamingBatchStream}; + +fn is_azure_openai(api_base: &str) -> bool { + url::Url::parse(api_base) + .ok() + .and_then(|u| u.host_str().map(OpenAIAdapter::is_azure_host)) + .unwrap_or(false) +} +#[cfg(feature = "argmax")] +pub use adapter::{StreamingBatchConfig, StreamingBatchEvent, StreamingBatchStream}; pub use batch::{BatchClient, BatchClientBuilder}; pub use error::Error; @@ -128,6 +134,10 @@ impl ListenClientBuilder { for (name, value) in &self.extra_headers { request = request.with_header(name, value); } + } else if is_azure_openai(original_api_base) { + if let Some(api_key) = self.api_key.as_deref() { + request = request.with_header("api-key", api_key); + } } else if let Some((header_name, header_value)) = adapter.build_auth_header(self.api_key.as_deref()) { diff --git a/crates/owhisper-client/src/providers.rs b/crates/owhisper-client/src/providers.rs index 37e86d3344..7dba0cf343 100644 --- a/crates/owhisper-client/src/providers.rs +++ b/crates/owhisper-client/src/providers.rs @@ -236,7 +236,14 @@ impl Provider { pub fn is_host(&self, host: &str) -> bool { let domain = self.domain(); - host == domain || host.ends_with(&format!(".{}", domain)) + let matches_domain = host == domain || host.ends_with(&format!(".{}", domain)); + + // Also match Azure OpenAI (*.openai.azure.com) as OpenAI provider + if *self == Self::OpenAI && host.ends_with(".openai.azure.com") { + return true; + } + + matches_domain } pub fn matches_url(&self, base_url: &str) -> bool { @@ -385,7 +392,7 @@ impl Provider { Self::AssemblyAI => from_adapter(&crate::adapter::AssemblyAIAdapter, msg), Self::Soniox => from_adapter(&crate::adapter::SonioxAdapter, msg), Self::Fireworks => from_adapter(&crate::adapter::FireworksAdapter, msg), - Self::OpenAI => from_adapter(&crate::adapter::OpenAIAdapter, msg), + Self::OpenAI => from_adapter(&crate::adapter::OpenAIAdapter::default(), msg), Self::Gladia => from_adapter(&crate::adapter::GladiaAdapter, msg), Self::ElevenLabs => from_adapter(&crate::adapter::ElevenLabsAdapter, msg), Self::DashScope => from_adapter(&crate::adapter::DashScopeAdapter, msg), diff --git a/crates/transcribe-proxy/src/routes/streaming/hyprnote.rs b/crates/transcribe-proxy/src/routes/streaming/hyprnote.rs index 90cfe1944a..009adb52d2 100644 --- a/crates/transcribe-proxy/src/routes/streaming/hyprnote.rs +++ b/crates/transcribe-proxy/src/routes/streaming/hyprnote.rs @@ -39,7 +39,7 @@ fn build_upstream_url_with_adapter( Provider::AssemblyAI => AssemblyAIAdapter.build_ws_url(api_base, params, channels), Provider::Soniox => SonioxAdapter.build_ws_url(api_base, params, channels), Provider::Fireworks => FireworksAdapter.build_ws_url(api_base, params, channels), - Provider::OpenAI => OpenAIAdapter.build_ws_url(api_base, params, channels), + Provider::OpenAI => OpenAIAdapter::default().build_ws_url(api_base, params, channels), Provider::Gladia => GladiaAdapter.build_ws_url(api_base, params, channels), Provider::ElevenLabs => ElevenLabsAdapter.build_ws_url(api_base, params, channels), Provider::DashScope => DashScopeAdapter.build_ws_url(api_base, params, channels), @@ -58,7 +58,7 @@ fn build_initial_message_with_adapter( Provider::AssemblyAI => AssemblyAIAdapter.initial_message(api_key, params, channels), Provider::Soniox => SonioxAdapter.initial_message(api_key, params, channels), Provider::Fireworks => FireworksAdapter.initial_message(api_key, params, channels), - Provider::OpenAI => OpenAIAdapter.initial_message(api_key, params, channels), + Provider::OpenAI => OpenAIAdapter::default().initial_message(api_key, params, channels), Provider::Gladia => GladiaAdapter.initial_message(api_key, params, channels), Provider::ElevenLabs => ElevenLabsAdapter.initial_message(api_key, params, channels), Provider::DashScope => DashScopeAdapter.initial_message(api_key, params, channels), @@ -81,7 +81,7 @@ fn build_response_transformer( Provider::AssemblyAI => AssemblyAIAdapter.parse_response(raw), Provider::Soniox => SonioxAdapter.parse_response(raw), Provider::Fireworks => FireworksAdapter.parse_response(raw), - Provider::OpenAI => OpenAIAdapter.parse_response(raw), + Provider::OpenAI => OpenAIAdapter::default().parse_response(raw), Provider::Gladia => GladiaAdapter.parse_response(raw), Provider::ElevenLabs => ElevenLabsAdapter.parse_response(raw), Provider::DashScope => DashScopeAdapter.parse_response(raw), diff --git a/plugins/analytics/src/lib.rs b/plugins/analytics/src/lib.rs index b06c6dbb3f..3e4c404264 100644 --- a/plugins/analytics/src/lib.rs +++ b/plugins/analytics/src/lib.rs @@ -34,19 +34,8 @@ pub fn init() -> tauri::plugin::TauriPlugin { tauri::plugin::Builder::new(PLUGIN_NAME) .invoke_handler(specta_builder.invoke_handler()) .setup(|app, _api| { - let posthog_key = { - #[cfg(not(debug_assertions))] - { - let v = env!("POSTHOG_API_KEY"); - assert!(v.starts_with("phc_")); - Some(v) - } - - #[cfg(debug_assertions)] - { - option_env!("POSTHOG_API_KEY") - } - }; + // Make PostHog optional for personal builds + let posthog_key: Option<&str> = option_env!("POSTHOG_API_KEY"); let outlit_key = option_env!("OUTLIT_PUBLIC_KEY"); diff --git a/plugins/calendar/src/lib.rs b/plugins/calendar/src/lib.rs index 3f7817c819..679c5d93ca 100644 --- a/plugins/calendar/src/lib.rs +++ b/plugins/calendar/src/lib.rs @@ -55,17 +55,7 @@ pub fn init() -> tauri::plugin::TauriPlugin { } fn get_api_base_url() -> String { - #[cfg(not(debug_assertions))] - { - env!("VITE_API_URL").to_string() - } - - #[cfg(debug_assertions)] - { - option_env!("VITE_API_URL") - .unwrap_or("http://localhost:3001") - .to_string() - } + std::env::var("VITE_API_URL").unwrap_or_else(|_| "http://localhost:3001".to_string()) } #[cfg(test)] diff --git a/plugins/fs2/src/error.rs b/plugins/fs2/src/error.rs index 546936d975..5e1995422e 100644 --- a/plugins/fs2/src/error.rs +++ b/plugins/fs2/src/error.rs @@ -1,4 +1,4 @@ -use serde::{Serialize, ser::Serializer}; +use serde::{ser::Serializer, Serialize}; pub type Result = std::result::Result;