Skip to content

Commit

Permalink
feat(lark): support interaction/command event (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma authored Oct 28, 2024
1 parent 07dca13 commit 33f5b9e
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 23 deletions.
2 changes: 1 addition & 1 deletion adapters/lark/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@satorijs/adapter-lark",
"description": "Lark (飞书) Adapter for Satorijs",
"version": "3.5.3",
"version": "3.6.0",
"type": "module",
"main": "lib/index.cjs",
"types": "lib/index.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions adapters/lark/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Adapter, Context, Logger, Schema } from '@satorijs/core'
import {} from '@cordisjs/plugin-server'

import { FeishuBot } from './bot'
import { AllEvents } from './types'
import { EventPayload } from './types'
import { adaptSession, Cipher } from './utils'

export class HttpServer<C extends Context = Context> extends Adapter<C, FeishuBot<C>> {
Expand Down Expand Up @@ -98,7 +98,7 @@ export class HttpServer<C extends Context = Context> extends Adapter<C, FeishuBo
})
}

async dispatchSession(body: AllEvents) {
async dispatchSession(body: EventPayload) {
const { header } = body
if (!header) return
const { app_id, event_type } = header
Expand Down
21 changes: 11 additions & 10 deletions adapters/lark/src/types/event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface EventHeader<T extends string> {
export interface EventHeader<K extends keyof Events> {
event_id: string
event_type: T
event_type: K
create_time: string
token: string
app_id: string
Expand All @@ -12,11 +12,12 @@ export type EventName = keyof Events

// In fact, this is the 2.0 version of the event sent by Lark.
// And only the 2.0 version has the `schema` field.
export type EventSkeleton<T extends EventName, Event, Header = EventHeader<T>> = {
schema: '2.0'
type: T
header: Header
event: Event
}

export type AllEvents = Events[EventName]
export type EventPayload = {
[K in keyof Events]: {
schema: '2.0'
// special added field for TypeScript
type: K
header: EventHeader<K>
event: Events[K]
}
}[keyof Events]
41 changes: 37 additions & 4 deletions adapters/lark/src/types/message/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ declare module '../event' {
* Receive message event.
* @see https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive
*/
'im.message.receive_v1': EventSkeleton<'im.message.receive_v1', {
'im.message.receive_v1': {
sender: {
sender_id: Lark.UserIds
sender_type?: string
Expand All @@ -47,18 +47,51 @@ declare module '../event' {
tenant_key: string
}[]
}
}>
}
/**
* Message read event.
* @see https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/message_read
*/
'im.message.message_read_v1': EventSkeleton<'im.message.message_read_v1', {
'im.message.message_read_v1': {
reader: {
reader_id: Lark.UserIds
read_time: string
tenant_key: string
}
message_id_list: string[]
}>
}
/**
* Message card callback event.
* @see https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/card-callback-communication
*/
'card.action.trigger': {
operator: {
tenant_key: string
user_id: string
union_id: string
open_id: string
}
token: string
action: {
value: any
tag: string
timezone?: string
name?: string
form_value?: any
input_value?: string
option?: string
options?: string[]
checked?: boolean
}
host: string
/** 卡片分发类型,固定取值为 url_preview,表示链接预览卡片。仅链接预览卡片有此字段。 */
delivery_type?: 'url_preview'
context: {
url?: string
preview_token?: string
open_message_id: string
open_chat_id: string
}
}
}
}
35 changes: 32 additions & 3 deletions adapters/lark/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import crypto from 'crypto'
import { Context, h, Session, trimSlash, Universal } from '@satorijs/core'
import { FeishuBot, LarkBot } from './bot'
import { AllEvents, Events, GetImChatResponse, Lark, MessageContentType, MessageType } from './types'
import { EventPayload, Events, GetImChatResponse, Lark, MessageContentType, MessageType } from './types'

export type Sender =
| {
Expand All @@ -22,7 +22,7 @@ export function adaptSender(sender: Sender, session: Session): Session {
return session
}

export async function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1']['event'], session: Session, details = true): Promise<Session> {
export async function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1'], session: Session, details = true): Promise<Session> {
const json = JSON.parse(data.message.content) as MessageContentType<MessageType>
const assetEndpoint = trimSlash(bot.config.selfUrl ?? bot.ctx.server.config.selfUrl) + bot.config.path + '/assets'
const content: (string | h)[] = []
Expand Down Expand Up @@ -71,7 +71,7 @@ export async function adaptMessage(bot: FeishuBot, data: Events['im.message.rece
return session
}

export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: AllEvents) {
export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: EventPayload) {
const session = bot.session()
session.setInternal('lark', body)

Expand All @@ -84,6 +84,35 @@ export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: A
adaptSender(body.event.sender, session)
await adaptMessage(bot, body.event, session)
break
case 'card.action.trigger':
if (body.event.action.value?._satori_type === 'command') {
session.type = 'interaction/command'
let content = body.event.action.value.content
const args = [], options = Object.create(null)
for (const [key, value] of Object.entries(body.event.action.form_value ?? {})) {
if (+key * 0 === 0) {
args[+key] = value
} else {
options[key] = value
}
}
for (let i = 0; i < args.length; ++i) {
if (i in args) {
content += ` ${args[i]}`
} else {
content += ` ''`
}
}
for (const [key, value] of Object.entries(options)) {
content += ` --${key} ${value}`
}
session.content = content
session.messageId = body.event.context.open_message_id
session.channelId = body.event.context.open_chat_id
session.guildId = body.event.context.open_chat_id
session.userId = body.event.operator.open_id
}
break
}
return session
}
Expand Down
11 changes: 8 additions & 3 deletions yakumo.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
- name: yakumo
- id: zzgvxg
name: yakumo
config:
pipeline:
build:
- tsc
- esbuild
clean:
- tsc --clean
- name: yakumo-esbuild
- name: yakumo-tsc
- id: 67eben
name: yakumo-esbuild
- id: fqmym8
name: yakumo-tsc
- id: qrzdog
name: yakumo/run

0 comments on commit 33f5b9e

Please sign in to comment.