feat: project list

This commit is contained in:
2025-09-06 01:44:33 +08:00
parent ef473d6084
commit 9b54d18ef3
11 changed files with 333 additions and 56 deletions

View File

@@ -20,7 +20,7 @@ export class AuthController {
if (!ctx.session.isNew) { if (!ctx.session.isNew) {
return ctx.session.user; return ctx.session.user;
} }
const { code } = (ctx.request as any).body; const { code } = ctx.request.body as LoginRequestBody;
const { access_token } = await gitea.getToken(code); const { access_token } = await gitea.getToken(code);
const giteaUser = await gitea.getUserInfo(access_token); const giteaUser = await gitea.getUserInfo(access_token);
log.debug(this.TAG, 'gitea user: %o', giteaUser); log.debug(this.TAG, 'gitea user: %o', giteaUser);
@@ -64,3 +64,7 @@ export class AuthController {
return ctx.session.user; return ctx.session.user;
} }
} }
interface LoginRequestBody {
code: string;
}

View File

@@ -4,8 +4,8 @@ import { log } from '../libs/logger.ts';
import { BusinessError } from '../middlewares/exception.ts'; import { BusinessError } from '../middlewares/exception.ts';
import { Controller, Get } from '../decorators/route.ts'; import { Controller, Get } from '../decorators/route.ts';
@Controller('/application') @Controller('/project')
export class ApplicationController { export class ProjectController {
@Get('/list') @Get('/list')
async list(ctx: Context) { async list(ctx: Context) {
log.debug('app', 'session %o', ctx.session); log.debug('app', 'session %o', ctx.session);

View File

@@ -1,3 +1,4 @@
import bodyParser from 'koa-bodyparser';
import type Koa from 'koa'; import type Koa from 'koa';
import type { Middleware } from './types.ts'; import type { Middleware } from './types.ts';
@@ -6,41 +7,6 @@ import type { Middleware } from './types.ts';
*/ */
export class BodyParser implements Middleware { export class BodyParser implements Middleware {
apply(app: Koa): void { apply(app: Koa): void {
// 使用动态导入来避免类型问题 app.use(bodyParser());
app.use(async (ctx, next) => {
if (ctx.request.method === 'POST' ||
ctx.request.method === 'PUT' ||
ctx.request.method === 'PATCH') {
// 简单的JSON解析
if (ctx.request.type === 'application/json') {
try {
const chunks: Buffer[] = [];
ctx.req.on('data', (chunk) => {
chunks.push(chunk);
});
await new Promise((resolve) => {
ctx.req.on('end', () => {
const body = Buffer.concat(chunks).toString();
try {
(ctx.request as any).body = JSON.parse(body);
} catch {
(ctx.request as any).body = {};
}
resolve(void 0);
});
});
} catch (error) {
(ctx.request as any).body = {};
}
} else {
(ctx.request as any).body = {};
}
}
await next();
});
} }
} }

View File

@@ -2,7 +2,7 @@ import KoaRouter from '@koa/router';
import type Koa from 'koa'; import type Koa from 'koa';
import type { Middleware } from './types.ts'; import type { Middleware } from './types.ts';
import { RouteScanner } from '../libs/route-scanner.ts'; import { RouteScanner } from '../libs/route-scanner.ts';
import { ApplicationController } from '../controllers/application.ts'; import { ProjectController } from '../controllers/project.ts';
import { UserController } from '../controllers/user.ts'; import { UserController } from '../controllers/user.ts';
import { AuthController } from '../controllers/auth.ts'; import { AuthController } from '../controllers/auth.ts';
import { log } from '../libs/logger.ts'; import { log } from '../libs/logger.ts';
@@ -33,7 +33,7 @@ export class Router implements Middleware {
private registerDecoratorRoutes(): void { private registerDecoratorRoutes(): void {
// 注册所有使用装饰器的控制器 // 注册所有使用装饰器的控制器
this.routeScanner.registerControllers([ this.routeScanner.registerControllers([
ApplicationController, ProjectController,
UserController, UserController,
AuthController, AuthController,
]); ]);

View File

@@ -14,6 +14,7 @@
"@koa/router": "^14.0.0", "@koa/router": "^14.0.0",
"@prisma/client": "^6.15.0", "@prisma/client": "^6.15.0",
"koa": "^3.0.1", "koa": "^3.0.1",
"koa-bodyparser": "^4.4.1",
"koa-session": "^7.0.2", "koa-session": "^7.0.2",
"pino": "^9.9.1", "pino": "^9.9.1",
"pino-pretty": "^13.1.1" "pino-pretty": "^13.1.1"
@@ -22,6 +23,7 @@
"@tsconfig/node-ts": "^23.6.1", "@tsconfig/node-ts": "^23.6.1",
"@tsconfig/node22": "^22.0.2", "@tsconfig/node22": "^22.0.2",
"@types/koa": "^3.0.0", "@types/koa": "^3.0.0",
"@types/koa-bodyparser": "^4.3.12",
"@types/koa__cors": "^5.0.0", "@types/koa__cors": "^5.0.0",
"@types/koa__router": "^12.0.4", "@types/koa__router": "^12.0.4",
"@types/node": "^24.3.0", "@types/node": "^24.3.0",

View File

@@ -0,0 +1,10 @@
import React, { useEffect } from 'react';
export function useAsyncEffect(
effect: () => Promise<void>,
deps: React.DependencyList,
) {
useEffect(() => {
effect();
}, [...deps]);
}

View File

@@ -1,12 +1,9 @@
import { Avatar, Layout, Menu } from '@arco-design/web-react'; import { Avatar, Layout, Menu } from '@arco-design/web-react';
import { import {
IconApps, IconApps,
IconBulb,
IconFire,
IconMenuFold, IconMenuFold,
IconMenuUnfold, IconMenuUnfold,
IconRobot, IconRobot,
IconSafe,
IconUser, IconUser,
} from '@arco-design/web-react/icon'; } from '@arco-design/web-react/icon';
import { useState } from 'react'; import { useState } from 'react';
@@ -21,9 +18,15 @@ function Home() {
<Layout.Sider <Layout.Sider
collapsible collapsible
onCollapse={setCollapsed} onCollapse={setCollapsed}
trigger={collapsed ? <IconMenuUnfold /> : <IconMenuFold />} trigger={
collapsed ? (
<IconMenuUnfold fontSize={16} />
) : (
<IconMenuFold fontSize={16} />
)
}
> >
<div className="flex flex-row items-center justify-center px-2 py-3"> <div className="flex flex-row items-center justify-center h-[56px]">
<Logo /> <Logo />
{!collapsed && <h2 className="ml-4 text-xl font-medium">Foka CI</h2>} {!collapsed && <h2 className="ml-4 text-xl font-medium">Foka CI</h2>}
</div> </div>
@@ -31,16 +34,17 @@ function Home() {
className="flex-1" className="flex-1"
defaultOpenKeys={['0']} defaultOpenKeys={['0']}
defaultSelectedKeys={['0_1']} defaultSelectedKeys={['0_1']}
collapse={collapsed}
> >
<Menu.Item key="0"> <Menu.Item key="0">
<Link to="/project" className="flex flex-row items-center"> <Link to="/project">
<IconApps fontSize={18} /> <IconApps fontSize={16} />
<span></span>
</Link> </Link>
</Menu.Item> </Menu.Item>
<Menu.Item key="1"> <Menu.Item key="1">
<Link to="/env" className="flex flex-row items-center"> <Link to="/env">
<IconRobot fontSize={18} /> <IconRobot fontSize={16} />
</Link> </Link>
</Menu.Item> </Menu.Item>

View File

@@ -1,8 +1,114 @@
import { Card, Grid, Link, Tag, Avatar, Space, Typography, Button } from '@arco-design/web-react';
import { IconBranch, IconCalendar, IconEye } from '@arco-design/web-react/icon';
import { useState } from 'react'; import { useState } from 'react';
import type { Project } from './types';
import { useAsyncEffect } from '../../hooks/useAsyncEffect';
import { projectService } from './service';
import IconGitea from '@assets/images/gitea.svg?react'
function Project() { const { Text, Paragraph } = Typography;
const [projects, setProjects] = useState([]);
return <div>project page</div>; function ProjectPage() {
const [projects, setProjects] = useState<Project[]>([]);
useAsyncEffect(async () => {
const list = await projectService.list();
setProjects(list);
}, []);
return (
<div className="p-6 bg-gray-100 min-h-screen">
<div className="mb-6">
<Typography.Title heading={2} className="!m-0 !text-gray-900">
</Typography.Title>
<Text type="secondary"></Text>
</div>
<Grid.Row gutter={[16, 16]}>
{projects.map((project) => (
<Grid.Col key={project.id} span={8}>
<Card
className="foka-card !rounded-xl border border-gray-200 h-[280px] hover:border-blue-200"
hoverable
bodyStyle={{ padding: '20px' }}
>
{/* 项目头部 */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<Avatar
size={40}
className="bg-blue-600 text-white text-base font-semibold"
>
{project.name.charAt(0).toUpperCase()}
</Avatar>
<div className="ml-3">
<Typography.Title
heading={5}
className="!m-0 !text-base !font-semibold"
>
{project.name}
</Typography.Title>
<Text type="secondary" className="text-xs">
2
</Text>
</div>
</div>
<Tag color="blue" size="small">
</Tag>
</div>
{/* 项目描述 */}
<Paragraph
className="!m-0 !mb-4 !text-gray-600 !text-sm !leading-6 h-[42px] overflow-hidden line-clamp-2"
>
{project.description || '暂无描述'}
</Paragraph>
{/* 项目信息 */}
<div className="mb-4">
<div className="mb-2 flex items-center">
<IconGitea className="mr-1.5 w-4" />
<Text
type="secondary"
className="text-xs"
>
{project.repository}
</Text>
</div>
<Space size={16}>
<div className="flex items-center">
<IconBranch className="mr-1 text-gray-500 text-xs" />
<Text className="text-xs text-gray-500">main</Text>
</div>
<div className="flex items-center">
<IconCalendar className="mr-1 text-gray-500 text-xs" />
<Text className="text-xs text-gray-500">3</Text>
</div>
</Space>
</div>
{/* 操作按钮 */}
<div className="flex items-center justify-between pt-3 border-t border-gray-100">
<Button
type="text"
size="small"
icon={<IconEye />}
className="text-gray-500"
>
</Button>
<Link className="text-xs font-medium">
</Link>
</div>
</Card>
</Grid.Col>
))}
</Grid.Row>
</div>
);
} }
export default Project; export default ProjectPage;

View File

@@ -0,0 +1,16 @@
import { net, type APIResponse } from "@shared";
import type { Project } from "./types";
class ProjectService {
async list() {
const { data } = await net.request<APIResponse<Project[]>>({
method: 'GET',
url: '/api/project/list',
})
return data;
}
}
export const projectService = new ProjectService();

View File

@@ -8,7 +8,7 @@ export interface Project {
id: string; id: string;
name: string; name: string;
description: string; description: string;
git: string; repository: string;
env: Record<string, string>; env: Record<string, string>;
createdAt: string; createdAt: string;
status: BuildStatus; status: BuildStatus;

169
pnpm-lock.yaml generated
View File

@@ -26,6 +26,9 @@ importers:
koa: koa:
specifier: ^3.0.1 specifier: ^3.0.1
version: 3.0.1 version: 3.0.1
koa-bodyparser:
specifier: ^4.4.1
version: 4.4.1
koa-session: koa-session:
specifier: ^7.0.2 specifier: ^7.0.2
version: 7.0.2 version: 7.0.2
@@ -45,6 +48,9 @@ importers:
'@types/koa': '@types/koa':
specifier: ^3.0.0 specifier: ^3.0.0
version: 3.0.0 version: 3.0.0
'@types/koa-bodyparser':
specifier: ^4.3.12
version: 4.3.12
'@types/koa__cors': '@types/koa__cors':
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0 version: 5.0.0
@@ -426,6 +432,9 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@hapi/bourne@3.0.0':
resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
'@isaacs/fs-minipass@4.0.1': '@isaacs/fs-minipass@4.0.1':
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
@@ -810,6 +819,9 @@ packages:
'@types/keygrip@1.0.6': '@types/keygrip@1.0.6':
resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
'@types/koa-bodyparser@4.3.12':
resolution: {integrity: sha512-hKMmRMVP889gPIdLZmmtou/BijaU1tHPyMNmcK7FAHAdATnRcGQQy78EqTTxLH1D4FTsrxIzklAQCso9oGoebQ==}
'@types/koa-compose@3.2.8': '@types/koa-compose@3.2.8':
resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==} resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
@@ -891,6 +903,10 @@ packages:
buffer@5.7.1: buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
c12@3.1.0: c12@3.1.0:
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==} resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
peerDependencies: peerDependencies:
@@ -903,6 +919,10 @@ packages:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
call-bound@1.0.4:
resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
engines: {node: '>= 0.4'}
callsites@3.1.0: callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@@ -925,6 +945,10 @@ packages:
citty@0.1.6: citty@0.1.6:
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
co-body@6.2.0:
resolution: {integrity: sha512-Kbpv2Yd1NdL1V/V4cwLVxraHDV6K8ayohr2rmH0J87Er8+zJjcTa6dAn9QMPC9CRgU8+aNajKbSf1TzDB1yKPA==}
engines: {node: '>=8.0.0'}
color-convert@1.9.3: color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@@ -980,6 +1004,9 @@ packages:
resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
copy-to@2.0.1:
resolution: {integrity: sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==}
core-js@3.45.1: core-js@3.45.1:
resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==} resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==}
@@ -1266,6 +1293,10 @@ packages:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
ieee754@1.2.1: ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@@ -1273,6 +1304,10 @@ packages:
resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
inflation@2.1.0:
resolution: {integrity: sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==}
engines: {node: '>= 0.8.0'}
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -1317,6 +1352,10 @@ packages:
resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
koa-bodyparser@4.4.1:
resolution: {integrity: sha512-kBH3IYPMb+iAXnrxIhXnW+gXV8OTzCu8VPDqvcDHW9SQrbkHmqPQtiZwrltNmSq6/lpipHnT7k7PsjlVD7kK0w==}
engines: {node: '>=8.0.0'}
koa-compose@4.1.0: koa-compose@4.1.0:
resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==} resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==}
@@ -1425,6 +1464,10 @@ packages:
mdn-data@2.0.30: mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'}
media-typer@1.1.0: media-typer@1.1.0:
resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -1501,6 +1544,10 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'}
ohash@2.0.11: ohash@2.0.11:
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
@@ -1590,9 +1637,17 @@ packages:
pure-rand@6.1.0: pure-rand@6.1.0:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
qs@6.14.0:
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
engines: {node: '>=0.6'}
quick-format-unescaped@4.0.4: quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
raw-body@2.5.2:
resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}
engines: {node: '>= 0.8'}
rc9@2.1.2: rc9@2.1.2:
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
@@ -1673,6 +1728,9 @@ packages:
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
engines: {node: '>=10'} engines: {node: '>=10'}
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
scheduler@0.23.2: scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
@@ -1695,6 +1753,22 @@ packages:
shallowequal@1.1.0: shallowequal@1.1.0:
resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
side-channel-list@1.0.0:
resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
engines: {node: '>= 0.4'}
side-channel-map@1.0.1:
resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
engines: {node: '>= 0.4'}
side-channel-weakmap@1.0.2:
resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
engines: {node: '>= 0.4'}
side-channel@1.1.0:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
simple-swizzle@0.2.2: simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
@@ -1772,6 +1846,10 @@ packages:
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
hasBin: true hasBin: true
type-is@1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
type-is@2.0.1: type-is@2.0.1:
resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -1784,6 +1862,10 @@ packages:
undici-types@7.10.0: undici-types@7.10.0:
resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
update-browserslist-db@1.1.3: update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true hasBin: true
@@ -2097,6 +2179,8 @@ snapshots:
'@esbuild/win32-x64@0.25.9': '@esbuild/win32-x64@0.25.9':
optional: true optional: true
'@hapi/bourne@3.0.0': {}
'@isaacs/fs-minipass@4.0.1': '@isaacs/fs-minipass@4.0.1':
dependencies: dependencies:
minipass: 7.1.2 minipass: 7.1.2
@@ -2506,6 +2590,10 @@ snapshots:
'@types/keygrip@1.0.6': {} '@types/keygrip@1.0.6': {}
'@types/koa-bodyparser@4.3.12':
dependencies:
'@types/koa': 3.0.0
'@types/koa-compose@3.2.8': '@types/koa-compose@3.2.8':
dependencies: dependencies:
'@types/koa': 3.0.0 '@types/koa': 3.0.0
@@ -2603,6 +2691,8 @@ snapshots:
base64-js: 1.5.1 base64-js: 1.5.1
ieee754: 1.2.1 ieee754: 1.2.1
bytes@3.1.2: {}
c12@3.1.0: c12@3.1.0:
dependencies: dependencies:
chokidar: 4.0.3 chokidar: 4.0.3
@@ -2623,6 +2713,11 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
function-bind: 1.1.2 function-bind: 1.1.2
call-bound@1.0.4:
dependencies:
call-bind-apply-helpers: 1.0.2
get-intrinsic: 1.3.0
callsites@3.1.0: {} callsites@3.1.0: {}
camelcase@6.3.0: {} camelcase@6.3.0: {}
@@ -2639,6 +2734,14 @@ snapshots:
dependencies: dependencies:
consola: 3.4.2 consola: 3.4.2
co-body@6.2.0:
dependencies:
'@hapi/bourne': 3.0.0
inflation: 2.1.0
qs: 6.14.0
raw-body: 2.5.2
type-is: 1.6.18
color-convert@1.9.3: color-convert@1.9.3:
dependencies: dependencies:
color-name: 1.1.3 color-name: 1.1.3
@@ -2686,6 +2789,8 @@ snapshots:
depd: 2.0.0 depd: 2.0.0
keygrip: 1.1.0 keygrip: 1.1.0
copy-to@2.0.1: {}
core-js@3.45.1: {} core-js@3.45.1: {}
cosmiconfig@8.3.6(typescript@5.9.2): cosmiconfig@8.3.6(typescript@5.9.2):
@@ -2980,6 +3085,10 @@ snapshots:
statuses: 2.0.1 statuses: 2.0.1
toidentifier: 1.0.1 toidentifier: 1.0.1
iconv-lite@0.4.24:
dependencies:
safer-buffer: 2.1.2
ieee754@1.2.1: {} ieee754@1.2.1: {}
import-fresh@3.3.1: import-fresh@3.3.1:
@@ -2987,6 +3096,8 @@ snapshots:
parent-module: 1.0.1 parent-module: 1.0.1
resolve-from: 4.0.0 resolve-from: 4.0.0
inflation@2.1.0: {}
inherits@2.0.4: {} inherits@2.0.4: {}
is-arrayish@0.2.1: {} is-arrayish@0.2.1: {}
@@ -3015,6 +3126,12 @@ snapshots:
dependencies: dependencies:
tsscmp: 1.0.6 tsscmp: 1.0.6
koa-bodyparser@4.4.1:
dependencies:
co-body: 6.2.0
copy-to: 2.0.1
type-is: 1.6.18
koa-compose@4.1.0: {} koa-compose@4.1.0: {}
koa-session@7.0.2: koa-session@7.0.2:
@@ -3117,6 +3234,8 @@ snapshots:
mdn-data@2.0.30: {} mdn-data@2.0.30: {}
media-typer@0.3.0: {}
media-typer@1.1.0: {} media-typer@1.1.0: {}
mime-db@1.52.0: {} mime-db@1.52.0: {}
@@ -3176,6 +3295,8 @@ snapshots:
object-assign@4.1.1: {} object-assign@4.1.1: {}
object-inspect@1.13.4: {}
ohash@2.0.11: {} ohash@2.0.11: {}
on-exit-leak-free@2.1.2: {} on-exit-leak-free@2.1.2: {}
@@ -3285,8 +3406,19 @@ snapshots:
pure-rand@6.1.0: {} pure-rand@6.1.0: {}
qs@6.14.0:
dependencies:
side-channel: 1.1.0
quick-format-unescaped@4.0.4: {} quick-format-unescaped@4.0.4: {}
raw-body@2.5.2:
dependencies:
bytes: 3.1.2
http-errors: 2.0.0
iconv-lite: 0.4.24
unpipe: 1.0.0
rc9@2.1.2: rc9@2.1.2:
dependencies: dependencies:
defu: 6.1.4 defu: 6.1.4
@@ -3358,6 +3490,8 @@ snapshots:
safe-stable-stringify@2.5.0: {} safe-stable-stringify@2.5.0: {}
safer-buffer@2.1.2: {}
scheduler@0.23.2: scheduler@0.23.2:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
@@ -3376,6 +3510,34 @@ snapshots:
shallowequal@1.1.0: {} shallowequal@1.1.0: {}
side-channel-list@1.0.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-map@1.0.1:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-weakmap@1.0.2:
dependencies:
call-bound: 1.0.4
es-errors: 1.3.0
get-intrinsic: 1.3.0
object-inspect: 1.13.4
side-channel-map: 1.0.1
side-channel@1.1.0:
dependencies:
es-errors: 1.3.0
object-inspect: 1.13.4
side-channel-list: 1.0.0
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
simple-swizzle@0.2.2: simple-swizzle@0.2.2:
dependencies: dependencies:
is-arrayish: 0.3.2 is-arrayish: 0.3.2
@@ -3447,6 +3609,11 @@ snapshots:
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
type-is@1.6.18:
dependencies:
media-typer: 0.3.0
mime-types: 2.1.35
type-is@2.0.1: type-is@2.0.1:
dependencies: dependencies:
content-type: 1.0.5 content-type: 1.0.5
@@ -3457,6 +3624,8 @@ snapshots:
undici-types@7.10.0: {} undici-types@7.10.0: {}
unpipe@1.0.0: {}
update-browserslist-db@1.1.3(browserslist@4.25.3): update-browserslist-db@1.1.3(browserslist@4.25.3):
dependencies: dependencies:
browserslist: 4.25.3 browserslist: 4.25.3