ai-world-sdk 1.2.0 → 1.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.
@@ -1581,3 +1581,123 @@ describe("Langchain SDK Tests", () => {
1581
1581
  }
1582
1582
  }, 240000);
1583
1583
  });
1584
+ // ==================== MinIO 存储测试 ====================
1585
+ describe("MinIO Storage Tests", () => {
1586
+ const PLUGIN_ID = "test-plugin";
1587
+ let storageClient;
1588
+ beforeAll(() => {
1589
+ index_1.sdkConfig.setPluginId(PLUGIN_ID);
1590
+ storageClient = new index_1.MinioStorageClient();
1591
+ });
1592
+ test("MinIO 存储 - 上传文件", async () => {
1593
+ const content = "Hello, MinIO! This is a test file.";
1594
+ const blob = new Blob([content], { type: "text/plain" });
1595
+ const file = new File([blob], "test-hello.txt", { type: "text/plain" });
1596
+ const result = await storageClient.upload("test/hello.txt", file);
1597
+ expect(result).toBeDefined();
1598
+ expect(result.path).toBe("test/hello.txt");
1599
+ expect(result.size).toBeGreaterThan(0);
1600
+ expect(result.etag).toBeDefined();
1601
+ console.log("上传成功:", result);
1602
+ }, 30000);
1603
+ test("MinIO 存储 - 列出文件", async () => {
1604
+ const files = await storageClient.list({ prefix: "test/" });
1605
+ expect(files).toBeDefined();
1606
+ expect(Array.isArray(files)).toBe(true);
1607
+ expect(files.length).toBeGreaterThan(0);
1608
+ const testFile = files.find((f) => f.name === "test/hello.txt");
1609
+ expect(testFile).toBeDefined();
1610
+ console.log("文件列表:", files);
1611
+ }, 30000);
1612
+ test("MinIO 存储 - 获取文件信息", async () => {
1613
+ const info = await storageClient.info("test/hello.txt");
1614
+ expect(info).toBeDefined();
1615
+ expect(info.name).toBe("test/hello.txt");
1616
+ expect(info.size).toBeGreaterThan(0);
1617
+ expect(info.content_type).toBe("text/plain");
1618
+ console.log("文件信息:", info);
1619
+ }, 30000);
1620
+ test("MinIO 存储 - 下载文件", async () => {
1621
+ const blob = await storageClient.download("test/hello.txt");
1622
+ expect(blob).toBeDefined();
1623
+ expect(blob.size).toBeGreaterThan(0);
1624
+ const text = await blob.text();
1625
+ expect(text).toBe("Hello, MinIO! This is a test file.");
1626
+ console.log("下载成功, 内容:", text);
1627
+ }, 30000);
1628
+ test("MinIO 存储 - 获取预签名下载 URL", async () => {
1629
+ const result = await storageClient.getPresignedUrl("test/hello.txt", 600);
1630
+ expect(result).toBeDefined();
1631
+ expect(result.url).toBeDefined();
1632
+ expect(result.url).toContain("http");
1633
+ expect(result.expires_in).toBe(600);
1634
+ console.log("预签名下载 URL:", result.url);
1635
+ }, 30000);
1636
+ test("MinIO 存储 - 获取预签名上传 URL", async () => {
1637
+ const result = await storageClient.getPresignedUploadUrl("test/upload-via-presigned.txt", 600);
1638
+ expect(result).toBeDefined();
1639
+ expect(result.url).toBeDefined();
1640
+ expect(result.url).toContain("http");
1641
+ expect(result.expires_in).toBe(600);
1642
+ console.log("预签名上传 URL:", result.url);
1643
+ }, 30000);
1644
+ test("MinIO 存储 - 删除文件", async () => {
1645
+ // 先上传一个用于删除测试的文件
1646
+ const blob = new Blob(["delete me"], { type: "text/plain" });
1647
+ const file = new File([blob], "to-delete.txt", { type: "text/plain" });
1648
+ await storageClient.upload("test/to-delete.txt", file);
1649
+ // 删除文件
1650
+ await storageClient.delete("test/to-delete.txt");
1651
+ console.log("删除成功: test/to-delete.txt");
1652
+ // 验证文件已删除(获取信息应该失败)
1653
+ try {
1654
+ await storageClient.info("test/to-delete.txt");
1655
+ // 如果没有抛出错误,说明文件还在
1656
+ console.warn("文件可能未被删除");
1657
+ }
1658
+ catch (error) {
1659
+ expect(error.message).toContain("404");
1660
+ console.log("验证: 文件已成功删除");
1661
+ }
1662
+ }, 30000);
1663
+ test("MinIO 存储 - 清理测试文件", async () => {
1664
+ // 清理上传的测试文件
1665
+ try {
1666
+ await storageClient.delete("test/hello.txt");
1667
+ console.log("清理完成: test/hello.txt");
1668
+ }
1669
+ catch {
1670
+ console.log("清理: test/hello.txt 已不存在");
1671
+ }
1672
+ }, 30000);
1673
+ test("MinIO 存储 - 无 Plugin ID 时应报错", async () => {
1674
+ // 创建一个没有 pluginId 的客户端
1675
+ const clientWithoutPlugin = new index_1.MinioStorageClient({
1676
+ baseUrl: "http://localhost:8000",
1677
+ token: index_1.sdkConfig.getToken() || "",
1678
+ });
1679
+ // 临时清除 pluginId
1680
+ const originalPluginId = index_1.sdkConfig.getPluginId();
1681
+ index_1.sdkConfig._pluginId = null;
1682
+ index_1.sdkConfig._headers = {
1683
+ ...index_1.sdkConfig.getHeaders(),
1684
+ };
1685
+ delete index_1.sdkConfig._headers["X-Plugin-Id"];
1686
+ const clientNoPlugin = new index_1.MinioStorageClient({
1687
+ baseUrl: "http://localhost:8000",
1688
+ token: index_1.sdkConfig.getToken() || "",
1689
+ });
1690
+ try {
1691
+ await clientNoPlugin.list();
1692
+ fail("应该抛出错误");
1693
+ }
1694
+ catch (error) {
1695
+ expect(error.message).toContain("X-Plugin-Id");
1696
+ console.log("正确抛出错误:", error.message);
1697
+ }
1698
+ // 恢复 pluginId
1699
+ if (originalPluginId) {
1700
+ index_1.sdkConfig.setPluginId(originalPluginId);
1701
+ }
1702
+ }, 30000);
1703
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MinioStorageClient 测试
3
+ * 使用真实 SDK 调用后端 /api/minio 接口
4
+ * 需要后端运行 + MinIO 服务可用
5
+ *
6
+ * 运行: npm run test:minio
7
+ */
8
+ export {};
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /**
3
+ * MinioStorageClient 测试
4
+ * 使用真实 SDK 调用后端 /api/minio 接口
5
+ * 需要后端运行 + MinIO 服务可用
6
+ *
7
+ * 运行: npm run test:minio
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ const dotenv = __importStar(require("dotenv"));
44
+ const index_1 = require("../index");
45
+ dotenv.config();
46
+ index_1.sdkConfig.setBaseUrl("http://localhost:8000");
47
+ index_1.sdkConfig.setToken(process.env.AUTH_TOKEN || process.env.TOKEN || "");
48
+ index_1.sdkConfig.setDebug(true);
49
+ const PLUGIN_ID = "test-plugin";
50
+ describe("MinioStorageClient 测试", () => {
51
+ let client;
52
+ beforeAll(() => {
53
+ index_1.sdkConfig.setPluginId(PLUGIN_ID);
54
+ client = new index_1.MinioStorageClient();
55
+ });
56
+ // ==================== 上传 ====================
57
+ test("上传文本文件", async () => {
58
+ const content = "Hello, MinIO! Timestamp: " + Date.now();
59
+ const blob = new Blob([content], { type: "text/plain" });
60
+ const file = new File([blob], "hello.txt", { type: "text/plain" });
61
+ const result = await client.upload("test/hello.txt", file);
62
+ expect(result).toBeDefined();
63
+ expect(result.path).toBe("test/hello.txt");
64
+ expect(result.size).toBeGreaterThan(0);
65
+ expect(result.etag).toBeDefined();
66
+ expect(result.bucket).toBeDefined();
67
+ console.log("上传成功:", result);
68
+ }, 30000);
69
+ test("上传不指定 path 时使用文件名", async () => {
70
+ const blob = new Blob(["auto-name-test"], { type: "text/plain" });
71
+ const file = new File([blob], "auto-name.txt", { type: "text/plain" });
72
+ const result = await client.upload("test/auto-name.txt", file);
73
+ expect(result).toBeDefined();
74
+ expect(result.size).toBe(14);
75
+ console.log("自动命名上传成功:", result);
76
+ }, 30000);
77
+ // ==================== 列表 ====================
78
+ test("列出文件", async () => {
79
+ const files = await client.list({ prefix: "test/" });
80
+ expect(files).toBeDefined();
81
+ expect(Array.isArray(files)).toBe(true);
82
+ expect(files.length).toBeGreaterThan(0);
83
+ const helloFile = files.find((f) => f.name === "test/hello.txt");
84
+ expect(helloFile).toBeDefined();
85
+ console.log(`文件列表 (${files.length} 个):`, files.map((f) => f.name));
86
+ }, 30000);
87
+ test("列出文件 - 无 prefix", async () => {
88
+ const files = await client.list();
89
+ expect(files).toBeDefined();
90
+ expect(Array.isArray(files)).toBe(true);
91
+ console.log(`全部文件 (${files.length} 个)`);
92
+ }, 30000);
93
+ test("列出文件 - 非递归", async () => {
94
+ const files = await client.list({ prefix: "test/", recursive: false });
95
+ expect(files).toBeDefined();
96
+ expect(Array.isArray(files)).toBe(true);
97
+ console.log(`非递归列表 (${files.length} 个):`, files.map((f) => ({ name: f.name, is_dir: f.is_dir })));
98
+ }, 30000);
99
+ // ==================== 文件信息 ====================
100
+ test("获取文件信息", async () => {
101
+ const info = await client.info("test/hello.txt");
102
+ expect(info).toBeDefined();
103
+ expect(info.name).toBe("test/hello.txt");
104
+ expect(info.size).toBeGreaterThan(0);
105
+ expect(info.content_type).toBe("text/plain");
106
+ expect(info.etag).toBeDefined();
107
+ expect(info.last_modified).toBeDefined();
108
+ console.log("文件信息:", info);
109
+ }, 30000);
110
+ // ==================== 下载 ====================
111
+ test("下载文件", async () => {
112
+ const blob = await client.download("test/hello.txt");
113
+ expect(blob).toBeDefined();
114
+ expect(blob.size).toBeGreaterThan(0);
115
+ const text = await blob.text();
116
+ expect(text).toContain("Hello, MinIO!");
117
+ console.log("下载成功, 大小:", blob.size, "内容:", text.substring(0, 50));
118
+ }, 30000);
119
+ // ==================== 预签名 URL ====================
120
+ test("获取预签名下载 URL", async () => {
121
+ const result = await client.getPresignedUrl("test/hello.txt", 600);
122
+ expect(result).toBeDefined();
123
+ expect(result.url).toBeDefined();
124
+ expect(result.url).toContain("http");
125
+ expect(result.expires_in).toBe(600);
126
+ console.log("预签名下载 URL:", result.url.substring(0, 100) + "...");
127
+ }, 30000);
128
+ test("获取预签名上传 URL", async () => {
129
+ const result = await client.getPresignedUploadUrl("test/presigned-upload.txt", 600);
130
+ expect(result).toBeDefined();
131
+ expect(result.url).toBeDefined();
132
+ expect(result.url).toContain("http");
133
+ expect(result.expires_in).toBe(600);
134
+ console.log("预签名上传 URL:", result.url.substring(0, 100) + "...");
135
+ }, 30000);
136
+ // ==================== 删除 ====================
137
+ test("删除文件", async () => {
138
+ // 上传一个用于删除的文件
139
+ const blob = new Blob(["delete me"], { type: "text/plain" });
140
+ const file = new File([blob], "to-delete.txt", { type: "text/plain" });
141
+ await client.upload("test/to-delete.txt", file);
142
+ // 删除
143
+ await client.delete("test/to-delete.txt");
144
+ console.log("删除成功: test/to-delete.txt");
145
+ // 验证文件已删除
146
+ try {
147
+ await client.info("test/to-delete.txt");
148
+ console.warn("文件可能未被删除");
149
+ }
150
+ catch (error) {
151
+ expect(error.message).toMatch(/404|不存在/);
152
+ console.log("验证: 文件已成功删除");
153
+ }
154
+ }, 30000);
155
+ // ==================== 清理 ====================
156
+ test("清理测试文件", async () => {
157
+ const filesToClean = ["test/hello.txt", "test/auto-name.txt"];
158
+ for (const path of filesToClean) {
159
+ try {
160
+ await client.delete(path);
161
+ console.log("清理:", path);
162
+ }
163
+ catch {
164
+ console.log("清理跳过:", path, "(不存在)");
165
+ }
166
+ }
167
+ }, 30000);
168
+ // ==================== 错误处理 ====================
169
+ test("下载不存在的文件应返回 404", async () => {
170
+ try {
171
+ await client.download("nonexist/file-" + Date.now() + ".txt");
172
+ fail("应该抛出错误");
173
+ }
174
+ catch (error) {
175
+ expect(error.message).toMatch(/404|不存在/);
176
+ console.log("正确返回 404:", error.message);
177
+ }
178
+ }, 30000);
179
+ test("无 Plugin ID 时应报错", async () => {
180
+ // 保存原始值
181
+ const originalPluginId = index_1.sdkConfig.getPluginId();
182
+ const originalHeaders = { ...index_1.sdkConfig.getHeaders() };
183
+ // 清除 pluginId
184
+ index_1.sdkConfig._pluginId = null;
185
+ delete index_1.sdkConfig._headers["X-Plugin-Id"];
186
+ const clientNoPlugin = new index_1.MinioStorageClient({
187
+ baseUrl: "http://localhost:8000",
188
+ token: index_1.sdkConfig.getToken() || "",
189
+ });
190
+ try {
191
+ await clientNoPlugin.list();
192
+ fail("应该抛出错误");
193
+ }
194
+ catch (error) {
195
+ expect(error.message).toContain("X-Plugin-Id");
196
+ console.log("正确抛出错误:", error.message);
197
+ }
198
+ // 恢复
199
+ if (originalPluginId) {
200
+ index_1.sdkConfig.setPluginId(originalPluginId);
201
+ }
202
+ }, 30000);
203
+ });
package/dist/config.d.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * 注意: {VERSION} 占位符会在构建时被替换为实际版本号
11
11
  */
12
- export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.2.0";
12
+ export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.2.1";
13
13
  /**
14
14
  * 版本兼容性错误
15
15
  */
@@ -24,8 +24,8 @@ declare class SDKConfig {
24
24
  private _pluginId;
25
25
  private _versionCompatible;
26
26
  private _versionCheckPromise;
27
- readonly sdkSignature = "AI_WORLD_SDK_V:1.2.0";
28
- readonly sdkVersion = "1.2.0";
27
+ readonly sdkSignature = "AI_WORLD_SDK_V:1.2.1";
28
+ readonly sdkVersion = "1.2.1";
29
29
  constructor();
30
30
  /**
31
31
  * Set global base URL
package/dist/config.js CHANGED
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.sdkConfig = exports.VersionCompatibilityError = exports.SDK_SIGNATURE = void 0;
8
8
  // SDK 版本号(构建时自动从 package.json 更新)
9
9
  // 此版本号会在运行 npm run build 时自动从 package.json 读取并更新
10
- const SDK_VERSION = "1.2.0";
10
+ const SDK_VERSION = "1.2.1";
11
11
  /**
12
12
  * SDK 特征码 - 用于在构建后的 JS 文件中识别 SDK 版本
13
13
  * 格式: AI_WORLD_SDK_V:版本号
@@ -15,7 +15,7 @@ const SDK_VERSION = "1.2.0";
15
15
  *
16
16
  * 注意: {VERSION} 占位符会在构建时被替换为实际版本号
17
17
  */
18
- exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.2.0";
18
+ exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.2.1";
19
19
  /**
20
20
  * 版本兼容性错误
21
21
  */
package/dist/index.d.ts CHANGED
@@ -27,6 +27,7 @@ export { GeminiImageGenerationClient, type GeminiImageGenerationConfig, type Gem
27
27
  export { VideoGenerationClient, type VideoGenerationConfig, type VideoGenerationRequest, type ContentGenerationTaskID, type ContentGenerationTask, };
28
28
  export { OpenAIVideoGenerationClient, type OpenAIVideoGenerationConfig, type OpenAIVideoGenerationRequest, type OpenAIVideoTaskResponse, };
29
29
  export { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions, };
30
+ export { MinioStorageClient, type MinioStorageConfig, type UploadResponse, type ObjectInfo, type PresignedUrlResponse, type UploadOptions, type ListOptions, } from "./minio";
30
31
  export { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo, };
31
32
  export { sdkConfig, VersionCompatibilityError, SDK_SIGNATURE } from "./config";
32
33
  /**
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.SDK_SIGNATURE = exports.VersionCompatibilityError = exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.DownloadClient = exports.OpenAIVideoGenerationClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
23
+ exports.SDK_SIGNATURE = exports.VersionCompatibilityError = exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.MinioStorageClient = exports.DownloadClient = exports.OpenAIVideoGenerationClient = exports.VideoGenerationClient = exports.GeminiImageGenerationClient = exports.DoubaoImageGenerationClient = exports.ChatAnthropic = exports.ChatGoogleGenerativeAI = exports.ChatOpenAI = exports.BaseChatModel = exports.AIMessageChunk = exports.SystemMessage = exports.AIMessage = exports.HumanMessage = void 0;
24
24
  exports.createChatModel = createChatModel;
25
25
  const openai_1 = require("./chat_models/openai");
26
26
  const google_1 = require("./chat_models/google");
@@ -53,6 +53,9 @@ var google_2 = require("./chat_models/google");
53
53
  Object.defineProperty(exports, "ChatGoogleGenerativeAI", { enumerable: true, get: function () { return google_2.ChatGoogleGenerativeAI; } });
54
54
  var anthropic_1 = require("./chat_models/anthropic");
55
55
  Object.defineProperty(exports, "ChatAnthropic", { enumerable: true, get: function () { return anthropic_1.ChatAnthropic; } });
56
+ // Export MinIO storage client
57
+ var minio_1 = require("./minio");
58
+ Object.defineProperty(exports, "MinioStorageClient", { enumerable: true, get: function () { return minio_1.MinioStorageClient; } });
56
59
  // Export global configuration
57
60
  var config_2 = require("./config");
58
61
  Object.defineProperty(exports, "sdkConfig", { enumerable: true, get: function () { return config_2.sdkConfig; } });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * MinIO Storage Client
3
+ * MinIO 对象存储客户端
4
+ * 通过后端 /api/minio 代理操作 MinIO 存储
5
+ */
6
+ export interface MinioStorageConfig {
7
+ baseUrl?: string;
8
+ token?: string;
9
+ headers?: Record<string, string>;
10
+ pluginId?: string;
11
+ }
12
+ export interface UploadResponse {
13
+ path: string;
14
+ object_path: string;
15
+ size: number;
16
+ etag: string;
17
+ bucket: string;
18
+ }
19
+ export interface ObjectInfo {
20
+ name: string;
21
+ size?: number;
22
+ last_modified?: string;
23
+ etag?: string;
24
+ is_dir?: boolean;
25
+ content_type?: string;
26
+ metadata?: Record<string, string>;
27
+ }
28
+ export interface PresignedUrlResponse {
29
+ url: string;
30
+ expires_in: number;
31
+ }
32
+ export interface UploadOptions {
33
+ /** MIME content type */
34
+ contentType?: string;
35
+ }
36
+ export interface ListOptions {
37
+ /** 路径前缀过滤 */
38
+ prefix?: string;
39
+ /** 是否递归列出子目录,默认 true */
40
+ recursive?: boolean;
41
+ }
42
+ export interface PresignedUploadRequest {
43
+ path: string;
44
+ expires_in?: number;
45
+ }
46
+ /**
47
+ * MinIO Storage Client
48
+ * MinIO 对象存储客户端类
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { MinioStorageClient, sdkConfig } from 'ai-world-sdk';
53
+ *
54
+ * sdkConfig.setPluginId('my-plugin');
55
+ *
56
+ * const storage = new MinioStorageClient();
57
+ *
58
+ * // 上传文件
59
+ * const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
60
+ * const result = await storage.upload('docs/hello.txt', file);
61
+ *
62
+ * // 列出文件
63
+ * const files = await storage.list({ prefix: 'docs/' });
64
+ *
65
+ * // 下载文件
66
+ * const blob = await storage.download('docs/hello.txt');
67
+ *
68
+ * // 获取预签名 URL
69
+ * const { url } = await storage.getPresignedUrl('docs/hello.txt');
70
+ *
71
+ * // 删除文件
72
+ * await storage.delete('docs/hello.txt');
73
+ * ```
74
+ */
75
+ export declare class MinioStorageClient {
76
+ private baseUrl;
77
+ private headers;
78
+ constructor(config?: MinioStorageConfig);
79
+ /**
80
+ * 确保 X-Plugin-Id 已设置
81
+ */
82
+ private ensurePluginId;
83
+ /**
84
+ * 处理错误响应
85
+ */
86
+ private handleErrorResponse;
87
+ /**
88
+ * Upload a file to MinIO storage
89
+ * 上传文件到 MinIO 存储
90
+ *
91
+ * @param path - 存储路径(不含 userId/pluginId 前缀)
92
+ * @param file - 要上传的文件 (File, Blob, 或 Buffer)
93
+ * @param options - 上传选项
94
+ * @returns 上传结果
95
+ */
96
+ upload(path: string, file: File | Blob, options?: UploadOptions): Promise<UploadResponse>;
97
+ /**
98
+ * Download a file from MinIO storage
99
+ * 从 MinIO 存储下载文件
100
+ *
101
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
102
+ * @returns 文件 Blob
103
+ */
104
+ download(path: string): Promise<Blob>;
105
+ /**
106
+ * List files in MinIO storage
107
+ * 列出 MinIO 存储中的文件
108
+ *
109
+ * @param options - 列表选项(prefix, recursive)
110
+ * @returns 对象信息列表
111
+ */
112
+ list(options?: ListOptions): Promise<ObjectInfo[]>;
113
+ /**
114
+ * Delete a file from MinIO storage
115
+ * 从 MinIO 存储中删除文件
116
+ *
117
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
118
+ */
119
+ delete(path: string): Promise<void>;
120
+ /**
121
+ * Get a presigned download URL
122
+ * 获取预签名下载 URL
123
+ *
124
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
125
+ * @param expiresIn - 过期时间(秒),默认 3600
126
+ * @returns 预签名 URL 信息
127
+ */
128
+ getPresignedUrl(path: string, expiresIn?: number): Promise<PresignedUrlResponse>;
129
+ /**
130
+ * Get a presigned upload URL
131
+ * 获取预签名上传 URL
132
+ *
133
+ * 返回一个可直接上传文件的临时 URL,客户端可直接 PUT 文件到该 URL。
134
+ *
135
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
136
+ * @param expiresIn - 过期时间(秒),默认 3600
137
+ * @returns 预签名 URL 信息
138
+ */
139
+ getPresignedUploadUrl(path: string, expiresIn?: number): Promise<PresignedUrlResponse>;
140
+ /**
141
+ * Get file information/metadata
142
+ * 获取文件元信息
143
+ *
144
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
145
+ * @returns 对象信息
146
+ */
147
+ info(path: string): Promise<ObjectInfo>;
148
+ /**
149
+ * Download a file and trigger browser download
150
+ * 下载文件并触发浏览器下载
151
+ *
152
+ * @param path - 文件路径
153
+ * @param filename - 可选的下载文件名
154
+ */
155
+ downloadAsFile(path: string, filename?: string): Promise<void>;
156
+ }
package/dist/minio.js ADDED
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+ /**
3
+ * MinIO Storage Client
4
+ * MinIO 对象存储客户端
5
+ * 通过后端 /api/minio 代理操作 MinIO 存储
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.MinioStorageClient = void 0;
9
+ const config_1 = require("./config");
10
+ const log_1 = require("./log");
11
+ // ==================== MinioStorageClient ====================
12
+ /**
13
+ * MinIO Storage Client
14
+ * MinIO 对象存储客户端类
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { MinioStorageClient, sdkConfig } from 'ai-world-sdk';
19
+ *
20
+ * sdkConfig.setPluginId('my-plugin');
21
+ *
22
+ * const storage = new MinioStorageClient();
23
+ *
24
+ * // 上传文件
25
+ * const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
26
+ * const result = await storage.upload('docs/hello.txt', file);
27
+ *
28
+ * // 列出文件
29
+ * const files = await storage.list({ prefix: 'docs/' });
30
+ *
31
+ * // 下载文件
32
+ * const blob = await storage.download('docs/hello.txt');
33
+ *
34
+ * // 获取预签名 URL
35
+ * const { url } = await storage.getPresignedUrl('docs/hello.txt');
36
+ *
37
+ * // 删除文件
38
+ * await storage.delete('docs/hello.txt');
39
+ * ```
40
+ */
41
+ class MinioStorageClient {
42
+ constructor(config = {}) {
43
+ // 使用配置的 baseUrl 或全局配置
44
+ this.baseUrl =
45
+ config.baseUrl ||
46
+ config_1.sdkConfig.getServerUrl() ||
47
+ (typeof window !== "undefined" ? window.location.origin : "");
48
+ // 合并 headers
49
+ const globalHeaders = config_1.sdkConfig.getHeaders();
50
+ const globalToken = config.token || config_1.sdkConfig.getToken();
51
+ this.headers = {
52
+ ...globalHeaders,
53
+ ...config.headers,
54
+ };
55
+ // 设置 plugin ID
56
+ const pluginId = config.pluginId || config_1.sdkConfig.getPluginId();
57
+ if (pluginId) {
58
+ this.headers["X-Plugin-Id"] = pluginId;
59
+ }
60
+ // 如果有 token,添加到 Authorization header
61
+ if (globalToken) {
62
+ this.headers["Authorization"] = `Bearer ${globalToken}`;
63
+ }
64
+ }
65
+ /**
66
+ * 确保 X-Plugin-Id 已设置
67
+ */
68
+ ensurePluginId() {
69
+ if (!this.headers["X-Plugin-Id"]) {
70
+ // 尝试从 sdkConfig 获取最新的 pluginId
71
+ const pluginId = config_1.sdkConfig.getPluginId();
72
+ if (pluginId) {
73
+ this.headers["X-Plugin-Id"] = pluginId;
74
+ }
75
+ else {
76
+ throw new Error("X-Plugin-Id is required. Set it via sdkConfig.setPluginId() or pass pluginId in MinioStorageConfig.");
77
+ }
78
+ }
79
+ }
80
+ /**
81
+ * 处理错误响应
82
+ */
83
+ async handleErrorResponse(response) {
84
+ let errorMessage = `Request failed: ${response.status} ${response.statusText}`;
85
+ try {
86
+ const errorText = await response.text();
87
+ const errorJson = JSON.parse(errorText);
88
+ errorMessage = errorJson.detail || errorMessage;
89
+ }
90
+ catch {
91
+ // 忽略解析错误
92
+ }
93
+ throw new Error(errorMessage);
94
+ }
95
+ /**
96
+ * Upload a file to MinIO storage
97
+ * 上传文件到 MinIO 存储
98
+ *
99
+ * @param path - 存储路径(不含 userId/pluginId 前缀)
100
+ * @param file - 要上传的文件 (File, Blob, 或 Buffer)
101
+ * @param options - 上传选项
102
+ * @returns 上传结果
103
+ */
104
+ async upload(path, file, options = {}) {
105
+ config_1.sdkConfig.ensureVersionCompatible();
106
+ this.ensurePluginId();
107
+ const apiUrl = `${this.baseUrl}/api/minio/upload?path=${encodeURIComponent(path)}`;
108
+ const formData = new FormData();
109
+ // 如果是 File 对象,保留文件名;否则使用 path 中的文件名
110
+ const filename = file instanceof File ? file.name : path.split("/").pop() || "file";
111
+ formData.append("file", file, filename);
112
+ // FormData 请求不应该设置 Content-Type,浏览器会自动添加 boundary
113
+ const headers = { ...this.headers };
114
+ delete headers["Content-Type"];
115
+ (0, log_1.debugLog)("MinIO upload request:", { path, filename, size: file.size });
116
+ (0, log_1.logRequest)("POST", apiUrl, headers);
117
+ const response = await fetch(apiUrl, {
118
+ method: "POST",
119
+ headers,
120
+ body: formData,
121
+ });
122
+ if (!response.ok) {
123
+ await this.handleErrorResponse(response);
124
+ }
125
+ const result = (await response.json());
126
+ (0, log_1.debugLog)("MinIO upload response:", result);
127
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, result);
128
+ return result;
129
+ }
130
+ /**
131
+ * Download a file from MinIO storage
132
+ * 从 MinIO 存储下载文件
133
+ *
134
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
135
+ * @returns 文件 Blob
136
+ */
137
+ async download(path) {
138
+ config_1.sdkConfig.ensureVersionCompatible();
139
+ this.ensurePluginId();
140
+ const apiUrl = `${this.baseUrl}/api/minio/download/${encodeURIComponent(path)}`;
141
+ (0, log_1.debugLog)("MinIO download request:", { path });
142
+ (0, log_1.logRequest)("GET", apiUrl, this.headers);
143
+ const response = await fetch(apiUrl, {
144
+ method: "GET",
145
+ headers: this.headers,
146
+ });
147
+ if (!response.ok) {
148
+ await this.handleErrorResponse(response);
149
+ }
150
+ const blob = await response.blob();
151
+ (0, log_1.debugLog)("MinIO download completed:", { size: blob.size, type: blob.type });
152
+ return blob;
153
+ }
154
+ /**
155
+ * List files in MinIO storage
156
+ * 列出 MinIO 存储中的文件
157
+ *
158
+ * @param options - 列表选项(prefix, recursive)
159
+ * @returns 对象信息列表
160
+ */
161
+ async list(options = {}) {
162
+ config_1.sdkConfig.ensureVersionCompatible();
163
+ this.ensurePluginId();
164
+ const params = new URLSearchParams();
165
+ if (options.prefix) {
166
+ params.append("prefix", options.prefix);
167
+ }
168
+ if (options.recursive !== undefined) {
169
+ params.append("recursive", String(options.recursive));
170
+ }
171
+ const queryString = params.toString();
172
+ const apiUrl = `${this.baseUrl}/api/minio/list${queryString ? `?${queryString}` : ""}`;
173
+ (0, log_1.debugLog)("MinIO list request:", options);
174
+ (0, log_1.logRequest)("GET", apiUrl, this.headers);
175
+ const response = await fetch(apiUrl, {
176
+ method: "GET",
177
+ headers: {
178
+ ...this.headers,
179
+ "Content-Type": "application/json",
180
+ },
181
+ });
182
+ if (!response.ok) {
183
+ await this.handleErrorResponse(response);
184
+ }
185
+ const result = (await response.json());
186
+ (0, log_1.debugLog)("MinIO list response:", { count: result.length });
187
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, result);
188
+ return result;
189
+ }
190
+ /**
191
+ * Delete a file from MinIO storage
192
+ * 从 MinIO 存储中删除文件
193
+ *
194
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
195
+ */
196
+ async delete(path) {
197
+ config_1.sdkConfig.ensureVersionCompatible();
198
+ this.ensurePluginId();
199
+ const apiUrl = `${this.baseUrl}/api/minio/delete/${encodeURIComponent(path)}`;
200
+ (0, log_1.debugLog)("MinIO delete request:", { path });
201
+ (0, log_1.logRequest)("DELETE", apiUrl, this.headers);
202
+ const response = await fetch(apiUrl, {
203
+ method: "DELETE",
204
+ headers: this.headers,
205
+ });
206
+ if (!response.ok) {
207
+ await this.handleErrorResponse(response);
208
+ }
209
+ (0, log_1.debugLog)("MinIO delete completed:", { path });
210
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, { path, deleted: true });
211
+ }
212
+ /**
213
+ * Get a presigned download URL
214
+ * 获取预签名下载 URL
215
+ *
216
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
217
+ * @param expiresIn - 过期时间(秒),默认 3600
218
+ * @returns 预签名 URL 信息
219
+ */
220
+ async getPresignedUrl(path, expiresIn = 3600) {
221
+ config_1.sdkConfig.ensureVersionCompatible();
222
+ this.ensurePluginId();
223
+ const apiUrl = `${this.baseUrl}/api/minio/presigned-url/${encodeURIComponent(path)}?expires_in=${expiresIn}`;
224
+ (0, log_1.debugLog)("MinIO presigned URL request:", { path, expiresIn });
225
+ (0, log_1.logRequest)("GET", apiUrl, this.headers);
226
+ const response = await fetch(apiUrl, {
227
+ method: "GET",
228
+ headers: this.headers,
229
+ });
230
+ if (!response.ok) {
231
+ await this.handleErrorResponse(response);
232
+ }
233
+ const result = (await response.json());
234
+ (0, log_1.debugLog)("MinIO presigned URL response:", result);
235
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, result);
236
+ return result;
237
+ }
238
+ /**
239
+ * Get a presigned upload URL
240
+ * 获取预签名上传 URL
241
+ *
242
+ * 返回一个可直接上传文件的临时 URL,客户端可直接 PUT 文件到该 URL。
243
+ *
244
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
245
+ * @param expiresIn - 过期时间(秒),默认 3600
246
+ * @returns 预签名 URL 信息
247
+ */
248
+ async getPresignedUploadUrl(path, expiresIn = 3600) {
249
+ config_1.sdkConfig.ensureVersionCompatible();
250
+ this.ensurePluginId();
251
+ const apiUrl = `${this.baseUrl}/api/minio/presigned-upload`;
252
+ const body = {
253
+ path,
254
+ expires_in: expiresIn,
255
+ };
256
+ (0, log_1.debugLog)("MinIO presigned upload URL request:", body);
257
+ (0, log_1.logRequest)("POST", apiUrl, this.headers);
258
+ const response = await fetch(apiUrl, {
259
+ method: "POST",
260
+ headers: {
261
+ ...this.headers,
262
+ "Content-Type": "application/json",
263
+ },
264
+ body: JSON.stringify(body),
265
+ });
266
+ if (!response.ok) {
267
+ await this.handleErrorResponse(response);
268
+ }
269
+ const result = (await response.json());
270
+ (0, log_1.debugLog)("MinIO presigned upload URL response:", result);
271
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, result);
272
+ return result;
273
+ }
274
+ /**
275
+ * Get file information/metadata
276
+ * 获取文件元信息
277
+ *
278
+ * @param path - 文件路径(不含 userId/pluginId 前缀)
279
+ * @returns 对象信息
280
+ */
281
+ async info(path) {
282
+ config_1.sdkConfig.ensureVersionCompatible();
283
+ this.ensurePluginId();
284
+ const apiUrl = `${this.baseUrl}/api/minio/info/${encodeURIComponent(path)}`;
285
+ (0, log_1.debugLog)("MinIO info request:", { path });
286
+ (0, log_1.logRequest)("GET", apiUrl, this.headers);
287
+ const response = await fetch(apiUrl, {
288
+ method: "GET",
289
+ headers: this.headers,
290
+ });
291
+ if (!response.ok) {
292
+ await this.handleErrorResponse(response);
293
+ }
294
+ const result = (await response.json());
295
+ (0, log_1.debugLog)("MinIO info response:", result);
296
+ (0, log_1.logResponse)(response.status, response.statusText, response.headers, result);
297
+ return result;
298
+ }
299
+ /**
300
+ * Download a file and trigger browser download
301
+ * 下载文件并触发浏览器下载
302
+ *
303
+ * @param path - 文件路径
304
+ * @param filename - 可选的下载文件名
305
+ */
306
+ async downloadAsFile(path, filename) {
307
+ const blob = await this.download(path);
308
+ // 确定下载文件名
309
+ const downloadFilename = filename || path.split("/").pop() || "download";
310
+ // 创建下载链接
311
+ const url = URL.createObjectURL(blob);
312
+ const a = document.createElement("a");
313
+ a.href = url;
314
+ a.download = downloadFilename;
315
+ document.body.appendChild(a);
316
+ a.click();
317
+ document.body.removeChild(a);
318
+ // 清理 URL
319
+ setTimeout(() => URL.revokeObjectURL(url), 100);
320
+ }
321
+ }
322
+ exports.MinioStorageClient = MinioStorageClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-world-sdk",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "TypeScript SDK for AI World Platform - Chat Models, Image Generation, and Video Generation",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,7 +25,9 @@
25
25
  "test:image-generation": "jest -t 'ImageGenerationClient - 基础图像生成'",
26
26
  "test:video-generation": "jest -t 'VideoGenerationClient - 轮询视频生成任务'",
27
27
  "test:llm": "jest --testPathPattern=llm.test.ts",
28
- "test:llm-real": "jest --testPathPattern=llm.real.test.ts"
28
+ "test:llm-real": "jest --testPathPattern=llm.real.test.ts",
29
+ "test:minio": "jest --testPathPattern=minio.test.ts",
30
+ "test:minio-real": "jest -t 'MinIO Storage Tests'"
29
31
  },
30
32
  "keywords": [
31
33
  "ai-world",