refactor: config 패키지 추가

This commit is contained in:
2025-04-30 15:23:26 +09:00
parent c52c602daf
commit 9da7aff85a
44 changed files with 504 additions and 112 deletions
@@ -2,8 +2,8 @@
import { usePathname, useRouter } from "next/navigation";
import { useQueryClient } from "@tanstack/react-query";
import type { MenuItem } from "@common/components/api";
import { BaseLayout } from "@common/components/ui";
import { BaseLayout } from "@common/components";
import type { MenuItem } from "@/entities/menu";
import { useMenuStore } from "@/shared/lib";
export default function WithBaseLayout({
+2
View File
@@ -11,6 +11,8 @@
"dependencies": {
"@common/assets": "workspace:*",
"@common/components": "workspace:*",
"@common/config": "workspace:*",
"@common/network": "workspace:*",
"@frontend-opensource/use-react-hooks": "^1.1.4",
"@hookform/resolvers": "^4.1.3",
"@minoru/react-dnd-treeview": "^3.5.0",
@@ -2,23 +2,24 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
import { AuthWrapper } from "@/entities/auth";
import { MenuWrapper } from "@/entities/menu";
import { StoreProvider } from "@/shared/providers";
import { AlertDialog } from "@/shared/ui/alert-dialog";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
import { initializeNextClientConfig } from "@common/config";
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
const queryClient = new QueryClient();
initializeNextClientConfig();
return (
<QueryClientProvider client={queryClient}>
<StoreProvider>
<ConfirmProvider>
<AuthWrapper>
<MenuWrapper>{children}</MenuWrapper>
<AlertDialog />
<ConfirmDialog />
</AuthWrapper>
<MenuWrapper>{children}</MenuWrapper>
<AlertDialog />
<ConfirmDialog />
</ConfirmProvider>
</StoreProvider>
</QueryClientProvider>
@@ -1,2 +1 @@
export { LoginApi } from "./api/login-service";
export { AuthWrapper } from "./lib/auth-wrapper";
@@ -1,49 +0,0 @@
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { client } from "@/shared/api";
import type { IUserInfo } from "@/shared/store";
import { getCookie, useUserStore } from "@/shared/lib";
import { ENDPOINT, AUTH_USER_ID } from "@/shared/config";
import { LoginApi } from "../api/login-service";
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
const router = useRouter();
const { userInfo, setUserInfo } = useUserStore((state) => state);
async function authCheck() {
const userId = getCookie(AUTH_USER_ID);
if (!userId) {
throw new Error("Missing required authentication tokens");
}
const response = await client.get<IUserInfo>(
`${ENDPOINT.USER_SERVICE.USERS}/${userId}`,
);
if (!userInfo) setUserInfo(response.data);
}
useEffect(() => {
(async () => {
try {
await authCheck();
} catch (error) {
console.error(error);
try {
await LoginApi.silentRefresh();
await authCheck();
} catch (refreshError) {
console.error("Token refresh failed:", refreshError);
setUserInfo(null);
router.push("/auth/login");
}
}
})();
}, []);
return <>{children}</>;
};
export { AuthWrapper };
@@ -1,6 +1,6 @@
import type { ColumnDef } from "@tanstack/react-table";
import type { UseFormReturn } from "react-hook-form";
import { Checkbox } from "@common/components/ui";
import { Checkbox } from "@common/components";
import type {
MenuAuthority,
MenuAuthorityFormData,
@@ -13,7 +13,7 @@ import {
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@common/components/ui";
} from "@common/components";
import { ENDPOINT } from "@/shared/config";
import { useAlertStore } from "@/shared/lib/use-alert-store";
import {
@@ -1,4 +1,4 @@
import { client } from "@common/components/api";
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type { MenuItem, MenuService } from "../model/menu-interface";
@@ -1 +1,2 @@
export { MenuWrapper } from "./lib/menu-wrapper";
export type { MenuItem } from "./model/menu-interface";
@@ -23,8 +23,8 @@ import {
DateRangePicker,
DialogClose,
DialogFooter,
} from "@common/components/ui";
import { cn } from "@common/components/lib";
cn,
} from "@common/components";
import { CodeSelect } from "@/entities/code/@x/posting";
import { SiteApi, type Site } from "@/entities/site/@x/posting";
import type { PageableList } from "@/shared/model";
@@ -1,7 +1,7 @@
import dayjs from "dayjs";
import type { ColumnDef } from "@tanstack/react-table";
import type { Post } from "@/entities/post";
import { Badge, Button } from "@common/components/ui";
import { Badge, Button } from "@common/components";
export const columns: ColumnDef<Post>[] = [
{
@@ -19,7 +19,7 @@ import {
SelectItem,
SelectTrigger,
SelectValue,
} from "@common/components/ui";
} from "@common/components";
import { PostApi, type Post, type PostParams } from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { columns } from "../model/notice-table-columns";
@@ -1,5 +1,5 @@
import { createStore } from "zustand/vanilla";
import type { MenuItem } from "@common/components/api";
import type { MenuItem } from "@/entities/menu";
export type MenuState = {
currentMenuInfo: MenuItem | null;
@@ -4,7 +4,7 @@ import {
DialogFooter,
DialogClose,
Button,
} from "@common/components/ui";
} from "@common/components";
import { useAlertStore } from "../lib/use-alert-store";
function AlertDialog() {
@@ -6,7 +6,7 @@ import {
DialogClose,
Button,
type ButtonProps,
} from "@common/components/ui";
} from "@common/components";
type ConfirmDialogProps = {
isOpen?: boolean;
+1 -1
View File
@@ -9,7 +9,7 @@ import {
type FieldPath,
type FieldValues,
} from "react-hook-form";
import { cn, Label } from "@common/components";
import { Label, cn } from "@common/components";
const Form = FormProvider;
@@ -1,4 +1,6 @@
import { Skeleton } from "@common/components/ui/skeleton";
"use client";
import { Skeleton } from "@common/components";
function SkeletonPage() {
return (
@@ -1,7 +1,6 @@
import { useEffect, useState } from "react";
import type { NodeModel, TreeMethods } from "@minoru/react-dnd-treeview";
import { Button } from "@common/components/ui";
import { cn } from "@common/components/lib";
import { Button, cn } from "@common/components";
import { EditableNode } from "./editable-node";
interface TreeData extends Record<string, unknown> {
@@ -68,7 +67,9 @@ function CustomNode<T extends TreeData>({
{editMode ? (
<EditableNode
value={nodeName}
onChange={(e) => setNodeName(e.target.value)}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setNodeName(e.target.value)
}
onSave={handleSave}
onCancel={handleCancel}
/>
@@ -11,8 +11,7 @@ import {
type DropOptions,
type Classes,
} from "@minoru/react-dnd-treeview";
import { Button } from "@common/components/ui";
import { cn } from "@common/components/lib";
import { Button, cn } from "@common/components";
import { CustomNode } from "./custom-node";
interface TreeData extends Record<string, unknown> {
@@ -1,5 +1,5 @@
import type { ComponentProps } from "react";
import { Button, Input } from "@common/components/ui";
import { Button, Input } from "@common/components";
type EditableNodeProps = {
depth?: number;
@@ -1,7 +1,7 @@
import { useRouter } from "next/navigation";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { type FieldValues, type UseFormReturn } from "react-hook-form";
import { Button } from "@common/components/ui";
import { Button } from "@common/components";
import { Form } from "@/shared/ui/form";
type FormWrapperProps<T extends FieldValues> = {
@@ -1,7 +1,7 @@
import { useRouter } from "next/navigation";
import { useMutation } from "@tanstack/react-query";
import { useConfirm } from "@frontend-opensource/use-react-hooks";
import { Button } from "@common/components/ui";
import { Button } from "@common/components";
import { PostApi } from "@/entities/post";
type PostActionProps = {
+3 -3
View File
@@ -25,9 +25,9 @@
"baseUrl": "./src",
"paths": {
"@/*": ["./*"],
"@common/components/*": ["../../../../packages/common/components/src/*"],
"@common/components": ["../../../../packages/common/components/src"],
"@common/network/*": ["../../../../packages/common/network/*"],
"@common/assets": ["../../../../packages/common/assets/dist/"],
"@common/components": ["../../../../packages/common/components/dist/"],
"@common/config": ["../../../../packages/common/config/dist/"],
"@common/network": ["../../../../packages/common/network/"]
}
},
@@ -1,4 +1,4 @@
import { client } from "@common/components/api";
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type { MenuItem, MenuService } from "../model/menu-interface";
@@ -0,0 +1 @@
+1
View File
@@ -26,6 +26,7 @@
},
"dependencies": {
"@common/assets": "workspace:*",
"@common/config": "workspace:*",
"@frontend-opensource/use-react-hooks": "^1.1.4",
"@minoru/react-dnd-treeview": "^3.5.0",
"@radix-ui/react-accordion": "^1.2.3",
+13 -5
View File
@@ -1,7 +1,15 @@
import { Client } from "@common/network";
import { BASE_URL, SITE_ID } from "../config";
import { getConfig } from "@common/config";
export const client = Client.getInstance({
baseURL: BASE_URL,
siteId: SITE_ID,
});
const getClientInstance = () => {
const config = getConfig();
const { PROXY_HOST, SITE_ID } = config;
const BASE_URL = `${PROXY_HOST}/server`;
return Client.getInstance({
baseURL: BASE_URL,
siteId: SITE_ID ?? "",
});
};
export const getApiClient = () => getClientInstance();
+3 -1
View File
@@ -1,4 +1,4 @@
import { client } from "./client";
import { getApiClient } from "./client";
import { ENDPOINT } from "../config";
export interface MenuItem {
@@ -21,6 +21,8 @@ export interface MenuItem {
requiredUrlPath: boolean;
}
const client = getApiClient();
export const getMenuList = async (siteId: string) => {
const response = await client.get<MenuItem[]>(
`${ENDPOINT.CMS_SERVICE.MENU_ROLES}/${siteId}`,
+3 -1
View File
@@ -1,4 +1,4 @@
import { client } from "./client";
import { getApiClient } from "./client";
import { ENDPOINT } from "../config";
export interface SiteInfo {
@@ -23,6 +23,8 @@ export interface SiteInfo {
mdfrNm: string;
}
const client = getApiClient();
export const getSiteInfo = async (siteId: string) => {
const response = await client.get<SiteInfo>(
`${ENDPOINT.CMS_SERVICE.SITES}/${siteId}`,
+3 -1
View File
@@ -1,4 +1,4 @@
import { client } from "./client";
import { getApiClient } from "./client";
import { ENDPOINT } from "../config";
export interface IUser {
@@ -35,6 +35,8 @@ export interface IUser {
hasPassword: boolean;
}
const client = getApiClient();
export const getUserInfo = async (userUniqId: string) => {
const response = await client.get<IUser>(
`${ENDPOINT.USER_SERVICE.USERS}/${userUniqId}`,
@@ -1,7 +1,3 @@
import { PROXY_HOST } from "./env";
export const BASE_URL = `${PROXY_HOST}/server`;
export const ENDPOINT = {
CMS_SERVICE: {
MENU_ROLES: "/cms-service/api/v1/menu-roles",
@@ -1,10 +0,0 @@
export const PORT = process.env.PORT || "3000";
export const PROXY_HOST = process.env.PROXY_HOST || `http://localhost:${PORT}`;
export const SERVER_API_URL = process.env.SERVER_API_URL;
export const SITE_ID = process.env.SITE_ID || "CS";
export const CLAIM_NAME = process.env.CLAIM_NAME || "Authorization";
export const ACCESS_TOKEN = process.env.ACCESS_TOKEN || "access-token";
export const REFRESH_TOKEN = process.env.REFRESH_TOKEN || "refresh-token";
export const AUTH_USER_ID = process.env.AUTH_USER_ID || "token-id";
@@ -1,2 +1 @@
export * from "./api";
export * from "./env";
@@ -1,8 +1,9 @@
import { useQuery } from "@tanstack/react-query";
import { images } from "@common/assets";
import { getConfig } from "@common/config";
import { ENDPOINT } from "../../config";
import { getCookie, setCookie } from "../../lib";
import { getSiteInfo, getUserInfo } from "../../api";
import { AUTH_USER_ID, ENDPOINT, SITE_ID } from "../../config";
import {
DropdownMenu,
DropdownMenuTrigger,
@@ -11,8 +12,10 @@ import {
} from "../dropdown-menu";
import { Button } from "../button";
const { AUTH_USER_ID, SITE_ID } = getConfig();
export function Header({ viewOnly }: { viewOnly?: boolean }) {
const userUniqId = getCookie(AUTH_USER_ID) ?? "";
const userUniqId = getCookie(AUTH_USER_ID ?? "") ?? "";
const { data: userInfo } = useQuery({
queryKey: [ENDPOINT.USER_SERVICE.USERS],
@@ -22,7 +25,7 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
const { data: siteInfo } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.SITES, SITE_ID],
queryFn: () => getSiteInfo(SITE_ID),
queryFn: () => getSiteInfo(SITE_ID ?? ""),
select: (data) => {
if (data.siteSkn) {
const siteSkin = data.siteSkn.toLowerCase();
@@ -1,8 +1,9 @@
import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { ChevronRight } from "lucide-react";
import { getConfig } from "@common/config";
import { ENDPOINT } from "../../config";
import { cn, setCookie } from "../../lib";
import { ENDPOINT, SITE_ID } from "../../config";
import { getMenuList, type MenuItem } from "../../api";
import {
Sidebar,
@@ -19,6 +20,8 @@ import {
} from "../collapsible";
import { getParentIds } from "./lib";
const { SITE_ID } = getConfig();
export function LNB({
viewOnly,
currentPath,
@@ -30,7 +33,7 @@ export function LNB({
}) {
const { data: menuList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES],
queryFn: () => getMenuList(SITE_ID),
queryFn: () => getMenuList(SITE_ID ?? ""),
enabled: !viewOnly,
});
+1 -1
View File
@@ -15,7 +15,7 @@
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@common/network/*": ["../network/*"],
"@common/config": ["../config/dist/"],
"@common/network": ["../network/"]
}
},
+1 -1
View File
@@ -10,7 +10,7 @@ export default defineConfig((options) => ({
format: ["esm"],
external: ["react", "react-dom"],
platform: "browser",
target: ["es2020", "chrome70", "edge18", "firefox70", "node18"],
target: ["es2020"],
tsconfig: path.resolve(__dirname, "tsconfig.build.json"),
sourcemap: !options.watch,
minify: !options.watch,
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@common/config",
"version": "0.1.0",
"private": true,
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"clean": "rm -rf dist .turbo node_modules"
},
"dependencies": {},
"devDependencies": {
"eslint": "^9.8.0",
"tsup": "^8.2.3",
"typescript": "^5.5.3",
"vite": "^5.3.5"
},
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from "./initialize-config";
export * from "./initializer";
@@ -0,0 +1,54 @@
export interface EnvConfig {
PORT?: string;
PROXY_HOST?: string;
SERVER_API_URL?: string;
SITE_ID?: string;
CLAIM_NAME?: string;
ACCESS_TOKEN?: string;
REFRESH_TOKEN?: string;
AUTH_USER_ID?: string;
}
const defaultConfig: EnvConfig = {
PORT: "3000",
PROXY_HOST: "",
SERVER_API_URL: "",
SITE_ID: "CS",
CLAIM_NAME: "Authorization",
ACCESS_TOKEN: "access-token",
REFRESH_TOKEN: "refresh-token",
AUTH_USER_ID: "token-id",
};
let isInitialized = false;
let envConfig: EnvConfig = { ...defaultConfig };
export function initializeConfig(values: Partial<EnvConfig>): void {
if (isInitialized) {
console.warn("Configuration already initialized. Skipping.");
return;
}
const filteredValues = Object.entries(values).reduce((acc, [key, value]) => {
if (value !== undefined && value !== null) {
acc[key as keyof EnvConfig] = value;
}
return acc;
}, {} as Partial<EnvConfig>);
if (filteredValues.PORT && !filteredValues.PROXY_HOST) {
filteredValues.PROXY_HOST = `http://localhost:${filteredValues.PORT}`;
}
envConfig = { ...defaultConfig, ...filteredValues };
isInitialized = true;
}
export function getConfig(): EnvConfig {
if (!isInitialized) {
console.warn(
"Attempted to access config before initialization. Returning default values."
);
}
return envConfig;
}
+20
View File
@@ -0,0 +1,20 @@
import { initializeConfig, type EnvConfig } from "./initialize-config";
export function initializeNextClientConfig(): void {
if (typeof window === "undefined") {
console.warn("initializeNextClientConfig called on the server. Skipping.");
return;
}
const env: Partial<EnvConfig> = {
PORT: process.env.NEXT_PUBLIC_PORT,
PROXY_HOST: process.env.NEXT_PUBLIC_PROXY_HOST,
SERVER_API_URL: process.env.NEXT_PUBLIC_SERVER_API_URL,
SITE_ID: process.env.NEXT_PUBLIC_SITE_ID,
CLAIM_NAME: process.env.NEXT_PUBLIC_CLAIM_NAME,
ACCESS_TOKEN: process.env.NEXT_PUBLIC_ACCESS_TOKEN,
REFRESH_TOKEN: process.env.NEXT_PUBLIC_REFRESH_TOKEN,
AUTH_USER_ID: process.env.NEXT_PUBLIC_AUTH_USER_ID,
};
initializeConfig(env);
}
+13
View File
@@ -0,0 +1,13 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node", "vite/client"],
"incremental": false
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"exclude": ["node_modules", "dist"]
}
+11
View File
@@ -0,0 +1,11 @@
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
external: [],
});
+301
View File
@@ -45,6 +45,12 @@ importers:
'@common/components':
specifier: workspace:*
version: link:../../../packages/common/components
'@common/config':
specifier: workspace:*
version: link:../../../packages/common/config
'@common/network':
specifier: workspace:*
version: link:../../../packages/common/network
'@frontend-opensource/use-react-hooks':
specifier: ^1.1.4
version: 1.1.4
@@ -475,6 +481,9 @@ importers:
'@common/assets':
specifier: workspace:*
version: link:../assets
'@common/config':
specifier: workspace:*
version: link:../config
'@frontend-opensource/use-react-hooks':
specifier: ^1.1.4
version: 1.1.4
@@ -678,6 +687,21 @@ importers:
specifier: 5.1.4
version: 5.1.4(typescript@5.6.3)(vite@6.2.0)
packages/common/config:
devDependencies:
eslint:
specifier: ^9.8.0
version: 9.21.0
tsup:
specifier: ^8.2.3
version: 8.3.6(postcss@8.5.3)(typescript@5.6.3)
typescript:
specifier: ^5.5.3
version: 5.6.3
vite:
specifier: ^5.3.5
version: 5.4.18(@types/node@22.13.9)
packages/common/network:
dependencies:
'@types/js-cookie':
@@ -923,6 +947,15 @@ packages:
dev: false
optional: true
/@esbuild/aix-ppc64@0.21.5:
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
requiresBuild: true
dev: true
optional: true
/@esbuild/aix-ppc64@0.24.2:
resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
engines: {node: '>=18'}
@@ -941,6 +974,15 @@ packages:
dev: true
optional: true
/@esbuild/android-arm64@0.21.5:
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm64@0.24.2:
resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
engines: {node: '>=18'}
@@ -959,6 +1001,15 @@ packages:
dev: true
optional: true
/@esbuild/android-arm@0.21.5:
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm@0.24.2:
resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
engines: {node: '>=18'}
@@ -977,6 +1028,15 @@ packages:
dev: true
optional: true
/@esbuild/android-x64@0.21.5:
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64@0.24.2:
resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
engines: {node: '>=18'}
@@ -995,6 +1055,15 @@ packages:
dev: true
optional: true
/@esbuild/darwin-arm64@0.21.5:
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64@0.24.2:
resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
engines: {node: '>=18'}
@@ -1013,6 +1082,15 @@ packages:
dev: true
optional: true
/@esbuild/darwin-x64@0.21.5:
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64@0.24.2:
resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
engines: {node: '>=18'}
@@ -1031,6 +1109,15 @@ packages:
dev: true
optional: true
/@esbuild/freebsd-arm64@0.21.5:
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64@0.24.2:
resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
engines: {node: '>=18'}
@@ -1049,6 +1136,15 @@ packages:
dev: true
optional: true
/@esbuild/freebsd-x64@0.21.5:
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64@0.24.2:
resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
engines: {node: '>=18'}
@@ -1067,6 +1163,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-arm64@0.21.5:
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64@0.24.2:
resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
engines: {node: '>=18'}
@@ -1085,6 +1190,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-arm@0.21.5:
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm@0.24.2:
resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
engines: {node: '>=18'}
@@ -1103,6 +1217,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-ia32@0.21.5:
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32@0.24.2:
resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
engines: {node: '>=18'}
@@ -1121,6 +1244,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-loong64@0.21.5:
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64@0.24.2:
resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
engines: {node: '>=18'}
@@ -1139,6 +1271,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-mips64el@0.21.5:
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el@0.24.2:
resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
engines: {node: '>=18'}
@@ -1157,6 +1298,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-ppc64@0.21.5:
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64@0.24.2:
resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
engines: {node: '>=18'}
@@ -1175,6 +1325,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-riscv64@0.21.5:
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64@0.24.2:
resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
engines: {node: '>=18'}
@@ -1193,6 +1352,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-s390x@0.21.5:
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x@0.24.2:
resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
engines: {node: '>=18'}
@@ -1211,6 +1379,15 @@ packages:
dev: true
optional: true
/@esbuild/linux-x64@0.21.5:
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64@0.24.2:
resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
engines: {node: '>=18'}
@@ -1247,6 +1424,15 @@ packages:
dev: true
optional: true
/@esbuild/netbsd-x64@0.21.5:
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64@0.24.2:
resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
engines: {node: '>=18'}
@@ -1283,6 +1469,15 @@ packages:
dev: true
optional: true
/@esbuild/openbsd-x64@0.21.5:
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64@0.24.2:
resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
engines: {node: '>=18'}
@@ -1301,6 +1496,15 @@ packages:
dev: true
optional: true
/@esbuild/sunos-x64@0.21.5:
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64@0.24.2:
resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
engines: {node: '>=18'}
@@ -1319,6 +1523,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-arm64@0.21.5:
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64@0.24.2:
resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
engines: {node: '>=18'}
@@ -1337,6 +1550,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-ia32@0.21.5:
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32@0.24.2:
resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
engines: {node: '>=18'}
@@ -1355,6 +1577,15 @@ packages:
dev: true
optional: true
/@esbuild/win32-x64@0.21.5:
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64@0.24.2:
resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
engines: {node: '>=18'}
@@ -5425,6 +5656,37 @@ packages:
- supports-color
dev: true
/esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
'@esbuild/android-arm': 0.21.5
'@esbuild/android-arm64': 0.21.5
'@esbuild/android-x64': 0.21.5
'@esbuild/darwin-arm64': 0.21.5
'@esbuild/darwin-x64': 0.21.5
'@esbuild/freebsd-arm64': 0.21.5
'@esbuild/freebsd-x64': 0.21.5
'@esbuild/linux-arm': 0.21.5
'@esbuild/linux-arm64': 0.21.5
'@esbuild/linux-ia32': 0.21.5
'@esbuild/linux-loong64': 0.21.5
'@esbuild/linux-mips64el': 0.21.5
'@esbuild/linux-ppc64': 0.21.5
'@esbuild/linux-riscv64': 0.21.5
'@esbuild/linux-s390x': 0.21.5
'@esbuild/linux-x64': 0.21.5
'@esbuild/netbsd-x64': 0.21.5
'@esbuild/openbsd-x64': 0.21.5
'@esbuild/sunos-x64': 0.21.5
'@esbuild/win32-arm64': 0.21.5
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
dev: true
/esbuild@0.24.2:
resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
engines: {node: '>=18'}
@@ -8993,6 +9255,45 @@ packages:
- typescript
dev: true
/vite@5.4.18(@types/node@22.13.9):
resolution: {integrity: sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
dependencies:
'@types/node': 22.13.9
esbuild: 0.21.5
postcss: 8.5.3
rollup: 4.34.8
optionalDependencies:
fsevents: 2.3.3
dev: true
/vite@6.2.0(@types/node@22.13.5):
resolution: {integrity: sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}