* stage 1: project init * stage 2: skeleton with navigation * step 2.5: streams list * step 4: stream playback experience * step 5-6: compose experience * fix: broken record * transcode media particles to mp4 * build: reproducible go generate * build: rename skaffold module for particle processor worker * infra: increase particle processor worker resources Was dealing with OOM errors * tweaks to mobile * log transcode work * view on desktop placeholder * tweak padding * cap video resolution to save on memory * infra: bump memory limits as insurance * ux improvements * update bundle id for mobile * config for mobile
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import * as SecureStore from "expo-secure-store";
|
|
import { create } from "zustand";
|
|
|
|
const AUTH_TOKEN_KEY = "auth_token";
|
|
|
|
interface SessionState {
|
|
token: string | null;
|
|
/**
|
|
* False until SecureStore returns the persisted token (or confirms absence).
|
|
* The API client should treat requests as unauthenticated until this flips —
|
|
* see `useSessionStore.subscribe` in App.tsx for the bootstrap.
|
|
*/
|
|
hydrated: boolean;
|
|
setToken: (token: string) => Promise<void>;
|
|
clearToken: () => Promise<void>;
|
|
}
|
|
|
|
export const useSessionStore = create<SessionState>((set) => ({
|
|
token: null,
|
|
hydrated: false,
|
|
|
|
setToken: async (token: string) => {
|
|
await SecureStore.setItemAsync(AUTH_TOKEN_KEY, token);
|
|
set({ token });
|
|
},
|
|
|
|
clearToken: async () => {
|
|
await SecureStore.deleteItemAsync(AUTH_TOKEN_KEY);
|
|
set({ token: null });
|
|
},
|
|
}));
|
|
|
|
/**
|
|
* Bootstrap the session by reading SecureStore once. Call from App.tsx before
|
|
* mounting the navigator. Resolves after the store reflects whatever was in
|
|
* persistent storage.
|
|
*/
|
|
export async function hydrateSession(): Promise<void> {
|
|
try {
|
|
const token = await SecureStore.getItemAsync(AUTH_TOKEN_KEY);
|
|
useSessionStore.setState({ token: token ?? null, hydrated: true });
|
|
} catch {
|
|
// SecureStore failures are non-fatal — proceed unauthenticated.
|
|
useSessionStore.setState({ token: null, hydrated: true });
|
|
}
|
|
}
|