Download src/lib/offlineQueue.ts from Esketch/CarboAny: direct link, hf CLI and curl.
- Browser
- Download file 4.59 kB
-
https://huggingface.co/spaces/Esketch/CarboAny/resolve/main/src/lib/offlineQueue.ts
- Command line
-
hf download hf://spaces/Esketch/CarboAny/src/lib/offlineQueue.ts
-
curl -L -o offlineQueue.ts https://huggingface.co/spaces/Esketch/CarboAny/resolve/main/src/lib/offlineQueue.ts
4.59 kB
| /** | |
| * offlineQueue.ts β WS-2 Field Expansion | |
| * μ€νλΌμΈ μ€ μ μΆ μμ²μ IndexedDBμ νμνκ³ , | |
| * μ¨λΌμΈ λ³΅κ· μ Background Sync(λλ ν΄λ§) λ‘ μ¬μ μ‘. | |
| */ | |
| export interface QueueItem { | |
| id?: number; | |
| url: string; | |
| method: string; | |
| headers: Record<string, string>; | |
| body: string; | |
| enqueuedAt: number; | |
| /** μλ³Έ λ―Έμ ID β UI νμμ© */ | |
| missionId: string | null; | |
| /** μ¬μ©μ ID */ | |
| userId: string; | |
| } | |
| interface SyncRegistration extends ServiceWorkerRegistration { | |
| sync: { | |
| register: (tag: string) => Promise<void>; | |
| }; | |
| } | |
| // ββ DB μ΄κΈ°ν βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const DB_NAME = 'carboany-queue'; | |
| const DB_VERSION = 1; | |
| const STORE = 'queue'; | |
| let _db: IDBDatabase | null = null; | |
| function openDb(): Promise<IDBDatabase> { | |
| if (_db) return Promise.resolve(_db); | |
| return new Promise((resolve, reject) => { | |
| const req = indexedDB.open(DB_NAME, DB_VERSION); | |
| req.onupgradeneeded = (e) => { | |
| const db = (e.target as IDBOpenDBRequest).result; | |
| if (!db.objectStoreNames.contains(STORE)) { | |
| db.createObjectStore(STORE, { keyPath: 'id', autoIncrement: true }); | |
| } | |
| }; | |
| req.onsuccess = (e) => { | |
| _db = (e.target as IDBOpenDBRequest).result; | |
| resolve(_db!); | |
| }; | |
| req.onerror = () => reject(req.error); | |
| }); | |
| } | |
| // ββ Enqueue βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export async function enqueueSubmission(item: Omit<QueueItem, 'id' | 'enqueuedAt'>): Promise<void> { | |
| const db = await openDb(); | |
| const entry: Omit<QueueItem, 'id'> = { ...item, enqueuedAt: Date.now() }; | |
| await new Promise<void>((res, rej) => { | |
| const tx = db.transaction(STORE, 'readwrite'); | |
| const req = tx.objectStore(STORE).add(entry); | |
| req.onsuccess = () => res(); | |
| req.onerror = () => rej(req.error); | |
| }); | |
| // Background Sync λ±λ‘ (μ§μνλ λΈλΌμ°μ ) | |
| if ('serviceWorker' in navigator && 'SyncManager' in window) { | |
| const reg = await navigator.serviceWorker.ready; | |
| await (reg as SyncRegistration).sync.register('carboany-offline-queue').catch(() => {}); | |
| } | |
| } | |
| // ββ Flush (μ¨λΌμΈ λ³΅κ· μ νΈμΆ) βββββββββββββββββββββββββββββββββββββββββββββββ | |
| export async function flushQueue( | |
| onSuccess?: (item: QueueItem) => void, | |
| onError?: (item: QueueItem, err: unknown) => void | |
| ): Promise<void> { | |
| const db = await openDb(); | |
| const items = await getAllItems(db); | |
| if (items.length === 0) return; | |
| for (const item of items) { | |
| try { | |
| const res = await fetch(item.url, { | |
| method: item.method, | |
| headers: item.headers, | |
| body: item.body, | |
| }); | |
| if (res.ok) { | |
| await deleteItem(db, item.id!); | |
| onSuccess?.(item); | |
| } else { | |
| onError?.(item, new Error(`HTTP ${res.status}`)); | |
| } | |
| } catch (err) { | |
| onError?.(item, err); | |
| } | |
| } | |
| } | |
| // ββ ν ν¬κΈ° μ‘°ν ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export async function getQueueSize(): Promise<number> { | |
| const db = await openDb(); | |
| return new Promise((res, rej) => { | |
| const tx = db.transaction(STORE, 'readonly'); | |
| const req = tx.objectStore(STORE).count(); | |
| req.onsuccess = () => res(req.result); | |
| req.onerror = () => rej(req.error); | |
| }); | |
| } | |
| // ββ λ΄λΆ μ νΈ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function getAllItems(db: IDBDatabase): Promise<QueueItem[]> { | |
| return new Promise((res, rej) => { | |
| const tx = db.transaction(STORE, 'readonly'); | |
| const req = tx.objectStore(STORE).getAll(); | |
| req.onsuccess = () => res(req.result as QueueItem[]); | |
| req.onerror = () => rej(req.error); | |
| }); | |
| } | |
| function deleteItem(db: IDBDatabase, id: number): Promise<void> { | |
| return new Promise((res, rej) => { | |
| const tx = db.transaction(STORE, 'readwrite'); | |
| const req = tx.objectStore(STORE).delete(id); | |
| req.onsuccess = () => res(); | |
| req.onerror = () => rej(req.error); | |
| }); | |
| } | |