From 6c5484b87405591ca5d698df9a00a8af4a0659a8 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Fri, 8 May 2026 21:14:11 +0200 Subject: [PATCH] feat(core-realtime): RealtimeHandlerRegistry --- .../src/realtime-handler-registry.test.ts | 44 +++++++++++++++++++ .../src/realtime-handler-registry.ts | 24 ++++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/core-realtime/src/realtime-handler-registry.test.ts create mode 100644 packages/core-realtime/src/realtime-handler-registry.ts diff --git a/packages/core-realtime/src/realtime-handler-registry.test.ts b/packages/core-realtime/src/realtime-handler-registry.test.ts new file mode 100644 index 0000000..c40ebea --- /dev/null +++ b/packages/core-realtime/src/realtime-handler-registry.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect, vi } from "vitest"; +import { z } from "zod"; +import { RealtimeHandlerRegistry } from "@/realtime-handler-registry"; +import { defineRealtimeChannel } from "@/realtime-channel"; + +const ch = defineRealtimeChannel( + "test.ch", + z.object({ x: z.number() }).strict(), + { scope: "authenticated" }, +); + +describe("RealtimeHandlerRegistry", () => { + it("registers and retrieves a handler by channel name", () => { + const reg = new RealtimeHandlerRegistry(); + const handler = vi.fn(); + reg.register({ descriptor: ch, handler }); + const got = reg.getInboundDescriptor("test.ch"); + expect(got).not.toBeNull(); + expect(got!.descriptor.name).toBe("test.ch"); + expect(got!.handler).toBe(handler); + }); + + it("returns null for unknown channel name", () => { + const reg = new RealtimeHandlerRegistry(); + expect(reg.getInboundDescriptor("unknown")).toBeNull(); + }); + + it("list() returns all registered descriptors", () => { + const reg = new RealtimeHandlerRegistry(); + reg.register({ descriptor: ch, handler: vi.fn() }); + expect(reg.list()).toHaveLength(1); + expect(reg.list()[0]!.descriptor.name).toBe("test.ch"); + }); + + it("re-registering the same channel replaces the previous entry", () => { + const reg = new RealtimeHandlerRegistry(); + const h1 = vi.fn(); + const h2 = vi.fn(); + reg.register({ descriptor: ch, handler: h1 }); + reg.register({ descriptor: ch, handler: h2 }); + expect(reg.getInboundDescriptor("test.ch")!.handler).toBe(h2); + expect(reg.list()).toHaveLength(1); + }); +}); diff --git a/packages/core-realtime/src/realtime-handler-registry.ts b/packages/core-realtime/src/realtime-handler-registry.ts new file mode 100644 index 0000000..b0db24f --- /dev/null +++ b/packages/core-realtime/src/realtime-handler-registry.ts @@ -0,0 +1,24 @@ +import type { z } from "zod"; +import type { IInboundDescriptor } from "./realtime-handler.interface"; + +export interface IRealtimeHandlerRegistry { + register(entry: IInboundDescriptor>): void; + getInboundDescriptor(channelName: string): IInboundDescriptor | null; + list(): IInboundDescriptor[]; +} + +export class RealtimeHandlerRegistry implements IRealtimeHandlerRegistry { + private readonly entries = new Map>(); + + register(entry: IInboundDescriptor>): void { + this.entries.set(entry.descriptor.name, entry as IInboundDescriptor); + } + + getInboundDescriptor(channelName: string): IInboundDescriptor | null { + return this.entries.get(channelName) ?? null; + } + + list(): IInboundDescriptor[] { + return Array.from(this.entries.values()); + } +}