test
This commit is contained in:
@@ -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
23
server/src/cache/index.ts
vendored
Normal 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'));
|
||||
52
server/src/db/collections/project.ts
Normal file
52
server/src/db/collections/project.ts
Normal 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
37
server/src/db/init.ts
Normal 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()
|
||||
26
server/src/db/types/collection.ts
Normal file
26
server/src/db/types/collection.ts
Normal 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;
|
||||
}
|
||||
1
server/src/db/types/index.ts
Normal file
1
server/src/db/types/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './collection.ts';
|
||||
7
server/src/modules/config.ts
Normal file
7
server/src/modules/config.ts
Normal 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
24
server/src/modules/db.ts
Normal 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);
|
||||
8
server/src/routes/auth.ts
Normal file
8
server/src/routes/auth.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { app } from '../app.ts'
|
||||
|
||||
app.route({
|
||||
path: 'auth',
|
||||
id: 'auth'
|
||||
}).define(async (ctx) => {
|
||||
// Authentication logic here
|
||||
}).addTo(app);
|
||||
@@ -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)
|
||||
@@ -1,3 +1,5 @@
|
||||
import './call/index.ts';
|
||||
|
||||
import './file-code/index.ts';
|
||||
import './file-code/index.ts';
|
||||
|
||||
import './auth.ts'
|
||||
Reference in New Issue
Block a user