{"version":3,"file":"index.mjs","names":[],"sources":["../src/rocketchat/ddp/ws_transport.ts","../src/rocketchat/ddp/auth.ts","../src/rocketchat/ddp/methods.ts","../src/rocketchat/ddp/protocol.ts","../src/rocketchat/ddp/subscriptions.ts","../src/rocketchat/client.ts","../src/rocketchat/security/revocation.ts","../src/rocketchat/security/revalidate.ts","../src/openclaw/runtime/account_runner.ts","../src/rocketchat/inbound/classify_chat_type.ts","../src/rocketchat/inbound/decode_message.ts","../src/rocketchat/policy/allowlist.ts","../src/rocketchat/policy/mentions.ts","../src/rocketchat/policy/policy.ts","../src/rocketchat/inbound/process_inbound.ts","../src/rocketchat/config/defaults.ts","../src/rocketchat/config/resolve_account.ts","../src/channel.ts","../src/rocketchat/ddp/fake_transport.ts","../src/rocketchat/inbound/session_keys.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/index.ts"],"sourcesContent":["import type { DdpTransport } from './transport'\n\ntype CloseInfo = { code?: number; reason?: string }\n\n// Real WebSocket-backed DDP transport for Node runtimes.\n//\n// Rocket.Chat DDP uses JSON frames over WebSocket at /websocket.\nexport class WebSocketDdpTransport implements DdpTransport {\n  private readonly ws: WebSocket\n  private messageHandlers: Array<(msg: unknown) => void> = []\n  private closeHandlers: Array<(info?: CloseInfo) => void> = []\n  private closed = false\n  private open = false\n  private readonly pendingSends: string[] = []\n\n  constructor(url: string) {\n    // Node 22+ provides global WebSocket (undici). We rely on OpenClaw's Node.\n    // If this ever runs in an environment without WebSocket, it will throw\n    // immediately, which is preferable to a silent no-op transport.\n    this.ws = new WebSocket(url)\n\n    // DDP sends frames immediately after creating the socket. Undici's WebSocket\n    // throws if you call send() before the connection is open.\n    this.ws.addEventListener('open', () => {\n      this.open = true\n      while (this.pendingSends.length > 0 && !this.closed) {\n        const payload = this.pendingSends.shift()\n        if (payload === undefined) break\n        this.ws.send(payload)\n      }\n    })\n\n    this.ws.addEventListener('message', (evt) => {\n      // evt.data is typically a string for JSON frames.\n      const raw = (evt as MessageEvent).data\n      if (typeof raw !== 'string') return\n\n      try {\n        const msg = JSON.parse(raw)\n        for (const h of this.messageHandlers) h(msg)\n      } catch {\n        // Ignore malformed frames; DDP protocol should be JSON.\n      }\n    })\n\n    this.ws.addEventListener('close', (evt) => {\n      this.closed = true\n      const info: CloseInfo = {\n        code: (evt as CloseEvent).code,\n        reason: (evt as CloseEvent).reason,\n      }\n      for (const h of this.closeHandlers) h(info)\n    })\n\n    this.ws.addEventListener('error', (evt) => {\n      // Provide a reason to consumers even if the implementation does not\n      // follow with a close event.\n      const msg = (evt as any)?.message\n      for (const h of this.closeHandlers) {\n        h({ code: 1011, reason: typeof msg === 'string' ? msg : 'websocket error' })\n      }\n    })\n  }\n\n  onMessage(cb: (msg: unknown) => void): void {\n    this.messageHandlers.push(cb)\n  }\n\n  onClose(cb: (info?: CloseInfo) => void): void {\n    this.closeHandlers.push(cb)\n  }\n\n  send(msg: unknown): void {\n    if (this.closed) return\n    const payload = JSON.stringify(msg)\n\n    if (!this.open) {\n      // Prevent unbounded growth if the socket never opens.\n      if (this.pendingSends.length >= 1000) {\n        this.close({ code: 1011, reason: 'send buffer overflow before open' })\n        return\n      }\n      this.pendingSends.push(payload)\n      return\n    }\n\n    this.ws.send(payload)\n  }\n\n  close(info?: CloseInfo): void {\n    if (this.closed) return\n    this.closed = true\n    this.ws.close(info?.code ?? 1000, info?.reason)\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 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 { 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 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    // Best-effort presence: Rocket.Chat may not show the user as online unless\n    // the client explicitly sets a presence status.\n    //\n    // Do not await this: a presence method mismatch should never block the\n    // channel from subscribing/processing messages.\n    void this.setPresenceOnline()\n  }\n\n  /** Send a message to a room via DDP. */\n  async sendMessage(params: { roomId: string; text: string }): Promise<unknown> {\n    return await this.ddp.call('sendMessage', [{ rid: params.roomId, msg: params.text }])\n  }\n\n  /**\n   * Best-effort presence update.\n   *\n   * Rocket.Chat's internal method names can vary across versions; we try a few\n   * known variants and treat failures as non-fatal.\n   */\n  private async setPresenceOnline(): Promise<void> {\n    const candidates: Array<{ method: string; params: unknown[] }> = [\n      // Common in Rocket.Chat Meteor apps.\n      { method: 'UserPresence:setDefaultStatus', params: ['online'] },\n      { method: 'UserPresence:setStatus', params: ['online'] },\n      // Some builds accept an object.\n      { method: 'UserPresence:setStatus', params: [{ status: 'online' }] },\n    ]\n\n    const callWithTimeout = async (method: string, params: unknown[]): Promise<void> => {\n      await Promise.race([\n        this.ddp.call(method, params).then(() => undefined),\n        new Promise<void>((_, reject) =>\n          setTimeout(() => reject(new Error('presence-timeout')), 2000)\n        ),\n      ])\n    }\n\n    let lastErr: unknown = null\n    for (const c of candidates) {\n      try {\n        await callWithTimeout(c.method, c.params)\n        return\n      } catch (err) {\n        lastErr = err\n      }\n    }\n\n    // Swallow failures: presence is optional.\n    void lastErr\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 { 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: max 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 { 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<{\n  client: RocketChatClient\n  transport: DdpTransport\n  stop: () => void\n}> {\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        // REST auth with PAT is not reliable across Rocket.Chat deployments.\n        // Revalidate by attempting a DDP resume login again. If it fails, assume\n        // the token was revoked and tear down the transport.\n        await client.loginWithResume(params.account.pat)\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    transport,\n    stop: () => {\n      revalidate.stop()\n      transport.close({ reason: 'stopped' })\n    },\n  }\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","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 { 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 { 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","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 normalizeRoomConfig(raw: RocketChatRoomConfig | undefined): RocketChatRoomConfig {\n  if (!raw) return {}\n\n  // Accept legacy/typoed config key used in the wild.\n  const r = raw as RocketChatRoomConfig & { requiresMention?: boolean }\n  if (r.requireMention === undefined && r.requiresMention !== undefined) {\n    return { ...r, requireMention: r.requiresMention }\n  }\n\n  return raw\n}\n\nfunction mergeRooms(\n  base: Record<string, RocketChatRoomConfig> | undefined,\n  override: Record<string, RocketChatRoomConfig> | undefined\n): Record<string, RocketChatRoomConfig> {\n  const merged = {\n    ...(base ?? {}),\n    ...(override ?? {}),\n  }\n\n  for (const [roomId, cfg] of Object.entries(merged)) {\n    merged[roomId] = normalizeRoomConfig(cfg)\n  }\n\n  return merged\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 { WebSocketDdpTransport } from './rocketchat/ddp/ws_transport'\nimport { startRocketChatAccount } from './openclaw/runtime/account_runner'\nimport { processInboundRoomMessage } from './rocketchat/inbound/process_inbound'\nimport { createOptionalChannelSetupAdapter } from 'openclaw/plugin-sdk/channel-setup'\nimport { dispatchInboundMessageWithBufferedDispatcher } from 'openclaw/plugin-sdk/reply-runtime'\nimport {\n  createChannelPluginBase,\n  type ChannelPlugin,\n  type OpenClawConfig,\n} from 'openclaw/plugin-sdk/core'\nimport {\n  resolveRocketChatAccount,\n  type ResolvedRocketChatAccount,\n} from './rocketchat/config/resolve_account'\nimport type { MsgContext, ReplyPayload } from 'openclaw/plugin-sdk/reply-runtime'\n\nfunction getAccountsSection(cfg: OpenClawConfig): Record<string, unknown> {\n  const section = (cfg.channels as Record<string, any> | undefined)?.rocketchat\n  return (section?.accounts ?? {}) as Record<string, unknown>\n}\n\nfunction serverUrlToDdpWsUrl(serverUrl: string): string {\n  const base = serverUrl.replace(/\\/$/, '')\n  if (base.startsWith('https://')) return `wss://${base.slice('https://'.length)}/websocket`\n  if (base.startsWith('http://')) return `ws://${base.slice('http://'.length)}/websocket`\n  return `${base}/websocket`\n}\n\ntype RunningAccount = {\n  stop: () => void\n}\n\nconst runningByAccountId = new Map<string, RunningAccount>()\n\nasync function startAccount(ctx: any): Promise<void> {\n  const { accountId, account, abortSignal } = ctx as {\n    accountId: string\n    account: ResolvedRocketChatAccount\n    abortSignal?: AbortSignal\n    log?: { info: (m: string) => void; warn: (m: string) => void; error: (m: string) => void }\n  }\n\n  const log = ctx?.log\n\n  // Ensure we never leave a stale runner around.\n  const existing = runningByAccountId.get(accountId)\n  if (existing) {\n    existing.stop()\n    runningByAccountId.delete(accountId)\n  }\n\n  if (!account.enabled) {\n    log?.info?.(`rocketchat/${accountId}: account disabled; not starting`)\n    return\n  }\n\n  // Provide an explicit, actionable error instead of an unlogged crash.\n  if (typeof WebSocket === 'undefined') {\n    throw new Error('rocketchat: global WebSocket is not available in this runtime')\n  }\n\n  const roomIds = Object.keys(account.rooms ?? {})\n  log?.info?.(`rocketchat/${accountId}: starting DDP session (rooms=${roomIds.length})`)\n\n  // Deliverer used by OpenClaw's reply runtime.\n  // deliver is wired after login when we have a real REST auth token.\n  let deliver: ((payload: ReplyPayload) => Promise<void>) | null = null\n\n  try {\n    const transport = new WebSocketDdpTransport(serverUrlToDdpWsUrl(account.serverUrl))\n\n    const closePromise = new Promise<void>((resolve) => {\n      transport.onClose(() => resolve())\n    })\n\n    // Attach inbound processing before we start so we do not miss events.\n    transport.onMessage((rawEvent) => {\n      try {\n        const normalized = processInboundRoomMessage({\n          account,\n          rawEvent,\n        })\n\n        if (!normalized.ok) return\n\n        if (!ctx?.channelRuntime) {\n          log?.warn?.(`rocketchat/${accountId}: channelRuntime missing; dropping inbound message`)\n          return\n        }\n\n        const inbound = normalized.value\n\n        // Feed into OpenClaw reply runtime.\n        // NOTE: We keep ctx minimal and provider-native (room id as To).\n        const msgCtx: MsgContext = {\n          Body: inbound.text,\n          RawBody: inbound.text,\n          CommandBody: inbound.text,\n          BodyForCommands: inbound.text,\n          From: inbound.sender.id,\n          To: inbound.roomId,\n          ChatType: inbound.chatType,\n          SenderId: inbound.sender.id,\n          SenderUsername: inbound.sender.username,\n          SenderName: inbound.sender.username,\n          NativeChannelId: inbound.roomId,\n          OriginatingChannel: 'rocketchat',\n          OriginatingTo: inbound.roomId,\n          ExplicitDeliverRoute: true,\n          AccountId: accountId,\n          Surface: 'rocketchat',\n          Provider: 'rocketchat',\n        }\n\n        if (!deliver) {\n          log?.warn?.(`rocketchat/${accountId}: deliver not ready; dropping inbound message`)\n          return\n        }\n\n        void dispatchInboundMessageWithBufferedDispatcher({\n          ctx: msgCtx,\n          cfg: ctx.cfg,\n          dispatcherOptions: {\n            deliver: async (payload) => {\n              payload.channelData = {\n                ...(payload.channelData ?? {}),\n                rocketchatRoomId: inbound.roomId,\n              }\n              await deliver?.(payload)\n            },\n          },\n        })\n      } catch (err) {\n        log?.error?.(\n          `rocketchat/${accountId}: inbound handler error: ${err instanceof Error ? err.stack || err.message : String(err)}`\n        )\n      }\n    })\n\n    const started = await startRocketChatAccount({\n      account,\n      roomIds,\n      createTransport: () => transport,\n    })\n\n    // Now that the DDP session is live, enable outbound delivery.\n    deliver = async (payload: ReplyPayload): Promise<void> => {\n      const text = payload.text ?? ''\n      if (!text) return\n\n      const roomId = String((payload.channelData as any)?.rocketchatRoomId ?? '')\n      if (!roomId) return\n\n      await started.client.sendMessage({ roomId, text })\n    }\n\n    runningByAccountId.set(accountId, {\n      stop: started.stop,\n    })\n\n    log?.info?.(`rocketchat/${accountId}: started`)\n\n    const abortPromise =\n      abortSignal && !abortSignal.aborted\n        ? new Promise<void>((resolve) => {\n            abortSignal.addEventListener('abort', () => resolve(), { once: true })\n          })\n        : Promise.resolve()\n\n    await Promise.race([closePromise, abortPromise])\n\n    if (abortSignal?.aborted) {\n      started.stop()\n      await closePromise\n    }\n  } catch (err) {\n    const msg = err instanceof Error ? err.stack || err.message : String(err)\n    log?.error?.(`rocketchat/${accountId}: start failed: ${msg}`)\n    throw err\n  }\n}\n\nasync function stopAccount(ctx: any): Promise<void> {\n  const { accountId } = ctx as { accountId: string }\n  const existing = runningByAccountId.get(accountId)\n  if (!existing) return\n\n  existing.stop()\n  runningByAccountId.delete(accountId)\n}\n\nconst base = createChannelPluginBase<ResolvedRocketChatAccount>({\n  id: 'rocketchat',\n  setup: createOptionalChannelSetupAdapter({\n    channel: 'rocketchat',\n    label: 'Rocket.Chat',\n    npmSpec: '@nhtio/rocket-chat-openclaw-integration',\n  }),\n})\n\n// Channel plugin surface.\n//\n// v1 wiring:\n// - config adapter for health/status\n// - gateway adapter to start/stop the account runtime (DDP WebSocket login)\nexport const rocketChatPlugin: ChannelPlugin<ResolvedRocketChatAccount> = {\n  ...base,\n  capabilities: {\n    chatTypes: ['direct', 'group'],\n    reactions: true,\n    reply: true,\n  },\n\n  config: {\n    listAccountIds: (cfg) => {\n      const ids = Object.keys(getAccountsSection(cfg))\n      return ids.length > 0 ? ids : ['default']\n    },\n\n    resolveAccount: (cfg, accountId) =>\n      resolveRocketChatAccount({\n        cfg: cfg as any,\n        accountId: accountId ?? 'default',\n      }),\n\n    inspectAccount: (cfg, accountId) => {\n      try {\n        const account = resolveRocketChatAccount({\n          cfg: cfg as any,\n          accountId: accountId ?? 'default',\n        })\n\n        return {\n          enabled: account.enabled,\n          configured: Boolean(\n            account.serverUrl && account.userId && account.username && account.pat\n          ),\n        }\n      } catch (err) {\n        return {\n          enabled: false,\n          configured: false,\n          error: err instanceof Error ? err.message : String(err),\n        }\n      }\n    },\n\n    defaultAccountId: (cfg) => {\n      const ids = Object.keys(getAccountsSection(cfg))\n      return ids[0] ?? 'default'\n    },\n  },\n\n  gateway: {\n    startAccount,\n    stopAccount,\n  },\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","/**\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","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","/**\n * @module @nhtio/rocket-chat-openclaw-integration\n */\n\nimport { rocketChatPlugin } from './channel'\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 */\nexport default defineChannelPluginEntry({\n  id: 'rocketchat',\n  name: 'Rocket.Chat',\n  description: 'Rocket.Chat channel plugin',\n  plugin: rocketChatPlugin,\n})\n"],"mappings":"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"}