init base app modules
This commit is contained in:
		
							
								
								
									
										68
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
node_modules
 | 
			
		||||
 | 
			
		||||
# mac
 | 
			
		||||
.DS_Store
 | 
			
		||||
 | 
			
		||||
.env*
 | 
			
		||||
!.env*example
 | 
			
		||||
 | 
			
		||||
dist
 | 
			
		||||
build
 | 
			
		||||
logs
 | 
			
		||||
 | 
			
		||||
.turbo
 | 
			
		||||
 | 
			
		||||
pack-dist
 | 
			
		||||
 | 
			
		||||
# astro
 | 
			
		||||
.astro
 | 
			
		||||
 | 
			
		||||
# next
 | 
			
		||||
.next
 | 
			
		||||
 | 
			
		||||
# nuxt
 | 
			
		||||
.nuxt
 | 
			
		||||
 | 
			
		||||
# vercel
 | 
			
		||||
.vercel
 | 
			
		||||
 | 
			
		||||
# vuepress
 | 
			
		||||
.vuepress/dist
 | 
			
		||||
 | 
			
		||||
# coverage
 | 
			
		||||
coverage/
 | 
			
		||||
 | 
			
		||||
# typescript
 | 
			
		||||
*.tsbuildinfo
 | 
			
		||||
 | 
			
		||||
# debug logs
 | 
			
		||||
*.log
 | 
			
		||||
*.tmp
 | 
			
		||||
 | 
			
		||||
# vscode
 | 
			
		||||
.vscode/*
 | 
			
		||||
!.vscode/settings.json
 | 
			
		||||
!.vscode/tasks.json
 | 
			
		||||
!.vscode/launch.json
 | 
			
		||||
!.vscode/extensions.json
 | 
			
		||||
 | 
			
		||||
# idea
 | 
			
		||||
.idea
 | 
			
		||||
 | 
			
		||||
# system
 | 
			
		||||
Thumbs.db
 | 
			
		||||
ehthumbs.db
 | 
			
		||||
Desktop.ini
 | 
			
		||||
 | 
			
		||||
# temp files
 | 
			
		||||
*.tmp
 | 
			
		||||
*.temp
 | 
			
		||||
 | 
			
		||||
# local development
 | 
			
		||||
*.local
 | 
			
		||||
 | 
			
		||||
public/r
 | 
			
		||||
 | 
			
		||||
.pnpm-store
 | 
			
		||||
 | 
			
		||||
storage/
 | 
			
		||||
							
								
								
									
										3
									
								
								.npmrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.npmrc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
 | 
			
		||||
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
 | 
			
		||||
ignore-workspace-root-check=true
 | 
			
		||||
							
								
								
									
										25
									
								
								apps/aliyun-ai/bun.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								apps/aliyun-ai/bun.config.mjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
// @ts-check
 | 
			
		||||
import { resolvePath } from '@kevisual/use-config/env';
 | 
			
		||||
import { execSync } from 'node:child_process';
 | 
			
		||||
 | 
			
		||||
const entry = 'src/index.ts';
 | 
			
		||||
const naming = 'app';
 | 
			
		||||
const external = ['sequelize', 'pg', 'sqlite3', 'minio', '@kevisual/router', 'pm2'];
 | 
			
		||||
/**
 | 
			
		||||
 * @type {import('bun').BuildConfig}
 | 
			
		||||
 */
 | 
			
		||||
await Bun.build({
 | 
			
		||||
  target: 'node',
 | 
			
		||||
  format: 'esm',
 | 
			
		||||
  entrypoints: [resolvePath(entry, { meta: import.meta })],
 | 
			
		||||
  outdir: resolvePath('./dist', { meta: import.meta }),
 | 
			
		||||
  naming: {
 | 
			
		||||
    entry: `${naming}.js`,
 | 
			
		||||
  },
 | 
			
		||||
  external: external,
 | 
			
		||||
  env: 'KEVISUAL_*',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// const cmd = `dts -i src/index.ts -o app.d.ts`;
 | 
			
		||||
// const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
 | 
			
		||||
// execSync(cmd, { stdio: 'inherit' });
 | 
			
		||||
							
								
								
									
										27
									
								
								apps/aliyun-ai/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								apps/aliyun-ai/package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "aliyun-ai",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "basename": "/root/aliyun-ai",
 | 
			
		||||
  "app": {
 | 
			
		||||
    "key": "aliyun-ai",
 | 
			
		||||
    "entry": "dist/app.js",
 | 
			
		||||
    "type": "system-app"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist"
 | 
			
		||||
  ],
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0  bun --watch src/dev.ts ",
 | 
			
		||||
    "build": "rimraf dist && bun run bun.config.mjs",
 | 
			
		||||
    "clean": "rm -rf dist",
 | 
			
		||||
    "pub": "npm run build && envision pack -p -u"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [],
 | 
			
		||||
  "author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "packageManager": "pnpm@10.12.1",
 | 
			
		||||
  "type": "module",
 | 
			
		||||
  "devDependencies": {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								apps/aliyun-ai/src/app.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								apps/aliyun-ai/src/app.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
import { app } from '@/modules/router.ts';
 | 
			
		||||
import { oss } from '@/modules/minio.ts';
 | 
			
		||||
import { config } from '@/modules/config.ts';
 | 
			
		||||
export { app, config, oss };
 | 
			
		||||
							
								
								
									
										6
									
								
								apps/aliyun-ai/src/dev.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/aliyun-ai/src/dev.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { app } from './index.ts';
 | 
			
		||||
 | 
			
		||||
app.listen(4000, () => {
 | 
			
		||||
  console.log('Server is running on http://localhost:4000');
 | 
			
		||||
  console.log('Press Ctrl+C to stop the server');
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										5
									
								
								apps/aliyun-ai/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								apps/aliyun-ai/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
import { app } from './app.ts';
 | 
			
		||||
 | 
			
		||||
import './routes/create-audio.ts';
 | 
			
		||||
 | 
			
		||||
export { app };
 | 
			
		||||
							
								
								
									
										75
									
								
								apps/aliyun-ai/src/routes/create-audio.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								apps/aliyun-ai/src/routes/create-audio.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
			
		||||
import { app, config, oss } from '../app.ts';
 | 
			
		||||
import { dashscopeTTS } from '@/examples/dash-scope/tts.ts';
 | 
			
		||||
import { randomLetter } from '@/utils/random.ts';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
type DashScopeTTSResponse = {
 | 
			
		||||
  output?: {
 | 
			
		||||
    finish_reason?: string;
 | 
			
		||||
    audio?: {
 | 
			
		||||
      expires_at?: number;
 | 
			
		||||
      data?: string;
 | 
			
		||||
      id?: string;
 | 
			
		||||
      url?: string;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  usage?: {
 | 
			
		||||
    input_tokens_details?: {
 | 
			
		||||
      text_tokens?: number;
 | 
			
		||||
    };
 | 
			
		||||
    total_tokens?: number;
 | 
			
		||||
    output_tokens?: number;
 | 
			
		||||
    input_tokens?: number;
 | 
			
		||||
    output_tokens_details?: {
 | 
			
		||||
      audio_tokens?: number;
 | 
			
		||||
      text_tokens?: number;
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  request_id?: string;
 | 
			
		||||
};
 | 
			
		||||
app
 | 
			
		||||
  .route({
 | 
			
		||||
    path: 'aliyun-ai',
 | 
			
		||||
    key: 'createVideos',
 | 
			
		||||
  })
 | 
			
		||||
  .define(async (ctx) => {
 | 
			
		||||
    const { text, model, save = 'none' } = ctx.query;
 | 
			
		||||
    if (!text) {
 | 
			
		||||
      ctx.throw(400, 'Text and model are required parameters');
 | 
			
		||||
    }
 | 
			
		||||
    const value: DashScopeTTSResponse = await dashscopeTTS({
 | 
			
		||||
      text,
 | 
			
		||||
      voice: model || 'Chelsie',
 | 
			
		||||
      token: config.BAILIAN_API_KEY,
 | 
			
		||||
    });
 | 
			
		||||
    const url = value?.output?.audio?.url;
 | 
			
		||||
    const fileName = `audio-${randomLetter(32)}.wav`;
 | 
			
		||||
    const username = 'share';
 | 
			
		||||
    const today = dayjs().format('YYYY-MM-DD');
 | 
			
		||||
    // 使用用户名和日期作为文件夹路径
 | 
			
		||||
    const filePath = `${username}/storage/aliyun-ai/audio/${today}/${fileName}`;
 | 
			
		||||
    if (url) {
 | 
			
		||||
      ctx.body = {
 | 
			
		||||
        audioUrl: url,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    if (save === 'minio' && url) {
 | 
			
		||||
      // 读取文件url地址的数据,并保存到 MinIO, 文件是 音频 wave 格式
 | 
			
		||||
      const audioData = await fetch(url).then((res) => res.arrayBuffer());
 | 
			
		||||
 | 
			
		||||
      // 将音频数据转换为 Buffer 并上传到 MinIO
 | 
			
		||||
      const buffer = Buffer.from(audioData);
 | 
			
		||||
      await oss.client.putObject(oss.bucketName, filePath, buffer, null, {
 | 
			
		||||
        'Content-Type': 'audio/wav',
 | 
			
		||||
        'app-source': 'aliyun-ai',
 | 
			
		||||
        share: 'public',
 | 
			
		||||
      });
 | 
			
		||||
      console.log('Audio file uploaded to MinIO:', filePath);
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      ctx.body.minio = filePath;
 | 
			
		||||
    }
 | 
			
		||||
    // 如果没有 url,抛出错误
 | 
			
		||||
    if (!url) {
 | 
			
		||||
      ctx.throw(500, 'Failed to create audio');
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
  .addTo(app);
 | 
			
		||||
							
								
								
									
										25
									
								
								bun.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								bun.config.mjs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
// @ts-check
 | 
			
		||||
import { resolvePath } from '@kevisual/use-config/env';
 | 
			
		||||
import { execSync } from 'node:child_process';
 | 
			
		||||
 | 
			
		||||
const entry = 'src/index.ts';
 | 
			
		||||
const naming = 'app';
 | 
			
		||||
const external = ['sequelize', 'pg', 'sqlite3', 'minio', '@kevisual/router', 'pm2'];
 | 
			
		||||
/**
 | 
			
		||||
 * @type {import('bun').BuildConfig}
 | 
			
		||||
 */
 | 
			
		||||
await Bun.build({
 | 
			
		||||
  target: 'node',
 | 
			
		||||
  format: 'esm',
 | 
			
		||||
  entrypoints: [resolvePath(entry, { meta: import.meta })],
 | 
			
		||||
  outdir: resolvePath('./dist', { meta: import.meta }),
 | 
			
		||||
  naming: {
 | 
			
		||||
    entry: `${naming}.js`,
 | 
			
		||||
  },
 | 
			
		||||
  external: external,
 | 
			
		||||
  env: 'KEVISUAL_*',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// const cmd = `dts -i src/index.ts -o app.d.ts`;
 | 
			
		||||
const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
 | 
			
		||||
execSync(cmd, { stdio: 'inherit' });
 | 
			
		||||
							
								
								
									
										66
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "ai-pages-services",
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "description": "",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "basename": "/root/ai-pages-services",
 | 
			
		||||
  "app": {
 | 
			
		||||
    "key": "ai-pages-services",
 | 
			
		||||
    "entry": "dist/app.js",
 | 
			
		||||
    "type": "system-app"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist"
 | 
			
		||||
  ],
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "cross-env NODE_TLS_REJECT_UNAUTHORIZED=0  bun --watch src/dev.ts ",
 | 
			
		||||
    "build": "rimraf dist && bun run bun.config.mjs",
 | 
			
		||||
    "test": "tsx  test/**/*.ts",
 | 
			
		||||
    "clean": "rm -rf dist",
 | 
			
		||||
    "pub": "npm run build && envision pack -p -u",
 | 
			
		||||
    "cmd": "tsx cmd/index.ts "
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [],
 | 
			
		||||
  "author": "abearxiong <xiongxiao@xiongxiao.me>",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "type": "module",
 | 
			
		||||
  "types": "types/index.d.ts",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@kevisual/code-center-module": "0.0.23",
 | 
			
		||||
    "@kevisual/router": "0.0.22",
 | 
			
		||||
    "@kevisual/use-config": "^1.0.18",
 | 
			
		||||
    "cookie": "^1.0.2",
 | 
			
		||||
    "dayjs": "^1.11.13",
 | 
			
		||||
    "formidable": "^3.5.4",
 | 
			
		||||
    "lodash-es": "^4.17.21"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@kevisual/context": "^0.0.3",
 | 
			
		||||
    "@kevisual/logger": "^0.0.4",
 | 
			
		||||
    "@kevisual/oss": "^0.0.12",
 | 
			
		||||
    "@kevisual/types": "^0.0.10",
 | 
			
		||||
    "@kevisual/use-config": "^1.0.19",
 | 
			
		||||
    "@types/bun": "^1.2.16",
 | 
			
		||||
    "@types/crypto-js": "^4.2.2",
 | 
			
		||||
    "@types/formidable": "^3.4.5",
 | 
			
		||||
    "@types/lodash-es": "^4.17.12",
 | 
			
		||||
    "@types/node": "^24.0.3",
 | 
			
		||||
    "commander": "^14.0.0",
 | 
			
		||||
    "concurrently": "^9.1.2",
 | 
			
		||||
    "cross-env": "^7.0.3",
 | 
			
		||||
    "inquire": "^0.4.8",
 | 
			
		||||
    "ioredis": "^5.6.1",
 | 
			
		||||
    "minio": "^8.0.5",
 | 
			
		||||
    "nanoid": "^5.1.5",
 | 
			
		||||
    "nodemon": "^3.1.10",
 | 
			
		||||
    "pg": "^8.16.1",
 | 
			
		||||
    "rimraf": "^6.0.1",
 | 
			
		||||
    "sequelize": "^6.37.7",
 | 
			
		||||
    "tape": "^5.9.0",
 | 
			
		||||
    "typescript": "^5.8.3"
 | 
			
		||||
  },
 | 
			
		||||
  "packageManager": "pnpm@10.12.1"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2789
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2789
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
packages:
 | 
			
		||||
  - 'apps/*'
 | 
			
		||||
							
								
								
									
										30
									
								
								src/examples/dash-scope/tts.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/examples/dash-scope/tts.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
// 使用DashScope API进行TTS (文本转语音) 请求
 | 
			
		||||
export const dashscopeTTS = async ({ text, voice = 'Chelsie', token }) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await fetch('https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation', {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization: `Bearer ${token}`,
 | 
			
		||||
        'Content-Type': 'application/json',
 | 
			
		||||
      },
 | 
			
		||||
      body: JSON.stringify({
 | 
			
		||||
        // model: 'qwen-tts',
 | 
			
		||||
        model: 'qwen-tts-latest',
 | 
			
		||||
        input: {
 | 
			
		||||
          text,
 | 
			
		||||
          voice,
 | 
			
		||||
        },
 | 
			
		||||
      }),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
      throw new Error(`HTTP error! Status: ${response.status}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const data = await response.json();
 | 
			
		||||
    return data;
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error('TTS 请求失败:', error);
 | 
			
		||||
    throw error;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										4
									
								
								src/modules/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/modules/config.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
import { useConfig } from '@kevisual/use-config';
 | 
			
		||||
 | 
			
		||||
export const config = useConfig();
 | 
			
		||||
export const isDev = config.ENV === 'development';
 | 
			
		||||
							
								
								
									
										6
									
								
								src/modules/logger.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/modules/logger.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { Logger } from '@kevisual/logger';
 | 
			
		||||
import { config } from './config.ts';
 | 
			
		||||
export const logger = new Logger({
 | 
			
		||||
  level: config.LOG_LEVEL || 'info',
 | 
			
		||||
  showTime: true,
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										41
									
								
								src/modules/minio.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/modules/minio.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
import { Client, ClientOptions } from 'minio';
 | 
			
		||||
import { config } from './config.ts';
 | 
			
		||||
import { OssBase } from '@kevisual/oss/services';
 | 
			
		||||
import { useContextKey } from '@kevisual/context';
 | 
			
		||||
const minioConfig = {
 | 
			
		||||
  endPoint: config.MINIO_ENDPOINT || 'localhost',
 | 
			
		||||
  port: parseInt(config.MINIO_PORT || '9000'),
 | 
			
		||||
  useSSL: config.MINIO_USE_SSL === 'true',
 | 
			
		||||
  accessKey: config.MINIO_ACCESS_KEY,
 | 
			
		||||
  secretKey: config.MINIO_SECRET_KEY,
 | 
			
		||||
};
 | 
			
		||||
export const minioClient = useContextKey('minioClient', () => {
 | 
			
		||||
  return new Client(minioConfig);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const bucketName = config.MINIO_BUCKET_NAME || 'resources';
 | 
			
		||||
if (!minioClient) {
 | 
			
		||||
  throw new Error('Minio client not initialized');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const check = () => {
 | 
			
		||||
  // 验证权限
 | 
			
		||||
  (async () => {
 | 
			
		||||
    const bucketExists = await minioClient.bucketExists(bucketName);
 | 
			
		||||
    if (!bucketExists) {
 | 
			
		||||
      await minioClient.makeBucket(bucketName);
 | 
			
		||||
    }
 | 
			
		||||
    console.log('bucketExists', bucketExists);
 | 
			
		||||
    // const res = await minioClient.putObject(bucketName, 'root/test/0.0.1/a.txt', 'test');
 | 
			
		||||
    // console.log('minio putObject', res);
 | 
			
		||||
  })();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const oss = useContextKey(
 | 
			
		||||
  'oss',
 | 
			
		||||
  new OssBase({
 | 
			
		||||
    client: minioClient,
 | 
			
		||||
    bucketName: bucketName,
 | 
			
		||||
    prefix: '',
 | 
			
		||||
  }),
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										3
									
								
								src/modules/notify.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/modules/notify.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
export const notify = () => {
 | 
			
		||||
  //
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										38
									
								
								src/modules/redis.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/modules/redis.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
import { Redis } from 'ioredis';
 | 
			
		||||
import { config } from './config.ts';
 | 
			
		||||
import { useContextKey } from '@kevisual/context';
 | 
			
		||||
 | 
			
		||||
const redisConfig = {
 | 
			
		||||
  host: config.REDIS_HOST || 'localhost',
 | 
			
		||||
  port: parseInt(config.REDIS_PORT || '6379'),
 | 
			
		||||
  password: config.REDIS_PASSWORD,
 | 
			
		||||
};
 | 
			
		||||
export const createRedisClient = (options = {}) => {
 | 
			
		||||
  const redisClient = new Redis({
 | 
			
		||||
    host: 'localhost', // Redis 服务器的主机名或 IP 地址
 | 
			
		||||
    port: 6379, // Redis 服务器的端口号
 | 
			
		||||
    // password: 'your_password', // Redis 的密码 (如果有)
 | 
			
		||||
    db: 0, // 要使用的 Redis 数据库索引 (0-15)
 | 
			
		||||
    keyPrefix: '', // key 前缀
 | 
			
		||||
    retryStrategy(times) {
 | 
			
		||||
      // 连接重试策略
 | 
			
		||||
      return Math.min(times * 50, 2000); // 每次重试时延迟增加
 | 
			
		||||
    },
 | 
			
		||||
    maxRetriesPerRequest: null, // 允许请求重试的次数 (如果需要无限次重试)
 | 
			
		||||
    ...redisConfig,
 | 
			
		||||
    ...options,
 | 
			
		||||
  });
 | 
			
		||||
  redisClient.on('connect', () => {
 | 
			
		||||
    console.log('Redis client connected successfully');
 | 
			
		||||
  });
 | 
			
		||||
  redisClient.on('error', (err) => {
 | 
			
		||||
    console.error('Redis client error:', err);
 | 
			
		||||
  });
 | 
			
		||||
  return redisClient;
 | 
			
		||||
};
 | 
			
		||||
// 配置 Redis 连接
 | 
			
		||||
export const redis = useContextKey('redis', () => createRedisClient());
 | 
			
		||||
 | 
			
		||||
// 初始化 Redis 客户端
 | 
			
		||||
// export const redisPublisher = createRedisClient(); // 用于发布消息
 | 
			
		||||
// export const redisSubscriber = createRedisClient(); // 用于订阅消息
 | 
			
		||||
							
								
								
									
										6
									
								
								src/modules/router.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/modules/router.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
import { App } from '@kevisual/router';
 | 
			
		||||
import { useContextKey } from '@kevisual/context';
 | 
			
		||||
const init = () => {
 | 
			
		||||
  return new App();
 | 
			
		||||
};
 | 
			
		||||
export const app = useContextKey('app', init);
 | 
			
		||||
							
								
								
									
										34
									
								
								src/modules/sequelize.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/modules/sequelize.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
import { Sequelize } from 'sequelize';
 | 
			
		||||
import { config } from './config.ts';
 | 
			
		||||
import { useContextKey } from '@kevisual/context';
 | 
			
		||||
 | 
			
		||||
export type PostgresConfig = {
 | 
			
		||||
  postgres: {
 | 
			
		||||
    username: string;
 | 
			
		||||
    password: string;
 | 
			
		||||
    host: string;
 | 
			
		||||
    port: number;
 | 
			
		||||
    database: string;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
if (!config.POSTGRES_PASSWORD || !config.POSTGRES_USER) {
 | 
			
		||||
  console.error('postgres config is required password and user');
 | 
			
		||||
  process.exit(1);
 | 
			
		||||
}
 | 
			
		||||
const postgresConfig = {
 | 
			
		||||
  username: config.POSTGRES_USER,
 | 
			
		||||
  password: config.POSTGRES_PASSWORD,
 | 
			
		||||
  host: config.POSTGRES_HOST || 'localhost',
 | 
			
		||||
  port: parseInt(config.POSTGRES_PORT || '5432'),
 | 
			
		||||
  database: config.POSTGRES_DB || 'postgres',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const init = async () => {
 | 
			
		||||
  return new Sequelize({
 | 
			
		||||
    dialect: 'postgres',
 | 
			
		||||
    ...postgresConfig,
 | 
			
		||||
    // logging: false,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const sequelize = useContextKey('sequelize', () => init());
 | 
			
		||||
							
								
								
									
										9
									
								
								src/modules/user.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/modules/user.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
import { sequelize, User, UserInit, Org, OrgInit } from '@kevisual/code-center-module';
 | 
			
		||||
 | 
			
		||||
export { sequelize, User, UserInit, Org, OrgInit };
 | 
			
		||||
 | 
			
		||||
export const init = () => {
 | 
			
		||||
  UserInit();
 | 
			
		||||
  OrgInit();
 | 
			
		||||
};
 | 
			
		||||
init();
 | 
			
		||||
							
								
								
									
										26
									
								
								src/utils/random.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/utils/random.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
import { customAlphabet } from 'nanoid';
 | 
			
		||||
 | 
			
		||||
export const letter = 'abcdefghijklmnopqrstuvwxyz';
 | 
			
		||||
export const number = '0123456789';
 | 
			
		||||
const alphanumeric = `${letter}${number}`;
 | 
			
		||||
export const alphanumericWithDash = `${alphanumeric}-`;
 | 
			
		||||
export const uuid = customAlphabet(letter);
 | 
			
		||||
 | 
			
		||||
export const nanoid = customAlphabet(alphanumeric, 10);
 | 
			
		||||
 | 
			
		||||
export const nanoidWithDash = customAlphabet(alphanumericWithDash, 10);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 创建一个随机的 id,以字母开头的字符串
 | 
			
		||||
 * @param number
 | 
			
		||||
 * @returns
 | 
			
		||||
 */
 | 
			
		||||
export const randomId = (number: number) => {
 | 
			
		||||
  const _letter = uuid(1);
 | 
			
		||||
  return `${_letter}${nanoid(number)}`;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const randomLetter = (number: number = 8, opts?: { before?: string; after?: string }) => {
 | 
			
		||||
  const { before = '', after = '' } = opts || {};
 | 
			
		||||
  return `${before}${uuid(number)}${after}`;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										19
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "@kevisual/types/json/backend.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "baseUrl": ".",
 | 
			
		||||
    "typeRoots": [
 | 
			
		||||
      "./node_modules/@types",
 | 
			
		||||
      "./node_modules/@kevisual"
 | 
			
		||||
    ],
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "@/*": [
 | 
			
		||||
        "src/*"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  "include": [
 | 
			
		||||
    "src/**/*",
 | 
			
		||||
    "apps/**/*",
 | 
			
		||||
  ],
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user