tiny-essentials
Version:
Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.
138 lines (119 loc) • 4.87 kB
JavaScript
;
var moment = require('moment-timezone');
var _ = require('lodash');
// @ts-nocheck
/** @typedef {import("firebase/database")} FbDatabase */
/** @typedef {import("firebase/database").DataSnapshot} DataSnapshot */
/** @typedef {import("firebase/database").DatabaseReference} DatabaseReference */
/**
* Firebase Presence System
*
* This module allows real-time tracking of user presence using Firebase Realtime Database.
* It handles multiple connections (tabs/devices), updates online status, and records the last time online.
*
* @module presenceSystem
*/
const presenceSystem = {
/**
* Returns the source code of the `start` function as a string, with placeholders replaced.
*
* This function is useful to retrieve a browser-compatible version of the `start` function
* for client-side injection (e.g., for Firebase emulators or test UIs).
*
* @param {string} [lodash='_'] - The lodash import replacement string (usually `_`).
* @returns {string} JavaScript source code as a string with `lodash` and `moment` replaced or removed.
*/
browserVersion: function (lodash = '_') {
// Get Browser Version
return presenceSystem.start
.toString()
.replace(`import _ from 'lodash'`, lodash)
.replace('let moment;', '')
.replace('moment = null;', 'console.error(err);')
.replace(
`import moment from 'moment-timezone'`,
"const tinypudding = 'Tiny Jasmini's Pudding.'",
);
},
/**
* Starts presence tracking for a given user in Firebase Realtime Database.
*
* It sets up handlers for `.info/connected`, manages disconnect events,
* and updates the last online time in UTC format.
*
* @param {object} database - Firebase database reference (usually `admin.database()` or `firebase.database()`).
* @param {string|object} myConnectionsRef - Path or database ref to the user's `connections` node.
* @param {string|object} lastOnlineRef - Path or database ref to the user's `lastOnline` node.
* @param {object} [data] - Optional configuration overrides.
* @param {boolean|object} [data.connected=true] - Data to store when device is connected.
* @param {Function} [data.removeError] - Callback for `onDisconnect().remove()` errors.
* @param {Function} [data.getDate] - Function to return a UTC-based timestamp object (uses `moment` if available).
*/
start: (database, myConnectionsRef, lastOnlineRef, data) => {
// Since I can connect from multiple devices or browser tabs, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
if (typeof myConnectionsRef === 'string') {
myConnectionsRef = database.ref(myConnectionsRef);
}
// stores the timestamp of my last disconnect (the last time I was seen online)
if (typeof lastOnlineRef === 'string') {
lastOnlineRef = database.ref(lastOnlineRef);
}
// Get Base
data = _.defaultsDeep({}, data, {
// Remove Error
removeError: (err) => {
if (err) {
console.group('could not establish onDisconnect event');
console.error(err);
console.groupEnd();
}
},
// Is Connected
connected: true,
// Get Data
getDate: function () {
// Prepare Values
let momentTime;
// Timezone Module
if (moment) {
momentTime = moment.utc().toObject();
}
// Vanilla
else {
const date = new Date();
momentTime = {
date: date.getUTCDate(),
hours: date.getUTCHours(),
milliseconds: date.getUTCMilliseconds(),
minutes: date.getUTCMinutes(),
months: date.getUTCMonth(),
seconds: date.getUTCSeconds(),
years: date.getUTCFullYear(),
};
}
// Insert Timezone Name
momentTime.timezone = 'Universal';
// Return the value
return momentTime;
},
});
// Prepare Connection
const connectedRef = database.ref('.info/connected');
connectedRef.on('value', (/** @type {DataSnapshot} */ snap) => {
if (snap.val() === true) {
// We're connected (or reconnected)! Do anything here that should happen only if online (or on reconnect)
const con = myConnectionsRef.push();
// When I disconnect, remove this device
con.onDisconnect().remove(data.removeError);
// Add this device to my connections list
// this value could contain info about the device or a timestamp too
con.set(data.connected);
// When I disconnect, update the last time I was seen online
const momentTime = data.getDate();
lastOnlineRef.onDisconnect().set(momentTime);
}
});
},
};
module.exports = presenceSystem;