Nxdom Framework

Nusantara eXtreme Development Object Model — dokumentasi resmi

IndexedDB & NX.ref — NexaStorage

Operasi store lokal lewat NX.Storage(), dDB.indexedDB, dan NX.ref — auto/manual mode, CRUD, query, watch, refresh, ukuran, export/import. Melengkapi buckets & Storage. Sebelumnya: NexaModels — berikutnya: NexaForge.

Di cuplikan berikut, biasanya const dDB = NX.Storage(); sudah tersedia. API utama ada di NX.ref setelah dDB.indexedDB.init(...).

Import & default stores

Daftar nama store bawaan yang sering dipakai bersama metadata / aktivitas:

const defaultStores = [ "nexaStore", "bucketsStore", "folderStructure", "activityLogs", "metadata", "recycleBin", "fileContents", "fileSettings", "presentations", ];

1. Inisialisasi database

const dDB = NX.Storage();

1.1 Auto mode

async function initAutoMode() { try { await dDB.indexedDB.init("MyAppDB", 1); console.log("Auto mode OK", NX.ref.getInfo()); } catch (error) { console.error("Auto mode init failed:", error); } }

1.2 Manual mode

async function initManualMode() { try { await dDB.indexedDB.init("MyAppDB", 1, ["users", "products", "orders"]); console.log("Stores:", NX.ref.getInfo().availableStores); } catch (error) { console.error("Manual mode init failed:", error); } }

1.3 Tambah store dinamis

async function addNewStores() { try { await dDB.indexedDB.init("MyAppDB", 1, ["users"]); await NX.ref.addStores(["products", "categories"]); console.log("Updated stores:", NX.ref.getInfo().availableStores); } catch (error) { console.error("addStores failed:", error); } }

2. Operasi CRUD dasar

2.1 Create / update

async function createUpdateData() { try { const userId = await NX.ref.set("users", { id: "user_001", name: "John Doe", email: "john@example.com", role: "admin", profile: { avatar: "avatar.jpg", bio: "Software Developer" }, }); console.log("Created id:", userId); await NX.ref.set("users", { id: "user_001", name: "John Smith", email: "john.smith@example.com", role: "admin", profile: { avatar: "new_avatar.jpg", bio: "Senior Software Developer" }, }); console.log("Updated OK"); } catch (error) { console.error("set failed:", error); } }

2.2 Read

async function readData() { try { const user = await NX.ref.get("users", "user_001"); const allUsers = await NX.ref.getAll("users"); const hasUsersStore = NX.ref.hasStore("users"); console.log(user, allUsers.data, hasUsersStore); } catch (error) { console.error("read failed:", error); } }

2.3 Delete

async function deleteData() { try { const result = await NX.ref.delete("users", "user_001"); const deletedUser = await NX.ref.get("users", "user_001"); console.log(result, deletedUser); } catch (error) { console.error("delete failed:", error); } }

3. Operasi data lanjutan

3.1 Get latest

async function getLatestData() { try { await NX.ref.set("posts", { id: "post_1", title: "First Post", content: "Content 1" }); await new Promise((r) => setTimeout(r, 100)); await NX.ref.set("posts", { id: "post_2", title: "Second Post", content: "Content 2" }); await new Promise((r) => setTimeout(r, 100)); await NX.ref.set("posts", { id: "post_3", title: "Latest Post", content: "Content 3" }); const latestPost = await NX.ref.getLatest("posts", 1); const latest2Posts = await NX.ref.getLatest("posts", 2); console.log(latestPost.data, latest2Posts.data); } catch (error) { console.error("getLatest failed:", error); } }

3.2 Get oldest

async function getOldestData() { try { const oldestPost = await NX.ref.getOldest("posts", 1); const oldest2Posts = await NX.ref.getOldest("posts", 2); console.log(oldestPost.data, oldest2Posts.data); } catch (error) { console.error("getOldest failed:", error); } }

3.3 Date range

async function getByDateRange() { try { const startDate = new Date("2025-01-01"); const endDate = new Date("2025-12-31"); const postsInRange = await NX.ref.getByDateRange("posts", startDate, endDate); console.log(postsInRange); } catch (error) { console.error("date range failed:", error); } }
async function searchData() { try { const allFields = await NX.ref.search("posts", "latest"); const titleOnly = await NX.ref.search("posts", "first", ["title"]); console.log(allFields, titleOnly); } catch (error) { console.error("search failed:", error); } }

4. Real-time & refresh

4.1 Watch

async function watchDataChanges() { try { const unwatch = NX.ref.watch("users", (event) => { console.log({ store: event.storeName, changeType: event.changeType, data: event.data, timestamp: event.timestamp, }); }); await NX.ref.set("users", { id: "user_002", name: "Jane Doe" }); await NX.ref.set("users", { id: "user_002", name: "Jane Smith" }); await NX.ref.delete("users", "user_002"); setTimeout(() => { unwatch(); }, 10000); } catch (error) { console.error("watch failed:", error); } }

4.2 Auto refresh dari API

async function setupAutoRefresh() { try { const pollId = await NX.ref.setupAutoRefresh("products", { strategy: "polling", endpoint: async () => { const response = await fetch("/api/products"); return await response.json(); }, pollInterval: 30000, immediate: true, }); console.log("pollId", pollId); setTimeout(() => NX.ref.stopPolling("products"), 300000); } catch (error) { console.error("setupAutoRefresh failed:", error); } }

4.3 Manual refresh

async function manualRefresh() { try { await NX.ref.refreshTable("products", async () => { const response = await fetch("/api/products"); return await response.json(); }); await NX.ref.refreshTable(); } catch (error) { console.error("manualRefresh failed:", error); } }

4.4 Simple refresh

async function simpleRefresh() { try { await NX.ref.set("users", { id: "user_1", name: "John", status: "active" }); await NX.ref.refresh(); await NX.ref.refresh("https://api.example.com/data", { onProgress: (progress) => console.log(`Progress: ${progress.completed}/${progress.total}`), }); await NX.ref.refreshTable("users", "https://api.example.com/users"); await NX.ref.refreshTable("products"); } catch (error) { console.error("simpleRefresh failed:", error); } }

4.5 Batch operations

async function batchOperations() { try { const batchData = [ { id: "product_1", name: "Laptop", price: 1000 }, { id: "product_2", name: "Mouse", price: 25 }, { id: "product_3", name: "Keyboard", price: 75 }, ]; await NX.ref.batchUpdate("products", batchData, { clearFirst: true, batchSize: 100, onProgress: (progress) => console.log(`Batch: ${progress.percentage}%`), }); } catch (error) { console.error("batchUpdate failed:", error); } }

5. Ukuran & cleanup

5.1 Monitoring

async function monitorDatabaseSize() { try { const sizeInfo = await NX.ref.getDatabaseSize(); const storeSize = await NX.ref.getStoreSize("users"); const dataSize = await NX.ref.getDataSize("users", "user_001"); const storageUsage = await NX.ref.getStorageUsage(); console.log(sizeInfo, storeSize, dataSize, storageUsage); } catch (error) { console.error("size monitoring failed:", error); } }

5.2 Auto monitor

async function startSizeMonitoring() { try { const stopMonitoring = NX.ref.monitorSize(30000); setTimeout(() => stopMonitoring(), 300000); } catch (error) { console.error("monitorSize failed:", error); } }

5.3 Cleanup by size

async function cleanupBySize() { try { const cleanupResult = await NX.ref.cleanupBySize("logs", 10); console.log(cleanupResult); } catch (error) { console.error("cleanupBySize failed:", error); } }

6. Export / import

6.1 Export

async function exportData() { try { const exportResult = await NX.ref.export(); const specificExport = await NX.ref.export(["users", "products"], { encrypt: true, includeMetadata: true, onProgress: (progress) => console.log(`Export: ${progress.completed}/${progress.total}`), }); await NX.ref.exportToFile("my_backup.json", ["users"], { encrypt: false, includeMetadata: true, }); console.log(exportResult, specificExport); } catch (error) { console.error("export failed:", error); } }

6.2 Import

async function importData() { try { const payload = { metadata: { dbName: "MyAppDB", exportDate: new Date().toISOString(), stores: ["users"], }, data: { users: [ { id: "user_003", name: "Alice Johnson", email: "alice@example.com" }, { id: "user_004", name: "Bob Wilson", email: "bob@example.com" }, ], }, }; const importResult = await NX.ref.import(payload, { decrypt: false, overwrite: true, onProgress: (progress) => console.log(`Import: ${progress.completed}/${progress.total}`), }); console.log(importResult); } catch (error) { console.error("import failed:", error); } }

6.3 Import dari berkas

async function importFromFile() { try { const fileInput = document.createElement("input"); fileInput.type = "file"; fileInput.accept = ".json"; fileInput.onchange = async (event) => { const file = event.target.files[0]; if (file) { const importResult = await NX.ref.importFromFile(file, { decrypt: false, overwrite: true, }); console.log(importResult); } }; fileInput.click(); } catch (error) { console.error("importFromFile failed:", error); } }

7. Safe operations

Antarmuka safe() mengurangi throw pada operasi umum:

async function safeOperations() { try { const safe = NX.ref.safe(); const user = await safe.get("nonexistent_store", "user_001"); const allData = await safe.getAll("nonexistent_store"); await safe.set("new_store", { id: "item_001", name: "New Item" }); const stores = safe.listStores(); console.log(user, allData, stores); } catch (error) { console.error("safeOperations failed:", error); } }

8. Info, reset & cleanup resource

8.1 Info & status

async function getDatabaseInfo() { try { const info = NX.ref.getInfo(); const realtimeStatus = NX.ref.getRealtimeStatus(); const hasUsers = NX.ref.hasStore("users"); console.log(info, realtimeStatus, hasUsers); } catch (error) { console.error("getInfo failed:", error); } }

8.2 Reset database (hapus semua data — hati-hati)

async function resetDatabase() { try { await NX.ref.resetDatabase(); await initAutoMode(); } catch (error) { console.error("resetDatabase failed:", error); } }

8.3 Bersihkan resource real-time

async function cleanupResources() { NX.ref.cleanup(); }

9. Sinkron dengan localStorage

Lewat instance Storage (bukan hanya NX.ref):

async function syncWithLocalStorage() { const storage = NX.Storage(); try { const toIdb = await storage.sync.localStorageToIndexedDB({ prefix: "app_", storeName: "localStorage_backup", overwrite: true, clearTarget: false, }); const toLs = await storage.sync.indexedDBToLocalStorage("users", { prefix: "backup_", overwrite: true, clearTarget: false, }); const both = await storage.sync.bidirectional("users", { localStoragePrefix: "sync_", strategy: "localStorage", }); console.log(toIdb, toLs, both); } catch (error) { console.error("sync failed:", error); } }

10. Bandingkan ukuran storage

Gunakan helper storage.compare pada instance NX.Storage().

async function compareStorages() { const storage = NX.Storage(); try { const sizes = await storage.compare.getSizes(); const health = await storage.compare.healthCheck(); console.log(sizes, health); } catch (error) { console.error("compare failed:", error); } }

11. Best practices & contoh

Contoh manajemen user

async function userManagementExample() { try { const users = [ { id: "admin_001", name: "Admin User", role: "admin", email: "admin@example.com" }, { id: "user_001", name: "Regular User", role: "user", email: "user@example.com" }, { id: "mod_001", name: "Moderator", role: "moderator", email: "mod@example.com" }, ]; for (const user of users) { await NX.ref.set("users", user); } const unwatch = NX.ref.watch("users", (event) => { console.log(event.changeType, event.data.name); }); const adminUsers = await NX.ref.search("users", "admin", ["role", "name"]); const latestUser = await NX.ref.getLatest("users", 1); await NX.ref.set("users", { id: "user_001", name: "Updated Regular User", role: "user", email: "updated.user@example.com", lastLogin: new Date().toISOString(), }); await NX.ref.exportToFile("users_backup.json", ["users"]); const userStoreSize = await NX.ref.getStoreSize("users"); console.log(adminUsers, latestUser.data, userStoreSize); setTimeout(() => unwatch(), 5000); } catch (error) { console.error("userManagementExample failed:", error); } }

Contoh katalog (ringkas)

async function ecommerceExample() { try { const products = [ { id: "prod_001", name: "Laptop Gaming", category: "Electronics", price: 1500, stock: 10 }, { id: "prod_002", name: "Wireless Mouse", category: "Accessories", price: 50, stock: 100 }, ]; await NX.ref.batchUpdate("products", products, { clearFirst: true }); const categories = [ { id: "cat_001", name: "Electronics", description: "Electronic devices" }, { id: "cat_002", name: "Accessories", description: "Computer accessories" }, ]; await NX.ref.batchUpdate("categories", categories, { clearFirst: true }); const laptops = await NX.ref.search("products", "laptop", ["name", "category"]); const allProducts = await NX.ref.getAll("products"); const expensive = allProducts.data.filter((p) => p.price > 100); const unwatchProducts = NX.ref.watch("products", (event) => { if (event.changeType === "update") console.log(event.data.name, event.data.stock); }); await NX.ref.set("products", { id: "prod_001", name: "Laptop Gaming", category: "Electronics", price: 1400, stock: 8, }); await NX.ref.exportToFile("catalog_backup.json", ["products", "categories"]); setTimeout(() => unwatchProducts(), 3000); console.log(laptops, expensive.length); } catch (error) { console.error("ecommerceExample failed:", error); } }

12. Error handling & debugging

Fallback init, cek hasil get, batch dengan skip item rusak, cek realtime:

async function errorHandlingExamples() { try { try { await dDB.indexedDB.init("MyAppDB", 1); } catch (error) { console.warn("IndexedDB gagal, fallback localStorage"); const storage = NX.Storage(); return storage.localStorage; } try { const user = await NX.ref.get("users", "nonexistent_user"); console.log(user || "No user"); } catch (error) { console.error("get user:", error.message); } const batchData = [ { id: "valid_001", name: "Valid Item 1" }, {}, { id: "valid_002", name: "Valid Item 2" }, ]; for (const item of batchData) { try { if (item.id && item.name) { await NX.ref.set("items", item); } else { console.warn("skip invalid", item); } } catch (error) { console.error("item save:", error.message); } } const realtimeStatus = NX.ref.getRealtimeStatus(); if (!realtimeStatus.broadcastChannel) { console.warn("Cross-tab sync tidak tersedia"); } } catch (error) { console.error("errorHandlingExamples failed:", error); } }

13. Optimasi performa

Batch besar, query terarah, ukuran store, batasi watcher:

async function performanceOptimization() { try { const largeDataset = Array.from({ length: 1000 }, (_, i) => ({ id: `item_${i}`, name: `Item ${i}`, data: `Large data content ${i}`.repeat(100), })); console.time("Batch Insert"); await NX.ref.batchUpdate("large_items", largeDataset, { batchSize: 100, onProgress: (progress) => { if (progress.percentage % 20 === 0) console.log(`${progress.percentage}%`); }, }); console.timeEnd("Batch Insert"); console.time("Latest Query"); const latest10 = await NX.ref.getLatest("large_items", 10); console.timeEnd("Latest Query"); console.log(latest10.data.length); const sizeInfo = await NX.ref.getStoreSize("large_items"); if (parseFloat(sizeInfo.sizeMB) > 5) { await NX.ref.cleanupBySize("large_items", 3); } let changeCount = 0; const unwatch = NX.ref.watch("large_items", () => { changeCount++; }); setTimeout(() => unwatch(), 5000); } catch (error) { console.error("performanceOptimization failed:", error); } }

14. Testing & validasi

Contoh merangkai tes: setiap fn mengacu ke fungsi contoh yang sudah didefinisikan di modul Anda.

async function runTests() { const tests = [ { name: "Auto Mode Initialization", fn: initAutoMode }, { name: "Manual Mode Initialization", fn: initManualMode }, { name: "CRUD Operations", fn: createUpdateData }, { name: "Data Queries", fn: getLatestData }, { name: "Search Functionality", fn: searchData }, { name: "Real-time Watching", fn: watchDataChanges }, { name: "Size Management", fn: monitorDatabaseSize }, { name: "Export/Import", fn: exportData }, { name: "Safe Operations", fn: safeOperations }, { name: "Cross-storage Sync", fn: syncWithLocalStorage }, { name: "User Management Example", fn: userManagementExample }, { name: "E-commerce Example", fn: ecommerceExample }, ]; const results = []; for (const test of tests) { try { await test.fn(); results.push({ name: test.name, status: "PASSED" }); } catch (error) { results.push({ name: test.name, status: "FAILED", error: error.message }); } } const passed = results.filter((r) => r.status === "PASSED").length; console.log("Passed", passed, "/", results.length); return results; }

15. Update field & merge

15.1 Beberapa field

await NX.ref.set("users", { id: "user_001", name: "John Doe", email: "john@example.com", age: 30, role: "user", profile: { avatar: "avatar.jpg", bio: "Software Developer", location: "Jakarta" }, settings: { theme: "light", notifications: true, language: "id" }, }); await NX.ref.updateFields("users", "user_001", { email: "john.new@example.com", age: 31, role: "admin", });

15.2 Satu field

await NX.ref.updateField("users", "user_001", "email", "updated.email@example.com"); await NX.ref.updateField("users", "user_001", "age", 32); await NX.ref.updateField("users", "user_001", "role", "super_admin");

15.3 Field bersarang (notasi titik)

await NX.ref.updateNestedField("users", "user_001", "profile.bio", "Senior Software Developer"); await NX.ref.updateNestedField("users", "user_001", "profile.location", "Bandung"); await NX.ref.updateNestedField("users", "user_001", "settings.theme", "dark"); await NX.ref.updateNestedField("users", "user_001", "settings.notifications", false);

15.4 Merge shallow & deep

await NX.ref.mergeData("users", "user_001", { status: "active", lastLogin: new Date().toISOString(), loginCount: 1, }); await NX.ref.mergeData( "users", "user_001", { profile: { bio: "Expert Software Developer", skills: ["JavaScript", "React", "Node.js"], }, settings: { language: "en", timezone: "Asia/Jakarta" }, }, { deepMerge: true } ); await NX.ref.mergeData( "users", "user_002", { name: "Jane Smith", email: "jane@example.com", profile: { bio: "UI/UX Designer", location: "Jakarta" }, }, { createIfNotExists: true } );

Ada pula batchUpdateFields, contoh partial e-commerce / profil, dan suite tes khusus partial update di implementasi NexaStorage Anda — pola pemakaian sama: store, id rekaman, objek field atau opsi deepMerge / createIfNotExists.

16. Export fungsi untuk pakai eksternal

Dari modul tunggal, re-export skenario uji / demo:

export { initAutoMode, initManualMode, addNewStores, createUpdateData, readData, deleteData, getLatestData, getOldestData, getByDateRange, searchData, watchDataChanges, setupAutoRefresh, manualRefresh, simpleRefresh, batchOperations, monitorDatabaseSize, startSizeMonitoring, cleanupBySize, exportData, importData, importFromFile, safeOperations, getDatabaseInfo, resetDatabase, cleanupResources, syncWithLocalStorage, compareStorages, userManagementExample, ecommerceExample, errorHandlingExamples, performanceOptimization, runTests, };

18. Multi store / multi database

18.1 Banyak store dalam satu DB

async function multipleStoresExample() { try { await dDB.indexedDB.init("MyAppDB", 1, [ "users", "products", "orders", "categories", "reviews", "settings", "logs", ]); await NX.ref.set("users", { id: "user_1", name: "John Doe", role: "admin" }); await NX.ref.set("products", { id: "prod_1", name: "Laptop", price: 1000 }); await NX.ref.set("orders", { id: "order_1", userId: "user_1", productId: "prod_1", total: 1000, }); const user = await NX.ref.get("users", "user_1"); const product = await NX.ref.get("products", "prod_1"); console.log(user, product); } catch (error) { console.error("multipleStoresExample failed:", error); } }

18.2 Auto mode / store runtime

async function dynamicStoreCreation() { try { await dDB.indexedDB.init("DynamicDB", 1); await NX.ref.set("customers", { id: "cust_1", name: "Alice", email: "alice@example.com" }); await NX.ref.set("suppliers", { id: "supp_1", name: "Tech Corp", contact: "tech@corp.com" }); console.log(NX.ref.listStores ? NX.ref.listStores() : NX.ref.getInfo().availableStores); } catch (error) { console.error("dynamicStoreCreation failed:", error); } }

20. Duplikasi data

NX.ref.duplicate(store, sourceId, newId) menyalin rekaman dengan id baru.

async function basicDuplicateExample() { try { await NX.ref.set("users", { id: "user_001", name: "John Doe", email: "john@example.com", role: "admin", profile: { avatar: "avatar.jpg", bio: "Software Developer", location: "Jakarta" }, settings: { theme: "dark", notifications: true, language: "id" }, }); const duplicateResult = await NX.ref.duplicate("users", "user_001", "user_001_copy"); const original = await NX.ref.get("users", "user_001"); const duplicate = await NX.ref.get("users", "user_001_copy"); console.log(duplicateResult, original, duplicate); } catch (error) { console.error("duplicate failed:", error); } }

19. Menambah tabel ke DB yang sudah ada

addStores() menambah nama store tanpa init ulang penuh:

async function addNewTablesToExistingDB() { try { await dDB.indexedDB.init("MyAppDB", 1, ["users", "products", "orders"]); await NX.ref.addStores(["categories", "reviews", "settings", "notifications", "logs"]); await NX.ref.set("categories", { id: "cat_1", name: "Electronics", description: "Electronic devices", }); await NX.ref.set("reviews", { id: "rev_1", productId: "prod_1", rating: 5, comment: "Excellent!", }); const category = await NX.ref.get("categories", "cat_1"); console.log(category, NX.ref.getInfo().availableStores); } catch (error) { console.error("addNewTablesToExistingDB failed:", error); } }

Berkas implementasi

Referensi integrasi: assets/modules/nxdom.js (inisialisasi NX.ref), modul Storage / IndexedDB di assets/modules sesuai struktur proyek Anda.