agent-bridge-aun 1.0.28 → 1.0.30

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/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  该插件依赖 `@agentunion/fastaun`,要求 Node.js 22.16 或更高版本。
12
12
 
13
- 附件回复按图片、视频和普通文件分组发送。MIME 类型为 `video/*` 的附件使用 EvolCore 标准 `type: "video"` 消息,使支持视频预览的 Peer 客户端显示播放器;保留原话题和请求引用。附件仍使用仅原 Peer 可访问的限时分享,不改变各 Agent 插件的产物回传策略。
13
+ 附件回复按图片、视频和普通文件分组发送。MIME 类型为 `video/*` 的附件使用 EvolCore 标准 `type: "video"` 消息,使支持视频预览的 Peer 客户端显示播放器;保留原话题和请求引用。视频沿用 EvolCore 标准上传流程:通过 SDK 上传可公开读取的对象,发送不带分享 URL 的标准对象引用,便于接收端取得下载票据及播放器分段读取;持有对象地址者可读取视频。图片和普通文件继续使用仅原 Peer 可访问的限时分享。该流程由插件独立实现,不调用 `ec` 命令,也不改变各 Agent 插件的产物回传策略。
14
14
 
15
15
  ABWeb 的 AUN 设置只展示已连接 AID,并按来源分组。成功注册并记录在插件 `created_aids` 中的 AID 属于本工程;共享密钥库中其余 AID 属于 EvolCore。旧版 `created-aids.json` 记录继续兼容。来源只用于展示,连接和关联由 AUN 插件直接管理。列表先显示已关联 Agent 的身份,各组按最近成功关联的时间倒序排列,时间相同或旧记录没有时间时按 AID 名称排序。关联时间保存在插件配置的 `binding_times` 中,刷新或重启后保留;旧记录不补造时间,再次关联成功后开始记录。
16
16
 
@@ -6,6 +6,7 @@ exports.downloadAunAttachments = downloadAunAttachments;
6
6
  exports.downloadAunAttachment = downloadAunAttachment;
7
7
  exports.uploadAunAttachments = uploadAunAttachments;
8
8
  const node_crypto_1 = require("node:crypto");
9
+ const node_util_1 = require("node:util");
9
10
  const attachments_1 = require("../../attachments");
10
11
  const aidPattern = /^[a-z0-9][a-z0-9_-]{2,63}\.[a-z0-9-]+(?:\.[a-z0-9-]+)+$/;
11
12
  const mimePattern = /^[A-Za-z0-9!#$&^_.+-]+\/[A-Za-z0-9!#$&^_.+-]+$/;
@@ -13,6 +14,21 @@ const imageTypes = new Set(["image/png", "image/jpeg", "image/webp"]);
13
14
  function digest(data) { return (0, node_crypto_1.createHash)("sha256").update(data).digest("hex"); }
14
15
  function validKey(key) { return /^[A-Za-z0-9._-]+(?:\/[A-Za-z0-9._-]+)*$/.test(key) && !key.split("/").some((part) => part === "." || part === ".."); }
15
16
  function validHash(value) { return /^[a-f0-9]{64}$/i.test(value); }
17
+ function normalizedMime(value) {
18
+ if (value === undefined)
19
+ return;
20
+ if (typeof value !== "string" || /[\u0000-\u001f\u007f]/.test(value))
21
+ throw new Error("AUN 附件 MIME 类型无效");
22
+ if (!value.trim())
23
+ return;
24
+ try {
25
+ const type = new node_util_1.MIMEType(value).essence;
26
+ if (mimePattern.test(type))
27
+ return type;
28
+ }
29
+ catch { /* 统一报告无效类型。 */ }
30
+ throw new Error("AUN 附件 MIME 类型无效");
31
+ }
16
32
  function validateReference(ref) {
17
33
  if (!aidPattern.test(ref.ownerAid) || !/^[A-Za-z0-9_-][A-Za-z0-9._-]{0,63}$/.test(ref.bucket) || !validKey(ref.objectKey))
18
34
  throw new Error("AUN 附件引用路径无效");
@@ -44,11 +60,9 @@ function parseAunAttachment(value) {
44
60
  const bucket = item.bucket === undefined ? "default" : typeof item.bucket === "string" ? item.bucket : "";
45
61
  const filename = (0, attachments_1.attachmentFilename)(typeof item.filename === "string" ? item.filename : objectKey);
46
62
  const ref = { ownerAid, bucket, objectKey, filename };
47
- if (item.content_type !== undefined) {
48
- if (typeof item.content_type !== "string")
49
- throw new Error("AUN 附件 MIME 类型无效");
50
- ref.contentType = item.content_type.toLowerCase();
51
- }
63
+ const contentType = normalizedMime(item.content_type);
64
+ if (contentType)
65
+ ref.contentType = contentType;
52
66
  if (item.size_bytes !== undefined) {
53
67
  if (typeof item.size_bytes !== "number")
54
68
  throw new Error("AUN 附件大小无效");
@@ -82,10 +96,8 @@ function checkedMetadata(meta, ref) {
82
96
  if ([meta.owner, meta.owner_aid].some((owner) => owner && owner !== ref.ownerAid) || meta.bucket && meta.bucket !== ref.bucket
83
97
  || [meta.path, meta.object_key].some((path) => path && path !== `/${ref.objectKey}` && path !== ref.objectKey))
84
98
  throw new Error("AUN 附件元数据引用不一致");
85
- const rawType = metadataValue(meta, "contentType", "content_type");
86
- if (rawType && (typeof rawType !== "string" || !mimePattern.test(rawType)))
87
- throw new Error("AUN 附件元数据 MIME 类型无效");
88
- const contentType = typeof rawType === "string" && rawType ? rawType.toLowerCase() : ref.contentType ?? "application/octet-stream";
99
+ const rawType = normalizedMime(metadataValue(meta, "contentType", "content_type"));
100
+ const contentType = rawType ?? ref.contentType ?? "application/octet-stream";
89
101
  if (ref.contentType && rawType && ref.contentType.toLowerCase() !== contentType)
90
102
  throw new Error("AUN 附件 MIME 类型校验失败");
91
103
  const sha256 = typeof meta.sha256 === "string" && meta.sha256 ? meta.sha256.toLowerCase() : undefined;
@@ -236,9 +248,16 @@ async function uploadAunAttachments(client, ownerAid, peerAid, items) {
236
248
  const filename = (0, attachments_1.attachmentFilename)(item.filename);
237
249
  const objectKey = `shared/${(0, node_crypto_1.randomUUID)()}/${filename.replace(/[^A-Za-z0-9._-]/g, "_")}`;
238
250
  const sha256 = digest(item.data);
239
- const ref = { ownerAid, bucket: "default", objectKey, filename, contentType: item.contentType.toLowerCase(), sizeBytes: item.data.byteLength, sha256 };
240
- const uploaded = await client.storage.writeBytes(`/${objectKey}`, item.data, { contentType: item.contentType, public: false, overwrite: false });
251
+ const contentType = item.contentType.toLowerCase();
252
+ // 视频播放器不携带 AID 凭据,沿用 EvolCore 的标准可读对象上传方式。
253
+ const video = contentType.startsWith("video/");
254
+ const ref = { ownerAid, bucket: "default", objectKey, filename, contentType, sizeBytes: item.data.byteLength, sha256 };
255
+ const uploaded = await client.storage.writeBytes(`/${objectKey}`, item.data, { contentType, public: video, overwrite: video });
241
256
  checkedMetadata({ ...uploaded, size: uploaded.size ?? uploaded.size_bytes ?? item.data.byteLength }, ref);
257
+ if (video) {
258
+ result.push({ owner_aid: ownerAid, object_key: objectKey, filename, content_type: contentType, size_bytes: item.data.byteLength, sha256 });
259
+ continue;
260
+ }
242
261
  const share = await client.storage.lowlevel.createShareLink({ owner: ownerAid, bucket: "default", objectKey, allowedAids: [peerAid], expireInSeconds: 86400 });
243
262
  if (share.owner_aid && share.owner_aid !== ownerAid || share.bucket && share.bucket !== "default" || share.object_key && share.object_key !== objectKey)
244
263
  throw new Error("AUN 附件分享对象不一致");
@@ -11,7 +11,7 @@ const node_url_1 = require("node:url");
11
11
  const messages_1 = require("./messages");
12
12
  const attachments_1 = require("./attachments");
13
13
  const manifest = {
14
- id: "aun", version: "1.0.28", type: "channel", displayName: "AUN 通道",
14
+ id: "aun", version: "1.0.30", type: "channel", displayName: "AUN 通道",
15
15
  entry: "dist/src-ts/plugins/aun/index.js", apiVersion: "1", process: "in-process",
16
16
  capabilities: ["channel", "channel.identity.create", "channel.receive", "channel.send", "health", "cli"],
17
17
  configSchema: "config.schema.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-bridge-aun",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "mu-agent-bridge 的 AUN 通道插件。",
5
5
  "keywords": [
6
6
  "mu-agent-bridge-plugin",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "aun",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "type": "channel",
5
5
  "displayName": "AUN 通道",
6
6
  "entry": "dist/src-ts/plugins/aun/index.js",