EdgeStream
TopicMatcher
TopicMatcher is the matching engine behind EdgeStream subscriptions. It evaluates patterns against topics using string operations — no regex compilation per call, designed for high-frequency invocation during message delivery.
Implementation Overview
TopicMatcher implements ITopicMatcher and provides four methods:
export interface ITopicMatcher {
matches(pattern: string, topic: string): boolean;
getParts(pattern: string): { prefix: string; isWildcard: boolean; level: number };
validate(pattern: string): void; // throws on invalid pattern
getMatchingPatterns(topic: string, patterns: string[]): string[];
}
The matches() Algorithm
// From source — efficient string-based matching
matches(pattern: string, topic: string): boolean {
if (!pattern || !topic) return false;
// 1. Exact match
if (pattern === topic) return true;
// 2. Wildcard match: pattern ends with .*
if (pattern.endsWith('.*')) {
const prefix = pattern.slice(0, -2); // remove .*
// topic must start with prefix + '.' + at least one character
return topic.startsWith(`${prefix}.`) && topic.length > prefix.length + 1;
}
return false;
}
// Examples:
matcher.matches('workflow.*', 'workflow.started') // → true
matcher.matches('workflow.*', 'workflow.') // → false (empty segment)
matcher.matches('workflow.*', 'workflow') // → false (no dot after prefix)
matcher.matches('workflow.*', 'workflow.node.done') // → false (two levels)
matcher.matches('workflow.started', 'workflow.started') // → true (exact)
getParts()
const matcher = new TopicMatcher();
matcher.getParts('workflow.*');
// → { prefix: 'workflow', isWildcard: true, level: 1 }
matcher.getParts('workflow.execution.*');
// → { prefix: 'workflow.execution', isWildcard: true, level: 2 }
matcher.getParts('workflow.started');
// → { prefix: 'workflow.started', isWildcard: false, level: 1 }
getMatchingPatterns()
Useful for finding which subscriptions should receive a given topic — used internally by SubscriptionManager:
const patterns = ['workflow.*', 'agent.*', 'workflow.started', 'notifications.*'];
const matching = matcher.getMatchingPatterns('workflow.started', patterns);
// → ['workflow.*', 'workflow.started']
Using TopicMatcher Directly
import { TopicMatcher } from 'edge-stream-js';
const matcher = new TopicMatcher();
// Validate before using as a subscription topic
try {
matcher.validate('workflow.*'); // OK
matcher.validate('workflow.*.events'); // Throws: wildcard not at end
} catch (e) {
console.error('Invalid topic pattern:', e.message);
}
// Check a match
const isMatch = matcher.matches('workflow.*', 'workflow.completed');
console.log(isMatch); // true
// Find matching subscriptions
const activePatterns = ['workflow.*', 'hil.*', 'notifications.*'];
const matched = matcher.getMatchingPatterns('workflow.completed', activePatterns);
console.log(matched); // ['workflow.*']
Design: No Regex
TopicMatcher intentionally avoids regex to prevent per-call regex compilation overhead. For high-throughput servers processing thousands of messages per second, the string-based approach is significantly faster. If you need more complex matching (multi-level wildcards, negation), implement a custom filter hook instead of relying on the subscription pattern.