UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

130 lines (129 loc) 6.27 kB
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js"; import { n as resolveGlobalDedupeCache } from "./dedupe-gst1CUro.js"; import { T as resolveDirectPluginRegistrationOwner, g as getPluginRegistrationContext, x as requireActivePluginChannelRegistry } from "./runtime-BL4wZfTq.js"; //#region src/plugins/interactive-shared.ts function toPluginInteractiveRegistryKey(channel, namespace) { return `${normalizeOptionalLowercaseString(channel) ?? ""}:${namespace.trim()}`; } function normalizePluginInteractiveNamespace(namespace) { return namespace.trim(); } function validatePluginInteractiveNamespace(namespace) { if (!namespace.trim()) return "Interactive handler namespace cannot be empty"; if (!/^[A-Za-z0-9._-]+$/.test(namespace.trim())) return "Interactive handler namespace must contain only letters, numbers, dots, underscores, and hyphens"; return null; } function resolvePluginInteractiveMatch(params) { const trimmedData = params.data.trim(); if (!trimmedData) return null; const separatorIndex = trimmedData.indexOf(":"); const namespace = separatorIndex >= 0 ? trimmedData.slice(0, separatorIndex) : normalizePluginInteractiveNamespace(trimmedData); const registration = params.interactiveHandlers.get(toPluginInteractiveRegistryKey(params.channel, namespace)); if (!registration) return null; return { registration, namespace, payload: separatorIndex >= 0 ? trimmedData.slice(separatorIndex + 1) : "" }; } //#endregion //#region src/plugins/interactive-state.ts const PLUGIN_INTERACTIVE_STATE_KEY = Symbol.for("openclaw.pluginInteractiveState"); const PLUGIN_INTERACTIVE_CALLBACK_DEDUPE_KEY = Symbol.for("openclaw.pluginInteractiveCallbackDedupe"); function hydrateInteractiveState(value) { const state = typeof value === "object" && value !== null ? value : void 0; return { callbackDedupe: resolveGlobalDedupeCache(PLUGIN_INTERACTIVE_CALLBACK_DEDUPE_KEY, { ttlMs: 3e5, maxSize: 4096 }), inflightCallbackDedupe: state?.inflightCallbackDedupe instanceof Set ? state.inflightCallbackDedupe : /* @__PURE__ */ new Set() }; } function getState() { const globalStore = globalThis; const hydrated = hydrateInteractiveState(globalStore[PLUGIN_INTERACTIVE_STATE_KEY]); globalStore[PLUGIN_INTERACTIVE_STATE_KEY] = hydrated; return hydrated; } /** Claims an interactive callback dedupe key while the callback is in flight. */ function claimPluginInteractiveCallbackDedupe(dedupeKey, now = Date.now()) { if (!dedupeKey) return true; const state = getState(); if (state.inflightCallbackDedupe.has(dedupeKey) || state.callbackDedupe.peek(dedupeKey, now)) return false; state.inflightCallbackDedupe.add(dedupeKey); return true; } /** Commits an interactive callback dedupe key after successful handling. */ function commitPluginInteractiveCallbackDedupe(dedupeKey, now = Date.now()) { if (!dedupeKey) return; const state = getState(); state.inflightCallbackDedupe.delete(dedupeKey); state.callbackDedupe.check(dedupeKey, now); } /** Releases an in-flight interactive callback dedupe claim without committing it. */ function releasePluginInteractiveCallbackDedupe(dedupeKey) { if (!dedupeKey) return; getState().inflightCallbackDedupe.delete(dedupeKey); } /** Clears plugin interactive handlers and callback dedupe state. */ function clearPluginInteractiveHandlersState() { const state = getState(); state.callbackDedupe.clear(); state.inflightCallbackDedupe.clear(); } //#endregion //#region src/plugins/interactive-registry.ts function requireInteractiveRegistrationRegistry() { return getPluginRegistrationContext()?.registry ?? requireActivePluginChannelRegistry(); } function asInteractiveHandlerLookup(registrations) { return { get: (key) => registrations.find((entry) => toPluginInteractiveRegistryKey(entry.channel, entry.namespace) === key) }; } /** Resolves a handler from registry-owned registrations without changing global state. */ function resolvePluginInteractiveRegistrationsMatch(registrations, channel, data) { return resolvePluginInteractiveMatch({ interactiveHandlers: asInteractiveHandlerLookup(registrations), channel, data }); } /** Registers one plugin interactive namespace for a channel. */ function registerPluginInteractiveHandlerWithOptions(registrations, pluginId, registration, opts) { const namespace = normalizePluginInteractiveNamespace(registration.namespace); const validationError = validatePluginInteractiveNamespace(namespace); if (validationError) return { ok: false, error: validationError }; const key = toPluginInteractiveRegistryKey(registration.channel, namespace); const existing = registrations.find((entry) => toPluginInteractiveRegistryKey(entry.channel, entry.namespace) === key); if (existing) return { ok: false, error: `Interactive handler namespace "${namespace}" already registered by plugin "${existing.pluginId}"` }; registrations.push({ ...registration, namespace, channel: normalizeOptionalLowercaseString(registration.channel) ?? "", pluginId, pluginName: opts?.pluginName, pluginRoot: opts?.pluginRoot }); return { ok: true }; } /** Registers one process-global interactive handler. */ function registerPluginInteractiveHandler(pluginId, registration, opts) { return registerPluginInteractiveHandlerWithOptions(requireInteractiveRegistrationRegistry().interactiveHandlers, resolveDirectPluginRegistrationOwner(pluginId) ?? pluginId, registration, opts); } /** Registers one handler whose lifetime follows its owning plugin registry. */ function registerPluginInteractiveHandlerInRegistry(registry, pluginId, registration, opts) { return registerPluginInteractiveHandlerWithOptions(registry.interactiveHandlers, pluginId, registration, opts); } /** Clears all active plugin interactive handlers. */ function clearPluginInteractiveHandlers() { requireActivePluginChannelRegistry().interactiveHandlers.length = 0; clearPluginInteractiveHandlersState(); } //#endregion export { claimPluginInteractiveCallbackDedupe as a, resolvePluginInteractiveRegistrationsMatch as i, registerPluginInteractiveHandler as n, commitPluginInteractiveCallbackDedupe as o, registerPluginInteractiveHandlerInRegistry as r, releasePluginInteractiveCallbackDedupe as s, clearPluginInteractiveHandlers as t };