@nhtio/rocket-chat-openclaw-integration 0.1.0-master-7f84cdcb

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/rocketchat/config/defaults.ts","../src/rocketchat/config/resolve_account.ts","../src/rocketchat/policy/allowlist.ts","../src/rocketchat/policy/mentions.ts","../src/rocketchat/policy/policy.ts","../src/rocketchat/ddp/fake_transport.ts","../src/rocketchat/ddp/protocol.ts","../src/rocketchat/ddp/methods.ts","../src/rocketchat/ddp/auth.ts","../src/rocketchat/ddp/subscriptions.ts","../src/rocketchat/client.ts","../src/rocketchat/inbound/decode_message.ts","../src/rocketchat/inbound/classify_chat_type.ts","../src/rocketchat/inbound/session_keys.ts","../src/rocketchat/inbound/process_inbound.ts","../src/rocketchat/rest/post_message.ts","../src/rocketchat/rest/react.ts","../src/rocketchat/rest/me.ts","../src/rocketchat/commands/parse.ts","../src/rocketchat/commands/dispatch.ts","../src/rocketchat/security/revocation.ts","../src/rocketchat/security/revalidate.ts","../src/openclaw/runtime/account_runner.ts","../src/index.ts"],"sourcesContent":["import type { RocketChatChannelConfig, RocketChatDmPolicy, RocketChatGroupPolicy } from './types'\n\n/**\n * Default DM policy for Rocket.Chat.\n *\n * v1 default is `pairing` (Slack-aligned).\n */\nexport const DEFAULT_DM_POLICY: RocketChatDmPolicy = 'pairing'\n\n/**\n * Default group policy for Rocket.Chat.\n *\n * v1 default is `allowlist` (fail closed).\n */\nexport const DEFAULT_GROUP_POLICY: RocketChatGroupPolicy = 'allowlist'\n\n/**\n * Default setting for mention gating in group chats.\n */\nexport const DEFAULT_REQUIRE_MENTION = true\n\n/**\n * Compute the effective channel config.\n *\n * This applies defaults, but does not validate credentials.\n */\nexport function resolveChannelDefaults(\n cfg: RocketChatChannelConfig | undefined\n): Required<Pick<RocketChatChannelConfig, 'dmPolicy' | 'groupPolicy'>> & RocketChatChannelConfig {\n return {\n ...cfg,\n dmPolicy: cfg?.dmPolicy ?? DEFAULT_DM_POLICY,\n groupPolicy: cfg?.groupPolicy ?? DEFAULT_GROUP_POLICY,\n }\n}\n","import { DEFAULT_DM_POLICY, DEFAULT_GROUP_POLICY, DEFAULT_REQUIRE_MENTION } from './defaults'\nimport type {\n RocketChatAccountConfig,\n RocketChatChannelConfig,\n RocketChatOpenClawConfig,\n RocketChatRoomConfig,\n} from './types'\n\n/**\n * Resolved account config for a specific OpenClaw agent id.\n */\nexport interface ResolvedRocketChatAccount {\n /** OpenClaw agent id / account id key. */\n accountId: string\n\n /** Whether this account is enabled after all merges. */\n enabled: boolean\n\n /** Rocket.Chat server base URL (https://...). */\n serverUrl: string\n\n /** Rocket.Chat bot user id. */\n userId: string\n\n /** Rocket.Chat bot username (for mention gating). */\n username: string\n\n /** Rocket.Chat personal access token. */\n pat: string\n\n /** Effective DM policy. */\n dmPolicy: NonNullable<RocketChatChannelConfig['dmPolicy']>\n\n /** Effective group policy. */\n groupPolicy: NonNullable<RocketChatChannelConfig['groupPolicy']>\n\n /** Effective sender allowlist. */\n allowFrom: string[]\n\n /** Effective operator allowlist for risky commands. */\n commandAllowFrom: string[]\n\n /** Effective per-room config. */\n rooms: Record<string, RocketChatRoomConfig>\n\n /** Default mention gating for group chats when room override is not present. */\n defaultRequireMention: boolean\n}\n\nfunction normalizeAccountId(raw: string): string {\n const trimmed = raw.trim()\n if (!trimmed) {\n throw new Error('rocketchat: accountId is required')\n }\n return trimmed\n}\n\nfunction normalizeHttpsUrl(raw: string, pathLabel: string): string {\n const trimmed = raw.trim()\n if (!trimmed) {\n throw new Error(`rocketchat: ${pathLabel} is required`)\n }\n if (!trimmed.startsWith('https://')) {\n throw new Error(`rocketchat: ${pathLabel} must start with https:// (got ${trimmed})`)\n }\n return trimmed.replace(/\\/$/, '')\n}\n\nfunction normalizeAllowlist(raw?: string[]): string[] {\n return (raw ?? []).map((v) => v.trim()).filter((v) => v.length > 0)\n}\n\nfunction mergeRooms(\n base: Record<string, RocketChatRoomConfig> | undefined,\n override: Record<string, RocketChatRoomConfig> | undefined\n): Record<string, RocketChatRoomConfig> {\n return {\n ...(base ?? {}),\n ...(override ?? {}),\n }\n}\n\n/**\n * Resolve the effective Rocket.Chat account configuration for a given agent id.\n *\n * Merging rules:\n * - Top-level `channels.rocketchat` is the base.\n * - `channels.rocketchat.accounts[accountId]` overrides base.\n *\n * Validation rules:\n * - If the merged account is enabled, it must have: serverUrl, userId, username, pat.\n */\nexport function resolveRocketChatAccount(params: {\n cfg: RocketChatOpenClawConfig\n accountId: string\n}): ResolvedRocketChatAccount {\n const accountId = normalizeAccountId(params.accountId)\n const channel: RocketChatChannelConfig | undefined = params.cfg.channels?.rocketchat\n\n const baseEnabled = channel?.enabled !== false\n const override: RocketChatAccountConfig | undefined = channel?.accounts?.[accountId]\n const accountEnabled = override?.enabled !== false\n const enabled = baseEnabled && accountEnabled\n\n const serverUrlRaw = override?.serverUrl ?? channel?.serverUrl\n const userIdRaw = override?.userId\n const usernameRaw = override?.username\n const patRaw = override?.pat\n\n if (!enabled) {\n // For disabled accounts we still return a fully-typed object, but with empty\n // credential fields. Callers should branch on enabled.\n return {\n accountId,\n enabled: false,\n serverUrl: serverUrlRaw?.trim() || '',\n userId: userIdRaw?.trim() || '',\n username: usernameRaw?.trim() || '',\n pat: patRaw?.trim() || '',\n dmPolicy: override?.dmPolicy ?? channel?.dmPolicy ?? DEFAULT_DM_POLICY,\n groupPolicy: override?.groupPolicy ?? channel?.groupPolicy ?? DEFAULT_GROUP_POLICY,\n allowFrom: normalizeAllowlist(override?.allowFrom ?? channel?.allowFrom),\n commandAllowFrom: normalizeAllowlist(override?.commandAllowFrom ?? channel?.commandAllowFrom),\n rooms: mergeRooms(channel?.rooms, override?.rooms),\n defaultRequireMention: DEFAULT_REQUIRE_MENTION,\n }\n }\n\n const serverUrl = normalizeHttpsUrl(serverUrlRaw ?? '', 'serverUrl')\n const userId = (userIdRaw ?? '').trim()\n const username = (usernameRaw ?? '').trim()\n const pat = (patRaw ?? '').trim()\n\n if (!userId) throw new Error(`rocketchat: userId is required for ${accountId}`)\n if (!username) throw new Error(`rocketchat: username is required for ${accountId}`)\n if (!pat) throw new Error(`rocketchat: pat is required for ${accountId}`)\n\n return {\n accountId,\n enabled: true,\n serverUrl,\n userId,\n username,\n pat,\n dmPolicy: override?.dmPolicy ?? channel?.dmPolicy ?? DEFAULT_DM_POLICY,\n groupPolicy: override?.groupPolicy ?? channel?.groupPolicy ?? DEFAULT_GROUP_POLICY,\n allowFrom: normalizeAllowlist(override?.allowFrom ?? channel?.allowFrom),\n commandAllowFrom: normalizeAllowlist(override?.commandAllowFrom ?? channel?.commandAllowFrom),\n rooms: mergeRooms(channel?.rooms, override?.rooms),\n defaultRequireMention: DEFAULT_REQUIRE_MENTION,\n }\n}\n","import type { RocketChatSender } from './chat_types'\n\n/**\n * Allowlist match result.\n */\nexport interface AllowlistMatch {\n /** True when the sender matches the allowlist. */\n allowed: boolean\n\n /** Optional reason for denial (for logging/debugging). */\n reason?: string\n}\n\nfunction normalizeEntry(raw: string): string {\n return raw.trim().toLowerCase()\n}\n\nfunction normalizeSender(sender: RocketChatSender): string[] {\n const entries: string[] = []\n if (sender.id) entries.push(normalizeEntry(sender.id))\n if (sender.username) entries.push(normalizeEntry(sender.username))\n return entries\n}\n\n/**\n * Match a sender against an allowlist.\n *\n * Supported allowlist formats (v1):\n * - `\"*\"` wildcard\n * - raw user id\n * - raw username (without @)\n */\nexport function matchAllowlist(params: {\n allowFrom: string[]\n sender: RocketChatSender\n}): AllowlistMatch {\n const allowFrom = params.allowFrom.map(normalizeEntry)\n if (allowFrom.includes('*')) {\n return { allowed: true }\n }\n\n const senderKeys = normalizeSender(params.sender)\n if (senderKeys.length === 0) {\n return { allowed: false, reason: 'missing-sender-id' }\n }\n\n const allowed = senderKeys.some((k) => allowFrom.includes(k))\n return allowed ? { allowed: true } : { allowed: false, reason: 'not-allowlisted' }\n}\n","/**\n * Check whether a message includes a mention of the bot.\n *\n * v1 decision: implement this using a simple substring check (no regex).\n */\nexport function messageMentionsBot(params: { text: string; botUsername: string }): boolean {\n const text = params.text\n const botUsername = params.botUsername.trim().replace(/^@/, '')\n if (!botUsername) return false\n return text.includes(`@${botUsername}`)\n}\n","import { matchAllowlist } from './allowlist'\nimport { messageMentionsBot } from './mentions'\nimport type { RocketChatChatType, RocketChatSender } from './chat_types'\nimport type { ResolvedRocketChatAccount } from '../config/resolve_account'\n\n/**\n * The result of applying policy checks to an inbound message.\n */\nexport interface PolicyDecision {\n allowed: boolean\n reason?: string\n}\n\n/**\n * Decide whether an inbound message is authorized to be processed.\n *\n * This is the single top-level policy function for v1.\n */\nexport function authorizeInboundMessage(params: {\n account: ResolvedRocketChatAccount\n chatType: RocketChatChatType\n roomId: string\n sender: RocketChatSender\n text: string\n}): PolicyDecision {\n if (!params.account.enabled) {\n return { allowed: false, reason: 'account-disabled' }\n }\n\n const baseAllowMatch = matchAllowlist({\n allowFrom: params.account.allowFrom,\n sender: params.sender,\n })\n\n if (params.chatType === 'direct') {\n if (params.account.dmPolicy === 'disabled') {\n return { allowed: false, reason: 'dm-disabled' }\n }\n\n if (params.account.dmPolicy === 'open') {\n // open still requires explicit wildcard or direct allowlist match.\n return baseAllowMatch.allowed\n ? { allowed: true }\n : { allowed: false, reason: baseAllowMatch.reason }\n }\n\n if (params.account.dmPolicy === 'allowlist') {\n return baseAllowMatch.allowed\n ? { allowed: true }\n : { allowed: false, reason: baseAllowMatch.reason }\n }\n\n // pairing (v1): treat as allowlist until pairing flow is implemented.\n return baseAllowMatch.allowed\n ? { allowed: true }\n : { allowed: false, reason: baseAllowMatch.reason ?? 'pairing-required' }\n }\n\n // group\n if (params.account.groupPolicy === 'disabled') {\n return { allowed: false, reason: 'group-disabled' }\n }\n\n const roomCfg = params.account.rooms[params.roomId]\n const requireMention = roomCfg?.requireMention ?? params.account.defaultRequireMention\n if (requireMention) {\n const mentioned = messageMentionsBot({\n text: params.text,\n botUsername: params.account.username,\n })\n if (!mentioned) {\n return { allowed: false, reason: 'missing-mention' }\n }\n }\n\n if (params.account.groupPolicy === 'allowlist') {\n // Room must be allowlisted under account.rooms. Using the presence of a room key\n // as the allowlist signal is consistent with Slack-style allowlist-by-id.\n if (!roomCfg) {\n return { allowed: false, reason: 'room-not-allowlisted' }\n }\n }\n\n if (!baseAllowMatch.allowed) {\n return { allowed: false, reason: baseAllowMatch.reason }\n }\n\n // Optional per-room user allowlist.\n const roomUsers = roomCfg?.users ?? []\n if (roomUsers.length > 0) {\n const roomMatch = matchAllowlist({ allowFrom: roomUsers, sender: params.sender })\n if (!roomMatch.allowed) {\n return { allowed: false, reason: roomMatch.reason ?? 'room-user-not-allowlisted' }\n }\n }\n\n return { allowed: true }\n}\n\n/**\n * Determine whether a prefix command is allowed.\n *\n * Risky commands (!model, !stop) require operator authorization.\n */\nexport function authorizeCommand(params: {\n account: ResolvedRocketChatAccount\n chatType: RocketChatChatType\n sender: RocketChatSender\n command: 'status' | 'model' | 'stop'\n}): PolicyDecision {\n if (!params.account.enabled) {\n return { allowed: false, reason: 'account-disabled' }\n }\n\n // Base sender must be allowlisted for all commands.\n const baseAllowMatch = matchAllowlist({\n allowFrom: params.account.allowFrom,\n sender: params.sender,\n })\n if (!baseAllowMatch.allowed) {\n return { allowed: false, reason: baseAllowMatch.reason }\n }\n\n if (params.command === 'status') {\n return { allowed: true }\n }\n\n // Operator allowlist.\n const operatorAllowFrom = params.account.commandAllowFrom\n\n // Default deny for risky commands in group chats when unset/empty.\n if (params.chatType === 'group' && operatorAllowFrom.length === 0) {\n return { allowed: false, reason: 'operator-allowlist-empty' }\n }\n\n const operatorMatch = matchAllowlist({\n allowFrom: operatorAllowFrom,\n sender: params.sender,\n })\n return operatorMatch.allowed\n ? { allowed: true }\n : { allowed: false, reason: operatorMatch.reason ?? 'not-operator' }\n}\n","import type { DdpTransport } from './transport'\n\n/**\n * A deterministic in-memory transport for unit testing DDP protocol logic.\n */\nexport class FakeDdpTransport implements DdpTransport {\n private messageHandlers: Array<(msg: unknown) => void> = []\n private closeHandlers: Array<(info?: { code?: number; reason?: string }) => void> = []\n\n /** Outbound frames sent by the client. */\n public readonly sent: unknown[] = []\n\n /** Whether close() has been called. */\n public closed = false\n\n onMessage(cb: (msg: unknown) => void): void {\n this.messageHandlers.push(cb)\n }\n\n onClose(cb: (info?: { code?: number; reason?: string }) => void): void {\n this.closeHandlers.push(cb)\n }\n\n send(msg: unknown): void {\n this.sent.push(msg)\n }\n\n close(info?: { code?: number; reason?: string }): void {\n this.closed = true\n for (const cb of this.closeHandlers) cb(info)\n }\n\n /**\n * Inject an inbound message as if it arrived from Rocket.Chat.\n */\n inject(msg: unknown): void {\n for (const cb of this.messageHandlers) cb(msg)\n }\n}\n","import type { DdpTransport } from './transport'\n\n/** DDP connect frame. */\nexport interface DdpConnectFrame {\n msg: 'connect'\n version: '1'\n support: ['1']\n}\n\n/** DDP ping frame. */\nexport interface DdpPingFrame {\n msg: 'ping'\n}\n\n/** DDP pong frame. */\nexport interface DdpPongFrame {\n msg: 'pong'\n}\n\n/**\n * Create the initial DDP connect frame.\n */\nexport function makeConnectFrame(): DdpConnectFrame {\n return { msg: 'connect', version: '1', support: ['1'] }\n}\n\n/**\n * Install baseline protocol handlers.\n *\n * Responsibilities:\n * - send initial connect\n * - respond to ping with pong\n */\nexport function installDdpProtocol(params: { transport: DdpTransport }): {\n sendConnect: () => void\n} {\n params.transport.onMessage((msg) => {\n const m = msg as Partial<DdpPingFrame> | null\n if (m && m.msg === 'ping') {\n const pong: DdpPongFrame = { msg: 'pong' }\n params.transport.send(pong)\n }\n })\n\n return {\n sendConnect: () => {\n params.transport.send(makeConnectFrame())\n },\n }\n}\n","import type { DdpTransport } from './transport'\n\nexport interface DdpMethodFrame {\n msg: 'method'\n method: string\n id: string\n params?: unknown[]\n}\n\nexport interface DdpResultFrame {\n msg: 'result'\n id: string\n result?: unknown\n error?: unknown\n}\n\nfunction isResultFrame(msg: unknown): msg is DdpResultFrame {\n if (!msg || typeof msg !== 'object') return false\n const m = msg as Record<string, unknown>\n return m.msg === 'result' && typeof m.id === 'string'\n}\n\n/**\n * Correlates DDP method calls with result frames.\n */\nexport class DdpMethodClient {\n private nextId = 1\n private pending = new Map<\n string,\n { resolve: (value: unknown) => void; reject: (err: unknown) => void }\n >()\n\n constructor(private readonly transport: DdpTransport) {\n this.transport.onMessage((msg) => {\n if (!isResultFrame(msg)) return\n const handler = this.pending.get(msg.id)\n if (!handler) return\n this.pending.delete(msg.id)\n\n if (msg.error !== undefined) {\n handler.reject(msg.error)\n return\n }\n handler.resolve(msg.result)\n })\n\n this.transport.onClose((info) => {\n // Fail all pending calls on close.\n const err = new Error(\n `DDP transport closed${info?.code ? ` (code=${info.code})` : ''}${\n info?.reason ? ` reason=${info.reason}` : ''\n }`\n )\n for (const [, handler] of this.pending) handler.reject(err)\n this.pending.clear()\n })\n }\n\n /**\n * Call a DDP method.\n */\n call(method: string, params?: unknown[]): Promise<unknown> {\n const id = String(this.nextId++)\n const frame: DdpMethodFrame = { msg: 'method', method, id }\n if (params) frame.params = params\n\n const promise = new Promise<unknown>((resolve, reject) => {\n this.pending.set(id, { resolve, reject })\n })\n\n this.transport.send(frame)\n return promise\n }\n}\n","import type { DdpMethodClient } from './methods'\n\n/**\n * Log in using a resume token.\n *\n * In v1 we treat the Rocket.Chat PAT as the resume token for DDP login.\n */\nexport async function ddpLoginWithResume(params: {\n ddp: DdpMethodClient\n resumeToken: string\n}): Promise<unknown> {\n return await params.ddp.call('login', [{ resume: params.resumeToken }])\n}\n","import type { DdpTransport } from './transport'\n\nexport interface DdpSubFrame {\n msg: 'sub'\n id: string\n name: string\n params: unknown[]\n}\n\nexport interface DdpReadyFrame {\n msg: 'ready'\n subs: string[]\n}\n\nfunction isReadyFrame(msg: unknown): msg is DdpReadyFrame {\n if (!msg || typeof msg !== 'object') return false\n const m = msg as Record<string, unknown>\n return m.msg === 'ready' && Array.isArray(m.subs)\n}\n\n/**\n * Minimal subscription client.\n */\nexport class DdpSubscriptionClient {\n private nextId = 1\n\n constructor(private readonly transport: DdpTransport) {}\n\n /**\n * Subscribe to a DDP stream.\n *\n * Resolves once the server acknowledges the subscription via a `ready` frame.\n */\n subscribe(name: string, params: unknown[]): Promise<{ subId: string }> {\n const subId = String(this.nextId++)\n const frame: DdpSubFrame = { msg: 'sub', id: subId, name, params }\n\n const promise = new Promise<{ subId: string }>((resolve) => {\n const handler = (msg: unknown) => {\n if (!isReadyFrame(msg)) return\n if (!msg.subs.includes(subId)) return\n resolve({ subId })\n }\n this.transport.onMessage(handler)\n })\n\n this.transport.send(frame)\n return promise\n }\n\n /**\n * Subscribe to the stream of room messages.\n */\n subscribeRoomMessages(roomId: string): Promise<{ subId: string }> {\n return this.subscribe('stream-room-messages', [roomId, false])\n }\n}\n","import { ddpLoginWithResume } from './ddp/auth'\nimport { DdpMethodClient } from './ddp/methods'\nimport { installDdpProtocol } from './ddp/protocol'\nimport { DdpSubscriptionClient } from './ddp/subscriptions'\nimport type { DdpTransport } from './ddp/transport'\n\n/**\n * Minimal Rocket.Chat client used by the OpenClaw channel plugin.\n *\n * v1 scope:\n * - DDP connect + ping/pong\n * - DDP login using resume token (PAT)\n * - subscribe to stream-room-messages\n *\n * This class is intentionally transport-agnostic so it can be unit-tested.\n */\nexport class RocketChatClient {\n private readonly ddp: DdpMethodClient\n private readonly subs: DdpSubscriptionClient\n private readonly protocol: ReturnType<typeof installDdpProtocol>\n\n constructor(transport: DdpTransport) {\n this.ddp = new DdpMethodClient(transport)\n this.subs = new DdpSubscriptionClient(transport)\n this.protocol = installDdpProtocol({ transport })\n }\n\n /**\n * Start the DDP session by sending the connect frame.\n */\n connect(): void {\n this.protocol.sendConnect()\n }\n\n /**\n * Authenticate the DDP session.\n */\n async loginWithResume(resumeToken: string): Promise<void> {\n await ddpLoginWithResume({ ddp: this.ddp, resumeToken })\n }\n\n /**\n * Subscribe to inbound room message streams for the provided rooms.\n */\n async subscribeRoomMessages(roomIds: string[]): Promise<void> {\n for (const roomId of roomIds) {\n await this.subs.subscribeRoomMessages(roomId)\n }\n }\n\n /**\n * Convenience helper for the common connect/login/subscribe sequence.\n */\n async start(params: { resumeToken: string; roomIds: string[] }): Promise<void> {\n this.connect()\n await this.loginWithResume(params.resumeToken)\n await this.subscribeRoomMessages(params.roomIds)\n }\n}\n","import type { InboundNormalizeResult } from './types'\nimport type { RocketChatSender } from '../policy/chat_types'\n\ntype RocketChatUser = {\n _id?: string\n username?: string\n}\n\ntype RocketChatMessage = {\n _id?: string\n rid?: string\n msg?: string\n u?: RocketChatUser\n tmid?: string\n}\n\ntype DdpChangedFrame = {\n msg?: string\n collection?: string\n fields?: {\n eventName?: string\n args?: unknown[]\n }\n}\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return Boolean(v) && typeof v === 'object'\n}\n\nfunction decodeSender(u: RocketChatUser | undefined): RocketChatSender {\n return {\n id: (u?._id ?? '').trim(),\n username: u?.username?.trim() || undefined,\n }\n}\n\nfunction decodeMessage(m: RocketChatMessage): {\n roomId: string\n messageId: string\n text: string\n sender: RocketChatSender\n threadId?: string\n} | null {\n const roomId = (m.rid ?? '').trim()\n const messageId = (m._id ?? '').trim()\n const text = (m.msg ?? '').toString()\n const sender = decodeSender(m.u)\n const threadId = m.tmid?.trim() || undefined\n\n if (!roomId) return null\n if (!messageId) return null\n if (!sender.id) return null\n\n return { roomId, messageId, text, sender, threadId }\n}\n\n/**\n * Decode a `stream-room-messages` event payload into a normalized message shape.\n *\n * We support a couple of common payload shapes:\n * - direct message object\n * - DDP changed envelope with fields.args[0] = message\n */\nexport function decodeRoomMessageEvent(raw: unknown): {\n roomId: string\n messageId: string\n text: string\n sender: RocketChatSender\n threadId?: string\n} | null {\n if (!isObject(raw)) return null\n\n // Shape 1: raw is already a Rocket.Chat message document.\n //\n // Note: DDP envelopes also have a `msg` field (e.g. msg=\"changed\"), so we must not\n // treat the presence of `msg` alone as evidence this is a message document.\n if ('rid' in raw || ('_id' in raw && 'u' in raw)) {\n return decodeMessage(raw as RocketChatMessage)\n }\n\n // Shape 2: DDP changed frame.\n const changed = raw as DdpChangedFrame\n if (changed.msg !== 'changed') return null\n\n // Some Rocket.Chat deployments expose this subscription name under the same\n // `stream-room-messages` key used for subscribe(). For safety in early v1,\n // accept any changed frame that includes args[0] shaped like a message.\n //\n // We still prefer strict matching when collection is present and known.\n if (\n changed.collection &&\n changed.collection !== 'stream-room-messages' &&\n changed.collection !== 'stream-room-messages-realtime'\n ) {\n return null\n }\n\n const args = changed.fields?.args\n const first = Array.isArray(args) ? args[0] : undefined\n if (!isObject(first)) return null\n\n return decodeMessage(first as RocketChatMessage)\n}\n\n/**\n * Normalize and validate an inbound message event.\n */\nexport function normalizeDecodedMessage(raw: unknown): InboundNormalizeResult {\n const decoded = decodeRoomMessageEvent(raw)\n if (!decoded) return { ok: false, reason: 'unrecognized-message-shape' }\n if (!decoded.roomId) return { ok: false, reason: 'missing-room-id' }\n if (!decoded.messageId) return { ok: false, reason: 'missing-message-id' }\n if (!decoded.sender.id) return { ok: false, reason: 'missing-sender-id' }\n return { ok: true, value: { ...decoded, chatType: 'group' } as any }\n}\n","import type { RocketChatChatType } from '../policy/chat_types'\n\n/**\n * Determine chat type for a room.\n *\n * v1: this is config-driven. The caller can supply an explicit room type map.\n */\nexport function classifyChatType(params: {\n roomId: string\n roomTypeById?: Record<string, RocketChatChatType>\n}): RocketChatChatType {\n const hint = params.roomTypeById?.[params.roomId]\n return hint ?? 'group'\n}\n","/**\n * Rocket.Chat session key components.\n */\nexport interface RocketChatSessionConversation {\n /** Base conversation id (room). */\n baseConversationId: string\n\n /** Optional thread id (when replying in a thread). */\n threadId?: string\n}\n\n/**\n * Compute the canonical conversation ids for OpenClaw session grammar.\n */\nexport function computeSessionConversation(params: {\n roomId: string\n threadId?: string\n}): RocketChatSessionConversation {\n const baseConversationId = params.roomId.trim()\n const threadId = params.threadId?.trim() || undefined\n return threadId ? { baseConversationId, threadId } : { baseConversationId }\n}\n","import { classifyChatType } from './classify_chat_type'\nimport { decodeRoomMessageEvent } from './decode_message'\nimport { authorizeInboundMessage } from '../policy/policy'\nimport type { ResolvedRocketChatAccount } from '../config/resolve_account'\nimport type { InboundNormalizeResult, RocketChatInboundMessage } from './types'\n\n/**\n * Normalize, classify, and authorize an inbound Rocket.Chat message event.\n */\nexport function processInboundRoomMessage(params: {\n account: ResolvedRocketChatAccount\n rawEvent: unknown\n roomTypeById?: Record<string, 'direct' | 'group'>\n}): InboundNormalizeResult {\n const decoded = decodeRoomMessageEvent(params.rawEvent)\n if (!decoded) return { ok: false, reason: 'unrecognized-message-shape' }\n\n // Loop prevention: ignore self-authored events.\n if (decoded.sender.id === params.account.userId) {\n return { ok: false, reason: 'self-message' }\n }\n\n const chatType = classifyChatType({\n roomId: decoded.roomId,\n roomTypeById: params.roomTypeById,\n })\n\n const decision = authorizeInboundMessage({\n account: params.account,\n chatType,\n roomId: decoded.roomId,\n sender: decoded.sender,\n text: decoded.text,\n })\n\n if (!decision.allowed) {\n return { ok: false, reason: decision.reason ?? 'blocked' }\n }\n\n const value: RocketChatInboundMessage = {\n roomId: decoded.roomId,\n messageId: decoded.messageId,\n text: decoded.text,\n sender: decoded.sender,\n chatType,\n threadId: decoded.threadId,\n }\n\n return { ok: true, value }\n}\n","export interface RocketChatPostMessageParams {\n /** Rocket.Chat base server URL, for example https://chat.example.com */\n serverUrl: string\n\n /** Rocket.Chat user id for auth. */\n userId: string\n\n /** Rocket.Chat personal access token for auth. */\n authToken: string\n\n /** Room id to post into. */\n roomId: string\n\n /** Message text. */\n text: string\n\n /** Optional thread message id (Rocket.Chat tmid). */\n threadId?: string\n}\n\nexport interface RocketChatPostMessageRequest {\n url: string\n method: 'POST'\n headers: Record<string, string>\n body: string\n}\n\nfunction normalizeServerUrl(serverUrl: string): string {\n const trimmed = serverUrl.trim().replace(/\\/$/, '')\n if (!trimmed.startsWith('https://')) {\n throw new Error(`rocketchat: serverUrl must start with https:// (got ${trimmed})`)\n }\n return trimmed\n}\n\n/**\n * Build a REST request for Rocket.Chat `chat.postMessage`.\n *\n * Reference: https://developer.rocket.chat/reference/api/rest-api/endpoints/messaging/chat-endpoints/postmessage\n */\nexport function buildPostMessageRequest(\n params: RocketChatPostMessageParams\n): RocketChatPostMessageRequest {\n const serverUrl = normalizeServerUrl(params.serverUrl)\n const url = `${serverUrl}/api/v1/chat.postMessage`\n\n const payload: Record<string, unknown> = {\n rid: params.roomId,\n msg: params.text,\n }\n if (params.threadId) {\n payload.tmid = params.threadId\n }\n\n return {\n url,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-User-Id': params.userId,\n 'X-Auth-Token': params.authToken,\n },\n body: JSON.stringify(payload),\n }\n}\n\n/**\n * Post a message using Rocket.Chat REST API.\n *\n * This function accepts an optional fetch implementation to keep unit tests deterministic.\n */\nexport async function postMessage(\n params: RocketChatPostMessageParams & {\n fetcher?: (input: string, init?: RequestInit) => Promise<Response>\n }\n): Promise<unknown> {\n const req = buildPostMessageRequest(params)\n const fetcher = params.fetcher ?? fetch\n\n const res = await fetcher(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n })\n\n const text = await res.text()\n if (!res.ok) {\n throw new Error(`rocketchat: chat.postMessage failed (${res.status}): ${text}`)\n }\n\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n","export interface RocketChatReactParams {\n /** Rocket.Chat base server URL, for example https://chat.example.com */\n serverUrl: string\n\n /** Rocket.Chat user id for auth. */\n userId: string\n\n /** Rocket.Chat personal access token for auth. */\n authToken: string\n\n /** Message id to react to. */\n messageId: string\n\n /** Emoji name (without surrounding colons), e.g. \"smile\". */\n emoji: string\n\n /** Whether to add or remove the reaction. */\n shouldReact: boolean\n}\n\nexport interface RocketChatReactRequest {\n url: string\n method: 'POST'\n headers: Record<string, string>\n body: string\n}\n\nfunction normalizeServerUrl(serverUrl: string): string {\n const trimmed = serverUrl.trim().replace(/\\/$/, '')\n if (!trimmed.startsWith('https://')) {\n throw new Error(`rocketchat: serverUrl must start with https:// (got ${trimmed})`)\n }\n return trimmed\n}\n\n/**\n * Build a REST request for Rocket.Chat `chat.react`.\n *\n * Reference: https://developer.rocket.chat/apidocs/react-to-message\n */\nexport function buildReactRequest(params: RocketChatReactParams): RocketChatReactRequest {\n const serverUrl = normalizeServerUrl(params.serverUrl)\n const url = `${serverUrl}/api/v1/chat.react`\n\n return {\n url,\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-User-Id': params.userId,\n 'X-Auth-Token': params.authToken,\n },\n body: JSON.stringify({\n messageId: params.messageId,\n emoji: params.emoji,\n shouldReact: params.shouldReact,\n }),\n }\n}\n\n/**\n * Set or unset a reaction using Rocket.Chat REST API.\n */\nexport async function reactToMessage(\n params: RocketChatReactParams & {\n fetcher?: (input: string, init?: RequestInit) => Promise<Response>\n }\n): Promise<unknown> {\n const req = buildReactRequest(params)\n const fetcher = params.fetcher ?? fetch\n\n const res = await fetcher(req.url, {\n method: req.method,\n headers: req.headers,\n body: req.body,\n })\n\n const text = await res.text()\n if (!res.ok) {\n throw new Error(`rocketchat: chat.react failed (${res.status}): ${text}`)\n }\n\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n","export interface RocketChatMeParams {\n serverUrl: string\n userId: string\n authToken: string\n}\n\nexport interface RocketChatMeRequest {\n url: string\n method: 'GET'\n headers: Record<string, string>\n}\n\nfunction normalizeServerUrl(serverUrl: string): string {\n const trimmed = serverUrl.trim().replace(/\\/$/, '')\n if (!trimmed.startsWith('https://')) {\n throw new Error(`rocketchat: serverUrl must start with https:// (got ${trimmed})`)\n }\n return trimmed\n}\n\n/**\n * Build a REST request for Rocket.Chat `GET /api/v1/me`.\n */\nexport function buildMeRequest(params: RocketChatMeParams): RocketChatMeRequest {\n const serverUrl = normalizeServerUrl(params.serverUrl)\n return {\n url: `${serverUrl}/api/v1/me`,\n method: 'GET',\n headers: {\n 'X-User-Id': params.userId,\n 'X-Auth-Token': params.authToken,\n },\n }\n}\n\n/**\n * Validate current credentials by calling Rocket.Chat `GET /api/v1/me`.\n */\nexport async function getMe(\n params: RocketChatMeParams & {\n fetcher?: (input: string, init?: RequestInit) => Promise<Response>\n }\n): Promise<unknown> {\n const req = buildMeRequest(params)\n const fetcher = params.fetcher ?? fetch\n\n const res = await fetcher(req.url, {\n method: req.method,\n headers: req.headers,\n })\n\n const text = await res.text()\n if (!res.ok) {\n throw new Error(`rocketchat: /api/v1/me failed (${res.status}): ${text}`)\n }\n\n try {\n return JSON.parse(text)\n } catch {\n return text\n }\n}\n","export type RocketChatPrefixCommandName = 'status' | 'model' | 'stop'\n\nexport type RocketChatPrefixCommand =\n | { kind: 'command'; name: 'status'; raw: string }\n | { kind: 'command'; name: 'stop'; raw: string }\n | { kind: 'command'; name: 'model'; raw: string; model: string }\n | { kind: 'not-a-command' }\n\nfunction tokenize(text: string): string[] {\n return text\n .trim()\n .split(/\\s+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0)\n}\n\n/**\n * Parse Rocket.Chat prefix commands.\n *\n * Rules:\n * - Only treat as command if the trimmed message begins with '!'.\n * - Commands supported: !status, !stop, !model <name>\n */\nexport function parsePrefixCommand(text: string): RocketChatPrefixCommand {\n const trimmed = text.trim()\n if (!trimmed.startsWith('!')) return { kind: 'not-a-command' }\n\n const tokens = tokenize(trimmed.slice(1))\n const name = (tokens[0] ?? '').toLowerCase()\n\n if (name === 'status') {\n return { kind: 'command', name: 'status', raw: trimmed }\n }\n\n if (name === 'stop') {\n return { kind: 'command', name: 'stop', raw: trimmed }\n }\n\n if (name === 'model') {\n const model = tokens.slice(1).join(' ').trim()\n if (!model) return { kind: 'not-a-command' }\n return { kind: 'command', name: 'model', raw: trimmed, model }\n }\n\n return { kind: 'not-a-command' }\n}\n","import { authorizeCommand } from '../policy/policy'\nimport type { RocketChatPrefixCommand } from './parse'\nimport type { ResolvedRocketChatAccount } from '../config/resolve_account'\nimport type { RocketChatChatType, RocketChatSender } from '../policy/chat_types'\n\n/**\n * Normalized command dispatch instruction.\n */\nexport type RocketChatCommandDispatch =\n | { ok: true; kind: 'openclaw-command'; commandText: string }\n | { ok: false; reason: string }\n\n/**\n * Map a parsed Rocket.Chat prefix command into an OpenClaw command message.\n */\nexport function dispatchPrefixCommand(params: {\n account: ResolvedRocketChatAccount\n chatType: RocketChatChatType\n sender: RocketChatSender\n parsed: RocketChatPrefixCommand\n}): RocketChatCommandDispatch {\n if (params.parsed.kind !== 'command') {\n return { ok: false, reason: 'not-a-command' }\n }\n\n const decision = authorizeCommand({\n account: params.account,\n chatType: params.chatType,\n sender: params.sender,\n command: params.parsed.name,\n })\n\n if (!decision.allowed) {\n return { ok: false, reason: decision.reason ?? 'blocked' }\n }\n\n if (params.parsed.name === 'status') {\n return { ok: true, kind: 'openclaw-command', commandText: '/status' }\n }\n\n if (params.parsed.name === 'stop') {\n return { ok: true, kind: 'openclaw-command', commandText: '/stop' }\n }\n\n return {\n ok: true,\n kind: 'openclaw-command',\n commandText: `/model ${params.parsed.model}`,\n }\n}\n","import type { DdpTransport } from '../ddp/transport'\n\n/**\n * Close the transport immediately when we determine the account is unauthorized.\n *\n * v1 spec requirement:\n * - On any auth error/unauthorized response on the WebSocket (or any REST call),\n * the plugin MUST immediately close the WebSocket and stop processing events\n * for that account.\n */\nexport function revokeOnUnauthorized(params: { transport: DdpTransport; reason: string }): void {\n params.transport.close({ reason: `unauthorized: ${params.reason}` })\n}\n","import { revokeOnUnauthorized } from './revocation'\nimport type { DdpTransport } from '../ddp/transport'\n\n/**\n * Options for periodic credential revalidation.\n */\nexport interface CredentialRevalidationOptions {\n /** Revalidation cadence in milliseconds. */\n intervalMs: number\n}\n\n/**\n * Start a periodic credential revalidation loop.\n *\n * This provides a bound on worst-case revocation latency for long-lived sessions.\n * v1 target: <= 5 minutes.\n */\nexport function startCredentialRevalidation(params: {\n transport: DdpTransport\n validateOnce: () => Promise<{ ok: true } | { ok: false; reason: string }>\n options: CredentialRevalidationOptions\n}): { stop: () => void } {\n let stopped = false\n const timer = setInterval(async () => {\n if (stopped) return\n\n try {\n const result = await params.validateOnce()\n if (!result.ok) {\n revokeOnUnauthorized({ transport: params.transport, reason: result.reason })\n }\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n revokeOnUnauthorized({ transport: params.transport, reason })\n }\n }, params.options.intervalMs)\n\n return {\n stop: () => {\n stopped = true\n clearInterval(timer)\n },\n }\n}\n","import { getMe } from '../../rocketchat/rest/me'\nimport { RocketChatClient } from '../../rocketchat/client'\nimport { startCredentialRevalidation } from '../../rocketchat/security/revalidate'\nimport type { DdpTransport } from '../../rocketchat/ddp/transport'\nimport type { ResolvedRocketChatAccount } from '../../rocketchat/config/resolve_account'\n\n/**\n * Factory for creating a transport per account.\n */\nexport type RocketChatTransportFactory = (params: {\n account: ResolvedRocketChatAccount\n}) => DdpTransport\n\n/**\n * Start (connect/login/subscribe) a Rocket.Chat client for a single account.\n *\n * v1 security requirements:\n * - periodic credential revalidation to bound revocation latency\n */\nexport async function startRocketChatAccount(params: {\n account: ResolvedRocketChatAccount\n roomIds: string[]\n createTransport: RocketChatTransportFactory\n\n /** Override credential revalidation cadence. Default is 5 minutes. */\n revalidateIntervalMs?: number\n\n /** Optional fetch injection for credential validation. */\n fetcher?: (input: string, init?: RequestInit) => Promise<Response>\n}): Promise<{ client: RocketChatClient; stop: () => void }> {\n const transport = params.createTransport({ account: params.account })\n const client = new RocketChatClient(transport)\n\n await client.start({ resumeToken: params.account.pat, roomIds: params.roomIds })\n\n const revalidate = startCredentialRevalidation({\n transport,\n options: { intervalMs: params.revalidateIntervalMs ?? 5 * 60 * 1000 },\n validateOnce: async () => {\n try {\n await getMe({\n serverUrl: params.account.serverUrl,\n userId: params.account.userId,\n authToken: params.account.pat,\n fetcher: params.fetcher,\n })\n return { ok: true } as const\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n return { ok: false, reason } as const\n }\n },\n })\n\n return {\n client,\n stop: () => {\n revalidate.stop()\n transport.close({ reason: 'stopped' })\n },\n }\n}\n","/**\n * @module @nhtio/rocket-chat-openclaw-integration\n */\n\nimport { defineChannelPluginEntry } from 'openclaw/plugin-sdk/core'\n\nexport type {\n RocketChatAccountConfig,\n RocketChatChannelConfig,\n RocketChatDmPolicy,\n RocketChatGroupPolicy,\n RocketChatOpenClawConfig,\n RocketChatRoomConfig,\n} from './rocketchat/config/types'\n\nexport {\n DEFAULT_DM_POLICY,\n DEFAULT_GROUP_POLICY,\n DEFAULT_REQUIRE_MENTION,\n resolveChannelDefaults,\n} from './rocketchat/config/defaults'\n\nexport type { ResolvedRocketChatAccount } from './rocketchat/config/resolve_account'\nexport { resolveRocketChatAccount } from './rocketchat/config/resolve_account'\n\nexport type { RocketChatChatType, RocketChatSender } from './rocketchat/policy/chat_types'\nexport type { PolicyDecision } from './rocketchat/policy/policy'\nexport { authorizeCommand, authorizeInboundMessage } from './rocketchat/policy/policy'\n\nexport type { DdpTransport } from './rocketchat/ddp/transport'\nexport { FakeDdpTransport } from './rocketchat/ddp/fake_transport'\nexport type { DdpConnectFrame, DdpPingFrame, DdpPongFrame } from './rocketchat/ddp/protocol'\nexport { installDdpProtocol, makeConnectFrame } from './rocketchat/ddp/protocol'\nexport type { DdpMethodFrame, DdpResultFrame } from './rocketchat/ddp/methods'\nexport { DdpMethodClient } from './rocketchat/ddp/methods'\nexport { ddpLoginWithResume } from './rocketchat/ddp/auth'\nexport type { DdpSubFrame, DdpReadyFrame } from './rocketchat/ddp/subscriptions'\nexport { DdpSubscriptionClient } from './rocketchat/ddp/subscriptions'\n\nexport { RocketChatClient } from './rocketchat/client'\n\nexport type { InboundNormalizeResult, RocketChatInboundMessage } from './rocketchat/inbound/types'\nexport { decodeRoomMessageEvent } from './rocketchat/inbound/decode_message'\nexport { classifyChatType } from './rocketchat/inbound/classify_chat_type'\nexport type { RocketChatSessionConversation } from './rocketchat/inbound/session_keys'\nexport { computeSessionConversation } from './rocketchat/inbound/session_keys'\nexport { processInboundRoomMessage } from './rocketchat/inbound/process_inbound'\n\nexport type {\n RocketChatPostMessageParams,\n RocketChatPostMessageRequest,\n} from './rocketchat/rest/post_message'\nexport { buildPostMessageRequest, postMessage } from './rocketchat/rest/post_message'\n\nexport type { RocketChatReactParams, RocketChatReactRequest } from './rocketchat/rest/react'\nexport { buildReactRequest, reactToMessage } from './rocketchat/rest/react'\n\nexport type { RocketChatMeParams, RocketChatMeRequest } from './rocketchat/rest/me'\nexport { buildMeRequest, getMe } from './rocketchat/rest/me'\n\nexport type {\n RocketChatPrefixCommand,\n RocketChatPrefixCommandName,\n} from './rocketchat/commands/parse'\nexport { parsePrefixCommand } from './rocketchat/commands/parse'\n\nexport type { RocketChatCommandDispatch } from './rocketchat/commands/dispatch'\nexport { dispatchPrefixCommand } from './rocketchat/commands/dispatch'\n\nexport type { CredentialRevalidationOptions } from './rocketchat/security/revalidate'\nexport { startCredentialRevalidation } from './rocketchat/security/revalidate'\nexport { revokeOnUnauthorized } from './rocketchat/security/revocation'\n\nexport type { RocketChatTransportFactory } from './openclaw/runtime/account_runner'\nexport { startRocketChatAccount } from './openclaw/runtime/account_runner'\n\n/**\n * The current version of the package.\n *\n * @tip This constant is replaced during the build process with the actual version of the package.\n */\nexport const version: string = __VERSION__\n\n/**\n * OpenClaw Rocket.Chat channel plugin entrypoint.\n *\n * This is a packaging skeleton only.\n * - No Rocket.Chat networking is implemented yet.\n * - The plugin exists so OpenClaw can discover/install the package as a channel plugin.\n */\nexport default defineChannelPluginEntry({\n id: 'rocketchat',\n name: 'Rocket.Chat',\n description: 'Rocket.Chat channel plugin',\n // Plugin implementation will be wired in later phases.\n // We provide a placeholder to keep the entrypoint valid.\n plugin: null as unknown as never,\n})\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ {
2
+ "id": "rocketchat",
3
+ "kind": "channel",
4
+ "channels": ["rocketchat"],
5
+ "name": "Rocket.Chat",
6
+ "description": "Rocket.Chat channel plugin",
7
+ "configSchema": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "channels": {
12
+ "type": "object",
13
+ "additionalProperties": true,
14
+ "properties": {
15
+ "rocketchat": {
16
+ "type": "object",
17
+ "additionalProperties": true,
18
+ "properties": {
19
+ "enabled": { "type": "boolean" },
20
+ "serverUrl": { "type": "string" },
21
+ "dmPolicy": {
22
+ "type": "string",
23
+ "enum": ["pairing", "allowlist", "open", "disabled"]
24
+ },
25
+ "groupPolicy": {
26
+ "type": "string",
27
+ "enum": ["open", "allowlist", "disabled"]
28
+ },
29
+ "allowFrom": {
30
+ "type": "array",
31
+ "items": { "type": "string" }
32
+ },
33
+ "commandAllowFrom": {
34
+ "type": "array",
35
+ "items": { "type": "string" }
36
+ },
37
+ "accounts": {
38
+ "type": "object",
39
+ "additionalProperties": true
40
+ },
41
+ "rooms": {
42
+ "type": "object",
43
+ "additionalProperties": true
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@nhtio/rocket-chat-openclaw-integration",
3
+ "version": "0.1.0-master-7f84cdcb",
4
+ "description": "An OpenClaw Plugin which allows RocketChat to be used as a communications channel",
5
+ "keywords": [],
6
+ "author": "Jak Giveon <jak@nht.io>",
7
+ "copyright": "© 2025-present New Horizon Technology LTD",
8
+ "license": "MIT",
9
+ "peerDependencies": {
10
+ "openclaw": ">=2026.4.2"
11
+ },
12
+ "peerDependenciesMeta": {
13
+ "openclaw": {
14
+ "optional": true
15
+ }
16
+ },
17
+ "module": "./index.mjs",
18
+ "main": "./index.cjs",
19
+ "exports": {
20
+ ".": {
21
+ "import": "./index.mjs",
22
+ "require": "./index.cjs",
23
+ "types": "./index.d.ts"
24
+ }
25
+ },
26
+ "openclaw": {
27
+ "extensions": [
28
+ "./dist/index.mjs"
29
+ ],
30
+ "channel": {
31
+ "id": "rocketchat",
32
+ "label": "Rocket.Chat",
33
+ "blurb": "Connect OpenClaw to Rocket.Chat (Realtime API)."
34
+ },
35
+ "bundle": {
36
+ "stageRuntimeDependencies": true
37
+ }
38
+ },
39
+ "packageManager": "pnpm@10.8.0+sha512.0e82714d1b5b43c74610193cb20734897c1d00de89d0e18420aebc5977fa13d780a9cb05734624e81ebd81cc876cd464794850641c48b9544326b5622ca29971",
40
+ "type": "module",
41
+ "dependencies": {}
42
+ }