
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@valian/rxjs-firebase
Advanced tools
RxJS operators and utilities for Firebase with real-time updates and TypeScript support
@valian/rxjs-firebase is a lightweight RxJS library that provides seamless integration with Firebase services. It offers real-time data synchronization, TypeScript support, and comprehensive state management for your RxJS-based applications.
onSnapshotpnpm add @valian/rxjs-firebase
This library requires the following peer dependencies:
rxjs ^7 || ^8firebase ^11 || ^12These are the primary operators that map Firestore snapshots into well-typed state objects.
import { doc } from 'firebase/firestore'
import { fromDocumentRef, documentSnapshotState } from '@valian/rxjs-firebase'
const userRef = doc(db, 'users', userId)
const userState$ = fromDocumentRef(userRef).pipe(
documentSnapshotState({
onSnapshot: (state) => console.log('exists', state.exists),
onError: (error) => console.error(error),
}),
)
With an immediate loading emission:
import { fromDocumentRef, documentSnapshotState, startWithDocumentSnapshotLoadingState } from '@valian/rxjs-firebase'
const userState$ = fromDocumentRef(userRef).pipe(documentSnapshotState(), startWithDocumentSnapshotLoadingState())
This is useful when you want subscribers to get an initial { isLoading: true } state synchronously before Firestore returns the first snapshot.
import { collection, query, where } from 'firebase/firestore'
import { fromQuery, querySnapshotState } from '@valian/rxjs-firebase'
const todosQuery = query(collection(db, 'todos'), where('userId', '==', userId))
const todosState$ = fromQuery(todosQuery).pipe(
querySnapshotState({
onSnapshot: (state) => console.log('size', state.size),
}),
)
With an immediate loading emission:
import { fromQuery, querySnapshotState, startWithQuerySnapshotLoadingState } from '@valian/rxjs-firebase'
const todosState$ = fromQuery(todosQuery).pipe(querySnapshotState(), startWithQuerySnapshotLoadingState())
When queries or refs can be null/undefined at times, prefer the documentSnapshot / querySnapshot operators below.
Creates an observable of DocumentSnapshot.
import { doc } from 'firebase/firestore'
import { fromDocumentRef } from '@valian/rxjs-firebase'
const user$ = fromDocumentRef(doc(db, 'users', 'user123'))
Creates an observable of QuerySnapshot.
import { collection, orderBy, query, where } from 'firebase/firestore'
import { fromQuery } from '@valian/rxjs-firebase'
const base = query(collection(db, 'todos'))
const todos$ = fromQuery(base)
const activeTodos$ = fromQuery(
query(collection(db, 'todos'), where('completed', '==', false), orderBy('createdAt', 'desc')),
)
Creates an observable of Firebase Auth user.
import { authState } from '@valian/rxjs-firebase'
const auth$ = authState()
BehaviorSubject that tracks a document state.
import { doc } from 'firebase/firestore'
import { DocumentSnapshotSubject } from '@valian/rxjs-firebase'
const subject = DocumentSnapshotSubject.fromDocumentRef(doc(db, 'users', 'user123'))
const sub = subject.subscribe((state) => {
if (state.isLoading) return
if (!state.exists) return console.log('Not found')
console.log(state.data)
})
sub.unsubscribe()
subject.complete()
BehaviorSubject that tracks a query state.
import { collection, query } from 'firebase/firestore'
import { QuerySnapshotSubject } from '@valian/rxjs-firebase'
const subject = QuerySnapshotSubject.fromQuery(query(collection(db, 'todos')))
const sub = subject.subscribe((state) => {
if (state.isLoading) return
console.log(state.size, state.data)
})
sub.unsubscribe()
subject.complete()
Takes a stream of DocumentReference | null | undefined and emits a DocumentSnapshotState, yielding a disabled state when the ref is null/undefined.
import { of } from 'rxjs'
import { documentSnapshot } from '@valian/rxjs-firebase'
of(userRef /* or null */)
.pipe(documentSnapshot())
.subscribe((state) => {
if (state.disabled) return
if (!state.exists) return
console.log(state.data)
})
Takes a stream of Query | null | undefined and emits a QuerySnapshotState, yielding a disabled state when the query is null/undefined.
import { of } from 'rxjs'
import { querySnapshot } from '@valian/rxjs-firebase'
of(todosQuery /* or null */)
.pipe(querySnapshot())
.subscribe((state) => {
if (state.disabled) return
console.log(state.size)
})
Wait until a document exists or time out.
import { doc } from 'firebase/firestore'
import { documentExists, documentSnapshotState, fromDocumentRef } from '@valian/rxjs-firebase'
const exists = await documentExists(fromDocumentRef(doc(db, 'users', userId)).pipe(documentSnapshotState()), 5_000)
Await the first non-loading, non-disabled state for either document or query streams.
import { waitForData } from '@valian/rxjs-firebase'
const ready = await waitForData(state$)
import { combineLatest, switchMap } from 'rxjs'
import { fromQuery, querySnapshotState } from '@valian/rxjs-firebase'
function createFilteredTodos(userId$: Observable<string>, completed$: Observable<boolean>) {
return combineLatest([userId$, completed$]).pipe(
switchMap(([userId, completed]) => {
const q = query(collection(db, 'todos'), where('userId', '==', userId), where('completed', '==', completed))
return fromQuery(q).pipe(querySnapshotState())
}),
)
}
import { combineLatest } from 'rxjs'
import { map } from 'rxjs/operators'
import { fromDocumentRef, fromQuery, documentSnapshotState, querySnapshotState } from '@valian/rxjs-firebase'
function getUserWithTodos(userId: string) {
const user$ = fromDocumentRef(doc(db, 'users', userId)).pipe(documentSnapshotState<User>())
const todos$ = fromQuery(query(collection(db, 'todos'), where('userId', '==', userId))).pipe(
querySnapshotState<Todo>(),
)
return combineLatest([user$, todos$]).pipe(
map(([userState, todosState]) => ({
user: userState.data,
todos: todosState.data,
isLoading: userState.isLoading || todosState.isLoading,
hasError: userState.hasError || todosState.hasError,
})),
)
}
MIT © Valian
Contributions are welcome! Please feel free to submit a Pull Request.
If you encounter any issues or have questions, please open an issue on GitHub.
FAQs
rxjs firebase utilities
We found that @valian/rxjs-firebase demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.