Files
hobbs-iac/compose/hf-pdocker-02/lifeos/local-api-realtime-shim.ts
T
jeremy f48c7a40cd fix: make LifeOS actually render in local mode
The container served a blank page. Four upstream assumptions broke a
root-served, Supabase-less deployment; all are patched at build time with
grep assertions so a silent upstream rename fails the build instead of
shipping a blank page again.

- React Router was pinned to basename '/app' (upstream is hosted under an
  /app path). At '/' it matched no route and rendered nothing -- silently,
  with only a console warning. This was the blank page.
- supabase.ts calls createClient() at module scope, which throws
  'supabaseUrl is required' on an empty string and killed the bundle before
  React mounted. Dummy values fix it; nothing reads Supabase in local mode.
- initAuth() only booted the local user for Tauri/Electron, so a browser
  build fell through to a Supabase login screen the backend cannot serve
  (it has no /api/auth/login or /api/auth/signup -- it is single-user).
- The local API adapter has no realtime layer, so supabase.channel() was
  undefined and every subscribing component tripped the ErrorBoundary
  ('Something went wrong'). Added no-op stubs; realtime is meaningless on a
  single-user instance.

Verified in a browser: dashboard and routed pages render, 0 fatal errors.

Known gap: the Flask backend implements only a subset of the cloud schema,
so quests, messages, partnerships, grocery_lists, recurring_transactions,
junction_traditions and habit_suggestions 404. Non-fatal; those features
degrade. Core (tasks/habits/goals/health/finance/journal/XP/AI chat) works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:32:14 -05:00

31 lines
1.4 KiB
TypeScript

// ─── Realtime no-op shim (appended to local-api.ts at image build) ───
//
// The local Flask API has no websocket/realtime layer -- upstream's LOCAL_MODE.md
// says so outright ("Realtime subscriptions -- NOT migrated"), but the adapter it
// ships still lacks `.channel()`, so every component that opens a subscription
// (useSubscription, useCurrentEvent, social, realm multiplayer) throws
// "TypeError: supabase.channel is not a function" and trips the ErrorBoundary --
// the whole app renders "Something went wrong".
//
// These stubs satisfy the call shape and do nothing. Reads still work: the app
// fetches through the normal query path. What is lost is live push updates, which
// are meaningless on a single-user instance with no other clients to sync from.
Object.assign(supabase as any, {
channel: (_name?: string, _opts?: any) => {
const ch: any = {
on: () => ch, // chainable, never fires
subscribe: (cb?: (status: string) => void) => { cb?.('SUBSCRIBED'); return ch; },
unsubscribe: async () => 'ok',
presenceState: () => ({}), // realm multiplayer: nobody else here
track: async () => 'ok',
untrack: async () => 'ok',
send: async () => 'ok',
};
return ch;
},
removeChannel: async () => 'ok',
removeAllChannels: async () => 'ok',
getChannels: () => [],
});