{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "useIndexedDB", "title": "useIndexedDB", "description": "useIndexedDB external hook", "files": [ { "path": "packages/external-hooks/src/useIndexedDB/constants.ts", "content": "export const IDB_KEY = \"__idb\";\n", "type": "registry:file", "target": "src/hooks/external-hooks/useIndexedDB/constants.ts" }, { "path": "packages/external-hooks/src/useIndexedDB/db.ts", "content": "import { IDB_KEY } from \"./constants\";\nimport type { IndexedDBConfig } from \"./interfaces\";\nimport { waitUntil } from \"./utils\";\n\nfunction validateStore(db: IDBDatabase, storeName: string) {\n return db.objectStoreNames.contains(storeName);\n}\n\ndeclare global {\n interface Window {\n [IDB_KEY]: {\n init: number;\n config: IndexedDBConfig;\n };\n }\n}\n\nexport function validateBeforeTransaction(db: IDBDatabase, storeName: string, reject: Function) {\n if (!db) {\n reject(\"Queried before opening connection\");\n }\n if (!validateStore(db, storeName)) {\n reject(`Store ${storeName} not found`);\n }\n}\n\nexport function createTransaction(\n db: IDBDatabase,\n dbMode: IDBTransactionMode,\n currentStore: string,\n resolve : any,\n reject?: any,\n abort?: any\n): IDBTransaction {\n let tx: IDBTransaction = db.transaction(currentStore, dbMode) as IDBTransaction;\n tx.onerror = reject;\n tx.oncomplete = resolve;\n tx.onabort = abort;\n return tx;\n}\n\nexport async function getConnection(config?: IndexedDBConfig): Promise {\n const idbInstance = typeof window !== \"undefined\" ? window.indexedDB : null;\n let _config = config;\n\n if (!config && idbInstance) {\n await waitUntil(() => window?.[IDB_KEY]?.[\"init\"] === 1);\n _config = window[IDB_KEY]?.[\"config\"];\n }\n\n return new Promise((resolve, reject) => {\n if (idbInstance) {\n const request: IDBOpenDBRequest = idbInstance.open(_config!.databaseName, _config!.version);\n\n request.onsuccess = () => {\n resolve(request.result);\n };\n\n request.onerror = (e: any) => {\n reject(e.target.error.name);\n };\n\n request.onupgradeneeded = (e: any) => {\n const db = e.target.result;\n config!.stores.forEach(s => {\n if (!db.objectStoreNames.contains(s.name)) {\n const store = db.createObjectStore(s.name, s.id);\n s.indices.forEach(c => {\n store.createIndex(c.name, c.keyPath, c.options);\n });\n }\n });\n db.close();\n resolve(undefined as any);\n };\n } else {\n reject(\"Failed to connect\");\n }\n });\n}\n\nexport function getActions(currentStore: string) {\n return {\n getByID(id: string | number) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readonly\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.get(id);\n request.onsuccess = (e: any) => {\n resolve(e.target.result as T);\n };\n })\n .catch(reject);\n });\n },\n getOneByKey(keyPath: string, value: string | number) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readonly\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let index = objectStore.index(keyPath);\n let request = index.get(value);\n request.onsuccess = (e: any) => {\n resolve(e.target.result);\n };\n })\n .catch(reject);\n });\n },\n getManyByKey(keyPath: string, value: string | number) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readonly\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let index = objectStore.index(keyPath);\n let request = index.getAll(value);\n request.onsuccess = (e: any) => {\n resolve(e.target.result);\n };\n })\n .catch(reject);\n });\n },\n getAll() {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readonly\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.getAll();\n request.onsuccess = (e: any) => {\n resolve(e.target.result as T[]);\n };\n })\n .catch(reject);\n });\n },\n\n add(value: T, key?: any) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readwrite\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.add(value, key);\n request.onsuccess = (e: any) => {\n (tx as any)?.commit?.();\n resolve(e.target.result);\n };\n })\n .catch(reject);\n });\n },\n\n update(value: T, key?: any) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readwrite\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.put(value, key);\n request.onsuccess = (e: any) => {\n (tx as any)?.commit?.();\n resolve(e.target.result);\n };\n })\n .catch(reject);\n });\n },\n\n deleteByID(id: any) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readwrite\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.delete(id);\n request.onsuccess = (e: any) => {\n (tx as any)?.commit?.();\n resolve(e);\n };\n })\n .catch(reject);\n });\n },\n deleteAll() {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readwrite\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.clear();\n request.onsuccess = (e: any) => {\n (tx as any)?.commit?.();\n resolve(e);\n };\n })\n .catch(reject);\n });\n },\n\n openCursor(cursorCallback: (e: Event) => any, keyRange?: IDBKeyRange) {\n return new Promise((resolve, reject) => {\n getConnection()\n .then(db => {\n validateBeforeTransaction(db, currentStore, reject);\n let tx = createTransaction(db, \"readonly\", currentStore, resolve, reject);\n let objectStore = tx.objectStore(currentStore);\n let request = objectStore.openCursor(keyRange);\n request.onsuccess = e => {\n cursorCallback(e);\n resolve();\n };\n })\n .catch(reject);\n });\n },\n };\n}\n", "type": "registry:file", "target": "src/hooks/external-hooks/useIndexedDB/db.ts" }, { "path": "packages/external-hooks/src/useIndexedDB/index.ts", "content": "import { useMemo } from \"react\";\n\nimport { IDB_KEY } from \"./constants\";\nimport { getActions, getConnection } from \"./db\";\nimport type { IndexedDBConfig } from \"./interfaces\";\n\nasync function setupIndexedDB(config: IndexedDBConfig) {\n return new Promise(async (resolve, reject) => {\n try {\n await getConnection(config);\n console.log(\"inside Init\", config);\n window[IDB_KEY] = { init: 1, config };\n resolve();\n } catch (e) {\n console.error(e);\n reject(e);\n }\n });\n}\n\nfunction useIndexedDB(storeName: string) {\n const _actions = useMemo(() => getActions(storeName), [storeName]);\n return _actions;\n}\n\nexport default useIndexedDB;\nexport {\n setupIndexedDB\n}\n", "type": "registry:file", "target": "src/hooks/external-hooks/useIndexedDB/index.ts" }, { "path": "packages/external-hooks/src/useIndexedDB/interfaces.ts", "content": "export interface IndexedDBColumn {\n name: string;\n keyPath: string;\n options?: IDBIndexParameters;\n}\n\nexport interface IndexedDBStore {\n name: string;\n id: IDBObjectStoreParameters;\n indices: IndexedDBColumn[];\n}\n\nexport interface IndexedDBConfig {\n databaseName: string;\n version: number;\n stores: IndexedDBStore[];\n}\n\nexport interface TransactionOptions {\n storeName: string;\n dbMode: IDBTransactionMode;\n error: (e: Event) => any;\n complete: (e: Event) => any;\n abort?: any;\n}\n", "type": "registry:file", "target": "src/hooks/external-hooks/useIndexedDB/interfaces.ts" }, { "path": "packages/external-hooks/src/useIndexedDB/utils.ts", "content": "/*\n * Taken From https://stackoverflow.com/a/69614443/4377220\n * for good DX + SSR\n */\n\ninterface WaitUntilProps {\n tick?: number;\n timeout?: number;\n}\n\nexport const waitUntil = (condition: () => boolean, options?: WaitUntilProps) => {\n return new Promise((resolve, reject) => {\n const interval = setInterval(() => {\n if (!condition()) return;\n\n clearInterval(interval);\n resolve();\n }, options?.tick || 100);\n\n setTimeout(() => {\n clearInterval(interval);\n reject(\"your error msg\");\n }, options?.timeout || 10000);\n });\n};\n", "type": "registry:file", "target": "src/hooks/external-hooks/useIndexedDB/utils.ts" } ], "type": "registry:hook" }