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

@ma7moudsalama/falak-app

v1.0.2

Published

Production-ready Vue 3 boilerplate with Firebase, PrimeVue, Tailwind, i18n, Groq AI, Paymob & more

Readme

فَلَك · Falak App

Production-ready Vue 3 boilerplate with Firebase, PrimeVue, Tailwind CSS, i18n (Arabic + English), Groq AI, Paymob payments, offline IndexedDB sync, and AES encryption — all wired up and ready to build on.

npm version License: MIT


Quick Start

# Scaffold a new project
npx @ma7moudsalama/falak-app create my-project

# Or install globally
npm i -g @ma7moudsalama/falak-app
falak create my-project

# Then
cd my-project
cp .env.example .env     # fill in your keys
npm run dev

What's Inside

| Layer | Package | Status | |---|---|---| | Framework | Vue 3 + Vite | ✅ Configured | | UI Library | PrimeVue 4 (Aura theme) | ✅ Configured | | Styling | Tailwind CSS 3 | ✅ Configured | | State | Pinia | ✅ Configured | | Routing | Vue Router 4 | ✅ Configured + guards | | Translation | Vue I18n 10 (EN + AR/RTL) | ✅ Configured | | Auth | Firebase Auth (Email, Google, Facebook) | ✅ Composable ready | | Database | Firebase Realtime DB | ✅ Composable ready | | Offline | IndexedDB via idb | ✅ Auto-sync | | Encryption | AES-256 via crypto-js | ✅ Composable ready | | AI | Groq SDK (LLaMA 3.3) | ✅ Composable ready | | Payments | Paymob | ✅ Composable + subscriptions |


Project Structure

src/
├── assets/
│   └── main.css              ← Tailwind + custom utilities
├── components/
│   └── layout/
│       └── AppLayout.vue     ← Sidebar + topbar layout shell
├── composables/
│   ├── useAuth.js            ← Firebase auth + roles + sessions
│   ├── useDatabase.js        ← RTDB + IndexedDB offline manager
│   ├── useCrypto.js          ← AES encrypt/decrypt
│   ├── useGroq.js            ← Groq AI chat + streaming
│   └── usePaymob.js          ← Paymob payments + subscriptions
├── firebase/
│   └── index.js              ← Firebase app init + all services
├── i18n/
│   ├── index.js              ← Vue I18n setup + locale switcher
│   └── locales/
│       ├── en.json
│       └── ar.json
├── router/
│   └── index.js              ← Routes + auth/role guards
├── stores/
│   └── auth.js               ← Pinia wrapper for useAuth
├── views/
│   ├── auth/
│   │   ├── LoginView.vue
│   │   ├── RegisterView.vue
│   │   └── ForgotView.vue
│   ├── HomeView.vue
│   ├── DashboardView.vue     ← Live data + AI + subscription demo
│   ├── ProfileView.vue
│   ├── AdminView.vue
│   └── NotFoundView.vue
├── App.vue
└── main.js

Configuration

1. Firebase

Edit src/firebase/index.js or set your .env:

VITE_FIREBASE_API_KEY=...
VITE_FIREBASE_AUTH_DOMAIN=...
VITE_FIREBASE_DATABASE_URL=...
VITE_FIREBASE_PROJECT_ID=...
VITE_FIREBASE_STORAGE_BUCKET=...
VITE_FIREBASE_MESSAGING_SENDER_ID=...
VITE_FIREBASE_APP_ID=...

Enable in Firebase Console:

  • Authentication → Email/Password, Google, Facebook
  • Realtime Database → create database
  • Upload firebase-rules.json as your security rules

2. Groq AI

VITE_GROQ_API_KEY=gsk_...
VITE_GROQ_MODEL=llama-3.3-70b-versatile

Get your key at console.groq.com.

3. Paymob

VITE_PAYMOB_API_KEY=...
VITE_PAYMOB_INTEGRATION_ID=...
VITE_PAYMOB_IFRAME_ID=...
VITE_PAYMOB_HMAC_SECRET=...

Get credentials from accept.paymob.com.

4. Encryption

VITE_ENCRYPTION_KEY=your_strong_random_secret

Composables API

useAuth()

import { useAuth } from '@/composables/useAuth.js'

const {
  currentUser,      // Ref<FirebaseUser | null>
  userProfile,      // Ref<Object>        — RTDB profile
  userRole,         // Ref<string>        — live from RTDB
  isAuthenticated,  // ComputedRef<bool>
  isAdmin,          // ComputedRef<bool>
  isSuperAdmin,     // ComputedRef<bool>
  isAuthReady,      // Ref<bool>          — true after first auth check
  isLoading,        // Ref<bool>
  authError,        // Ref<string | null>

  register,         // ({ email, password, displayName }) → { success, user }
  login,            // ({ email, password })              → { success, user }
  logout,           //                                    → { success }
  resetPassword,    // (email)                            → { success }
  changePassword,   // ({ currentPassword, newPassword }) → { success }
  loginWithGoogle,  // (useRedirect?)                     → { success, user }
  loginWithFacebook,// (useRedirect?)                     → { success, user }
  updateUserProfile,// (data)                             → { success }
  setUserRole,      // (uid, role)                        → { success }   ← admin only
  deleteAccount,    //                                    → { success }
  hasPermission,    // (permission) → bool
  hasRole,          // (...roles)   → bool
  ROLES             // { SUPER_ADMIN, ADMIN, USER, GUEST }
} = useAuth()

User roles are stored in /users/{uid}/role in RTDB and listened to in real-time. Session data (online, lastSeen) is written to /sessions/{uid} with onDisconnect handling.


useDatabase(options?)

import { useDatabase } from '@/composables/useDatabase.js'

const db = useDatabase({
  encryptedPaths: ['payments/*'],   // paths to auto-encrypt
  encryptFields:  ['ssn', 'card']   // field names to encrypt
})

// One-time read (offline-aware)
const user = await db.get('users/uid123')

// Write (blocked offline with error)
await db.set('todos/1', { text: 'Buy milk', done: false })
await db.update('todos/1', { done: true })
await db.push('todos', { text: 'New item' })   // → { success, key }
await db.remove('todos/1')

// Real-time listener (reactive ref + IDB sync)
const { data, unsubscribe } = db.listen('todos')
// data.value updates live

// Real-time child events (efficient for large lists)
const { items, unsubscribe } = db.listenList('messages')
// items.value = { key1: {...}, key2: {...} }

// Offline-only reads
const cached = await db.getOffline('todos')
const all    = await db.getAllOffline('todos')

// Network status
db.isOnline   // Ref<bool>

Offline behavior:

  • All write operations return { success: false, error: 'You are offline. Data is read-only.' } when offline.
  • Read operations return IndexedDB cached data.
  • Remote changes are auto-synced to IDB when online.

useCrypto()

import { useCrypto } from '@/composables/useCrypto.js'

const { encrypt, decrypt, encryptObject, decryptObject,
        encryptFields, decryptFields, hash, hmac, randomToken } = useCrypto()

const cipher = encrypt('sensitive data')
const plain  = decrypt(cipher)

const encObj = encryptObject({ ssn: '123-45-6789', name: 'Max' })
const obj    = decryptObject(encObj)

// Encrypt only specific fields
const safe = encryptFields(userData, ['ssn', 'bankAccount'])
const back = decryptFields(safe, ['ssn', 'bankAccount'])

// SHA256 hash
const hashed = hash('mypassword')

// HMAC (used by Paymob webhook verification)
const sig = hmac('message', 'secret')

useGroq(systemPrompt?)

import { useGroq } from '@/composables/useGroq.js'

const groq = useGroq('You are a helpful assistant.')

// Single prompt
const reply = await groq.chat('What is Vue.js?')

// Streaming
await groq.streamChat('Tell me a story', (chunk, full) => {
  output.value = full
})

// Multi-turn conversation
await groq.sendConversation('Hello!')
await groq.sendConversation('What did I just say?')

// Streaming multi-turn
await groq.streamConversation('Continue...', (chunk) => { ... })

// Audio transcription (Whisper)
const text = await groq.transcribe(audioBlob, 'ar')

groq.clearConversation()
groq.setSystemPrompt('New system prompt')

usePaymob() + useSubscription()

import { usePaymob, useSubscription, PLANS } from '@/composables/usePaymob.js'

// ── Payments ──
const paymob = usePaymob()

// Full payment flow → opens iframe URL
const result = await paymob.initPayment({
  amountCents: 14900,       // 149.00 EGP
  currency:    'EGP',
  billingData: { ... }
})
// result.iframeUrl  → embed or open

// Open in new tab
await paymob.openPaymentTab({ amountCents: 14900, ... })

// Verify Paymob webhook HMAC
const valid = paymob.verifyHmac(callbackData)

// ── Subscriptions ──
const sub = useSubscription()

// Initialize free plan for new users
await sub.initFreeplan(userId)

// Activate after successful payment
await sub.activateSubscription(userId, 'PRO', { paymobOrderId: 12345, amountCents: 14900 })

// Real-time subscription listener
const { data } = sub.listenSubscription(userId)
// data.value = { planId, status, expiresAt, features, ... }

// Feature gating
const canUseAPI = await sub.hasFeature(userId, 'api_access')
const active    = await sub.isActive(userId)

await sub.cancelSubscription(userId)

Subscription data in RTDB (/subscriptions/{uid}):

{
  "planId":    "pro",
  "planName":  "Pro",
  "status":    "active",
  "features":  ["read", "write", "advanced_features", "api_access"],
  "startedAt": 1700000000000,
  "expiresAt": 1702592000000,
  "autoRenew": true,
  "paymentHistory": [{ "paidAt": 1700000000000, "amountCents": 14900 }]
}

i18n

import { setLocale } from '@/i18n/index.js'

setLocale('ar')   // switches to Arabic + sets dir="rtl"
setLocale('en')   // switches to English + sets dir="ltr"

In templates:

<p>{{ $t('auth.email') }}</p>
<p>{{ $d(date, 'short') }}</p>
<p>{{ $n(149, 'egp') }}</p>

To add a new language, add its locale file to src/i18n/locales/ and register it in src/i18n/index.js.


Security Rules

Upload firebase-rules.json to your Firebase Realtime Database rules:

Firebase Console → Realtime Database → Rules → paste contents

Scripts

npm run dev       # Start dev server (http://localhost:5173)
npm run build     # Production build → dist/
npm run preview   # Preview production build
npm run lint      # Lint + auto-fix

License

MIT © Falak App