@satorijs/adapter-lark 3.9.4 → 3.10.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.
package/lib/bot.d.ts CHANGED
@@ -5,17 +5,14 @@ import { Internal } from './internal';
5
5
  export declare class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config> {
6
6
  static inject: string[];
7
7
  static MessageEncoder: typeof LarkMessageEncoder;
8
- _token?: string;
9
8
  _refresher?: NodeJS.Timeout;
10
9
  http: HTTP;
11
10
  assetsQuester: HTTP;
12
- internal: Internal;
11
+ internal: Internal<C>;
13
12
  constructor(ctx: C, config: LarkBot.Config);
14
13
  getResourceUrl(type: string, message_id: string, file_key: string): string;
15
14
  initialize(): Promise<void>;
16
15
  private refreshToken;
17
- get token(): string;
18
- set token(v: string);
19
16
  editMessage(channelId: string, messageId: string, content: h.Fragment): Promise<void>;
20
17
  deleteMessage(channelId: string, messageId: string): Promise<void>;
21
18
  getMessage(channelId: string, messageId: string, recursive?: boolean): Promise<Universal.Message>;
package/lib/content.d.ts CHANGED
@@ -299,6 +299,9 @@ export declare namespace MessageContent {
299
299
  name?: string;
300
300
  required?: boolean;
301
301
  action_type?: 'link' | 'request' | 'multi' | 'form_submit' | 'form_reset';
302
+ value?: Record<string, string>;
303
+ url?: string;
304
+ multi_url?: Omit<URLs, 'url'>;
302
305
  }
303
306
  interface ConfirmElement {
304
307
  title: PlainTextElement;
@@ -421,7 +424,7 @@ export declare namespace MessageContent {
421
424
  type Width = 'default' | 'fill' | string;
422
425
  type Type = 'default' | 'primary' | 'danger' | 'text' | 'primary_text' | 'danger_text' | 'primary_filled' | 'danger_filled' | 'laser';
423
426
  }
424
- type Element = DivElement | MarkdownElement | HRElement | ActionElement | NoteElement | ChartElement | TableElement | ImageElement | FormElement | InputElement | ButtonElement;
427
+ type Element = DivElement | MarkdownElement | HRElement | ActionElement | NoteElement | ChartElement | TableElement | ImageElement | FormElement | InputElement | ButtonElement | CheckerElement;
425
428
  }
426
429
  interface Template {
427
430
  type: 'template';
package/lib/index.cjs CHANGED
@@ -146,17 +146,21 @@ async function adaptSession(bot, body) {
146
146
  const toArg = /* @__PURE__ */ __name((value) => {
147
147
  if (typeof value === "string") {
148
148
  return `'${value}'`;
149
- } else if (typeof value === "number") {
150
- return value;
151
149
  } else {
152
- return `''`;
150
+ return value;
153
151
  }
154
152
  }, "toArg");
155
153
  for (let i = 0; i < args.length; ++i) {
156
154
  content += ` ${toArg(args[i])}`;
157
155
  }
158
156
  for (const [key, value] of Object.entries(options)) {
159
- content += ` --${key} ${toArg(value)}`;
157
+ if (value === true) {
158
+ content += ` --${key}`;
159
+ } else if (value === false) {
160
+ content += ` --no-${key}`;
161
+ } else {
162
+ content += ` --${key} ${toArg(value)}`;
163
+ }
160
164
  }
161
165
  if (body.event.action.input_value) {
162
166
  content += ` ${toArg(body.event.action.input_value)}`;
@@ -322,6 +326,7 @@ var HttpServer = class extends import_core2.Adapter {
322
326
  });
323
327
  if (!result) return ctx.status = 403;
324
328
  }
329
+ if (!ctx.request.is("json")) return ctx.status = 415;
325
330
  const body = this._tryDecryptBody(ctx.request.body);
326
331
  if (body?.type === "url_verification" && body?.challenge && typeof body.challenge === "string") {
327
332
  ctx.response.body = { challenge: body.challenge };
@@ -574,10 +579,18 @@ var LarkMessageEncoder = class extends import_core3.MessageEncoder {
574
579
  if (type === "text") {
575
580
  this.textContent += attrs.content;
576
581
  } else if (type === "at") {
577
- if (attrs.type === "all") {
578
- this.textContent += `<at user_id="all">${attrs.name ?? "所有人"}</at>`;
582
+ if (this.card) {
583
+ if (attrs.type === "all") {
584
+ this.textContent += `<at id=all>${attrs.name ?? ""}</at>`;
585
+ } else {
586
+ this.textContent += `<at id=${attrs.id}>${attrs.name ?? ""}</at>`;
587
+ }
579
588
  } else {
580
- this.textContent += `<at user_id="${attrs.id}">${attrs.name}</at>`;
589
+ if (attrs.type === "all") {
590
+ this.textContent += `<at user_id="all">${attrs.name ?? ""}</at>`;
591
+ } else {
592
+ this.textContent += `<at user_id="${attrs.id}">${attrs.name ?? ""}</at>`;
593
+ }
581
594
  }
582
595
  } else if (type === "a") {
583
596
  await this.render(children);
@@ -612,7 +625,7 @@ var LarkMessageEncoder = class extends import_core3.MessageEncoder {
612
625
  const length = this.card?.elements.length;
613
626
  await this.render(children);
614
627
  if (this.card?.elements.length > length) {
615
- const elements = this.card?.elements.slice(length);
628
+ const elements = this.card?.elements.splice(length);
616
629
  this.card.elements.push({
617
630
  tag: "form",
618
631
  name: attrs.name || "Form",
@@ -620,24 +633,56 @@ var LarkMessageEncoder = class extends import_core3.MessageEncoder {
620
633
  });
621
634
  }
622
635
  } else if (type === "input") {
623
- this.flushText();
624
- this.card?.elements.push({
625
- tag: "action",
626
- actions: [{
627
- tag: "input",
636
+ if (attrs.type === "checkbox") {
637
+ this.flushText();
638
+ await this.render(children);
639
+ this.card?.elements.push({
640
+ tag: "checker",
628
641
  name: attrs.name,
629
- width: attrs.width,
630
- label: attrs.label && {
642
+ checked: attrs.checked,
643
+ text: {
631
644
  tag: "plain_text",
632
- content: attrs.label
633
- },
634
- placeholder: attrs.placeholder && {
645
+ content: this.textContent
646
+ }
647
+ });
648
+ } else if (attrs.type === "submit") {
649
+ this.flushText(true);
650
+ await this.render(children);
651
+ this.card?.elements.push({
652
+ tag: "button",
653
+ name: attrs.name,
654
+ text: {
635
655
  tag: "plain_text",
636
- content: attrs.placeholder
656
+ content: this.textContent
637
657
  },
638
- behaviors: this.createBehavior(attrs)
639
- }]
640
- });
658
+ action_type: "form_submit",
659
+ value: {
660
+ _satori_type: "command",
661
+ content: attrs.text
662
+ }
663
+ });
664
+ } else {
665
+ this.flushText();
666
+ await this.render(children);
667
+ this.card?.elements.push({
668
+ tag: "action",
669
+ actions: [{
670
+ tag: "input",
671
+ name: attrs.name,
672
+ width: attrs.width,
673
+ label: this.textContent && {
674
+ tag: "plain_text",
675
+ content: this.textContent
676
+ },
677
+ placeholder: attrs.placeholder && {
678
+ tag: "plain_text",
679
+ content: attrs.placeholder
680
+ },
681
+ behaviors: this.createBehavior(attrs)
682
+ }]
683
+ });
684
+ }
685
+ this.textContent = "";
641
686
  } else if (type === "button") {
642
687
  this.card ??= { elements: [] };
643
688
  this.flushText(true);
@@ -875,7 +920,6 @@ var LarkBot = class extends import_core5.Bot {
875
920
  }
876
921
  static inject = ["server", "http"];
877
922
  static MessageEncoder = LarkMessageEncoder;
878
- _token;
879
923
  _refresher;
880
924
  http;
881
925
  assetsQuester;
@@ -916,23 +960,23 @@ var LarkBot = class extends import_core5.Bot {
916
960
  this.online();
917
961
  }
918
962
  async refreshToken() {
919
- const { tenant_access_token: token } = await this.internal.tenantAccessTokenInternalAuth({
920
- app_id: this.config.appId,
921
- app_secret: this.config.appSecret
922
- });
923
- this.logger.debug("refreshed token %s", token);
924
- this.token = token;
963
+ let timeout = import_core5.Time.minute * 20;
964
+ try {
965
+ const { tenant_access_token: token } = await this.internal.tenantAccessTokenInternalAuth({
966
+ app_id: this.config.appId,
967
+ app_secret: this.config.appSecret
968
+ });
969
+ this.logger.debug("refreshed token %s", token);
970
+ this.http.config.headers.Authorization = `Bearer ${token}`;
971
+ } catch (error) {
972
+ this.logger.error("failed to refresh token, retrying in 10s");
973
+ this.logger.error(error);
974
+ timeout = import_core5.Time.second * 10;
975
+ }
925
976
  if (this._refresher) clearTimeout(this._refresher);
926
- this._refresher = setTimeout(() => this.refreshToken(), import_core5.Time.minute * 20);
977
+ this._refresher = setTimeout(() => this.refreshToken(), timeout);
927
978
  this.online();
928
979
  }
929
- get token() {
930
- return this._token;
931
- }
932
- set token(v) {
933
- this._token = v;
934
- this.http.config.headers.Authorization = `Bearer ${v}`;
935
- }
936
980
  async editMessage(channelId, messageId, content) {
937
981
  const encoder = new LarkMessageEncoder(this, channelId);
938
982
  encoder.editMessageIds = [messageId];
package/lib/internal.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Dict, HTTP } from '@satorijs/core';
1
+ import { Context, Dict, HTTP } from '@satorijs/core';
2
2
  import { LarkBot } from './bot';
3
3
  export interface Internal {
4
4
  }
@@ -28,9 +28,9 @@ export interface InternalRoute {
28
28
  multipart?: boolean;
29
29
  type?: 'raw-json' | 'binary';
30
30
  }
31
- export declare class Internal {
31
+ export declare class Internal<C extends Context = Context> {
32
32
  private bot;
33
- constructor(bot: LarkBot);
33
+ constructor(bot: LarkBot<C>);
34
34
  private _assertResponse;
35
35
  private _buildData;
36
36
  static define(routes: Dict<Partial<Record<HTTP.Method, string | InternalRoute>>>): void;
package/lib/utils.d.ts CHANGED
@@ -146,9 +146,9 @@ export type Sender = {
146
146
  tenant_key: string;
147
147
  });
148
148
  export declare function adaptSender(sender: Sender, session: Session): Session;
149
- export declare function adaptMessage(bot: LarkBot, data: Events['im.message.receive_v1'], session: Session, details?: boolean): Promise<Session>;
149
+ export declare function adaptMessage<C extends Context = Context>(bot: LarkBot<C>, data: Events['im.message.receive_v1'], session: Session, details?: boolean): Promise<Session>;
150
150
  export declare function adaptSession<C extends Context>(bot: LarkBot<C>, body: EventPayload): Promise<C[typeof import("cordis").Context.session]>;
151
- export declare function decodeMessage(bot: LarkBot, body: Message, details?: boolean): Promise<Universal.Message>;
151
+ export declare function decodeMessage<C extends Context = Context>(bot: LarkBot<C>, body: Message, details?: boolean): Promise<Universal.Message>;
152
152
  /**
153
153
  * Get ID type from id string
154
154
  * @see https://open.larksuite.com/document/home/user-identity-introduction/introduction
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.9.4",
4
+ "version": "3.10.0",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
7
7
  "types": "lib/index.d.ts",
@@ -37,7 +37,7 @@
37
37
  "@cordisjs/plugin-server": "^0.2.5",
38
38
  "@satorijs/core": "^4.5.0",
39
39
  "cordis": "^3.18.1",
40
- "cosmokit": "^1.6.3",
40
+ "cosmokit": "^1.7.2",
41
41
  "dedent": "^1.5.3"
42
42
  },
43
43
  "peerDependencies": {
package/src/bot.ts CHANGED
@@ -18,11 +18,10 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
18
18
  static inject = ['server', 'http']
19
19
  static MessageEncoder = LarkMessageEncoder
20
20
 
21
- _token?: string
22
21
  _refresher?: NodeJS.Timeout
23
22
  http: HTTP
24
23
  assetsQuester: HTTP
25
- internal: Internal
24
+ internal: Internal<C>
26
25
 
27
26
  constructor(ctx: C, config: LarkBot.Config) {
28
27
  super(ctx, config, 'lark')
@@ -74,31 +73,29 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
74
73
  }
75
74
 
76
75
  private async refreshToken() {
77
- const { tenant_access_token: token } = await this.internal.tenantAccessTokenInternalAuth({
78
- app_id: this.config.appId,
79
- app_secret: this.config.appSecret,
80
- })
81
- this.logger.debug('refreshed token %s', token)
82
- this.token = token
83
- if (this._refresher) clearTimeout(this._refresher)
84
76
  // https://open.feishu.cn/document/server-docs/authentication-management/access-token/tenant_access_token_internal
85
77
  // tenant_access_token 的最大有效期是 2 小时。
86
78
  // 剩余有效期小于 30 分钟时,调用本接口会返回一个新的 tenant_access_token,此时会同时存在两个有效的 tenant_access_token。
87
79
  // 剩余有效期大于等于 30 分钟时,调用本接口会返回原有的 tenant_access_token。
88
80
  // 初次获得 token 后的半小时内必须刷新一次,因为初次获得的 token 可能是 1.5 小时前生成的。
89
- this._refresher = setTimeout(() => this.refreshToken(), Time.minute * 20)
81
+ let timeout = Time.minute * 20
82
+ try {
83
+ const { tenant_access_token: token } = await this.internal.tenantAccessTokenInternalAuth({
84
+ app_id: this.config.appId,
85
+ app_secret: this.config.appSecret,
86
+ })
87
+ this.logger.debug('refreshed token %s', token)
88
+ this.http.config.headers!.Authorization = `Bearer ${token}`
89
+ } catch (error) {
90
+ this.logger.error('failed to refresh token, retrying in 10s')
91
+ this.logger.error(error)
92
+ timeout = Time.second * 10
93
+ }
94
+ if (this._refresher) clearTimeout(this._refresher)
95
+ this._refresher = setTimeout(() => this.refreshToken(), timeout)
90
96
  this.online()
91
97
  }
92
98
 
93
- get token() {
94
- return this._token
95
- }
96
-
97
- set token(v: string) {
98
- this._token = v
99
- this.http.config.headers.Authorization = `Bearer ${v}`
100
- }
101
-
102
99
  async editMessage(channelId: string, messageId: string, content: h.Fragment) {
103
100
  const encoder = new LarkMessageEncoder(this, channelId)
104
101
  encoder.editMessageIds = [messageId]
@@ -111,9 +108,9 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
111
108
 
112
109
  async getMessage(channelId: string, messageId: string, recursive = true) {
113
110
  const data = await this.internal.getImMessage(messageId)
114
- const message = await Utils.decodeMessage(this, data.items[0], recursive)
111
+ const message = await Utils.decodeMessage(this, data.items![0], recursive)
115
112
  const im = await this.internal.getImChat(channelId)
116
- message.channel.type = im.chat_mode === 'p2p' ? Universal.Channel.Type.DIRECT : Universal.Channel.Type.TEXT
113
+ message.channel!.type = im.chat_mode === 'p2p' ? Universal.Channel.Type.DIRECT : Universal.Channel.Type.TEXT
117
114
  return message
118
115
  }
119
116
 
@@ -125,7 +122,7 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
125
122
 
126
123
  async getUser(userId: string, guildId?: string) {
127
124
  const data = await this.internal.getContactUser(userId)
128
- return Utils.decodeUser(data.user)
125
+ return Utils.decodeUser(data.user!)
129
126
  }
130
127
 
131
128
  async getChannel(channelId: string) {
@@ -149,7 +146,7 @@ export class LarkBot<C extends Context = Context> extends Bot<C, LarkBot.Config>
149
146
 
150
147
  async getGuildMemberList(guildId: string, after?: string) {
151
148
  const members = await this.internal.getImChatMembers(guildId, { page_token: after })
152
- const data = members.items.map(v => ({ user: { id: v.member_id, name: v.name }, name: v.name }))
149
+ const data = members.items!.map(v => ({ user: { id: v.member_id, name: v.name }, name: v.name }))
153
150
  return { data, next: members.page_token }
154
151
  }
155
152
 
package/src/content.ts CHANGED
@@ -378,6 +378,10 @@ export namespace MessageContent {
378
378
  name?: string
379
379
  required?: boolean
380
380
  action_type?: 'link' | 'request' | 'multi' | 'form_submit' | 'form_reset'
381
+ // legacy fields
382
+ value?: Record<string, string>
383
+ url?: string
384
+ multi_url?: Omit<URLs, 'url'>
381
385
  }
382
386
 
383
387
  export interface ConfirmElement {
@@ -526,6 +530,7 @@ export namespace MessageContent {
526
530
  | FormElement
527
531
  | InputElement
528
532
  | ButtonElement
533
+ | CheckerElement
529
534
  }
530
535
 
531
536
  export interface Template {
package/src/http.ts CHANGED
@@ -43,6 +43,9 @@ export class HttpServer<C extends Context = Context> extends Adapter<C, LarkBot<
43
43
  if (!result) return (ctx.status = 403)
44
44
  }
45
45
 
46
+ // only accept JSON body
47
+ if (!ctx.request.is('json')) return ctx.status = 415
48
+
46
49
  // try to decrypt message first if encryptKey is set
47
50
  const body = this._tryDecryptBody(ctx.request.body)
48
51
  // respond challenge message
@@ -81,7 +84,7 @@ export class HttpServer<C extends Context = Context> extends Adapter<C, LarkBot<
81
84
  if (!header) return
82
85
  const { app_id, event_type } = header
83
86
  body.type = event_type // add type to body to ease typescript type narrowing
84
- const bot = this.bots.find((bot) => bot.config.appId === app_id)
87
+ const bot = this.bots.find((bot) => bot.config.appId === app_id)!
85
88
  const session = await adaptSession(bot, body)
86
89
  bot.dispatch(session)
87
90
  }
package/src/internal.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Dict, HTTP, makeArray } from '@satorijs/core'
1
+ import { Context, Dict, HTTP, makeArray } from '@satorijs/core'
2
2
  import { LarkBot } from './bot'
3
3
 
4
4
  export interface Internal {}
@@ -33,8 +33,8 @@ export interface InternalRoute {
33
33
  type?: 'raw-json' | 'binary'
34
34
  }
35
35
 
36
- export class Internal {
37
- constructor(private bot: LarkBot) {}
36
+ export class Internal<C extends Context = Context> {
37
+ constructor(private bot: LarkBot<C>) {}
38
38
 
39
39
  private _assertResponse(response: HTTP.Response<BaseResponse>) {
40
40
  if (!response.data.code) return
@@ -113,12 +113,13 @@ export class Internal {
113
113
  const { argIndex, itemsKey = 'items', tokenKey = 'page_token' } = route.pagination
114
114
  const iterArgs = [...args]
115
115
  iterArgs[argIndex] = { ...args[argIndex] }
116
- let pagination: { data: any[]; next?: any } | undefined
116
+ type Pagniation = { data: any[]; next?: any }
117
+ let pagination: Pagniation | undefined
117
118
  result.next = async function () {
118
- pagination ??= await this[Symbol.for('satori.pagination')]()
119
+ pagination ??= await this[Symbol.for('satori.pagination')]() as Pagniation
119
120
  if (pagination.data.length) return { done: false, value: pagination.data.shift() }
120
121
  if (!pagination.next) return { done: true, value: undefined }
121
- pagination = await this[Symbol.for('satori.pagination')]()
122
+ pagination = await this[Symbol.for('satori.pagination')]() as Pagniation
122
123
  return this.next()
123
124
  }
124
125
  result[Symbol.asyncIterator] = function () {
package/src/message.ts CHANGED
@@ -206,10 +206,18 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
206
206
  if (type === 'text') {
207
207
  this.textContent += attrs.content
208
208
  } else if (type === 'at') {
209
- if (attrs.type === 'all') {
210
- this.textContent += `<at user_id="all">${attrs.name ?? '所有人'}</at>`
209
+ if (this.card) {
210
+ if (attrs.type === 'all') {
211
+ this.textContent += `<at id=all>${attrs.name ?? ''}</at>`
212
+ } else {
213
+ this.textContent += `<at id=${attrs.id}>${attrs.name ?? ''}</at>`
214
+ }
211
215
  } else {
212
- this.textContent += `<at user_id="${attrs.id}">${attrs.name}</at>`
216
+ if (attrs.type === 'all') {
217
+ this.textContent += `<at user_id="all">${attrs.name ?? ''}</at>`
218
+ } else {
219
+ this.textContent += `<at user_id="${attrs.id}">${attrs.name ?? ''}</at>`
220
+ }
213
221
  }
214
222
  } else if (type === 'a') {
215
223
  await this.render(children)
@@ -245,7 +253,7 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
245
253
  const length = this.card?.elements.length
246
254
  await this.render(children)
247
255
  if (this.card?.elements.length > length) {
248
- const elements = this.card?.elements.slice(length)
256
+ const elements = this.card?.elements.splice(length)
249
257
  this.card.elements.push({
250
258
  tag: 'form',
251
259
  name: attrs.name || 'Form',
@@ -253,24 +261,56 @@ export class LarkMessageEncoder<C extends Context = Context> extends MessageEnco
253
261
  })
254
262
  }
255
263
  } else if (type === 'input') {
256
- this.flushText()
257
- this.card?.elements.push({
258
- tag: 'action',
259
- actions: [{
260
- tag: 'input',
264
+ if (attrs.type === 'checkbox') {
265
+ this.flushText()
266
+ await this.render(children)
267
+ this.card?.elements.push({
268
+ tag: 'checker',
261
269
  name: attrs.name,
262
- width: attrs.width,
263
- label: attrs.label && {
270
+ checked: attrs.checked,
271
+ text: {
264
272
  tag: 'plain_text',
265
- content: attrs.label,
273
+ content: this.textContent,
266
274
  },
267
- placeholder: attrs.placeholder && {
275
+ })
276
+ } else if (attrs.type === 'submit') {
277
+ this.flushText(true)
278
+ await this.render(children)
279
+ this.card?.elements.push({
280
+ tag: 'button',
281
+ name: attrs.name,
282
+ text: {
268
283
  tag: 'plain_text',
269
- content: attrs.placeholder,
284
+ content: this.textContent,
270
285
  },
271
- behaviors: this.createBehavior(attrs),
272
- }],
273
- })
286
+ action_type: 'form_submit',
287
+ value: {
288
+ _satori_type: 'command',
289
+ content: attrs.text,
290
+ },
291
+ })
292
+ } else {
293
+ this.flushText()
294
+ await this.render(children)
295
+ this.card?.elements.push({
296
+ tag: 'action',
297
+ actions: [{
298
+ tag: 'input',
299
+ name: attrs.name,
300
+ width: attrs.width,
301
+ label: this.textContent && {
302
+ tag: 'plain_text',
303
+ content: this.textContent,
304
+ },
305
+ placeholder: attrs.placeholder && {
306
+ tag: 'plain_text',
307
+ content: attrs.placeholder,
308
+ },
309
+ behaviors: this.createBehavior(attrs),
310
+ }],
311
+ })
312
+ }
313
+ this.textContent = ''
274
314
  } else if (type === 'button') {
275
315
  this.card ??= { elements: [] }
276
316
  this.flushText(true)
package/src/utils.ts CHANGED
@@ -168,7 +168,12 @@ export function adaptSender(sender: Sender, session: Session): Session {
168
168
  return session
169
169
  }
170
170
 
171
- export async function adaptMessage(bot: LarkBot, data: Events['im.message.receive_v1'], session: Session, details = true): Promise<Session> {
171
+ export async function adaptMessage<C extends Context = Context>(
172
+ bot: LarkBot<C>,
173
+ data: Events['im.message.receive_v1'],
174
+ session: Session,
175
+ details = true,
176
+ ): Promise<Session> {
172
177
  const json = JSON.parse(data.message.content)
173
178
  const content: (string | h)[] = []
174
179
  switch (data.message.message_type) {
@@ -182,7 +187,7 @@ export async function adaptMessage(bot: LarkBot, data: Events['im.message.receiv
182
187
  // Lark's `at` Element would be `@user_id` in text
183
188
  text.split(' ').forEach((word) => {
184
189
  if (word.startsWith('@')) {
185
- const mention = data.message.mentions.find((mention) => mention.key === word)
190
+ const mention = data.message.mentions.find((mention) => mention.key === word)!
186
191
  content.push(h.at(mention.id.open_id, { name: mention.name }))
187
192
  } else {
188
193
  content.push(word)
@@ -261,17 +266,21 @@ export async function adaptSession<C extends Context>(bot: LarkBot<C>, body: Eve
261
266
  const toArg = (value: any) => {
262
267
  if (typeof value === 'string') {
263
268
  return `'${value}'`
264
- } else if (typeof value === 'number') {
269
+ } else { // number, boolean
265
270
  return value
266
- } else {
267
- return `''`
268
271
  }
269
272
  }
270
273
  for (let i = 0; i < args.length; ++i) {
271
274
  content += ` ${toArg(args[i])}`
272
275
  }
273
276
  for (const [key, value] of Object.entries(options)) {
274
- content += ` --${key} ${toArg(value)}`
277
+ if (value === true) {
278
+ content += ` --${key}`
279
+ } else if (value === false) {
280
+ content += ` --no-${key}`
281
+ } else {
282
+ content += ` --${key} ${toArg(value)}`
283
+ }
275
284
  }
276
285
  if (body.event.action.input_value) {
277
286
  content += ` ${toArg(body.event.action.input_value)}`
@@ -291,8 +300,8 @@ export async function adaptSession<C extends Context>(bot: LarkBot<C>, body: Eve
291
300
  }
292
301
 
293
302
  // TODO: This function has many duplicated code with `adaptMessage`, should refactor them
294
- export async function decodeMessage(bot: LarkBot, body: Message, details = true): Promise<Universal.Message> {
295
- const json = JSON.parse(body.body.content)
303
+ export async function decodeMessage<C extends Context = Context>(bot: LarkBot<C>, body: Message, details = true): Promise<Universal.Message> {
304
+ const json = JSON.parse(body.body!.content)
296
305
  const content: h[] = []
297
306
  switch (body.msg_type) {
298
307
  case 'text': {
@@ -305,7 +314,7 @@ export async function decodeMessage(bot: LarkBot, body: Message, details = true)
305
314
  // Lark's `at` Element would be `@user_id` in text
306
315
  text.split(' ').forEach((word) => {
307
316
  if (word.startsWith('@')) {
308
- const mention = body.mentions.find((mention) => mention.key === word)
317
+ const mention = body.mentions!.find((mention) => mention.key === word)!
309
318
  content.push(h.at(mention.id, { name: mention.name }))
310
319
  } else {
311
320
  content.push(h.text(word))
@@ -314,37 +323,37 @@ export async function decodeMessage(bot: LarkBot, body: Message, details = true)
314
323
  break
315
324
  }
316
325
  case 'image':
317
- content.push(h.image(bot.getResourceUrl('image', body.message_id, json.image_key)))
326
+ content.push(h.image(bot.getResourceUrl('image', body.message_id!, json.image_key)))
318
327
  break
319
328
  case 'audio':
320
- content.push(h.audio(bot.getResourceUrl('file', body.message_id, json.file_key)))
329
+ content.push(h.audio(bot.getResourceUrl('file', body.message_id!, json.file_key)))
321
330
  break
322
331
  case 'media':
323
- content.push(h.video(bot.getResourceUrl('file', body.message_id, json.file_key), {
332
+ content.push(h.video(bot.getResourceUrl('file', body.message_id!, json.file_key), {
324
333
  poster: json.image_key,
325
334
  }))
326
335
  break
327
336
  case 'file':
328
- content.push(h.file(bot.getResourceUrl('file', body.message_id, json.file_key)))
337
+ content.push(h.file(bot.getResourceUrl('file', body.message_id!, json.file_key)))
329
338
  break
330
339
  }
331
340
 
332
341
  return {
333
- timestamp: +body.update_time,
334
- createdAt: +body.create_time,
335
- updatedAt: +body.update_time,
342
+ timestamp: +body.update_time!,
343
+ createdAt: +body.create_time!,
344
+ updatedAt: +body.update_time!,
336
345
  id: body.message_id,
337
346
  messageId: body.message_id,
338
347
  user: {
339
- id: body.sender.id,
348
+ id: body.sender!.id,
340
349
  },
341
350
  channel: {
342
- id: body.chat_id,
351
+ id: body.chat_id!,
343
352
  type: Universal.Channel.Type.TEXT,
344
353
  },
345
354
  content: content.map((c) => c.toString()).join(' '),
346
355
  elements: content,
347
- quote: (body.upper_message_id && details) ? await bot.getMessage(body.chat_id, body.upper_message_id, false) : undefined,
356
+ quote: (body.upper_message_id && details) ? await bot.getMessage(body.chat_id!, body.upper_message_id, false) : undefined,
348
357
  }
349
358
  }
350
359
 
@@ -371,7 +380,7 @@ export function decodeChannel(channelId: string, guild: GetImChatResponse): Univ
371
380
 
372
381
  export function decodeGuild(guild: ListChat): Universal.Guild {
373
382
  return {
374
- id: guild.chat_id,
383
+ id: guild.chat_id!,
375
384
  name: guild.name,
376
385
  avatar: guild.avatar,
377
386
  }
@@ -379,7 +388,7 @@ export function decodeGuild(guild: ListChat): Universal.Guild {
379
388
 
380
389
  export function decodeUser(user: User): Universal.User {
381
390
  return {
382
- id: user.open_id,
391
+ id: user.open_id!,
383
392
  avatar: user.avatar?.avatar_origin,
384
393
  isBot: false,
385
394
  name: user.name,