@satorijs/adapter-lark 3.10.5 → 3.11.0

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.
Files changed (119) hide show
  1. package/lib/content.d.ts +2 -1
  2. package/lib/index.cjs +3296 -2387
  3. package/lib/internal.d.ts +4 -4
  4. package/lib/message.d.ts +1 -0
  5. package/lib/types/acs.d.ts +212 -172
  6. package/lib/types/admin.d.ts +331 -291
  7. package/lib/types/aily.d.ts +331 -216
  8. package/lib/types/apaas.d.ts +646 -494
  9. package/lib/types/application.d.ts +559 -458
  10. package/lib/types/approval.d.ts +826 -791
  11. package/lib/types/attendance.d.ts +1094 -994
  12. package/lib/types/auth.d.ts +66 -61
  13. package/lib/types/authen.d.ts +221 -186
  14. package/lib/types/baike.d.ts +258 -233
  15. package/lib/types/base.d.ts +74 -0
  16. package/lib/types/bitable.d.ts +830 -770
  17. package/lib/types/board.d.ts +29 -14
  18. package/lib/types/calendar.d.ts +660 -605
  19. package/lib/types/cardkit.d.ts +149 -134
  20. package/lib/types/compensation.d.ts +84 -49
  21. package/lib/types/contact.d.ts +1279 -1204
  22. package/lib/types/corehr.d.ts +4982 -4526
  23. package/lib/types/directory.d.ts +447 -0
  24. package/lib/types/docs.d.ts +28 -18
  25. package/lib/types/document_ai.d.ts +347 -252
  26. package/lib/types/docx.d.ts +428 -383
  27. package/lib/types/drive.d.ts +1093 -1048
  28. package/lib/types/ehr.d.ts +66 -51
  29. package/lib/types/event.d.ts +16 -6
  30. package/lib/types/helpdesk.d.ts +816 -741
  31. package/lib/types/hire.d.ts +3955 -3589
  32. package/lib/types/human_authentication.d.ts +32 -22
  33. package/lib/types/im.d.ts +1420 -1295
  34. package/lib/types/index.d.ts +1422 -330
  35. package/lib/types/lingo.d.ts +279 -249
  36. package/lib/types/mail.d.ts +1032 -675
  37. package/lib/types/mdm.d.ts +105 -37
  38. package/lib/types/minutes.d.ts +73 -26
  39. package/lib/types/moments.d.ts +23 -13
  40. package/lib/types/okr.d.ts +266 -225
  41. package/lib/types/optical_char_recognition.d.ts +22 -12
  42. package/lib/types/passport.d.ts +58 -48
  43. package/lib/types/payroll.d.ts +210 -53
  44. package/lib/types/performance.d.ts +463 -414
  45. package/lib/types/personal_settings.d.ts +93 -82
  46. package/lib/types/report.d.ts +79 -58
  47. package/lib/types/search.d.ts +265 -235
  48. package/lib/types/security_and_compliance.d.ts +30 -19
  49. package/lib/types/sheets.d.ts +356 -321
  50. package/lib/types/speech_to_text.d.ts +44 -34
  51. package/lib/types/task.d.ts +998 -1087
  52. package/lib/types/tenant.d.ts +25 -15
  53. package/lib/types/translation.d.ts +42 -32
  54. package/lib/types/trust_party.d.ts +81 -0
  55. package/lib/types/vc.d.ts +1218 -1123
  56. package/lib/types/verification.d.ts +11 -6
  57. package/lib/types/wiki.d.ts +270 -235
  58. package/lib/types/workplace.d.ts +58 -38
  59. package/lib/utils.d.ts +2 -2
  60. package/package.json +4 -4
  61. package/src/bot.ts +15 -15
  62. package/src/content.ts +2 -0
  63. package/src/internal.ts +29 -12
  64. package/src/message.ts +76 -24
  65. package/src/types/acs.ts +234 -186
  66. package/src/types/admin.ts +353 -305
  67. package/src/types/aily.ts +375 -233
  68. package/src/types/apaas.ts +754 -568
  69. package/src/types/application.ts +633 -507
  70. package/src/types/approval.ts +914 -872
  71. package/src/types/attendance.ts +1226 -1104
  72. package/src/types/auth.ts +72 -66
  73. package/src/types/authen.ts +233 -191
  74. package/src/types/baike.ts +276 -246
  75. package/src/types/base.ts +93 -0
  76. package/src/types/bitable.ts +966 -894
  77. package/src/types/board.ts +34 -16
  78. package/src/types/calendar.ts +751 -685
  79. package/src/types/cardkit.ts +164 -146
  80. package/src/types/compensation.ts +97 -55
  81. package/src/types/contact.ts +1465 -1375
  82. package/src/types/corehr.ts +5664 -5077
  83. package/src/types/directory.ts +569 -0
  84. package/src/types/docs.ts +31 -19
  85. package/src/types/document_ai.ts +401 -287
  86. package/src/types/docx.ts +492 -438
  87. package/src/types/drive.ts +1266 -1213
  88. package/src/types/ehr.ts +71 -53
  89. package/src/types/event.ts +19 -7
  90. package/src/types/helpdesk.ts +930 -840
  91. package/src/types/hire.ts +4453 -4019
  92. package/src/types/human_authentication.ts +35 -23
  93. package/src/types/im.ts +1626 -1476
  94. package/src/types/index.ts +1532 -346
  95. package/src/types/lingo.ts +299 -263
  96. package/src/types/mail.ts +1231 -779
  97. package/src/types/mdm.ts +122 -39
  98. package/src/types/minutes.ts +88 -28
  99. package/src/types/moments.ts +26 -14
  100. package/src/types/okr.ts +286 -238
  101. package/src/types/optical_char_recognition.ts +25 -13
  102. package/src/types/passport.ts +62 -50
  103. package/src/types/payroll.ts +254 -57
  104. package/src/types/performance.ts +528 -467
  105. package/src/types/personal_settings.ts +101 -89
  106. package/src/types/report.ts +86 -62
  107. package/src/types/search.ts +285 -249
  108. package/src/types/security_and_compliance.ts +33 -21
  109. package/src/types/sheets.ts +421 -379
  110. package/src/types/speech_to_text.ts +48 -36
  111. package/src/types/task.ts +1152 -1260
  112. package/src/types/tenant.ts +29 -17
  113. package/src/types/translation.ts +46 -34
  114. package/src/types/trust_party.ts +110 -0
  115. package/src/types/vc.ts +1397 -1283
  116. package/src/types/verification.ts +13 -7
  117. package/src/types/wiki.ts +293 -251
  118. package/src/types/workplace.ts +65 -41
  119. package/src/utils.ts +7 -6
package/lib/utils.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Context, Session, Universal } from '@satorijs/core';
2
2
  import { LarkBot } from './bot';
3
- import { GetImChatResponse, ListChat, Message, User } from './types';
3
+ import { Im, ListChat, Message, User } from './types';
4
4
  import { MessageContent } from './content';
5
5
  export interface EventHeader<K extends keyof Events> {
6
6
  event_id: string;
@@ -154,7 +154,7 @@ export declare function decodeMessage<C extends Context = Context>(bot: LarkBot<
154
154
  * @see https://open.larksuite.com/document/home/user-identity-introduction/introduction
155
155
  */
156
156
  export declare function extractIdType(id: string): ReceiveIdType;
157
- export declare function decodeChannel(channelId: string, guild: GetImChatResponse): Universal.Channel;
157
+ export declare function decodeChannel(channelId: string, guild: Im.Chat.GetResponse): Universal.Channel;
158
158
  export declare function decodeGuild(guild: ListChat): Universal.Guild;
159
159
  export declare function decodeUser(user: User): Universal.User;
160
160
  export declare class Cipher {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@satorijs/adapter-lark",
3
3
  "description": "Lark (飞书) Adapter for Satorijs",
4
- "version": "3.10.5",
4
+ "version": "3.11.0",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
7
7
  "types": "lib/index.d.ts",
@@ -34,13 +34,13 @@
34
34
  "chat"
35
35
  ],
36
36
  "devDependencies": {
37
- "@cordisjs/plugin-server": "^0.2.5",
38
- "@satorijs/core": "^4.5.0",
37
+ "@cordisjs/plugin-server": "^0.2.7",
38
+ "@satorijs/core": "^4.5.2",
39
39
  "cordis": "^3.18.1",
40
40
  "cosmokit": "^1.7.2",
41
41
  "dedent": "^1.5.3"
42
42
  },
43
43
  "peerDependencies": {
44
- "@satorijs/core": "^4.5.0"
44
+ "@satorijs/core": "^4.5.2"
45
45
  }
46
46
  }
package/src/bot.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Bot, Context, h, HTTP, Schema, Time, Universal } from '@satorijs/core'
2
- import { CreateImFileForm } from './types'
2
+ import { Im } from './types'
3
3
  import { HttpServer } from './http'
4
4
  import { LarkMessageEncoder } from './message'
5
5
  import { Internal } from './internal'
6
6
  import * as Utils from './utils'
7
7
 
8
- const fileTypeMap: Record<Exclude<CreateImFileForm['file_type'], 'stream'>, string[]> = {
8
+ const fileTypeMap: Record<Exclude<Im.File.CreateForm['file_type'], 'stream'>, string[]> = {
9
9
  opus: ['audio/opus'],
10
10
  mp4: ['video/mp4'],
11
11
  pdf: ['application/pdf'],
@@ -80,7 +80,7 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
80
80
  // 初次获得 token 后的半小时内必须刷新一次,因为初次获得的 token 可能是 1.5 小时前生成的。
81
81
  let timeout = Time.minute * 20
82
82
  try {
83
- const { tenant_access_token: token } = await this.internal.tenantAccessTokenInternalAuth({
83
+ const { tenant_access_token: token } = await this.internal.auth.tenantAccessTokenInternal({
84
84
  app_id: this.config.appId,
85
85
  app_secret: this.config.appSecret,
86
86
  })
@@ -103,30 +103,30 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
103
103
  }
104
104
 
105
105
  async deleteMessage(channelId: string, messageId: string) {
106
- await this.internal.deleteImMessage(messageId)
106
+ await this.internal.im.message.delete(messageId)
107
107
  }
108
108
 
109
109
  async getMessage(channelId: string, messageId: string, recursive = true) {
110
- const data = await this.internal.getImMessage(messageId)
110
+ const data = await this.internal.im.message.get(messageId)
111
111
  const message = await Utils.decodeMessage(this, data.items![0], recursive)
112
- const im = await this.internal.getImChat(channelId)
112
+ const im = await this.internal.im.chat.get(channelId)
113
113
  message.channel!.type = im.chat_mode === 'p2p' ? Universal.Channel.Type.DIRECT : Universal.Channel.Type.TEXT
114
114
  return message
115
115
  }
116
116
 
117
117
  async getMessageList(channelId: string, before?: string) {
118
- const messages = await this.internal.listImMessage({ container_id_type: 'chat', container_id: channelId, page_token: before })
118
+ const messages = await this.internal.im.message.list({ container_id_type: 'chat', container_id: channelId, page_token: before })
119
119
  const data = await Promise.all(messages.items.reverse().map(data => Utils.decodeMessage(this, data)))
120
120
  return { data, next: data[0]?.id }
121
121
  }
122
122
 
123
123
  async getUser(userId: string, guildId?: string) {
124
- const data = await this.internal.getContactUser(userId)
124
+ const data = await this.internal.contact.user.get(userId)
125
125
  return Utils.decodeUser(data.user!)
126
126
  }
127
127
 
128
128
  async getChannel(channelId: string) {
129
- const chat = await this.internal.getImChat(channelId)
129
+ const chat = await this.internal.im.chat.get(channelId)
130
130
  return Utils.decodeChannel(channelId, chat)
131
131
  }
132
132
 
@@ -135,31 +135,31 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
135
135
  }
136
136
 
137
137
  async getGuild(guildId: string) {
138
- const chat = await this.internal.getImChat(guildId)
138
+ const chat = await this.internal.im.chat.get(guildId)
139
139
  return Utils.decodeGuild(chat)
140
140
  }
141
141
 
142
142
  async getGuildList(after?: string) {
143
- const chats = await this.internal.listImChat({ page_token: after })
143
+ const chats = await this.internal.im.chat.list({ page_token: after })
144
144
  return { data: chats.items.map(Utils.decodeGuild), next: chats.page_token }
145
145
  }
146
146
 
147
147
  async getGuildMemberList(guildId: string, after?: string) {
148
- const members = await this.internal.getImChatMembers(guildId, { page_token: after })
148
+ const members = await this.internal.im.chat.members.get(guildId, { page_token: after })
149
149
  const data = members.items!.map(v => ({ user: { id: v.member_id, name: v.name }, name: v.name }))
150
150
  return { data, next: members.page_token }
151
151
  }
152
152
 
153
153
  async createUpload(...uploads: Universal.Upload[]): Promise<string[]> {
154
154
  return await Promise.all(uploads.map(async (upload) => {
155
- let type: CreateImFileForm['file_type'] = 'stream'
155
+ let type: Im.File.CreateForm['file_type'] = 'stream'
156
156
  for (const [key, value] of Object.entries(fileTypeMap)) {
157
157
  if (value.includes(upload.type)) {
158
- type = key as CreateImFileForm['file_type']
158
+ type = key as Im.File.CreateForm['file_type']
159
159
  break
160
160
  }
161
161
  }
162
- const response = await this.internal.createImFile({
162
+ const response = await this.internal.im.file.create({
163
163
  file_name: upload.filename,
164
164
  file_type: type,
165
165
  file: new Blob([upload.data]),
package/src/content.ts CHANGED
@@ -447,6 +447,7 @@ export namespace MessageContent {
447
447
  export interface SelectElement extends BaseSelectElement<'select_static'> {
448
448
  options: OptionElement[]
449
449
  initial_option?: string
450
+ behaviors?: ActionBehavior[]
450
451
  }
451
452
 
452
453
  export interface MultiSelectElement extends BaseSelectElement<'multi_select_static'> {
@@ -553,6 +554,7 @@ export namespace MessageContent {
553
554
  | ButtonElement
554
555
  | CheckerElement
555
556
  | ColumnSetElement
557
+ | SelectElement
556
558
  }
557
559
 
558
560
  export interface Template {
package/src/internal.ts CHANGED
@@ -34,17 +34,26 @@ export interface InternalRoute {
34
34
  }
35
35
 
36
36
  export class Internal<C extends Context = Context> {
37
- constructor(private bot: LarkBot<C>) {}
37
+ constructor(bot: LarkBot<C>, tree = Internal._tree) {
38
+ return new Proxy(this, {
39
+ get: (target, prop) => {
40
+ if (typeof prop === 'symbol') return Reflect.get(target, prop)
41
+ const value = tree[prop]
42
+ if (typeof value === 'function') return value.bind(bot)
43
+ if (value) return new Internal(bot, value)
44
+ },
45
+ })
46
+ }
38
47
 
39
- private _assertResponse(response: HTTP.Response<BaseResponse>) {
48
+ private static _assertResponse(bot: LarkBot, response: HTTP.Response<BaseResponse>) {
40
49
  if (!response.data.code) return
41
- this.bot.logger.debug('response: %o', response.data)
50
+ bot.logger.debug('response: %o', response.data)
42
51
  const error = new HTTP.Error(`request failed`)
43
52
  error.response = response
44
53
  throw error
45
54
  }
46
55
 
47
- private _buildData(arg: object, options: InternalRoute) {
56
+ private static _buildData(arg: object, options: InternalRoute) {
48
57
  if (options.multipart) {
49
58
  const form = new FormData()
50
59
  for (const [key, value] of Object.entries(arg)) {
@@ -60,6 +69,8 @@ export class Internal<C extends Context = Context> {
60
69
  }
61
70
  }
62
71
 
72
+ private static _tree: Dict = Object.create(null)
73
+
63
74
  static define(routes: Dict<Partial<Record<HTTP.Method, string | InternalRoute>>>) {
64
75
  for (const path in routes) {
65
76
  for (const key in routes[path]) {
@@ -69,7 +80,7 @@ export class Internal<C extends Context = Context> {
69
80
  route = { name: route }
70
81
  }
71
82
 
72
- const impl = async function (this: Internal, ...args: any[]) {
83
+ const impl = async function (bot: LarkBot, ...args: any[]) {
73
84
  const raw = args.join(', ')
74
85
  const url = path.replace(/\{([^}]+)\}/g, () => {
75
86
  if (!args.length) throw new Error(`too few arguments for ${path}, received ${raw}`)
@@ -80,10 +91,10 @@ export class Internal<C extends Context = Context> {
80
91
  if (method === 'GET' || method === 'DELETE') {
81
92
  config.params = args[0]
82
93
  } else {
83
- config.data = this._buildData(args[0], route)
94
+ config.data = Internal._buildData(args[0], route)
84
95
  }
85
96
  } else if (args.length === 2 && method !== 'GET' && method !== 'DELETE') {
86
- config.data = this._buildData(args[0], route)
97
+ config.data = Internal._buildData(args[0], route)
87
98
  config.params = args[1]
88
99
  } else if (args.length > 1) {
89
100
  throw new Error(`too many arguments for ${path}, received ${raw}`)
@@ -91,8 +102,8 @@ export class Internal<C extends Context = Context> {
91
102
  if (route.type === 'binary') {
92
103
  config.responseType = 'arraybuffer'
93
104
  }
94
- const response = await this.bot.http(method, url, config)
95
- this._assertResponse(response)
105
+ const response = await bot.http(method, url, config)
106
+ Internal._assertResponse(bot, response)
96
107
  if (route.type === 'raw-json' || route.type === 'binary') {
97
108
  return response.data
98
109
  } else {
@@ -100,12 +111,18 @@ export class Internal<C extends Context = Context> {
100
111
  }
101
112
  }
102
113
 
103
- Internal.prototype[route.name] = function (this: Internal, ...args: any[]) {
114
+ let root = Internal._tree
115
+ const parts = route.name.split('.')
116
+ const lastPart = parts.pop()!
117
+ for (const part of parts) {
118
+ root = root[part] ??= Object.create(null)
119
+ }
120
+ root[lastPart] = function (this: LarkBot, ...args: any[]) {
104
121
  let promise: Promise<any> | undefined
105
122
  const result = {} as Paginated
106
123
  for (const key of ['then', 'catch', 'finally']) {
107
124
  result[key] = (...args2: any[]) => {
108
- return (promise ??= impl.apply(this, args))[key](...args2)
125
+ return (promise ??= impl(this, ...args))[key](...args2)
109
126
  }
110
127
  }
111
128
 
@@ -126,7 +143,7 @@ export class Internal<C extends Context = Context> {
126
143
  return this
127
144
  }
128
145
  result[Symbol.for('satori.pagination')] = async () => {
129
- const data = await impl.apply(this, iterArgs)
146
+ const data = await impl(this, ...iterArgs)
130
147
  iterArgs[argIndex].page_token = data[tokenKey]
131
148
  return {
132
149
  data: data[itemsKey],
package/src/message.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Context, Dict, h, MessageEncoder } from '@satorijs/core'
2
2
  import { LarkBot } from './bot'
3
- import { CreateImFileForm, Message } from './types'
3
+ import { Im, Message } from './types'
4
4
  import { EventPayload, extractIdType } from './utils'
5
5
  import { MessageContent } from './content'
6
6
 
@@ -13,6 +13,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
13
13
  private card: MessageContent.Card | undefined
14
14
  private noteElements: MessageContent.Card.NoteElement.InnerElement[] | undefined
15
15
  private actionElements: MessageContent.Card.Element[] = []
16
+ private isForm = false
16
17
 
17
18
  public editMessageIds: string[] | undefined
18
19
 
@@ -28,7 +29,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
28
29
  }
29
30
  } else if (this.referrer.type === 'card.action.trigger') {
30
31
  // cannot determine whether the card is in thread or not
31
- const { items: [message] } = await this.bot.internal.getImMessage(this.referrer.event.context.open_message_id)
32
+ const { items: [message] } = await this.bot.internal.im.message.get(this.referrer.event.context.open_message_id)
32
33
  if (message?.thread_id) {
33
34
  quote = {
34
35
  id: this.referrer.event.context.open_message_id,
@@ -42,18 +43,18 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
42
43
  if (!messageId) throw new Error('No message to edit')
43
44
  if (data.msg_type === 'interactive') {
44
45
  delete data.msg_type
45
- await this.bot.internal.patchImMessage(messageId, data)
46
+ await this.bot.internal.im.message.patch(messageId, data)
46
47
  } else {
47
- await this.bot.internal.updateImMessage(messageId, data)
48
+ await this.bot.internal.im.message.update(messageId, data)
48
49
  }
49
50
  } else if (quote?.id) {
50
- resp = await this.bot.internal.replyImMessage(quote.id, {
51
+ resp = await this.bot.internal.im.message.reply(quote.id, {
51
52
  ...data,
52
53
  reply_in_thread: quote.replyInThread,
53
54
  })
54
55
  } else {
55
56
  data.receive_id = this.channelId
56
- resp = await this.bot.internal.createImMessage(data, {
57
+ resp = await this.bot.internal.im.message.create(data, {
57
58
  receive_id_type: extractIdType(this.channelId),
58
59
  })
59
60
  }
@@ -127,7 +128,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
127
128
 
128
129
  async createImage(url: string) {
129
130
  const { filename, type, data } = await this.bot.assetsQuester.file(url)
130
- const { image_key } = await this.bot.internal.createImImage({
131
+ const { image_key } = await this.bot.internal.im.image.create({
131
132
  image_type: 'message',
132
133
  image: new File([data], filename, { type }),
133
134
  })
@@ -148,7 +149,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
148
149
 
149
150
  const { filename, type, data } = await this.bot.assetsQuester.file(url)
150
151
 
151
- let file_type: CreateImFileForm['file_type']
152
+ let file_type: Im.File.CreateForm['file_type']
152
153
  if (_type === 'audio') {
153
154
  // FIXME: only support opus
154
155
  file_type = 'opus'
@@ -164,7 +165,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
164
165
  }
165
166
  }
166
167
 
167
- const form: CreateImFileForm = {
168
+ const form: Im.File.CreateForm = {
168
169
  file_type,
169
170
  file: new File([data], filename, { type }),
170
171
  file_name: filename,
@@ -173,7 +174,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
173
174
  form.duration = attrs.duration
174
175
  }
175
176
 
176
- const { file_key } = await this.bot.internal.createImFile(form)
177
+ const { file_key } = await this.bot.internal.im.file.create(form)
177
178
  await this.post({
178
179
  msg_type: _type === 'video' ? 'media' : _type,
179
180
  content: JSON.stringify({ file_key }),
@@ -251,7 +252,9 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
251
252
  } else if (type === 'form') {
252
253
  this.flushText()
253
254
  const length = this.card?.elements.length
255
+ this.isForm = true
254
256
  await this.render(children)
257
+ this.isForm = false
255
258
  if (this.card?.elements.length > length) {
256
259
  const elements = this.card?.elements.splice(length)
257
260
  this.card.elements.push({
@@ -267,7 +270,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
267
270
  this.card?.elements.push({
268
271
  tag: 'checker',
269
272
  name: (attrs.argument ? '@@' : attrs.option ? `@${attrs.option}=` : '') + attrs.name,
270
- checked: attrs.checked,
273
+ checked: attrs.value,
271
274
  text: {
272
275
  tag: 'plain_text',
273
276
  content: this.textContent,
@@ -293,20 +296,68 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
293
296
  this.textContent = ''
294
297
  } else {
295
298
  this.flushText()
299
+ const input: MessageContent.Card.InputElement = {
300
+ tag: 'input',
301
+ name: attrs.name,
302
+ width: attrs.width,
303
+ label: attrs.label && {
304
+ tag: 'plain_text',
305
+ content: attrs.label,
306
+ },
307
+ placeholder: attrs.placeholder && {
308
+ tag: 'plain_text',
309
+ content: attrs.placeholder,
310
+ },
311
+ default_value: attrs.value,
312
+ disabled: attrs.disabled,
313
+ required: attrs.required,
314
+ }
315
+ if (this.isForm) {
316
+ this.card?.elements.push(input)
317
+ } else {
318
+ this.card?.elements.push({
319
+ tag: 'action',
320
+ actions: [{
321
+ ...input,
322
+ behaviors: this.createBehavior(attrs),
323
+ }],
324
+ })
325
+ }
326
+ }
327
+ } else if (type === 'select') {
328
+ this.flushText()
329
+ const select: MessageContent.Card.SelectElement = {
330
+ tag: 'select_static',
331
+ name: attrs.name,
332
+ width: attrs.width,
333
+ initial_option: attrs.value,
334
+ disabled: attrs.disabled,
335
+ required: attrs.required,
336
+ placeholder: attrs.placeholder && {
337
+ tag: 'plain_text',
338
+ content: attrs.placeholder,
339
+ },
340
+ options: [],
341
+ }
342
+ for (const child of children) {
343
+ if (child.type !== 'option') continue
344
+ await this.render(child.children)
345
+ select.options.push({
346
+ value: child.attrs.value,
347
+ text: {
348
+ tag: 'plain_text',
349
+ content: this.textContent ?? child.attrs.value,
350
+ },
351
+ })
352
+ this.textContent = ''
353
+ }
354
+ if (this.isForm) {
355
+ this.card?.elements.push(select)
356
+ } else {
296
357
  this.card?.elements.push({
297
358
  tag: 'action',
298
359
  actions: [{
299
- tag: 'input',
300
- name: attrs.name,
301
- width: attrs.width,
302
- label: attrs.label && {
303
- tag: 'plain_text',
304
- content: attrs.label,
305
- },
306
- placeholder: attrs.placeholder && {
307
- tag: 'plain_text',
308
- content: attrs.placeholder,
309
- },
360
+ ...select,
310
361
  behaviors: this.createBehavior(attrs),
311
362
  }],
312
363
  })
@@ -437,13 +488,14 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
437
488
  }
438
489
  this.card = { elements: [] }
439
490
  await this.render(child.children)
491
+ this.flushText()
440
492
  columns.push({
441
493
  tag: 'column',
442
494
  width: child.attrs.width,
443
495
  weight: child.attrs.weight,
444
496
  padding: child.attrs.padding,
445
- vertical_align: child.attrs.verticalAlign,
446
- vertical_spacing: child.attrs.verticalSpacing,
497
+ vertical_align: child.attrs.verticalAlign ?? 'center',
498
+ vertical_spacing: child.attrs.verticalSpacing ?? '0px',
447
499
  background_style: child.attrs.backgroundStyle,
448
500
  elements: this.card.elements,
449
501
  })