Advanced
observe()
Extend any object with event capabilities.
typescript
observe<C>(component: C, options?: ObserveOptions): Child<C, Shape>Parameters:
component- Any object to extend with event methodsoptions- Optional{ signal?: AbortSignal }for automatic cleanup
Returns: Component with added event methods and cleanup function
Example:
typescript
const modal = { isOpen: false }
const enhancedModal = observer.observe(modal)
enhancedModal.on('open', () => {
enhancedModal.isOpen = true
})
enhancedModal.emit('open')
enhancedModal.cleanup() // Cleans up only the observed component's listenersListener Transfer & Copy
Move or duplicate listeners between observer instances. Useful when cloning engines (e.g. a FetchEngine) and carrying over observability listeners to the new instance.
typescript
const source = new ObserverEngine<AppEvents>();
const target = new ObserverEngine<AppEvents>();
source.on('analytics', trackEvent);
source.on('user:login', logLogin);
// Transfer: source loses listeners, target gains them
ObserverEngine.transfer(source, target);
// Copy: source keeps listeners, target also gets them
ObserverEngine.copy(source, target);Both methods stack with existing target listeners — they won't overwrite what's already there.
Filtering
Use filter (opt-in) and exclude (opt-out) to selectively transfer:
typescript
// Only transfer specific events
ObserverEngine.transfer(source, target, {
filter: ['analytics', /^user:/]
});
// Transfer everything except internal events
ObserverEngine.transfer(source, target, {
exclude: [/^internal:/]
});
// Compose: filter narrows first, exclude removes from that set
ObserverEngine.transfer(source, target, {
filter: [/^fetch:/],
exclude: ['fetch:debug']
});Error Types
EventError
Error thrown by EventGenerator methods.
typescript
class EventError extends Error {
event?: string | RegExp
listener?: Function
data?: unknown
constructor(message: string, opts?: {
event: string | RegExp
listener: Function
data: unknown
})
}
// Type guard
function isEventError(err: unknown): err is EventErrorUsage:
typescript
const [result, err] = await attempt(() => generator.next())
if (err && isEventError(err)) {
console.log('Event error:', err.event, err.data)
}EventTrace
Debug error with stack trace information.
typescript
class EventTrace extends Error {
listener: Function | null
data: unknown | null
func: string
event: string
stack: string
}Helper Functions
makeEventTracer()
Create debug trace for event operations.
typescript
makeEventTracer(
event: string,
caller: string,
listenerOrData?: Function | unknown
): EventTraceisEventError()
Type guard for EventError instances.
typescript
isEventError(err: unknown): err is EventErrorType Definitions
Core Types
typescript
// Event shape constraint
type Events<Shape> = keyof Shape
// Event data extraction
type EventData<S, E extends Events<S> | RegExp = Events<S>> =
E extends Events<S>
? S[E]
: E extends RegExp
? ObserverEngine.RgxEmitData<S>
: S[Events<S>]ObserverEngine Types
typescript
namespace ObserverEngine {
// Event callback signature
interface EventCallback<Shape> {
(data: Shape, info?: { event: string, listener: Function }): void
}
// Regex emit data format
type RgxEmitData<Shape> = {
event: Events<Shape>
data: Shape[Events<Shape>]
}
// Cleanup function
type Cleanup = () => void
// Component observation types
type Component<Ev> = {
on: ObserverEngine<Ev>['on']
once: ObserverEngine<Ev>['once']
emit: ObserverEngine<Ev>['emit']
off: ObserverEngine<Ev>['off']
}
type Child<C, Ev> = C & Component<Ev> & {
cleanup: Cleanup
}
// Listener options (AbortSignal support)
type ListenerOptions = {
signal?: AbortSignal
}
// Observe options (AbortSignal support)
type ObserveOptions = {
signal?: AbortSignal
}
// Transfer/copy options
type TransferOptions<Ev> = {
filter?: (Events<Ev> | RegExp)[]
exclude?: (Events<Ev> | RegExp)[]
}
// Spy function names
type FuncName = 'on' | 'once' | 'off' | 'emit' | 'cleanup'
// Spy action payload
type SpyAction<Ev> = {
event: keyof Ev | RegExp | '*'
listener?: Function | null
data?: unknown
fn: FuncName
context: ObserverEngine<any>
}
// Configuration types
interface Spy<Ev> {
(action: SpyAction<Ev>): void
}
interface EmitValidator<Ev> {
(event: keyof Ev, data: Ev[keyof Ev], context: ObserverEngine<Ev>): void
(event: RegExp, data: unknown, context: ObserverEngine<Ev>): void
(event: '*', data: unknown, context: ObserverEngine<Ev>): void
}
type Options<Ev> = {
name?: string
spy?: Spy<Ev>
emitValidator?: EmitValidator<Ev>
signal?: AbortSignal
}
// Full component with observe and $observer access
type Instance<Ev> = Component<Ev> & {
observe: ObserverEngine<Ev>['observe']
$observer: ObserverEngine<Ev>
}
}Promise Extensions
typescript
// Enhanced promise with cleanup
class EventPromise<T> extends Promise<T> {
cleanup?: () => void
reject?: (err: Error | string) => void
resolve?: (value: T) => void
}
// Deferred event with cleanup
class DeferredEvent<T> extends Deferred<T> {
promise: EventPromise<T>
cleanup?: () => void
}Best Practices
Error Handling
typescript
// Always use type guards
const [result, err] = await attempt(() => generator.next())
if (err && isEventError(err)) {
console.log('Generator error:', err.event)
}
// Handle queue errors
queue.on('error', ({ error, data }) => {
console.error('Queue error:', error.message, data)
})Memory Management
typescript
// Always cleanup generators
const generator = observer.on('event')
try {
for await (const data of generator) {
// Process data
}
} finally {
generator.cleanup()
}
// Cleanup components
const enhanced = observer.observe(component)
enhanced.cleanup() // ⚠️ WARNING: Removes ALL listeners from the observerPerformance Optimization
typescript
// Use regex efficiently
const userEvents = observer.on(/^user:/)
// Better than multiple individual listeners
// Configure queues appropriately
const queue = observer.queue('event', processor, {
concurrency: 5, // Balance throughput vs resources
rateLimitCapacity: 100, // Prevent overwhelming downstream
taskTimeoutMs: 30000, // Prevent hanging tasks
processIntervalMs: 10 // Avoid tight loops
})