NewLife/cube-front

feat: 初始化提交
笑笑 authored at 2025-05-13 21:25:06
f5a809d
Tree
0 Parent(s)
Summary: 93 changed files with 13182 additions and 0 deletions.
Added +9 -0
Added +1 -0
Added +32 -0
Added +6 -0
Added +9 -0
Added +61 -0
Added +1 -0
Added +279 -0
Added +35 -0
Added +16 -0
Added +10 -0
Added +10 -0
Added +37 -0
Added +5 -0
Added +15 -0
Added +30 -0
Added +164 -0
Added +71 -0
Added +110 -0
Added +126 -0
Added +93 -0
Added +16 -0
Added +30 -0
Added +17 -0
Added +61 -0
Added +124 -0
Added +575 -0
Added +1 -0
Added +21 -0
Added +11 -0
Added +78 -0
Added +67 -0
Added +66 -0
Added +11 -0
Added +16 -0
Added +146 -0
Added +73 -0
Added +72 -0
Added +114 -0
Added +139 -0
Added +434 -0
Added +124 -0
Added +97 -0
Added +21 -0
Added +138 -0
Added +12 -0
Added +5 -0
Added +27 -0
Added +56 -0
Added +62 -0
Added +98 -0
Added +102 -0
Added +34 -0
Added +207 -0
Added +113 -0
Added +24 -0
Added +46 -0
Added +136 -0
Added +52 -0
Added +21 -0
Added +33 -0
Added +399 -0
Added +5 -0
Added +37 -0
Added +117 -0
Added +46 -0
Added +110 -0
Added +15 -0
Added +8 -0
Added +5 -0
Added +39 -0
Added +12 -0
Added +36 -0
Added +20 -0
Added +9 -0
Added +460 -0
Added +65 -0
Added +2 -0
Added +61 -0
Added +16 -0
Added +84 -0
Added +6716 -0
Added +3 -0
Added +59 -0
Added +13 -0
Added +52 -0
Added +12 -0
Added +37 -0
Added +17 -0
Added +21 -0
Added +11 -0
Added +81 -0
Added +14 -0
Added +9 -0
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..5a5809d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue,css,scss,sass,less,styl}]
+charset = utf-8
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+end_of_line = lf
+max_line_length = 100
Added +1 -0
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..6313b56
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
Added +32 -0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e2a2ae9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo
+.comate
+.lingma
Added +6 -0
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..7c60ba7
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+  "$schema": "https://json.schemastore.org/prettierrc",
+  "semi": true,
+  "singleQuote": true,
+  "printWidth": 100
+}
\ No newline at end of file
Added +9 -0
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..a06a8c6
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,9 @@
+{
+  "recommendations": [
+    "Vue.volar",
+    "vitest.explorer",
+    "dbaeumer.vscode-eslint",
+    "EditorConfig.EditorConfig",
+    "esbenp.prettier-vscode"
+  ]
+}
Added +61 -0
diff --git a/apps/cube-core/package.json b/apps/cube-core/package.json
new file mode 100644
index 0000000..0a254ac
--- /dev/null
+++ b/apps/cube-core/package.json
@@ -0,0 +1,61 @@
+{
+  "name": "cube-iam",
+  "private": true,
+  "version": "0.0.0",
+  "type": "commonjs",
+  "scripts": {
+    "dev": "node ../../node_modules/vite/bin/vite.js dev",
+    "build": "vite build",
+    "build2": "tsc -b && vite build",
+    "lint": "eslint .",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "@types/lodash": "^4.17.9",
+    "@vueuse/core": "^13.0.0",
+    "@vueuse/integrations": "^13.0.0",
+    "autoprefixer": "^10.4.20",
+    "axios": "^1.8.4",
+    "element-plus": "^2.9.7",
+    "lodash": "^4.17.21",
+    "pinia": "^3.0.1",
+    "postcss": "^8.5.3",
+    "sass-loader": "^16.0.5",
+    "tailwindcss": "^4.1.3",
+    "universal-cookie": "^8.0.1",
+    "vue": "^3.5.13",
+    "vue-router": "^4.5.0"
+  },
+  "devDependencies": {
+    "@tsconfig/node22": "^22.0.0",
+    "@types/jsdom": "^21.1.7",
+    "@types/node": "^22.13.9",
+    "@vitejs/plugin-vue": "^5.2.1",
+    "@vitejs/plugin-vue-jsx": "^4.1.1",
+    "@vitest/eslint-plugin": "^1.1.36",
+    "@vue/eslint-config-prettier": "^10.2.0",
+    "@vue/eslint-config-typescript": "^14.5.0",
+    "@vue/test-utils": "^2.4.6",
+    "@vue/tsconfig": "^0.7.0",
+    "cypress": "^14.1.0",
+    "eslint": "^9.21.0",
+    "eslint-plugin-cypress": "^4.2.0",
+    "eslint-plugin-oxlint": "^0.15.13",
+    "eslint-plugin-vue": "~10.0.0",
+    "jiti": "^2.4.2",
+    "jsdom": "^26.0.0",
+    "npm-run-all2": "^7.0.2",
+    "oxlint": "^0.15.13",
+    "prettier": "3.5.3",
+    "start-server-and-test": "^2.0.10",
+    "typescript": "~5.8.0",
+    "vite": "^6.2.1",
+    "vite-plugin-vue-devtools": "^7.7.2",
+    "vitest": "^3.0.8",
+    "vue-tsc": "^2.2.8"
+  },
+  "engines": {
+    "node": ">=18",
+    "pnpm": ">=10"
+  }
+}
\ No newline at end of file
Added +1 -0
diff --git a/apps/cube-core/src/main.ts b/apps/cube-core/src/main.ts
new file mode 100644
index 0000000..02e4efb
--- /dev/null
+++ b/apps/cube-core/src/main.ts
@@ -0,0 +1 @@
+export { default as routes } from './routes';
Added +279 -0
diff --git a/apps/cube-core/src/pages/admin/user/index.vue b/apps/cube-core/src/pages/admin/user/index.vue
new file mode 100644
index 0000000..1779e0f
--- /dev/null
+++ b/apps/cube-core/src/pages/admin/user/index.vue
@@ -0,0 +1,279 @@
+<template>
+  <div class="user-container">
+    <el-card class="box-card">
+      <template #header>
+        <div class="card-header">
+          <h3>用户管理</h3>
+          <el-button type="primary" @click="handleAdd">新增用户</el-button>
+        </div>
+      </template>
+
+      <el-form :inline="true" :model="searchForm" class="search-form">
+        <el-form-item label="用户名">
+          <el-input v-model="searchForm.username" placeholder="请输入用户名" clearable />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="resetSearch">重置</el-button>
+        </el-form-item>
+      </el-form>
+
+      <CbTable :data-set="userDataSet" show-pagination />
+    </el-card>
+
+    <!-- 用户表单对话框 -->
+    <el-dialog
+      v-model="dialogVisible"
+      :title="formType === 'add' ? '新增用户' : '编辑用户'"
+      width="500px"
+    >
+      <el-form ref="userFormRef" :model="userForm" :rules="userFormRules" label-width="100px">
+        <el-form-item label="用户名" prop="username">
+          <el-input v-model="userForm.username" placeholder="请输入用户名" />
+        </el-form-item>
+        <el-form-item label="邮箱" prop="email">
+          <el-input v-model="userForm.email" placeholder="请输入邮箱" />
+        </el-form-item>
+        <el-form-item label="手机号" prop="phone">
+          <el-input v-model="userForm.phone" placeholder="请输入手机号" />
+        </el-form-item>
+        <el-form-item label="密码" prop="password" v-if="formType === 'add'">
+          <el-input v-model="userForm.password" type="password" placeholder="请输入密码" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-switch v-model="userForm.status" :active-value="1" :inactive-value="0" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="dialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="submitForm">确定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, h } from 'vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { DataSet } from 'cube-front/core/dataset/data-set/DataSet';
+import CbTable from 'cube-front/core/components/CbTable.vue';
+import type { FormInstance, FormRules } from 'element-plus';
+
+// 定义用户类型接口
+interface User {
+  id: string | number;
+  username: string;
+  email: string;
+  phone: string;
+  password?: string;
+  status: number;
+  createdAt?: string;
+}
+
+// 查询表单
+const searchForm = reactive({
+  username: '',
+});
+
+// 用户数据集
+const userColumns = [
+  { prop: 'id', label: 'ID', width: 80 },
+  { prop: 'username', label: '用户名' },
+  { prop: 'email', label: '邮箱' },
+  { prop: 'phone', label: '手机号' },
+  { prop: 'createdAt', label: '创建时间' },
+  {
+    prop: 'status',
+    label: '状态',
+    render: (value: number) => {
+      return value === 1
+        ? h('el-tag', { type: 'success' }, () => '启用')
+        : h('el-tag', { type: 'danger' }, () => '禁用');
+    },
+  },
+  {
+    label: '操作',
+    width: 200,
+    render: (_value: unknown, row: User) => [
+      h(
+        'el-button',
+        {
+          type: 'primary',
+          size: 'small',
+          onClick: () => handleEdit(row),
+        },
+        () => '编辑',
+      ),
+      h(
+        'el-button',
+        {
+          type: 'danger',
+          size: 'small',
+          onClick: () => handleDelete(row),
+        },
+        () => '删除',
+      ),
+    ],
+  },
+] as import('cube-front/core/dataset/data-set/DataSet').ColumnConfig<User, keyof User>[];
+
+const userDataSet = new DataSet<User, { username: string }>({
+  transport: {
+    read: ({ params }) => ({
+      url: '/Admin/User',
+      method: 'get',
+      params: {
+        ...params,
+        username: searchForm.username,
+      },
+    }),
+    create: ({ data }) => ({
+      url: '/Admin/User',
+      method: 'post',
+      data,
+    }),
+    update: ({ data }) => ({
+      url: `/Admin/User/${data.id}`,
+      method: 'put',
+      data,
+    }),
+    destroy: ({ data }) => ({
+      url: `/Admin/User/${data.id}`,
+      method: 'delete',
+    }),
+  },
+  autoQuery: true,
+  columns: userColumns,
+});
+
+// 用户表单相关
+const dialogVisible = ref(false);
+const formType = ref<'add' | 'edit'>('add');
+const userFormRef = ref<FormInstance | null>(null);
+const userForm = reactive<User>({
+  id: '',
+  username: '',
+  email: '',
+  phone: '',
+  password: '',
+  status: 1,
+});
+
+// 表单验证规则
+const userFormRules = reactive<FormRules>({
+  username: [
+    { required: true, message: '请输入用户名', trigger: 'blur' },
+    { min: 3, max: 20, message: '长度在 3 到 20 个字符', trigger: 'blur' },
+  ],
+  email: [
+    { required: true, message: '请输入邮箱', trigger: 'blur' },
+    { type: 'email' as const, message: '请输入正确的邮箱地址', trigger: 'blur' },
+  ],
+  phone: [
+    { required: true, message: '请输入手机号', trigger: 'blur' },
+    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' },
+  ],
+  password: [
+    { required: true, message: '请输入密码', trigger: 'blur' },
+    { min: 6, max: 20, message: '长度在 6 到 20 个字符', trigger: 'blur' },
+  ],
+});
+
+// 搜索
+const handleSearch = () => {
+  userDataSet.currentPage = 1;
+  userDataSet.read();
+};
+
+// 重置搜索
+const resetSearch = () => {
+  searchForm.username = '';
+  userDataSet.currentPage = 1;
+  userDataSet.read();
+};
+
+// 新增用户
+const handleAdd = () => {
+  formType.value = 'add';
+  Object.assign(userForm, {
+    id: '',
+    username: '',
+    email: '',
+    phone: '',
+    password: '',
+    status: 1,
+  });
+  dialogVisible.value = true;
+};
+
+// 编辑用户
+const handleEdit = (row: User) => {
+  formType.value = 'edit';
+  Object.assign(userForm, {
+    id: row.id,
+    username: row.username,
+    email: row.email,
+    phone: row.phone,
+    status: row.status,
+  });
+  dialogVisible.value = true;
+};
+
+// 删除用户
+const handleDelete = (row: User) => {
+  ElMessageBox.confirm('确认删除该用户吗?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+  })
+    .then(async () => {
+      try {
+        await userDataSet.destroy(row);
+        ElMessage.success('删除成功');
+      } catch (error) {
+        ElMessage.error('删除失败');
+        console.error('删除失败:', error);
+      }
+    })
+    .catch(() => {});
+};
+
+// 提交表单
+const submitForm = async () => {
+  if (!userFormRef.value) return;
+
+  userFormRef.value.validate(async (valid: boolean) => {
+    if (valid) {
+      try {
+        if (formType.value === 'add') {
+          await userDataSet.create(userForm);
+          ElMessage.success('新增成功');
+        } else {
+          await userDataSet.update(userForm);
+          ElMessage.success('编辑成功');
+        }
+        dialogVisible.value = false;
+      } catch (error) {
+        ElMessage.error(formType.value === 'add' ? '新增失败' : '编辑失败');
+        console.error(formType.value === 'add' ? '新增失败:' : '编辑失败:', error);
+      }
+    }
+  });
+};
+</script>
+
+<style scoped>
+.user-container {
+  padding: 20px;
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.search-form {
+  margin-bottom: 20px;
+}
+</style>
Added +35 -0
diff --git a/apps/cube-core/src/pages/user-management/user-account/index.vue b/apps/cube-core/src/pages/user-management/user-account/index.vue
new file mode 100644
index 0000000..42d9b84
--- /dev/null
+++ b/apps/cube-core/src/pages/user-management/user-account/index.vue
@@ -0,0 +1,35 @@
+<template>
+  <div class="user-account-container">
+    <h1>User Account Management</h1>
+    <div class="content">
+      <!-- Your content here -->
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+export default {
+  name: 'UserAccount',
+  data() {
+    return {
+      // Your reactive data here
+    }
+  },
+  methods: {
+    // Your methods here
+  },
+  mounted() {
+    // Component lifecycle hook
+  }
+}
+</script>
+
+<style scoped>
+.user-account-container {
+  padding: 20px;
+}
+
+.content {
+  margin-top: 20px;
+}
+</style>
Added +16 -0
diff --git a/apps/cube-core/src/routes/index.ts b/apps/cube-core/src/routes/index.ts
new file mode 100644
index 0000000..2d53797
--- /dev/null
+++ b/apps/cube-core/src/routes/index.ts
@@ -0,0 +1,16 @@
+import { type RouteRecordRaw } from 'vue-router';
+
+const routes: RouteRecordRaw[] = [
+  {
+    path: '/iam/user-management/user-account',
+    name: 'user-account',
+    component: () => import('../pages/user-management/user-account/index.vue'),
+  },
+  {
+    path: '/Admin/User',
+    name: 'admin-user',
+    component: () => import('../pages/admin/user/index.vue'),
+  },
+];
+
+export default routes;
Added +10 -0
diff --git a/apps/cube-core/vite.config.ts b/apps/cube-core/vite.config.ts
new file mode 100644
index 0000000..f49fdac
--- /dev/null
+++ b/apps/cube-core/vite.config.ts
@@ -0,0 +1,10 @@
+import { type UserConfig } from 'vite';
+import parentConfig from '../../vite.config';
+import path from 'node:path';
+
+const config: UserConfig = {
+  ...parentConfig,
+  root: path.resolve(__dirname, '../../'),
+};
+
+export default config;
Added +10 -0
diff --git a/auto-imports.d.ts b/auto-imports.d.ts
new file mode 100644
index 0000000..9d24007
--- /dev/null
+++ b/auto-imports.d.ts
@@ -0,0 +1,10 @@
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
+// Generated by unplugin-auto-import
+// biome-ignore lint: disable
+export {}
+declare global {
+
+}
Added +37 -0
diff --git a/components.d.ts b/components.d.ts
new file mode 100644
index 0000000..792a361
--- /dev/null
+++ b/components.d.ts
@@ -0,0 +1,37 @@
+/* eslint-disable */
+// @ts-nocheck
+// Generated by unplugin-vue-components
+// Read more: https://github.com/vuejs/core/pull/3399
+// biome-ignore lint: disable
+export {}
+
+/* prettier-ignore */
+declare module 'vue' {
+  export interface GlobalComponents {
+    ElButton: typeof import('element-plus/es')['ElButton']
+    ElCard: typeof import('element-plus/es')['ElCard']
+    ElDialog: typeof import('element-plus/es')['ElDialog']
+    ElForm: typeof import('element-plus/es')['ElForm']
+    ElFormItem: typeof import('element-plus/es')['ElFormItem']
+    ElInput: typeof import('element-plus/es')['ElInput']
+    ElPagination: typeof import('element-plus/es')['ElPagination']
+    ElSwitch: typeof import('element-plus/es')['ElSwitch']
+    ElTable: typeof import('element-plus/es')['ElTable']
+    ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTag: typeof import('element-plus/es')['ElTag']
+    ElTooltip: typeof import('element-plus/es')['ElTooltip']
+    HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
+    IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
+    IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
+    IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
+    IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
+    IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
+    RouterLink: typeof import('vue-router')['RouterLink']
+    RouterView: typeof import('vue-router')['RouterView']
+    TheWelcome: typeof import('./src/components/TheWelcome.vue')['default']
+    WelcomeItem: typeof import('./src/components/WelcomeItem.vue')['default']
+  }
+  export interface ComponentCustomProperties {
+    vLoading: typeof import('element-plus/es')['ElLoadingDirective']
+  }
+}
Added +5 -0
diff --git a/configs/microAppConfig.json b/configs/microAppConfig.json
new file mode 100644
index 0000000..bc9fc53
--- /dev/null
+++ b/configs/microAppConfig.json
@@ -0,0 +1,5 @@
+  [
+    {
+      "name": "cube-iam"
+    }
+  ]
\ No newline at end of file
Added +15 -0
diff --git a/core/App.vue b/core/App.vue
new file mode 100644
index 0000000..8871fe7
--- /dev/null
+++ b/core/App.vue
@@ -0,0 +1,15 @@
+<script setup lang="ts">
+import { ElConfigProvider } from 'element-plus';
+import { RouterView } from 'vue-router';
+import RootLayout from './layouts/RootLayout.vue';
+</script>
+
+<template>
+  <ElConfigProvider>
+    <RouterView v-slot="{ Component }">
+      <RootLayout>
+        <component :is="Component" />
+      </RootLayout>
+    </RouterView>
+  </ElConfigProvider>
+</template>
Added +30 -0
diff --git a/core/client.d.ts b/core/client.d.ts
new file mode 100644
index 0000000..738adc8
--- /dev/null
+++ b/core/client.d.ts
@@ -0,0 +1,30 @@
+declare module 'virtual:cube-front-app' {
+  import { DefineComponent } from 'vue'
+  const App: DefineComponent
+  export { App }
+}
+
+declare module 'virtual:cube-front-routes' {
+  import { RouteRecordRaw } from 'vue-router'
+  const routes: RouteRecordRaw[]
+  export default routes
+}
+
+declare module 'virtual:cube-front-app-names' {
+  const appConfigs: string[]
+  export { appConfigs }
+  export default appConfigs
+}
+
+interface Window {
+  router: import('vue-router').Router
+  store: import('pinia').Pinia
+}
+
+// declare module 'cube-front' {
+//   import { PluginOption } from 'vite';
+
+//   declare function cubeFront(): PluginOption;
+
+//   export { cubeFront as default };
+// }
Added +164 -0
diff --git a/core/components/CbTable.vue b/core/components/CbTable.vue
new file mode 100644
index 0000000..77932d0
--- /dev/null
+++ b/core/components/CbTable.vue
@@ -0,0 +1,164 @@
+<template>
+  <div class="cb-table">
+    <el-table
+      :data="dataSet.data"
+      :loading="dataSet.loading"
+      v-bind="$attrs"
+      @sort-change="handleSortChange"
+      @filter-change="handleFilterChange"
+    >
+      <template v-if="columns && columns.length">
+        <el-table-column
+          v-for="col in columns"
+          :key="String(col.prop)"
+          :prop="col.prop ? String(col.prop) : undefined"
+          :label="col.label"
+          :width="col.width"
+          :min-width="col.minWidth"
+          :sortable="col.sortable"
+          :align="col.align"
+          :header-align="col.headerAlign"
+          :fixed="col.fixed"
+          :type="col.type"
+          :index="col.index"
+          :formatter="
+            (row, column, cellValue, index) => {
+              return col.formatter
+                ? col.formatter(
+                    row,
+                    {
+                      ...(column as any),
+                    },
+                    cellValue,
+                    index,
+                  )
+                : '';
+            }
+          "
+          :filters="col.filters"
+          :filter-method="col.filterMethod"
+          :filter-multiple="col.filterMultiple"
+          :filtered-value="col.filteredValue"
+          :show-overflow-tooltip="col.showOverflowTooltip"
+          :class-name="col.className"
+          :label-class-name="col.labelClassName"
+          :resizable="col.resizable"
+          :sort-method="col.sortMethod"
+          :sort-by="col.sortBy"
+          :selectable="col.selectable"
+          :reserve-selection="col.reserveSelection"
+          :column-key="col.columnKey"
+        >
+          <template v-if="col.render && col.prop" #default="{ row, $index }">
+            <span>{{ col.render(row[col.prop], row, $index) }}</span>
+          </template>
+        </el-table-column>
+      </template>
+      <slot v-else></slot>
+    </el-table>
+
+    <div class="pagination-wrapper" v-if="showPagination">
+      <el-pagination
+        :current-page="currentPage"
+        :page-size="dataSet.pageSize"
+        :total="total"
+        :page-sizes="[10, 20, 50, 100]"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="
+          (page) => {
+            currentPage = page;
+          }
+        "
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, watch, computed } from 'vue';
+import type { DataSet } from '../dataset/data-set/DataSet';
+
+defineOptions({
+  name: 'CbTable',
+});
+
+type Props = {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  dataSet: DataSet<any, any>;
+  showPagination?: boolean;
+};
+const props = defineProps<Props>();
+
+const columns = computed(() => {
+  // 兼容 getColumns 方法不存在的情况
+  return typeof props.dataSet.getColumns === 'function' ? props.dataSet.getColumns() : [];
+});
+
+const currentPage = ref(1);
+const total = ref(0);
+
+const handleSortChange = ({ prop, order }: { prop: string; order: string }) => {
+  query({ sortField: prop, sortOrder: order });
+};
+
+const handleFilterChange = (filters: Record<string, unknown>) => {
+  query({ filters });
+};
+
+const handleSizeChange = (size: number) => {
+  query({ currentPage: currentPage.value, pageSize: size });
+};
+
+/**
+ *  查询方法
+ * @param params { currentPage?: number; pageSize?: number; [key: string]: any }
+ */
+function query(params: { currentPage?: number; pageSize?: number; [key: string]: unknown } = {}) {
+  const ds = props.dataSet;
+  if (params.currentPage !== undefined) {
+    ds.currentPage = params.currentPage;
+  }
+  if (params.pageSize !== undefined) {
+    ds.pageSize = params.pageSize;
+  }
+
+  delete params.currentPage;
+  delete params.pageSize;
+
+  ds.read(params);
+}
+
+watch(
+  () => props.dataSet.totalCount,
+  (newValue) => {
+    total.value = newValue;
+  },
+  { immediate: true },
+);
+
+// 兼容性处理:如果dataSet没有totalCount属性,则使用data.length
+watch(
+  () => props.dataSet.data,
+  () => {
+    if (typeof props.dataSet.totalCount === 'undefined') {
+      total.value = props.dataSet.data.length;
+    }
+  },
+);
+watch(currentPage, (val, oldVal) => {
+  if (val !== oldVal) {
+    query({ currentPage: val, pageSize: props.dataSet.pageSize });
+  }
+});
+</script>
+
+<style scoped>
+.cb-table {
+  width: 100%;
+}
+.pagination-wrapper {
+  margin-top: 16px;
+  text-align: right;
+}
+</style>
Added +71 -0
diff --git a/core/components/LanguageSwitch.vue b/core/components/LanguageSwitch.vue
new file mode 100644
index 0000000..06e5986
--- /dev/null
+++ b/core/components/LanguageSwitch.vue
@@ -0,0 +1,71 @@
+<template>
+  <div class="language-switch">
+    <el-dropdown @command="handleCommand">
+      <span class="el-dropdown-link">
+        {{ currentLanguageLabel }}
+        <el-icon class="el-icon--right">
+          <arrow-down />
+        </el-icon>
+      </span>
+      <template #dropdown>
+        <el-dropdown-menu>
+          <el-dropdown-item
+            v-for="item in languages"
+            :key="item.value"
+            :command="item.value"
+            :class="{ active: currentLanguage === item.value }"
+          >
+            {{ item.label }}
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </template>
+    </el-dropdown>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+import { ArrowDown } from '@element-plus/icons-vue';
+import { getCurrentLanguage, setLanguage } from '../i18n';
+
+defineOptions({
+  name: 'LanguageSwitch',
+});
+
+const languages = [
+  { label: '中文', value: 'zh-CN' },
+  { label: 'English', value: 'en-US' },
+];
+
+const currentLanguage = ref(getCurrentLanguage());
+
+const currentLanguageLabel = computed(() => {
+  const lang = languages.find((item) => item.value === currentLanguage.value);
+  return lang ? lang.label : '中文';
+});
+
+// 处理语言切换
+function handleCommand(command: typeof currentLanguage.value) {
+  if (command !== currentLanguage.value) {
+    currentLanguage.value = command;
+    setLanguage(command);
+  }
+}
+</script>
+
+<style scoped>
+.language-switch {
+  cursor: pointer;
+  user-select: none;
+}
+
+.el-dropdown-link {
+  display: flex;
+  align-items: center;
+}
+
+:deep(.el-dropdown-menu__item.active) {
+  color: var(--el-color-primary);
+  background-color: var(--el-dropdown-menuItem-hover-fill);
+}
+</style>
Added +110 -0
diff --git a/core/components/Notification.ts b/core/components/Notification.ts
new file mode 100644
index 0000000..0c4cc7d
--- /dev/null
+++ b/core/components/Notification.ts
@@ -0,0 +1,110 @@
+
+/**
+ * 通知工具组件
+ * 封装 Element Plus 的 ElNotification 组件
+ */
+import { ElNotification } from 'element-plus'
+import type { NotificationParams } from '../types/notification'
+
+/**
+ * 显示信息通知
+ * @param {Object} params - 通知参数
+ * @param {string} params.message - 通知消息内容
+ * @param {string} [params.title] - 通知标题
+ * @param {number} [params.duration] - 显示时间,单位毫秒
+ */
+const info = (params: NotificationParams) => {
+  ElNotification({
+    type: 'info',
+    message: params.message,
+    title: params.title || '信息',
+    duration: params.duration || 3000,
+  })
+}
+
+/**
+ * 显示成功通知
+ * @param {Object} params - 通知参数
+ * @param {string} params.message - 通知消息内容
+ * @param {string} [params.title] - 通知标题
+ * @param {number} [params.duration] - 显示时间,单位毫秒
+ */
+const success = (params: NotificationParams) => {
+  ElNotification({
+    type: 'success',
+    message: params.message,
+    title: params.title || '成功',
+    duration: params.duration || 3000,
+  })
+}
+
+/**
+ * 显示错误通知
+ * @param {Object} params - 通知参数
+ * @param {string} params.message - 通知消息内容
+ * @param {string} [params.title] - 通知标题
+ * @param {number} [params.duration] - 显示时间,单位毫秒
+ */
+const error = (params: NotificationParams) => {
+  ElNotification({
+    type: 'error',
+    message: params.message,
+    title: params.title || '错误',
+    duration: params.duration || 5000,
+  })
+}
+
+/**
+ * 显示警告通知
+ * @param {Object} params - 通知参数
+ * @param {string} params.message - 通知消息内容
+ * @param {string} [params.title] - 通知标题
+ * @param {number} [params.duration] - 显示时间,单位毫秒
+ */
+const warning = (params: NotificationParams) => {
+  ElNotification({
+    type: 'warning',
+    message: params.message,
+    title: params.title || '警告',
+    duration: params.duration || 4000,
+  })
+}
+
+/**
+ * 根据类型自动显示对应的通知
+ * @param {string} type - 通知类型:info, success, error, warning
+ * @param {string} message - 通知消息内容
+ * @param {string} [title] - 通知标题
+ * @param {number} [duration] - 显示时间,单位毫秒
+ */
+const autoNotification = (type: string, message: string, title?: string, duration?: number) => {
+  const params = { message, title, duration }
+
+  switch (type) {
+    case 'success':
+      success(params)
+      break
+    case 'error':
+      error(params)
+      break
+    case 'warning':
+      warning(params)
+      break
+    case 'info':
+    default:
+      info(params)
+      break
+  }
+}
+
+// 导出通知函数
+const Notification = {
+  info,
+  success,
+  error,
+  warning,
+  autoNotification,
+}
+
+export default Notification
+
Added +126 -0
diff --git a/core/components/TextOverflow.vue b/core/components/TextOverflow.vue
new file mode 100644
index 0000000..3e46955
--- /dev/null
+++ b/core/components/TextOverflow.vue
@@ -0,0 +1,126 @@
+<script setup lang="ts">
+import { ref, onMounted, nextTick } from 'vue';
+import { ElTooltip } from 'element-plus';
+
+defineOptions({
+  name: 'TextOverflow',
+});
+
+interface Props {
+  /**
+   * 要显示的文本内容
+   */
+  text: string;
+  /**
+   * tooltip显示位置
+   * @default 'top'
+   */
+  tooltipPlacement?:
+    | 'top'
+    | 'top-start'
+    | 'top-end'
+    | 'bottom'
+    | 'bottom-start'
+    | 'bottom-end'
+    | 'left'
+    | 'left-start'
+    | 'left-end'
+    | 'right'
+    | 'right-start'
+    | 'right-end';
+  /**
+   * 是否始终显示tooltip,无论是否溢出
+   * @default false
+   */
+  alwaysShowTooltip?: boolean;
+  /**
+   * 自定义class
+   */
+  class?: string;
+  /**
+   * 检测溢出的延迟时间(毫秒)
+   * @default 0
+   */
+  checkDelay?: number;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  tooltipPlacement: 'top',
+  alwaysShowTooltip: false,
+  customClass: '',
+  checkDelay: 0,
+});
+
+const textRef = ref<HTMLElement | null>(null);
+const isTextOverflow = ref(false);
+
+/**
+ * 检查文本是否溢出
+ */
+const checkTextOverflow = () => {
+  if (!textRef.value) return;
+
+  const element = textRef.value;
+  // 通过比较scrollWidth和clientWidth判断是否溢出
+  isTextOverflow.value = element.scrollWidth > element.clientWidth;
+};
+
+/**
+ * 初始化时检查是否溢出
+ */
+onMounted(async () => {
+  // 添加延迟,确保DOM已完全渲染
+  await nextTick();
+
+  if (props.checkDelay > 0) {
+    setTimeout(checkTextOverflow, props.checkDelay);
+  } else {
+    checkTextOverflow();
+  }
+
+  // 监听窗口大小变化,重新检测溢出状态
+  window.addEventListener('resize', checkTextOverflow);
+});
+
+/**
+ * 判断是否需要显示tooltip
+ */
+const shouldShowTooltip = () => {
+  return props.alwaysShowTooltip || isTextOverflow.value;
+};
+</script>
+
+<template>
+  <div class="text-overflow-container" :class="props.class">
+    <ElTooltip
+      :content="props.text"
+      :disabled="!shouldShowTooltip()"
+      :placement="props.tooltipPlacement"
+      :enterable="false"
+      popper-class="text-overflow-tooltip"
+    >
+      <div ref="textRef" class="text-overflow-content">
+        {{ props.text }}
+      </div>
+    </ElTooltip>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.text-overflow-container {
+  width: 100%;
+  display: inline-block;
+}
+
+.text-overflow-content {
+  width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+:deep(.text-overflow-tooltip) {
+  max-width: 300px;
+  word-break: break-word;
+}
+</style>
Added +93 -0
diff --git a/core/configure/defaultConfig/index.ts b/core/configure/defaultConfig/index.ts
new file mode 100644
index 0000000..d14ffb4
--- /dev/null
+++ b/core/configure/defaultConfig/index.ts
@@ -0,0 +1,93 @@
+import type { CubeFrontConfig } from '../types';
+import type { AxiosRequestConfig } from 'axios';
+
+export const defaultConfig: CubeFrontConfig = {
+  base: {
+    title: '魔方系统',
+    logo: '/logo.png',
+    footer: '版权所有',
+    env: process.env.NODE_ENV as 'development' | 'production' | 'test',
+  },
+  menu: {
+    getMenuAxiosConfig: () => {
+      return {
+        method: 'get',
+        url: '/Admin/Menu',
+      };
+    },
+    isMenuTree: false,
+    dataKey: 'data',
+    idField: 'id',
+    parentField: 'parentID',
+    nameField: 'title',
+    pathField: 'url',
+    titleField: 'displayName',
+    iconField: 'icon',
+    sortField: 'sort',
+    childrenField: 'children',
+  },
+  user: {
+    getUserInfoAxiosConfig: (): AxiosRequestConfig => {
+      return {
+        method: 'get',
+        url: '/Admin/User/Info',
+      };
+    },
+  },
+  ui: {
+    layout: {
+      header: {
+        show: true,
+        fixed: true,
+        theme: 'light',
+      },
+      sider: {
+        show: true,
+        collapsible: true,
+        defaultCollapsed: false,
+        width: 200,
+        collapsedWidth: 80,
+        theme: 'light',
+      },
+      footer: {
+        show: true,
+        fixed: false,
+      },
+    },
+    theme: {
+      primaryColor: '#1890ff',
+      linkColor: '#1890ff',
+      successColor: '#52c41a',
+      warningColor: '#faad14',
+      errorColor: '#f5222d',
+      font: {
+        baseSize: 14,
+        family:
+          '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
+      },
+    },
+  },
+  request: {
+    baseURL: '',
+    timeout: 10000,
+    responseIntercept: (response) => response,
+  },
+  auth: {
+    tokenKey: 'token',
+    oauthUrl: '/Sso/Login?name=NewLife&source=front-end&r=',
+    redirectUrl: '/login',
+    pageTitle: '登录',
+    background: '',
+    logoutAxiosConfig: (): AxiosRequestConfig => {
+      return {
+        method: 'GET',
+        url: '/Admin/User/Logout',
+      };
+    },
+    reLoginParams: {
+      // 默认的重新登录参数
+    },
+  },
+};
+
+export default defaultConfig;
Added +16 -0
diff --git a/core/configure/environments/development.ts b/core/configure/environments/development.ts
new file mode 100644
index 0000000..6a22a27
--- /dev/null
+++ b/core/configure/environments/development.ts
@@ -0,0 +1,16 @@
+import type { CubeFrontConfig } from '../types';
+
+/**
+ * 开发环境配置
+ */
+export const developmentConfig: Partial<{
+  [key in keyof CubeFrontConfig]: Partial<CubeFrontConfig[key]>;
+}> = {
+  base: {
+    env: 'development',
+  },
+  request: {
+    baseURL: 'https://cube.newlifex.com',
+    // 其他API配置
+  },
+};
Added +30 -0
diff --git a/core/configure/environments/index.ts b/core/configure/environments/index.ts
new file mode 100644
index 0000000..1ab7f4a
--- /dev/null
+++ b/core/configure/environments/index.ts
@@ -0,0 +1,30 @@
+import type { CubeFrontConfig } from '../types'
+import { developmentConfig } from './development'
+import { productionConfig } from './production'
+import { defaultConfig } from '../defaultConfig'
+import { deepMerge } from '../../utils/object'
+
+/**
+ * 获取环境特定配置
+ * @param env 环境类型
+ * @returns 合并后的配置
+ */
+export function getEnvConfig(env: string = import.meta.env.MODE): CubeFrontConfig {
+  let envConfig = {}
+
+  switch (env) {
+    case 'development':
+      envConfig = developmentConfig
+      break
+    case 'production':
+      envConfig = productionConfig
+      break
+    case 'test':
+      envConfig = {}
+      break
+    default:
+      envConfig = {}
+  }
+
+  return deepMerge(defaultConfig, envConfig) as CubeFrontConfig
+}
Added +17 -0
diff --git a/core/configure/environments/production.ts b/core/configure/environments/production.ts
new file mode 100644
index 0000000..f9878b1
--- /dev/null
+++ b/core/configure/environments/production.ts
@@ -0,0 +1,17 @@
+import type { CubeFrontConfig } from '../types'
+
+/**
+ * 生产环境配置
+ */
+export const productionConfig: Partial<{
+  [key in keyof CubeFrontConfig]: Partial<CubeFrontConfig[key]>
+}> = {
+  base: {
+    env: 'production',
+    // 其他基础配置
+  },
+  // api: {
+  //   baseURL: '/api',
+  //   // 其他API配置
+  // },
+}
Added +61 -0
diff --git a/core/configure/index.ts b/core/configure/index.ts
new file mode 100644
index 0000000..8987403
--- /dev/null
+++ b/core/configure/index.ts
@@ -0,0 +1,61 @@
+import { getEnvConfig } from './environments';
+import type { CubeFrontConfig } from './types';
+import { defaultConfig } from './defaultConfig';
+
+/**
+ * 获取当前环境配置
+ */
+export function getConfig(): CubeFrontConfig {
+  return getEnvConfig();
+}
+
+/**
+ * 合并配置
+ */
+export function mergeConfig(config?: Partial<CubeFrontConfig>): CubeFrontConfig {
+  // 深度合并配置
+  return {
+    ...defaultConfig,
+    ...config,
+    base: {
+      ...defaultConfig.base,
+      ...(config?.base || {}),
+    },
+    ui: {
+      ...defaultConfig.ui,
+      ...(config?.ui || {}),
+      layout: {
+        ...defaultConfig.ui.layout,
+        ...(config?.ui?.layout || {}),
+      },
+      theme: {
+        ...defaultConfig.ui.theme,
+        ...(config?.ui?.theme || {}),
+      },
+    },
+    request: {
+      ...defaultConfig.request,
+      ...(config?.request || {}),
+    },
+    auth: {
+      ...defaultConfig.auth,
+      ...(config?.auth || {}),
+      reLoginParams: {
+        ...(defaultConfig.auth.reLoginParams || {}),
+        ...(config?.auth?.reLoginParams || {}),
+      },
+    },
+  };
+}
+
+// 导出配置类型
+export type {
+  CubeFrontConfig,
+  BaseConfig, // 替代 AppConfig
+  AuthConfig, // 替代 LoginConfig
+  RequestConfig, // 替代 RequestConfig
+  UIConfig, // 包含原 LayoutConfig 和 ThemeConfig
+} from './types';
+
+// 导出默认配置
+export { defaultConfig } from './defaultConfig';
Added +124 -0
diff --git a/core/configure/types.d.ts b/core/configure/types.d.ts
new file mode 100644
index 0000000..9f482d8
--- /dev/null
+++ b/core/configure/types.d.ts
@@ -0,0 +1,124 @@
+import type { AxiosRequestConfig } from 'axios';
+
+// 基础配置
+export interface BaseConfig {
+  title: string;
+  logo?: string;
+  footer?: string;
+  env?: 'development' | 'production' | 'test';
+}
+
+// 菜单相关配置
+export interface MenuConfig {
+  getMenuAxiosConfig:
+    | AxiosRequestConfig
+    | (() => AxiosRequestConfig)
+    | (() => Promise<AxiosRequestConfig>);
+  isMenuTree: boolean;
+  dataKey: string;
+  idField: string;
+  parentField: string;
+  nameField: string;
+  pathField: string;
+  titleField: string;
+  iconField: string;
+  sortField: string;
+  childrenField: string;
+}
+
+// 用户相关配置
+export interface UserConfig {
+  getUserInfoAxiosConfig:
+    | AxiosRequestConfig
+    | (() => AxiosRequestConfig)
+    | (() => Promise<AxiosRequestConfig>);
+}
+
+// UI相关配置
+export interface UIConfig {
+  layout: {
+    header: {
+      show: boolean;
+      fixed: boolean;
+      theme: 'light' | 'dark';
+      height?: number;
+    };
+    sider?: {
+      show?: boolean;
+      collapsible?: boolean;
+      defaultCollapsed?: boolean;
+      width?: number;
+      collapsedWidth?: number;
+      theme?: 'light' | 'dark';
+    };
+    footer?: {
+      show?: boolean;
+      fixed?: boolean;
+    };
+  };
+  theme?: {
+    primaryColor?: string;
+    linkColor?: string;
+    successColor?: string;
+    warningColor?: string;
+    errorColor?: string;
+    font?: {
+      baseSize?: number;
+      family?: string;
+    };
+  };
+}
+
+// API相关配置
+export interface RequestConfig {
+  /** 基础URL */
+  baseURL: string;
+  /** 请求超时时间 */
+  timeout?: number;
+  /** 额外请求头 */
+  additionalRequestHeader?: Recore<string, string> | (() => Recore<string, string>);
+  /** 响应拦截器 */
+  responseIntercept?: (response: AxiosResponse) => void;
+}
+
+// 认证相关配置
+export interface AuthConfig {
+  tokenKey: string;
+  oauthUrl: string;
+  redirectUrl?: string;
+  pageTitle?: string;
+  background?: string;
+  logoutAxiosConfig?:
+    | AxiosRequestConfig
+    | (() => AxiosRequestConfig)
+    | (() => Promise<AxiosRequestConfig>);
+  reLoginParams?: {
+    titleIntlCode?: string;
+    titleIntlDefault?: string;
+    messageIntlCode?: string;
+    messageIntlDefault?: string;
+    okTextIntlCode?: string;
+    okTextIntlDefault?: string;
+    cancelTextIntlCode?: string;
+    cancelTextIntlDefault?: string;
+    loginPageUrl?: string;
+    cancelText?: string;
+    onModalShow?: () => void;
+    onOk?: () => void;
+    onCancel?: () => void;
+    noticeMethod?: Array<() => void>;
+    isShow?: boolean;
+    isUseCustomizeModal?: boolean;
+    customizeModalProps?: Recore<string, unknown>;
+  };
+}
+
+// 总配置
+export interface CubeFrontConfig {
+  base: BaseConfig;
+  ui: UIConfig;
+  request: RequestConfig;
+  auth: AuthConfig;
+  menu: MenuConfig;
+  user: UserConfig;
+}
Added +575 -0
diff --git a/core/dataset/data-set/DataSet.ts b/core/dataset/data-set/DataSet.ts
new file mode 100644
index 0000000..f901a5a
--- /dev/null
+++ b/core/dataset/data-set/DataSet.ts
@@ -0,0 +1,575 @@
+import { ref, toRaw, type UnwrapRef } from 'vue';
+import { type AxiosRequestConfig, type AxiosInstance } from 'axios';
+import axios from '../../utils/request';
+import { generateResponseData, getDataByKey } from '../../utils/common';
+import type { VNode } from 'vue';
+
+/**
+ * 数据集配置选项接口
+ * @template T 数据类型
+ * @template Q 查询参数类型
+ */
+export type TransportHookProps = {
+  data?: object;
+  params?: object;
+  dataSet?: DataSet;
+  [key: string]: object | undefined;
+};
+
+export type TransportType = (props: TransportHookProps) => AxiosRequestConfig;
+
+/**
+ * 表格列配置
+ */
+
+export type ColumnConfig<T, K extends keyof T = keyof T> = {
+  /** 字段名,必须是T的key */
+  prop?: K | string;
+  /** 列标题 */
+  label?: string;
+  /** 列类型 */
+  type?: 'selection' | 'index' | 'expand' | string;
+  /** 列宽度 */
+  width?: string | number;
+  /** 最小宽度 */
+  minWidth?: string | number;
+  /** 是否可排序 */
+  sortable?: boolean | string;
+  /** 排序方法 */
+  sortMethod?: (a: T, b: T) => number;
+  /** 排序依据 */
+  sortBy?: string | ((row: T, index: number) => string) | string[];
+  /** 排序顺序 */
+  sortOrders?: Array<'ascending' | 'descending' | null>;
+  /** 是否可拖动宽度 */
+  resizable?: boolean;
+  /** 对齐方式 */
+  align?: 'left' | 'center' | 'right' | string;
+  /** 表头对齐方式 */
+  headerAlign?: 'left' | 'center' | 'right' | string;
+  /** 固定列 */
+  fixed?: boolean | 'left' | 'right' | string;
+  /** 列的 class 名称 */
+  className?: string;
+  /** 列头的 class 名称 */
+  labelClassName?: string;
+  /** 是否显示 tooltip */
+  showOverflowTooltip?: boolean | string;
+  /** tooltip 格式化 */
+  tooltipFormatter?: (row: T, column: ColumnConfig<T>, cellValue: unknown, index: number) => string;
+  /** 格式化函数 */
+  formatter?: (
+    row: T,
+    column: ColumnConfig<T>,
+    cellValue: unknown,
+    index: number,
+  ) => VNode | string;
+  /** 索引列自定义内容 */
+  index?: number | ((index: number) => number);
+  /** 是否多选列可用 */
+  selectable?: (row: T, index: number) => boolean;
+  /** 多选列数据是否保留 */
+  reserveSelection?: boolean;
+  /** column key */
+  columnKey?: string;
+  /** 筛选数据 */
+  filters?: Array<{ text: string; value: string }>;
+  /** 筛选方法 */
+  filterMethod?: (value: unknown, row: T, column: ColumnConfig<T>) => boolean;
+  /** 筛选多选 */
+  filterMultiple?: boolean;
+  /** 筛选列的默认值 */
+  filteredValue?: string[];
+  /** 筛选弹窗位置 */
+  filterPlacement?: string;
+  /** 筛选弹窗 class */
+  filterClassName?: string;
+  /** render slot */
+  render?: (value: T[K], row: T, rowIndex: number) => VNode | string;
+};
+
+interface DataSetOptions<T, Q> {
+  axios?: AxiosInstance;
+  /** 初始数据数组 */
+  data?: T[];
+  /** 数据项唯一标识字段名,默认为'id' */
+  idField?: string;
+  /** 可查询字段配置 */
+  queryFields?: {
+    /** 字段名,必须是Q的key */
+    name: keyof Q;
+    /** 字段类型 */
+    type: 'string' | 'number' | 'boolean' | 'date';
+    /** 是否支持模糊查询 */
+    fuzzy?: boolean;
+  }[];
+  /** 字段配置 */
+  fields?: {
+    /** 字段名,必须是T的key */
+    name: keyof T;
+    /** 字段标签 */
+    label?: string;
+    /** 字段类型 */
+    type: 'string' | 'number' | 'boolean' | 'date' | 'object';
+    /** 是否必填 */
+    required?: boolean;
+    /** 默认值 */
+    defaultValue?: T[keyof T];
+    /** 校验规则 */
+    validator?: (value: T[keyof T]) => boolean | string;
+  }[];
+  /** 列配置 */
+  columns?: ColumnConfig<T>[];
+  /** 传输配置 */
+  transport?: {
+    /** 创建记录 */
+    create?: TransportType;
+    /** 读取数据 */
+    read?: TransportType;
+    /** 更新记录 */
+    update?: TransportType;
+    /** 删除记录 */
+    destroy?: TransportType;
+    /** 数据校验 */
+    validate?: TransportType;
+    /** 表单提交 */
+    submit?: TransportType;
+  };
+  /** 是否初始化后自动查询远程数据 */
+  autoQuery?: boolean;
+  /** 默认分页大小 */
+  pageSize?: number;
+  /** 数据属性名,默认为'data' */
+  dataKey?: string;
+  /** 数据总数属性名,默认为'total' */
+  totalCountKey?: string;
+}
+
+/**
+ * 响应式数据集管理类
+ * 使用Vue的响应式系统管理数据集合,支持增删改查等操作
+ * @template T 数据类型
+ * @template Q 查询参数类型
+ */
+export class DataSet<T, Q> {
+  /** 响应式数据数组 */
+  private readonly _data = ref<Array<T>>([]);
+  /** 当前选中项的引用 */
+  private readonly _current = ref<T | null>(null);
+  /** 数据项唯一标识字段名 */
+  private readonly _idField: string;
+  /** 可查询字段配置 */
+  private readonly _queryFields: DataSetOptions<T, Q>['queryFields'];
+  /** 字段配置 */
+  private readonly _fields: DataSetOptions<T, Q>['fields'];
+  /** 传输配置 */
+  private readonly _transport: DataSetOptions<T, Q>['transport'];
+  /** 加载状态 */
+  private readonly _loading = ref(false);
+  /** 分页大小 */
+  private readonly _pageSize = ref(10);
+  /** 当前页码 */
+  private readonly _currentPage = ref(1);
+  /** 数据总数 */
+  private readonly _totalCount = ref(0);
+  /** 自定义axios实例 */
+  private readonly _axios?: AxiosInstance;
+
+  private readonly _options: DataSetOptions<T, Q>;
+
+  get pageSize() {
+    return this._pageSize.value;
+  }
+
+  set pageSize(value: number) {
+    this._pageSize.value = value;
+  }
+
+  get currentPage() {
+    return this._currentPage.value;
+  }
+
+  set currentPage(value: number) {
+    this._currentPage.value = value;
+  }
+
+  get totalCount() {
+    return this._totalCount.value;
+  }
+
+  set totalCount(value: number) {
+    this._totalCount.value = value;
+  }
+
+  /**
+   * 创建数据集实例
+   * @param options 数据集配置选项
+   */
+  constructor(options: DataSetOptions<T, Q> = {}) {
+    this._idField = options.idField || 'id';
+    this._queryFields = options.queryFields;
+    this._fields = options.fields;
+    this._transport = options.transport;
+    this._pageSize.value = options.pageSize || 10;
+    this._axios = options.axios;
+
+    this._options = options;
+
+    if (options.data) {
+      const value = this._data.value as T[];
+      value.push(...options.data);
+      this._totalCount.value = value.length;
+    }
+
+    if (options.autoQuery && this._transport?.read) {
+      this.read();
+    }
+  }
+
+  get axios(): AxiosInstance {
+    return this._axios || axios;
+  }
+
+  /**
+   *
+   * 获取数据集中的所有数据
+   * @returns 数据数组
+   */
+  get data(): T[] {
+    return this._data.value as T[];
+  }
+
+  /**
+   * 获取当前选中的数据项
+   * @returns 当前选中项或null
+   */
+  get current(): T | null {
+    return this._current.value;
+  }
+
+  /**
+   * 设置当前选中的数据项
+   * @param value 要设置为当前项的数据
+   */
+  set current(value: T | null) {
+    this._current.value = value;
+  }
+
+  /**
+   * 向数据集添加新数据项
+   * @param item 要添加的数据项
+   * @example
+   * dataset.add({id: 1, name: 'John'});
+   */
+  add(item: T): void {
+    this._data.value.push(item);
+    this._totalCount.value++;
+  }
+
+  /**
+   * 从数据集中移除指定数据项
+   * @param item 要移除的数据项
+   * @returns 是否成功移除
+   * @example
+   * const success = dataset.remove(itemToRemove);
+   */
+  remove(item: T): boolean {
+    const index = this._data.value.findIndex((i) => i[this._idField] === item[this._idField]);
+    if (index >= 0) {
+      this._data.value.splice(index, 1);
+      this._totalCount.value = Math.max(0, this._totalCount.value - 1);
+      if (this.current && this.current[this._idField] === item[this._idField]) {
+        this.current = null;
+      }
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * 更新数据集中的指定数据项
+   * @param item 包含更新数据的数据项
+   * @returns 是否成功更新
+   * @example
+   * const success = dataset.update(updatedItem);
+   */
+  update(item: T): boolean {
+    const index = this._data.value.findIndex((i) => i[this._idField] === item[this._idField]);
+    if (index >= 0) {
+      this._data.value[index] = item;
+      return true;
+    }
+    return false;
+  }
+
+  /**
+   * 查询符合条件的数据项
+   * @param fn 过滤函数,接收数据项和可选查询参数,返回是否匹配
+   * @returns 符合条件的数据项数组
+   * @example
+   * const adults = dataset.query((user) => user.age >= 18);
+   * // 使用查询参数
+   * const results = dataset.query((user, query) => {
+   *   return query?.minAge ? user.age >= query.minAge : true;
+   * }, { minAge: 18 });
+   */
+  /**
+   * 查询数据项
+   * @param fnOrQuery 过滤函数或查询对象
+   * @param query 可选查询参数(当第一个参数是函数时使用)
+   * @returns 符合条件的数据项数组
+   * @example
+   * // 使用过滤函数
+   * dataset.query((user) => user.age >= 18);
+   * // 使用查询对象(需配置queryFields)
+   * dataset.query({ name: 'John', age: 18 });
+   */
+  query(fnOrQuery: ((item: T, query?: Q) => boolean) | Record<string, any>, query?: Q): T[] {
+    if (typeof fnOrQuery === 'function') {
+      return this._data.value.filter((item) => fnOrQuery(item, query));
+    }
+
+    if (!this._queryFields) {
+      console.warn('Query fields not configured, falling back to full scan');
+      return this._data.value.filter((item) =>
+        Object.entries(fnOrQuery).every(([key, value]) => item[key as keyof T] === value),
+      );
+    }
+
+    return this._data.value.filter((item) => {
+      return Object.entries(fnOrQuery).every(([key, value]) => {
+        const fieldConfig = this._queryFields?.find((f) => f.name === key);
+        if (!fieldConfig) return true;
+
+        if (fieldConfig.fuzzy && fieldConfig.type === 'string') {
+          return String(item[key as keyof Q]).includes(String(value));
+        }
+        return item[key as keyof Q] === value;
+      });
+    });
+  }
+
+  /**
+   * 根据ID查找数据项
+   * @param id 要查找的数据项ID
+   * @returns 找到的数据项或undefined
+   * @example
+   * const user = dataset.findById(1);
+   */
+  findById(id: unknown): T | undefined {
+    return this._data.value.find((item) => item[this._idField] === id);
+  }
+
+  /**
+   * 获取字段配置
+   * @returns 字段配置数组
+   */
+  getFields() {
+    return this._fields;
+  }
+
+  /**
+   * 获取列配置
+   * @returns 列配置数组
+   */
+  getColumns() {
+    return this._options.columns;
+  }
+
+  /**
+   * 获取加载状态
+   * @returns 是否正在加载
+   */
+  get loading() {
+    return this._loading.value;
+  }
+
+  /**
+   * 设置加载状态
+   */
+  set loading(value: boolean) {
+    this._loading.value = value;
+  }
+
+  /**
+   * 读取数据
+   * @param params 查询参数
+   * @returns Promise包含查询结果
+   */
+  async read(params?: object): Promise<T[]> {
+    if (!this._transport?.read) {
+      throw new Error('Read transport not configured');
+    }
+
+    this._loading.value = true;
+    try {
+      const config = this._transport.read({
+        params: {
+          ...params,
+          pageSize: this._pageSize.value,
+          pageIndex: this._currentPage.value,
+        },
+        dataSet: this,
+      });
+
+      // response有可能是原始的响应对象,也可能是经过处理的配置对象
+      const response = await this.axios(config);
+
+      let res = response as object;
+
+      // 首先判断response是否是AxiosResponse对象
+      if (
+        'data' in res &&
+        'status' in res &&
+        'statusText' in res &&
+        'headers' in res &&
+        'config' in res &&
+        'request' in res
+      ) {
+        res = response.data;
+      }
+
+      // 处理响应数据
+
+      const { dataKey = 'data', totalCountKey = 'page.totalCount' } = this._options;
+
+      // 使用generateResponseData处理响应数据
+      const processedData = generateResponseData(res, dataKey) as T[];
+      const totalCount = getDataByKey(res, totalCountKey) as number;
+
+      // 默认情况
+      this._data.value = processedData;
+      this._totalCount.value = totalCount;
+      return processedData;
+    } finally {
+      this._loading.value = false;
+    }
+  }
+
+  /**
+   * 创建记录
+   * @param data 要创建的数据
+   * @returns Promise包含创建结果
+   */
+  async create(data: T): Promise<T> {
+    if (!this._transport?.create) {
+      throw new Error('Create transport not configured');
+    }
+
+    this._loading.value = true;
+    try {
+      const config = this._transport.create({ data, dataSet: this });
+      const response = await this.axios(config);
+
+      this._data.value.push(response.data);
+      this._totalCount.value++;
+      return response.data;
+    } finally {
+      this._loading.value = false;
+    }
+  }
+
+  /**
+   * 更新记录
+   * @param data 要更新的数据
+   * @returns Promise包含更新结果
+   */
+  async update(data: T): Promise<T> {
+    if (!this._transport?.update) {
+      throw new Error('Update transport not configured');
+    }
+
+    this._loading.value = true;
+    try {
+      const config = this._transport.update({ data, dataSet: this });
+      const response = await this.axios(config);
+
+      const index = this._data.value.findIndex(
+        (item) => item[this._idField] === data[this._idField],
+      );
+      if (index >= 0) {
+        this._data.value[index] = response.data;
+      }
+      return response.data;
+    } finally {
+      this._loading.value = false;
+    }
+  }
+
+  /**
+   * 删除记录
+   * @param data 要删除的数据
+   * @returns Promise包含删除结果
+   */
+  async destroy(data: T): Promise<boolean> {
+    if (!this._transport?.destroy) {
+      throw new Error('Destroy transport not configured');
+    }
+
+    this._loading.value = true;
+    try {
+      const config = this._transport.destroy({ data, dataSet: this });
+      await this.axios(config);
+
+      const index = this._data.value.findIndex(
+        (item) => item[this._idField] === data[this._idField],
+      );
+      if (index >= 0) {
+        this._data.value.splice(index, 1);
+        this._totalCount.value = Math.max(0, this._totalCount.value - 1);
+      }
+      return true;
+    } finally {
+      this._loading.value = false;
+    }
+  }
+
+  /**
+   * 根据字段名获取字段配置
+   * @param name 字段名
+   * @returns 字段配置或undefined
+   */
+  getField(name: keyof T) {
+    return this._fields?.find((f) => f.name === name);
+  }
+
+  /**
+   * 验证数据项是否符合字段配置
+   * @param item 数据项
+   * @returns 验证结果
+   */
+  validate(item: T) {
+    if (!this._fields) return { valid: true, errors: [] };
+
+    const errors: { field: keyof T; message: string }[] = [];
+
+    this._fields.forEach((field) => {
+      const value = item[field.name];
+
+      // 检查必填字段
+      if (field.required && (value === undefined || value === null || value === '')) {
+        errors.push({
+          field: field.name,
+          message: `${field.label || String(field.name)} 是必填字段`,
+        });
+        return;
+      }
+
+      // 执行自定义校验
+      if (field.validator) {
+        const result = field.validator(value);
+        if (result !== true) {
+          errors.push({
+            field: field.name,
+            message: result || `${field.label || String(field.name)} 校验失败`,
+          });
+        }
+      }
+    });
+
+    return {
+      valid: errors.length === 0,
+      errors,
+    };
+  }
+}
Added +1 -0
diff --git a/core/dataset/index.ts b/core/dataset/index.ts
new file mode 100644
index 0000000..a57cee3
--- /dev/null
+++ b/core/dataset/index.ts
@@ -0,0 +1 @@
+export * from './data-set/DataSet';
Added +21 -0
diff --git a/core/dataset/types.d.ts b/core/dataset/types.d.ts
new file mode 100644
index 0000000..bc88cf2
--- /dev/null
+++ b/core/dataset/types.d.ts
@@ -0,0 +1,21 @@
+import { DataSet } from './data-set/DataSet';
+
+declare module './data-set/DataSet' {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  interface DataSet<T = any, Q = any> {
+    /**
+     * 获取数据集长度
+     */
+    readonly length: number;
+    /**
+     * 清空数据集
+     */
+    clear(): void;
+    /**
+     * 批量添加数据
+     */
+    addAll(items: T[]): void;
+  }
+}
+
+export {};
Added +11 -0
diff --git a/core/global.css b/core/global.css
new file mode 100644
index 0000000..b5837bd
--- /dev/null
+++ b/core/global.css
@@ -0,0 +1,11 @@
+@import 'tailwindcss/preflight';
+@import 'tailwindcss/utilities';
+
+body {
+  margin: 0;
+  padding: 0;
+}
+
+:root {
+  --primary-color: #1890ff;
+}
Added +78 -0
diff --git a/core/i18n/index.ts b/core/i18n/index.ts
new file mode 100644
index 0000000..336928b
--- /dev/null
+++ b/core/i18n/index.ts
@@ -0,0 +1,78 @@
+import { createI18n } from 'vue-i18n';
+import zhCN from './locales/zh-CN';
+import enUS from './locales/en-US';
+
+// 获取浏览器语言设置
+function getBrowserLanguage() {
+  const navigatorLanguage = navigator.language;
+  if (navigatorLanguage.startsWith('zh')) {
+    return 'zh-CN';
+  }
+  return 'en-US';
+}
+
+// 获取本地存储的语言设置或使用浏览器语言
+function getLanguage() {
+  return localStorage.getItem('cube-language') || getBrowserLanguage();
+}
+
+// 创建 i18n 实例
+const i18n = createI18n({
+  legacy: false, // 使用组合式 API
+  locale: getLanguage(),
+  fallbackLocale: 'zh-CN', // 设置回退语言
+  messages: {
+    'zh-CN': zhCN,
+    'en-US': enUS,
+  },
+  silentTranslationWarn: true,
+});
+
+// 导出 i18n 实例
+export default i18n;
+
+/**
+ * 切换语言的工具函数
+ * @param {string} lang - 语言代码
+ */
+export function setLanguage(lang: typeof i18n.global.locale.value) {
+  i18n.global.locale.value = lang;
+  localStorage.setItem('cube-language', lang);
+  // 可以在这里添加其他语言切换逻辑,比如更新 HTML 标签的 lang 属性
+  document.querySelector('html')?.setAttribute('lang', lang);
+}
+
+// 获取当前语言
+export function getCurrentLanguage() {
+  return i18n.global.locale.value;
+}
+
+// 创建一个与 react-intl-universal 兼容的接口
+export const intl = {
+  get: (key: string) => {
+    return {
+      d: (defaultValue: string) => {
+        const message = i18n.global.t(key);
+        return message !== key ? message : defaultValue;
+      },
+    };
+  },
+  getHTML: (key: string) => {
+    return {
+      d: (defaultValue: string) => {
+        const message = i18n.global.t(key);
+        return message !== key ? message : defaultValue;
+      },
+    };
+  },
+  formatMessage: (options: { id: string; defaultMessage?: string }) => {
+    const message = i18n.global.t(options.id);
+    return message !== options.id ? message : options.defaultMessage || options.id;
+  },
+  formatHTMLMessage: (options: { id: string; defaultMessage?: string }) => {
+    const message = i18n.global.t(options.id);
+    return message !== options.id ? message : options.defaultMessage || options.id;
+  },
+  getLocale: () => i18n.global.locale.value,
+  determineLocale: () => i18n.global.locale.value,
+};
Added +67 -0
diff --git a/core/i18n/locales/en-US.ts b/core/i18n/locales/en-US.ts
new file mode 100644
index 0000000..eeb4dde
--- /dev/null
+++ b/core/i18n/locales/en-US.ts
@@ -0,0 +1,67 @@
+export default {
+  // Common
+  'cube.notification.success': 'Operation successful',
+  'cube.notification.failed': 'Operation failed',
+  'cube.notification.warn': 'Operation warning',
+  'cube.cancel': 'Cancel',
+  'cube.basicLayout.errorCode': 'Error code',
+  'cube.basicLayout.errorDetail': 'Click here to learn more',
+  'cube.basicLayout.viewMore': 'View more',
+  'cube.view.pleaseLoginAgain':
+    'Your login has expired. Please manually save the content you are editing to avoid data loss.',
+  'cube.view.logInAgain': 'Log in again',
+
+  // Menu
+  'menu.home': 'Home',
+  'menu.dashboard': 'Dashboard',
+  'menu.settings': 'Settings',
+  'menu.profile': 'Profile',
+
+  // Buttons
+  'button.submit': 'Submit',
+  'button.cancel': 'Cancel',
+  'button.save': 'Save',
+  'button.edit': 'Edit',
+  'button.delete': 'Delete',
+  'button.add': 'Add',
+  'button.search': 'Search',
+  'button.reset': 'Reset',
+  'button.back': 'Back',
+  'button.confirm': 'Confirm',
+
+  // Forms
+  'form.required': 'Required',
+  'form.invalid': 'Invalid format',
+  'form.placeholder': 'Please enter {field}',
+  'form.select.placeholder': 'Please select {field}',
+
+  // Authentication
+  'auth.login': 'Login',
+  'auth.logout': 'Logout',
+  'auth.username': 'Username',
+  'auth.password': 'Password',
+  'auth.rememberMe': 'Remember me',
+  'auth.forgotPassword': 'Forgot password',
+  'auth.login.error': 'Incorrect username or password',
+  'auth.login.success': 'Login successful',
+  'auth.login.expired': 'You are offline',
+
+  // Permissions
+  'permission.denied': 'Permission denied',
+  'permission.unauthorized': 'Unauthorized access',
+
+  // Errors
+  'error.network': 'Network error, please check your connection',
+  'error.server': 'Server error, please try again later',
+  'error.unknown': 'Unknown error',
+  'error.notFound': 'Page not found',
+
+  // Notifications
+  'notification.message': 'Message',
+  'notification.success': 'Success',
+  'notification.error': 'Error',
+  'notification.warning': 'Warning',
+  'notification.info': 'Info',
+  'notification.network.typeError': 'Network request exception',
+  'notification.typeError.description': 'Please try again later',
+};
Added +66 -0
diff --git a/core/i18n/locales/zh-CN.ts b/core/i18n/locales/zh-CN.ts
new file mode 100644
index 0000000..4bb6cbc
--- /dev/null
+++ b/core/i18n/locales/zh-CN.ts
@@ -0,0 +1,66 @@
+export default {
+  // 通用
+  'cube.notification.success': '操作成功',
+  'cube.notification.failed': '操作失败',
+  'cube.notification.warn': '操作异常',
+  'cube.cancel': '取消',
+  'cube.basicLayout.errorCode': '错误编码',
+  'cube.basicLayout.errorDetail': '点击此处了解更多',
+  'cube.basicLayout.viewMore': '查看更多',
+  'cube.view.pleaseLoginAgain': '您的登录已过期,请手动保存正在编辑的内容,避免数据丢失。',
+  'cube.view.logInAgain': '重新登录',
+
+  // 菜单
+  'menu.home': '首页',
+  'menu.dashboard': '仪表盘',
+  'menu.settings': '设置',
+  'menu.profile': '个人中心',
+
+  // 按钮
+  'button.submit': '提交',
+  'button.cancel': '取消',
+  'button.save': '保存',
+  'button.edit': '编辑',
+  'button.delete': '删除',
+  'button.add': '新增',
+  'button.search': '搜索',
+  'button.reset': '重置',
+  'button.back': '返回',
+  'button.confirm': '确认',
+
+  // 表单
+  'form.required': '必填项',
+  'form.invalid': '格式不正确',
+  'form.placeholder': '请输入{field}',
+  'form.select.placeholder': '请选择{field}',
+
+  // 认证
+  'auth.login': '登录',
+  'auth.logout': '退出登录',
+  'auth.username': '用户名',
+  'auth.password': '密码',
+  'auth.rememberMe': '记住我',
+  'auth.forgotPassword': '忘记密码',
+  'auth.login.error': '用户名或密码错误',
+  'auth.login.success': '登录成功',
+  'auth.login.expired': '您已下线',
+
+  // 权限
+  'permission.denied': '权限不足',
+  'permission.unauthorized': '未授权访问',
+
+  // 错误
+  'error.network': '网络错误,请检查您的网络连接',
+  'error.server': '服务器错误,请稍后重试',
+  'error.unknown': '未知错误',
+  'error.notFound': '页面不存在',
+
+  // 消息通知
+  'notification.message': '消息',
+  'notification.success': '成功',
+  'notification.error': '错误',
+  'notification.warning': '警告',
+  'notification.info': '提示',
+  'notification.network.typeError': '网络请求异常',
+  'notification.typeError.description': '请稍后重试',
+};
Added +11 -0
diff --git a/core/layouts/MainLayout/Breadcrumb/index.vue b/core/layouts/MainLayout/Breadcrumb/index.vue
new file mode 100644
index 0000000..c1c7113
--- /dev/null
+++ b/core/layouts/MainLayout/Breadcrumb/index.vue
@@ -0,0 +1,11 @@
+<script setup lang="ts">
+// 面包屑组件暂时为空
+</script>
+
+<template>
+  <div>
+    <!-- <h1>Breadcrumb</h1> -->
+  </div>
+</template>
+
+<style lang="scss" scoped></style>
Added +16 -0
diff --git a/core/layouts/MainLayout/Content/index.vue b/core/layouts/MainLayout/Content/index.vue
new file mode 100644
index 0000000..3bcf804
--- /dev/null
+++ b/core/layouts/MainLayout/Content/index.vue
@@ -0,0 +1,16 @@
+<script setup lang="ts">
+// 无需特殊逻辑
+</script>
+
+<template>
+  <div class="content">
+    <slot></slot>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.content {
+  height: 100%;
+  overflow: auto;
+}
+</style>
Added +146 -0
diff --git a/core/layouts/MainLayout/index.vue b/core/layouts/MainLayout/index.vue
new file mode 100644
index 0000000..6e0ea3f
--- /dev/null
+++ b/core/layouts/MainLayout/index.vue
@@ -0,0 +1,146 @@
+<script setup lang="ts">
+import { ref } from 'vue';
+import Navbar from './Navbar/index.vue';
+import Content from './Content/index.vue';
+import Sider from './Sider/index.vue';
+import { useUserStore } from 'cube-front/core/stores/user';
+
+const userStore = useUserStore();
+const collapsed = ref(false);
+
+const navbarHeight = 56;
+const menuWidth = collapsed.value ? 48 : 120;
+const paddingLeft = { paddingLeft: menuWidth + 'px' };
+const paddingTop = { paddingTop: navbarHeight + 'px' };
+
+const paddingStyle = { ...paddingLeft, ...paddingTop };
+</script>
+
+<template>
+  <div class="layout">
+    <div class="layoutNavbar">
+      <Navbar :currentUser="userStore.userInfo" :logout="userStore.logout" :collapsed="false" />
+    </div>
+    <div class="layoutMain">
+      <div class="layoutSidebar" :style="{ ...paddingTop, width: menuWidth + 'px' }">
+        <Sider />
+      </div>
+      <div class="layoutContent" :style="paddingStyle">
+        <div class="layoutContentWrapper">
+          <!-- <div v-if="breadcrumb.length > 0" class="layoutBreadcrumb">
+            <Breadcrumb></Breadcrumb>
+          </div> -->
+          <Content>
+            <slot></slot>
+          </Content>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+$nav-size-height: 56px;
+$layout-max-width: 1100px;
+
+.layout {
+  width: 100%;
+  height: 100%;
+  background-color: #e9f6fe;
+}
+
+.layoutNavbar {
+  position: fixed;
+  width: 100%;
+  min-width: $layout-max-width;
+  top: 0;
+  left: 0;
+  height: $nav-size-height;
+  z-index: 100;
+
+  &-hidden {
+    height: 0;
+  }
+}
+
+.layoutMain {
+  .layoutSidebar {
+    position: fixed;
+    height: 100%;
+    top: 0;
+    left: 0;
+    z-index: 99;
+    box-sizing: border-box;
+
+    ::-webkit-scrollbar {
+      width: 12px;
+      height: 4px;
+    }
+
+    ::-webkit-scrollbar-thumb {
+      border: 4px solid transparent;
+      background-clip: padding-box;
+      border-radius: 7px;
+      background-color: var(--color-text-4);
+    }
+
+    ::-webkit-scrollbar-thumb:hover {
+      background-color: var(--color-text-3);
+    }
+
+    &::after {
+      content: '';
+      display: block;
+      position: absolute;
+      top: 0;
+      right: -1px;
+      width: 1px;
+      height: 100%;
+      background-color: var(--color-border);
+    }
+
+    .collapseBtn {
+      height: 24px;
+      width: 24px;
+      background-color: var(--color-fill-1);
+      color: var(--color-text-3);
+      border-radius: 2px;
+      cursor: pointer;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      // 位置
+      position: absolute;
+      bottom: 12px;
+      right: 12px;
+
+      &:hover {
+        background-color: var(--color-fill-3);
+      }
+    }
+  }
+
+  .layoutContent {
+    background-color: #e9f6fe;
+    min-width: $layout-max-width;
+    min-height: 100vh;
+    height: 100vh;
+    transition: padding-left 0.2s;
+    box-sizing: border-box;
+    padding-right: 5px;
+    padding-bottom: 5px;
+  }
+
+  .layoutContentWrapper {
+    height: 100%;
+    background-color: #fff;
+    border-radius: 14px;
+    padding: 16px 6px 0 16px;
+    box-sizing: border-box;
+  }
+
+  .layoutBreadcrumb {
+    margin-bottom: 16px;
+  }
+}
+</style>
Added +73 -0
diff --git a/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenu.vue b/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenu.vue
new file mode 100644
index 0000000..8feb62d
--- /dev/null
+++ b/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenu.vue
@@ -0,0 +1,73 @@
+<template>
+  <div class="menu-cascader-second">
+    <div :class="['menu-cascader-second-title']" :style="{ width }">
+      {{ renderMenuTitle(menu) }}
+    </div>
+    <div class="menu-cascader-second-item-wrap" :style="{ width }">
+      <SecondCascaderMenuItem
+        v-for="leaf in menu.children || []"
+        :key="leaf.id"
+        :menu="leaf"
+        :active-menu="activeMenu"
+        :on-menu-click="onMenuClick || ((menu) => {})"
+      />
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { type TreeMenuItem } from 'cube-front/core/stores/menu';
+import { renderMenuTitle } from 'cube-front/core/utils/menuHelpers';
+import SecondCascaderMenuItem from './SecondCascaderMenuItem.vue';
+import { computed } from 'vue';
+
+/**
+ * 二级层叠菜单组件Props接口定义
+ */
+interface SecondCascaderMenuProps {
+  /** 菜单项 */
+  menu: TreeMenuItem;
+  /** 宽度 */
+  width: string;
+  /** 单行菜单项数量 */
+  menuItemColumns: number;
+  /** 激活菜单项 */
+  activeMenu?: TreeMenuItem;
+  /** 菜单点击回调函数 */
+  onMenuClick?: (menu: TreeMenuItem) => void;
+}
+
+const props = defineProps<SecondCascaderMenuProps>();
+
+const menuItemColumns = computed(() => props.menuItemColumns);
+</script>
+
+<style lang="scss" scoped>
+.menu-cascader-second {
+  padding-bottom: 16px;
+
+  .menu-cascader-second-title {
+    letter-spacing: 0;
+    height: 40px;
+    margin-left: 16px;
+    padding-left: 20px;
+    color: #333;
+    font-weight: 700;
+    border-bottom: 1px solid #f1f1f1;
+    font-size: 16px;
+    line-height: 40px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    word-break: break-all;
+    white-space: nowrap;
+  }
+
+  .menu-cascader-second-item-wrap {
+    margin-top: 8px;
+    display: grid;
+    grid-template-columns: repeat(v-bind(menuItemColumns), 1fr);
+    width: 100%;
+    gap: 0;
+  }
+}
+</style>
Added +72 -0
diff --git a/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenuItem.vue b/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenuItem.vue
new file mode 100644
index 0000000..31da6dc
--- /dev/null
+++ b/core/layouts/MainLayout/Navbar/CascaderMenu/components/SecondCascaderMenuItem.vue
@@ -0,0 +1,72 @@
+<template>
+  <div
+    :class="[
+      'menu-cascader-second-item',
+      {
+        'menu-cascader-second-item-active': isChildMenu(activeMenu, menu),
+      },
+    ]"
+    @click="handleMenuClick"
+  >
+    <TextOverflow :text="renderMenuTitle(menu)" tooltip-placement="right" class="menu-title-text" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { type TreeMenuItem } from 'cube-front/core/stores/menu';
+import { isChildMenu, renderMenuTitle } from 'cube-front/core/utils/menuHelpers';
+import TextOverflow from 'cube-front/core/components/TextOverflow.vue';
+
+/**
+ * 二级层叠菜单项组件Props接口定义
+ */
+interface SecondCascaderMenuItemProps {
+  /** 菜单项 */
+  menu: TreeMenuItem;
+  /** 激活菜单项 */
+  activeMenu?: TreeMenuItem;
+  /** 菜单点击回调函数 */
+  onMenuClick: (menu: TreeMenuItem) => void;
+}
+
+const props = defineProps<SecondCascaderMenuItemProps>();
+
+/**
+ * 处理菜单项点击
+ * @param event 鼠标事件
+ */
+const handleMenuClick = (event: MouseEvent) => {
+  event.preventDefault();
+  event.stopPropagation();
+  props.onMenuClick?.(props.menu);
+};
+</script>
+
+<style lang="scss" scoped>
+.menu-cascader-second-item {
+  font-size: 14px;
+  letter-spacing: 0;
+  width: 100%;
+  height: 36px;
+  margin-top: 0;
+  margin-bottom: 0;
+  margin-left: 16px;
+  padding-left: 20px;
+  padding-right: 10px;
+  color: #6a6a6a;
+  line-height: 36px;
+  cursor: pointer;
+
+  .menu-title-text {
+    width: 100%;
+    display: block;
+  }
+  box-sizing: border-box;
+
+  &-active,
+  &:hover {
+    color: var(--primary-color);
+    background: #e9f6fe;
+  }
+}
+</style>
Added +114 -0
diff --git a/core/layouts/MainLayout/Navbar/CascaderMenu/index.vue b/core/layouts/MainLayout/Navbar/CascaderMenu/index.vue
new file mode 100644
index 0000000..66456d9
--- /dev/null
+++ b/core/layouts/MainLayout/Navbar/CascaderMenu/index.vue
@@ -0,0 +1,114 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+import { type TreeMenuItem } from 'cube-front/core/stores/menu';
+import SecondCascaderMenu from './components/SecondCascaderMenu.vue';
+import { isChildMenu, hasChildren } from 'cube-front/core/utils/menuHelpers';
+
+/**
+ * 层叠菜单组件Props接口定义
+ */
+interface CascaderMenuProps {
+  /** 菜单项 */
+  menu: TreeMenuItem;
+  /** 激活菜单项 */
+  activeMenu?: TreeMenuItem;
+  /** 当前鼠标悬浮菜单项 */
+  currentMenu?: TreeMenuItem;
+  /** 菜单点击回调函数 */
+  onMenuClick: (menu: TreeMenuItem) => void;
+}
+
+const props = defineProps<CascaderMenuProps>();
+
+/** 一行显示菜单项数量 */
+const menuItemColumns = 3;
+/** 子菜单宽度 */
+const subMenuWidth = 225;
+/** 层叠菜单宽度 */
+const subWidth = `${subMenuWidth * menuItemColumns}px`;
+/** 导航栏宽度 */
+const navWidth = '200px';
+/** 是否折叠 */
+const collapsed = false;
+
+/**
+ * 计算处理后的子菜单列表
+ * 将没有子菜单的项目归类到一起,有子菜单的单独列出
+ */
+const children = computed(() => {
+  /**  无子菜单的菜单项  */
+  const noChildrenList = props.menu.children?.filter((item) => !hasChildren(item));
+
+  /** 有子菜单的菜单项 */
+  const childrenList: TreeMenuItem[] =
+    noChildrenList && noChildrenList.length > 0
+      ? [
+          {
+            ...props.menu,
+            children: noChildrenList,
+          },
+        ]
+      : [];
+
+  props.menu.children?.forEach((item) => {
+    if (noChildrenList?.includes(item)) return;
+    childrenList.push(item);
+  });
+
+  return childrenList;
+});
+</script>
+
+<template>
+  <div
+    :class="[
+      'menu-cascader',
+      {
+        'menu-cascader-current': currentMenu && isChildMenu(currentMenu, menu),
+      },
+    ]"
+    :style="{
+      maxWidth: collapsed ? 'calc(100vw - 50px)' : `calc(100vw - ${navWidth})`,
+    }"
+  >
+    <SecondCascaderMenu
+      v-for="second in children"
+      :key="second.id"
+      :menu="second"
+      :width="subWidth"
+      :menuItemColumns="menuItemColumns"
+      :active-menu="activeMenu"
+      :on-menu-click="onMenuClick"
+    />
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.menu-cascader {
+  position: relative;
+  box-sizing: border-box;
+  display: none;
+  height: 100%;
+  width: 675px;
+  max-width: calc(100vw - 200px);
+  overflow: hidden auto;
+  padding: 32px 16px 0;
+  z-index: 1100;
+  background: #fff;
+  border-left: 1px solid #f0f0f0;
+
+  /* 完全隐藏滚动条,但保留滚动功能 */
+  scrollbar-width: none;
+  -ms-overflow-style: none;
+
+  &::-webkit-scrollbar {
+    width: 0;
+    height: 0;
+    display: none;
+  }
+}
+
+.menu-cascader-current {
+  display: block;
+}
+</style>
Added +139 -0
diff --git a/core/layouts/MainLayout/Navbar/index.vue b/core/layouts/MainLayout/Navbar/index.vue
new file mode 100644
index 0000000..37f955d
--- /dev/null
+++ b/core/layouts/MainLayout/Navbar/index.vue
@@ -0,0 +1,139 @@
+<script setup lang="ts">
+import { storeToRefs } from 'pinia';
+import Menu from './Menu/index.vue';
+import { type UserInfo } from 'cube-front/core/stores/user';
+import { useMenuStore } from 'cube-front/core/stores/menu';
+import { getConfig } from 'cube-front/core/configure';
+
+interface NavbarProps {
+  currentUser?: Partial<UserInfo>;
+  logout: () => void;
+  collapsed: boolean;
+}
+
+defineProps<NavbarProps>();
+
+const menuStore = useMenuStore();
+const baseConfig = getConfig().base;
+
+// 使用storeToRefs保持解构属性的响应性
+const { treeMenus: mainMenus } = storeToRefs(menuStore);
+
+const title = baseConfig.title;
+</script>
+
+<template>
+  <div class="navbar">
+    <div class="left">
+      <div class="logo">
+        <!-- <Login /> -->
+        <div class="logoName">{{ title }}</div>
+      </div>
+    </div>
+
+    <div class="right">
+      <!-- 顶部导航信息 -->
+      <div class="menu-wrapper">
+        <Menu :tabPanes="mainMenus" />
+      </div>
+
+      <!-- 顶部导航操作栏 -->
+      <div class="actions-wrapper">
+        <!-- 头像 -->
+        <div class="user-info">
+          <span class="userName">{{ currentUser?.realName }}</span>
+        </div>
+        <div class="actionItem" @click="logout">退出</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+$left-width: 200px;
+
+.navbar {
+  display: flex;
+  box-sizing: border-box;
+  background-color: #e9f6fe;
+  height: 56px; /* 固定导航栏高度为56px */
+  position: relative;
+
+  .left {
+    display: flex;
+    align-items: center;
+    width: 200px;
+    height: 56px; /* 确保左侧内容也是56px高 */
+
+    .logo {
+      display: flex;
+      align-items: center;
+      width: $left-width;
+      padding-left: 20px;
+      box-sizing: border-box;
+    }
+
+    .logoName {
+      font-weight: 500;
+      font-size: 20px;
+      margin-left: 10px;
+      font-family:
+        Alimama ShuHeiTi,
+        Alimama ShuHeiTi;
+      font-weight: bold;
+      font-size: 20px;
+      color: #1d2129;
+      line-height: 28px;
+      text-align: left;
+      font-style: normal;
+      text-transform: none;
+    }
+  }
+
+  .right {
+    display: flex;
+    justify-content: space-between;
+    list-style: none;
+    padding-right: 20px;
+    width: calc(100% - #{$left-width});
+    height: 56px; /* 确保右侧区域高度也是56px */
+
+    .menu-wrapper {
+      flex: 1;
+      overflow: hidden; /* 确保菜单不会超出其容器 */
+      margin-right: 20px; /* 与操作区域保持间距 */
+    }
+
+    .actions-wrapper {
+      display: flex;
+      align-items: center;
+      justify-content: flex-end;
+      white-space: nowrap; /* 防止文本换行 */
+      min-width: 150px; /* 确保操作区域有最小宽度 */
+      padding-left: 15px; /* 与菜单保持一定距离 */
+      z-index: 15; /* 确保显示在菜单之上 */
+      background-color: #e9f6fe; /* 与导航栏背景色一致 */
+
+      .user-info {
+        display: flex;
+        align-items: center;
+      }
+
+      .userName {
+        margin-left: 5px;
+        font-weight: 500;
+      }
+
+      .actionItem {
+        cursor: pointer;
+        margin-left: 15px;
+        color: #1890ff;
+
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+  }
+}
+</style>
Added +434 -0
diff --git a/core/layouts/MainLayout/Navbar/Menu/index.vue b/core/layouts/MainLayout/Navbar/Menu/index.vue
new file mode 100644
index 0000000..6156ac7
--- /dev/null
+++ b/core/layouts/MainLayout/Navbar/Menu/index.vue
@@ -0,0 +1,434 @@
+<script setup lang="tsx">
+import { computed, ref, onMounted, nextTick, watch } from 'vue';
+import { useRouter } from 'vue-router';
+import { type TreeMenuItem, useMenuStore } from 'cube-front/core/stores/menu';
+import CascaderMenu from '../CascaderMenu/index.vue';
+import { ElScrollbar } from 'element-plus';
+import { hasChildren } from 'cube-front/core/utils/menuHelpers';
+import { openMenuTab } from 'cube-front/core/utils/menuTab';
+
+/**
+ * Menu组件Props接口定义
+ */
+interface MenuProps {
+  /** 菜单项数组 */
+  tabPanes?: Array<TreeMenuItem>;
+}
+
+const props = defineProps<MenuProps>();
+const cascaderMenuWidth = 724;
+const clientX = ref<number>(0);
+const menuCascaderHeight = ref<number>(500);
+const router = useRouter();
+const menuStore = useMenuStore();
+const activeMenu = computed(() => menuStore.activeMenu);
+
+/** 当前鼠标悬浮位置菜单,层叠菜单组件需要 */
+const currentMenu = ref<TreeMenuItem | undefined>();
+
+// 滚动相关引用和状态
+const scrollbarRef = ref<InstanceType<typeof ElScrollbar> | null>(null);
+const menuRef = ref<HTMLElement | null>(null);
+const showLeftArrow = ref(false);
+const showRightArrow = ref(false);
+const scrollPosition = ref(0);
+const scrollWidth = ref(0);
+const containerWidth = ref(0);
+
+/**
+ * 更新箭头显示状态
+ */
+const updateArrowVisibility = () => {
+  if (!menuRef.value || !scrollbarRef.value) return;
+
+  const wrapperElement = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
+  if (!wrapperElement) return;
+
+  scrollPosition.value = wrapperElement.scrollLeft;
+  scrollWidth.value = menuRef.value.scrollWidth;
+  containerWidth.value = wrapperElement.clientWidth;
+
+  // 显示/隐藏左右箭头
+  showLeftArrow.value = scrollPosition.value > 0;
+
+  // 添加2px的容差值,解决右侧边缘判断精度问题
+  const scrollRightTolerance = 2; // 2像素的容差值
+  showRightArrow.value =
+    scrollWidth.value > containerWidth.value &&
+    scrollPosition.value < scrollWidth.value - containerWidth.value - scrollRightTolerance;
+};
+
+/**
+ * 向左滚动
+ */
+const scrollLeft = () => {
+  if (!scrollbarRef.value?.$el) return;
+  const wrapperElement = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
+  if (!wrapperElement) return;
+
+  wrapperElement.scrollLeft -= 200; // 滚动200px
+  updateArrowVisibility();
+};
+
+/**
+ * 向右滚动
+ */
+const scrollRight = () => {
+  if (!scrollbarRef.value?.$el) return;
+  const wrapperElement = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
+  if (!wrapperElement) return;
+
+  wrapperElement.scrollLeft += 200; // 滚动200px
+  updateArrowVisibility();
+};
+
+/**
+ * 处理鼠标滚轮事件
+ */
+const handleWheel = (e: WheelEvent) => {
+  if (!scrollbarRef.value?.$el) return;
+  const wrapperElement = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
+  if (!wrapperElement) return;
+
+  // 阻止默认的垂直滚动
+  e.preventDefault();
+
+  // 水平滚动距离
+  const delta = e.deltaY || e.deltaX;
+  wrapperElement.scrollLeft += delta;
+  updateArrowVisibility();
+};
+
+// 组件挂载后初始化
+onMounted(async () => {
+  await nextTick();
+
+  // 初始化箭头状态
+  updateArrowVisibility();
+
+  // 添加滚动事件监听
+  window.addEventListener('resize', updateArrowVisibility);
+  if (scrollbarRef.value?.$el) {
+    const wrapperElement = scrollbarRef.value.$el.querySelector('.el-scrollbar__wrap');
+    if (wrapperElement) {
+      wrapperElement.addEventListener('scroll', updateArrowVisibility);
+      // 添加鼠标滚轮事件
+      scrollbarRef.value.$el.addEventListener('wheel', handleWheel, { passive: false });
+    }
+  }
+});
+
+// 监听菜单项变化,更新箭头态
+watch(
+  () => props.tabPanes,
+  async () => {
+    await nextTick();
+    updateArrowVisibility();
+  },
+  { deep: true },
+);
+
+/**
+ * 计算是否显示层叠菜单
+ */
+const showCascaderMenu = computed(() => {
+  // 如果是顶级菜单,但是没有子菜单,不显示
+  if (currentMenu.value && !currentMenu.value.parentMenu) {
+    return hasChildren(currentMenu.value);
+  }
+
+  // 子菜单,显示
+  return currentMenu.value !== undefined;
+});
+
+/**
+ * 检查菜单项是否应该高亮显示
+ * @param menu 要检查的菜单项
+ * @returns 是否应该高亮显示
+ */
+const isMenuActive = (menu: TreeMenuItem) => {
+  // 直接判断顶级活动菜单路径匹配
+  if (menuStore.topLevelActiveMenu?.path === menu.path) {
+    return true;
+  }
+
+  // 通过ID匹配顶级活动菜单
+  if (menuStore.topLevelActiveMenu?.id === menu.id) {
+    return true;
+  }
+
+  // 判断当前激活菜单是否是该菜单的子菜单
+  if (activeMenu.value && isChildOf(activeMenu.value, menu)) {
+    return true;
+  }
+
+  // 当前路由路径匹配菜单路径
+  if (router.currentRoute.value.path === menu.path) {
+    return true;
+  }
+
+  return false;
+};
+
+/**
+ * 检查一个菜单是否是另一个菜单的子菜单(包括多级子菜单)
+ * @param child 可能的子菜单
+ * @param parent 可能的父菜单
+ * @returns 是否是子菜单关系
+ */
+const isChildOf = (child: TreeMenuItem, parent: TreeMenuItem) => {
+  if (!child || !parent) return false;
+  if (child.id === parent.id) return true;
+
+  // 向上遍历查找父菜单
+  let currentParent = child.parentMenu;
+  while (currentParent) {
+    if (currentParent.id === parent.id) return true;
+    currentParent = currentParent.parentMenu;
+  }
+
+  return false;
+};
+
+/**
+ * 鼠标悬浮在菜单处处理
+ * @param event 鼠标事件
+ * @param menuItem 菜单项
+ */
+const handleMouseEnter = (event: MouseEvent, menuItem: TreeMenuItem) => {
+  event.preventDefault();
+  event.stopPropagation();
+
+  const target = event.target as HTMLElement;
+
+  /** 层叠菜单展示的左边距 */
+  let x = event.clientX - (target?.clientWidth || 0);
+
+  // 菜单宽度大于屏幕宽度时,计算偏移量
+  if (x + cascaderMenuWidth > window.innerWidth) {
+    x = window.innerWidth - cascaderMenuWidth;
+  }
+
+  clientX.value = x;
+  currentMenu.value = menuItem;
+};
+
+/**
+ * 鼠标离开菜单项处理
+ */
+const handleMouseLeave = (event: MouseEvent) => {
+  event.preventDefault();
+  event.stopPropagation();
+
+  currentMenu.value = undefined;
+};
+
+/**
+ * 遮罩触发处理
+ */
+const handleMaskTrigger = (e: MouseEvent) => {
+  // 只有当鼠标移动到遮罩区域,而不是导航栏或级联菜单时才隐藏
+  const target = e.target as HTMLElement;
+  const relatedTarget = e.relatedTarget as HTMLElement;
+
+  //  如果鼠标从菜单区域移出到遮罩区域,才隐藏菜单
+  if (
+    target &&
+    target.classList.contains('side-mask') &&
+    !relatedTarget?.closest('.menu-cascader-parent') &&
+    !relatedTarget?.closest('.menu-container')
+  ) {
+    currentMenu.value = undefined;
+  }
+};
+
+/**
+ * 菜单点击处理
+ * @param menu 菜单项
+ */
+const onMenuClick = (menu: TreeMenuItem) => {
+  openMenuTab({
+    url: menu.path,
+    title: menu.name,
+  });
+
+  menuStore.setActiveMenu(menu);
+
+  currentMenu.value = undefined;
+};
+</script>
+
+<template>
+  <div class="menu-container" @mouseleave="handleMouseLeave">
+    <!-- 左箭头按钮 -->
+    <div class="scroll-arrow left-arrow" @click="scrollLeft" v-show="showLeftArrow">
+      <i class="el-icon-arrow-left">&lt;</i>
+    </div>
+
+    <ElScrollbar class="menu-scrollbar" ref="scrollbarRef">
+      <div class="menu" ref="menuRef">
+        <li v-for="(tabPane, index) in props.tabPanes" :key="index">
+          <div
+            class="menu-item"
+            :class="{ 'menu-item-active': isMenuActive(tabPane) }"
+            @mouseenter="(e) => handleMouseEnter(e, tabPane)"
+          >
+            {{ tabPane.title || tabPane.name }}
+          </div>
+        </li>
+      </div>
+    </ElScrollbar>
+
+    <!-- 右箭头按钮 -->
+    <div class="scroll-arrow right-arrow" @click="scrollRight" v-show="showRightArrow">
+      <i class="el-icon-arrow-right">&gt;</i>
+    </div>
+    <!-- 只渲染当前鼠标悬停的一级菜单的级联菜单 -->
+    <div
+      v-if="currentMenu"
+      :style="{ left: `${clientX}px`, height: `${menuCascaderHeight}px` }"
+      class="menu-cascader-parent"
+    >
+      <CascaderMenu
+        v-show="showCascaderMenu"
+        :menu="currentMenu"
+        :currentMenu="currentMenu"
+        :activeMenu="activeMenu"
+        :onMenuClick="onMenuClick"
+      />
+    </div>
+    <div
+      v-if="showCascaderMenu"
+      class="side-mask"
+      @mouseenter="(e) => handleMaskTrigger(e)"
+      @mousemove="(e) => handleMaskTrigger(e)"
+    ></div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.menu-container {
+  position: relative;
+  width: 100%;
+  height: 56px;
+  display: flex;
+  align-items: center;
+  overflow: hidden; /* 确保内容不会溢出 */
+}
+
+.scroll-arrow {
+  position: absolute;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 24px;
+  height: 56px;
+  background-color: rgba(233, 246, 254, 0.9);
+  color: #1890ff;
+  cursor: pointer;
+  z-index: 20; /* 提高层级确保显示在其他元素之上 */
+
+  &:hover {
+    background-color: rgba(233, 246, 254, 1);
+  }
+
+  &.left-arrow {
+    left: 0;
+    box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
+  }
+
+  &.right-arrow {
+    right: 0;
+    box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.menu-scrollbar {
+  flex: 1; /* 使用flex布局占据所有可用空间 */
+  width: 100%;
+  height: 63px;
+  overflow: hidden; /* 确保不会出现额外的滚动条 */
+
+  :deep(.el-scrollbar__wrap) {
+    overflow-x: auto;
+    overflow-y: hidden;
+
+    /* 完全隐藏滚动条,但保留滚动功能 */
+    scrollbar-width: none;
+    -ms-overflow-style: none;
+
+    &::-webkit-scrollbar {
+      width: 0;
+      height: 0;
+      display: none;
+    }
+  }
+
+  /* 覆盖Element Plus默认滚动条样式 */
+  :deep(.el-scrollbar__bar) {
+    display: none !important;
+  }
+}
+
+.menu {
+  display: flex;
+  height: 56px;
+  margin: 0;
+  padding: 0 10px;
+  list-style: none;
+  white-space: nowrap; /* 防止菜单项换行 */
+  min-width: max-content; /* 确保内容不会被压缩 */
+  box-sizing: border-box;
+  width: fit-content; /* 适应内容宽度 */
+
+  .menu-item {
+    display: flex;
+    align-items: center;
+    height: 100%;
+    margin: auto 32px auto 5px;
+    cursor: pointer;
+    font-weight: 600;
+    color: #6d6f72;
+    padding: 0 5px;
+    transition: color 0.2s ease;
+
+    &-active {
+      color: #1890ff;
+      font-weight: 600;
+      position: relative;
+
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        width: 100%;
+        height: 2px;
+        background-color: #1890ff;
+      }
+    }
+
+    &:hover {
+      color: #1890ff;
+    }
+  }
+}
+
+.menu-cascader-parent {
+  position: fixed;
+  min-height: 60vh;
+  max-height: 80vh;
+  overflow: auto;
+  top: 56px;
+  z-index: 1100;
+}
+
+.side-mask {
+  position: fixed;
+  inset: 56px 0 0;
+  z-index: 1080;
+  background-color: #000;
+  cursor: pointer;
+  opacity: 0.1;
+}
+</style>
Added +124 -0
diff --git a/core/layouts/MainLayout/Sider/index.vue b/core/layouts/MainLayout/Sider/index.vue
new file mode 100644
index 0000000..fedb8b3
--- /dev/null
+++ b/core/layouts/MainLayout/Sider/index.vue
@@ -0,0 +1,124 @@
+<script setup lang="ts">
+import { computed } from 'vue';
+import { openMenuTab } from '../../../utils/menuTab';
+import { useMenuStore, type TreeMenuItem } from '../../../stores/menu';
+import { renderMenuTitle } from 'cube-front/core/utils/menuHelpers';
+import TextOverflow from '../../../components/TextOverflow.vue';
+
+const menuStore = useMenuStore();
+
+const parentMenu = computed(() => {
+  return menuStore.activeMenu?.parentMenu;
+});
+
+/** 点击菜单处理 */
+const handleMenuClick = (menu: TreeMenuItem) => {
+  openMenuTab({
+    url: menu.path,
+    title: menu.name,
+  });
+
+  menuStore.setActiveMenu(menu);
+};
+
+function isMenuActive(menu: TreeMenuItem) {
+  return menu.path === menuStore.activeMenu?.path;
+}
+</script>
+
+<template>
+  <div class="sider">
+    <!-- 菜单容器 -->
+    <div class="menuContainer">
+      <!-- 一级菜单名,带图标 -->
+      <div class="title">
+        <Icon v-if="parentMenu?.icon" :type="parentMenu.icon" />
+        <span>{{ parentMenu?.title }}</span>
+      </div>
+      <!-- 二级菜单名 -->
+      <div
+        v-for="item in parentMenu?.children"
+        :key="item.name"
+        :class="['menuName', isMenuActive(item) && 'active']"
+        @click="() => handleMenuClick(item)"
+      >
+        <TextOverflow
+          :text="renderMenuTitle(item)"
+          tooltip-placement="right"
+          class="menu-title-text"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.sider {
+  width: 100%;
+  height: 100%;
+  background-color: #e9f6fe;
+
+  .menuContainer {
+    height: 100%;
+    overflow-y: auto;
+
+    /* 完全隐藏滚动条 */
+    scrollbar-width: none;
+    -ms-overflow-style: none;
+
+    &::-webkit-scrollbar {
+      width: 0;
+      height: 0;
+      display: none;
+    }
+
+    /* 悬浮时可使用滚动,但保持滚动条隐藏 */
+    &:hover {
+      overflow-y: auto;
+    }
+    .title {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-weight: 600;
+      font-size: 14px;
+      color: #86909c;
+      margin-bottom: 16px;
+
+      span {
+        margin-left: 4px;
+      }
+    }
+
+    .menuName {
+      height: 32px;
+      font-weight: 600;
+      font-size: 14px;
+      // color: #1D2129;
+      color: #6d6f72;
+      line-height: 20px;
+      margin: 0 8px 4px 8px;
+      padding: 6px 0 6px 20px;
+      text-align: left;
+      user-select: none;
+      cursor: pointer;
+
+      .menu-title-text {
+        /* 继承菜单项样式 */
+        width: 100%;
+      }
+
+      &:hover {
+        color: #007fff;
+      }
+    }
+
+    .active {
+      background: rgba(255, 255, 255, 0.7);
+      border-radius: 8px;
+      color: #007fff;
+      box-shadow: 0px 2px 8px 0px rgba(92, 173, 255, 0.1);
+    }
+  }
+}
+</style>
Added +97 -0
diff --git a/core/layouts/RootLayout.vue b/core/layouts/RootLayout.vue
new file mode 100644
index 0000000..5288c48
--- /dev/null
+++ b/core/layouts/RootLayout.vue
@@ -0,0 +1,97 @@
+<script setup lang="ts">
+import { onBeforeMount, onMounted, watch, computed } from 'vue';
+import { useRouter, useRoute } from 'vue-router';
+// import NotFound from '../pages/404.vue'
+// import Loading from '../pages/loading.vue'
+import { useUserStore } from '../stores/user';
+import { useMenuStore } from '../stores/menu';
+import MainLayout from './MainLayout/index.vue';
+import { getUrlHashToken } from '../utils/token';
+
+const router = useRouter();
+const route = useRoute();
+const userStore = useUserStore();
+const menuStore = useMenuStore();
+console.log('routes', router.getRoutes());
+
+// 使用计算属性获取响应式的 meta 对象
+const meta = computed(() => route.meta);
+
+function checkLogin() {
+  const token = getUrlHashToken();
+
+  // 如果token存在,说明UrlHashToken存在,重新路由,确保UrlHashToken消失,否则导航完之后UrlHashToken会存在
+  // 同时路由必须是匹配上了才跳转,否则初始路由默认“/”,就会跳转到“/”而丢失原本路由
+  if (token && route.matched.length > 0) {
+    router.push({ path: route.path, query: route.query });
+  }
+}
+
+// 监听整个路由对象变化
+watch(
+  route,
+  (newRoute, oldRoute) => {
+    console.log('路由变化', {
+      newPath: newRoute.path,
+      oldPath: oldRoute?.path,
+      newMeta: newRoute.meta,
+      oldMeta: oldRoute?.meta,
+    });
+    // 在这里可以添加路由变化时需要执行的逻辑
+  },
+  { deep: true },
+);
+
+onBeforeMount(() => {
+  // 当刷新页面时,导航守卫before还没执行,这里先执行了,因此这里先检查登录情况
+  checkLogin();
+});
+
+onMounted(async () => {
+  try {
+    await userStore.fetchUserInfoAsync();
+    await menuStore.fetchMenuAsync();
+  } catch (e) {
+    console.error(e);
+  }
+});
+</script>
+
+<template>
+  <!-- 如果是登录页面,直接返回 -->
+  <template v-if="route.path === '/login'">
+    <slot />
+  </template>
+
+  <!-- 无布局 -->
+  <template v-else-if="meta.layout === false">
+    <slot />
+  </template>
+
+  <!-- 布局 -->
+  <template v-else>
+    <MainLayout>
+      <!-- 组件缓存 -->
+      <KeepAlive v-if="meta.keepAlive">
+        <Transition
+          v-if="meta.transition"
+          v-bind="typeof meta.transition === 'object' ? meta.transition : {}"
+        >
+          <slot />
+        </Transition>
+        <slot v-else />
+      </KeepAlive>
+
+      <!-- 无缓存但有过渡 -->
+      <Transition
+        v-else-if="meta.transition"
+        v-bind="typeof meta.transition === 'object' ? meta.transition : {}"
+      >
+        <slot />
+      </Transition>
+
+      <!-- 无缓存无过渡 -->
+      <slot v-else />
+    </MainLayout>
+  </template>
+</template>
Added +21 -0
diff --git a/core/main.ts b/core/main.ts
new file mode 100644
index 0000000..afe4bd1
--- /dev/null
+++ b/core/main.ts
@@ -0,0 +1,21 @@
+import App from './App.vue';
+import { createApp } from 'vue';
+import { createPinia } from 'pinia';
+import ElementPlus from 'element-plus';
+import 'element-plus/dist/index.css';
+import router from './router';
+import i18n from './i18n';
+import './global.css';
+
+const app = createApp(App);
+const pinia = createPinia();
+
+app.use(router);
+app.use(pinia);
+app.use(i18n); // 添加 i18n 插件
+app.use(ElementPlus);
+app.mount('#app');
+
+// 全局暴露路由和状态管理实例,方便调试和外部访问
+window.router = router;
+window.store = pinia;
Added +138 -0
diff --git a/core/microAppRouter.ts b/core/microAppRouter.ts
new file mode 100644
index 0000000..3f04fae
--- /dev/null
+++ b/core/microAppRouter.ts
@@ -0,0 +1,138 @@
+/**
+ * 微前端路由注册中心
+ * 负责各子应用路由的注册、匹配和导航
+ */
+
+import type { Router } from 'vue-router';
+import type { ConfigRoute } from './typings';
+import defaultRoutes from './routes';
+import appNames from 'virtual:cube-front-app-names';
+
+// 定义应用信息类型
+interface AppInfo {
+  name: string;
+  prefix?: string;
+  routes: ConfigRoute[];
+}
+
+// 存储所有已注册的应用及其路由信息
+const appRegistry = new Map<string, AppInfo>();
+
+// 存储路由前缀与应用的映射
+const prefixMap = new Map<string, string>();
+
+/**
+ * 注册应用路由
+ * @param {string} appName - 应用名称
+ * @param {Array} routes - 应用路由配置
+ * @param {Function?} loadApp - 加载应用的方法
+ * @param {string?} appPrefix - 应用路由前缀
+ */
+export function registerAppRoutes(
+  appName: string,
+  router: Router,
+  routes: ConfigRoute[],
+  appPrefix?: string,
+): void {
+  if (!appName || !routes) {
+    console.error('注册应用路由失败:缺少必要参数');
+    return;
+  }
+
+  // 注册应用信息
+  appRegistry.set(appName, {
+    name: appName,
+    routes,
+    prefix: appPrefix,
+  });
+
+  // 如果有前缀,建立前缀与应用的映射
+  if (appPrefix) {
+    prefixMap.set(appPrefix, appName);
+  }
+
+  routes.forEach((route) => {
+    router.addRoute(route);
+  });
+
+  console.log(`应用 ${appName} 路由注册成功`);
+}
+
+/**
+ * 匹配路由所属的应用
+ * @param {string} path - 当前路径
+ * @returns {Object|null} - 匹配的应用信息
+ */
+export function matchAppByRoute(path: string): AppInfo | null | undefined {
+  if (!path) return null;
+
+  // 获取路径的第一级
+  const firstSegment = path.split('/')[1] || '';
+
+  // 1. 优先匹配前缀
+  const appName = prefixMap.get(firstSegment);
+  if (appName) {
+    return appRegistry.get(appName);
+  }
+
+  // 2. 遍历所有应用,查找匹配的路由
+  for (const [_, appInfo] of appRegistry) {
+    // 检查应用的路由是否匹配当前路径
+    const matchedRoute = appInfo.routes.find((route) => {
+      // 简单路由匹配逻辑,实际可能需要更复杂的匹配算法
+      const routePath = route.path;
+      return path === routePath || path.startsWith(`${routePath}/`);
+    });
+
+    if (matchedRoute) {
+      return appInfo;
+    }
+  }
+
+  return null;
+}
+
+/**
+ * 获取所有已注册的应用信息
+ * @returns {Array} - 应用信息列表
+ */
+export function getRegisteredApps(): AppInfo[] {
+  return Array.from(appRegistry.values());
+}
+
+/** 注册微前端应用,并注册路由 */
+export function initAppRoutes(router: Router) {
+  // 注册微应用的路由,不再注册默认路由,避免重复注册
+  // 原因:默认路由已经在router实例创建时通过routes参数注册
+
+  const modules = import.meta.glob('/apps/*/src/main.ts', { eager: true });
+
+  Object.keys(modules).forEach((modulePath) => {
+    // try{
+    const appName = modulePath.split('/')[2];
+    const appModule = modules[modulePath] as { routes: ConfigRoute[] };
+
+    console.log('加载应用模块成功', appName, appModule);
+
+    const appRoutes = appModule.routes;
+    registerAppRoutes(appName, router, appRoutes);
+    // }
+    // catch ((error: any) => {
+    //   console.error(`Failed to load app ${appName}:`, error)
+    // })
+  });
+
+  // // 增加路由守卫
+  // router.beforeEach((to, from, next) => {
+  //   const matchedApp = matchAppByRoute(to.path);
+  //   if (matchedApp) {
+  //     // 找到匹配的应用,进行路由跳转
+  //     next();
+  //   } else {
+  //     // 没有匹配的应用,进行默认路由跳转
+  //     next();
+  //   }
+  //   console.log('路由守卫', to, from, next);
+  //   console.log('当前路由', to.path);
+  // });
+}
Added +12 -0
diff --git a/core/pages/Loading.vue b/core/pages/Loading.vue
new file mode 100644
index 0000000..856b49f
--- /dev/null
+++ b/core/pages/Loading.vue
@@ -0,0 +1,12 @@
+<script lang="tsx">
+import { defineComponent } from 'vue'
+
+export default defineComponent({
+  name: 'PageLoading',
+  setup() {
+    return () => (
+      <div>loading...</div>
+    )
+  }
+})
+</script>
Added +5 -0
diff --git a/core/pages/PageHome.vue b/core/pages/PageHome.vue
new file mode 100644
index 0000000..3e870cb
--- /dev/null
+++ b/core/pages/PageHome.vue
@@ -0,0 +1,5 @@
+<script lang="ts" setup></script>
+
+<template>
+  <div>主页</div>
+</template>
Added +27 -0
diff --git a/core/pages/PageLogin.vue b/core/pages/PageLogin.vue
new file mode 100644
index 0000000..9c302fc
--- /dev/null
+++ b/core/pages/PageLogin.vue
@@ -0,0 +1,27 @@
+<script lang="ts" setup>
+/**
+ * 处理OAuth认证重定向的登录组件。
+ *
+ * 该组件会自动将用户重定向到配置的OAuth登录URL。
+ * 它从路由查询参数中提取重定向URL(默认为'/'),
+ * 将其与当前源结合,并将其作为参数传递给OAuth端点。
+ *
+ * 由于立即重定向到配置中定义的外部认证服务,该组件不渲染任何内容。
+ *
+ * @returns {null} - 由于立即重定向,组件不渲染任何内容
+ */
+import { useRoute } from 'vue-router';
+import { getConfig } from '../configure';
+debugger;
+const route = useRoute();
+const config = getConfig();
+const oauthUrl = config.auth.oauthUrl;
+const baseURL = config.request.baseURL;
+console.log('login', route);
+const redirect = `${location.origin}${route.query.redirect || '/'}`;
+location.href = `${baseURL}${oauthUrl}${encodeURIComponent(redirect)}`;
+</script>
+
+<template>
+  <div>Loading...</div>
+</template>
Added +56 -0
diff --git a/core/pages/PageNotFound.vue b/core/pages/PageNotFound.vue
new file mode 100644
index 0000000..38ec467
--- /dev/null
+++ b/core/pages/PageNotFound.vue
@@ -0,0 +1,56 @@
+<template>
+  <div class="page-not-found">
+    <h1>404</h1>
+    <h2>Page Not Found</h2>
+    <p>The page you are looking for does not exist or has been moved.</p>
+    <router-link to="/" class="home-link">Go to Home Page</router-link>
+  </div>
+</template>
+
+<script lang="ts">
+export default {
+  name: 'PageNotFound',
+}
+</script>
+
+<style scoped>
+.page-not-found {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100vh;
+  text-align: center;
+  padding: 0 20px;
+}
+
+h1 {
+  font-size: 6rem;
+  margin-bottom: 0;
+  color: #e74c3c;
+}
+
+h2 {
+  font-size: 2rem;
+  margin-top: 0;
+  margin-bottom: 20px;
+}
+
+p {
+  margin-bottom: 30px;
+  color: #666;
+}
+
+.home-link {
+  padding: 10px 20px;
+  background-color: #3498db;
+  color: white;
+  text-decoration: none;
+  border-radius: 4px;
+  transition: background-color 0.3s;
+}
+
+.home-link:hover {
+  background-color: #2980b9;
+}
+</style>
Added +62 -0
diff --git a/core/pages/PageUnauthorized.vue b/core/pages/PageUnauthorized.vue
new file mode 100644
index 0000000..46fc9f8
--- /dev/null
+++ b/core/pages/PageUnauthorized.vue
@@ -0,0 +1,62 @@
+<template>
+  <div class="unauthorized-container">
+    <el-row justify="center" align="middle" class="unauthorized-content">
+      <el-col :span="24" class="img-col">
+        <img
+          class="unauthorized-img"
+          src="https://cdn.jsdelivr.net/gh/element-plus/element-plus@latest/docs/public/404.png"
+          alt="未授权"
+        />
+      </el-col>
+      <el-col :span="24" class="text-col">
+        <div class="unauthorized-text">
+          抱歉,您未登录或身份认证已失效,请点击下方按钮重新登录!
+        </div>
+      </el-col>
+      <el-col :span="24" class="btn-col">
+        <el-button type="primary" size="large" @click="goLogin">立即跳转</el-button>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ElButton, ElRow, ElCol } from 'element-plus'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+function goLogin() {
+  router.replace({ path: '/login' })
+}
+</script>
+
+<style scoped>
+.unauthorized-container {
+  min-height: 100vh;
+  background: #f7f8fa;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.unauthorized-content {
+  width: 100%;
+  text-align: center;
+  flex-direction: column;
+}
+.img-col {
+  margin-bottom: 32px;
+}
+.unauthorized-img {
+  max-width: 400px;
+  width: 100%;
+  margin: 0 auto;
+}
+.text-col {
+  font-size: 28px;
+  color: #333;
+  margin-bottom: 32px;
+}
+.btn-col {
+  margin-top: 12px;
+}
+</style>
Added +98 -0
diff --git a/core/plugin/index.ts b/core/plugin/index.ts
new file mode 100644
index 0000000..8561c5f
--- /dev/null
+++ b/core/plugin/index.ts
@@ -0,0 +1,98 @@
+import path from 'path';
+import { type PluginOption, type ResolvedConfig } from 'vite';
+import { type ConfigRoute } from '../typings.d';
+import fs from 'fs';
+
+export default function vitePluginCubeFront() {
+  const virtualModuleNamePrefix = 'cube';
+  const virtualModuleIdPrefix = 'virtual:cube-front-';
+  const resolvedVirtualModuleIdPrefix = '\0' + virtualModuleIdPrefix;
+
+  // 虚拟模块名称常量
+
+  const appName = 'app';
+  const appNamesName = 'app-names';
+
+  /** 配置信息 */
+  let config: ResolvedConfig & { routes: ConfigRoute[]; };
+  /** 包含路由信息的字符串代码 */
+  let routesStr: string | undefined;
+
+  const viteCubeApp: PluginOption = {
+    name: `vite:${virtualModuleNamePrefix}-${appName}`,
+    enforce: 'post',
+    config: (_config, _m) => {
+      return {
+        // resolve: {
+        //   alias: {
+        //     'cube-front': path.resolve(__dirname, './'),
+        //   },
+        // },
+      };
+    },
+    configResolved: (_config) => {
+      // console.log('configResolved--------------------', config)
+    },
+    resolveId(id: string) {
+      if (id === virtualModuleIdPrefix + appName) {
+        return resolvedVirtualModuleIdPrefix + appName;
+      }
+    },
+    load(id: string) {
+      if (id === resolvedVirtualModuleIdPrefix + appName) {
+        return `
+        export const msg = "from virtual module"
+        export { default as App } from 'cube-front/core/App.vue'
+        `;
+      }
+    },
+    transform(code: string, _id: string) {
+      return code;
+    },
+    transformIndexHtml(html: string) {
+      return html;
+    },
+  };
+
+  // 新增应用配置插件
+  const viteCubeAppNames: PluginOption = {
+    name: `vite:${virtualModuleNamePrefix}-${appNamesName}`,
+    enforce: 'post',
+    configResolved: (cfg) => {
+      config = cfg as ResolvedConfig & { routes: ConfigRoute[]; };
+    },
+    resolveId(id: string) {
+      if (id === virtualModuleIdPrefix + appNamesName) {
+        return resolvedVirtualModuleIdPrefix + appNamesName;
+      }
+    },
+    load(id: string) {
+      if (id === resolvedVirtualModuleIdPrefix + appNamesName) {
+        try {
+          // 读取microAppConfig.json文件
+          const configPath = path.resolve(config.root, 'configs/microAppConfig.json');
+          const microAppConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
+
+          // 构建应用路径数组
+          const appPaths = microAppConfig.map((app: { name: string; }) => {
+            return app.name;
+          });
+
+          // 导出应用配置数组
+          return `
+export const appNames = ${JSON.stringify(appPaths)}
+export default ${JSON.stringify(appPaths)}
+`;
+        } catch (error) {
+          console.error('Failed to load microAppConfig.json', error);
+          return `
+export const appNames = []
+export default []
+`;
+        }
+      }
+    },
+  };
+
+  return [viteCubeApp, viteCubeAppNames];
+}
Added +102 -0
diff --git a/core/router/index.ts b/core/router/index.ts
new file mode 100644
index 0000000..dd3b674
--- /dev/null
+++ b/core/router/index.ts
@@ -0,0 +1,102 @@
+import { createRouter, createWebHistory, type Router } from 'vue-router';
+import routes from '../routes';
+import { initAppRoutes } from '../microAppRouter';
+import { useUserStore } from '../stores/user';
+import { useMenuStore } from '../stores/menu';
+import { getAccessToken } from '../utils/token';
+
+// 创建路由实例
+const router: Router = createRouter({
+  history: createWebHistory(),
+  routes,
+});
+
+// 初始化微前端应用路由(不包括默认路由,因为已在路由实例创建时注册)
+// 修改原因:避免默认路由的重复注册
+initAppRoutes(router);
+
+// 先从URL中获取token
+import { getUrlHashToken } from '../utils/token';
+
+// 全局导航守卫
+router.beforeEach(async (to, from, next) => {
+  // 先检查URL中是否有token并处理
+  const hashToken = getUrlHashToken();
+
+  // 如果URL中有hash token,重新路由到相同页面,保持原查询参数
+  if (hashToken) {
+    // 保留原查询参数,确保导航结束后hash消失
+    window.location.hash = '';
+    return next({ path: to.path, query: to.query });
+  }
+
+  // 获取localStorage中的token
+  const hasToken = !!getAccessToken();
+
+  // 获取store
+  const userStore = useUserStore();
+  const menuStore = useMenuStore();
+
+  // 判断路由是否需要认证(根据路由元信息)
+  // 使用可选链和空值合并运算符,如果meta或auth未定义,默认需要认证
+  const requireAuth = to.meta?.auth ?? true;
+
+  // 如果已经在登录页且要去的也是登录页,直接放行
+  if (from.path === '/login' && to.path === '/login') {
+    return next();
+  }
+
+  // 如果有token
+  if (hasToken) {
+    // 如果去登录页,直接跳转到首页
+    if (to.path === '/login') {
+      if (to.query.redirect) {
+        next({ path: to.query.redirect as string });
+      } else {
+        next({ path: '/' });
+      }
+    } else {
+      // 如果没有用户信息,获取用户信息
+      if (!userStore.hasUserInfo) {
+        try {
+          await userStore.fetchUserInfoAsync();
+        } catch (error) {
+          // 获取用户信息失败,可能是token无效,跳转到登录页
+          console.error('获取用户信息失败:', error);
+          next({ path: '/login' });
+          return;
+        }
+      }
+
+      // 如果没有菜单信息,获取菜单信息
+      if (!menuStore.hasMenus) {
+        try {
+          await menuStore.fetchMenuAsync();
+        } catch (error) {
+          console.error('获取菜单信息失败:', error);
+          // 获取菜单失败但不影响导航,继续放行
+        }
+      }
+
+      // 更新当前活动菜单
+      if (menuStore.hasMenus) {
+        menuStore.setActiveMenuByPath(to.path);
+      }
+
+      // 继续导航
+      next();
+    }
+  } else {
+    // 无token的情况
+
+    // 如果路由不需要认证,直接放行
+    if (!requireAuth) {
+      next();
+    } else {
+      // 需要认证的路由,重定向到登录页
+      next({ path: '/login', query: { redirect: to.fullPath } });
+    }
+  }
+});
+
+export default router;
Added +34 -0
diff --git a/core/routes/index.ts b/core/routes/index.ts
new file mode 100644
index 0000000..ed69435
--- /dev/null
+++ b/core/routes/index.ts
@@ -0,0 +1,34 @@
+import { type ConfigRoute } from '../typings.d';
+
+const routes: ConfigRoute[] = [
+  {
+    path: '/',
+    name: 'home',
+    meta: {
+      title: '首页',
+    },
+    component: () => import('../pages/PageHome.vue'),
+  },
+  {
+    path: '/login',
+    name: 'login',
+    meta: {
+      title: '登录',
+      auth: false,
+      layout: false,
+    },
+    component: () => import('../pages/PageLogin.vue'),
+  },
+  {
+    path: '/unauthorized',
+    name: 'unauthorized',
+    meta: {
+      title: '未授权',
+      layout: false,
+      auth: false,
+    },
+    component: () => import('../pages/PageUnauthorized.vue'),
+  },
+];
+
+export default routes;
Added +207 -0
diff --git a/core/stores/menu.ts b/core/stores/menu.ts
new file mode 100644
index 0000000..dbd9746
--- /dev/null
+++ b/core/stores/menu.ts
@@ -0,0 +1,207 @@
+import { defineStore } from 'pinia';
+import { getConfig } from 'cube-front/core/configure';
+import { getDataByKey, isPromise } from '../utils/common';
+import { type AxiosRequestConfig } from 'axios';
+import request from '../utils/request';
+
+export interface FlatMenuItem {
+  id: string;
+  name: string;
+  path: string;
+  title?: string;
+  icon?: string;
+  sort?: number;
+  parentId?: string | null;
+  active?: boolean;
+}
+
+export interface TreeMenuItem {
+  id: string;
+  name: string;
+  path: string;
+  title?: string;
+  icon?: string;
+  sort?: number;
+  parentId?: string | null;
+  parentMenu?: TreeMenuItem;
+  children?: TreeMenuItem[];
+  active?: boolean;
+}
+
+/** 平铺菜单转换成树形菜单 */
+export function convertFlatMenuToTreeMenu(flatMenu: FlatMenuItem[]): TreeMenuItem[] {
+  const menuMap: { [id: string]: TreeMenuItem } = {};
+
+  // Create a map of menu items using their IDs as keys
+  flatMenu.forEach((item) => {
+    menuMap[item.id] = item;
+  });
+
+  const treeMenu: TreeMenuItem[] = [];
+
+  // Iterate over the flat menu items and build the tree menu
+  flatMenu.forEach((item) => {
+    const menuItem = menuMap[item.id];
+
+    if (item.parentId) {
+      const parentItem = menuMap[item.parentId];
+      if (parentItem) {
+        parentItem.children = parentItem.children || [];
+        parentItem.children.push(menuItem);
+        menuItem.parentMenu = parentItem;
+      }
+    } else {
+      treeMenu.push(menuItem);
+    }
+  });
+
+  return treeMenu;
+}
+
+/** 树形菜单转换成平铺菜单 */
+export function convertTreeMenuToFlatMenu(
+  treeMenuList: TreeMenuItem[],
+  parentMenu?: TreeMenuItem,
+): FlatMenuItem[] {
+  const flatMenu: FlatMenuItem[] = [];
+
+  const flatten = (menuList: TreeMenuItem[], parentMenu2?: TreeMenuItem) => {
+    menuList.forEach((item) => {
+      item.parentMenu = parentMenu2;
+      flatMenu.push(item);
+      if (item.children) {
+        flatten(item.children, item);
+      }
+    });
+  };
+
+  flatten(treeMenuList, parentMenu);
+
+  return flatMenu;
+}
+
+/** 将菜单数据按照配置的字段名称进行转换,支持平铺数据和树形数据 */
+const covertMenu = (list: never[]) => {
+  const menuConfig = getConfig().menu;
+  const newList = list.map((item) => {
+    const newItem: TreeMenuItem = {
+      ...(item as TreeMenuItem),
+      id: item[menuConfig.idField],
+      parentId: item[menuConfig.parentField],
+      name: item[menuConfig.nameField],
+      path: item[menuConfig.pathField],
+      title: item[menuConfig.titleField],
+      icon: item[menuConfig.iconField],
+      sort: item[menuConfig.sortField],
+      children: item[menuConfig.childrenField]
+        ? covertMenu(item[menuConfig.childrenField])
+        : undefined,
+    };
+
+    return newItem;
+  });
+
+  return newList;
+};
+
+const state: {
+  /** 平铺菜单  */
+  flatMenus: Array<FlatMenuItem> | undefined;
+  /** 树形菜单 */
+  treeMenus: Array<TreeMenuItem> | undefined;
+  activeMenu: TreeMenuItem | undefined;
+  loading: boolean;
+} = {
+  flatMenus: undefined,
+  treeMenus: undefined,
+  activeMenu: undefined,
+  loading: false,
+};
+
+const getTopLevelMenu = (menu: TreeMenuItem) => {
+  if (menu.parentMenu) {
+    return getTopLevelMenu(menu.parentMenu);
+  }
+  return menu;
+};
+
+export const useMenuStore = defineStore('menu', {
+  state: () => state,
+  getters: {
+    hasMenus: (state) =>
+      state.flatMenus &&
+      state.treeMenus &&
+      state.flatMenus.length > 0 &&
+      state.treeMenus.length > 0,
+    topLevelActiveMenu: (state) => {
+      return state.activeMenu && getTopLevelMenu(state.activeMenu);
+    },
+  },
+  actions: {
+    setFlatMenus(data: Array<FlatMenuItem>) {
+      this.flatMenus = data;
+      this.treeMenus = convertFlatMenuToTreeMenu(data);
+    },
+    setTreeMenus(data: Array<TreeMenuItem>) {
+      this.treeMenus = data;
+      this.flatMenus = convertTreeMenuToFlatMenu(data);
+    },
+    setActiveMenu(menu: TreeMenuItem) {
+      this.activeMenu = menu;
+    },
+    setActiveMenuByPath(path: string) {
+      const activeMenu = this.flatMenus?.find((item) => item.path === path);
+      this.setActiveMenu(activeMenu as TreeMenuItem);
+    },
+    async fetchMenuAsync() {
+      if (this.loading) return;
+      this.loading = true;
+      // 如果没有菜单信息,则获取菜单信息
+      if (!this.hasMenus) {
+        const menuConfig = getConfig().menu;
+        const getMenuAxiosConfig = menuConfig.getMenuAxiosConfig;
+
+        // 处理不同类型的 getMenuAxiosConfig
+        const processMenuRequestAsync = async (config: AxiosRequestConfig) => {
+          try {
+            const res = await request(config);
+            // 增加延时,避免下面的赋值触发更新再次请求
+            setTimeout(() => {
+              this.loading = false;
+            }, 1000);
+
+            const data = getDataByKey(res as never, menuConfig.dataKey);
+
+            if (menuConfig.isMenuTree) {
+              this.setTreeMenus(covertMenu(data as never[]));
+            } else {
+              this.setFlatMenus(covertMenu(data as never[]));
+            }
+            this.setActiveMenuByPath(window.location.pathname);
+          } catch (error) {
+            // 如果报错,增加延时,避免下面的赋值触发更新再次请求
+            setTimeout(() => {
+              this.loading = false;
+            }, 1000);
+          }
+        };
+
+        // 根据类型执行不同操作
+        if (typeof getMenuAxiosConfig === 'function') {
+          const config = getMenuAxiosConfig();
+          if (config instanceof Promise) {
+            // 处理返回 Promise 类型的配置
+            await processMenuRequestAsync(await config);
+          } else {
+            await processMenuRequestAsync(config);
+          }
+        } else {
+          // 处理直接配置对象
+          await processMenuRequestAsync(getMenuAxiosConfig);
+        }
+      } else {
+        this.loading = false;
+      }
+    },
+  },
+});
Added +113 -0
diff --git a/core/stores/user.ts b/core/stores/user.ts
new file mode 100644
index 0000000..f891b8c
--- /dev/null
+++ b/core/stores/user.ts
@@ -0,0 +1,113 @@
+import { defineStore } from 'pinia';
+import { getConfig } from 'cube-front/core/configure';
+import axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios';
+import request from '../utils/request';
+import { removeAccessToken } from '../utils/token';
+
+/** 用户信息 */
+export interface UserInfo {
+  id: number;
+  name: string;
+  realName: string;
+  email: string;
+  avatar: string;
+  phone: string;
+  role: string;
+  token: string;
+  roles: string[];
+}
+
+const state: {
+  userInfo: Partial<UserInfo> | undefined;
+  loading: boolean;
+} = {
+  userInfo: undefined,
+  loading: false,
+};
+
+export const useUserStore = defineStore('user', {
+  state: () => state,
+  getters: {
+    hasUserInfo: (state) => !!state.userInfo,
+  },
+  actions: {
+    setUserInfo(info: Partial<UserInfo>) {
+      this.userInfo = { ...this.userInfo, ...info };
+    },
+    /**
+     * 用户登出
+     * 先调用登出接口,再清除用户状态和token,并重定向到登录页
+     */
+    async logout() {
+      try {
+        // 获取认证配置
+        const authConfig = getConfig().auth;
+        // 默认登出请求配置
+        let axiosConfig: AxiosRequestConfig;
+
+        // 如果有专门的登出配置,则使用该配置
+        if (authConfig.logoutAxiosConfig) {
+          if (typeof authConfig.logoutAxiosConfig === 'function') {
+            const config = authConfig.logoutAxiosConfig();
+            if (config instanceof Promise) {
+              axiosConfig = await authConfig.logoutAxiosConfig();
+            } else {
+              axiosConfig = config;
+            }
+          } else {
+            axiosConfig = authConfig.logoutAxiosConfig;
+          }
+
+          // 调用登出接口
+          await request(axiosConfig);
+        }
+      } catch (error) {
+        console.error('登出接口调用失败:', error);
+      } finally {
+        // 无论接口调用成功与否,都执行本地清理操作
+
+        // 清除用户信息
+        this.userInfo = undefined;
+
+        // 清除token
+        removeAccessToken();
+
+        // 重定向到登录页
+        window.location.href = '/login';
+      }
+    },
+    async fetchUserInfoAsync() {
+      if (this.loading) return;
+      this.loading = true;
+      // 如果没有用户信息,则获取获取用户信息、菜单信息
+      if (!this.hasUserInfo) {
+        const userConfig = getConfig().user;
+        const getUserInfoAxiosConfig = userConfig.getUserInfoAxiosConfig;
+        let axiosConfig: AxiosRequestConfig;
+
+        if (typeof getUserInfoAxiosConfig === 'function') {
+          const config = getUserInfoAxiosConfig();
+          if (config instanceof Promise) {
+            axiosConfig = await getUserInfoAxiosConfig();
+          } else {
+            axiosConfig = config;
+          }
+        } else {
+          axiosConfig = getUserInfoAxiosConfig;
+        }
+
+        try {
+          const response: AxiosResponse<Partial<UserInfo>> = await request<
+            Partial<UserInfo>,
+            AxiosResponse<Partial<UserInfo>>
+          >(axiosConfig);
+          this.setUserInfo(response.data);
+        } catch (error) {
+          console.error('Failed to fetch user info:', error);
+        } finally {
+          this.loading = false;
+        }
+      }
+    },
+  },
+});
Added +24 -0
diff --git a/core/types/notification.d.ts b/core/types/notification.d.ts
new file mode 100644
index 0000000..9564b12
--- /dev/null
+++ b/core/types/notification.d.ts
@@ -0,0 +1,24 @@
+/**
+ * 通知参数类型定义
+ */
+export interface NotificationParams {
+  /**
+   * 通知消息内容
+   */
+  message: string;
+
+  /**
+   * 通知标题(可选)
+   */
+  title?: string;
+
+  /**
+   * 显示时间,单位毫秒(可选)
+   */
+  duration?: number;
+}
+
+/**
+ * 通知类型
+ */
+export type NotificationType = 'success' | 'warning' | 'info' | 'error';
Added +46 -0
diff --git a/core/typings.d.ts b/core/typings.d.ts
new file mode 100644
index 0000000..34b35bf
--- /dev/null
+++ b/core/typings.d.ts
@@ -0,0 +1,46 @@
+import { type TransitionProps } from 'vue'
+import { type RouteComponent, type RouteRecordRaw } from 'vue-router'
+
+interface RouteMeta {
+  /** 是否需要权限
+   * @default true
+   */
+  auth?: boolean
+  /** 图标 */
+  icon?: string
+  /** 布局,不设置的话使用默认布局,设置了false 则不使用布局
+   * @default true 使用默认布局
+   */
+  layout?: string | boolean
+  /** 是否缓存页面
+   * @default false
+   */
+  keepAlive?: boolean
+  /** 标题 */
+  title?: string
+  /** 切换路由是否需要过渡
+   * @default false
+   */
+  transition?: boolean | TransitionProps
+}
+
+type BaseRoute = RouteRecordRaw & {
+  /** 路由元信息 */
+  meta?: RouteMeta
+}
+
+/** 配置路由,组件为 string */
+export type ConfigRoute = BaseRoute
+// & {
+/** 组件绝对路径地址
+ * @example
+ * import path from 'node:path'
+ * path.resolve(__dirname, 'src/pages/login/index.tsx')
+ */
+// component: string
+// }
+
+/** 组件路由,组件为 解析后模块 */
+export type ComponentRoute = BaseRoute & {
+  component: RouteComponent | (() => Promise<RouteComponent>)
+}
Added +136 -0
diff --git a/core/utils/common.ts b/core/utils/common.ts
new file mode 100644
index 0000000..4279c02
--- /dev/null
+++ b/core/utils/common.ts
@@ -0,0 +1,136 @@
+import notification from '../components/Notification.ts';
+import { useTimestamp } from '@vueuse/core';
+
+/**
+ * 生成指定长度的随机十六进制字符串
+ */
+function getRandomHex(length: number): string {
+  const bytes = new Uint8Array(Math.ceil(length / 2));
+  window.crypto.getRandomValues(bytes);
+  return Array.from(bytes)
+    .map((byte) => byte.toString(16).padStart(2, '0'))
+    .join('')
+    .substring(0, length);
+}
+
+export function getResponse(
+  response:
+    | {
+        failed: boolean;
+        detailsMessage: string;
+        message: string;
+        description: unknown;
+        code: unknown;
+        requestMessage: string | number | boolean | null | undefined;
+        content: unknown;
+        type: unknown;
+      }
+    | null
+    | undefined,
+  errorCallback?: (arg0: unknown) => void,
+) {
+  if (response && response.failed === true) {
+    if (errorCallback) {
+      errorCallback(response);
+    } else {
+      const msg = {
+        message: response.detailsMessage || response.message || '操作失败',
+      };
+      switch (response.type) {
+        case 'info':
+          notification.info(msg);
+          break;
+        case 'warn':
+          notification.warning(msg);
+          break;
+        case 'error':
+        default:
+          notification.error(msg);
+          break;
+      }
+    }
+  } else {
+    return response;
+  }
+}
+
+/**
+ * 根据给定的键路径从对象中获取数据
+ * @param obj 源数据对象
+ * @param key 键路径,可以是简单字符串或点分隔的路径,如 "data.items.list"
+ * @param defaultValue 如果找不到值时返回的默认值
+ * @returns 找到的值或默认值
+ */
+export function getDataByKey<T = unknown>(
+  obj: object,
+  key: string,
+  defaultValue?: T,
+): T | undefined | null {
+  if (obj === null || obj === undefined) {
+    return defaultValue;
+  }
+
+  // 支持点分隔的键路径
+  const keys = key.split('.');
+  let result: unknown | Record<string, unknown | Record<string, unknown>> = obj;
+
+  for (const k of keys) {
+    if (result === null || result === undefined) {
+      return defaultValue;
+    }
+
+    if (typeof result !== 'object') {
+      return defaultValue;
+    } else {
+      // 使用类型断言确保TypeScript知道result是一个可索引的对象
+      const resultObj = result as Record<string, unknown>;
+      if (!(k in resultObj)) {
+        return defaultValue;
+      } else {
+        result = resultObj[k];
+      }
+    }
+  }
+
+  return result === undefined || result === null ? defaultValue : (result as T);
+}
+
+/**
+ * 处理响应数据
+ * @param item 原始数据项
+ * @param dataKey 数据键路径
+ * @returns 处理后的对象数组
+ */
+export function generateResponseData(item: unknown, dataKey?: string): object[] {
+  if (item) {
+    if (Array.isArray(item)) {
+      return item;
+    }
+    if (typeof item === 'object') {
+      if (dataKey) {
+        const result = getDataByKey<unknown>(item as Record<string, unknown>, dataKey);
+        if (result === undefined || result === null) {
+          return [item];
+        }
+        if (Array.isArray(result)) {
+          return result;
+        }
+        if (typeof result === 'object') {
+          return [result as object];
+        }
+      } else {
+        return [item];
+      }
+    }
+  }
+  return [];
+}
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function isPromise(obj: any): boolean {
+  return (
+    !!obj &&
+    (typeof obj === 'object' || typeof obj === 'function') &&
+    typeof obj.then === 'function'
+  );
+}
Added +52 -0
diff --git a/core/utils/menuHelpers.ts b/core/utils/menuHelpers.ts
new file mode 100644
index 0000000..d81c358
--- /dev/null
+++ b/core/utils/menuHelpers.ts
@@ -0,0 +1,52 @@
+import { type TreeMenuItem } from 'cube-front/core/stores/menu';
+
+/**
+ * 判断 childMenu 的祖先是否是parentMenu
+ * @param childMenu 子菜单
+ * @param parentMenu 父菜单
+ * @returns 是否为子菜单
+ */
+export function isChildMenu(childMenu?: TreeMenuItem, parentMenu?: TreeMenuItem): boolean {
+  if (!childMenu || !parentMenu) {
+    return false;
+  }
+
+  if (parentMenu.id === childMenu.id) {
+    return true;
+  } else if (childMenu.parentMenu) {
+    return isChildMenu(childMenu.parentMenu, parentMenu);
+  }
+
+  return false;
+}
+
+/**
+ * 获取菜单的标题
+ * @param menu 菜单项
+ * @returns 菜单标题
+ */
+export function renderMenuTitle(menu: TreeMenuItem): string {
+  const lastPathSegment = menu.path.split('/').filter(Boolean).pop() || '...';
+  return menu.title || menu.name || lastPathSegment;
+}
+
+/**
+ * 检查菜单是否有子菜单
+ * @param menu 菜单项
+ * @returns 是否有子菜单
+ */
+export function hasChildren(menu?: TreeMenuItem): boolean {
+  return Boolean(menu?.children && menu.children.length > 0);
+}
+
+/**
+ * 获取顶层菜单
+ * @param menu 菜单项
+ * @returns 顶层菜单
+ */
+export function getTopLevelMenu(menu: TreeMenuItem): TreeMenuItem {
+  if (menu.parentMenu) {
+    return getTopLevelMenu(menu.parentMenu);
+  }
+  return menu;
+}
Added +21 -0
diff --git a/core/utils/menuTab.ts b/core/utils/menuTab.ts
new file mode 100644
index 0000000..8a43e26
--- /dev/null
+++ b/core/utils/menuTab.ts
@@ -0,0 +1,21 @@
+import { gotoPage } from './router';
+
+/**
+ * 打开菜单对应的标签页
+ * @param options 打开标签页的配置项
+ * @param options.url 标签页对应的URL路径
+ * @param options.title 标签页的标题(可选)
+ */
+export function openMenuTab(options: { url: string; title?: string }): void {
+  const { url, title } = options;
+
+  // 使用路由跳转到指定的页面
+  gotoPage(url);
+
+  // 可以在这里添加标签页的其他处理逻辑
+  // 例如保存打开的标签页到本地存储,或者更新标签页状态
+  console.log(`打开标签页: ${title || url}`);
+
+  // 如果项目中有标签页管理的状态,可以在这里更新
+  // 例如: store.dispatch('tabs/addTab', { url, title });
+}
Added +33 -0
diff --git a/core/utils/object.ts b/core/utils/object.ts
new file mode 100644
index 0000000..48b8edd
--- /dev/null
+++ b/core/utils/object.ts
@@ -0,0 +1,33 @@
+/**
+ * 深度合并对象
+ * @param target 目标对象
+ * @param source 源对象
+ * @returns 合并后的对象
+ */
+export function deepMerge<T extends object = object>(target: T, source: any): T {
+  const result = { ...target };
+
+  if (isObject(target) && isObject(source)) {
+    for (const key in source) {
+      if (isObject(source[key])) {
+        if (!result[key]) {
+          Object.assign(result, { [key]: {} });
+        }
+        result[key] = deepMerge(result[key], source[key]);
+      } else {
+        Object.assign(result, { [key]: source[key] });
+      }
+    }
+  }
+
+  return result;
+}
+
+/**
+ * 判断是否为对象
+ * @param item 待检查项
+ * @returns 是否为对象
+ */
+export function isObject(item: any): boolean {
+  return item && typeof item === 'object' && !Array.isArray(item);
+}
\ No newline at end of file
Added +399 -0
diff --git a/core/utils/request.ts b/core/utils/request.ts
new file mode 100644
index 0000000..c4c1111
--- /dev/null
+++ b/core/utils/request.ts
@@ -0,0 +1,399 @@
+/**
+ * HTTP请求工具
+ * 封装axios,处理请求拦截、响应拦截、错误处理和401授权问题
+ */
+import axios, {
+  type AxiosError,
+  type AxiosInterceptorManager,
+  type AxiosRequestConfig,
+  type AxiosRequestHeaders,
+  type AxiosResponse,
+  type InternalAxiosRequestConfig,
+} from 'axios';
+import queryString from 'query-string';
+import { getSession, removeAllCookie, setSession } from './storage';
+import { getAccessToken, removeAccessToken } from './token';
+import { getConfig } from '../configure';
+import { gotoPage } from './router';
+import { getResponse } from './common';
+import notification from '../components/Notification';
+
+import { ElMessageBox } from 'element-plus';
+import { intl } from '../i18n';
+
+/**
+ * Modal对话框工具
+ * 封装Element Plus的ElMessageBox组件
+ */
+const Modal = {
+  /**
+   * 打开模态对话框
+   * @param {Object} options - 对话框配置选项
+   * @returns {Promise} - 返回对话框实例
+   */
+  open: (options: {
+    title?: string;
+    children?: string;
+    cancelText?: string;
+    okText?: string;
+    onOk?: () => void;
+    onCancel?: () => void;
+    afterClose?: () => void;
+    key?: string;
+  }) => {
+    return ElMessageBox({
+      title: options.title || '提示',
+      message: options.children || '',
+      showCancelButton: !!options.cancelText,
+      confirmButtonText: options.okText || '确定',
+      cancelButtonText: options.cancelText || '取消',
+      type: 'warning',
+      callback: (action: 'confirm' | 'cancel' | 'close') => {
+        if (action === 'confirm' && typeof options.onOk === 'function') {
+          options.onOk();
+        } else if (action === 'cancel' && typeof options.onCancel === 'function') {
+          options.onCancel();
+        }
+
+        if (typeof options.afterClose === 'function') {
+          options.afterClose();
+        }
+      },
+    });
+  },
+  close: () => {
+    ElMessageBox.close();
+  },
+  /**
+   * 更新当前打开的对话框
+   * @param {Object} props - 要更新的属性
+   */
+  update: (props: Record<string, unknown>) => {
+    // Element Plus的对话框不直接支持更新,这里提供一个兼容接口
+    console.log('Modal.update called with props:', props);
+  },
+};
+
+// 常量定义
+const BASE_PATH = '';
+const INDEX_ROUTE_PATH = '/';
+
+/**
+ * 重定向到登录页
+ * @param {Object} options - 配置选项
+ * @param {string} options.loginPageUrl - 可选的登录页URL
+ */
+export function redirectToLogin({ loginPageUrl }: { loginPageUrl?: string } = {}) {
+  removeAccessToken();
+  removeAllCookie();
+
+  const {
+    request: { baseURL: API_HOST },
+    auth: { oauthUrl },
+  } = getConfig();
+  const LOGIN_URL = loginPageUrl || `${API_HOST}${oauthUrl}`;
+
+  const sessionData = getSession('redirectUrl');
+  let cacheLocation = sessionData;
+  if (!cacheLocation) {
+    cacheLocation = encodeURIComponent(`${window.location.origin}${BASE_PATH || '/'}`);
+  }
+
+  // const modifyReloginLocation = getConfig().auth?.modifyReloginLocation;
+  // if (modifyReloginLocation) {
+  //   cacheLocation = modifyReloginLocation(cacheLocation, {
+  //     BASE_PATH: BASE_PATH || '/',
+  //   });
+  // }
+
+  // 构建重定向URL
+  const redirectParams = getSession('templateParams') || '';
+  if (LOGIN_URL.includes('?')) {
+    window.location.href = `${LOGIN_URL}&redirect_uri=${cacheLocation}${redirectParams}`;
+  } else {
+    window.location.href = `${LOGIN_URL}?redirect_uri=${cacheLocation}${redirectParams}`;
+  }
+}
+
+// 创建带token的axios实例
+const cubeAxios = axios.create();
+
+// 创建不带token的axios实例
+const notWithTokenAxios = axios.create();
+notWithTokenAxios.interceptors.request.use((config) => {
+  const {
+    request: { baseURL: API_HOST },
+  } = getConfig();
+  let { url = '' } = config;
+  if (url.indexOf('://') === -1 && !url.startsWith('/_api')) {
+    url = `${API_HOST}${url}`;
+  }
+  return {
+    ...config,
+    url,
+  };
+});
+
+// 401错误标志,防止重复处理401
+let isErrorFlag = false;
+
+/**
+ * 鉴权拦截处理
+ * @param {number} status - HTTP状态码
+ * @param {InternalAxiosRequestConfig} config - 请求配置
+ * @returns {boolean} - 是否继续处理响应
+ */
+function authIntercept(status: number, config: InternalAxiosRequestConfig) {
+  if (status === 401) {
+    // 避免重复处理401
+    if (isErrorFlag) {
+      return false;
+    }
+
+    /**
+     * 设置重定向URL到会话存储
+     */
+    const setRedirectUrl = () => {
+      let _cacheLocation = window.location.toString().replace('/unauthorized', '');
+      // @ts-expect-error 全局窗口对象可能包含routerBase属性
+      const basePath = (window.routerBase || BASE_PATH)?.replace(/\/$/, '');
+      const url1 = new URL(_cacheLocation);
+      let p = url1.pathname;
+      if (basePath && p.startsWith(basePath)) {
+        p = p.replace(basePath, '');
+      }
+      if (p === '/') {
+        url1.pathname = `${basePath}${INDEX_ROUTE_PATH}`;
+        _cacheLocation = url1.toString();
+      }
+      const cacheLocation = encodeURIComponent(_cacheLocation);
+      const searchParams = queryString.parse(window.location.search)?.template;
+      const templateParams = searchParams ? `&template=${searchParams}` : '';
+
+      setSession('templateParams', templateParams);
+      setSession('redirectUrl', cacheLocation);
+    };
+
+    isErrorFlag = true;
+    const { url = '' } = config;
+    const {
+      user: { getUserInfoAxiosConfig },
+    } = getConfig();
+
+    let AUTH_SELF_URL = '/Admin/User/Info';
+    if (typeof getUserInfoAxiosConfig === 'function') {
+      const config = getUserInfoAxiosConfig();
+      if (!(config instanceof Promise)) {
+        AUTH_SELF_URL = config.url || AUTH_SELF_URL;
+      }
+    } else {
+      AUTH_SELF_URL = getUserInfoAxiosConfig.url || AUTH_SELF_URL;
+    }
+
+    const isSelf401 = url.includes(AUTH_SELF_URL);
+
+    if (isSelf401) {
+      setRedirectUrl();
+      redirectToLogin();
+      return false;
+    }
+
+    /**
+     * 跳转到未授权页面
+     * @param {string} pageUrl - 未授权页面路径
+     */
+    const redirectToUnauthorized = (pageUrl = '/unauthorized') => {
+      const language = intl.getLocale()?.replace('-', '_');
+
+      // 登录后需要跳回的界面,放到session中
+      if (!window.location.pathname.startsWith(`${BASE_PATH}${pageUrl.replace(/^\//, '')}`)) {
+        setRedirectUrl();
+      }
+
+      // token失效,跳转到token失效页面
+      gotoPage(`${pageUrl}?language=${language}${getSession('templateParams') || ''}`);
+    };
+
+    // 当位于/unauthorized页面时,不处理401
+    const isInUnauthorizedPage = window.location.toString().indexOf('/unauthorized') !== -1;
+    if (isInUnauthorizedPage) {
+      return false;
+    }
+
+    setTimeout(() => {
+      redirectToUnauthorized();
+    }, 100);
+  }
+  return true;
+}
+
+/**
+ * 响应错误处理
+ * @param {Object} error - 错误对象
+ * @returns {Promise} - 处理后的Promise
+ */
+function handleResponseError(error: AxiosError) {
+  // 移除debugger语句,优化错误日志记录
+  console.error('Request error:', error.message, error.config?.url);
+
+  const { response, config, code } = error;
+
+  // 如果response为空,直接返回
+  if (!response) {
+    if (code === 'ERR_NETWORK') {
+      notification.error({ message: intl.get('notification.network.typeError').d('网络请求异常') });
+      return;
+    }
+    return Promise.reject(error);
+  }
+
+  const envConfig = getConfig();
+
+  // 判断是否鉴权问题
+  if (response && response.status && !authIntercept(response.status, response.config)) {
+    return Promise.reject(false);
+  }
+
+  // 状态204当做成功处理
+  if (response?.status === 204) {
+    return undefined;
+  }
+
+  // 响应拦截,请求时设置
+  const responseIntercept = envConfig.request.responseIntercept;
+  if (responseIntercept && typeof responseIntercept === 'function') {
+    responseIntercept(error);
+  }
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  const data = response?.data as any;
+  const errorObj = {
+    type: undefined,
+    message: error.message,
+    // @ts-expect-error 包含描述的可能的字段
+    description: `${data?.description || data?.content || response?.requestMessage || ''}`,
+  };
+
+  if (data && data.code > 200) {
+    errorObj.message =
+      data.message || data.code || data.type || intl.get('cube.notification.failed').d('操作失败');
+    // errorObj.type === data.type;
+  }
+
+  if (data && data.detailsMessage) {
+    errorObj.description += `\n ${data.detailsMessage}`;
+  }
+
+  if (errorObj.message === 'Network Error') {
+    errorObj.message = intl.get('notification.network.typeError').d('网络请求异常');
+    errorObj.description = intl.get('notification.typeError.description').d('请稍后重试');
+  }
+
+  if (response.status === 200) {
+    getResponse(data);
+  } else if (response.status) {
+    notification.autoNotification(
+      errorObj?.type || 'error',
+      errorObj?.message,
+      errorObj?.description,
+    );
+  }
+
+  throw error;
+}
+
+/**
+ * 处理成功响应
+ * @param {Object} response - 响应对象
+ * @returns {any} - 处理后的响应数据,默认返回data
+ */
+function handleResponseSuccess(response: AxiosResponse) {
+  const { status, data, config } = response;
+
+  if (config.responseType === 'text' && typeof data !== 'string') {
+    return JSON.stringify(data);
+  }
+
+  // 响应拦截
+  const responseIntercept = getConfig().request.responseIntercept;
+  if (responseIntercept && typeof responseIntercept === 'function') {
+    responseIntercept(response);
+  }
+
+  // 异常响应拦截
+  if (data && typeof data === 'object' && 'code' in data && data.code !== 0 && data.code !== 200) {
+    // 处理业务逻辑错误
+    const errorCode = data.code;
+    const errorMessage = data.message || intl.get('error.unknown').d('未知错误');
+
+    // 输出业务错误日志,但仍然返回响应以供业务代码处理
+    console.warn(`业务错误 [${errorCode}]: ${errorMessage}`, data);
+  }
+
+  return data;
+}
+
+cubeAxios.interceptors.response.use(handleResponseSuccess, handleResponseError);
+
+/**
+ * 请求拦截器
+ * @param {Object} config - 请求配置
+ * @returns {Object} - 处理后的请求配置
+ */
+function handleRequestConfig(config: InternalAxiosRequestConfig) {
+  const {
+    request: { baseURL: API_HOST },
+  } = getConfig();
+  let { url = '' } = config || {};
+
+  if (url.indexOf('://') === -1 && !url.startsWith('/_api')) {
+    url = `${API_HOST}${url}`;
+  }
+
+  // 添加额外的请求头
+  const additionalRequestHeaderConfig = getConfig().request.additionalRequestHeader;
+  let additionalRequestHeader: Record<string, string> = {};
+  if (additionalRequestHeaderConfig) {
+    additionalRequestHeader =
+      typeof additionalRequestHeaderConfig === 'function'
+        ? additionalRequestHeaderConfig()
+        : additionalRequestHeaderConfig;
+  }
+
+  const newOptions: InternalAxiosRequestConfig = {
+    ...config,
+    url,
+    withCredentials: true,
+    headers: {
+      Authorization: `bearer ${getAccessToken()}`,
+      ...additionalRequestHeader,
+      ...(config?.headers || {}),
+    } as AxiosRequestHeaders,
+  };
+
+  return newOptions;
+}
+
+/**
+ * 请求错误处理
+ * @param {Object} error - 错误对象
+ * @returns {Promise} - 处理后的Promise
+ */
+async function handleRequestError(error: AxiosError) {
+  const { config } = error;
+
+  console.error('Request processing error:', error.message);
+
+  return Promise.reject(error);
+}
+
+const requestHandlers = [handleRequestConfig, handleRequestError];
+cubeAxios.interceptors.request.use(handleRequestConfig, handleRequestError);
+
+// 导出配置好的axios实例
+export const request = cubeAxios;
+export default request;
+export { cubeAxios };
+
+// 替换原来导出的toReLogin
+export { redirectToLogin as toReLogin };
Added +5 -0
diff --git a/core/utils/router.ts b/core/utils/router.ts
new file mode 100644
index 0000000..58b9510
--- /dev/null
+++ b/core/utils/router.ts
@@ -0,0 +1,5 @@
+import { type RouteLocationRaw } from "vue-router"
+
+export const gotoPage = (to: RouteLocationRaw) => {
+  window.router?.push(to)
+}
Added +37 -0
diff --git a/core/utils/storage.ts b/core/utils/storage.ts
new file mode 100644
index 0000000..ca2a10c
--- /dev/null
+++ b/core/utils/storage.ts
@@ -0,0 +1,37 @@
+import { forIn as _forIn} from "lodash";
+import Cookies from 'universal-cookie';
+const cookies = new Cookies();
+
+/**
+ * 存储sessionStorage
+ */
+export function setSession(key: string, value: any) {
+  if (value === undefined || value === null) {
+    window.sessionStorage.removeItem(key);
+    return;
+  }
+  const formatValue = JSON.stringify(value);
+  window.sessionStorage.setItem(key, formatValue);
+  return true;
+}
+
+/**
+ * 获取sessionStorage
+ */
+export function getSession(key: string) {
+  const value = sessionStorage.getItem(key);
+  if (value) {
+    return JSON.parse(value);
+  }
+  return null;
+}
+
+export function removeAllCookie() {
+  _forIn(cookies.getAll(), (_: any, key: string) => {
+    cookies.remove(key);
+  });
+}
+
+export function getCookie(key: string) {
+  return cookies.get(key);
+}
\ No newline at end of file
Added +117 -0
diff --git a/core/utils/token.ts b/core/utils/token.ts
new file mode 100644
index 0000000..a2a6eb9
--- /dev/null
+++ b/core/utils/token.ts
@@ -0,0 +1,117 @@
+import { getConfig } from '../configure';
+
+export const NEW_ACCESS_TOKEN = 'token';
+export const NEW_REFRESH_TOKEN = 'refresh_token';
+export const REFRESH_TOKEN = 'refresh_token';
+
+function getTokenName() {
+  const config = getConfig();
+
+  return config.auth.tokenKey || NEW_ACCESS_TOKEN;
+}
+
+/**
+ * 从本地存储获取刷新令牌
+ * @returns {string | null} 返回存储的刷新令牌,如果不存在则返回 null
+ */
+export const getRefreshToken = () => {
+  return localStorage.getItem(NEW_REFRESH_TOKEN);
+};
+
+/**
+ * 设置刷新令牌到本地存储
+ * @param token 需要存储的刷新令牌字符串
+ */
+export function setRefreshToken(token: string) {
+  localStorage.setItem(NEW_REFRESH_TOKEN, token);
+}
+
+/**
+ * 从本地存储获取访问令牌
+ * @returns {string | null} 返回存储的访问令牌,如果不存在则返回 null
+ */
+export const getAccessToken = () => {
+  return localStorage.getItem(getTokenName());
+};
+
+/**
+ * 从哈希中提取访问令牌
+ * @returns 返回访问令牌字符串
+ */
+export const extractAccessTokenFromHash = () => {
+  return getAccessToken();
+};
+
+/**
+ * 抽取RefreshToken
+ * @param {String} hash   hash值
+ */
+export function extractRefreshTokenFromHash(hash: string) {
+  if (hash) {
+    const ai = hash.indexOf(REFRESH_TOKEN);
+    if (ai !== -1) {
+      const refreshTokenReg = /#?refresh_token=[0-9a-zA-Z-]*/g;
+      hash.match(refreshTokenReg);
+      const centerReg = hash.match(refreshTokenReg)?.[0];
+      const refreshToken = centerReg?.split('=')[1];
+      return refreshToken;
+    }
+  }
+  return null;
+}
+
+/**
+ * 设置访问令牌到本地存储
+ * @param token 需要存储的访问令牌字符串
+ */
+export function setAccessToken(token: string) {
+  localStorage.setItem(getTokenName(), token);
+}
+
+/**
+ * 移除本地存储中的访问令牌
+ *
+ * 从浏览器的 localStorage 中删除访问令牌。
+ * 令牌名称从环境配置中获取,如果配置中未指定则使用默认值 NEW_ACCESS_TOKEN
+ */
+export function removeAccessToken() {
+  localStorage.removeItem(getTokenName());
+}
+
+/**
+ * 从 URL hash 中获取 token 参数
+ *
+ * 遍历 URL hash 中的所有参数,查找包含 'token' 的键
+ * 如果找到 token,将其存储到 localStorage 中,并清空 URL hash
+ *
+ * @returns {string|null} 返回找到的 token,如果未找到则返回 null
+ */
+/**
+ * 从 URL hash 中获取 token 参数
+ *
+ * 处理形如 #token=xxx 或 #/path#token=xxx 的哈希值
+ * 如果找到 token,将其存储到 localStorage 中,并清空 URL hash
+ *
+ * @returns {string|null} 返回找到的 token,如果未找到则返回 null
+ */
+export function getUrlHashToken() {
+  const tokenName = getTokenName();
+
+  // 获取哈希值(不含#符号)
+  let hash = window.location.hash;
+  if (hash.startsWith('#')) {
+    hash = hash.substring(1);
+  }
+
+  // 处理直接在哈希中的token(如 #token=xxx)
+  const tokenRegex = new RegExp(`${tokenName}=([^&]+)`);
+  const match = hash.match(tokenRegex);
+
+  if (match && match[1]) {
+    const token = match[1];
+    localStorage.setItem(tokenName, token);
+    return token;
+  }
+
+  return null;
+}
Added +46 -0
diff --git a/core/utils/url.ts b/core/utils/url.ts
new file mode 100644
index 0000000..daf01d2
--- /dev/null
+++ b/core/utils/url.ts
@@ -0,0 +1,46 @@
+import qs from 'query-string';
+export function isUrl(path: string) {
+  /* eslint no-useless-escape:0 */
+  const reg =
+    /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)(:[\d]+)?((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/g;
+  return reg.test(path);
+}
+
+/**
+ * 生成带Get参数的URL
+ * @param {String} url      原来的url
+ * @param {Object} params   get 参数
+ */
+export function generateUrlWithGetParam(url: string, params: {}) {
+  let newUrl = url;
+  if (params && Object.keys(params).length >= 1) {
+    const newParams = params; // filterNullValueObject
+    if (Object.keys(newParams).length >= 1) {
+      newUrl += `${url.indexOf('?') >= 0 ? '&' : '?'}${qs.stringify(newParams)}`;
+    }
+  }
+  return newUrl;
+}
+
+/**
+ * 得到get请求后面的参数部分,并去掉参数值为空的
+ * @param param
+ * @returns {String}
+ */
+export function getUrlParam(param: { [x: string]: any }) {
+  let on = true;
+  let result = '';
+  for (const item in param) {
+    if (on) {
+      on = false;
+      if (param[item] || param[item] === 0 || param[item] === false) {
+        result = `?${item}=${param[item]}`;
+      } else {
+        result = '?';
+      }
+    } else if (param[item] || param[item] === 0 || param[item] === false) {
+      result = `${result}&${item}=${param[item]}`;
+    }
+  }
+  return result;
+}
Added +110 -0
diff --git a/core/utils/user.ts b/core/utils/user.ts
new file mode 100644
index 0000000..7a81752
--- /dev/null
+++ b/core/utils/user.ts
@@ -0,0 +1,110 @@
+export const getCurrentUser = () => {
+  const userInfo = window.store.state.value.userInfo;
+  return userInfo;
+};
+
+/**
+ * 获取当前租户信息
+ */
+export function getCurrentTenant() {
+  const state = window.getDvaApp?.()?._store.getState();
+  const _state$user = state.user,
+    user = _state$user === void 0 ? {} : _state$user;
+  const _user$currentUser = user.currentUser,
+    currentUser = _user$currentUser === void 0 ? {} : _user$currentUser;
+  const tenantId = currentUser.tenantId,
+    tenantName = currentUser.tenantName,
+    tenantNum = currentUser.tenantNum;
+  return {
+    tenantId,
+    tenantName,
+    tenantNum,
+  };
+}
+
+/**
+ * 获取当前用户角色租户id
+ */
+export function getCurrentTenantId() {
+  return getCurrentTenant().tenantId;
+}
+
+/**
+ * 获取当前用户角色租户id
+ */
+export function getCurrentOrganizationId() {
+  let _getCurrentTenant;
+  return (_getCurrentTenant = getCurrentTenant()) === null || _getCurrentTenant === void 0
+    ? void 0
+    : _getCurrentTenant.tenantId;
+  // return getCurrentUser()?.organizationId;
+}
+
+export function isTenantRoleLevel() {
+  const _getCurrentRole = getCurrentRole(),
+    level = _getCurrentRole.level;
+  return level !== 'site';
+}
+
+/**
+ * 获取当前用户所属租户 ID
+ */
+export function getUserOrganizationId() {
+  return getCurrentUser().organizationId;
+}
+
+/**
+ * 获取当前登录用户id
+ */
+export function getCurrentUserId() {
+  return getCurrentUser().id;
+}
+export function isEqualOrganization() {
+  const _getCurrentRole2 = getCurrentRole(),
+    level = _getCurrentRole2.level;
+  return level === 'organization';
+}
+export function getCurrentRole(dvaState: any = undefined) {
+  const state = dvaState || window.getDvaApp?.()?._store.getState();
+  const _state$user2 = state.user,
+    user = _state$user2 === void 0 ? {} : _state$user2;
+  const _user$currentUser2 = user.currentUser,
+    currentUser = _user$currentUser2 === void 0 ? {} : _user$currentUser2;
+  const currentRoleId = currentUser.currentRoleId,
+    currentRoleName = currentUser.currentRoleName,
+    currentRoleLevel = currentUser.currentRoleLevel,
+    currentRoleCode = currentUser.currentRoleCode;
+  return {
+    id: currentRoleId,
+    name: currentRoleName,
+    level: currentRoleLevel,
+    code: currentRoleCode,
+  };
+}
+if (process.env.NODE_ENV === 'development') {
+  window.getCurrentOrganizationId = getCurrentOrganizationId;
+}
+
+/**
+ * 获取系统当前语言
+ * @export
+ * @returns
+ */
+export function getCurrentLanguage() {
+  const state = window.getDvaApp?.()?._store.getState();
+  const _state$user3 = state.user,
+    user = _state$user3 === void 0 ? {} : _state$user3;
+  const _user$currentUser3 = user.currentUser,
+    currentUser = _user$currentUser3 === void 0 ? {} : _user$currentUser3;
+  const language = currentUser.language;
+  return language;
+}
+
+/**
+ * 获取平台版本API
+ */
+export function getPlatformVersionApi(api: any) {
+  const tenantId = getCurrentOrganizationId();
+  const isTenantLevel = isTenantRoleLevel();
+  return isTenantLevel ? `${tenantId}/${api}` : `${api}`;
+}
Added +15 -0
diff --git a/cypress.config.ts b/cypress.config.ts
new file mode 100644
index 0000000..95fdb53
--- /dev/null
+++ b/cypress.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "cypress";
+
+export default defineConfig({
+  e2e: {
+    specPattern: "cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}",
+    baseUrl: "http://localhost:4173",
+  },
+
+  component: {
+    devServer: {
+      framework: "vue",
+      bundler: "vite",
+    },
+  },
+});
Added +8 -0
diff --git a/cypress/e2e/example.cy.ts b/cypress/e2e/example.cy.ts
new file mode 100644
index 0000000..7554c35
--- /dev/null
+++ b/cypress/e2e/example.cy.ts
@@ -0,0 +1,8 @@
+// https://on.cypress.io/api
+
+describe('My First Test', () => {
+  it('visits the app root url', () => {
+    cy.visit('/')
+    cy.contains('h1', 'You did it!')
+  })
+})
Added +5 -0
diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json
new file mode 100644
index 0000000..02e4254
--- /dev/null
+++ b/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+  "name": "Using fixtures to represent data",
+  "email": "hello@cypress.io",
+  "body": "Fixtures are a great way to mock data for responses to routes"
+}
Added +39 -0
diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts
new file mode 100644
index 0000000..9b7bb8e
--- /dev/null
+++ b/cypress/support/commands.ts
@@ -0,0 +1,39 @@
+/// <reference types="cypress" />
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+//   namespace Cypress {
+//     interface Chainable {
+//       login(email: string, password: string): Chainable<void>
+//       drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
+//       visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
+//     }
+//   }
+// }
+
+export {}
Added +12 -0
diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html
new file mode 100644
index 0000000..ac6e79f
--- /dev/null
+++ b/cypress/support/component-index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
+    <title>Components App</title>
+  </head>
+  <body>
+    <div data-cy-root></div>
+  </body>
+</html>
\ No newline at end of file
Added +36 -0
diff --git a/cypress/support/component.ts b/cypress/support/component.ts
new file mode 100644
index 0000000..44aa720
--- /dev/null
+++ b/cypress/support/component.ts
@@ -0,0 +1,36 @@
+// ***********************************************************
+// This example support/component.ts is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+import { mount } from 'cypress/vue'
+
+// Augment the Cypress namespace to include type definitions for
+// your custom command.
+// Alternatively, can be defined in cypress/support/component.d.ts
+// with a <reference path="./component" /> at the top of your spec.
+declare global {
+  namespace Cypress {
+    interface Chainable {
+      mount: typeof mount
+    }
+  }
+}
+
+Cypress.Commands.add('mount', mount)
+
+// Example use:
+// cy.mount(MyComponent)
\ No newline at end of file
Added +20 -0
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts
new file mode 100644
index 0000000..d68db96
--- /dev/null
+++ b/cypress/support/e2e.ts
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
Added +9 -0
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
new file mode 100644
index 0000000..c8f4bce
--- /dev/null
+++ b/cypress/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.dom.json",
+  "include": ["./e2e/**/*", "./support/**/*"],
+  "exclude": ["./support/component.*"],
+  "compilerOptions": {
+    "isolatedModules": false,
+    "types": ["cypress"]
+  }
+}
Added +460 -0
diff --git a/docs/project-specification.md b/docs/project-specification.md
new file mode 100644
index 0000000..98b420f
--- /dev/null
+++ b/docs/project-specification.md
@@ -0,0 +1,460 @@
+# Vite + Vue3 项目规范
+
+## 目录
+
+- [项目结构规范](#项目结构规范)
+- [文件命名规范](#文件命名规范)
+- [Vue组件规范](#Vue组件规范)
+- [JavaScript/TypeScript规范](#JavaScriptTypeScript规范)
+- [CSS/SCSS规范](#CSS/SCSS规范)
+- [注释规范](#注释规范)
+- [性能优化规范](#性能优化规范)
+- [错误处理规范](#错误处理规范)
+- [安全规范](#安全规范)
+- [单元测试规范](#单元测试规范)
+- [Git提交规范](#Git提交规范)
+- [国际化规范](#国际化规范)
+- [可访问性(A11y)规范](#可访问性A11y规范)
+- [构建与部署规范](#构建与部署规范)
+
+## 项目结构规范
+
+```
+cube-front/
+├── public/                 # 静态资源目录
+├── src/
+│   ├── api/                # API接口定义
+│   ├── assets/             # 项目资源文件
+│   │   ├── icons/          # 图标
+│   │   ├── images/         # 图片
+│   │   └── styles/         # 全局样式
+│   ├── components/         # 公共组件
+│   │   ├── base/           # 基础组件
+│   │   └── business/       # 业务组件
+│   ├── composables/        # 组合式函数
+│   ├── config/             # 配置文件
+│   ├── constants/          # 常量定义
+│   ├── directives/         # 自定义指令
+│   ├── hooks/              # 自定义钩子
+│   ├── layouts/            # 布局组件
+│   ├── plugins/            # 插件
+│   ├── router/             # 路由配置
+│   ├── store/              # 状态管理
+│   ├── types/              # 类型定义
+│   ├── utils/              # 工具函数
+│   ├── views/              # 页面视图
+│   ├── App.vue             # 根组件
+│   ├── main.ts             # 入口文件
+│   └── env.d.ts            # 环境变量类型声明
+├── tests/                  # 测试文件
+├── .env                    # 环境变量
+├── .eslintrc.js            # ESLint配置
+├── .prettierrc.js          # Prettier配置
+├── tsconfig.json           # TypeScript配置
+├── vite.config.ts          # Vite配置
+└── package.json            # 项目依赖
+```
+
+### 目录说明
+
+- **api**: 按模块划分API请求
+- **components**:
+  - **base**: 基础UI组件,不包含业务逻辑
+  - **business**: 包含业务逻辑的可复用组件
+- **composables**: 可复用的组合式函数
+- **views**: 按模块/功能划分的页面组件
+
+## 文件命名规范
+
+### 文件夹命名
+
+- 使用kebab-case(短横线)命名法
+- 例如:`user-management`,`data-analysis`
+
+### 文件命名
+
+1. **Vue组件文件**:
+
+   - 使用PascalCase(帕斯卡)命名法
+   - 例如:`UserProfile.vue`,`DataTable.vue`
+   - 基础组件以`Base`为前缀,如`BaseButton.vue`
+   - 单例组件以`The`为前缀,如`TheHeader.vue`
+
+2. **TypeScript文件**:
+
+   - 普通工具类文件使用kebab-case,如`date-utils.ts`
+   - 类文件使用PascalCase,如`UserService.ts`
+   - 类型定义文件使用`.d.ts`后缀,且使用PascalCase,如`ApiResponse.d.ts`
+
+3. **样式文件**:
+
+   - 使用kebab-case,如`main-theme.scss`
+   - 组件私有样式与组件同名,如`UserProfile.scss`
+
+4. **测试文件**:
+   - 使用与被测试文件相同的命名方式,后缀`.spec.ts`或`.test.ts`
+   - 例如:`UserProfile.spec.ts`
+
+## Vue组件规范
+
+### 组件结构
+
+```vue
+<template>
+  <!-- 模板内容 -->
+</template>
+
+<script setup lang="ts">
+// 导入
+import { ref } from 'vue'
+import type { PropType } from 'vue'
+
+// 类型定义
+
+// Props定义
+const props = defineProps({
+  propName: {
+    type: String as PropType<string>,
+    required: true,
+    default: '',
+  },
+})
+
+// Emits定义
+const emit = defineEmits<{
+  (e: 'update', value: string): void
+  (e: 'submit'): void
+}>()
+
+// 响应式状态
+const count = ref(0)
+
+// 计算属性
+
+// 方法定义
+
+// 生命周期钩子
+
+// 侦听器
+</script>
+
+<style scoped lang="scss">
+/* 组件样式 */
+</style>
+```
+
+### Props规范
+
+- 必须使用对象形式定义props,指定类型、默认值、是否必须等
+- TypeScript项目中使用PropType指定复杂类型
+- Props命名使用camelCase
+
+### 事件命名
+
+- 使用kebab-case命名事件
+- 使用语义化名称,如`update:modelValue`、`item-click`
+
+### 组件通信
+
+- 父子组件:Props down, Events up
+- 跨层级组件:Provide/Inject或状态管理
+- 避免使用事件总线
+
+## JavaScript/TypeScript规范
+
+### TypeScript类型规范
+- 使用TypeScript类型系统
+- 对于复杂类型,使用TypeScript类型别名
+- 对于函数参数和返回值,使用TypeScript类型定义
+- 对于类型导入,使用type关键字,如`import { type User } from './types'`
+
+### JavaScript/TypeScript命名规范
+
+1. **变量命名**:
+
+   - 使用camelCase
+   - 布尔值类型变量使用`is`、`has`、`can`等前缀
+   - 例如:`userName`、`isVisible`、`hasPermission`
+
+2. **常量命名**:
+
+   - 使用UPPER_SNAKE_CASE
+   - 例如:`MAX_COUNT`、`API_BASE_URL`
+
+3. **函数命名**:
+
+   - 使用camelCase
+   - 动词开头,表明操作
+   - 例如:`getUserInfo()`、`handleSubmit()`
+
+4. **类和接口命名**:
+
+   - 使用PascalCase
+   - 例如:`UserService`、`DataModel`
+   - 接口名不要使用`I`前缀,例如使用`User`而非`IUser`
+
+5. **类型命名**:
+   - 使用PascalCase
+   - 例如:`UserInfo`、`ApiResponse`
+
+### 函数规范
+
+- 一个函数只做一件事
+- 函数参数不超过3个,多参数使用对象传递
+- 使用函数声明式而非函数表达式
+  - 为什么推荐使用函数声明式而非函数表达式
+  - 函数声明式和函数表达式是JavaScript中定义函数的两种主要方式:
+  
+  ```javascript
+  // 函数声明式
+  function doSomething() {
+    // 函数体
+  }
+  
+  // 函数表达式
+  const doSomething = function() {
+    // 函数体
+  };
+  ```
+  
+  - 函数声明式的优势
+  
+    1. **变量提升(Hoisting)** - 函数声明会被提升到当前作用域顶部,允许在代码中任何位置调用,而函数表达式必须先定义后使用
+
+    2. **代码可读性** - 函数声明在视觉上更容易识别为一个函数,开头的`function`关键字立即表明这是一个函数定义
+
+    3. **调试友好** - 在错误堆栈跟踪中,函数声明会显示函数名,而匿名函数表达式则不会
+
+    4. **语义明确** - 函数声明更清晰地表达"这是一个独立功能单元"的意图,而不是一个变量被赋予了函数值
+
+    5. **维护性** - 在大型项目中使用一致的函数定义方式有助于代码维护
+
+    6. **自文档化** - 函数声明总是强制命名,提高了代码的自解释性
+- 避免副作用,保持函数纯净
+
+### 异步处理
+
+- 优先使用async/await代替Promise链
+- 正确处理错误,使用try/catch
+- 避免回调地狱
+
+## CSS/SCSS规范
+
+### CSS/SCSS命名规范
+
+- 多个单词使用短横线(kebab-case)连接
+- 例如:`.card`,`.card-title`,`.user-profile-section`
+
+### 样式结构
+
+- 避免深层次嵌套,最好不超过3层
+- 组件样式使用`scoped`或CSS Module
+- 全局样式放在assets/styles目录下
+
+### 变量使用
+
+- 颜色、字体、间距等使用CSS变量(变量文件放在styles/variables下)
+- 避免硬编码值
+
+## 注释规范
+
+### 文件顶部注释
+
+```typescript
+/**
+ * 文件描述
+ * @author 作者名
+ * @date 2023-01-01
+ */
+```
+
+### 函数注释
+
+```typescript
+/**
+ * 函数描述
+ * @param {string} param1 - 参数1描述
+ * @param {number} param2 - 参数2描述
+ * @returns {boolean} 返回值描述
+ */
+function example(param1: string, param2: number): boolean {
+  // 函数实现
+}
+```
+
+### 复杂逻辑注释
+
+- 对于复杂的业务逻辑,添加必要的注释
+- 注释解释"为什么"这样做,而不是"做了什么"
+
+## 性能优化规范
+
+### Vue组件优化
+
+- 合理使用`v-if`和`v-show`
+- 使用`keep-alive`缓存组件状态
+- 大型列表使用虚拟滚动
+- 避免深层次的响应式对象
+- 组件中使用`shallowRef`和`shallowReactive`来优化非递归监听场景
+
+### 懒加载和代码分割
+
+- 路由组件使用动态导入实现懒加载
+
+  ```typescript
+  const routes = [
+    {
+      path: '/user',
+      component: () => import('./views/User.vue')
+    }
+  ]
+  ```
+
+- 大型组件库按需导入
+- 图片资源使用懒加载
+
+### 构建优化
+
+- 生产环境启用代码压缩和tree-shaking
+- 使用现代模式构建(`modern mode`)
+- 优化依赖大小,定期审查并移除未使用的依赖
+
+## 错误处理规范
+
+### 前端错误
+
+- 实现全局错误处理
+- 对可预见的错误进行优雅降级
+- 使用`try/catch`捕获异步操作错误
+
+### 错误监控
+
+- 集成错误监控系统(如Sentry)
+- 记录用户操作路径,便于复现问题
+- 设置错误严重程度,区分处理
+
+## 安全规范
+
+### 数据处理
+
+- 所有用户输入必须验证和消毒
+- 使用`v-html`时必须确保内容安全
+- 不在前端存储敏感信息
+- API响应数据使用TypeScript类型限制,避免运行时错误
+
+### 认证与授权
+
+- 敏感操作必须二次验证
+- 实现合理的RBAC权限控制
+- 使用HTTPS,确保Cookie设置`Secure`和`HttpOnly`标志
+
+## 单元测试规范
+
+### 测试覆盖
+
+- 业务组件的核心功能必须有单元测试
+- 工具函数必须有单元测试
+- 最低测试覆盖率要求:70%
+
+### 测试内容
+
+- 组件测试:渲染结果、事件交互、Props验证
+- 工具函数测试:边界情况、异常处理
+- 复杂逻辑:分支覆盖
+
+### 测试技术
+
+- 使用Vue Test Utils测试组件
+- 使用Vitest进行单元测试
+- 使用Cypress进行端到端(E2E)测试
+- 使用JSDOM模拟浏览器环境进行组件测试
+- 单元测试命令:`pnpm test:unit`
+- E2E测试命令:
+  - 生产模式:`pnpm test:e2e`
+  - 开发模式:`pnpm test:e2e:dev`
+
+### 测试最佳实践
+
+- 单元测试应该快速且独立,不依赖外部服务
+- 使用Mock函数模拟API调用和第三方服务
+- 为异步组件编写测试时使用`flushPromises`
+- 组件测试应聚焦于组件API而非实现细节
+- E2E测试应覆盖关键用户流程和业务场景
+- 使用测试驱动开发(TDD)方法开发核心功能
+
+## Git提交规范
+
+- 使用Angular提交规范
+- 格式:`<type>(<scope>): <subject>`
+- 类型(type):
+  - feat: 新功能
+  - fix: 修复bug
+  - docs: 文档更新
+  - style: 代码风格修改
+  - refactor: 重构
+  - test: 测试相关
+  - chore: 构建过程或辅助工具变更
+
+### 示例
+
+```
+feat(user): 添加用户认证功能
+fix(api): 修复数据请求超时问题
+docs(readme): 更新安装说明
+```
+
+## 国际化规范
+
+### 文本管理
+
+- 所有用户可见的文本必须使用i18n
+- 禁止在代码中硬编码文本
+- 使用命名空间组织翻译键名
+
+### 格式规范
+
+- 翻译键名使用点符号层次结构,如`user.profile.title`
+- 包含变量的文本使用命名参数,如`{name}已登录`
+- 日期、数字、货币等使用i18n格式化函数
+
+## 可访问性(A11y)规范
+
+### 语义化HTML
+
+- 使用正确的HTML标签表达内容含义
+- 表单控件必须有关联的`label`
+- 图片必须有`alt`属性
+
+### 键盘导航
+
+- 所有交互元素必须可通过键盘访问
+- 合理使用`tabindex`属性
+- 实现合适的焦点管理
+
+### 颜色与对比度
+
+- 确保文本与背景色对比度符合WCAG标准(最低4.5:1)
+- 不仅使用颜色传达信息(考虑色盲用户)
+
+## 构建与部署规范
+
+### 环境配置
+
+- 使用`.env`文件区分开发/测试/生产环境
+- 环境变量必须以`VITE_`前缀
+- 敏感配置不应提交到代码库
+
+### 部署流程
+
+- 使用CI/CD自动化部署
+- 发布前必须通过所有测试
+- 实现灰度发布或A/B测试机制
+
+## 代码审查清单
+
+- [ ] 代码是否符合项目规范
+- [ ] 是否有重复代码可以优化
+- [ ] 是否有潜在的性能问题
+- [ ] 是否有适当的错误处理
+- [ ] 是否有必要的注释
+- [ ] 是否编写了测试
Added +65 -0
diff --git a/docs/project.md b/docs/project.md
new file mode 100644
index 0000000..0534de9
--- /dev/null
+++ b/docs/project.md
@@ -0,0 +1,65 @@
+# 项目架构文档
+
+## 技术栈
+```mermaid
+pie
+  title 技术栈组成
+  "Vue 3" : 35
+  "TypeScript" : 25
+  "Vite" : 20
+  "Pinia" : 10
+  "Element Plus" : 10
+```
+
+## 核心架构
+### 微前端架构
+```mermaid
+graph TD
+  A[主应用] --> B[cube-iam子应用]
+  A --> C[核心模块]
+  C --> D[路由系统]
+  C --> E[权限控制]
+```
+
+### 目录结构
+```
+core/         # 核心业务逻辑
+  stores/     # 状态管理
+  layouts/    # 布局系统
+  configs/    # 应用配置
+src/          # 主应用代码
+configs/      # 微前端配置
+```
+
+## 模块分析
+### 路由系统
+- **文件位置**: 
+  - `src/router/index.ts` (基础路由)
+  - `core/routes/index.ts` (微前端路由)
+- 特点:
+  - 动态路由加载
+  - 权限路由过滤
+
+### 状态管理
+```typescript
+// core/stores/user.ts
+interface UserState {
+  token: string
+  roles: string[]
+}
+```
+
+### 权限控制
+- 基于角色的访问控制
+- 动态菜单生成
+- 路由守卫拦截
+
+## 开发规范
+1. 组件命名:大驼峰式
+2. 状态管理:严格使用Pinia
+3. 代码风格:ESLint + Prettier
+
+## 待办优化
+1. [ ] 完善环境变量类型定义
+2. [ ] 提取公共工具函数
+3. [ ] 增强菜单组件类型
\ No newline at end of file
Added +2 -0
diff --git a/env.d.ts b/env.d.ts
new file mode 100644
index 0000000..7a542d0
--- /dev/null
+++ b/env.d.ts
@@ -0,0 +1,2 @@
+/// <reference types="vite/client" />
+/// <reference types="cypress" />
Added +61 -0
diff --git a/eslint.config.ts b/eslint.config.ts
new file mode 100644
index 0000000..773c315
--- /dev/null
+++ b/eslint.config.ts
@@ -0,0 +1,61 @@
+import pluginVue from 'eslint-plugin-vue'
+import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
+import pluginVitest from '@vitest/eslint-plugin'
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import pluginCypress from 'eslint-plugin-cypress/flat'
+import oxlint from 'eslint-plugin-oxlint'
+import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
+
+// To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
+import { configureVueProject } from '@vue/eslint-config-typescript'
+configureVueProject({ scriptLangs: ['ts', 'tsx'] })
+// More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
+
+export default defineConfigWithVueTs(
+  {
+    name: 'app/files-to-lint',
+    files: ['**/*.{ts,mts,tsx,vue}'],
+  },
+
+  {
+    name: 'app/files-to-ignore',
+    ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
+  },
+
+  pluginVue.configs['flat/essential'],
+  vueTsConfigs.recommended,
+
+  {
+    rules: {
+      'vue/multi-word-component-names': ['error', {
+        ignores: ['index']
+      }]
+    }
+  },
+
+  {
+    ...pluginVitest.configs.recommended,
+    files: ['src/**/__tests__/*'],
+  },
+
+  {
+    ...pluginCypress.configs.recommended,
+    files: [
+      'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}',
+      'cypress/support/**/*.{js,ts,jsx,tsx}'
+    ],
+  },
+  ...oxlint.configs['flat/recommended'],
+  skipFormatting,
+  {
+    settings: {
+      'import/extensions': ['.js', '.jsx', '.ts', '.tsx', '.vue'],
+      'import/resolver': {
+        typescript: {
+          alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
+        },
+      },
+    },
+  }
+)
Added +16 -0
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..60dcb0a
--- /dev/null
+++ b/index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html lang="">
+
+<head>
+  <meta charset="UTF-8">
+  <link rel="icon" href="/favicon.ico">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Cube-Front</title>
+</head>
+
+<body>
+  <div id="app"></div>
+  <script type="module" src="/core/main.ts"></script>
+</body>
+
+</html>
\ No newline at end of file
Added +84 -0
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..221b56c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,84 @@
+{
+  "name": "cube-front",
+  "version": "0.1.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "run-p type-check \"build-only {@}\" --",
+    "preview": "vite preview",
+    "test:unit": "vitest",
+    "prepare": "cypress install",
+    "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'",
+    "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'",
+    "build-only": "vite build",
+    "build:plugin": "set BUILD_TARGET=plugin&& vite build",
+    "type-check": "vue-tsc --build",
+    "lint:oxlint": "oxlint . --fix -D correctness --ignore-path .gitignore",
+    "lint:eslint": "eslint . --fix",
+    "lint": "run-s lint:*",
+    "format": "prettier --write src/"
+  },
+  "dependencies": {
+    "@types/lodash": "^4.17.9",
+    "@vue/reactivity": "^3.5.13",
+    "@vue/runtime-dom": "^3.5.13",
+    "@vueuse/core": "^13.0.0",
+    "@vueuse/integrations": "^13.0.0",
+    "axios": "^1.8.4",
+    "element-plus": "^2.9.7",
+    "lodash": "^4.17.21",
+    "pinia": "^3.0.1",
+    "query-string": "^9.1.1",
+    "universal-cookie": "^8.0.1",
+    "vue": "^3.5.13",
+    "vue-i18n": "^9.0.0",
+    "vue-router": "^4.5.0"
+  },
+  "devDependencies": {
+    "@tsconfig/node22": "^22.0.0",
+    "@types/jsdom": "^21.1.7",
+    "@types/node": "^22.13.9",
+    "@vitejs/plugin-vue": "^5.2.1",
+    "@vitejs/plugin-vue-jsx": "^4.1.1",
+    "@vitest/eslint-plugin": "^1.1.36",
+    "@vue/eslint-config-prettier": "^10.2.0",
+    "@vue/eslint-config-typescript": "^14.5.0",
+    "@vue/test-utils": "^2.4.6",
+    "@vue/tsconfig": "^0.7.0",
+    "autoprefixer": "^10.4.20",
+    "cypress": "^14.1.0",
+    "eslint": "^9.21.0",
+    "eslint-import-resolver-typescript": "^4.3.2",
+    "eslint-plugin-cypress": "^4.2.0",
+    "eslint-plugin-oxlint": "^0.15.13",
+    "eslint-plugin-vue": "~10.0.0",
+    "jiti": "^2.4.2",
+    "jsdom": "^26.0.0",
+    "npm-run-all2": "^7.0.2",
+    "oxlint": "^0.15.13",
+    "postcss": "^8.5.3",
+    "prettier": "3.5.3",
+    "sass": "^1.86.3",
+    "sass-loader": "^16.0.5",
+    "start-server-and-test": "^2.0.10",
+    "tailwindcss": "^4.1.3",
+    "typescript": "~5.8.2",
+    "unplugin-auto-import": "^19.1.2",
+    "unplugin-vue-components": "^28.5.0",
+    "vite": "^6.2.1",
+    "vite-plugin-vue-devtools": "^7.7.2",
+    "vitest": "^3.0.8",
+    "vue-tsc": "^2.2.8"
+  },
+  "engines": {
+    "node": ">=18",
+    "pnpm": ">=10"
+  },
+  "pnpm": {
+    "onlyBuiltDependencies": [
+      "cypress",
+      "eslint"
+    ]
+  }
+}
\ No newline at end of file
Added +6716 -0
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..804b561
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,6716 @@
+lockfileVersion: '9.0'
+
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
+importers:
+
+  .:
+    dependencies:
+      '@types/lodash':
+        specifier: ^4.17.9
+        version: 4.17.16
+      '@vue/reactivity':
+        specifier: ^3.5.13
+        version: 3.5.13
+      '@vue/runtime-dom':
+        specifier: ^3.5.13
+        version: 3.5.13
+      '@vueuse/core':
+        specifier: ^13.0.0
+        version: 13.0.0(vue@3.5.13(typescript@5.8.2))
+      '@vueuse/integrations':
+        specifier: ^13.0.0
+        version: 13.0.0(async-validator@4.2.5)(axios@1.8.4)(universal-cookie@8.0.1)(vue@3.5.13(typescript@5.8.2))
+      axios:
+        specifier: ^1.8.4
+        version: 1.8.4(debug@4.4.0)
+      element-plus:
+        specifier: ^2.9.7
+        version: 2.9.7(vue@3.5.13(typescript@5.8.2))
+      lodash:
+        specifier: ^4.17.21
+        version: 4.17.21
+      pinia:
+        specifier: ^3.0.1
+        version: 3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
+      query-string:
+        specifier: ^9.1.1
+        version: 9.1.1
+      universal-cookie:
+        specifier: ^8.0.1
+        version: 8.0.1
+      vue:
+        specifier: ^3.5.13
+        version: 3.5.13(typescript@5.8.2)
+      vue-i18n:
+        specifier: ^9.0.0
+        version: 9.14.4(vue@3.5.13(typescript@5.8.2))
+      vue-router:
+        specifier: ^4.5.0
+        version: 4.5.0(vue@3.5.13(typescript@5.8.2))
+    devDependencies:
+      '@tsconfig/node22':
+        specifier: ^22.0.0
+        version: 22.0.0
+      '@types/jsdom':
+        specifier: ^21.1.7
+        version: 21.1.7
+      '@types/node':
+        specifier: ^22.13.9
+        version: 22.13.10
+      '@vitejs/plugin-vue':
+        specifier: ^5.2.1
+        version: 5.2.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))
+      '@vitejs/plugin-vue-jsx':
+        specifier: ^4.1.1
+        version: 4.1.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))
+      '@vitest/eslint-plugin':
+        specifier: ^1.1.36
+        version: 1.1.38(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)(vitest@3.0.9(@types/node@22.13.10)(jiti@2.4.2)(jsdom@26.0.0)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))
+      '@vue/eslint-config-prettier':
+        specifier: ^10.2.0
+        version: 10.2.0(eslint@9.22.0(jiti@2.4.2))(prettier@3.5.3)
+      '@vue/eslint-config-typescript':
+        specifier: ^14.5.0
+        version: 14.5.0(eslint-plugin-vue@10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2))))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@vue/test-utils':
+        specifier: ^2.4.6
+        version: 2.4.6
+      '@vue/tsconfig':
+        specifier: ^0.7.0
+        version: 0.7.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))
+      autoprefixer:
+        specifier: ^10.4.20
+        version: 10.4.21(postcss@8.5.3)
+      cypress:
+        specifier: ^14.1.0
+        version: 14.2.0
+      eslint:
+        specifier: ^9.21.0
+        version: 9.22.0(jiti@2.4.2)
+      eslint-import-resolver-typescript:
+        specifier: ^4.3.2
+        version: 4.3.2(eslint@9.22.0(jiti@2.4.2))
+      eslint-plugin-cypress:
+        specifier: ^4.2.0
+        version: 4.2.0(eslint@9.22.0(jiti@2.4.2))
+      eslint-plugin-oxlint:
+        specifier: ^0.15.13
+        version: 0.15.15
+      eslint-plugin-vue:
+        specifier: ~10.0.0
+        version: 10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2)))
+      jiti:
+        specifier: ^2.4.2
+        version: 2.4.2
+      jsdom:
+        specifier: ^26.0.0
+        version: 26.0.0
+      npm-run-all2:
+        specifier: ^7.0.2
+        version: 7.0.2
+      oxlint:
+        specifier: ^0.15.13
+        version: 0.15.15
+      postcss:
+        specifier: ^8.5.3
+        version: 8.5.3
+      prettier:
+        specifier: 3.5.3
+        version: 3.5.3
+      sass:
+        specifier: ^1.86.3
+        version: 1.86.3
+      sass-loader:
+        specifier: ^16.0.5
+        version: 16.0.5(sass@1.86.3)
+      start-server-and-test:
+        specifier: ^2.0.10
+        version: 2.0.11
+      tailwindcss:
+        specifier: ^4.1.3
+        version: 4.1.3
+      typescript:
+        specifier: ~5.8.2
+        version: 5.8.2
+      unplugin-auto-import:
+        specifier: ^19.1.2
+        version: 19.1.2(@vueuse/core@13.0.0(vue@3.5.13(typescript@5.8.2)))
+      unplugin-vue-components:
+        specifier: ^28.5.0
+        version: 28.5.0(@babel/parser@7.26.10)(vue@3.5.13(typescript@5.8.2))
+      vite:
+        specifier: ^6.2.1
+        version: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vite-plugin-vue-devtools:
+        specifier: ^7.7.2
+        version: 7.7.2(rollup@4.35.0)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))
+      vitest:
+        specifier: ^3.0.8
+        version: 3.0.9(@types/node@22.13.10)(jiti@2.4.2)(jsdom@26.0.0)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vue-tsc:
+        specifier: ^2.2.8
+        version: 2.2.8(typescript@5.8.2)
+
+packages:
+
+  '@ampproject/remapping@2.3.0':
+    resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+    engines: {node: '>=6.0.0'}
+
+  '@antfu/utils@0.7.10':
+    resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==}
+
+  '@asamuzakjp/css-color@3.1.1':
+    resolution: {integrity: sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==}
+
+  '@babel/code-frame@7.26.2':
+    resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/compat-data@7.26.8':
+    resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/core@7.26.10':
+    resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/generator@7.26.10':
+    resolution: {integrity: sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-annotate-as-pure@7.25.9':
+    resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-compilation-targets@7.26.5':
+    resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-create-class-features-plugin@7.26.9':
+    resolution: {integrity: sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-member-expression-to-functions@7.25.9':
+    resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-imports@7.25.9':
+    resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-module-transforms@7.26.0':
+    resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-optimise-call-expression@7.25.9':
+    resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-plugin-utils@7.26.5':
+    resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-replace-supers@7.26.5':
+    resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0
+
+  '@babel/helper-skip-transparent-expression-wrappers@7.25.9':
+    resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-string-parser@7.25.9':
+    resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-identifier@7.25.9':
+    resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helper-validator-option@7.25.9':
+    resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/helpers@7.26.10':
+    resolution: {integrity: sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/parser@7.26.10':
+    resolution: {integrity: sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==}
+    engines: {node: '>=6.0.0'}
+    hasBin: true
+
+  '@babel/plugin-proposal-decorators@7.25.9':
+    resolution: {integrity: sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-decorators@7.25.9':
+    resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-attributes@7.26.0':
+    resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-import-meta@7.10.4':
+    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-jsx@7.25.9':
+    resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-syntax-typescript@7.25.9':
+    resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/plugin-transform-typescript@7.26.8':
+    resolution: {integrity: sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==}
+    engines: {node: '>=6.9.0'}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@babel/template@7.26.9':
+    resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/traverse@7.26.10':
+    resolution: {integrity: sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==}
+    engines: {node: '>=6.9.0'}
+
+  '@babel/types@7.26.10':
+    resolution: {integrity: sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==}
+    engines: {node: '>=6.9.0'}
+
+  '@colors/colors@1.5.0':
+    resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
+    engines: {node: '>=0.1.90'}
+
+  '@csstools/color-helpers@5.0.2':
+    resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==}
+    engines: {node: '>=18'}
+
+  '@csstools/css-calc@2.1.2':
+    resolution: {integrity: sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==}
+    engines: {node: '>=18'}
+    peerDependencies:
+      '@csstools/css-parser-algorithms': ^3.0.4
+      '@csstools/css-tokenizer': ^3.0.3
+
+  '@csstools/css-color-parser@3.0.8':
+    resolution: {integrity: sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==}
+    engines: {node: '>=18'}
+    peerDependencies:
+      '@csstools/css-parser-algorithms': ^3.0.4
+      '@csstools/css-tokenizer': ^3.0.3
+
+  '@csstools/css-parser-algorithms@3.0.4':
+    resolution: {integrity: sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==}
+    engines: {node: '>=18'}
+    peerDependencies:
+      '@csstools/css-tokenizer': ^3.0.3
+
+  '@csstools/css-tokenizer@3.0.3':
+    resolution: {integrity: sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==}
+    engines: {node: '>=18'}
+
+  '@ctrl/tinycolor@3.6.1':
+    resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==}
+    engines: {node: '>=10'}
+
+  '@cypress/request@3.0.8':
+    resolution: {integrity: sha512-h0NFgh1mJmm1nr4jCwkGHwKneVYKghUyWe6TMNrk0B9zsjAJxpg8C4/+BAcmLgCPa1vj1V8rNUaILl+zYRUWBQ==}
+    engines: {node: '>= 6'}
+
+  '@cypress/xvfb@1.2.4':
+    resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==}
+
+  '@element-plus/icons-vue@2.3.1':
+    resolution: {integrity: sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==}
+    peerDependencies:
+      vue: ^3.2.0
+
+  '@emnapi/core@1.4.0':
+    resolution: {integrity: sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==}
+
+  '@emnapi/runtime@1.4.0':
+    resolution: {integrity: sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==}
+
+  '@emnapi/wasi-threads@1.0.1':
+    resolution: {integrity: sha512-iIBu7mwkq4UQGeMEM8bLwNK962nXdhodeScX4slfQnRhEMMzvYivHhutCIk8uojvmASXXPC2WNEjwxFWk72Oqw==}
+
+  '@esbuild/aix-ppc64@0.25.1':
+    resolution: {integrity: sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [aix]
+
+  '@esbuild/android-arm64@0.25.1':
+    resolution: {integrity: sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [android]
+
+  '@esbuild/android-arm@0.25.1':
+    resolution: {integrity: sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [android]
+
+  '@esbuild/android-x64@0.25.1':
+    resolution: {integrity: sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [android]
+
+  '@esbuild/darwin-arm64@0.25.1':
+    resolution: {integrity: sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@esbuild/darwin-x64@0.25.1':
+    resolution: {integrity: sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@esbuild/freebsd-arm64@0.25.1':
+    resolution: {integrity: sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@esbuild/freebsd-x64@0.25.1':
+    resolution: {integrity: sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@esbuild/linux-arm64@0.25.1':
+    resolution: {integrity: sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@esbuild/linux-arm@0.25.1':
+    resolution: {integrity: sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==}
+    engines: {node: '>=18'}
+    cpu: [arm]
+    os: [linux]
+
+  '@esbuild/linux-ia32@0.25.1':
+    resolution: {integrity: sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [linux]
+
+  '@esbuild/linux-loong64@0.25.1':
+    resolution: {integrity: sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==}
+    engines: {node: '>=18'}
+    cpu: [loong64]
+    os: [linux]
+
+  '@esbuild/linux-mips64el@0.25.1':
+    resolution: {integrity: sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==}
+    engines: {node: '>=18'}
+    cpu: [mips64el]
+    os: [linux]
+
+  '@esbuild/linux-ppc64@0.25.1':
+    resolution: {integrity: sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==}
+    engines: {node: '>=18'}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@esbuild/linux-riscv64@0.25.1':
+    resolution: {integrity: sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==}
+    engines: {node: '>=18'}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@esbuild/linux-s390x@0.25.1':
+    resolution: {integrity: sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==}
+    engines: {node: '>=18'}
+    cpu: [s390x]
+    os: [linux]
+
+  '@esbuild/linux-x64@0.25.1':
+    resolution: {integrity: sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [linux]
+
+  '@esbuild/netbsd-arm64@0.25.1':
+    resolution: {integrity: sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [netbsd]
+
+  '@esbuild/netbsd-x64@0.25.1':
+    resolution: {integrity: sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [netbsd]
+
+  '@esbuild/openbsd-arm64@0.25.1':
+    resolution: {integrity: sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [openbsd]
+
+  '@esbuild/openbsd-x64@0.25.1':
+    resolution: {integrity: sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [openbsd]
+
+  '@esbuild/sunos-x64@0.25.1':
+    resolution: {integrity: sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [sunos]
+
+  '@esbuild/win32-arm64@0.25.1':
+    resolution: {integrity: sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==}
+    engines: {node: '>=18'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@esbuild/win32-ia32@0.25.1':
+    resolution: {integrity: sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==}
+    engines: {node: '>=18'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@esbuild/win32-x64@0.25.1':
+    resolution: {integrity: sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==}
+    engines: {node: '>=18'}
+    cpu: [x64]
+    os: [win32]
+
+  '@eslint-community/eslint-utils@4.5.1':
+    resolution: {integrity: sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+
+  '@eslint-community/regexpp@4.12.1':
+    resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+
+  '@eslint/config-array@0.19.2':
+    resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/config-helpers@0.1.0':
+    resolution: {integrity: sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/core@0.12.0':
+    resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/eslintrc@3.3.0':
+    resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/js@9.22.0':
+    resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/object-schema@2.1.6':
+    resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@eslint/plugin-kit@0.2.7':
+    resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@floating-ui/core@1.6.9':
+    resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==}
+
+  '@floating-ui/dom@1.6.13':
+    resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==}
+
+  '@floating-ui/utils@0.2.9':
+    resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
+
+  '@hapi/hoek@9.3.0':
+    resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
+
+  '@hapi/topo@5.1.0':
+    resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
+
+  '@humanfs/core@0.19.1':
+    resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
+    engines: {node: '>=18.18.0'}
+
+  '@humanfs/node@0.16.6':
+    resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==}
+    engines: {node: '>=18.18.0'}
+
+  '@humanwhocodes/module-importer@1.0.1':
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+
+  '@humanwhocodes/retry@0.3.1':
+    resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==}
+    engines: {node: '>=18.18'}
+
+  '@humanwhocodes/retry@0.4.2':
+    resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==}
+    engines: {node: '>=18.18'}
+
+  '@intlify/core-base@9.14.4':
+    resolution: {integrity: sha512-vtZCt7NqWhKEtHa3SD/322DlgP5uR9MqWxnE0y8Q0tjDs9H5Lxhss+b5wv8rmuXRoHKLESNgw9d+EN9ybBbj9g==}
+    engines: {node: '>= 16'}
+
+  '@intlify/message-compiler@9.14.4':
+    resolution: {integrity: sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==}
+    engines: {node: '>= 16'}
+
+  '@intlify/shared@9.14.4':
+    resolution: {integrity: sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==}
+    engines: {node: '>= 16'}
+
+  '@isaacs/cliui@8.0.2':
+    resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+    engines: {node: '>=12'}
+
+  '@jridgewell/gen-mapping@0.3.8':
+    resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/resolve-uri@3.1.2':
+    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/set-array@1.2.1':
+    resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}
+    engines: {node: '>=6.0.0'}
+
+  '@jridgewell/sourcemap-codec@1.5.0':
+    resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}
+
+  '@jridgewell/trace-mapping@0.3.25':
+    resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+
+  '@napi-rs/wasm-runtime@0.2.8':
+    resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==}
+
+  '@nodelib/fs.scandir@2.1.5':
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.stat@2.0.5':
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+
+  '@nodelib/fs.walk@1.2.8':
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+
+  '@one-ini/wasm@0.1.1':
+    resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
+
+  '@oxlint/darwin-arm64@0.15.15':
+    resolution: {integrity: sha512-7GOyGM6D36lUhsOvavAVpF72SycPVG0Enunx0bzv8g0+9TklzOSFN3FJlZjLst14VPdZWujZMLgkQC7tOp+Rwg==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@oxlint/darwin-x64@0.15.15':
+    resolution: {integrity: sha512-pbrnYFwMn/fuX0z3IeQ05Nvo/b1zGxjmmWgkrQSDwYHxBxP6NT41hk1pmqkcA+v53xk9wvOa/6vBBI/U30F8Ow==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@oxlint/linux-arm64-gnu@0.15.15':
+    resolution: {integrity: sha512-QWjG3YVsDlIvDTBUPmtPiyqP34ZQpFJqQh2JO94pBih11lFxQ0IGVMEXDhmW3WdiSFPZSJsZGzWynalM9eg+RA==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@oxlint/linux-arm64-musl@0.15.15':
+    resolution: {integrity: sha512-4W0YsmMSbNzzExOWhk+6zNfmJEmKFqSjFIn8CKLtYFvH8kF6KjoW4/0HNsDNYW5Fz+KOut/2JgkvxAiKH+r0zA==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@oxlint/linux-x64-gnu@0.15.15':
+    resolution: {integrity: sha512-agP3e+eQ6tE5tqN6VI4Uukx2yvjwYFjtrDMcB19J7PmGOaFRwuMuT0sNWK/9guvhuS9aCINNZTi3kEhMy9Qgng==}
+    cpu: [x64]
+    os: [linux]
+
+  '@oxlint/linux-x64-musl@0.15.15':
+    resolution: {integrity: sha512-L2qE9NhhUafsJOO4pofLx/0hW5IB0sfJa6bS85q0j+ySaI0f3CxMaAadrZLFSuqHWB3oF18B5yvzaPWsc2ohbQ==}
+    cpu: [x64]
+    os: [linux]
+
+  '@oxlint/win32-arm64@0.15.15':
+    resolution: {integrity: sha512-B7f4VAS/E78n8zy6XZlNeyYOtWTel4BJn/22Ap2yEAlNzO34ot8dGfpLk6MqTUWJrRnARwVBVmc3wRVrsOT5yg==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@oxlint/win32-x64@0.15.15':
+    resolution: {integrity: sha512-ZM9T3/OpaQ3qvrk/VuHO2EQmhNH4cOZdr/b/Ju9VKwBr+ahhqMn3W5srrplWQWxfsb0yd1yBj7iD0jdAps2iLg==}
+    cpu: [x64]
+    os: [win32]
+
+  '@parcel/watcher-android-arm64@2.5.1':
+    resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm64]
+    os: [android]
+
+  '@parcel/watcher-darwin-arm64@2.5.1':
+    resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@parcel/watcher-darwin-x64@2.5.1':
+    resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [x64]
+    os: [darwin]
+
+  '@parcel/watcher-freebsd-x64@2.5.1':
+    resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@parcel/watcher-linux-arm-glibc@2.5.1':
+    resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm]
+    os: [linux]
+
+  '@parcel/watcher-linux-arm-musl@2.5.1':
+    resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm]
+    os: [linux]
+
+  '@parcel/watcher-linux-arm64-glibc@2.5.1':
+    resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@parcel/watcher-linux-arm64-musl@2.5.1':
+    resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm64]
+    os: [linux]
+
+  '@parcel/watcher-linux-x64-glibc@2.5.1':
+    resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@parcel/watcher-linux-x64-musl@2.5.1':
+    resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [x64]
+    os: [linux]
+
+  '@parcel/watcher-win32-arm64@2.5.1':
+    resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [arm64]
+    os: [win32]
+
+  '@parcel/watcher-win32-ia32@2.5.1':
+    resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [ia32]
+    os: [win32]
+
+  '@parcel/watcher-win32-x64@2.5.1':
+    resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+    engines: {node: '>= 10.0.0'}
+    cpu: [x64]
+    os: [win32]
+
+  '@parcel/watcher@2.5.1':
+    resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+    engines: {node: '>= 10.0.0'}
+
+  '@pkgjs/parseargs@0.11.0':
+    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+    engines: {node: '>=14'}
+
+  '@pkgr/core@0.1.2':
+    resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==}
+    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+
+  '@polka/url@1.0.0-next.28':
+    resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==}
+
+  '@rollup/pluginutils@5.1.4':
+    resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==}
+    engines: {node: '>=14.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+    peerDependenciesMeta:
+      rollup:
+        optional: true
+
+  '@rollup/rollup-android-arm-eabi@4.35.0':
+    resolution: {integrity: sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ==}
+    cpu: [arm]
+    os: [android]
+
+  '@rollup/rollup-android-arm64@4.35.0':
+    resolution: {integrity: sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA==}
+    cpu: [arm64]
+    os: [android]
+
+  '@rollup/rollup-darwin-arm64@4.35.0':
+    resolution: {integrity: sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@rollup/rollup-darwin-x64@4.35.0':
+    resolution: {integrity: sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@rollup/rollup-freebsd-arm64@4.35.0':
+    resolution: {integrity: sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ==}
+    cpu: [arm64]
+    os: [freebsd]
+
+  '@rollup/rollup-freebsd-x64@4.35.0':
+    resolution: {integrity: sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw==}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.35.0':
+    resolution: {integrity: sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm-musleabihf@4.35.0':
+    resolution: {integrity: sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A==}
+    cpu: [arm]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-gnu@4.35.0':
+    resolution: {integrity: sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-arm64-musl@4.35.0':
+    resolution: {integrity: sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.35.0':
+    resolution: {integrity: sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g==}
+    cpu: [loong64]
+    os: [linux]
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.35.0':
+    resolution: {integrity: sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@rollup/rollup-linux-riscv64-gnu@4.35.0':
+    resolution: {integrity: sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@rollup/rollup-linux-s390x-gnu@4.35.0':
+    resolution: {integrity: sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-gnu@4.35.0':
+    resolution: {integrity: sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-linux-x64-musl@4.35.0':
+    resolution: {integrity: sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg==}
+    cpu: [x64]
+    os: [linux]
+
+  '@rollup/rollup-win32-arm64-msvc@4.35.0':
+    resolution: {integrity: sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@rollup/rollup-win32-ia32-msvc@4.35.0':
+    resolution: {integrity: sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@rollup/rollup-win32-x64-msvc@4.35.0':
+    resolution: {integrity: sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw==}
+    cpu: [x64]
+    os: [win32]
+
+  '@sec-ant/readable-stream@0.4.1':
+    resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
+
+  '@sideway/address@4.1.5':
+    resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
+
+  '@sideway/formula@3.0.1':
+    resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
+
+  '@sideway/pinpoint@2.0.0':
+    resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
+
+  '@sindresorhus/merge-streams@4.0.0':
+    resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==}
+    engines: {node: '>=18'}
+
+  '@sxzz/popperjs-es@2.11.7':
+    resolution: {integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==}
+
+  '@tsconfig/node22@22.0.0':
+    resolution: {integrity: sha512-twLQ77zevtxobBOD4ToAtVmuYrpeYUh3qh+TEp+08IWhpsrIflVHqQ1F1CiPxQGL7doCdBIOOCF+1Tm833faNg==}
+
+  '@tybys/wasm-util@0.9.0':
+    resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
+
+  '@types/estree@1.0.6':
+    resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+
+  '@types/jsdom@21.1.7':
+    resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==}
+
+  '@types/json-schema@7.0.15':
+    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+  '@types/lodash-es@4.17.12':
+    resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
+
+  '@types/lodash@4.17.16':
+    resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==}
+
+  '@types/node@22.13.10':
+    resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==}
+
+  '@types/sinonjs__fake-timers@8.1.1':
+    resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
+
+  '@types/sizzle@2.3.9':
+    resolution: {integrity: sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==}
+
+  '@types/tough-cookie@4.0.5':
+    resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
+
+  '@types/web-bluetooth@0.0.16':
+    resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
+
+  '@types/web-bluetooth@0.0.21':
+    resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
+
+  '@types/yauzl@2.10.3':
+    resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==}
+
+  '@typescript-eslint/eslint-plugin@8.26.1':
+    resolution: {integrity: sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
+
+  '@typescript-eslint/parser@8.26.1':
+    resolution: {integrity: sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
+
+  '@typescript-eslint/scope-manager@8.26.1':
+    resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@typescript-eslint/type-utils@8.26.1':
+    resolution: {integrity: sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
+
+  '@typescript-eslint/types@8.26.1':
+    resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@typescript-eslint/typescript-estree@8.26.1':
+    resolution: {integrity: sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      typescript: '>=4.8.4 <5.9.0'
+
+  '@typescript-eslint/utils@8.26.1':
+    resolution: {integrity: sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
+
+  '@typescript-eslint/visitor-keys@8.26.1':
+    resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  '@unrs/resolver-binding-darwin-arm64@1.5.0':
+    resolution: {integrity: sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==}
+    cpu: [arm64]
+    os: [darwin]
+
+  '@unrs/resolver-binding-darwin-x64@1.5.0':
+    resolution: {integrity: sha512-qpUrXgH4e/0xu1LOhPEdfgSY3vIXOxDQv370NEL8npN8h40HcQDA+Pl2r4HBW6tTXezWIjxUFcP7tj529RZtDw==}
+    cpu: [x64]
+    os: [darwin]
+
+  '@unrs/resolver-binding-freebsd-x64@1.5.0':
+    resolution: {integrity: sha512-3tX8r8vgjvZzaJZB4jvxUaaFCDCb3aWDCpZN3EjhGnnwhztslI05KSG5NY/jNjlcZ5QWZ7dEZZ/rNBFsmTaSPw==}
+    cpu: [x64]
+    os: [freebsd]
+
+  '@unrs/resolver-binding-linux-arm-gnueabihf@1.5.0':
+    resolution: {integrity: sha512-FH+ixzBKaUU9fWOj3TYO+Yn/eO6kYvMLV9eNJlJlkU7OgrxkCmiMS6wUbyT0KA3FOZGxnEQ2z3/BHgYm2jqeLA==}
+    cpu: [arm]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-arm-musleabihf@1.5.0':
+    resolution: {integrity: sha512-pxCgXMgwB/4PfqFQg73lMhmWwcC0j5L+dNXhZoz/0ek0iS/oAWl65fxZeT/OnU7fVs52MgdP2q02EipqJJXHSg==}
+    cpu: [arm]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-arm64-gnu@1.5.0':
+    resolution: {integrity: sha512-FX2FV7vpLE/+Z0NZX9/1pwWud5Wocm/2PgpUXbT5aSV3QEB10kBPJAzssOQylvdj8mOHoKl5pVkXpbCwww/T2g==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-arm64-musl@1.5.0':
+    resolution: {integrity: sha512-+gF97xst1BZb28T3nwwzEtq2ewCoMDGKsenYsZuvpmNrW0019G1iUAunZN+FG55L21y+uP7zsGX06OXDQ/viKw==}
+    cpu: [arm64]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-ppc64-gnu@1.5.0':
+    resolution: {integrity: sha512-5bEmVcQw9js8JYM2LkUBw5SeELSIxX+qKf9bFrfFINKAp4noZ//hUxLpbF7u/3gTBN1GsER6xOzIZlw/VTdXtA==}
+    cpu: [ppc64]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-riscv64-gnu@1.5.0':
+    resolution: {integrity: sha512-GGk/8TPUsf1Q99F+lzMdjE6sGL26uJCwQ9TlvBs8zR3cLQNw/MIumPN7zrs3GFGySjnwXc8gA6J3HKbejywmqA==}
+    cpu: [riscv64]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-s390x-gnu@1.5.0':
+    resolution: {integrity: sha512-5uRkFYYVNAeVaA4W/CwugjFN3iDOHCPqsBLCCOoJiMfFMMz4evBRsg+498OFa9w6VcTn2bD5aI+RRayaIgk2Sw==}
+    cpu: [s390x]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-x64-gnu@1.5.0':
+    resolution: {integrity: sha512-j905CZH3nehYy6NimNqC2B14pxn4Ltd7guKMyPTzKehbFXTUgihQS/ZfHQTdojkMzbSwBOSgq1dOrY+IpgxDsA==}
+    cpu: [x64]
+    os: [linux]
+
+  '@unrs/resolver-binding-linux-x64-musl@1.5.0':
+    resolution: {integrity: sha512-dmLevQTuzQRwu5A+mvj54R5aye5I4PVKiWqGxg8tTaYP2k2oTs/3Mo8mgnhPk28VoYCi0fdFYpgzCd4AJndQvQ==}
+    cpu: [x64]
+    os: [linux]
+
+  '@unrs/resolver-binding-wasm32-wasi@1.5.0':
+    resolution: {integrity: sha512-LtJMhwu7avhoi+kKfAZOKN773RtzLBVVF90YJbB0wyMpUj9yQPeA+mteVUI9P70OG/opH47FeV5AWeaNWWgqJg==}
+    engines: {node: '>=14.0.0'}
+    cpu: [wasm32]
+
+  '@unrs/resolver-binding-win32-arm64-msvc@1.5.0':
+    resolution: {integrity: sha512-FTZBxLL4SO1mgIM86KykzJmPeTPisBDHQV6xtfDXbTMrentuZ6SdQKJUV5BWaoUK3p8kIULlrCcucqdCnk8Npg==}
+    cpu: [arm64]
+    os: [win32]
+
+  '@unrs/resolver-binding-win32-ia32-msvc@1.5.0':
+    resolution: {integrity: sha512-i5bB7vJ1waUsFciU/FKLd4Zw0VnAkvhiJ4//jYQXyDUuiLKodmtQZVTcOPU7pp97RrNgCFtXfC1gnvj/DHPJTw==}
+    cpu: [ia32]
+    os: [win32]
+
+  '@unrs/resolver-binding-win32-x64-msvc@1.5.0':
+    resolution: {integrity: sha512-wAvXp4k7jhioi4SebXW/yfzzYwsUCr9kIX4gCsUFKpCTUf8Mi7vScJXI3S+kupSUf0LbVHudR8qBbe2wFMSNUw==}
+    cpu: [x64]
+    os: [win32]
+
+  '@vitejs/plugin-vue-jsx@4.1.1':
+    resolution: {integrity: sha512-uMJqv/7u1zz/9NbWAD3XdjaY20tKTf17XVfQ9zq4wY1BjsB/PjpJPMe2xiG39QpP4ZdhYNhm4Hvo66uJrykNLA==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    peerDependencies:
+      vite: ^5.0.0 || ^6.0.0
+      vue: ^3.0.0
+
+  '@vitejs/plugin-vue@5.2.1':
+    resolution: {integrity: sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+    peerDependencies:
+      vite: ^5.0.0 || ^6.0.0
+      vue: ^3.2.25
+
+  '@vitest/eslint-plugin@1.1.38':
+    resolution: {integrity: sha512-KcOTZyVz8RiM5HyriiDVrP1CyBGuhRxle+lBsmSs6NTJEO/8dKVAq+f5vQzHj1/Kc7bYXSDO6yBe62Zx0t5iaw==}
+    peerDependencies:
+      '@typescript-eslint/utils': ^8.24.0
+      eslint: '>= 8.57.0'
+      typescript: '>= 5.0.0'
+      vitest: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+      vitest:
+        optional: true
+
+  '@vitest/expect@3.0.9':
+    resolution: {integrity: sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==}
+
+  '@vitest/mocker@3.0.9':
+    resolution: {integrity: sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==}
+    peerDependencies:
+      msw: ^2.4.9
+      vite: ^5.0.0 || ^6.0.0
+    peerDependenciesMeta:
+      msw:
+        optional: true
+      vite:
+        optional: true
+
+  '@vitest/pretty-format@3.0.9':
+    resolution: {integrity: sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==}
+
+  '@vitest/runner@3.0.9':
+    resolution: {integrity: sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==}
+
+  '@vitest/snapshot@3.0.9':
+    resolution: {integrity: sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==}
+
+  '@vitest/spy@3.0.9':
+    resolution: {integrity: sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==}
+
+  '@vitest/utils@3.0.9':
+    resolution: {integrity: sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==}
+
+  '@volar/language-core@2.4.12':
+    resolution: {integrity: sha512-RLrFdXEaQBWfSnYGVxvR2WrO6Bub0unkdHYIdC31HzIEqATIuuhRRzYu76iGPZ6OtA4Au1SnW0ZwIqPP217YhA==}
+
+  '@volar/source-map@2.4.12':
+    resolution: {integrity: sha512-bUFIKvn2U0AWojOaqf63ER0N/iHIBYZPpNGogfLPQ68F5Eet6FnLlyho7BS0y2HJ1jFhSif7AcuTx1TqsCzRzw==}
+
+  '@volar/typescript@2.4.12':
+    resolution: {integrity: sha512-HJB73OTJDgPc80K30wxi3if4fSsZZAOScbj2fcicMuOPoOkcf9NNAINb33o+DzhBdF9xTKC1gnPmIRDous5S0g==}
+
+  '@vue/babel-helper-vue-transform-on@1.4.0':
+    resolution: {integrity: sha512-mCokbouEQ/ocRce/FpKCRItGo+013tHg7tixg3DUNS+6bmIchPt66012kBMm476vyEIJPafrvOf4E5OYj3shSw==}
+
+  '@vue/babel-plugin-jsx@1.4.0':
+    resolution: {integrity: sha512-9zAHmwgMWlaN6qRKdrg1uKsBKHvnUU+Py+MOCTuYZBoZsopa90Di10QRjB+YPnVss0BZbG/H5XFwJY1fTxJWhA==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+    peerDependenciesMeta:
+      '@babel/core':
+        optional: true
+
+  '@vue/babel-plugin-resolve-type@1.4.0':
+    resolution: {integrity: sha512-4xqDRRbQQEWHQyjlYSgZsWj44KfiF6D+ktCuXyZ8EnVDYV3pztmXJDf1HveAjUAXxAnR8daCQT51RneWWxtTyQ==}
+    peerDependencies:
+      '@babel/core': ^7.0.0-0
+
+  '@vue/compiler-core@3.5.13':
+    resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==}
+
+  '@vue/compiler-dom@3.5.13':
+    resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==}
+
+  '@vue/compiler-sfc@3.5.13':
+    resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==}
+
+  '@vue/compiler-ssr@3.5.13':
+    resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==}
+
+  '@vue/compiler-vue2@2.7.16':
+    resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==}
+
+  '@vue/devtools-api@6.6.4':
+    resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
+
+  '@vue/devtools-api@7.7.2':
+    resolution: {integrity: sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA==}
+
+  '@vue/devtools-core@7.7.2':
+    resolution: {integrity: sha512-lexREWj1lKi91Tblr38ntSsy6CvI8ba7u+jmwh2yruib/ltLUcsIzEjCnrkh1yYGGIKXbAuYV2tOG10fGDB9OQ==}
+    peerDependencies:
+      vue: ^3.0.0
+
+  '@vue/devtools-kit@7.7.2':
+    resolution: {integrity: sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==}
+
+  '@vue/devtools-shared@7.7.2':
+    resolution: {integrity: sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==}
+
+  '@vue/eslint-config-prettier@10.2.0':
+    resolution: {integrity: sha512-GL3YBLwv/+b86yHcNNfPJxOTtVFJ4Mbc9UU3zR+KVoG7SwGTjPT+32fXamscNumElhcpXW3mT0DgzS9w32S7Bw==}
+    peerDependencies:
+      eslint: '>= 8.21.0'
+      prettier: '>= 3.0.0'
+
+  '@vue/eslint-config-typescript@14.5.0':
+    resolution: {integrity: sha512-5oPOyuwkw++AP5gHDh5YFmST50dPfWOcm3/W7Nbh42IK5O3H74ytWAw0TrCRTaBoD/02khnWXuZf1Bz1xflavQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^9.10.0
+      eslint-plugin-vue: ^9.28.0 || ^10.0.0
+      typescript: '>=4.8.4'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@vue/language-core@2.2.8':
+    resolution: {integrity: sha512-rrzB0wPGBvcwaSNRriVWdNAbHQWSf0NlGqgKHK5mEkXpefjUlVRP62u03KvwZpvKVjRnBIQ/Lwre+Mx9N6juUQ==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  '@vue/reactivity@3.5.13':
+    resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==}
+
+  '@vue/runtime-core@3.5.13':
+    resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==}
+
+  '@vue/runtime-dom@3.5.13':
+    resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==}
+
+  '@vue/server-renderer@3.5.13':
+    resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==}
+    peerDependencies:
+      vue: 3.5.13
+
+  '@vue/shared@3.5.13':
+    resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==}
+
+  '@vue/test-utils@2.4.6':
+    resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
+
+  '@vue/tsconfig@0.7.0':
+    resolution: {integrity: sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==}
+    peerDependencies:
+      typescript: 5.x
+      vue: ^3.4.0
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+      vue:
+        optional: true
+
+  '@vueuse/core@13.0.0':
+    resolution: {integrity: sha512-rkgb4a8/0b234lMGCT29WkCjPfsX0oxrIRR7FDndRoW3FsaC9NBzefXg/9TLhAgwM11f49XnutshM4LzJBrQ5g==}
+    peerDependencies:
+      vue: ^3.5.0
+
+  '@vueuse/core@9.13.0':
+    resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
+
+  '@vueuse/integrations@13.0.0':
+    resolution: {integrity: sha512-PXARslYRWf4u0xjdW6N5eC5kVQj2z/dxfZ7ildI1okLm2AwmhL+wiWzaNMSJMxTKX4ew7kNe70yJg1QjnWmE5w==}
+    peerDependencies:
+      async-validator: ^4
+      axios: ^1
+      change-case: ^5
+      drauu: ^0.4
+      focus-trap: ^7
+      fuse.js: ^7
+      idb-keyval: ^6
+      jwt-decode: ^4
+      nprogress: ^0.2
+      qrcode: ^1.5
+      sortablejs: ^1
+      universal-cookie: ^7
+      vue: ^3.5.0
+    peerDependenciesMeta:
+      async-validator:
+        optional: true
+      axios:
+        optional: true
+      change-case:
+        optional: true
+      drauu:
+        optional: true
+      focus-trap:
+        optional: true
+      fuse.js:
+        optional: true
+      idb-keyval:
+        optional: true
+      jwt-decode:
+        optional: true
+      nprogress:
+        optional: true
+      qrcode:
+        optional: true
+      sortablejs:
+        optional: true
+      universal-cookie:
+        optional: true
+
+  '@vueuse/metadata@13.0.0':
+    resolution: {integrity: sha512-TRNksqmvtvqsuHf7bbgH9OSXEV2b6+M3BSN4LR5oxWKykOFT9gV78+C2/0++Pq9KCp9KQ1OQDPvGlWNQpOb2Mw==}
+
+  '@vueuse/metadata@9.13.0':
+    resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
+
+  '@vueuse/shared@13.0.0':
+    resolution: {integrity: sha512-9MiHhAPw+sqCF/RLo8V6HsjRqEdNEWVpDLm2WBRW2G/kSQjb8X901sozXpSCaeLG0f7TEfMrT4XNaA5m1ez7Dg==}
+    peerDependencies:
+      vue: ^3.5.0
+
+  '@vueuse/shared@9.13.0':
+    resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
+
+  abbrev@2.0.0:
+    resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+
+  acorn-jsx@5.3.2:
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+
+  acorn@8.14.1:
+    resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}
+    engines: {node: '>=0.4.0'}
+    hasBin: true
+
+  agent-base@7.1.3:
+    resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
+    engines: {node: '>= 14'}
+
+  aggregate-error@3.1.0:
+    resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+    engines: {node: '>=8'}
+
+  ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+
+  alien-signals@1.0.7:
+    resolution: {integrity: sha512-OfUBerxNtc4PsNwkSu8KVHMOJUKmFLmLmeYsBBTnwzlezm+LmvJk31iE7Ggk1hS/S7GIrn9QNGm+NlkhxJmMQQ==}
+
+  ansi-colors@4.1.3:
+    resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
+    engines: {node: '>=6'}
+
+  ansi-escapes@4.3.2:
+    resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+    engines: {node: '>=8'}
+
+  ansi-regex@5.0.1:
+    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+    engines: {node: '>=8'}
+
+  ansi-regex@6.1.0:
+    resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==}
+    engines: {node: '>=12'}
+
+  ansi-styles@4.3.0:
+    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+    engines: {node: '>=8'}
+
+  ansi-styles@6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+
+  anymatch@3.1.3:
+    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
+    engines: {node: '>= 8'}
+
+  arch@2.2.0:
+    resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
+
+  arg@5.0.2:
+    resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
+
+  argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+  asn1@0.2.6:
+    resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+
+  assert-plus@1.0.0:
+    resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==}
+    engines: {node: '>=0.8'}
+
+  assertion-error@2.0.1:
+    resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+    engines: {node: '>=12'}
+
+  astral-regex@2.0.0:
+    resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+    engines: {node: '>=8'}
+
+  async-validator@4.2.5:
+    resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
+
+  async@3.2.3:
+    resolution: {integrity: sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==}
+
+  asynckit@0.4.0:
+    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
+  at-least-node@1.0.0:
+    resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
+    engines: {node: '>= 4.0.0'}
+
+  autoprefixer@10.4.21:
+    resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==}
+    engines: {node: ^10 || ^12 || >=14}
+    hasBin: true
+    peerDependencies:
+      postcss: ^8.1.0
+
+  aws-sign2@0.7.0:
+    resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
+
+  aws4@1.13.2:
+    resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==}
+
+  axios@1.8.4:
+    resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
+
+  balanced-match@1.0.2:
+    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+
+  base64-js@1.5.1:
+    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+  bcrypt-pbkdf@1.0.2:
+    resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==}
+
+  binary-extensions@2.3.0:
+    resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
+    engines: {node: '>=8'}
+
+  birpc@0.2.19:
+    resolution: {integrity: sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==}
+
+  blob-util@2.0.2:
+    resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
+
+  bluebird@3.7.2:
+    resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+
+  boolbase@1.0.0:
+    resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+
+  brace-expansion@1.1.11:
+    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+
+  brace-expansion@2.0.1:
+    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
+
+  braces@3.0.3:
+    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+    engines: {node: '>=8'}
+
+  browserslist@4.24.4:
+    resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
+    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+    hasBin: true
+
+  buffer-crc32@0.2.13:
+    resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+
+  buffer@5.7.1:
+    resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+
+  bundle-name@4.1.0:
+    resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
+    engines: {node: '>=18'}
+
+  cac@6.7.14:
+    resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+    engines: {node: '>=8'}
+
+  cachedir@2.4.0:
+    resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==}
+    engines: {node: '>=6'}
+
+  call-bind-apply-helpers@1.0.2:
+    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
+    engines: {node: '>= 0.4'}
+
+  call-bound@1.0.4:
+    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}
+    engines: {node: '>= 0.4'}
+
+  callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+
+  caniuse-lite@1.0.30001705:
+    resolution: {integrity: sha512-S0uyMMiYvA7CxNgomYBwwwPUnWzFD83f3B1ce5jHUfHTH//QL6hHsreI8RVC5606R4ssqravelYO5TU6t8sEyg==}
+
+  caseless@0.12.0:
+    resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
+
+  chai@5.2.0:
+    resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
+    engines: {node: '>=12'}
+
+  chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+
+  check-error@2.1.1:
+    resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
+    engines: {node: '>= 16'}
+
+  check-more-types@2.24.0:
+    resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==}
+    engines: {node: '>= 0.8.0'}
+
+  chokidar@3.6.0:
+    resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
+    engines: {node: '>= 8.10.0'}
+
+  chokidar@4.0.3:
+    resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
+    engines: {node: '>= 14.16.0'}
+
+  ci-info@4.2.0:
+    resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==}
+    engines: {node: '>=8'}
+
+  clean-stack@2.2.0:
+    resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+    engines: {node: '>=6'}
+
+  cli-cursor@3.1.0:
+    resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+    engines: {node: '>=8'}
+
+  cli-table3@0.6.5:
+    resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==}
+    engines: {node: 10.* || >= 12.*}
+
+  cli-truncate@2.1.0:
+    resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
+    engines: {node: '>=8'}
+
+  color-convert@2.0.1:
+    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+    engines: {node: '>=7.0.0'}
+
+  color-name@1.1.4:
+    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+  colorette@2.0.20:
+    resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+
+  combined-stream@1.0.8:
+    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+    engines: {node: '>= 0.8'}
+
+  commander@10.0.1:
+    resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
+    engines: {node: '>=14'}
+
+  commander@6.2.1:
+    resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
+    engines: {node: '>= 6'}
+
+  common-tags@1.8.2:
+    resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
+    engines: {node: '>=4.0.0'}
+
+  concat-map@0.0.1:
+    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
+
+  confbox@0.1.8:
+    resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
+
+  confbox@0.2.2:
+    resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
+
+  config-chain@1.1.13:
+    resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+
+  convert-source-map@2.0.0:
+    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+  cookie@1.0.2:
+    resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
+    engines: {node: '>=18'}
+
+  copy-anything@2.0.6:
+    resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==}
+
+  copy-anything@3.0.5:
+    resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
+    engines: {node: '>=12.13'}
+
+  core-util-is@1.0.2:
+    resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==}
+
+  cross-spawn@7.0.6:
+    resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
+    engines: {node: '>= 8'}
+
+  cssesc@3.0.0:
+    resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  cssstyle@4.3.0:
+    resolution: {integrity: sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==}
+    engines: {node: '>=18'}
+
+  csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+  cypress@14.2.0:
+    resolution: {integrity: sha512-u7fuc9JEpSYLOdu8mzZDZ/JWsHUzR5pc8i1TeSqMz/bafXp+6IweMAeyphsEJ6/13qbB6nwTEY1m+GUAp6GqCQ==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+
+  dashdash@1.14.1:
+    resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==}
+    engines: {node: '>=0.10'}
+
+  data-urls@5.0.0:
+    resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+    engines: {node: '>=18'}
+
+  dayjs@1.11.13:
+    resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
+
+  de-indent@1.0.2:
+    resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
+
+  debug@3.2.7:
+    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  debug@4.4.0:
+    resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+    engines: {node: '>=6.0'}
+    peerDependencies:
+      supports-color: '*'
+    peerDependenciesMeta:
+      supports-color:
+        optional: true
+
+  decimal.js@10.5.0:
+    resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}
+
+  decode-uri-component@0.4.1:
+    resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==}
+    engines: {node: '>=14.16'}
+
+  deep-eql@5.0.2:
+    resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+    engines: {node: '>=6'}
+
+  deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+
+  default-browser-id@5.0.0:
+    resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==}
+    engines: {node: '>=18'}
+
+  default-browser@5.2.1:
+    resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==}
+    engines: {node: '>=18'}
+
+  define-lazy-prop@3.0.0:
+    resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
+    engines: {node: '>=12'}
+
+  delayed-stream@1.0.0:
+    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+    engines: {node: '>=0.4.0'}
+
+  detect-libc@1.0.3:
+    resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+    engines: {node: '>=0.10'}
+    hasBin: true
+
+  dunder-proto@1.0.1:
+    resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
+    engines: {node: '>= 0.4'}
+
+  duplexer@0.1.2:
+    resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
+
+  eastasianwidth@0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+
+  ecc-jsbn@0.1.2:
+    resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
+
+  editorconfig@1.0.4:
+    resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  electron-to-chromium@1.5.119:
+    resolution: {integrity: sha512-Ku4NMzUjz3e3Vweh7PhApPrZSS4fyiCIbcIrG9eKrriYVLmbMepETR/v6SU7xPm98QTqMSYiCwfO89QNjXLkbQ==}
+
+  element-plus@2.9.7:
+    resolution: {integrity: sha512-6vjZh5SXBncLhUwJGTVKS5oDljfgGMh6J4zVTeAZK3YdMUN76FgpvHkwwFXocpJpMbii6rDYU3sgie64FyPerQ==}
+    peerDependencies:
+      vue: ^3.2.0
+
+  emoji-regex@8.0.0:
+    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+
+  emoji-regex@9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+
+  end-of-stream@1.4.4:
+    resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+
+  enquirer@2.4.1:
+    resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==}
+    engines: {node: '>=8.6'}
+
+  entities@4.5.0:
+    resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+    engines: {node: '>=0.12'}
+
+  errno@0.1.8:
+    resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
+    hasBin: true
+
+  error-stack-parser-es@0.1.5:
+    resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==}
+
+  es-define-property@1.0.1:
+    resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
+    engines: {node: '>= 0.4'}
+
+  es-errors@1.3.0:
+    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+    engines: {node: '>= 0.4'}
+
+  es-module-lexer@1.6.0:
+    resolution: {integrity: sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==}
+
+  es-object-atoms@1.1.1:
+    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
+    engines: {node: '>= 0.4'}
+
+  es-set-tostringtag@2.1.0:
+    resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
+    engines: {node: '>= 0.4'}
+
+  esbuild@0.25.1:
+    resolution: {integrity: sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==}
+    engines: {node: '>=18'}
+    hasBin: true
+
+  escalade@3.2.0:
+    resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+    engines: {node: '>=6'}
+
+  escape-html@1.0.3:
+    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
+
+  escape-string-regexp@1.0.5:
+    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
+    engines: {node: '>=0.8.0'}
+
+  escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+
+  escape-string-regexp@5.0.0:
+    resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
+    engines: {node: '>=12'}
+
+  eslint-config-prettier@10.1.1:
+    resolution: {integrity: sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==}
+    hasBin: true
+    peerDependencies:
+      eslint: '>=7.0.0'
+
+  eslint-import-resolver-typescript@4.3.2:
+    resolution: {integrity: sha512-T2LqBXj87ndEC9t1LrDiPkzalSFzD4rrXr6BTzGdgMx1jdQM4T972guQvg7Ih+LNO51GURXI/qMHS5GF3h1ilw==}
+    engines: {node: ^16.17.0 || >=18.6.0}
+    peerDependencies:
+      eslint: '*'
+      eslint-plugin-import: '*'
+      eslint-plugin-import-x: '*'
+    peerDependenciesMeta:
+      eslint-plugin-import:
+        optional: true
+      eslint-plugin-import-x:
+        optional: true
+
+  eslint-plugin-cypress@4.2.0:
+    resolution: {integrity: sha512-v5cyt0VYb1tEEODBJSE44PocYOwQsckyexJhCs7LtdD3FGO6D2GjnZB2s2Sts4RcxdxECTWX01nObOZRs26bQw==}
+    peerDependencies:
+      eslint: '>=9'
+
+  eslint-plugin-oxlint@0.15.15:
+    resolution: {integrity: sha512-n5RJ3INUx5eqeOvdtr+5+bOK070NF52C0qxa7any7vnvA8GqoFP6vMOYQ966DhmOc69bunzvoVHk/Fis0a/yAQ==}
+
+  eslint-plugin-prettier@5.2.3:
+    resolution: {integrity: sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      '@types/eslint': '>=8.0.0'
+      eslint: '>=8.0.0'
+      eslint-config-prettier: '*'
+      prettier: '>=3.0.0'
+    peerDependenciesMeta:
+      '@types/eslint':
+        optional: true
+      eslint-config-prettier:
+        optional: true
+
+  eslint-plugin-vue@10.0.0:
+    resolution: {integrity: sha512-XKckedtajqwmaX6u1VnECmZ6xJt+YvlmMzBPZd+/sI3ub2lpYZyFnsyWo7c3nMOQKJQudeyk1lw/JxdgeKT64w==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      vue-eslint-parser: ^10.0.0
+
+  eslint-scope@8.3.0:
+    resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  eslint-visitor-keys@3.4.3:
+    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+
+  eslint-visitor-keys@4.2.0:
+    resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  eslint@9.22.0:
+    resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    hasBin: true
+    peerDependencies:
+      jiti: '*'
+    peerDependenciesMeta:
+      jiti:
+        optional: true
+
+  espree@10.3.0:
+    resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
+  esquery@1.6.0:
+    resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}
+    engines: {node: '>=0.10'}
+
+  esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+
+  estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+
+  estree-walker@2.0.2:
+    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
+  estree-walker@3.0.3:
+    resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
+
+  esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+
+  event-stream@3.3.4:
+    resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==}
+
+  eventemitter2@6.4.7:
+    resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
+
+  execa@4.1.0:
+    resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
+    engines: {node: '>=10'}
+
+  execa@5.1.1:
+    resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+    engines: {node: '>=10'}
+
+  execa@9.5.2:
+    resolution: {integrity: sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==}
+    engines: {node: ^18.19.0 || >=20.5.0}
+
+  executable@4.1.1:
+    resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
+    engines: {node: '>=4'}
+
+  expect-type@1.2.0:
+    resolution: {integrity: sha512-80F22aiJ3GLyVnS/B3HzgR6RelZVumzj9jkL0Rhz4h0xYbNW9PjlQz5h3J/SShErbXBc295vseR4/MIbVmUbeA==}
+    engines: {node: '>=12.0.0'}
+
+  exsolve@1.0.5:
+    resolution: {integrity: sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==}
+
+  extend@3.0.2:
+    resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+
+  extract-zip@2.0.1:
+    resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
+    engines: {node: '>= 10.17.0'}
+    hasBin: true
+
+  extsprintf@1.3.0:
+    resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==}
+    engines: {'0': node >=0.6.0}
+
+  fast-deep-equal@3.1.3:
+    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+  fast-diff@1.1.2:
+    resolution: {integrity: sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==}
+
+  fast-glob@3.3.3:
+    resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
+    engines: {node: '>=8.6.0'}
+
+  fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+  fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+
+  fastq@1.19.1:
+    resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
+
+  fd-slicer@1.1.0:
+    resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
+
+  fdir@6.4.3:
+    resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==}
+    peerDependencies:
+      picomatch: ^3 || ^4
+    peerDependenciesMeta:
+      picomatch:
+        optional: true
+
+  figures@3.2.0:
+    resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
+    engines: {node: '>=8'}
+
+  figures@6.1.0:
+    resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
+    engines: {node: '>=18'}
+
+  file-entry-cache@8.0.0:
+    resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
+    engines: {node: '>=16.0.0'}
+
+  fill-range@7.1.1:
+    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+    engines: {node: '>=8'}
+
+  filter-obj@5.1.0:
+    resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==}
+    engines: {node: '>=14.16'}
+
+  find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+
+  flat-cache@4.0.1:
+    resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
+    engines: {node: '>=16'}
+
+  flatted@3.3.3:
+    resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
+
+  follow-redirects@1.15.9:
+    resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
+    engines: {node: '>=4.0'}
+    peerDependencies:
+      debug: '*'
+    peerDependenciesMeta:
+      debug:
+        optional: true
+
+  foreground-child@3.3.1:
+    resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
+    engines: {node: '>=14'}
+
+  forever-agent@0.6.1:
+    resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
+
+  form-data@4.0.2:
+    resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==}
+    engines: {node: '>= 6'}
+
+  fraction.js@4.3.7:
+    resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
+
+  from@0.1.7:
+    resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
+
+  fs-extra@11.3.0:
+    resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==}
+    engines: {node: '>=14.14'}
+
+  fs-extra@9.1.0:
+    resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
+    engines: {node: '>=10'}
+
+  fsevents@2.3.3:
+    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+    os: [darwin]
+
+  function-bind@1.1.2:
+    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+  gensync@1.0.0-beta.2:
+    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+    engines: {node: '>=6.9.0'}
+
+  get-intrinsic@1.3.0:
+    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
+    engines: {node: '>= 0.4'}
+
+  get-proto@1.0.1:
+    resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
+    engines: {node: '>= 0.4'}
+
+  get-stream@5.2.0:
+    resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+    engines: {node: '>=8'}
+
+  get-stream@6.0.1:
+    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+    engines: {node: '>=10'}
+
+  get-stream@9.0.1:
+    resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
+    engines: {node: '>=18'}
+
+  get-tsconfig@4.10.0:
+    resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==}
+
+  getos@3.2.1:
+    resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
+
+  getpass@0.1.7:
+    resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==}
+
+  glob-parent@5.1.2:
+    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+    engines: {node: '>= 6'}
+
+  glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+
+  glob@10.4.5:
+    resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
+    hasBin: true
+
+  global-dirs@3.0.1:
+    resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
+    engines: {node: '>=10'}
+
+  globals@11.12.0:
+    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+    engines: {node: '>=4'}
+
+  globals@14.0.0:
+    resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
+    engines: {node: '>=18'}
+
+  globals@15.15.0:
+    resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==}
+    engines: {node: '>=18'}
+
+  gopd@1.2.0:
+    resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
+    engines: {node: '>= 0.4'}
+
+  graceful-fs@4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
+
+  graphemer@1.4.0:
+    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+
+  has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+
+  has-symbols@1.1.0:
+    resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
+    engines: {node: '>= 0.4'}
+
+  has-tostringtag@1.0.2:
+    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+    engines: {node: '>= 0.4'}
+
+  hasown@2.0.2:
+    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+    engines: {node: '>= 0.4'}
+
+  he@1.2.0:
+    resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+    hasBin: true
+
+  hookable@5.5.3:
+    resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
+
+  html-encoding-sniffer@4.0.0:
+    resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+    engines: {node: '>=18'}
+
+  http-proxy-agent@7.0.2:
+    resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+    engines: {node: '>= 14'}
+
+  http-signature@1.4.0:
+    resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==}
+    engines: {node: '>=0.10'}
+
+  https-proxy-agent@7.0.6:
+    resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+    engines: {node: '>= 14'}
+
+  human-signals@1.1.1:
+    resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
+    engines: {node: '>=8.12.0'}
+
+  human-signals@2.1.0:
+    resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+    engines: {node: '>=10.17.0'}
+
+  human-signals@8.0.0:
+    resolution: {integrity: sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==}
+    engines: {node: '>=18.18.0'}
+
+  iconv-lite@0.6.3:
+    resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+    engines: {node: '>=0.10.0'}
+
+  ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
+  ignore@5.3.2:
+    resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
+    engines: {node: '>= 4'}
+
+  image-size@0.5.5:
+    resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  immutable@5.0.3:
+    resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
+
+  import-fresh@3.3.1:
+    resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+    engines: {node: '>=6'}
+
+  imurmurhash@0.1.4:
+    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
+    engines: {node: '>=0.8.19'}
+
+  indent-string@4.0.0:
+    resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+    engines: {node: '>=8'}
+
+  ini@1.3.8:
+    resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+
+  ini@2.0.0:
+    resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
+    engines: {node: '>=10'}
+
+  is-binary-path@2.1.0:
+    resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+    engines: {node: '>=8'}
+
+  is-bun-module@2.0.0:
+    resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==}
+
+  is-docker@3.0.0:
+    resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==}
+    engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+    hasBin: true
+
+  is-extglob@2.1.1:
+    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+    engines: {node: '>=0.10.0'}
+
+  is-fullwidth-code-point@3.0.0:
+    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+    engines: {node: '>=8'}
+
+  is-glob@4.0.3:
+    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+    engines: {node: '>=0.10.0'}
+
+  is-inside-container@1.0.0:
+    resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
+    engines: {node: '>=14.16'}
+    hasBin: true
+
+  is-installed-globally@0.4.0:
+    resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
+    engines: {node: '>=10'}
+
+  is-number@7.0.0:
+    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+    engines: {node: '>=0.12.0'}
+
+  is-path-inside@3.0.3:
+    resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+    engines: {node: '>=8'}
+
+  is-plain-obj@4.1.0:
+    resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
+    engines: {node: '>=12'}
+
+  is-potential-custom-element-name@1.0.1:
+    resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
+  is-stream@2.0.1:
+    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+    engines: {node: '>=8'}
+
+  is-stream@4.0.1:
+    resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
+    engines: {node: '>=18'}
+
+  is-typedarray@1.0.0:
+    resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
+
+  is-unicode-supported@0.1.0:
+    resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+    engines: {node: '>=10'}
+
+  is-unicode-supported@2.1.0:
+    resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==}
+    engines: {node: '>=18'}
+
+  is-what@3.14.1:
+    resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==}
+
+  is-what@4.1.16:
+    resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
+    engines: {node: '>=12.13'}
+
+  is-wsl@3.1.0:
+    resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==}
+    engines: {node: '>=16'}
+
+  isexe@2.0.0:
+    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+  isexe@3.1.1:
+    resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==}
+    engines: {node: '>=16'}
+
+  isstream@0.1.2:
+    resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
+
+  jackspeak@3.4.3:
+    resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==}
+
+  jiti@2.4.2:
+    resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
+    hasBin: true
+
+  joi@17.13.3:
+    resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
+
+  js-beautify@1.15.4:
+    resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  js-cookie@3.0.5:
+    resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+    engines: {node: '>=14'}
+
+  js-tokens@4.0.0:
+    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+  js-tokens@9.0.1:
+    resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
+  js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+
+  jsbn@0.1.1:
+    resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
+
+  jsdom@26.0.0:
+    resolution: {integrity: sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==}
+    engines: {node: '>=18'}
+    peerDependencies:
+      canvas: ^3.0.0
+    peerDependenciesMeta:
+      canvas:
+        optional: true
+
+  jsesc@3.1.0:
+    resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  json-buffer@3.0.1:
+    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+
+  json-parse-even-better-errors@4.0.0:
+    resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==}
+    engines: {node: ^18.17.0 || >=20.5.0}
+
+  json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
+  json-schema@0.4.0:
+    resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+
+  json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+
+  json-stringify-safe@5.0.1:
+    resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
+
+  json5@2.2.3:
+    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  jsonc-parser@3.3.1:
+    resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==}
+
+  jsonfile@6.1.0:
+    resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+
+  jsprim@2.0.2:
+    resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
+    engines: {'0': node >=0.6.0}
+
+  keyv@4.5.4:
+    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+
+  kolorist@1.8.0:
+    resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==}
+
+  lazy-ass@1.6.0:
+    resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
+    engines: {node: '> 0.8'}
+
+  less@4.2.2:
+    resolution: {integrity: sha512-tkuLHQlvWUTeQ3doAqnHbNn8T6WX1KA8yvbKG9x4VtKtIjHsVKQZCH11zRgAfbDAXC2UNIg/K9BYAAcEzUIrNg==}
+    engines: {node: '>=6'}
+    hasBin: true
+
+  levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+
+  listr2@3.14.0:
+    resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      enquirer: '>= 2.3.0 < 3'
+    peerDependenciesMeta:
+      enquirer:
+        optional: true
+
+  local-pkg@1.1.1:
+    resolution: {integrity: sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==}
+    engines: {node: '>=14'}
+
+  locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+
+  lodash-es@4.17.21:
+    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
+
+  lodash-unified@1.0.3:
+    resolution: {integrity: sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==}
+    peerDependencies:
+      '@types/lodash-es': '*'
+      lodash: '*'
+      lodash-es: '*'
+
+  lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+
+  lodash.once@4.1.1:
+    resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
+
+  lodash@4.17.21:
+    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+
+  log-symbols@4.1.0:
+    resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+    engines: {node: '>=10'}
+
+  log-update@4.0.0:
+    resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
+    engines: {node: '>=10'}
+
+  loupe@3.1.3:
+    resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==}
+
+  lru-cache@10.4.3:
+    resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+
+  lru-cache@5.1.1:
+    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+  magic-string@0.30.17:
+    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
+
+  make-dir@2.1.0:
+    resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+    engines: {node: '>=6'}
+
+  map-stream@0.1.0:
+    resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==}
+
+  math-intrinsics@1.1.0:
+    resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
+    engines: {node: '>= 0.4'}
+
+  memoize-one@6.0.0:
+    resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
+
+  memorystream@0.3.1:
+    resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==}
+    engines: {node: '>= 0.10.0'}
+
+  merge-stream@2.0.0:
+    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+
+  merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+
+  micromatch@4.0.8:
+    resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+    engines: {node: '>=8.6'}
+
+  mime-db@1.52.0:
+    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
+    engines: {node: '>= 0.6'}
+
+  mime-types@2.1.35:
+    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
+    engines: {node: '>= 0.6'}
+
+  mime@1.6.0:
+    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+    engines: {node: '>=4'}
+    hasBin: true
+
+  mimic-fn@2.1.0:
+    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+    engines: {node: '>=6'}
+
+  minimatch@3.1.2:
+    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
+
+  minimatch@9.0.1:
+    resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimatch@9.0.5:
+    resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  minimist@1.2.8:
+    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+
+  minipass@7.1.2:
+    resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+
+  mitt@3.0.1:
+    resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
+
+  mlly@1.7.4:
+    resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
+
+  mrmime@2.0.1:
+    resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
+    engines: {node: '>=10'}
+
+  ms@2.1.3:
+    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+  muggle-string@0.4.1:
+    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+
+  nanoid@3.3.10:
+    resolution: {integrity: sha512-vSJJTG+t/dIKAUhUDw/dLdZ9s//5OxcHqLaDWWrW4Cdq7o6tdLIczUkMXt2MBNmk6sJRZBZRXVixs7URY1CmIg==}
+    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+    hasBin: true
+
+  nanoid@5.1.5:
+    resolution: {integrity: sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==}
+    engines: {node: ^18 || >=20}
+    hasBin: true
+
+  natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+
+  needle@3.3.1:
+    resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==}
+    engines: {node: '>= 4.4.x'}
+    hasBin: true
+
+  neo-async@2.6.2:
+    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+
+  node-addon-api@7.1.1:
+    resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+  node-releases@2.0.19:
+    resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+  nopt@7.2.1:
+    resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
+    engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+    hasBin: true
+
+  normalize-path@3.0.0:
+    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+    engines: {node: '>=0.10.0'}
+
+  normalize-range@0.1.2:
+    resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==}
+    engines: {node: '>=0.10.0'}
+
+  normalize-wheel-es@1.2.0:
+    resolution: {integrity: sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==}
+
+  npm-normalize-package-bin@4.0.0:
+    resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==}
+    engines: {node: ^18.17.0 || >=20.5.0}
+
+  npm-run-all2@7.0.2:
+    resolution: {integrity: sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==}
+    engines: {node: ^18.17.0 || >=20.5.0, npm: '>= 9'}
+    hasBin: true
+
+  npm-run-path@4.0.1:
+    resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+    engines: {node: '>=8'}
+
+  npm-run-path@6.0.0:
+    resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==}
+    engines: {node: '>=18'}
+
+  nth-check@2.1.1:
+    resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+
+  nwsapi@2.2.19:
+    resolution: {integrity: sha512-94bcyI3RsqiZufXjkr3ltkI86iEl+I7uiHVDtcq9wJUTwYQJ5odHDeSzkkrRzi80jJ8MaeZgqKjH1bAWAFw9bA==}
+
+  object-inspect@1.13.4:
+    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
+    engines: {node: '>= 0.4'}
+
+  once@1.4.0:
+    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
+
+  onetime@5.1.2:
+    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+    engines: {node: '>=6'}
+
+  open@10.1.0:
+    resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==}
+    engines: {node: '>=18'}
+
+  optionator@0.9.4:
+    resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+    engines: {node: '>= 0.8.0'}
+
+  ospath@1.2.2:
+    resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==}
+
+  oxlint@0.15.15:
+    resolution: {integrity: sha512-oQNc1mAHrrbKiXyKJMGs9VCZfwGfLy7YiQKa4qupi71X/u4xyWqOh36YKXqWOXnmm2y7vfWFpGZlhJPAa9tMqA==}
+    engines: {node: '>=8.*'}
+    hasBin: true
+
+  p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+
+  p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+
+  p-map@4.0.0:
+    resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+    engines: {node: '>=10'}
+
+  package-json-from-dist@1.0.1:
+    resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
+
+  parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+
+  parse-ms@4.0.0:
+    resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
+    engines: {node: '>=18'}
+
+  parse-node-version@1.0.1:
+    resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
+    engines: {node: '>= 0.10'}
+
+  parse5@7.2.1:
+    resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
+
+  path-browserify@1.0.1:
+    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
+  path-exists@4.0.0:
+    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+    engines: {node: '>=8'}
+
+  path-key@3.1.1:
+    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+    engines: {node: '>=8'}
+
+  path-key@4.0.0:
+    resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
+    engines: {node: '>=12'}
+
+  path-scurry@1.11.1:
+    resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==}
+    engines: {node: '>=16 || 14 >=14.18'}
+
+  pathe@2.0.3:
+    resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+
+  pathval@2.0.0:
+    resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
+    engines: {node: '>= 14.16'}
+
+  pause-stream@0.0.11:
+    resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==}
+
+  pend@1.2.0:
+    resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
+
+  perfect-debounce@1.0.0:
+    resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
+
+  performance-now@2.1.0:
+    resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==}
+
+  picocolors@1.1.1:
+    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+  picomatch@2.3.1:
+    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+    engines: {node: '>=8.6'}
+
+  picomatch@4.0.2:
+    resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
+    engines: {node: '>=12'}
+
+  pidtree@0.6.0:
+    resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
+    engines: {node: '>=0.10'}
+    hasBin: true
+
+  pify@2.3.0:
+    resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
+    engines: {node: '>=0.10.0'}
+
+  pify@4.0.1:
+    resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+    engines: {node: '>=6'}
+
+  pinia@3.0.1:
+    resolution: {integrity: sha512-WXglsDzztOTH6IfcJ99ltYZin2mY8XZCXujkYWVIJlBjqsP6ST7zw+Aarh63E1cDVYeyUcPCxPHzJpEOmzB6Wg==}
+    peerDependencies:
+      typescript: '>=4.4.4'
+      vue: ^2.7.0 || ^3.5.11
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  pkg-types@1.3.1:
+    resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+
+  pkg-types@2.1.0:
+    resolution: {integrity: sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==}
+
+  postcss-selector-parser@6.1.2:
+    resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+    engines: {node: '>=4'}
+
+  postcss-value-parser@4.2.0:
+    resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+  postcss@8.5.3:
+    resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+    engines: {node: ^10 || ^12 || >=14}
+
+  prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+
+  prettier-linter-helpers@1.0.0:
+    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+    engines: {node: '>=6.0.0'}
+
+  prettier@3.5.3:
+    resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==}
+    engines: {node: '>=14'}
+    hasBin: true
+
+  pretty-bytes@5.6.0:
+    resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
+    engines: {node: '>=6'}
+
+  pretty-ms@9.2.0:
+    resolution: {integrity: sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==}
+    engines: {node: '>=18'}
+
+  process@0.11.10:
+    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+    engines: {node: '>= 0.6.0'}
+
+  proto-list@1.2.4:
+    resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+
+  proxy-from-env@1.0.0:
+    resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
+
+  proxy-from-env@1.1.0:
+    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
+  prr@1.0.1:
+    resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
+
+  ps-tree@1.2.0:
+    resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==}
+    engines: {node: '>= 0.10'}
+    hasBin: true
+
+  pump@3.0.2:
+    resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==}
+
+  punycode@2.3.1:
+    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
+    engines: {node: '>=6'}
+
+  qs@6.14.0:
+    resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
+    engines: {node: '>=0.6'}
+
+  quansync@0.2.10:
+    resolution: {integrity: sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==}
+
+  query-string@9.1.1:
+    resolution: {integrity: sha512-MWkCOVIcJP9QSKU52Ngow6bsAWAPlPK2MludXvcrS2bGZSl+T1qX9MZvRIkqUIkGLJquMJHWfsT6eRqUpp4aWg==}
+    engines: {node: '>=18'}
+
+  queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+
+  read-package-json-fast@4.0.0:
+    resolution: {integrity: sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==}
+    engines: {node: ^18.17.0 || >=20.5.0}
+
+  readdirp@3.6.0:
+    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+    engines: {node: '>=8.10.0'}
+
+  readdirp@4.1.2:
+    resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
+    engines: {node: '>= 14.18.0'}
+
+  request-progress@3.0.0:
+    resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
+
+  resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+
+  resolve-pkg-maps@1.0.0:
+    resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+
+  restore-cursor@3.1.0:
+    resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+    engines: {node: '>=8'}
+
+  reusify@1.1.0:
+    resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+
+  rfdc@1.4.1:
+    resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
+
+  rollup@4.35.0:
+    resolution: {integrity: sha512-kg6oI4g+vc41vePJyO6dHt/yl0Rz3Thv0kJeVQ3D1kS3E5XSuKbPc29G4IpT/Kv1KQwgHVcN+HtyS+HYLNSvQg==}
+    engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+    hasBin: true
+
+  rrweb-cssom@0.8.0:
+    resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
+
+  run-applescript@7.0.0:
+    resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
+    engines: {node: '>=18'}
+
+  run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+
+  rxjs@7.8.2:
+    resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
+
+  safe-buffer@5.2.1:
+    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+  safer-buffer@2.1.2:
+    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+  sass-loader@16.0.5:
+    resolution: {integrity: sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==}
+    engines: {node: '>= 18.12.0'}
+    peerDependencies:
+      '@rspack/core': 0.x || 1.x
+      node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
+      sass: ^1.3.0
+      sass-embedded: '*'
+      webpack: ^5.0.0
+    peerDependenciesMeta:
+      '@rspack/core':
+        optional: true
+      node-sass:
+        optional: true
+      sass:
+        optional: true
+      sass-embedded:
+        optional: true
+      webpack:
+        optional: true
+
+  sass@1.86.3:
+    resolution: {integrity: sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==}
+    engines: {node: '>=14.0.0'}
+    hasBin: true
+
+  sax@1.4.1:
+    resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
+
+  saxes@6.0.0:
+    resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+    engines: {node: '>=v12.22.7'}
+
+  scule@1.3.0:
+    resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==}
+
+  semver@5.7.2:
+    resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
+    hasBin: true
+
+  semver@6.3.1:
+    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+    hasBin: true
+
+  semver@7.7.1:
+    resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}
+    engines: {node: '>=10'}
+    hasBin: true
+
+  shebang-command@2.0.0:
+    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+    engines: {node: '>=8'}
+
+  shebang-regex@3.0.0:
+    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+    engines: {node: '>=8'}
+
+  shell-quote@1.8.2:
+    resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-list@1.0.0:
+    resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-map@1.0.1:
+    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}
+    engines: {node: '>= 0.4'}
+
+  side-channel-weakmap@1.0.2:
+    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}
+    engines: {node: '>= 0.4'}
+
+  side-channel@1.1.0:
+    resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
+    engines: {node: '>= 0.4'}
+
+  siginfo@2.0.0:
+    resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
+  signal-exit@3.0.7:
+    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+
+  signal-exit@4.1.0:
+    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
+    engines: {node: '>=14'}
+
+  sirv@3.0.1:
+    resolution: {integrity: sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==}
+    engines: {node: '>=18'}
+
+  slice-ansi@3.0.0:
+    resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
+    engines: {node: '>=8'}
+
+  slice-ansi@4.0.0:
+    resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+    engines: {node: '>=10'}
+
+  source-map-js@1.2.1:
+    resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+    engines: {node: '>=0.10.0'}
+
+  source-map@0.6.1:
+    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+    engines: {node: '>=0.10.0'}
+
+  speakingurl@14.0.1:
+    resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
+    engines: {node: '>=0.10.0'}
+
+  split-on-first@3.0.0:
+    resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==}
+    engines: {node: '>=12'}
+
+  split@0.3.3:
+    resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==}
+
+  sshpk@1.18.0:
+    resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==}
+    engines: {node: '>=0.10.0'}
+    hasBin: true
+
+  stable-hash@0.0.5:
+    resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==}
+
+  stackback@0.0.2:
+    resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
+  start-server-and-test@2.0.11:
+    resolution: {integrity: sha512-TN39gLzPhHAflxyOkE/oMfQGj+pj3JgF6qVicFH/JrXt7xXktidKXwqfRga+ve7lVA8+RgPZVc25VrEPRScaDw==}
+    engines: {node: '>=16'}
+    hasBin: true
+
+  std-env@3.8.1:
+    resolution: {integrity: sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==}
+
+  stream-combiner@0.0.4:
+    resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==}
+
+  string-width@4.2.3:
+    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+    engines: {node: '>=8'}
+
+  string-width@5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+
+  strip-ansi@6.0.1:
+    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+    engines: {node: '>=8'}
+
+  strip-ansi@7.1.0:
+    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+    engines: {node: '>=12'}
+
+  strip-final-newline@2.0.0:
+    resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+    engines: {node: '>=6'}
+
+  strip-final-newline@4.0.0:
+    resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
+    engines: {node: '>=18'}
+
+  strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+
+  strip-literal@3.0.0:
+    resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==}
+
+  superjson@2.2.2:
+    resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==}
+    engines: {node: '>=16'}
+
+  supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+
+  supports-color@8.1.1:
+    resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+    engines: {node: '>=10'}
+
+  symbol-tree@3.2.4:
+    resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
+  synckit@0.9.2:
+    resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+
+  tailwindcss@4.1.3:
+    resolution: {integrity: sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g==}
+
+  throttleit@1.0.1:
+    resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==}
+
+  through@2.3.8:
+    resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
+
+  tinybench@2.9.0:
+    resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+  tinyexec@0.3.2:
+    resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
+  tinyglobby@0.2.12:
+    resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==}
+    engines: {node: '>=12.0.0'}
+
+  tinypool@1.0.2:
+    resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==}
+    engines: {node: ^18.0.0 || >=20.0.0}
+
+  tinyrainbow@2.0.0:
+    resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+    engines: {node: '>=14.0.0'}
+
+  tinyspy@3.0.2:
+    resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
+    engines: {node: '>=14.0.0'}
+
+  tldts-core@6.1.85:
+    resolution: {integrity: sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==}
+
+  tldts@6.1.85:
+    resolution: {integrity: sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w==}
+    hasBin: true
+
+  tmp@0.2.3:
+    resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==}
+    engines: {node: '>=14.14'}
+
+  to-regex-range@5.0.1:
+    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+    engines: {node: '>=8.0'}
+
+  totalist@3.0.1:
+    resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
+    engines: {node: '>=6'}
+
+  tough-cookie@5.1.2:
+    resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==}
+    engines: {node: '>=16'}
+
+  tr46@5.1.0:
+    resolution: {integrity: sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==}
+    engines: {node: '>=18'}
+
+  tree-kill@1.2.2:
+    resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
+    hasBin: true
+
+  ts-api-utils@2.0.1:
+    resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
+    engines: {node: '>=18.12'}
+    peerDependencies:
+      typescript: '>=4.8.4'
+
+  tslib@2.8.1:
+    resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+  tunnel-agent@0.6.0:
+    resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
+
+  tweetnacl@0.14.5:
+    resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
+
+  type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+
+  type-fest@0.21.3:
+    resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+    engines: {node: '>=10'}
+
+  typescript-eslint@8.26.1:
+    resolution: {integrity: sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
+
+  typescript@5.8.2:
+    resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
+  ufo@1.6.1:
+    resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==}
+
+  undici-types@6.20.0:
+    resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
+
+  unicorn-magic@0.3.0:
+    resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
+    engines: {node: '>=18'}
+
+  unimport@4.2.0:
+    resolution: {integrity: sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==}
+    engines: {node: '>=18.12.0'}
+
+  universal-cookie@8.0.1:
+    resolution: {integrity: sha512-B6ks9FLLnP1UbPPcveOidfvB9pHjP+wekP2uRYB9YDfKVpvcjKgy1W5Zj+cEXJ9KTPnqOKGfVDQBmn8/YCQfRg==}
+
+  universalify@2.0.1:
+    resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
+    engines: {node: '>= 10.0.0'}
+
+  unplugin-auto-import@19.1.2:
+    resolution: {integrity: sha512-EkxNIJm4ZPYtV7rRaPBKnsscgTaifIZNrJF5DkMffTxkUOJOlJuKVypA6YBSBOjzPJDTFPjfVmCQPoBuOO+YYQ==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@nuxt/kit': ^3.2.2
+      '@vueuse/core': '*'
+    peerDependenciesMeta:
+      '@nuxt/kit':
+        optional: true
+      '@vueuse/core':
+        optional: true
+
+  unplugin-utils@0.2.4:
+    resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==}
+    engines: {node: '>=18.12.0'}
+
+  unplugin-vue-components@28.5.0:
+    resolution: {integrity: sha512-o7fMKU/uI8NiP+E0W62zoduuguWqB0obTfHFtbr1AP2uo2lhUPnPttWUE92yesdiYfo9/0hxIrj38FMc1eaySg==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@babel/parser': ^7.15.8
+      '@nuxt/kit': ^3.2.2
+      vue: 2 || 3
+    peerDependenciesMeta:
+      '@babel/parser':
+        optional: true
+      '@nuxt/kit':
+        optional: true
+
+  unplugin@2.3.2:
+    resolution: {integrity: sha512-3n7YA46rROb3zSj8fFxtxC/PqoyvYQ0llwz9wtUPUutr9ig09C8gGo5CWCwHrUzlqC1LLR43kxp5vEIyH1ac1w==}
+    engines: {node: '>=18.12.0'}
+
+  unrs-resolver@1.5.0:
+    resolution: {integrity: sha512-6aia3Oy7SEe0MuUGQm2nsyob0L2+g57w178K5SE/3pvSGAIp28BB2O921fKx424Ahc/gQ6v0DXFbhcpyhGZdOA==}
+
+  untildify@4.0.0:
+    resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
+    engines: {node: '>=8'}
+
+  update-browserslist-db@1.1.3:
+    resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+    hasBin: true
+    peerDependencies:
+      browserslist: '>= 4.21.0'
+
+  uri-js@4.4.1:
+    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+
+  util-deprecate@1.0.2:
+    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
+
+  uuid@8.3.2:
+    resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+    hasBin: true
+
+  verror@1.10.0:
+    resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==}
+    engines: {'0': node >=0.6.0}
+
+  vite-hot-client@0.2.4:
+    resolution: {integrity: sha512-a1nzURqO7DDmnXqabFOliz908FRmIppkBKsJthS8rbe8hBEXwEwe4C3Pp33Z1JoFCYfVL4kTOMLKk0ZZxREIeA==}
+    peerDependencies:
+      vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0
+
+  vite-node@3.0.9:
+    resolution: {integrity: sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+
+  vite-plugin-inspect@0.8.9:
+    resolution: {integrity: sha512-22/8qn+LYonzibb1VeFZmISdVao5kC22jmEKm24vfFE8siEn47EpVcCLYMv6iKOYMJfjSvSJfueOwcFCkUnV3A==}
+    engines: {node: '>=14'}
+    peerDependencies:
+      '@nuxt/kit': '*'
+      vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.1
+    peerDependenciesMeta:
+      '@nuxt/kit':
+        optional: true
+
+  vite-plugin-vue-devtools@7.7.2:
+    resolution: {integrity: sha512-5V0UijQWiSBj32blkyPEqIbzc6HO9c1bwnBhx+ay2dzU0FakH+qMdNUT8nF9BvDE+i6I1U8CqCuJiO20vKEdQw==}
+    engines: {node: '>=v14.21.3'}
+    peerDependencies:
+      vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0
+
+  vite-plugin-vue-inspector@5.3.1:
+    resolution: {integrity: sha512-cBk172kZKTdvGpJuzCCLg8lJ909wopwsu3Ve9FsL1XsnLBiRT9U3MePcqrgGHgCX2ZgkqZmAGR8taxw+TV6s7A==}
+    peerDependencies:
+      vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.0-0
+
+  vite@6.2.2:
+    resolution: {integrity: sha512-yW7PeMM+LkDzc7CgJuRLMW2Jz0FxMOsVJ8Lv3gpgW9WLcb9cTW+121UEr1hvmfR7w3SegR5ItvYyzVz1vxNJgQ==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+    peerDependencies:
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      jiti: '>=1.21.0'
+      less: '*'
+      lightningcss: ^1.21.0
+      sass: '*'
+      sass-embedded: '*'
+      stylus: '*'
+      sugarss: '*'
+      terser: ^5.16.0
+      tsx: ^4.8.1
+      yaml: ^2.4.2
+    peerDependenciesMeta:
+      '@types/node':
+        optional: true
+      jiti:
+        optional: true
+      less:
+        optional: true
+      lightningcss:
+        optional: true
+      sass:
+        optional: true
+      sass-embedded:
+        optional: true
+      stylus:
+        optional: true
+      sugarss:
+        optional: true
+      terser:
+        optional: true
+      tsx:
+        optional: true
+      yaml:
+        optional: true
+
+  vitest@3.0.9:
+    resolution: {integrity: sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==}
+    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+    hasBin: true
+    peerDependencies:
+      '@edge-runtime/vm': '*'
+      '@types/debug': ^4.1.12
+      '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+      '@vitest/browser': 3.0.9
+      '@vitest/ui': 3.0.9
+      happy-dom: '*'
+      jsdom: '*'
+    peerDependenciesMeta:
+      '@edge-runtime/vm':
+        optional: true
+      '@types/debug':
+        optional: true
+      '@types/node':
+        optional: true
+      '@vitest/browser':
+        optional: true
+      '@vitest/ui':
+        optional: true
+      happy-dom:
+        optional: true
+      jsdom:
+        optional: true
+
+  vscode-uri@3.1.0:
+    resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
+
+  vue-component-type-helpers@2.2.8:
+    resolution: {integrity: sha512-4bjIsC284coDO9om4HPA62M7wfsTvcmZyzdfR0aUlFXqq4tXxM1APyXpNVxPC8QazKw9OhmZNHBVDA6ODaZsrA==}
+
+  vue-demi@0.14.10:
+    resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
+    engines: {node: '>=12'}
+    hasBin: true
+    peerDependencies:
+      '@vue/composition-api': ^1.0.0-rc.1
+      vue: ^3.0.0-0 || ^2.6.0
+    peerDependenciesMeta:
+      '@vue/composition-api':
+        optional: true
+
+  vue-eslint-parser@10.1.1:
+    resolution: {integrity: sha512-bh2Z/Au5slro9QJ3neFYLanZtb1jH+W2bKqGHXAoYD4vZgNG3KeotL7JpPv5xzY4UXUXJl7TrIsnzECH63kd3Q==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+
+  vue-i18n@9.14.4:
+    resolution: {integrity: sha512-B934C8yUyWLT0EMud3DySrwSUJI7ZNiWYsEEz2gknTthqKiG4dzWE/WSa8AzCuSQzwBEv4HtG1jZDhgzPfWSKQ==}
+    engines: {node: '>= 16'}
+    peerDependencies:
+      vue: ^3.0.0
+
+  vue-router@4.5.0:
+    resolution: {integrity: sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==}
+    peerDependencies:
+      vue: ^3.2.0
+
+  vue-tsc@2.2.8:
+    resolution: {integrity: sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==}
+    hasBin: true
+    peerDependencies:
+      typescript: '>=5.0.0'
+
+  vue@3.5.13:
+    resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+
+  w3c-xmlserializer@5.0.0:
+    resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+    engines: {node: '>=18'}
+
+  wait-on@8.0.3:
+    resolution: {integrity: sha512-nQFqAFzZDeRxsu7S3C7LbuxslHhk+gnJZHyethuGKAn2IVleIbTB9I3vJSQiSR+DifUqmdzfPMoMPJfLqMF2vw==}
+    engines: {node: '>=12.0.0'}
+    hasBin: true
+
+  webidl-conversions@7.0.0:
+    resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+    engines: {node: '>=12'}
+
+  webpack-virtual-modules@0.6.2:
+    resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+
+  whatwg-encoding@3.1.1:
+    resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+    engines: {node: '>=18'}
+
+  whatwg-mimetype@4.0.0:
+    resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+    engines: {node: '>=18'}
+
+  whatwg-url@14.2.0:
+    resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
+    engines: {node: '>=18'}
+
+  which@2.0.2:
+    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+    engines: {node: '>= 8'}
+    hasBin: true
+
+  which@5.0.0:
+    resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==}
+    engines: {node: ^18.17.0 || >=20.5.0}
+    hasBin: true
+
+  why-is-node-running@2.3.0:
+    resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+    engines: {node: '>=8'}
+    hasBin: true
+
+  word-wrap@1.2.5:
+    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+    engines: {node: '>=0.10.0'}
+
+  wrap-ansi@6.2.0:
+    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+    engines: {node: '>=8'}
+
+  wrap-ansi@7.0.0:
+    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+    engines: {node: '>=10'}
+
+  wrap-ansi@8.1.0:
+    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+    engines: {node: '>=12'}
+
+  wrappy@1.0.2:
+    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
+
+  ws@8.18.1:
+    resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      bufferutil: ^4.0.1
+      utf-8-validate: '>=5.0.2'
+    peerDependenciesMeta:
+      bufferutil:
+        optional: true
+      utf-8-validate:
+        optional: true
+
+  xml-name-validator@4.0.0:
+    resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+    engines: {node: '>=12'}
+
+  xml-name-validator@5.0.0:
+    resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+    engines: {node: '>=18'}
+
+  xmlchars@2.2.0:
+    resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
+  yallist@3.1.1:
+    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+  yaml@2.7.0:
+    resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==}
+    engines: {node: '>= 14'}
+    hasBin: true
+
+  yauzl@2.10.0:
+    resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
+
+  yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+
+  yoctocolors@2.1.1:
+    resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==}
+    engines: {node: '>=18'}
+
+snapshots:
+
+  '@ampproject/remapping@2.3.0':
+    dependencies:
+      '@jridgewell/gen-mapping': 0.3.8
+      '@jridgewell/trace-mapping': 0.3.25
+
+  '@antfu/utils@0.7.10': {}
+
+  '@asamuzakjp/css-color@3.1.1':
+    dependencies:
+      '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-color-parser': 3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-tokenizer': 3.0.3
+      lru-cache: 10.4.3
+
+  '@babel/code-frame@7.26.2':
+    dependencies:
+      '@babel/helper-validator-identifier': 7.25.9
+      js-tokens: 4.0.0
+      picocolors: 1.1.1
+
+  '@babel/compat-data@7.26.8': {}
+
+  '@babel/core@7.26.10':
+    dependencies:
+      '@ampproject/remapping': 2.3.0
+      '@babel/code-frame': 7.26.2
+      '@babel/generator': 7.26.10
+      '@babel/helper-compilation-targets': 7.26.5
+      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)
+      '@babel/helpers': 7.26.10
+      '@babel/parser': 7.26.10
+      '@babel/template': 7.26.9
+      '@babel/traverse': 7.26.10
+      '@babel/types': 7.26.10
+      convert-source-map: 2.0.0
+      debug: 4.4.0(supports-color@8.1.1)
+      gensync: 1.0.0-beta.2
+      json5: 2.2.3
+      semver: 6.3.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/generator@7.26.10':
+    dependencies:
+      '@babel/parser': 7.26.10
+      '@babel/types': 7.26.10
+      '@jridgewell/gen-mapping': 0.3.8
+      '@jridgewell/trace-mapping': 0.3.25
+      jsesc: 3.1.0
+
+  '@babel/helper-annotate-as-pure@7.25.9':
+    dependencies:
+      '@babel/types': 7.26.10
+
+  '@babel/helper-compilation-targets@7.26.5':
+    dependencies:
+      '@babel/compat-data': 7.26.8
+      '@babel/helper-validator-option': 7.25.9
+      browserslist: 4.24.4
+      lru-cache: 5.1.1
+      semver: 6.3.1
+
+  '@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-annotate-as-pure': 7.25.9
+      '@babel/helper-member-expression-to-functions': 7.25.9
+      '@babel/helper-optimise-call-expression': 7.25.9
+      '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.10)
+      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
+      '@babel/traverse': 7.26.10
+      semver: 6.3.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-member-expression-to-functions@7.25.9':
+    dependencies:
+      '@babel/traverse': 7.26.10
+      '@babel/types': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-module-imports@7.25.9':
+    dependencies:
+      '@babel/traverse': 7.26.10
+      '@babel/types': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-module-imports': 7.25.9
+      '@babel/helper-validator-identifier': 7.25.9
+      '@babel/traverse': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-optimise-call-expression@7.25.9':
+    dependencies:
+      '@babel/types': 7.26.10
+
+  '@babel/helper-plugin-utils@7.26.5': {}
+
+  '@babel/helper-replace-supers@7.26.5(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-member-expression-to-functions': 7.25.9
+      '@babel/helper-optimise-call-expression': 7.25.9
+      '@babel/traverse': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-skip-transparent-expression-wrappers@7.25.9':
+    dependencies:
+      '@babel/traverse': 7.26.10
+      '@babel/types': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/helper-string-parser@7.25.9': {}
+
+  '@babel/helper-validator-identifier@7.25.9': {}
+
+  '@babel/helper-validator-option@7.25.9': {}
+
+  '@babel/helpers@7.26.10':
+    dependencies:
+      '@babel/template': 7.26.9
+      '@babel/types': 7.26.10
+
+  '@babel/parser@7.26.10':
+    dependencies:
+      '@babel/types': 7.26.10
+
+  '@babel/plugin-proposal-decorators@7.25.9(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.10)
+      '@babel/helper-plugin-utils': 7.26.5
+      '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.10)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-plugin-utils': 7.26.5
+
+  '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-plugin-utils': 7.26.5
+
+  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-plugin-utils': 7.26.5
+
+  '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-plugin-utils': 7.26.5
+
+  '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-plugin-utils': 7.26.5
+
+  '@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/helper-annotate-as-pure': 7.25.9
+      '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.10)
+      '@babel/helper-plugin-utils': 7.26.5
+      '@babel/helper-skip-transparent-expression-wrappers': 7.25.9
+      '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.10)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/template@7.26.9':
+    dependencies:
+      '@babel/code-frame': 7.26.2
+      '@babel/parser': 7.26.10
+      '@babel/types': 7.26.10
+
+  '@babel/traverse@7.26.10':
+    dependencies:
+      '@babel/code-frame': 7.26.2
+      '@babel/generator': 7.26.10
+      '@babel/parser': 7.26.10
+      '@babel/template': 7.26.9
+      '@babel/types': 7.26.10
+      debug: 4.4.0(supports-color@8.1.1)
+      globals: 11.12.0
+    transitivePeerDependencies:
+      - supports-color
+
+  '@babel/types@7.26.10':
+    dependencies:
+      '@babel/helper-string-parser': 7.25.9
+      '@babel/helper-validator-identifier': 7.25.9
+
+  '@colors/colors@1.5.0':
+    optional: true
+
+  '@csstools/color-helpers@5.0.2': {}
+
+  '@csstools/css-calc@2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
+    dependencies:
+      '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-tokenizer': 3.0.3
+
+  '@csstools/css-color-parser@3.0.8(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)':
+    dependencies:
+      '@csstools/color-helpers': 5.0.2
+      '@csstools/css-calc': 2.1.2(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-parser-algorithms': 3.0.4(@csstools/css-tokenizer@3.0.3)
+      '@csstools/css-tokenizer': 3.0.3
+
+  '@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3)':
+    dependencies:
+      '@csstools/css-tokenizer': 3.0.3
+
+  '@csstools/css-tokenizer@3.0.3': {}
+
+  '@ctrl/tinycolor@3.6.1': {}
+
+  '@cypress/request@3.0.8':
+    dependencies:
+      aws-sign2: 0.7.0
+      aws4: 1.13.2
+      caseless: 0.12.0
+      combined-stream: 1.0.8
+      extend: 3.0.2
+      forever-agent: 0.6.1
+      form-data: 4.0.2
+      http-signature: 1.4.0
+      is-typedarray: 1.0.0
+      isstream: 0.1.2
+      json-stringify-safe: 5.0.1
+      mime-types: 2.1.35
+      performance-now: 2.1.0
+      qs: 6.14.0
+      safe-buffer: 5.2.1
+      tough-cookie: 5.1.2
+      tunnel-agent: 0.6.0
+      uuid: 8.3.2
+
+  '@cypress/xvfb@1.2.4(supports-color@8.1.1)':
+    dependencies:
+      debug: 3.2.7(supports-color@8.1.1)
+      lodash.once: 4.1.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@element-plus/icons-vue@2.3.1(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@emnapi/core@1.4.0':
+    dependencies:
+      '@emnapi/wasi-threads': 1.0.1
+      tslib: 2.8.1
+    optional: true
+
+  '@emnapi/runtime@1.4.0':
+    dependencies:
+      tslib: 2.8.1
+    optional: true
+
+  '@emnapi/wasi-threads@1.0.1':
+    dependencies:
+      tslib: 2.8.1
+    optional: true
+
+  '@esbuild/aix-ppc64@0.25.1':
+    optional: true
+
+  '@esbuild/android-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/android-arm@0.25.1':
+    optional: true
+
+  '@esbuild/android-x64@0.25.1':
+    optional: true
+
+  '@esbuild/darwin-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/darwin-x64@0.25.1':
+    optional: true
+
+  '@esbuild/freebsd-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/freebsd-x64@0.25.1':
+    optional: true
+
+  '@esbuild/linux-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/linux-arm@0.25.1':
+    optional: true
+
+  '@esbuild/linux-ia32@0.25.1':
+    optional: true
+
+  '@esbuild/linux-loong64@0.25.1':
+    optional: true
+
+  '@esbuild/linux-mips64el@0.25.1':
+    optional: true
+
+  '@esbuild/linux-ppc64@0.25.1':
+    optional: true
+
+  '@esbuild/linux-riscv64@0.25.1':
+    optional: true
+
+  '@esbuild/linux-s390x@0.25.1':
+    optional: true
+
+  '@esbuild/linux-x64@0.25.1':
+    optional: true
+
+  '@esbuild/netbsd-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/netbsd-x64@0.25.1':
+    optional: true
+
+  '@esbuild/openbsd-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/openbsd-x64@0.25.1':
+    optional: true
+
+  '@esbuild/sunos-x64@0.25.1':
+    optional: true
+
+  '@esbuild/win32-arm64@0.25.1':
+    optional: true
+
+  '@esbuild/win32-ia32@0.25.1':
+    optional: true
+
+  '@esbuild/win32-x64@0.25.1':
+    optional: true
+
+  '@eslint-community/eslint-utils@4.5.1(eslint@9.22.0(jiti@2.4.2))':
+    dependencies:
+      eslint: 9.22.0(jiti@2.4.2)
+      eslint-visitor-keys: 3.4.3
+
+  '@eslint-community/regexpp@4.12.1': {}
+
+  '@eslint/config-array@0.19.2':
+    dependencies:
+      '@eslint/object-schema': 2.1.6
+      debug: 4.4.0(supports-color@8.1.1)
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@eslint/config-helpers@0.1.0': {}
+
+  '@eslint/core@0.12.0':
+    dependencies:
+      '@types/json-schema': 7.0.15
+
+  '@eslint/eslintrc@3.3.0':
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.4.0(supports-color@8.1.1)
+      espree: 10.3.0
+      globals: 14.0.0
+      ignore: 5.3.2
+      import-fresh: 3.3.1
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+
+  '@eslint/js@9.22.0': {}
+
+  '@eslint/object-schema@2.1.6': {}
+
+  '@eslint/plugin-kit@0.2.7':
+    dependencies:
+      '@eslint/core': 0.12.0
+      levn: 0.4.1
+
+  '@floating-ui/core@1.6.9':
+    dependencies:
+      '@floating-ui/utils': 0.2.9
+
+  '@floating-ui/dom@1.6.13':
+    dependencies:
+      '@floating-ui/core': 1.6.9
+      '@floating-ui/utils': 0.2.9
+
+  '@floating-ui/utils@0.2.9': {}
+
+  '@hapi/hoek@9.3.0': {}
+
+  '@hapi/topo@5.1.0':
+    dependencies:
+      '@hapi/hoek': 9.3.0
+
+  '@humanfs/core@0.19.1': {}
+
+  '@humanfs/node@0.16.6':
+    dependencies:
+      '@humanfs/core': 0.19.1
+      '@humanwhocodes/retry': 0.3.1
+
+  '@humanwhocodes/module-importer@1.0.1': {}
+
+  '@humanwhocodes/retry@0.3.1': {}
+
+  '@humanwhocodes/retry@0.4.2': {}
+
+  '@intlify/core-base@9.14.4':
+    dependencies:
+      '@intlify/message-compiler': 9.14.4
+      '@intlify/shared': 9.14.4
+
+  '@intlify/message-compiler@9.14.4':
+    dependencies:
+      '@intlify/shared': 9.14.4
+      source-map-js: 1.2.1
+
+  '@intlify/shared@9.14.4': {}
+
+  '@isaacs/cliui@8.0.2':
+    dependencies:
+      string-width: 5.1.2
+      string-width-cjs: string-width@4.2.3
+      strip-ansi: 7.1.0
+      strip-ansi-cjs: strip-ansi@6.0.1
+      wrap-ansi: 8.1.0
+      wrap-ansi-cjs: wrap-ansi@7.0.0
+
+  '@jridgewell/gen-mapping@0.3.8':
+    dependencies:
+      '@jridgewell/set-array': 1.2.1
+      '@jridgewell/sourcemap-codec': 1.5.0
+      '@jridgewell/trace-mapping': 0.3.25
+
+  '@jridgewell/resolve-uri@3.1.2': {}
+
+  '@jridgewell/set-array@1.2.1': {}
+
+  '@jridgewell/sourcemap-codec@1.5.0': {}
+
+  '@jridgewell/trace-mapping@0.3.25':
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.2
+      '@jridgewell/sourcemap-codec': 1.5.0
+
+  '@napi-rs/wasm-runtime@0.2.8':
+    dependencies:
+      '@emnapi/core': 1.4.0
+      '@emnapi/runtime': 1.4.0
+      '@tybys/wasm-util': 0.9.0
+    optional: true
+
+  '@nodelib/fs.scandir@2.1.5':
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+
+  '@nodelib/fs.stat@2.0.5': {}
+
+  '@nodelib/fs.walk@1.2.8':
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.19.1
+
+  '@one-ini/wasm@0.1.1': {}
+
+  '@oxlint/darwin-arm64@0.15.15':
+    optional: true
+
+  '@oxlint/darwin-x64@0.15.15':
+    optional: true
+
+  '@oxlint/linux-arm64-gnu@0.15.15':
+    optional: true
+
+  '@oxlint/linux-arm64-musl@0.15.15':
+    optional: true
+
+  '@oxlint/linux-x64-gnu@0.15.15':
+    optional: true
+
+  '@oxlint/linux-x64-musl@0.15.15':
+    optional: true
+
+  '@oxlint/win32-arm64@0.15.15':
+    optional: true
+
+  '@oxlint/win32-x64@0.15.15':
+    optional: true
+
+  '@parcel/watcher-android-arm64@2.5.1':
+    optional: true
+
+  '@parcel/watcher-darwin-arm64@2.5.1':
+    optional: true
+
+  '@parcel/watcher-darwin-x64@2.5.1':
+    optional: true
+
+  '@parcel/watcher-freebsd-x64@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-arm-glibc@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-arm-musl@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-arm64-glibc@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-arm64-musl@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-x64-glibc@2.5.1':
+    optional: true
+
+  '@parcel/watcher-linux-x64-musl@2.5.1':
+    optional: true
+
+  '@parcel/watcher-win32-arm64@2.5.1':
+    optional: true
+
+  '@parcel/watcher-win32-ia32@2.5.1':
+    optional: true
+
+  '@parcel/watcher-win32-x64@2.5.1':
+    optional: true
+
+  '@parcel/watcher@2.5.1':
+    dependencies:
+      detect-libc: 1.0.3
+      is-glob: 4.0.3
+      micromatch: 4.0.8
+      node-addon-api: 7.1.1
+    optionalDependencies:
+      '@parcel/watcher-android-arm64': 2.5.1
+      '@parcel/watcher-darwin-arm64': 2.5.1
+      '@parcel/watcher-darwin-x64': 2.5.1
+      '@parcel/watcher-freebsd-x64': 2.5.1
+      '@parcel/watcher-linux-arm-glibc': 2.5.1
+      '@parcel/watcher-linux-arm-musl': 2.5.1
+      '@parcel/watcher-linux-arm64-glibc': 2.5.1
+      '@parcel/watcher-linux-arm64-musl': 2.5.1
+      '@parcel/watcher-linux-x64-glibc': 2.5.1
+      '@parcel/watcher-linux-x64-musl': 2.5.1
+      '@parcel/watcher-win32-arm64': 2.5.1
+      '@parcel/watcher-win32-ia32': 2.5.1
+      '@parcel/watcher-win32-x64': 2.5.1
+    optional: true
+
+  '@pkgjs/parseargs@0.11.0':
+    optional: true
+
+  '@pkgr/core@0.1.2': {}
+
+  '@polka/url@1.0.0-next.28': {}
+
+  '@rollup/pluginutils@5.1.4(rollup@4.35.0)':
+    dependencies:
+      '@types/estree': 1.0.6
+      estree-walker: 2.0.2
+      picomatch: 4.0.2
+    optionalDependencies:
+      rollup: 4.35.0
+
+  '@rollup/rollup-android-arm-eabi@4.35.0':
+    optional: true
+
+  '@rollup/rollup-android-arm64@4.35.0':
+    optional: true
+
+  '@rollup/rollup-darwin-arm64@4.35.0':
+    optional: true
+
+  '@rollup/rollup-darwin-x64@4.35.0':
+    optional: true
+
+  '@rollup/rollup-freebsd-arm64@4.35.0':
+    optional: true
+
+  '@rollup/rollup-freebsd-x64@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm-gnueabihf@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm-musleabihf@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-arm64-musl@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-loongarch64-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-powerpc64le-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-riscv64-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-s390x-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-x64-gnu@4.35.0':
+    optional: true
+
+  '@rollup/rollup-linux-x64-musl@4.35.0':
+    optional: true
+
+  '@rollup/rollup-win32-arm64-msvc@4.35.0':
+    optional: true
+
+  '@rollup/rollup-win32-ia32-msvc@4.35.0':
+    optional: true
+
+  '@rollup/rollup-win32-x64-msvc@4.35.0':
+    optional: true
+
+  '@sec-ant/readable-stream@0.4.1': {}
+
+  '@sideway/address@4.1.5':
+    dependencies:
+      '@hapi/hoek': 9.3.0
+
+  '@sideway/formula@3.0.1': {}
+
+  '@sideway/pinpoint@2.0.0': {}
+
+  '@sindresorhus/merge-streams@4.0.0': {}
+
+  '@sxzz/popperjs-es@2.11.7': {}
+
+  '@tsconfig/node22@22.0.0': {}
+
+  '@tybys/wasm-util@0.9.0':
+    dependencies:
+      tslib: 2.8.1
+    optional: true
+
+  '@types/estree@1.0.6': {}
+
+  '@types/jsdom@21.1.7':
+    dependencies:
+      '@types/node': 22.13.10
+      '@types/tough-cookie': 4.0.5
+      parse5: 7.2.1
+
+  '@types/json-schema@7.0.15': {}
+
+  '@types/lodash-es@4.17.12':
+    dependencies:
+      '@types/lodash': 4.17.16
+
+  '@types/lodash@4.17.16': {}
+
+  '@types/node@22.13.10':
+    dependencies:
+      undici-types: 6.20.0
+
+  '@types/sinonjs__fake-timers@8.1.1': {}
+
+  '@types/sizzle@2.3.9': {}
+
+  '@types/tough-cookie@4.0.5': {}
+
+  '@types/web-bluetooth@0.0.16': {}
+
+  '@types/web-bluetooth@0.0.21': {}
+
+  '@types/yauzl@2.10.3':
+    dependencies:
+      '@types/node': 22.13.10
+    optional: true
+
+  '@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+    dependencies:
+      '@eslint-community/regexpp': 4.12.1
+      '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@typescript-eslint/scope-manager': 8.26.1
+      '@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@typescript-eslint/visitor-keys': 8.26.1
+      eslint: 9.22.0(jiti@2.4.2)
+      graphemer: 1.4.0
+      ignore: 5.3.2
+      natural-compare: 1.4.0
+      ts-api-utils: 2.0.1(typescript@5.8.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 8.26.1
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
+      '@typescript-eslint/visitor-keys': 8.26.1
+      debug: 4.4.0(supports-color@8.1.1)
+      eslint: 9.22.0(jiti@2.4.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/scope-manager@8.26.1':
+    dependencies:
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/visitor-keys': 8.26.1
+
+  '@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+    dependencies:
+      '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
+      '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      debug: 4.4.0(supports-color@8.1.1)
+      eslint: 9.22.0(jiti@2.4.2)
+      ts-api-utils: 2.0.1(typescript@5.8.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/types@8.26.1': {}
+
+  '@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.2)':
+    dependencies:
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/visitor-keys': 8.26.1
+      debug: 4.4.0(supports-color@8.1.1)
+      fast-glob: 3.3.3
+      is-glob: 4.0.3
+      minimatch: 9.0.5
+      semver: 7.7.1
+      ts-api-utils: 2.0.1(typescript@5.8.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+    dependencies:
+      '@eslint-community/eslint-utils': 4.5.1(eslint@9.22.0(jiti@2.4.2))
+      '@typescript-eslint/scope-manager': 8.26.1
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
+      eslint: 9.22.0(jiti@2.4.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@typescript-eslint/visitor-keys@8.26.1':
+    dependencies:
+      '@typescript-eslint/types': 8.26.1
+      eslint-visitor-keys: 4.2.0
+
+  '@unrs/resolver-binding-darwin-arm64@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-darwin-x64@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-freebsd-x64@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-arm-gnueabihf@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-arm-musleabihf@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-arm64-gnu@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-arm64-musl@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-ppc64-gnu@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-riscv64-gnu@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-s390x-gnu@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-x64-gnu@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-linux-x64-musl@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-wasm32-wasi@1.5.0':
+    dependencies:
+      '@napi-rs/wasm-runtime': 0.2.8
+    optional: true
+
+  '@unrs/resolver-binding-win32-arm64-msvc@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-win32-ia32-msvc@1.5.0':
+    optional: true
+
+  '@unrs/resolver-binding-win32-x64-msvc@1.5.0':
+    optional: true
+
+  '@vitejs/plugin-vue-jsx@4.1.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.10)
+      '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.26.10)
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vue: 3.5.13(typescript@5.8.2)
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vitejs/plugin-vue@5.2.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@vitest/eslint-plugin@1.1.38(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)(vitest@3.0.9(@types/node@22.13.10)(jiti@2.4.2)(jsdom@26.0.0)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))':
+    dependencies:
+      '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      eslint: 9.22.0(jiti@2.4.2)
+    optionalDependencies:
+      typescript: 5.8.2
+      vitest: 3.0.9(@types/node@22.13.10)(jiti@2.4.2)(jsdom@26.0.0)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+
+  '@vitest/expect@3.0.9':
+    dependencies:
+      '@vitest/spy': 3.0.9
+      '@vitest/utils': 3.0.9
+      chai: 5.2.0
+      tinyrainbow: 2.0.0
+
+  '@vitest/mocker@3.0.9(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))':
+    dependencies:
+      '@vitest/spy': 3.0.9
+      estree-walker: 3.0.3
+      magic-string: 0.30.17
+    optionalDependencies:
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+
+  '@vitest/pretty-format@3.0.9':
+    dependencies:
+      tinyrainbow: 2.0.0
+
+  '@vitest/runner@3.0.9':
+    dependencies:
+      '@vitest/utils': 3.0.9
+      pathe: 2.0.3
+
+  '@vitest/snapshot@3.0.9':
+    dependencies:
+      '@vitest/pretty-format': 3.0.9
+      magic-string: 0.30.17
+      pathe: 2.0.3
+
+  '@vitest/spy@3.0.9':
+    dependencies:
+      tinyspy: 3.0.2
+
+  '@vitest/utils@3.0.9':
+    dependencies:
+      '@vitest/pretty-format': 3.0.9
+      loupe: 3.1.3
+      tinyrainbow: 2.0.0
+
+  '@volar/language-core@2.4.12':
+    dependencies:
+      '@volar/source-map': 2.4.12
+
+  '@volar/source-map@2.4.12': {}
+
+  '@volar/typescript@2.4.12':
+    dependencies:
+      '@volar/language-core': 2.4.12
+      path-browserify: 1.0.1
+      vscode-uri: 3.1.0
+
+  '@vue/babel-helper-vue-transform-on@1.4.0': {}
+
+  '@vue/babel-plugin-jsx@1.4.0(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/helper-module-imports': 7.25.9
+      '@babel/helper-plugin-utils': 7.26.5
+      '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10)
+      '@babel/template': 7.26.9
+      '@babel/traverse': 7.26.10
+      '@babel/types': 7.26.10
+      '@vue/babel-helper-vue-transform-on': 1.4.0
+      '@vue/babel-plugin-resolve-type': 1.4.0(@babel/core@7.26.10)
+      '@vue/shared': 3.5.13
+    optionalDependencies:
+      '@babel/core': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vue/babel-plugin-resolve-type@1.4.0(@babel/core@7.26.10)':
+    dependencies:
+      '@babel/code-frame': 7.26.2
+      '@babel/core': 7.26.10
+      '@babel/helper-module-imports': 7.25.9
+      '@babel/helper-plugin-utils': 7.26.5
+      '@babel/parser': 7.26.10
+      '@vue/compiler-sfc': 3.5.13
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vue/compiler-core@3.5.13':
+    dependencies:
+      '@babel/parser': 7.26.10
+      '@vue/shared': 3.5.13
+      entities: 4.5.0
+      estree-walker: 2.0.2
+      source-map-js: 1.2.1
+
+  '@vue/compiler-dom@3.5.13':
+    dependencies:
+      '@vue/compiler-core': 3.5.13
+      '@vue/shared': 3.5.13
+
+  '@vue/compiler-sfc@3.5.13':
+    dependencies:
+      '@babel/parser': 7.26.10
+      '@vue/compiler-core': 3.5.13
+      '@vue/compiler-dom': 3.5.13
+      '@vue/compiler-ssr': 3.5.13
+      '@vue/shared': 3.5.13
+      estree-walker: 2.0.2
+      magic-string: 0.30.17
+      postcss: 8.5.3
+      source-map-js: 1.2.1
+
+  '@vue/compiler-ssr@3.5.13':
+    dependencies:
+      '@vue/compiler-dom': 3.5.13
+      '@vue/shared': 3.5.13
+
+  '@vue/compiler-vue2@2.7.16':
+    dependencies:
+      de-indent: 1.0.2
+      he: 1.2.0
+
+  '@vue/devtools-api@6.6.4': {}
+
+  '@vue/devtools-api@7.7.2':
+    dependencies:
+      '@vue/devtools-kit': 7.7.2
+
+  '@vue/devtools-core@7.7.2(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@vue/devtools-kit': 7.7.2
+      '@vue/devtools-shared': 7.7.2
+      mitt: 3.0.1
+      nanoid: 5.1.5
+      pathe: 2.0.3
+      vite-hot-client: 0.2.4(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))
+      vue: 3.5.13(typescript@5.8.2)
+    transitivePeerDependencies:
+      - vite
+
+  '@vue/devtools-kit@7.7.2':
+    dependencies:
+      '@vue/devtools-shared': 7.7.2
+      birpc: 0.2.19
+      hookable: 5.5.3
+      mitt: 3.0.1
+      perfect-debounce: 1.0.0
+      speakingurl: 14.0.1
+      superjson: 2.2.2
+
+  '@vue/devtools-shared@7.7.2':
+    dependencies:
+      rfdc: 1.4.1
+
+  '@vue/eslint-config-prettier@10.2.0(eslint@9.22.0(jiti@2.4.2))(prettier@3.5.3)':
+    dependencies:
+      eslint: 9.22.0(jiti@2.4.2)
+      eslint-config-prettier: 10.1.1(eslint@9.22.0(jiti@2.4.2))
+      eslint-plugin-prettier: 5.2.3(eslint-config-prettier@10.1.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(prettier@3.5.3)
+      prettier: 3.5.3
+    transitivePeerDependencies:
+      - '@types/eslint'
+
+  '@vue/eslint-config-typescript@14.5.0(eslint-plugin-vue@10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2))))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
+    dependencies:
+      '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      eslint: 9.22.0(jiti@2.4.2)
+      eslint-plugin-vue: 10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2)))
+      fast-glob: 3.3.3
+      typescript-eslint: 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      vue-eslint-parser: 10.1.1(eslint@9.22.0(jiti@2.4.2))
+    optionalDependencies:
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  '@vue/language-core@2.2.8(typescript@5.8.2)':
+    dependencies:
+      '@volar/language-core': 2.4.12
+      '@vue/compiler-dom': 3.5.13
+      '@vue/compiler-vue2': 2.7.16
+      '@vue/shared': 3.5.13
+      alien-signals: 1.0.7
+      minimatch: 9.0.5
+      muggle-string: 0.4.1
+      path-browserify: 1.0.1
+    optionalDependencies:
+      typescript: 5.8.2
+
+  '@vue/reactivity@3.5.13':
+    dependencies:
+      '@vue/shared': 3.5.13
+
+  '@vue/runtime-core@3.5.13':
+    dependencies:
+      '@vue/reactivity': 3.5.13
+      '@vue/shared': 3.5.13
+
+  '@vue/runtime-dom@3.5.13':
+    dependencies:
+      '@vue/reactivity': 3.5.13
+      '@vue/runtime-core': 3.5.13
+      '@vue/shared': 3.5.13
+      csstype: 3.1.3
+
+  '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@vue/compiler-ssr': 3.5.13
+      '@vue/shared': 3.5.13
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@vue/shared@3.5.13': {}
+
+  '@vue/test-utils@2.4.6':
+    dependencies:
+      js-beautify: 1.15.4
+      vue-component-type-helpers: 2.2.8
+
+  '@vue/tsconfig@0.7.0(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2))':
+    optionalDependencies:
+      typescript: 5.8.2
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@vueuse/core@13.0.0(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@types/web-bluetooth': 0.0.21
+      '@vueuse/metadata': 13.0.0
+      '@vueuse/shared': 13.0.0(vue@3.5.13(typescript@5.8.2))
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@vueuse/core@9.13.0(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@types/web-bluetooth': 0.0.16
+      '@vueuse/metadata': 9.13.0
+      '@vueuse/shared': 9.13.0(vue@3.5.13(typescript@5.8.2))
+      vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
+  '@vueuse/integrations@13.0.0(async-validator@4.2.5)(axios@1.8.4)(universal-cookie@8.0.1)(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      '@vueuse/core': 13.0.0(vue@3.5.13(typescript@5.8.2))
+      '@vueuse/shared': 13.0.0(vue@3.5.13(typescript@5.8.2))
+      vue: 3.5.13(typescript@5.8.2)
+    optionalDependencies:
+      async-validator: 4.2.5
+      axios: 1.8.4(debug@4.4.0)
+      universal-cookie: 8.0.1
+
+  '@vueuse/metadata@13.0.0': {}
+
+  '@vueuse/metadata@9.13.0': {}
+
+  '@vueuse/shared@13.0.0(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      vue: 3.5.13(typescript@5.8.2)
+
+  '@vueuse/shared@9.13.0(vue@3.5.13(typescript@5.8.2))':
+    dependencies:
+      vue-demi: 0.14.10(vue@3.5.13(typescript@5.8.2))
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+      - vue
+
+  abbrev@2.0.0: {}
+
+  acorn-jsx@5.3.2(acorn@8.14.1):
+    dependencies:
+      acorn: 8.14.1
+
+  acorn@8.14.1: {}
+
+  agent-base@7.1.3: {}
+
+  aggregate-error@3.1.0:
+    dependencies:
+      clean-stack: 2.2.0
+      indent-string: 4.0.0
+
+  ajv@6.12.6:
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+
+  alien-signals@1.0.7: {}
+
+  ansi-colors@4.1.3: {}
+
+  ansi-escapes@4.3.2:
+    dependencies:
+      type-fest: 0.21.3
+
+  ansi-regex@5.0.1: {}
+
+  ansi-regex@6.1.0: {}
+
+  ansi-styles@4.3.0:
+    dependencies:
+      color-convert: 2.0.1
+
+  ansi-styles@6.2.1: {}
+
+  anymatch@3.1.3:
+    dependencies:
+      normalize-path: 3.0.0
+      picomatch: 2.3.1
+
+  arch@2.2.0: {}
+
+  arg@5.0.2: {}
+
+  argparse@2.0.1: {}
+
+  asn1@0.2.6:
+    dependencies:
+      safer-buffer: 2.1.2
+
+  assert-plus@1.0.0: {}
+
+  assertion-error@2.0.1: {}
+
+  astral-regex@2.0.0: {}
+
+  async-validator@4.2.5: {}
+
+  async@3.2.3: {}
+
+  asynckit@0.4.0: {}
+
+  at-least-node@1.0.0: {}
+
+  autoprefixer@10.4.21(postcss@8.5.3):
+    dependencies:
+      browserslist: 4.24.4
+      caniuse-lite: 1.0.30001705
+      fraction.js: 4.3.7
+      normalize-range: 0.1.2
+      picocolors: 1.1.1
+      postcss: 8.5.3
+      postcss-value-parser: 4.2.0
+
+  aws-sign2@0.7.0: {}
+
+  aws4@1.13.2: {}
+
+  axios@1.8.4(debug@4.4.0):
+    dependencies:
+      follow-redirects: 1.15.9(debug@4.4.0)
+      form-data: 4.0.2
+      proxy-from-env: 1.1.0
+    transitivePeerDependencies:
+      - debug
+
+  balanced-match@1.0.2: {}
+
+  base64-js@1.5.1: {}
+
+  bcrypt-pbkdf@1.0.2:
+    dependencies:
+      tweetnacl: 0.14.5
+
+  binary-extensions@2.3.0: {}
+
+  birpc@0.2.19: {}
+
+  blob-util@2.0.2: {}
+
+  bluebird@3.7.2: {}
+
+  boolbase@1.0.0: {}
+
+  brace-expansion@1.1.11:
+    dependencies:
+      balanced-match: 1.0.2
+      concat-map: 0.0.1
+
+  brace-expansion@2.0.1:
+    dependencies:
+      balanced-match: 1.0.2
+
+  braces@3.0.3:
+    dependencies:
+      fill-range: 7.1.1
+
+  browserslist@4.24.4:
+    dependencies:
+      caniuse-lite: 1.0.30001705
+      electron-to-chromium: 1.5.119
+      node-releases: 2.0.19
+      update-browserslist-db: 1.1.3(browserslist@4.24.4)
+
+  buffer-crc32@0.2.13: {}
+
+  buffer@5.7.1:
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+
+  bundle-name@4.1.0:
+    dependencies:
+      run-applescript: 7.0.0
+
+  cac@6.7.14: {}
+
+  cachedir@2.4.0: {}
+
+  call-bind-apply-helpers@1.0.2:
+    dependencies:
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+
+  call-bound@1.0.4:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      get-intrinsic: 1.3.0
+
+  callsites@3.1.0: {}
+
+  caniuse-lite@1.0.30001705: {}
+
+  caseless@0.12.0: {}
+
+  chai@5.2.0:
+    dependencies:
+      assertion-error: 2.0.1
+      check-error: 2.1.1
+      deep-eql: 5.0.2
+      loupe: 3.1.3
+      pathval: 2.0.0
+
+  chalk@4.1.2:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+
+  check-error@2.1.1: {}
+
+  check-more-types@2.24.0: {}
+
+  chokidar@3.6.0:
+    dependencies:
+      anymatch: 3.1.3
+      braces: 3.0.3
+      glob-parent: 5.1.2
+      is-binary-path: 2.1.0
+      is-glob: 4.0.3
+      normalize-path: 3.0.0
+      readdirp: 3.6.0
+    optionalDependencies:
+      fsevents: 2.3.3
+
+  chokidar@4.0.3:
+    dependencies:
+      readdirp: 4.1.2
+
+  ci-info@4.2.0: {}
+
+  clean-stack@2.2.0: {}
+
+  cli-cursor@3.1.0:
+    dependencies:
+      restore-cursor: 3.1.0
+
+  cli-table3@0.6.5:
+    dependencies:
+      string-width: 4.2.3
+    optionalDependencies:
+      '@colors/colors': 1.5.0
+
+  cli-truncate@2.1.0:
+    dependencies:
+      slice-ansi: 3.0.0
+      string-width: 4.2.3
+
+  color-convert@2.0.1:
+    dependencies:
+      color-name: 1.1.4
+
+  color-name@1.1.4: {}
+
+  colorette@2.0.20: {}
+
+  combined-stream@1.0.8:
+    dependencies:
+      delayed-stream: 1.0.0
+
+  commander@10.0.1: {}
+
+  commander@6.2.1: {}
+
+  common-tags@1.8.2: {}
+
+  concat-map@0.0.1: {}
+
+  confbox@0.1.8: {}
+
+  confbox@0.2.2: {}
+
+  config-chain@1.1.13:
+    dependencies:
+      ini: 1.3.8
+      proto-list: 1.2.4
+
+  convert-source-map@2.0.0: {}
+
+  cookie@1.0.2: {}
+
+  copy-anything@2.0.6:
+    dependencies:
+      is-what: 3.14.1
+    optional: true
+
+  copy-anything@3.0.5:
+    dependencies:
+      is-what: 4.1.16
+
+  core-util-is@1.0.2: {}
+
+  cross-spawn@7.0.6:
+    dependencies:
+      path-key: 3.1.1
+      shebang-command: 2.0.0
+      which: 2.0.2
+
+  cssesc@3.0.0: {}
+
+  cssstyle@4.3.0:
+    dependencies:
+      '@asamuzakjp/css-color': 3.1.1
+      rrweb-cssom: 0.8.0
+
+  csstype@3.1.3: {}
+
+  cypress@14.2.0:
+    dependencies:
+      '@cypress/request': 3.0.8
+      '@cypress/xvfb': 1.2.4(supports-color@8.1.1)
+      '@types/sinonjs__fake-timers': 8.1.1
+      '@types/sizzle': 2.3.9
+      arch: 2.2.0
+      blob-util: 2.0.2
+      bluebird: 3.7.2
+      buffer: 5.7.1
+      cachedir: 2.4.0
+      chalk: 4.1.2
+      check-more-types: 2.24.0
+      ci-info: 4.2.0
+      cli-cursor: 3.1.0
+      cli-table3: 0.6.5
+      commander: 6.2.1
+      common-tags: 1.8.2
+      dayjs: 1.11.13
+      debug: 4.4.0(supports-color@8.1.1)
+      enquirer: 2.4.1
+      eventemitter2: 6.4.7
+      execa: 4.1.0
+      executable: 4.1.1
+      extract-zip: 2.0.1(supports-color@8.1.1)
+      figures: 3.2.0
+      fs-extra: 9.1.0
+      getos: 3.2.1
+      is-installed-globally: 0.4.0
+      lazy-ass: 1.6.0
+      listr2: 3.14.0(enquirer@2.4.1)
+      lodash: 4.17.21
+      log-symbols: 4.1.0
+      minimist: 1.2.8
+      ospath: 1.2.2
+      pretty-bytes: 5.6.0
+      process: 0.11.10
+      proxy-from-env: 1.0.0
+      request-progress: 3.0.0
+      semver: 7.7.1
+      supports-color: 8.1.1
+      tmp: 0.2.3
+      tree-kill: 1.2.2
+      untildify: 4.0.0
+      yauzl: 2.10.0
+
+  dashdash@1.14.1:
+    dependencies:
+      assert-plus: 1.0.0
+
+  data-urls@5.0.0:
+    dependencies:
+      whatwg-mimetype: 4.0.0
+      whatwg-url: 14.2.0
+
+  dayjs@1.11.13: {}
+
+  de-indent@1.0.2: {}
+
+  debug@3.2.7(supports-color@8.1.1):
+    dependencies:
+      ms: 2.1.3
+    optionalDependencies:
+      supports-color: 8.1.1
+
+  debug@4.4.0(supports-color@8.1.1):
+    dependencies:
+      ms: 2.1.3
+    optionalDependencies:
+      supports-color: 8.1.1
+
+  decimal.js@10.5.0: {}
+
+  decode-uri-component@0.4.1: {}
+
+  deep-eql@5.0.2: {}
+
+  deep-is@0.1.4: {}
+
+  default-browser-id@5.0.0: {}
+
+  default-browser@5.2.1:
+    dependencies:
+      bundle-name: 4.1.0
+      default-browser-id: 5.0.0
+
+  define-lazy-prop@3.0.0: {}
+
+  delayed-stream@1.0.0: {}
+
+  detect-libc@1.0.3:
+    optional: true
+
+  dunder-proto@1.0.1:
+    dependencies:
+      call-bind-apply-helpers: 1.0.2
+      es-errors: 1.3.0
+      gopd: 1.2.0
+
+  duplexer@0.1.2: {}
+
+  eastasianwidth@0.2.0: {}
+
+  ecc-jsbn@0.1.2:
+    dependencies:
+      jsbn: 0.1.1
+      safer-buffer: 2.1.2
+
+  editorconfig@1.0.4:
+    dependencies:
+      '@one-ini/wasm': 0.1.1
+      commander: 10.0.1
+      minimatch: 9.0.1
+      semver: 7.7.1
+
+  electron-to-chromium@1.5.119: {}
+
+  element-plus@2.9.7(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      '@ctrl/tinycolor': 3.6.1
+      '@element-plus/icons-vue': 2.3.1(vue@3.5.13(typescript@5.8.2))
+      '@floating-ui/dom': 1.6.13
+      '@popperjs/core': '@sxzz/popperjs-es@2.11.7'
+      '@types/lodash': 4.17.16
+      '@types/lodash-es': 4.17.12
+      '@vueuse/core': 9.13.0(vue@3.5.13(typescript@5.8.2))
+      async-validator: 4.2.5
+      dayjs: 1.11.13
+      escape-html: 1.0.3
+      lodash: 4.17.21
+      lodash-es: 4.17.21
+      lodash-unified: 1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21)
+      memoize-one: 6.0.0
+      normalize-wheel-es: 1.2.0
+      vue: 3.5.13(typescript@5.8.2)
+    transitivePeerDependencies:
+      - '@vue/composition-api'
+
+  emoji-regex@8.0.0: {}
+
+  emoji-regex@9.2.2: {}
+
+  end-of-stream@1.4.4:
+    dependencies:
+      once: 1.4.0
+
+  enquirer@2.4.1:
+    dependencies:
+      ansi-colors: 4.1.3
+      strip-ansi: 6.0.1
+
+  entities@4.5.0: {}
+
+  errno@0.1.8:
+    dependencies:
+      prr: 1.0.1
+    optional: true
+
+  error-stack-parser-es@0.1.5: {}
+
+  es-define-property@1.0.1: {}
+
+  es-errors@1.3.0: {}
+
+  es-module-lexer@1.6.0: {}
+
+  es-object-atoms@1.1.1:
+    dependencies:
+      es-errors: 1.3.0
+
+  es-set-tostringtag@2.1.0:
+    dependencies:
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      has-tostringtag: 1.0.2
+      hasown: 2.0.2
+
+  esbuild@0.25.1:
+    optionalDependencies:
+      '@esbuild/aix-ppc64': 0.25.1
+      '@esbuild/android-arm': 0.25.1
+      '@esbuild/android-arm64': 0.25.1
+      '@esbuild/android-x64': 0.25.1
+      '@esbuild/darwin-arm64': 0.25.1
+      '@esbuild/darwin-x64': 0.25.1
+      '@esbuild/freebsd-arm64': 0.25.1
+      '@esbuild/freebsd-x64': 0.25.1
+      '@esbuild/linux-arm': 0.25.1
+      '@esbuild/linux-arm64': 0.25.1
+      '@esbuild/linux-ia32': 0.25.1
+      '@esbuild/linux-loong64': 0.25.1
+      '@esbuild/linux-mips64el': 0.25.1
+      '@esbuild/linux-ppc64': 0.25.1
+      '@esbuild/linux-riscv64': 0.25.1
+      '@esbuild/linux-s390x': 0.25.1
+      '@esbuild/linux-x64': 0.25.1
+      '@esbuild/netbsd-arm64': 0.25.1
+      '@esbuild/netbsd-x64': 0.25.1
+      '@esbuild/openbsd-arm64': 0.25.1
+      '@esbuild/openbsd-x64': 0.25.1
+      '@esbuild/sunos-x64': 0.25.1
+      '@esbuild/win32-arm64': 0.25.1
+      '@esbuild/win32-ia32': 0.25.1
+      '@esbuild/win32-x64': 0.25.1
+
+  escalade@3.2.0: {}
+
+  escape-html@1.0.3: {}
+
+  escape-string-regexp@1.0.5: {}
+
+  escape-string-regexp@4.0.0: {}
+
+  escape-string-regexp@5.0.0: {}
+
+  eslint-config-prettier@10.1.1(eslint@9.22.0(jiti@2.4.2)):
+    dependencies:
+      eslint: 9.22.0(jiti@2.4.2)
+
+  eslint-import-resolver-typescript@4.3.2(eslint@9.22.0(jiti@2.4.2)):
+    dependencies:
+      debug: 4.4.0(supports-color@8.1.1)
+      eslint: 9.22.0(jiti@2.4.2)
+      get-tsconfig: 4.10.0
+      is-bun-module: 2.0.0
+      stable-hash: 0.0.5
+      tinyglobby: 0.2.12
+      unrs-resolver: 1.5.0
+    transitivePeerDependencies:
+      - supports-color
+
+  eslint-plugin-cypress@4.2.0(eslint@9.22.0(jiti@2.4.2)):
+    dependencies:
+      eslint: 9.22.0(jiti@2.4.2)
+      globals: 15.15.0
+
+  eslint-plugin-oxlint@0.15.15:
+    dependencies:
+      jsonc-parser: 3.3.1
+
+  eslint-plugin-prettier@5.2.3(eslint-config-prettier@10.1.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(prettier@3.5.3):
+    dependencies:
+      eslint: 9.22.0(jiti@2.4.2)
+      prettier: 3.5.3
+      prettier-linter-helpers: 1.0.0
+      synckit: 0.9.2
+    optionalDependencies:
+      eslint-config-prettier: 10.1.1(eslint@9.22.0(jiti@2.4.2))
+
+  eslint-plugin-vue@10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2))):
+    dependencies:
+      '@eslint-community/eslint-utils': 4.5.1(eslint@9.22.0(jiti@2.4.2))
+      eslint: 9.22.0(jiti@2.4.2)
+      natural-compare: 1.4.0
+      nth-check: 2.1.1
+      postcss-selector-parser: 6.1.2
+      semver: 7.7.1
+      vue-eslint-parser: 10.1.1(eslint@9.22.0(jiti@2.4.2))
+      xml-name-validator: 4.0.0
+
+  eslint-scope@8.3.0:
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+
+  eslint-visitor-keys@3.4.3: {}
+
+  eslint-visitor-keys@4.2.0: {}
+
+  eslint@9.22.0(jiti@2.4.2):
+    dependencies:
+      '@eslint-community/eslint-utils': 4.5.1(eslint@9.22.0(jiti@2.4.2))
+      '@eslint-community/regexpp': 4.12.1
+      '@eslint/config-array': 0.19.2
+      '@eslint/config-helpers': 0.1.0
+      '@eslint/core': 0.12.0
+      '@eslint/eslintrc': 3.3.0
+      '@eslint/js': 9.22.0
+      '@eslint/plugin-kit': 0.2.7
+      '@humanfs/node': 0.16.6
+      '@humanwhocodes/module-importer': 1.0.1
+      '@humanwhocodes/retry': 0.4.2
+      '@types/estree': 1.0.6
+      '@types/json-schema': 7.0.15
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.6
+      debug: 4.4.0(supports-color@8.1.1)
+      escape-string-regexp: 4.0.0
+      eslint-scope: 8.3.0
+      eslint-visitor-keys: 4.2.0
+      espree: 10.3.0
+      esquery: 1.6.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 8.0.0
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      ignore: 5.3.2
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      json-stable-stringify-without-jsonify: 1.0.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.4
+    optionalDependencies:
+      jiti: 2.4.2
+    transitivePeerDependencies:
+      - supports-color
+
+  espree@10.3.0:
+    dependencies:
+      acorn: 8.14.1
+      acorn-jsx: 5.3.2(acorn@8.14.1)
+      eslint-visitor-keys: 4.2.0
+
+  esquery@1.6.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  esrecurse@4.3.0:
+    dependencies:
+      estraverse: 5.3.0
+
+  estraverse@5.3.0: {}
+
+  estree-walker@2.0.2: {}
+
+  estree-walker@3.0.3:
+    dependencies:
+      '@types/estree': 1.0.6
+
+  esutils@2.0.3: {}
+
+  event-stream@3.3.4:
+    dependencies:
+      duplexer: 0.1.2
+      from: 0.1.7
+      map-stream: 0.1.0
+      pause-stream: 0.0.11
+      split: 0.3.3
+      stream-combiner: 0.0.4
+      through: 2.3.8
+
+  eventemitter2@6.4.7: {}
+
+  execa@4.1.0:
+    dependencies:
+      cross-spawn: 7.0.6
+      get-stream: 5.2.0
+      human-signals: 1.1.1
+      is-stream: 2.0.1
+      merge-stream: 2.0.0
+      npm-run-path: 4.0.1
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+      strip-final-newline: 2.0.0
+
+  execa@5.1.1:
+    dependencies:
+      cross-spawn: 7.0.6
+      get-stream: 6.0.1
+      human-signals: 2.1.0
+      is-stream: 2.0.1
+      merge-stream: 2.0.0
+      npm-run-path: 4.0.1
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+      strip-final-newline: 2.0.0
+
+  execa@9.5.2:
+    dependencies:
+      '@sindresorhus/merge-streams': 4.0.0
+      cross-spawn: 7.0.6
+      figures: 6.1.0
+      get-stream: 9.0.1
+      human-signals: 8.0.0
+      is-plain-obj: 4.1.0
+      is-stream: 4.0.1
+      npm-run-path: 6.0.0
+      pretty-ms: 9.2.0
+      signal-exit: 4.1.0
+      strip-final-newline: 4.0.0
+      yoctocolors: 2.1.1
+
+  executable@4.1.1:
+    dependencies:
+      pify: 2.3.0
+
+  expect-type@1.2.0: {}
+
+  exsolve@1.0.5: {}
+
+  extend@3.0.2: {}
+
+  extract-zip@2.0.1(supports-color@8.1.1):
+    dependencies:
+      debug: 4.4.0(supports-color@8.1.1)
+      get-stream: 5.2.0
+      yauzl: 2.10.0
+    optionalDependencies:
+      '@types/yauzl': 2.10.3
+    transitivePeerDependencies:
+      - supports-color
+
+  extsprintf@1.3.0: {}
+
+  fast-deep-equal@3.1.3: {}
+
+  fast-diff@1.1.2: {}
+
+  fast-glob@3.3.3:
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.8
+
+  fast-json-stable-stringify@2.1.0: {}
+
+  fast-levenshtein@2.0.6: {}
+
+  fastq@1.19.1:
+    dependencies:
+      reusify: 1.1.0
+
+  fd-slicer@1.1.0:
+    dependencies:
+      pend: 1.2.0
+
+  fdir@6.4.3(picomatch@4.0.2):
+    optionalDependencies:
+      picomatch: 4.0.2
+
+  figures@3.2.0:
+    dependencies:
+      escape-string-regexp: 1.0.5
+
+  figures@6.1.0:
+    dependencies:
+      is-unicode-supported: 2.1.0
+
+  file-entry-cache@8.0.0:
+    dependencies:
+      flat-cache: 4.0.1
+
+  fill-range@7.1.1:
+    dependencies:
+      to-regex-range: 5.0.1
+
+  filter-obj@5.1.0: {}
+
+  find-up@5.0.0:
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+
+  flat-cache@4.0.1:
+    dependencies:
+      flatted: 3.3.3
+      keyv: 4.5.4
+
+  flatted@3.3.3: {}
+
+  follow-redirects@1.15.9(debug@4.4.0):
+    optionalDependencies:
+      debug: 4.4.0(supports-color@8.1.1)
+
+  foreground-child@3.3.1:
+    dependencies:
+      cross-spawn: 7.0.6
+      signal-exit: 4.1.0
+
+  forever-agent@0.6.1: {}
+
+  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.35
+
+  fraction.js@4.3.7: {}
+
+  from@0.1.7: {}
+
+  fs-extra@11.3.0:
+    dependencies:
+      graceful-fs: 4.2.11
+      jsonfile: 6.1.0
+      universalify: 2.0.1
+
+  fs-extra@9.1.0:
+    dependencies:
+      at-least-node: 1.0.0
+      graceful-fs: 4.2.11
+      jsonfile: 6.1.0
+      universalify: 2.0.1
+
+  fsevents@2.3.3:
+    optional: true
+
+  function-bind@1.1.2: {}
+
+  gensync@1.0.0-beta.2: {}
+
+  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
+
+  get-proto@1.0.1:
+    dependencies:
+      dunder-proto: 1.0.1
+      es-object-atoms: 1.1.1
+
+  get-stream@5.2.0:
+    dependencies:
+      pump: 3.0.2
+
+  get-stream@6.0.1: {}
+
+  get-stream@9.0.1:
+    dependencies:
+      '@sec-ant/readable-stream': 0.4.1
+      is-stream: 4.0.1
+
+  get-tsconfig@4.10.0:
+    dependencies:
+      resolve-pkg-maps: 1.0.0
+
+  getos@3.2.1:
+    dependencies:
+      async: 3.2.3
+
+  getpass@0.1.7:
+    dependencies:
+      assert-plus: 1.0.0
+
+  glob-parent@5.1.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob-parent@6.0.2:
+    dependencies:
+      is-glob: 4.0.3
+
+  glob@10.4.5:
+    dependencies:
+      foreground-child: 3.3.1
+      jackspeak: 3.4.3
+      minimatch: 9.0.5
+      minipass: 7.1.2
+      package-json-from-dist: 1.0.1
+      path-scurry: 1.11.1
+
+  global-dirs@3.0.1:
+    dependencies:
+      ini: 2.0.0
+
+  globals@11.12.0: {}
+
+  globals@14.0.0: {}
+
+  globals@15.15.0: {}
+
+  gopd@1.2.0: {}
+
+  graceful-fs@4.2.11: {}
+
+  graphemer@1.4.0: {}
+
+  has-flag@4.0.0: {}
+
+  has-symbols@1.1.0: {}
+
+  has-tostringtag@1.0.2:
+    dependencies:
+      has-symbols: 1.1.0
+
+  hasown@2.0.2:
+    dependencies:
+      function-bind: 1.1.2
+
+  he@1.2.0: {}
+
+  hookable@5.5.3: {}
+
+  html-encoding-sniffer@4.0.0:
+    dependencies:
+      whatwg-encoding: 3.1.1
+
+  http-proxy-agent@7.0.2:
+    dependencies:
+      agent-base: 7.1.3
+      debug: 4.4.0(supports-color@8.1.1)
+    transitivePeerDependencies:
+      - supports-color
+
+  http-signature@1.4.0:
+    dependencies:
+      assert-plus: 1.0.0
+      jsprim: 2.0.2
+      sshpk: 1.18.0
+
+  https-proxy-agent@7.0.6:
+    dependencies:
+      agent-base: 7.1.3
+      debug: 4.4.0(supports-color@8.1.1)
+    transitivePeerDependencies:
+      - supports-color
+
+  human-signals@1.1.1: {}
+
+  human-signals@2.1.0: {}
+
+  human-signals@8.0.0: {}
+
+  iconv-lite@0.6.3:
+    dependencies:
+      safer-buffer: 2.1.2
+
+  ieee754@1.2.1: {}
+
+  ignore@5.3.2: {}
+
+  image-size@0.5.5:
+    optional: true
+
+  immutable@5.0.3: {}
+
+  import-fresh@3.3.1:
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
+
+  imurmurhash@0.1.4: {}
+
+  indent-string@4.0.0: {}
+
+  ini@1.3.8: {}
+
+  ini@2.0.0: {}
+
+  is-binary-path@2.1.0:
+    dependencies:
+      binary-extensions: 2.3.0
+
+  is-bun-module@2.0.0:
+    dependencies:
+      semver: 7.7.1
+
+  is-docker@3.0.0: {}
+
+  is-extglob@2.1.1: {}
+
+  is-fullwidth-code-point@3.0.0: {}
+
+  is-glob@4.0.3:
+    dependencies:
+      is-extglob: 2.1.1
+
+  is-inside-container@1.0.0:
+    dependencies:
+      is-docker: 3.0.0
+
+  is-installed-globally@0.4.0:
+    dependencies:
+      global-dirs: 3.0.1
+      is-path-inside: 3.0.3
+
+  is-number@7.0.0: {}
+
+  is-path-inside@3.0.3: {}
+
+  is-plain-obj@4.1.0: {}
+
+  is-potential-custom-element-name@1.0.1: {}
+
+  is-stream@2.0.1: {}
+
+  is-stream@4.0.1: {}
+
+  is-typedarray@1.0.0: {}
+
+  is-unicode-supported@0.1.0: {}
+
+  is-unicode-supported@2.1.0: {}
+
+  is-what@3.14.1:
+    optional: true
+
+  is-what@4.1.16: {}
+
+  is-wsl@3.1.0:
+    dependencies:
+      is-inside-container: 1.0.0
+
+  isexe@2.0.0: {}
+
+  isexe@3.1.1: {}
+
+  isstream@0.1.2: {}
+
+  jackspeak@3.4.3:
+    dependencies:
+      '@isaacs/cliui': 8.0.2
+    optionalDependencies:
+      '@pkgjs/parseargs': 0.11.0
+
+  jiti@2.4.2: {}
+
+  joi@17.13.3:
+    dependencies:
+      '@hapi/hoek': 9.3.0
+      '@hapi/topo': 5.1.0
+      '@sideway/address': 4.1.5
+      '@sideway/formula': 3.0.1
+      '@sideway/pinpoint': 2.0.0
+
+  js-beautify@1.15.4:
+    dependencies:
+      config-chain: 1.1.13
+      editorconfig: 1.0.4
+      glob: 10.4.5
+      js-cookie: 3.0.5
+      nopt: 7.2.1
+
+  js-cookie@3.0.5: {}
+
+  js-tokens@4.0.0: {}
+
+  js-tokens@9.0.1: {}
+
+  js-yaml@4.1.0:
+    dependencies:
+      argparse: 2.0.1
+
+  jsbn@0.1.1: {}
+
+  jsdom@26.0.0:
+    dependencies:
+      cssstyle: 4.3.0
+      data-urls: 5.0.0
+      decimal.js: 10.5.0
+      form-data: 4.0.2
+      html-encoding-sniffer: 4.0.0
+      http-proxy-agent: 7.0.2
+      https-proxy-agent: 7.0.6
+      is-potential-custom-element-name: 1.0.1
+      nwsapi: 2.2.19
+      parse5: 7.2.1
+      rrweb-cssom: 0.8.0
+      saxes: 6.0.0
+      symbol-tree: 3.2.4
+      tough-cookie: 5.1.2
+      w3c-xmlserializer: 5.0.0
+      webidl-conversions: 7.0.0
+      whatwg-encoding: 3.1.1
+      whatwg-mimetype: 4.0.0
+      whatwg-url: 14.2.0
+      ws: 8.18.1
+      xml-name-validator: 5.0.0
+    transitivePeerDependencies:
+      - bufferutil
+      - supports-color
+      - utf-8-validate
+
+  jsesc@3.1.0: {}
+
+  json-buffer@3.0.1: {}
+
+  json-parse-even-better-errors@4.0.0: {}
+
+  json-schema-traverse@0.4.1: {}
+
+  json-schema@0.4.0: {}
+
+  json-stable-stringify-without-jsonify@1.0.1: {}
+
+  json-stringify-safe@5.0.1: {}
+
+  json5@2.2.3: {}
+
+  jsonc-parser@3.3.1: {}
+
+  jsonfile@6.1.0:
+    dependencies:
+      universalify: 2.0.1
+    optionalDependencies:
+      graceful-fs: 4.2.11
+
+  jsprim@2.0.2:
+    dependencies:
+      assert-plus: 1.0.0
+      extsprintf: 1.3.0
+      json-schema: 0.4.0
+      verror: 1.10.0
+
+  keyv@4.5.4:
+    dependencies:
+      json-buffer: 3.0.1
+
+  kolorist@1.8.0: {}
+
+  lazy-ass@1.6.0: {}
+
+  less@4.2.2:
+    dependencies:
+      copy-anything: 2.0.6
+      parse-node-version: 1.0.1
+      tslib: 2.8.1
+    optionalDependencies:
+      errno: 0.1.8
+      graceful-fs: 4.2.11
+      image-size: 0.5.5
+      make-dir: 2.1.0
+      mime: 1.6.0
+      needle: 3.3.1
+      source-map: 0.6.1
+    optional: true
+
+  levn@0.4.1:
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+
+  listr2@3.14.0(enquirer@2.4.1):
+    dependencies:
+      cli-truncate: 2.1.0
+      colorette: 2.0.20
+      log-update: 4.0.0
+      p-map: 4.0.0
+      rfdc: 1.4.1
+      rxjs: 7.8.2
+      through: 2.3.8
+      wrap-ansi: 7.0.0
+    optionalDependencies:
+      enquirer: 2.4.1
+
+  local-pkg@1.1.1:
+    dependencies:
+      mlly: 1.7.4
+      pkg-types: 2.1.0
+      quansync: 0.2.10
+
+  locate-path@6.0.0:
+    dependencies:
+      p-locate: 5.0.0
+
+  lodash-es@4.17.21: {}
+
+  lodash-unified@1.0.3(@types/lodash-es@4.17.12)(lodash-es@4.17.21)(lodash@4.17.21):
+    dependencies:
+      '@types/lodash-es': 4.17.12
+      lodash: 4.17.21
+      lodash-es: 4.17.21
+
+  lodash.merge@4.6.2: {}
+
+  lodash.once@4.1.1: {}
+
+  lodash@4.17.21: {}
+
+  log-symbols@4.1.0:
+    dependencies:
+      chalk: 4.1.2
+      is-unicode-supported: 0.1.0
+
+  log-update@4.0.0:
+    dependencies:
+      ansi-escapes: 4.3.2
+      cli-cursor: 3.1.0
+      slice-ansi: 4.0.0
+      wrap-ansi: 6.2.0
+
+  loupe@3.1.3: {}
+
+  lru-cache@10.4.3: {}
+
+  lru-cache@5.1.1:
+    dependencies:
+      yallist: 3.1.1
+
+  magic-string@0.30.17:
+    dependencies:
+      '@jridgewell/sourcemap-codec': 1.5.0
+
+  make-dir@2.1.0:
+    dependencies:
+      pify: 4.0.1
+      semver: 5.7.2
+    optional: true
+
+  map-stream@0.1.0: {}
+
+  math-intrinsics@1.1.0: {}
+
+  memoize-one@6.0.0: {}
+
+  memorystream@0.3.1: {}
+
+  merge-stream@2.0.0: {}
+
+  merge2@1.4.1: {}
+
+  micromatch@4.0.8:
+    dependencies:
+      braces: 3.0.3
+      picomatch: 2.3.1
+
+  mime-db@1.52.0: {}
+
+  mime-types@2.1.35:
+    dependencies:
+      mime-db: 1.52.0
+
+  mime@1.6.0:
+    optional: true
+
+  mimic-fn@2.1.0: {}
+
+  minimatch@3.1.2:
+    dependencies:
+      brace-expansion: 1.1.11
+
+  minimatch@9.0.1:
+    dependencies:
+      brace-expansion: 2.0.1
+
+  minimatch@9.0.5:
+    dependencies:
+      brace-expansion: 2.0.1
+
+  minimist@1.2.8: {}
+
+  minipass@7.1.2: {}
+
+  mitt@3.0.1: {}
+
+  mlly@1.7.4:
+    dependencies:
+      acorn: 8.14.1
+      pathe: 2.0.3
+      pkg-types: 1.3.1
+      ufo: 1.6.1
+
+  mrmime@2.0.1: {}
+
+  ms@2.1.3: {}
+
+  muggle-string@0.4.1: {}
+
+  nanoid@3.3.10: {}
+
+  nanoid@5.1.5: {}
+
+  natural-compare@1.4.0: {}
+
+  needle@3.3.1:
+    dependencies:
+      iconv-lite: 0.6.3
+      sax: 1.4.1
+    optional: true
+
+  neo-async@2.6.2: {}
+
+  node-addon-api@7.1.1:
+    optional: true
+
+  node-releases@2.0.19: {}
+
+  nopt@7.2.1:
+    dependencies:
+      abbrev: 2.0.0
+
+  normalize-path@3.0.0: {}
+
+  normalize-range@0.1.2: {}
+
+  normalize-wheel-es@1.2.0: {}
+
+  npm-normalize-package-bin@4.0.0: {}
+
+  npm-run-all2@7.0.2:
+    dependencies:
+      ansi-styles: 6.2.1
+      cross-spawn: 7.0.6
+      memorystream: 0.3.1
+      minimatch: 9.0.5
+      pidtree: 0.6.0
+      read-package-json-fast: 4.0.0
+      shell-quote: 1.8.2
+      which: 5.0.0
+
+  npm-run-path@4.0.1:
+    dependencies:
+      path-key: 3.1.1
+
+  npm-run-path@6.0.0:
+    dependencies:
+      path-key: 4.0.0
+      unicorn-magic: 0.3.0
+
+  nth-check@2.1.1:
+    dependencies:
+      boolbase: 1.0.0
+
+  nwsapi@2.2.19: {}
+
+  object-inspect@1.13.4: {}
+
+  once@1.4.0:
+    dependencies:
+      wrappy: 1.0.2
+
+  onetime@5.1.2:
+    dependencies:
+      mimic-fn: 2.1.0
+
+  open@10.1.0:
+    dependencies:
+      default-browser: 5.2.1
+      define-lazy-prop: 3.0.0
+      is-inside-container: 1.0.0
+      is-wsl: 3.1.0
+
+  optionator@0.9.4:
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.5
+
+  ospath@1.2.2: {}
+
+  oxlint@0.15.15:
+    optionalDependencies:
+      '@oxlint/darwin-arm64': 0.15.15
+      '@oxlint/darwin-x64': 0.15.15
+      '@oxlint/linux-arm64-gnu': 0.15.15
+      '@oxlint/linux-arm64-musl': 0.15.15
+      '@oxlint/linux-x64-gnu': 0.15.15
+      '@oxlint/linux-x64-musl': 0.15.15
+      '@oxlint/win32-arm64': 0.15.15
+      '@oxlint/win32-x64': 0.15.15
+
+  p-limit@3.1.0:
+    dependencies:
+      yocto-queue: 0.1.0
+
+  p-locate@5.0.0:
+    dependencies:
+      p-limit: 3.1.0
+
+  p-map@4.0.0:
+    dependencies:
+      aggregate-error: 3.1.0
+
+  package-json-from-dist@1.0.1: {}
+
+  parent-module@1.0.1:
+    dependencies:
+      callsites: 3.1.0
+
+  parse-ms@4.0.0: {}
+
+  parse-node-version@1.0.1:
+    optional: true
+
+  parse5@7.2.1:
+    dependencies:
+      entities: 4.5.0
+
+  path-browserify@1.0.1: {}
+
+  path-exists@4.0.0: {}
+
+  path-key@3.1.1: {}
+
+  path-key@4.0.0: {}
+
+  path-scurry@1.11.1:
+    dependencies:
+      lru-cache: 10.4.3
+      minipass: 7.1.2
+
+  pathe@2.0.3: {}
+
+  pathval@2.0.0: {}
+
+  pause-stream@0.0.11:
+    dependencies:
+      through: 2.3.8
+
+  pend@1.2.0: {}
+
+  perfect-debounce@1.0.0: {}
+
+  performance-now@2.1.0: {}
+
+  picocolors@1.1.1: {}
+
+  picomatch@2.3.1: {}
+
+  picomatch@4.0.2: {}
+
+  pidtree@0.6.0: {}
+
+  pify@2.3.0: {}
+
+  pify@4.0.1:
+    optional: true
+
+  pinia@3.0.1(typescript@5.8.2)(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      '@vue/devtools-api': 7.7.2
+      vue: 3.5.13(typescript@5.8.2)
+    optionalDependencies:
+      typescript: 5.8.2
+
+  pkg-types@1.3.1:
+    dependencies:
+      confbox: 0.1.8
+      mlly: 1.7.4
+      pathe: 2.0.3
+
+  pkg-types@2.1.0:
+    dependencies:
+      confbox: 0.2.2
+      exsolve: 1.0.5
+      pathe: 2.0.3
+
+  postcss-selector-parser@6.1.2:
+    dependencies:
+      cssesc: 3.0.0
+      util-deprecate: 1.0.2
+
+  postcss-value-parser@4.2.0: {}
+
+  postcss@8.5.3:
+    dependencies:
+      nanoid: 3.3.10
+      picocolors: 1.1.1
+      source-map-js: 1.2.1
+
+  prelude-ls@1.2.1: {}
+
+  prettier-linter-helpers@1.0.0:
+    dependencies:
+      fast-diff: 1.1.2
+
+  prettier@3.5.3: {}
+
+  pretty-bytes@5.6.0: {}
+
+  pretty-ms@9.2.0:
+    dependencies:
+      parse-ms: 4.0.0
+
+  process@0.11.10: {}
+
+  proto-list@1.2.4: {}
+
+  proxy-from-env@1.0.0: {}
+
+  proxy-from-env@1.1.0: {}
+
+  prr@1.0.1:
+    optional: true
+
+  ps-tree@1.2.0:
+    dependencies:
+      event-stream: 3.3.4
+
+  pump@3.0.2:
+    dependencies:
+      end-of-stream: 1.4.4
+      once: 1.4.0
+
+  punycode@2.3.1: {}
+
+  qs@6.14.0:
+    dependencies:
+      side-channel: 1.1.0
+
+  quansync@0.2.10: {}
+
+  query-string@9.1.1:
+    dependencies:
+      decode-uri-component: 0.4.1
+      filter-obj: 5.1.0
+      split-on-first: 3.0.0
+
+  queue-microtask@1.2.3: {}
+
+  read-package-json-fast@4.0.0:
+    dependencies:
+      json-parse-even-better-errors: 4.0.0
+      npm-normalize-package-bin: 4.0.0
+
+  readdirp@3.6.0:
+    dependencies:
+      picomatch: 2.3.1
+
+  readdirp@4.1.2: {}
+
+  request-progress@3.0.0:
+    dependencies:
+      throttleit: 1.0.1
+
+  resolve-from@4.0.0: {}
+
+  resolve-pkg-maps@1.0.0: {}
+
+  restore-cursor@3.1.0:
+    dependencies:
+      onetime: 5.1.2
+      signal-exit: 3.0.7
+
+  reusify@1.1.0: {}
+
+  rfdc@1.4.1: {}
+
+  rollup@4.35.0:
+    dependencies:
+      '@types/estree': 1.0.6
+    optionalDependencies:
+      '@rollup/rollup-android-arm-eabi': 4.35.0
+      '@rollup/rollup-android-arm64': 4.35.0
+      '@rollup/rollup-darwin-arm64': 4.35.0
+      '@rollup/rollup-darwin-x64': 4.35.0
+      '@rollup/rollup-freebsd-arm64': 4.35.0
+      '@rollup/rollup-freebsd-x64': 4.35.0
+      '@rollup/rollup-linux-arm-gnueabihf': 4.35.0
+      '@rollup/rollup-linux-arm-musleabihf': 4.35.0
+      '@rollup/rollup-linux-arm64-gnu': 4.35.0
+      '@rollup/rollup-linux-arm64-musl': 4.35.0
+      '@rollup/rollup-linux-loongarch64-gnu': 4.35.0
+      '@rollup/rollup-linux-powerpc64le-gnu': 4.35.0
+      '@rollup/rollup-linux-riscv64-gnu': 4.35.0
+      '@rollup/rollup-linux-s390x-gnu': 4.35.0
+      '@rollup/rollup-linux-x64-gnu': 4.35.0
+      '@rollup/rollup-linux-x64-musl': 4.35.0
+      '@rollup/rollup-win32-arm64-msvc': 4.35.0
+      '@rollup/rollup-win32-ia32-msvc': 4.35.0
+      '@rollup/rollup-win32-x64-msvc': 4.35.0
+      fsevents: 2.3.3
+
+  rrweb-cssom@0.8.0: {}
+
+  run-applescript@7.0.0: {}
+
+  run-parallel@1.2.0:
+    dependencies:
+      queue-microtask: 1.2.3
+
+  rxjs@7.8.2:
+    dependencies:
+      tslib: 2.8.1
+
+  safe-buffer@5.2.1: {}
+
+  safer-buffer@2.1.2: {}
+
+  sass-loader@16.0.5(sass@1.86.3):
+    dependencies:
+      neo-async: 2.6.2
+    optionalDependencies:
+      sass: 1.86.3
+
+  sass@1.86.3:
+    dependencies:
+      chokidar: 4.0.3
+      immutable: 5.0.3
+      source-map-js: 1.2.1
+    optionalDependencies:
+      '@parcel/watcher': 2.5.1
+
+  sax@1.4.1:
+    optional: true
+
+  saxes@6.0.0:
+    dependencies:
+      xmlchars: 2.2.0
+
+  scule@1.3.0: {}
+
+  semver@5.7.2:
+    optional: true
+
+  semver@6.3.1: {}
+
+  semver@7.7.1: {}
+
+  shebang-command@2.0.0:
+    dependencies:
+      shebang-regex: 3.0.0
+
+  shebang-regex@3.0.0: {}
+
+  shell-quote@1.8.2: {}
+
+  side-channel-list@1.0.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-map@1.0.1:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+
+  side-channel-weakmap@1.0.2:
+    dependencies:
+      call-bound: 1.0.4
+      es-errors: 1.3.0
+      get-intrinsic: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-map: 1.0.1
+
+  side-channel@1.1.0:
+    dependencies:
+      es-errors: 1.3.0
+      object-inspect: 1.13.4
+      side-channel-list: 1.0.0
+      side-channel-map: 1.0.1
+      side-channel-weakmap: 1.0.2
+
+  siginfo@2.0.0: {}
+
+  signal-exit@3.0.7: {}
+
+  signal-exit@4.1.0: {}
+
+  sirv@3.0.1:
+    dependencies:
+      '@polka/url': 1.0.0-next.28
+      mrmime: 2.0.1
+      totalist: 3.0.1
+
+  slice-ansi@3.0.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      astral-regex: 2.0.0
+      is-fullwidth-code-point: 3.0.0
+
+  slice-ansi@4.0.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      astral-regex: 2.0.0
+      is-fullwidth-code-point: 3.0.0
+
+  source-map-js@1.2.1: {}
+
+  source-map@0.6.1:
+    optional: true
+
+  speakingurl@14.0.1: {}
+
+  split-on-first@3.0.0: {}
+
+  split@0.3.3:
+    dependencies:
+      through: 2.3.8
+
+  sshpk@1.18.0:
+    dependencies:
+      asn1: 0.2.6
+      assert-plus: 1.0.0
+      bcrypt-pbkdf: 1.0.2
+      dashdash: 1.14.1
+      ecc-jsbn: 0.1.2
+      getpass: 0.1.7
+      jsbn: 0.1.1
+      safer-buffer: 2.1.2
+      tweetnacl: 0.14.5
+
+  stable-hash@0.0.5: {}
+
+  stackback@0.0.2: {}
+
+  start-server-and-test@2.0.11:
+    dependencies:
+      arg: 5.0.2
+      bluebird: 3.7.2
+      check-more-types: 2.24.0
+      debug: 4.4.0(supports-color@8.1.1)
+      execa: 5.1.1
+      lazy-ass: 1.6.0
+      ps-tree: 1.2.0
+      wait-on: 8.0.3(debug@4.4.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  std-env@3.8.1: {}
+
+  stream-combiner@0.0.4:
+    dependencies:
+      duplexer: 0.1.2
+
+  string-width@4.2.3:
+    dependencies:
+      emoji-regex: 8.0.0
+      is-fullwidth-code-point: 3.0.0
+      strip-ansi: 6.0.1
+
+  string-width@5.1.2:
+    dependencies:
+      eastasianwidth: 0.2.0
+      emoji-regex: 9.2.2
+      strip-ansi: 7.1.0
+
+  strip-ansi@6.0.1:
+    dependencies:
+      ansi-regex: 5.0.1
+
+  strip-ansi@7.1.0:
+    dependencies:
+      ansi-regex: 6.1.0
+
+  strip-final-newline@2.0.0: {}
+
+  strip-final-newline@4.0.0: {}
+
+  strip-json-comments@3.1.1: {}
+
+  strip-literal@3.0.0:
+    dependencies:
+      js-tokens: 9.0.1
+
+  superjson@2.2.2:
+    dependencies:
+      copy-anything: 3.0.5
+
+  supports-color@7.2.0:
+    dependencies:
+      has-flag: 4.0.0
+
+  supports-color@8.1.1:
+    dependencies:
+      has-flag: 4.0.0
+
+  symbol-tree@3.2.4: {}
+
+  synckit@0.9.2:
+    dependencies:
+      '@pkgr/core': 0.1.2
+      tslib: 2.8.1
+
+  tailwindcss@4.1.3: {}
+
+  throttleit@1.0.1: {}
+
+  through@2.3.8: {}
+
+  tinybench@2.9.0: {}
+
+  tinyexec@0.3.2: {}
+
+  tinyglobby@0.2.12:
+    dependencies:
+      fdir: 6.4.3(picomatch@4.0.2)
+      picomatch: 4.0.2
+
+  tinypool@1.0.2: {}
+
+  tinyrainbow@2.0.0: {}
+
+  tinyspy@3.0.2: {}
+
+  tldts-core@6.1.85: {}
+
+  tldts@6.1.85:
+    dependencies:
+      tldts-core: 6.1.85
+
+  tmp@0.2.3: {}
+
+  to-regex-range@5.0.1:
+    dependencies:
+      is-number: 7.0.0
+
+  totalist@3.0.1: {}
+
+  tough-cookie@5.1.2:
+    dependencies:
+      tldts: 6.1.85
+
+  tr46@5.1.0:
+    dependencies:
+      punycode: 2.3.1
+
+  tree-kill@1.2.2: {}
+
+  ts-api-utils@2.0.1(typescript@5.8.2):
+    dependencies:
+      typescript: 5.8.2
+
+  tslib@2.8.1: {}
+
+  tunnel-agent@0.6.0:
+    dependencies:
+      safe-buffer: 5.2.1
+
+  tweetnacl@0.14.5: {}
+
+  type-check@0.4.0:
+    dependencies:
+      prelude-ls: 1.2.1
+
+  type-fest@0.21.3: {}
+
+  typescript-eslint@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
+    dependencies:
+      '@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      '@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
+      eslint: 9.22.0(jiti@2.4.2)
+      typescript: 5.8.2
+    transitivePeerDependencies:
+      - supports-color
+
+  typescript@5.8.2: {}
+
+  ufo@1.6.1: {}
+
+  undici-types@6.20.0: {}
+
+  unicorn-magic@0.3.0: {}
+
+  unimport@4.2.0:
+    dependencies:
+      acorn: 8.14.1
+      escape-string-regexp: 5.0.0
+      estree-walker: 3.0.3
+      local-pkg: 1.1.1
+      magic-string: 0.30.17
+      mlly: 1.7.4
+      pathe: 2.0.3
+      picomatch: 4.0.2
+      pkg-types: 2.1.0
+      scule: 1.3.0
+      strip-literal: 3.0.0
+      tinyglobby: 0.2.12
+      unplugin: 2.3.2
+      unplugin-utils: 0.2.4
+
+  universal-cookie@8.0.1:
+    dependencies:
+      cookie: 1.0.2
+
+  universalify@2.0.1: {}
+
+  unplugin-auto-import@19.1.2(@vueuse/core@13.0.0(vue@3.5.13(typescript@5.8.2))):
+    dependencies:
+      local-pkg: 1.1.1
+      magic-string: 0.30.17
+      picomatch: 4.0.2
+      unimport: 4.2.0
+      unplugin: 2.3.2
+      unplugin-utils: 0.2.4
+    optionalDependencies:
+      '@vueuse/core': 13.0.0(vue@3.5.13(typescript@5.8.2))
+
+  unplugin-utils@0.2.4:
+    dependencies:
+      pathe: 2.0.3
+      picomatch: 4.0.2
+
+  unplugin-vue-components@28.5.0(@babel/parser@7.26.10)(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      chokidar: 3.6.0
+      debug: 4.4.0(supports-color@8.1.1)
+      local-pkg: 1.1.1
+      magic-string: 0.30.17
+      mlly: 1.7.4
+      tinyglobby: 0.2.12
+      unplugin: 2.3.2
+      unplugin-utils: 0.2.4
+      vue: 3.5.13(typescript@5.8.2)
+    optionalDependencies:
+      '@babel/parser': 7.26.10
+    transitivePeerDependencies:
+      - supports-color
+
+  unplugin@2.3.2:
+    dependencies:
+      acorn: 8.14.1
+      picomatch: 4.0.2
+      webpack-virtual-modules: 0.6.2
+
+  unrs-resolver@1.5.0:
+    optionalDependencies:
+      '@unrs/resolver-binding-darwin-arm64': 1.5.0
+      '@unrs/resolver-binding-darwin-x64': 1.5.0
+      '@unrs/resolver-binding-freebsd-x64': 1.5.0
+      '@unrs/resolver-binding-linux-arm-gnueabihf': 1.5.0
+      '@unrs/resolver-binding-linux-arm-musleabihf': 1.5.0
+      '@unrs/resolver-binding-linux-arm64-gnu': 1.5.0
+      '@unrs/resolver-binding-linux-arm64-musl': 1.5.0
+      '@unrs/resolver-binding-linux-ppc64-gnu': 1.5.0
+      '@unrs/resolver-binding-linux-riscv64-gnu': 1.5.0
+      '@unrs/resolver-binding-linux-s390x-gnu': 1.5.0
+      '@unrs/resolver-binding-linux-x64-gnu': 1.5.0
+      '@unrs/resolver-binding-linux-x64-musl': 1.5.0
+      '@unrs/resolver-binding-wasm32-wasi': 1.5.0
+      '@unrs/resolver-binding-win32-arm64-msvc': 1.5.0
+      '@unrs/resolver-binding-win32-ia32-msvc': 1.5.0
+      '@unrs/resolver-binding-win32-x64-msvc': 1.5.0
+
+  untildify@4.0.0: {}
+
+  update-browserslist-db@1.1.3(browserslist@4.24.4):
+    dependencies:
+      browserslist: 4.24.4
+      escalade: 3.2.0
+      picocolors: 1.1.1
+
+  uri-js@4.4.1:
+    dependencies:
+      punycode: 2.3.1
+
+  util-deprecate@1.0.2: {}
+
+  uuid@8.3.2: {}
+
+  verror@1.10.0:
+    dependencies:
+      assert-plus: 1.0.0
+      core-util-is: 1.0.2
+      extsprintf: 1.3.0
+
+  vite-hot-client@0.2.4(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)):
+    dependencies:
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+
+  vite-node@3.0.9(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0):
+    dependencies:
+      cac: 6.7.14
+      debug: 4.4.0(supports-color@8.1.1)
+      es-module-lexer: 1.6.0
+      pathe: 2.0.3
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - '@types/node'
+      - jiti
+      - less
+      - lightningcss
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+      - tsx
+      - yaml
+
+  vite-plugin-inspect@0.8.9(rollup@4.35.0)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)):
+    dependencies:
+      '@antfu/utils': 0.7.10
+      '@rollup/pluginutils': 5.1.4(rollup@4.35.0)
+      debug: 4.4.0(supports-color@8.1.1)
+      error-stack-parser-es: 0.1.5
+      fs-extra: 11.3.0
+      open: 10.1.0
+      perfect-debounce: 1.0.0
+      picocolors: 1.1.1
+      sirv: 3.0.1
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - rollup
+      - supports-color
+
+  vite-plugin-vue-devtools@7.7.2(rollup@4.35.0)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      '@vue/devtools-core': 7.7.2(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))(vue@3.5.13(typescript@5.8.2))
+      '@vue/devtools-kit': 7.7.2
+      '@vue/devtools-shared': 7.7.2
+      execa: 9.5.2
+      sirv: 3.0.1
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vite-plugin-inspect: 0.8.9(rollup@4.35.0)(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))
+      vite-plugin-vue-inspector: 5.3.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))
+    transitivePeerDependencies:
+      - '@nuxt/kit'
+      - rollup
+      - supports-color
+      - vue
+
+  vite-plugin-vue-inspector@5.3.1(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)):
+    dependencies:
+      '@babel/core': 7.26.10
+      '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.10)
+      '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.10)
+      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.10)
+      '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.10)
+      '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.26.10)
+      '@vue/compiler-dom': 3.5.13
+      kolorist: 1.8.0
+      magic-string: 0.30.17
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+    transitivePeerDependencies:
+      - supports-color
+
+  vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0):
+    dependencies:
+      esbuild: 0.25.1
+      postcss: 8.5.3
+      rollup: 4.35.0
+    optionalDependencies:
+      '@types/node': 22.13.10
+      fsevents: 2.3.3
+      jiti: 2.4.2
+      less: 4.2.2
+      sass: 1.86.3
+      yaml: 2.7.0
+
+  vitest@3.0.9(@types/node@22.13.10)(jiti@2.4.2)(jsdom@26.0.0)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0):
+    dependencies:
+      '@vitest/expect': 3.0.9
+      '@vitest/mocker': 3.0.9(vite@6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0))
+      '@vitest/pretty-format': 3.0.9
+      '@vitest/runner': 3.0.9
+      '@vitest/snapshot': 3.0.9
+      '@vitest/spy': 3.0.9
+      '@vitest/utils': 3.0.9
+      chai: 5.2.0
+      debug: 4.4.0(supports-color@8.1.1)
+      expect-type: 1.2.0
+      magic-string: 0.30.17
+      pathe: 2.0.3
+      std-env: 3.8.1
+      tinybench: 2.9.0
+      tinyexec: 0.3.2
+      tinypool: 1.0.2
+      tinyrainbow: 2.0.0
+      vite: 6.2.2(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      vite-node: 3.0.9(@types/node@22.13.10)(jiti@2.4.2)(less@4.2.2)(sass@1.86.3)(yaml@2.7.0)
+      why-is-node-running: 2.3.0
+    optionalDependencies:
+      '@types/node': 22.13.10
+      jsdom: 26.0.0
+    transitivePeerDependencies:
+      - jiti
+      - less
+      - lightningcss
+      - msw
+      - sass
+      - sass-embedded
+      - stylus
+      - sugarss
+      - supports-color
+      - terser
+      - tsx
+      - yaml
+
+  vscode-uri@3.1.0: {}
+
+  vue-component-type-helpers@2.2.8: {}
+
+  vue-demi@0.14.10(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      vue: 3.5.13(typescript@5.8.2)
+
+  vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2)):
+    dependencies:
+      debug: 4.4.0(supports-color@8.1.1)
+      eslint: 9.22.0(jiti@2.4.2)
+      eslint-scope: 8.3.0
+      eslint-visitor-keys: 4.2.0
+      espree: 10.3.0
+      esquery: 1.6.0
+      lodash: 4.17.21
+      semver: 7.7.1
+    transitivePeerDependencies:
+      - supports-color
+
+  vue-i18n@9.14.4(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      '@intlify/core-base': 9.14.4
+      '@intlify/shared': 9.14.4
+      '@vue/devtools-api': 6.6.4
+      vue: 3.5.13(typescript@5.8.2)
+
+  vue-router@4.5.0(vue@3.5.13(typescript@5.8.2)):
+    dependencies:
+      '@vue/devtools-api': 6.6.4
+      vue: 3.5.13(typescript@5.8.2)
+
+  vue-tsc@2.2.8(typescript@5.8.2):
+    dependencies:
+      '@volar/typescript': 2.4.12
+      '@vue/language-core': 2.2.8(typescript@5.8.2)
+      typescript: 5.8.2
+
+  vue@3.5.13(typescript@5.8.2):
+    dependencies:
+      '@vue/compiler-dom': 3.5.13
+      '@vue/compiler-sfc': 3.5.13
+      '@vue/runtime-dom': 3.5.13
+      '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.2))
+      '@vue/shared': 3.5.13
+    optionalDependencies:
+      typescript: 5.8.2
+
+  w3c-xmlserializer@5.0.0:
+    dependencies:
+      xml-name-validator: 5.0.0
+
+  wait-on@8.0.3(debug@4.4.0):
+    dependencies:
+      axios: 1.8.4(debug@4.4.0)
+      joi: 17.13.3
+      lodash: 4.17.21
+      minimist: 1.2.8
+      rxjs: 7.8.2
+    transitivePeerDependencies:
+      - debug
+
+  webidl-conversions@7.0.0: {}
+
+  webpack-virtual-modules@0.6.2: {}
+
+  whatwg-encoding@3.1.1:
+    dependencies:
+      iconv-lite: 0.6.3
+
+  whatwg-mimetype@4.0.0: {}
+
+  whatwg-url@14.2.0:
+    dependencies:
+      tr46: 5.1.0
+      webidl-conversions: 7.0.0
+
+  which@2.0.2:
+    dependencies:
+      isexe: 2.0.0
+
+  which@5.0.0:
+    dependencies:
+      isexe: 3.1.1
+
+  why-is-node-running@2.3.0:
+    dependencies:
+      siginfo: 2.0.0
+      stackback: 0.0.2
+
+  word-wrap@1.2.5: {}
+
+  wrap-ansi@6.2.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+
+  wrap-ansi@7.0.0:
+    dependencies:
+      ansi-styles: 4.3.0
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+
+  wrap-ansi@8.1.0:
+    dependencies:
+      ansi-styles: 6.2.1
+      string-width: 5.1.2
+      strip-ansi: 7.1.0
+
+  wrappy@1.0.2: {}
+
+  ws@8.18.1: {}
+
+  xml-name-validator@4.0.0: {}
+
+  xml-name-validator@5.0.0: {}
+
+  xmlchars@2.2.0: {}
+
+  yallist@3.1.1: {}
+
+  yaml@2.7.0:
+    optional: true
+
+  yauzl@2.10.0:
+    dependencies:
+      buffer-crc32: 0.2.13
+      fd-slicer: 1.1.0
+
+  yocto-queue@0.1.0: {}
+
+  yoctocolors@2.1.1: {}
Added +3 -0
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
new file mode 100644
index 0000000..b49dbd7
--- /dev/null
+++ b/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+packages:
+  - 'packages/*'
+  - 'core'
Added +59 -0
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8c862ab
--- /dev/null
+++ b/README.md
@@ -0,0 +1,59 @@
+# cube-front
+
+## 推荐的IDE设置
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)(并禁用Vetur)。
+
+## `.vue`导入在TS中的类型支持
+
+TypeScript默认无法处理`.vue`导入的类型信息,所以我们用`vue-tsc`替换`tsc` CLI进行类型检查。在编辑器中,我们需要[Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)使TypeScript语言服务能够识别`.vue`类型。
+
+## 自定义配置
+
+查看[Vite配置参考](https://vite.dev/config/)。
+
+## 项目设置
+
+```sh
+pnpm install
+```
+
+### 编译和开发热重载
+
+```sh
+pnpm dev
+```
+
+### 类型检查、编译和生产环境压缩
+
+```sh
+pnpm build
+```
+
+### 使用[Vitest](https://vitest.dev/)运行单元测试
+
+```sh
+pnpm test:unit
+```
+
+### 使用[Cypress](https://www.cypress.io/)运行端到端测试
+
+```sh
+pnpm test:e2e:dev
+```
+
+这将针对Vite开发服务器运行端到端测试。
+它比生产构建要快得多。
+
+但在部署之前,仍然建议使用`test:e2e`测试生产构建(例如在CI环境中):
+
+```sh
+pnpm build
+pnpm test:e2e
+```
+
+### 使用[ESLint](https://eslint.org/)进行代码检查
+
+```sh
+pnpm lint
+```
Added +13 -0
diff --git a/ROADMAP.md b/ROADMAP.md
new file mode 100644
index 0000000..9c9e669
--- /dev/null
+++ b/ROADMAP.md
@@ -0,0 +1,13 @@
+# 路线图
+
+## 目标
+
+我们的目标是构建一个高效、可靠且易于使用的软件产品。通过以下路线图,我们将逐步实现这些目标。
+
+## 阶段一:生成入口虚拟模块
+
+生成一个虚拟的模块,导出一个App.tsx,App实现默认路由布局。通过文件夹结构生成路由,注入到路由系统
+
+## 阶段二:生成布局虚拟模块
+
+实现一个默认布局,路由系统默认使用该布局
Added +52 -0
diff --git a/src/plugins/vite-plugin-force-css-module.ts b/src/plugins/vite-plugin-force-css-module.ts
new file mode 100644
index 0000000..32fed92
--- /dev/null
+++ b/src/plugins/vite-plugin-force-css-module.ts
@@ -0,0 +1,52 @@
+import fs from 'fs'
+import path from 'path'
+import { PluginOption } from 'vite';
+
+const langs = 'css|less'
+const langsRegExp = new RegExp(`\\.(${langs})\\?modules$`)
+const langsModuleRegExp = new RegExp(`\\.module\\.(${langs})\\?modules$`)
+
+/** 强制使导入的css变成模块。
+ *  vite中,导入的样式文件带module,就会被处理成模块,此插件正是利用这一原理,将查询参数?modules的样式文件名加上module。
+ *  只要带查询参数?modules,无论是直接引入还是导出成模块,都会被处理成模块。
+ */
+const forceCssModulePlugin = (): PluginOption => {
+  return {
+    name: 'force-css-module',
+    enforce: 'pre',
+    resolveId(source, importer) {
+      let id = source;
+      // 导入样式的路径带有?modules,且没有.module
+      if (langsRegExp.test(id) && !id.includes('.module')) {
+        // 根据importer,补充完整id为绝对路径,增加.module并保留?modules,以便load时使用
+        if (importer) {
+          const importerDir = path.dirname(importer);
+
+          // If source is a relative path, resolve it based on importer
+          if (!path.isAbsolute(id) && !id.startsWith('http')) {
+            id = path.resolve(importerDir, id);
+          }
+        }
+
+        const newId = id.replace(langsRegExp, '.module.$1?modules');
+
+        return newId;
+      }
+
+      return null;
+    },
+    load(id: string) {
+      // 处理模块 CSS 的加载
+      if (langsModuleRegExp.test(id)) {
+        // 去掉 ?modules,读取原始 CSS 内容并返回
+        const content = fs.readFileSync(id.replace('.module', '').replace('?modules', ''), 'utf-8');
+
+        return content;
+      }
+
+      return null;
+    },
+  };
+};
+
+export default forceCssModulePlugin;
\ No newline at end of file
Added +12 -0
diff --git a/src/stores/counter.ts b/src/stores/counter.ts
new file mode 100644
index 0000000..b6757ba
--- /dev/null
+++ b/src/stores/counter.ts
@@ -0,0 +1,12 @@
+import { ref, computed } from 'vue'
+import { defineStore } from 'pinia'
+
+export const useCounterStore = defineStore('counter', () => {
+  const count = ref(0)
+  const doubleCount = computed(() => count.value * 2)
+  function increment() {
+    count.value++
+  }
+
+  return { count, doubleCount, increment }
+})
Added +37 -0
diff --git a/tsconfig.app.json b/tsconfig.app.json
new file mode 100644
index 0000000..af02613
--- /dev/null
+++ b/tsconfig.app.json
@@ -0,0 +1,37 @@
+{
+  "extends": "@vue/tsconfig/tsconfig.dom.json",
+  "include": [
+    "env.d.ts",
+    "./**/*.vue",
+    "./**/*.ts",
+    "./**/*.d.ts",
+    "configs/microAppConfig.js",
+    "core/pages/Login.ts"
+  ],
+  "exclude": [
+    "src/**/__tests__/*"
+  ],
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "types": [
+      "element-plus/global"
+    ],
+    "paths": {
+      "@/*": [
+        "./src/*"
+      ],
+      "cube-front/core": [
+        "./core"
+      ],
+      "cube-front/core/*": [
+        "./core/*"
+      ],
+      "cube-front": [
+        "./"
+      ],
+      "cube-front/*": [
+        "./*"
+      ],
+    }
+  }
+}
\ No newline at end of file
Added +17 -0
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..5304731
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,17 @@
+{
+  "files": [],
+  "references": [
+    {
+      "path": "./tsconfig.node.json"
+    },
+    {
+      "path": "./tsconfig.app.json"
+    },
+    {
+      "path": "./tsconfig.vitest.json"
+    }
+  ],
+  "compilerOptions": {
+    "module": "NodeNext"
+  }
+}
Added +21 -0
diff --git a/tsconfig.node.json b/tsconfig.node.json
new file mode 100644
index 0000000..e9949e7
--- /dev/null
+++ b/tsconfig.node.json
@@ -0,0 +1,21 @@
+{
+  "extends": "@tsconfig/node22/tsconfig.json",
+  "include": [
+    "vite.config.*",
+    "vitest.config.*",
+    "cypress.config.*",
+    "nightwatch.conf.*",
+    "playwright.config.*",
+    "eslint.config.*"
+  ],
+  "compilerOptions": {
+    "noEmit": true,
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "allowSyntheticDefaultImports": true,
+    "types": [
+      "node"
+    ]
+  }
+}
\ No newline at end of file
Added +11 -0
diff --git a/tsconfig.vitest.json b/tsconfig.vitest.json
new file mode 100644
index 0000000..7d1d8ce
--- /dev/null
+++ b/tsconfig.vitest.json
@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.app.json",
+  "include": ["src/**/__tests__/*", "env.d.ts"],
+  "exclude": [],
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.vitest.tsbuildinfo",
+
+    "lib": [],
+    "types": ["node", "jsdom"]
+  }
+}
Added +81 -0
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..6630d97
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,81 @@
+import { join } from 'path';
+import { fileURLToPath, URL } from 'node:url';
+
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import vueJsx from '@vitejs/plugin-vue-jsx';
+import vueDevTools from 'vite-plugin-vue-devtools';
+import AutoImport from 'unplugin-auto-import/vite';
+import Components from 'unplugin-vue-components/vite';
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
+import cubeFront from './core/plugin/index'; // This is the plugin we want to build as a library
+
+// https://vite.dev/config/
+export default defineConfig(({ command, mode }) => {
+  // Check an environment variable to determine the build target
+  if (process.env.BUILD_TARGET === 'plugin') {
+    return {
+      // Configuration for building the plugin as a library
+      build: {
+        lib: {
+          entry: fileURLToPath(new URL('./core/plugin/index.ts', import.meta.url)),
+          name: 'CubeFrontPlugin', // Global variable name for UMD build (if UMD format is included)
+          formats: ['es'], // Output ES Module format
+          fileName: () => 'index.js', // Output to dist/plugin/index.js
+        },
+        rollupOptions: {
+          // Externalize dependencies that should not be bundled into the library
+          // e.g., external: ['vue'],
+          external: [], // Adjust if your plugin has peer dependencies
+          output: {
+            // globals: { // Define globals for externalized UMD dependencies
+            //   vue: 'Vue',
+            // },
+          },
+        },
+        outDir: 'dist/plugin', // Output directory for the plugin
+        sourcemap: true,
+        ssr: true, // Indicate that this library is intended for SSR/Node.js-like environments
+      },
+      // Plugins needed for building the library itself (if any)
+      // Typically, fewer plugins are needed for a library compared to an app.
+      // If core/plugin/index.ts is plain TS/JS, it might not need vue plugins.
+      plugins: [
+        // Add plugins required for your library build if necessary
+        // For example, if it uses Vue features:
+        // vue(),
+        // vueJsx(),
+      ],
+    };
+  } else {
+    // Default configuration for building the main application
+    return {
+      plugins: [
+        vue(),
+        vueJsx(),
+        vueDevTools(),
+        cubeFront(), // The plugin is used here in the main app build
+        AutoImport({
+          resolvers: [ElementPlusResolver()],
+        }),
+        Components({
+          resolvers: [ElementPlusResolver()],
+        }),
+      ],
+      resolve: {
+        alias: {
+          '@': fileURLToPath(new URL('./src', import.meta.url)),
+          'cube-front/core': fileURLToPath(new URL('./core', import.meta.url)),
+          'cube-front': join(__dirname, './'),
+        },
+      },
+      build: {
+        sourcemap: true, // Generates source maps for better debugging
+        outDir: 'dist', // Main app output directory
+      },
+      server: {
+        port: 8080,
+      },
+    };
+  }
+});
Added +14 -0
diff --git a/vitest.config.ts b/vitest.config.ts
new file mode 100644
index 0000000..c328717
--- /dev/null
+++ b/vitest.config.ts
@@ -0,0 +1,14 @@
+import { fileURLToPath } from 'node:url'
+import { mergeConfig, defineConfig, configDefaults } from 'vitest/config'
+import viteConfig from './vite.config'
+
+export default mergeConfig(
+  viteConfig,
+  defineConfig({
+    test: {
+      environment: 'jsdom',
+      exclude: [...configDefaults.exclude, 'e2e/**'],
+      root: fileURLToPath(new URL('./', import.meta.url)),
+    },
+  }),
+)