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

@renpwn/alquran.js

v0.14.11

Published

Node.js library untuk mengakses Al-Qur'an dengan database SQLite + FTS5. Dilengkapi teks Arab, terjemahan, tafsir 6 sumber, transliterasi, dan audio. Ideal untuk bot WhatsApp/Telegram, aplikasi mobile, dan website Islamic.

Readme

@renpwn/alquran.js - Complete Al-Qur'an Library for Node.js

License: MIT Node.js npm version Database Tafsir Downloads

📖 Table of Contents

🎯 Filosofi Proyek

"Sehari baca 100 pesan bisa, tapi 1 ayat pun jarang."

Proyek ini lahir dari kesadaran bahwa di era digital yang penuh dengan pesan dan notifikasi, kita mudah teralihkan dari hal-hal yang penting. Library ini hadir untuk mengembalikan fokus kita kepada Al-Qur'an, dengan menyediakan akses mudah ke ayat-ayat dan tafsirnya melalui kode program.

Misi: Membantu developer Muslim membangun aplikasi yang mengingatkan pada kebaikan, dengan prinsip:

  • 1 Hari 25 Ayat dan Tafsir atau Hadis (random) - Konsumsi Al-Qur'an yang terukur
  • Integrasi mudah - Cukup beberapa baris kode
  • Sumber terpercaya - Data dari ulama dan institusi resmi

✨ Fitur Utama

  • Database SQLite + FTS5 - Pencarian super cepat
  • 6 Sumber Tafsir - Kemenag, Ibnu Katsir, Jalalain, Quraish Shihab, Saadi, dll
  • Teks Arab Utsmani - Standar Madinah
  • Terjemahan Kemenag - Resmi Indonesia
  • Transliterasi Latin - Latinisasi akurat
  • Audio Murottal - Syaikh Alafasy 128kbps
  • Fuzzy Matching - Auto-correct otomatis
  • Full-Text Search - Cari dalam Arab, Latin, dan terjemahan
  • Random System - Sistem ayat random harian
  • Multi-format Query - Dukungan berbagai format input

📦 Instalasi

# Install package
npm install @renpwn/alquran.js

# Atau dengan yarn
yarn add @renpwn/alquran.js

# Atau dengan pnpm
pnpm add @renpwn/alquran.js

🚀 Mulai Cepat

// 1. Import library
import alquranHandler from '@renpwn/alquran.js';

// 2. Query dengan berbagai format
const ayatKursi = await alquranHandler('2:255');
const yasin1_10 = await alquranHandler('yasin 1-10');
const randomAyat = await alquranHandler('');
const daftarSurah = await alquranHandler('list');

// 3. Tampilkan hasil
console.log('Ayat Kursi:', ayatKursi.ayahs[0].arab);
console.log('Total ayat Yasin:', yasin1_10.totalAyat);
console.log('Surah random:', randomAyat.surah);
console.log('Jumlah surah:', daftarSurah.length);

Hasil Format:

{
  mode: 'default',
  surahNumber: 2,
  surah: "Al Baqarah",
  arti: "Sapi Betina",
  range: "255",
  totalAyat: 286,
  tafsir: "kemenag",
  ayahs: [
    {
      ayah: 255,
      arab: "اللَّهُ لَا إِلَٰهَ إِلَّا هُوَ الْحَيُّ الْقَيُّومُ...",
      transliterasi: "Allāhu lā ilāha illā huw, al-ḥayyul-qayyụm...",
      id: "Allah, tidak ada Tuhan selain Dia. Yang Mahahidup, Yang Mahaberdiri Sendiri...",
      en: "Allah! There is no god ˹worthy of worship˺ except Him...",
      tafsir: "Ayat Kursi adalah ayat teragung dalam Al-Qur'an...",
      audioUrl: "https://cdn.islamic.network/quran/audio/128/ar.alafasy/256.mp3"
    }
  ]
}

🏗️ Arsitektur

@renpwn/alquran.js/
├── 📁 node_modules/
├── 📁 db/                  # Database SQLite (otomatis dibuat)
│   └── quran.db            # File database utama
├── 📁 json/                # JSON file (otomatis dibuat)
│   └── Alquran_1.json       # File Json
├── 📁 json_min/             # JSON_min file (otomatis dibuat)
│   └── Alquran_1.min.json    # File Json min
├── index.js                📦 MAIN EXPORT - Import ini saja!
├── setting.db.js           🔧 Database connector & utilities
├── 📁 mt/                  ⚙️ Internal modules
│   ├── db.js              🗃️ Database initializer
│   └── quran.js           🌐 Web scraper 3-mode
├── 📁 examples/            💡 Contoh penggunaan
│   ├── test_lib.js        🧪 Test script
│   └── bot_whatsapp.js    🤖 Contoh bot
├── package.json           📄 Package configuration
└── README.md              📖 Documentation

📖 API Reference Lengkap

Fungsi Utama

import alquranHandler from '@renpwn/alquran.js';

const result = await alquranHandler(input, options);

Parameter Input

| Format | Contoh | Deskripsi | Output | |--------|--------|-----------|--------| | surah:ayat | "2:255" | Ayat spesifik | Surah 2 ayat 255 | | surah | "yasin" | Seluruh surah | Semua ayat Yasin | | surah start-end | "al baqarah 1-10" | Multiple ayat | Ayat 1-10 Al-Baqarah | | pencarian | "dengan nama allah" | Full-text search | Hasil pencarian | | list | "list" | Metadata surah | 114 surah | | kosong | "" | Random ayat | Ayat random |

Options Object

const options = {
  tafsir: 'kemenag',      // Pilih tafsir (default: random)
  // Pilihan: 'kemenag', 'kemenag_ringkas', 'ibnu_katsir', 
  //         'jalalain', 'quraish_shihab', 'saadi'
};

Return Object

{
  // Metadata
  mode: 'default' | 'search' | 'list',
  surahNumber: 2,
  surah: "Al Baqarah",
  arti: "Sapi Betina",
  range: "255",
  totalAyat: 286,
  tafsir: "kemenag",
  
  // Data Ayat
  ayahs: [
    {
      ayah: 255,
      arab: "اللَّهُ لَا إِلَٰهَ إِلَّا هُوَ...",
      transliterasi: "Allāhu lā ilāha illā huw...",
      id: "Allah, tidak ada Tuhan selain Dia...",
      en: "Allah! There is no god except Him...",
      tafsir: "Tafsir lengkap...",
      audioUrl: "https://cdn.islamic.network/.../256.mp3",
      noAudio: 256      // Global audio index
    }
  ],
  
  // Debug info (hanya jika fuzzy matching)
  debug: {
    input: "albaqarah",
    bestMatch: "albaqarah",
    rating: 0.95,
    top5: [...]
  }
}

🔧 Setup & Konfigurasi

Inisialisasi Database

Database akan otomatis dibuat saat pertama kali digunakan. Untuk setup manual:

# 1. Inisialisasi struktur database
npm run init-db

# 2. Scrape semua data dari web (114 surah)
npm run scrape:all

# 3. Migrasi JSON ke database (jika ada)
npm run migrate:json

# 4. Rebuild full-text search index
npm run rebuild-fts

Scraper CLI (SELF MAINTENANCE)

# Gunakan scraper melalui npx
npx alquran-scrape -m 1 -b -c 5

# Mode yang tersedia:
# -m 1 : Web scraping → JSON & Database
# -m 2 : Web scraping → JSON saja
# -m 3 : JSON → Database migrasi

# Opsi tambahan:
# -S : Surah spesifik (contoh: -S 36 untuk Yasin)
# -s : Start dari surah (contoh: -s 41)
# -b : Batch mode (semua surah)
# -r : Resume (skip data yang sudah ada)
# -c : Concurrent requests (default: 5)

NPM Scripts

{
  "scripts": {
    "start": "node index.js",
    "scrape:all": "node mt/quran.js -m 1 -b -c 5",
    "scrape:surah": "node mt/quran.js -m 1 -S",
    "migrate:json": "node mt/quran.js -m 3 -b",
    "test": "node examples/test_lib.js",
    "init-db": "node mt/db.js",
    "rebuild-fts": "node -e \"import('./index.js').then(m => m.default('', {rebuildFTS: true}))\""
  }
}

🗃️ Struktur Database

Tabel Utama

-- 1. Metadata surah
CREATE TABLE surahs (
  no INTEGER PRIMARY KEY,    -- 1-114
  name TEXT NOT NULL,        -- "Al Fatihah"
  ar TEXT,                   -- "الفاتحة"
  en TEXT,                   -- "The Opening"
  id TEXT,                   -- "Pembuka"
  ayat INTEGER NOT NULL,     -- Jumlah ayat
  place TEXT,                -- 'Meccan' atau 'Medinan'
  type TEXT                  -- 'Makkiyah' atau 'Madaniyah'
);

-- 2. Ayat dengan teks Arab
CREATE TABLE ayahs (
  id INTEGER PRIMARY KEY,
  surah_id INTEGER REFERENCES surahs(no),
  ayat INTEGER,              -- Nomor ayat dalam surah
  text_ar TEXT,              -- Teks Arab Utsmani
  text_latin TEXT,           -- Transliterasi Latin
  juz INTEGER,               -- Nomor juz
  page INTEGER               -- Nomor halaman mushaf
);

-- 3. Terjemahan multi-bahasa
CREATE TABLE translations (
  id INTEGER PRIMARY KEY,
  surah_id INTEGER,
  ayah_id INTEGER,
  lang TEXT,                 -- 'id', 'en', dll
  text TEXT,
  translator TEXT            -- Nama penerjemah
);

-- 4. Tafsir dari 6 sumber
CREATE TABLE tafsirs (
  id INTEGER PRIMARY KEY,
  surah_id INTEGER,
  ayah_id INTEGER,
  kitab TEXT,                -- 'kemenag', 'ibnu_katsir', dll
  text TEXT,
  author TEXT,               -- Nama penafsir
  source TEXT                -- Sumber asli
);

Full-Text Search Tables (FTS5)

-- Virtual tables untuk pencarian instan
CREATE VIRTUAL TABLE surahs_fts USING fts5(name, ar, en, id);
CREATE VIRTUAL TABLE ayahs_fts USING fts5(text_ar, text_latin);
CREATE VIRTUAL TABLE translations_fts USING fts5(text);
CREATE VIRTUAL TABLE tafsirs_fts USING fts5(text);

🔍 Advanced Usage

1. Akses Database Langsung

import { openDB, closeDB, query, execute } from '@renpwn/alquran.js/database';

// Buka koneksi
const db = openDB();

// Query manual
const surahs = await db.all('SELECT * FROM surahs ORDER BY no');
const ayat = await db.get(
  'SELECT * FROM ayahs WHERE surah_id = ? AND ayat = ?',
  [2, 255]
);

// Gunakan helper functions
const results = await query('SELECT * FROM surahs WHERE no < ?', [10]);
await execute('UPDATE cache SET value = ? WHERE key = ?', ['data', 'key']);

// Jangan lupa tutup koneksi
await closeDB();

2. Sistem "1 Hari 25 Ayat"

// Implementasi lengkap sistem harian
class DailyQuranSystem {
  constructor() {
    this.dailyGoal = 25;
    this.progress = new Map();
  }

  async getDailyAyat(userId, date = new Date()) {
    const dateKey = date.toISOString().split('T')[0];
    
    if (!this.progress.has(userId)) {
      this.progress.set(userId, {});
    }
    
    const userProgress = this.progress.get(userId);
    
    if (!userProgress[dateKey]) {
      // Generate 25 ayat random untuk hari ini
      userProgress[dateKey] = await this.generateDailyAyat();
    }
    
    return {
      date: dateKey,
      ayahs: userProgress[dateKey],
      completed: userProgress[dateKey].length,
      total: this.dailyGoal
    };
  }

  async generateDailyAyat() {
    const ayahs = [];
    
    for (let i = 0; i < 25; i++) {
      // Random surah dan ayat
      const surahNum = Math.floor(Math.random() * 114) + 1;
      const surahData = await alquranHandler(`${surahNum}`);
      const ayatNum = Math.floor(Math.random() * surahData.totalAyat) + 1;
      
      // Ambil ayat spesifik
      const ayatData = await alquranHandler(`${surahNum}:${ayatNum}`, {
        tafsir: this.getRandomTafsir()
      });
      
      ayahs.push({
        ...ayatData.ayahs[0],
        order: i + 1,
        surah: surahData.surah,
        surahNumber: surahNum
      });
    }
    
    return ayahs;
  }

  getRandomTafsir() {
    const tafsirs = ['kemenag', 'ibnu_katsir', 'jalalain', 'quraish_shihab', 'saadi'];
    return tafsirs[Math.floor(Math.random() * tafsirs.length)];
  }
}

3. Batch Processing dengan Progress

import { EventEmitter } from 'events';

class QuranBatchProcessor extends EventEmitter {
  constructor() {
    super();
    this.batchSize = 10;
  }

  async processQueries(queries) {
    const results = [];
    const total = queries.length;
    
    for (let i = 0; i < total; i += this.batchSize) {
      const batch = queries.slice(i, i + this.batchSize);
      const batchPromises = batch.map(async (query, index) => {
        try {
          const result = await alquranHandler(query);
          return { success: true, data: result };
        } catch (error) {
          return { success: false, error: error.message };
        }
      });
      
      const batchResults = await Promise.all(batchPromises);
      results.push(...batchResults);
      
      // Emit progress event
      this.emit('progress', {
        processed: Math.min(i + this.batchSize, total),
        total,
        percentage: ((i + this.batchSize) / total * 100).toFixed(2)
      });
    }
    
    return results;
  }
}

// Penggunaan
const processor = new QuranBatchProcessor();
processor.on('progress', (stats) => {
  console.log(`Progress: ${stats.processed}/${stats.total} (${stats.percentage}%)`);
});

const queries = ['2:255', 'yasin 1-10', 'al kahfi', 'list', ''];
const results = await processor.processQueries(queries);

4. Custom Tafsir Aggregator

async function getMultiTafsir(surah, ayat) {
  const tafsirSources = [
    { key: 'kemenag', name: 'Tafsir Kemenag' },
    { key: 'ibnu_katsir', name: 'Tafsir Ibnu Katsir' },
    { key: 'jalalain', name: 'Tafsir Jalalain' },
    { key: 'quraish_shihab', name: 'Tafsir Quraish Shihab' },
    { key: 'saadi', name: 'Tafsir Saadi' }
  ];

  const results = [];
  
  for (const source of tafsirSources) {
    const result = await alquranHandler(`${surah}:${ayat}`, {
      tafsir: source.key,
      min: true
    });
    
    if (result.ayahs[0].tafsir) {
      results.push({
        source: source.name,
        tafsir: result.ayahs[0].tafsir,
        length: result.ayahs[0].tafsir.length
      });
    }
    
    // Delay antar request
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  // Sort by length (shortest first)
  results.sort((a, b) => a.length - b.length);
  
  return results;
}

// Contoh penggunaan
const multiTafsir = await getMultiTafsir(2, 255);
multiTafsir.forEach(t => {
  console.log(`\n=== ${t.source} ===`);
  console.log(t.tafsir.substring(0, 200) + '...');
});

5. Audio Streaming & Download

import fs from 'fs';
import https from 'https';
import { openDB } from '@renpwn/alquran.js/database';

class QuranAudioManager {
  constructor() {
    this.db = openDB();
    this.audioBaseUrl = 'https://cdn.islamic.network/quran/audio/128/ar.alafasy';
  }

  async getAudioUrl(surah, ayat) {
    // Hitung global audio index
    const totalAyatBefore = await this.getTotalAyatBefore(surah);
    const globalIndex = totalAyatBefore + ayat;
    
    return `${this.audioBaseUrl}/${globalIndex}.mp3`;
  }

  async getTotalAyatBefore(surah) {
    const result = await this.db.get(
      'SELECT SUM(ayat) as total FROM surahs WHERE no < ?',
      [surah]
    );
    return result.total || 0;
  }

  async downloadAudio(surah, ayat, outputPath) {
    const audioUrl = await this.getAudioUrl(surah, ayat);
    
    return new Promise((resolve, reject) => {
      https.get(audioUrl, (response) => {
        if (response.statusCode === 200) {
          const fileStream = fs.createWriteStream(outputPath);
          response.pipe(fileStream);
          fileStream.on('finish', () => {
            fileStream.close();
            resolve(outputPath);
          });
        } else {
          reject(new Error(`Failed to download: ${response.statusCode}`));
        }
      }).on('error', reject);
    });
  }

  async streamAudio(surah, ayat) {
    const audioUrl = await this.getAudioUrl(surah, ayat);
    return fetch(audioUrl).then(res => res.body);
  }
}

// Contoh penggunaan
const audioManager = new QuranAudioManager();

// Download audio
await audioManager.downloadAudio(2, 255, 'ayat-kursi.mp3');

// Dapatkan URL untuk streaming
const audioUrl = await audioManager.getAudioUrl(36, 1);
console.log('Audio URL:', audioUrl);

📊 Sumber Data Terpercaya

Al-Qur'an & Tafsir

| Komponen | Sumber | Kualitas | |----------|--------|----------| | Teks Arab Utsmani | LiteQuran.net | Standar Madinah | | Terjemahan Kemenag | Qur'an Kemenag RI | Resmi Indonesia | | Terjemahan Inggris | Sahih International | Terjemahan akurat | | Transliterasi | LiteQuran.net | Latinisasi akurat | | Tafsir Kemenag | Qurano.com | Lengkap & ringkas | | Tafsir Ibnu Katsir | Qurano.com | Klasik rujukan | | Tafsir Jalalain | Qurano.com | Ringkas padat | | Tafsir Quraish Shihab | Qurano.com | Kontekstual modern | | Tafsir Saadi | Qurano.com | Penjelasan sederhana | | Audio Murottal | Islamic Network | Syaikh Alafasy 128kbps |

Murottal Qur'an dan Terjemahan

🎯 Use Cases

1. Bot WhatsApp/Telegram

// Contoh implementasi bot WhatsApp
import { Client, LocalAuth } from 'whatsapp-web.js';
import alquranHandler from '@renpwn/alquran.js';

class QuranBot {
  constructor() {
    this.client = new Client({
      authStrategy: new LocalAuth(),
      puppeteer: { headless: true }
    });
    
    this.setupEvents();
  }

  setupEvents() {
    this.client.on('qr', (qr) => {
      console.log('QR Code:', qr);
    });

    this.client.on('ready', () => {
      console.log('Bot is ready!');
    });

    this.client.on('message', async (message) => {
      if (message.body.startsWith('!quran')) {
        const query = message.body.replace('!quran', '').trim();
        await this.handleQuranQuery(message, query);
      }
    });
  }

  async handleQuranQuery(message, query) {
    try {
      const result = await alquranHandler(query || '');
      
      if (result.mode === 'list') {
        // Kirim daftar surah
        const surahList = result.map(s => `${s.no}. ${s.name} (${s.arti})`).join('\n');
        await message.reply(`*Daftar Surah:*\n\n${surahList}`);
      } else if (result.ayahs) {
        // Kirim ayat
        const ayat = result.ayahs[0];
        const response = `
*${result.surah} Ayat ${result.range}*

${ayat.arab}

*Transliterasi:*
${ayat.transliterasi}

*Terjemahan:*
${ayat.id}

*Tafsir ${result.tafsir}:*
${ayat.tafsir.substring(0, 200)}...

📖 *Audio:* ${ayat.audioUrl}
        `;
        
        await message.reply(response);
      }
    } catch (error) {
      await message.reply(`❌ Error: ${error.message}`);
    }
  }

  start() {
    this.client.initialize();
  }
}

// Jalankan bot
const bot = new QuranBot();
bot.start();

2. REST API dengan Express.js

import express from 'express';
import alquranHandler from '@renpwn/alquran.js';

const app = express();
const port = process.env.PORT || 3000;

// Middleware
app.use(express.json());
app.use(express.static('public'));

// Routes
app.get('/api/quran', async (req, res) => {
  try {
    const { query, tafsir, lang, min } = req.query;
    const result = await alquranHandler(query || '', {
      tafsir,
      lang,
      min: min === 'true'
    });
    res.json(result);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

app.get('/api/daily', async (req, res) => {
  try {
    // Generate 25 ayat random untuk hari ini
    const date = new Date();
    const seed = date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();
    
    const ayahs = [];
    for (let i = 0; i < 25; i++) {
      const randomQuery = ''; // Random ayat
      const result = await alquranHandler(randomQuery);
      ayahs.push(result.ayahs[0]);
    }
    
    res.json({
      date: date.toISOString().split('T')[0],
      seed,
      ayahs
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/search', async (req, res) => {
  try {
    const { q, limit = 10 } = req.query;
    if (!q) {
      return res.status(400).json({ error: 'Query parameter required' });
    }
    
    // Implementasi pencarian custom
    const result = await alquranHandler(q);
    res.json({
      query: q,
      results: result.ayahs.slice(0, limit),
      total: result.ayahs.length
    });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Web interface
app.get('/', (req, res) => {
  res.sendFile(process.cwd() + '/public/index.html');
});

app.listen(port, () => {
  console.log(`Quran API running on http://localhost:${port}`);
});

3. React Native App

// components/QuranReader.js
import React, { useState, useEffect } from 'react';
import { View, Text, ScrollView, TouchableOpacity } from 'react-native';
import alquranHandler from '@renpwn/alquran.js';

const QuranReader = () => {
  const [surah, setSurah] = useState(null);
  const [currentAyat, setCurrentAyat] = useState(1);
  const [tafsir, setTafsir] = useState('kemenag');

  useEffect(() => {
    loadSurah(1); // Load Al-Fatihah by default
  }, []);

  const loadSurah = async (surahNumber) => {
    try {
      const result = await alquranHandler(surahNumber.toString());
      setSurah(result);
    } catch (error) {
      console.error('Error loading surah:', error);
    }
  };

  const renderAyat = (ayat) => (
    <View key={ayat.ayah} style={styles.ayatContainer}>
      <Text style={styles.arabicText}>{ayat.arab}</Text>
      <Text style={styles.transliteration}>{ayat.transliterasi}</Text>
      <Text style={styles.translation}>{ayat.id}</Text>
      {ayat.tafsir && (
        <Text style={styles.tafsir}>Tafsir: {ayat.tafsir.substring(0, 150)}...</Text>
      )}
    </View>
  );

  if (!surah) {
    return <Text>Loading...</Text>;
  }

  return (
    <ScrollView style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.surahName}>{surah.surah}</Text>
        <Text style={styles.surahMeaning}>{surah.arti}</Text>
      </View>

      <View style={styles.controls}>
        <TouchableOpacity onPress={() => loadSurah(surah.surahNumber - 1)}>
          <Text>Previous Surah</Text>
        </TouchableOpacity>
        <Text>Surah {surah.surahNumber} of 114</Text>
        <TouchableOpacity onPress={() => loadSurah(surah.surahNumber + 1)}>
          <Text>Next Surah</Text>
        </TouchableOpacity>
      </View>

      {surah.ayahs.map(renderAyat)}
    </ScrollView>
  );
};

export default QuranReader;

4. E-Learning Platform

class QuranLearningPlatform {
  constructor(userId) {
    this.userId = userId;
    this.progress = this.loadProgress();
    this.levels = [
      { name: 'Pemula', target: 10 },
      { name: 'Menengah', target: 50 },
      { name: 'Lanjutan', target: 100 },
      { name: 'Ahli', target: 6236 }
    ];
  }

  async startDailySession() {
    const session = {
      date: new Date().toISOString(),
      ayahs: [],
      score: 0,
      completed: false
    };

    // Generate 25 random ayahs
    for (let i = 0; i < 25; i++) {
      const randomAyat = await alquranHandler('');
      session.ayahs.push({
        ...randomAyat.ayahs[0],
        question: this.generateQuestion(randomAyat.ayahs[0]),
        answered: false,
        correct: null
      });
    }

    this.currentSession = session;
    return session;
  }

  generateQuestion(ayat) {
    const questionTypes = [
      {
        type: 'translation',
        question: `Terjemahan dari ayat di atas adalah?`,
        options: [
          ayat.id,
          this.generateWrongTranslation(ayat.id),
          this.generateWrongTranslation(ayat.id),
          this.generateWrongTranslation(ayat.id)
        ]
      },
      {
        type: 'tafsir',
        question: `Makna dari ayat di atas adalah?`,
        options: [
          ayat.tafsir?.substring(0, 100) + '...',
          this.generateWrongTafsir(ayat.tafsir),
          this.generateWrongTafsir(ayat.tafsir),
          this.generateWrongTafsir(ayat.tafsir)
        ]
      }
    ];

    const type = questionTypes[Math.floor(Math.random() * questionTypes.length)];
    return {
      ...type,
      correctAnswer: 0,
      ayat: ayat.arab
    };
  }

  async submitAnswer(questionIndex, answerIndex) {
    if (!this.currentSession) return null;

    const question = this.currentSession.ayahs[questionIndex];
    const correct = answerIndex === question.question.correctAnswer;

    question.answered = true;
    question.correct = correct;

    if (correct) {
      this.currentSession.score += 10;
      this.progress.totalScore += 10;
      this.progress.correctAnswers++;
    } else {
      this.progress.wrongAnswers++;
    }

    this.saveProgress();

    return {
      correct,
      correctAnswer: question.question.correctAnswer,
      explanation: correct ? 'Jawaban benar!' : 'Jawaban salah, coba pelajari lagi.'
    };
  }

  getProgress() {
    const level = this.levels.find(l => this.progress.totalScore < l.target) || 
                  this.levels[this.levels.length - 1];
    
    return {
      userId: this.userId,
      level: level.name,
      score: this.progress.totalScore,
      nextLevel: level.target,
      progress: (this.progress.totalScore / level.target * 100).toFixed(2),
      stats: {
        correct: this.progress.correctAnswers,
        wrong: this.progress.wrongAnswers,
        accuracy: (this.progress.correctAnswers / 
                  (this.progress.correctAnswers + this.progress.wrongAnswers) * 100).toFixed(2)
      }
    };
  }
}

⚡ Performance

  • Query Response: < 50ms untuk kebanyakan operasi
  • FTS5 Search: < 100ms untuk 10k+ ayat
  • Memory Usage: ~5MB untuk database 50MB
  • Concurrent Users: Support 100+ dengan connection pooling
  • Cache Hit Rate: ~95% dengan proper caching

Optimization Tips

// 1. Implement caching
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes

async function cachedAlquran(query, options) {
  const cacheKey = `${query}:${JSON.stringify(options)}`;
  
  if (cache.has(cacheKey)) {
    const { timestamp, data } = cache.get(cacheKey);
    if (Date.now() - timestamp < CACHE_TTL) {
      return data;
    }
  }
  
  const data = await alquranHandler(query, options);
  cache.set(cacheKey, {
    timestamp: Date.now(),
    data
  });
  
  return data;
}

// 2. Connection pooling untuk database
import { Database } from 'sqlite3';
import { open } from 'sqlite';

const dbPromise = open({
  filename: './db/quran.db',
  driver: Database
});

// 3. Batch processing untuk multiple queries
async function batchProcess(queries) {
  const results = [];
  const batchSize = 5;
  
  for (let i = 0; i < queries.length; i += batchSize) {
    const batch = queries.slice(i, i + batchSize);
    const batchResults = await Promise.all(
      batch.map(q => alquranHandler(q))
    );
    results.push(...batchResults);
  }
  
  return results;
}

🚨 Error Handling

import alquranHandler from '@renpwn/alquran.js';

async function safeQuranQuery(query, options) {
  try {
    return await alquranHandler(query, options);
  } catch (error) {
    // Handle different error types
    if (error.message.includes('database')) {
      console.error('Database error:', error.message);
      // Try to reinitialize database
      await initializeDatabase();
      return await alquranHandler(query, options);
    } else if (error.message.includes('network')) {
      console.error('Network error:', error.message);
      // Return cached data if available
      return getCachedData(query);
    } else if (error.message.includes('invalid query')) {
      console.error('Invalid query:', query);
      // Try fuzzy matching
      return await alquranHandler('', options);
    } else {
      console.error('Unknown error:', error.message);
      throw error;
    }
  }
}

// Contoh error yang umum:
// 1. Database not initialized
// 2. Invalid query format
// 3. Surah/ayat not found
// 4. Network error (scraper)
// 5. File system error
// 6. Memory limit exceeded

// Graceful degradation
async function getAyatWithFallback(query) {
  const sources = [
    async () => await alquranHandler(query),
    async () => await fetchFromAPI(query),
    async () => await getFromLocalCache(query),
    () => getDefaultAyat()
  ];
  
  for (const source of sources) {
    try {
      const result = await source();
      if (result) return result;
    } catch (error) {
      console.warn(`Source failed: ${error.message}`);
    }
  }
  
  throw new Error('All sources failed');
}

🤝 Kontribusi

Kami menyambut kontribusi dari semua developer! Berikut cara berkontribusi:

Cara Kontribusi

  1. Fork repository
  2. Buat feature branch
git checkout -b feature/amazing-feature
  1. Commit changes
git commit -m 'Add some amazing feature'
  1. Push ke branch
git push origin feature/amazing-feature
  1. Buat Pull Request

Area yang Butuh Kontribusi

  • 🌐 Terjemahan bahasa lain (Urdu, French, Spanish, dll)
  • 📚 Sumber tafsir tambahan
  • 🧪 Unit tests & integration tests
  • ⚡ Performance optimization
  • 📱 Mobile app examples
  • 🔌 Plugin & extensions
  • 📖 Documentation improvement
  • 🐛 Bug fixes

Code Style

// Gunakan ES6+ features
// Jangan lupa error handling
// Dokumentasi untuk fungsi kompleks
// Test untuk fitur baru

Testing

# Run tests
npm test

# Lint code
npx eslint .

# Format code
npx prettier --write .

📄 License

MIT License

Copyright (c) 2024 Ardy Ren

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

🔗 Links & Support

Official Channels

Komunitas & Grup

Sosial Media & Sponsor

Support Development

# ⭐ Star repository di GitHub
# 📢 Share dengan developer Muslim lain
# 🐛 Report bugs dan issues
# 💡 Suggest new features
# 🔧 Submit pull requests

⭐ Pro Tip: Untuk aplikasi production, implementasikan sistem caching seperti Redis dan monitoring seperti New Relic untuk performa optimal!

// Contoh caching dengan Redis
import Redis from 'ioredis';
const redis = new Redis();

async function getWithRedisCache(query, options) {
  const key = `quran:${query}:${JSON.stringify(options)}`;
  
  // Try cache first
  const cached = await redis.get(key);
  if (cached) {
    return JSON.parse(cached);
  }
  
  // Get fresh data
  const data = await alquranHandler(query, options);
  
  // Cache for 1 hour
  await redis.setex(key, 3600, JSON.stringify(data));
  
  return data;
}

Selamat mengembangkan aplikasi yang mengingatkan pada kebaikan! 🚀


"Bacalah Kitab (Al-Qur'an) yang telah diwahyukan kepadamu (Muhammad) dan tegakkanlah salat. Sesungguhnya salat itu mencegah dari (perbuatan) keji dan mungkar. Dan (ketahuilah) mengingat Allah (salat) itu lebih besar (keutamaannya dari ibadah yang lain). Allah mengetahui apa yang kamu kerjakan." (QS. Al-Ankabut: 45)