feat: add client rule registry

This commit is contained in:
nav
2026-04-08 22:39:49 +00:00
parent 58818e11d1
commit 07c2438fb8
2 changed files with 92 additions and 0 deletions

85
plugin/core/rules.ts Normal file
View File

@@ -0,0 +1,85 @@
import { BUILTIN_RULE, CodecError, parseRuleMessage } from "../../../Yonexus.Protocol/src/index.js";
export type ClientRuleProcessor = (message: string) => unknown;
export class ClientRuleRegistryError extends Error {
constructor(message: string) {
super(message);
this.name = "ClientRuleRegistryError";
}
}
export interface ClientRuleRegistry {
readonly size: number;
registerRule(rule: string, processor: ClientRuleProcessor): void;
hasRule(rule: string): boolean;
dispatch(raw: string): boolean;
getRules(): readonly string[];
}
export class YonexusClientRuleRegistry implements ClientRuleRegistry {
private readonly rules = new Map<string, ClientRuleProcessor>();
get size(): number {
return this.rules.size;
}
registerRule(rule: string, processor: ClientRuleProcessor): void {
const normalizedRule = this.normalizeRule(rule);
if (this.rules.has(normalizedRule)) {
throw new ClientRuleRegistryError(
`Rule '${normalizedRule}' is already registered`
);
}
this.rules.set(normalizedRule, processor);
}
hasRule(rule: string): boolean {
return this.rules.has(rule.trim());
}
dispatch(raw: string): boolean {
const parsed = parseRuleMessage(raw);
const processor = this.rules.get(parsed.ruleIdentifier);
if (!processor) {
return false;
}
processor(raw);
return true;
}
getRules(): readonly string[] {
return [...this.rules.keys()];
}
private normalizeRule(rule: string): string {
const normalizedRule = rule.trim();
if (!normalizedRule) {
throw new ClientRuleRegistryError("Rule identifier must be a non-empty string");
}
if (normalizedRule === BUILTIN_RULE) {
throw new ClientRuleRegistryError(
`Rule identifier '${BUILTIN_RULE}' is reserved`
);
}
try {
parseRuleMessage(`${normalizedRule}::probe`);
} catch (error) {
if (error instanceof CodecError) {
throw new ClientRuleRegistryError(error.message);
}
throw error;
}
return normalizedRule;
}
}
export function createClientRuleRegistry(): ClientRuleRegistry {
return new YonexusClientRuleRegistry();
}