@jayfong/x-server 2.116.0 → 2.117.0
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/lib/_cjs/exports.js +24 -0
- package/lib/_cjs/services/ai.js +48 -0
- package/lib/_cjs/services/file_store.js +67 -0
- package/lib/exports.d.ts +4 -0
- package/lib/exports.js +4 -0
- package/lib/services/ai.d.ts +31 -0
- package/lib/services/ai.js +43 -0
- package/lib/services/file_store.d.ts +49 -0
- package/lib/services/file_store.js +61 -0
- package/package.json +4 -1
package/lib/_cjs/exports.js
CHANGED
|
@@ -139,6 +139,12 @@ Object.keys(_xml_parser).forEach(function (key) {
|
|
|
139
139
|
if (key in exports && exports[key] === _xml_parser[key]) return;
|
|
140
140
|
exports[key] = _xml_parser[key];
|
|
141
141
|
});
|
|
142
|
+
var _ai = require("./services/ai");
|
|
143
|
+
Object.keys(_ai).forEach(function (key) {
|
|
144
|
+
if (key === "default" || key === "__esModule") return;
|
|
145
|
+
if (key in exports && exports[key] === _ai[key]) return;
|
|
146
|
+
exports[key] = _ai[key];
|
|
147
|
+
});
|
|
142
148
|
var _base2 = require("./services/base");
|
|
143
149
|
Object.keys(_base2).forEach(function (key) {
|
|
144
150
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -187,6 +193,18 @@ Object.keys(_emoji).forEach(function (key) {
|
|
|
187
193
|
if (key in exports && exports[key] === _emoji[key]) return;
|
|
188
194
|
exports[key] = _emoji[key];
|
|
189
195
|
});
|
|
196
|
+
var _file_store = require("./services/file_store");
|
|
197
|
+
Object.keys(_file_store).forEach(function (key) {
|
|
198
|
+
if (key === "default" || key === "__esModule") return;
|
|
199
|
+
if (key in exports && exports[key] === _file_store[key]) return;
|
|
200
|
+
exports[key] = _file_store[key];
|
|
201
|
+
});
|
|
202
|
+
var _html = require("./services/html");
|
|
203
|
+
Object.keys(_html).forEach(function (key) {
|
|
204
|
+
if (key === "default" || key === "__esModule") return;
|
|
205
|
+
if (key in exports && exports[key] === _html[key]) return;
|
|
206
|
+
exports[key] = _html[key];
|
|
207
|
+
});
|
|
190
208
|
var _jwt = require("./services/jwt");
|
|
191
209
|
Object.keys(_jwt).forEach(function (key) {
|
|
192
210
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -211,6 +229,12 @@ Object.keys(_pay).forEach(function (key) {
|
|
|
211
229
|
if (key in exports && exports[key] === _pay[key]) return;
|
|
212
230
|
exports[key] = _pay[key];
|
|
213
231
|
});
|
|
232
|
+
var _random = require("./services/random");
|
|
233
|
+
Object.keys(_random).forEach(function (key) {
|
|
234
|
+
if (key === "default" || key === "__esModule") return;
|
|
235
|
+
if (key in exports && exports[key] === _random[key]) return;
|
|
236
|
+
exports[key] = _random[key];
|
|
237
|
+
});
|
|
214
238
|
var _rate_limit = require("./services/rate_limit");
|
|
215
239
|
Object.keys(_rate_limit).forEach(function (key) {
|
|
216
240
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
exports.__esModule = true;
|
|
4
|
+
exports.AiService = void 0;
|
|
5
|
+
var _xRequest = require("@jayfong/x-request");
|
|
6
|
+
var _vtils = require("vtils");
|
|
7
|
+
class AiService {
|
|
8
|
+
static async ask(payload) {
|
|
9
|
+
const res = await _xRequest.xr.postJson({
|
|
10
|
+
url: `${payload.baseUrl}/chat/completions`,
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Bearer ${payload.apiKey}`,
|
|
13
|
+
...payload.headers
|
|
14
|
+
},
|
|
15
|
+
data: {
|
|
16
|
+
model: payload.model,
|
|
17
|
+
messages: [...(payload.prompt ? [{
|
|
18
|
+
role: 'system',
|
|
19
|
+
content: payload.prompt
|
|
20
|
+
}] : []), {
|
|
21
|
+
role: 'user',
|
|
22
|
+
content: payload.question
|
|
23
|
+
}],
|
|
24
|
+
stream: false
|
|
25
|
+
},
|
|
26
|
+
timeoutMs: (0, _vtils.ms)('1m'),
|
|
27
|
+
noThrowHttpErrors: true
|
|
28
|
+
});
|
|
29
|
+
if (res.status !== 200) {
|
|
30
|
+
console.error(res.data);
|
|
31
|
+
throw new Error(JSON.stringify(res.data));
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
answer: res.data.choices[0].message.content
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
constructor(options) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
this.serviceName = 'ai';
|
|
40
|
+
}
|
|
41
|
+
ask(payload) {
|
|
42
|
+
return AiService.ask({
|
|
43
|
+
...this.options,
|
|
44
|
+
...payload
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.AiService = AiService;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.FileStoreService = void 0;
|
|
6
|
+
var _clientS = require("@aws-sdk/client-s3");
|
|
7
|
+
var _s3RequestPresigner = require("@aws-sdk/s3-request-presigner");
|
|
8
|
+
var _xRequest = require("@jayfong/x-request");
|
|
9
|
+
var _mime = _interopRequireDefault(require("mime"));
|
|
10
|
+
var _vtils = require("vtils");
|
|
11
|
+
var _x = require("../x");
|
|
12
|
+
class FileStoreService {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
this.options = options;
|
|
15
|
+
this.serviceName = 'fileStore';
|
|
16
|
+
this.endpoint = '';
|
|
17
|
+
this.dir = '';
|
|
18
|
+
this.cdnUrl = '';
|
|
19
|
+
this.endpoint = (0, _vtils.isUrl)(this.options.endpoint) ? this.options.endpoint : `https://${this.options.endpoint}`;
|
|
20
|
+
this.dir = this.options.dir ? `${this.options.dir.replace(/^\/+/, '').replace(/\/+$/, '')}` : '';
|
|
21
|
+
this.cdnUrl = ((0, _vtils.isUrl)(this.options.cdnUrl) ? this.options.cdnUrl : `https://${this.options.cdnUrl}`).replace(/\/+$/, '');
|
|
22
|
+
}
|
|
23
|
+
async getUploadUrl(payload) {
|
|
24
|
+
const s3Client = new _clientS.S3Client({
|
|
25
|
+
credentials: {
|
|
26
|
+
accessKeyId: this.options.accessKey,
|
|
27
|
+
secretAccessKey: this.options.secretKey
|
|
28
|
+
},
|
|
29
|
+
endpoint: this.endpoint,
|
|
30
|
+
region: 'x'
|
|
31
|
+
});
|
|
32
|
+
const contentType = _mime.default.getType(payload.fileName) || 'application/octet-stream';
|
|
33
|
+
const fileName = payload.keepName ? payload.fileName : `${_x.x.random.cuid2()}.${_mime.default.getExtension(contentType)}`;
|
|
34
|
+
const dir = this.dir ? `${this.dir}/` : '';
|
|
35
|
+
const command = new _clientS.PutObjectCommand({
|
|
36
|
+
Bucket: this.options.bucket,
|
|
37
|
+
Key: `${dir}${fileName}`,
|
|
38
|
+
ContentType: contentType
|
|
39
|
+
});
|
|
40
|
+
const uploadUrl = await (0, _s3RequestPresigner.getSignedUrl)(s3Client, command, {
|
|
41
|
+
expiresIn: (0, _vtils.ms)(payload.ttl, true)
|
|
42
|
+
});
|
|
43
|
+
const publicUrl = `${this.cdnUrl}/${dir}${fileName}`;
|
|
44
|
+
return {
|
|
45
|
+
contentType,
|
|
46
|
+
uploadUrl,
|
|
47
|
+
publicUrl
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async upload(payload) {
|
|
51
|
+
const res = await this.getUploadUrl({
|
|
52
|
+
fileName: payload.fileName,
|
|
53
|
+
ttl: (0, _vtils.ms)('1m'),
|
|
54
|
+
keepName: payload.keepName
|
|
55
|
+
});
|
|
56
|
+
await _xRequest.xr.post({
|
|
57
|
+
url: res.uploadUrl,
|
|
58
|
+
method: 'PUT',
|
|
59
|
+
headers: {
|
|
60
|
+
'Content-Type': res.contentType
|
|
61
|
+
},
|
|
62
|
+
data: payload.content
|
|
63
|
+
});
|
|
64
|
+
return res;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.FileStoreService = FileStoreService;
|
package/lib/exports.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export * from './plugins/file_parser';
|
|
|
21
21
|
export * from './plugins/form_body_parser';
|
|
22
22
|
export * from './plugins/ws_parser';
|
|
23
23
|
export * from './plugins/xml_parser';
|
|
24
|
+
export * from './services/ai';
|
|
24
25
|
export * from './services/base';
|
|
25
26
|
export * from './services/cache';
|
|
26
27
|
export * from './services/captcha';
|
|
@@ -29,10 +30,13 @@ export * from './services/db_value';
|
|
|
29
30
|
export * from './services/dingtalk';
|
|
30
31
|
export * from './services/dispose';
|
|
31
32
|
export * from './services/emoji';
|
|
33
|
+
export * from './services/file_store';
|
|
34
|
+
export * from './services/html';
|
|
32
35
|
export * from './services/jwt';
|
|
33
36
|
export * from './services/log';
|
|
34
37
|
export * from './services/mail';
|
|
35
38
|
export * from './services/pay';
|
|
39
|
+
export * from './services/random';
|
|
36
40
|
export * from './services/rate_limit';
|
|
37
41
|
export * from './services/redis';
|
|
38
42
|
export * from './services/sensitive_words';
|
package/lib/exports.js
CHANGED
|
@@ -22,6 +22,7 @@ export * from "./plugins/file_parser";
|
|
|
22
22
|
export * from "./plugins/form_body_parser";
|
|
23
23
|
export * from "./plugins/ws_parser";
|
|
24
24
|
export * from "./plugins/xml_parser";
|
|
25
|
+
export * from "./services/ai";
|
|
25
26
|
export * from "./services/base";
|
|
26
27
|
export * from "./services/cache";
|
|
27
28
|
export * from "./services/captcha";
|
|
@@ -30,10 +31,13 @@ export * from "./services/db_value";
|
|
|
30
31
|
export * from "./services/dingtalk";
|
|
31
32
|
export * from "./services/dispose";
|
|
32
33
|
export * from "./services/emoji";
|
|
34
|
+
export * from "./services/file_store";
|
|
35
|
+
export * from "./services/html";
|
|
33
36
|
export * from "./services/jwt";
|
|
34
37
|
export * from "./services/log";
|
|
35
38
|
export * from "./services/mail";
|
|
36
39
|
export * from "./services/pay";
|
|
40
|
+
export * from "./services/random";
|
|
37
41
|
export * from "./services/rate_limit";
|
|
38
42
|
export * from "./services/redis";
|
|
39
43
|
export * from "./services/sensitive_words";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PartialBy } from 'vtils/types';
|
|
2
|
+
import type { BaseService } from './base';
|
|
3
|
+
export type AiServiceOptions = {
|
|
4
|
+
/** 基础路径,如: https://dashscope.aliyuncs.com/compatible-mode/v1 */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** API密钥,如: sk-xxx */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** 模型名称,如: deepseek-v3.1 */
|
|
9
|
+
model: string;
|
|
10
|
+
/** 额外请求头 */
|
|
11
|
+
headers?: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
export type AiServiceAskPayload = AiServiceOptions & {
|
|
14
|
+
prompt?: string;
|
|
15
|
+
question: string;
|
|
16
|
+
};
|
|
17
|
+
export type AiServiceAskResult = {
|
|
18
|
+
answer: string;
|
|
19
|
+
};
|
|
20
|
+
export declare class AiService implements BaseService {
|
|
21
|
+
private options;
|
|
22
|
+
serviceName: string;
|
|
23
|
+
static ask(payload: AiServiceAskPayload): Promise<AiServiceAskResult>;
|
|
24
|
+
constructor(options: AiServiceOptions);
|
|
25
|
+
ask(payload: PartialBy<AiServiceAskPayload, keyof AiServiceOptions>): Promise<AiServiceAskResult>;
|
|
26
|
+
}
|
|
27
|
+
declare module '../x' {
|
|
28
|
+
interface X {
|
|
29
|
+
ai: AiService;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { xr } from '@jayfong/x-request';
|
|
2
|
+
import { ms } from 'vtils';
|
|
3
|
+
export class AiService {
|
|
4
|
+
static async ask(payload) {
|
|
5
|
+
const res = await xr.postJson({
|
|
6
|
+
url: `${payload.baseUrl}/chat/completions`,
|
|
7
|
+
headers: {
|
|
8
|
+
Authorization: `Bearer ${payload.apiKey}`,
|
|
9
|
+
...payload.headers
|
|
10
|
+
},
|
|
11
|
+
data: {
|
|
12
|
+
model: payload.model,
|
|
13
|
+
messages: [...(payload.prompt ? [{
|
|
14
|
+
role: 'system',
|
|
15
|
+
content: payload.prompt
|
|
16
|
+
}] : []), {
|
|
17
|
+
role: 'user',
|
|
18
|
+
content: payload.question
|
|
19
|
+
}],
|
|
20
|
+
stream: false
|
|
21
|
+
},
|
|
22
|
+
timeoutMs: ms('1m'),
|
|
23
|
+
noThrowHttpErrors: true
|
|
24
|
+
});
|
|
25
|
+
if (res.status !== 200) {
|
|
26
|
+
console.error(res.data);
|
|
27
|
+
throw new Error(JSON.stringify(res.data));
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
answer: res.data.choices[0].message.content
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
constructor(options) {
|
|
34
|
+
this.options = options;
|
|
35
|
+
this.serviceName = 'ai';
|
|
36
|
+
}
|
|
37
|
+
ask(payload) {
|
|
38
|
+
return AiService.ask({
|
|
39
|
+
...this.options,
|
|
40
|
+
...payload
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { BaseService } from './base';
|
|
2
|
+
export type FileStoreServiceOptions = {
|
|
3
|
+
accessKey: string;
|
|
4
|
+
secretKey: string;
|
|
5
|
+
/** 如: cos.ap-guangzhou.myqcloud.com */
|
|
6
|
+
endpoint: string;
|
|
7
|
+
/** 如: image-311111 */
|
|
8
|
+
bucket: string;
|
|
9
|
+
/** 如: x */
|
|
10
|
+
dir: string;
|
|
11
|
+
/** 如: cdn.com */
|
|
12
|
+
cdnUrl: string;
|
|
13
|
+
};
|
|
14
|
+
export type FileStoreServiceGetUploadUrlPayload = {
|
|
15
|
+
fileName: string;
|
|
16
|
+
ttl: number;
|
|
17
|
+
keepName?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type FileStoreServiceGetUploadUrlResult = {
|
|
20
|
+
/** 文件类型 */
|
|
21
|
+
contentType: string;
|
|
22
|
+
/** 文件上传地址 */
|
|
23
|
+
uploadUrl: string;
|
|
24
|
+
/** 文件公开访问地址 */
|
|
25
|
+
publicUrl: string;
|
|
26
|
+
};
|
|
27
|
+
export type FileStoreServiceUploadPayload = {
|
|
28
|
+
/** 文件名 */
|
|
29
|
+
fileName: string;
|
|
30
|
+
/** 文件内容 */
|
|
31
|
+
content: Buffer;
|
|
32
|
+
keepName?: boolean;
|
|
33
|
+
};
|
|
34
|
+
export type FileStoreServiceUploadResult = FileStoreServiceGetUploadUrlResult;
|
|
35
|
+
export declare class FileStoreService implements BaseService {
|
|
36
|
+
private options;
|
|
37
|
+
serviceName: string;
|
|
38
|
+
private endpoint;
|
|
39
|
+
private dir;
|
|
40
|
+
private cdnUrl;
|
|
41
|
+
constructor(options: FileStoreServiceOptions);
|
|
42
|
+
getUploadUrl(payload: FileStoreServiceGetUploadUrlPayload): Promise<FileStoreServiceGetUploadUrlResult>;
|
|
43
|
+
upload(payload: FileStoreServiceUploadPayload): Promise<FileStoreServiceUploadResult>;
|
|
44
|
+
}
|
|
45
|
+
declare module '../x' {
|
|
46
|
+
interface X {
|
|
47
|
+
fileStore: FileStoreService;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
|
|
2
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
3
|
+
import { xr } from '@jayfong/x-request';
|
|
4
|
+
import mime from 'mime';
|
|
5
|
+
import { isUrl, ms } from 'vtils';
|
|
6
|
+
import { x } from "../x";
|
|
7
|
+
export class FileStoreService {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.serviceName = 'fileStore';
|
|
11
|
+
this.endpoint = '';
|
|
12
|
+
this.dir = '';
|
|
13
|
+
this.cdnUrl = '';
|
|
14
|
+
this.endpoint = isUrl(this.options.endpoint) ? this.options.endpoint : `https://${this.options.endpoint}`;
|
|
15
|
+
this.dir = this.options.dir ? `${this.options.dir.replace(/^\/+/, '').replace(/\/+$/, '')}` : '';
|
|
16
|
+
this.cdnUrl = (isUrl(this.options.cdnUrl) ? this.options.cdnUrl : `https://${this.options.cdnUrl}`).replace(/\/+$/, '');
|
|
17
|
+
}
|
|
18
|
+
async getUploadUrl(payload) {
|
|
19
|
+
const s3Client = new S3Client({
|
|
20
|
+
credentials: {
|
|
21
|
+
accessKeyId: this.options.accessKey,
|
|
22
|
+
secretAccessKey: this.options.secretKey
|
|
23
|
+
},
|
|
24
|
+
endpoint: this.endpoint,
|
|
25
|
+
region: 'x'
|
|
26
|
+
});
|
|
27
|
+
const contentType = mime.getType(payload.fileName) || 'application/octet-stream';
|
|
28
|
+
const fileName = payload.keepName ? payload.fileName : `${x.random.cuid2()}.${mime.getExtension(contentType)}`;
|
|
29
|
+
const dir = this.dir ? `${this.dir}/` : '';
|
|
30
|
+
const command = new PutObjectCommand({
|
|
31
|
+
Bucket: this.options.bucket,
|
|
32
|
+
Key: `${dir}${fileName}`,
|
|
33
|
+
ContentType: contentType
|
|
34
|
+
});
|
|
35
|
+
const uploadUrl = await getSignedUrl(s3Client, command, {
|
|
36
|
+
expiresIn: ms(payload.ttl, true)
|
|
37
|
+
});
|
|
38
|
+
const publicUrl = `${this.cdnUrl}/${dir}${fileName}`;
|
|
39
|
+
return {
|
|
40
|
+
contentType,
|
|
41
|
+
uploadUrl,
|
|
42
|
+
publicUrl
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async upload(payload) {
|
|
46
|
+
const res = await this.getUploadUrl({
|
|
47
|
+
fileName: payload.fileName,
|
|
48
|
+
ttl: ms('1m'),
|
|
49
|
+
keepName: payload.keepName
|
|
50
|
+
});
|
|
51
|
+
await xr.post({
|
|
52
|
+
url: res.uploadUrl,
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': res.contentType
|
|
56
|
+
},
|
|
57
|
+
data: payload.content
|
|
58
|
+
});
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jayfong/x-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.117.0",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "lib/_cjs/index.js",
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
"test_api_qiqi": "cd /Users/admin/Documents/jfWorks/qiqi-server && DEBUG=api tsx /Users/admin/Documents/jfWorks/x/packages/x-server/src/cli/cli.ts api"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
+
"@aws-sdk/client-s3": "^3.1079.0",
|
|
25
|
+
"@aws-sdk/s3-request-presigner": "^3.1079.0",
|
|
24
26
|
"@fastify/compress": "^7.0.3",
|
|
25
27
|
"@fastify/cookie": "^9.4.0",
|
|
26
28
|
"@fastify/cors": "^8.3.0",
|
|
@@ -61,6 +63,7 @@
|
|
|
61
63
|
"jsonwebtoken": "^8.5.1",
|
|
62
64
|
"lru-cache": "^10.0.0",
|
|
63
65
|
"lz-string": "^1.4.4",
|
|
66
|
+
"mime": "^4.1.0",
|
|
64
67
|
"mini-svg-data-uri": "^1.4.4",
|
|
65
68
|
"node-ssh": "^13.1.0",
|
|
66
69
|
"nodemailer": "^6.7.3",
|