ai-world-sdk 1.5.13 → 1.5.16
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.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const TEST_DIR = path.join(__dirname, "__config_dotenv_test_tmp__");
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
if (!fs.existsSync(TEST_DIR)) {
|
|
41
|
+
fs.mkdirSync(TEST_DIR, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
// 清除相关环境变量
|
|
44
|
+
delete process.env.AI_WORLD_TOKEN;
|
|
45
|
+
delete process.env.DEBUG_TOKEN;
|
|
46
|
+
delete process.env.DEBUG;
|
|
47
|
+
delete process.env.PLUGIN_ID;
|
|
48
|
+
delete process.env.AI_WORLD_BASE_URL;
|
|
49
|
+
delete process.env.AI_WORLD_ENV_FILE;
|
|
50
|
+
});
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
if (fs.existsSync(TEST_DIR)) {
|
|
53
|
+
fs.rmSync(TEST_DIR, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
delete process.env.AI_WORLD_TOKEN;
|
|
56
|
+
delete process.env.DEBUG_TOKEN;
|
|
57
|
+
delete process.env.DEBUG;
|
|
58
|
+
delete process.env.PLUGIN_ID;
|
|
59
|
+
delete process.env.AI_WORLD_BASE_URL;
|
|
60
|
+
delete process.env.AI_WORLD_ENV_FILE;
|
|
61
|
+
jest.resetModules();
|
|
62
|
+
});
|
|
63
|
+
describe("SDKConfig dotenv loading", () => {
|
|
64
|
+
it("loads AI_WORLD_TOKEN from .env file", () => {
|
|
65
|
+
const envPath = path.join(TEST_DIR, ".env");
|
|
66
|
+
fs.writeFileSync(envPath, "AI_WORLD_TOKEN=token-from-env\n");
|
|
67
|
+
const originalCwd = process.cwd();
|
|
68
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
69
|
+
jest.resetModules();
|
|
70
|
+
const { sdkConfig } = require("../config");
|
|
71
|
+
expect(sdkConfig.getToken()).toBe("token-from-env");
|
|
72
|
+
jest.spyOn(process, "cwd").mockReturnValue(originalCwd);
|
|
73
|
+
});
|
|
74
|
+
it(".env.local overrides .env", () => {
|
|
75
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env"), "AI_WORLD_TOKEN=from-env\n");
|
|
76
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env.local"), "AI_WORLD_TOKEN=from-env-local\n");
|
|
77
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
78
|
+
jest.resetModules();
|
|
79
|
+
const { sdkConfig } = require("../config");
|
|
80
|
+
expect(sdkConfig.getToken()).toBe("from-env-local");
|
|
81
|
+
});
|
|
82
|
+
it("process.env overrides .env.local", () => {
|
|
83
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env.local"), "AI_WORLD_TOKEN=from-file\n");
|
|
84
|
+
process.env.AI_WORLD_TOKEN = "from-process-env";
|
|
85
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
86
|
+
jest.resetModules();
|
|
87
|
+
const { sdkConfig } = require("../config");
|
|
88
|
+
expect(sdkConfig.getToken()).toBe("from-process-env");
|
|
89
|
+
});
|
|
90
|
+
it("loads custom env file via AI_WORLD_ENV_FILE (lowest priority)", () => {
|
|
91
|
+
const customPath = path.join(TEST_DIR, ".env.custom");
|
|
92
|
+
fs.writeFileSync(customPath, "AI_WORLD_TOKEN=from-custom\nPLUGIN_ID=custom-plugin\n");
|
|
93
|
+
process.env.AI_WORLD_ENV_FILE = customPath;
|
|
94
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
95
|
+
jest.resetModules();
|
|
96
|
+
const { sdkConfig } = require("../config");
|
|
97
|
+
expect(sdkConfig.getToken()).toBe("from-custom");
|
|
98
|
+
expect(sdkConfig.getPluginId()).toBe("custom-plugin");
|
|
99
|
+
});
|
|
100
|
+
it("custom env file does not override .env.local", () => {
|
|
101
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env.local"), "AI_WORLD_TOKEN=from-local\n");
|
|
102
|
+
const customPath = path.join(TEST_DIR, ".env.custom");
|
|
103
|
+
fs.writeFileSync(customPath, "AI_WORLD_TOKEN=from-custom\nPLUGIN_ID=custom-plugin\n");
|
|
104
|
+
process.env.AI_WORLD_ENV_FILE = customPath;
|
|
105
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
106
|
+
jest.resetModules();
|
|
107
|
+
const { sdkConfig } = require("../config");
|
|
108
|
+
expect(sdkConfig.getToken()).toBe("from-local");
|
|
109
|
+
expect(sdkConfig.getPluginId()).toBe("custom-plugin");
|
|
110
|
+
});
|
|
111
|
+
it("loads AI_WORLD_BASE_URL from .env", () => {
|
|
112
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env"), "AI_WORLD_BASE_URL=https://my-server.com/\n");
|
|
113
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
114
|
+
jest.resetModules();
|
|
115
|
+
const { sdkConfig } = require("../config");
|
|
116
|
+
expect(sdkConfig.getServerUrl()).toBe("https://my-server.com");
|
|
117
|
+
});
|
|
118
|
+
it("loads DEBUG_TOKEN as fallback when AI_WORLD_TOKEN is not set", () => {
|
|
119
|
+
fs.writeFileSync(path.join(TEST_DIR, ".env.local"), "DEBUG_TOKEN=debug-fallback\n");
|
|
120
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
121
|
+
jest.resetModules();
|
|
122
|
+
const { sdkConfig } = require("../config");
|
|
123
|
+
expect(sdkConfig.getToken()).toBe("debug-fallback");
|
|
124
|
+
});
|
|
125
|
+
it("works when no .env files exist", () => {
|
|
126
|
+
jest.spyOn(process, "cwd").mockReturnValue(TEST_DIR);
|
|
127
|
+
jest.resetModules();
|
|
128
|
+
const { sdkConfig } = require("../config");
|
|
129
|
+
expect(sdkConfig.getToken()).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
});
|
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.5.
|
|
12
|
+
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.16";
|
|
13
13
|
/**
|
|
14
14
|
* 版本兼容性错误
|
|
15
15
|
*/
|
|
@@ -35,8 +35,8 @@ declare class SDKConfig {
|
|
|
35
35
|
private _authCheckPromise;
|
|
36
36
|
private _currentUser;
|
|
37
37
|
private _cliMode;
|
|
38
|
-
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.
|
|
39
|
-
readonly sdkVersion = "1.5.
|
|
38
|
+
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.16";
|
|
39
|
+
readonly sdkVersion = "1.5.16";
|
|
40
40
|
constructor();
|
|
41
41
|
/**
|
|
42
42
|
* Set global base URL
|
|
@@ -94,6 +94,12 @@ declare class SDKConfig {
|
|
|
94
94
|
*/
|
|
95
95
|
checkAuthentication(): Promise<boolean>;
|
|
96
96
|
private _performAuthCheck;
|
|
97
|
+
/**
|
|
98
|
+
* 加载 .env 文件到 process.env
|
|
99
|
+
* 优先级(高 → 低):已有 process.env > .env.local > .env > AI_WORLD_ENV_FILE 指定文件
|
|
100
|
+
* dotenv 默认不覆盖已存在的环境变量,按优先级从高到低加载即可
|
|
101
|
+
*/
|
|
102
|
+
private _loadDotenv;
|
|
97
103
|
private _nodeAuthCheck;
|
|
98
104
|
/**
|
|
99
105
|
* 获取当前登录状态
|
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.5.
|
|
10
|
+
const SDK_VERSION = "1.5.16";
|
|
11
11
|
/**
|
|
12
12
|
* SDK 特征码 - 用于在构建后的 JS 文件中识别 SDK 版本
|
|
13
13
|
* 格式: AI_WORLD_SDK_V:版本号
|
|
@@ -15,7 +15,7 @@ const SDK_VERSION = "1.5.13";
|
|
|
15
15
|
*
|
|
16
16
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
17
17
|
*/
|
|
18
|
-
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.
|
|
18
|
+
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.16";
|
|
19
19
|
/**
|
|
20
20
|
* 版本兼容性错误
|
|
21
21
|
*/
|
|
@@ -95,8 +95,9 @@ class SDKConfig {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
98
|
-
// 非浏览器环境(Node.js / Vite dev
|
|
98
|
+
// 非浏览器环境(Node.js / Vite dev):先加载 .env 文件,再从 process.env 读取
|
|
99
99
|
try {
|
|
100
|
+
this._loadDotenv();
|
|
100
101
|
const token = typeof process !== 'undefined' && process.env?.AI_WORLD_TOKEN;
|
|
101
102
|
if (token) {
|
|
102
103
|
this._token = token;
|
|
@@ -279,6 +280,41 @@ class SDKConfig {
|
|
|
279
280
|
return false;
|
|
280
281
|
}
|
|
281
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* 加载 .env 文件到 process.env
|
|
285
|
+
* 优先级(高 → 低):已有 process.env > .env.local > .env > AI_WORLD_ENV_FILE 指定文件
|
|
286
|
+
* dotenv 默认不覆盖已存在的环境变量,按优先级从高到低加载即可
|
|
287
|
+
*/
|
|
288
|
+
_loadDotenv() {
|
|
289
|
+
try {
|
|
290
|
+
const dotenv = require('dotenv');
|
|
291
|
+
const path = require('path');
|
|
292
|
+
const fs = require('fs');
|
|
293
|
+
const cwd = process.cwd();
|
|
294
|
+
console.log('server cwd:', cwd);
|
|
295
|
+
// .env.local 优先级最高(仅次于已有 process.env)
|
|
296
|
+
const envLocalPath = path.resolve(cwd, '.env.local');
|
|
297
|
+
if (fs.existsSync(envLocalPath)) {
|
|
298
|
+
dotenv.config({ path: envLocalPath });
|
|
299
|
+
}
|
|
300
|
+
// .env 次之
|
|
301
|
+
const envPath = path.resolve(cwd, '.env');
|
|
302
|
+
if (fs.existsSync(envPath)) {
|
|
303
|
+
dotenv.config({ path: envPath });
|
|
304
|
+
}
|
|
305
|
+
// 用户通过 AI_WORLD_ENV_FILE 指定自定义 .env 文件(最低优先级)
|
|
306
|
+
const customEnvFile = process.env.AI_WORLD_ENV_FILE;
|
|
307
|
+
if (customEnvFile) {
|
|
308
|
+
const customPath = path.isAbsolute(customEnvFile) ? customEnvFile : path.resolve(cwd, customEnvFile);
|
|
309
|
+
if (fs.existsSync(customPath)) {
|
|
310
|
+
dotenv.config({ path: customPath });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch {
|
|
315
|
+
// dotenv 不可用或文件加载失败时静默忽略
|
|
316
|
+
}
|
|
317
|
+
}
|
|
282
318
|
_nodeAuthCheck(baseUrl, token) {
|
|
283
319
|
return new Promise((resolve) => {
|
|
284
320
|
try {
|
package/dist/login.js
CHANGED
|
@@ -98,9 +98,13 @@ function validateToken(baseUrl, token) {
|
|
|
98
98
|
res.resume();
|
|
99
99
|
resolve(res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300);
|
|
100
100
|
});
|
|
101
|
-
req.on("error", () =>
|
|
101
|
+
req.on("error", (e) => {
|
|
102
|
+
console.error(`[ai-world] 验证 token 失败: `, e);
|
|
103
|
+
resolve(false);
|
|
104
|
+
});
|
|
102
105
|
}
|
|
103
|
-
catch {
|
|
106
|
+
catch (e) {
|
|
107
|
+
console.error(`[ai-world] 验证 token 失败: `, e);
|
|
104
108
|
resolve(false);
|
|
105
109
|
}
|
|
106
110
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-world-sdk",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.16",
|
|
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",
|
|
@@ -63,11 +63,9 @@
|
|
|
63
63
|
"author": "ai-world",
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@types/dotenv": "^8.2.0",
|
|
67
66
|
"@types/jest": "^29.5.0",
|
|
68
67
|
"@types/node": "^20.0.0",
|
|
69
68
|
"@types/vscode": "^1.110.0",
|
|
70
|
-
"dotenv": "^16.0.0",
|
|
71
69
|
"jest": "^29.5.0",
|
|
72
70
|
"ts-jest": "^29.1.0",
|
|
73
71
|
"ts-node": "^10.9.2",
|
|
@@ -86,6 +84,7 @@
|
|
|
86
84
|
"@openrouter/ai-sdk-provider": "./pacakges/ai-sdk-provider",
|
|
87
85
|
"ai": "^6.0.162",
|
|
88
86
|
"commander": "^14.0.3",
|
|
87
|
+
"dotenv": "^16.0.0",
|
|
89
88
|
"undici": "^8.1.0"
|
|
90
89
|
}
|
|
91
90
|
}
|
|
@@ -119,11 +119,70 @@ sdkConfig.setToken('your-jwt-token');
|
|
|
119
119
|
sdkConfig.setPluginId('my-plugin');
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
也可通过环境变量自动初始化(SDK 自动读取 `.env.local` > `.env` > `AI_WORLD_ENV_FILE` 指定文件):
|
|
123
123
|
- `AI_WORLD_BASE_URL` — 服务端地址,插件 JS 后端启动时由平台自动注入
|
|
124
124
|
- `PLUGIN_ID` — 插件 ID
|
|
125
125
|
- `DEBUG_TOKEN` — 调试用 JWT Token
|
|
126
126
|
- `AI_WORLD_TOKEN` — 用户登录后获取的 JWT Token
|
|
127
|
+
- `AI_WORLD_ENV_FILE` — 指定自定义 `.env` 文件路径(绝对或相对路径均可)
|
|
128
|
+
|
|
129
|
+
### 插件 JS 后端环境(平台自动注入)
|
|
130
|
+
|
|
131
|
+
当插件配置了 Node.js 后端(`plugin.json` 的 `backend` 字段),平台启动子进程时会自动注入以下环境变量:
|
|
132
|
+
|
|
133
|
+
| 环境变量 | 说明 |
|
|
134
|
+
|----------|------|
|
|
135
|
+
| `PORT` | **插件后端必须监听的端口**(平台自动分配,范围 19000~19999) |
|
|
136
|
+
| `SERVER_PORT` | 同 `PORT`,兼容别名 |
|
|
137
|
+
| `PLUGIN_ID` | 当前插件 ID |
|
|
138
|
+
| `AI_WORLD_BASE_URL` | 平台后端地址(默认 `http://127.0.0.1:8000`) |
|
|
139
|
+
| `AI_WORLD_ENV_FILE` | 平台写入的 `.env` 文件路径(`server/.env`),SDK 自动加载 |
|
|
140
|
+
| `NODE_ENV` | 固定为 `production` |
|
|
141
|
+
|
|
142
|
+
**重要**:插件后端 **必须** 监听 `PORT` 环境变量指定的端口,否则平台无法正确代理请求。
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
// server/index.js 示例
|
|
146
|
+
const express = require('express');
|
|
147
|
+
const app = express();
|
|
148
|
+
const port = process.env.PORT || 3000;
|
|
149
|
+
|
|
150
|
+
app.get('/health', (req, res) => res.json({ status: 'ok' }));
|
|
151
|
+
app.get('/api/hello', (req, res) => res.json({ message: 'Hello from plugin backend!' }));
|
|
152
|
+
|
|
153
|
+
app.listen(port, () => {
|
|
154
|
+
console.log(`Plugin backend listening on port ${port}`);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 插件前端请求插件后端(HTTP 代理)
|
|
159
|
+
|
|
160
|
+
平台为每个 JS 后端插件注册了 HTTP 反向代理路由,**插件前端不需要知道后端实际端口**,统一通过以下地址访问:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
{AI_WORLD_BASE_URL}/api/{plugin-id}/server/{path}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
例如插件 ID 为 `my-plugin`,后端有 `/api/hello` 接口,前端请求地址为:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
https://aiworld.local:8000/api/my-plugin/server/api/hello
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
在插件前端代码中使用 `sdkConfig` 获取 baseUrl:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { sdkConfig } from 'ai-world-sdk';
|
|
176
|
+
|
|
177
|
+
// 插件前端请求插件后端
|
|
178
|
+
const baseUrl = sdkConfig.getServerUrl();
|
|
179
|
+
const pluginId = sdkConfig.getPluginId();
|
|
180
|
+
const response = await fetch(`${baseUrl}/api/${pluginId}/server/api/hello`, {
|
|
181
|
+
headers: { 'Authorization': `Bearer ${sdkConfig.getToken()}` }
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
WebSocket 同理:`ws(s)://{host}/api/{plugin-id}/server/ws`
|
|
127
186
|
|
|
128
187
|
## 功能模块
|
|
129
188
|
|