@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.
@@ -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.116.0",
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",