UNPKG

@tangential/firebase-util

Version:

Utility classes and shared functionality for Tangential services that use Firebase.

134 lines 15.5 kB
import { set, push, remove, update, onValue } from 'firebase/database'; import { BehaviorSubject } from 'rxjs'; import { filter, first } from 'rxjs/operators'; import { Placeholder } from './placeholder'; export const OnRefKeys = { value: 'value', child_added: 'child_added', child_removed: 'child_removed', child_changed: 'child_changed', child_moved: 'child_moved', }; /** * Copy-paste for local use, rather than create a dependency on core. */ const isObject = function (value) { return (typeof value === 'object' || value['constructor'] === Object); }; /** * Prevent typescript casting issues while maintaining/enhancing type safety. */ export class FireBlanket { /** * Read the value once and return. * @param query */ static value(query) { return new Promise((resolve, reject) => { onValue(query, (snap) => { resolve(snap); }, { onlyOnce: true }); }); } static value$(query) { const subject = new BehaviorSubject(Placeholder); // this semicolon is required. /** @todo: ggranum: The unsubscribe is hacky, and won't actually remove the firebase * listener unless there is a 'next' element called * @maybeBug: Possible memory leak for long-running sessions with many value listeners * */ subject['_firebaseUnsubscribe'] = onValue(query, (snap) => { if (subject.closed) { subject['_firebaseUnsubscribe'](); delete subject['_firebaseUnsubscribe']; } subject.next(snap); }, (error) => { subject.error(error); }); return subject; } static awaitValue$(query) { return this.value$(query).pipe(filter(v => v !== Placeholder)); } static valueOnce$(query) { return this.value$(query).pipe(first(v => v !== Placeholder)); } static set(ref, value) { return new Promise((resolve, reject) => { try { set(ref, value).then(() => { }).catch((e) => { if (e) { reject(e); } else { resolve(); } }); } catch (e) { reject(e); } }); } static push(ref, value) { return new Promise((resolve, reject) => { try { push(ref, value).catch((e) => { if (e) { reject(e); } else { resolve(); } }); } catch (e) { reject(e); } }); } static update(ref, value) { return update(ref, value); } static remove(ref) { return remove(ref); } } FireBlanket.util = { clean(obj, deep = true) { const cleanObj = {}; Object.keys(obj).forEach((key) => { let value = obj[key]; if (FireBlanket.util.isLegalFirebaseKey(key) && FireBlanket.util.isLegalFirebaseValue(value)) { cleanObj[key] = (deep && isObject(value)) ? FireBlanket.util.clean(value) : value; } }); return cleanObj; }, removeIllegalKeys(obj) { const cleanObj = {}; Object.keys(obj).forEach((key) => { if (FireBlanket.util.isLegalFirebaseKey(key)) { cleanObj[key] = obj[key]; } }); return cleanObj; }, isLegalFirebaseKey(key) { return key !== null && key !== undefined && !key.startsWith('$'); }, isLegalFirebaseValue(value) { return value !== null && value !== undefined; }, isFirebaseGeneratedId(key) { let isKey = false; // starts with "-" will be true for over a decade. if (key && key.length === 20 && key.startsWith('-')) { isKey = true; } return isKey; } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZS1ibGFua2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdGFuZ2VudGlhbC9maXJlYmFzZS11dGlsL3NyYy9saWIvZmlyZS1ibGFua2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdEUsT0FBTyxFQUFDLGVBQWUsRUFBYSxNQUFNLE1BQU0sQ0FBQTtBQUNoRCxPQUFPLEVBQUMsTUFBTSxFQUFFLEtBQUssRUFBQyxNQUFNLGdCQUFnQixDQUFBO0FBRTVDLE9BQU8sRUFBQyxXQUFXLEVBQUMsTUFBTSxlQUFlLENBQUE7QUFHekMsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHO0lBQ3ZCLEtBQUssRUFBb0IsT0FBTztJQUNoQyxXQUFXLEVBQWMsYUFBYTtJQUN0QyxhQUFhLEVBQVksZUFBZTtJQUN4QyxhQUFhLEVBQVksZUFBZTtJQUN4QyxXQUFXLEVBQWMsYUFBYTtDQUN2QyxDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFFBQVEsR0FBRyxVQUFVLEtBQVU7SUFDbkMsT0FBTyxDQUFDLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsYUFBYSxDQUFDLEtBQUssTUFBTSxDQUFDLENBQUE7QUFDdkUsQ0FBQyxDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sV0FBVztJQTRDdEI7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFZO1FBQ3ZCLE9BQU8sSUFBSSxPQUFPLENBQWUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDbkQsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLElBQWtCLEVBQUUsRUFBRTtnQkFDcEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hCLENBQUMsRUFBRTtnQkFDRCxR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UyxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUNsRSxDQUFDO0lBRUQsb0JBQW9CLENBQUMsS0FBVTtRQUM3QixPQUFPLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLFNBQVMsQ0FBQTtJQUM5QyxDQUFDO0lBRUQscUJBQXFCLENBQUMsR0FBVztRQUMvQixJQUFJLEtBQUssR0FBRyxLQUFLLENBQUE7UUFDakIsa0RBQWtEO1FBQ2xELElBQUksR0FBRyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEtBQUssRUFBRSxJQUFJLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDbkQsS0FBSyxHQUFHLElBQUksQ0FBQTtTQUNiO1FBQ0QsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0NBRUYsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7RGF0YWJhc2VSZWZlcmVuY2UsIFF1ZXJ5LCBEYXRhU25hcHNob3R9IGZyb20gJ0BmaXJlYmFzZS9kYXRhYmFzZSdcbmltcG9ydCB7IHNldCwgcHVzaCwgcmVtb3ZlLCB1cGRhdGUsIG9uVmFsdWUgfSBmcm9tICdmaXJlYmFzZS9kYXRhYmFzZSdcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlfSBmcm9tICdyeGpzJ1xuaW1wb3J0IHtmaWx0ZXIsIGZpcnN0fSBmcm9tICdyeGpzL29wZXJhdG9ycydcblxuaW1wb3J0IHtQbGFjZWhvbGRlcn0gZnJvbSAnLi9wbGFjZWhvbGRlcidcblxuZXhwb3J0IHR5cGUgT25SZWZLZXkgPSAndmFsdWUnIHwgJ2NoaWxkX2FkZGVkJyB8ICdjaGlsZF9yZW1vdmVkJyB8ICdjaGlsZF9jaGFuZ2VkJyB8ICdjaGlsZF9tb3ZlZCdcbmV4cG9ydCBjb25zdCBPblJlZktleXMgPSB7XG4gIHZhbHVlOiAgICAgICAgIDxPblJlZktleT4ndmFsdWUnLFxuICBjaGlsZF9hZGRlZDogICA8T25SZWZLZXk+J2NoaWxkX2FkZGVkJyxcbiAgY2hpbGRfcmVtb3ZlZDogPE9uUmVmS2V5PidjaGlsZF9yZW1vdmVkJyxcbiAgY2hpbGRfY2hhbmdlZDogPE9uUmVmS2V5PidjaGlsZF9jaGFuZ2VkJyxcbiAgY2hpbGRfbW92ZWQ6ICAgPE9uUmVmS2V5PidjaGlsZF9tb3ZlZCcsXG59XG5cbi8qKlxuICogQ29weS1wYXN0ZSBmb3IgbG9jYWwgdXNlLCByYXRoZXIgdGhhbiBjcmVhdGUgYSBkZXBlbmRlbmN5IG9uIGNvcmUuXG4gKi9cbmNvbnN0IGlzT2JqZWN0ID0gZnVuY3Rpb24gKHZhbHVlOiBhbnkpOiBib29sZWFuIHtcbiAgcmV0dXJuICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnIHx8IHZhbHVlWydjb25zdHJ1Y3RvciddID09PSBPYmplY3QpXG59XG5cbi8qKlxuICogUHJldmVudCB0eXBlc2NyaXB0IGNhc3RpbmcgaXNzdWVzIHdoaWxlIG1haW50YWluaW5nL2VuaGFuY2luZyB0eXBlIHNhZmV0eS5cbiAqL1xuZXhwb3J0IGNsYXNzIEZpcmVCbGFua2V0IHtcblxuICBzdGF0aWMgdXRpbCA9IHtcblxuICAgIGNsZWFuPFQgZXh0ZW5kcyBvYmplY3Q+KG9iajogVCwgZGVlcDogYm9vbGVhbiA9IHRydWUpOiBUIHtcbiAgICAgIGNvbnN0IGNsZWFuT2JqOiBUID0gPFQ+e31cbiAgICAgIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICAgIGxldCB2YWx1ZSA9IChvYmogYXMgYW55KVtrZXldXG4gICAgICAgIGlmIChGaXJlQmxhbmtldC51dGlsLmlzTGVnYWxGaXJlYmFzZUtleShrZXkpICYmIEZpcmVCbGFua2V0LnV0aWwuaXNMZWdhbEZpcmViYXNlVmFsdWUodmFsdWUpKSB7XG4gICAgICAgICAgKGNsZWFuT2JqIGFzIGFueSlba2V5XSA9IChkZWVwICYmIGlzT2JqZWN0KHZhbHVlKSkgPyBGaXJlQmxhbmtldC51dGlsLmNsZWFuKHZhbHVlKSA6IHZhbHVlXG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgICByZXR1cm4gY2xlYW5PYmpcbiAgICB9LFxuXG4gICAgcmVtb3ZlSWxsZWdhbEtleXM8VCBleHRlbmRzIG9iamVjdD4ob2JqOiBUKTogVCB7XG4gICAgICBjb25zdCBjbGVhbk9iajogVCA9IDxUPnt9XG4gICAgICBPYmplY3Qua2V5cyhvYmogYXMgYW55KS5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgaWYgKEZpcmVCbGFua2V0LnV0aWwuaXNMZWdhbEZpcmViYXNlS2V5KGtleSkpIHtcbiAgICAgICAgICAoY2xlYW5PYmogYXMgYW55KVtrZXldID0gKG9iaiBhcyBhbnkpW2tleV1cbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIHJldHVybiBjbGVhbk9ialxuICAgIH0sXG5cbiAgICBpc0xlZ2FsRmlyZWJhc2VLZXkoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgIHJldHVybiBrZXkgIT09IG51bGwgJiYga2V5ICE9PSB1bmRlZmluZWQgJiYgIWtleS5zdGFydHNXaXRoKCckJylcbiAgICB9LFxuXG4gICAgaXNMZWdhbEZpcmViYXNlVmFsdWUodmFsdWU6IGFueSk6IGJvb2xlYW4ge1xuICAgICAgcmV0dXJuIHZhbHVlICE9PSBudWxsICYmIHZhbHVlICE9PSB1bmRlZmluZWRcbiAgICB9LFxuXG4gICAgaXNGaXJlYmFzZUdlbmVyYXRlZElkKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICBsZXQgaXNLZXkgPSBmYWxzZVxuICAgICAgLy8gc3RhcnRzIHdpdGggXCItXCIgd2lsbCBiZSB0cnVlIGZvciBvdmVyIGEgZGVjYWRlLlxuICAgICAgaWYgKGtleSAmJiBrZXkubGVuZ3RoID09PSAyMCAmJiBrZXkuc3RhcnRzV2l0aCgnLScpKSB7XG4gICAgICAgIGlzS2V5ID0gdHJ1ZVxuICAgICAgfVxuICAgICAgcmV0dXJuIGlzS2V5XG4gICAgfVxuXG4gIH1cblxuICAvKipcbiAgICogUmVhZCB0aGUgdmFsdWUgb25jZSBhbmQgcmV0dXJuLlxuICAgKiBAcGFyYW0gcXVlcnlcbiAgICovXG4gIHN0YXRpYyB2YWx1ZShxdWVyeTogUXVlcnkpOiBQcm9taXNlPERhdGFTbmFwc2hvdD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZTxEYXRhU25hcHNob3Q+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIG9uVmFsdWUocXVlcnksIChzbmFwOiBEYXRhU25hcHNob3QpID0+IHtcbiAgICAgICAgcmVzb2x2ZShzbmFwKTtcbiAgICAgIH0sIHtcbiAgICAgICAgb25seU9uY2U6IHRydWVcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgc3RhdGljIHZhbHVlJChxdWVyeTogUXVlcnkpOiBPYnNlcnZhYmxlPERhdGFTbmFwc2hvdD4ge1xuICAgIGNvbnN0IHN1YmplY3QgPSBuZXcgQmVoYXZpb3JTdWJqZWN0KFBsYWNlaG9sZGVyKTsgLy8gdGhpcyBzZW1pY29sb24gaXMgcmVxdWlyZWQuXG5cbiAgICAvKiogQHRvZG86IGdncmFudW06IFRoZSB1bnN1YnNjcmliZSBpcyBoYWNreSwgYW5kIHdvbid0IGFjdHVhbGx5IHJlbW92ZSB0aGUgZmlyZWJhc2VcbiAgICAgKiBsaXN0ZW5lciB1bmxlc3MgdGhlcmUgaXMgYSAnbmV4dCcgZWxlbWVudCBjYWxsZWRcbiAgICAgKiBAbWF5YmVCdWc6IFBvc3NpYmxlIG1lbW9yeSBsZWFrIGZvciBsb25nLXJ1bm5pbmcgc2Vzc2lvbnMgd2l0aCBtYW55IHZhbHVlIGxpc3RlbmVyc1xuICAgICAqICovXG4gICAgICAoc3ViamVjdCBhcyBhbnkpWydfZmlyZWJhc2VVbnN1YnNjcmliZSddID0gb25WYWx1ZShxdWVyeSwgKHNuYXA6IERhdGFTbmFwc2hvdCkgPT4ge1xuICAgICAgaWYoc3ViamVjdC5jbG9zZWQpe1xuICAgICAgICAoc3ViamVjdCBhcyBhbnkpWydfZmlyZWJhc2VVbnN1YnNjcmliZSddKClcbiAgICAgICAgZGVsZXRlIChzdWJqZWN0IGFzIGFueSlbJ19maXJlYmFzZVVuc3Vic2NyaWJlJ11cbiAgICAgIH1cbiAgICAgIHN1YmplY3QubmV4dChzbmFwKVxuICAgIH0sIChlcnJvcjogYW55KSA9PiB7XG4gICAgICBzdWJqZWN0LmVycm9yKGVycm9yKVxuICAgIH0pXG4gICAgcmV0dXJuIHN1YmplY3RcbiAgfVxuXG4gIHN0YXRpYyBhd2FpdFZhbHVlJChxdWVyeTogUXVlcnkpOiBPYnNlcnZhYmxlPERhdGFTbmFwc2hvdD4ge1xuICAgIHJldHVybiB0aGlzLnZhbHVlJChxdWVyeSkucGlwZShmaWx0ZXIodiA9PiB2ICE9PSBQbGFjZWhvbGRlcikpXG4gIH1cblxuICBzdGF0aWMgdmFsdWVPbmNlJChxdWVyeTogUXVlcnkpOiBPYnNlcnZhYmxlPERhdGFTbmFwc2hvdD4ge1xuICAgIHJldHVybiB0aGlzLnZhbHVlJChxdWVyeSkucGlwZShmaXJzdCh2ID0+IHYgIT09IFBsYWNlaG9sZGVyKSlcbiAgfVxuXG4gIHN0YXRpYyBzZXQ8VD4ocmVmOiBEYXRhYmFzZVJlZmVyZW5jZSwgdmFsdWU6IFQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgc2V0KHJlZiwgdmFsdWUpLnRoZW4oKCkgPT4ge30pLmNhdGNoKChlOiBFcnJvcikgPT4ge1xuICAgICAgICAgIGlmIChlKSB7XG4gICAgICAgICAgICByZWplY3QoZSlcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZWplY3QoZSlcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgc3RhdGljIHB1c2g8VD4ocmVmOiBEYXRhYmFzZVJlZmVyZW5jZSwgdmFsdWU6IFQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcHVzaChyZWYsIHZhbHVlKS5jYXRjaCgoZTogRXJyb3IpID0+IHtcbiAgICAgICAgICBpZiAoZSkge1xuICAgICAgICAgICAgcmVqZWN0KGUpXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlc29sdmUoKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpXG4gICAgICB9XG4gICAgfSlcbiAgfVxuXG4gIHN0YXRpYyB1cGRhdGU8VCBleHRlbmRzIG9iamVjdD4ocmVmOiBEYXRhYmFzZVJlZmVyZW5jZSwgdmFsdWU6IFQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICByZXR1cm4gdXBkYXRlKHJlZiwgdmFsdWUgKVxuICB9XG5cbiAgc3RhdGljIHJlbW92ZTxUPihyZWY6IERhdGFiYXNlUmVmZXJlbmNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHJlbW92ZShyZWYpXG4gIH1cbn1cbiJdfQ==