ultisuite-client/lib/platform.ts
R3D347HR4Y d6d18f911b
Some checks failed
E2E / Playwright e2e (push) Has been cancelled
Lots of stuff and mobile app
2026-06-17 00:13:28 +02:00

85 lines
2.9 KiB
TypeScript

/**
* Platform detection shared by web and the Tauri mobile/native builds.
*
* - `IS_MOBILE_BUILD` is a *build-time* flag (set by `NEXT_PUBLIC_MOBILE=1`)
* used to gate the static export, drop server API routes, and switch auth to
* the native flow. It is statically analyzable so dead code is tree-shaken.
* - `isTauriRuntime()` is a *runtime* check (the same static bundle can be
* loaded by a browser during development, e.g. `pnpm dev`, even when built in
* mobile mode).
*/
/** True when the bundle was built for the Tauri native shells. */
export const IS_MOBILE_BUILD = process.env.NEXT_PUBLIC_MOBILE === "1"
/**
* The per-app product this build targets (UltiMail, UltiDrive, …). Drives the
* default start route, the deep-link scheme, and which sibling apps the suite
* launcher tries to open. Defaults to `mail` (the pilot).
*/
export type SuiteApp = "mail" | "drive" | "agenda" | "meet" | "chat" | "contacts"
export const SUITE_APP: SuiteApp =
(process.env.NEXT_PUBLIC_SUITE_APP as SuiteApp | undefined) ?? "mail"
/** Custom URL scheme for this app's deep links, e.g. `ultimail://`. */
export function appScheme(app: SuiteApp = SUITE_APP): string {
return `ulti${app}`
}
/** Default start route for an app shell. */
export function appStartRoute(app: SuiteApp = SUITE_APP): string {
switch (app) {
case "mail":
return "/mail"
case "drive":
return "/drive"
case "agenda":
return "/agenda"
case "meet":
return "/meet"
case "chat":
return "/chat"
case "contacts":
return "/contacts"
default:
return "/mail"
}
}
/**
* Map an in-app route to the suite app that "owns" it, so the launcher can open
* the sibling native app instead of navigating in-webview. Returns null for
* routes that should stay in the current app (settings, account, admin, …).
*/
export function suiteAppForRoute(route: string): SuiteApp | null {
const path = route.split("?")[0]
if (path.startsWith("/mail")) return "mail"
if (path.startsWith("/drive")) return "drive"
if (path.startsWith("/agenda")) return "agenda"
if (path.startsWith("/meet")) return "agenda" // UltiCal+UltiMeet share one app
if (path.startsWith("/chat")) return "chat"
if (path.startsWith("/contacts")) return "contacts"
return null
}
/** True only when actually executing inside a Tauri webview. */
export function isTauriRuntime(): boolean {
if (typeof window === "undefined") return false
return (
"__TAURI_INTERNALS__" in window ||
"__TAURI__" in window ||
// Tauri v2 exposes this in some configurations.
(window as { isTauri?: boolean }).isTauri === true
)
}
/**
* True when we should use the native auth + runtime-config code paths.
* Mobile builds always use native paths; a mobile build opened in a plain
* browser (dev) also uses them so the flow can be exercised without a device.
*/
export function useNativeRuntime(): boolean {
return IS_MOBILE_BUILD || isTauriRuntime()
}