Portal Community

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.