Compare commits
No commits in common. "c6b7736daca35b244b7674e2193a835ba7ab3e5c" and "58b4e2613c5df3df1aa4ae23d89c41a9db0e96f9" have entirely different histories.
c6b7736dac
...
58b4e2613c
8
bun.lock
8
bun.lock
@ -23,8 +23,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/core": {
|
"packages/core": {
|
||||||
"name": "@cvsa/core",
|
"name": "core",
|
||||||
"version": "0.0.1",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koshnic/ratelimit": "^1.0.3",
|
"@koshnic/ratelimit": "^1.0.3",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
@ -35,7 +34,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ioredis": "^5.0.0",
|
"@types/ioredis": "^5.0.0",
|
||||||
"typescript": "^5.8.3",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"packages/crawler": {
|
"packages/crawler": {
|
||||||
@ -114,8 +112,6 @@
|
|||||||
|
|
||||||
"@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="],
|
"@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="],
|
||||||
|
|
||||||
"@cvsa/core": ["@cvsa/core@workspace:packages/core"],
|
|
||||||
|
|
||||||
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="],
|
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="],
|
||||||
|
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||||
@ -532,6 +528,8 @@
|
|||||||
|
|
||||||
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"core": ["core@workspace:packages/core"],
|
||||||
|
|
||||||
"crawler": ["crawler@workspace:packages/crawler"],
|
"crawler": ["crawler@workspace:packages/crawler"],
|
||||||
|
|
||||||
"cron-parser": ["cron-parser@4.9.0", "", { "dependencies": { "luxon": "^3.2.1" } }, "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q=="],
|
"cron-parser": ["cron-parser@4.9.0", "", { "dependencies": { "luxon": "^3.2.1" } }, "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q=="],
|
||||||
|
@ -4,7 +4,7 @@ import { SlidingWindow } from "@core/mq/slidingWindow.ts";
|
|||||||
import { getCaptchaConfigMaxDuration, getCurrentCaptchaDifficulty } from "@/lib/auth/captchaDifficulty.ts";
|
import { getCaptchaConfigMaxDuration, getCurrentCaptchaDifficulty } from "@/lib/auth/captchaDifficulty.ts";
|
||||||
import { sqlCred } from "@core/db/dbNew.ts";
|
import { sqlCred } from "@core/db/dbNew.ts";
|
||||||
import { redis } from "@core/db/redis.ts";
|
import { redis } from "@core/db/redis.ts";
|
||||||
import { verify } from "hono/jwt";
|
import { verify } from 'hono/jwt';
|
||||||
import { JwtTokenInvalid, JwtTokenExpired } from "hono/utils/jwt/types";
|
import { JwtTokenInvalid, JwtTokenExpired } from "hono/utils/jwt/types";
|
||||||
import { getJWTsecret } from "@/lib/auth/getJWTsecret.ts";
|
import { getJWTsecret } from "@/lib/auth/getJWTsecret.ts";
|
||||||
import { lockManager } from "@core/mq/lockManager.ts";
|
import { lockManager } from "@core/mq/lockManager.ts";
|
||||||
@ -23,8 +23,7 @@ export const captchaMiddleware = async (c: Context, next: Next) => {
|
|||||||
if (!authHeader) {
|
if (!authHeader) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "'Authorization' header is missing.",
|
message: "'Authorization' header is missing.",
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 401);
|
return c.json<ErrorResponse>(response, 401);
|
||||||
}
|
}
|
||||||
@ -33,8 +32,7 @@ export const captchaMiddleware = async (c: Context, next: Next) => {
|
|||||||
if (!authIsBearer || authHeader.length < 8) {
|
if (!authIsBearer || authHeader.length < 8) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "'Authorization' header is invalid.",
|
message: "'Authorization' header is invalid.",
|
||||||
code: "INVALID_HEADER",
|
code: "INVALID_HEADER"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
}
|
}
|
||||||
@ -62,48 +60,47 @@ export const captchaMiddleware = async (c: Context, next: Next) => {
|
|||||||
if (consumed) {
|
if (consumed) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Token has already been used.",
|
message: "Token has already been used.",
|
||||||
code: "INVALID_CREDENTIALS",
|
code: "INVALID_CREDENTIALS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 401);
|
return c.json<ErrorResponse>(response, 401);
|
||||||
}
|
}
|
||||||
if (difficulty < requiredDifficulty) {
|
if (difficulty < requiredDifficulty) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Token too weak.",
|
message: "Token too weak.",
|
||||||
code: "UNAUTHORIZED",
|
code: "UNAUTHORIZED"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 401);
|
return c.json<ErrorResponse>(response, 401);
|
||||||
}
|
}
|
||||||
const EXPIRE_FIVE_MINUTES = 300;
|
const EXPIRE_FIVE_MINUTES = 300;
|
||||||
await lockManager.acquireLock(tokenID, EXPIRE_FIVE_MINUTES);
|
await lockManager.acquireLock(tokenID, EXPIRE_FIVE_MINUTES);
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
if (e instanceof JwtTokenInvalid) {
|
if (e instanceof JwtTokenInvalid) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Failed to verify the token.",
|
message: "Failed to verify the token.",
|
||||||
code: "INVALID_CREDENTIALS",
|
code: "INVALID_CREDENTIALS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
} else if (e instanceof JwtTokenExpired) {
|
}
|
||||||
|
else if (e instanceof JwtTokenExpired) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Token expired.",
|
message: "Token expired.",
|
||||||
code: "INVALID_CREDENTIALS",
|
code: "INVALID_CREDENTIALS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
} else if (e instanceof ValidationError) {
|
}
|
||||||
|
else if (e instanceof ValidationError) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
code: "INVALID_QUERY_PARAMS",
|
code: "INVALID_QUERY_PARAMS",
|
||||||
message: "Invalid query parameters",
|
message: "Invalid query parameters",
|
||||||
errors: e.errors
|
errors: e.errors
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Unknown error.",
|
message: "Unknown error.",
|
||||||
code: "UNKNOWN_ERROR",
|
code: "UNKNOWN_ERROR"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 500);
|
return c.json<ErrorResponse>(response, 500);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Context, Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { Variables } from "hono/types";
|
import { Variables } from "hono/types";
|
||||||
import { bodyLimitForPing } from "./bodyLimits.ts";
|
import { bodyLimitForPing } from "./bodyLimits.ts";
|
||||||
import { pingHandler } from "routes/ping";
|
import { pingHandler } from "routes/ping";
|
||||||
@ -8,21 +8,10 @@ import { logger } from "./logger.ts";
|
|||||||
import { timing } from "hono/timing";
|
import { timing } from "hono/timing";
|
||||||
import { contentType } from "./contentType.ts";
|
import { contentType } from "./contentType.ts";
|
||||||
import { captchaMiddleware } from "./captcha.ts";
|
import { captchaMiddleware } from "./captcha.ts";
|
||||||
import { cors } from "hono/cors";
|
import { cors } from 'hono/cors';
|
||||||
|
|
||||||
export function configureMiddleWares(app: Hono<{ Variables: Variables }>) {
|
export function configureMiddleWares(app: Hono<{ Variables: Variables }>) {
|
||||||
app.use("*", async (c, next) => {
|
app.all("*", cors());
|
||||||
if (c.req.path === "/user") {
|
|
||||||
const corsMiddlewareHandler = cors({
|
|
||||||
origin: c.req.header("Origin"),
|
|
||||||
credentials: true
|
|
||||||
});
|
|
||||||
return corsMiddlewareHandler(c, next);
|
|
||||||
}
|
|
||||||
const corsMiddlewareHandler = cors();
|
|
||||||
return corsMiddlewareHandler(c, next);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use("*", contentType);
|
app.use("*", contentType);
|
||||||
app.use(timing());
|
app.use(timing());
|
||||||
app.use("*", preetifyResponse);
|
app.use("*", preetifyResponse);
|
||||||
|
@ -6,8 +6,8 @@ import { RateLimiter } from "@koshnic/ratelimit";
|
|||||||
import { ErrorResponse } from "@/src/schema";
|
import { ErrorResponse } from "@/src/schema";
|
||||||
import { redis } from "@core/db/redis.ts";
|
import { redis } from "@core/db/redis.ts";
|
||||||
|
|
||||||
export const getUserIP = (c: Context) => {
|
export const getIdentifier = (c: Context, includeIP: boolean = true) => {
|
||||||
let ipAddr = null;
|
let ipAddr = generateRandomId(6);
|
||||||
const info = getConnInfo(c);
|
const info = getConnInfo(c);
|
||||||
if (info.remote && info.remote.address) {
|
if (info.remote && info.remote.address) {
|
||||||
ipAddr = info.remote.address;
|
ipAddr = info.remote.address;
|
||||||
@ -16,14 +16,6 @@ export const getUserIP = (c: Context) => {
|
|||||||
if (forwardedFor) {
|
if (forwardedFor) {
|
||||||
ipAddr = forwardedFor.split(",")[0];
|
ipAddr = forwardedFor.split(",")[0];
|
||||||
}
|
}
|
||||||
return ipAddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getIdentifier = (c: Context, includeIP: boolean = true) => {
|
|
||||||
let ipAddr = generateRandomId(6);
|
|
||||||
if (getUserIP(c)) {
|
|
||||||
ipAddr = getUserIP(c);
|
|
||||||
}
|
|
||||||
const path = c.req.path;
|
const path = c.req.path;
|
||||||
const method = c.req.method;
|
const method = c.req.method;
|
||||||
const ipIdentifier = includeIP ? `@${ipAddr}` : "";
|
const ipIdentifier = includeIP ? `@${ipAddr}` : "";
|
||||||
|
@ -2,7 +2,7 @@ import { Context } from "hono";
|
|||||||
import { Bindings, BlankEnv } from "hono/types";
|
import { Bindings, BlankEnv } from "hono/types";
|
||||||
import { ErrorResponse } from "src/schema";
|
import { ErrorResponse } from "src/schema";
|
||||||
import { createHandlers } from "src/utils.ts";
|
import { createHandlers } from "src/utils.ts";
|
||||||
import { sign } from "hono/jwt";
|
import { sign } from 'hono/jwt'
|
||||||
import { generateRandomId } from "@core/lib/randomID.ts";
|
import { generateRandomId } from "@core/lib/randomID.ts";
|
||||||
import { getJWTsecret } from "lib/auth/getJWTsecret.ts";
|
import { getJWTsecret } from "lib/auth/getJWTsecret.ts";
|
||||||
|
|
||||||
@ -34,8 +34,7 @@ export const verifyChallengeHandler = createHandlers(
|
|||||||
if (!ans) {
|
if (!ans) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Missing required query parameter: ans",
|
message: "Missing required query parameter: ans",
|
||||||
code: "INVALID_QUERY_PARAMS",
|
code: "INVALID_QUERY_PARAMS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
}
|
}
|
||||||
@ -44,33 +43,26 @@ export const verifyChallengeHandler = createHandlers(
|
|||||||
if (data.error && res.status === 404) {
|
if (data.error && res.status === 404) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: data.error,
|
message: data.error,
|
||||||
code: "ENTITY_NOT_FOUND",
|
code: "ENTITY_NOT_FOUND"
|
||||||
i18n: {
|
|
||||||
key: "backend.error.captcha_not_found"
|
|
||||||
},
|
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 401);
|
return c.json<ErrorResponse>(response, 401);
|
||||||
} else if (data.error && res.status === 400) {
|
} else if (data.error && res.status === 400) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: data.error,
|
message: data.error,
|
||||||
code: "INVALID_QUERY_PARAMS",
|
code: "INVALID_QUERY_PARAMS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 400);
|
return c.json<ErrorResponse>(response, 400);
|
||||||
} else if (data.error) {
|
} else if (data.error) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: data.error,
|
message: data.error,
|
||||||
code: "UNKNOWN_ERROR",
|
code: "UNKNOWN_ERROR"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 500);
|
return c.json<ErrorResponse>(response, 500);
|
||||||
}
|
}
|
||||||
if (!data.success) {
|
if (!data.success) {
|
||||||
const response: ErrorResponse = {
|
const response: ErrorResponse = {
|
||||||
message: "Incorrect answer",
|
message: "Incorrect answer",
|
||||||
code: "INVALID_CREDENTIALS",
|
code: "INVALID_CREDENTIALS"
|
||||||
errors: []
|
|
||||||
};
|
};
|
||||||
return c.json<ErrorResponse>(response, 401);
|
return c.json<ErrorResponse>(response, 401);
|
||||||
}
|
}
|
||||||
@ -82,16 +74,13 @@ export const verifyChallengeHandler = createHandlers(
|
|||||||
const jwtSecret = r as string;
|
const jwtSecret = r as string;
|
||||||
|
|
||||||
const tokenID = generateRandomId(6);
|
const tokenID = generateRandomId(6);
|
||||||
const NOW = Math.floor(Date.now() / 1000);
|
const NOW = Math.floor(Date.now() / 1000)
|
||||||
const FIVE_MINUTES_LATER = NOW + 60 * 5;
|
const FIVE_MINUTES_LATER = NOW + 60 * 5;
|
||||||
const jwt = await sign(
|
const jwt = await sign({
|
||||||
{
|
|
||||||
difficulty: data.difficulty!,
|
difficulty: data.difficulty!,
|
||||||
id: tokenID,
|
id: tokenID,
|
||||||
exp: FIVE_MINUTES_LATER
|
exp: FIVE_MINUTES_LATER
|
||||||
},
|
}, jwtSecret);
|
||||||
jwtSecret
|
|
||||||
);
|
|
||||||
return c.json({
|
return c.json({
|
||||||
token: jwt
|
token: jwt
|
||||||
});
|
});
|
||||||
|
@ -2,13 +2,21 @@ import { createHandlers } from "src/utils.ts";
|
|||||||
import { getCurrentCaptchaDifficulty } from "@/lib/auth/captchaDifficulty.ts";
|
import { getCurrentCaptchaDifficulty } from "@/lib/auth/captchaDifficulty.ts";
|
||||||
import { sqlCred } from "@core/db/dbNew.ts";
|
import { sqlCred } from "@core/db/dbNew.ts";
|
||||||
import { object, string, ValidationError } from "yup";
|
import { object, string, ValidationError } from "yup";
|
||||||
import { CaptchaSessionResponse, ErrorResponse } from "@/src/schema";
|
import { ErrorResponse } from "@/src/schema";
|
||||||
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
||||||
|
|
||||||
const bodySchema = object({
|
const bodySchema = object({
|
||||||
route: string().matches(/(?:GET|POST|PUT|PATCH|DELETE)-\/.*/g)
|
route: string().matches(/(?:GET|POST|PUT|PATCH|DELETE)-\/.*/g)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface CaptchaSessionResponse {
|
||||||
|
success: boolean;
|
||||||
|
id: string;
|
||||||
|
g: string;
|
||||||
|
n: string;
|
||||||
|
t: number;
|
||||||
|
}
|
||||||
|
|
||||||
const createNewChallenge = async (difficulty: number) => {
|
const createNewChallenge = async (difficulty: number) => {
|
||||||
const baseURL = process.env["UCAPTCHA_URL"];
|
const baseURL = process.env["UCAPTCHA_URL"];
|
||||||
const url = new URL(baseURL);
|
const url = new URL(baseURL);
|
||||||
@ -16,19 +24,19 @@ const createNewChallenge = async (difficulty: number) => {
|
|||||||
return await fetch(url.toString(), {
|
return await fetch(url.toString(), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
difficulty: difficulty
|
difficulty: difficulty,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
export const createCaptchaSessionHandler = createHandlers(async (c) => {
|
export const createCaptchaSessionHandler = createHandlers(async (c) => {
|
||||||
try {
|
try {
|
||||||
const requestBody = await bodySchema.validate(await c.req.json());
|
const requestBody = await bodySchema.validate(await c.req.json());
|
||||||
const { route } = requestBody;
|
const { route } = requestBody;
|
||||||
const difficuly = await getCurrentCaptchaDifficulty(sqlCred, route);
|
const difficuly = await getCurrentCaptchaDifficulty(sqlCred, route)
|
||||||
const res = await createNewChallenge(difficuly);
|
const res = await createNewChallenge(difficuly);
|
||||||
return c.json<CaptchaSessionResponse|unknown>(await res.json(), res.status as ContentfulStatusCode);
|
return c.json<CaptchaSessionResponse|unknown>(await res.json(), res.status as ContentfulStatusCode);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
import { createHandlers } from "src/utils.ts";
|
|
||||||
import Argon2id from "@rabbit-company/argon2id";
|
|
||||||
import { object, string, ValidationError } from "yup";
|
|
||||||
import type { Context } from "hono";
|
|
||||||
import type { Bindings, BlankEnv, BlankInput } from "hono/types";
|
|
||||||
import { sqlCred } from "@core/db/dbNew.ts";
|
|
||||||
import { ErrorResponse, SignUpResponse } from "src/schema";
|
|
||||||
import { generateRandomId } from "@core/lib/randomID";
|
|
||||||
import { getUserIP } from "@/middleware/rateLimiters";
|
|
||||||
import { setCookie } from "hono/cookie";
|
|
||||||
|
|
||||||
const RegistrationBodySchema = object({
|
|
||||||
username: string().trim().required("Username is required").max(50, "Username cannot exceed 50 characters"),
|
|
||||||
password: string().required("Password is required"),
|
|
||||||
nickname: string().optional()
|
|
||||||
});
|
|
||||||
|
|
||||||
type ContextType = Context<BlankEnv & { Bindings: Bindings }, "/user", BlankInput>;
|
|
||||||
|
|
||||||
export const userExists = async (username: string) => {
|
|
||||||
const result = await sqlCred`
|
|
||||||
SELECT 1
|
|
||||||
FROM users
|
|
||||||
WHERE username = ${username}
|
|
||||||
`;
|
|
||||||
return result.length > 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createLoginSession = async (uid: number, ua?: string, ip?: string): Promise<string> => {
|
|
||||||
const ip_address = ip || null;
|
|
||||||
const user_agent = ua || null;
|
|
||||||
const id = generateRandomId(24);
|
|
||||||
await sqlCred`
|
|
||||||
INSERT INTO login_sessions (id, uid, expire_at, ip_address, user_agent)
|
|
||||||
VALUES (${id}, ${uid}, CURRENT_TIMESTAMP + INTERVAL '1 year', ${ip_address}, ${user_agent})
|
|
||||||
`;
|
|
||||||
return id;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUserIDByName = async (username: string) => {
|
|
||||||
const result = await sqlCred<{ id: number }[]>`
|
|
||||||
SELECT id
|
|
||||||
FROM users
|
|
||||||
WHERE username = ${username}
|
|
||||||
`;
|
|
||||||
if (result.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return result[0].id;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const registerHandler = createHandlers(async (c: ContextType) => {
|
|
||||||
try {
|
|
||||||
const body = await RegistrationBodySchema.validate(await c.req.json());
|
|
||||||
const { username, password, nickname } = body;
|
|
||||||
|
|
||||||
if (await userExists(username)) {
|
|
||||||
const response: ErrorResponse = {
|
|
||||||
message: `User "${username}" already exists.`,
|
|
||||||
code: "ENTITY_EXISTS",
|
|
||||||
errors: [],
|
|
||||||
i18n: {
|
|
||||||
key: "backend.error.user_exists",
|
|
||||||
values: {
|
|
||||||
username: username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse>(response, 400);
|
|
||||||
}
|
|
||||||
|
|
||||||
const hash = await Argon2id.hashEncoded(password);
|
|
||||||
|
|
||||||
await sqlCred`
|
|
||||||
INSERT INTO users (username, password, nickname)
|
|
||||||
VALUES (${username}, ${hash}, ${nickname ? nickname : null})
|
|
||||||
`;
|
|
||||||
|
|
||||||
const uid = await getUserIDByName(username);
|
|
||||||
|
|
||||||
if (!uid) {
|
|
||||||
const response: ErrorResponse<string> = {
|
|
||||||
message: "Cannot find registered user.",
|
|
||||||
errors: [`Cannot find user ${username} in table 'users'.`],
|
|
||||||
code: "ENTITY_NOT_FOUND",
|
|
||||||
i18n: {
|
|
||||||
key: "backend.error.user_not_found_after_register",
|
|
||||||
values: {
|
|
||||||
username: username
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse<string>>(response, 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
const sessionID = await createLoginSession(uid, c.req.header("User-Agent"), getUserIP(c));
|
|
||||||
|
|
||||||
const response: SignUpResponse = {
|
|
||||||
username: username,
|
|
||||||
token: sessionID
|
|
||||||
};
|
|
||||||
|
|
||||||
const A_YEAR = 365 * 86400;
|
|
||||||
const isDev = process.env.NODE_ENV === "development";
|
|
||||||
|
|
||||||
setCookie(c, "session_id", sessionID, {
|
|
||||||
path: "/",
|
|
||||||
maxAge: A_YEAR,
|
|
||||||
domain: process.env.DOMAIN,
|
|
||||||
secure: isDev ? false : true,
|
|
||||||
sameSite: "Lax"
|
|
||||||
});
|
|
||||||
|
|
||||||
return c.json<SignUpResponse>(response, 201);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof ValidationError) {
|
|
||||||
const response: ErrorResponse<string> = {
|
|
||||||
message: "Invalid registration data.",
|
|
||||||
errors: e.errors,
|
|
||||||
code: "INVALID_PAYLOAD"
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse<string>>(response, 400);
|
|
||||||
} else if (e instanceof SyntaxError) {
|
|
||||||
const response: ErrorResponse<string> = {
|
|
||||||
message: "Invalid JSON payload.",
|
|
||||||
errors: [e.message],
|
|
||||||
code: "INVALID_FORMAT"
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse<string>>(response, 400);
|
|
||||||
} else {
|
|
||||||
const response: ErrorResponse<string> = {
|
|
||||||
message: "Unknown error.",
|
|
||||||
errors: [(e as Error).message],
|
|
||||||
code: "UNKNOWN_ERROR"
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse<string>>(response, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
@ -1,2 +1 @@
|
|||||||
export * from "./POST.ts";
|
export * from "./register.ts";
|
||||||
export * from "./session/[id]/GET.ts";
|
|
||||||
|
74
packages/backend/routes/user/register.ts
Normal file
74
packages/backend/routes/user/register.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { createHandlers } from "src/utils.ts";
|
||||||
|
import Argon2id from "@rabbit-company/argon2id";
|
||||||
|
import { object, string, ValidationError } from "yup";
|
||||||
|
import type { Context } from "hono";
|
||||||
|
import type { Bindings, BlankEnv, BlankInput } from "hono/types";
|
||||||
|
import { sqlCred } from "@core/db/dbNew.ts";
|
||||||
|
import { ErrorResponse, StatusResponse } from "src/schema";
|
||||||
|
|
||||||
|
const RegistrationBodySchema = object({
|
||||||
|
username: string().trim().required("Username is required").max(50, "Username cannot exceed 50 characters"),
|
||||||
|
password: string().required("Password is required"),
|
||||||
|
nickname: string().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
type ContextType = Context<BlankEnv & { Bindings: Bindings }, "/user", BlankInput>;
|
||||||
|
|
||||||
|
export const userExists = async (username: string) => {
|
||||||
|
const result = await sqlCred`
|
||||||
|
SELECT 1
|
||||||
|
FROM users
|
||||||
|
WHERE username = ${username}
|
||||||
|
`;
|
||||||
|
return result.length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const registerHandler = createHandlers(async (c: ContextType) => {
|
||||||
|
try {
|
||||||
|
const body = await RegistrationBodySchema.validate(await c.req.json());
|
||||||
|
const { username, password, nickname } = body;
|
||||||
|
|
||||||
|
if (await userExists(username)) {
|
||||||
|
const response: StatusResponse = {
|
||||||
|
message: `User "${username}" already exists.`
|
||||||
|
};
|
||||||
|
return c.json<StatusResponse>(response, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = await Argon2id.hashEncoded(password);
|
||||||
|
|
||||||
|
await sqlCred`
|
||||||
|
INSERT INTO users (username, password, nickname)
|
||||||
|
VALUES (${username}, ${hash}, ${nickname ? nickname : null})
|
||||||
|
`;
|
||||||
|
|
||||||
|
const response: StatusResponse = {
|
||||||
|
message: `User '${username}' registered successfully.`
|
||||||
|
};
|
||||||
|
|
||||||
|
return c.json<StatusResponse>(response, 201);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof ValidationError) {
|
||||||
|
const response: ErrorResponse<string> = {
|
||||||
|
message: "Invalid registration data.",
|
||||||
|
errors: e.errors,
|
||||||
|
code: "INVALID_PAYLOAD"
|
||||||
|
};
|
||||||
|
return c.json<ErrorResponse<string>>(response, 400);
|
||||||
|
} else if (e instanceof SyntaxError) {
|
||||||
|
const response: ErrorResponse<string> = {
|
||||||
|
message: "Invalid JSON payload.",
|
||||||
|
errors: [e.message],
|
||||||
|
code: "INVALID_FORMAT"
|
||||||
|
};
|
||||||
|
return c.json<ErrorResponse<string>>(response, 400);
|
||||||
|
} else {
|
||||||
|
const response: ErrorResponse<string> = {
|
||||||
|
message: "Unknown error.",
|
||||||
|
errors: [(e as Error).message],
|
||||||
|
code: "UNKNOWN_ERROR"
|
||||||
|
};
|
||||||
|
return c.json<ErrorResponse<string>>(response, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -1,32 +0,0 @@
|
|||||||
import { Context } from "hono";
|
|
||||||
import { Bindings, BlankEnv } from "hono/types";
|
|
||||||
import { ErrorResponse } from "src/schema";
|
|
||||||
import { createHandlers } from "src/utils.ts";
|
|
||||||
import { sqlCred } from "@core/db/dbNew";
|
|
||||||
import { DatabaseUserType } from "@core/db/schema";
|
|
||||||
|
|
||||||
export const getUserByLoginSessionHandler = createHandlers(
|
|
||||||
async (c: Context<BlankEnv & { Bindings: Bindings }, "/user/session/:id">) => {
|
|
||||||
const id = c.req.param("id");
|
|
||||||
const users = await sqlCred<DatabaseUserType[]>`
|
|
||||||
SELECT u.*
|
|
||||||
FROM users u
|
|
||||||
JOIN login_sessions ls ON u.id = ls.uid
|
|
||||||
WHERE ls.id = ${id};
|
|
||||||
`;
|
|
||||||
if (users.length === 0) {
|
|
||||||
const response: ErrorResponse = {
|
|
||||||
message: "Cannot find user",
|
|
||||||
code: "ENTITY_NOT_FOUND",
|
|
||||||
errors: []
|
|
||||||
};
|
|
||||||
return c.json<ErrorResponse>(response, 404);
|
|
||||||
}
|
|
||||||
const user = users[0];
|
|
||||||
return c.json({
|
|
||||||
username: user.username,
|
|
||||||
nickname: user.nickname,
|
|
||||||
role: user.role
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,23 +1,23 @@
|
|||||||
import { rootHandler } from "routes";
|
import { rootHandler } from "routes";
|
||||||
import { pingHandler } from "routes/ping";
|
import { pingHandler } from "routes/ping";
|
||||||
import { getUserByLoginSessionHandler, registerHandler } from "routes/user";
|
import { registerHandler } from "routes/user";
|
||||||
import { videoInfoHandler, getSnapshotsHanlder } from "routes/video";
|
import { videoInfoHandler, getSnapshotsHanlder } from "routes/video";
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { Variables } from "hono/types";
|
import { Variables } from "hono/types";
|
||||||
import { createCaptchaSessionHandler, verifyChallengeHandler } from "routes/captcha";
|
import { createCaptchaSessionHandler, verifyChallengeHandler } from "routes/captcha";
|
||||||
import { getCaptchaDifficultyHandler } from "routes/captcha/difficulty/GET.ts";
|
import { getCaptchaDifficultyHandler } from "../routes/captcha/difficulty/GET.ts";
|
||||||
|
|
||||||
export function configureRoutes(app: Hono<{ Variables: Variables }>) {
|
export function configureRoutes(app: Hono<{ Variables: Variables }>) {
|
||||||
app.get("/", ...rootHandler);
|
app.get("/", ...rootHandler);
|
||||||
app.all("/ping", ...pingHandler);
|
app.all("/ping", ...pingHandler);
|
||||||
|
|
||||||
app.get("/video/:id/snapshots", ...getSnapshotsHanlder);
|
app.get("/video/:id/snapshots", ...getSnapshotsHanlder);
|
||||||
app.get("/video/:id/info", ...videoInfoHandler);
|
|
||||||
|
|
||||||
app.post("/user", ...registerHandler);
|
app.post("/user", ...registerHandler);
|
||||||
app.get("/user/session/:id", ...getUserByLoginSessionHandler);
|
|
||||||
|
app.get("/video/:id/info", ...videoInfoHandler);
|
||||||
|
|
||||||
app.post("/captcha/session", ...createCaptchaSessionHandler);
|
app.post("/captcha/session", ...createCaptchaSessionHandler);
|
||||||
app.get("/captcha/:id/result", ...verifyChallengeHandler);
|
app.get("/captcha/:id/result", ...verifyChallengeHandler);
|
||||||
app.get("/captcha/difficulty", ...getCaptchaDifficultyHandler);
|
|
||||||
|
app.get("/captcha/difficulty", ...getCaptchaDifficultyHandler)
|
||||||
}
|
}
|
||||||
|
42
packages/backend/src/schema.d.ts
vendored
42
packages/backend/src/schema.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
export type ErrorCode =
|
type ErrorCode =
|
||||||
| "INVALID_QUERY_PARAMS"
|
| "INVALID_QUERY_PARAMS"
|
||||||
| "UNKNOWN_ERROR"
|
| "UNKNOWN_ERROR"
|
||||||
| "INVALID_PAYLOAD"
|
| "INVALID_PAYLOAD"
|
||||||
@ -9,50 +9,14 @@ export type ErrorCode =
|
|||||||
| "INVALID_CREDENTIALS"
|
| "INVALID_CREDENTIALS"
|
||||||
| "ENTITY_NOT_FOUND"
|
| "ENTITY_NOT_FOUND"
|
||||||
| "SERVER_ERROR"
|
| "SERVER_ERROR"
|
||||||
| "RATE_LIMIT_EXCEEDED"
|
| "RATE_LIMIT_EXCEEDED";
|
||||||
| "ENTITY_EXISTS";
|
|
||||||
|
|
||||||
export interface ErrorResponse<E=string> {
|
export interface ErrorResponse<E=string> {
|
||||||
code: ErrorCode;
|
code: ErrorCode;
|
||||||
message: string;
|
message: string;
|
||||||
errors: E[] = [];
|
errors?: E[];
|
||||||
i18n?: {
|
|
||||||
key: string;
|
|
||||||
values?: {
|
|
||||||
[key: string]: string | number | Date;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StatusResponse {
|
export interface StatusResponse {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CaptchaSessionResponse = ErrorResponse | CaptchaSessionRawResponse;
|
|
||||||
|
|
||||||
interface CaptchaSessionRawResponse {
|
|
||||||
success: boolean;
|
|
||||||
id: string;
|
|
||||||
g: string;
|
|
||||||
n: string;
|
|
||||||
t: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SignUpResponse {
|
|
||||||
username: string;
|
|
||||||
token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface UserResponse {
|
|
||||||
username: string;
|
|
||||||
nickname: string | null;
|
|
||||||
role: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CaptchaVerificationRawResponse = {
|
|
||||||
token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CaptchaVerificationResponse =
|
|
||||||
| ErrorResponse
|
|
||||||
| CaptchaVerificationRawResponse;
|
|
||||||
|
@ -2,7 +2,7 @@ const requiredEnvVars = ["DB_HOST", "DB_NAME", "DB_USER", "DB_PASSWORD", "DB_POR
|
|||||||
|
|
||||||
const getEnvVar = (key: string) => {
|
const getEnvVar = (key: string) => {
|
||||||
return process.env[key] || import.meta.env[key];
|
return process.env[key] || import.meta.env[key];
|
||||||
};
|
}
|
||||||
|
|
||||||
const unsetVars = requiredEnvVars.filter((key) => getEnvVar(key) === undefined);
|
const unsetVars = requiredEnvVars.filter((key) => getEnvVar(key) === undefined);
|
||||||
|
|
||||||
@ -10,8 +10,6 @@ if (unsetVars.length > 0) {
|
|||||||
throw new Error(`Missing required environment variables: ${unsetVars.join(", ")}`);
|
throw new Error(`Missing required environment variables: ${unsetVars.join(", ")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(process.env);
|
|
||||||
|
|
||||||
const databaseHost = getEnvVar("DB_HOST")!;
|
const databaseHost = getEnvVar("DB_HOST")!;
|
||||||
const databaseName = getEnvVar("DB_NAME");
|
const databaseName = getEnvVar("DB_NAME");
|
||||||
const databaseNameCred = getEnvVar("DB_NAME_CRED")!;
|
const databaseNameCred = getEnvVar("DB_NAME_CRED")!;
|
||||||
|
9
packages/core/db/schema.d.ts
vendored
9
packages/core/db/schema.d.ts
vendored
@ -53,12 +53,3 @@ export interface SnapshotScheduleType {
|
|||||||
finished_at?: string;
|
finished_at?: string;
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatabaseUserType {
|
|
||||||
id: number;
|
|
||||||
username: string;
|
|
||||||
nickname: string | null;
|
|
||||||
password: string;
|
|
||||||
unq_id: string;
|
|
||||||
role: string;
|
|
||||||
}
|
|
||||||
|
62
packages/core/db/videoSnapshot.ts
Normal file
62
packages/core/db/videoSnapshot.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import type { Client } from "https://deno.land/x/postgres@v0.19.3/mod.ts";
|
||||||
|
import type { VideoSnapshotType } from "./schema.d.ts";
|
||||||
|
|
||||||
|
export async function getVideoSnapshots(
|
||||||
|
client: Client,
|
||||||
|
aid: number,
|
||||||
|
limit: number,
|
||||||
|
pageOrOffset: number,
|
||||||
|
reverse: boolean,
|
||||||
|
mode: "page" | "offset" = "page",
|
||||||
|
) {
|
||||||
|
const offset = mode === "page" ? (pageOrOffset - 1) * limit : pageOrOffset;
|
||||||
|
const queryDesc: string = `
|
||||||
|
SELECT *
|
||||||
|
FROM video_snapshot
|
||||||
|
WHERE aid = $1
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
LIMIT $2
|
||||||
|
OFFSET $3
|
||||||
|
`;
|
||||||
|
const queryAsc: string = `
|
||||||
|
SELECT *
|
||||||
|
FROM video_snapshot
|
||||||
|
WHERE aid = $1
|
||||||
|
ORDER BY created_at
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`;
|
||||||
|
const query = reverse ? queryAsc : queryDesc;
|
||||||
|
const queryResult = await client.queryObject<VideoSnapshotType>(query, [aid, limit, offset]);
|
||||||
|
return queryResult.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getVideoSnapshotsByBV(
|
||||||
|
client: Client,
|
||||||
|
bv: string,
|
||||||
|
limit: number,
|
||||||
|
pageOrOffset: number,
|
||||||
|
reverse: boolean,
|
||||||
|
mode: "page" | "offset" = "page",
|
||||||
|
) {
|
||||||
|
const offset = mode === "page" ? (pageOrOffset - 1) * limit : pageOrOffset;
|
||||||
|
const queryAsc = `
|
||||||
|
SELECT vs.*
|
||||||
|
FROM video_snapshot vs
|
||||||
|
JOIN bilibili_metadata bm ON vs.aid = bm.aid
|
||||||
|
WHERE bm.bvid = $1
|
||||||
|
ORDER BY vs.created_at
|
||||||
|
LIMIT $2
|
||||||
|
OFFSET $3
|
||||||
|
`;
|
||||||
|
const queryDesc: string = `
|
||||||
|
SELECT *
|
||||||
|
FROM video_snapshot vs
|
||||||
|
JOIN bilibili_metadata bm ON vs.aid = bm.aid
|
||||||
|
WHERE bm.bvid = $1
|
||||||
|
ORDER BY vs.created_at DESC
|
||||||
|
LIMIT $2 OFFSET $3
|
||||||
|
`;
|
||||||
|
const query = reverse ? queryAsc : queryDesc;
|
||||||
|
const queryResult = await client.queryObject<VideoSnapshotType>(query, [bv, limit, offset]);
|
||||||
|
return queryResult.rows;
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
export * from "./db/dbNew";
|
|
@ -1,10 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@cvsa/core",
|
"name": "core",
|
||||||
"private": false,
|
|
||||||
"version": "0.0.1",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "bun --env-file=.env.test run vitest",
|
"test": "bun --env-file=.env.test run vitest"
|
||||||
"build": "bun build ./index.ts --target node --outdir ./dist"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koshnic/ratelimit": "^1.0.3",
|
"@koshnic/ratelimit": "^1.0.3",
|
||||||
@ -16,7 +13,5 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ioredis": "^5.0.0"
|
"@types/ioredis": "^5.0.0"
|
||||||
},
|
}
|
||||||
"main": "./dist/index.js",
|
|
||||||
"types": "./types.d.ts"
|
|
||||||
}
|
}
|
||||||
|
1
packages/core/types.d.ts
vendored
1
packages/core/types.d.ts
vendored
@ -1 +0,0 @@
|
|||||||
export * from "./db/schema";
|
|
@ -1,449 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: "Inter Variable";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterVariable.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter Variable";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterVariable-Italic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static fonts */
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Thin.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ThinItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraLight.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraLightItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Light.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-LightItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Regular.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Italic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Medium.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-MediumItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-SemiBold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-SemiBoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Bold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-BoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraBold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-ExtraBoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-Black.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("Inter-BlackItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Thin.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-ThinItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-ExtraLight.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Light.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-LightItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Regular.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Italic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Medium.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-MediumItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-SemiBold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Bold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-BoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-ExtraBold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-Black.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "InterDisplay";
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("InterDisplay-BlackItalic.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-feature-values InterVariable {
|
|
||||||
@character-variant {
|
|
||||||
cv01: 1;
|
|
||||||
cv02: 2;
|
|
||||||
cv03: 3;
|
|
||||||
cv04: 4;
|
|
||||||
cv05: 5;
|
|
||||||
cv06: 6;
|
|
||||||
cv07: 7;
|
|
||||||
cv08: 8;
|
|
||||||
cv09: 9;
|
|
||||||
cv10: 10;
|
|
||||||
cv11: 11;
|
|
||||||
cv12: 12;
|
|
||||||
cv13: 13;
|
|
||||||
alt-1: 1; /* Alternate one */
|
|
||||||
alt-3: 9; /* Flat-top three */
|
|
||||||
open-4: 2; /* Open four */
|
|
||||||
open-6: 3; /* Open six */
|
|
||||||
open-9: 4; /* Open nine */
|
|
||||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
|
||||||
simplified-u: 6; /* Simplified u */
|
|
||||||
alt-double-s: 7; /* Alternate German double s */
|
|
||||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
|
||||||
uc-g-with-spur: 10; /* Capital G with spur */
|
|
||||||
single-story-a: 11; /* Single-story a */
|
|
||||||
compact-lc-f: 12; /* Compact f */
|
|
||||||
compact-lc-t: 13; /* Compact t */
|
|
||||||
}
|
|
||||||
@styleset {
|
|
||||||
ss01: 1;
|
|
||||||
ss02: 2;
|
|
||||||
ss03: 3;
|
|
||||||
ss04: 4;
|
|
||||||
ss05: 5;
|
|
||||||
ss06: 6;
|
|
||||||
ss07: 7;
|
|
||||||
ss08: 8;
|
|
||||||
open-digits: 1; /* Open digits */
|
|
||||||
disambiguation: 2; /* Disambiguation (with zero) */
|
|
||||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
|
||||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
|
||||||
square-punctuation: 7; /* Square punctuation */
|
|
||||||
square-quotes: 8; /* Square quotes */
|
|
||||||
circled-characters: 5; /* Circled characters */
|
|
||||||
squared-characters: 6; /* Squared characters */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@font-feature-values Inter {
|
|
||||||
@character-variant {
|
|
||||||
cv01: 1;
|
|
||||||
cv02: 2;
|
|
||||||
cv03: 3;
|
|
||||||
cv04: 4;
|
|
||||||
cv05: 5;
|
|
||||||
cv06: 6;
|
|
||||||
cv07: 7;
|
|
||||||
cv08: 8;
|
|
||||||
cv09: 9;
|
|
||||||
cv10: 10;
|
|
||||||
cv11: 11;
|
|
||||||
cv12: 12;
|
|
||||||
cv13: 13;
|
|
||||||
alt-1: 1; /* Alternate one */
|
|
||||||
alt-3: 9; /* Flat-top three */
|
|
||||||
open-4: 2; /* Open four */
|
|
||||||
open-6: 3; /* Open six */
|
|
||||||
open-9: 4; /* Open nine */
|
|
||||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
|
||||||
simplified-u: 6; /* Simplified u */
|
|
||||||
alt-double-s: 7; /* Alternate German double s */
|
|
||||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
|
||||||
uc-g-with-spur: 10; /* Capital G with spur */
|
|
||||||
single-story-a: 11; /* Single-story a */
|
|
||||||
compact-lc-f: 12; /* Compact f */
|
|
||||||
compact-lc-t: 13; /* Compact t */
|
|
||||||
}
|
|
||||||
@styleset {
|
|
||||||
ss01: 1;
|
|
||||||
ss02: 2;
|
|
||||||
ss03: 3;
|
|
||||||
ss04: 4;
|
|
||||||
ss05: 5;
|
|
||||||
ss06: 6;
|
|
||||||
ss07: 7;
|
|
||||||
ss08: 8;
|
|
||||||
open-digits: 1; /* Open digits */
|
|
||||||
disambiguation: 2; /* Disambiguation (with zero) */
|
|
||||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
|
||||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
|
||||||
square-punctuation: 7; /* Square punctuation */
|
|
||||||
square-quotes: 8; /* Square quotes */
|
|
||||||
circled-characters: 5; /* Circled characters */
|
|
||||||
squared-characters: 6; /* Squared characters */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@font-feature-values InterDisplay {
|
|
||||||
@character-variant {
|
|
||||||
cv01: 1;
|
|
||||||
cv02: 2;
|
|
||||||
cv03: 3;
|
|
||||||
cv04: 4;
|
|
||||||
cv05: 5;
|
|
||||||
cv06: 6;
|
|
||||||
cv07: 7;
|
|
||||||
cv08: 8;
|
|
||||||
cv09: 9;
|
|
||||||
cv10: 10;
|
|
||||||
cv11: 11;
|
|
||||||
cv12: 12;
|
|
||||||
cv13: 13;
|
|
||||||
alt-1: 1; /* Alternate one */
|
|
||||||
alt-3: 9; /* Flat-top three */
|
|
||||||
open-4: 2; /* Open four */
|
|
||||||
open-6: 3; /* Open six */
|
|
||||||
open-9: 4; /* Open nine */
|
|
||||||
lc-l-with-tail: 5; /* Lower-case L with tail */
|
|
||||||
simplified-u: 6; /* Simplified u */
|
|
||||||
alt-double-s: 7; /* Alternate German double s */
|
|
||||||
uc-i-with-serif: 8; /* Upper-case i with serif */
|
|
||||||
uc-g-with-spur: 10; /* Capital G with spur */
|
|
||||||
single-story-a: 11; /* Single-story a */
|
|
||||||
compact-lc-f: 12; /* Compact f */
|
|
||||||
compact-lc-t: 13; /* Compact t */
|
|
||||||
}
|
|
||||||
@styleset {
|
|
||||||
ss01: 1;
|
|
||||||
ss02: 2;
|
|
||||||
ss03: 3;
|
|
||||||
ss04: 4;
|
|
||||||
ss05: 5;
|
|
||||||
ss06: 6;
|
|
||||||
ss07: 7;
|
|
||||||
ss08: 8;
|
|
||||||
open-digits: 1; /* Open digits */
|
|
||||||
disambiguation: 2; /* Disambiguation (with zero) */
|
|
||||||
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
|
||||||
round-quotes-and-commas: 3; /* Round quotes & commas */
|
|
||||||
square-punctuation: 7; /* Square punctuation */
|
|
||||||
square-quotes: 8; /* Square quotes */
|
|
||||||
circled-characters: 5; /* Circled characters */
|
|
||||||
squared-characters: 6; /* Squared characters */
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: "MiSans VF";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 150 700;
|
|
||||||
font-display: optional;
|
|
||||||
src: url("MiSans VF.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Thin.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-ExtraLight.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Light.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 360;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Normal.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Regular.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Medium.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Demibold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Semibold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Bold.woff2") format("woff2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "MiSans";
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: url("MiSans-Heavy.woff2") format("woff2");
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { Header } from "@/components/shell/Header";
|
|
||||||
import { getUserBySession } from "@/lib/db/user";
|
|
||||||
import { UserResponse } from "@backend/src/schema";
|
|
||||||
import { cookies } from "next/headers";
|
|
||||||
|
|
||||||
export default async function Home() {
|
|
||||||
const cookieStore = await cookies();
|
|
||||||
const sessionID = cookieStore.get("session_id");
|
|
||||||
let user: undefined | UserResponse = undefined;
|
|
||||||
if (sessionID) {
|
|
||||||
user = await getUserBySession(sessionID.value);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Header user={user} />
|
|
||||||
<main className="flex flex-col items-center justify-center h-full flex-grow gap-8 px-4">
|
|
||||||
<h1 className="text-4xl font-medium text-center">正在施工中……</h1>
|
|
||||||
<p>在搜索栏输入BV号或AV号,可以查询目前数据库收集到的信息~</p>
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
import { DialogButton, DialogButtonGroup, DialogHeadline, DialogSupportingText } from "@/components/ui/Dialog";
|
|
||||||
import { ErrorCode as ResponseErrorCode } from "@backend/src/schema";
|
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
|
|
||||||
interface ErrorDialogProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
closeDialog: () => void;
|
|
||||||
errorCode?: ResponseErrorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ErrorDialog: React.FC<ErrorDialogProps> = ({ children, closeDialog, errorCode }) => {
|
|
||||||
const t = useTranslations("backend.error_code");
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DialogHeadline>{errorCode ? t(errorCode) : "错误"}</DialogHeadline>
|
|
||||||
<DialogSupportingText>{children}</DialogSupportingText>
|
|
||||||
<DialogButtonGroup>
|
|
||||||
<DialogButton onClick={closeDialog}>关闭</DialogButton>
|
|
||||||
</DialogButtonGroup>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,146 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import TextField from "@/components/ui/TextField";
|
|
||||||
import LoadingSpinner from "@/components/icons/LoadingSpinner";
|
|
||||||
import { Portal } from "@/components/utils/Portal";
|
|
||||||
import { Dialog } from "@/components/ui/Dialog";
|
|
||||||
import { setLocale } from "yup";
|
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
import { useCaptcha } from "@/components/hooks/useCaptcha";
|
|
||||||
import useSWRMutation from "swr/mutation";
|
|
||||||
import { requestSignUp } from "./request";
|
|
||||||
import { FilledButton } from "@/components/ui/Buttons/FilledButton";
|
|
||||||
import { ErrorDialog } from "./ErrorDialog";
|
|
||||||
import { ApiRequestError } from "@/lib/net";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
|
|
||||||
setLocale({
|
|
||||||
mixed: {
|
|
||||||
default: "field_invalid",
|
|
||||||
required: () => ({ key: "field_required" })
|
|
||||||
},
|
|
||||||
string: {
|
|
||||||
min: ({ min }) => ({ key: "field_too_short", values: { min } }),
|
|
||||||
max: ({ max }) => ({ key: "field_too_big", values: { max } })
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export interface LocalizedMessage {
|
|
||||||
key: string;
|
|
||||||
values: {
|
|
||||||
[key: string]: number | string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RegistrationFormProps {
|
|
||||||
backendURL: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SignUpForm: React.FC<RegistrationFormProps> = ({ backendURL }) => {
|
|
||||||
const [usernameInput, setUsername] = useState("");
|
|
||||||
const [passwordInput, setPassword] = useState("");
|
|
||||||
const [nicknameInput, setNickname] = useState("");
|
|
||||||
const [showDialog, setShowDialog] = useState(false);
|
|
||||||
const [dialogContent, setDialogContent] = useState(<></>);
|
|
||||||
const [isLoading, setLoading] = useState(false);
|
|
||||||
const t = useTranslations("");
|
|
||||||
const { startCaptcha, captchaResult, captchaUsed, setCaptchaUsedState, captchaError } = useCaptcha({
|
|
||||||
backendURL,
|
|
||||||
route: "POST-/user"
|
|
||||||
});
|
|
||||||
const { trigger } = useSWRMutation(`${backendURL}/user`, requestSignUp);
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const translateErrorMessage = (item: LocalizedMessage | string, path?: string) => {
|
|
||||||
if (typeof item === "string") {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
return t(`yup_errors.${item.key}`, { ...item.values, field: path ? t(path) : "" });
|
|
||||||
};
|
|
||||||
|
|
||||||
const register = async () => {
|
|
||||||
try {
|
|
||||||
if (captchaUsed || !captchaResult) {
|
|
||||||
await startCaptcha();
|
|
||||||
}
|
|
||||||
|
|
||||||
await trigger({
|
|
||||||
data: {
|
|
||||||
username: usernameInput,
|
|
||||||
password: passwordInput,
|
|
||||||
nickname: nicknameInput
|
|
||||||
},
|
|
||||||
setShowDialog,
|
|
||||||
captchaResult,
|
|
||||||
setCaptchaUsedState,
|
|
||||||
translateErrorMessage,
|
|
||||||
setDialogContent,
|
|
||||||
t
|
|
||||||
});
|
|
||||||
|
|
||||||
router.push("/");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!captchaError || captchaError === undefined) return;
|
|
||||||
const err = captchaError as ApiRequestError;
|
|
||||||
setShowDialog(true);
|
|
||||||
if (err.code && err.code == -1) {
|
|
||||||
setDialogContent(
|
|
||||||
<ErrorDialog closeDialog={() => setShowDialog(false)}>
|
|
||||||
<p>无法连接到服务器,请检查你的网络连接后重试。</p>
|
|
||||||
</ErrorDialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}, [captchaError]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
startCaptcha();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<form
|
|
||||||
className="w-full flex flex-col gap-6"
|
|
||||||
onSubmit={async (e) => {
|
|
||||||
setLoading(true);
|
|
||||||
e.preventDefault();
|
|
||||||
await register();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TextField
|
|
||||||
labelText="用户名"
|
|
||||||
inputText={usernameInput}
|
|
||||||
onInputTextChange={setUsername}
|
|
||||||
maxChar={50}
|
|
||||||
supportingText="*必填。用户名是唯一的,不区分大小写。"
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
labelText="密码"
|
|
||||||
type="password"
|
|
||||||
inputText={passwordInput}
|
|
||||||
onInputTextChange={setPassword}
|
|
||||||
supportingText="*必填。密码至少为 4 个字符。"
|
|
||||||
maxChar={120}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
labelText="昵称"
|
|
||||||
inputText={nicknameInput}
|
|
||||||
onInputTextChange={setNickname}
|
|
||||||
supportingText="昵称可以重复。"
|
|
||||||
maxChar={30}
|
|
||||||
/>
|
|
||||||
<FilledButton type="submit" disabled={isLoading}>
|
|
||||||
{isLoading ? <LoadingSpinner /> : <span>注册</span>}
|
|
||||||
</FilledButton>
|
|
||||||
<Portal>
|
|
||||||
<Dialog show={showDialog}>{dialogContent}</Dialog>
|
|
||||||
</Portal>
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SignUpForm;
|
|
@ -1,151 +0,0 @@
|
|||||||
import { Dispatch, JSX, SetStateAction } from "react";
|
|
||||||
import { ApiRequestError, fetcher } from "@/lib/net";
|
|
||||||
import type { CaptchaVerificationRawResponse, ErrorResponse, SignUpResponse } from "@backend/src/schema";
|
|
||||||
import { Link } from "@/i18n/navigation";
|
|
||||||
import { LocalizedMessage } from "./SignUpForm";
|
|
||||||
import { ErrorDialog } from "./ErrorDialog";
|
|
||||||
import { string, object, ValidationError } from "yup";
|
|
||||||
|
|
||||||
interface SignUpFormData {
|
|
||||||
username: string;
|
|
||||||
password: string;
|
|
||||||
nickname?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FormSchema = object().shape({
|
|
||||||
username: string().required().max(50),
|
|
||||||
password: string().required().min(4).max(120),
|
|
||||||
nickname: string().optional().max(30)
|
|
||||||
});
|
|
||||||
|
|
||||||
const validateForm = async (
|
|
||||||
data: SignUpFormData,
|
|
||||||
setShowDialog: Dispatch<SetStateAction<boolean>>,
|
|
||||||
setDialogContent: Dispatch<SetStateAction<JSX.Element>>,
|
|
||||||
translateErrorMessage: (item: LocalizedMessage | string, path?: string) => string
|
|
||||||
): Promise<SignUpFormData | null> => {
|
|
||||||
const { username: usernameInput, password: passwordInput, nickname: nicknameInput } = data;
|
|
||||||
try {
|
|
||||||
const formData = await FormSchema.validate(
|
|
||||||
{
|
|
||||||
username: usernameInput,
|
|
||||||
password: passwordInput,
|
|
||||||
nickname: nicknameInput
|
|
||||||
},
|
|
||||||
{ abortEarly: false }
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
username: formData.username,
|
|
||||||
password: formData.password,
|
|
||||||
nickname: formData.nickname
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
if (!(e instanceof ValidationError)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
setShowDialog(true);
|
|
||||||
setDialogContent(
|
|
||||||
<ErrorDialog closeDialog={() => setShowDialog(false)}>
|
|
||||||
<p>注册信息填写有误,请检查后重新提交。</p>
|
|
||||||
<span>错误信息: </span>
|
|
||||||
<br />
|
|
||||||
<ol className="list-decimal list-inside">
|
|
||||||
{e.errors.map((item, i) => {
|
|
||||||
return <li key={i}>{translateErrorMessage(item, e.inner[i].path)}</li>;
|
|
||||||
})}
|
|
||||||
</ol>
|
|
||||||
</ErrorDialog>
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
interface RequestSignUpArgs {
|
|
||||||
data: SignUpFormData;
|
|
||||||
setShowDialog: Dispatch<SetStateAction<boolean>>;
|
|
||||||
setDialogContent: Dispatch<SetStateAction<JSX.Element>>;
|
|
||||||
translateErrorMessage: (item: LocalizedMessage | string, path?: string) => string;
|
|
||||||
setCaptchaUsedState: Dispatch<SetStateAction<boolean>>;
|
|
||||||
captchaResult: CaptchaVerificationRawResponse | undefined;
|
|
||||||
t: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const requestSignUp = async (url: string, { arg }: { arg: RequestSignUpArgs }) => {
|
|
||||||
const { data, setShowDialog, setDialogContent, translateErrorMessage, setCaptchaUsedState, captchaResult, t } = arg;
|
|
||||||
const res = await validateForm(data, setShowDialog, setDialogContent, translateErrorMessage);
|
|
||||||
if (!res) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { username, nickname, password } = res;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!captchaResult) {
|
|
||||||
const err = new ApiRequestError("Cannot get captcha result");
|
|
||||||
err.response = {
|
|
||||||
code: "UNKNOWN_ERROR",
|
|
||||||
message: "Cannot get captch verifiction result",
|
|
||||||
i18n: {
|
|
||||||
key: "captcha_failed_to_get"
|
|
||||||
}
|
|
||||||
} as ErrorResponse;
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
setCaptchaUsedState(true);
|
|
||||||
const registrationResponse = await fetcher<SignUpResponse>(url, {
|
|
||||||
method: "POST",
|
|
||||||
withCredentials: true,
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${captchaResult!.token}`
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
nickname: nickname
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return registrationResponse;
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof ApiRequestError && error.response) {
|
|
||||||
const res = error.response as ErrorResponse;
|
|
||||||
setShowDialog(true);
|
|
||||||
setDialogContent(
|
|
||||||
<ErrorDialog closeDialog={() => setShowDialog(false)} errorCode={res.code}>
|
|
||||||
<p>无法为你注册账户。</p>
|
|
||||||
<p>
|
|
||||||
错误信息: <br />
|
|
||||||
{res.i18n
|
|
||||||
? t.rich(res.i18n.key, {
|
|
||||||
...res.i18n.values,
|
|
||||||
support: (chunks: string) => <Link href="/support">{chunks}</Link>
|
|
||||||
})
|
|
||||||
: res.message}
|
|
||||||
</p>
|
|
||||||
</ErrorDialog>
|
|
||||||
);
|
|
||||||
} else if (error instanceof Error) {
|
|
||||||
setShowDialog(true);
|
|
||||||
setDialogContent(
|
|
||||||
<ErrorDialog closeDialog={() => setShowDialog(false)}>
|
|
||||||
<p>无法为你注册账户。</p>
|
|
||||||
<p>
|
|
||||||
错误信息:
|
|
||||||
<br />
|
|
||||||
{error.message}
|
|
||||||
</p>
|
|
||||||
</ErrorDialog>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setShowDialog(true);
|
|
||||||
setDialogContent(
|
|
||||||
<ErrorDialog closeDialog={() => setShowDialog(false)} errorCode="UNKNOWN_ERROR">
|
|
||||||
<p>无法为你注册账户。</p>
|
|
||||||
<p>
|
|
||||||
错误信息: <br />
|
|
||||||
<pre className="break-all">{JSON.stringify(error)}</pre>
|
|
||||||
</p>
|
|
||||||
</ErrorDialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
450
packages/next/app/fonts/InterFont/Inter.css
Normal file
450
packages/next/app/fonts/InterFont/Inter.css
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: InterVariable;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterVariable.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: InterVariable;
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterVariable-Italic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static fonts */
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Thin.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-ThinItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-ExtraLight.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-ExtraLightItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Light.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-LightItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Regular.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Italic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Medium.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-MediumItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-SemiBold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-SemiBoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Bold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-BoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-ExtraBold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-ExtraBoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-Black.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Inter";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("Inter-BlackItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Thin.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-ThinItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-ExtraLight.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-ExtraLightItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Light.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-LightItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Regular.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Italic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Medium.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-MediumItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-SemiBold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-SemiBoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Bold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-BoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-ExtraBold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-ExtraBoldItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-Black.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "InterDisplay";
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("InterDisplay-BlackItalic.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-feature-values InterVariable {
|
||||||
|
@character-variant {
|
||||||
|
cv01: 1;
|
||||||
|
cv02: 2;
|
||||||
|
cv03: 3;
|
||||||
|
cv04: 4;
|
||||||
|
cv05: 5;
|
||||||
|
cv06: 6;
|
||||||
|
cv07: 7;
|
||||||
|
cv08: 8;
|
||||||
|
cv09: 9;
|
||||||
|
cv10: 10;
|
||||||
|
cv11: 11;
|
||||||
|
cv12: 12;
|
||||||
|
cv13: 13;
|
||||||
|
alt-1: 1; /* Alternate one */
|
||||||
|
alt-3: 9; /* Flat-top three */
|
||||||
|
open-4: 2; /* Open four */
|
||||||
|
open-6: 3; /* Open six */
|
||||||
|
open-9: 4; /* Open nine */
|
||||||
|
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||||
|
simplified-u: 6; /* Simplified u */
|
||||||
|
alt-double-s: 7; /* Alternate German double s */
|
||||||
|
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||||
|
uc-g-with-spur: 10; /* Capital G with spur */
|
||||||
|
single-story-a: 11; /* Single-story a */
|
||||||
|
compact-lc-f: 12; /* Compact f */
|
||||||
|
compact-lc-t: 13; /* Compact t */
|
||||||
|
}
|
||||||
|
@styleset {
|
||||||
|
ss01: 1;
|
||||||
|
ss02: 2;
|
||||||
|
ss03: 3;
|
||||||
|
ss04: 4;
|
||||||
|
ss05: 5;
|
||||||
|
ss06: 6;
|
||||||
|
ss07: 7;
|
||||||
|
ss08: 8;
|
||||||
|
open-digits: 1; /* Open digits */
|
||||||
|
disambiguation: 2; /* Disambiguation (with zero) */
|
||||||
|
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||||
|
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||||
|
square-punctuation: 7; /* Square punctuation */
|
||||||
|
square-quotes: 8; /* Square quotes */
|
||||||
|
circled-characters: 5; /* Circled characters */
|
||||||
|
squared-characters: 6; /* Squared characters */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@font-feature-values Inter {
|
||||||
|
|
||||||
|
@character-variant {
|
||||||
|
cv01: 1;
|
||||||
|
cv02: 2;
|
||||||
|
cv03: 3;
|
||||||
|
cv04: 4;
|
||||||
|
cv05: 5;
|
||||||
|
cv06: 6;
|
||||||
|
cv07: 7;
|
||||||
|
cv08: 8;
|
||||||
|
cv09: 9;
|
||||||
|
cv10: 10;
|
||||||
|
cv11: 11;
|
||||||
|
cv12: 12;
|
||||||
|
cv13: 13;
|
||||||
|
alt-1: 1; /* Alternate one */
|
||||||
|
alt-3: 9; /* Flat-top three */
|
||||||
|
open-4: 2; /* Open four */
|
||||||
|
open-6: 3; /* Open six */
|
||||||
|
open-9: 4; /* Open nine */
|
||||||
|
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||||
|
simplified-u: 6; /* Simplified u */
|
||||||
|
alt-double-s: 7; /* Alternate German double s */
|
||||||
|
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||||
|
uc-g-with-spur: 10; /* Capital G with spur */
|
||||||
|
single-story-a: 11; /* Single-story a */
|
||||||
|
compact-lc-f: 12; /* Compact f */
|
||||||
|
compact-lc-t: 13; /* Compact t */
|
||||||
|
}
|
||||||
|
@styleset {
|
||||||
|
ss01: 1;
|
||||||
|
ss02: 2;
|
||||||
|
ss03: 3;
|
||||||
|
ss04: 4;
|
||||||
|
ss05: 5;
|
||||||
|
ss06: 6;
|
||||||
|
ss07: 7;
|
||||||
|
ss08: 8;
|
||||||
|
open-digits: 1; /* Open digits */
|
||||||
|
disambiguation: 2; /* Disambiguation (with zero) */
|
||||||
|
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||||
|
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||||
|
square-punctuation: 7; /* Square punctuation */
|
||||||
|
square-quotes: 8; /* Square quotes */
|
||||||
|
circled-characters: 5; /* Circled characters */
|
||||||
|
squared-characters: 6; /* Squared characters */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@font-feature-values InterDisplay {
|
||||||
|
@character-variant {
|
||||||
|
cv01: 1;
|
||||||
|
cv02: 2;
|
||||||
|
cv03: 3;
|
||||||
|
cv04: 4;
|
||||||
|
cv05: 5;
|
||||||
|
cv06: 6;
|
||||||
|
cv07: 7;
|
||||||
|
cv08: 8;
|
||||||
|
cv09: 9;
|
||||||
|
cv10: 10;
|
||||||
|
cv11: 11;
|
||||||
|
cv12: 12;
|
||||||
|
cv13: 13;
|
||||||
|
alt-1: 1; /* Alternate one */
|
||||||
|
alt-3: 9; /* Flat-top three */
|
||||||
|
open-4: 2; /* Open four */
|
||||||
|
open-6: 3; /* Open six */
|
||||||
|
open-9: 4; /* Open nine */
|
||||||
|
lc-l-with-tail: 5; /* Lower-case L with tail */
|
||||||
|
simplified-u: 6; /* Simplified u */
|
||||||
|
alt-double-s: 7; /* Alternate German double s */
|
||||||
|
uc-i-with-serif: 8; /* Upper-case i with serif */
|
||||||
|
uc-g-with-spur: 10; /* Capital G with spur */
|
||||||
|
single-story-a: 11; /* Single-story a */
|
||||||
|
compact-lc-f: 12; /* Compact f */
|
||||||
|
compact-lc-t: 13; /* Compact t */
|
||||||
|
}
|
||||||
|
@styleset {
|
||||||
|
ss01: 1;
|
||||||
|
ss02: 2;
|
||||||
|
ss03: 3;
|
||||||
|
ss04: 4;
|
||||||
|
ss05: 5;
|
||||||
|
ss06: 6;
|
||||||
|
ss07: 7;
|
||||||
|
ss08: 8;
|
||||||
|
open-digits: 1; /* Open digits */
|
||||||
|
disambiguation: 2; /* Disambiguation (with zero) */
|
||||||
|
disambiguation-except-zero: 4; /* Disambiguation (no zero) */
|
||||||
|
round-quotes-and-commas: 3; /* Round quotes & commas */
|
||||||
|
square-punctuation: 7; /* Square punctuation */
|
||||||
|
square-quotes: 8; /* Square quotes */
|
||||||
|
circled-characters: 5; /* Circled characters */
|
||||||
|
squared-characters: 6; /* Squared characters */
|
||||||
|
}
|
||||||
|
}
|
88
packages/next/app/fonts/MiSans/MiSans.css
Normal file
88
packages/next/app/fonts/MiSans/MiSans.css
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "MiSans VF";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 150 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans VF.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Thin.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-ExtraLight.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Light.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 360;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Normal.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Regular.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Medium.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Demibold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Semibold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Bold.woff2") format("woff2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "MiSans";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("MiSans-Heavy.woff2") format("woff2");
|
||||||
|
}
|
@ -79,6 +79,8 @@
|
|||||||
--color-dark-on-error: #690005;
|
--color-dark-on-error: #690005;
|
||||||
--color-dark-error-container: #93000a;
|
--color-dark-error-container: #93000a;
|
||||||
--color-dark-on-error-container: #ffdad6;
|
--color-dark-on-error-container: #ffdad6;
|
||||||
|
|
||||||
|
--font-zh: "InterVariable", "MiSans VF", sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@ -86,7 +88,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
font-family: "Inter", "MiSans", sans-serif;
|
font-family: "MiSans", "Inter", sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@apply bg-surface dark:bg-dark-surface text-on-surface dark:text-dark-on-surface;
|
@apply bg-surface dark:bg-dark-surface text-on-surface dark:text-dark-on-surface;
|
||||||
}
|
}
|
@ -1,25 +1,16 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { routing } from "@/i18n/routing";
|
|
||||||
import { NextIntlClientProvider, hasLocale } from "next-intl";
|
|
||||||
import { notFound } from "next/navigation";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "中V档案馆"
|
title: "中V档案馆"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children
|
||||||
params
|
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
params: Promise<{ locale: string }>;
|
|
||||||
}>) {
|
}>) {
|
||||||
const { locale } = await params;
|
|
||||||
if (!hasLocale(routing.locales, locale)) {
|
|
||||||
notFound();
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<head>
|
<head>
|
||||||
@ -28,10 +19,8 @@ export default async function RootLayout({
|
|||||||
<title>中V档案馆</title>
|
<title>中V档案馆</title>
|
||||||
</head>
|
</head>
|
||||||
<body className="min-h-screen flex flex-col">
|
<body className="min-h-screen flex flex-col">
|
||||||
<NextIntlClientProvider>
|
|
||||||
{children}
|
{children}
|
||||||
<div id="portal-root"></div>
|
<div id="portal-root"></div>
|
||||||
</NextIntlClientProvider>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
13
packages/next/app/page.tsx
Normal file
13
packages/next/app/page.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Header } from "@/components/shell/Header";
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<main className="flex flex-col items-center justify-center h-full flex-grow gap-8 px-4">
|
||||||
|
<h1 className="text-4xl font-medium text-center">正在施工中……</h1>
|
||||||
|
<p>在搜索栏输入BV号或AV号,可以查询目前数据库收集到的信息~</p>
|
||||||
|
</main>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
178
packages/next/app/signup/SignUpForm.tsx
Normal file
178
packages/next/app/signup/SignUpForm.tsx
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import TextField from "@/components/ui/TextField";
|
||||||
|
import LoadingSpinner from "@/components/icons/LoadingSpinner";
|
||||||
|
import { computeVdfInWorker } from "@/lib/vdf";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import { ApiRequestError } from "@/lib/net";
|
||||||
|
import { Portal } from "@/components/utils/Portal";
|
||||||
|
import { Dialog, DialogButton, DialogButtonGroup, DialogHeadline, DialogSupportingText } from "@/components/ui/Dialog";
|
||||||
|
import { FilledButton } from "@/components/ui/Buttons/FilledButton";
|
||||||
|
|
||||||
|
interface CaptchaSessionResponse {
|
||||||
|
g: string;
|
||||||
|
n: string;
|
||||||
|
t: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CaptchaResultResponse {
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetcher<JSON = any>(input: RequestInfo, init?: RequestInit): Promise<JSON> {
|
||||||
|
const res = await fetch(input, init);
|
||||||
|
if (!res.ok) {
|
||||||
|
const error = new ApiRequestError("An error occurred while fetching the data.");
|
||||||
|
error.response = await res.json();
|
||||||
|
error.code = res.status;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegistrationFormProps {
|
||||||
|
backendURL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SignUpForm: React.FC<RegistrationFormProps> = ({ backendURL }) => {
|
||||||
|
const [username, setUsername] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [nickname, setNickname] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [showDialog, setShowDialog] = useState(false);
|
||||||
|
const [dialogContent, setDialogContent] = useState(<></>);
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: captchaSession,
|
||||||
|
error: captchaSessionError,
|
||||||
|
mutate: createCaptchaSession
|
||||||
|
} = useSWR<CaptchaSessionResponse>(
|
||||||
|
`${backendURL}/captcha/session`,
|
||||||
|
(url) =>
|
||||||
|
fetcher(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ route: "POST-/user" })
|
||||||
|
}),
|
||||||
|
{ revalidateOnFocus: false, revalidateOnReconnect: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const getCaptchaResult = async (id: string, ans: string): Promise<CaptchaResultResponse> => {
|
||||||
|
const url = new URL(`${backendURL}/captcha/${id}/result`);
|
||||||
|
url.searchParams.set("ans", ans);
|
||||||
|
return fetcher<CaptchaResultResponse>(url.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
const register = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
if (!captchaSession?.g || !captchaSession?.n || !captchaSession?.t || !captchaSession?.id) {
|
||||||
|
console.error("Captcha session data is missing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ans = await computeVdfInWorker(
|
||||||
|
BigInt(captchaSession.g),
|
||||||
|
BigInt(captchaSession.n),
|
||||||
|
BigInt(captchaSession.t)
|
||||||
|
);
|
||||||
|
const captchaResult = await getCaptchaResult(captchaSession.id, ans.result.toString());
|
||||||
|
|
||||||
|
if (!captchaResult.token) {
|
||||||
|
}
|
||||||
|
// Proceed with user registration using username, password, and nickname
|
||||||
|
const registrationUrl = new URL(`${backendURL}/user`);
|
||||||
|
const registrationResponse = await fetch(registrationUrl.toString(), {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${captchaResult.token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
nickname
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (registrationResponse.ok) {
|
||||||
|
console.log("Registration successful!");
|
||||||
|
// Optionally redirect the user or show a success message
|
||||||
|
//router.push("/login"); // Example redirection
|
||||||
|
} else {
|
||||||
|
console.error("Registration failed:", await registrationResponse.json());
|
||||||
|
// Handle registration error
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Registration process error:", error);
|
||||||
|
// Handle general error
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
className="w-full flex flex-col gap-6"
|
||||||
|
onSubmit={async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await register();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
labelText="用户名"
|
||||||
|
inputText={username}
|
||||||
|
onInputTextChange={setUsername}
|
||||||
|
maxChar={50}
|
||||||
|
supportingText="*必填。用户名是唯一的,不区分大小写。"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
labelText="密码"
|
||||||
|
type="password"
|
||||||
|
inputText={password}
|
||||||
|
onInputTextChange={setPassword}
|
||||||
|
supportingText="*必填。密码至少为 4 个字符。"
|
||||||
|
maxChar={120}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
labelText="昵称"
|
||||||
|
inputText={nickname}
|
||||||
|
onInputTextChange={setNickname}
|
||||||
|
supportingText="昵称可以重复。"
|
||||||
|
maxChar={30}
|
||||||
|
/>
|
||||||
|
<FilledButton
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setShowDialog(true);
|
||||||
|
setDialogContent(
|
||||||
|
<>
|
||||||
|
<DialogHeadline>Error</DialogHeadline>
|
||||||
|
<DialogSupportingText>
|
||||||
|
<p>Your operation frequency is too high. Please try again later. (RATE_LIMIT_EXCEED)</p>
|
||||||
|
</DialogSupportingText>
|
||||||
|
<DialogButtonGroup>
|
||||||
|
<DialogButton onClick={() => setShowDialog(false)}>Close</DialogButton>
|
||||||
|
</DialogButtonGroup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
size="m"
|
||||||
|
shape="square"
|
||||||
|
>
|
||||||
|
Show Dialog
|
||||||
|
</FilledButton>
|
||||||
|
<FilledButton type="submit" disabled={loading}>
|
||||||
|
{!loading ? <span>注册</span> : <LoadingSpinner />}
|
||||||
|
</FilledButton>
|
||||||
|
<Portal>
|
||||||
|
<Dialog show={showDialog}>{dialogContent}</Dialog>
|
||||||
|
</Portal>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SignUpForm;
|
@ -4,7 +4,7 @@ import SignUpForm from "./SignUpForm";
|
|||||||
|
|
||||||
export default function SignupPage() {
|
export default function SignupPage() {
|
||||||
return (
|
return (
|
||||||
<main className="relative flex-grow pt-8 px-4 md:w-full md:h-full md:flex md:items-center md:justify-center">
|
<main className="relative flex-grow pt-8 md:pt-0 px-4 md:w-full md:h-full md:flex md:items-center md:justify-center">
|
||||||
<div
|
<div
|
||||||
className="md:w-[40rem] rounded-md md:p-8 md:-translate-y-6
|
className="md:w-[40rem] rounded-md md:p-8 md:-translate-y-6
|
||||||
md:bg-surface-container md:dark:bg-dark-surface-container"
|
md:bg-surface-container md:dark:bg-dark-surface-container"
|
@ -4,24 +4,19 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "next",
|
"name": "next",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cvsa/core": "^0.0.1",
|
"framer-motion": "^12.12.2",
|
||||||
"axios": "^1.9.0",
|
"next": "^15.1.8",
|
||||||
"framer-motion": "^12.15.0",
|
|
||||||
"i18next": "^25.2.1",
|
|
||||||
"next": "^15.3.3",
|
|
||||||
"next-intl": "^4.1.0",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"swr": "^2.3.3",
|
"swr": "^2.3.3",
|
||||||
"yup": "^1.6.1",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.8",
|
"@tailwindcss/postcss": "^4",
|
||||||
"@types/node": "^20.17.57",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19.1.6",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19",
|
||||||
"tailwindcss": "^4.1.8",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -30,26 +25,8 @@
|
|||||||
|
|
||||||
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],
|
||||||
|
|
||||||
"@babel/runtime": ["@babel/runtime@7.27.4", "", {}, "sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA=="],
|
|
||||||
|
|
||||||
"@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="],
|
|
||||||
|
|
||||||
"@cvsa/core": ["@cvsa/core@0.0.1", "", { "dependencies": { "@koshnic/ratelimit": "^1.0.3", "chalk": "^5.4.1", "ioredis": "^5.6.1", "logform": "^2.7.0", "postgres": "^3.4.5", "winston": "^3.17.0" } }, "sha512-h7p2AHcvdIA7GCJq4k1sOSGGbs/qjdHa4WlcCh6p1rVgpkpXp6v1Q9lvXca3uqAkInwzXctDSGwKiQp65K5XOg=="],
|
|
||||||
|
|
||||||
"@dabh/diagnostics": ["@dabh/diagnostics@2.0.3", "", { "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA=="],
|
|
||||||
|
|
||||||
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
"@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||||
|
|
||||||
"@formatjs/ecma402-abstract": ["@formatjs/ecma402-abstract@2.3.4", "", { "dependencies": { "@formatjs/fast-memoize": "2.2.7", "@formatjs/intl-localematcher": "0.6.1", "decimal.js": "^10.4.3", "tslib": "^2.8.0" } }, "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA=="],
|
|
||||||
|
|
||||||
"@formatjs/fast-memoize": ["@formatjs/fast-memoize@2.2.7", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ=="],
|
|
||||||
|
|
||||||
"@formatjs/icu-messageformat-parser": ["@formatjs/icu-messageformat-parser@2.11.2", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "@formatjs/icu-skeleton-parser": "1.8.14", "tslib": "^2.8.0" } }, "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA=="],
|
|
||||||
|
|
||||||
"@formatjs/icu-skeleton-parser": ["@formatjs/icu-skeleton-parser@1.8.14", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "tslib": "^2.8.0" } }, "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ=="],
|
|
||||||
|
|
||||||
"@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.5.10", "", { "dependencies": { "tslib": "2" } }, "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q=="],
|
|
||||||
|
|
||||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
|
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
|
||||||
|
|
||||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
|
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
|
||||||
@ -92,8 +69,6 @@
|
|||||||
|
|
||||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
|
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
|
||||||
|
|
||||||
"@ioredis/commands": ["@ioredis/commands@1.2.0", "", {}, "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="],
|
|
||||||
|
|
||||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||||
|
|
||||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="],
|
||||||
@ -106,126 +81,72 @@
|
|||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||||
|
|
||||||
"@koshnic/ratelimit": ["@koshnic/ratelimit@1.0.3", "", { "dependencies": { "@types/chai": "^4.3.9", "@types/mocha": "^10.0.3", "chai": "^4.3.10", "ioredis": "^5.3.2", "mocha": "^10.2.0" } }, "sha512-cfDcSc+I+M4hNM+/4M+lfn8UuTq4OEFKl78ThOcGNaO7g8tWb1vm2qVpV1p1loYao1mqk00NBNwHQu2E/qFq2g=="],
|
"@next/env": ["@next/env@15.3.2", "", {}, "sha512-xURk++7P7qR9JG1jJtLzPzf0qEvqCN0A/T3DXf8IPMKo9/6FfjxtEffRJIIew/bIL4T3C2jLLqBor8B/zVlx6g=="],
|
||||||
|
|
||||||
"@next/env": ["@next/env@15.3.3", "", {}, "sha512-OdiMrzCl2Xi0VTjiQQUK0Xh7bJHnOuET2s+3V+Y40WJBAXrJeGA3f+I8MZJ/YQ3mVGi5XGR1L66oFlgqXhQ4Vw=="],
|
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2DR6kY/OGcokbnCsjHpNeQblqCZ85/1j6njYSkzRdpLn5At7OkSdmk7WyAmB9G0k25+VgqVZ/u356OSoQZ3z0g=="],
|
||||||
|
|
||||||
"@next/swc-darwin-arm64": ["@next/swc-darwin-arm64@15.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WRJERLuH+O3oYB4yZNVahSVFmtxRNjNF1I1c34tYMoJb0Pve+7/RaLAJJizyYiFhjYNGHRAE1Ri2Fd23zgDqhg=="],
|
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ro/fdqaZWL6k1S/5CLv1I0DaZfDVJkWNaUU3un8Lg6m0YENWlDulmIWzV96Iou2wEYyEsZq51mwV8+XQXqMp3w=="],
|
||||||
|
|
||||||
"@next/swc-darwin-x64": ["@next/swc-darwin-x64@15.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-XHdzH/yBc55lu78k/XwtuFR/ZXUTcflpRXcsu0nKmF45U96jt1tsOZhVrn5YH+paw66zOANpOnFQ9i6/j+UYvw=="],
|
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-covwwtZYhlbRWK2HlYX9835qXum4xYZ3E2Mra1mdQ+0ICGoMiw1+nVAn4d9Bo7R3JqSmK1grMq/va+0cdh7bJA=="],
|
||||||
|
|
||||||
"@next/swc-linux-arm64-gnu": ["@next/swc-linux-arm64-gnu@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-VZ3sYL2LXB8znNGcjhocikEkag/8xiLgnvQts41tq6i+wql63SMS1Q6N8RVXHw5pEUjiof+II3HkDd7GFcgkzw=="],
|
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-KQkMEillvlW5Qk5mtGA/3Yz0/tzpNlSw6/3/ttsV1lNtMuOHcGii3zVeXZyi4EJmmLDKYcTcByV2wVsOhDt/zg=="],
|
||||||
|
|
||||||
"@next/swc-linux-arm64-musl": ["@next/swc-linux-arm64-musl@15.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-h6Y1fLU4RWAp1HPNJWDYBQ+e3G7sLckyBXhmH9ajn8l/RSMnhbuPBV/fXmy3muMcVwoJdHL+UtzRzs0nXOf9SA=="],
|
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uRBo6THWei0chz+Y5j37qzx+BtoDRFIkDzZjlpCItBRXyMPIg079eIkOCl3aqr2tkxL4HFyJ4GHDes7W8HuAUg=="],
|
||||||
|
|
||||||
"@next/swc-linux-x64-gnu": ["@next/swc-linux-x64-gnu@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw=="],
|
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.2", "", { "os": "linux", "cpu": "x64" }, "sha512-+uxFlPuCNx/T9PdMClOqeE8USKzj8tVz37KflT3Kdbx/LOlZBRI2yxuIcmx1mPNK8DwSOMNCr4ureSet7eyC0w=="],
|
||||||
|
|
||||||
"@next/swc-linux-x64-musl": ["@next/swc-linux-x64-musl@15.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw=="],
|
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-LLTKmaI5cfD8dVzh5Vt7+OMo+AIOClEdIU/TSKbXXT2iScUTSxOGoBhfuv+FU8R9MLmrkIL1e2fBMkEEjYAtPQ=="],
|
||||||
|
|
||||||
"@next/swc-win32-arm64-msvc": ["@next/swc-win32-arm64-msvc@15.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-SxorONgi6K7ZUysMtRF3mIeHC5aA3IQLmKFQzU0OuhuUYwpOBc1ypaLJLP5Bf3M9k53KUUUj4vTPwzGvl/NwlQ=="],
|
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aW5B8wOPioJ4mBdMDXkt5f3j8pUr9W8AnlX0Df35uRWNT1Y6RIybxjnSUe+PhM+M1bwgyY8PHLmXZC6zT1o5tA=="],
|
||||||
|
|
||||||
"@next/swc-win32-x64-msvc": ["@next/swc-win32-x64-msvc@15.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4QZG6F8enl9/S2+yIiOiju0iCTFd93d8VC1q9LZS4p/Xuk81W2QDjCFeoogmrWWkAD59z8ZxepBQap2dKS5ruw=="],
|
|
||||||
|
|
||||||
"@schummar/icu-type-parser": ["@schummar/icu-type-parser@1.21.5", "", {}, "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw=="],
|
|
||||||
|
|
||||||
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
|
"@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="],
|
||||||
|
|
||||||
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
|
"@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="],
|
||||||
|
|
||||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.8", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.8" } }, "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q=="],
|
"@tailwindcss/node": ["@tailwindcss/node@4.1.7", "", { "dependencies": { "@ampproject/remapping": "^2.3.0", "enhanced-resolve": "^5.18.1", "jiti": "^2.4.2", "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", "tailwindcss": "4.1.7" } }, "sha512-9rsOpdY9idRI2NH6CL4wORFY0+Q6fnx9XP9Ju+iq/0wJwGD5IByIgFmwVbyy4ymuyprj8Qh4ErxMKTUL4uNh3g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.8", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.8", "@tailwindcss/oxide-darwin-arm64": "4.1.8", "@tailwindcss/oxide-darwin-x64": "4.1.8", "@tailwindcss/oxide-freebsd-x64": "4.1.8", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8", "@tailwindcss/oxide-linux-arm64-musl": "4.1.8", "@tailwindcss/oxide-linux-x64-gnu": "4.1.8", "@tailwindcss/oxide-linux-x64-musl": "4.1.8", "@tailwindcss/oxide-wasm32-wasi": "4.1.8", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8", "@tailwindcss/oxide-win32-x64-msvc": "4.1.8" } }, "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A=="],
|
"@tailwindcss/oxide": ["@tailwindcss/oxide@4.1.7", "", { "dependencies": { "detect-libc": "^2.0.4", "tar": "^7.4.3" }, "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.1.7", "@tailwindcss/oxide-darwin-arm64": "4.1.7", "@tailwindcss/oxide-darwin-x64": "4.1.7", "@tailwindcss/oxide-freebsd-x64": "4.1.7", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.7", "@tailwindcss/oxide-linux-arm64-gnu": "4.1.7", "@tailwindcss/oxide-linux-arm64-musl": "4.1.7", "@tailwindcss/oxide-linux-x64-gnu": "4.1.7", "@tailwindcss/oxide-linux-x64-musl": "4.1.7", "@tailwindcss/oxide-wasm32-wasi": "4.1.7", "@tailwindcss/oxide-win32-arm64-msvc": "4.1.7", "@tailwindcss/oxide-win32-x64-msvc": "4.1.7" } }, "sha512-5SF95Ctm9DFiUyjUPnDGkoKItPX/k+xifcQhcqX5RA85m50jw1pT/KzjdvlqxRja45Y52nR4MR9fD1JYd7f8NQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.8", "", { "os": "android", "cpu": "arm64" }, "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg=="],
|
"@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.1.7", "", { "os": "android", "cpu": "arm64" }, "sha512-IWA410JZ8fF7kACus6BrUwY2Z1t1hm0+ZWNEzykKmMNM09wQooOcN/VXr0p/WJdtHZ90PvJf2AIBS/Ceqx1emg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A=="],
|
"@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.1.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-81jUw9To7fimGGkuJ2W5h3/oGonTOZKZ8C2ghm/TTxbwvfSiFSDPd6/A/KE2N7Jp4mv3Ps9OFqg2fEKgZFfsvg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw=="],
|
"@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.1.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-q77rWjEyGHV4PdDBtrzO0tgBBPlQWKY7wZK0cUok/HaGgbNKecegNxCGikuPJn5wFAlIywC3v+WMBt0PEBtwGw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.8", "", { "os": "freebsd", "cpu": "x64" }, "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg=="],
|
"@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.1.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-RfmdbbK6G6ptgF4qqbzoxmH+PKfP4KSVs7SRlTwcbRgBwezJkAO3Qta/7gDy10Q2DcUVkKxFLXUQO6J3CRvBGw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8", "", { "os": "linux", "cpu": "arm" }, "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ=="],
|
"@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.1.7", "", { "os": "linux", "cpu": "arm" }, "sha512-OZqsGvpwOa13lVd1z6JVwQXadEobmesxQ4AxhrwRiPuE04quvZHWn/LnihMg7/XkN+dTioXp/VMu/p6A5eZP3g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q=="],
|
"@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.1.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-voMvBTnJSfKecJxGkoeAyW/2XRToLZ227LxswLAwKY7YslG/Xkw9/tJNH+3IVh5bdYzYE7DfiaPbRkSHFxY1xA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ=="],
|
"@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.1.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-PjGuNNmJeKHnP58M7XyjJyla8LPo+RmwHQpBI+W/OxqrwojyuCQ+GUtygu7jUqTEexejZHr/z3nBc/gTiXBj4A=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g=="],
|
"@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.1.7", "", { "os": "linux", "cpu": "x64" }, "sha512-HMs+Va+ZR3gC3mLZE00gXxtBo3JoSQxtu9lobbZd+DmfkIxR54NO7Z+UQNPsa0P/ITn1TevtFxXTpsRU7qEvWg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.8", "", { "os": "linux", "cpu": "x64" }, "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg=="],
|
"@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.1.7", "", { "os": "linux", "cpu": "x64" }, "sha512-MHZ6jyNlutdHH8rd+YTdr3QbXrHXqwIhHw9e7yXEBcQdluGwhpQY2Eku8UZK6ReLaWtQ4gijIv5QoM5eE+qlsA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.8", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.10", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg=="],
|
"@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.1.7", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@emnapi/wasi-threads": "^1.0.2", "@napi-rs/wasm-runtime": "^0.2.9", "@tybys/wasm-util": "^0.9.0", "tslib": "^2.8.0" }, "cpu": "none" }, "sha512-ANaSKt74ZRzE2TvJmUcbFQ8zS201cIPxUDm5qez5rLEwWkie2SkGtA4P+GPTj+u8N6JbPrC8MtY8RmJA35Oo+A=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA=="],
|
"@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.1.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-HUiSiXQ9gLJBAPCMVRk2RT1ZrBjto7WvqsPBwUrNK2BcdSxMnk19h4pjZjI7zgPhDxlAbJSumTC4ljeA9y0tEw=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.8", "", { "os": "win32", "cpu": "x64" }, "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ=="],
|
"@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.1.7", "", { "os": "win32", "cpu": "x64" }, "sha512-rYHGmvoHiLJ8hWucSfSOEmdCBIGZIq7SpkPRSqLsH2Ab2YUNgKeAPT1Fi2cx3+hnYOrAb0jp9cRyode3bBW4mQ=="],
|
||||||
|
|
||||||
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.8", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.8", "@tailwindcss/oxide": "4.1.8", "postcss": "^8.4.41", "tailwindcss": "4.1.8" } }, "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw=="],
|
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.7", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.7", "@tailwindcss/oxide": "4.1.7", "postcss": "^8.4.41", "tailwindcss": "4.1.7" } }, "sha512-88g3qmNZn7jDgrrcp3ZXEQfp9CVox7xjP1HN2TFKI03CltPVd/c61ydn5qJJL8FYunn0OqBaW5HNUga0kmPVvw=="],
|
||||||
|
|
||||||
"@types/chai": ["@types/chai@4.3.20", "", {}, "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ=="],
|
"@types/node": ["@types/node@20.17.50", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-Mxiq0ULv/zo1OzOhwPqOA13I81CV/W3nvd3ChtQZRT5Cwz3cr0FKo/wMSsbTqL3EXpaBAEQhva2B8ByRkOIh9A=="],
|
||||||
|
|
||||||
"@types/mocha": ["@types/mocha@10.0.10", "", {}, "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q=="],
|
"@types/react": ["@types/react@19.1.5", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-piErsCVVbpMMT2r7wbawdZsq4xMvIAhQuac2gedQHysu1TZYEigE6pnFfgZT+/jQnrRuF5r+SHzuehFjfRjr4g=="],
|
||||||
|
|
||||||
"@types/node": ["@types/node@20.17.57", "", { "dependencies": { "undici-types": "~6.19.2" } }, "sha512-f3T4y6VU4fVQDKVqJV4Uppy8c1p/sVvS3peyqxyWnzkqXFJLRU7Y1Bl7rMS1Qe9z0v4M6McY0Fp9yBsgHJUsWQ=="],
|
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.1.6", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q=="],
|
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.1.5", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg=="],
|
"@types/react-dom": ["@types/react-dom@19.1.5", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg=="],
|
||||||
|
|
||||||
"@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="],
|
|
||||||
|
|
||||||
"ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
|
|
||||||
|
|
||||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
|
||||||
|
|
||||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
|
||||||
|
|
||||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
|
||||||
|
|
||||||
"argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
|
|
||||||
|
|
||||||
"assertion-error": ["assertion-error@1.1.0", "", {}, "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="],
|
|
||||||
|
|
||||||
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
|
|
||||||
|
|
||||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
|
|
||||||
|
|
||||||
"axios": ["axios@1.9.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg=="],
|
|
||||||
|
|
||||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
|
||||||
|
|
||||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
|
||||||
|
|
||||||
"brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
|
|
||||||
|
|
||||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
|
||||||
|
|
||||||
"browser-stdout": ["browser-stdout@1.3.1", "", {}, "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="],
|
|
||||||
|
|
||||||
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
|
"busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="],
|
||||||
|
|
||||||
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
|
||||||
|
|
||||||
"camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="],
|
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001718", "", {}, "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw=="],
|
"caniuse-lite": ["caniuse-lite@1.0.30001718", "", {}, "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw=="],
|
||||||
|
|
||||||
"chai": ["chai@4.5.0", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", "deep-eql": "^4.1.3", "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", "type-detect": "^4.1.0" } }, "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw=="],
|
|
||||||
|
|
||||||
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
|
||||||
|
|
||||||
"check-error": ["check-error@1.0.3", "", { "dependencies": { "get-func-name": "^2.0.2" } }, "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg=="],
|
|
||||||
|
|
||||||
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
|
||||||
|
|
||||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
"client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="],
|
||||||
|
|
||||||
"cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="],
|
|
||||||
|
|
||||||
"cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="],
|
|
||||||
|
|
||||||
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
|
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
|
||||||
|
|
||||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||||
@ -234,132 +155,22 @@
|
|||||||
|
|
||||||
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||||
|
|
||||||
"colorspace": ["colorspace@1.1.4", "", { "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" } }, "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w=="],
|
|
||||||
|
|
||||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
|
||||||
|
|
||||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
|
||||||
|
|
||||||
"decamelize": ["decamelize@4.0.0", "", {}, "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="],
|
|
||||||
|
|
||||||
"decimal.js": ["decimal.js@10.5.0", "", {}, "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw=="],
|
|
||||||
|
|
||||||
"deep-eql": ["deep-eql@4.1.4", "", { "dependencies": { "type-detect": "^4.0.0" } }, "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg=="],
|
|
||||||
|
|
||||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="],
|
|
||||||
|
|
||||||
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
|
|
||||||
|
|
||||||
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
||||||
|
|
||||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||||
|
|
||||||
"diff": ["diff@5.2.0", "", {}, "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A=="],
|
|
||||||
|
|
||||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
|
||||||
|
|
||||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
|
||||||
|
|
||||||
"enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="],
|
|
||||||
|
|
||||||
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
"enhanced-resolve": ["enhanced-resolve@5.18.1", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg=="],
|
||||||
|
|
||||||
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
"framer-motion": ["framer-motion@12.12.2", "", { "dependencies": { "motion-dom": "^12.12.1", "motion-utils": "^12.12.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-qCszZCiGWkilL40E3VuhIJJC/CS3SIBl2IHyGK8FU30nOUhTmhBNWPrNFyozAWH/bXxwzi19vJHIGVdALF0LCg=="],
|
||||||
|
|
||||||
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
|
||||||
|
|
||||||
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
|
||||||
|
|
||||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
|
||||||
|
|
||||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
|
||||||
|
|
||||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
|
||||||
|
|
||||||
"fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="],
|
|
||||||
|
|
||||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
|
||||||
|
|
||||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
|
||||||
|
|
||||||
"flat": ["flat@5.0.2", "", { "bin": { "flat": "cli.js" } }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="],
|
|
||||||
|
|
||||||
"fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="],
|
|
||||||
|
|
||||||
"follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="],
|
|
||||||
|
|
||||||
"form-data": ["form-data@4.0.2", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "mime-types": "^2.1.12" } }, "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w=="],
|
|
||||||
|
|
||||||
"framer-motion": ["framer-motion@12.15.0", "", { "dependencies": { "motion-dom": "^12.15.0", "motion-utils": "^12.12.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-XKg/LnKExdLGugZrDILV7jZjI599785lDIJZLxMiiIFidCsy0a4R2ZEf+Izm67zyOuJgQYTHOmodi7igQsw3vg=="],
|
|
||||||
|
|
||||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
|
|
||||||
|
|
||||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
|
||||||
|
|
||||||
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
||||||
|
|
||||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
|
||||||
|
|
||||||
"get-func-name": ["get-func-name@2.0.2", "", {}, "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ=="],
|
|
||||||
|
|
||||||
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
|
||||||
|
|
||||||
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
|
||||||
|
|
||||||
"glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
|
|
||||||
|
|
||||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
||||||
|
|
||||||
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
|
||||||
|
|
||||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||||
|
|
||||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
|
||||||
|
|
||||||
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
|
||||||
|
|
||||||
"has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="],
|
|
||||||
|
|
||||||
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
|
||||||
|
|
||||||
"he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="],
|
|
||||||
|
|
||||||
"i18next": ["i18next@25.2.1", "", { "dependencies": { "@babel/runtime": "^7.27.1" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw=="],
|
|
||||||
|
|
||||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
|
|
||||||
|
|
||||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
|
||||||
|
|
||||||
"intl-messageformat": ["intl-messageformat@10.7.16", "", { "dependencies": { "@formatjs/ecma402-abstract": "2.3.4", "@formatjs/fast-memoize": "2.2.7", "@formatjs/icu-messageformat-parser": "2.11.2", "tslib": "^2.8.0" } }, "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug=="],
|
|
||||||
|
|
||||||
"ioredis": ["ioredis@5.6.1", "", { "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA=="],
|
|
||||||
|
|
||||||
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||||
|
|
||||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
|
||||||
|
|
||||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
|
||||||
|
|
||||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
|
||||||
|
|
||||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
|
||||||
|
|
||||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
|
||||||
|
|
||||||
"is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="],
|
|
||||||
|
|
||||||
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
|
||||||
|
|
||||||
"is-unicode-supported": ["is-unicode-supported@0.1.0", "", {}, "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw=="],
|
|
||||||
|
|
||||||
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
"jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
|
||||||
|
|
||||||
"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
|
|
||||||
|
|
||||||
"kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="],
|
|
||||||
|
|
||||||
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "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" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
"lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "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" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
|
||||||
|
|
||||||
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
|
||||||
@ -382,186 +193,62 @@
|
|||||||
|
|
||||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
|
||||||
|
|
||||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
|
||||||
|
|
||||||
"lodash.defaults": ["lodash.defaults@4.2.0", "", {}, "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="],
|
|
||||||
|
|
||||||
"lodash.isarguments": ["lodash.isarguments@3.1.0", "", {}, "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="],
|
|
||||||
|
|
||||||
"log-symbols": ["log-symbols@4.1.0", "", { "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" } }, "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg=="],
|
|
||||||
|
|
||||||
"logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="],
|
|
||||||
|
|
||||||
"loupe": ["loupe@2.3.7", "", { "dependencies": { "get-func-name": "^2.0.1" } }, "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA=="],
|
|
||||||
|
|
||||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||||
|
|
||||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
|
||||||
|
|
||||||
"mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
|
|
||||||
|
|
||||||
"mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
|
|
||||||
|
|
||||||
"minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="],
|
|
||||||
|
|
||||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
|
|
||||||
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
||||||
|
|
||||||
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||||
|
|
||||||
"mocha": ["mocha@10.8.2", "", { "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", "chokidar": "^3.5.3", "debug": "^4.3.5", "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", "glob": "^8.1.0", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", "minimatch": "^5.1.6", "ms": "^2.1.3", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", "workerpool": "^6.5.1", "yargs": "^16.2.0", "yargs-parser": "^20.2.9", "yargs-unparser": "^2.0.0" }, "bin": { "mocha": "bin/mocha.js", "_mocha": "bin/_mocha" } }, "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg=="],
|
"motion-dom": ["motion-dom@12.12.1", "", { "dependencies": { "motion-utils": "^12.12.1" } }, "sha512-GXq/uUbZBEiFFE+K1Z/sxdPdadMdfJ/jmBALDfIuHGi0NmtealLOfH9FqT+6aNPgVx8ilq0DtYmyQlo6Uj9LKQ=="],
|
||||||
|
|
||||||
"motion-dom": ["motion-dom@12.15.0", "", { "dependencies": { "motion-utils": "^12.12.1" } }, "sha512-D2ldJgor+2vdcrDtKJw48k3OddXiZN1dDLLWrS8kiHzQdYVruh0IoTwbJBslrnTXIPgFED7PBN2Zbwl7rNqnhA=="],
|
|
||||||
|
|
||||||
"motion-utils": ["motion-utils@12.12.1", "", {}, "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w=="],
|
"motion-utils": ["motion-utils@12.12.1", "", {}, "sha512-f9qiqUHm7hWSLlNW8gS9pisnsN7CRFRD58vNjptKdsqFLpkVnX00TNeD6Q0d27V9KzT7ySFyK1TZ/DShfVOv6w=="],
|
||||||
|
|
||||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
||||||
|
|
||||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||||
|
|
||||||
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
"next": ["next@15.3.2", "", { "dependencies": { "@next/env": "15.3.2", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.2", "@next/swc-darwin-x64": "15.3.2", "@next/swc-linux-arm64-gnu": "15.3.2", "@next/swc-linux-arm64-musl": "15.3.2", "@next/swc-linux-x64-gnu": "15.3.2", "@next/swc-linux-x64-musl": "15.3.2", "@next/swc-win32-arm64-msvc": "15.3.2", "@next/swc-win32-x64-msvc": "15.3.2", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "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" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-CA3BatMyHkxZ48sgOCLdVHjFU36N7TF1HhqAHLFOkV6buwZnvMI84Cug8xD56B9mCuKrqXnLn94417GrZ/jjCQ=="],
|
||||||
|
|
||||||
"next": ["next@15.3.3", "", { "dependencies": { "@next/env": "15.3.3", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "15.3.3", "@next/swc-darwin-x64": "15.3.3", "@next/swc-linux-arm64-gnu": "15.3.3", "@next/swc-linux-arm64-musl": "15.3.3", "@next/swc-linux-x64-gnu": "15.3.3", "@next/swc-linux-x64-musl": "15.3.3", "@next/swc-win32-arm64-msvc": "15.3.3", "@next/swc-win32-x64-msvc": "15.3.3", "sharp": "^0.34.1" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.41.2", "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" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-JqNj29hHNmCLtNvd090SyRbXJiivQ+58XjCcrC50Crb5g5u2zi7Y2YivbsEfzk6AtVI80akdOQbaMZwWB1Hthw=="],
|
|
||||||
|
|
||||||
"next-intl": ["next-intl@4.1.0", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.5.4", "negotiator": "^1.0.0", "use-intl": "^4.1.0" }, "peerDependencies": { "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-JNJRjc7sdnfUxhZmGcvzDszZ60tQKrygV/VLsgzXhnJDxQPn1cN2rVpc53adA1SvBJwPK2O6Sc6b4gYSILjCzw=="],
|
|
||||||
|
|
||||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
|
||||||
|
|
||||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
|
||||||
|
|
||||||
"one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="],
|
|
||||||
|
|
||||||
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
|
||||||
|
|
||||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
|
||||||
|
|
||||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
|
||||||
|
|
||||||
"pathval": ["pathval@1.1.1", "", {}, "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="],
|
|
||||||
|
|
||||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||||
|
|
||||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
|
||||||
|
|
||||||
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
"postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="],
|
||||||
|
|
||||||
"postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="],
|
|
||||||
|
|
||||||
"property-expr": ["property-expr@2.0.6", "", {}, "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="],
|
|
||||||
|
|
||||||
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
|
|
||||||
|
|
||||||
"randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="],
|
|
||||||
|
|
||||||
"react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
|
"react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="],
|
||||||
|
|
||||||
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
|
"react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="],
|
||||||
|
|
||||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
|
||||||
|
|
||||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
|
||||||
|
|
||||||
"redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="],
|
|
||||||
|
|
||||||
"redis-parser": ["redis-parser@3.0.0", "", { "dependencies": { "redis-errors": "^1.0.0" } }, "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A=="],
|
|
||||||
|
|
||||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
|
||||||
|
|
||||||
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
|
||||||
|
|
||||||
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
|
|
||||||
|
|
||||||
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
|
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
|
||||||
|
|
||||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||||
|
|
||||||
"serialize-javascript": ["serialize-javascript@6.0.2", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="],
|
|
||||||
|
|
||||||
"sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
|
"sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
|
||||||
|
|
||||||
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
||||||
|
|
||||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||||
|
|
||||||
"stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="],
|
|
||||||
|
|
||||||
"standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="],
|
|
||||||
|
|
||||||
"streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
|
"streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="],
|
||||||
|
|
||||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
|
||||||
|
|
||||||
"string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="],
|
|
||||||
|
|
||||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
|
||||||
|
|
||||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
|
||||||
|
|
||||||
"styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
|
"styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="],
|
||||||
|
|
||||||
"supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
|
|
||||||
|
|
||||||
"swr": ["swr@2.3.3", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A=="],
|
"swr": ["swr@2.3.3", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A=="],
|
||||||
|
|
||||||
"tailwindcss": ["tailwindcss@4.1.8", "", {}, "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og=="],
|
"tailwindcss": ["tailwindcss@4.1.7", "", {}, "sha512-kr1o/ErIdNhTz8uzAYL7TpaUuzKIE6QPQ4qmSdxnoX/lo+5wmUHQA6h3L5yIqEImSRnAAURDirLu/BgiXGPAhg=="],
|
||||||
|
|
||||||
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
||||||
|
|
||||||
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||||
|
|
||||||
"text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="],
|
|
||||||
|
|
||||||
"tiny-case": ["tiny-case@1.0.3", "", {}, "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="],
|
|
||||||
|
|
||||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
|
||||||
|
|
||||||
"toposort": ["toposort@2.0.2", "", {}, "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="],
|
|
||||||
|
|
||||||
"triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="],
|
|
||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="],
|
|
||||||
|
|
||||||
"type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="],
|
|
||||||
|
|
||||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||||
|
|
||||||
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
"undici-types": ["undici-types@6.19.8", "", {}, "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="],
|
||||||
|
|
||||||
"use-intl": ["use-intl@4.1.0", "", { "dependencies": { "@formatjs/fast-memoize": "^2.2.0", "@schummar/icu-type-parser": "1.21.5", "intl-messageformat": "^10.5.14" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, "sha512-mQvDYFvoGn+bm/PWvlQOtluKCknsQ5a9F1Cj0hMfBjMBVTwnOqLPd6srhjvVdEQEQFVyHM1PfyifKqKYb11M9Q=="],
|
|
||||||
|
|
||||||
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
||||||
|
|
||||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
|
||||||
|
|
||||||
"winston": ["winston@3.17.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw=="],
|
|
||||||
|
|
||||||
"winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="],
|
|
||||||
|
|
||||||
"workerpool": ["workerpool@6.5.1", "", {}, "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA=="],
|
|
||||||
|
|
||||||
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
|
||||||
|
|
||||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
||||||
|
|
||||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
|
||||||
|
|
||||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||||
|
|
||||||
"yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="],
|
|
||||||
|
|
||||||
"yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="],
|
|
||||||
|
|
||||||
"yargs-unparser": ["yargs-unparser@2.0.0", "", { "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" } }, "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA=="],
|
|
||||||
|
|
||||||
"yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
|
||||||
|
|
||||||
"yup": ["yup@1.6.1", "", { "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", "toposort": "^2.0.2", "type-fest": "^2.19.0" } }, "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA=="],
|
|
||||||
|
|
||||||
"@formatjs/ecma402-abstract/@formatjs/intl-localematcher": ["@formatjs/intl-localematcher@0.6.1", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||||
@ -574,16 +261,6 @@
|
|||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
||||||
"colorspace/color": ["color@3.2.1", "", { "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" } }, "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="],
|
|
||||||
|
|
||||||
"log-symbols/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
|
||||||
|
|
||||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||||
|
|
||||||
"colorspace/color/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
|
||||||
|
|
||||||
"log-symbols/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
|
||||||
|
|
||||||
"colorspace/color/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
import useSWRMutation from "swr/mutation";
|
|
||||||
import { useState } from "react";
|
|
||||||
import type { CaptchaVerificationRawResponse, CaptchaSessionRawResponse } from "@backend/src/schema";
|
|
||||||
import { fetcher } from "@/lib/net";
|
|
||||||
import { computeVdfInWorker } from "@/lib/vdf";
|
|
||||||
|
|
||||||
interface UseCaptchaOptions {
|
|
||||||
backendURL: string;
|
|
||||||
route: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useCaptcha({ backendURL, route }: UseCaptchaOptions) {
|
|
||||||
const fullUrl = `${backendURL}/captcha/session`;
|
|
||||||
const [isUsed, setIsUsed] = useState(false);
|
|
||||||
|
|
||||||
const { trigger, data, isMutating, error } = useSWRMutation<CaptchaVerificationRawResponse, Error>(
|
|
||||||
fullUrl,
|
|
||||||
async (url: string) => {
|
|
||||||
const sessionRes = await fetcher<CaptchaSessionRawResponse>(url, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
data: { route }
|
|
||||||
});
|
|
||||||
|
|
||||||
const { g, n, t, id } = sessionRes;
|
|
||||||
if (!g || !n || !t || !id) {
|
|
||||||
throw new Error("Missing required CAPTCHA parameters");
|
|
||||||
}
|
|
||||||
|
|
||||||
const ans = await computeVdfInWorker(BigInt(g), BigInt(n), BigInt(t));
|
|
||||||
|
|
||||||
const resultUrl = new URL(`${backendURL}/captcha/${id}/result`);
|
|
||||||
resultUrl.searchParams.set("ans", ans.result.toString());
|
|
||||||
|
|
||||||
const result = await fetcher<CaptchaVerificationRawResponse>(resultUrl.toString());
|
|
||||||
setIsUsed(false);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
startCaptcha: trigger,
|
|
||||||
captchaResult: data,
|
|
||||||
isLoadingCaptcha: isMutating,
|
|
||||||
captchaError: error,
|
|
||||||
captchaUsed: isUsed,
|
|
||||||
setCaptchaUsedState: setIsUsed
|
|
||||||
};
|
|
||||||
}
|
|
@ -15,14 +15,9 @@ import { SearchIcon } from "@/components/icons/SearchIcon";
|
|||||||
import { InfoIcon } from "@/components/icons/InfoIcon";
|
import { InfoIcon } from "@/components/icons/InfoIcon";
|
||||||
import { HomeIcon } from "@/components/icons/HomeIcon";
|
import { HomeIcon } from "@/components/icons/HomeIcon";
|
||||||
import { TextButton } from "@/components/ui/Buttons/TextButton";
|
import { TextButton } from "@/components/ui/Buttons/TextButton";
|
||||||
import { Link } from "@/i18n/navigation";
|
import Link from "next/link";
|
||||||
import { UserResponse } from "@backend/src/schema";
|
|
||||||
|
|
||||||
interface HeaderProps {
|
export const HeaderDestop = () => {
|
||||||
user?: UserResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HeaderDestop = ({ user }: HeaderProps) => {
|
|
||||||
return (
|
return (
|
||||||
<div className="hidden md:flex relative top-0 left-0 w-full h-28 z-20 justify-between">
|
<div className="hidden md:flex relative top-0 left-0 w-full h-28 z-20 justify-between">
|
||||||
<div className="w-[305px] xl:ml-8 inline-flex items-center">
|
<div className="w-[305px] xl:ml-8 inline-flex items-center">
|
||||||
@ -42,19 +37,14 @@ export const HeaderDestop = ({ user }: HeaderProps) => {
|
|||||||
className="inline-flex relative gap-6 h-full lg:right-12
|
className="inline-flex relative gap-6 h-full lg:right-12
|
||||||
text-xl font-medium items-center w-[15rem] min-w-[8rem] mr-4 lg:mr-0 lg:w-[305px] justify-end"
|
text-xl font-medium items-center w-[15rem] min-w-[8rem] mr-4 lg:mr-0 lg:w-[305px] justify-end"
|
||||||
>
|
>
|
||||||
{user ? (
|
<a href="/signup">注册</a>
|
||||||
<Link href="/my/profile">{user.nickname || user.username}</Link>
|
|
||||||
) : (
|
|
||||||
<Link href="/signup">注册</Link>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<a href="/about">关于</a>
|
<a href="/about">关于</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const HeaderMobile = ({ user }: HeaderProps) => {
|
export const HeaderMobile = () => {
|
||||||
const [showDrawer, setShowDrawer] = useState(false);
|
const [showDrawer, setShowDrawer] = useState(false);
|
||||||
const [showsearchBox, setShowsearchBox] = useState(false);
|
const [showsearchBox, setShowsearchBox] = useState(false);
|
||||||
|
|
||||||
@ -111,14 +101,14 @@ export const HeaderMobile = ({ user }: HeaderProps) => {
|
|||||||
)}
|
)}
|
||||||
{!showsearchBox && (
|
{!showsearchBox && (
|
||||||
<div className="absolute left-1/2 -translate-x-1/2 -translate-y-0.5 inline-flex h-full items-center">
|
<div className="absolute left-1/2 -translate-x-1/2 -translate-y-0.5 inline-flex h-full items-center">
|
||||||
<Link href="/">
|
<a href="/">
|
||||||
<DarkModeImage
|
<DarkModeImage
|
||||||
lightSrc={LogoMobileLight}
|
lightSrc={LogoMobileLight}
|
||||||
darkSrc={LogoMobileDark}
|
darkSrc={LogoMobileDark}
|
||||||
alt="Logo"
|
alt="Logo"
|
||||||
className="w-24 h-8 translate-y-[2px]"
|
className="w-24 h-8 translate-y-[2px]"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showsearchBox && <SearchBox close={() => setShowsearchBox(false)} />}
|
{showsearchBox && <SearchBox close={() => setShowsearchBox(false)} />}
|
||||||
@ -135,11 +125,11 @@ export const HeaderMobile = ({ user }: HeaderProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Header = (props: HeaderProps) => {
|
export const Header = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HeaderDestop {...props} />
|
<HeaderDestop />
|
||||||
<HeaderMobile {...props} />
|
<HeaderMobile />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,86 +1,41 @@
|
|||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { TextButton } from "./Buttons/TextButton";
|
import { TextButton } from "./Buttons/TextButton";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export const useDisableBodyScroll = (open: boolean) => {
|
interface DialogProps {
|
||||||
useEffect(() => {
|
|
||||||
if (open) {
|
|
||||||
document.body.style.overflow = "hidden";
|
|
||||||
} else {
|
|
||||||
document.body.style.overflow = "unset";
|
|
||||||
}
|
|
||||||
}, [open]);
|
|
||||||
};
|
|
||||||
|
|
||||||
type OptionalChidrenProps<T = React.HTMLAttributes<HTMLElement>> = T & {
|
|
||||||
children?: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
type HeadElementAttr = React.HTMLAttributes<HTMLHeadElement>;
|
|
||||||
type DivElementAttr = React.HTMLAttributes<HTMLDivElement>;
|
|
||||||
type ButtonElementAttr = React.HTMLAttributes<HTMLButtonElement>;
|
|
||||||
|
|
||||||
type DialogHeadlineProps = OptionalChidrenProps<HeadElementAttr>;
|
|
||||||
type DialogSupportingTextProps = OptionalChidrenProps<DivElementAttr>;
|
|
||||||
type DialogButtonGroupProps = OptionalChidrenProps<DivElementAttr>;
|
|
||||||
|
|
||||||
interface DialogButtonProps extends OptionalChidrenProps<ButtonElementAttr> {
|
|
||||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
||||||
}
|
|
||||||
interface DialogProps extends OptionalChidrenProps<DivElementAttr> {
|
|
||||||
show: boolean;
|
show: boolean;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DialogHeadline: React.FC<DialogHeadlineProps> = ({
|
interface OptionalChidrenProps {
|
||||||
children,
|
children?: React.ReactNode;
|
||||||
className,
|
|
||||||
...rest
|
|
||||||
}: DialogHeadlineProps) => {
|
|
||||||
return (
|
|
||||||
<h2 className={"text-2xl leading-8 text-on-surface dark:text-dark-on-surface " + className || ""} {...rest}>
|
|
||||||
{children}
|
|
||||||
</h2>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DialogSupportingText: React.FC<DialogSupportingTextProps> = ({
|
|
||||||
children,
|
|
||||||
className,
|
|
||||||
...rest
|
|
||||||
}: DialogHeadlineProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"mt-4 text-sm leading-5 mb-6 text-on-surface-variant dark:text-dark-on-surface-variant " + className ||
|
|
||||||
""
|
|
||||||
}
|
}
|
||||||
{...rest}
|
|
||||||
>
|
type DialogHeadlineProps = OptionalChidrenProps;
|
||||||
{children}
|
type DialogSupportingTextProps = OptionalChidrenProps;
|
||||||
</div>
|
type DialogButtonGroupProps = OptionalChidrenProps;
|
||||||
);
|
|
||||||
|
interface DialogButtonProps extends OptionalChidrenProps {
|
||||||
|
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DialogHeadline: React.FC<DialogHeadlineProps> = ({ children }: DialogHeadlineProps) => {
|
||||||
|
return <h2 className="text-2xl leading-8 text-on-surface dark:text-dark-on-surface">{children}</h2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DialogButton: React.FC<DialogButtonProps> = ({ children, onClick, ...rest }: DialogButtonProps) => {
|
export const DialogSupportingText: React.FC<DialogSupportingTextProps> = ({ children }: DialogHeadlineProps) => {
|
||||||
return (
|
return <div className="mt-4 text-sm leading-5 mb-6">{children}</div>;
|
||||||
<TextButton onClick={onClick} {...rest}>
|
|
||||||
{children}
|
|
||||||
</TextButton>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DialogButtonGroup: React.FC<DialogButtonGroupProps> = ({ children, ...rest }: DialogButtonGroupProps) => {
|
export const DialogButton: React.FC<DialogButtonProps> = ({ children, onClick }: DialogButtonProps) => {
|
||||||
return (
|
return <TextButton onClick={onClick}>{children}</TextButton>;
|
||||||
<div className="flex justify-end gap-2" {...rest}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Dialog: React.FC<DialogProps> = ({ show, children, className }: DialogProps) => {
|
export const DialogButtonGroup: React.FC<DialogButtonGroupProps> = ({ children }: DialogButtonGroupProps) => {
|
||||||
useDisableBodyScroll(show);
|
return <div className="flex justify-end gap-2">{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Dialog: React.FC<DialogProps> = ({ show, children }: DialogProps) => {
|
||||||
return (
|
return (
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{show && (
|
{show && (
|
||||||
@ -94,13 +49,12 @@ export const Dialog: React.FC<DialogProps> = ({ show, children, className }: Dia
|
|||||||
transition={{ duration: 0.3 }}
|
transition={{ duration: 0.3 }}
|
||||||
/>
|
/>
|
||||||
<motion.div
|
<motion.div
|
||||||
className={`fixed min-w-[17.5rem] sm:max-w-[35rem] h-auto z-50 bg-surface-container-high
|
className="fixed min-w-[17.5rem] sm:max-w-[35rem] h-auto z-50 bg-surface-container-high
|
||||||
shadow-2xl shadow-shadow/15 rounded-[1.75rem] p-6 dark:bg-dark-surface-container-high mx-2 ${className}`}
|
shadow-2xl shadow-shadow/15 rounded-[1.75rem] p-6 dark:bg-dark-surface-container-high mx-2"
|
||||||
initial={{ opacity: 0.5, transform: "scale(1.1)" }}
|
initial={{ opacity: 0.5, transform: "scale(1.1)" }}
|
||||||
animate={{ opacity: 1, transform: "scale(1)" }}
|
animate={{ opacity: 1, transform: "scale(1)" }}
|
||||||
exit={{ opacity: 0 }}
|
exit={{ opacity: 0 }}
|
||||||
transition={{ ease: [0.31, 0.69, 0.3, 1.02], duration: 0.3 }}
|
transition={{ ease: [0.31, 0.69, 0.3, 1.02], duration: 0.3 }}
|
||||||
aria-modal="true"
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
import { ReactNode } from "react";
|
|
||||||
|
|
||||||
// These tags are available
|
|
||||||
type Tag = "p" | "b" | "i";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
children(tags: Record<Tag, (chunks: ReactNode) => ReactNode>): ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function LocalizedRichText({ children }: Props) {
|
|
||||||
return (
|
|
||||||
<div className="prose">
|
|
||||||
{children({
|
|
||||||
p: (chunks: ReactNode) => <p>{chunks}</p>,
|
|
||||||
b: (chunks: ReactNode) => <b className="font-semibold">{chunks}</b>,
|
|
||||||
i: (chunks: ReactNode) => <i className="italic">{chunks}</i>
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { createNavigation } from "next-intl/navigation";
|
|
||||||
import { routing } from "./routing";
|
|
||||||
|
|
||||||
// Lightweight wrappers around Next.js' navigation
|
|
||||||
// APIs that consider the routing configuration
|
|
||||||
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);
|
|
@ -1,21 +0,0 @@
|
|||||||
import { getRequestConfig } from "next-intl/server";
|
|
||||||
import { hasLocale } from "next-intl";
|
|
||||||
import { routing } from "./routing";
|
|
||||||
import zh from "./strings/zh.json";
|
|
||||||
import en from "./strings/en.json";
|
|
||||||
|
|
||||||
const stringsMap = {
|
|
||||||
zh: zh,
|
|
||||||
en: en
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getRequestConfig(async ({ requestLocale }) => {
|
|
||||||
// Typically corresponds to the `[locale]` segment
|
|
||||||
const requested = await requestLocale;
|
|
||||||
const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale;
|
|
||||||
|
|
||||||
return {
|
|
||||||
locale,
|
|
||||||
messages: stringsMap[locale]
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,11 +0,0 @@
|
|||||||
import { defineRouting } from "next-intl/routing";
|
|
||||||
|
|
||||||
export const routing = defineRouting({
|
|
||||||
// A list of all locales that are supported
|
|
||||||
locales: ["en", "zh"],
|
|
||||||
|
|
||||||
// Used when no locale matches
|
|
||||||
defaultLocale: "zh",
|
|
||||||
|
|
||||||
localePrefix: "as-needed"
|
|
||||||
});
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"yup_errors": {
|
|
||||||
"field_too_short": "{field}至少需要{min}个字符。",
|
|
||||||
"field_too_long": "{field}不能多于{max}个字符。"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"yup_errors": {
|
|
||||||
"field_too_short": "{field}至少需要 {min} 个字符。",
|
|
||||||
"field_too_big": "{field}不能多于 {max} 个字符。",
|
|
||||||
"field_required": "请填写{field}。"
|
|
||||||
},
|
|
||||||
"username": "用户名",
|
|
||||||
"password": "密码",
|
|
||||||
"nickname": "昵称",
|
|
||||||
"backend": {
|
|
||||||
"error": {
|
|
||||||
"captcha_failed": "无法完成安全验证。",
|
|
||||||
"user_exists": "用户名 “{username}” 已被占用。",
|
|
||||||
"user_not_found_after_register": "我们的服务器出现错误:找不到名为'{username}'的用户。请联系我们的<support>支持团队</support>,反馈此问题。",
|
|
||||||
"captcha_not_found": "无法完成安全验证。你可以刷新页面并重试。如果此问题反复出现,你可以联系我们的<support>支持团队</support>,反馈此问题。"
|
|
||||||
},
|
|
||||||
"error_code": {
|
|
||||||
"INVALID_QUERY_PARAMS": "查询无效",
|
|
||||||
"UNKNOWN_ERROR": "未知错误",
|
|
||||||
"INVALID_PAYLOAD": "请求格式错误",
|
|
||||||
"INVALID_FORMAT": "数据格式错误",
|
|
||||||
"INVALID_HEADER": "请求头无效",
|
|
||||||
"BODY_TOO_LARGE": "请求体过大",
|
|
||||||
"UNAUTHORIZED": "未授权",
|
|
||||||
"INVALID_CREDENTIALS": "凭证无效",
|
|
||||||
"ENTITY_NOT_FOUND": "实体不存在",
|
|
||||||
"SERVER_ERROR": "服务器错误",
|
|
||||||
"RATE_LIMIT_EXCEEDED": "请求过于频繁",
|
|
||||||
"ENTITY_EXISTS": "实体已存在"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
import { DatabaseUserType, sqlCred } from "@cvsa/core";
|
|
||||||
|
|
||||||
export const getUserBySession = async (sessionID: string) => {
|
|
||||||
const users = await sqlCred<DatabaseUserType[]>`
|
|
||||||
SELECT u.*
|
|
||||||
FROM users u
|
|
||||||
JOIN login_sessions ls ON u.id = ls.uid
|
|
||||||
WHERE ls.id = ${sessionID};
|
|
||||||
`;
|
|
||||||
if (users.length === 0) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
const user = users[0];
|
|
||||||
return {
|
|
||||||
username: user.username,
|
|
||||||
nickname: user.nickname,
|
|
||||||
role: user.role
|
|
||||||
};
|
|
||||||
};
|
|
@ -1,5 +1,3 @@
|
|||||||
import axios, { AxiosRequestConfig, AxiosError, Method } from "axios";
|
|
||||||
|
|
||||||
export class ApiRequestError extends Error {
|
export class ApiRequestError extends Error {
|
||||||
public code: number | undefined;
|
public code: number | undefined;
|
||||||
public response: unknown | undefined;
|
public response: unknown | undefined;
|
||||||
@ -10,48 +8,3 @@ export class ApiRequestError extends Error {
|
|||||||
this.response = res;
|
this.response = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpMethod = Extract<Method, "GET" | "POST" | "PUT" | "DELETE" | "PATCH">;
|
|
||||||
|
|
||||||
const httpMethods = {
|
|
||||||
get: axios.get,
|
|
||||||
post: axios.post,
|
|
||||||
put: axios.put,
|
|
||||||
delete: axios.delete,
|
|
||||||
patch: axios.patch
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function fetcher<JSON = unknown>(
|
|
||||||
url: string,
|
|
||||||
init?: Omit<AxiosRequestConfig, "method"> & { method?: HttpMethod }
|
|
||||||
): Promise<JSON> {
|
|
||||||
const { method = "get", data, ...config } = init || {};
|
|
||||||
|
|
||||||
const fullConfig: AxiosRequestConfig = {
|
|
||||||
method,
|
|
||||||
...config,
|
|
||||||
timeout: 10000
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const m = method.toLowerCase() as keyof typeof httpMethods;
|
|
||||||
if (["post", "patch", "put"].includes(m)) {
|
|
||||||
const response = await httpMethods[m](url, data, fullConfig);
|
|
||||||
return response.data;
|
|
||||||
} else {
|
|
||||||
const response = await httpMethods[m](url, fullConfig);
|
|
||||||
return response.data;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
const axiosError = error as AxiosError;
|
|
||||||
|
|
||||||
if (axiosError.response) {
|
|
||||||
const { status, data } = axiosError.response;
|
|
||||||
throw new ApiRequestError(`HTTP error! status: ${status}`, data, status);
|
|
||||||
} else if (axiosError.request) {
|
|
||||||
throw new ApiRequestError("No response received", undefined, -1);
|
|
||||||
} else {
|
|
||||||
throw new ApiRequestError(axiosError.message || "Unknown error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
import createMiddleware from "next-intl/middleware";
|
|
||||||
import { routing } from "@/i18n/routing";
|
|
||||||
|
|
||||||
export default createMiddleware(routing);
|
|
||||||
|
|
||||||
export const config = {
|
|
||||||
// Match all pathnames except for
|
|
||||||
// - … if they start with `/api`, `/trpc`, `/_next` or `/_vercel`
|
|
||||||
// - … the ones containing a dot (e.g. `favicon.ico`)
|
|
||||||
matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)"
|
|
||||||
};
|
|
@ -1,13 +1,7 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
import createNextIntlPlugin from "next-intl/plugin";
|
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
devIndicators: false,
|
devIndicators: false
|
||||||
experimental: {
|
|
||||||
externalDir: true
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const withNextIntl = createNextIntlPlugin();
|
export default nextConfig;
|
||||||
|
|
||||||
export default withNextIntl(nextConfig);
|
|
||||||
|
@ -5,28 +5,23 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack -p 7400",
|
"dev": "next dev --turbopack -p 7400",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start -p 7400",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"format": "prettier --write ."
|
"format": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cvsa/core": "^0.0.1",
|
"framer-motion": "^12.12.2",
|
||||||
"axios": "^1.9.0",
|
"next": "^15.1.8",
|
||||||
"framer-motion": "^12.15.0",
|
|
||||||
"i18next": "^25.2.1",
|
|
||||||
"next": "^15.3.3",
|
|
||||||
"next-intl": "^4.1.0",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"swr": "^2.3.3",
|
"swr": "^2.3.3"
|
||||||
"yup": "^1.6.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5",
|
||||||
"@types/node": "^20.17.57",
|
"@types/node": "^20",
|
||||||
"@types/react": "^19.1.6",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19",
|
||||||
"@tailwindcss/postcss": "^4.1.8",
|
"@tailwindcss/postcss": "^4",
|
||||||
"tailwindcss": "^4.1.8"
|
"tailwindcss": "^4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./*"],
|
"@/*": ["./*"]
|
||||||
"@backend/*": ["../backend/*"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
Loading…
Reference in New Issue
Block a user