This commit is contained in:
2025-10-18 03:43:58 +08:00
parent da0ebde816
commit d3174a73f3
12 changed files with 210 additions and 6 deletions

View File

@@ -23,6 +23,8 @@
"dependencies": {
"@kevisual/noco": "^0.0.1",
"@kevisual/router": "^0.0.29",
"fast-glob": "^3.3.3"
"fast-glob": "^3.3.3",
"pocketbase": "^0.26.2",
"unstorage": "^1.17.1"
}
}

23
server/src/cache/index.ts vendored Normal file
View File

@@ -0,0 +1,23 @@
import { createStorage } from 'unstorage'
import fsLiteDriver from "unstorage/drivers/fs-lite";
import { codeRoot } from '@/modules/config.ts';
import memoryDriver from "unstorage/drivers/memory";
export const storage = createStorage({
// @ts-ignore
driver: memoryDriver(),
});
export const codeStorage = createStorage({
// @ts-ignore
driver: fsLiteDriver({
base: './code'
})
})
// storage.setItem('test-ke/test-key.json', 'test-value');
// console.log('Cache test-key:', await storage.getItem('test-key'));
storage.setItem('root/light-code-demo/main.ts', 'test-value2');
console.log('Cache test-key:', await storage.getItem('root/light-code-demo/main.ts'));
console.log('has', await codeStorage.hasItem('root/light-code-demo/main.ts'));

View File

@@ -0,0 +1,52 @@
import { Field } from '../types/index.ts';
export const projectStatus = ['提交', '审核中', '审核通过']; // 提交,审核中,审核通过
export type projectStatus = typeof projectStatus[number];
export const projectFields: Field[] = [
{
name: 'title',
type: 'text',
},
{
name: 'description',
type: 'text',
},
{
name: 'status',
type: 'text'
},
{
name: 'key',
type: 'text',
},
{
name: 'owner',
type: 'text',
},
{
name: 'data',
type: 'json'
},
{
name: 'files',
type: 'json'
},
{
name: "createdAt",
onCreate: true,
onUpdate: false,
type: "autodate"
},
{
name: "updatedAt",
onCreate: true,
onUpdate: true,
type: "autodate"
},
];
export const name = 'xx_projects';
export const type = 'base';

37
server/src/db/init.ts Normal file
View File

@@ -0,0 +1,37 @@
import { pb, db } from '../modules/db.ts'
import * as projects from './collections/project.ts'
// 要求
// 1. collection只做新增不做修改
// 2. collection不存在就创建
// 3. 每一个collection的定义在文档中需要有
export const main = async () => {
try {
await db.ensureLogin().catch(() => { throw new Error('Login failed'); });
// 程序第一次运行的时候执行,如果已经初始化过则跳过
const collections = await db.pb.collections.getFullList({
filter: 'name ~ "xx_%"',
})
console.log('Existing collections:', collections.map(c => c.name));
const dbs = [projects]
for (const coll of dbs) {
const exists = collections.find(c => c.name === coll.name)
if (exists) {
console.log(`Collection ${coll.name} already exists, skipping creation.`);
continue;
}
// 第一步,获取那个叉叉开头的 Collection。第二步获取它的版本。
const createdCollection = await db.pb.collections.create({
name: coll.name,
type: coll?.type || 'base',
fields: coll?.projectFields,
})
console.log('Created collection:', createdCollection);
}
} catch (error) {
console.error('Error during DB initialization:', error);
}
}
main()

View File

@@ -0,0 +1,26 @@
export type Field = {
/**
* The unique identifier for the field
*/
id?: string;
/**
* The name of the field
*/
name: string;
type?: 'text' | 'json' | 'autodate' | 'boolean' | 'number' | 'email' | 'url' | 'file' | 'relation';
/**
* Indicates whether the field is required
*/
required?: boolean;
/**
* Only for 'autodate' type
* Indicates whether to set the date on record creation or update
*/
onCreate?: boolean;
/** Only for 'autodate' type
* Indicates whether to set the date on record update
*/
onUpdate?: boolean;
options?: Record<string, any>;
[key: string]: any;
}

View File

@@ -0,0 +1 @@
export * from './collection.ts';

View File

@@ -0,0 +1,7 @@
import { useConfig } from '@kevisual/use-config'
import path from 'path';
export const config = useConfig()
export const codeRoot = path.join(process.cwd(), 'code');

24
server/src/modules/db.ts Normal file
View File

@@ -0,0 +1,24 @@
import PocketBase from 'pocketbase';
const POCKETBASE_URL = 'https://pocketbase.pro.xiongxiao.me/';
export const pb = new PocketBase(POCKETBASE_URL);
export class DB {
pb: PocketBase
constructor(pb: PocketBase) {
this.pb = pb
}
async ensureLogin() {
const pb = this.pb;
if (!pb.authStore.isValid) {
await pb.collection("_superusers").authWithPassword('xiongxiao@xiongxiao.me', '123456xx');
}
return pb.authStore.record;
}
async getCollection(name: string) {
await this.ensureLogin();
return this.pb.collection(name);
}
}
export const db = new DB(pb);

View File

@@ -0,0 +1,8 @@
import { app } from '../app.ts'
app.route({
path: 'auth',
id: 'auth'
}).define(async (ctx) => {
// Authentication logic here
}).addTo(app);

View File

@@ -2,9 +2,10 @@ import { app } from '@/app.ts';
import path from 'node:path'
import glob from 'fast-glob';
import fs from 'node:fs'
import { codeRoot } from '@/modules/config.ts';
const list = async () => {
const root = path.join(process.cwd(), 'code');
const files = await glob('**/*.ts', { cwd: root });
const files = await glob('**/*.ts', { cwd: codeRoot });
type FileContent = {
path: string;
content: string;
@@ -12,7 +13,7 @@ const list = async () => {
const filesContent: FileContent[] = [];
for (const file of files) {
if (file.startsWith('node_modules') || file.startsWith('dist') || file.startsWith('.git')) continue;
const fullPath = path.join(root, file);
const fullPath = path.join(codeRoot, file);
const content = fs.readFileSync(fullPath, 'utf-8');
if (content) {
filesContent.push({ path: file, content: content });
@@ -20,9 +21,19 @@ const list = async () => {
}
return filesContent;
}
app.route({
path: 'file-code'
}).define(async (ctx) => {
const files = await list();
ctx.body = files
}).addTo(app);
}).addTo(app);
app.route({
path: 'file-code',
key: 'upload',
middleware: ['auth']
}).define(async (ctx) => {
}).addTo(app)

View File

@@ -1,3 +1,5 @@
import './call/index.ts';
import './file-code/index.ts';
import './file-code/index.ts';
import './auth.ts'