@maru-hana/realtime
v0.3.0
Published
TypeScript client SDK for Maru Realtime — real-time database with REST and WebSocket
Downloads
52
Readme
@maru-hana/realtime
TypeScript client SDK for Maru Realtime — a real-time database with REST CRUD and WebSocket subscriptions.
Install
npm install @maru-hana/realtimeQuick start
import { initializeApp, getDatabase, doc, collection, getDoc, setDoc, updateDoc, deleteDoc, getDocs, onSnapshot } from '@maru-hana/realtime'
const app = initializeApp({
apiKey: 'your-api-key',
projectId: 'your-project-id',
})
const db = getDatabase(app)CRUD
const userDoc = doc(db, 'users', 'alice')
// Read one document (null if not found)
const data = await getDoc(userDoc)
// Write (replace entire document)
await setDoc(userDoc, { name: 'Alice', age: 30 })
// Partial update (merge fields)
await updateDoc(userDoc, { age: 31 })
// Delete
await deleteDoc(userDoc)
// List all documents in a collection
const userCol = collection(db, 'users')
const { items, total } = await getDocs(userCol)
// With pagination
const { items, total } = await getDocs(userCol, { limit: 20, offset: 0 })
console.log(`showing ${items.length} of ${total}`)Filters and queries
Pass a filters array to getDocs to narrow results server-side. Each filter has a field, an op, and a typed value. Multiple filters combine with AND.
import { collection, getDocs } from '@maru-hana/realtime'
// Date-range query scoped to a location
const { items } = await getDocs(collection(db, 'revenue'), {
filters: [
{ field: 'date', op: '>=', value: '2026-01-01' },
{ field: 'date', op: '<=', value: '2026-12-31' },
{ field: 'locationId', op: '==', value: 'loc-123' },
],
sortBy: 'date',
sortDir: 'desc',
limit: 50,
})Supported operators: ==, !=, >, >=, <, <=. The full set is exported as the FILTER_OPS tuple if you need to enumerate them at runtime (e.g. to populate a UI dropdown).
- Values must be primitives:
string | number | boolean | null. - Range operators (
>,>=,<,<=) use JavaScript comparison semantics — pass values that match the stored runtime type (number vs number, ISO-string vs ISO-string). - A filter on a missing field never matches.
Deprecated
The older filterField / filterValue options still work (equivalent to a single == filter) but are deprecated — prefer filters.
Real-time subscriptions
// Subscribe to a single document
const unsub = onSnapshot(doc(db, 'users', 'alice'), (data) => {
if (data === null) console.log('document deleted')
else console.log('updated:', data)
}, (err) => {
console.error('error:', err)
})
// Subscribe to all changes in a collection
const unsub2 = onSnapshot(collection(db, 'users'), (data) => {
console.log('collection change:', data)
})
// Stop listening
unsub()
unsub2()A single WebSocket connection is shared per db instance. It reconnects automatically with exponential backoff if disconnected.
Error handling
All CRUD functions throw Error on non-2xx responses:
try {
await setDoc(userDoc, { name: 'Alice' })
} catch (err) {
console.error(err.message) // e.g. "API error 401: unauthorized"
}onSnapshot never throws — pass an optional error callback as the third argument.
Configuration
| Option | Required | Default | Description |
|--------|----------|---------|-------------|
| apiKey | ✓ | — | API key for your project |
| projectId | ✓ | — | Your project ID |
| wsUrl | — | wss://api-realtime.maru-it.com | WebSocket base URL |
| apiUrl | — | derived from wsUrl | REST API base URL |
License
MIT
