Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(lark): support interaction/command event #324

Merged
merged 2 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading