@karinjs/adapter-qqbot 2.0.0 → 2.2.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,4 +1,5 @@
1
- import { d as sleep, f as log, i as getDefaultConfig, n as config, o as writeConfig } from "./config-H7LrvlNU.js";
1
+ import { i as getDefaultConfig, m as log, n as config, o as writeConfig } from "./config-B_Gc9JKZ.js";
2
+ import { a as sleep } from "./common-by1GpV0b.js";
2
3
  import qrcode from "qrcode";
3
4
  import axios from "node-karin/axios";
4
5
  import crypto from "node:crypto";
@@ -128,7 +129,7 @@ const renderQr = async (url) => {
128
129
  * 3. 解密返回 secret
129
130
  */
130
131
  const qrRegister = async (opts = {}) => {
131
- const { timeoutSeconds = DEFAULT_TIMEOUT_S, onQr } = opts;
132
+ const { timeoutSeconds = DEFAULT_TIMEOUT_S, printTerminal = false, onQr } = opts;
132
133
  const deadline = Date.now() + timeoutSeconds * 1e3;
133
134
  for (let refresh = 0; refresh <= MAX_REFRESHES; refresh++) {
134
135
  let task;
@@ -141,11 +142,13 @@ const qrRegister = async (opts = {}) => {
141
142
  const url = buildConnectUrl(task.taskId);
142
143
  const { ascii, base64 } = await renderQr(url);
143
144
  const qrDeadline = Date.now() + QR_TTL_MS;
144
- if (ascii) {
145
- console.log();
146
- console.log(ascii);
145
+ if (printTerminal) {
146
+ if (ascii) {
147
+ console.log();
148
+ console.log(ascii);
149
+ }
150
+ console.log(` 请使用 QQ 扫码(60s 内有效),或在手机 QQ 打开:\n ${url}\n`);
147
151
  }
148
- console.log(` 请使用 QQ 扫码(60s 内有效),或在手机 QQ 打开:\n ${url}\n`);
149
152
  if (onQr) try {
150
153
  await onQr({
151
154
  url,
@@ -196,7 +199,7 @@ const qrRegister = async (opts = {}) => {
196
199
  }
197
200
  if (expired) {
198
201
  if (refresh >= MAX_REFRESHES) {
199
- log("error", `[扫码登录] 二维码已过期 ${MAX_REFRESHES + 1} 次,终止流程`);
202
+ log("error", `[扫码登录] 二维码已过期 4 次,终止流程`);
200
203
  return null;
201
204
  }
202
205
  log("info", `[扫码登录] 二维码 60s 内未完成扫码,正在刷新 (${refresh + 1}/${MAX_REFRESHES})`);
@@ -0,0 +1,4 @@
1
+ import "./config-B_Gc9JKZ.js";
2
+ import "./common-by1GpV0b.js";
3
+
4
+ export { };
@@ -1,22 +1,24 @@
1
- import * as _$node_karin0 from "node-karin";
2
-
3
1
  //#region src/web.config.d.ts
4
- declare const _default: _$node_karin0.DefineConfig<{
5
- qqbot: Array<{
6
- name: string;
7
- appId: string;
8
- secret: string;
9
- prodApi: string;
10
- sandboxApi: string;
11
- tokenApi: string;
12
- sandbox: boolean;
13
- qqEnable: boolean;
14
- guildEnable: boolean;
15
- guildMode: boolean;
16
- regex: string[];
17
- "keyboard:enable": boolean;
18
- "event:type": string;
19
- }>;
20
- }>;
2
+ type WebQQBotInput = {
3
+ name: unknown;
4
+ appId: unknown;
5
+ secret: unknown;
6
+ 'proxy:api': unknown;
7
+ 'proxy:ws': unknown;
8
+ sandbox: unknown;
9
+ qqEnable: unknown;
10
+ guildEnable: unknown;
11
+ guildMode: unknown;
12
+ regex: unknown;
13
+ 'keyboard:enable': unknown;
14
+ 'markdown:enable': unknown;
15
+ 'messageCache:enable': unknown;
16
+ 'messageCache:self': unknown;
17
+ 'event:type': unknown;
18
+ };
19
+ type WebConfigInput = {
20
+ qqbot: WebQQBotInput[];
21
+ };
22
+ declare const _default: import("node-karin").DefineComponentConfig<WebConfigInput>;
21
23
  //#endregion
22
24
  export { _default as default };
@@ -1,8 +1,92 @@
1
- import { a as pkg, n as config, o as writeConfig } from "./config-H7LrvlNU.js";
2
- import "./utils-DO4gEkVN.js";
1
+ import { a as readConfigFile, f as pkg, i as getDefaultConfig, n as config, o as writeConfig, s as buildFallbackWsUrlFromApi, u as normalizeProxyConfig } from "./config-B_Gc9JKZ.js";
2
+ import "./utils-DIq0lGMt.js";
3
3
  import { components, defineConfig } from "node-karin";
4
4
 
5
5
  //#region src/web.config.ts
6
+ const defaultProxy = () => getDefaultConfig()[0].proxy;
7
+ const unwrapValue = (value) => {
8
+ if (value && typeof value === "object" && "value" in value) return value.value;
9
+ return value;
10
+ };
11
+ const toBool = (value, fallback) => {
12
+ const raw = unwrapValue(value);
13
+ if (typeof raw === "boolean") return raw;
14
+ if (typeof raw === "number") return raw !== 0;
15
+ if (typeof raw === "string") {
16
+ const normalized = raw.trim().toLowerCase();
17
+ if ([
18
+ "false",
19
+ "0",
20
+ "off",
21
+ "no",
22
+ ""
23
+ ].includes(normalized)) return false;
24
+ if ([
25
+ "true",
26
+ "1",
27
+ "on",
28
+ "yes"
29
+ ].includes(normalized)) return true;
30
+ }
31
+ if (raw === null || raw === void 0) return fallback;
32
+ return fallback;
33
+ };
34
+ const toStringValue = (value, fallback = "") => {
35
+ const raw = unwrapValue(value);
36
+ if (typeof raw === "string") return raw;
37
+ if (raw === null || raw === void 0) return fallback;
38
+ return String(raw);
39
+ };
40
+ const toStringList = (value) => {
41
+ const raw = unwrapValue(value);
42
+ if (!Array.isArray(raw)) return [];
43
+ return raw.map((item) => toStringValue(item)).filter(Boolean);
44
+ };
45
+ const proxyKeys = (sandbox) => sandbox ? {
46
+ api: "sandboxApi",
47
+ ws: "sandboxWs"
48
+ } : {
49
+ api: "prodApi",
50
+ ws: "prodWs"
51
+ };
52
+ const getBotProxyInput = (item) => {
53
+ const keys = proxyKeys(!!item.sandbox);
54
+ const proxy = item.proxy || defaultProxy();
55
+ return {
56
+ "proxy:api": proxy[keys.api] || defaultProxy()[keys.api],
57
+ "proxy:ws": proxy[keys.ws] || defaultProxy()[keys.ws]
58
+ };
59
+ };
60
+ const proxyFromInput = (item, previous) => {
61
+ const def = defaultProxy();
62
+ const sandbox = toBool(item.sandbox, previous?.sandbox ?? false);
63
+ const previousSandbox = previous?.sandbox ?? sandbox;
64
+ const keys = proxyKeys(sandbox);
65
+ const previousVisibleKeys = proxyKeys(previousSandbox);
66
+ const previousProxy = previous?.proxy;
67
+ const base = {
68
+ ...def,
69
+ ...previousProxy
70
+ };
71
+ const envChanged = !!previous && previousSandbox !== sandbox;
72
+ const rawApi = toStringValue(item["proxy:api"]).trim();
73
+ const rawWs = toStringValue(item["proxy:ws"]).trim();
74
+ const previousVisibleApi = previousProxy?.[previousVisibleKeys.api] || def[previousVisibleKeys.api];
75
+ const previousVisibleWs = previousProxy?.[previousVisibleKeys.ws] || def[previousVisibleKeys.ws];
76
+ const api = envChanged && rawApi === previousVisibleApi ? base[keys.api] || def[keys.api] : rawApi || base[keys.api] || def[keys.api];
77
+ const previousApi = previousProxy?.[keys.api] || def[keys.api];
78
+ const previousWs = previousProxy?.[keys.ws] || def[keys.ws];
79
+ const wsInput = envChanged && rawWs === previousVisibleWs ? base[keys.ws] || def[keys.ws] : rawWs;
80
+ let ws = wsInput || previousWs || def[keys.ws];
81
+ const previousAutoWs = buildFallbackWsUrlFromApi(previousApi);
82
+ if (!wsInput || wsInput === previousWs && previousWs === previousAutoWs && api !== previousApi) ws = buildFallbackWsUrlFromApi(api);
83
+ return normalizeProxyConfig({
84
+ ...base,
85
+ [keys.api]: api,
86
+ tokenApi: base.tokenApi || def.tokenApi,
87
+ [keys.ws]: ws
88
+ });
89
+ };
6
90
  var web_config_default = defineConfig({
7
91
  info: {
8
92
  id: pkg().name,
@@ -23,108 +107,140 @@ var web_config_default = defineConfig({
23
107
  name: item.name,
24
108
  appId: item.appId,
25
109
  secret: item.secret,
26
- prodApi: item.prodApi,
27
- sandboxApi: item.sandboxApi,
28
- tokenApi: item.tokenApi,
110
+ "event:type": String(item.event?.type ?? 2),
29
111
  sandbox: item.sandbox,
30
112
  qqEnable: item.qqEnable,
31
113
  guildEnable: item.guildEnable,
32
114
  guildMode: item.guildMode === 1,
33
115
  regex: item.regex.map((r) => `${r.reg} ${r.rep}`),
34
116
  "keyboard:enable": item.keyboard?.enable !== false,
35
- "event:type": String(item.event?.type ?? 2)
117
+ "markdown:enable": item.markdown?.enable !== false,
118
+ "messageCache:enable": item.messageCache?.enable === true,
119
+ "messageCache:self": item.messageCache?.self === true,
120
+ ...getBotProxyInput(item)
36
121
  });
37
122
  });
38
- return [components.accordionPro.create("qqbot", data, {
39
- label: "QQBot",
40
- description: "QQBot 配置",
123
+ return [components.divider.horizontal("bot-section", {
124
+ description: "机器人账号",
125
+ descPosition: 5
126
+ }), components.accordionPro.create("qqbot", data, {
127
+ label: "QQ 官方机器人列表",
128
+ description: "每一项对应一个 QQ 官方机器人账号。新增机器人时先填 AppID 和 Secret,再按需调整接收方式、场景能力和发送能力。",
41
129
  children: {
42
130
  key: "qqbotConfig",
43
131
  children: [
132
+ components.radio.group("event:type", {
133
+ label: "事件接收方式",
134
+ description: "QQ 官方机器人只有 Webhook 推送和 WebSocket 主动连接两种接收方式。不确定时选择 WebSocket;如果 QQ 后台已启用 Webhook,可在下方高级设置填写第三方 Webhook 转 WebSocket 服务地址。",
135
+ defaultValue: "2",
136
+ radio: [
137
+ components.radio.create("0", {
138
+ label: "关闭接收",
139
+ value: "0",
140
+ description: "停用这个机器人,不连接 WebSocket,也不接收 Webhook 事件。"
141
+ }),
142
+ components.radio.create("1", {
143
+ label: "Webhook 推送",
144
+ value: "1",
145
+ description: "由 QQ 官方把事件推送到 Karin 的 /qqbot/webhook 路由。通常需要公网地址,并在 QQ 后台配置回调地址。"
146
+ }),
147
+ components.radio.create("2", {
148
+ label: "WebSocket 主动连接",
149
+ value: "2",
150
+ description: "适配器主动连接 WebSocket 地址接收事件。默认连接 QQ 官方网关;如果 QQ 后台已开 Webhook,可改为第三方 Webhook 转 WebSocket 服务地址。"
151
+ })
152
+ ]
153
+ }),
154
+ components.divider.horizontal("bot-basic-section", {
155
+ description: "基础信息",
156
+ descPosition: 5
157
+ }),
44
158
  components.input.create("name", {
45
- label: "机器人名称",
46
- description: "机器人名称,扫码登录会自动获取"
159
+ label: "机器人显示名称",
160
+ description: "只用于 Karin 配置页和日志里识别这个机器人,不影响 QQ 平台资料。扫码登录写入配置时通常会自动填充。"
47
161
  }),
48
162
  components.input.create("appId", {
49
- label: "AppID",
50
- description: "机器人 AppID",
163
+ label: "机器人 AppID",
164
+ description: "QQ 开放平台机器人应用的 AppID,是识别机器人账号的唯一编号。填错会导致鉴权和收发消息失败。",
51
165
  isRequired: true
52
166
  }),
53
167
  components.input.create("secret", {
54
- label: "Secret",
55
- description: "机器人 Secret",
168
+ label: "机器人 Secret",
169
+ description: "QQ 开放平台机器人应用的 Secret,用于获取 access token。请不要泄露;扫码授权会刷新 Secret,旧 Secret 会立即失效。",
56
170
  isRequired: true
57
171
  }),
58
- components.input.create("prodApi", {
59
- label: "正式环境 API",
60
- defaultValue: "https://api.sgroup.qq.com",
61
- isRequired: true
62
- }),
63
- components.input.create("sandboxApi", {
64
- label: "沙盒环境 API",
65
- defaultValue: "https://sandbox.api.sgroup.qq.com",
66
- isRequired: true
67
- }),
68
- components.input.create("tokenApi", {
69
- label: "AccessToken 接口",
70
- defaultValue: "https://bots.qq.com/app/getAppAccessToken",
71
- isRequired: true
172
+ components.divider.horizontal("bot-scene-section", {
173
+ description: "场景能力",
174
+ descPosition: 5
72
175
  }),
73
176
  components.switch.create("sandbox", {
74
- label: "沙盒环境",
75
- description: "启用后调用沙盒 API",
177
+ label: "使用沙盒环境",
178
+ description: "开启后这个机器人会使用沙盒环境的 OpenAPI 和 WebSocket 地址;关闭时使用正式环境地址。正式上线机器人请关闭。",
76
179
  defaultSelected: false
77
180
  }),
78
181
  components.switch.create("qqEnable", {
79
- label: "QQ 场景",
80
- description: "是否处理私聊和群聊消息",
182
+ label: "启用 QQ 私聊 / 群聊",
183
+ description: "开启后会处理 QQ 单聊和群聊里的消息事件;如果这个机器人只用于频道,可以关闭。",
81
184
  defaultSelected: true
82
185
  }),
83
186
  components.switch.create("guildEnable", {
84
- label: "频道场景",
85
- description: "是否处理频道消息",
187
+ label: "启用频道消息",
188
+ description: "开启后会处理 QQ 频道消息事件;如果这个机器人只用于私聊或群聊,可以关闭。",
86
189
  defaultSelected: true
87
190
  }),
88
191
  components.switch.create("guildMode", {
89
- label: "频道私域模式",
90
- description: "开启 = 私域机器人;关闭 = 公域机器人",
192
+ label: "频道私域机器人模式",
193
+ description: "关闭时按公域机器人处理,通常只接收 @ 机器人相关消息;开启时按私域机器人处理,可接收更多频道消息,需确认机器人权限匹配。",
91
194
  defaultSelected: false
92
195
  }),
196
+ components.divider.horizontal("bot-message-section", {
197
+ description: "消息发送",
198
+ descPosition: 5
199
+ }),
93
200
  components.input.group("regex", {
94
201
  data: [],
95
202
  label: "消息正则替换",
96
- description: "每行格式:正则表达式 替换内容。如:^/ #",
203
+ description: "收到文本消息后,先按这里的规则替换内容,再交给 Karin 插件处理。每行格式是“正则表达式 替换内容”,中间用空格分隔;例如“^/ #”会把“/菜单”改成“#菜单”。不懂正则可以保留默认或清空。",
97
204
  template: components.input.create("regex", {
98
- label: "正则规则",
205
+ label: "一条替换规则",
99
206
  placeholder: "^/ #"
100
207
  })
101
208
  }),
102
209
  components.switch.create("keyboard:enable", {
103
- label: "URL 自动按钮",
104
- description: "将文本中的链接自动转为 keyboard 按钮",
210
+ label: "把链接自动转成按钮",
211
+ description: "开启后,发送文本里出现的 http(s) 链接会尽量转成 QQ keyboard 按钮,用户可以直接点按钮打开链接。该能力依赖 Markdown 通道。",
105
212
  defaultSelected: true
106
213
  }),
107
- components.radio.group("event:type", {
108
- label: "事件接收方式",
109
- description: "选择 QQ 官方推送事件的方式",
110
- defaultValue: "2",
111
- radio: [
112
- components.radio.create("0", {
113
- label: "关闭",
114
- value: "0",
115
- description: "不接收任何事件"
116
- }),
117
- components.radio.create("1", {
118
- label: "Webhook",
119
- value: "1",
120
- description: "QQ 官方主动推送事件到本机"
121
- }),
122
- components.radio.create("2", {
123
- label: "WebSocket",
124
- value: "2",
125
- description: "主动连接 QQ 官方 WebSocket 网关接收事件(推荐)"
126
- })
127
- ]
214
+ components.switch.create("markdown:enable", {
215
+ label: "启用 Markdown 发送通道",
216
+ description: "开启后普通文本和图片优先合并为 QQ Markdown 消息,Markdown 里的图片会以内嵌图片形式发送;关闭后普通图片会按官方富媒体单独上传发送。插件显式传入的 segment.markdown 不受此开关影响。",
217
+ defaultSelected: true
218
+ }),
219
+ components.divider.horizontal("bot-cache-section", {
220
+ description: "消息缓存",
221
+ descPosition: 5
222
+ }),
223
+ components.switch.create("messageCache:enable", {
224
+ label: "缓存收到的消息到数据库",
225
+ description: "开启后会把最近一天收到的消息写入本地数据库,供 bot.getMsg 等查询使用;收到的图片、语音、视频等富媒体也会保存到本地。消息量大时会明显占用磁盘空间。",
226
+ defaultSelected: false
227
+ }),
228
+ components.switch.create("messageCache:self", {
229
+ label: "同时缓存机器人自己发出的消息",
230
+ description: "只有开启“缓存收到的消息到数据库”后才生效。开启后,机器人发送成功的消息也会写入缓存,方便之后通过消息 ID 查询。",
231
+ defaultSelected: false
232
+ }),
233
+ components.divider.horizontal("bot-proxy-section", {
234
+ description: "连接代理(高级设置:通常只在使用 Webhook 转 WebSocket 服务时填写,除非你知道你在做什么,否则不建议更改)",
235
+ descPosition: 5
236
+ }),
237
+ components.input.create("proxy:ws", {
238
+ label: "WebSocket 接入地址",
239
+ description: "事件接收方式为 WebSocket 时连接的地址。常见用途是填写第三方 Webhook 转 WebSocket 服务地址,因为 QQ 后台开启 Webhook 后通常无法再直连官方 WebSocket。不填会使用当前环境的官方默认网关。"
240
+ }),
241
+ components.input.create("proxy:api", {
242
+ label: "OpenAPI 反代地址",
243
+ description: "用于发送消息、上传媒体、查询网关和获取机器人资料的 QQ OpenAPI 根地址。多数 Webhook 转 WebSocket 场景不用改这里;只有 OpenAPI 请求也需要走反代时才填写。"
128
244
  })
129
245
  ]
130
246
  }
@@ -135,37 +251,65 @@ var web_config_default = defineConfig({
135
251
  success: false,
136
252
  message: "保存失败:配置格式错误"
137
253
  };
138
- const data = input.qqbot.map((item) => {
139
- const guildMode = item.guildMode === true ? 1 : 0;
140
- const eventType = Number(item["event:type"] ?? 0);
141
- const regex = (item.regex || []).map((str) => {
142
- const parts = str.split(" ");
254
+ const prevConfig = readConfigFile();
255
+ let data;
256
+ try {
257
+ data = input.qqbot.map((item) => {
258
+ const previous = prevConfig.find((cfg) => cfg.appId === toStringValue(item.appId));
259
+ const sandbox = toBool(item.sandbox, previous?.sandbox ?? false);
260
+ const qqEnable = toBool(item.qqEnable, previous?.qqEnable ?? true);
261
+ const guildEnable = toBool(item.guildEnable, previous?.guildEnable ?? true);
262
+ const guildMode = toBool(item.guildMode, previous?.guildMode === 1) ? 1 : 0;
263
+ const eventType = Number(toStringValue(item["event:type"], String(previous?.event?.type ?? 0)));
264
+ const keyboardEnable = toBool(item["keyboard:enable"], previous?.keyboard?.enable ?? true);
265
+ const markdownEnable = toBool(item["markdown:enable"], previous?.markdown?.enable ?? true);
266
+ const messageCacheEnable = toBool(item["messageCache:enable"], previous?.messageCache?.enable ?? false);
267
+ const messageCacheSelf = toBool(item["messageCache:self"], previous?.messageCache?.self ?? false);
268
+ const regex = toStringList(item.regex).map((str) => {
269
+ const parts = str.split(" ");
270
+ return {
271
+ reg: parts[0]?.replace(/^<|>$/g, "") || "",
272
+ rep: parts[1]?.replace(/^<|>$/g, "") || ""
273
+ };
274
+ });
275
+ const proxy = proxyFromInput(item, previous);
143
276
  return {
144
- reg: parts[0]?.replace(/^<|>$/g, "") || "",
145
- rep: parts[1]?.replace(/^<|>$/g, "") || ""
277
+ name: toStringValue(item.name),
278
+ appId: toStringValue(item.appId),
279
+ secret: toStringValue(item.secret),
280
+ proxy,
281
+ sandbox,
282
+ qqEnable,
283
+ guildEnable,
284
+ guildMode,
285
+ regex,
286
+ keyboard: { enable: keyboardEnable },
287
+ markdown: { enable: markdownEnable },
288
+ messageCache: {
289
+ enable: messageCacheEnable,
290
+ self: messageCacheSelf
291
+ },
292
+ event: { type: eventType }
146
293
  };
147
294
  });
295
+ } catch (err) {
148
296
  return {
149
- name: item.name || "",
150
- appId: item.appId || "",
151
- secret: item.secret || "",
152
- prodApi: item.prodApi || "https://api.sgroup.qq.com",
153
- sandboxApi: item.sandboxApi || "https://sandbox.api.sgroup.qq.com",
154
- tokenApi: item.tokenApi || "https://bots.qq.com/app/getAppAccessToken",
155
- sandbox: !!item.sandbox,
156
- qqEnable: !!item.qqEnable,
157
- guildEnable: !!item.guildEnable,
158
- guildMode,
159
- regex,
160
- keyboard: { enable: item["keyboard:enable"] !== false },
161
- event: { type: eventType }
297
+ success: false,
298
+ message: `保存失败:代理地址格式错误:${err?.message || "unknown"}`
162
299
  };
163
- });
164
- writeConfig(data);
165
- return {
166
- success: true,
167
- message: "保存成功"
168
- };
300
+ }
301
+ try {
302
+ writeConfig(data);
303
+ return {
304
+ success: true,
305
+ message: "保存成功"
306
+ };
307
+ } catch (err) {
308
+ return {
309
+ success: false,
310
+ message: `保存失败:${err?.message || "unknown"}`
311
+ };
312
+ }
169
313
  }
170
314
  });
171
315
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@karinjs/adapter-qqbot",
3
- "version": "2.0.0",
3
+ "version": "2.2.1",
4
4
  "description": "karin adapter for QQ Official Bot (2.0)",
5
5
  "homepage": "https://github.com/KarinJS/karin-plugin-adapter-qqbot",
6
6
  "bugs": {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@karinjs/geturls": "^1.0.2",
31
- "form-data": "^4.0.5",
31
+ "form-data": "^4.0.6",
32
32
  "image-size": "^2.0.2",
33
33
  "qrcode": "^1.5.4",
34
34
  "silk-wasm": "^3.7.1",
@@ -36,24 +36,19 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/express": "5.0.6",
39
- "@types/node": "^24.12.4",
39
+ "@types/node": "^24.13.2",
40
40
  "@types/qrcode": "^1.5.6",
41
41
  "eslint": "^9.39.4",
42
42
  "neostandard": "^0.13.0",
43
- "node-karin": "^1.15.5",
44
- "tsdown": "^0.22.0",
45
- "tsx": "^4.22.0",
43
+ "node-karin": "1.16.3",
44
+ "tsdown": "^0.22.3",
45
+ "tsx": "^4.23.0",
46
46
  "typescript": "^6.0.3"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",
50
50
  "registry": "https://registry.npmjs.org"
51
51
  },
52
- "pnpm": {
53
- "overrides": {
54
- "yaml@>=2.0.0 <2.8.3": "^2.8.3"
55
- }
56
- },
57
52
  "karin": {
58
53
  "main": "src/index.ts",
59
54
  "apps": [