test
This commit is contained in:
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
@@ -23,6 +23,12 @@ importers:
|
|||||||
fast-glob:
|
fast-glob:
|
||||||
specifier: ^3.3.3
|
specifier: ^3.3.3
|
||||||
version: 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:
|
devDependencies:
|
||||||
'@kevisual/local-proxy':
|
'@kevisual/local-proxy':
|
||||||
specifier: ^0.0.6
|
specifier: ^0.0.6
|
||||||
@@ -2010,6 +2016,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
pocketbase@0.26.2:
|
||||||
|
resolution: {integrity: sha512-WA8EOBc3QnSJh8rJ3iYoi9DmmPOMFIgVfAmIGux7wwruUEIzXgvrO4u0W2htfQjGIcyezJkdZOy5Xmh7SxAftw==}
|
||||||
|
|
||||||
postcss@8.5.6:
|
postcss@8.5.6:
|
||||||
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
@@ -4837,6 +4846,8 @@ snapshots:
|
|||||||
|
|
||||||
picomatch@4.0.3: {}
|
picomatch@4.0.3: {}
|
||||||
|
|
||||||
|
pocketbase@0.26.2: {}
|
||||||
|
|
||||||
postcss@8.5.6:
|
postcss@8.5.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.11
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kevisual/noco": "^0.0.1",
|
"@kevisual/noco": "^0.0.1",
|
||||||
"@kevisual/router": "^0.0.29",
|
"@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 path from 'node:path'
|
||||||
import glob from 'fast-glob';
|
import glob from 'fast-glob';
|
||||||
import fs from 'node:fs'
|
import fs from 'node:fs'
|
||||||
|
import { codeRoot } from '@/modules/config.ts';
|
||||||
const list = async () => {
|
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 = {
|
type FileContent = {
|
||||||
path: string;
|
path: string;
|
||||||
content: string;
|
content: string;
|
||||||
@@ -12,7 +13,7 @@ const list = async () => {
|
|||||||
const filesContent: FileContent[] = [];
|
const filesContent: FileContent[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
if (file.startsWith('node_modules') || file.startsWith('dist') || file.startsWith('.git')) continue;
|
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');
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
||||||
if (content) {
|
if (content) {
|
||||||
filesContent.push({ path: file, content: content });
|
filesContent.push({ path: file, content: content });
|
||||||
@@ -20,9 +21,19 @@ const list = async () => {
|
|||||||
}
|
}
|
||||||
return filesContent;
|
return filesContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.route({
|
app.route({
|
||||||
path: 'file-code'
|
path: 'file-code'
|
||||||
}).define(async (ctx) => {
|
}).define(async (ctx) => {
|
||||||
const files = await list();
|
const files = await list();
|
||||||
ctx.body = files
|
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 './call/index.ts';
|
||||||
|
|
||||||
import './file-code/index.ts';
|
import './file-code/index.ts';
|
||||||
|
|
||||||
|
import './auth.ts'
|
||||||
Reference in New Issue
Block a user