npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nexabase-console

v2.2.0

Published

SDK Client resmi untuk NexaBase: Platform Sinkronisasi NoSQL, Realtime, File Storage, & Autentikasi Offline-First.

Readme

NexaBase JavaScript SDK (nexabase-console)

SDK Client Resmi untuk NexaBase: Platform sinkronisasi database modern yang menyatukan fungsionalitas Firestore NoSQL, Real-Time Database, File Storage, dan Edge Authentication dengan dukungan Offline-First (IndexedDB) serta Passwordless OTP.


🚀 Fitur Utama

  • ⚡ Real-Time Synchronization & Anti-Flicker Engine: Sinkronisasi data real-time dengan latency rendah menggunakan Server-Sent Events (SSE) yang dilengkapi Deep Comparison Data Hashing untuk mencegah re-render/flicker komponen UI saat sync.
  • 🚀 Latency Compensation (Optimistic UI & 0ms Local Render): Penulisan data (setDoc, updateDoc, deleteDoc, writeBatch) langsung memperbarui cache lokal IndexedDB dan memicu onSnapshot secara instan (0ms) sebelum konfirmasi jaringan selesai.
  • 🔄 Delta Updates (docChanges()): Dukungan native pelacakan perubahan inkremental (added, modified, removed) pada QuerySnapshot untuk manipulasi elemen UI secara presisi tanpa mengunduh ulang seluruh dataset.
  • 🔒 Concurrency Control & Transactions (runTransaction): Transaksi dua arah (Read-Before-Write) atomik dengan kontrol konkurensi (Optimistic Locking & Automatic Retry) untuk mencegah race conditions pada pemotongan stok, kuota, atau transaksi finansial.
  • 📦 Offline-First & Auto-Sync: Sinkronisasi state lokal secara otomatis menggunakan IndexedDB. Data tetap tersimpan di browser jika koneksi terputus dan akan disinkronkan ke server secara otomatis saat kembali online.
  • 🔥 Modular Firestore API & TypeScript Generics: Desain API modular modern mirip Firebase SDK (v9+) dengan dukungan penuh parameter tipe generik (TypeScript Generics) untuk menjamin tipe data yang aman (type-safe) secara end-to-end.
  • 🔑 Secure Auth & Passwordless OTP: Dukungan penuh registrasi, login email/sandi, serta OTP instan via SMTP yang aman.
  • 📂 File Storage Integration: Unggah aset media dan file blob ke cloud storage dengan satu perintah.

📦 Instalasi

Instal package melalui npm atau yarn:

npm install nexabase-console
# atau
yarn add nexabase-console

🛠️ Cara Penggunaan & Contoh Kode

1. Inisialisasi Aplikasi

import { initializeApp, getFirestore } from 'nexabase-console';

const app = initializeApp({
  projectId: 'PROYEK_NEXABASE_ID_ANDA',
  apiKey: 'NEXABASE_API_KEY_ANDA' // Opsional, default endpoint mengarah ke https://db.nexabase.id
});

const db = getFirestore(app);

🛡️ Keamanan & Autentikasi Ganda (API Key & Sesi)

Untuk mendukung arsitektur server-side proxy atau direct API key yang sangat fleksibel, SDK secara otomatis mengirimkan token Anda dalam dua format header sekaligus:

  • Authorization: Bearer <token>: Digunakan untuk validasi token JWT sesi user.
  • x-api-key: <api_key>: Digunakan untuk otentikasi aman tanpa sesi menggunakan API Key proyek.

Hal ini mencegah kegagalan otentikasi (Error 403 Forbidden: Please login) saat memanggil metode di server menggunakan API Key proyek.

⚡ Sinkronisasi Offline & Database-Priority Engine (IndexedDB Cache)

NexaBase SDK mengimplementasikan manajemen cache tangguh yang serupa dengan Firebase untuk menjamin keandalan aplikasi saat jaringan tidak stabil:

  1. Prioritas Database Utama (network-first secara default): SDK memprioritaskan pengambilan data dari database remote server untuk menjamin kesegaran data (data freshness).
  2. Fast-Fail Network Timeout: Setiap permintaan database remote memiliki batas waktu (timeout) selama 6 detik. Jika jaringan sangat lambat (lie-fi) atau offline, SDK akan gagal cepat dan mengalihkan pembacaan ke IndexedDB local cache secara transparan tanpa menghentikan aplikasi.
  3. Pembaruan Optimistik Instan: Mutasi data (setDoc, patchDoc, deleteDoc, writeBatch) langsung ditulis ke IndexedDB secara optimistik. Semua listener snapshot (onSnapshot) akan menerima perubahan secara instan agar UI terasa sangat responsif (snappy).
  4. Heartbeat Polling Outbox (Setiap 10 Detik): Di samping mendengarkan event transisi jaringan online, SDK menjalankan polling latar belakang setiap 10 detik. Jika koneksi terdeteksi pulih, SDK akan mem-flush antrean mutasi offline secara berurutan (FIFO).
  5. Deduplikasi & Proteksi Kemacetan Antrean: SDK menggunakan kunci idempotensi (X-Idempotency-Key) untuk mencegah tulisan ganda. Selain itu, jika server membalas dengan kesalahan definitif sisi klien (seperti 400 Bad Request atau 403 Forbidden), SDK akan secara otomatis membuang job cacat tersebut dari antrean untuk mencegah antrean macet selamanya.

2. Firestore-like Modular API (NoSQL)

Menulis Data Baru (Set Doc)

import { doc, setDoc } from 'nexabase-console';

const main = async () => {
  const profileRef = doc(db, 'users', 'budi_santoso');
  const res = await setDoc(profileRef, {
    name: 'Budi Santoso',
    email: '[email protected]',
    age: 28,
    hobbies: ['Coding', 'Cycling']
  });
  
  console.log("Data berhasil disimpan:", res);
};

main();

Memperbarui Sebagian Data (Update Doc)

import { doc, updateDoc } from 'nexabase-console';

const editData = async () => {
  const profileRef = doc(db, 'users', 'budi_santoso');
  await updateDoc(profileRef, {
    age: 29 // Hanya memperbarui field age
  });
};

Membaca Satu Dokumen (Get Doc)

import { doc, getDoc } from 'nexabase-console';

const readData = async () => {
  const profileRef = doc(db, 'users', 'budi_santoso');
  const snapshot = await getDoc(profileRef);
  
  if (snapshot.exists()) {
    console.log("Isi data:", snapshot.data());
  } else {
    console.log("Dokumen tidak ditemukan.");
  }
};

Mendengarkan Perubahan Data secara Real-Time (onSnapshot & docChanges)

import { collection, onSnapshot } from 'nexabase-console';

const listenLiveChats = () => {
  const chatsRef = collection(db, 'chats');
  
  // onSnapshot menggunakan Anti-Flicker Engine (Deep Comparison)
  // - Langsung memancarkan cache lokal secara instan (0ms) tanpa layar putih
  // - Membandingkan hash data server sebelum re-render agar UI tidak berkedip
  const unsubscribe = onSnapshot(chatsRef, (querySnapshot) => {
    // 1. Ambil rincian pembaruan inkremental (Delta/Diff Updates)
    if (querySnapshot.docChanges) {
      const changes = querySnapshot.docChanges();
      changes.forEach((change) => {
        if (change.type === 'added') console.log("Pesan baru:", change.doc.data());
        if (change.type === 'modified') console.log("Pesan diedit:", change.doc.data());
        if (change.type === 'removed') console.log("Pesan dihapus:", change.doc.id);
      });
    }

    // 2. Iterasi seluruh koleksi
    querySnapshot.forEach((doc) => {
      console.log(doc.id, "=>", doc.data());
    });
  });
  
  // Panggil unsubscribe() untuk menghentikan pemantauan realtime
  // unsubscribe();
};

Agregasi Data & Hitung Dokumen (getCountFromServer / getAggregateFromServer)

Mendukung fungsi agregasi server 1:1 seperti Firebase SDK: getCountFromServer(), getAggregateFromServer(), count(), sum(), dan average().

import { 
  collection, 
  query, 
  where, 
  getCountFromServer, 
  getAggregateFromServer, 
  count, 
  sum, 
  average 
} from 'nexabase-console';

// 1. Menghitung total dokumen (getCountFromServer)
const productsRef = collection(db, 'products');
const qAvailable = query(productsRef, where('status', '==', 'active'));

const countSnapshot = await getCountFromServer(qAvailable);
console.log("Total produk aktif:", countSnapshot.data().count);

// 2. Agregasi multi-field (getAggregateFromServer)
const orderStats = await getAggregateFromServer(collection(db, 'orders'), {
  totalOrders: count(),
  totalRevenue: sum('totalAmount'),
  avgOrderValue: average('totalAmount')
});

console.log("Jumlah order:", orderStats.data().totalOrders);
console.log("Total pendapatan:", orderStats.data().totalRevenue);
console.log("Rata-rata transaksi:", orderStats.data().avgOrderValue);

Menggunakan Atomic Write Batch (Untuk Upload File / Excel Massal)

Jika Anda mengunggah data sekaligus dalam jumlah besar dari file (misal: import 500 resi dari Excel), hindari memanggil setDoc satu per satu di dalam looping. Gunakan fitur writeBatch yang membundel seluruh operasi Anda dalam satu pengiriman jaringan (hingga 500 operasi per eksekusi).

Catatan: Jika alur kerjanya adalah kasir/admin melakukan scan barcode satu-per-satu lalu menekan enter, maka Anda TIDAK PERLU menggunakan writeBatch. Menyimpan data satu-per-satu (setDoc / addDoc) setiap kali dienter adalah cara yang paling benar dan normal untuk kebutuhan realtime. Database dapat dengan mudah menangani 500 scan yang terjadi secara bertahap sepanjang hari.

import { doc, writeBatch } from 'nexabase-console';

const executeBulkUpload = async (listResi) => {
  const batch = writeBatch(db);
  
  // ListResi adalah array berisi objek resi. Maksimal 500 per batch.
  listResi.forEach((resi) => {
    // Referensi dokumen
    const docRef = doc(db, 'resi', resi.nomor_resi);
    batch.set(docRef, resi);
  });
  
  // Eksekusi semua secara atomik (bersamaan dalam 1 request)
  const result = await batch.commit();
  console.log(`Berhasil mengunggah ${listResi.length} resi secara massal.`);
};

Menggunakan Transactions (runTransaction) — Concurrency Control

import { doc, runTransaction } from 'nexabase-console';

async function potongStokAman(productId, variantId, qtyBeli) {
  const productRef = doc(db, 'products', productId);

  try {
    const hasil = await runTransaction(db, async (transaction) => {
      // 1. Baca dokumen di dalam transaksi (Read)
      const productSnap = await transaction.get(productRef);
      if (!productSnap.exists()) {
        throw new Error("Produk tidak ditemukan!");
      }

      const productData = productSnap.data();
      const variantIndex = productData.variants?.findIndex((v) => v.id === variantId);
      if (variantIndex === -1 || variantIndex === undefined) {
        throw new Error("Varian produk tidak ditemukan!");
      }

      const variant = productData.variants[variantIndex];
      const stokSaatIni = variant.stock;

      // 2. Validasi stok sebelum dipotong
      if (stokSaatIni < qtyBeli) {
        throw new Error(`Stok tidak mencukupi! Tersedia: ${stokSaatIni}, Diminta: ${qtyBeli}`);
      }

      // 3. Kalkulasi data baru
      const updatedVariants = [...productData.variants];
      updatedVariants[variantIndex] = {
        ...variant,
        stock: stokSaatIni - qtyBeli
      };

      // 4. Tulis perubahan di dalam transaksi (Write)
      transaction.update(productRef, {
        variants: updatedVariants,
        updatedAt: new Date().toISOString()
      });

      return { success: true, sisaStok: stokSaatIni - qtyBeli };
    });

    console.log("Transaksi Berhasil!", hasil);
  } catch (error) {
    console.error("Transaksi Gagal / Conflict:", error.message);
  }
}

3. Autentikasi Pengguna & OTP Tanpa Sandi (SDK v2.0.0)

Inisialisasi Auth & Realtime State Listener

import { getAuth, NexaAuthError } from 'nexabase-console';

const auth = getAuth(app);

// Realtime Listener & Sync Sesi Multi-Tab via StorageEvent
const unsubscribe = auth.onAuthStateChanged((user) => {
  if (user) {
    console.log("User terautentikasi:", user.uid, "| Email:", user.email);
  } else {
    console.log("User ter-logout / belum login");
  }
});

Pendaftaran & Login Email/Password

// 1. Registrasi Akun Baru
const register = async () => {
  try {
    const session = await auth.createUserWithEmailAndPassword(
      '[email protected]', 
      'Password123!', 
      'Budi Santoso'
    );
    console.log("Registrasi Berhasil! UID:", session.user.uid);
  } catch (err) {
    if (err instanceof NexaAuthError && err.code === 'auth/email-already-in-use') {
      console.error("Email sudah terdaftar.");
    }
  }
};

// 2. Login User (Dukungan Automatic Single-Flight Token Refresh)
const login = async () => {
  try {
    const session = await auth.signInWithEmailAndPassword(
      '[email protected]', 
      'Password123!'
    );
    console.log("Access Token JWT:", session.accessToken);
    console.log("Refresh Token:", session.refreshToken);
  } catch (err) {
    if (err instanceof NexaAuthError && err.code === 'auth/invalid-credential') {
      console.error("Email atau password salah.");
    }
  }
};

Login Passwordless dengan OTP (Email 6-Digit)

// 1. Kirim OTP Ke Email (Berlaku 5 Menit, Hash Single-Use)
const sendMyOtp = async () => {
  const res = await auth.sendOtp('[email protected]');
  console.log("Kode OTP berhasil terkirim:", res.message);
};

// 2. Verifikasi OTP dari Input Pengguna
const verifyMyOtp = async () => {
  try {
    const otpCode = '123456'; // Kode 6 digit yang dikirim ke email
    const session = await auth.signInWithOtp('[email protected]', otpCode);
    console.log("Login OTP Berhasil! Welcome:", session.user.email);
  } catch (err) {
    if (err instanceof NexaAuthError) {
      if (err.code === 'auth/invalid-otp') console.error("OTP tidak valid.");
      if (err.code === 'auth/expired-otp') console.error("OTP kedaluwarsa.");
      if (err.code === 'auth/too-many-otp-attempts') console.error("Terlalu banyak percobaan.");
    }
  }
};

Mengambil ID Token untuk Request API / Server Verification

// Mengambil token JWT (dengan auto-refresh jika hampir expired)
const idToken = await auth.getIdToken(/* forceRefresh */ false);

// Mengambil rincian klaim token (exp, authTime, claims)
const tokenResult = await auth.getIdTokenResult();
console.log("Token Kedaluwarsa:", tokenResult.expirationTime);

Update Profil, Reset Password & Sign Out

// Update Profil
await auth.updateProfile({ name: 'Budi Santoso, M.T.', photoURL: 'https://example.com/photo.jpg' });

// Reset Password Email
await auth.sendPasswordResetEmail('[email protected]');

// Revoke All Sessions
await auth.revokeAllSessions();

// === Opsi Logout Akun (Sign Out) ===
// 1. Method Instance (Rekomendasi)
await auth.signOut();

// 2. Fungsi Standar Modular
import { signOut } from 'nexabase-console';
await signOut(auth);

// 3. Namespace Helper
import { NexabaseAuth } from 'nexabase-console';
await NexabaseAuth.signOut(auth);

// 4. Shortcut dari objek App
await app.signOut();

4. File Storage API

const uploadImage = async (fileBlob) => {
  const storageRef = app.storage().ref('avatars/andi.jpg');
  const result = await storageRef.put(fileBlob);
  
  console.log("Akses File URL Publik Anda:", result.url);
};

📂 Penanganan Tipe Konten Dinamis (Form Data Boundary)

Unggahan file menggunakan format multipart standard yang dibungkus dalam objek FormData. SDK ini secara otomatis mendeteksi payload FormData dan membebaskan header Content-Type bawaan agar browser dapat secara dinamis menetapkan tipe konten yang menyertakan kode batas unik (multipart boundary).

Ini menghilangkan bug berkas kosong ({}) yang disebabkan oleh tumpang tindihnya header application/json di Axios.


5. Keamanan Tipe TypeScript (Generics) & Kueri Lanjutan

Dukungan TypeScript Generics

Kini Anda bisa mendefinisikan tipe data struktur dokumen Anda agar penulisan dan pembacaan data sepenuhnya aman (Type-safe).

import { collection, doc, getDoc, getDocs } from 'nexabase-console';

interface Product {
  name: string;
  price: number;
  stock: number;
  tags: string[];
}

// 1. Definisikan tipe koleksi
const productsCol = collection<Product>(db, 'products');

// 2. Definisikan tipe referensi dokumen
const productRef = doc<Product>(db, 'products', 'prod_a');

// 3. Baca data dengan Autocomplete & Type Checking penuh
const snapshot = await getDoc(productRef);
if (snapshot.exists()) {
  const data = snapshot.data(); // Tipe data otomatis terdeteksi sebagai 'Product'
  console.log(data.name);  // Aman! Autocomplete tersedia
  console.log(data.price); // Aman!
}

Kompatibilitas QuerySnapshot (docChanges())

Bagi Anda yang bermigrasi dari Firebase, objek QuerySnapshot yang dikembalikan oleh getDocs atau onSnapshot kini mendukung metode .docChanges() secara native:

const snapshot = await getDocs(productsCol);
const changes = snapshot.docChanges(); // Mengembalikan array perubahan dokumen

Filter Offline Lengkap (Advanced Querying Operators)

Mekanisme kueri offline pada SDK NexaBase kini mendukung operator Firestore tingkat lanjut secara penuh demi keandalan luar biasa bahkan saat koneksi terputus:

  • Operator dasar: ==, !=, >, <, >=, <=
  • Operator array & keanggotaan: in, not-in, array-contains, array-contains-any

🗄️ Dukungan Sinkronisasi Offline (IndexedDB)

NexaBase JS SDK dikembangkan dengan arsitektur Offline-First.

  1. Optimistic Rendering: Jika perangkat offline, SDK akan langsung mengupdate cache IndexedDB lokal dan men-trigger callback subscriber onSnapshot agar UI pengguna langsung merespons secara instan.
  2. Background Queue: Setiap perubahan mutasi (setDoc, updateDoc, deleteDoc, writeBatch) saat offline disimpan secara aman di IndexedDB.
  3. Automatic Resync: Saat koneksi internet mendeteksi status online, antrean modifikasi akan dikirimkan kembali secara beruntun ke Server cloud NexaBase secara otomatis tanpa intervensi pengguna.

📄 Lisensi

Proyek ini dilisensikan di bawah Lisensi MIT. Bebas digunakan untuk keperluan pribadi, komersial, maupun edukasi.