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.
Maintainers
Readme
EdmaxLabs Core SDK
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-coreCreate 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 tokenproject: required project idpersistence: enable offline persistence and syncapp_name: optional cache namespace for the local persistence layerdefault_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 resultsource:"initial" | "insert" | "update" | "delete"changedDocId: the document that triggered the emissionfromCache: whether the emission came from local cacheoldIndex: previous index in the result setnewIndex: next index in the result setpreviousDoc: 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:
=====!=<<=>>=innincontains
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
useEffectcleanup. onSnapshotreturns full results for collections and queries.onChildListenergives 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:testStart the local static server:
npm run manual:test:serveThen open:
http://localhost:4173/manual-tests/index.htmlWhat 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
