### Minimal Feishu Bot Example Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md This snippet demonstrates the basic setup and usage of the createLarkChannel function to establish a connection, listen for messages, and send replies. It includes essential configuration like app credentials, logger level, and bot policies. The connection is established using `connect()`, and graceful disconnection is handled on SIGINT. ```typescript import { createLarkChannel, LoggerLevel } from '@larksuiteoapi/node-sdk'; const channel = createLarkChannel({ appId: process.env.FEISHU_APP_ID!, appSecret: process.env.FEISHU_APP_SECRET!, loggerLevel: LoggerLevel.info, policy: { requireMention: true, dmMode: 'open' }, }); channel.on('message', async (msg) => { await channel.send( msg.chatId, { markdown: `received: ${msg.content}` }, { replyTo: msg.messageId }, ); }); await channel.connect(); console.log(`connected as ${channel.botIdentity!.name}`); process.on('SIGINT', async () => { await channel.disconnect(); process.exit(0); }); ``` -------------------------------- ### Install Node.js SDK using npm Source: https://github.com/larksuite/node-sdk/blob/main/README.md Install the LarkSuite Node.js SDK using npm. ```shell npm install @larksuiteoapi/node-sdk ``` -------------------------------- ### Install Node.js SDK using yarn Source: https://github.com/larksuite/node-sdk/blob/main/README.md Install the LarkSuite Node.js SDK using yarn. ```shell yarn add @larksuiteoapi/node-sdk ``` -------------------------------- ### Install Vercel Chat Adapter for Lark Source: https://github.com/larksuite/node-sdk/blob/main/docs/vercel-chat-adapter/README.md Install the adapter using pnpm. This command adds the necessary package to your project dependencies. ```bash pnpm add @larksuite/vercel-chat-adapter ``` -------------------------------- ### API Call Example: Send Message Source: https://github.com/larksuite/node-sdk/blob/main/README.md Demonstrates how to send a text message to a group chat using the SDK's semantic calling method. Ensure you have a client instance configured. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; const client = new lark.Client({ appId: 'app id', appSecret: 'app secret', appType: lark.AppType.SelfBuild, domain: lark.Domain.Feishu, }); const res = await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'receive_id', content: JSON.stringify({text: 'hello world' Р'}), msg_type: 'text', }, }); ``` -------------------------------- ### Iterate Through Paginated User List Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use the listWithIterator method to efficiently retrieve paginated user data. This example demonstrates processing data in chunks of 20. ```typescript for await (const items of await client.contact.user.listWithIterator({ params: { department_id: '0', page_size: 20, }, })) { console.log(items); } ``` -------------------------------- ### Manually Control Pagination with Iterator Source: https://github.com/larksuite/node-sdk/blob/main/README.md Manually control the iteration of paginated results using the async iterator's next() method. This example fetches data in chunks of 20. ```typescript const listIterator = await SDKClient.contact.user.listWithIterator({ params: { department_id: '0', page_size: 20, }, }); const { value } = await listIterator[Symbol.asyncIterator]().next(); console.log(value); ``` -------------------------------- ### Get Chat Information Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Retrieve information about a specific chat using its `chatId`. ```typescript // Chat info const info = await channel.getChatInfo(chatId); ``` -------------------------------- ### Runtime Policy Update Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Updates the runtime policy, for example, to manage group allowlists. ```APIDOC ## Runtime Policy Update Updates the runtime policy configuration. ```typescript channel.updatePolicy({ groupAllowlist: ['oc_xxx'] }); ``` ``` -------------------------------- ### Update Runtime Policy Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Allows updating the runtime policy, for example, to specify allowed groups. ```typescript // Runtime policy update channel.updatePolicy({ groupAllowlist: ['oc_xxx'] }); ``` -------------------------------- ### Create Client for Store Applications Source: https://github.com/larksuite/node-sdk/blob/main/README.md Instantiate a client for store applications, specifying the app type as ISV. This is necessary for store-based apps. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; const client = new lark.Client({ appId: 'app id', appSecret: 'app secret', appType: lark.AppType.ISV, }); ``` -------------------------------- ### Create App with Addons Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use `addons` to incrementally request scopes, events, and callbacks when creating a new app. This pre-fills the confirmation page for the user. `createOnly: true` ensures a new app is created. ```typescript // Create: incrementally request scopes/events/callbacks, and only allow // creating a new app (selecting an existing app is disabled) const result = await lark.registerApp({ addons: { scopes: { tenant: ['im:message:send_as_bot'], user: ['calendar:calendar:read'] }, events: { items: { tenant: ['im.message.receive_v1'] } }, callbacks: { items: ['card.action.trigger'] }, }, createOnly: true, onQRCodeReady(info) { /* ... */ }, }); ``` -------------------------------- ### Configure Request Options with Multiple Settings Source: https://github.com/larksuite/node-sdk/blob/main/README.md Combine multiple request modification methods, such as setting tenant token and tenant key, using `withAll`. ```typescript await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'receive_id', content: JSON.stringify({text: 'hello world'}), msg_type: 'text', }, }, lark.withAll([ lark.withTenantToken('tenant token'), lark.withTenantKey('tenant key') ])); ``` -------------------------------- ### Initialize Lark Adapter with Chat SDK Source: https://github.com/larksuite/node-sdk/blob/main/docs/vercel-chat-adapter/README.md Create a new Chat SDK bot instance and configure it with the Lark adapter. The adapter automatically detects Lark credentials from environment variables. ```typescript import { Chat } from "chat"; import { createLarkAdapter } from "@larksuite/vercel-chat-adapter"; import { createMemoryState } from "@chat-adapter/state-memory"; const bot = new Chat({ userName: "mybot", adapters: { lark: createLarkAdapter(), }, state: createMemoryState(), }); bot.onNewMention(async (thread, message) => { await thread.subscribe(); await thread.post(`You said: ${message.text}`); }); bot.onDirectMessage(async (thread, message) => { await thread.post(`Got your DM: ${message.text}`); }); await bot.initialize(); ``` -------------------------------- ### Create Client for Self-Built Applications Source: https://github.com/larksuite/node-sdk/blob/main/README.md Instantiate a client for self-built applications using your app ID and app secret. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; const client = new lark. Client({ appId: 'app id', appSecret: 'app secret' }); ``` -------------------------------- ### Download File and Write to Disk Source: https://github.com/larksuite/node-sdk/blob/main/README.md Download a file using client.im.file.get and write its content directly to a specified file path using writeFile. ```typescript const resp = await client.im.file.get({ path: { file_key: 'file key', }, }); await resp.writeFile(`filepath.suffix`); ``` -------------------------------- ### Configure Request Options with Tenant Token Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use SDK helper methods to set request options like tenant tokens. The `withTenantToken` method is used here. ```typescript await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'receive_id', content: JSON.stringify({text: 'hello world'}), msg_type: 'text', }, }, lark.withTenantToken('tenant token')); ``` -------------------------------- ### Initiate API Call with Tenant Key for Store Apps Source: https://github.com/larksuite/node-sdk/blob/main/README.md When using a store application client, manually pass the tenant key using `lark.withTenantKey` for API calls. ```typescript client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'chat_id', content: JSON.stringify({text: 'hello world'}), msg_type: 'text' }, }, lark.withTenantKey('tenant key')); ``` -------------------------------- ### Send Default Message Card with SDK Helper Source: https://github.com/larksuite/node-sdk/blob/main/README.md Utilize the SDK's default card builder for a quick way to send a basic message card. Requires importing the SDK. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'your receive_id', content: lark.messageCard.defaultCard({ title: 'Card Title', content: 'Card Content' }), msg_type: 'interactive' } }) ``` -------------------------------- ### Download Resources Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Use `downloadResource` to download files, images, or other resources using their file key. ```typescript // Resource download const buf = await channel.downloadResource(fileKey, 'image'); ``` -------------------------------- ### Upload a File Source: https://github.com/larksuite/node-sdk/blob/main/README.md Upload a file using the client.im.file.create method. Ensure the file is read into a buffer before passing it as data. ```typescript const res = await client.im.file.create({ data: { file_type: 'mp4', file_name: 'test.mp4', file: fs.readFileSync('file path'), }, }); ``` -------------------------------- ### Update App with Addons Source: https://github.com/larksuite/node-sdk/blob/main/README.md Pass the `appId` of an existing app to update its configuration incrementally using `addons`. The user will re-scan the QR code to confirm the changes. ```typescript // Update: pass the appId of an existing app to let the user re-scan and // confirm, incrementally granting scopes to that app await lark.registerApp({ appId: 'cli_xxx', addons: { scopes: { tenant: ['drive:drive.metadata:readonly'] } }, onQRCodeReady(info) { /* ... */ }, }); ``` -------------------------------- ### Register App with OAuth 2.0 Device Authorization Grant Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use registerApp to create an app and obtain credentials by having users scan a QR code. Handles status changes during the process. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; try { const result = await lark.registerApp({ onQRCodeReady(info) { console.log(`Scan the QR code: ${info.url}`); console.log(`Link expires in ${info.expireIn} seconds`); }, onStatusChange(info) { // Handle status changes: 'polling' | 'slow_down' | 'domain_switched' }, }); console.log('App ID:', result.client_id); console.log('App Secret:', result.client_secret); // Use the credentials to initialize a Client const client = new lark.Client({ appId: result.client_id, appSecret: result.client_secret, }); } catch (e) { // e.code: 'access_denied' | 'expired_token' | 'abort' | ... // e.description: error description console.error(e.code, e.description); } ``` -------------------------------- ### Import SDK in CommonJS Source: https://github.com/larksuite/node-sdk/blob/main/README.md Import the LarkSuite SDK for use in CommonJS environments. ```javascript const lark = require('@larksuiteoapi/node-sdk'); ``` -------------------------------- ### Import SDK in TypeScript Source: https://github.com/larksuite/node-sdk/blob/main/README.md Import the LarkSuite SDK for use in TypeScript projects. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; ``` -------------------------------- ### Integrate Lark SDK with Koa-Router Source: https://github.com/larksuite/node-sdk/blob/main/README.md This snippet shows how to use the Lark SDK's event dispatcher with koa-router for handling incoming events. It includes setting up a Koa server, defining routes, and registering an event handler for message reception. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; import Koa from 'koa'; import Router from '@koa/router'; import koaBody from 'koa-body'; const server = new Koa(); const router = new Router(); server.use(koaBody()); const eventDispatcher = new lark.EventDispatcher({ encryptKey: 'encryptKey', }).register({ 'im.message.receive_v1': async (data) => { const open_chat_id = data.message.chat_id; const res = await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: open_chat_id, content: JSON.stringify({text: 'hello world'}) msg_type: 'text' }, }); return res; }, }); router.post('/webhook/event', lark.adaptKoaRouter(eventDispatcher)); server.use(router.routes()); server.listen(3000); ``` -------------------------------- ### Send Message with Options Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a message with additional options such as replying to a specific message or mentioning users. Do not hand-write '@username'; use the `mentions` array. ```typescript await channel.send(chatId, { markdown: 'please check' }, { replyTo: msg.messageId, replyInThread: true, mentions: msg.mentions.filter(m => !m.isBot), }); ``` -------------------------------- ### Make a Manual API Request Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use the client.request method for direct API calls when specific semantic methods are not available. This requires specifying the HTTP method, URL, and data/params. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; const client = new lark. Client({ appId: 'app id', appSecret: 'app secret', appType: lark.AppType.SelfBuild, domain: lark.Domain.Feishu, }); const res = await client. request({ method: 'POST', url: 'xxx', data: {}, params: {}, }); ``` -------------------------------- ### Send Image Message from Local Path Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send an image message by providing a local file path. The SDK will read the file and upload it. ```typescript await channel.send(chatId, { image: { source: './fixtures/sample.png' } }); ``` -------------------------------- ### Resource Download Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Downloads a resource, such as an image, using its key. ```APIDOC ## Resource Download Downloads a resource identified by its key. ```typescript const buf = await channel.downloadResource(fileKey, 'image'); ``` ``` -------------------------------- ### Create and Use Lark Channel for Conversational Bots Source: https://github.com/larksuite/node-sdk/blob/main/README.md This snippet demonstrates creating a Lark channel, which is a high-level abstraction for conversational bots. It sets up a listener for incoming messages and sends a reply. The channel handles transport, message normalization, and outbound sending. ```typescript import { createLarkChannel } from '@larksuiteoapi/node-sdk'; const channel = createLarkChannel({ appId, appSecret }); channel.on('message', async (msg) => { await channel.send( msg.chatId, { markdown: `received: ${msg.content}` }, { replyTo: msg.messageId }, ); }); await channel.connect(); ``` -------------------------------- ### Download File and Stream to File Source: https://github.com/larksuite/node-sdk/blob/main/README.md Obtain a readable stream for a downloaded file using getReadableStream and pipe it to a writable stream to save it to disk. Note: Streams can only be consumed once. ```typescript import * as fs from 'fs'; const resp = await client.im.file.get({ path: { file_key: 'file key', }, }); const readableStream = resp.getReadableStream(); const writableStream = fs.createWriteStream('file url'); readableStream.pipe(writableStream); ``` -------------------------------- ### Register Lark App with Scan-to-Create Source: https://github.com/larksuite/node-sdk/blob/main/docs/vercel-chat-adapter/README.md Use this snippet to initiate Lark's official scan-to-create flow. It generates a QR code for mobile app approval and returns the client ID and secret. ```typescript import { registerLarkApp, createLarkAdapter } from "@larksuite/vercel-chat-adapter"; import qrcode from "qrcode-terminal"; // `pnpm add -D qrcode-terminal` const { client_id, client_secret } = await registerLarkApp({ onQRCodeReady: ({ url }) => { console.log("Scan this QR with your Lark mobile app:"); qrcode.generate(url, { small: true }); }, onStatusChange: ({ status }) => console.log("status:", status), }); // Stash these somewhere durable (env vars, secrets manager, …) console.log("LARK_APP_ID=", client_id); console.log("LARK_APP_SECRET=", client_secret); const adapter = createLarkAdapter({ appId: client_id, appSecret: client_secret, }); ``` -------------------------------- ### Send Image Message from URL Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send an image message by providing a URL. The SDK will download and upload the image. Ensure the URL is accessible and the SDK has SSRF protection enabled if necessary. ```typescript await channel.send(chatId, { image: { source: 'https://example.com/a.jpg' } }); ``` -------------------------------- ### Send Video Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a video message using a Buffer. The duration in milliseconds and an optional cover image key must be provided. The SDK may attempt to parse the duration from the header. ```typescript await channel.send(chatId, { video: { source: buf, duration: 5000, coverImageKey: 'img_xxx' } }); ``` -------------------------------- ### Send Message Card Using Template Source: https://github.com/larksuite/node-sdk/blob/main/README.md Send a message card using a template ID and variables for dynamic content. This simplifies sending rich message cards. ```typescript client.im.message.createByCard({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'your receive_id', template_id: 'your template_id', template_variable: { content: "Card Content", title: "Card Title" } } }) ``` -------------------------------- ### Send File Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a file message using a Buffer. You must provide the file content as a Buffer and specify the file name. ```typescript await channel.send(chatId, { file: { source: buf, fileName: 'doc.pdf' } }); ``` -------------------------------- ### Subscribe to IM Messages with Long Connection Mode Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use this snippet to establish a WebSocket connection and subscribe to 'im.message.receive_v1' events. It processes incoming messages and sends a reply using the Lark client. Requires Lark SDK version 1.24.0 or later. ```typescript import * as Lark from '@larksuiteoapi/node-sdk'; const baseConfig = { appId: 'xxx', appSecret: 'xxx' } const client = new Lark.Client(baseConfig); const wsClient = new Lark.WSClient({...baseConfig, loggerLevel: Lark.LoggerLevel.info}); wsClient.start({ eventDispatcher: new Lark.EventDispatcher({}).register({ 'im.message.receive_v1': async (data) => { const { message: { chat_id, content} } = data; await client.im.v1.message.create({ params: { receive_id_type: "chat_id" }, data: { receive_id: chat_id, content: Lark.messageCard.defaultCard({ title: `reply: ${JSON.parse(content).text}`, content: 'hello' }), msg_type: 'interactive' } }); } }) }); ``` -------------------------------- ### Handle Events with Koa Source: https://github.com/larksuite/node-sdk/blob/main/README.md Combine event handling with a Koa.js application using the SDK's Koa adapter. koa-body is recommended for formatting request data. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; import Koa from 'koa'; import koaBody from 'koa-body'; const server = new Koa(); server.use(koaBody()); const eventDispatcher = new lark.EventDispatcher({ encryptKey: 'encryptKey', }).register({ 'im.message.receive_v1': async (data) => { const open_chat_id = data.message.chat_id; const res = await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: open_chat_id, content: JSON.stringify({text: 'hello world'}), msg_type: 'text' }, }); return res; }, }); server.use(lark.adaptKoa('/webhook/event', eventDispatcher)); server.listen(3000); ``` -------------------------------- ### Environment Variables for Lark Configuration Source: https://github.com/larksuite/node-sdk/blob/main/docs/vercel-chat-adapter/README.md Set these environment variables to configure your Lark application. The adapter can automatically detect appId and appSecret from these variables. ```bash LARK_APP_ID=cli_xxxxxxxx LARK_APP_SECRET=xxxxxxxxxxxxxxxx LARK_BOT_USERNAME=mybot ``` -------------------------------- ### Send Audio Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send an audio message using a Buffer. The duration in milliseconds must be provided. The SDK may attempt to parse it from the header. ```typescript await channel.send(chatId, { audio: { source: buf, duration: 3000 } }); ``` -------------------------------- ### Send Simple Message Card Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use this method to send a basic message card with a title and content. The content is provided as a JSON string. ```typescript client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'your receive_id', content: JSON.stringify({ "config": { "wide_screen_mode": true }, "elements": [ { "tag": "markdown", "content": "Card Content" } ], "header": { "template": "blue", "title": { "content": "Card Title", "tag": "plain_text" } } } ), msg_type: 'interactive' } }) ``` -------------------------------- ### Listen for Lark Channel Events Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Use the `channel.on()` method to subscribe to various events emitted by the Lark channel. This includes messages, card actions, reactions, bot invitations, comments, policy rejections, and errors. Ensure you handle WebSocket reconnecting and reconnected events if applicable. ```typescript channel.on('message', async (msg) => { /* NormalizedMessage */ }); channel.on('cardAction', async (evt) => { /* card button click */ }); channel.on('reaction', (evt) => { /* emoji reaction add/remove */ }); channel.on('botAdded', (evt) => { /* bot invited into a group */ }); channel.on('comment', async (evt) => { /* doc comment mentioning the bot */ }); channel.on('reject', (evt) => { /* policy rejection */ }); channel.on('error', (err) => { /* inbound dispatcher error */ }); channel.on('reconnecting', () => { /* WebSocket reconnecting */ }); channel.on('reconnected', () => { /* WebSocket reconnected */ }); ``` -------------------------------- ### Handle Events with Express Source: https://github.com/larksuite/node-sdk/blob/main/README.md Integrate event handling with an Express.js application using the SDK's express adapter. Ensure body-parser is used to format incoming request data. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; import express from 'express'; import bodyParser from 'body-parser'; const server = express(); server.use(bodyParser.json()); const eventDispatcher = new lark.EventDispatcher({ encryptKey: 'encryptKey', }).register({ 'im.message.receive_v1': async (data) => { const chatId = data.message.chat_id; const res = await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: chatId, content: JSON.stringify({text: 'hello world'}), msg_type: 'text' }, }); return res; } }); server.use('/webhook/event', lark.adaptExpress(eventDispatcher)); server.listen(3000); ``` -------------------------------- ### Send Markdown Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a message formatted using Feishu's markdown. The SDK handles the conversion to the appropriate format. ```typescript await channel.send(chatId, { markdown: 'hello **world**' }); ``` -------------------------------- ### Streaming Replies Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Allows for streaming replies to messages, enabling dynamic content generation and display with a typewriter animation effect. ```APIDOC ## Streaming Replies This method allows for streaming replies to messages. The SDK handles throttling and the typewriter animation. ```typescript channel.on('message', async (msg) => { await channel.stream(msg.chatId, { markdown: async (s) => { for await (const chunk of llmStream(msg.content)) { await s.append(chunk); } }, }, { replyTo: msg.messageId }); }); ``` **Behavior Notes:** - A placeholder card with "Thinking..." is sent before the first `append`. - The server renders the typewriter animation. - If the producer never produces anything, the card shows "(no content)". - If the producer throws an error, the card appends "— (Generation interrupted)" and the error propagates. ``` -------------------------------- ### channel.send Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Sends a message to a specified chat. Supports various input types including text, markdown, posts, cards, images, files, audio, video, shared chats/users, and stickers. Options for replies and mentions are also available. ```APIDOC ## `channel.send` ### Description Sends a message to a specified chat. Supports various input types including text, markdown, posts, cards, images, files, audio, video, shared chats/users, and stickers. Options for replies and mentions are also available. ### Method `channel.send(chatId, input, options?)` ### Parameters #### Path Parameters - **chatId** (string) - Required - The ID of the chat to send the message to. #### Request Body (`input` parameter) Supports nine input variants: - **text**: (string) - Plain text message. - **markdown**: (string) - Markdown formatted message. - **post**: (object) - Raw JSON for a Feishu post. - **card**: (object) - JSON for a Feishu card (v2). - **image**: (object) - Image message. - **source**: (string | Buffer) - URL, local path, or Buffer of the image. - **file**: (object) - File message. - **source**: (Buffer) - Buffer of the file. - **fileName**: (string) - Name of the file. - **audio**: (object) - Audio message. - **source**: (Buffer) - Buffer of the audio. - **duration**: (number) - Duration of the audio in milliseconds. - **video**: (object) - Video message. - **source**: (Buffer) - Buffer of the video. - **duration**: (number) - Duration of the video in milliseconds. - **coverImageKey**: (string) - Key for the cover image. - **shareChat**: (object) - Share chat message. - **chatId**: (string) - The ID of the chat to share. - **shareUser**: (object) - Share user message. - **userId**: (string) - The ID of the user to share. - **sticker**: (object) - Sticker message. - **fileKey**: (string) - The file key of the sticker. #### Options (`options` parameter) - **replyTo** (string) - Optional - The message ID to reply to. - **replyInThread** (boolean) - Optional - Whether to reply within the thread. - **mentions** (MentionInfo[]) - Optional - An array of mention information. ### Request Example ```typescript // Sending a markdown message with a reply and mentions await channel.send(chatId, { markdown: 'please check' }, { replyTo: msg.messageId, replyInThread: true, mentions: msg.mentions.filter(m => !m.isBot), }); // Sending an image from a URL await channel.send(chatId, { image: { source: 'https://example.com/a.jpg' } }); ``` ### Response Throws a `LarkChannelError` on failure, with specific fallbacks for `target_revoked` and `format_error`. ``` -------------------------------- ### Direct Client Access Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Provides an escape hatch to directly call the underlying Client for advanced or unsupported operations. ```APIDOC ## Escape Hatch: Direct Client Access Allows direct access to the underlying Client for advanced operations. ```typescript await channel.rawClient.im.v1.chat.list({}); ``` ``` -------------------------------- ### Send Sticker Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a sticker message using its file key. Requires the `fileKey` of the sticker. ```typescript await channel.send(chatId, { sticker: { fileKey: 'file_v3_xxx' } }); ``` -------------------------------- ### Enable Auto Challenge with Lark Adapters Source: https://github.com/larksuite/node-sdk/blob/main/README.md These snippets show how to enable the automatic challenge-response verification for event request URLs when using different Lark SDK adapters. Set `autoChallenge: true` in the options to enable this feature. ```typescript // adaptDefault lark.adaptDefault('/webhook/event', eventDispatcher, { autoChallenge: true, }); ``` ```typescript // express lark.adaptExpress(eventDispatcher, { autoChallenge: true, }); ``` ```typescript // koa lark.adaptKoa('/webhook/event', eventDispatcher, { autoChallenge: true, }); ``` ```typescript // koa-router router.post( '/webhook/event', lark.adaptKoaRouter(eventDispatcher, { autoChallenge: true, }) ); ``` -------------------------------- ### Send Streaming Replies Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Use this to send streaming replies to messages. The SDK handles throttling and typewriter animation. A placeholder card is sent before the first append, and error handling is included for interrupted generations. ```typescript channel.on('message', async (msg) => { await channel.stream(msg.chatId, { markdown: async (s) => { for await (const chunk of llmStream(msg.content)) { await s.append(chunk); } }, }, { replyTo: msg.messageId }); }); ``` -------------------------------- ### Direct Client Access Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Provides an escape hatch to directly call the underlying Client for advanced operations, such as listing chats. ```typescript // Escape hatch: call the underlying Client directly await channel.rawClient.im.v1.chat.list({}); ``` -------------------------------- ### Update, Edit, and Recall Messages Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Provides low-level functions for managing messages. Use `updateCard` for card messages, `editMessage` for text/post messages, and `recallMessage` to delete a message. ```typescript // Message-level await channel.updateCard(messageId, newCardJson); await channel.editMessage(messageId, newText); // text / post messages only await channel.recallMessage(messageId); ``` -------------------------------- ### Send Card Message (V2) Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a message using the V2 card format. Requires a JSON object conforming to the card schema. ```typescript await channel.send(chatId, { card: cardJsonV2 }); ``` -------------------------------- ### Chat Information Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Retrieves information about a specific chat. ```APIDOC ## Chat Info Retrieves information for a given chat ID. ```typescript const info = await channel.getChatInfo(chatId); ``` ``` -------------------------------- ### Reactions Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Manages reactions on messages, including adding and removing them by ID or emoji. ```APIDOC ## Reactions ### Add Reaction Adds a reaction to a message. ```typescript const reactionId = await channel.addReaction(messageId, 'THUMBSUP'); ``` ### Remove Reaction by ID Removes a reaction from a message using its reaction ID. ```typescript await channel.removeReaction(messageId, reactionId); ``` ### Remove Reaction by Emoji Removes a reaction from a message using its emoji. ```typescript const removed = await channel.removeReactionByEmoji(messageId, 'THUMBSUP'); // returns boolean ``` **Note:** A bot can only delete reactions it added. The `addReaction` method returns the `reaction_id` which must be stored if removal by ID is intended, as event payloads do not contain this ID. ``` -------------------------------- ### Send Text Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Use this to send a simple plain text message to a chat. Requires the chat ID and the text content. ```typescript await channel.send(chatId, { text: 'plain text' }); ``` -------------------------------- ### Handle Events with Node.js http Module Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use this snippet to handle incoming events using the built-in Node.js http module. The EventDispatcher handles data decryption internally. ```typescript import http from 'http'; import * as lark from '@larksuiteoapi/node-sdk'; const eventDispatcher = new lark.EventDispatcher({ encryptKey: 'encrypt key' }).register({ 'im.message.receive_v1': async (data) => { const chatId = data.message.chat_id; const res = await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: chatId, content: JSON.stringify({text: 'hello world'}) msg_type: 'text' }, }); return res; } }); const server = http.createServer(); server.on('request', lark.adaptDefault('/webhook/event', eventDispatcher)); server.listen(3000); ``` -------------------------------- ### Configure Request Options with Custom Headers Source: https://github.com/larksuite/node-sdk/blob/main/README.md Modify API request parameters, such as adding custom headers, by passing a second options object to the request method. ```typescript await client.im.message.create({ params: { receive_id_type: 'chat_id', }, data: { receive_id: 'receive_id', content: JSON.stringify({text: 'hello world' Р'}), msg_type: 'text', }, }, { headers: { customizedHeaderKey: 'customizedHeaderValue' } }); ``` -------------------------------- ### Normalize Raw Event Data Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Use the normalize function to transform raw event data into a structure compatible with the channel's message event handler. Options can be provided to customize the normalization process, such as stripping bot mentions. ```typescript import { normalize, normalizeCardAction, normalizeReaction, normalizeBotAdded, normalizeComment, RawMessageEvent, NormalizeOptions, } from '@larksuiteoapi/node-sdk'; const msg = await normalize(rawEvent, { botIdentity, stripBotMentions: true }); // `msg` is structurally equivalent to what `channel.on('message')` receives. ``` -------------------------------- ### Handle Interactive Message Card Actions Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use CardActionHandler to process user interactions with message cards. It can return a new card to update the message. ```typescript import http from 'http'; import * as lark from '@larksuiteoapi/node-sdk'; import type { InteractiveCardActionEvent, InteractiveCard } from '@larksuiteoapi/node-sdk'; const cardDispatcher = new lark.CardActionHandler( { encryptKey: 'encrypt key', verificationToken: 'verification token' }, async (data: InteractiveCardActionEvent) => { console.log(data); const newCard: InteractiveCard = { // your new interactive card content header: {}, elements: [] }; return newCard; } ); const server = http.createServer(); server.on('request', lark.adaptDefault('/webhook/card', cardDispatcher)); server.listen(3000); ``` -------------------------------- ### Custom Event Dispatcher Invocation Source: https://github.com/larksuite/node-sdk/blob/main/README.md This snippet demonstrates how to manually invoke the event dispatcher for custom service integrations. It shows how to extract request data and headers and pass them to the dispatcher's invoke method. ```typescript const data = server.getData(); const headers = server.getHeaders(); const assigned = Object.assign( Object.create({ headers }), data, ); const result = await dispatcher.invoke(assigned); server.sendResult(result); ``` -------------------------------- ### Message Management Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Provides methods for updating, editing, and recalling messages. ```APIDOC ## Message-level Operations ### Update Card Updates a card message with new JSON content. ```typescript await channel.updateCard(messageId, newCardJson); ``` ### Edit Message Edits an existing text or post message. ```typescript await channel.editMessage(messageId, newText); ``` ### Recall Message Recalls (deletes) a previously sent message. ```typescript await channel.recallMessage(messageId); ``` ``` -------------------------------- ### Send Post Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a structured post message. Requires a JSON object conforming to the post schema. ```typescript await channel.send(chatId, { post: rawPostJson }); ``` -------------------------------- ### Share User Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a message that shares a user. Requires the `userId` of the user to be shared. ```typescript await channel.send(chatId, { shareUser: { userId: 'ou_xxx' } }); ``` -------------------------------- ### Share Chat Message Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Send a message that shares a chat. Requires the `chatId` of the chat to be shared. ```typescript await channel.send(chatId, { shareChat: { chatId: 'oc_xxx' } }); ``` -------------------------------- ### Decrypt Encrypted Data with AESCipher Source: https://github.com/larksuite/node-sdk/blob/main/README.md Use this method to decrypt data pushed by the open platform when Encrypted Push is configured. The SDK generally handles this internally. ```typescript import * as lark from '@larksuiteoapi/node-sdk'; new lark.AESCipher('encrypt key').decrypt('content'); ``` -------------------------------- ### Manage Message Reactions Source: https://github.com/larksuite/node-sdk/blob/main/docs/channel.md Functions for adding and removing reactions to messages. `addReaction` returns a `reaction_id` which must be stored to remove the reaction later. `removeReactionByEmoji` can remove a reaction using its emoji. ```typescript // Reactions const reactionId = await channel.addReaction(messageId, 'THUMBSUP'); await channel.removeReaction(messageId, reactionId); // delete by id const removed = await channel.removeReactionByEmoji(messageId, 'THUMBSUP'); // delete by emoji (returns boolean) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.