refactor(web): DRY platform-sync.ts — remove 88 lines of hand-rolled auth, delegate to auth-client

This commit is contained in:
saravanakumardb1 2026-02-28 11:49:06 -08:00
parent 8a5a40676a
commit f80602d2b1

View File

@ -54,11 +54,9 @@ export interface OfflineQueueItem {
enqueuedAt: number;
}
// ── API Client ────────────────────────────────────────────────
// ── API Client (delegated to @bytelyst/auth-client) ──────────
const STORAGE_KEYS = {
authToken: 'chronomind-auth-token',
refreshToken: 'chronomind-refresh-token',
lastSync: 'chronomind-platform-last-sync',
offlineQueue: 'chronomind-offline-queue',
syncEnabled: 'chronomind-platform-sync-enabled',
@ -66,77 +64,9 @@ const STORAGE_KEYS = {
export const PRODUCT_ID = _PRODUCT_ID;
function getBaseUrl(): string {
if (typeof window !== 'undefined' && (window as unknown as Record<string, unknown>).__PLATFORM_URL__) {
return (window as unknown as Record<string, unknown>).__PLATFORM_URL__ as string;
}
return process.env.NEXT_PUBLIC_PLATFORM_SERVICE_URL ?? 'https://api.chronomind.app';
}
function getAuthToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem(STORAGE_KEYS.authToken);
}
function getRefreshToken(): string | null {
if (typeof window === 'undefined') return null;
return localStorage.getItem(STORAGE_KEYS.refreshToken);
}
export function setRefreshToken(token: string | null): void {
if (typeof window === 'undefined') return;
if (token) {
localStorage.setItem(STORAGE_KEYS.refreshToken, token);
} else {
localStorage.removeItem(STORAGE_KEYS.refreshToken);
}
}
let _refreshPromise: Promise<boolean> | null = null;
/**
* Attempt to refresh the access token using the stored refresh token.
* Returns true if refresh succeeded, false otherwise.
* Deduplicates concurrent refresh attempts.
*/
export async function refreshAccessToken(): Promise<boolean> {
if (_refreshPromise) return _refreshPromise;
_refreshPromise = (async () => {
const rt = getRefreshToken();
if (!rt) return false;
try {
const res = await fetch(`${getBaseUrl()}/auth/refresh`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-product-id': PRODUCT_ID,
'x-request-id': crypto.randomUUID(),
},
body: JSON.stringify({ refreshToken: rt }),
});
if (!res.ok) {
// Refresh token is invalid/expired — clear both tokens
setAuthToken(null);
setRefreshToken(null);
return false;
}
const data = await res.json() as { accessToken: string; refreshToken: string };
setAuthToken(data.accessToken);
setRefreshToken(data.refreshToken);
return true;
} catch {
return false;
}
})();
try {
return await _refreshPromise;
} finally {
_refreshPromise = null;
export class SyncConflictError extends Error {
constructor(public serverData: unknown) {
super('Sync conflict — server has newer version');
}
}
@ -145,7 +75,9 @@ async function apiRequest<T>(
method: string,
body?: unknown
): Promise<T> {
const token = getAuthToken();
const client = getAuthClient();
const token = client.getAccessToken();
const baseUrl = process.env.NEXT_PUBLIC_PLATFORM_SERVICE_URL ?? 'https://api.chronomind.app';
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'x-request-id': crypto.randomUUID(),
@ -153,7 +85,7 @@ async function apiRequest<T>(
};
if (token) headers['Authorization'] = `Bearer ${token}`;
const res = await fetch(`${getBaseUrl()}${path}`, {
const res = await fetch(`${baseUrl}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
@ -166,7 +98,7 @@ async function apiRequest<T>(
// On 401, attempt a silent token refresh and retry once
if (res.status === 401 && !path.startsWith('/auth/')) {
const refreshed = await refreshAccessToken();
const refreshed = await client.refreshAccessToken();
if (refreshed) {
return apiRequest<T>(path, method, body);
}
@ -180,26 +112,19 @@ async function apiRequest<T>(
return res.json();
}
export class SyncConflictError extends Error {
constructor(public serverData: unknown) {
super('Sync conflict — server has newer version');
}
}
// ── Public API ────────────────────────────────────────────────
export function setAuthToken(token: string | null): void {
if (typeof window === 'undefined') return;
const client = getAuthClient();
if (token) {
localStorage.setItem(STORAGE_KEYS.authToken, token);
client.setTokens(token, client.getRefreshToken() ?? '');
} else {
localStorage.removeItem(STORAGE_KEYS.authToken);
localStorage.removeItem(STORAGE_KEYS.refreshToken);
client.clearTokens();
}
}
export function isAuthenticated(): boolean {
return getAuthToken() !== null;
return getAuthClient().isAuthenticated();
}
export function isSyncEnabled(): boolean {