Discord: share component registry across module instances

This commit is contained in:
huntharo
2026-03-20 16:28:41 -04:00
parent 1fdff248f3
commit aaa70cd185
2 changed files with 43 additions and 3 deletions

View File

@@ -1,9 +1,23 @@
import type { DiscordComponentEntry, DiscordModalEntry } from "./components.js";
const DEFAULT_COMPONENT_TTL_MS = 30 * 60 * 1000;
const DISCORD_COMPONENT_ENTRIES_KEY = Symbol.for("openclaw.discord.componentEntries");
const DISCORD_MODAL_ENTRIES_KEY = Symbol.for("openclaw.discord.modalEntries");
const componentEntries = new Map<string, DiscordComponentEntry>();
const modalEntries = new Map<string, DiscordModalEntry>();
function resolveGlobalMap<TKey, TValue>(key: symbol): Map<TKey, TValue> {
const globalStore = globalThis as Record<PropertyKey, unknown>;
if (globalStore[key] instanceof Map) {
return globalStore[key] as Map<TKey, TValue>;
}
const created = new Map<TKey, TValue>();
globalStore[key] = created;
return created;
}
const componentEntries = resolveGlobalMap<string, DiscordComponentEntry>(
DISCORD_COMPONENT_ENTRIES_KEY,
);
const modalEntries = resolveGlobalMap<string, DiscordModalEntry>(DISCORD_MODAL_ENTRIES_KEY);
function isExpired(entry: { expiresAt?: number }, now: number) {
return typeof entry.expiresAt === "number" && entry.expiresAt <= now;

View File

@@ -1,5 +1,5 @@
import { MessageFlags } from "discord-api-types/v10";
import { describe, expect, it, beforeEach } from "vitest";
import { beforeEach, describe, expect, it } from "vitest";
import {
clearDiscordComponentEntries,
registerDiscordComponentEntries,
@@ -78,6 +78,8 @@ describe("discord component registry", () => {
clearDiscordComponentEntries();
});
const componentsRegistryModuleUrl = new URL("./components-registry.ts", import.meta.url).href;
it("registers and consumes component entries", () => {
registerDiscordComponentEntries({
entries: [{ id: "btn_1", kind: "button", label: "Confirm" }],
@@ -102,4 +104,28 @@ describe("discord component registry", () => {
expect(consumed?.id).toBe("btn_1");
expect(resolveDiscordComponentEntry({ id: "btn_1" })).toBeNull();
});
it("shares registry state across duplicate module instances", async () => {
const first = (await import(
`${componentsRegistryModuleUrl}?t=first-${Date.now()}`
)) as typeof import("./components-registry.js");
const second = (await import(
`${componentsRegistryModuleUrl}?t=second-${Date.now()}`
)) as typeof import("./components-registry.js");
first.clearDiscordComponentEntries();
first.registerDiscordComponentEntries({
entries: [{ id: "btn_shared", kind: "button", label: "Shared" }],
modals: [],
});
expect(second.resolveDiscordComponentEntry({ id: "btn_shared", consume: false })).toMatchObject(
{
id: "btn_shared",
label: "Shared",
},
);
second.clearDiscordComponentEntries();
});
});