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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@fjell/lib-firestore

v4.4.76

Published

Firestore Library for Fjell

Downloads

3,041

Readme

@fjell/lib-firestore

Firestore integration for the Fjell ecosystem providing NoSQL database implementations for Google Cloud Firestore.

New Architecture (v4.4.12+)

This library now uses the new FirestoreLibrary architecture that extends @fjell/lib:

fjell-registry.Instance
  ↓ extends
fjell-lib.Library
  ↓ extends
fjell-lib-firestore.FirestoreLibrary

Installation

npm install @fjell/lib-firestore @fjell/lib @fjell/registry firebase-admin

Quick Start

New FirestoreLibrary API (v4.4.12+)

import { createRegistry } from '@fjell/registry';
import { createFirestoreLibrary, FirestoreLibrary } from '@fjell/lib-firestore';
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';

// Initialize Firestore
const app = initializeApp();
const firestore = getFirestore(app);

// Create a FirestoreLibrary
const userLibrary: FirestoreLibrary<UserItem, 'user'> = createFirestoreLibrary(
  ['user'], // Key type array
  ['users'], // Collection names
  firestore,
  {
    validators: {
      email: (email) => email.includes('@')
    },
    hooks: {
      beforeCreate: async (user) => {
        user.createdAt = new Date();
        return user;
      }
    }
  },
  [], // Scopes
  registry
);

// Use the library
const users = await userLibrary.operations.all({});
const newUser = await userLibrary.operations.create({
  name: 'Alice Johnson',
  email: '[email protected]'
});

// Access Firestore-specific features
console.log('Firestore project:', userLibrary.firestore.projectId);

Features

FirestoreLibrary Extends Library

The FirestoreLibrary interface adds:

  • firestore: Firestore database instance
  • All Library features: operations, options, coordinate, registry
interface FirestoreLibrary<T, S> extends Library<T, S> {
  firestore: FirebaseFirestore.Firestore;
}

NoSQL Operations

Built-in operations automatically use Firestore collections:

// CRUD operations use Firestore under the hood
await userLibrary.operations.create(userData);
await userLibrary.operations.find({ filter: { email: '[email protected]' } });
await userLibrary.operations.update(['user-123'], { name: 'Alice Smith' });
await userLibrary.operations.remove(['user-123']);

// Advanced queries with Firestore features
await userLibrary.operations.all({
  filter: {
    status: 'active',
    createdAt: { '>=': new Date('2024-01-01') }
  },
  sort: { createdAt: 'desc' },
  limit: 10
});

Collection Integration

Your Firestore collections are automatically managed:

// Create FirestoreLibrary with collection configuration
const userLibrary = createFirestoreLibrary(
  ['user'],
  ['users'], // Collection name in Firestore
  firestore,
  options
);

// Operations automatically use the 'users' collection
const users = await userLibrary.operations.all({}); // Query users collection

Advanced Usage

Multiple Collections

// User library with multiple related collections
const userLibrary = createFirestoreLibrary(
  ['user'],
  ['users', 'user_profiles', 'user_settings'], // Multiple collections
  firestore,
  {
    hooks: {
      afterCreate: async (user) => {
        // Automatically create profile and settings documents
        await firestore.collection('user_profiles').doc(user.id).set({
          userId: user.id,
          displayName: user.name
        });
        await firestore.collection('user_settings').doc(user.id).set({
          userId: user.id,
          theme: 'light'
        });
      }
    }
  }
);

Custom Operations

import { createOperations } from '@fjell/lib-firestore';

const customOperations = createOperations(firestore, definition, registry, {
  // Custom business logic
  actions: {
    activate: async (keys, params) => {
      const userRef = firestore.collection('users').doc(keys[0]);
      await userRef.update({
        status: 'active',
        activatedAt: admin.firestore.FieldValue.serverTimestamp()
      });
      return { success: true };
    }
  },

  // Custom analytics using Firestore aggregation
  facets: {
    userStats: async (query, options) => {
      const snapshot = await firestore.collection('users').get();
      const users = snapshot.docs.map(doc => doc.data());
      return {
        total: users.length,
        active: users.filter(u => u.status === 'active').length,
        byRegion: groupBy(users, 'region')
      };
    }
  }
});

Hierarchical Data with Subcollections

Support for contained items with Firestore subcollections:

// Order library with location hierarchy
const orderItemLibrary = createFirestoreLibrary(
  ['orderItem', 'order', 'customer'], // Nested hierarchy
  ['customers/{customerId}/orders/{orderId}/items'], // Subcollection path
  firestore,
  options
);

// Query order items with location context
const orderItems = await orderItemLibrary.operations.all({}, ['order-123', 'customer-456']);

Real-time Updates

Firestore real-time capabilities:

// Set up real-time listener (custom implementation)
const unsubscribe = firestore
  .collection('users')
  .where('status', '==', 'active')
  .onSnapshot((snapshot) => {
    snapshot.docChanges().forEach((change) => {
      if (change.type === 'added') {
        console.log('New user:', change.doc.data());
      }
    });
  });

Migration Guide

From v4.4.11 and earlier

  1. No breaking changes - existing code continues to work
  2. Optional migration to new naming:
// Clean Library architecture
import { createFirestoreLibrary, FirestoreLibrary } from '@fjell/lib-firestore';
  1. Benefits of the new architecture:
    • Clear naming that shows inheritance hierarchy
    • Better TypeScript autocomplete and documentation
    • Future-proof as the ecosystem evolves

Simple Setup

Use the FirestoreLibrary for all new development:

// Clean, consistent API
const userLibrary = createFirestoreLibrary(kta, collections, firestore, options);
const orderLibrary = createFirestoreLibrary(orderKta, orderCollections, firestore, orderOptions);

Architecture Benefits

  1. Clear Inheritance: Shows how FirestoreLibrary extends Library
  2. Type Safety: Full TypeScript support throughout the hierarchy
  3. NoSQL Focus: FirestoreLibrary is clearly Firestore-specific
  4. Real-time Ready: Built for Firestore's real-time capabilities
  5. Clean API: Consistent naming and patterns across all libraries

Firestore-Specific Features

Document References

// Working with document references
const userRef = firestore.collection('users').doc('user-123');
const user = await userLibrary.operations.get(['user-123']);

// Batch operations
const batch = firestore.batch();
batch.set(userRef, userData);
batch.update(profileRef, profileData);
await batch.commit();

Transactions

// Firestore transactions
await firestore.runTransaction(async (transaction) => {
  const userDoc = await transaction.get(userRef);
  if (userDoc.exists) {
    transaction.update(userRef, { lastLogin: new Date() });
  }
});

Security Rules Integration

// Design your data model to work with Firestore security rules
const orderLibrary = createFirestoreLibrary(
  ['order'],
  ['orders'],
  firestore,
  {
    // Operations automatically include user context for security rules
    hooks: {
      beforeCreate: async (order) => {
        order.ownerId = getCurrentUserId(); // For security rules
        return order;
      }
    }
  }
);

Examples

See the examples/ directory for complete working examples:

  • Basic Firestore integration
  • Real-time data sync
  • Subcollection management
  • Security rules patterns

TypeScript Support

Full TypeScript support with proper type inference:

import { Item } from '@fjell/core';

interface User extends Item<'user'> {
  id: string;
  name: string;
  email: string;
  status: 'active' | 'inactive';
}

const userLibrary: FirestoreLibrary<User, 'user'> = createFirestoreLibrary(
  ['user'],
  ['users'],
  firestore,
  options
);

// Full type safety
const user: User = await userLibrary.operations.create({
  name: 'Alice',
  email: '[email protected]',
  status: 'active'
});

Performance Considerations

Indexing

// Design operations with Firestore indexing in mind
await userLibrary.operations.find({
  filter: {
    status: 'active',        // Simple field index
    region: 'us-west',      // Composite index needed
    createdAt: { '>=': date } // for this combination
  }
});

Pagination

// Efficient pagination with Firestore cursors
let lastDoc = null;
const pageSize = 20;

const getNextPage = async () => {
  const query = lastDoc
    ? firestore.collection('users').startAfter(lastDoc).limit(pageSize)
    : firestore.collection('users').limit(pageSize);

  const snapshot = await query.get();
  lastDoc = snapshot.docs[snapshot.docs.length - 1];
  return snapshot.docs.map(doc => doc.data());
};

Next Steps

  • Check out @fjell/lib-sequelize for SQL database integration
  • See @fjell/lib for core Library functionality
  • Read @fjell/registry for base coordination features
  • Review Firestore documentation for advanced features