LogoRobo.js

Flashcore realtime

Realtime subscriptions for Flashcore model changes.

Subscribe to Flashcore model changes in real-time. The realtime plugin tracks creates, updates, and deletes -- notifying subscribers when matching records change. It includes JSON Patch diffs, subscription limits, and automatic idle cleanup.

This is a server-side feature. It runs in the Robo backend, not in the browser.

Setup

import { Flashcore } from 'robo.js'
import { realtime } from '@robojs/sync/flashcore'

await Flashcore.init({
	plugins: [realtime()]
})
import { Flashcore } from 'robo.js'
import { realtime } from '@robojs/sync/flashcore'

await Flashcore.init({
	plugins: [realtime()]
})

Configuration

Pass a config object to customize limits and timeouts.

realtime({
	maxSubscriptionsPerModel: 500,
	maxTotalSubscriptions: 5000,
	idleTimeout: 1800000,          // 30 minutes
	maxRecordsPerSubscription: 5000
})
realtime({
	maxSubscriptionsPerModel: 500,
	maxTotalSubscriptions: 5000,
	idleTimeout: 1800000,          // 30 minutes
	maxRecordsPerSubscription: 5000
})
OptionTypeDefaultDescription
maxSubscriptionsPerModelnumber1000Maximum subscriptions per Flashcore model
maxTotalSubscriptionsnumber10000Maximum total subscriptions across all models
idleTimeoutnumber3600000 (1 hour)Milliseconds before idle subscriptions are cleaned up
maxRecordsPerSubscriptionnumber10000Maximum records tracked per subscription

Subscribing to model changes

Once initialized, Flashcore models gain a .subscribe() method.

const unsubscribe = User.subscribe({
	where: { status: 'active' },
	callbacks: {
		onAdd: (user) => console.log('New active user:', user),
		onChange: (user, patches) => console.log('User changed:', user.id, patches),
		onRemove: (user) => console.log('User no longer active:', user),
		onComplete: () => console.log('Subscription ended')
	}
})

// Stop listening
unsubscribe()
const unsubscribe = User.subscribe({
	where: { status: 'active' },
	callbacks: {
		onAdd: (user) => console.log('New active user:', user),
		onChange: (user, patches) => console.log('User changed:', user.id, patches),
		onRemove: (user) => console.log('User no longer active:', user),
		onComplete: () => console.log('Subscription ended')
	}
})

// Stop listening
unsubscribe()

Callback reference

CallbackSignatureWhen it fires
onAdd(record: T) => voidA new record matches the filter (created or updated into filter)
onChange(record: T, patches: JSONPatch[]) => voidA matching record is updated
onRemove(record: T) => voidA record no longer matches (deleted or updated out of filter)
onComplete() => voidSubscription ended (idle timeout or shutdown)

JSON Patches

The onChange callback receives an array of RFC 6902 JSON Patches describing what changed.

interface JSONPatch {
	op: 'add' | 'remove' | 'replace' | 'move' | 'copy' | 'test'
	path: string
	value?: unknown
	from?: string
}

Example:

onChange: (user, patches) => {
	for (const patch of patches) {
		if (patch.path === '/score' && patch.op === 'replace') {
			console.log('Score changed to:', patch.value)
		}
	}
}
onChange: (user, patches) => {
	for (const patch of patches) {
		if (patch.path === '/score' && patch.op === 'replace') {
			console.log('Score changed to:', patch.value)
		}
	}
}

Subscription limits

Exceeding configured limits throws a SubscriptionLimitError:

import { SubscriptionLimitError } from '@robojs/sync/flashcore'

try {
	User.subscribe({ where: { status: 'active' }, callbacks: { onAdd: () => {} } })
} catch (error) {
	if (error instanceof SubscriptionLimitError) {
		console.log('Limit exceeded:', error.type)
		// error.type: 'per-model' | 'total' | 'records'
	}
}
import { SubscriptionLimitError } from '@robojs/sync/flashcore'

try {
	User.subscribe({ where: { status: 'active' }, callbacks: { onAdd: () => {} } })
} catch (error) {
	if (error instanceof SubscriptionLimitError) {
		console.log('Limit exceeded:', error.type)
		// error.type: 'per-model' | 'total' | 'records'
	}
}

Client extensions

Query subscription counts from the Flashcore client:

const totalSubs = Flashcore.getSubscriptionCount()
const userSubs = Flashcore.getModelSubscriptionCount('User')
const totalSubs = Flashcore.getSubscriptionCount()
const userSubs = Flashcore.getModelSubscriptionCount('User')

Idle cleanup

Subscriptions are automatically cleaned up after idleTimeout (default: 1 hour). The cleanup check runs every 60 seconds. When a subscription is cleaned up, its onComplete callback fires.

Next Steps

On this page