| import type { WebhookRequestBody } from "@line/bot-sdk"; |
| import type { Request, Response, NextFunction } from "express"; |
| import { DEFAULT_GROUP_HISTORY_LIMIT, type HistoryEntry } from "../auto-reply/reply/history.js"; |
| import type { OpenClawConfig } from "../config/config.js"; |
| import { loadConfig } from "../config/config.js"; |
| import { logVerbose } from "../globals.js"; |
| import { createNonExitingRuntime, type RuntimeEnv } from "../runtime.js"; |
| import { resolveLineAccount } from "./accounts.js"; |
| import { createLineWebhookReplayCache, handleLineWebhookEvents } from "./bot-handlers.js"; |
| import type { LineInboundContext } from "./bot-message-context.js"; |
| import type { ResolvedLineAccount } from "./types.js"; |
| import { startLineWebhook } from "./webhook.js"; |
|
|
| export interface LineBotOptions { |
| channelAccessToken: string; |
| channelSecret: string; |
| accountId?: string; |
| runtime?: RuntimeEnv; |
| config?: OpenClawConfig; |
| mediaMaxMb?: number; |
| onMessage?: (ctx: LineInboundContext) => Promise<void>; |
| } |
|
|
| export interface LineBot { |
| handleWebhook: (body: WebhookRequestBody) => Promise<void>; |
| account: ResolvedLineAccount; |
| } |
|
|
| export function createLineBot(opts: LineBotOptions): LineBot { |
| const runtime: RuntimeEnv = opts.runtime ?? createNonExitingRuntime(); |
|
|
| const cfg = opts.config ?? loadConfig(); |
| const account = resolveLineAccount({ |
| cfg, |
| accountId: opts.accountId, |
| }); |
|
|
| const mediaMaxBytes = (opts.mediaMaxMb ?? account.config.mediaMaxMb ?? 10) * 1024 * 1024; |
|
|
| const processMessage = |
| opts.onMessage ?? |
| (async () => { |
| logVerbose("line: no message handler configured"); |
| }); |
| const replayCache = createLineWebhookReplayCache(); |
| const groupHistories = new Map<string, HistoryEntry[]>(); |
|
|
| const handleWebhook = async (body: WebhookRequestBody): Promise<void> => { |
| if (!body.events || body.events.length === 0) { |
| return; |
| } |
|
|
| await handleLineWebhookEvents(body.events, { |
| cfg, |
| account, |
| runtime, |
| mediaMaxBytes, |
| processMessage, |
| replayCache, |
| groupHistories, |
| historyLimit: cfg.messages?.groupChat?.historyLimit ?? DEFAULT_GROUP_HISTORY_LIMIT, |
| }); |
| }; |
|
|
| return { |
| handleWebhook, |
| account, |
| }; |
| } |
|
|
| export function createLineWebhookCallback( |
| bot: LineBot, |
| channelSecret: string, |
| path = "/line/webhook", |
| ): { path: string; handler: (req: Request, res: Response, _next: NextFunction) => Promise<void> } { |
| const { handler } = startLineWebhook({ |
| channelSecret, |
| onEvents: bot.handleWebhook, |
| path, |
| }); |
|
|
| return { path, handler }; |
| } |
|
|