export function matchChannelTemplate( template: string, candidate: string, ): { params: Record } | null { // No placeholders: exact match. if (!template.includes("{")) { return template === candidate ? { params: {} } : null; } // Build a regex from the template, replacing {name} with named groups. const names: string[] = []; const escaped = template.replace(/[.+?^${}()|[\]\\]/g, "\\$&"); // escape regex specials // The above escapes `{` and `}` too — restore them around placeholders. const pattern = escaped.replace(/\\\{([a-zA-Z_][a-zA-Z0-9_]*)\\\}/g, (_m, name) => { names.push(name); return `([^.]+)`; }); const re = new RegExp(`^${pattern}$`); const match = candidate.match(re); if (!match) return null; const params: Record = {}; names.forEach((name, i) => { params[name] = match[i + 1]!; }); return { params }; }