ylib-wecom-openclaw-plugin 2026.4.29
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 +596 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +99 -0
- package/dist/src/accounts.d.ts +57 -0
- package/dist/src/accounts.js +247 -0
- package/dist/src/agent/api-client.d.ts +95 -0
- package/dist/src/agent/api-client.js +425 -0
- package/dist/src/agent/handler.d.ts +64 -0
- package/dist/src/agent/handler.js +731 -0
- package/dist/src/agent/index.d.ts +5 -0
- package/dist/src/agent/index.js +21 -0
- package/dist/src/agent/webhook.d.ts +25 -0
- package/dist/src/agent/webhook.js +294 -0
- package/dist/src/agent/xml.d.ts +21 -0
- package/dist/src/agent/xml.js +43 -0
- package/dist/src/channel.d.ts +5 -0
- package/dist/src/channel.js +815 -0
- package/dist/src/chat-queue.d.ts +31 -0
- package/dist/src/chat-queue.js +53 -0
- package/dist/src/config-schema.d.ts +587 -0
- package/dist/src/config-schema.js +146 -0
- package/dist/src/const.d.ts +128 -0
- package/dist/src/const.js +168 -0
- package/dist/src/dm-policy.d.ts +29 -0
- package/dist/src/dm-policy.js +146 -0
- package/dist/src/dynamic-agent.d.ts +37 -0
- package/dist/src/dynamic-agent.js +67 -0
- package/dist/src/dynamic-routing.d.ts +65 -0
- package/dist/src/dynamic-routing.js +62 -0
- package/dist/src/endpoint-dispatch.d.ts +54 -0
- package/dist/src/endpoint-dispatch.js +967 -0
- package/dist/src/endpoint-event-adapter.d.ts +15 -0
- package/dist/src/endpoint-event-adapter.js +427 -0
- package/dist/src/group-policy.d.ts +30 -0
- package/dist/src/group-policy.js +126 -0
- package/dist/src/http.d.ts +27 -0
- package/dist/src/http.js +168 -0
- package/dist/src/im-runtime-telemetry.d.ts +25 -0
- package/dist/src/im-runtime-telemetry.js +68 -0
- package/dist/src/interface.d.ts +192 -0
- package/dist/src/interface.js +5 -0
- package/dist/src/markdown-chunk.d.ts +1 -0
- package/dist/src/markdown-chunk.js +396 -0
- package/dist/src/mcp/index.d.ts +6 -0
- package/dist/src/mcp/index.js +28 -0
- package/dist/src/mcp/interceptors/biz-error.d.ts +11 -0
- package/dist/src/mcp/interceptors/biz-error.js +73 -0
- package/dist/src/mcp/interceptors/doc-auth-error.d.ts +10 -0
- package/dist/src/mcp/interceptors/doc-auth-error.js +235 -0
- package/dist/src/mcp/interceptors/index.d.ts +35 -0
- package/dist/src/mcp/interceptors/index.js +143 -0
- package/dist/src/mcp/interceptors/msg-media.d.ts +11 -0
- package/dist/src/mcp/interceptors/msg-media.js +201 -0
- package/dist/src/mcp/interceptors/smartpage-create.d.ts +30 -0
- package/dist/src/mcp/interceptors/smartpage-create.js +252 -0
- package/dist/src/mcp/interceptors/smartpage-export.d.ts +17 -0
- package/dist/src/mcp/interceptors/smartpage-export.js +135 -0
- package/dist/src/mcp/interceptors/smartsheet-upload.d.ts +22 -0
- package/dist/src/mcp/interceptors/smartsheet-upload.js +388 -0
- package/dist/src/mcp/interceptors/types.d.ts +64 -0
- package/dist/src/mcp/interceptors/types.js +8 -0
- package/dist/src/mcp/schema.d.ts +11 -0
- package/dist/src/mcp/schema.js +115 -0
- package/dist/src/mcp/tool.d.ts +63 -0
- package/dist/src/mcp/tool.js +318 -0
- package/dist/src/mcp/transport.d.ts +94 -0
- package/dist/src/mcp/transport.js +702 -0
- package/dist/src/media-handler.d.ts +55 -0
- package/dist/src/media-handler.js +306 -0
- package/dist/src/media-uploader.d.ts +142 -0
- package/dist/src/media-uploader.js +446 -0
- package/dist/src/message-parser.d.ts +104 -0
- package/dist/src/message-parser.js +232 -0
- package/dist/src/message-sender.d.ts +54 -0
- package/dist/src/message-sender.js +210 -0
- package/dist/src/monitor.d.ts +69 -0
- package/dist/src/monitor.js +1846 -0
- package/dist/src/onboarding.d.ts +8 -0
- package/dist/src/onboarding.js +248 -0
- package/dist/src/openclaw-compat.d.ts +148 -0
- package/dist/src/openclaw-compat.js +839 -0
- package/dist/src/proactive-markdown-send.d.ts +14 -0
- package/dist/src/proactive-markdown-send.js +205 -0
- package/dist/src/reqid-store.d.ts +23 -0
- package/dist/src/reqid-store.js +136 -0
- package/dist/src/runtime.d.ts +2 -0
- package/dist/src/runtime.js +7 -0
- package/dist/src/shared/command-auth.d.ts +23 -0
- package/dist/src/shared/command-auth.js +112 -0
- package/dist/src/shared/xml-parser.d.ts +46 -0
- package/dist/src/shared/xml-parser.js +228 -0
- package/dist/src/state-dir-resolve.d.ts +2 -0
- package/dist/src/state-dir-resolve.js +33 -0
- package/dist/src/state-manager.d.ts +115 -0
- package/dist/src/state-manager.js +413 -0
- package/dist/src/target.d.ts +35 -0
- package/dist/src/target.js +71 -0
- package/dist/src/template-card-manager.d.ts +55 -0
- package/dist/src/template-card-manager.js +316 -0
- package/dist/src/template-card-parser.d.ts +37 -0
- package/dist/src/template-card-parser.js +672 -0
- package/dist/src/timeout.d.ts +20 -0
- package/dist/src/timeout.js +57 -0
- package/dist/src/types/account.d.ts +29 -0
- package/dist/src/types/account.js +5 -0
- package/dist/src/types/config.d.ts +98 -0
- package/dist/src/types/config.js +8 -0
- package/dist/src/types/constants.d.ts +42 -0
- package/dist/src/types/constants.js +45 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.js +17 -0
- package/dist/src/types/message.d.ts +238 -0
- package/dist/src/types/message.js +6 -0
- package/dist/src/utils.d.ts +148 -0
- package/dist/src/utils.js +92 -0
- package/dist/src/version.d.ts +2 -0
- package/dist/src/version.js +28 -0
- package/dist/src/webhook/command-auth.d.ts +47 -0
- package/dist/src/webhook/command-auth.js +137 -0
- package/dist/src/webhook/gateway.d.ts +36 -0
- package/dist/src/webhook/gateway.js +297 -0
- package/dist/src/webhook/handler.d.ts +19 -0
- package/dist/src/webhook/handler.js +481 -0
- package/dist/src/webhook/helpers.d.ts +157 -0
- package/dist/src/webhook/helpers.js +936 -0
- package/dist/src/webhook/http.d.ts +27 -0
- package/dist/src/webhook/http.js +168 -0
- package/dist/src/webhook/index.d.ts +11 -0
- package/dist/src/webhook/index.js +43 -0
- package/dist/src/webhook/media.d.ts +30 -0
- package/dist/src/webhook/media.js +152 -0
- package/dist/src/webhook/monitor.d.ts +59 -0
- package/dist/src/webhook/monitor.js +1672 -0
- package/dist/src/webhook/state.d.ts +220 -0
- package/dist/src/webhook/state.js +568 -0
- package/dist/src/webhook/target.d.ts +41 -0
- package/dist/src/webhook/target.js +165 -0
- package/dist/src/webhook/types.d.ts +348 -0
- package/dist/src/webhook/types.js +36 -0
- package/dist/src/webhook/video-frame.d.ts +13 -0
- package/dist/src/webhook/video-frame.js +108 -0
- package/openclaw.plugin.json +19 -0
- package/package.json +96 -0
- package/schema.json +534 -0
- package/scripts/generate-schema.mjs +33 -0
- package/skills/wecom-contact/SKILL.md +162 -0
- package/skills/wecom-doc/SKILL.md +162 -0
- package/skills/wecom-doc/references/create-doc.md +56 -0
- package/skills/wecom-doc/references/edit-doc-content.md +68 -0
- package/skills/wecom-doc/references/get-doc-content.md +88 -0
- package/skills/wecom-doc/references/smartpage-create.md +125 -0
- package/skills/wecom-doc/references/smartpage-export.md +160 -0
- package/skills/wecom-meeting/SKILL.md +441 -0
- package/skills/wecom-meeting/references/example-full.md +30 -0
- package/skills/wecom-meeting/references/example-reminder.md +46 -0
- package/skills/wecom-meeting/references/example-security.md +22 -0
- package/skills/wecom-meeting/references/response-get-meeting-info.md +148 -0
- package/skills/wecom-msg/SKILL.md +157 -0
- package/skills/wecom-msg/references/api-get-messages.md +93 -0
- package/skills/wecom-msg/references/api-get-msg-chat-list.md +58 -0
- package/skills/wecom-msg/references/api-get-msg-media.md +44 -0
- package/skills/wecom-msg/references/api-send-message.md +39 -0
- package/skills/wecom-preflight/SKILL.md +141 -0
- package/skills/wecom-schedule/SKILL.md +161 -0
- package/skills/wecom-schedule/references/api-check-availability.md +56 -0
- package/skills/wecom-schedule/references/api-create-schedule.md +38 -0
- package/skills/wecom-schedule/references/api-get-schedule-detail.md +81 -0
- package/skills/wecom-schedule/references/api-update-schedule.md +32 -0
- package/skills/wecom-schedule/references/ref-reminders.md +24 -0
- package/skills/wecom-send-media/SKILL.md +68 -0
- package/skills/wecom-send-template-card/SKILL.md +157 -0
- package/skills/wecom-send-template-card/references/api-template-card-types.md +358 -0
- package/skills/wecom-smartsheet/SKILL.md +164 -0
- package/skills/wecom-smartsheet/references/smartsheet-cell-value-formats.md +163 -0
- package/skills/wecom-smartsheet/references/smartsheet-field-types.md +44 -0
- package/skills/wecom-smartsheet/references/smartsheet-get-records.md +96 -0
- package/skills/wecom-smartsheet/references/webhook-examples.md +185 -0
- package/skills/wecom-smartsheet/references/webhook-fallback.md +184 -0
- package/skills/wecom-todo/SKILL.md +392 -0
- package/skills/wecom-todo/examples/workflows.md +163 -0
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* openclaw plugin-sdk 高版本方法兼容层
|
|
4
|
+
*
|
|
5
|
+
* 部分方法(如 loadOutboundMediaFromUrl、detectMime、getDefaultMediaLocalRoots)
|
|
6
|
+
* 仅在较新版本的 openclaw plugin-sdk 中才导出。
|
|
7
|
+
*
|
|
8
|
+
* 本模块在加载时一次性探测 SDK 导出,存在则直接 re-export SDK 版本,
|
|
9
|
+
* 不存在则导出 fallback 实现。其他模块统一从本文件导入,无需关心底层兼容细节。
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
24
|
+
if (mod && mod.__esModule) return mod;
|
|
25
|
+
var result = {};
|
|
26
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
27
|
+
__setModuleDefault(result, mod);
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
31
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
32
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
33
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
34
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
35
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
36
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
40
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
41
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
42
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
43
|
+
function step(op) {
|
|
44
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
45
|
+
while (_) try {
|
|
46
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
47
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
48
|
+
switch (op[0]) {
|
|
49
|
+
case 0: case 1: t = op; break;
|
|
50
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
51
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
52
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
53
|
+
default:
|
|
54
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
55
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
56
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
57
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
58
|
+
if (t[2]) _.ops.pop();
|
|
59
|
+
_.trys.pop(); continue;
|
|
60
|
+
}
|
|
61
|
+
op = body.call(thisArg, _);
|
|
62
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
63
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
|
67
|
+
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
|
68
|
+
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
69
|
+
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
70
|
+
r[k] = a[j];
|
|
71
|
+
return r;
|
|
72
|
+
};
|
|
73
|
+
exports.__esModule = true;
|
|
74
|
+
exports.buildAccountScopedDmSecurityPolicyCompat = exports.formatPairingApproveHint = exports.buildAccountScopedDmSecurityPolicy = exports.parseOptionalDelimitedEntries = exports.emptyPluginConfigSchema = exports.getDefaultMediaLocalRoots = exports.addWildcardAllowFrom = exports.loadOutboundMediaFromUrl = exports.detectMime = exports.DEFAULT_ACCOUNT_ID = exports.resolveStateDir = void 0;
|
|
75
|
+
var fs = __importStar(require("node:fs/promises"));
|
|
76
|
+
var path = __importStar(require("node:path"));
|
|
77
|
+
var os = __importStar(require("node:os"));
|
|
78
|
+
var node_url_1 = require("node:url");
|
|
79
|
+
var state_dir_resolve_js_1 = require("./state-dir-resolve.js");
|
|
80
|
+
exports.resolveStateDir = state_dir_resolve_js_1.resolveStateDir;
|
|
81
|
+
exports.DEFAULT_ACCOUNT_ID = "default";
|
|
82
|
+
var REMOTE_MEDIA_FETCH_TIMEOUT_MS = 20000;
|
|
83
|
+
var REMOTE_MEDIA_FETCH_MAX_ATTEMPTS = 3;
|
|
84
|
+
var REMOTE_MEDIA_FETCH_RETRY_DELAY_MS = 600;
|
|
85
|
+
var _sdkReady = Promise.resolve().then(function () { return __importStar(require("ylib-openclaw/plugin-sdk")); }).then(function (sdk) {
|
|
86
|
+
var exports = {};
|
|
87
|
+
if (typeof sdk.loadOutboundMediaFromUrl === "function") {
|
|
88
|
+
exports.loadOutboundMediaFromUrl = sdk.loadOutboundMediaFromUrl;
|
|
89
|
+
}
|
|
90
|
+
if (typeof sdk.detectMime === "function") {
|
|
91
|
+
exports.detectMime = sdk.detectMime;
|
|
92
|
+
}
|
|
93
|
+
if (typeof sdk.getDefaultMediaLocalRoots === "function") {
|
|
94
|
+
exports.getDefaultMediaLocalRoots = sdk.getDefaultMediaLocalRoots;
|
|
95
|
+
}
|
|
96
|
+
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
97
|
+
exports.addWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
98
|
+
}
|
|
99
|
+
return exports;
|
|
100
|
+
})["catch"](function () {
|
|
101
|
+
// openclaw/plugin-sdk 不可用或版本过低,全部使用 fallback
|
|
102
|
+
return {};
|
|
103
|
+
});
|
|
104
|
+
// 同时尝试从 plugin-sdk/setup 模块探测(缓存同步可用的引用)
|
|
105
|
+
var _cachedAddWildcardAllowFrom;
|
|
106
|
+
var _setupSdkReady = Promise.resolve().then(function () { return __importStar(require("ylib-openclaw/plugin-sdk")); }).then(function (sdk) {
|
|
107
|
+
if (typeof sdk.addWildcardAllowFrom === "function") {
|
|
108
|
+
_cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
109
|
+
}
|
|
110
|
+
})["catch"](function () { });
|
|
111
|
+
// 同时也从 core 模块的结果中缓存
|
|
112
|
+
_sdkReady.then(function (sdk) {
|
|
113
|
+
if (!_cachedAddWildcardAllowFrom && sdk.addWildcardAllowFrom) {
|
|
114
|
+
_cachedAddWildcardAllowFrom = sdk.addWildcardAllowFrom;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// ============================================================================
|
|
118
|
+
// detectMime —— 检测 MIME 类型
|
|
119
|
+
// ============================================================================
|
|
120
|
+
var MIME_BY_EXT = {
|
|
121
|
+
".heic": "image/heic",
|
|
122
|
+
".heif": "image/heif",
|
|
123
|
+
".jpg": "image/jpeg",
|
|
124
|
+
".jpeg": "image/jpeg",
|
|
125
|
+
".png": "image/png",
|
|
126
|
+
".webp": "image/webp",
|
|
127
|
+
".gif": "image/gif",
|
|
128
|
+
".ogg": "audio/ogg",
|
|
129
|
+
".mp3": "audio/mpeg",
|
|
130
|
+
".m4a": "audio/x-m4a",
|
|
131
|
+
".mp4": "video/mp4",
|
|
132
|
+
".mov": "video/quicktime",
|
|
133
|
+
".pdf": "application/pdf",
|
|
134
|
+
".json": "application/json",
|
|
135
|
+
".zip": "application/zip",
|
|
136
|
+
".gz": "application/gzip",
|
|
137
|
+
".tar": "application/x-tar",
|
|
138
|
+
".7z": "application/x-7z-compressed",
|
|
139
|
+
".rar": "application/vnd.rar",
|
|
140
|
+
".doc": "application/msword",
|
|
141
|
+
".xls": "application/vnd.ms-excel",
|
|
142
|
+
".ppt": "application/vnd.ms-powerpoint",
|
|
143
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
144
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
145
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
146
|
+
".csv": "text/csv",
|
|
147
|
+
".txt": "text/plain",
|
|
148
|
+
".md": "text/markdown",
|
|
149
|
+
".amr": "audio/amr",
|
|
150
|
+
".aac": "audio/aac",
|
|
151
|
+
".wav": "audio/wav",
|
|
152
|
+
".webm": "video/webm",
|
|
153
|
+
".avi": "video/x-msvideo",
|
|
154
|
+
".bmp": "image/bmp",
|
|
155
|
+
".svg": "image/svg+xml"
|
|
156
|
+
};
|
|
157
|
+
/** 通过 buffer 魔术字节嗅探 MIME 类型(动态导入 file-type,不强依赖) */
|
|
158
|
+
function sniffMimeFromBuffer(buffer) {
|
|
159
|
+
var _a;
|
|
160
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
161
|
+
var fileTypeFromBuffer, type, _b;
|
|
162
|
+
return __generator(this, function (_c) {
|
|
163
|
+
switch (_c.label) {
|
|
164
|
+
case 0:
|
|
165
|
+
_c.trys.push([0, 3, , 4]);
|
|
166
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("file-type")); })];
|
|
167
|
+
case 1:
|
|
168
|
+
fileTypeFromBuffer = (_c.sent()).fileTypeFromBuffer;
|
|
169
|
+
return [4 /*yield*/, fileTypeFromBuffer(buffer)];
|
|
170
|
+
case 2:
|
|
171
|
+
type = _c.sent();
|
|
172
|
+
return [2 /*return*/, (_a = type === null || type === void 0 ? void 0 : type.mime) !== null && _a !== void 0 ? _a : undefined];
|
|
173
|
+
case 3:
|
|
174
|
+
_b = _c.sent();
|
|
175
|
+
return [2 /*return*/, undefined];
|
|
176
|
+
case 4: return [2 /*return*/];
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
/** fallback 版 detectMime,参考 weclaw/src/media/mime.ts */
|
|
182
|
+
function detectMimeFallback(opts) {
|
|
183
|
+
var _a, _b, _c;
|
|
184
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
185
|
+
var ext, extMime, sniffed, _d, isGeneric, headerMime;
|
|
186
|
+
return __generator(this, function (_e) {
|
|
187
|
+
switch (_e.label) {
|
|
188
|
+
case 0:
|
|
189
|
+
ext = opts.filePath ? path.extname(opts.filePath).toLowerCase() : undefined;
|
|
190
|
+
extMime = ext ? MIME_BY_EXT[ext] : undefined;
|
|
191
|
+
if (!opts.buffer) return [3 /*break*/, 2];
|
|
192
|
+
return [4 /*yield*/, sniffMimeFromBuffer(opts.buffer)];
|
|
193
|
+
case 1:
|
|
194
|
+
_d = _e.sent();
|
|
195
|
+
return [3 /*break*/, 3];
|
|
196
|
+
case 2:
|
|
197
|
+
_d = undefined;
|
|
198
|
+
_e.label = 3;
|
|
199
|
+
case 3:
|
|
200
|
+
sniffed = _d;
|
|
201
|
+
isGeneric = function (m) {
|
|
202
|
+
return !m || m === "application/octet-stream" || m === "application/zip";
|
|
203
|
+
};
|
|
204
|
+
if (sniffed && (!isGeneric(sniffed) || !extMime)) {
|
|
205
|
+
return [2 /*return*/, sniffed];
|
|
206
|
+
}
|
|
207
|
+
if (extMime) {
|
|
208
|
+
return [2 /*return*/, extMime];
|
|
209
|
+
}
|
|
210
|
+
headerMime = (_c = (_b = (_a = opts.headerMime) === null || _a === void 0 ? void 0 : _a.split(";")) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.trim().toLowerCase();
|
|
211
|
+
if (headerMime && !isGeneric(headerMime)) {
|
|
212
|
+
return [2 /*return*/, headerMime];
|
|
213
|
+
}
|
|
214
|
+
if (sniffed) {
|
|
215
|
+
return [2 /*return*/, sniffed];
|
|
216
|
+
}
|
|
217
|
+
if (headerMime) {
|
|
218
|
+
return [2 /*return*/, headerMime];
|
|
219
|
+
}
|
|
220
|
+
return [2 /*return*/, undefined];
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 检测 MIME 类型(兼容入口)
|
|
227
|
+
*
|
|
228
|
+
* 支持两种调用签名以兼容不同使用场景:
|
|
229
|
+
* - detectMime(buffer) → 旧式调用
|
|
230
|
+
* - detectMime({ buffer, headerMime, filePath }) → 完整参数
|
|
231
|
+
*
|
|
232
|
+
* 优先使用 SDK 版本,不可用时使用 fallback。
|
|
233
|
+
*/
|
|
234
|
+
function detectMime(bufferOrOpts) {
|
|
235
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
236
|
+
var sdk, opts, _a;
|
|
237
|
+
return __generator(this, function (_b) {
|
|
238
|
+
switch (_b.label) {
|
|
239
|
+
case 0: return [4 /*yield*/, _sdkReady];
|
|
240
|
+
case 1:
|
|
241
|
+
sdk = _b.sent();
|
|
242
|
+
opts = Buffer.isBuffer(bufferOrOpts)
|
|
243
|
+
? { buffer: bufferOrOpts }
|
|
244
|
+
: bufferOrOpts;
|
|
245
|
+
if (!sdk.detectMime) return [3 /*break*/, 5];
|
|
246
|
+
_b.label = 2;
|
|
247
|
+
case 2:
|
|
248
|
+
_b.trys.push([2, 4, , 5]);
|
|
249
|
+
return [4 /*yield*/, sdk.detectMime(opts)];
|
|
250
|
+
case 3: return [2 /*return*/, _b.sent()];
|
|
251
|
+
case 4:
|
|
252
|
+
_a = _b.sent();
|
|
253
|
+
return [3 /*break*/, 5];
|
|
254
|
+
case 5: return [2 /*return*/, detectMimeFallback(opts)];
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
exports.detectMime = detectMime;
|
|
260
|
+
// ============================================================================
|
|
261
|
+
// loadOutboundMediaFromUrl —— 从 URL/路径加载媒体文件
|
|
262
|
+
// ============================================================================
|
|
263
|
+
/** 安全的本地文件路径校验,参考 weclaw/src/web/media.ts */
|
|
264
|
+
function assertLocalMediaAllowed(mediaPath, localRoots) {
|
|
265
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
266
|
+
var resolved, _a, _i, localRoots_1, root, resolvedRoot, _b;
|
|
267
|
+
return __generator(this, function (_c) {
|
|
268
|
+
switch (_c.label) {
|
|
269
|
+
case 0:
|
|
270
|
+
if (!localRoots || localRoots.length === 0) {
|
|
271
|
+
throw new Error("Local media path is not under an allowed directory: " + mediaPath);
|
|
272
|
+
}
|
|
273
|
+
_c.label = 1;
|
|
274
|
+
case 1:
|
|
275
|
+
_c.trys.push([1, 3, , 4]);
|
|
276
|
+
return [4 /*yield*/, fs.realpath(mediaPath)];
|
|
277
|
+
case 2:
|
|
278
|
+
resolved = _c.sent();
|
|
279
|
+
return [3 /*break*/, 4];
|
|
280
|
+
case 3:
|
|
281
|
+
_a = _c.sent();
|
|
282
|
+
resolved = path.resolve(mediaPath);
|
|
283
|
+
return [3 /*break*/, 4];
|
|
284
|
+
case 4:
|
|
285
|
+
_i = 0, localRoots_1 = localRoots;
|
|
286
|
+
_c.label = 5;
|
|
287
|
+
case 5:
|
|
288
|
+
if (!(_i < localRoots_1.length)) return [3 /*break*/, 11];
|
|
289
|
+
root = localRoots_1[_i];
|
|
290
|
+
resolvedRoot = void 0;
|
|
291
|
+
_c.label = 6;
|
|
292
|
+
case 6:
|
|
293
|
+
_c.trys.push([6, 8, , 9]);
|
|
294
|
+
return [4 /*yield*/, fs.realpath(root)];
|
|
295
|
+
case 7:
|
|
296
|
+
resolvedRoot = _c.sent();
|
|
297
|
+
return [3 /*break*/, 9];
|
|
298
|
+
case 8:
|
|
299
|
+
_b = _c.sent();
|
|
300
|
+
resolvedRoot = path.resolve(root);
|
|
301
|
+
return [3 /*break*/, 9];
|
|
302
|
+
case 9:
|
|
303
|
+
if (resolvedRoot === path.parse(resolvedRoot).root) {
|
|
304
|
+
return [3 /*break*/, 10];
|
|
305
|
+
}
|
|
306
|
+
if (resolved === resolvedRoot || resolved.startsWith(resolvedRoot + path.sep)) {
|
|
307
|
+
return [2 /*return*/];
|
|
308
|
+
}
|
|
309
|
+
_c.label = 10;
|
|
310
|
+
case 10:
|
|
311
|
+
_i++;
|
|
312
|
+
return [3 /*break*/, 5];
|
|
313
|
+
case 11: throw new Error("Local media path is not under an allowed directory: " + mediaPath);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
/** 从远程 URL 获取媒体 */
|
|
319
|
+
function shouldRetryRemoteFetchStatus(status) {
|
|
320
|
+
return status === 408 || status === 429 || status >= 500;
|
|
321
|
+
}
|
|
322
|
+
function shouldRetryRemoteFetchError(err) {
|
|
323
|
+
var _a, _b;
|
|
324
|
+
var code = String(((_a = err) === null || _a === void 0 ? void 0 : _a.code) || "").trim();
|
|
325
|
+
if (code === "ECONNRESET" ||
|
|
326
|
+
code === "ETIMEDOUT" ||
|
|
327
|
+
code === "ECONNREFUSED" ||
|
|
328
|
+
code === "EAI_AGAIN" ||
|
|
329
|
+
code === "ENETUNREACH" ||
|
|
330
|
+
code === "EHOSTUNREACH") {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
var message = String(((_b = err) === null || _b === void 0 ? void 0 : _b.message) || err || "").toLowerCase();
|
|
334
|
+
return (message.includes("network") ||
|
|
335
|
+
message.includes("timed out") ||
|
|
336
|
+
message.includes("timeout") ||
|
|
337
|
+
message.includes("socket hang up") ||
|
|
338
|
+
message.includes("fetch failed") ||
|
|
339
|
+
message.includes("connection reset"));
|
|
340
|
+
}
|
|
341
|
+
function sleep(ms) {
|
|
342
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
343
|
+
return __generator(this, function (_a) {
|
|
344
|
+
switch (_a.label) {
|
|
345
|
+
case 0: return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, ms); })];
|
|
346
|
+
case 1:
|
|
347
|
+
_a.sent();
|
|
348
|
+
return [2 /*return*/];
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
function fetchRemoteMedia(url, maxBytes, gatewayToken) {
|
|
354
|
+
var _a, _b, _c;
|
|
355
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
356
|
+
var headers, token, res, lastErr, _loop_1, attempt, state_1, buffer, _d, _e, headerMime, fileName, disposition, match, contentType;
|
|
357
|
+
return __generator(this, function (_f) {
|
|
358
|
+
switch (_f.label) {
|
|
359
|
+
case 0:
|
|
360
|
+
headers = {};
|
|
361
|
+
token = String(gatewayToken || "").trim();
|
|
362
|
+
if (token) {
|
|
363
|
+
headers.Authorization = "Bearer " + token;
|
|
364
|
+
}
|
|
365
|
+
res = null;
|
|
366
|
+
lastErr = null;
|
|
367
|
+
_loop_1 = function (attempt) {
|
|
368
|
+
var controller, timer, err_1;
|
|
369
|
+
return __generator(this, function (_a) {
|
|
370
|
+
switch (_a.label) {
|
|
371
|
+
case 0:
|
|
372
|
+
controller = new AbortController();
|
|
373
|
+
timer = setTimeout(function () { return controller.abort(); }, REMOTE_MEDIA_FETCH_TIMEOUT_MS);
|
|
374
|
+
_a.label = 1;
|
|
375
|
+
case 1:
|
|
376
|
+
_a.trys.push([1, 3, , 6]);
|
|
377
|
+
return [4 /*yield*/, fetch(url, {
|
|
378
|
+
redirect: "follow",
|
|
379
|
+
headers: Object.keys(headers).length ? headers : undefined,
|
|
380
|
+
signal: controller.signal
|
|
381
|
+
})];
|
|
382
|
+
case 2:
|
|
383
|
+
res = _a.sent();
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
return [3 /*break*/, 6];
|
|
386
|
+
case 3:
|
|
387
|
+
err_1 = _a.sent();
|
|
388
|
+
clearTimeout(timer);
|
|
389
|
+
lastErr = err_1;
|
|
390
|
+
if (!(attempt < REMOTE_MEDIA_FETCH_MAX_ATTEMPTS && shouldRetryRemoteFetchError(err_1))) return [3 /*break*/, 5];
|
|
391
|
+
return [4 /*yield*/, sleep(REMOTE_MEDIA_FETCH_RETRY_DELAY_MS * attempt)];
|
|
392
|
+
case 4:
|
|
393
|
+
_a.sent();
|
|
394
|
+
return [2 /*return*/, "continue"];
|
|
395
|
+
case 5: throw err_1;
|
|
396
|
+
case 6:
|
|
397
|
+
if (res.ok) {
|
|
398
|
+
return [2 /*return*/, "break"];
|
|
399
|
+
}
|
|
400
|
+
lastErr = new Error("HTTP " + res.status + " " + res.statusText);
|
|
401
|
+
if (!(attempt < REMOTE_MEDIA_FETCH_MAX_ATTEMPTS &&
|
|
402
|
+
shouldRetryRemoteFetchStatus(res.status))) return [3 /*break*/, 8];
|
|
403
|
+
return [4 /*yield*/, sleep(REMOTE_MEDIA_FETCH_RETRY_DELAY_MS * attempt)];
|
|
404
|
+
case 7:
|
|
405
|
+
_a.sent();
|
|
406
|
+
return [2 /*return*/, "continue"];
|
|
407
|
+
case 8: throw new Error("Failed to fetch media from " + url + ": HTTP " + res.status + " " + res.statusText);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
};
|
|
411
|
+
attempt = 1;
|
|
412
|
+
_f.label = 1;
|
|
413
|
+
case 1:
|
|
414
|
+
if (!(attempt <= REMOTE_MEDIA_FETCH_MAX_ATTEMPTS)) return [3 /*break*/, 4];
|
|
415
|
+
return [5 /*yield**/, _loop_1(attempt)];
|
|
416
|
+
case 2:
|
|
417
|
+
state_1 = _f.sent();
|
|
418
|
+
if (state_1 === "break")
|
|
419
|
+
return [3 /*break*/, 4];
|
|
420
|
+
_f.label = 3;
|
|
421
|
+
case 3:
|
|
422
|
+
attempt += 1;
|
|
423
|
+
return [3 /*break*/, 1];
|
|
424
|
+
case 4:
|
|
425
|
+
if (!res) {
|
|
426
|
+
throw new Error("Failed to fetch media from " + url + ": " + String(lastErr || "unknown error"));
|
|
427
|
+
}
|
|
428
|
+
_e = (_d = Buffer).from;
|
|
429
|
+
return [4 /*yield*/, res.arrayBuffer()];
|
|
430
|
+
case 5:
|
|
431
|
+
buffer = _e.apply(_d, [_f.sent()]);
|
|
432
|
+
if (maxBytes && buffer.length > maxBytes) {
|
|
433
|
+
throw new Error("Media from " + url + " exceeds max size (" + buffer.length + " > " + maxBytes + ")");
|
|
434
|
+
}
|
|
435
|
+
headerMime = (_c = (_b = (_a = res.headers.get("content-type")) === null || _a === void 0 ? void 0 : _a.split(";")) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.trim();
|
|
436
|
+
disposition = res.headers.get("content-disposition");
|
|
437
|
+
if (disposition) {
|
|
438
|
+
match = /filename\*?\s*=\s*(?:UTF-8''|")?([^";]+)/i.exec(disposition);
|
|
439
|
+
if (match === null || match === void 0 ? void 0 : match[1]) {
|
|
440
|
+
try {
|
|
441
|
+
fileName = path.basename(decodeURIComponent(match[1].replace(/["']/g, "").trim()));
|
|
442
|
+
}
|
|
443
|
+
catch (_g) {
|
|
444
|
+
fileName = path.basename(match[1].replace(/["']/g, "").trim());
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (!fileName) {
|
|
449
|
+
fileName = extractFileNameFromUrl(url);
|
|
450
|
+
}
|
|
451
|
+
return [4 /*yield*/, detectMimeFallback({ buffer: buffer, headerMime: headerMime, filePath: fileName !== null && fileName !== void 0 ? fileName : url })];
|
|
452
|
+
case 6:
|
|
453
|
+
contentType = _f.sent();
|
|
454
|
+
return [2 /*return*/, { buffer: buffer, contentType: contentType, fileName: fileName }];
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
function extractFileNameFromUrl(url) {
|
|
460
|
+
try {
|
|
461
|
+
var parsed = new URL(url);
|
|
462
|
+
for (var _i = 0, _a = [
|
|
463
|
+
"relative_path",
|
|
464
|
+
"path",
|
|
465
|
+
"file_path",
|
|
466
|
+
"filepath",
|
|
467
|
+
"target_path",
|
|
468
|
+
"source_path",
|
|
469
|
+
]; _i < _a.length; _i++) {
|
|
470
|
+
var key = _a[_i];
|
|
471
|
+
var rawPath = parsed.searchParams.get(key);
|
|
472
|
+
if (!rawPath)
|
|
473
|
+
continue;
|
|
474
|
+
var base_1 = path.basename(decodeURIComponent(rawPath));
|
|
475
|
+
if (base_1 && base_1 !== "." && base_1 !== "..")
|
|
476
|
+
return base_1;
|
|
477
|
+
}
|
|
478
|
+
var base = path.basename(decodeURIComponent(parsed.pathname));
|
|
479
|
+
if (base && base.includes("."))
|
|
480
|
+
return base;
|
|
481
|
+
}
|
|
482
|
+
catch (_b) {
|
|
483
|
+
// ignore malformed URL
|
|
484
|
+
}
|
|
485
|
+
return undefined;
|
|
486
|
+
}
|
|
487
|
+
function isTrustedGatewayMediaUrl(mediaUrl, gatewayBaseUrl) {
|
|
488
|
+
var baseText = String(gatewayBaseUrl || "").trim().replace(/\/+$/, "");
|
|
489
|
+
if (!baseText)
|
|
490
|
+
return false;
|
|
491
|
+
try {
|
|
492
|
+
var target = new URL(mediaUrl);
|
|
493
|
+
var base = new URL(baseText);
|
|
494
|
+
if (target.origin !== base.origin)
|
|
495
|
+
return false;
|
|
496
|
+
var basePath = base.pathname.replace(/\/+$/, "");
|
|
497
|
+
if (basePath && basePath !== "/" && !target.pathname.startsWith(basePath + "/")) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
return (target.pathname.includes("/file_system/view") ||
|
|
501
|
+
target.pathname.includes("/api/media/") ||
|
|
502
|
+
target.pathname.includes("/media/"));
|
|
503
|
+
}
|
|
504
|
+
catch (_a) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/** 展开 ~ 为用户主目录 */
|
|
509
|
+
function resolveUserPath(p) {
|
|
510
|
+
if (p.startsWith("~")) {
|
|
511
|
+
return path.join(os.homedir(), p.slice(1));
|
|
512
|
+
}
|
|
513
|
+
return p;
|
|
514
|
+
}
|
|
515
|
+
/** fallback 版 loadOutboundMediaFromUrl,参考 weclaw/src/web/media.ts */
|
|
516
|
+
function loadOutboundMediaFromUrlFallback(mediaUrl, options) {
|
|
517
|
+
if (options === void 0) { options = {}; }
|
|
518
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
519
|
+
var maxBytes, mediaLocalRoots, gatewayToken, trustedGatewayBaseUrl, fetched, data, stat, fh, err_2, mime, fileName;
|
|
520
|
+
return __generator(this, function (_a) {
|
|
521
|
+
switch (_a.label) {
|
|
522
|
+
case 0:
|
|
523
|
+
maxBytes = options.maxBytes, mediaLocalRoots = options.mediaLocalRoots, gatewayToken = options.gatewayToken, trustedGatewayBaseUrl = options.trustedGatewayBaseUrl;
|
|
524
|
+
// 去除 MEDIA: 前缀
|
|
525
|
+
mediaUrl = mediaUrl.replace(/^\s*MEDIA\s*:\s*/i, "");
|
|
526
|
+
// 处理 file:// URL
|
|
527
|
+
if (mediaUrl.startsWith("file://")) {
|
|
528
|
+
try {
|
|
529
|
+
mediaUrl = node_url_1.fileURLToPath(mediaUrl);
|
|
530
|
+
}
|
|
531
|
+
catch (_b) {
|
|
532
|
+
throw new Error("Invalid file:// URL: " + mediaUrl);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (!/^https?:\/\//i.test(mediaUrl)) return [3 /*break*/, 2];
|
|
536
|
+
return [4 /*yield*/, fetchRemoteMedia(mediaUrl, maxBytes, gatewayToken)];
|
|
537
|
+
case 1:
|
|
538
|
+
fetched = _a.sent();
|
|
539
|
+
return [2 /*return*/, {
|
|
540
|
+
buffer: fetched.buffer,
|
|
541
|
+
contentType: fetched.contentType,
|
|
542
|
+
fileName: fetched.fileName
|
|
543
|
+
}];
|
|
544
|
+
case 2:
|
|
545
|
+
// 展开 ~ 路径
|
|
546
|
+
if (mediaUrl.startsWith("~")) {
|
|
547
|
+
mediaUrl = resolveUserPath(mediaUrl);
|
|
548
|
+
}
|
|
549
|
+
// 本地文件:安全校验
|
|
550
|
+
return [4 /*yield*/, assertLocalMediaAllowed(mediaUrl, mediaLocalRoots)];
|
|
551
|
+
case 3:
|
|
552
|
+
// 本地文件:安全校验
|
|
553
|
+
_a.sent();
|
|
554
|
+
_a.label = 4;
|
|
555
|
+
case 4:
|
|
556
|
+
_a.trys.push([4, 12, , 13]);
|
|
557
|
+
return [4 /*yield*/, fs.stat(mediaUrl)];
|
|
558
|
+
case 5:
|
|
559
|
+
stat = _a.sent();
|
|
560
|
+
if (!stat.isFile()) {
|
|
561
|
+
throw new Error("Local media path is not a file: " + mediaUrl);
|
|
562
|
+
}
|
|
563
|
+
return [4 /*yield*/, fs.open(mediaUrl, "r")];
|
|
564
|
+
case 6:
|
|
565
|
+
fh = _a.sent();
|
|
566
|
+
_a.label = 7;
|
|
567
|
+
case 7:
|
|
568
|
+
_a.trys.push([7, , 9, 11]);
|
|
569
|
+
return [4 /*yield*/, fh.read({ buffer: Buffer.alloc(stat.size), length: stat.size }).then(function (r) { return r.buffer.subarray(0, r.bytesRead); })];
|
|
570
|
+
case 8:
|
|
571
|
+
data = _a.sent();
|
|
572
|
+
return [3 /*break*/, 11];
|
|
573
|
+
case 9: return [4 /*yield*/, fh.close()];
|
|
574
|
+
case 10:
|
|
575
|
+
_a.sent();
|
|
576
|
+
return [7 /*endfinally*/];
|
|
577
|
+
case 11: return [3 /*break*/, 13];
|
|
578
|
+
case 12:
|
|
579
|
+
err_2 = _a.sent();
|
|
580
|
+
if ((err_2 === null || err_2 === void 0 ? void 0 : err_2.code) === "ENOENT") {
|
|
581
|
+
throw new Error("Local media file not found: " + mediaUrl);
|
|
582
|
+
}
|
|
583
|
+
throw err_2;
|
|
584
|
+
case 13:
|
|
585
|
+
if (maxBytes && data.length > maxBytes) {
|
|
586
|
+
throw new Error("Local media exceeds max size (" + data.length + " > " + maxBytes + ")");
|
|
587
|
+
}
|
|
588
|
+
return [4 /*yield*/, detectMimeFallback({ buffer: data, filePath: mediaUrl })];
|
|
589
|
+
case 14:
|
|
590
|
+
mime = _a.sent();
|
|
591
|
+
fileName = path.basename(mediaUrl) || undefined;
|
|
592
|
+
return [2 /*return*/, {
|
|
593
|
+
buffer: data,
|
|
594
|
+
contentType: mime,
|
|
595
|
+
fileName: fileName
|
|
596
|
+
}];
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* 从 URL 或本地路径加载媒体文件(兼容入口)
|
|
603
|
+
*
|
|
604
|
+
* 优先使用 SDK 版本,不可用时使用 fallback。
|
|
605
|
+
* SDK 版本抛出的业务异常(如 LocalMediaAccessError)会直接透传。
|
|
606
|
+
*/
|
|
607
|
+
function loadOutboundMediaFromUrl(mediaUrl, options) {
|
|
608
|
+
if (options === void 0) { options = {}; }
|
|
609
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
610
|
+
var sdk;
|
|
611
|
+
return __generator(this, function (_a) {
|
|
612
|
+
switch (_a.label) {
|
|
613
|
+
case 0:
|
|
614
|
+
if (options.gatewayToken &&
|
|
615
|
+
isTrustedGatewayMediaUrl(mediaUrl, options.trustedGatewayBaseUrl)) {
|
|
616
|
+
return [2 /*return*/, fetchRemoteMedia(mediaUrl, options.maxBytes, options.gatewayToken)];
|
|
617
|
+
}
|
|
618
|
+
return [4 /*yield*/, _sdkReady];
|
|
619
|
+
case 1:
|
|
620
|
+
sdk = _a.sent();
|
|
621
|
+
if (sdk.loadOutboundMediaFromUrl) {
|
|
622
|
+
return [2 /*return*/, sdk.loadOutboundMediaFromUrl(mediaUrl, options)];
|
|
623
|
+
}
|
|
624
|
+
return [2 /*return*/, loadOutboundMediaFromUrlFallback(mediaUrl, options)];
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
exports.loadOutboundMediaFromUrl = loadOutboundMediaFromUrl;
|
|
630
|
+
// ============================================================================
|
|
631
|
+
// addWildcardAllowFrom —— 向 allowFrom 列表添加通配符 "*"
|
|
632
|
+
// ============================================================================
|
|
633
|
+
/** fallback 版 addWildcardAllowFrom:确保列表中包含 "*" 通配符 */
|
|
634
|
+
function addWildcardAllowFromFallback(allowFrom) {
|
|
635
|
+
if (allowFrom.includes("*")) {
|
|
636
|
+
return allowFrom;
|
|
637
|
+
}
|
|
638
|
+
return __spreadArrays(allowFrom, ["*"]);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 向 allowFrom 列表添加通配符 "*"(兼容入口)
|
|
642
|
+
*
|
|
643
|
+
* 当 dmPolicy 为 "open" 时,需要确保 allowFrom 中包含 "*" 以允许所有来源。
|
|
644
|
+
* 优先使用 SDK 版本(plugin-sdk/setup 或 plugin-sdk/core),不可用时使用 fallback。
|
|
645
|
+
*
|
|
646
|
+
* 注意:此函数为同步函数,与 SDK 原始签名一致。
|
|
647
|
+
* SDK 引用在模块加载时异步探测并缓存,调用时同步读取缓存。
|
|
648
|
+
*/
|
|
649
|
+
function addWildcardAllowFrom(allowFrom) {
|
|
650
|
+
if (_cachedAddWildcardAllowFrom) {
|
|
651
|
+
try {
|
|
652
|
+
return _cachedAddWildcardAllowFrom(allowFrom);
|
|
653
|
+
}
|
|
654
|
+
catch (_a) {
|
|
655
|
+
// SDK 版本异常,降级到 fallback
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return addWildcardAllowFromFallback(allowFrom);
|
|
659
|
+
}
|
|
660
|
+
exports.addWildcardAllowFrom = addWildcardAllowFrom;
|
|
661
|
+
// ============================================================================
|
|
662
|
+
// getDefaultMediaLocalRoots —— 获取默认媒体本地路径白名单
|
|
663
|
+
// ============================================================================
|
|
664
|
+
/**
|
|
665
|
+
* 获取默认媒体本地路径白名单(兼容入口)
|
|
666
|
+
*
|
|
667
|
+
* 优先使用 SDK 版本,不可用时手动构建白名单(与 weclaw/src/media/local-roots.ts 逻辑一致)。
|
|
668
|
+
*/
|
|
669
|
+
function getDefaultMediaLocalRoots() {
|
|
670
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
671
|
+
var sdk, stateDir;
|
|
672
|
+
return __generator(this, function (_a) {
|
|
673
|
+
switch (_a.label) {
|
|
674
|
+
case 0: return [4 /*yield*/, _sdkReady];
|
|
675
|
+
case 1:
|
|
676
|
+
sdk = _a.sent();
|
|
677
|
+
if (sdk.getDefaultMediaLocalRoots) {
|
|
678
|
+
try {
|
|
679
|
+
return [2 /*return*/, sdk.getDefaultMediaLocalRoots()];
|
|
680
|
+
}
|
|
681
|
+
catch (_b) {
|
|
682
|
+
// SDK 版本异常,降级到 fallback
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
stateDir = path.resolve(state_dir_resolve_js_1.resolveStateDir());
|
|
686
|
+
return [2 /*return*/, [
|
|
687
|
+
path.join(stateDir, "media"),
|
|
688
|
+
path.join(stateDir, "agents"),
|
|
689
|
+
path.join(stateDir, "workspace"),
|
|
690
|
+
path.join(stateDir, "sandboxes"),
|
|
691
|
+
]];
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
exports.getDefaultMediaLocalRoots = getDefaultMediaLocalRoots;
|
|
697
|
+
function emptyPluginConfigSchema() {
|
|
698
|
+
return {
|
|
699
|
+
type: 'object',
|
|
700
|
+
additionalProperties: false,
|
|
701
|
+
properties: {}
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
exports.emptyPluginConfigSchema = emptyPluginConfigSchema;
|
|
705
|
+
// ============================================================================
|
|
706
|
+
// 辅助函数(参考 moltbot 实现)
|
|
707
|
+
// ============================================================================
|
|
708
|
+
/**
|
|
709
|
+
* 解析可选的分隔条目
|
|
710
|
+
* @param value 输入字符串,支持逗号、分号、换行符分隔
|
|
711
|
+
* @returns 解析后的字符串数组,如果输入为空则返回 undefined
|
|
712
|
+
*/
|
|
713
|
+
function parseOptionalDelimitedEntries(value) {
|
|
714
|
+
if (!(value === null || value === void 0 ? void 0 : value.trim())) {
|
|
715
|
+
return undefined;
|
|
716
|
+
}
|
|
717
|
+
var parsed = value
|
|
718
|
+
.split(/[\n,;]+/g)
|
|
719
|
+
.map(function (entry) { return entry.trim(); })
|
|
720
|
+
.filter(Boolean);
|
|
721
|
+
return parsed.length > 0 ? parsed : undefined;
|
|
722
|
+
}
|
|
723
|
+
exports.parseOptionalDelimitedEntries = parseOptionalDelimitedEntries;
|
|
724
|
+
/**
|
|
725
|
+
* 构建账户范围的 DM 安全策略
|
|
726
|
+
*/
|
|
727
|
+
function buildAccountScopedDmSecurityPolicy(params) {
|
|
728
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
729
|
+
var DEFAULT_ACCOUNT_ID = "default";
|
|
730
|
+
var resolvedAccountId = (_b = (_a = params.accountId) !== null && _a !== void 0 ? _a : params.fallbackAccountId) !== null && _b !== void 0 ? _b : DEFAULT_ACCOUNT_ID;
|
|
731
|
+
var channelConfig = (_c = params.cfg.channels) === null || _c === void 0 ? void 0 : _c[params.channelKey];
|
|
732
|
+
var useAccountPath = Boolean((_d = channelConfig === null || channelConfig === void 0 ? void 0 : channelConfig.accounts) === null || _d === void 0 ? void 0 : _d[resolvedAccountId]);
|
|
733
|
+
var basePath = useAccountPath
|
|
734
|
+
? "channels." + params.channelKey + ".accounts." + resolvedAccountId + "."
|
|
735
|
+
: "channels." + params.channelKey + ".";
|
|
736
|
+
var allowFromPath = "" + basePath + ((_e = params.allowFromPathSuffix) !== null && _e !== void 0 ? _e : "");
|
|
737
|
+
var policyPath = params.policyPathSuffix != null ? "" + basePath + params.policyPathSuffix : undefined;
|
|
738
|
+
return {
|
|
739
|
+
policy: (_g = (_f = params.policy) !== null && _f !== void 0 ? _f : params.defaultPolicy) !== null && _g !== void 0 ? _g : "pairing",
|
|
740
|
+
allowFrom: (_h = params.allowFrom) !== null && _h !== void 0 ? _h : [],
|
|
741
|
+
policyPath: policyPath,
|
|
742
|
+
allowFromPath: allowFromPath,
|
|
743
|
+
approveHint: (_j = params.approveHint) !== null && _j !== void 0 ? _j : formatPairingApproveHint((_k = params.approveChannelId) !== null && _k !== void 0 ? _k : params.channelKey),
|
|
744
|
+
normalizeEntry: params.normalizeEntry
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
exports.buildAccountScopedDmSecurityPolicy = buildAccountScopedDmSecurityPolicy;
|
|
748
|
+
/**
|
|
749
|
+
* 格式化配对审批提示信息(参考 moltbot 实现)
|
|
750
|
+
* @param channelId 频道ID
|
|
751
|
+
* @returns 配对审批提示字符串
|
|
752
|
+
*/
|
|
753
|
+
function formatPairingApproveHint(channelId) {
|
|
754
|
+
var listCmd = "openclaw pairing list " + channelId;
|
|
755
|
+
var approveCmd = "openclaw pairing approve " + channelId + " <code>";
|
|
756
|
+
return "\u5411 " + channelId + " \u673A\u5668\u4EBA\u53D1\u9001\u6D88\u606F\u4EE5\u5B8C\u6210\u914D\u5BF9\u5BA1\u6279\uFF08\u547D\u4EE4\u884C\uFF1A" + listCmd + " / " + approveCmd + "\uFF09";
|
|
757
|
+
}
|
|
758
|
+
exports.formatPairingApproveHint = formatPairingApproveHint;
|
|
759
|
+
/**
|
|
760
|
+
* fallback 实现:构建多账号作用域的 DM 安全策略对象。
|
|
761
|
+
*
|
|
762
|
+
* 逻辑与 openclaw/plugin-sdk/channel-policy 中的
|
|
763
|
+
* buildAccountScopedDmSecurityPolicy 完全一致。
|
|
764
|
+
*/
|
|
765
|
+
function buildAccountScopedDmSecurityPolicyFallback(params) {
|
|
766
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
767
|
+
var DEFAULT_ACCOUNT = "default";
|
|
768
|
+
var resolvedAccountId = (_b = (_a = params.accountId) !== null && _a !== void 0 ? _a : params.fallbackAccountId) !== null && _b !== void 0 ? _b : DEFAULT_ACCOUNT;
|
|
769
|
+
var channelConfig = (_c = params.cfg.channels) === null || _c === void 0 ? void 0 : _c[params.channelKey];
|
|
770
|
+
var useAccountPath = Boolean((_d = channelConfig === null || channelConfig === void 0 ? void 0 : channelConfig.accounts) === null || _d === void 0 ? void 0 : _d[resolvedAccountId]);
|
|
771
|
+
var basePath = useAccountPath
|
|
772
|
+
? "channels." + params.channelKey + ".accounts." + resolvedAccountId + "."
|
|
773
|
+
: "channels." + params.channelKey + ".";
|
|
774
|
+
var allowFromPath = "" + basePath + ((_e = params.allowFromPathSuffix) !== null && _e !== void 0 ? _e : "");
|
|
775
|
+
var policyPath = params.policyPathSuffix != null
|
|
776
|
+
? "" + basePath + params.policyPathSuffix
|
|
777
|
+
: undefined;
|
|
778
|
+
// 构建 approveHint 的简化版本(不依赖 formatCliCommand)
|
|
779
|
+
var channelId = (_f = params.approveChannelId) !== null && _f !== void 0 ? _f : params.channelKey;
|
|
780
|
+
var defaultApproveHint = "Approve via: openclaw pairing list " + channelId + " / openclaw pairing approve " + channelId + " <code>";
|
|
781
|
+
return {
|
|
782
|
+
policy: (_h = (_g = params.policy) !== null && _g !== void 0 ? _g : params.defaultPolicy) !== null && _h !== void 0 ? _h : "pairing",
|
|
783
|
+
allowFrom: (_j = params.allowFrom) !== null && _j !== void 0 ? _j : [],
|
|
784
|
+
policyPath: policyPath,
|
|
785
|
+
allowFromPath: allowFromPath,
|
|
786
|
+
approveHint: (_k = params.approveHint) !== null && _k !== void 0 ? _k : defaultApproveHint,
|
|
787
|
+
normalizeEntry: params.normalizeEntry
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
// 一次性探测 SDK 是否导出了 buildAccountScopedDmSecurityPolicy
|
|
791
|
+
var _sdkPolicyReady = (function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
792
|
+
var sdk, _a;
|
|
793
|
+
return __generator(this, function (_b) {
|
|
794
|
+
switch (_b.label) {
|
|
795
|
+
case 0:
|
|
796
|
+
_b.trys.push([0, 2, , 3]);
|
|
797
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require("ylib-openclaw/plugin-sdk")); })];
|
|
798
|
+
case 1:
|
|
799
|
+
sdk = _b.sent();
|
|
800
|
+
if (typeof sdk.buildAccountScopedDmSecurityPolicy === "function") {
|
|
801
|
+
return [2 /*return*/, { buildAccountScopedDmSecurityPolicy: sdk.buildAccountScopedDmSecurityPolicy }];
|
|
802
|
+
}
|
|
803
|
+
return [2 /*return*/, {}];
|
|
804
|
+
case 2:
|
|
805
|
+
_a = _b.sent();
|
|
806
|
+
// openclaw/plugin-sdk 不可用或版本过低
|
|
807
|
+
return [2 /*return*/, {}];
|
|
808
|
+
case 3: return [2 /*return*/];
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
}); })();
|
|
812
|
+
/**
|
|
813
|
+
* 构建多账号作用域的 DM 安全策略(兼容入口)
|
|
814
|
+
*
|
|
815
|
+
* 优先使用 SDK 版本(openclaw/plugin-sdk/channel-policy),
|
|
816
|
+
* 不可用时使用 fallback 实现。
|
|
817
|
+
*/
|
|
818
|
+
function buildAccountScopedDmSecurityPolicyCompat(params) {
|
|
819
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
820
|
+
var sdk;
|
|
821
|
+
return __generator(this, function (_a) {
|
|
822
|
+
switch (_a.label) {
|
|
823
|
+
case 0: return [4 /*yield*/, _sdkPolicyReady];
|
|
824
|
+
case 1:
|
|
825
|
+
sdk = _a.sent();
|
|
826
|
+
if (sdk.buildAccountScopedDmSecurityPolicy) {
|
|
827
|
+
try {
|
|
828
|
+
return [2 /*return*/, sdk.buildAccountScopedDmSecurityPolicy(params)];
|
|
829
|
+
}
|
|
830
|
+
catch (_b) {
|
|
831
|
+
// SDK 版本异常,降级到 fallback
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return [2 /*return*/, buildAccountScopedDmSecurityPolicyFallback(params)];
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
exports.buildAccountScopedDmSecurityPolicyCompat = buildAccountScopedDmSecurityPolicyCompat;
|