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

@dataql/firebase-adapter

v1.4.0

Published

Firebase adapter for DataQL with zero API changes

Downloads

20

Readme

@dataql/firebase-adapter

Migrate from Firebase/Firestore to DataQL with zero API changes. This adapter provides a Firebase-compatible API that runs on DataQL with automatic scaling, caching, and offline support.

Installation

npm install @dataql/core @dataql/firebase-adapter

Quick Start

import { initializeApp, getFirestore } from "@dataql/firebase-adapter";

// Initialize Firebase app with DataQL
const firebaseConfig = {
  apiKey: "your-api-key",
  authDomain: "your-project.firebaseapp.com",
  projectId: "your-project",
  storageBucket: "your-project.appspot.com",
  messagingSenderId: "123456789",
  appId: "1:123456789:web:abcdef123456",
};

const app = initializeApp(firebaseConfig, {
  appToken: "your-app-token", // Required for DataQL authentication
  env: "prod", // Environment: 'dev' or 'prod'
  dbName: "your_app_db", // Database name for data isolation
});

const db = getFirestore(app);

// Use familiar Firestore syntax - all operations powered by DataQL
const usersRef = db.collection("users");

// Add a document
const docRef = await usersRef.add({
  name: "John Doe",
  email: "[email protected]",
  age: 30,
  active: true,
});

console.log("Document written with ID: ", docRef.id);

// Query documents
const snapshot = await usersRef
  .where("active", "==", true)
  .where("age", ">=", 18)
  .orderBy("name")
  .limit(10)
  .get();

snapshot.forEach((doc) => {
  console.log(doc.id, " => ", doc.data());
});

// Real-time listener
const unsubscribe = usersRef.onSnapshot((snapshot) => {
  snapshot.forEach((doc) => {
    console.log("User:", doc.data());
  });
});

// Clean up listener
unsubscribe();

Configuration

const app = initializeApp(firebaseConfig, {
  appToken: "your-app-token", // Required - authentication for DataQL
  env: "prod", // Optional - 'dev' or 'prod' (default: 'prod')
  devPrefix: "dev_", // Optional - prefix for dev environment collections
  dbName: "your_app_db", // Optional - database name for data isolation
  customConnection: undefined, // Optional - for custom integrations
});

Configuration Options

  • appToken (required): Authentication token for DataQL
  • env: Environment - 'dev' or 'prod' (default: 'prod')
  • devPrefix: Collection prefix for development environment (default: 'dev_')
  • dbName: Database name for data isolation (each client gets dedicated database)
  • customConnection: Advanced option for custom integrations

Benefits Over Direct Firebase

While maintaining 100% Firebase API compatibility, you get DataQL's enhanced capabilities:

  • Simplified Setup: No need to manage Firebase projects, billing, or infrastructure
  • Auto-scaling: Automatic scaling based on usage
  • Offline-first: Built-in offline support with automatic sync when online
  • Real-time: Live data updates across all connected clients
  • Global Performance: Data served from edge locations worldwide for low latency
  • Data Isolation: Each client gets their own dedicated database automatically
  • Multi-layer Caching: Optimized performance with intelligent caching

Migration Guide

From Firebase

  1. Replace imports:

    // Before
    import { initializeApp } from "firebase/app";
    import { getFirestore } from "firebase/firestore";
    
    // After
    import { initializeApp, getFirestore } from "@dataql/firebase-adapter";
  2. Update app initialization:

    // Before - Direct Firebase connection
    const app = initializeApp(firebaseConfig);
    
    // After - DataQL authentication
    const app = initializeApp(firebaseConfig, {
      appToken: "your-app-token", // Required for DataQL authentication
      dbName: "your_app_db", // Your database name
    });
  3. Your Firestore code works exactly the same:

    // This works exactly the same - but now powered by DataQL
    const db = getFirestore(app);
    const snapshot = await db.collection("users").get();

API Compatibility

Supported Firebase Features

Firestore Database

  • initializeApp(config, options) - Initialize Firebase app
  • getFirestore(app) - Get Firestore instance
  • collection(path) - Get collection reference
  • doc(path) - Get document reference

Collection Operations

  • .add(data) - Add document to collection
  • .doc(id) - Get document by ID
  • .where(field, operator, value) - Filter documents
  • .orderBy(field, direction) - Sort documents
  • .limit(count) - Limit number of results
  • .get() - Execute query and get snapshot
  • .onSnapshot(callback) - Real-time listener

Document Operations

  • .get() - Get document snapshot
  • .set(data, options) - Set document data
  • .update(data) - Update document fields
  • .delete() - Delete document
  • .onSnapshot(callback) - Real-time document listener

Query Operators

  • == - Equal to
  • != - Not equal to
  • < - Less than
  • <= - Less than or equal to
  • > - Greater than
  • >= - Greater than or equal to
  • array-contains - Array contains value
  • in - Field value is in array
  • array-contains-any - Array contains any of the values

Response Types

  • DocumentSnapshot with .data(), .get(), .exists
  • QuerySnapshot with .docs, .size, .empty, .forEach()
  • QueryDocumentSnapshot with .data(), .get()
  • WriteResult with .writeTime

DataQL Enhancements

While maintaining Firebase compatibility, you also get DataQL's additional features:

  • Offline-first: Automatic offline support and sync
  • Multi-region: Global data distribution
  • Schema validation: Optional schema enforcement
  • WAL support: Write-ahead logging for reliability
  • Unique document creation: createUnique() method to prevent duplicates

TypeScript Support

Full TypeScript support with inferred types:

import {
  initializeApp,
  getFirestore,
  DocumentData,
} from "@dataql/firebase-adapter";

interface User {
  name: string;
  email: string;
  age?: number;
  active: boolean;
  createdAt?: string;
}

const app = initializeApp(firebaseConfig, options);
const db = getFirestore(app);

// Type-safe operations
const usersRef = db.collection("users");
const userDoc = await usersRef.doc("user123").get();

if (userDoc.exists) {
  const userData = userDoc.data() as User;
  console.log("User:", userData.name);
}

// Typed queries
const activeUsers = await usersRef.where("active", "==", true).get();

activeUsers.forEach((doc) => {
  const user = doc.data() as User;
  console.log("Active user:", user.name);
});

Real-time Subscriptions

Real-time features work just like Firebase:

// Collection listener
const unsubscribe = db.collection("messages").onSnapshot((snapshot) => {
  snapshot.docChanges().forEach((change) => {
    if (change.type === "added") {
      console.log("New message:", change.doc.data());
    } else if (change.type === "modified") {
      console.log("Modified message:", change.doc.data());
    } else if (change.type === "removed") {
      console.log("Removed message:", change.doc.data());
    }
  });
});

// Document listener
const docUnsubscribe = db.doc("users/user123").onSnapshot((doc) => {
  if (doc.exists) {
    console.log("Current data:", doc.data());
  } else {
    console.log("Document does not exist");
  }
});

// Cleanup
unsubscribe();
docUnsubscribe();

Advanced Queries

Complex queries with multiple filters and ordering:

// Complex filtering
const posts = await db
  .collection("posts")
  .where("published", "==", true)
  .where("category", "in", ["tech", "science"])
  .where("likes", ">=", 10)
  .orderBy("createdAt", "desc")
  .limit(20)
  .get();

posts.forEach((doc) => {
  console.log("Post:", doc.data());
});

// Array queries
const usersByTags = await db
  .collection("users")
  .where("tags", "array-contains", "developer")
  .get();

const usersByMultipleTags = await db
  .collection("users")
  .where("tags", "array-contains-any", ["developer", "designer"])
  .get();

// Compound queries
const recentActiveUsers = await db
  .collection("users")
  .where("active", "==", true)
  .where("lastLoginAt", ">=", "2024-01-01")
  .orderBy("lastLoginAt", "desc")
  .limit(50)
  .get();

Document Operations

Standard Firestore document operations:

const userRef = db.collection("users").doc("user123");

// Create/set document
await userRef.set({
  name: "John Doe",
  email: "[email protected]",
  active: true,
});

// Update specific fields
await userRef.update({
  name: "John Smith",
  lastUpdated: new Date(),
});

// Merge data with existing document
await userRef.set(
  {
    preferences: {
      theme: "dark",
      notifications: true,
    },
  },
  { merge: true }
);

// Get document
const doc = await userRef.get();
if (doc.exists) {
  console.log("User data:", doc.data());
} else {
  console.log("User not found");
}

// Delete document
await userRef.delete();

Error Handling

Standard Firebase error handling:

try {
  const doc = await db.collection("users").doc("user123").get();
  if (doc.exists) {
    console.log("User:", doc.data());
  } else {
    console.log("User not found");
  }
} catch (error) {
  console.error("Error getting user:", error);
}

// Handling write operations
try {
  await db.collection("users").add({
    name: "Jane Doe",
    email: "[email protected]",
  });
  console.log("User created successfully");
} catch (error) {
  console.error("Error creating user:", error);
}

Limitations

Some advanced Firebase features are not yet supported:

  • Authentication: Firebase Auth methods are not implemented (implement your own authentication layer)
  • Storage: Firebase Storage methods are not implemented (use DataQL's storage instead)
  • Cloud Functions: Firebase Functions are not supported (use DataQL's serverless functions instead)
  • Security Rules: Not implemented (use DataQL's security features instead)
  • Subcollections: Nested collections are not fully implemented
  • Transactions: Atomic transactions are not yet supported
  • Batch writes: Batch operations are not yet supported
  • Pagination cursors: startAt, endAt methods are simplified

If you need these features, please open an issue.

Examples

Basic CRUD Operations

const db = getFirestore(app);

// Create
const newUserRef = await db.collection("users").add({
  name: "Alice Johnson",
  email: "[email protected]",
  role: "admin",
  createdAt: new Date(),
});

// Read
const userSnapshot = await db
  .collection("users")
  .where("role", "==", "admin")
  .get();

userSnapshot.forEach((doc) => {
  console.log("Admin user:", doc.data());
});

// Update
await db.collection("users").doc(newUserRef.id).update({
  name: "Alice Smith",
  updatedAt: new Date(),
});

// Delete
await db.collection("users").doc(newUserRef.id).delete();

Real-time Chat Application

// Listen for new messages
const messagesRef = db.collection("messages");

const unsubscribe = messagesRef
  .orderBy("timestamp", "desc")
  .limit(50)
  .onSnapshot((snapshot) => {
    snapshot.forEach((doc) => {
      const message = doc.data();
      addMessageToUI(message);
    });
  });

// Send a message
async function sendMessage(text: string, userId: string) {
  try {
    await messagesRef.add({
      text,
      userId,
      timestamp: new Date(),
      reactions: [],
    });
  } catch (error) {
    console.error("Failed to send message:", error);
  }
}

// Cleanup
function cleanup() {
  unsubscribe();
}

E-commerce Product Catalog

// Query products by category with pagination
async function getProducts(category: string, limit: number = 20) {
  const productsRef = db.collection("products");

  const snapshot = await productsRef
    .where("category", "==", category)
    .where("inStock", "==", true)
    .orderBy("price", "asc")
    .limit(limit)
    .get();

  return snapshot.docs.map((doc) => ({
    id: doc.id,
    ...doc.data(),
  }));
}

// Search products by tags
async function searchProducts(tags: string[]) {
  const productsRef = db.collection("products");

  const snapshot = await productsRef
    .where("tags", "array-contains-any", tags)
    .where("available", "==", true)
    .get();

  return snapshot.docs.map((doc) => ({
    id: doc.id,
    ...doc.data(),
  }));
}

// Update product inventory
async function updateInventory(productId: string, quantity: number) {
  const productRef = db.collection("products").doc(productId);

  await productRef.update({
    inventory: quantity,
    inStock: quantity > 0,
    lastUpdated: new Date(),
  });
}

License

MIT