@zhin.js/core 1.0.1 → 1.0.3

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 (69) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/app.d.ts +10 -2
  3. package/lib/app.d.ts.map +1 -1
  4. package/lib/app.js +27 -2
  5. package/lib/app.js.map +1 -1
  6. package/lib/bot.d.ts +4 -2
  7. package/lib/bot.d.ts.map +1 -1
  8. package/lib/command.d.ts +2 -1
  9. package/lib/command.d.ts.map +1 -1
  10. package/lib/command.js.map +1 -1
  11. package/lib/component.d.ts +22 -102
  12. package/lib/component.d.ts.map +1 -1
  13. package/lib/component.js +438 -242
  14. package/lib/component.js.map +1 -1
  15. package/lib/jsx-dev-runtime.d.ts +3 -0
  16. package/lib/jsx-dev-runtime.d.ts.map +1 -0
  17. package/lib/jsx-dev-runtime.js +3 -0
  18. package/lib/jsx-dev-runtime.js.map +1 -0
  19. package/lib/jsx-runtime.d.ts +12 -0
  20. package/lib/jsx-runtime.d.ts.map +1 -0
  21. package/lib/jsx-runtime.js +11 -0
  22. package/lib/jsx-runtime.js.map +1 -0
  23. package/lib/jsx.d.ts +32 -0
  24. package/lib/jsx.d.ts.map +1 -0
  25. package/lib/jsx.js +57 -0
  26. package/lib/jsx.js.map +1 -0
  27. package/lib/log-transport.d.ts +37 -0
  28. package/lib/log-transport.d.ts.map +1 -0
  29. package/lib/log-transport.js +136 -0
  30. package/lib/log-transport.js.map +1 -0
  31. package/lib/message.d.ts +10 -7
  32. package/lib/message.d.ts.map +1 -1
  33. package/lib/message.js.map +1 -1
  34. package/lib/models/system-log.d.ts +11 -0
  35. package/lib/models/system-log.d.ts.map +1 -0
  36. package/lib/models/system-log.js +9 -0
  37. package/lib/models/system-log.js.map +1 -0
  38. package/lib/plugin.d.ts +4 -3
  39. package/lib/plugin.d.ts.map +1 -1
  40. package/lib/plugin.js +12 -2
  41. package/lib/plugin.js.map +1 -1
  42. package/lib/prompt.d.ts.map +1 -1
  43. package/lib/prompt.js +3 -2
  44. package/lib/prompt.js.map +1 -1
  45. package/lib/types.d.ts +13 -15
  46. package/lib/types.d.ts.map +1 -1
  47. package/lib/utils.d.ts.map +1 -1
  48. package/lib/utils.js +3 -1
  49. package/lib/utils.js.map +1 -1
  50. package/package.json +16 -4
  51. package/src/app.ts +37 -4
  52. package/src/bot.ts +5 -3
  53. package/src/command.ts +2 -1
  54. package/src/component.ts +523 -280
  55. package/src/jsx-dev-runtime.ts +2 -0
  56. package/src/jsx-runtime.ts +12 -0
  57. package/src/jsx.d.ts +52 -0
  58. package/src/jsx.ts +92 -0
  59. package/src/log-transport.ts +163 -0
  60. package/src/message.ts +8 -5
  61. package/src/models/system-log.ts +20 -0
  62. package/src/plugin.ts +19 -5
  63. package/src/prompt.ts +3 -2
  64. package/src/types.ts +13 -13
  65. package/src/utils.ts +6 -5
  66. package/tests/component-new.test.ts +348 -0
  67. package/tests/expression-evaluation.test.ts +258 -0
  68. package/tests/plugin.test.ts +26 -17
  69. package/tests/component.test.ts +0 -656
@@ -0,0 +1,2 @@
1
+ export * from './jsx-runtime.js'
2
+ export {jsx as jsxDEV} from './jsx.js'
@@ -0,0 +1,12 @@
1
+ // JSX 运行时入口文件
2
+ import { jsx, jsxs, Fragment, renderJSX } from './jsx.js';
3
+
4
+ export { jsx, jsxs, Fragment, renderJSX };
5
+
6
+ // 默认导出 JSX 运行时
7
+ export default {
8
+ jsx,
9
+ jsxs,
10
+ Fragment,
11
+ renderJSX
12
+ };
package/src/jsx.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { SendContent } from './types.js';
2
+ import { Component,ComponentContext } from './component.js';
3
+ import { MessageElement } from './types.js';
4
+
5
+ declare global {
6
+ namespace JSX {
7
+ interface Element {
8
+ type: string | Component<any>;
9
+ data: Record<string, any>;
10
+ children?: JSXChildren;
11
+ }
12
+
13
+ interface ElementClass {
14
+ render(props: any, context?: ComponentContext): MaybePromise<SendContent>;
15
+ }
16
+
17
+ interface ElementAttributesProperty {
18
+ data: {};
19
+ }
20
+
21
+ interface ElementChildrenAttribute {
22
+ children: {};
23
+ }
24
+
25
+ interface IntrinsicElements {
26
+ // 简化的组件元素
27
+ fetch: JSXFetchElement;
28
+ }
29
+ }
30
+ }
31
+
32
+ // 简化的组件属性接口
33
+ interface JSXBaseElement {
34
+ children?: JSXChildren;
35
+ }
36
+
37
+ interface JSXFetchElement extends JSXBaseElement {
38
+ url?: string;
39
+ }
40
+
41
+ // JSX 子元素类型
42
+ type JSXChildren = MessageElement | string | number | boolean | null | undefined | JSXChildren[];
43
+
44
+ // JSX 元素类型
45
+ type JSXElement = {
46
+ type: string | Component<any>;
47
+ data: Record<string, any>;
48
+ children?: JSXChildren;
49
+ };
50
+
51
+ // 类型辅助
52
+ type MaybePromise<T> = T | Promise<T>;
package/src/jsx.ts ADDED
@@ -0,0 +1,92 @@
1
+ import { MaybePromise } from '@zhin.js/types';
2
+ import { SendContent,MessageElement } from './types.js';
3
+ import { MessageComponent } from './message.js';
4
+ import { Component, ComponentContext } from './component.js';
5
+
6
+
7
+ // JSX 子元素类型
8
+ export type JSXChildren = MessageElement | string | number | boolean | null | undefined | JSXChildren[];
9
+
10
+ // JSX 元素类型
11
+ export type JSXElementType = string | Component<any> ;
12
+
13
+ // JSX 属性类型
14
+ export type JSXProps = Record<string, any> & {
15
+ children?: JSXChildren;
16
+ };
17
+ export {Fragment} from './component.js'
18
+ // 全局 JSX 命名空间
19
+ declare global {
20
+ namespace JSX {
21
+ interface Element extends MessageComponent<any> {}
22
+ interface ElementClass {
23
+ render(props: any, context?: ComponentContext): MaybePromise<SendContent>;
24
+ }
25
+ interface ElementAttributesProperty {
26
+ data: {};
27
+ }
28
+ interface ElementChildrenAttribute {
29
+ children: {};
30
+ }
31
+ interface IntrinsicElements {
32
+ [elemName: string]: any;
33
+ }
34
+ }
35
+ }
36
+
37
+ // JSX 运行时函数
38
+ export function jsx(type: JSXElementType, data: JSXProps): MessageElement {
39
+ return {
40
+ type,
41
+ data,
42
+ } as MessageElement;
43
+ }
44
+
45
+ // JSX Fragment 支持
46
+ export function jsxs(type: JSXElementType, props: JSXProps): MessageElement {
47
+ return jsx(type, props);
48
+ }
49
+
50
+
51
+ // JSX 渲染函数
52
+ export async function renderJSX(element: MessageComponent<any>, context?: ComponentContext): Promise<SendContent> {
53
+ if (typeof element.type === 'string') {
54
+ if (element.type === 'Fragment') {
55
+ return await renderChildren(element.data.children, context);
56
+ }
57
+ // 其他内置组件处理
58
+ return await renderChildren(element.data.children, context);
59
+ } else if (typeof element.type === 'function') {
60
+ // 函数组件
61
+ const component = element.type as Component<any>;
62
+ return await component(element.data, context || {} as ComponentContext);
63
+ } else {
64
+ // 类组件或其他类型
65
+ const component = element.type as Component<any>;
66
+ return await component(element.data, context || {} as ComponentContext);
67
+ }
68
+ }
69
+
70
+ // 渲染子元素
71
+ async function renderChildren(children: JSXChildren, context?: ComponentContext): Promise<SendContent> {
72
+ if (children == null) return '';
73
+ if (typeof children === 'string' || typeof children === 'number' || typeof children === 'boolean') {
74
+ return String(children);
75
+ }
76
+ if (Array.isArray(children)) {
77
+ const results = await Promise.all(children.map(async child => {
78
+ if (typeof child === 'string' || typeof child === 'number' || typeof child === 'boolean') {
79
+ return String(child);
80
+ }
81
+ if (child && typeof child === 'object' && 'type' in child) {
82
+ return await renderJSX(child as MessageComponent<any>, context);
83
+ }
84
+ return '';
85
+ }));
86
+ return results.join('');
87
+ }
88
+ if (children && typeof children === 'object' && 'type' in children) {
89
+ return await renderJSX(children as MessageComponent<any>, context);
90
+ }
91
+ return '';
92
+ }
@@ -0,0 +1,163 @@
1
+ import { LogTransport } from '@zhin.js/logger'
2
+ import { App } from './app.js'
3
+
4
+ /**
5
+ * 数据库日志传输器
6
+ * 将日志存储到数据库,并自动清理旧日志
7
+ */
8
+ export class DatabaseLogTransport implements LogTransport {
9
+ private app: App
10
+ private stripAnsiRegex = /\x1b\[[0-9;]*m/g
11
+ private cleanupTimer?: NodeJS.Timeout
12
+ private maxDays: number
13
+ private maxRecords: number
14
+ private cleanupInterval: number
15
+
16
+ constructor(app: App) {
17
+ this.app = app
18
+
19
+ // 从配置读取日志清理策略
20
+ const logConfig = app['config']?.log || {}
21
+ this.maxDays = logConfig.maxDays || 7 // 默认保留 7 天
22
+ this.maxRecords = logConfig.maxRecords || 10000 // 默认最多 10000 条
23
+ this.cleanupInterval = logConfig.cleanupInterval || 24 // 默认 24 小时清理一次
24
+
25
+ // 启动定时清理
26
+ this.startCleanup()
27
+ }
28
+
29
+ /**
30
+ * 启动定时清理任务
31
+ */
32
+ private startCleanup(): void {
33
+ // 立即执行一次清理
34
+ this.cleanupOldLogs().catch(err => {
35
+ this.app.logger.error('[DatabaseLogTransport] Initial cleanup failed:', err.message)
36
+ })
37
+
38
+ // 设置定时任务
39
+ this.cleanupTimer = setInterval(() => {
40
+ this.cleanupOldLogs().catch(err => {
41
+ this.app.logger.error('[DatabaseLogTransport] Scheduled cleanup failed:', err.message)
42
+ })
43
+ }, this.cleanupInterval * 60 * 60 * 1000) // 转换为毫秒
44
+ }
45
+
46
+ /**
47
+ * 清理旧日志
48
+ */
49
+ private async cleanupOldLogs(): Promise<void> {
50
+ if (!this.app.database) {
51
+ return
52
+ }
53
+
54
+ try {
55
+ const LogModel = this.app.database.model('SystemLog')
56
+ if (!LogModel) {
57
+ return
58
+ }
59
+
60
+ // 1. 按时间清理:删除超过 maxDays 天的日志
61
+ const cutoffDate = new Date()
62
+ cutoffDate.setDate(cutoffDate.getDate() - this.maxDays)
63
+
64
+ const deletedByDate = await LogModel
65
+ .delete({ timestamp: { $lt: cutoffDate } })
66
+
67
+ // 2. 按数量清理:如果日志总数超过 maxRecords,删除最旧的
68
+ const total = await LogModel.select()
69
+ const totalCount = total.length
70
+
71
+ if (totalCount > this.maxRecords) {
72
+ const excessCount = totalCount - this.maxRecords
73
+
74
+ // 查找最旧的 excessCount 条日志的 ID
75
+ const oldestLogs = await LogModel
76
+ .select('id','timestamp')
77
+ .orderBy('timestamp', 'ASC')
78
+ .limit(excessCount)
79
+
80
+ const idsToDelete = oldestLogs.map((log: any) => log.id)
81
+
82
+ if (idsToDelete.length > 0) {
83
+ await LogModel
84
+ .delete({ id: { $in: idsToDelete } })
85
+ }
86
+ }
87
+
88
+ this.app.logger.info(
89
+ `[DatabaseLogTransport] Log cleanup completed. ` +
90
+ `Deleted ${deletedByDate || 0} logs older than ${this.maxDays} days. ` +
91
+ `Current total: ${Math.max(0, totalCount - (deletedByDate || 0))} logs.`
92
+ )
93
+ } catch (error) {
94
+ // 静默处理错误
95
+ this.app.logger.error('[DatabaseLogTransport] Cleanup error:', (error as Error).message)
96
+ }
97
+ }
98
+
99
+ /**
100
+ * 停止清理任务
101
+ */
102
+ public stopCleanup(): void {
103
+ if (this.cleanupTimer) {
104
+ clearInterval(this.cleanupTimer)
105
+ this.cleanupTimer = undefined
106
+ }
107
+ }
108
+
109
+ /**
110
+ * 移除 ANSI 颜色代码
111
+ */
112
+ private stripAnsi(str: string): string {
113
+ return str.replace(this.stripAnsiRegex, '')
114
+ }
115
+
116
+ write(message: string): void {
117
+ // 移除 ANSI 颜色代码
118
+ const cleanMessage = this.stripAnsi(message)
119
+
120
+ // 解析日志消息
121
+ // 格式: [09-08 04:07:55.852] [INFO] [MyApp]: message
122
+ const logRegex = /\[[\d-]+ [\d:.]+\] \[(\w+)\] \[([^\]]+)\]: ([\s\S]+)/
123
+ const match = cleanMessage.match(logRegex)
124
+
125
+ if (match) {
126
+ const [, level, name, msg] = match
127
+ const source = name.split(':')[0] // 取第一部分作为 source
128
+
129
+ // 异步存储到数据库,不阻塞日志输出
130
+ this.saveToDatabase(level.toLowerCase(), name, msg.trim(), source).catch(err => {
131
+ // 避免日志存储失败导致应用崩溃
132
+ console.error('[DatabaseLogTransport] Failed to save log:', err.message)
133
+ })
134
+ }
135
+ }
136
+
137
+ /**
138
+ * 保存日志到数据库
139
+ */
140
+ private async saveToDatabase(level: string, name: string, message: string, source: string): Promise<void> {
141
+ if (!this.app.database) {
142
+ return // 没有数据库则跳过
143
+ }
144
+
145
+ try {
146
+ const LogModel = this.app.database.model('SystemLog')
147
+ if (!LogModel) {
148
+ return // 模型不存在则跳过
149
+ }
150
+
151
+ await LogModel.create({
152
+ level,
153
+ name,
154
+ message,
155
+ source,
156
+ timestamp: new Date()
157
+ })
158
+ } catch (error) {
159
+ // 静默处理错误,避免干扰主流程
160
+ }
161
+ }
162
+ }
163
+
package/src/message.ts CHANGED
@@ -1,10 +1,13 @@
1
- import {MaybePromise} from "@zhin.js/types";
2
- import {MessageSegment, MessageSender, RegisteredAdapter, SendContent} from "./types";
1
+ import {MessageElement, MessageSender, SendContent} from "./types";
2
+ import { Component } from "./component.js";
3
3
 
4
4
  /**
5
5
  * 消息组件类型:用于自定义消息结构
6
6
  */
7
- export type MessageComponent<T extends object>=(props:T&{children:SendContent})=>MaybePromise<SendContent>
7
+ export type MessageComponent<T extends object>={
8
+ type:Component<T&{children?:SendContent}>
9
+ data:T
10
+ }
8
11
  /**
9
12
  * 消息频道信息
10
13
  */
@@ -23,9 +26,9 @@ export interface MessageBase {
23
26
  $id: string;
24
27
  $adapter:string
25
28
  $bot:string
26
- $content: MessageSegment[];
29
+ $content: MessageElement[];
27
30
  $sender: MessageSender;
28
- $reply(content:SendContent,quote?:boolean|string):Promise<void>
31
+ $reply(content:SendContent,quote?:boolean|string):Promise<string>
29
32
  $channel: MessageChannel;
30
33
  $timestamp: number;
31
34
  $raw: string;
@@ -0,0 +1,20 @@
1
+ import { Schema } from '@zhin.js/database'
2
+
3
+ export interface SystemLog {
4
+ id?: number
5
+ level: string
6
+ name: string
7
+ message: string
8
+ source: string
9
+ timestamp: Date
10
+ }
11
+
12
+ export const SystemLogSchema:Schema<SystemLog>={
13
+ id: { type: 'integer', autoIncrement: true, primary: true },
14
+ level: { type: 'text', nullable: false },
15
+ name: { type: 'text', nullable: false },
16
+ message: { type: 'text', nullable: false },
17
+ source: { type: 'text', nullable: false },
18
+ timestamp: { type: 'date', nullable: false }
19
+ }
20
+
package/src/plugin.ts CHANGED
@@ -9,7 +9,7 @@ import {Message} from './message.js'
9
9
  import {Dependency, Logger,} from "@zhin.js/hmr";
10
10
  import {App} from "./app";
11
11
  import {MessageCommand} from "./command.js";
12
- import {Component} from "./component.js";
12
+ import {Component, renderComponents} from "./component.js";
13
13
  import { PluginError, MessageError, errorManager } from './errors.js';
14
14
  import {remove} from "./utils.js";
15
15
  import {Prompt} from "./prompt.js";
@@ -29,8 +29,8 @@ export type MessageMiddleware<P extends RegisteredAdapter=RegisteredAdapter> = (
29
29
  * 支持命令注册、中间件、组件、定时任务、模型等。
30
30
  */
31
31
  export class Plugin extends Dependency<Plugin> {
32
- middlewares: MessageMiddleware<any>[] = [];
33
- components: Map<string, Component<any, any, any>> = new Map();
32
+ middlewares: MessageMiddleware<RegisteredAdapter>[] = [];
33
+ components: Map<string, Component<any>> = new Map();
34
34
  schemas: Map<string,Schema<any>>=new Map();
35
35
  commands:MessageCommand[]=[];
36
36
  crons:Cron[]=[];
@@ -54,7 +54,7 @@ export class Plugin extends Dependency<Plugin> {
54
54
  return next()
55
55
  });
56
56
  // 发送前渲染组件
57
- this.beforeSend((options)=>Component.render(this.components,options))
57
+ this.beforeSend((options)=>renderComponents(this.components,options))
58
58
  // 资源清理:卸载时清空模型、定时任务等
59
59
  this.on('dispose',()=>{
60
60
  for(const name of this.schemas.keys()){
@@ -140,7 +140,7 @@ export class Plugin extends Dependency<Plugin> {
140
140
  return temp.getLogger(names.join('/'))
141
141
  }
142
142
  /** 添加组件 */
143
- addComponent<T = {}, D = {}, P = Component.Props<T>>(component:Component<T,D,P>){
143
+ addComponent<T=any>(component:Component<T>){
144
144
  this.components.set(component.name,component);
145
145
  }
146
146
  /** 添加中间件 */
@@ -178,6 +178,20 @@ export class Plugin extends Dependency<Plugin> {
178
178
  throw messageError
179
179
  }
180
180
  }
181
+ recallMessage(adapter:string,bot:string,id:string){
182
+ try{
183
+ this.app.recallMessage(adapter,bot,id)
184
+ }catch(error){
185
+ const messageError = new MessageError(
186
+ `撤回消息失败: ${(error as Error).message}`,
187
+ id,
188
+ undefined,
189
+ { originalError: error }
190
+ )
191
+ errorManager.handle(messageError)
192
+ throw messageError
193
+ }
194
+ }
181
195
 
182
196
  /** 销毁插件 */
183
197
  dispose(): void {
package/src/prompt.ts CHANGED
@@ -27,8 +27,8 @@ export class Prompt<P extends RegisteredAdapter> {
27
27
  * @param config 提问配置
28
28
  */
29
29
  private prompt<T = any>(config: Prompt.Config<T>) {
30
- return new Promise<T>((resolve, reject) => {
31
- this.event.$reply(config.tips);
30
+ return new Promise<T>(async (resolve, reject) => {
31
+ const id = await this.event.$reply(config.tips);
32
32
  this.middleware(
33
33
  input => {
34
34
  if (input instanceof Error) {
@@ -37,6 +37,7 @@ export class Prompt<P extends RegisteredAdapter> {
37
37
  else reject(input);
38
38
  return;
39
39
  }
40
+ this.plugin.recallMessage(this.event.$adapter,this.event.$bot,id);
40
41
  resolve(config.format(input));
41
42
  },
42
43
  config.timeout,
package/src/types.ts CHANGED
@@ -1,20 +1,10 @@
1
- import {MaybePromise}from '@zhin.js/types'
1
+ import {MaybePromise,RegisteredAdapters}from '@zhin.js/types'
2
2
  import {MessageChannel} from "./message.js";
3
3
  import {Adapter} from "./adapter.js";
4
4
  import {Bot,BotConfig} from "./bot.js";
5
5
  import { Databases,Registry } from "@zhin.js/database";
6
+ import { MessageComponent } from "./message.js";
6
7
 
7
- /**
8
- * 类型定义文件:包含适配器、消息、数据库、配置等核心类型声明。
9
- * 协作者可通过本文件了解各主要数据结构的用途与关系。
10
- */
11
- declare module '@zhin.js/types'{
12
- interface GlobalContext extends RegisteredAdapters{}
13
- }
14
- /**
15
- * 所有已注册适配器的类型映射(key为适配器名,value为Adapter实例)
16
- */
17
- export interface RegisteredAdapters extends Record<string, Adapter>{}
18
8
  /**
19
9
  * 数据库配置类型,支持多种数据库驱动
20
10
  */
@@ -52,6 +42,7 @@ export interface MessageSegment {
52
42
  type: string;
53
43
  data: Record<string, any>;
54
44
  }
45
+ export type MessageElement=MessageSegment|MessageComponent<any>
55
46
  /**
56
47
  * 单个或数组类型
57
48
  */
@@ -59,7 +50,7 @@ export type MaybeArray<T>=T|T[]
59
50
  /**
60
51
  * 消息发送内容类型
61
52
  */
62
- export type SendContent=MaybeArray<string|MessageSegment>
53
+ export type SendContent=MaybeArray<string|MessageElement>
63
54
  /**
64
55
  * 消息发送者信息
65
56
  */
@@ -107,6 +98,15 @@ export interface AppConfig {
107
98
  disable_dependencies?: string[];
108
99
  /** 是否启用调试模式 */
109
100
  debug?: boolean;
101
+ /** 日志配置 */
102
+ log?: {
103
+ /** 最大日志保留天数,默认 7 天 */
104
+ maxDays?: number;
105
+ /** 最大日志条数,默认 10000 条 */
106
+ maxRecords?: number;
107
+ /** 自动清理间隔(小时),默认 24 小时 */
108
+ cleanupInterval?: number;
109
+ };
110
110
  }
111
111
  /**
112
112
  * defineConfig辅助类型,支持函数式/对象式配置
package/src/utils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {Dict, MessageSegment, SendContent} from "./types";
1
+ import {Dict, MessageElement, MessageSegment, SendContent} from "./types";
2
2
 
3
3
  export function getValueWithRuntime(template: string, ctx: Dict) {
4
4
  const result = evaluate(template, ctx);
@@ -79,10 +79,10 @@ export namespace segment{
79
79
  }
80
80
  export function from(content: SendContent): SendContent {
81
81
  if (!Array.isArray(content)) content=[content];
82
- const toString=(template:string|MessageSegment)=>{
82
+ const toString=(template:string|MessageElement)=>{
83
83
  if(typeof template!=='string') return [template]
84
84
  template=unescape(template);
85
- const result: MessageSegment[] = [];
85
+ const result: MessageElement[] = [];
86
86
  const closingReg = /<(\S+)(\s[^>]+)?\/>/;
87
87
  const twinningReg = /<(\S+)(\s[^>]+)?>([\s\S]*?)<\/\1>/;
88
88
  while (template.length) {
@@ -132,7 +132,7 @@ export namespace segment{
132
132
  return content.reduce((result,item)=>{
133
133
  result.push(...toString(item))
134
134
  return result;
135
- },[] as MessageSegment[])
135
+ },[] as MessageElement[])
136
136
  }
137
137
  export function raw(content:SendContent){
138
138
  if(!Array.isArray(content)) content=[content]
@@ -147,7 +147,8 @@ export namespace segment{
147
147
  if(!Array.isArray(content)) content=[content]
148
148
  return content.map(item=>{
149
149
  if(typeof item==='string') return item
150
- const {type,data}=item
150
+ let {type,data}=item
151
+ if(typeof type==='function') type=type.name
151
152
  if(type==='text') return data.text
152
153
  return `<${type} ${Object.keys(data).map(key=>`${key}='${escape(JSON.stringify(data[key]))}'`).join(' ')}/>`
153
154
  }).join('')