@napuketto/adapter 0.0.4 → 0.0.6
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/dist/core/index.d.mts +1 -1
- package/dist/core/index.mjs +1 -1
- package/dist/{core-Bj5L8WeZ.mjs → core-DE2jZQR7.mjs} +3 -3
- package/dist/core-DE2jZQR7.mjs.map +1 -0
- package/dist/{index-CmhGncOe.d.mts → index-Cr-XE2SG.d.mts} +3 -3
- package/dist/index-Cr-XE2SG.d.mts.map +1 -0
- package/dist/onebot11/index.d.mts +1 -1
- package/dist/onebot11/index.d.mts.map +1 -1
- package/dist/onebot11/index.mjs +22 -19
- package/dist/onebot11/index.mjs.map +1 -1
- package/dist/{raw-message-Du7tvR1D.mjs → raw-message-DfHdOVHi.mjs} +7 -7
- package/dist/raw-message-DfHdOVHi.mjs.map +1 -0
- package/dist/satori/index.d.mts +1 -1
- package/dist/satori/index.d.mts.map +1 -1
- package/dist/satori/index.mjs +40 -16
- package/dist/satori/index.mjs.map +1 -1
- package/package.json +4 -4
- package/dist/core-Bj5L8WeZ.mjs.map +0 -1
- package/dist/index-CmhGncOe.d.mts.map +0 -1
- package/dist/raw-message-Du7tvR1D.mjs.map +0 -1
|
@@ -26,20 +26,20 @@ function createWsServerSchema(defaultPort) {
|
|
|
26
26
|
}
|
|
27
27
|
//#endregion
|
|
28
28
|
//#region src/core/gray-tip.ts
|
|
29
|
+
/** 非空 uid 才加入集合。 */
|
|
30
|
+
function collectUids(uids, ...candidates) {
|
|
31
|
+
for (const uid of candidates) if (uid !== void 0 && uid !== "") uids.add(uid);
|
|
32
|
+
}
|
|
29
33
|
/** 收集 grayTip 涉及的 uid(批量 uidToUin 用)。 */
|
|
30
34
|
function collectGrayTipUids(msg) {
|
|
31
35
|
const uids = /* @__PURE__ */ new Set();
|
|
32
36
|
for (const el of msg.elements) {
|
|
33
37
|
const g = el.grayTipElement;
|
|
34
38
|
if (g === void 0) continue;
|
|
35
|
-
|
|
36
|
-
if (revoke?.operatorUid !== void 0 && revoke.operatorUid !== "") uids.add(revoke.operatorUid);
|
|
39
|
+
collectUids(uids, g.revokeElement?.operatorUid);
|
|
37
40
|
const grp = g.groupElement;
|
|
38
41
|
if (grp === void 0) continue;
|
|
39
|
-
|
|
40
|
-
if (grp.adminUid !== void 0 && grp.adminUid !== "") uids.add(grp.adminUid);
|
|
41
|
-
if (grp.shutUp?.admin?.uid !== void 0 && grp.shutUp.admin.uid !== "") uids.add(grp.shutUp.admin.uid);
|
|
42
|
-
if (grp.shutUp?.member?.uid !== void 0 && grp.shutUp.member.uid !== "") uids.add(grp.shutUp.member.uid);
|
|
42
|
+
collectUids(uids, grp.memberUid, grp.adminUid, grp.shutUp?.admin?.uid, grp.shutUp?.member?.uid);
|
|
43
43
|
}
|
|
44
44
|
return [...uids];
|
|
45
45
|
}
|
|
@@ -56,4 +56,4 @@ function forEachRawMessage(msgs, handler) {
|
|
|
56
56
|
//#endregion
|
|
57
57
|
export { createWsServerSchema as i, collectGrayTipUids as n, createHttpServerSchema as r, forEachRawMessage as t };
|
|
58
58
|
|
|
59
|
-
//# sourceMappingURL=raw-message-
|
|
59
|
+
//# sourceMappingURL=raw-message-DfHdOVHi.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-message-DfHdOVHi.mjs","names":[],"sources":["../src/core/transport-schema.ts","../src/core/gray-tip.ts","../src/core/raw-message.ts"],"sourcesContent":["/**\n * 协议传输实例 schema(OB11 / Satori 共用,2026-08-08 克隆合并)\n *\n * HTTP 反向服务器 / WS 事件服务器的实例级 schema 结构两协议一致,\n * 仅默认端口与扩展字段不同——提取工厂函数,各协议按需调用。\n */\nimport { z } from \"zod\";\n\n/** 传输实例基础 schema(enabled/host/port/token 骨架,HTTP 与 WS 共用)。 */\nfunction createServerSchema(defaultPort: number) {\n return z.object({\n enabled: z.boolean().default(false),\n host: z.string().default(\"127.0.0.1\"),\n port: z.number().int().default(defaultPort),\n /** 实例级 token,覆盖全局 token(缺省继承全局)。 */\n token: z.string().optional(),\n });\n}\n\n/** HTTP 反向服务器实例 schema(第三方指令入口 / HTTP RPC,OB11 / Satori 共用)。 */\nexport function createHttpServerSchema(defaultPort: number) {\n return createServerSchema(defaultPort);\n}\n\n/** WS 事件服务器实例 schema(反向 WS server,OB11 / Satori 共用)。 */\nexport function createWsServerSchema(defaultPort: number) {\n return createServerSchema(defaultPort);\n}\n","/**\n * grayTip 元素工具(OB11 / Satori 共用,2026-08-08 克隆合并)\n *\n * grayTip(系统提示消息)涉及的操作者/成员 uid 需要批量 uid→uin 转换,\n * 两协议翻译层共用同一套收集逻辑。\n */\nimport type { RawMessage } from \"@napuketto/kernel\";\n\n/** 非空 uid 才加入集合。 */\nfunction collectUids(uids: Set<string>, ...candidates: Array<string | undefined>): void {\n for (const uid of candidates) {\n if (uid !== undefined && uid !== \"\") {\n uids.add(uid);\n }\n }\n}\n\n/** 收集 grayTip 涉及的 uid(批量 uidToUin 用)。 */\nexport function collectGrayTipUids(msg: RawMessage): string[] {\n const uids = new Set<string>();\n for (const el of msg.elements) {\n const g = el.grayTipElement;\n if (g === undefined) {\n continue;\n }\n collectUids(uids, g.revokeElement?.operatorUid);\n const grp = g.groupElement;\n if (grp === undefined) {\n continue;\n }\n collectUids(\n uids,\n grp.memberUid,\n grp.adminUid,\n grp.shutUp?.admin?.uid,\n grp.shutUp?.member?.uid,\n );\n }\n return [...uids];\n}\n","/**\n * RawMessage 数组规范化(OB11 / Satori 共用,2026-08-08 克隆合并)\n *\n * onRecvMsg 回调参数运行时实证为消息数组(2026-08-07),但兼容单条对象\n * 传入——统一规范化为数组并过滤无效项后逐条回调。\n */\nimport type { RawMessage } from \"@napuketto/kernel\";\n\n/** 逐条处理消息(自动规范化数组 + 过滤非对象项)。 */\nexport function forEachRawMessage(msgs: unknown, handler: (msg: RawMessage) => void): void {\n const list = Array.isArray(msgs) ? msgs : [msgs];\n for (const msg of list) {\n if (!msg || typeof msg !== \"object\") {\n continue;\n }\n handler(msg as RawMessage);\n }\n}\n"],"mappings":";;;;;;;;;AASA,SAAS,mBAAmB,aAAqB;CAC7C,OAAO,EAAE,OAAO;EACZ,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,KAAK;EAClC,MAAM,EAAE,OAAO,CAAC,CAAC,QAAQ,WAAW;EACpC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,WAAW;;EAE1C,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS;CAC/B,CAAC;AACL;;AAGA,SAAgB,uBAAuB,aAAqB;CACxD,OAAO,mBAAmB,WAAW;AACzC;;AAGA,SAAgB,qBAAqB,aAAqB;CACtD,OAAO,mBAAmB,WAAW;AACzC;;;;AClBA,SAAS,YAAY,MAAmB,GAAG,YAA6C;CACpF,KAAK,MAAM,OAAO,YACd,IAAI,QAAQ,KAAA,KAAa,QAAQ,IAC7B,KAAK,IAAI,GAAG;AAGxB;;AAGA,SAAgB,mBAAmB,KAA2B;CAC1D,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,MAAM,IAAI,UAAU;EAC3B,MAAM,IAAI,GAAG;EACb,IAAI,MAAM,KAAA,GACN;EAEJ,YAAY,MAAM,EAAE,eAAe,WAAW;EAC9C,MAAM,MAAM,EAAE;EACd,IAAI,QAAQ,KAAA,GACR;EAEJ,YACI,MACA,IAAI,WACJ,IAAI,UACJ,IAAI,QAAQ,OAAO,KACnB,IAAI,QAAQ,QAAQ,GACxB;CACJ;CACA,OAAO,CAAC,GAAG,IAAI;AACnB;;;;AC9BA,SAAgB,kBAAkB,MAAe,SAA0C;CACvF,MAAM,OAAO,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;CAC/C,KAAK,MAAM,OAAO,MAAM;EACpB,IAAI,CAAC,OAAO,OAAO,QAAQ,UACvB;EAEJ,QAAQ,GAAiB;CAC7B;AACJ"}
|
package/dist/satori/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as ActionRegistry, r as ProtocolConfig, t as BaseProtocolAdapter } from "../index-
|
|
1
|
+
import { o as ActionRegistry, r as ProtocolConfig, t as BaseProtocolAdapter } from "../index-Cr-XE2SG.mjs";
|
|
2
2
|
import "../gray-tip-CcpfI1Og.mjs";
|
|
3
3
|
import { CanonicalElement, FriendApi, GroupApi, GroupCache, GroupNotifyApi, KernelErrorCode, MsgApi, MsgEventChannel, Peer, ProfileApi } from "@napuketto/kernel";
|
|
4
4
|
import { ZodType, z } from "zod";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/satori/action/base-action.ts","../../src/satori/helper/element/element.ts","../../src/satori/helper/element/canonical.ts","../../src/satori/helper/element/deps.ts","../../src/satori/helper/element/element-convert.ts","../../src/satori/api/satori-api.ts","../../src/satori/action/registry.ts","../../src/satori/action/index.ts","../../src/satori/helper/config.ts","../../src/satori/helper/error.ts","../../src/satori/types/resource.ts","../../src/satori/helper/translate.ts","../../src/satori/adapter.ts","../../src/satori/event/translate.ts","../../src/satori/types/api.ts","../../src/satori/types/event.ts","../../src/satori/transport.ts"],"mappings":";;;;;;;cAYa,0BAA0B;WAC1B;EAET,YAAY,gBAAgB;;;;;;uBAeV,iBAAiB,UAAU;;oBAE3B;;oBAEA,QAAQ,QAAQ;;EAG5B,IAAI,mBAAmB,QAAQ;;qBAyBlB,QAAQ,SAAS,WAAW,QAAQ;;;;;UC3C1C;EACb;EACA,QAAQ;EACR,WAAW;EACX;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/satori/action/base-action.ts","../../src/satori/helper/element/element.ts","../../src/satori/helper/element/canonical.ts","../../src/satori/helper/element/deps.ts","../../src/satori/helper/element/element-convert.ts","../../src/satori/api/satori-api.ts","../../src/satori/action/registry.ts","../../src/satori/action/index.ts","../../src/satori/helper/config.ts","../../src/satori/helper/error.ts","../../src/satori/types/resource.ts","../../src/satori/helper/translate.ts","../../src/satori/adapter.ts","../../src/satori/event/translate.ts","../../src/satori/types/api.ts","../../src/satori/types/event.ts","../../src/satori/transport.ts"],"mappings":";;;;;;;cAYa,0BAA0B;WAC1B;EAET,YAAY,gBAAgB;;;;;;uBAeV,iBAAiB,UAAU;;oBAE3B;;oBAEA,QAAQ,QAAQ;;EAG5B,IAAI,mBAAmB,QAAQ;;qBAyBlB,QAAQ,SAAS,WAAW,QAAQ;;;;;UC3C1C;EACb;EACA,QAAQ;EACR,WAAW;EACX;;;;;;iBAsJY,cAAc,iBAAiB;;iBA4C/B,eAAe,UAAU;;;;UC/MxB;;EAEb,YAAY,mBAAmB,QAAQ;;;;;;iBAgGrB,0BAClB,UAAU,oBACV,OAAM,wBACP,QAAQ;;;;;;;;;;;UCtGM;;EAEb,WAAW,mBAAmB,QAAQ;;EAEtC;;;;;iBCOkB,0BAClB,UAAU,iBACV,MAAM,wBACP,QAAQ;;iBA2HW,wBAClB,iBACA,MAAM,wBACP,QAAQ;;;;UChIM;EACb,QAAQ;EACR,UAAU;EACV,gBAAgB;EAChB,WAAW;EACX,YAAY;;EAEZ;IAAQ;IAAa;;;EAErB;;EAEA,aAAa;;;cAIJ;WACA,QAAQ;WACR,UAAU;WACV,gBAAgB;WAChB,WAAW;WACX,YAAY;WACZ;IAAQ;IAAa;;WACrB;WACA;WACA,YAAY;;;;;mBAMJ;EAEjB,YAAY,MAAM;;EAalB,eAAe,mBAAmB;;;;;;EAS5B,YAAY,oBAAoB,QAAQ;;UAoBhC;;EAOd,SAAS,iBAAiB,QAAQ;;EAKlC,SAAS,iBAAiB,QAAQ;;EAKlC,mBAAmB;;;;;KCxGX,uBAAuB,eAAe;;;;UCkCjC;EACb,KAAK;;;iBAsBO,2BAA2B,MAAM,mBAAmB;;;;cC9CvD,oBAAkB,EAAA;;;;;;;;;;;;;;;GAS7B,EAAA,KAAA;;KAGU,eAAe,EAAE,aAAa;;;;cCvB7B,qBAAqB,OAAO;;cAY5B;WACT;WACA;WACA;WACA;WACA;WACA;WACA;;;;;;;;;;;cCnBS;WACT;WACA;WACA;WACA;;KAEQ,sBAAsB,0BAA0B;;cAG/C;WACT;WACA;WACA;WACA;WACA;;KAEQ,sBAAsB,0BAA0B;;UAG3C;EACb;EACA;EACA;EACA;EACA;;;UAIa;EACb;EACA,MAAM;EACN;EACA;;;UAIa;EACb;EACA;EACA;;;UAIa;EACb,OAAO;EACP;EACA;EACA;EACA,QAAQ;;;UAIK;EACb;EACA;;;UAIa;EACb,OAAO;EACP;;;UAIa;EACb;EACA;;;UAIa;;EAEb;;EAEA;;EAEA,OAAO;;EAEP,QAAQ;;EAER;;EAEA;;;UAIa;EACb;EACA;EACA,UAAU;EACV,QAAQ;EACR,SAAS;EACT,OAAO;EACP;EACA;;;;;UC1Fa;;EAEb;;EAEA,YAAY,mBAAmB,QAAQ;;;;;UCe1B,6BAA6B;;EAE1C,QAAQ,eAAe;;EAEvB,aAAa;;EAEb,YAAY;;;cAIH,+BAA+B,oBAAoB;WACnD;WACA,4BAAY;;;;;;;;;;;;;;;2BAAsB;mBAE1B;mBACA;mBACA;UACT;UACA;UACA;EAER,YAAY,MAAM;;UAoBJ;;UAkBN;;UAKA;;UAaM;;UAUN;;UAmBM;;UAWA;;UAaN;;UAaA;;UAMA;;;;;UClKK;EACb;EACA;EACA,UAAU;EACV,QAAQ;EACR,UAAU;EACV,OAAO;EACP,SAAS;EACT,WAAW;;;UAIE,wBAAwB;;;;;;;UCzBxB,KAAK;EAClB,MAAM;EACN;;;UAIa,SAAS;EACtB,MAAM;EACN;EACA;;;cAIS;WACT;WACA;WACA;;KAEQ,oBAAoB,wBAAwB;;cAG3C;WACT;WACA;;KAEQ,gBAAgB,oBAAoB;;;;cCVnC;WACT;WACA;WACA;WACA;WACA;WACA;;KAEQ,iBAAiB,qBAAqB;;UAGjC,OAAO;EACpB,IAAI;EACJ,OAAO;;;UAIM;EACb;EACA;;;UAIa;EACb,QAAQ;EACR;;;UAIa;EACb;;;UAIa;EACb;EACA;EACA,UAAU;;;UAIG;EACb;;;UAIa;;EAEb;;EAEA;;EAEA;;EAEA,OAAO;;EAEP,OAAO;;EAEP,SAAS;;EAET,UAAU;;EAEV,QAAQ;;EAER,SAAS;;EAET,QAAQ;;EAER,SAAS;;EAET,UAAU;;EAEV,WAAW;;EAEX,OAAO;;EAEP,OAAO;;;;;UC5DM;;EAEb,UAAU;;EAEV,aAAa;;;UAIA;;EAEb,QAAQ;;EAER,aAAa;;EAEb,UAAU;;EAEV,aAAa;;;iBAID,yBACZ,MAAM,kCACP;;iBAsJa,cAAc,OAAO;EAAU;EAAY,MAAM"}
|
package/dist/satori/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as ActionRegistry, n as BaseProtocolAdapter } from "../core-
|
|
2
|
-
import { i as createWsServerSchema, n as collectGrayTipUids, r as createHttpServerSchema, t as forEachRawMessage } from "../raw-message-
|
|
1
|
+
import { a as ActionRegistry, n as BaseProtocolAdapter } from "../core-DE2jZQR7.mjs";
|
|
2
|
+
import { i as createWsServerSchema, n as collectGrayTipUids, r as createHttpServerSchema, t as forEachRawMessage } from "../raw-message-DfHdOVHi.mjs";
|
|
3
3
|
import { ChatType, GrayTipSubType, NTGroupRequestOperateTypes, TipGroupElementType, isKernelError, kernelError, toCanonicalElements } from "@napuketto/kernel";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { join } from "node:path";
|
|
@@ -238,8 +238,10 @@ function decodeEntity(body) {
|
|
|
238
238
|
return `&${body};`;
|
|
239
239
|
}
|
|
240
240
|
/** 解码字符串中的全部实体。 */
|
|
241
|
+
const ENTITY_RE = /&([^;]+);/g;
|
|
242
|
+
/** 解码字符串中的全部实体。 */
|
|
241
243
|
function decodeEntities(input) {
|
|
242
|
-
return input.replace(
|
|
244
|
+
return input.replace(ENTITY_RE, (_full, body) => decodeEntity(body));
|
|
243
245
|
}
|
|
244
246
|
/** 元素名:小写字母/数字/连字符,以字母开头(规范)。 */
|
|
245
247
|
const NAME_RE = /^[a-z][a-z0-9-]*/i;
|
|
@@ -256,15 +258,21 @@ function readTagName(source, pos) {
|
|
|
256
258
|
end: pos + m[0].length
|
|
257
259
|
};
|
|
258
260
|
}
|
|
261
|
+
/** 空白字符。 */
|
|
262
|
+
const SPACE_RE = /\s/;
|
|
259
263
|
/** 跳过空白;返回下一个非空白位置。 */
|
|
260
264
|
function skipSpaces(source, start) {
|
|
261
265
|
let i = start;
|
|
262
|
-
while (i < source.length &&
|
|
266
|
+
while (i < source.length && SPACE_RE.test(source.charAt(i))) i += 1;
|
|
263
267
|
return i;
|
|
264
268
|
}
|
|
269
|
+
/** 属性名(字母数字 / 冒号(命名空间)/ 连字符 / 下划线)。 */
|
|
270
|
+
const ATTR_NAME_RE = /^[a-zA-Z0-9:_-]+/;
|
|
271
|
+
/** 无引号属性值的结束字符(空白 / >)。 */
|
|
272
|
+
const ATTR_VALUE_END_RE = /[\s>]/;
|
|
265
273
|
/** 读取单个属性(名 / = / 值 / 无值属性),更新 attrs,返回下一个位置。 */
|
|
266
274
|
function readAttr(source, start, attrs) {
|
|
267
|
-
const keyMatch =
|
|
275
|
+
const keyMatch = ATTR_NAME_RE.exec(source.slice(start));
|
|
268
276
|
if (keyMatch === null) return start + 1;
|
|
269
277
|
const key = keyMatch[0];
|
|
270
278
|
let i = skipSpaces(source, start + key.length);
|
|
@@ -282,7 +290,7 @@ function readAttr(source, start, attrs) {
|
|
|
282
290
|
if (i < source.length) i += 1;
|
|
283
291
|
} else {
|
|
284
292
|
const valueStart = i;
|
|
285
|
-
while (i < source.length &&
|
|
293
|
+
while (i < source.length && !ATTR_VALUE_END_RE.test(source.charAt(i))) i += 1;
|
|
286
294
|
attrs[key] = decodeEntities(source.slice(valueStart, i));
|
|
287
295
|
}
|
|
288
296
|
return i;
|
|
@@ -307,7 +315,7 @@ function readTagAttrs(source, start) {
|
|
|
307
315
|
i += 1;
|
|
308
316
|
continue;
|
|
309
317
|
}
|
|
310
|
-
if (
|
|
318
|
+
if (SPACE_RE.test(ch)) {
|
|
311
319
|
i += 1;
|
|
312
320
|
continue;
|
|
313
321
|
}
|
|
@@ -354,33 +362,43 @@ function readTag(source, pos) {
|
|
|
354
362
|
* - 未配对的标签视为文本内容的一部分
|
|
355
363
|
* - 文本内容前后包含换行符的连续空白会被忽略
|
|
356
364
|
*/
|
|
365
|
+
/** 文本转义正则(& < >)。 */
|
|
366
|
+
const TEXT_ESCAPE_RE = /[&<>]/g;
|
|
357
367
|
/** 文本转义(& < >)。 */
|
|
358
368
|
function encodeText(input) {
|
|
359
|
-
return input.replace(
|
|
369
|
+
return input.replace(TEXT_ESCAPE_RE, (ch) => {
|
|
360
370
|
if (ch === "&") return "&";
|
|
361
371
|
if (ch === "<") return "<";
|
|
362
372
|
return ">";
|
|
363
373
|
});
|
|
364
374
|
}
|
|
375
|
+
/** 属性值转义正则(& " < >)。 */
|
|
376
|
+
const ATTR_ESCAPE_RE = /[&"<>]/g;
|
|
365
377
|
/** 属性值转义(& " < >)。 */
|
|
366
378
|
function encodeAttr(input) {
|
|
367
|
-
return input.replace(
|
|
379
|
+
return input.replace(ATTR_ESCAPE_RE, (ch) => {
|
|
368
380
|
if (ch === "&") return "&";
|
|
369
381
|
if (ch === "\"") return """;
|
|
370
382
|
if (ch === "<") return "<";
|
|
371
383
|
return ">";
|
|
372
384
|
});
|
|
373
385
|
}
|
|
386
|
+
/** 行首连续空白。 */
|
|
387
|
+
const LEADING_WS_RE = /^\s+/;
|
|
388
|
+
/** 行尾连续空白。 */
|
|
389
|
+
const TRAILING_WS_RE = /\s+$/;
|
|
390
|
+
/** 换行符。 */
|
|
391
|
+
const NEWLINE_RE = /[\r\n]/;
|
|
374
392
|
/**
|
|
375
393
|
* 文本规范化:开头/结尾的「包含换行符的连续空白」被忽略(规范),
|
|
376
394
|
* 中间的空白与不含换行的首尾空白保留。
|
|
377
395
|
*/
|
|
378
396
|
function normalizeText(raw) {
|
|
379
|
-
const leading =
|
|
380
|
-
const trailing =
|
|
397
|
+
const leading = LEADING_WS_RE.exec(raw);
|
|
398
|
+
const trailing = TRAILING_WS_RE.exec(raw);
|
|
381
399
|
let out = raw;
|
|
382
|
-
if (leading !== null &&
|
|
383
|
-
if (trailing !== null &&
|
|
400
|
+
if (leading !== null && NEWLINE_RE.test(leading[0])) out = out.slice(leading[0].length);
|
|
401
|
+
if (trailing !== null && NEWLINE_RE.test(trailing[0])) out = out.slice(0, -trailing[0].length);
|
|
384
402
|
return out;
|
|
385
403
|
}
|
|
386
404
|
/** Satori 消息解析器状态(挂载点 / 文本缓冲 / 栈管理,拆分主循环复杂度)。 */
|
|
@@ -532,6 +550,10 @@ function resolveInternalPath(src) {
|
|
|
532
550
|
const tmpIdx = rest.indexOf("_tmp/");
|
|
533
551
|
return tmpIdx === -1 ? rest : rest.slice(tmpIdx + 5);
|
|
534
552
|
}
|
|
553
|
+
/** http(s) URL 前缀。 */
|
|
554
|
+
const HTTP_URL_RE = /^https?:\/\//i;
|
|
555
|
+
/** 文件名不安全字符(URL 尾部段转文件名时替换)。 */
|
|
556
|
+
const UNSAFE_NAME_RE = /[^a-zA-Z0-9._-]/g;
|
|
535
557
|
/**
|
|
536
558
|
* 解析资源 src:
|
|
537
559
|
* - internal:{platform}/{user.id}/{path} → 本地路径(第一版仅支持 _tmp 保留路径)
|
|
@@ -540,7 +562,7 @@ function resolveInternalPath(src) {
|
|
|
540
562
|
*/
|
|
541
563
|
async function resolveAsset(src, cacheDir) {
|
|
542
564
|
if (src.startsWith("internal:")) return resolveInternalPath(src);
|
|
543
|
-
if (
|
|
565
|
+
if (HTTP_URL_RE.test(src)) return downloadAsset(src, cacheDir);
|
|
544
566
|
return src;
|
|
545
567
|
}
|
|
546
568
|
/** 下载 URL 资源到缓存目录(返回本地路径)。 */
|
|
@@ -549,7 +571,7 @@ async function downloadAsset(url, cacheDir) {
|
|
|
549
571
|
const res = await fetch(url);
|
|
550
572
|
if (!res.ok) throw kernelError(`下载资源失败: ${url}`, "SEND_FAILED");
|
|
551
573
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
552
|
-
const safeName = (url.split("/").pop() ?? `asset-${Date.now()}`).replace(
|
|
574
|
+
const safeName = (url.split("/").pop() ?? `asset-${Date.now()}`).replace(UNSAFE_NAME_RE, "_") || `asset-${Date.now()}`;
|
|
553
575
|
const filePath = join(cacheDir, safeName);
|
|
554
576
|
await writeFile(filePath, buf);
|
|
555
577
|
return filePath;
|
|
@@ -1642,6 +1664,8 @@ const WS_EVENTS_PATH = "/v1/events";
|
|
|
1642
1664
|
const V1_PREFIX = "/v1/";
|
|
1643
1665
|
/** Authorization 头前缀。 */
|
|
1644
1666
|
const BEARER_PREFIX = "Bearer ";
|
|
1667
|
+
/** resource.method 路径模式(resource 与 method 均为字母开头的小写标识符,可含连字符/数字)。 */
|
|
1668
|
+
const ACTION_PATH_RE = /^([a-z][a-z0-9-]*)(?:\.[a-z][a-z0-9-]*)+$/i;
|
|
1645
1669
|
/** 按配置装配 Satori 传输。 */
|
|
1646
1670
|
function assembleSatoriTransports(opts) {
|
|
1647
1671
|
const { config, broadcaster, registry, login } = opts;
|
|
@@ -1693,7 +1717,7 @@ function makeBearerAuthorize(token) {
|
|
|
1693
1717
|
function parseActionPath(path) {
|
|
1694
1718
|
if (!path.startsWith(V1_PREFIX)) return null;
|
|
1695
1719
|
const rest = path.slice(4);
|
|
1696
|
-
if (
|
|
1720
|
+
if (ACTION_PATH_RE.exec(rest) === null) return null;
|
|
1697
1721
|
return rest;
|
|
1698
1722
|
}
|
|
1699
1723
|
/** HTTP RPC 分发。 */
|