Skip to content

Repository files navigation

Firebase NodeJS Client

Compact firebase client implementation for NodeJS environment

Installation

Requires Node.js >= 20.19.

npm install @eneris/firebase-nodejs-client
yarn add @eneris/firebase-nodejs-client

Why do we need another module

Current official modules support only

  • Node.js as Admin with few to no client capabilities
  • Browser only env (hard linked to window, IndexedDB and WebWorkers)

I needed a module that I could use in any JavaScript environment. The main difference is that you can provide your own storage with simple get/set methods for data persistence.

Putting this public, so it can help some other projects too. Will add more parts based on my project needs or upon request.

What is done / planned

  • ✅ Web Installations
  • ✅ Mobile Installations
  • ✅ Remote config
  • ✅ Cloud Messaging - receiving push notifications (PushReceiver)
  • ✅ Cloud Messaging - sending push notifications (PushSender)
  • ✅ Google Analytics 4 events (Analytics)
  • ✅ HeartBeat
  • ✅ Reliability tests using the Node.js test runner

Exports

Export Description
FirebaseApp Shared app instance holding credentials, storage, logger and crypto
Installations Firebase Installations (FID + auth token) and heartbeat header
InstallationsRequestError Thrown by Installations methods on a non-ok FIS response, carries status
RemoteConfig Remote config fetch/activate with auto refresh (also the default export)
Value Remote config value returned by getValue/getAll, with typed getters
Analytics GA4 event logging through the g/collect endpoint
PushReceiver Persistent MCS/FCM connection receiving push notifications
PushSender Sending push notifications via the FCM HTTP v1 API
PushReceiverLegacy Drop-in compatible API for @eneris/push-receiver consumers

How to use it

const fs = require('fs')
const path = require('path')
const { FirebaseApp, Installations, RemoteConfig } = require('@eneris/firebase-nodejs-client')

const storageFileName = path.join(__dirname, 'storage.json')

let store = {}

if (fs.existsSync(storageFileName)) {
    store = JSON.parse(fs.readFileSync(storageFileName).toString())
}

const app = new FirebaseApp({
    credentials: { /* CREDENTIALS HERE */ },
    storage: {
        get: (key) => store[key],
        set: (key, value) => {
            store[key] = value

            fs.writeFileSync(storageFileName, JSON.stringify(store, null, 2))
        }
    }
})

const remoteConfig = new RemoteConfig(app, {
    defaultConfig: {
        test: 'true'
    }
})

remoteConfig.on('fetch', () => {
    console.log('fetch')
})

remoteConfig.on('activate', () => {
    console.log('activate')
})

remoteConfig.fetchAndActivate().then(() => {
    console.log(remoteConfig.getAll())
})

Every module namespaces its own keys inside the provided storage, so a single storage instance can be shared by all of them. See FirebaseApp for all available options.

Receiving push notifications

PushReceiver registers the app with GCM/FCM, keeps a persistent connection to mtalk.google.com open, decrypts incoming messages and deduplicates them using persistent ids stored in your storage. Registration data is persisted, so a restarted process reuses the same FCM token.

// Second argument is the push identity config (bundleId, chrome identity, timeZone, vapidKey).
// Every field is optional and falls back to its DEFAULT_* value, but the object itself is required.
const client = new PushReceiver(app, {})

client.onNotification(({ message, persistentId }) => {
    console.log('Notification received', persistentId, message)
})

await client.connect()

console.log('FCM token:', client.fcmToken)

Migrating from @eneris/push-receiver? Use PushReceiverLegacy, which keeps the old config and credentials shape.

Sending push notifications

PushSender sends messages through the FCM HTTP v1 API using your service account.

const sender = new PushSender({ /* SERVICE ACCOUNT JSON HERE */ })

await sender.send({ title: 'Hello', body: 'World' }, fcmToken)

Analytics

Analytics sends GA4 events to the same g/collect endpoint gtag.js uses, so no api_secret is needed.

const analytics = new Analytics({ app })

await analytics.logEvent('page_view', { page_title: 'Home' })

Examples

Wiki

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages