adp-openclaw 0.0.42 → 0.0.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adp-openclaw",
3
- "version": "0.0.42",
3
+ "version": "0.0.44",
4
4
  "description": "ADP-OpenClaw demo channel plugin (Go WebSocket backend)",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -66,42 +66,65 @@ const REQUEST_TIMEOUT_MS = 30000;
66
66
 
67
67
  // ==================== 工具函数 ====================
68
68
 
69
+ /** 扩展名到 MIME 类型的映射 */
70
+ const EXT_TO_MIME_MAP: Record<string, string> = {
71
+ ".txt": "text/plain",
72
+ ".md": "text/markdown",
73
+ ".json": "application/json",
74
+ ".html": "text/html",
75
+ ".css": "text/css",
76
+ ".js": "text/javascript",
77
+ ".ts": "text/x.typescript",
78
+ ".xml": "application/xml",
79
+ ".yaml": "application/yaml",
80
+ ".yml": "application/yaml",
81
+ ".pdf": "application/pdf",
82
+ ".png": "image/png",
83
+ ".jpg": "image/jpeg",
84
+ ".jpeg": "image/jpeg",
85
+ ".gif": "image/gif",
86
+ ".webp": "image/webp",
87
+ ".svg": "image/svg+xml",
88
+ ".csv": "text/csv",
89
+ ".zip": "application/zip",
90
+ ".doc": "application/msword",
91
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
92
+ ".xls": "application/vnd.ms-excel",
93
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
94
+ ".ppt": "application/vnd.ms-powerpoint",
95
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
96
+ ".mp3": "audio/mpeg",
97
+ ".mp4": "video/mp4",
98
+ ".wav": "audio/wav",
99
+ };
100
+
101
+ /** MIME 类型到扩展名的映射(反向映射) */
102
+ const MIME_TO_EXT_MAP: Record<string, string> = Object.fromEntries(
103
+ Object.entries(EXT_TO_MIME_MAP).map(([ext, mime]) => [mime, ext.slice(1)]) // 去掉 "." 前缀
104
+ );
105
+
69
106
  /**
70
107
  * 根据文件扩展名推断 MIME 类型
71
- */
108
+ */
72
109
  function inferMimeType(fileName: string): string {
73
110
  const ext = extname(fileName).toLowerCase();
74
- const mimeMap: Record<string, string> = {
75
- ".txt": "text/plain",
76
- ".md": "text/markdown",
77
- ".json": "application/json",
78
- ".html": "text/html",
79
- ".css": "text/css",
80
- ".js": "text/javascript",
81
- ".ts": "text/x.typescript",
82
- ".xml": "application/xml",
83
- ".yaml": "application/yaml",
84
- ".yml": "application/yaml",
85
- ".pdf": "application/pdf",
86
- ".png": "image/png",
87
- ".jpg": "image/jpeg",
88
- ".jpeg": "image/jpeg",
89
- ".gif": "image/gif",
90
- ".webp": "image/webp",
91
- ".svg": "image/svg+xml",
92
- ".csv": "text/csv",
93
- ".zip": "application/zip",
94
- ".doc": "application/msword",
95
- ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
96
- ".xls": "application/vnd.ms-excel",
97
- ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
98
- ".ppt": "application/vnd.ms-powerpoint",
99
- ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
100
- ".mp3": "audio/mpeg",
101
- ".mp4": "video/mp4",
102
- ".wav": "audio/wav",
103
- };
104
- return mimeMap[ext] || "application/octet-stream";
111
+ return EXT_TO_MIME_MAP[ext] || "application/octet-stream";
112
+ }
113
+
114
+ /**
115
+ * 把 MIME 类型或扩展名转换为纯扩展名(不带点)
116
+ * 服务端 API 期望的是文件扩展名,而不是 MIME 类型
117
+ */
118
+ function toFileExtension(fileTypeOrMime: string): string {
119
+ if (!fileTypeOrMime) return "";
120
+
121
+ // 如果已经是扩展名格式(不包含 /),直接返回(去掉可能的前导点)
122
+ if (!fileTypeOrMime.includes("/")) {
123
+ return fileTypeOrMime.replace(/^\./, "");
124
+ }
125
+
126
+ // 如果是 MIME 类型,转换为扩展名
127
+ return MIME_TO_EXT_MAP[fileTypeOrMime] || fileTypeOrMime;
105
128
  }
106
129
 
107
130
  /**
@@ -163,13 +186,16 @@ export async function getStorageCredential(
163
186
  token: string,
164
187
  fileType?: string
165
188
  ): Promise<DescribeRemoteBotStorageCredentialRsp> {
189
+ // 把 MIME 类型转换为文件扩展名,服务端 API 期望的是扩展名
190
+ const fileExtension = toFileExtension(fileType || "");
191
+
166
192
  const requestBody: DescribeRemoteBotStorageCredentialReq = {
167
193
  token,
168
- file_type: fileType || "",
194
+ file_type: fileExtension,
169
195
  };
170
196
 
171
197
  console.log(`[ADP-UPLOAD] Calling credential API: ${CREDENTIAL_API_URL}`);
172
- console.log(`[ADP-UPLOAD] Request body: token=${token.substring(0, 10)}..., file_type=${fileType || ""}`);
198
+ console.log(`[ADP-UPLOAD] Request body: token=${token.substring(0, 10)}..., file_type=${fileExtension} (original: ${fileType || ""})`);
173
199
 
174
200
  const response = await fetchWithTimeout(
175
201
  CREDENTIAL_API_URL,
@@ -229,12 +255,14 @@ export async function uploadFileToCos(
229
255
  // 2. 读取文件内容
230
256
  const fileContent = await readFile(filePath);
231
257
 
232
- // 3. 解码预签名的上传URL和下载URL
233
- const uploadUrl = decodeURIComponent(credential.upload_url);
234
- const fileUrl = decodeURIComponent(credential.file_url);
258
+ // 3. 获取预签名的上传URL和下载URL
259
+ // 注意:不要用 decodeURIComponent 解码整个 URL,会破坏签名参数
260
+ // JSON 解析已经处理了 \u0026 -> & 的转换
261
+ const uploadUrl = credential.upload_url;
262
+ const fileUrl = credential.file_url;
235
263
 
236
264
  console.log(`[ADP-UPLOAD] upload_url: ${uploadUrl.substring(0, 100)}...`);
237
- console.log(`[ADP-UPLOAD] file_url (download): ${fileUrl.substring(0, 100)}...`);
265
+ console.log(`[ADP-UPLOAD] file_url (download): ${fileUrl}...`);
238
266
 
239
267
  // 4. 执行上传(直接PUT到预签名URL,不需要额外签名)
240
268
  const response = await fetchWithTimeout(
@@ -255,7 +283,7 @@ export async function uploadFileToCos(
255
283
  throw new Error(`上传文件失败: ${response.status} ${errorText}`);
256
284
  }
257
285
 
258
- console.log(`[ADP-UPLOAD] Upload success, returning file_url: ${fileUrl.substring(0, 100)}...`);
286
+ console.log(`[ADP-UPLOAD] Upload success, returning file_url: ${fileUrl}...`);
259
287
 
260
288
  // 5. 返回下载URL
261
289
  return fileUrl;