@karinjs/adapter-qqbot 1.2.9 → 1.3.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,265 +0,0 @@
1
- import path from 'path';
2
- import { common, common as Common } from '../utils/common.js';
3
- import { handler, common as karinCommon, segment, } from 'node-karin';
4
- /**
5
- * 图文模板
6
- */
7
- export async function markdownTemplate(Opt) {
8
- const { bot, data, type, openid, message_id } = Opt;
9
- /** 先对消息进行分类 */
10
- const text = [];
11
- const image = [];
12
- /** 待发送列表 */
13
- const send_list = [];
14
- let seq = common.random(1, 999999);
15
- let keyboard;
16
- const params = [];
17
- const markdown = [];
18
- const list = [];
19
- const buttons = [];
20
- const imgs = [];
21
- const result = {
22
- message_id: '',
23
- message_time: 0,
24
- raw_data: [],
25
- };
26
- const textFn = async () => {
27
- text.sort((a, b) => a.index - b.index);
28
- const data = Common.getQQBotButton(text.map(v => v.data.text).join(''));
29
- const val = type === "users" /* PathType.Friends */ ? Common.formatText(data.text, true) : Common.formatText(data.text);
30
- /** 去除at全体 */
31
- params.push({ key: bot.markdown.oldTemplate.textStartKey, values: [val] });
32
- /** 按钮 */
33
- buttons.push(...data.data);
34
- };
35
- const imageFn = async (i) => {
36
- const { url, width, height } = await handler.call('qqbot.files', { file: i.data.file, type: 'image', name: '0.png' });
37
- imgs.push({ index: i.index, url, width, height });
38
- };
39
- const mediaFn = async (file, type, name, FileType) => {
40
- const { url } = await handler.call('qqbot.files', { file, type, name });
41
- const { file_info } = await bot.super.uploadMedia(openid, type, url, FileType);
42
- const opt = bot.super.buildMedia('', file_info, message_id, ++seq);
43
- const res = await bot.super.sendMessage(openid, type, opt);
44
- result.raw_data.push(res);
45
- };
46
- await Promise.all(data.map(async (data, index) => {
47
- switch (data.type) {
48
- case 'text':
49
- text.push({ index, data });
50
- break;
51
- case 'image':
52
- image.push({ index, data });
53
- break;
54
- case 'at': {
55
- if (type === "users" /* PathType.Friends */)
56
- break;
57
- text.push({ index, data: segment.text(`<qqbot-at-user id="${data.uid || data.uin}" />`) });
58
- break;
59
- }
60
- case 'record': {
61
- const file = await common.voiceToSilk(data.file);
62
- list.push(mediaFn(file, type, '0.silk', 3 /* FileType.Record */));
63
- break;
64
- }
65
- case 'video': {
66
- list.push(mediaFn(data.file, type, '0.mp4', 2 /* FileType.Video */));
67
- break;
68
- }
69
- case 'file': {
70
- /** 判断是不是一个本地路径 */
71
- let ext = Date.now() + '';
72
- if (path.isAbsolute(data.file))
73
- ext = Date.now() + path.extname(data.file);
74
- list.push(mediaFn(data.file, type, ext, 4 /* FileType.File */));
75
- break;
76
- }
77
- case 'button': {
78
- buttons.push(data);
79
- break;
80
- }
81
- case 'markdown': {
82
- text.push({ index, data: { type: 'text', text: data.content } });
83
- break;
84
- }
85
- case 'markdown_tpl': {
86
- markdown.push({ index, custom_template_id: data.custom_template_id, params: data.params });
87
- break;
88
- }
89
- default:
90
- break;
91
- }
92
- }));
93
- if (text.length || image.length) {
94
- /** 处理文本 */
95
- if (text.length)
96
- list.push(textFn());
97
- /** 处理图片 */
98
- image.map(i => list.push(imageFn(i)));
99
- await Promise.all(list);
100
- }
101
- else {
102
- await Promise.all(list);
103
- }
104
- if (buttons.length) {
105
- const rows = [];
106
- buttons.forEach(v => {
107
- const button = karinCommon.buttonToQQBot(v);
108
- rows.push(...button);
109
- });
110
- keyboard = { content: { rows: [...rows] } };
111
- }
112
- if (markdown.length) {
113
- markdown.sort((a, b) => a.index - b.index);
114
- await Promise.all(markdown.map(async (v, index) => {
115
- const opt = bot.super.buildTplMarkdown(v.custom_template_id, v.params, keyboard, message_id, ++seq);
116
- send_list.push({ index: v.index, opt });
117
- }));
118
- }
119
- if (imgs.length) {
120
- imgs.sort((a, b) => a.index - b.index);
121
- /** 取第一个 */
122
- const { url, width, height } = imgs[0];
123
- params.push({ key: bot.markdown.oldTemplate.imgDescKey, values: [`img #${width}px #${height}px`] });
124
- params.push({ key: bot.markdown.oldTemplate.imgUrlKey, values: [url] });
125
- /** 去除第一个 */
126
- imgs.shift();
127
- send_list.push({ index: -1, opt: bot.super.buildTplMarkdown(bot.markdown.templateId, params, keyboard, message_id, ++seq) });
128
- /** 剩下的构建为单独的md */
129
- await Promise.all(imgs.map(async (img) => {
130
- const { url, width, height } = img;
131
- const params = [];
132
- params.push({ key: bot.markdown.oldTemplate.imgDescKey, values: [`img #${width}px #${height}px`] });
133
- params.push({ key: bot.markdown.oldTemplate.imgUrlKey, values: [url] });
134
- send_list.push({ index: img.index, opt: bot.super.buildTplMarkdown(bot.markdown.templateId, params, keyboard, message_id, ++seq) });
135
- }));
136
- }
137
- else {
138
- params.length && send_list.push({ index: -1, opt: bot.super.buildTplMarkdown(bot.markdown.templateId, params, keyboard, message_id, ++seq) });
139
- }
140
- /** 并发发送 */
141
- await Promise.all(send_list.map(async (v, index) => {
142
- index !== 0 && await new Promise(resolve => setTimeout(resolve, index * 100));
143
- const res = await bot.super.sendMessage(openid, type, v.opt);
144
- result.raw_data.push(res);
145
- }));
146
- result.message_id = result.raw_data[0].id;
147
- result.message_time = result.raw_data[0].time;
148
- return result;
149
- }
150
- /**
151
- * 原生markdown
152
- */
153
- export async function markdownRaw(Opt) {
154
- const { bot, data, type, openid, message_id } = Opt;
155
- /** 待发送列表 */
156
- const send_list = [];
157
- let seq = common.random(1, 999999);
158
- const list = [];
159
- const result = {
160
- message_id: '',
161
- message_time: 0,
162
- raw_data: [],
163
- };
164
- let keyboard;
165
- const buttons = [];
166
- const message = [];
167
- const markdown_tpl = [];
168
- const imageFn = async (index, data) => {
169
- const { url, width, height } = await handler.call('qqbot.files', { file: data.file, type: 'image', name: '0.png' });
170
- message.push({ index, data: `![img #${width}px #${height}px](${url})` });
171
- };
172
- /** 富媒体消息直接发送 无需和正常消息走 */
173
- const mediaFn = async (file, type, name, FileType) => {
174
- const { url } = await handler.call('qqbot.files', { file, type, name });
175
- const { file_info } = await bot.super.uploadMedia(openid, type, url, FileType);
176
- const opt = bot.super.buildMedia('', file_info, message_id, ++seq);
177
- const res = await bot.super.sendMessage(openid, type, opt);
178
- result.raw_data.push(res);
179
- };
180
- await Promise.all(data.map(async (data, index) => {
181
- switch (data.type) {
182
- case 'text': {
183
- /** 先提取掉url 随后放出按钮中 */
184
- const res = Common.getQQBotButton(data.text);
185
- buttons.push(...res.data);
186
- const text = type === "users" /* PathType.Friends */ ? Common.formatText(res.text, true) : Common.formatText(res.text);
187
- message.push({ index, data: text });
188
- break;
189
- }
190
- case 'image':
191
- imageFn(index, data);
192
- break;
193
- case 'at': {
194
- if (type === "users" /* PathType.Friends */)
195
- break;
196
- message.push({ index, data: `<qqbot-at-user id="${data.uid || data.uin}" />` });
197
- break;
198
- }
199
- case 'record': {
200
- const file = await common.voiceToSilk(data.file);
201
- list.push(mediaFn(file, type, '0.silk', 3 /* FileType.Record */));
202
- break;
203
- }
204
- case 'video': {
205
- list.push(mediaFn(data.file, type, '0.mp4', 2 /* FileType.Video */));
206
- break;
207
- }
208
- case 'file': {
209
- /** 判断是不是一个本地路径 */
210
- let ext = Date.now() + '';
211
- if (path.isAbsolute(data.file))
212
- ext = Date.now() + path.extname(data.file);
213
- list.push(mediaFn(data.file, type, ext, 4 /* FileType.File */));
214
- break;
215
- }
216
- case 'button': {
217
- buttons.push(data);
218
- break;
219
- }
220
- case 'keyboard': {
221
- buttons.push(data);
222
- break;
223
- }
224
- case 'markdown': {
225
- message.push({ index, data: data.content });
226
- break;
227
- }
228
- // 原生下发模板多少有点问题...
229
- case 'markdown_tpl': {
230
- markdown_tpl.push({ index, data });
231
- break;
232
- }
233
- default:
234
- break;
235
- }
236
- }));
237
- await Promise.all(list);
238
- if (buttons.length) {
239
- const rows = [];
240
- buttons.forEach(v => {
241
- const button = karinCommon.buttonToQQBot(v);
242
- rows.push(...button);
243
- });
244
- keyboard = { content: { rows: [...rows] } };
245
- }
246
- if (markdown_tpl.length) {
247
- await Promise.all(markdown_tpl.map(async (v, index) => {
248
- const opt = bot.super.buildTplMarkdown(v.data.custom_template_id, v.data.params, keyboard, message_id, ++seq);
249
- send_list.push({ index: v.index, opt });
250
- }));
251
- }
252
- if (message.length) {
253
- message.sort((a, b) => a.index - b.index);
254
- send_list.push({ index: -1, opt: bot.super.buildRawMarkdown(message.map(v => v.data).join(''), keyboard, message_id, ++seq) });
255
- }
256
- /** 并发发送 */
257
- await Promise.all(send_list.map(async (v, index) => {
258
- index !== 0 && await new Promise(resolve => setTimeout(resolve, index * 100));
259
- const res = await bot.super.sendMessage(openid, type, v.opt);
260
- result.raw_data.push(res);
261
- }));
262
- result.message_id = result.raw_data[0].id;
263
- result.message_time = result.raw_data[0].time;
264
- return result;
265
- }
package/lib/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- import './core/index.js';
2
- import Jimp from 'jimp';
3
- export default Jimp;
package/lib/index.js DELETED
@@ -1,7 +0,0 @@
1
- import './core/index.js';
2
- import Jimp from 'jimp';
3
- import { logger, common } from 'node-karin';
4
- import { basename, dirPath } from './utils/dir.js';
5
- const pkg = common.readJson(dirPath + '/package.json');
6
- logger.info(`${logger.violet(`[插件:${pkg.version}]`)} ${logger.green(basename)} 初始化完成~`);
7
- export default Jimp;
@@ -1,232 +0,0 @@
1
- import { Attachment } from './media.js';
2
- /**
3
- * opcode
4
- * 客户端操作含义如下:
5
- * Receive 客户端接收到服务端 push 的消息
6
- * Send 客户端发送消息
7
- * Reply 客户端接收到服务端发送的消息之后的回包(HTTP 回调模式)
8
- */
9
- export declare const enum Opcode {
10
- /** Dispatch [Receive] 服务端进行消息推送 */
11
- Dispatch = 0,
12
- /** Heartbeat [Send/Receive] 客户端或服务端发送心跳 */
13
- Heartbeat = 1,
14
- /** Identify [Send] 客户端发送鉴权 */
15
- Identify = 2,
16
- /** Resume [Send] 客户端恢复连接 */
17
- Resume = 6,
18
- /** Reconnect [Receive] 服务端通知客户端重新连接 */
19
- Reconnect = 7,
20
- /** Invalid Session [Receive] 当identify或resume的时候,如果参数有错,服务端会返回该消息 */
21
- InvalidSession = 9,
22
- /** Hello [Receive] 当客户端与网关建立ws连接之后,网关下发的第一条消息 */
23
- Hello = 10,
24
- /** Heartbeat ACK [Receive/Reply] 当发送心跳成功之后,就会收到该消息 */
25
- HeartbeatACK = 11,
26
- /** HTTP Callback ACK [Reply] 仅用于 http 回调模式的回包,代表机器人收到了平台推送的数据 */
27
- HTTPCallbackACK = 12
28
- }
29
- /**
30
- * 心跳生命周期事件
31
- */
32
- export interface HeartbeatEvent {
33
- /** opcode */
34
- op: Opcode.Hello;
35
- /** 事件内容 */
36
- d: {
37
- /** 心跳声明周期 */
38
- heartbeat_interval: number;
39
- };
40
- }
41
- /**
42
- * 心跳回包事件
43
- */
44
- export interface HeartbeatACKEvent {
45
- /** opcode */
46
- op: Opcode.HeartbeatACK;
47
- }
48
- /**
49
- * 子事件类型
50
- */
51
- export declare const enum EventType {
52
- /** 在鉴权成功后下发 代表建立连接成功 */
53
- READY = "READY",
54
- /** 恢复登录状态后 不发遗漏事件完毕下发 */
55
- RESUMED = "RESUMED",
56
- /** 当机器人加入新的guild时 */
57
- GUILD_CREATE = "GUILD_CREATE",
58
- /** 当guild资料发生变更时 */
59
- GUILD_UPDATE = "GUILD_UPDATE",
60
- /** 当机器人退出guild时 */
61
- GUILD_DELETE = "GUILD_DELETE",
62
- /** 当channel被创建时 */
63
- CHANNEL_CREATE = "CHANNEL_CREATE",
64
- /** 当channel被更新时 */
65
- CHANNEL_UPDATE = "CHANNEL_UPDATE",
66
- /** 当channel被删除时 */
67
- CHANNEL_DELETE = "CHANNEL_DELETE",
68
- /** 当成员加入时 */
69
- GUILD_MEMBER_ADD = "GUILD_MEMBER_ADD",
70
- /** 当成员资料变更时 */
71
- GUILD_MEMBER_UPDATE = "GUILD_MEMBER_UPDATE",
72
- /** 当成员被移除时 */
73
- GUILD_MEMBER_REMOVE = "GUILD_MEMBER_REMOVE",
74
- /** 发送消息事件,代表频道内的全部消息,而不只是 at 机器人的消息。内容与 AT_MESSAGE_CREATE 相同 */
75
- MESSAGE_CREATE = "MESSAGE_CREATE",
76
- /** 删除(撤回)消息事件 */
77
- MESSAGE_DELETE = "MESSAGE_DELETE",
78
- /** 为消息添加表情表态 */
79
- MESSAGE_REACTION_ADD = "MESSAGE_REACTION_ADD",
80
- /** 为消息删除表情表态 */
81
- MESSAGE_REACTION_REMOVE = "MESSAGE_REACTION_REMOVE",
82
- /** 当收到用户发给机器人的私信消息时 */
83
- DIRECT_MESSAGE_CREATE = "DIRECT_MESSAGE_CREATE",
84
- /** 删除(撤回)消息事件 */
85
- DIRECT_MESSAGE_DELETE = "DIRECT_MESSAGE_DELETE",
86
- /** 用户单聊发消息给机器人时候 */
87
- C2C_MESSAGE_CREATE = "C2C_MESSAGE_CREATE",
88
- /** 用户添加使用机器人 */
89
- FRIEND_ADD = "FRIEND_ADD",
90
- /** 用户删除机器人 */
91
- FRIEND_DEL = "FRIEND_DEL",
92
- /** 用户在机器人资料卡手动关闭"主动消息"推送 */
93
- C2C_MSG_REJECT = "C2C_MSG_REJECT",
94
- /** 用户在机器人资料卡手动开启"主动消息"推送开关 */
95
- C2C_MSG_RECEIVE = "C2C_MSG_RECEIVE",
96
- /** 用户在群里@机器人时收到的消息 */
97
- GROUP_AT_MESSAGE_CREATE = "GROUP_AT_MESSAGE_CREATE",
98
- /** 机器人被添加到群聊 */
99
- GROUP_ADD_ROBOT = "GROUP_ADD_ROBOT",
100
- /** 机器人被移出群聊 */
101
- GROUP_DEL_ROBOT = "GROUP_DEL_ROBOT",
102
- /** 群管理员主动在机器人资料页操作关闭通知 */
103
- GROUP_MSG_REJECT = "GROUP_MSG_REJECT",
104
- /** 群管理员主动在机器人资料页操作开启通知 */
105
- GROUP_MSG_RECEIVE = "GROUP_MSG_RECEIVE",
106
- /** 互动事件创建时 */
107
- INTERACTION_CREATE = "INTERACTION_CREATE",
108
- /** 消息审核通过 */
109
- MESSAGE_AUDIT_PASS = "MESSAGE_AUDIT_PASS",
110
- /** 消息审核不通过 */
111
- MESSAGE_AUDIT_REJECT = "MESSAGE_AUDIT_REJECT",
112
- /** 当用户创建主题时 */
113
- FORUM_THREAD_CREATE = "FORUM_THREAD_CREATE",
114
- /** 当用户更新主题时 */
115
- FORUM_THREAD_UPDATE = "FORUM_THREAD_UPDATE",
116
- /** 当用户删除主题时 */
117
- FORUM_THREAD_DELETE = "FORUM_THREAD_DELETE",
118
- /** 当用户创建帖子时 */
119
- FORUM_POST_CREATE = "FORUM_POST_CREATE",
120
- /** 当用户删除帖子时 */
121
- FORUM_POST_DELETE = "FORUM_POST_DELETE",
122
- /** 当用户回复评论时 */
123
- FORUM_REPLY_CREATE = "FORUM_REPLY_CREATE",
124
- /** 当用户回复评论时 */
125
- FORUM_REPLY_DELETE = "FORUM_REPLY_DELETE",
126
- /** 当用户发表审核通过时 */
127
- FORUM_PUBLISH_AUDIT_RESULT = "FORUM_PUBLISH_AUDIT_RESULT",
128
- /** 音频开始播放时 */
129
- AUDIO_START = "AUDIO_START",
130
- /** 音频播放结束时 */
131
- AUDIO_FINISH = "AUDIO_FINISH",
132
- /** 上麦时 */
133
- AUDIO_ON_MIC = "AUDIO_ON_MIC",
134
- /** 下麦时 */
135
- AUDIO_OFF_MIC = "AUDIO_OFF_MIC",
136
- /** 当收到@机器人的消息时 */
137
- AT_MESSAGE_CREATE = "AT_MESSAGE_CREATE",
138
- /** 当频道的消息被删除时 */
139
- PUBLIC_MESSAGE_DELETE = "PUBLIC_MESSAGE_DELETE"
140
- }
141
- /**
142
- * 子事件基类
143
- */
144
- export interface Event {
145
- /** opcode */
146
- op: Opcode.Dispatch;
147
- /** 序列号 */
148
- s: number;
149
- /** 事件类型 */
150
- t: EventType;
151
- }
152
- /**
153
- * READY子事件
154
- */
155
- export interface ReadyEvent extends Event {
156
- /** 事件类型 */
157
- t: EventType.READY;
158
- /** 事件内容 */
159
- d: {
160
- version: number;
161
- session_id: string;
162
- user: {
163
- /** 机器人的user_id */
164
- id: string;
165
- /** 机器人的nickname */
166
- username: string;
167
- bot: boolean;
168
- status: number;
169
- };
170
- shard: Number[];
171
- };
172
- }
173
- /**
174
- * C2C_MESSAGE_CREATE子事件
175
- */
176
- export interface C2CMessageCreateEvent extends Event {
177
- /** 事件类型 */
178
- t: EventType.C2C_MESSAGE_CREATE;
179
- /** 平台方消息ID 格式: C2C_MESSAGE_CREATE:abc... */
180
- id: string;
181
- d: {
182
- /** 富媒体消息 */
183
- attachments?: Array<Attachment>;
184
- /** 发送者信息 */
185
- author: {
186
- /** 发送者的id 目前版本和user_openid一致 */
187
- id: string;
188
- /** 发送者的user_openid */
189
- user_openid: string;
190
- };
191
- /** 消息内容 */
192
- content: string;
193
- /** 消息ID message_id */
194
- id: string;
195
- /** 消息发送时间 */
196
- timestamp: string;
197
- };
198
- }
199
- /**
200
- * GROUP_AT_MESSAGE_CREATE子事件
201
- */
202
- export interface GroupAtMessageCreateEvent extends Event {
203
- /** 事件类型 */
204
- t: EventType.GROUP_AT_MESSAGE_CREATE;
205
- /** 平台方消息ID 格式: GROUP_AT_MESSAGE_CREATE:abc... */
206
- id: string;
207
- d: {
208
- /** 富媒体消息 */
209
- attachments?: Array<Attachment>;
210
- /** 发送者信息 */
211
- author: {
212
- /** 发送者的id 目前版本和user_openid一致 */
213
- id: string;
214
- /** 发送者的user_openid */
215
- member_openid: string;
216
- };
217
- /** 消息内容 */
218
- content: string;
219
- /** 群ID group_id 目前版本和group_openid一致 */
220
- group_id: string;
221
- /** 消息ID group_openid */
222
- group_openid: string;
223
- /** 消息ID message_id */
224
- id: string;
225
- /** 消息发送时间 */
226
- timestamp: string;
227
- };
228
- }
229
- /**
230
- * 所有子事件
231
- */
232
- export type SubEvent = ReadyEvent | C2CMessageCreateEvent | GroupAtMessageCreateEvent;
@@ -1 +0,0 @@
1
- export {};
@@ -1,3 +0,0 @@
1
- export * from './message.js';
2
- export * from './media.js';
3
- export * from './event.js';
@@ -1,3 +0,0 @@
1
- export * from './message.js';
2
- export * from './media.js';
3
- export * from './event.js';
@@ -1,100 +0,0 @@
1
- /**
2
- * 需要注意 目前只有私聊可以收到file类型的消息
3
- */
4
- export type Content_type = 'image/gif' | 'image/jpeg' | 'image/png' | 'file';
5
- /**
6
- * 富媒体文件类型
7
- */
8
- export declare const enum FileType {
9
- /**
10
- * 图片
11
- */
12
- Image = 1,
13
- /**
14
- * 视频
15
- */
16
- Video = 2,
17
- /**
18
- * 语音
19
- */
20
- Record = 3,
21
- /**
22
- * 文件
23
- */
24
- File = 4
25
- }
26
- /**
27
- * 富媒体基类
28
- */
29
- export interface Attachment {
30
- /**
31
- * 类型
32
- */
33
- content_type: Content_type;
34
- /** 未知作用 */
35
- content?: string;
36
- /**
37
- * 文件名
38
- */
39
- filename: string;
40
- /**
41
- * 图片高度
42
- */
43
- height?: number;
44
- /**
45
- * 图片宽度
46
- */
47
- width?: number;
48
- /**
49
- * 文件大小
50
- */
51
- size: number;
52
- /**
53
- * 文件url
54
- */
55
- url: string;
56
- }
57
- /**
58
- * 富媒体消息结构
59
- */
60
- export interface MediaType {
61
- /** 文件信息 */
62
- file_info: string;
63
- }
64
- /**
65
- * 上传富媒体文件请求参数
66
- */
67
- export interface UploadMediaOptions {
68
- /**
69
- * 媒体的文件类型
70
- * - 1. 图片 png/jpg
71
- * - 2. 视频 mp4
72
- * - 3. 语音 silk
73
- * - 4. 文件
74
- */
75
- file_type: FileType;
76
- /**
77
- * 媒体资源的URL
78
- */
79
- url?: string;
80
- /** 不带前缀的base64 */
81
- file_data?: string;
82
- /**
83
- * 是否直接发送消息到目标端
84
- * 如果设置为 true,将会消耗主动消息频次
85
- */
86
- srv_send_msg: boolean;
87
- }
88
- /**
89
- * 上传富媒体文件返回数据
90
- */
91
- export interface UploadMediaResponse {
92
- /** 文件 ID */
93
- file_uuid: string;
94
- /** 文件信息,用于发消息接口的 media 字段使用 */
95
- file_info: string;
96
- /** 有效期,表示剩余多少秒到期,到期后 file_info 失效,当等于 0 时,表示可长期使用 */
97
- ttl: number;
98
- /** 发送消息的唯一ID,当srv_send_msg设置为true时返回 */
99
- id?: string;
100
- }
@@ -1 +0,0 @@
1
- export {};