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

@sofiakb/fireblaze-node-ts

v1.2.0-dev.1

Published

A repository layer for Firestore, built on firebase-admin.

Readme

Contributors Forks Stargazers Issues MIT License

About The Library

@sofiakb/fireblaze-node-ts wraps the Firestore Admin SDK in a small repository/active-record-style class (FirestoreRepository<T>) so you can model a collection as a class instead of calling firestore.collection(...) by hand everywhere: casting documents to your own model, a chainable query builder, soft deletes, pagination, unique-key enforcement, and batched bulk operations.

Built With

Prerequisites

  • A Firebase Admin app already initialized (firebase-admin), or a Firestore instance you pass in yourself.
  • Node.js and TypeScript.

Installation

npm install --save @sofiakb/fireblaze-node-ts

Usage

Define a model and a repository

import { FirestoreRepository } from "@sofiakb/fireblaze-node-ts";

class User {
    id!: string;
    name!: string;
    email!: string;
    createdAt: any;
    updatedAt: any;

    constructor(attributes: any = {}) {
        Object.assign(this, attributes);
    }
}

class UserRepository extends FirestoreRepository<User> {
    constructor() {
        super({ collectionName: "users", model: User });
    }
}

By default FirestoreRepository resolves the Firestore instance via getFirestore() (the default Firebase Admin app). Pass firestore in the constructor attributes to use a specific instance (e.g. a named app, or the Firestore emulator).

CRUD

const users = new UserRepository();

const user = await users.store({ name: "Alice", email: "[email protected]" });
const found = await users.find(user.id);
await users.update(user.id, { name: "Alice B." });
await users.delete(user.id);

Querying

import { Filter } from "@google-cloud/firestore";

const adults = await users
    .where(Filter.where("age", ">=", 18))
    .orderBy("age", "desc")
    .limit(20)
    .get();

const first = await users.where(Filter.where("email", "==", "[email protected]")).first();

Pagination

const page = await users.paginate(2, 20); // page, per-page
// page.data, page.page, page.per, page.total, page.latest, page.prev, page.next

Soft deletes

class UserRepository extends FirestoreRepository<User> {
    constructor() {
        super({ collectionName: "users", model: User });
        this.softDeletes = true;
    }
}

await users.softDelete(user.id);
await users.find(user.id); // null by default
await users.find(user.id, { withSoftDelete: true }); // returns the document

Unique constraints

import { UniqueConstraintException } from "@sofiakb/fireblaze-node-ts";

try {
    await users.storeUnique({ name: "Alice", email: "[email protected]" }, ["email"]);
} catch (e) {
    if (e instanceof UniqueConstraintException) {
        // an existing document already has this email
    }
}

Bulk operations

await users.storeMultiple([{ name: "A" }, { name: "B" }]);
await users.updateMultiple(["id1", "id2"], { active: true });
await users.deleteMultiple(["id1", "id2"]);
await users.whereIn("id", ["id1", "id2", "id3"]);
await users.whereNotIn("id", ["id1"]);

Related-data appends

class UserRepository extends FirestoreRepository<User> {
    async withPostsCount(data: any): Promise<number> {
        // `this` is the repository instance here
        return (await postsRepository.where(Filter.where("authorId", "==", data.id)).get()).length;
    }
}

const user = await users.with("postsCount").find(id);
// user.postsCount is now populated

API overview

| Method | Description | | --- | --- | | store(data) / storeUnique(data, uniqueKeys) / storeMultiple(values) | Create one or more documents | | find(id, options?) / doc(id, cast?, options?) / findOneById(id) | Fetch a single document | | update(id, data, force?) / updateArray(id, key, ...values) / updateMultiple(ids, data) | Update documents | | delete(id) / deleteMultiple(values) / softDelete(id) / truncate() | Remove documents | | where(filter) / orderBy / limit / limitToLast / startAt / startAfter / endAt / endBefore / first() / get(cast?) | Chainable query builder | | whereIn(column, values) / whereNotIn(column, values) | in / not-in queries, automatically chunked past Firestore's 10-value limit | | count(all?) / countQuery() / paginate(page, limit) | Counting and pagination | | copy(destCollectionName) / fields.add(fields) / fields.delete(fields) | Collection-level maintenance helpers | | search(column, query) | Best-effort case-insensitive prefix search — see Known limitations | | with(key) / appends | Populate computed/related fields via with<Key>() methods on a repository subclass |

Known limitations

  • search() builds a Firestore range query intended to approximate a case-insensitive substring search. It reliably matches prefixes, but for values that only contain the query as a substring further in the string, whether they're returned currently depends on the case of the value's first character (e.g. searching "an" finds "Banana" but not "banana"). This is a known, documented limitation — Firestore has no native case-insensitive substring index, and a fully correct fix would mean either scanning the whole collection on every call or requiring a normalized field maintained by the caller. Neither is a drop-in fix, so it hasn't been changed. See tests/integration/search.integration.test.ts for the exact behavior this locks in.

Development

npm install
npm run build      # tsc + tsc-alias -> lib/
npm run lint        # prettier + eslint --fix
npm test             # unit tests (Jest)
npm run test:emulator # integration tests against the Firestore emulator (requires the Firebase CLI + a JRE)

Unit tests (src/**/__tests__/*.test.ts) don't need any external service. Integration tests (tests/integration/*.integration.test.ts) run against a local Firestore emulator started by firebase emulators:exec (config in firebase.json/firestore.rules/.firebaserc).

Roadmap

See the open issues for a list of proposed features (and known issues).

License

Distributed under the MIT License. See LICENSE for more information.