@mastra/core
Version:
171 lines • 6.75 kB
TypeScript
import type { MastraServerCache } from '../cache/base.js';
import type { IMastraLogger } from '../logger/index.js';
import { PubSub } from './pubsub.js';
import type { LeaseProvider } from './pubsub.js';
import type { Event, EventCallback, SubscribeOptions } from './types.js';
/**
* Options for CachingPubSub
*/
export interface CachingPubSubOptions {
/**
* Optional prefix for cache keys to namespace events.
* Defaults to 'pubsub:'.
*/
keyPrefix?: string;
/**
* Optional logger for structured logging.
* Falls back to console.error if not provided.
*/
logger?: IMastraLogger;
}
/**
* A PubSub decorator that adds event caching and replay capabilities.
*
* Wraps any PubSub implementation and uses MastraServerCache to:
* - Cache all published events per topic
* - Enable replay of cached events for late subscribers
*
* This enables resumable streams - clients can disconnect and reconnect
* without missing events.
*
* ## Batching
*
* `CachingPubSub` is transparent to `options.batch`: `subscribe()` forwards
* the option to the inner PubSub, and `supportsNativeBatching` mirrors the
* inner's value. Wrapping a non-native inner with `{ batch: {...} }` results
* in unbatched delivery — use an inner that returns
* `supportsNativeBatching === true` (e.g. `EventEmitterPubSub`) if you need
* batched delivery.
*
* @example
* ```typescript
* import { EventEmitterPubSub, CachingPubSub } from '@mastra/core/events';
* import { InMemoryServerCache } from '@mastra/core/cache';
*
* const cache = new InMemoryServerCache();
* const pubsub = new CachingPubSub(new EventEmitterPubSub(), cache);
*
* // Subscribe with replay - receives cached events first, then live
* await pubsub.subscribeWithReplay('my-topic', (event) => {
* console.log(event);
* });
* ```
*/
export declare class CachingPubSub extends PubSub {
private readonly inner;
private readonly cache;
private readonly keyPrefix;
private readonly logger?;
/** Maps original callbacks to their wrapped versions for proper unsubscribe */
private callbackMap;
constructor(inner: PubSub, cache: MastraServerCache, options?: CachingPubSubOptions);
get supportsNativeBatching(): boolean;
/**
* Log an error message using the configured logger or console.error.
*/
private logError;
/**
* Stable key used to deduplicate an event across the cache-replay and
* live-delivery paths.
*
* We cannot dedup on `event.id`: `CachingPubSub.publish` assigns the id and
* caches the event with it, but inner PubSub implementations
* (EventEmitterPubSub, UnixSocketPubSub, …) regenerate `id` inside their own
* `publish`, so the cached copy and the live copy of the SAME publish carry
* different ids. The sequential `index` is assigned here and is preserved by
* every inner implementation, so it matches across both paths. Events without
* an index are never cached (see `publish`), so they can't be replay/live
* duplicated — falling back to `id` for them is safe.
*/
private dedupKey;
/**
* Get the cache key for a topic's event list
*/
private getCacheKey;
/**
* Get the cache key for a topic's index counter
*/
private getCounterKey;
/**
* Publish an event to a topic.
* The event is cached with a sequential index before being published to the inner PubSub.
*
* Uses atomic increment for index assignment to prevent race conditions
* when multiple events are published concurrently.
*/
publish(topic: string, event: Omit<Event, 'id' | 'createdAt' | 'index'>, options?: {
localOnly?: boolean;
}): Promise<void>;
/**
* Subscribe to live events on a topic (no replay).
*/
subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void>;
/**
* Subscribe to a topic with automatic replay of cached events.
* Delegates to {@link subscribeFromOffset} with offset 0.
*/
subscribeWithReplay(topic: string, cb: EventCallback): Promise<void>;
/**
* Subscribe to a topic with replay starting from a specific index.
* More efficient than full replay when the client knows their last position.
*
* Order of operations:
* 1. Subscribe to live events FIRST — buffer deliveries during bootstrap
* 2. Fetch and deliver cached history in order
* 3. Drain the buffer, skipping events already delivered via history
* 4. Switch to passthrough with an index watermark for steady-state dedup
*
* @param topic - The topic to subscribe to
* @param offset - Start replaying from this index (0-based)
* @param cb - Callback invoked for each event
*/
subscribeFromOffset(topic: string, offset: number, cb: EventCallback): Promise<void>;
/**
* Unsubscribe from a topic.
*/
unsubscribe(topic: string, cb: EventCallback): Promise<void>;
/**
* Get historical events for a topic from cache.
*/
getHistory(topic: string, offset?: number): Promise<Event[]>;
/**
* Flush any pending operations on the inner PubSub.
*/
flush(): Promise<void>;
/**
* Expose the inner's {@link LeaseProvider} when it has one, otherwise
* `undefined`. Leasing is a capability of the underlying backend
* (e.g. Redis), not of the caching decorator itself — so rather than
* unconditionally declaring lease methods (which would make
* {@link isLeaseProvider} report `true` even when the inner can't
* coordinate a lock), we surface the inner's capability directly. The
* signals runtime unwraps this so wrapping with caching preserves real
* distributed lease semantics without faking them.
*/
getLeaseProvider(): LeaseProvider | undefined;
/**
* Clear cached events for a specific topic.
* Call this when a stream completes to free memory.
* Also clears the index counter.
*/
clearTopic(topic: string): Promise<void>;
/**
* Get the inner PubSub instance.
* Useful for accessing implementation-specific methods like close().
*/
getInner(): PubSub;
}
/**
* Factory function to wrap a PubSub with caching capabilities.
*
* @example
* ```typescript
* import { withCaching, EventEmitterPubSub } from '@mastra/core/events';
* import { InMemoryServerCache } from '@mastra/core/cache';
*
* const cache = new InMemoryServerCache();
* const pubsub = withCaching(new EventEmitterPubSub(), cache);
* ```
*/
export declare function withCaching(pubsub: PubSub, cache: MastraServerCache, options?: CachingPubSubOptions): CachingPubSub;
//# sourceMappingURL=caching-pubsub.d.ts.map