diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a484ce9..0fd4539 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,12 @@ importers: fast-glob: specifier: ^3.3.3 version: 3.3.3 + pocketbase: + specifier: ^0.26.2 + version: 0.26.2 + unstorage: + specifier: ^1.17.1 + version: 1.17.1(idb-keyval@6.2.2) devDependencies: '@kevisual/local-proxy': specifier: ^0.0.6 @@ -2010,6 +2016,9 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pocketbase@0.26.2: + resolution: {integrity: sha512-WA8EOBc3QnSJh8rJ3iYoi9DmmPOMFIgVfAmIGux7wwruUEIzXgvrO4u0W2htfQjGIcyezJkdZOy5Xmh7SxAftw==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -4837,6 +4846,8 @@ snapshots: picomatch@4.0.3: {} + pocketbase@0.26.2: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 diff --git a/server/package.json b/server/package.json index abc6c5c..0086636 100644 --- a/server/package.json +++ b/server/package.json @@ -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" } } \ No newline at end of file diff --git a/server/src/cache/index.ts b/server/src/cache/index.ts new file mode 100644 index 0000000..319eee4 --- /dev/null +++ b/server/src/cache/index.ts @@ -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')); diff --git a/server/src/db/collections/project.ts b/server/src/db/collections/project.ts new file mode 100644 index 0000000..b4ae1d5 --- /dev/null +++ b/server/src/db/collections/project.ts @@ -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'; \ No newline at end of file diff --git a/server/src/db/init.ts b/server/src/db/init.ts new file mode 100644 index 0000000..cbc206a --- /dev/null +++ b/server/src/db/init.ts @@ -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() diff --git a/server/src/db/types/collection.ts b/server/src/db/types/collection.ts new file mode 100644 index 0000000..742c047 --- /dev/null +++ b/server/src/db/types/collection.ts @@ -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; + [key: string]: any; +} \ No newline at end of file diff --git a/server/src/db/types/index.ts b/server/src/db/types/index.ts new file mode 100644 index 0000000..df8b40f --- /dev/null +++ b/server/src/db/types/index.ts @@ -0,0 +1 @@ +export * from './collection.ts'; \ No newline at end of file diff --git a/server/src/modules/config.ts b/server/src/modules/config.ts new file mode 100644 index 0000000..d9633e5 --- /dev/null +++ b/server/src/modules/config.ts @@ -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'); \ No newline at end of file diff --git a/server/src/modules/db.ts b/server/src/modules/db.ts new file mode 100644 index 0000000..ddb496a --- /dev/null +++ b/server/src/modules/db.ts @@ -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); \ No newline at end of file diff --git a/server/src/routes/auth.ts b/server/src/routes/auth.ts new file mode 100644 index 0000000..ec1f2fb --- /dev/null +++ b/server/src/routes/auth.ts @@ -0,0 +1,8 @@ +import { app } from '../app.ts' + +app.route({ + path: 'auth', + id: 'auth' +}).define(async (ctx) => { + // Authentication logic here +}).addTo(app); \ No newline at end of file diff --git a/server/src/routes/file-code/index.ts b/server/src/routes/file-code/index.ts index 148a986..e19a987 100644 --- a/server/src/routes/file-code/index.ts +++ b/server/src/routes/file-code/index.ts @@ -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); \ No newline at end of file +}).addTo(app); + + +app.route({ + path: 'file-code', + key: 'upload', + middleware: ['auth'] +}).define(async (ctx) => { + +}).addTo(app) \ No newline at end of file diff --git a/server/src/routes/index.ts b/server/src/routes/index.ts index 7f2bae5..7f00dd1 100644 --- a/server/src/routes/index.ts +++ b/server/src/routes/index.ts @@ -1,3 +1,5 @@ import './call/index.ts'; -import './file-code/index.ts'; \ No newline at end of file +import './file-code/index.ts'; + +import './auth.ts' \ No newline at end of file