@satorijs/adapter-lark 3.5.3 → 3.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,23 +1,35 @@
1
- // https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/im-v1/message/create_json
1
+ // https://open.larksuite.com/document/server-docs/im-v1/message-content-description/create_json
2
2
 
3
- export namespace MessageContent {
4
- export type Contents =
5
- | Text
6
- | Image
7
- | ShareChat
8
- | ShareUser
9
- | Audio
10
- | Media
11
- | File
12
- | Sticker
13
- | RichText
14
-
15
- export type MediaContents =
16
- | Image
17
- | Audio
18
- | Media
19
- | File
3
+ declare global {
4
+ namespace JSX {
5
+ interface IntrinsicElements {
6
+ 'lark:share-chat': {
7
+ 'chat-id': string
8
+ }
9
+ 'lark:share-user': {
10
+ 'user-id': string
11
+ }
12
+ 'lark:system': {
13
+ 'need-rollup'?: boolean
14
+ }
15
+ }
16
+ }
17
+ }
18
+
19
+ export interface MessageContent {
20
+ text: MessageContent.Text
21
+ post: MessageContent.RichText
22
+ image: MessageContent.Image
23
+ file: MessageContent.File
24
+ audio: MessageContent.Audio
25
+ media: MessageContent.Media
26
+ sticker: MessageContent.Sticker
27
+ share_chat: MessageContent.ShareChat
28
+ share_user: MessageContent.ShareUser
29
+ system: MessageContent.System
30
+ }
20
31
 
32
+ export namespace MessageContent {
21
33
  export interface Text {
22
34
  text: string
23
35
  }
@@ -40,7 +52,7 @@ export namespace MessageContent {
40
52
 
41
53
  export interface Media {
42
54
  file_key: string
43
- image_key: string
55
+ image_key?: string
44
56
  }
45
57
 
46
58
  export interface File {
@@ -51,52 +63,264 @@ export namespace MessageContent {
51
63
  file_key: string
52
64
  }
53
65
 
66
+ export interface System {
67
+ type: 'divider'
68
+ params: {
69
+ divider_text: {
70
+ text: string
71
+ i18n_text?: Record<string, string>
72
+ }
73
+ }
74
+ options?: {
75
+ need_rollup?: boolean
76
+ }
77
+ }
78
+
54
79
  export interface RichText {
55
80
  [locale: string]: {
56
- title: string
81
+ title?: string
57
82
  content: RichText.Paragraph[]
58
83
  }
59
84
  }
60
85
 
61
86
  export namespace RichText {
62
- export interface Paragraph extends Array<RichText.Content> {}
87
+ export type Style = 'bold' | 'italic' | 'underline' | 'lineThrough'
63
88
 
64
- export interface BaseContent {
65
- tag: string
89
+ export interface BaseElement<T extends string = string> {
90
+ tag: T
66
91
  }
67
92
 
68
- export interface TextContent extends BaseContent {
69
- tag: 'text'
93
+ export interface TextElement extends BaseElement<'text'> {
70
94
  text: string
71
95
  un_escape?: boolean
96
+ style?: Style[]
72
97
  }
73
- export interface LinkContent extends BaseContent {
74
- tag: 'a'
98
+
99
+ export interface LinkElement extends BaseElement<'a'> {
75
100
  text: string
76
101
  href: string
102
+ style?: Style[]
77
103
  }
78
- export interface AtContent extends BaseContent {
79
- tag: 'at'
104
+
105
+ export interface AtElement extends BaseElement<'at'> {
80
106
  user_id: string
81
- user_name?: string
107
+ style?: Style[]
108
+ // user_name?: string
82
109
  }
83
- export interface ImageContent extends BaseContent {
84
- tag: 'img'
110
+
111
+ export interface ImageElement extends BaseElement<'img'> {
85
112
  image_key: string
86
- height?: number
87
- width?: number
113
+ // height?: number
114
+ // width?: number
88
115
  }
89
- export interface MediaContent extends BaseContent {
90
- tag: 'media'
116
+
117
+ export interface MediaElement extends BaseElement<'media'> {
91
118
  file_key: string
92
119
  image_key?: string
93
120
  }
94
121
 
95
- export type Content =
96
- | RichText.TextContent
97
- | RichText.LinkContent
98
- | RichText.AtContent
99
- | RichText.ImageContent
100
- | RichText.MediaContent
122
+ export interface EmotionElement extends BaseElement<'emoji'> {
123
+ emoji_type: string
124
+ }
125
+
126
+ export interface CodeBlockElement extends BaseElement<'code_block'> {
127
+ language?: string
128
+ text: string
129
+ }
130
+
131
+ export interface HRElement extends BaseElement<'hr'> {}
132
+
133
+ export interface MarkdownElement extends BaseElement<'md'> {
134
+ text: string
135
+ }
136
+
137
+ export type InlineElement =
138
+ | TextElement
139
+ | LinkElement
140
+ | AtElement
141
+ | EmotionElement
142
+ | MarkdownElement
143
+
144
+ export type BlockElement =
145
+ | ImageElement
146
+ | MediaElement
147
+ | CodeBlockElement
148
+ | HRElement
149
+
150
+ export type Paragraph =
151
+ | InlineElement[]
152
+ | [BlockElement]
153
+ }
154
+
155
+ export interface Card {
156
+ config: Card.Config
157
+ card_link?: Card.URLs
158
+ elements?: Card.Element[]
159
+ }
160
+
161
+ export namespace Card {
162
+ /** @see https://open.larksuite.com/document/common-capabilities/message-card/getting-started/card-structure/card-configuration */
163
+ export interface Config {
164
+ enable_forward?: boolean
165
+ update_multi?: boolean
166
+ }
167
+
168
+ export interface URLs {
169
+ url: string
170
+ pc_url?: string
171
+ ios_url?: string
172
+ android_url?: string
173
+ }
174
+
175
+ /** @see https://open.larksuite.com/document/common-capabilities/message-card/message-cards-content/card-header */
176
+ export interface Header {
177
+ title: I18nPlainTextElement
178
+ subtitle?: I18nPlainTextElement
179
+ template?: Header.Template
180
+ icon?: CustomIconElement
181
+ ud_icon?: StandardIconElement
182
+ text_tag_list?: TextTagElement[]
183
+ i18n_text_tag_list?: Record<string, TextTagElement[]>
184
+ }
185
+
186
+ export namespace Header {
187
+ export type Template = 'blue' | 'wathet' | 'turquoise' | 'green' | 'yellow' | 'orange' | 'red' | 'carmine' | 'violet' | 'purple' | 'indigo' | 'grey' | 'default'
188
+ }
189
+
190
+ export interface BaseElement<T extends string = string> {
191
+ tag: T
192
+ }
193
+
194
+ export type TextSize =
195
+ | 'heading-0' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading'
196
+ | 'normal' | 'notation' | 'xxxx-large' | 'xxx-large' | 'xx-large' | 'x-large' | 'large' | 'medium' | 'small' | 'x-small'
197
+
198
+ export type TextAlign = 'left' | 'center' | 'right'
199
+
200
+ export interface PlainTextElement extends BaseElement<'plain_text'> {
201
+ content: string
202
+ }
203
+
204
+ export interface I18nPlainTextElement extends PlainTextElement {
205
+ i18n?: Record<string, string>
206
+ }
207
+
208
+ export interface DivPlainTextElement extends PlainTextElement {
209
+ text_size?: TextSize
210
+ text_color?: string
211
+ text_align?: TextAlign
212
+ lines?: number
213
+ icon?: IconElement
214
+ }
215
+
216
+ export type IconElement = StandardIconElement | CustomIconElement
217
+
218
+ export interface CustomIconElement extends BaseElement<'custom_icon'> {
219
+ img_key: string
220
+ }
221
+
222
+ export interface StandardIconElement extends BaseElement<'standard_icon'> {
223
+ token: string
224
+ color?: string
225
+ }
226
+
227
+ export interface TextTagElement extends BaseElement<'text_tag'> {
228
+ text: PlainTextElement
229
+ color: TextTagElement.Color
230
+ }
231
+
232
+ export namespace TextTagElement {
233
+ export type Color = 'neutral' | 'blue' | 'torqoise' | 'lime' | 'orange' | 'violet' | 'indigo' | 'wathet' | 'green' | 'yellow' | 'red' | 'purple' | 'carmine'
234
+ }
235
+
236
+ export interface ImageElement extends BaseElement<'image'> {
237
+ img_key: string
238
+ alt?: PlainTextElement
239
+ title?: PlainTextElement
240
+ custom_width?: number
241
+ compact_width?: boolean
242
+ mode?: 'crop_center' | 'fit_horizontal' | 'large' | 'medium' | 'small' | 'tiny'
243
+ preview?: boolean
244
+ }
245
+
246
+ export interface HorizontalRuleElement extends BaseElement<'hr'> {}
247
+
248
+ export interface DivElement extends BaseElement<'div'> {
249
+ text?: DivPlainTextElement
250
+ }
251
+
252
+ export interface MarkdownElement extends BaseElement<'markdown'> {
253
+ content: string
254
+ text_size?: TextSize
255
+ text_align?: TextAlign
256
+ href?: Record<string, URLs>
257
+ }
258
+
259
+ export interface HorizontalRuleElement extends BaseElement<'hr'> {}
260
+
261
+ export interface ActionModule extends BaseElement<'action'> {
262
+ actions: ActionElement[]
263
+ layout?: 'bisected' | 'trisection' | 'flow'
264
+ }
265
+
266
+ export type ActionElement =
267
+ | ButtonElement
268
+
269
+ export type ActionBehavior =
270
+ | OpenURLBehavior
271
+ | CallbackBehavior
272
+
273
+ export interface OpenURLBehavior {
274
+ type: 'open_url'
275
+ default_url: string
276
+ pc_url?: string
277
+ ios_url?: string
278
+ android_url?: string
279
+ }
280
+
281
+ export interface CallbackBehavior {
282
+ type: 'callback'
283
+ value: Record<string, string>
284
+ }
285
+
286
+ export interface ButtonElement extends BaseElement<'button'> {
287
+ text: PlainTextElement
288
+ type?: ButtonElement.Type
289
+ size?: ButtonElement.Size
290
+ width?: ButtonElement.Width
291
+ icon?: IconElement
292
+ hover_tips?: PlainTextElement
293
+ disabled?: boolean
294
+ disabled_tips?: PlainTextElement
295
+ confirm?: {
296
+ title: PlainTextElement
297
+ text: PlainTextElement
298
+ }
299
+ behaviors?: ActionBehavior[]
300
+ // form-related fields
301
+ name?: string
302
+ required?: boolean
303
+ action_type?: 'link' | 'request' | 'multi' | 'form_submit' | 'form_reset'
304
+ }
305
+
306
+ export namespace ButtonElement {
307
+ export type Size = 'tiny' | 'small' | 'medium' | 'large'
308
+ export type Width = 'default' | 'fill' | string
309
+ export type Type = 'default' | 'primary' | 'danger' | 'text' | 'primary_text' | 'danger_text' | 'primary_filled' | 'danger_filled' | 'laser'
310
+ }
311
+
312
+ export type Element =
313
+ | DivElement
314
+ | MarkdownElement
315
+ | HorizontalRuleElement
316
+ | ActionModule
317
+ }
318
+
319
+ export interface Template {
320
+ type: 'template'
321
+ data: {
322
+ template_id: string
323
+ template_variable: object
324
+ }
101
325
  }
102
326
  }
@@ -1,31 +1,14 @@
1
- import { Lark } from '..'
2
- import { MessageContent } from './content'
1
+ import { Lark, MessageContent } from '..'
3
2
 
4
3
  export * from './content'
5
4
 
6
- export type MessageType = 'text' | 'post' | 'image' | 'file' | 'audio' | 'media' | 'sticker' | 'interactive' | 'share_chat' | 'share_user'
7
-
8
- export interface MessageContentMap {
9
- 'text': MessageContent.Text
10
- 'post': MessageContent.RichText
11
- 'image': MessageContent.Image
12
- 'file': MessageContent.File
13
- 'audio': MessageContent.Audio
14
- 'media': MessageContent.Media
15
- 'sticker': MessageContent.Sticker
16
- 'share_chat': MessageContent.ShareChat
17
- 'share_user': MessageContent.ShareUser
18
- }
19
-
20
- export type MessageContentType<T extends MessageType> = T extends keyof MessageContentMap ? MessageContentMap[T] : any
21
-
22
5
  declare module '../event' {
23
6
  export interface Events {
24
7
  /**
25
8
  * Receive message event.
26
9
  * @see https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/receive
27
10
  */
28
- 'im.message.receive_v1': EventSkeleton<'im.message.receive_v1', {
11
+ 'im.message.receive_v1': {
29
12
  sender: {
30
13
  sender_id: Lark.UserIds
31
14
  sender_type?: string
@@ -38,7 +21,7 @@ declare module '../event' {
38
21
  create_time: string
39
22
  chat_id: string
40
23
  chat_type: string
41
- message_type: MessageType
24
+ message_type: keyof MessageContent
42
25
  content: string
43
26
  mentions: {
44
27
  key: string
@@ -47,18 +30,51 @@ declare module '../event' {
47
30
  tenant_key: string
48
31
  }[]
49
32
  }
50
- }>
33
+ }
51
34
  /**
52
35
  * Message read event.
53
36
  * @see https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/events/message_read
54
37
  */
55
- 'im.message.message_read_v1': EventSkeleton<'im.message.message_read_v1', {
38
+ 'im.message.message_read_v1': {
56
39
  reader: {
57
40
  reader_id: Lark.UserIds
58
41
  read_time: string
59
42
  tenant_key: string
60
43
  }
61
44
  message_id_list: string[]
62
- }>
45
+ }
46
+ /**
47
+ * Message card callback event.
48
+ * @see https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/card-callback-communication
49
+ */
50
+ 'card.action.trigger': {
51
+ operator: {
52
+ tenant_key: string
53
+ user_id: string
54
+ union_id: string
55
+ open_id: string
56
+ }
57
+ token: string
58
+ action: {
59
+ value: any
60
+ tag: string
61
+ timezone?: string
62
+ name?: string
63
+ form_value?: any
64
+ input_value?: string
65
+ option?: string
66
+ options?: string[]
67
+ checked?: boolean
68
+ }
69
+ host: string
70
+ /** 卡片分发类型,固定取值为 url_preview,表示链接预览卡片。仅链接预览卡片有此字段。 */
71
+ delivery_type?: 'url_preview'
72
+ context: {
73
+ url?: string
74
+ preview_token?: string
75
+ open_message_id: string
76
+ open_chat_id: string
77
+ }
78
+ }
63
79
  }
64
80
  }
package/src/utils.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import crypto from 'crypto'
2
2
  import { Context, h, Session, trimSlash, Universal } from '@satorijs/core'
3
- import { FeishuBot, LarkBot } from './bot'
4
- import { AllEvents, Events, GetImChatResponse, Lark, MessageContentType, MessageType } from './types'
3
+ import { LarkBot } from './bot'
4
+ import { EventPayload, Events, GetImChatResponse, Lark } from './types'
5
5
 
6
6
  export type Sender =
7
7
  | {
@@ -22,8 +22,8 @@ export function adaptSender(sender: Sender, session: Session): Session {
22
22
  return session
23
23
  }
24
24
 
25
- export async function adaptMessage(bot: FeishuBot, data: Events['im.message.receive_v1']['event'], session: Session, details = true): Promise<Session> {
26
- const json = JSON.parse(data.message.content) as MessageContentType<MessageType>
25
+ export async function adaptMessage(bot: LarkBot, data: Events['im.message.receive_v1'], session: Session, details = true): Promise<Session> {
26
+ const json = JSON.parse(data.message.content)
27
27
  const assetEndpoint = trimSlash(bot.config.selfUrl ?? bot.ctx.server.config.selfUrl) + bot.config.path + '/assets'
28
28
  const content: (string | h)[] = []
29
29
  switch (data.message.message_type) {
@@ -71,7 +71,7 @@ export async function adaptMessage(bot: FeishuBot, data: Events['im.message.rece
71
71
  return session
72
72
  }
73
73
 
74
- export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: AllEvents) {
74
+ export async function adaptSession<C extends Context>(bot: LarkBot<C>, body: EventPayload) {
75
75
  const session = bot.session()
76
76
  session.setInternal('lark', body)
77
77
 
@@ -84,13 +84,42 @@ export async function adaptSession<C extends Context>(bot: FeishuBot<C>, body: A
84
84
  adaptSender(body.event.sender, session)
85
85
  await adaptMessage(bot, body.event, session)
86
86
  break
87
+ case 'card.action.trigger':
88
+ if (body.event.action.value?._satori_type === 'command') {
89
+ session.type = 'interaction/command'
90
+ let content = body.event.action.value.content
91
+ const args = [], options = Object.create(null)
92
+ for (const [key, value] of Object.entries(body.event.action.form_value ?? {})) {
93
+ if (+key * 0 === 0) {
94
+ args[+key] = value
95
+ } else {
96
+ options[key] = value
97
+ }
98
+ }
99
+ for (let i = 0; i < args.length; ++i) {
100
+ if (i in args) {
101
+ content += ` ${args[i]}`
102
+ } else {
103
+ content += ` ''`
104
+ }
105
+ }
106
+ for (const [key, value] of Object.entries(options)) {
107
+ content += ` --${key} ${value}`
108
+ }
109
+ session.content = content
110
+ session.messageId = body.event.context.open_message_id
111
+ session.channelId = body.event.context.open_chat_id
112
+ session.guildId = body.event.context.open_chat_id
113
+ session.userId = body.event.operator.open_id
114
+ }
115
+ break
87
116
  }
88
117
  return session
89
118
  }
90
119
 
91
120
  // TODO: This function has many duplicated code with `adaptMessage`, should refactor them
92
121
  export async function decodeMessage(bot: LarkBot, body: Lark.Message, details = true): Promise<Universal.Message> {
93
- const json = JSON.parse(body.body.content) as MessageContentType<MessageType>
122
+ const json = JSON.parse(body.body.content)
94
123
  const assetEndpoint = trimSlash(bot.config.selfUrl ?? bot.ctx.server.config.selfUrl) + bot.config.path + '/assets'
95
124
  const content: h[] = []
96
125
  switch (body.msg_type) {