← Public packages
@kody/mailroom
Offline-first PWA for your Kody mailbox: sent and received threads, copy-prompt for agents, no send.
src/ui/app-url.ts
39 lines · 1.4 KB · TypeScriptexport function resolveAppUrl(base: string, path: string, origin: string): string {
const root = new URL(base || '/', origin)
if (!root.pathname.endsWith('/')) root.pathname += '/'
return new URL(String(path).replace(/^\//, ''), root).toString()
}
export function scopedAssetPath(scope: string, path: string): string {
const root = scope.endsWith('/') ? scope : `${scope}/`
return `${root}${String(path).replace(/^\//, '')}`
}
export function serviceWorkerScope(base: string, origin: string): string {
const root = new URL(base || '/', origin)
if (!root.pathname.endsWith('/')) root.pathname += '/'
return root.href
}
export function shouldCanonicalizeClientPath(pathname: string): boolean {
return Boolean(pathname) && !pathname.endsWith('/')
}
export function serviceWorkerAllowedPath(base: string): string {
const path = base.startsWith('/') ? base : `/${base}`
return path.endsWith('/') && path !== '/' ? path.slice(0, -1) : path
}
export function needsCanonicalAppRedirect(
pathname: string,
appBasePath: string,
): boolean {
return pathname === appBasePath
}
/** Parse a query int. Missing/blank must not become 0 — `Number(null)` is 0. */
export function numberParam(value: string | null, fallback: number): number {
if (value == null || value.trim() === '') return fallback
const parsed = Number(value)
return Number.isFinite(parsed) ? parsed : fallback
}