mobile download

This commit is contained in:
Macbook
2026-05-28 14:44:19 +09:00
parent e2816b037f
commit 3503ef33f5
152 changed files with 11021 additions and 687 deletions
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
import { storageGetSync, storageRemove, storageSetSync } from './storage/index.js';
export type UserRole = 'ADMIN' | 'USER';
export interface AuthSession {
userId: number;
username: string;
displayName: string;
role: UserRole;
}
const USER_ID_KEY = 'gc_user_id';
const USERNAME_KEY = 'gc_username';
const DISPLAY_NAME_KEY = 'gc_display_name';
const ROLE_KEY = 'gc_user_role';
function normalizeRole(role: string): UserRole {
return role === 'ADMIN' ? 'ADMIN' : 'USER';
}
export function getAuthSession(): AuthSession | null {
const id = storageGetSync(USER_ID_KEY);
if (!id) return null;
const userId = Number(id);
if (!Number.isFinite(userId) || userId <= 0) return null;
const username = storageGetSync(USERNAME_KEY) ?? '';
const displayName = storageGetSync(DISPLAY_NAME_KEY) ?? username;
const storedRole = storageGetSync(ROLE_KEY);
const role = normalizeRole(storedRole ?? 'USER');
return { userId, username, displayName, role };
}
export function setAuthSession(session: AuthSession): void {
storageSetSync(USER_ID_KEY, String(session.userId));
storageSetSync(USERNAME_KEY, session.username);
storageSetSync(DISPLAY_NAME_KEY, session.displayName);
storageSetSync(ROLE_KEY, session.role);
}
export async function clearAuthSession(): Promise<void> {
await storageRemove(USER_ID_KEY);
await storageRemove(USERNAME_KEY);
await storageRemove(DISPLAY_NAME_KEY);
await storageRemove(ROLE_KEY);
}
export function isLoggedIn(): boolean {
return getAuthSession() !== null;
}
+10
View File
@@ -0,0 +1,10 @@
export * from './api/backendApi';
export {
initStorage,
storageGet,
storageSet,
storageGetSync,
storageSetSync,
storageRemove,
} from './storage/index';
export * from './auth';
+75
View File
@@ -0,0 +1,75 @@
/**
* Storage adapter — Capacitor Preferences (native) with localStorage fallback (browser dev).
*/
import { Preferences } from '@capacitor/preferences';
const memoryCache = new Map<string, string>();
let prefsReady = false;
async function ensurePrefs(): Promise<boolean> {
if (prefsReady) return true;
try {
await Preferences.get({ key: '__probe__' });
prefsReady = true;
return true;
} catch {
return false;
}
}
export async function storageGet(key: string): Promise<string | null> {
if (memoryCache.has(key)) return memoryCache.get(key) ?? null;
if (await ensurePrefs()) {
const { value } = await Preferences.get({ key });
if (value != null) {
memoryCache.set(key, value);
return value;
}
}
if (typeof localStorage !== 'undefined') {
return localStorage.getItem(key);
}
return null;
}
export async function storageSet(key: string, value: string): Promise<void> {
memoryCache.set(key, value);
if (await ensurePrefs()) {
await Preferences.set({ key, value });
}
if (typeof localStorage !== 'undefined') {
localStorage.setItem(key, value);
}
}
export async function storageRemove(key: string): Promise<void> {
memoryCache.delete(key);
if (await ensurePrefs()) {
await Preferences.remove({ key });
}
if (typeof localStorage !== 'undefined') {
localStorage.removeItem(key);
}
}
/** Sync read for hot paths (uses memory cache populated at init). */
export function storageGetSync(key: string): string | null {
if (memoryCache.has(key)) return memoryCache.get(key) ?? null;
if (typeof localStorage !== 'undefined') return localStorage.getItem(key);
return null;
}
export function storageSetSync(key: string, value: string): void {
memoryCache.set(key, value);
if (typeof localStorage !== 'undefined') localStorage.setItem(key, value);
void storageSet(key, value);
}
export async function initStorage(): Promise<void> {
const keys = ['gc_device_id', 'gc_user_id', 'gc_username', 'gc_display_name', 'gc_user_role', 'gc_api_base_url'];
if (!(await ensurePrefs())) return;
for (const key of keys) {
const { value } = await Preferences.get({ key });
if (value != null) memoryCache.set(key, value);
}
}
+9
View File
@@ -0,0 +1,9 @@
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_BASE_URL?: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}