@akashjs/runtime 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-CO4D6JTQ.cjs +2 -0
- package/dist/chunk-CO4D6JTQ.cjs.map +1 -0
- package/dist/chunk-NC5RE4IQ.js +2 -0
- package/dist/chunk-NC5RE4IQ.js.map +1 -0
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/offline.cjs +1 -1
- package/dist/offline.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-5NJYYK3Q.js +0 -2
- package/dist/chunk-5NJYYK3Q.js.map +0 -1
- package/dist/chunk-JSBB2VV3.cjs +0 -2
- package/dist/chunk-JSBB2VV3.cjs.map +0 -1
package/dist/offline.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkCO4D6JTQ_cjs=require('./chunk-CO4D6JTQ.cjs');require('./chunk-RTJ6UDGV.cjs');Object.defineProperty(exports,"createOfflineStore",{enumerable:true,get:function(){return chunkCO4D6JTQ_cjs.a}});//# sourceMappingURL=offline.cjs.map
|
|
2
2
|
//# sourceMappingURL=offline.cjs.map
|
package/dist/offline.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{a as createOfflineStore}from'./chunk-
|
|
1
|
+
export{a as createOfflineStore}from'./chunk-NC5RE4IQ.js';import'./chunk-TWA4T6PX.js';//# sourceMappingURL=offline.js.map
|
|
2
2
|
//# sourceMappingURL=offline.js.map
|
package/package.json
CHANGED
package/dist/chunk-5NJYYK3Q.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import {l,m}from'./chunk-TWA4T6PX.js';async function j(a,t=1){return typeof indexedDB>"u"?Promise.reject(new Error("IndexedDB not available")):new Promise((c,r)=>{try{let n=indexedDB.open(a,t);n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains("items")||i.createObjectStore("items"),i.objectStoreNames.contains("pending")||i.createObjectStore("pending",{autoIncrement:!0});},n.onsuccess=()=>c(n.result),n.onerror=()=>r(n.error??new Error("IndexedDB open failed"));}catch(n){r(n);}})}async function x(a,t){return new Promise((c,r)=>{let i=a.transaction(t,"readonly").objectStore(t).getAll();i.onsuccess=()=>c(i.result),i.onerror=()=>r(i.error);})}async function D(a,t,c,r){return new Promise((n,i)=>{let l=a.transaction(t,"readwrite");l.objectStore(t).put(r,c),l.oncomplete=()=>n(),l.onerror=()=>i(l.error);})}async function B(a,t,c){return new Promise((r,n)=>{let i=a.transaction(t,"readwrite");i.objectStore(t).delete(c),i.oncomplete=()=>r(),i.onerror=()=>n(i.error);})}async function p(a,t){return new Promise((c,r)=>{let n=a.transaction(t,"readwrite");n.objectStore(t).clear(),n.oncomplete=()=>c(),n.onerror=()=>r(n.error);})}function A(a,t={}){let c=t.keyField??"id",r=l([]),n=l([]),i=l(false),l$1=l(typeof navigator<"u"?navigator.onLine:true),b=m(()=>n().length),o=null,m$1=null,T=false;typeof window<"u"&&(window.addEventListener("online",()=>{l$1.set(true),v();}),window.addEventListener("offline",()=>l$1.set(false)));async function O(){if(!(typeof indexedDB>"u"))try{o=await j(`akash-offline-${a}`,t.version??1);let e=await x(o,"items");r.set(e);let s=await x(o,"pending");n.set(s);}catch(e){console.error("[AkashJS] Offline store init failed:",e);}}let k=O();if(t.sync){let e=t.sync.interval??3e4;m$1=setInterval(()=>{l$1()&&b()>0&&!i()&&v();},e);}function g(e){return String(e[c])}function w(e){let s=g(e);r.update(d=>{let f=d.findIndex(u=>g(u)===s);if(f!==-1){let u=[...d];return u[f]=e,u}return [...d,e]}),S({type:"put",key:s,value:e,timestamp:Date.now()}),o&&D(o,"items",s,e);}function I(e){r.update(s=>s.filter(d=>g(d)!==e)),S({type:"delete",key:e,timestamp:Date.now()}),o&&B(o,"items",e);}function S(e){n.update(s=>[...s,e]),o&&o.transaction("pending","readwrite").objectStore("pending").add(e);}async function v(){if(await k,!t.sync||i()||T)return;let e=n();if(e.length===0)return;i.set(true);let s=t.sync.fetch??globalThis.fetch.bind(globalThis);try{if((await s(t.sync.url,{method:"POST",headers:{"Content-Type":"application/json",...t.sync.headers},body:JSON.stringify({ops:e})})).ok){n.set([]),o&&await p(o,"pending");let f=await s(t.sync.url,{headers:t.sync.headers});if(f.ok){let u=await f.json();if(r.set(u),o){await p(o,"items");for(let P of u)await D(o,"items",g(P),P);}}}}catch(d){console.warn("[AkashJS] Offline sync failed:",d);}finally{i.set(false);}}return {items:()=>r(),get(e){return r().find(s=>g(s)===e)},put:w,add:w,update(e,s){let d=r().find(f=>g(f)===e);d&&w({...d,...s});},remove:I,clear(){r.set([]),n.set([]),o&&(p(o,"items"),p(o,"pending"));},pending:b,syncing:()=>i(),online:()=>l$1(),sync:v,dispose(){T=true,m$1&&clearInterval(m$1),o?.close();}}}export{A as a};//# sourceMappingURL=chunk-5NJYYK3Q.js.map
|
|
2
|
-
//# sourceMappingURL=chunk-5NJYYK3Q.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/offline.ts"],"names":["openDB","name","version","resolve","reject","request","db","err","idbGetAll","store","req","idbPut","key","value","tx","idbDelete","idbClear","createOfflineStore","options","keyField","items","signal","pendingOps","syncing","online","pending","computed","syncTimer","disposed","syncNow","init","stored","ops","initPromise","interval","getKey","item","put","list","idx","i","next","queueOp","remove","op","fetchFn","serverResponse","serverItems","partial","existing"],"mappings":"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","file":"chunk-5NJYYK3Q.js","sourcesContent":["/**\n * Offline-first store with IndexedDB persistence and background sync.\n *\n * Data persists across page reloads. Changes made offline queue up\n * and sync automatically when connection returns. Conflict resolution\n * via configurable strategies (last-write-wins, merge, custom).\n *\n * ```ts\n * const todos = createOfflineStore('todos', {\n * sync: { url: '/api/todos', strategy: 'last-write-wins' },\n * });\n *\n * todos.add({ id: '1', text: 'Buy milk', done: false });\n * todos.items(); // reactive list\n * todos.syncing(); // boolean\n * todos.pending(); // number of unsynced changes\n * ```\n */\n\nimport { signal, computed } from './signals.js';\nimport type { Signal, ReadonlySignal } from './signals.js';\n\n// =========================================================================\n// Types\n// =========================================================================\n\nexport type ConflictStrategy = 'last-write-wins' | 'client-wins' | 'server-wins' | 'manual';\n\nexport interface OfflineStoreOptions<T> {\n /** Sync configuration */\n sync?: {\n /** Server URL for sync */\n url: string;\n /** Conflict resolution strategy (default: 'last-write-wins') */\n strategy?: ConflictStrategy;\n /** Sync interval in ms (default: 30000) */\n interval?: number;\n /** Custom fetch */\n fetch?: typeof globalThis.fetch;\n /** Auth headers */\n headers?: Record<string, string>;\n };\n /** Key field for items (default: 'id') */\n keyField?: string;\n /** Version for schema migrations */\n version?: number;\n}\n\nexport interface OfflineStore<T extends Record<string, unknown>> {\n /** All items (reactive) */\n items: ReadonlySignal<T[]>;\n /** Get a single item by key */\n get(key: string): T | undefined;\n /** Add or update an item */\n put(item: T): void;\n /** Add a new item */\n add(item: T): void;\n /** Update an existing item */\n update(key: string, partial: Partial<T>): void;\n /** Remove an item by key */\n remove(key: string): void;\n /** Clear all items */\n clear(): void;\n /** Number of unsynced changes */\n pending: ReadonlySignal<number>;\n /** Whether sync is in progress */\n syncing: ReadonlySignal<boolean>;\n /** Whether online */\n online: ReadonlySignal<boolean>;\n /** Force a sync now */\n sync(): Promise<void>;\n /** Dispose the store (stop sync, close DB) */\n dispose(): void;\n}\n\n/** An operation in the change queue */\ninterface PendingOp<T> {\n type: 'put' | 'delete';\n key: string;\n value?: T;\n timestamp: number;\n}\n\n// =========================================================================\n// IndexedDB wrapper\n// =========================================================================\n\nasync function openDB(name: string, version = 1): Promise<IDBDatabase> {\n if (typeof indexedDB === 'undefined') {\n return Promise.reject(new Error('IndexedDB not available'));\n }\n return new Promise((resolve, reject) => {\n try {\n const request = indexedDB.open(name, version);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains('items')) {\n db.createObjectStore('items');\n }\n if (!db.objectStoreNames.contains('pending')) {\n db.createObjectStore('pending', { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'));\n } catch (err) {\n reject(err);\n }\n });\n}\n\nasync function idbGetAll<T>(db: IDBDatabase, store: string): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readonly');\n const req = tx.objectStore(store).getAll();\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\nasync function idbPut(db: IDBDatabase, store: string, key: string, value: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).put(value, key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nasync function idbDelete(db: IDBDatabase, store: string, key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).delete(key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nasync function idbClear(db: IDBDatabase, store: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n// =========================================================================\n// createOfflineStore\n// =========================================================================\n\n/**\n * Create an offline-first store backed by IndexedDB.\n */\nexport function createOfflineStore<T extends Record<string, unknown>>(\n name: string,\n options: OfflineStoreOptions<T> = {},\n): OfflineStore<T> {\n const keyField = options.keyField ?? 'id';\n const items = signal<T[]>([]);\n const pendingOps = signal<PendingOp<T>[]>([]);\n const syncing = signal(false);\n const online = signal(typeof navigator !== 'undefined' ? navigator.onLine : true);\n const pending = computed(() => pendingOps().length);\n\n let db: IDBDatabase | null = null;\n let syncTimer: ReturnType<typeof setInterval> | null = null;\n let disposed = false;\n\n // Online/offline tracking\n if (typeof window !== 'undefined') {\n window.addEventListener('online', () => {\n online.set(true);\n syncNow();\n });\n window.addEventListener('offline', () => online.set(false));\n }\n\n // Initialize — load from IndexedDB\n async function init(): Promise<void> {\n if (typeof indexedDB === 'undefined') return;\n try {\n db = await openDB(`akash-offline-${name}`, options.version ?? 1);\n const stored = await idbGetAll<T>(db, 'items');\n items.set(stored);\n const ops = await idbGetAll<PendingOp<T>>(db, 'pending');\n pendingOps.set(ops);\n } catch (err) { console.error('[AkashJS] Offline store init failed:', err); }\n }\n\n const initPromise = init();\n\n // Start periodic sync\n if (options.sync) {\n const interval = options.sync.interval ?? 30000;\n syncTimer = setInterval(() => {\n if (online() && pending() > 0 && !syncing()) {\n syncNow();\n }\n }, interval);\n }\n\n function getKey(item: T): string {\n return String((item as any)[keyField]);\n }\n\n function put(item: T): void {\n const key = getKey(item);\n items.update((list) => {\n const idx = list.findIndex((i) => getKey(i) === key);\n if (idx !== -1) {\n const next = [...list];\n next[idx] = item;\n return next;\n }\n return [...list, item];\n });\n\n queueOp({ type: 'put', key, value: item, timestamp: Date.now() });\n if (db) idbPut(db, 'items', key, item);\n }\n\n function remove(key: string): void {\n items.update((list) => list.filter((i) => getKey(i) !== key));\n queueOp({ type: 'delete', key, timestamp: Date.now() });\n if (db) idbDelete(db, 'items', key);\n }\n\n function queueOp(op: PendingOp<T>): void {\n pendingOps.update((ops) => [...ops, op]);\n if (db) {\n const tx = db.transaction('pending', 'readwrite');\n tx.objectStore('pending').add(op);\n }\n }\n\n async function syncNow(): Promise<void> {\n await initPromise;\n if (!options.sync || syncing() || disposed) return;\n const ops = pendingOps();\n if (ops.length === 0) return;\n\n syncing.set(true);\n const fetchFn = options.sync.fetch ?? globalThis.fetch.bind(globalThis);\n\n try {\n const response = await fetchFn(options.sync.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...options.sync.headers,\n },\n body: JSON.stringify({ ops }),\n });\n\n if (response.ok) {\n pendingOps.set([]);\n if (db) await idbClear(db, 'pending');\n\n // Fetch latest server state\n const serverResponse = await fetchFn(options.sync.url, {\n headers: options.sync.headers,\n });\n if (serverResponse.ok) {\n const serverItems = await serverResponse.json() as T[];\n items.set(serverItems);\n // Update IndexedDB\n if (db) {\n await idbClear(db, 'items');\n for (const item of serverItems) {\n await idbPut(db, 'items', getKey(item), item);\n }\n }\n }\n }\n } catch (err) { console.warn('[AkashJS] Offline sync failed:', err); }\n finally {\n syncing.set(false);\n }\n }\n\n return {\n items: () => items(),\n get(key: string) { return items().find((i) => getKey(i) === key); },\n put,\n add: put,\n update(key: string, partial: Partial<T>) {\n const existing = items().find((i) => getKey(i) === key);\n if (existing) put({ ...existing, ...partial });\n },\n remove,\n clear() {\n items.set([]);\n pendingOps.set([]);\n if (db) {\n idbClear(db, 'items');\n idbClear(db, 'pending');\n }\n },\n pending,\n syncing: () => syncing(),\n online: () => online(),\n sync: syncNow,\n dispose() {\n disposed = true;\n if (syncTimer) clearInterval(syncTimer);\n db?.close();\n },\n };\n}\n"]}
|
package/dist/chunk-JSBB2VV3.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
'use strict';var chunkRTJ6UDGV_cjs=require('./chunk-RTJ6UDGV.cjs');async function j(a,t=1){return typeof indexedDB>"u"?Promise.reject(new Error("IndexedDB not available")):new Promise((c,r)=>{try{let n=indexedDB.open(a,t);n.onupgradeneeded=()=>{let i=n.result;i.objectStoreNames.contains("items")||i.createObjectStore("items"),i.objectStoreNames.contains("pending")||i.createObjectStore("pending",{autoIncrement:!0});},n.onsuccess=()=>c(n.result),n.onerror=()=>r(n.error??new Error("IndexedDB open failed"));}catch(n){r(n);}})}async function x(a,t){return new Promise((c,r)=>{let i=a.transaction(t,"readonly").objectStore(t).getAll();i.onsuccess=()=>c(i.result),i.onerror=()=>r(i.error);})}async function D(a,t,c,r){return new Promise((n,i)=>{let l=a.transaction(t,"readwrite");l.objectStore(t).put(r,c),l.oncomplete=()=>n(),l.onerror=()=>i(l.error);})}async function B(a,t,c){return new Promise((r,n)=>{let i=a.transaction(t,"readwrite");i.objectStore(t).delete(c),i.oncomplete=()=>r(),i.onerror=()=>n(i.error);})}async function p(a,t){return new Promise((c,r)=>{let n=a.transaction(t,"readwrite");n.objectStore(t).clear(),n.oncomplete=()=>c(),n.onerror=()=>r(n.error);})}function A(a,t={}){let c=t.keyField??"id",r=chunkRTJ6UDGV_cjs.l([]),n=chunkRTJ6UDGV_cjs.l([]),i=chunkRTJ6UDGV_cjs.l(false),l=chunkRTJ6UDGV_cjs.l(typeof navigator<"u"?navigator.onLine:true),b=chunkRTJ6UDGV_cjs.m(()=>n().length),o=null,m=null,T=false;typeof window<"u"&&(window.addEventListener("online",()=>{l.set(true),v();}),window.addEventListener("offline",()=>l.set(false)));async function O(){if(!(typeof indexedDB>"u"))try{o=await j(`akash-offline-${a}`,t.version??1);let e=await x(o,"items");r.set(e);let s=await x(o,"pending");n.set(s);}catch(e){console.error("[AkashJS] Offline store init failed:",e);}}let k=O();if(t.sync){let e=t.sync.interval??3e4;m=setInterval(()=>{l()&&b()>0&&!i()&&v();},e);}function g(e){return String(e[c])}function w(e){let s=g(e);r.update(d=>{let f=d.findIndex(u=>g(u)===s);if(f!==-1){let u=[...d];return u[f]=e,u}return [...d,e]}),S({type:"put",key:s,value:e,timestamp:Date.now()}),o&&D(o,"items",s,e);}function I(e){r.update(s=>s.filter(d=>g(d)!==e)),S({type:"delete",key:e,timestamp:Date.now()}),o&&B(o,"items",e);}function S(e){n.update(s=>[...s,e]),o&&o.transaction("pending","readwrite").objectStore("pending").add(e);}async function v(){if(await k,!t.sync||i()||T)return;let e=n();if(e.length===0)return;i.set(true);let s=t.sync.fetch??globalThis.fetch.bind(globalThis);try{if((await s(t.sync.url,{method:"POST",headers:{"Content-Type":"application/json",...t.sync.headers},body:JSON.stringify({ops:e})})).ok){n.set([]),o&&await p(o,"pending");let f=await s(t.sync.url,{headers:t.sync.headers});if(f.ok){let u=await f.json();if(r.set(u),o){await p(o,"items");for(let P of u)await D(o,"items",g(P),P);}}}}catch(d){console.warn("[AkashJS] Offline sync failed:",d);}finally{i.set(false);}}return {items:()=>r(),get(e){return r().find(s=>g(s)===e)},put:w,add:w,update(e,s){let d=r().find(f=>g(f)===e);d&&w({...d,...s});},remove:I,clear(){r.set([]),n.set([]),o&&(p(o,"items"),p(o,"pending"));},pending:b,syncing:()=>i(),online:()=>l(),sync:v,dispose(){T=true,m&&clearInterval(m),o?.close();}}}exports.a=A;//# sourceMappingURL=chunk-JSBB2VV3.cjs.map
|
|
2
|
-
//# sourceMappingURL=chunk-JSBB2VV3.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/offline.ts"],"names":["openDB","name","version","resolve","reject","request","db","err","idbGetAll","store","req","idbPut","key","value","tx","idbDelete","idbClear","createOfflineStore","options","keyField","items","signal","pendingOps","syncing","online","pending","computed","syncTimer","disposed","syncNow","init","stored","ops","initPromise","interval","getKey","item","put","list","idx","i","next","queueOp","remove","op","fetchFn","serverResponse","serverItems","partial","existing"],"mappings":"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","file":"chunk-JSBB2VV3.cjs","sourcesContent":["/**\n * Offline-first store with IndexedDB persistence and background sync.\n *\n * Data persists across page reloads. Changes made offline queue up\n * and sync automatically when connection returns. Conflict resolution\n * via configurable strategies (last-write-wins, merge, custom).\n *\n * ```ts\n * const todos = createOfflineStore('todos', {\n * sync: { url: '/api/todos', strategy: 'last-write-wins' },\n * });\n *\n * todos.add({ id: '1', text: 'Buy milk', done: false });\n * todos.items(); // reactive list\n * todos.syncing(); // boolean\n * todos.pending(); // number of unsynced changes\n * ```\n */\n\nimport { signal, computed } from './signals.js';\nimport type { Signal, ReadonlySignal } from './signals.js';\n\n// =========================================================================\n// Types\n// =========================================================================\n\nexport type ConflictStrategy = 'last-write-wins' | 'client-wins' | 'server-wins' | 'manual';\n\nexport interface OfflineStoreOptions<T> {\n /** Sync configuration */\n sync?: {\n /** Server URL for sync */\n url: string;\n /** Conflict resolution strategy (default: 'last-write-wins') */\n strategy?: ConflictStrategy;\n /** Sync interval in ms (default: 30000) */\n interval?: number;\n /** Custom fetch */\n fetch?: typeof globalThis.fetch;\n /** Auth headers */\n headers?: Record<string, string>;\n };\n /** Key field for items (default: 'id') */\n keyField?: string;\n /** Version for schema migrations */\n version?: number;\n}\n\nexport interface OfflineStore<T extends Record<string, unknown>> {\n /** All items (reactive) */\n items: ReadonlySignal<T[]>;\n /** Get a single item by key */\n get(key: string): T | undefined;\n /** Add or update an item */\n put(item: T): void;\n /** Add a new item */\n add(item: T): void;\n /** Update an existing item */\n update(key: string, partial: Partial<T>): void;\n /** Remove an item by key */\n remove(key: string): void;\n /** Clear all items */\n clear(): void;\n /** Number of unsynced changes */\n pending: ReadonlySignal<number>;\n /** Whether sync is in progress */\n syncing: ReadonlySignal<boolean>;\n /** Whether online */\n online: ReadonlySignal<boolean>;\n /** Force a sync now */\n sync(): Promise<void>;\n /** Dispose the store (stop sync, close DB) */\n dispose(): void;\n}\n\n/** An operation in the change queue */\ninterface PendingOp<T> {\n type: 'put' | 'delete';\n key: string;\n value?: T;\n timestamp: number;\n}\n\n// =========================================================================\n// IndexedDB wrapper\n// =========================================================================\n\nasync function openDB(name: string, version = 1): Promise<IDBDatabase> {\n if (typeof indexedDB === 'undefined') {\n return Promise.reject(new Error('IndexedDB not available'));\n }\n return new Promise((resolve, reject) => {\n try {\n const request = indexedDB.open(name, version);\n request.onupgradeneeded = () => {\n const db = request.result;\n if (!db.objectStoreNames.contains('items')) {\n db.createObjectStore('items');\n }\n if (!db.objectStoreNames.contains('pending')) {\n db.createObjectStore('pending', { autoIncrement: true });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error('IndexedDB open failed'));\n } catch (err) {\n reject(err);\n }\n });\n}\n\nasync function idbGetAll<T>(db: IDBDatabase, store: string): Promise<T[]> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readonly');\n const req = tx.objectStore(store).getAll();\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n}\n\nasync function idbPut(db: IDBDatabase, store: string, key: string, value: unknown): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).put(value, key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nasync function idbDelete(db: IDBDatabase, store: string, key: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).delete(key);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\nasync function idbClear(db: IDBDatabase, store: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const tx = db.transaction(store, 'readwrite');\n tx.objectStore(store).clear();\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n}\n\n// =========================================================================\n// createOfflineStore\n// =========================================================================\n\n/**\n * Create an offline-first store backed by IndexedDB.\n */\nexport function createOfflineStore<T extends Record<string, unknown>>(\n name: string,\n options: OfflineStoreOptions<T> = {},\n): OfflineStore<T> {\n const keyField = options.keyField ?? 'id';\n const items = signal<T[]>([]);\n const pendingOps = signal<PendingOp<T>[]>([]);\n const syncing = signal(false);\n const online = signal(typeof navigator !== 'undefined' ? navigator.onLine : true);\n const pending = computed(() => pendingOps().length);\n\n let db: IDBDatabase | null = null;\n let syncTimer: ReturnType<typeof setInterval> | null = null;\n let disposed = false;\n\n // Online/offline tracking\n if (typeof window !== 'undefined') {\n window.addEventListener('online', () => {\n online.set(true);\n syncNow();\n });\n window.addEventListener('offline', () => online.set(false));\n }\n\n // Initialize — load from IndexedDB\n async function init(): Promise<void> {\n if (typeof indexedDB === 'undefined') return;\n try {\n db = await openDB(`akash-offline-${name}`, options.version ?? 1);\n const stored = await idbGetAll<T>(db, 'items');\n items.set(stored);\n const ops = await idbGetAll<PendingOp<T>>(db, 'pending');\n pendingOps.set(ops);\n } catch (err) { console.error('[AkashJS] Offline store init failed:', err); }\n }\n\n const initPromise = init();\n\n // Start periodic sync\n if (options.sync) {\n const interval = options.sync.interval ?? 30000;\n syncTimer = setInterval(() => {\n if (online() && pending() > 0 && !syncing()) {\n syncNow();\n }\n }, interval);\n }\n\n function getKey(item: T): string {\n return String((item as any)[keyField]);\n }\n\n function put(item: T): void {\n const key = getKey(item);\n items.update((list) => {\n const idx = list.findIndex((i) => getKey(i) === key);\n if (idx !== -1) {\n const next = [...list];\n next[idx] = item;\n return next;\n }\n return [...list, item];\n });\n\n queueOp({ type: 'put', key, value: item, timestamp: Date.now() });\n if (db) idbPut(db, 'items', key, item);\n }\n\n function remove(key: string): void {\n items.update((list) => list.filter((i) => getKey(i) !== key));\n queueOp({ type: 'delete', key, timestamp: Date.now() });\n if (db) idbDelete(db, 'items', key);\n }\n\n function queueOp(op: PendingOp<T>): void {\n pendingOps.update((ops) => [...ops, op]);\n if (db) {\n const tx = db.transaction('pending', 'readwrite');\n tx.objectStore('pending').add(op);\n }\n }\n\n async function syncNow(): Promise<void> {\n await initPromise;\n if (!options.sync || syncing() || disposed) return;\n const ops = pendingOps();\n if (ops.length === 0) return;\n\n syncing.set(true);\n const fetchFn = options.sync.fetch ?? globalThis.fetch.bind(globalThis);\n\n try {\n const response = await fetchFn(options.sync.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...options.sync.headers,\n },\n body: JSON.stringify({ ops }),\n });\n\n if (response.ok) {\n pendingOps.set([]);\n if (db) await idbClear(db, 'pending');\n\n // Fetch latest server state\n const serverResponse = await fetchFn(options.sync.url, {\n headers: options.sync.headers,\n });\n if (serverResponse.ok) {\n const serverItems = await serverResponse.json() as T[];\n items.set(serverItems);\n // Update IndexedDB\n if (db) {\n await idbClear(db, 'items');\n for (const item of serverItems) {\n await idbPut(db, 'items', getKey(item), item);\n }\n }\n }\n }\n } catch (err) { console.warn('[AkashJS] Offline sync failed:', err); }\n finally {\n syncing.set(false);\n }\n }\n\n return {\n items: () => items(),\n get(key: string) { return items().find((i) => getKey(i) === key); },\n put,\n add: put,\n update(key: string, partial: Partial<T>) {\n const existing = items().find((i) => getKey(i) === key);\n if (existing) put({ ...existing, ...partial });\n },\n remove,\n clear() {\n items.set([]);\n pendingOps.set([]);\n if (db) {\n idbClear(db, 'items');\n idbClear(db, 'pending');\n }\n },\n pending,\n syncing: () => syncing(),\n online: () => online(),\n sync: syncNow,\n dispose() {\n disposed = true;\n if (syncTimer) clearInterval(syncTimer);\n db?.close();\n },\n };\n}\n"]}
|