infra: add linting and formatting for js projects (#230)
* wip * wip * wip * format * wip(mobile): lint and format * cleanup * nits * nits * idiomatic react * nit * format all root files
This commit was merged in pull request #230.
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import { create } from "zustand";
|
||||
import { signInWithCustomToken, signOut as firebaseSignOut } from "firebase/auth";
|
||||
import { apiClient } from "@/api/client";
|
||||
import type { Human } from "@/api/types";
|
||||
import { firebaseAuth } from "@/firebase";
|
||||
import { logError, ApiError } from "@/lib/errors";
|
||||
import { useSessionStore } from "./session-store";
|
||||
import { create } from 'zustand';
|
||||
import {
|
||||
signInWithCustomToken,
|
||||
signOut as firebaseSignOut,
|
||||
} from 'firebase/auth';
|
||||
import { apiClient } from '@/api/client';
|
||||
import type { Human } from '@/api/types';
|
||||
import { firebaseAuth } from '@/firebase';
|
||||
import { logError, ApiError } from '@/lib/errors';
|
||||
import { useSessionStore } from './session-store';
|
||||
|
||||
async function signInToFirebase() {
|
||||
try {
|
||||
@@ -13,11 +16,11 @@ async function signInToFirebase() {
|
||||
} catch (err) {
|
||||
// Firestore subscriptions will fail until the next successful sign-in; the
|
||||
// rest of the app keeps working against Orion.
|
||||
logError(err, { scope: "auth.firebase" });
|
||||
logError(err, { scope: 'auth.firebase' });
|
||||
}
|
||||
}
|
||||
|
||||
type AuthStatus = "idle" | "restoring" | "unauthenticated" | "authenticated";
|
||||
type AuthStatus = 'idle' | 'restoring' | 'unauthenticated' | 'authenticated';
|
||||
|
||||
interface AuthState {
|
||||
status: AuthStatus;
|
||||
@@ -34,7 +37,7 @@ interface AuthState {
|
||||
}
|
||||
|
||||
export const useAuthStore = create<AuthState>((set) => ({
|
||||
status: "idle",
|
||||
status: 'idle',
|
||||
user: null,
|
||||
isRequestingCode: false,
|
||||
isSigningIn: false,
|
||||
@@ -44,20 +47,20 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
restoreSession: async () => {
|
||||
const token = useSessionStore.getState().token;
|
||||
if (!token) {
|
||||
set({ status: "unauthenticated" });
|
||||
set({ status: 'unauthenticated' });
|
||||
return;
|
||||
}
|
||||
|
||||
set({ status: "restoring" });
|
||||
set({ status: 'restoring' });
|
||||
try {
|
||||
const user = await apiClient.me();
|
||||
await signInToFirebase();
|
||||
set({ status: "authenticated", user });
|
||||
set({ status: 'authenticated', user });
|
||||
} catch (err) {
|
||||
// Expected on expired/invalid tokens — fall back to the login screen.
|
||||
logError(err, { scope: "auth.restore" });
|
||||
logError(err, { scope: 'auth.restore' });
|
||||
useSessionStore.getState().clearToken();
|
||||
set({ status: "unauthenticated", user: null });
|
||||
set({ status: 'unauthenticated', user: null });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -66,8 +69,7 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
try {
|
||||
await apiClient.requestCode({ email });
|
||||
} catch (e) {
|
||||
const message =
|
||||
e instanceof ApiError ? e.message : "Failed to send code";
|
||||
const message = e instanceof ApiError ? e.message : 'Failed to send code';
|
||||
set({ error: message });
|
||||
throw e;
|
||||
} finally {
|
||||
@@ -81,10 +83,9 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
const { human, token } = await apiClient.signIn({ email, code });
|
||||
useSessionStore.getState().setToken(token);
|
||||
await signInToFirebase();
|
||||
set({ status: "authenticated", user: human });
|
||||
set({ status: 'authenticated', user: human });
|
||||
} catch (e) {
|
||||
const message =
|
||||
e instanceof ApiError ? e.message : "Failed to sign in";
|
||||
const message = e instanceof ApiError ? e.message : 'Failed to sign in';
|
||||
set({ error: message });
|
||||
throw e;
|
||||
} finally {
|
||||
@@ -98,14 +99,14 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
await apiClient.signOut();
|
||||
} catch (err) {
|
||||
// Best-effort — sign out locally regardless.
|
||||
logError(err, { scope: "auth.signOut" });
|
||||
logError(err, { scope: 'auth.signOut' });
|
||||
} finally {
|
||||
await firebaseSignOut(firebaseAuth).catch((err) =>
|
||||
logError(err, { scope: "auth.firebaseSignOut" }),
|
||||
logError(err, { scope: 'auth.firebaseSignOut' }),
|
||||
);
|
||||
useSessionStore.getState().clearToken();
|
||||
set({
|
||||
status: "unauthenticated",
|
||||
status: 'unauthenticated',
|
||||
user: null,
|
||||
isSigningOut: false,
|
||||
error: null,
|
||||
@@ -120,9 +121,9 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
useSessionStore.subscribe((state, prevState) => {
|
||||
if (prevState.token && !state.token) {
|
||||
const authState = useAuthStore.getState();
|
||||
if (authState.status === "authenticated") {
|
||||
if (authState.status === 'authenticated') {
|
||||
useAuthStore.setState({
|
||||
status: "unauthenticated",
|
||||
status: 'unauthenticated',
|
||||
user: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import type { AutoplayPayload } from "@/lib/autoplay-ipc";
|
||||
import { create } from 'zustand';
|
||||
import type { AutoplayPayload } from '@/lib/autoplay-ipc';
|
||||
|
||||
interface AutoplayPayloadState {
|
||||
payload: AutoplayPayload | null;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
const STORAGE_KEY = "llink:autoplay-muted";
|
||||
const STORAGE_KEY = 'llink:autoplay-muted';
|
||||
|
||||
function loadMuted(): boolean {
|
||||
try {
|
||||
return localStorage.getItem(STORAGE_KEY) === "true";
|
||||
return localStorage.getItem(STORAGE_KEY) === 'true';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
/**
|
||||
* Fire-and-forget intents that drive the compose flow from outside the active
|
||||
@@ -18,7 +18,7 @@ import { create } from "zustand";
|
||||
* ultimately invoke the same callbacks the intent dispatcher does, so the
|
||||
* guard logic stays in one place.
|
||||
*/
|
||||
export type ComposeIntent = "record" | "text" | "stop" | "cancel" | "send";
|
||||
export type ComposeIntent = 'record' | 'text' | 'stop' | 'cancel' | 'send';
|
||||
|
||||
interface ComposeIntentState {
|
||||
intent: { kind: ComposeIntent } | null;
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
export interface SavedDevice {
|
||||
deviceId: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const MIC_KEY = "llink:mic-device";
|
||||
const CAMERA_KEY = "llink:camera-device";
|
||||
const MIC_KEY = 'llink:mic-device';
|
||||
const CAMERA_KEY = 'llink:camera-device';
|
||||
|
||||
function load(key: string): SavedDevice | null {
|
||||
try {
|
||||
const raw = localStorage.getItem(key);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as SavedDevice;
|
||||
if (typeof parsed?.deviceId !== "string") return null;
|
||||
return { deviceId: parsed.deviceId, label: parsed.label ?? "" };
|
||||
if (typeof parsed?.deviceId !== 'string') return null;
|
||||
return { deviceId: parsed.deviceId, label: parsed.label ?? '' };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
export type RecordingMode = "video" | "audio";
|
||||
export type RecordingMode = 'video' | 'audio';
|
||||
|
||||
const KEY = "llink:recording-mode";
|
||||
const KEY = 'llink:recording-mode';
|
||||
|
||||
interface MediaSettingsState {
|
||||
recordingMode: RecordingMode;
|
||||
@@ -12,7 +12,7 @@ interface MediaSettingsState {
|
||||
export const useMediaSettingsStore = create<MediaSettingsState>((set) => ({
|
||||
recordingMode: (() => {
|
||||
const stored = localStorage.getItem(KEY);
|
||||
return stored === "audio" ? "audio" : "video";
|
||||
return stored === 'audio' ? 'audio' : 'video';
|
||||
})(),
|
||||
setRecordingMode: (mode) => {
|
||||
localStorage.setItem(KEY, mode);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
/**
|
||||
* Single source of truth for "is stream playback paused." Each component that
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import { create } from 'zustand';
|
||||
|
||||
const AUTH_TOKEN_KEY = "auth_token";
|
||||
const AUTH_TOKEN_KEY = 'auth_token';
|
||||
|
||||
interface SessionState {
|
||||
token: string | null;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { create } from "zustand";
|
||||
import { soundEffects } from "@/lib/sound-effects/engine";
|
||||
import { create } from 'zustand';
|
||||
import { soundEffects } from '@/lib/sound-effects/engine';
|
||||
|
||||
const ENABLED_KEY = "llink:soundEffects-enabled";
|
||||
const ENABLED_KEY = 'llink:soundEffects-enabled';
|
||||
const DEFAULT_ENABLED = true;
|
||||
|
||||
function loadEnabled(): boolean {
|
||||
try {
|
||||
const v = localStorage.getItem(ENABLED_KEY);
|
||||
return v === null ? DEFAULT_ENABLED : v === "true";
|
||||
return v === null ? DEFAULT_ENABLED : v === 'true';
|
||||
} catch {
|
||||
return DEFAULT_ENABLED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user