ai-world-sdk 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -28,8 +28,9 @@ export { VideoGenerationClient, type VideoGenerationConfig, type VideoGeneration
28
28
  export { OpenAIVideoGenerationClient, type OpenAIVideoGenerationConfig, type OpenAIVideoGenerationRequest, type OpenAIVideoTaskResponse, };
29
29
  export { DownloadClient, type DownloadConfig, type DownloadOptions, type StreamDownloadOptions, };
30
30
  export { MinioStorageClient, type MinioStorageConfig, type UploadResponse, type ObjectInfo, type PresignedUrlResponse, type UploadOptions, type ListOptions, } from "./minio";
31
+ export { ResourceClient, type ResourceClientConfig, type ResourceInfo, type AccessLevel, type UploadResourceOptions, type ListResourceOptions, } from "./resource";
31
32
  export { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo, };
32
- export { sdkConfig, VersionCompatibilityError, SDK_SIGNATURE } from "./config";
33
+ export { sdkConfig, VersionCompatibilityError, SDK_SIGNATURE, type AuthenticatedUser } from "./config";
33
34
  /**
34
35
  * Create a chat model instance based on model name
35
36
  */
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.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;
23
+ exports.SDK_SIGNATURE = exports.VersionCompatibilityError = exports.sdkConfig = exports.getCurrentUserInfo = exports.AuthClient = exports.ResourceClient = 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");
@@ -56,6 +56,9 @@ Object.defineProperty(exports, "ChatAnthropic", { enumerable: true, get: functio
56
56
  // Export MinIO storage client
57
57
  var minio_1 = require("./minio");
58
58
  Object.defineProperty(exports, "MinioStorageClient", { enumerable: true, get: function () { return minio_1.MinioStorageClient; } });
59
+ // Export resource management client
60
+ var resource_1 = require("./resource");
61
+ Object.defineProperty(exports, "ResourceClient", { enumerable: true, get: function () { return resource_1.ResourceClient; } });
59
62
  // Export global configuration
60
63
  var config_2 = require("./config");
61
64
  Object.defineProperty(exports, "sdkConfig", { enumerable: true, get: function () { return config_2.sdkConfig; } });
@@ -0,0 +1,32 @@
1
+ /**
2
+ * AI World SDK - Login utilities (Node.js only)
3
+ * 登录工具函数,仅在 Node.js 环境使用(Vite Plugin / CLI)
4
+ */
5
+ /**
6
+ * 从项目根目录推断 pluginId:plugin.json plugin_id → package.json name → 目录名
7
+ */
8
+ export declare function resolvePluginId(projectRoot: string): string;
9
+ export interface LoginOptions {
10
+ baseUrl?: string;
11
+ timeout?: number;
12
+ }
13
+ export interface LoginResult {
14
+ token: string;
15
+ baseUrl: string;
16
+ }
17
+ /**
18
+ * 验证 token 是否有效
19
+ */
20
+ export declare function validateToken(baseUrl: string, token: string): Promise<boolean>;
21
+ /**
22
+ * 读取 .env.local 中的环境变量
23
+ */
24
+ export declare function readEnvLocal(projectRoot: string): Record<string, string>;
25
+ /**
26
+ * 写入/合并 .env.local,只更新指定的 key,保留其他内容
27
+ */
28
+ export declare function writeEnvLocal(projectRoot: string, updates: Record<string, string>): void;
29
+ /**
30
+ * 执行登录流程:启动本地 HTTP 服务器 → 打开浏览器 → 等待回调
31
+ */
32
+ export declare function performLogin(options?: LoginOptions): Promise<LoginResult>;
package/dist/login.js ADDED
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ /**
3
+ * AI World SDK - Login utilities (Node.js only)
4
+ * 登录工具函数,仅在 Node.js 环境使用(Vite Plugin / CLI)
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.resolvePluginId = resolvePluginId;
41
+ exports.validateToken = validateToken;
42
+ exports.readEnvLocal = readEnvLocal;
43
+ exports.writeEnvLocal = writeEnvLocal;
44
+ exports.performLogin = performLogin;
45
+ const http = __importStar(require("http"));
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const child_process_1 = require("child_process");
49
+ /**
50
+ * 从项目根目录推断 pluginId:plugin.json plugin_id → package.json name → 目录名
51
+ */
52
+ function resolvePluginId(projectRoot) {
53
+ try {
54
+ const pluginJsonPath = path.join(projectRoot, "plugin.json");
55
+ if (fs.existsSync(pluginJsonPath)) {
56
+ const data = JSON.parse(fs.readFileSync(pluginJsonPath, "utf-8"));
57
+ if (data.plugin_id)
58
+ return data.plugin_id;
59
+ }
60
+ }
61
+ catch {
62
+ // ignore parse errors
63
+ }
64
+ try {
65
+ const pkgJsonPath = path.join(projectRoot, "package.json");
66
+ if (fs.existsSync(pkgJsonPath)) {
67
+ const data = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
68
+ if (data.name)
69
+ return data.name;
70
+ }
71
+ }
72
+ catch {
73
+ // ignore parse errors
74
+ }
75
+ return path.basename(projectRoot);
76
+ }
77
+ const CALLBACK_PORT = 18000;
78
+ const LOGIN_TIMEOUT_MS = 60000;
79
+ const DEFAULT_BASE_URL = "https://aiworld.local:8000";
80
+ /**
81
+ * 验证 token 是否有效
82
+ */
83
+ async function validateToken(baseUrl, token) {
84
+ try {
85
+ const response = await fetch(`${baseUrl}/api/auth/me`, {
86
+ method: "GET",
87
+ headers: {
88
+ Authorization: `Bearer ${token}`,
89
+ "Content-Type": "application/json",
90
+ },
91
+ });
92
+ return response.ok;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ }
98
+ /**
99
+ * 强制确保端口可用:如果被占用则 kill 占用进程
100
+ */
101
+ function ensurePort(port) {
102
+ try {
103
+ const result = (0, child_process_1.execSync)(`lsof -ti:${port}`, { encoding: "utf-8" }).trim();
104
+ if (result) {
105
+ const pids = result.split("\n").filter(Boolean);
106
+ for (const pid of pids) {
107
+ try {
108
+ (0, child_process_1.execSync)(`kill -9 ${pid}`, { stdio: "ignore" });
109
+ }
110
+ catch {
111
+ // pid may have already exited
112
+ }
113
+ }
114
+ // Brief wait for OS to release the port
115
+ (0, child_process_1.execSync)("sleep 0.3");
116
+ }
117
+ }
118
+ catch {
119
+ // lsof returns non-zero when no process found — port is free
120
+ }
121
+ }
122
+ /**
123
+ * 打开浏览器
124
+ */
125
+ function openBrowser(url) {
126
+ const platform = process.platform;
127
+ const cmd = platform === "darwin"
128
+ ? "open"
129
+ : platform === "win32"
130
+ ? "start"
131
+ : "xdg-open";
132
+ (0, child_process_1.exec)(`${cmd} "${url}"`, (err) => {
133
+ if (err) {
134
+ console.log(`[ai-world] 无法自动打开浏览器,请手动访问: ${url}`);
135
+ }
136
+ });
137
+ }
138
+ /**
139
+ * 读取 .env.local 中的环境变量
140
+ */
141
+ function readEnvLocal(projectRoot) {
142
+ const envPath = path.join(projectRoot, ".env.local");
143
+ const vars = {};
144
+ if (!fs.existsSync(envPath))
145
+ return vars;
146
+ const content = fs.readFileSync(envPath, "utf-8");
147
+ for (const line of content.split("\n")) {
148
+ const trimmed = line.trim();
149
+ if (!trimmed || trimmed.startsWith("#"))
150
+ continue;
151
+ const eqIdx = trimmed.indexOf("=");
152
+ if (eqIdx === -1)
153
+ continue;
154
+ const key = trimmed.slice(0, eqIdx).trim();
155
+ const value = trimmed.slice(eqIdx + 1).trim();
156
+ vars[key] = value;
157
+ }
158
+ return vars;
159
+ }
160
+ /**
161
+ * 写入/合并 .env.local,只更新指定的 key,保留其他内容
162
+ */
163
+ function writeEnvLocal(projectRoot, updates) {
164
+ const envPath = path.join(projectRoot, ".env.local");
165
+ let lines = [];
166
+ if (fs.existsSync(envPath)) {
167
+ lines = fs.readFileSync(envPath, "utf-8").split("\n");
168
+ }
169
+ const updatedKeys = new Set();
170
+ for (let i = 0; i < lines.length; i++) {
171
+ const trimmed = lines[i].trim();
172
+ if (!trimmed || trimmed.startsWith("#"))
173
+ continue;
174
+ const eqIdx = trimmed.indexOf("=");
175
+ if (eqIdx === -1)
176
+ continue;
177
+ const key = trimmed.slice(0, eqIdx).trim();
178
+ if (key in updates) {
179
+ lines[i] = `${key}=${updates[key]}`;
180
+ updatedKeys.add(key);
181
+ }
182
+ }
183
+ for (const [key, value] of Object.entries(updates)) {
184
+ if (!updatedKeys.has(key)) {
185
+ lines.push(`${key}=${value}`);
186
+ }
187
+ }
188
+ // Remove trailing empty lines then add single newline at end
189
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
190
+ lines.pop();
191
+ }
192
+ lines.push("");
193
+ fs.writeFileSync(envPath, lines.join("\n"), "utf-8");
194
+ }
195
+ /**
196
+ * 执行登录流程:启动本地 HTTP 服务器 → 打开浏览器 → 等待回调
197
+ */
198
+ function performLogin(options = {}) {
199
+ const baseUrl = options.baseUrl || DEFAULT_BASE_URL;
200
+ const timeout = options.timeout || LOGIN_TIMEOUT_MS;
201
+ return new Promise((resolve, reject) => {
202
+ ensurePort(CALLBACK_PORT);
203
+ let settled = false;
204
+ let timeoutId;
205
+ const server = http.createServer((req, res) => {
206
+ const url = new URL(req.url || "/", `http://localhost:${CALLBACK_PORT}`);
207
+ if (url.pathname === "/callback") {
208
+ const token = url.searchParams.get("token");
209
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
210
+ if (token) {
211
+ res.end(`
212
+ <!DOCTYPE html>
213
+ <html><head><meta charset="utf-8"><title>AI World 登录成功</title></head>
214
+ <body style="display:flex;justify-content:center;align-items:center;height:100vh;font-family:system-ui;background:#f5f5f5">
215
+ <div style="text-align:center;padding:40px;background:white;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.1)">
216
+ <h2 style="color:#52c41a">✓ 登录成功</h2>
217
+ <p style="color:#666">Token 已保存,可以关闭此页面</p>
218
+ </div></body></html>`);
219
+ if (!settled) {
220
+ settled = true;
221
+ clearTimeout(timeoutId);
222
+ server.close();
223
+ resolve({ token, baseUrl });
224
+ }
225
+ }
226
+ else {
227
+ res.end(`
228
+ <!DOCTYPE html>
229
+ <html><head><meta charset="utf-8"><title>AI World 登录失败</title></head>
230
+ <body style="display:flex;justify-content:center;align-items:center;height:100vh;font-family:system-ui;background:#f5f5f5">
231
+ <div style="text-align:center;padding:40px;background:white;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.1)">
232
+ <h2 style="color:#ff4d4f">✗ 登录失败</h2>
233
+ <p style="color:#666">未收到 token,请重试</p>
234
+ </div></body></html>`);
235
+ }
236
+ return;
237
+ }
238
+ res.writeHead(404);
239
+ res.end("Not Found");
240
+ });
241
+ server.on("error", (err) => {
242
+ if (!settled) {
243
+ settled = true;
244
+ reject(new Error(`无法启动本地回调服务器: ${err.message}`));
245
+ }
246
+ });
247
+ server.listen(CALLBACK_PORT, () => {
248
+ const callbackUrl = `http://localhost:${CALLBACK_PORT}/callback`;
249
+ const loginUrl = `${baseUrl}/api/auth/login?redirect=${encodeURIComponent(callbackUrl)}`;
250
+ console.log(`[ai-world] 正在打开浏览器登录...`);
251
+ console.log(`[ai-world] 如果浏览器未自动打开,请手动访问:`);
252
+ console.log(`[ai-world] ${loginUrl}`);
253
+ openBrowser(loginUrl);
254
+ timeoutId = setTimeout(() => {
255
+ if (!settled) {
256
+ settled = true;
257
+ server.close();
258
+ reject(new Error(`登录超时(${timeout / 1000}s),请重新启动 dev server`));
259
+ }
260
+ }, timeout);
261
+ });
262
+ });
263
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Resource Client
3
+ * 资源管理客户端
4
+ * 通过后端 /api/resources 代理操作资源管理系统
5
+ * 支持 private / specific_users / public 三级访问控制,默认按 plugin_id 隔离
6
+ */
7
+ export interface ResourceClientConfig {
8
+ baseUrl?: string;
9
+ token?: string;
10
+ headers?: Record<string, string>;
11
+ pluginId?: string;
12
+ }
13
+ export type AccessLevel = "private" | "specific_users" | "public";
14
+ export interface ResourceInfo {
15
+ id: number;
16
+ owner_id: number;
17
+ plugin_id: string;
18
+ path: string;
19
+ object_path: string;
20
+ filename: string;
21
+ size: number;
22
+ content_type: string;
23
+ access_level: AccessLevel;
24
+ description?: string;
25
+ created_at: string;
26
+ updated_at: string;
27
+ shared_users?: number[];
28
+ }
29
+ export interface UploadResourceOptions {
30
+ accessLevel?: AccessLevel;
31
+ description?: string;
32
+ contentType?: string;
33
+ }
34
+ export interface ListResourceOptions {
35
+ crossPlugin?: boolean;
36
+ }
37
+ /**
38
+ * Resource Client
39
+ * 资源管理客户端类
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * import { ResourceClient, sdkConfig } from 'ai-world-sdk';
44
+ *
45
+ * sdkConfig.setPluginId('my-plugin');
46
+ * const resources = new ResourceClient();
47
+ *
48
+ * // 上传并设为公开
49
+ * const file = new File(['hello'], 'hello.txt', { type: 'text/plain' });
50
+ * const res = await resources.upload('docs/hello.txt', file, { accessLevel: 'public' });
51
+ *
52
+ * // 列出我的资源
53
+ * const myFiles = await resources.listMy();
54
+ *
55
+ * // 查看某用户的公开资源
56
+ * const userFiles = await resources.listByUser(42);
57
+ *
58
+ * // 分享给指定用户
59
+ * await resources.addShare(res.id, 99);
60
+ *
61
+ * // 通过 userId + path 下载
62
+ * const blob = await resources.downloadByUser(42, 'docs/hello.txt');
63
+ * ```
64
+ */
65
+ export declare class ResourceClient {
66
+ private baseUrl;
67
+ private headers;
68
+ constructor(config?: ResourceClientConfig);
69
+ private ensurePluginId;
70
+ private handleErrorResponse;
71
+ /**
72
+ * 上传文件并创建资源记录
73
+ */
74
+ upload(path: string, file: File | Blob, options?: UploadResourceOptions): Promise<ResourceInfo>;
75
+ /**
76
+ * 列出当前用户的资源
77
+ */
78
+ listMy(options?: ListResourceOptions): Promise<ResourceInfo[]>;
79
+ /**
80
+ * 获取资源详情
81
+ */
82
+ getInfo(resourceId: number): Promise<ResourceInfo>;
83
+ /**
84
+ * 修改资源访问级别
85
+ */
86
+ updateAccess(resourceId: number, accessLevel: AccessLevel): Promise<ResourceInfo>;
87
+ /**
88
+ * 批量添加用户的访问授权
89
+ *
90
+ * @param resourceId - 资源 ID
91
+ * @param userIds - 被授权用户 ID 列表(支持单个或多个)
92
+ */
93
+ addShare(resourceId: number, userIds: number | number[]): Promise<{
94
+ resource_id: number;
95
+ added_user_ids: number[];
96
+ total_requested: number;
97
+ }>;
98
+ /**
99
+ * 批量移除用户的访问授权
100
+ *
101
+ * @param resourceId - 资源 ID
102
+ * @param userIds - 要移除授权的用户 ID 列表(支持单个或多个)
103
+ */
104
+ removeShare(resourceId: number, userIds: number | number[]): Promise<{
105
+ resource_id: number;
106
+ removed_user_ids: number[];
107
+ total_requested: number;
108
+ }>;
109
+ /**
110
+ * 通过资源 ID 下载
111
+ */
112
+ download(resourceId: number): Promise<Blob>;
113
+ /**
114
+ * 删除资源
115
+ */
116
+ delete(resourceId: number): Promise<void>;
117
+ /**
118
+ * 列出指定用户的可访问资源
119
+ */
120
+ listByUser(userId: number, options?: ListResourceOptions): Promise<ResourceInfo[]>;
121
+ /**
122
+ * 通过 userId + path 下载资源
123
+ */
124
+ downloadByUser(userId: number, path: string, pluginId?: string): Promise<Blob>;
125
+ /**
126
+ * 列出被分享给当前用户的资源
127
+ */
128
+ listSharedWithMe(options?: ListResourceOptions): Promise<ResourceInfo[]>;
129
+ /**
130
+ * 列出所有 public 资源
131
+ */
132
+ listPublic(options?: ListResourceOptions): Promise<ResourceInfo[]>;
133
+ /**
134
+ * 下载资源并触发浏览器下载
135
+ */
136
+ downloadAsFile(resourceId: number, filename?: string): Promise<void>;
137
+ }