Gotchas when converting SvelteKit server loads to universal loads for Capacitor: locals unavailable, server imports fail, timezone APIs survive, type gaps hide in loader but surface in components.
When converting SvelteKit routes from +page.server.ts to universal +page.ts for Capacitor compatibility, watch for server-only APIs that silently work differently in universal context:
locals is unavailable — event.locals.user doesn't exist in universal loads. Move user context to a client-side store (get_ctx()) and consume it in the component instead of the loader return value.
logger from server modules — $lib/server/* imports fail in universal loads. Replace with console.error.
Timezone-dependent computations survive — new Date().toLocaleDateString('en-CA', { timeZone: 'America/New_York' }) works identically in browser JS, so server-computed timezone values can move to universal loads without change.
Type safety gap — TypeScript won't catch the locals removal at the loader level because PageLoad simply doesn't have locals in its type. But downstream components referencing data.self_username (removed from return) will fail at svelte-check time. Always run svelte-check after conversion, not just tsc.
Pair with webPathToMobile — Even after converting to universal loads, mobile routes may still benefit from redirection to a dedicated mobile page (e.g., /pulse → /m/explore where pulse is embedded with bottom tabs). The universal load conversion makes the web route work in-app; the redirect makes it good in-app.