Initial commit from Create Next App
This commit is contained in:
41
.gitignore
vendored
Normal file
41
.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
36
README.md
Normal file
36
README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
26
app/globals.css
Normal file
26
app/globals.css
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: #ffffff;
|
||||||
|
--foreground: #171717;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme inline {
|
||||||
|
--color-background: var(--background);
|
||||||
|
--color-foreground: var(--foreground);
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background: #0a0a0a;
|
||||||
|
--foreground: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--foreground);
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
34
app/layout.tsx
Normal file
34
app/layout.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { Geist, Geist_Mono } from "next/font/google";
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
const geistSans = Geist({
|
||||||
|
variable: "--font-geist-sans",
|
||||||
|
subsets: ["latin"],
|
||||||
|
});
|
||||||
|
|
||||||
|
const geistMono = Geist_Mono({
|
||||||
|
variable: "--font-geist-mono",
|
||||||
|
subsets: ["latin"],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Create Next App",
|
||||||
|
description: "Generated by create next app",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body
|
||||||
|
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
103
app/page.tsx
Normal file
103
app/page.tsx
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="font-sans grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20">
|
||||||
|
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
||||||
|
<Image
|
||||||
|
className="dark:invert"
|
||||||
|
src="/next.svg"
|
||||||
|
alt="Next.js logo"
|
||||||
|
width={180}
|
||||||
|
height={38}
|
||||||
|
priority
|
||||||
|
/>
|
||||||
|
<ol className="font-mono list-inside list-decimal text-sm/6 text-center sm:text-left">
|
||||||
|
<li className="mb-2 tracking-[-.01em]">
|
||||||
|
Get started by editing{" "}
|
||||||
|
<code className="bg-black/[.05] dark:bg-white/[.06] font-mono font-semibold px-1 py-0.5 rounded">
|
||||||
|
app/page.tsx
|
||||||
|
</code>
|
||||||
|
.
|
||||||
|
</li>
|
||||||
|
<li className="tracking-[-.01em]">
|
||||||
|
Save and see your changes instantly.
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
||||||
|
<a
|
||||||
|
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
||||||
|
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className="dark:invert"
|
||||||
|
src="/vercel.svg"
|
||||||
|
alt="Vercel logomark"
|
||||||
|
width={20}
|
||||||
|
height={20}
|
||||||
|
/>
|
||||||
|
Deploy now
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
||||||
|
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Read our docs
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="/file.svg"
|
||||||
|
alt="File icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
Learn
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="/window.svg"
|
||||||
|
alt="Window icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
Examples
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="/globe.svg"
|
||||||
|
alt="Globe icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
Go to nextjs.org →
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
867
docs/API文档.md
Normal file
867
docs/API文档.md
Normal file
@@ -0,0 +1,867 @@
|
|||||||
|
# 账户管理系统 API 文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本文档描述了账户管理系统的API接口,用于Web前端对接。系统提供了账户的获取、上传、更新、删除和统计等功能。
|
||||||
|
|
||||||
|
### 基础信息
|
||||||
|
|
||||||
|
- **基础URL**: `{API_BASE_URL}`
|
||||||
|
- **数据格式**: JSON
|
||||||
|
- **字符编码**: UTF-8
|
||||||
|
- **认证方式**: 需要在请求头中包含认证信息
|
||||||
|
|
||||||
|
### 通用响应格式
|
||||||
|
|
||||||
|
所有API接口都使用统一的响应格式:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ApiResponse<T> {
|
||||||
|
code: BusinessCode; // 业务状态码
|
||||||
|
message: string; // 响应消息
|
||||||
|
data: T | null; // 响应数据
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 业务状态码 (BusinessCode)
|
||||||
|
|
||||||
|
| 状态码 | 名称 | 说明 |
|
||||||
|
|--------|------|------|
|
||||||
|
| 0 | Success | 请求成功 |
|
||||||
|
| 1001 | NoResource | 资源不存在 |
|
||||||
|
| 2001 | InvalidParams | 参数无效 |
|
||||||
|
| 3001 | ResourceConflict | 资源冲突 |
|
||||||
|
| 4001 | PermissionDenied | 权限不足 |
|
||||||
|
| 5001 | BusinessError | 业务错误 |
|
||||||
|
|
||||||
|
## 数据模型
|
||||||
|
|
||||||
|
### 账户 (Account)
|
||||||
|
|
||||||
|
账户是系统的核心数据模型,包含以下字段:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Account {
|
||||||
|
id: number; // 账户ID,自增主键
|
||||||
|
ownerId: string; // 所有者ID
|
||||||
|
platform: string; // 平台名称
|
||||||
|
customId: string; // 自定义ID
|
||||||
|
data: string; // 账户数据,JSON格式字符串
|
||||||
|
status: string; // 账户状态
|
||||||
|
notes?: string; // 备注,可选
|
||||||
|
lockedAt?: Date; // 锁定时间,可选
|
||||||
|
createdAt: Date; // 创建时间
|
||||||
|
updatedAt: Date; // 更新时间
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 账户状态
|
||||||
|
|
||||||
|
- `available`: 可用
|
||||||
|
- `locked`: 已锁定
|
||||||
|
- 其他自定义状态
|
||||||
|
|
||||||
|
### 分页结果 (PaginationResult)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface PaginationResult {
|
||||||
|
page: number; // 当前页码
|
||||||
|
pageSize: number; // 每页条数
|
||||||
|
total: number; // 总记录数
|
||||||
|
totalPages: number; // 总页数
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 统计概览 (StatsOverview)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface StatsOverview {
|
||||||
|
totalAccounts: number; // 总账户数
|
||||||
|
platformSummary: Record<string, number>; // 平台统计
|
||||||
|
ownerSummary: Record<string, number>; // 所有者统计
|
||||||
|
statusSummary: Record<string, number>; // 状态统计
|
||||||
|
detailedBreakdown: { // 详细统计
|
||||||
|
platform: string;
|
||||||
|
ownerId: string;
|
||||||
|
status: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API 接口
|
||||||
|
|
||||||
|
### 1. 账户获取接口
|
||||||
|
|
||||||
|
用于脚本端获取可用账户。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /s/v1/{ownerId}/acquire?platform={platform}&count={count}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| ownerId | 路径 | string | 是 | 所有者ID |
|
||||||
|
| platform | 查询 | string | 是 | 平台名称 |
|
||||||
|
| count | 查询 | number | 否 | 获取数量,默认1,最大100 |
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully acquired 1 account.",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"customId": "custom123",
|
||||||
|
"data": "{\"username\":\"test\",\"password\":\"123456\"}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
无可用账户响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 1001,
|
||||||
|
"message": "No available accounts found for platform 'example'.",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch获取账户
|
||||||
|
async function acquireAccounts(ownerId, platform, count = 1) {
|
||||||
|
const response = await fetch(`/s/v1/${ownerId}/acquire?platform=${platform}&count=${count}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const result = await acquireAccounts('owner123', 'example', 2);
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('获取成功:', result.data);
|
||||||
|
} else {
|
||||||
|
console.error('获取失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 账户状态更新接口
|
||||||
|
|
||||||
|
用于脚本端更新账户状态。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /s/v1/{ownerId}/update/{accountId}/{newStatus}?notes={notes}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| ownerId | 路径 | string | 是 | 所有者ID |
|
||||||
|
| accountId | 路径 | number | 是 | 账户ID |
|
||||||
|
| newStatus | 路径 | string | 是 | 新状态 |
|
||||||
|
| notes | 查询 | string | 否 | 备注 |
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Account status updated to 'used'.",
|
||||||
|
"data": {
|
||||||
|
"updatedId": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
权限不足响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 4001,
|
||||||
|
"message": "Account not found or permission denied.",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch更新账户状态
|
||||||
|
async function updateAccountStatus(ownerId, accountId, newStatus, notes) {
|
||||||
|
const url = `/s/v1/${ownerId}/update/${accountId}/${newStatus}`;
|
||||||
|
if (notes) {
|
||||||
|
url += `?notes=${encodeURIComponent(notes)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const result = await updateAccountStatus('owner123', 1, 'used', '测试使用');
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('更新成功:', result.data);
|
||||||
|
} else {
|
||||||
|
console.error('更新失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 账户上传接口
|
||||||
|
|
||||||
|
用于脚本端批量上传账户。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /s/v1/{ownerId}/upload
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"platform": "string",
|
||||||
|
"customId": "string",
|
||||||
|
"data": "string",
|
||||||
|
"status": "string"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| ownerId | 路径 | string | 是 | 所有者ID |
|
||||||
|
| body | 请求体 | ScriptUploadItem[] | 是 | 账户数据数组 |
|
||||||
|
|
||||||
|
#### ScriptUploadItem 类型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ScriptUploadItem {
|
||||||
|
platform: string; // 平台名称
|
||||||
|
customId: string; // 自定义ID
|
||||||
|
data: string; // 账户数据,JSON格式字符串
|
||||||
|
status?: string; // 账户状态,可选,默认为"available"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully processed 2 accounts (1 created, 1 updated).",
|
||||||
|
"data": {
|
||||||
|
"processedCount": 2,
|
||||||
|
"createdCount": 1,
|
||||||
|
"updatedCount": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch上传账户
|
||||||
|
async function uploadAccounts(ownerId, accounts) {
|
||||||
|
const response = await fetch(`/s/v1/${ownerId}/upload`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(accounts)
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const accounts = [
|
||||||
|
{
|
||||||
|
platform: 'example',
|
||||||
|
customId: 'user123',
|
||||||
|
data: JSON.stringify({ username: 'user123', password: 'pass123' }),
|
||||||
|
status: 'available'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
platform: 'example',
|
||||||
|
customId: 'user456',
|
||||||
|
data: JSON.stringify({ username: 'user456', password: 'pass456' })
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const result = await uploadAccounts('owner123', accounts);
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('上传成功:', result.data);
|
||||||
|
} else {
|
||||||
|
console.error('上传失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 账户列表接口
|
||||||
|
|
||||||
|
用于Web端获取账户列表,支持筛选、分页和排序。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /web/v1/accounts/list
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"filters": {
|
||||||
|
"platform": "string",
|
||||||
|
"status": ["string"],
|
||||||
|
"ownerId": "string",
|
||||||
|
"search": "string"
|
||||||
|
},
|
||||||
|
"pagination": {
|
||||||
|
"page": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
},
|
||||||
|
"sort": {
|
||||||
|
"field": "id",
|
||||||
|
"order": "desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| filters | 请求体 | ListAccountsFilters | 否 | 筛选条件 |
|
||||||
|
| pagination | 请求体 | object | 是 | 分页参数 |
|
||||||
|
| sort | 请求体 | object | 是 | 排序参数 |
|
||||||
|
|
||||||
|
#### ListAccountsFilters 类型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ListAccountsFilters {
|
||||||
|
platform?: string; // 平台名称筛选
|
||||||
|
status?: string[]; // 状态筛选,多选
|
||||||
|
ownerId?: string; // 所有者ID筛选
|
||||||
|
search?: string; // 搜索关键词,搜索customId和notes
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 排序字段
|
||||||
|
|
||||||
|
支持以下字段排序:
|
||||||
|
- `id`: 账户ID
|
||||||
|
- `ownerId`: 所有者ID
|
||||||
|
- `platform`: 平台名称
|
||||||
|
- `customId`: 自定义ID
|
||||||
|
- `data`: 账户数据
|
||||||
|
- `status`: 账户状态
|
||||||
|
- `notes`: 备注
|
||||||
|
- `lockedAt`: 锁定时间
|
||||||
|
- `createdAt`: 创建时间
|
||||||
|
- `updatedAt`: 更新时间
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Success",
|
||||||
|
"data": {
|
||||||
|
"list": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"ownerId": "owner123",
|
||||||
|
"platform": "example",
|
||||||
|
"customId": "user123",
|
||||||
|
"data": "{\"username\":\"user123\",\"password\":\"pass123\"}",
|
||||||
|
"status": "available",
|
||||||
|
"notes": "测试账户",
|
||||||
|
"lockedAt": null,
|
||||||
|
"createdAt": "2023-01-01T00:00:00.000Z",
|
||||||
|
"updatedAt": "2023-01-01T00:00:00.000Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pagination": {
|
||||||
|
"page": 1,
|
||||||
|
"pageSize": 10,
|
||||||
|
"total": 1,
|
||||||
|
"totalPages": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch获取账户列表
|
||||||
|
async function getAccountsList(filters, pagination, sort) {
|
||||||
|
const response = await fetch('/web/v1/accounts/list', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
filters,
|
||||||
|
pagination,
|
||||||
|
sort
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const filters = {
|
||||||
|
platform: 'example',
|
||||||
|
status: ['available'],
|
||||||
|
search: 'test'
|
||||||
|
};
|
||||||
|
|
||||||
|
const pagination = {
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
const sort = {
|
||||||
|
field: 'createdAt',
|
||||||
|
order: 'desc'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await getAccountsList(filters, pagination, sort);
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('账户列表:', result.data.list);
|
||||||
|
console.log('分页信息:', result.data.pagination);
|
||||||
|
} else {
|
||||||
|
console.error('获取失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 批量删除账户接口
|
||||||
|
|
||||||
|
用于Web端批量删除账户。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /web/v1/accounts/delete-batch
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ids": [1, 2, 3]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| ids | 请求体 | number[] | 是 | 要删除的账户ID数组 |
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully deleted 3 accounts.",
|
||||||
|
"data": {
|
||||||
|
"deletedCount": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch批量删除账户
|
||||||
|
async function batchDeleteAccounts(ids) {
|
||||||
|
const response = await fetch('/web/v1/accounts/delete-batch', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ids })
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const result = await batchDeleteAccounts([1, 2, 3]);
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('删除成功:', result.data);
|
||||||
|
} else {
|
||||||
|
console.error('删除失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 批量更新账户接口
|
||||||
|
|
||||||
|
用于Web端批量更新账户。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /web/v1/accounts/update-batch
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 请求体
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ids": [1, 2, 3],
|
||||||
|
"payload": {
|
||||||
|
"status": "available",
|
||||||
|
"ownerId": "newOwner",
|
||||||
|
"notes": "批量更新备注"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 参数
|
||||||
|
|
||||||
|
| 参数名 | 位置 | 类型 | 必填 | 说明 |
|
||||||
|
|--------|------|------|------|------|
|
||||||
|
| ids | 请求体 | number[] | 是 | 要更新的账户ID数组 |
|
||||||
|
| payload | 请求体 | object | 是 | 更新数据 |
|
||||||
|
|
||||||
|
#### payload 类型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface UpdatePayload {
|
||||||
|
status?: string; // 新状态
|
||||||
|
ownerId?: string; // 新所有者ID
|
||||||
|
notes?: string; // 新备注
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully updated 3 accounts.",
|
||||||
|
"data": {
|
||||||
|
"updatedCount": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch批量更新账户
|
||||||
|
async function batchUpdateAccounts(ids, payload) {
|
||||||
|
const response = await fetch('/web/v1/accounts/update-batch', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ids, payload })
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const ids = [1, 2, 3];
|
||||||
|
const payload = {
|
||||||
|
status: 'available',
|
||||||
|
notes: '批量更新为可用状态'
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await batchUpdateAccounts(ids, payload);
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('更新成功:', result.data);
|
||||||
|
} else {
|
||||||
|
console.error('更新失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 统计概览接口
|
||||||
|
|
||||||
|
用于Web端获取账户统计信息。
|
||||||
|
|
||||||
|
#### 请求
|
||||||
|
|
||||||
|
```http
|
||||||
|
GET /web/v1/stats/overview
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 响应
|
||||||
|
|
||||||
|
成功响应:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Success",
|
||||||
|
"data": {
|
||||||
|
"totalAccounts": 100,
|
||||||
|
"platformSummary": {
|
||||||
|
"example": 50,
|
||||||
|
"test": 30,
|
||||||
|
"demo": 20
|
||||||
|
},
|
||||||
|
"ownerSummary": {
|
||||||
|
"owner1": 40,
|
||||||
|
"owner2": 35,
|
||||||
|
"owner3": 25
|
||||||
|
},
|
||||||
|
"statusSummary": {
|
||||||
|
"available": 70,
|
||||||
|
"locked": 20,
|
||||||
|
"used": 10
|
||||||
|
},
|
||||||
|
"detailedBreakdown": [
|
||||||
|
{
|
||||||
|
"platform": "example",
|
||||||
|
"ownerId": "owner1",
|
||||||
|
"status": "available",
|
||||||
|
"count": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "example",
|
||||||
|
"ownerId": "owner1",
|
||||||
|
"status": "locked",
|
||||||
|
"count": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用fetch获取统计概览
|
||||||
|
async function getStatsOverview() {
|
||||||
|
const response = await fetch('/web/v1/stats/overview', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer YOUR_TOKEN'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用示例
|
||||||
|
const result = await getStatsOverview();
|
||||||
|
if (result.code === 0) {
|
||||||
|
console.log('总账户数:', result.data.totalAccounts);
|
||||||
|
console.log('平台统计:', result.data.platformSummary);
|
||||||
|
console.log('所有者统计:', result.data.ownerSummary);
|
||||||
|
console.log('状态统计:', result.data.statusSummary);
|
||||||
|
console.log('详细统计:', result.data.detailedBreakdown);
|
||||||
|
} else {
|
||||||
|
console.error('获取失败:', result.message);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
所有API接口在发生错误时都会返回统一的错误响应格式:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": "错误码",
|
||||||
|
"message": "错误信息",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 常见错误码
|
||||||
|
|
||||||
|
| 错误码 | 说明 | 处理建议 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| 1001 | 资源不存在 | 检查请求的资源是否存在 |
|
||||||
|
| 2001 | 参数无效 | 检查请求参数是否符合要求 |
|
||||||
|
| 3001 | 资源冲突 | 检查是否有重复数据 |
|
||||||
|
| 4001 | 权限不足 | 检查认证信息是否正确 |
|
||||||
|
| 5001 | 业务错误 | 检查业务逻辑是否正确 |
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
1. **认证**:所有API请求都需要在请求头中包含认证信息,例如:
|
||||||
|
```http
|
||||||
|
Authorization: Bearer YOUR_TOKEN
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **错误处理**:前端应该根据返回的`code`值进行相应的错误处理,而不是依赖`message`字段。
|
||||||
|
|
||||||
|
3. **分页**:在获取列表数据时,合理设置分页大小,建议不超过100条。
|
||||||
|
|
||||||
|
4. **批量操作**:批量操作时,建议限制单次操作的数量,避免服务器压力过大。
|
||||||
|
|
||||||
|
5. **数据格式**:账户数据字段`data`存储的是JSON格式字符串,前端需要进行相应的序列化和反序列化操作。
|
||||||
|
|
||||||
|
## 类型定义
|
||||||
|
|
||||||
|
以下是完整的TypeScript类型定义,可以直接在前端项目中使用:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 业务状态码
|
||||||
|
enum BusinessCode {
|
||||||
|
Success = 0,
|
||||||
|
NoResource = 1001,
|
||||||
|
InvalidParams = 2001,
|
||||||
|
ResourceConflict = 3001,
|
||||||
|
PermissionDenied = 4001,
|
||||||
|
BusinessError = 5001,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用响应格式
|
||||||
|
interface ApiResponse<T> {
|
||||||
|
code: BusinessCode;
|
||||||
|
message: string;
|
||||||
|
data: T | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账户类型
|
||||||
|
interface Account {
|
||||||
|
id: number;
|
||||||
|
ownerId: string;
|
||||||
|
platform: string;
|
||||||
|
customId: string;
|
||||||
|
data: string;
|
||||||
|
status: string;
|
||||||
|
notes?: string;
|
||||||
|
lockedAt?: Date | null;
|
||||||
|
createdAt: Date;
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页结果
|
||||||
|
interface PaginationResult {
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 脚本获取响应
|
||||||
|
type ScriptAcquireResponse = Pick<Account, 'id' | 'customId' | 'data'>[];
|
||||||
|
|
||||||
|
// 脚本上传项
|
||||||
|
interface ScriptUploadItem {
|
||||||
|
platform: string;
|
||||||
|
customId: string;
|
||||||
|
data: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账户列表筛选条件
|
||||||
|
interface ListAccountsFilters {
|
||||||
|
platform?: string;
|
||||||
|
status?: string[];
|
||||||
|
ownerId?: string;
|
||||||
|
search?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账户列表请求体
|
||||||
|
interface ListAccountsBody {
|
||||||
|
filters: ListAccountsFilters;
|
||||||
|
pagination: {
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
};
|
||||||
|
sort: {
|
||||||
|
field: keyof Account;
|
||||||
|
order: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账户列表响应
|
||||||
|
interface ListAccountsResponse {
|
||||||
|
list: Account[];
|
||||||
|
pagination: PaginationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除请求体
|
||||||
|
interface BatchDeleteBody {
|
||||||
|
ids: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新请求体
|
||||||
|
interface BatchUpdateBody {
|
||||||
|
ids: number[];
|
||||||
|
payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes'>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计概览
|
||||||
|
interface StatsOverview {
|
||||||
|
totalAccounts: number;
|
||||||
|
platformSummary: Record<string, number>;
|
||||||
|
ownerSummary: Record<string, number>;
|
||||||
|
statusSummary: Record<string, number>;
|
||||||
|
detailedBreakdown: {
|
||||||
|
platform: string;
|
||||||
|
ownerId: string;
|
||||||
|
status: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 版本历史
|
||||||
|
|
||||||
|
| 版本 | 日期 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 1.0.0 | 2023-01-01 | 初始版本 |
|
||||||
328
docs/后端设计.md
Normal file
328
docs/后端设计.md
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
### **轻量化账号管理平台 - 工程设计蓝图**
|
||||||
|
|
||||||
|
#### 1. 核心设计哲学
|
||||||
|
|
||||||
|
* **单表驱动**: 所有核心数据聚合在 `accounts` 表,简化数据库模型。
|
||||||
|
* **OwnerID 即身份**: `ownerId` 同时作为拥有者标识和API认证凭证。
|
||||||
|
* **配置硬编码**: 关键状态(如 `available`, `locked`)硬编码在业务逻辑中,降低系统复杂性。
|
||||||
|
* **职责分离的API**: 为自动化脚本和管理后台提供两套独立的、高度优化的API。
|
||||||
|
* **规范化通信**: 所有API遵循统一的响应结构,业务结果通过 `code` 字段传递。
|
||||||
|
* **高性能与健壮性**: 依赖PostgreSQL原生特性(事务、行锁、索引)和专用的后台任务确保系统稳定。
|
||||||
|
|
||||||
|
#### 2. 技术栈
|
||||||
|
|
||||||
|
* **运行时**: Node.js (v18+)
|
||||||
|
* **语言**: TypeScript
|
||||||
|
* **Web 框架**: **Fastify**
|
||||||
|
* **数据库**: PostgreSQL (v14+)
|
||||||
|
* **ORM/查询构建器**: **Drizzle ORM**
|
||||||
|
* **数据校验**: **Zod**
|
||||||
|
|
||||||
|
#### 3. 项目结构
|
||||||
|
|
||||||
|
采用模块化、可扩展的目录结构,清晰分离各项职责。
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── drizzle/ # Drizzle ORM 迁移文件
|
||||||
|
├── src/
|
||||||
|
│ ├── api/ # API 路由定义
|
||||||
|
│ │ └── v1/
|
||||||
|
│ │ ├── web/ # 前端管理后台 API
|
||||||
|
│ │ │ ├── accounts.ts # 账号增删改查
|
||||||
|
│ │ │ └── stats.ts # 统计数据
|
||||||
|
│ │ └── script/ # 自动化脚本 API
|
||||||
|
│ │ └── actions.ts # 获取、更新、上传
|
||||||
|
│ ├── core/ # 核心业务逻辑 (Services)
|
||||||
|
│ │ └── AccountService.ts # 封装所有与账号相关的业务操作
|
||||||
|
│ ├── db/ # 数据库配置与 Schema
|
||||||
|
│ │ ├── index.ts # Drizzle 客户端实例
|
||||||
|
│ │ └── schema.ts # 数据库表定义
|
||||||
|
│ ├── jobs/ # 后台定时任务
|
||||||
|
│ │ └── staleLockCleanup.ts # 清理超时锁定的任务
|
||||||
|
│ ├── lib/ # 通用库、工具函数
|
||||||
|
│ │ └── apiResponse.ts # 统一响应格式的辅助函数
|
||||||
|
│ ├── types/ # 全局类型定义
|
||||||
|
│ │ ├── api.ts # API 请求/响应体类型
|
||||||
|
│ │ └── index.ts # 核心业务模型类型
|
||||||
|
│ ├── index.ts # 应用入口,启动 Fastify 服务器
|
||||||
|
│ └── config.ts # 应用配置 (数据库连接、端口等)
|
||||||
|
├── .env # 环境变量
|
||||||
|
├── .env.example
|
||||||
|
├── package.json
|
||||||
|
└── tsconfig.json
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. 数据库设计 (单表模型)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// file: src/db/schema.ts
|
||||||
|
import { pgTable, serial, varchar, timestamp, uniqueIndex, text, index } from 'drizzle-orm/pg-core';
|
||||||
|
|
||||||
|
export const accounts = pgTable('accounts', {
|
||||||
|
id: serial('id').primaryKey(),
|
||||||
|
ownerId: varchar('owner_id', { length: 128 }).notNull(),
|
||||||
|
platform: varchar('platform', { length: 100 }).notNull(),
|
||||||
|
customId: varchar('custom_id', { length: 255 }).notNull(),
|
||||||
|
data: text('data').notNull(),
|
||||||
|
status: varchar('status', { length: 50 }).notNull(),
|
||||||
|
notes: text('notes'),
|
||||||
|
lockedAt: timestamp('locked_at'),
|
||||||
|
createdAt: timestamp('created_at').defaultNow().notNull(),
|
||||||
|
updatedAt: timestamp('updated_at').defaultNow().notNull(),
|
||||||
|
}, (table) => ({
|
||||||
|
platformCustomIdIdx: uniqueIndex('platform_custom_id_idx').on(table.platform, table.customId),
|
||||||
|
ownerIdStatusIdx: index('owner_id_status_idx').on(table.ownerId, table.status),
|
||||||
|
platformOwnerIdx: index('platform_owner_idx').on(table.platform, table.ownerId),
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. 核心类型与接口定义
|
||||||
|
|
||||||
|
##### 5.1. 业务模型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// file: src/types/index.ts
|
||||||
|
import { accounts } from '../db/schema';
|
||||||
|
import { InferSelectModel } from 'drizzle-orm';
|
||||||
|
|
||||||
|
// 从数据库 Schema 自动推断出的 Account 类型,确保与数据库一致
|
||||||
|
export type Account = InferSelectModel<typeof accounts>;
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 5.2. API 通信规范
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// file: src/types/api.ts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务状态码枚举,避免使用魔法数字
|
||||||
|
*/
|
||||||
|
export enum BusinessCode {
|
||||||
|
Success = 0,
|
||||||
|
NoResource = 1001,
|
||||||
|
InvalidParams = 2001,
|
||||||
|
ResourceConflict = 3001,
|
||||||
|
PermissionDenied = 4001, // 业务层权限拒绝
|
||||||
|
BusinessError = 5001,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的 API 响应体结构
|
||||||
|
*/
|
||||||
|
export interface ApiResponse<T> {
|
||||||
|
code: BusinessCode;
|
||||||
|
message: string;
|
||||||
|
data: T | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询结果
|
||||||
|
*/
|
||||||
|
export interface PaginationResult {
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
total: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### 5.3. API 请求/响应体类型
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// file: src/types/api.ts
|
||||||
|
|
||||||
|
// --- 脚本 API ---
|
||||||
|
|
||||||
|
export type ScriptAcquireResponse = Pick<Account, 'id' | 'customId' | 'data'>[];
|
||||||
|
|
||||||
|
export interface ScriptUploadItem {
|
||||||
|
platform: string;
|
||||||
|
customId: string;
|
||||||
|
data: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 前端管理 API ---
|
||||||
|
|
||||||
|
export interface ListAccountsFilters {
|
||||||
|
platform?: string;
|
||||||
|
status?: string[];
|
||||||
|
ownerId?: string;
|
||||||
|
search?: string; // 模糊搜索 customId 或 notes
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListAccountsBody {
|
||||||
|
filters: ListAccountsFilters;
|
||||||
|
pagination: {
|
||||||
|
page: number;
|
||||||
|
pageSize: number;
|
||||||
|
};
|
||||||
|
sort: {
|
||||||
|
field: keyof Account;
|
||||||
|
order: 'asc' | 'desc';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ListAccountsResponse {
|
||||||
|
list: Account[];
|
||||||
|
pagination: PaginationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchDeleteBody {
|
||||||
|
ids: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchUpdateBody {
|
||||||
|
ids: number[];
|
||||||
|
payload: Partial<Pick<Account, 'status' | 'ownerId' | 'notes'>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StatsOverview {
|
||||||
|
totalAccounts: number;
|
||||||
|
platformSummary: Record<string, number>;
|
||||||
|
ownerSummary: Record<string, number>;
|
||||||
|
statusSummary: Record<string, number>;
|
||||||
|
detailedBreakdown: {
|
||||||
|
platform: string;
|
||||||
|
ownerId: string;
|
||||||
|
status: string;
|
||||||
|
count: number;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **6. API 设计**
|
||||||
|
|
||||||
|
#### A. 脚本专用 API (Base URL: `/s/v1/{ownerId}`)
|
||||||
|
|
||||||
|
**认证**: 所有请求通过 URL 中的 `{ownerId}` 进行身份验证和授权。
|
||||||
|
|
||||||
|
1. **获取账号**
|
||||||
|
* **Endpoint**: `GET /acquire`
|
||||||
|
* **描述**: 获取一个或多个可用的账号,并将其状态锁定。
|
||||||
|
* **Query Params**:
|
||||||
|
* `platform` (string, **必须**): 平台标识。
|
||||||
|
* `count` (number, 可选, 默认 1): 获取数量。
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<ScriptAcquireResponse>
|
||||||
|
{
|
||||||
|
"code": 0, // BusinessCode.Success
|
||||||
|
"message": "Successfully acquired 2 accounts.",
|
||||||
|
"data": [
|
||||||
|
{ "id": 101, "customId": "user1@gmail.com", "data": "cookie_string_1" },
|
||||||
|
{ "id": 102, "customId": "user2@gmail.com", "data": "cookie_string_2" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* **业务失败响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<null>
|
||||||
|
{
|
||||||
|
"code": 1001, // BusinessCode.NoResource
|
||||||
|
"message": "No available accounts found for platform 'google'.",
|
||||||
|
"data": null
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **更新账号状态**
|
||||||
|
* **Endpoint**: `GET /update/{accountId}/{newStatus}`
|
||||||
|
* **描述**: 快速更新指定账号的状态。
|
||||||
|
* **Query Params**:
|
||||||
|
* `notes` (string, 可选): 添加备注信息。
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<{ updatedId: number }>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Account status updated to 'banned'.",
|
||||||
|
"data": { "updatedId": 12345 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
* **传输错误响应 (403 Forbidden)**: 当 URL 中的 `ownerId` 与 `accountId` 对应的账号所有者不匹配时返回。
|
||||||
|
|
||||||
|
3. **上传/更新账号**
|
||||||
|
* **Endpoint**: `POST /upload`
|
||||||
|
* **描述**: 批量创建或更新账号。
|
||||||
|
* **Request Body**: `ScriptUploadItem[]`
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<{ processedCount: number, createdCount: number, updatedCount: number }>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully processed 10 accounts (5 created, 5 updated).",
|
||||||
|
"data": { "processedCount": 10, "createdCount": 5, "updatedCount": 5 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### B. 前端管理 API (Base URL: `/web/v1`)
|
||||||
|
|
||||||
|
1. **获取账号列表 (复杂查询)**
|
||||||
|
* **Endpoint**: `POST /accounts/list`
|
||||||
|
* **描述**: 支持多维度筛选、分页和排序的账号查询。
|
||||||
|
* **Request Body**: `ListAccountsBody`
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<ListAccountsResponse>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Success",
|
||||||
|
"data": {
|
||||||
|
"list": [ /* ... Account 对象数组 ... */ ],
|
||||||
|
"pagination": { "page": 1, "pageSize": 50, "total": 123, "totalPages": 3 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **批量删除账号**
|
||||||
|
* **Endpoint**: `POST /accounts/delete-batch`
|
||||||
|
* **描述**: 根据 ID 列表批量删除账号。
|
||||||
|
* **Request Body**: `BatchDeleteBody`
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<{ deletedCount: number }>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully deleted 5 accounts.",
|
||||||
|
"data": { "deletedCount": 5 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **批量更新账号**
|
||||||
|
* **Endpoint**: `POST /accounts/update-batch`
|
||||||
|
* **描述**: 批量修改账号的状态、所有者或备注。
|
||||||
|
* **Request Body**: `BatchUpdateBody`
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<{ updatedCount: number }>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Successfully updated 3 accounts.",
|
||||||
|
"data": { "updatedCount": 3 }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **核心统计接口**
|
||||||
|
* **Endpoint**: `GET /stats/overview`
|
||||||
|
* **描述**: 一次性获取仪表盘所需的全部聚合统计数据。
|
||||||
|
* **成功响应 (200 OK)**:
|
||||||
|
```json
|
||||||
|
// Body: ApiResponse<StatsOverview>
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "Success",
|
||||||
|
"data": { /* ... StatsOverview 对象 ... */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### **7. 关键后台任务**
|
||||||
|
|
||||||
|
* **任务名称**: Stale Lock Cleanup (超时锁定清理)
|
||||||
|
* **执行频率**: 建议每 1 分钟执行一次。
|
||||||
|
* **核心逻辑**:
|
||||||
|
* 查找所有 `status` 为 `locked` 且 `lockedAt` 时间早于预设阈值(例如 5 分钟前)的账号。
|
||||||
|
* 执行 SQL: `UPDATE accounts SET status = 'available', lockedAt = NULL WHERE status = 'locked' AND lockedAt < NOW() - INTERVAL '5 minutes';`
|
||||||
|
* **目的**: 自动释放因脚本异常中断而未能解锁的账号,保证账号资源的流转性。
|
||||||
7
next.config.ts
Normal file
7
next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
/* config options here */
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "accounts-manager-web",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev --turbopack",
|
||||||
|
"build": "next build --turbopack",
|
||||||
|
"start": "next start"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "19.1.0",
|
||||||
|
"react-dom": "19.1.0",
|
||||||
|
"next": "15.5.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"tailwindcss": "^4"
|
||||||
|
}
|
||||||
|
}
|
||||||
993
pnpm-lock.yaml
generated
Normal file
993
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,993 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
dependencies:
|
||||||
|
next:
|
||||||
|
specifier: 15.5.3
|
||||||
|
version: 15.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
|
react:
|
||||||
|
specifier: 19.1.0
|
||||||
|
version: 19.1.0
|
||||||
|
react-dom:
|
||||||
|
specifier: 19.1.0
|
||||||
|
version: 19.1.0(react@19.1.0)
|
||||||
|
devDependencies:
|
||||||
|
'@tailwindcss/postcss':
|
||||||
|
specifier: ^4
|
||||||
|
version: 4.1.13
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^20
|
||||||
|
version: 20.19.17
|
||||||
|
'@types/react':
|
||||||
|
specifier: ^19
|
||||||
|
version: 19.1.13
|
||||||
|
'@types/react-dom':
|
||||||
|
specifier: ^19
|
||||||
|
version: 19.1.9(@types/react@19.1.13)
|
||||||
|
tailwindcss:
|
||||||
|
specifier: ^4
|
||||||
|
version: 4.1.13
|
||||||
|
typescript:
|
||||||
|
specifier: ^5
|
||||||
|
version: 5.9.2
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
'@alloc/quick-lru@5.2.0':
|
||||||
|
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.5.0':
|
||||||
|
resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==}
|
||||||
|
|
||||||
|
'@img/colour@1.0.0':
|
||||||
|
resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.3':
|
||||||
|
resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.3':
|
||||||
|
resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.3':
|
||||||
|
resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.4':
|
||||||
|
resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ppc64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.4':
|
||||||
|
resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.4':
|
||||||
|
resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [wasm32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.4':
|
||||||
|
resolution: {integrity: sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.4':
|
||||||
|
resolution: {integrity: sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@isaacs/fs-minipass@4.0.1':
|
||||||
|
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
||||||
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2':
|
||||||
|
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5':
|
||||||
|
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
|
'@next/env@15.5.3':
|
||||||
|
resolution: {integrity: sha512-RSEDTRqyihYXygx/OJXwvVupfr9m04+0vH8vyy0HfZ7keRto6VX9BbEk0J2PUk0VGy6YhklJUSrgForov5F9pw==}
|
||||||
|
|
||||||
|
'@next/swc-darwin-arm64@15.5.3':
|
||||||
|
resolution: {integrity: sha512-nzbHQo69+au9wJkGKTU9lP7PXv0d1J5ljFpvb+LnEomLtSbJkbZyEs6sbF3plQmiOB2l9OBtN2tNSvCH1nQ9Jg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@next/swc-darwin-x64@15.5.3':
|
||||||
|
resolution: {integrity: sha512-w83w4SkOOhekJOcA5HBvHyGzgV1W/XvOfpkrxIse4uPWhYTTRwtGEM4v/jiXwNSJvfRvah0H8/uTLBKRXlef8g==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@next/swc-linux-arm64-gnu@15.5.3':
|
||||||
|
resolution: {integrity: sha512-+m7pfIs0/yvgVu26ieaKrifV8C8yiLe7jVp9SpcIzg7XmyyNE7toC1fy5IOQozmr6kWl/JONC51osih2RyoXRw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@next/swc-linux-arm64-musl@15.5.3':
|
||||||
|
resolution: {integrity: sha512-u3PEIzuguSenoZviZJahNLgCexGFhso5mxWCrrIMdvpZn6lkME5vc/ADZG8UUk5K1uWRy4hqSFECrON6UKQBbQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@next/swc-linux-x64-gnu@15.5.3':
|
||||||
|
resolution: {integrity: sha512-lDtOOScYDZxI2BENN9m0pfVPJDSuUkAD1YXSvlJF0DKwZt0WlA7T7o3wrcEr4Q+iHYGzEaVuZcsIbCps4K27sA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@next/swc-linux-x64-musl@15.5.3':
|
||||||
|
resolution: {integrity: sha512-9vWVUnsx9PrY2NwdVRJ4dUURAQ8Su0sLRPqcCCxtX5zIQUBES12eRVHq6b70bbfaVaxIDGJN2afHui0eDm+cLg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@next/swc-win32-arm64-msvc@15.5.3':
|
||||||
|
resolution: {integrity: sha512-1CU20FZzY9LFQigRi6jM45oJMU3KziA5/sSG+dXeVaTm661snQP6xu3ykGxxwU5sLG3sh14teO/IOEPVsQMRfA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@next/swc-win32-x64-msvc@15.5.3':
|
||||||
|
resolution: {integrity: sha512-JMoLAq3n3y5tKXPQwCK5c+6tmwkuFDa2XAxz8Wm4+IVthdBZdZGh+lmiLUHg9f9IDwIQpUjp+ysd6OkYTyZRZw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@swc/helpers@0.5.15':
|
||||||
|
resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
|
||||||
|
|
||||||
|
'@tailwindcss/node@4.1.13':
|
||||||
|
resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==}
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-android-arm64@4.1.13':
|
||||||
|
resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [android]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-arm64@4.1.13':
|
||||||
|
resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-x64@4.1.13':
|
||||||
|
resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-freebsd-x64@4.1.13':
|
||||||
|
resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
|
||||||
|
resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
|
||||||
|
resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl@4.1.13':
|
||||||
|
resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu@4.1.13':
|
||||||
|
resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl@4.1.13':
|
||||||
|
resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi@4.1.13':
|
||||||
|
resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==}
|
||||||
|
engines: {node: '>=14.0.0'}
|
||||||
|
cpu: [wasm32]
|
||||||
|
bundledDependencies:
|
||||||
|
- '@napi-rs/wasm-runtime'
|
||||||
|
- '@emnapi/core'
|
||||||
|
- '@emnapi/runtime'
|
||||||
|
- '@tybys/wasm-util'
|
||||||
|
- '@emnapi/wasi-threads'
|
||||||
|
- tslib
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
|
||||||
|
resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc@4.1.13':
|
||||||
|
resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
'@tailwindcss/oxide@4.1.13':
|
||||||
|
resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==}
|
||||||
|
engines: {node: '>= 10'}
|
||||||
|
|
||||||
|
'@tailwindcss/postcss@4.1.13':
|
||||||
|
resolution: {integrity: sha512-HLgx6YSFKJT7rJqh9oJs/TkBFhxuMOfUKSBEPYwV+t78POOBsdQ7crhZLzwcH3T0UyUuOzU/GK5pk5eKr3wCiQ==}
|
||||||
|
|
||||||
|
'@types/node@20.19.17':
|
||||||
|
resolution: {integrity: sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==}
|
||||||
|
|
||||||
|
'@types/react-dom@19.1.9':
|
||||||
|
resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^19.0.0
|
||||||
|
|
||||||
|
'@types/react@19.1.13':
|
||||||
|
resolution: {integrity: sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==}
|
||||||
|
|
||||||
|
caniuse-lite@1.0.30001743:
|
||||||
|
resolution: {integrity: sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==}
|
||||||
|
|
||||||
|
chownr@3.0.0:
|
||||||
|
resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
client-only@0.0.1:
|
||||||
|
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||||
|
|
||||||
|
csstype@3.1.3:
|
||||||
|
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
|
||||||
|
|
||||||
|
detect-libc@2.1.0:
|
||||||
|
resolution: {integrity: sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
enhanced-resolve@5.18.3:
|
||||||
|
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
graceful-fs@4.2.11:
|
||||||
|
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||||
|
|
||||||
|
jiti@2.5.1:
|
||||||
|
resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
lightningcss-darwin-arm64@1.30.1:
|
||||||
|
resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
lightningcss-darwin-x64@1.30.1:
|
||||||
|
resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
lightningcss-freebsd-x64@1.30.1:
|
||||||
|
resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [freebsd]
|
||||||
|
|
||||||
|
lightningcss-linux-arm-gnueabihf@1.30.1:
|
||||||
|
resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-gnu@1.30.1:
|
||||||
|
resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-musl@1.30.1:
|
||||||
|
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
lightningcss-linux-x64-gnu@1.30.1:
|
||||||
|
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
|
lightningcss-linux-x64-musl@1.30.1:
|
||||||
|
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
|
lightningcss-win32-arm64-msvc@1.30.1:
|
||||||
|
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
lightningcss-win32-x64-msvc@1.30.1:
|
||||||
|
resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
|
lightningcss@1.30.1:
|
||||||
|
resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
||||||
|
magic-string@0.30.19:
|
||||||
|
resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
|
||||||
|
|
||||||
|
minipass@7.1.2:
|
||||||
|
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||||
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
|
||||||
|
minizlib@3.1.0:
|
||||||
|
resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
nanoid@3.3.11:
|
||||||
|
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
|
||||||
|
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
next@15.5.3:
|
||||||
|
resolution: {integrity: sha512-r/liNAx16SQj4D+XH/oI1dlpv9tdKJ6cONYPwwcCC46f2NjpaRWY+EKCzULfgQYV6YKXjHBchff2IZBSlZmJNw==}
|
||||||
|
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.1.0
|
||||||
|
'@playwright/test': ^1.51.1
|
||||||
|
babel-plugin-react-compiler: '*'
|
||||||
|
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
|
||||||
|
react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
|
||||||
|
sass: ^1.3.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@opentelemetry/api':
|
||||||
|
optional: true
|
||||||
|
'@playwright/test':
|
||||||
|
optional: true
|
||||||
|
babel-plugin-react-compiler:
|
||||||
|
optional: true
|
||||||
|
sass:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
picocolors@1.1.1:
|
||||||
|
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||||
|
|
||||||
|
postcss@8.4.31:
|
||||||
|
resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
|
||||||
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
|
react-dom@19.1.0:
|
||||||
|
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^19.1.0
|
||||||
|
|
||||||
|
react@19.1.0:
|
||||||
|
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
scheduler@0.26.0:
|
||||||
|
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
|
||||||
|
|
||||||
|
semver@7.7.2:
|
||||||
|
resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
sharp@0.34.4:
|
||||||
|
resolution: {integrity: sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
|
|
||||||
|
source-map-js@1.2.1:
|
||||||
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
styled-jsx@5.1.6:
|
||||||
|
resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==}
|
||||||
|
engines: {node: '>= 12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@babel/core': '*'
|
||||||
|
babel-plugin-macros: '*'
|
||||||
|
react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@babel/core':
|
||||||
|
optional: true
|
||||||
|
babel-plugin-macros:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
tailwindcss@4.1.13:
|
||||||
|
resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==}
|
||||||
|
|
||||||
|
tapable@2.2.3:
|
||||||
|
resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
tar@7.4.4:
|
||||||
|
resolution: {integrity: sha512-O1z7ajPkjTgEgmTGz0v9X4eqeEXTDREPTO77pVC1Nbs86feBU1Zhdg+edzavPmYW1olxkwsqA2v4uOw6E8LeDg==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
tslib@2.8.1:
|
||||||
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
typescript@5.9.2:
|
||||||
|
resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
|
||||||
|
engines: {node: '>=14.17'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
undici-types@6.21.0:
|
||||||
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
|
yallist@5.0.0:
|
||||||
|
resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
|
|
||||||
|
'@emnapi/runtime@1.5.0':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/colour@1.0.0':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-darwin-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-darwin-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-darwin-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-arm@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-ppc64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-s390x@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linux-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64@1.2.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-arm@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-ppc64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-s390x@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linux-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-arm64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-linuxmusl-x64@0.34.4':
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-wasm32@0.34.4':
|
||||||
|
dependencies:
|
||||||
|
'@emnapi/runtime': 1.5.0
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-arm64@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-ia32@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@img/sharp-win32-x64@0.34.4':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@isaacs/fs-minipass@4.0.1':
|
||||||
|
dependencies:
|
||||||
|
minipass: 7.1.2
|
||||||
|
|
||||||
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
|
|
||||||
|
'@jridgewell/remapping@2.3.5':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/gen-mapping': 0.3.13
|
||||||
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
|
|
||||||
|
'@jridgewell/resolve-uri@3.1.2': {}
|
||||||
|
|
||||||
|
'@jridgewell/sourcemap-codec@1.5.5': {}
|
||||||
|
|
||||||
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@next/env@15.5.3': {}
|
||||||
|
|
||||||
|
'@next/swc-darwin-arm64@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-darwin-x64@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-linux-arm64-gnu@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-linux-arm64-musl@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-linux-x64-gnu@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-linux-x64-musl@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-win32-arm64-msvc@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@next/swc-win32-x64-msvc@15.5.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@swc/helpers@0.5.15':
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
|
'@tailwindcss/node@4.1.13':
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/remapping': 2.3.5
|
||||||
|
enhanced-resolve: 5.18.3
|
||||||
|
jiti: 2.5.1
|
||||||
|
lightningcss: 1.30.1
|
||||||
|
magic-string: 0.30.19
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
tailwindcss: 4.1.13
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-android-arm64@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-arm64@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-darwin-x64@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-freebsd-x64@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc@4.1.13':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tailwindcss/oxide@4.1.13':
|
||||||
|
dependencies:
|
||||||
|
detect-libc: 2.1.0
|
||||||
|
tar: 7.4.4
|
||||||
|
optionalDependencies:
|
||||||
|
'@tailwindcss/oxide-android-arm64': 4.1.13
|
||||||
|
'@tailwindcss/oxide-darwin-arm64': 4.1.13
|
||||||
|
'@tailwindcss/oxide-darwin-x64': 4.1.13
|
||||||
|
'@tailwindcss/oxide-freebsd-x64': 4.1.13
|
||||||
|
'@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13
|
||||||
|
'@tailwindcss/oxide-linux-arm64-gnu': 4.1.13
|
||||||
|
'@tailwindcss/oxide-linux-arm64-musl': 4.1.13
|
||||||
|
'@tailwindcss/oxide-linux-x64-gnu': 4.1.13
|
||||||
|
'@tailwindcss/oxide-linux-x64-musl': 4.1.13
|
||||||
|
'@tailwindcss/oxide-wasm32-wasi': 4.1.13
|
||||||
|
'@tailwindcss/oxide-win32-arm64-msvc': 4.1.13
|
||||||
|
'@tailwindcss/oxide-win32-x64-msvc': 4.1.13
|
||||||
|
|
||||||
|
'@tailwindcss/postcss@4.1.13':
|
||||||
|
dependencies:
|
||||||
|
'@alloc/quick-lru': 5.2.0
|
||||||
|
'@tailwindcss/node': 4.1.13
|
||||||
|
'@tailwindcss/oxide': 4.1.13
|
||||||
|
postcss: 8.5.6
|
||||||
|
tailwindcss: 4.1.13
|
||||||
|
|
||||||
|
'@types/node@20.19.17':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 6.21.0
|
||||||
|
|
||||||
|
'@types/react-dom@19.1.9(@types/react@19.1.13)':
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 19.1.13
|
||||||
|
|
||||||
|
'@types/react@19.1.13':
|
||||||
|
dependencies:
|
||||||
|
csstype: 3.1.3
|
||||||
|
|
||||||
|
caniuse-lite@1.0.30001743: {}
|
||||||
|
|
||||||
|
chownr@3.0.0: {}
|
||||||
|
|
||||||
|
client-only@0.0.1: {}
|
||||||
|
|
||||||
|
csstype@3.1.3: {}
|
||||||
|
|
||||||
|
detect-libc@2.1.0: {}
|
||||||
|
|
||||||
|
enhanced-resolve@5.18.3:
|
||||||
|
dependencies:
|
||||||
|
graceful-fs: 4.2.11
|
||||||
|
tapable: 2.2.3
|
||||||
|
|
||||||
|
graceful-fs@4.2.11: {}
|
||||||
|
|
||||||
|
jiti@2.5.1: {}
|
||||||
|
|
||||||
|
lightningcss-darwin-arm64@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-darwin-x64@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-freebsd-x64@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm-gnueabihf@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-gnu@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-arm64-musl@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-x64-gnu@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-linux-x64-musl@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-win32-arm64-msvc@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss-win32-x64-msvc@1.30.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
lightningcss@1.30.1:
|
||||||
|
dependencies:
|
||||||
|
detect-libc: 2.1.0
|
||||||
|
optionalDependencies:
|
||||||
|
lightningcss-darwin-arm64: 1.30.1
|
||||||
|
lightningcss-darwin-x64: 1.30.1
|
||||||
|
lightningcss-freebsd-x64: 1.30.1
|
||||||
|
lightningcss-linux-arm-gnueabihf: 1.30.1
|
||||||
|
lightningcss-linux-arm64-gnu: 1.30.1
|
||||||
|
lightningcss-linux-arm64-musl: 1.30.1
|
||||||
|
lightningcss-linux-x64-gnu: 1.30.1
|
||||||
|
lightningcss-linux-x64-musl: 1.30.1
|
||||||
|
lightningcss-win32-arm64-msvc: 1.30.1
|
||||||
|
lightningcss-win32-x64-msvc: 1.30.1
|
||||||
|
|
||||||
|
magic-string@0.30.19:
|
||||||
|
dependencies:
|
||||||
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
minipass@7.1.2: {}
|
||||||
|
|
||||||
|
minizlib@3.1.0:
|
||||||
|
dependencies:
|
||||||
|
minipass: 7.1.2
|
||||||
|
|
||||||
|
nanoid@3.3.11: {}
|
||||||
|
|
||||||
|
next@15.5.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
'@next/env': 15.5.3
|
||||||
|
'@swc/helpers': 0.5.15
|
||||||
|
caniuse-lite: 1.0.30001743
|
||||||
|
postcss: 8.4.31
|
||||||
|
react: 19.1.0
|
||||||
|
react-dom: 19.1.0(react@19.1.0)
|
||||||
|
styled-jsx: 5.1.6(react@19.1.0)
|
||||||
|
optionalDependencies:
|
||||||
|
'@next/swc-darwin-arm64': 15.5.3
|
||||||
|
'@next/swc-darwin-x64': 15.5.3
|
||||||
|
'@next/swc-linux-arm64-gnu': 15.5.3
|
||||||
|
'@next/swc-linux-arm64-musl': 15.5.3
|
||||||
|
'@next/swc-linux-x64-gnu': 15.5.3
|
||||||
|
'@next/swc-linux-x64-musl': 15.5.3
|
||||||
|
'@next/swc-win32-arm64-msvc': 15.5.3
|
||||||
|
'@next/swc-win32-x64-msvc': 15.5.3
|
||||||
|
sharp: 0.34.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@babel/core'
|
||||||
|
- babel-plugin-macros
|
||||||
|
|
||||||
|
picocolors@1.1.1: {}
|
||||||
|
|
||||||
|
postcss@8.4.31:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.11
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
postcss@8.5.6:
|
||||||
|
dependencies:
|
||||||
|
nanoid: 3.3.11
|
||||||
|
picocolors: 1.1.1
|
||||||
|
source-map-js: 1.2.1
|
||||||
|
|
||||||
|
react-dom@19.1.0(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
react: 19.1.0
|
||||||
|
scheduler: 0.26.0
|
||||||
|
|
||||||
|
react@19.1.0: {}
|
||||||
|
|
||||||
|
scheduler@0.26.0: {}
|
||||||
|
|
||||||
|
semver@7.7.2:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
sharp@0.34.4:
|
||||||
|
dependencies:
|
||||||
|
'@img/colour': 1.0.0
|
||||||
|
detect-libc: 2.1.0
|
||||||
|
semver: 7.7.2
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-darwin-arm64': 0.34.4
|
||||||
|
'@img/sharp-darwin-x64': 0.34.4
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-ppc64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.2.3
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.2.3
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.2.3
|
||||||
|
'@img/sharp-linux-arm': 0.34.4
|
||||||
|
'@img/sharp-linux-arm64': 0.34.4
|
||||||
|
'@img/sharp-linux-ppc64': 0.34.4
|
||||||
|
'@img/sharp-linux-s390x': 0.34.4
|
||||||
|
'@img/sharp-linux-x64': 0.34.4
|
||||||
|
'@img/sharp-linuxmusl-arm64': 0.34.4
|
||||||
|
'@img/sharp-linuxmusl-x64': 0.34.4
|
||||||
|
'@img/sharp-wasm32': 0.34.4
|
||||||
|
'@img/sharp-win32-arm64': 0.34.4
|
||||||
|
'@img/sharp-win32-ia32': 0.34.4
|
||||||
|
'@img/sharp-win32-x64': 0.34.4
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
|
styled-jsx@5.1.6(react@19.1.0):
|
||||||
|
dependencies:
|
||||||
|
client-only: 0.0.1
|
||||||
|
react: 19.1.0
|
||||||
|
|
||||||
|
tailwindcss@4.1.13: {}
|
||||||
|
|
||||||
|
tapable@2.2.3: {}
|
||||||
|
|
||||||
|
tar@7.4.4:
|
||||||
|
dependencies:
|
||||||
|
'@isaacs/fs-minipass': 4.0.1
|
||||||
|
chownr: 3.0.0
|
||||||
|
minipass: 7.1.2
|
||||||
|
minizlib: 3.1.0
|
||||||
|
yallist: 5.0.0
|
||||||
|
|
||||||
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
typescript@5.9.2: {}
|
||||||
|
|
||||||
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
|
yallist@5.0.0: {}
|
||||||
5
postcss.config.mjs
Normal file
5
postcss.config.mjs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: ["@tailwindcss/postcss"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
1
public/file.svg
Normal file
1
public/file.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
public/globe.svg
Normal file
1
public/globe.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
public/next.svg
Normal file
1
public/next.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
public/vercel.svg
Normal file
1
public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
1
public/window.svg
Normal file
1
public/window.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2017",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user