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

edmaxlabs-core

v2.6.9

Published

Official Framework-Agnostic SDK for EdmaxLabs services, including database, storage, authentication, and more. Works with React, Vue, Angular, Node.js, and vanilla JavaScript.

Readme

EdmaxLabs Core SDK

npm version License: MIT

edmaxlabs-core is the official framework-agnostic SDK for EdmaxLabs services. It supports database access, realtime listeners, offline persistence, authentication, storage, and cloud functions.

Installation

npm install edmaxlabs-core

Create an App

import EdmaxLabs from "edmaxlabs-core";

const app = new EdmaxLabs({
  token: "your-api-token",
  project: "your-project-id",
  persistence: true,
  app_name: "my-web-app",
});

Config options:

  • token: required API token
  • project: required project id
  • persistence: enable offline persistence and sync
  • app_name: optional cache namespace for the local persistence layer
  • default_bucket: optional default storage bucket

React Quick Start

import { useEffect, useState } from "react";
import EdmaxLabs from "edmaxlabs-core";

const app = new EdmaxLabs({
  token: "your-api-token",
  project: "your-project-id",
  persistence: true,
  app_name: "chat-app",
});

export function MessagesList() {
  const [messages, setMessages] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = app.getDatabase
      .collection("messages")
      .onSnapshot((snapshots) => {
        setMessages(snapshots.map((doc) => doc.data));
        setLoading(false);
      });

    return unsubscribe;
  }, []);

  if (loading) return <p>Loading...</p>;

  return (
    <ul>
      {messages.map((message) => (
        <li key={message.id}>{message.text}</li>
      ))}
    </ul>
  );
}

Realtime

onSnapshot

onSnapshot is still fully supported. For collections and queries it returns the full current result set every time something changes.

const unsubscribe = app.getDatabase
  .collection("messages")
  .onSnapshot((snapshots, change, changedDocId) => {
    console.log("change:", change);
    console.log("changedDocId:", changedDocId);
    console.log("docs:", snapshots.map((doc) => doc.data));
  });

unsubscribe();

Document listeners work the same way:

const unsubscribe = app.getDatabase
  .collection("messages")
  .doc("message-1")
  .onSnapshot((snapshot, change) => {
    console.log("change:", change);
    console.log("doc:", snapshot?.data ?? null);
  });

onChildListener

Yes, onChildListener is now available.

Use it when you want Firestore-style granular callbacks instead of diffing the full array yourself.

const unsubscribe = app.getDatabase
  .collection("messages")
  .onChildListener({
    onChildAdded(snapshot, context) {
      console.log("added:", snapshot.data);
      console.log("index:", context.newIndex);
      console.log("fromCache:", context.fromCache);
    },
    onChildUpdated(snapshot, context) {
      console.log("updated:", snapshot.data);
      console.log("oldIndex:", context.oldIndex);
      console.log("newIndex:", context.newIndex);
      console.log("previous:", context.previousDoc?.data ?? null);
    },
    onChildRemoved(snapshot, context) {
      console.log("removed:", snapshot.data);
      console.log("oldIndex:", context.oldIndex);
    },
  });

unsubscribe();

It also works on queries:

const unsubscribe = app.getDatabase
  .collection("messages")
  .query
  .where({ key: "roomId", op: "==", value: "general" })
  .onChildListener({
    onChildAdded(snapshot) {
      console.log("room message:", snapshot.data);
    },
  });

Child listener callback context includes:

  • snapshots: the current full query result
  • source: "initial" | "insert" | "update" | "delete"
  • changedDocId: the document that triggered the emission
  • fromCache: whether the emission came from local cache
  • oldIndex: previous index in the result set
  • newIndex: next index in the result set
  • previousDoc: previous version of the document when available

Collections and Documents

Get all documents

const users = await app.getDatabase.collection("users").get();

users.forEach((user) => {
  console.log(user.id, user.data);
});

Get one document

const user = await app.getDatabase.collection("users").doc("user-1").get();

if (user) {
  console.log(user.data);
}

Create with generated id

const created = await app.getDatabase.collection("messages").add({
  text: "Hello world",
  roomId: "general",
  createdAt: Date.now(),
});

Set a known id

await app.getDatabase.collection("users").doc("user-1").set({
  name: "Jane",
  email: "[email protected]",
});

Update a document

await app.getDatabase.collection("users").doc("user-1").update({
  lastLoginAt: Date.now(),
});

Delete a document

await app.getDatabase.collection("users").doc("user-1").delete();

Queries

Build queries with collection.query.where(...).

const activeUsers = await app.getDatabase
  .collection("users")
  .query
  .where({ key: "status", op: "==", value: "active" })
  .where({ key: "age", op: ">=", value: 18 })
  .get();

Supported operators:

  • ==
  • ===
  • !=
  • <
  • <=
  • >
  • >=
  • in
  • nin
  • contains

Query snapshots are supported too:

const unsubscribe = app.getDatabase
  .collection("users")
  .query
  .where({ key: "status", op: "==", value: "active" })
  .onSnapshot((snapshots) => {
    console.log("active users:", snapshots.map((doc) => doc.data));
  });

Offline Persistence

Enable it with persistence: true.

const app = new EdmaxLabs({
  token: "your-api-token",
  project: "your-project-id",
  persistence: true,
});

What you get:

  • local cached reads
  • optimistic local writes
  • background sync when the network returns
  • realtime listeners backed by the local cache first

Useful helpers:

app.isOfflineEnabled;

await app.sync();
await app.retrySync();

const failed = await app.getFailedMutations();
console.log(failed);

const usage = await app.getStorageUsage();
console.log(usage);

await app.clearCache();

const offline = app.offline();
console.log(offline.enabled);
console.log(offline.getListenerCount());

Authentication

Current user

const user = app.getAuthentication.currentUser();
console.log(user);

Auth state listener

const unsubscribe = app.getAuthentication.authState({
  onChange(user) {
    console.log("signed in:", user);
  },
  onSignOut() {
    console.log("signed out");
  },
  onDeleted() {
    console.log("user deleted");
  },
});

Create account

const user = await app.getAuthentication.createUserWithEmailAndPassword({
  email: "[email protected]",
  password: "secret123",
});

Sign in

const user = await app.getAuthentication.signInWithEmailAndPassword({
  email: "[email protected]",
  password: "secret123",
});

Sign out

await app.getAuthentication.signOut();

Storage

const uploaded = await app.getStorage.upload(file);
console.log(uploaded);

const fileMeta = await app.getStorage.get("file-id");
const fileInfo = await app.getStorage.getMeta("file-id");

await app.getStorage.delete("file-id");

Cloud Functions

const result = await app.getFunctions.call("sendWelcomeEmail", {
  userId: "user-1",
});

console.log(result);

Batch Writes

const db = app.getDatabase;
const batch = db.batch();

batch.set(db.collection("users").doc("u1"), {
  name: "Jane",
});

batch.update(db.collection("users").doc("u2"), {
  online: true,
});

batch.delete(db.collection("users").doc("u3"));

await batch.commit();

Important Notes

  • Always unsubscribe realtime listeners in React useEffect cleanup.
  • onSnapshot returns full results for collections and queries.
  • onChildListener gives you granular callbacks like Firestore.
  • With persistence enabled, listeners can emit cached data first and then refresh with synced data.
  • Query results while offline reflect the latest local cache available on that device.

Minimal React Pattern

useEffect(() => {
  const unsubscribe = app.getDatabase
    .collection("messages")
    .onChildListener({
      onChildAdded(snapshot) {
        console.log("new message", snapshot.data);
      },
      onChildUpdated(snapshot) {
        console.log("edited message", snapshot.data);
      },
      onChildRemoved(snapshot) {
        console.log("deleted message", snapshot.id);
      },
    });

  return unsubscribe;
}, []);

Manual SDK Testing

There is now a manual browser test harness inside this repo.

Build the SDK:

npm run manual:test

Start the local static server:

npm run manual:test:serve

Then open:

http://localhost:4173/manual-tests/index.html

What you can verify there:

  • collection.onSnapshot(...)
  • query.onSnapshot(...)
  • document.onSnapshot(...)
  • collection.onChildListener(...)
  • create, set, update, delete flows
  • persistence-enabled behavior in the browser
  • offline/online transitions using devtools network controls
  • multiple active listeners at once

License

MIT