Vulnerable dependencies upgraded: - Backend: league/commonmark >=2.8.2 (HTML injection bypass), phpunit/phpunit >=11.5.50, laravel/tinker (psysh LPE) - Frontend: axios 1.13→1.15 (SSRF + metadata exfiltration), @casl/ability updated (prototype pollution) - Removed swiper from all 3 apps (prototype pollution CVE, only used in Vuexy demo pages) XSS vectors removed: - Deleted Vuexy demo pages with v-html rendering API data: help-center/article, academy/course-details - Deleted all front-pages (landing, pricing, checkout, payment) — Vuexy marketing template, not Crewli business logic - Deleted swiper demo components and views - Fixed admin main.ts: replaced innerHTML with template literal with safe DOM construction using textContent Cookie security: - Added SameSite=Strict and Secure flags to admin cookie defaults Cleanup: - Removed swiper SCSS from all 3 apps - Removed swiper custom element config from all 3 vite configs - Portal localStorage cleanup verified: reset() clears all keys, called on both explicit logout and 401 interceptor Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
136 lines
3.8 KiB
TypeScript
136 lines
3.8 KiB
TypeScript
import { fileURLToPath } from "node:url";
|
||
import vue from "@vitejs/plugin-vue";
|
||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||
import AutoImport from "unplugin-auto-import/vite";
|
||
import Components from "unplugin-vue-components/vite";
|
||
import {
|
||
VueRouterAutoImports,
|
||
getPascalCaseRouteName,
|
||
} from "unplugin-vue-router";
|
||
import VueRouter from "unplugin-vue-router/vite";
|
||
import { defineConfig } from "vite";
|
||
import VueDevTools from "vite-plugin-vue-devtools";
|
||
import MetaLayouts from "vite-plugin-vue-meta-layouts";
|
||
import vuetify from "vite-plugin-vuetify";
|
||
import svgLoader from "vite-svg-loader";
|
||
|
||
// https://vitejs.dev/config/
|
||
export default defineConfig({
|
||
plugins: [
|
||
// Docs: https://github.com/posva/unplugin-vue-router
|
||
// ℹ️ This plugin should be placed before vue plugin
|
||
VueRouter({
|
||
getRouteName: (routeNode) => {
|
||
// Convert pascal case to kebab case
|
||
return getPascalCaseRouteName(routeNode)
|
||
.replace(/([a-z\d])([A-Z])/g, "$1-$2")
|
||
.toLowerCase();
|
||
},
|
||
}),
|
||
vue(),
|
||
VueDevTools(),
|
||
vueJsx(),
|
||
|
||
// Docs: https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin
|
||
vuetify({
|
||
styles: {
|
||
// Absolute URL so resolution does not depend on process cwd (fixes common SASS 404s).
|
||
configFile: fileURLToPath(
|
||
new URL("./src/styles/settings.scss", import.meta.url),
|
||
),
|
||
},
|
||
}),
|
||
|
||
// Docs: https://github.com/dishait/vite-plugin-vue-meta-layouts?tab=readme-ov-file
|
||
MetaLayouts({
|
||
target: "./src/layouts",
|
||
defaultLayout: "default",
|
||
}),
|
||
|
||
// Docs: https://github.com/antfu/unplugin-vue-components#unplugin-vue-components
|
||
Components({
|
||
dirs: ["src/@core/components", "src/views/demos", "src/components"],
|
||
dts: true,
|
||
resolvers: [
|
||
(componentName) => {
|
||
// Auto import `VueApexCharts`
|
||
if (componentName === "VueApexCharts")
|
||
return {
|
||
name: "default",
|
||
from: "vue3-apexcharts",
|
||
as: "VueApexCharts",
|
||
};
|
||
},
|
||
],
|
||
}),
|
||
|
||
// Docs: https://github.com/antfu/unplugin-auto-import#unplugin-auto-import
|
||
AutoImport({
|
||
imports: [
|
||
"vue",
|
||
VueRouterAutoImports,
|
||
"@vueuse/core",
|
||
"@vueuse/math",
|
||
"vue-i18n",
|
||
"pinia",
|
||
],
|
||
dirs: [
|
||
"./src/@core/utils",
|
||
"./src/@core/composable/",
|
||
"./src/composables/",
|
||
"./src/utils/",
|
||
"./src/plugins/*/composables/*",
|
||
],
|
||
vueTemplate: true,
|
||
|
||
// ℹ️ Disabled to avoid confusion & accidental usage
|
||
ignore: ["useCookies", "useStorage"],
|
||
}),
|
||
|
||
svgLoader(),
|
||
],
|
||
define: { "process.env": {} },
|
||
resolve: {
|
||
alias: {
|
||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||
"@themeConfig": fileURLToPath(
|
||
new URL("./themeConfig.ts", import.meta.url),
|
||
),
|
||
"@core": fileURLToPath(new URL("./src/@core", import.meta.url)),
|
||
"@layouts": fileURLToPath(new URL("./src/@layouts", import.meta.url)),
|
||
"@images": fileURLToPath(
|
||
new URL("./src/assets/images/", import.meta.url),
|
||
),
|
||
"@styles": fileURLToPath(
|
||
new URL("./src/assets/styles/", import.meta.url),
|
||
),
|
||
"@configured-variables": fileURLToPath(
|
||
new URL(
|
||
"./src/assets/styles/variables/_template.scss",
|
||
import.meta.url,
|
||
),
|
||
),
|
||
},
|
||
},
|
||
server: {
|
||
port: 5174,
|
||
proxy: {
|
||
"/api": {
|
||
target: "http://localhost:8000",
|
||
changeOrigin: true,
|
||
},
|
||
},
|
||
warmup: {
|
||
clientFiles: ["./src/pages/**/*.vue", "./src/components/**/*.vue"],
|
||
},
|
||
},
|
||
build: {
|
||
chunkSizeWarningLimit: 5000,
|
||
},
|
||
optimizeDeps: {
|
||
exclude: ["vuetify"],
|
||
entries: ["./src/**/*.vue"],
|
||
force: true,
|
||
},
|
||
});
|